diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..ce4cc1b --- /dev/null +++ b/.clang-format @@ -0,0 +1,40 @@ +# Use the Google style in this project. +BasedOnStyle: Google + +# Some folks prefer to write "int& foo" while others prefer "int &foo". The +# Google Style Guide only asks for consistency within a project, we chose +# "int& foo" for this project: +DerivePointerAlignment: false +PointerAlignment: Left + +SortIncludes: false + +IncludeBlocks: Merge +IncludeCategories: +# Matches common headers first, but sorts them after project includes +- Regex: '^\"google/cloud/internal/disable_deprecation_warnings.inc\"$' + Priority: -1 +- Regex: '^\"google/cloud/(internal/|grpc_utils/|testing_util/|[^/]+\.h)' + Priority: 1000 +- Regex: '^\"google/cloud/' # project includes should sort first + Priority: 500 +- Regex: '^\"' + Priority: 1500 +- Regex: '^' + Priority: 5000 + +# Format raw string literals with a `pb` or `proto` tag as proto. +RawStringFormats: +- Language: TextProto + Delimiters: + - 'pb' + - 'proto' + BasedOnStyle: Google + +CommentPragmas: '(@copydoc)' \ No newline at end of file diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..b63d312 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +*.elf +.git/ +.vscode/ +docs/ +tools/ \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..9103071 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Ignore all differences in line endings +* -crlf \ No newline at end of file diff --git a/.github/workflows/compilation.yml b/.github/workflows/compilation.yml deleted file mode 100644 index 1e35fb2..0000000 --- a/.github/workflows/compilation.yml +++ /dev/null @@ -1,60 +0,0 @@ -# Based on https://github.com/ps2dev/gsKit/blob/master/.github/workflows/compilation.yml -# Thanks fjtrujy! - -name: CI - -on: - push: - pull_request: - repository_dispatch: - types: [run_build] - -jobs: - build: - runs-on: ubuntu-latest - container: ps2dev/ps2sdk-ports:latest - steps: - - uses: actions/checkout@v2 - - - name: Install dependencies - run: | - apk add build-base git - - - name: Compile engine - working-directory: ./ - env: - ZLIB: ${PS2SDK}/ports - LIBTIFF: ${PS2SDK}/ports - LIBJPEG: ${PS2SDK}/ports - LIBPNG: ${PS2SDK}/ports - TYRA: ${GITHUB_WORKSPACE} - run: | - make - - - name: Compile unit test project - working-directory: ./ - env: - TYRA: ${GITHUB_WORKSPACE} - run: | - make tests - - - name: Compile cube project - working-directory: ./ - env: - TYRA: ${GITHUB_WORKSPACE} - run: | - make cube - - - name: Compile floors project - working-directory: ./ - env: - TYRA: ${GITHUB_WORKSPACE} - run: | - make floors - - - name: Compile dolphin project - working-directory: ./ - env: - TYRA: ${GITHUB_WORKSPACE} - run: | - make dolphin diff --git a/.gitignore b/.gitignore index 489b289..77ef3f5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,38 +1,33 @@ -.vscode/ -.idea/ - -# --- - -# Prerequisites -*.d - -# Compiled Object files -*.slo -*.lo -*.o - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app -*.erl -*.elf +# --- + +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.vsm + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app +*.erl +*.elf +*.irx diff --git a/.vscode/.gitignore b/.vscode/.gitignore new file mode 100644 index 0000000..dae89fb --- /dev/null +++ b/.vscode/.gitignore @@ -0,0 +1,6 @@ +*.log + +# Configuration files +/c_cpp_properties.json +/tasks.json +/settings.json diff --git a/.vscode/configurations/windows-docker/c_cpp_properties.json b/.vscode/configurations/windows-docker/c_cpp_properties.json new file mode 100644 index 0000000..57181bd --- /dev/null +++ b/.vscode/configurations/windows-docker/c_cpp_properties.json @@ -0,0 +1,41 @@ +{ + "configurations": [ + { + "name": "Docker PS2SDK", + "includePath": [ + "${workspaceFolder}/**", + "C:/Users/YOUR-INTELLISENSE-PATH/ps2dev-intellisense/ps2sdk/common/include/**", + "C:/Users/YOUR-INTELLISENSE-PATH/ps2dev-intellisense/ps2sdk/ee/include/**", + "C:/Users/YOUR-INTELLISENSE-PATH/ps2dev-intellisense/ps2sdk/iop/include/**", + "C:/Users/YOUR-INTELLISENSE-PATH/ps2dev-intellisense/ps2sdk/ports/include/**", + "C:/Users/YOUR-INTELLISENSE-PATH/ps2dev-intellisense/ee/include/**", + "C:/Users/YOUR-INTELLISENSE-PATH/ps2dev-intellisense/ee/lib/gcc/mips64r5900el-ps2-elf/11.3.0/include/**", + "C:/Users/YOUR-INTELLISENSE-PATH/ps2dev-intellisense/ee/lib/gcc/mips64r5900el-ps2-elf/11.3.0/include-fixed/**", + "C:/Users/YOUR-INTELLISENSE-PATH/ps2dev-intellisense/ee/lib/gcc/mips64r5900el-ps2-elf/11.3.0/install-tools/include/**", + "C:/Users/YOUR-INTELLISENSE-PATH/ps2dev-intellisense/ee/lib/gcc/mips64r5900el-ps2-elf/11.3.0/plugin/include/**", + "C:/Users/YOUR-INTELLISENSE-PATH/ps2dev-intellisense/ee/mips64r5900el-ps2-elf/include/**", + "C:/Users/YOUR-INTELLISENSE-PATH/ps2dev-intellisense/ee/mips64r5900el-ps2-elf/sys-include/**", + "C:/Users/YOUR-INTELLISENSE-PATH/ps2dev-intellisense/gsKit/include/**", + "C:/Users/YOUR-INTELLISENSE-PATH/ps2dev-intellisense/iop/lib/gcc/mipsel-ps2-elf/11.3.0/include/**", + "C:/Users/YOUR-INTELLISENSE-PATH/ps2dev-intellisense/iop/lib/gcc/mipsel-ps2-elf/11.3.0/install-tools/include/**", + "C:/Users/YOUR-INTELLISENSE-PATH/ps2dev-intellisense/iop/lib/gcc/mipsel-ps2-elf/11.3.0/plugin/include/**", + "C:/Users/YOUR-INTELLISENSE-PATH/ps2dev-intellisense/iop/lib/gcc/mipsel-ps2-elf/11.3.0/include-fixed/**", + "C:/Users/YOUR-INTELLISENSE-PATH/ps2dev-intellisense/iop/lib/gcc/mipsel-ps2-irx/11.3.0/include/**", + "C:/Users/YOUR-INTELLISENSE-PATH/ps2dev-intellisense/iop/lib/gcc/mipsel-ps2-irx/11.3.0/install-tools/include/**", + "C:/Users/YOUR-INTELLISENSE-PATH/ps2dev-intellisense/iop/lib/gcc/mipsel-ps2-irx/11.3.0/plugin/include/**", + "C:/Users/YOUR-INTELLISENSE-PATH/ps2dev-intellisense/iop/lib/gcc/mipsel-ps2-irx/11.3.0/include-fixed/**" + ], + "defines": [ + "_EE", + "_IOP", + "__SPU__", + "INTELLISENSE" + ], + "cppStandard": "c++20", + "compilerPath": "", // Should be empty + "intelliSenseMode": "linux-gcc-x86", + "configurationProvider": "ms-vscode.cpptools" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/configurations/windows-docker/settings.json b/.vscode/configurations/windows-docker/settings.json new file mode 100644 index 0000000..56568d9 --- /dev/null +++ b/.vscode/configurations/windows-docker/settings.json @@ -0,0 +1,14 @@ +{ + "buildDirectory": "demo", + "C_Cpp.default.intelliSenseMode": "gcc-x86", + "files.associations": { + "*.vcl": "asm-collection", + "*.i": "asm-collection", + "*.vsm": "asm-collection", + "*.vclpp": "asm-collection", + "*.hpp": "cpp", + "*.cpp": "cpp", + "*.h": "c", + "*.c": "c" + } +} \ No newline at end of file diff --git a/.vscode/configurations/windows-docker/tasks.json b/.vscode/configurations/windows-docker/tasks.json new file mode 100644 index 0000000..d5c81c8 --- /dev/null +++ b/.vscode/configurations/windows-docker/tasks.json @@ -0,0 +1,119 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Build & run", + "dependsOrder": "sequence", + "dependsOn": [ + "1. Copy source code to docker volume", + "2. Compile via docker container", + "3. Copy binaries to host", + "4. Run PCSX2" + ], + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "type": "shell", + "label": "1. Copy source code to docker volume", + "command": "docker exec -t tyra-compiler sh -c 'rsync -ac --delete --exclude \".git\" --exclude \"docs\" --exclude \".vscode\" --exclude \"tools\" --exclude \"obj\" --exclude \"bin\" /host/ /src/'" + }, + { + "type": "shell", + "label": "2. Compile via docker container", + "command": "docker exec -t tyra-compiler sh -c 'cd ${config:buildDirectory} && make build-engine all'", + "problemMatcher": { + "base": "$gcc", + "fileLocation": [ + "autoDetect" + ] + } + }, + { + "type": "shell", + "label": "3. Copy binaries to host", + "command": "docker exec -t tyra-compiler sh -c 'rsync -zac --include=\"*/\" --include=\"bin/**\" --exclude=\"*\" /src/ /host/'" + }, + { + "type": "shell", + "label": "4. Run PCSX2", + "options": { + "cwd": "${config:buildDirectory}" + }, + "command": "./run.ps1" + }, + { + "type": "shell", + "label": "Convert WAV to ADPCM", + "dependsOn": [ + "1. Copy source code to docker volume" + ], + "command": "docker exec -t tyra-compiler sh -c 'adpenc ${input:wav2adpcmSource} ${input:wav2adpcmTarget} && rsync -zac /src/${input:wav2adpcmTarget} /host/${input:wav2adpcmTarget}'" + }, + { + "type": "shell", + "label": "Cleanup", + "command": "docker exec -t tyra-compiler sh -c 'rm -rf /src/*'" + }, + { + "type": "shell", + "label": "Send to PS2", + "command": "docker exec -t tyra-compiler sh -c 'cd ${config:buildDirectory}/bin && killall -v ps2client || true && ps2client -h ${input:ps2Ip} reset && ps2client -h ${input:ps2Ip} reset && ps2client -h ${input:ps2Ip} execee host:$(find . -maxdepth 1 -type f -name \"*.elf\")'" + }, + { + "type": "shell", + "label": "Open PS2 output logger", + "command": "docker stop ps2-logs || true && docker run -t --rm --name=ps2-logs -p ${input:local2Ip}:18194:18194/udp h4570/tyra sh -c 'ps2client -h ${input:ps2Ip} listen'", + "runOptions": { + "instanceLimit": 1 + }, + "presentation": { + "reveal": "always", + "panel": "new" + } + }, + { + "type": "shell", + "label": "Start docker container", + "command": "docker compose up -d" + }, + { + "type": "shell", + "label": "Stop docker container", + "command": "docker compose down" + }, + { + "type": "shell", + "label": "[Debug] Copy obj directory to host", + "command": "docker exec -t tyra-compiler sh -c 'rsync -zac --include=\"*/\" --include=\"obj/**\" --exclude=\"*\" /src/ /host/'" + } + ], + "inputs": [ + { + "id": "wav2adpcmSource", + "description": "Source file path (ex. ):", + "default": "demo/res/sound.wav", + "type": "promptString" + }, + { + "id": "wav2adpcmTarget", + "description": "Target file path (ex. ):", + "default": "demo/res/sound.adpcm", + "type": "promptString" + }, + { + "id": "ps2Ip", + "description": "PS2link ip address:", + "default": "192.168.1.200", + "type": "promptString" + }, + { + "id": "local2Ip", + "description": "Local ip address:", + "default": "192.168.1.245", + "type": "promptString" + } + ] +} \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..83ad6c7 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "ms-vscode.cpptools-extension-pack", + "ryzngard.vscode-header-source", + "maziac.asm-code-lens", + "dmnsgn.vscode-wavefront" + ] +} \ No newline at end of file diff --git a/CHANGELOG.MD b/CHANGELOG.MD deleted file mode 100644 index 3f1f18e..0000000 --- a/CHANGELOG.MD +++ /dev/null @@ -1,134 +0,0 @@ -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [1.36.3] - 2021-05-28 - -### Added -- Unit test project -- Assert -- CI via Github workflows -- Install tutorial as separated .MD file - -### Changed -- Improved BMP loader. -- All PRINT_LOG and PRINT_ERR to consoleLog() and assertMsg() -- Refactored makefiles -- **CHANGED ENV VARIABLES!** -- Install tutorial -- Readme - -## [1.31.2] - 2021-02-06 - -### Added -- Id to MeshFrame -- Non textured rendering (RGBA only) - -### Changed -- Moved color from mesh to mesh material. -- OBJ Loader refactor -- Logic of loadFrom() -- Migrated to GCC9 (valid with latest PS2SDK) - -### Removed -- Removed MeshId from TextureLink, TextureRepository - -## [1.29.1] - 2020-12-27 -### Added -- Created libpacket2 in PS2SDK -- Dolphin sample -- 2D support (Sprite class) -- Alpha blending (transparency) -- PNG support -- ADPCM support in audio class -- AudioFinish event in audio class -- BoundingBox class -- A lot of useful funcs in Matrix class -- Mock of file service -- Array mode to draw() (highly optimized for small meshes) -- VCLPP - Usage of VU1 Preprocessor - -### Changed -- Project setup (makefile mostly) -- Readme -- Switched into libpacket2 in `vifsender` and `gifsender` -- Timer class refactor -- Engine base refactor -- MeshTexture into Texture -- Refactored floors sample -- Refactored Audio class -- Fixed Path 3 lighting -- Refactored, optimized math classes (vector, matrix..) -- Cleanup in camera base -- Refactored Path 3 and Path 1 rendering -- Synchronization functions (`renderer->waitForRender()`) -- BMP class refactor -- Dff Loader refactor -- Optimized rendering data preparation - -### Removed -- Ari sample -- VU1 class - -## [1.1.0] - 2020-11-03 -### Added -- A lot of useful functions to Mesh class -- MeshFrame class -- MeshMaterial class -- MeshTexture class -- TextureLink struct -- Texture wrapping settings -- TextureRepository class -- PRINT_ERR() -- Ari sample - -### Changed -- Project setup (gitignore etc.) -- Readme -- DFF loader refactor -- OBJ loader refactor -- MD2 loader refactor -- 3D data classes refactor (one interface for all) -- Rendering refactor - -### Removed -- MeshSpec class -- Texture class -- Md2Model class -- ObjModel class -- DffModel class - -## [1.0.0] - 2020-10-28 -### Added -- Project setup (gitignore etc.) -- License -- Readme -- BMP support -- DFF support -- MD2 support -- OBJ support -- Animation support -- Engine base -- AudioListener class -- Rendering base -- Path 1 renderer (VU1) -- Path 3 renderer (GIF) -- Math classes (matrix, vector, plane..) -- Audio support (bg song only) -- Camera base -- Base lighting support (bugged) for Path 3 -- Pad support -- EE Timer -- Math class -- String class -- Mesh class with AABB -- Makefile -- Primitive floors sample - -[1.36.3]: https://github.com/h4570/tyra/compare/v1.31.2-alpha...v1.36.3-alpha -[1.31.2]: https://github.com/h4570/tyra/compare/v1.29.1-alpha...v1.31.2-alpha -[1.29.1]: https://github.com/h4570/tyra/compare/1.1.0...v1.29.1-alpha -[1.1.0]: https://github.com/h4570/tyra/compare/1.0.0...1.1.0 -[1.0.0]: https://github.com/h4570/tyra/compare/1.0.0 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..dfd1c4e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,67 @@ +# syntax=docker/dockerfile:1 +FROM ubuntu:20.04 + +# Install necessary packages for PS2DEV, VCLPP and VCL. +RUN apt-get update +ARG DEBIAN_FRONTEND=noninteractive +RUN apt-get install -y git make g++ texinfo bison flex gettext libgmp3-dev \ + libmpfr-dev libmpc-dev gcc binutils cmake wget patch zlib1g-dev libgsl-dev \ + unzip + +# Setup PS2DEV env +ENV PS2DEV /usr/local/ps2dev +RUN mkdir -p $PS2DEV +RUN chown -R $USER: $PS2DEV +ENV PS2SDK $PS2DEV/ps2sdk +ENV GSKIT $PS2DEV/gsKit +ENV PATH $PATH:${PS2DEV}/bin:${PS2DEV}/ee/bin:${PS2DEV}/iop/bin:${PS2DEV}/dvp/bin:${PS2SDK}/bin + +# Compile PS2DEV +RUN mkdir -p /temp/ps2dev +RUN git clone https://github.com/ps2dev/ps2dev.git /temp/ps2dev +WORKDIR "/temp/ps2dev" +RUN ./build-all.sh + +# Compile VCLPP +RUN mkdir -p /temp/vclpp +RUN git clone https://github.com/glampert/vclpp.git /temp/vclpp +WORKDIR "/temp/vclpp" +RUN make + +# Download VCL +RUN mkdir -p /temp/vcl +WORKDIR "/temp/vcl" +RUN wget http://apgcglz.cluster028.hosting.ovh.net/tyra/vcl.zip +RUN unzip vcl.zip + +# ------------------------------------------------------------------------------ + +# Start from clean image +FROM ubuntu:20.04 + +# Set ENV variables +ENV PS2DEV /usr/local/ps2dev +ENV PS2SDK $PS2DEV/ps2sdk +ENV PATH $PATH:${PS2DEV}/bin:${PS2DEV}/ee/bin:${PS2DEV}/iop/bin:${PS2DEV}/dvp/bin:${PS2SDK}/bin + +# Copy stuff from previous stage +COPY --from=0 ${PS2DEV} ${PS2DEV} +COPY --from=0 /temp/vcl/vcl /usr/bin/vcl +COPY --from=0 /temp/vclpp/vclpp /usr/bin/vclpp + +# Install packages for emulating x86 and Tyra (make, libmpc, psmisc) +RUN apt-get update +RUN apt-get install -y make rsync libmpc-dev qemu qemu-user-static binfmt-support psmisc + +# Add 32bit executables support for VCL +RUN dpkg --add-architecture i386 +RUN apt-get update +RUN apt-get install -y libstdc++5:i386 +RUN update-binfmts --install i386 /usr/bin/qemu-i386-static --magic '\x7fELF\x01\x01\x01\x03\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x03\x00\x01\x00\x00\x00' --mask '\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xf8\xff\xff\xff\xff\xff\xff\xff' + +# Set chmod +RUN chmod 755 /usr/bin/vclpp +RUN chmod 755 /usr/bin/vcl + +WORKDIR /src +CMD ["/bin/bash"] \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 261eeb9..0000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/Makefile b/Makefile deleted file mode 100644 index e6ff12f..0000000 --- a/Makefile +++ /dev/null @@ -1,97 +0,0 @@ -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2021, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# André Guilherme - -TYRA_DIR = ./ - -LIB_NAME = libtyra.a - -# ENGINE OBJECTS -ENGINE_OBJS = src/engine/engine.o \ - src/engine/modules/audio.o \ - src/engine/modules/camera_base.o \ - src/engine/modules/file_service.o \ - src/engine/modules/gif_sender.o \ - src/engine/modules/light.o \ - src/engine/modules/pad.o \ - src/engine/modules/renderer.o \ - src/engine/modules/texture_repository.o \ - src/engine/modules/timer.o \ - src/engine/modules/vif_sender.o \ - src/engine/models/math/matrix.o \ - src/engine/models/math/plane.o \ - src/engine/models/math/point.o \ - src/engine/models/math/vector3.o \ - src/engine/models/mesh_frame.o \ - src/engine/models/bounding_box.o \ - src/engine/models/mesh_material.o \ - src/engine/models/mesh.o \ - src/engine/models/sprite.o \ - src/engine/models/texture.o \ - src/engine/utils/math.o \ - src/engine/utils/string.o \ - src/engine/loaders/bmp_loader.o \ - src/engine/loaders/dff_loader.o \ - src/engine/loaders/md2_loader.o \ - src/engine/loaders/obj_loader.o \ - src/engine/loaders/png_loader.o \ - src/engine/vu1_progs/draw3D.o \ - -EE_LIBS := $(EE_LIBS) -ldraw -lcdvd -lgraph -lmath3d -lpacket -ldma -lpacket2 -lpad -laudsrv -lc -lstdc++ -lpng -lz - -EE_INCS := -I$(TYRA)/src/engine/include -I$(PS2SDK)/ports/include $(EE_INCS) - -EE_LDFLAGS := -L$(PS2SDK)/ports/lib -L$(TYRA)/src/engine $(EE_LDFLAGS) - -EE_CXXFLAGS := -DHAVE_LIBJPEG -DHAVE_LIBTIFF -DHAVE_LIBPNG -DHAVE_ZLIB -D_XCDVD $(EE_CXXFLAGS) - -EE_DVP = dvp-as - -EE_VCL = vcl - -EE_VCLPP = vclpp - -all: $(ENGINE_OBJS) - ar rcs $(LIB_NAME) $(ENGINE_OBJS) - cp -f $(LIB_NAME) $(PS2SDK)/ee/lib - rm -f $(ENGINE_OBJS) - -# Cube example -cube: - $(MAKE) -C src/samples/cube all clean - -# Dolphin example -dolphin: - $(MAKE) -C src/samples/dolphin all clean - -# Floors example -floors: - $(MAKE) -C src/samples/floors all clean - -# Rebuild the engine -rebuild-engine: - $(MAKE) -C src/engine && make && make EE_CXXFLAGS="-DNDEBUG $(EE_CXXFLAGS)" - -# Rebuild debug engine -rebuild-dbg-engine: - $(MAKE) -C src/engine && make && make - -# Unit tests folder -tests: - $(MAKE) -C src/unit_tests all clean - -# %.vcl: %.vclpp -# $(EE_VCLPP) $< $@ - -# %.vsm: %.vcl -# $(EE_VCL) $< >> $@ - -%.o: %.vsm - $(EE_DVP) $< -o $@ - -include $(PS2SDK)/samples/Makefile.pref -include $(PS2SDK)/samples/Makefile.eeglobal \ No newline at end of file diff --git a/Makefile.base b/Makefile.base new file mode 100644 index 0000000..e31c0b7 --- /dev/null +++ b/Makefile.base @@ -0,0 +1,117 @@ +#Compiler and Linker +EE_PREFIX := mips64r5900el-ps2-elf- +AR := $(EE_PREFIX)ar +AS := $(EE_PREFIX)as +CC := $(EE_PREFIX)gcc +CXX := $(EE_PREFIX)g++ +STRIP := $(EE_PREFIX)strip +BIN2S := $(PS2SDK)/bin/bin2s +VCL := vcl +VCLPP := vclpp +DVP := dvp-as + +IRXEMBEDDEDEXT := irx-em + +#Flags, Libraries and Includes +CFLAGS += -D_EE -Wall -O3 +LINKFLAGS += -O3 -Wl,-zmax-page-size=128 +ASFLAGS += -O3 +LIB += -lstdc++ -ldma -lpacket2 -lgraph -ldraw -lmath3d -lpng -lz -lpad -laudsrv -lpatches -lcdvd +INC += -I$(PS2DEV)/ps2sdk/ee/include -I$(PS2DEV)/ps2sdk/common/include -I$(PS2DEV)/ps2sdk/ports/include + +#--------------------------------------------------------------------------------- +#DO NOT EDIT BELOW THIS LINE +#--------------------------------------------------------------------------------- +SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT)) +OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT))) + +IRXEM_SOURCES := $(shell find $(SRCDIR) -type f -name *.$(IRXEMBEDDEDEXT)) +IRXEM_OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(IRXEM_SOURCES:.$(IRXEMBEDDEDEXT)=.$(OBJEXT))) + +VU_SOURCES_VCL := $(shell find $(SRCDIR) -type f -name *.$(VCLEXT)) +VU_OBJECTS_VCL := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(VU_SOURCES_VCL:.$(VCLEXT)=.$(OBJEXT))) + +VU_SOURCES_VSM := $(shell find $(SRCDIR) -type f -name *.$(VSMEXT)) +VU_OBJECTS_VSM := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(VU_SOURCES_VSM:.$(VSMEXT)=.$(OBJEXT))) + +VCL_SOURCES := $(shell find $(SRCDIR) -type f -name *.$(VCLPPEXT)) +VCL_OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(VCL_SOURCES:.$(VCLPPEXT)=.$(OBJEXT))) + +#Default Make +all: resources $(TARGET) +#all: resources irxcopy $(TARGET) + +release: + $(MAKE) CFLAGS="-DNDEBUG $(CFLAGS)" + +#Remake +remake: cleaner all + +#Copy Resources from Resources Directory to Target Directory +resources: directories + @cp -r $(RESDIR)/* $(TARGETDIR)/ || true + +#Make the Directories +directories: + @mkdir -p $(TARGETDIR) + @mkdir -p $(BUILDDIR) + +#Clean only Objects +clean: + @$(RM) -rf $(BUILDDIR) + +#Full Clean, Objects and Binaries +cleaner: clean + @$(RM) -rf $(TARGETDIR) + @$(RM) -rf $(BUILDDIR) + +#irxcopy: +# @cp $(PS2SDK)/iop/irx/audsrv.irx $(TARGETDIR)/audsrv.irx + +#Pull in dependency info for *existing* .o files +-include $(OBJECTS:.$(OBJEXT)=.$(DEPEXT)) + +#Link +$(TARGET): $(OBJECTS) $(VCL_OBJECTS) $(VU_OBJECTS_VCL) $(VU_OBJECTS_VSM) $(IRXEM_OBJECTS) + $(CXX) -T$(PS2DEV)/ps2sdk/ee/startup/linkfile -o $(TARGETDIR)/$(TARGET) $^ -L$(PS2DEV)/ps2sdk/ee/lib -L$(PS2SDK)/ports/lib $(LINKFLAGS) $(LIBDIRS) $(LIB) + $(STRIP) --strip-all $(TARGETDIR)/$(TARGET) + +$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(IRXEMBEDDEDEXT) + @mkdir -p $(dir $@) + @rm -f $@.s + $(BIN2S) $(shell head -1 $<) $@.s $(shell sed -n '2p' $<) + $(AS) $(ASFLAGS) $@.s -o $@ + +$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT) + @mkdir -p $(dir $@) + $(CXX) $(CFLAGS) $(INC) -c -o $@ $< + @$(CXX) $(CFLAGS) $(INCDEP) -MM $(SRCDIR)/$*.$(SRCEXT) > $(BUILDDIR)/$*.$(DEPEXT) + @cp -f $(BUILDDIR)/$*.$(DEPEXT) $(BUILDDIR)/$*.$(DEPEXT).tmp + @sed -e 's|.*:|$(BUILDDIR)/$*.$(OBJEXT):|' < $(BUILDDIR)/$*.$(DEPEXT).tmp > $(BUILDDIR)/$*.$(DEPEXT) + @sed -e 's/.*://' -e 's/\\$$//' < $(BUILDDIR)/$*.$(DEPEXT).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(BUILDDIR)/$*.$(DEPEXT) + @rm -f $(BUILDDIR)/$*.$(DEPEXT).tmp + +$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(VCLEXT) + @mkdir -p $(dir $@) + @rm -f $@.vsm + $(VCL) $< >> $@.vsm + $(DVP) $@.vsm -o $@ + +$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(VSMEXT) + @mkdir -p $(dir $@) + $(DVP) $< -o $@ + +$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(VCLPPEXT) + @mkdir -p $(dir $@) + @rm -f $@.vcl + @rm -f $@.vsm + $(VCLPP) $< $@.vcl + $(VCL) $@.vcl > $@.vsm + $(DVP) $@.vsm -o $@ + +run-pcsx2: + taskkill.exe /f /t /im pcsx2x64.exe || true + $(WSL_LINUX_PCSX2)/pcsx2x64.exe --elf=$(WSL_MAKE_WINDOWS)$(CURDIR)/$(TARGETDIR)/$(TARGET) + +#Non-File Targets +.PHONY: all remake clean cleaner resources \ No newline at end of file diff --git a/README.MD b/README.MD index 494b6aa..6d604c6 100644 --- a/README.MD +++ b/README.MD @@ -1,190 +1,167 @@ -[![Contributors][contributors-shield]][contributors-url] -[![MIT License][license-shield]][license-url] -[![Discord](https://img.shields.io/badge/discord-Tyra-brightgreen?logo=discord)](https://discord.gg/NhhTmg3Gm5) -[![Discord](https://img.shields.io/badge/discord-PS2--Scene-brightgreen?logo=discord)](https://discord.gg/7dCr6ThSN5) - -
-

- - Logo - - -

Tyra - alpha 1.36.3

- -

- Open source game engine for PlayStation 2™ -
- Dolphin sample » -   - Floors sample » -
-
- Report Bug - · - Request Feature -

-

- -[![Stargazers repo roster for h4570/tyra](https://reporoster.com/stars/h4570/tyra)](https://github.com/h4570/tyra/stargazers) - -## Table of Contents - -* [About the Project](#about-the-project) - * [Samples](#samples) - * [Description](#description) - * [Features](#features) - * [Branches](#branches) -* [Getting Started](#getting-started) - * [Installation](#installation) - * [Prerequisites](#prerequisites) -* [Roadmap](#roadmap) -* [Contributing](#contributing) -* [License](#license) -* [Built With](#built-with) -* [Acronyms](#acronyms) -* [Thanks](#thanks) - -
- -## About the Project - -Sample code -Sample game - -### Samples -* [Dolphin](https://github.com/h4570/tyra/tree/master/src/samples/dolphin) -* [Floors](https://github.com/h4570/tyra/tree/master/src/samples/floors) -* [Cube](https://github.com/h4570/tyra/tree/master/src/samples/cube) - -### Description -Tyra is a project that aims to facilitate the development of PlayStation 2 games. The goal is simple API which will allow you to develop some nice small homebrew games in a short period of time. Finally, (thanks to PS2DEV team) Tyra supports C++20, so we are free from the 2003's GCC which only supported C++98. -**Project is on alpha stage, so keep in mind that there are many things to be done and to fix.** -Unfortunately there are not many people, which want's to help with this project. **If you want to be a volunteer**, but don't have too much knowledge in this field, write to me on Discord, **I will be happy to help.** - -When project will be on beta stage, we plan to create some YouTube tutorials :) - -**Why was this project created?** -PS2 development can be a big challenge. -PS2 it's pretty low-level and there are a lot of stuff that you must do from scratch. -For example, if you want to render something using only PS2DEV you must: -- Create VU1 micro-program -- Load micro-program and send it to VU1 -- Create parser for your 3D file -- Create parser for texture file -- Calculate lights, shadows, MVP matrices (3D->2D).. -- Clip triangles ([sic!](https://github.com/h4570/tyra/issues/14)) -- Prepare DMA packets for coprocessors communication -- Setup rasterizer (GS) -- Send texture to GS -- Send packets -- Synchronize all - -but with Tyra you can do it with methods like `loadObj()` and `draw()` 😁. - -### Features -* 3D support - VU1 "Path 1 rendering" -* 2D support - PNG & BMP -* Frustum culling, backface culling -* OpenGL adaptions: Perspective projection, lookAt camera -* Texture support - .bmp and png -* Mesh loaders: ".obj", ".dff" (RenderWare, GTA:SA) and ".md2" (Quake II) -* Threading support -* Animation support for obj and md2 -* Audio support - .wav and .adpcm -* Pad support - -### Branches -* Master - monthly releases - tested on PS2 & PCSX2. -* Develop - daily builds - can be unstable. - -
- -## Getting Started - -### Installation -Step by step [tutorial here](https://github.com/h4570/tyra/tree/develop/docs) -If you need any support, feel free to ask questions on discord: -[![Discord](https://img.shields.io/badge/discord-Tyra-brightgreen?logo=discord)](https://discord.gg/NhhTmg3Gm5) - -### Prerequisites - -* PS2 DEV environment - [PS2DEV](https://github.com/ps2dev/ps2dev) -* At least #58ffb33 PS2SDK (28.05.2021) - [PS2SDK](https://github.com/ps2dev/ps2sdk) -* PS2 Emulator. For example [PCSX2](https://pcsx2.net/) - -
- -## Extra info -* If you want to use your own .obj file, please check "triangulate faces" in blender. -PS2 is supporting only triangle primitive type. - -
- -## Roadmap - -### Roadmap for next master release: -[Next release roadmap](https://github.com/h4570/tyra/projects/4) - -See the [open issues](https://github.com/h4570/tyra/issues) for a list of proposed features (and known issues). - -
- -## Contributing - -Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**. - -1. Fork the Project -2. Create your Feature Branch (`git checkout -b feature/amazing-feature`) -3. Commit your Changes (`git commit -m 'Add some amazing-feature'`) -4. Push to the Branch (`git push origin feature/amazing-feature`) -5. Open a Pull Request - -
- -## License - -Distributed under the Apache License 2.0 License. See `LICENSE` for more information. - -
- -## Built With - -* [PS2DEV](https://github.com/ps2dev/ps2dev) - -
- -## Acronyms -* EE (Emotion Engine) - whole set of processors and subsystems that make up the PlayStation 2 -* GS (Graphic synthesizer) - configurable rasterizer and texture mapper. Has only 2MB~ memory for textures, but for the opposite have very high transfer rate, so you can switch textures in the blink -* VU0 - programmable (ASM) vector processor that is accessed by inline assembly code injected into C program. -* VU1 - programmable (ASM) vector processor, which is similar to vertex shader. Accessed via DMA. -* IOP - I/O processor which enables access to peripheral devices, such the game controller - -
- -## Thanks - -Without these guys, everything would be harder: -* Dr Henry Fortuna - for code sources -* Rick Gaiser, fjtrujy - for help and new GCC! -* Lukasz D.K. - for huge archive of PS2 stuff -* Guilherme Lampert - for code sources -* Jesper Svennevid, Daniel Collin - for openvcl's code samples -* Whole PS2DEV team -* Manieq - for nice splash screens! -* And so many other guys. Thanks! - -Project Link: [https://github.com/h4570/tyra](https://github.com/h4570/tyra) -Sandro Sobczyński - sandro.sobczynski@gmail.com -[![LinkedIn][linkedin-shield]](https://linkedin.com/in/sandro-sobczyński-28820b15a) - -
- - Logo - - -[contributors-shield]: https://img.shields.io/github/contributors/h4570/tyra.svg?style=flat-square -[contributors-url]: https://github.com/h4570/tyra/graphs/contributors -[linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=flat-square&logo=linkedin&colorB=555 -[license-shield]: https://img.shields.io/github/license/h4570/tyra.svg?style=flat-square -[license-url]: https://github.com/h4570/tyra/blob/master/LICENSE +[![Contributors][contributors-shield]][contributors-url] +[![MIT License][license-shield]][license-url] +[![Discord](https://img.shields.io/badge/discord-Tyra-brightgreen?logo=discord)](https://discord.gg/NhhTmg3Gm5) +[![Discord](https://img.shields.io/badge/discord-PS2--Scene-brightgreen?logo=discord)](https://discord.gg/7dCr6ThSN5) + +
+

+ + Logo + + +

Tyra - 2.0

+ +

+ Open source game engine for PlayStation 2™ +
+ YouTube tutorials » +   +
+
+ Report Bug + · + Request Feature +

+

+ +[![Stargazers repo roster for h4570/tyra](https://reporoster.com/stars/h4570/tyra)](https://github.com/h4570/tyra/stargazers) + +## Table of Contents + +* [About the project](#about-the-project) + * [Description](#description) + * [Tutorials](#tutorials) + * [Features](#features) + * [Branches](#branches) +* [Contributing](#contributing) +* [License](#license) +* [Built With](#built-with) +* [Acronyms](#acronyms) +* [Thanks](#thanks) + +
+ +## About the Project +

+ Sample code + Sample game +

+ +--- +### Description +Tyra is a project that allows you to easily create games for the PlayStation 2 console. +When I tried to make a game for PS2 a few years ago, I realized how many things had to be done to tame this exotic console architecture. +Decision was simple - I need to create an engine which will handle 3D file loading, 2D/3D rendering, animation, audio, handling between PS2 CPUs, synchronization and it should be simple as possible - so people with no experience can create a simple game in a few hours. +**And that's what Tyra is all about.** + +### Tutorials +* Setup environment - [Text tutorial](https://github.com/h4570/tyra/tree/master/docs/install) or [Video (soon)](https://www.youtube.com/playlist?list=PLdQVLBcXRRWvtMi-OqccDWLTEFEisD5RH) +* Cook game assets - [Video (soon)](https://www.youtube.com/playlist?list=PLdQVLBcXRRWvtMi-OqccDWLTEFEisD5RH) +* Create game from template - [Video (soon)](https://www.youtube.com/playlist?list=PLdQVLBcXRRWvtMi-OqccDWLTEFEisD5RH) +--- +* 01 - [Code](https://github.com/h4570/tyra/tree/master/tutorials/01-hello), [Video (soon)](https://www.youtube.com/playlist?list=PLdQVLBcXRRWvtMi-OqccDWLTEFEisD5RH) - Hello world +* 02 - [Code](https://github.com/h4570/tyra/tree/master/tutorials/02-sprite), [Video (soon)](https://www.youtube.com/playlist?list=PLdQVLBcXRRWvtMi-OqccDWLTEFEisD5RH) - 2D rendering +* 03 - [Code](https://github.com/h4570/tyra/tree/master/tutorials/03-minecraft), [Video (soon)](https://www.youtube.com/playlist?list=PLdQVLBcXRRWvtMi-OqccDWLTEFEisD5RH) - 3D minecraft blocks +* 04 - [Code](https://github.com/h4570/tyra/tree/master/tutorials/04-de_dust2), [Video (soon)](https://www.youtube.com/playlist?list=PLdQVLBcXRRWvtMi-OqccDWLTEFEisD5RH) - `de_dust2.obj` rendering +* 05 - [Code](https://github.com/h4570/tyra/tree/master/tutorials/05-animation), [Video (soon)](https://www.youtube.com/playlist?list=PLdQVLBcXRRWvtMi-OqccDWLTEFEisD5RH) - 3D animation +* 06 - [Code](https://github.com/h4570/tyra/tree/master/tutorials/06-audio), [Video (soon)](https://www.youtube.com/playlist?list=PLdQVLBcXRRWvtMi-OqccDWLTEFEisD5RH) - Background music and sound effects +* 07 - [Code](https://github.com/h4570/tyra/tree/master/tutorials/07-lighting), [Video (soon)](https://www.youtube.com/playlist?list=PLdQVLBcXRRWvtMi-OqccDWLTEFEisD5RH) - Static lightmap and dynamic directional lights +* 08 - [Code](https://github.com/h4570/tyra/tree/master/tutorials/08-skybox-debug), [Video (soon)](https://www.youtube.com/playlist?list=PLdQVLBcXRRWvtMi-OqccDWLTEFEisD5RH) - Skybox and debug rendering +* 09 - [Code](https://github.com/h4570/tyra/tree/master/tutorials/09-manual-mode), [Video (soon)](https://www.youtube.com/playlist?list=PLdQVLBcXRRWvtMi-OqccDWLTEFEisD5RH) - Manual rendering (a'la OpenGL) + +--- + +### Features +* Docker image with Tyra, all tools and `PS2DEV` C++20 compiler +* 3D rendering via `VU1` coprocessor: + * Static rendering + * Morph animation rendering + * Super optimized, custom minecraft block renderer + * Debug rendering (lines, boxes, bboxes) + * Manual rendering (a'la `OpenGL`) +* 2D rendering +* Frustum culling: + * Simple - culling whole mesh + * Precise - culling only visible parts of mesh +* Clipping: + * Standard "fake", but fast PS2 clipping done in `VU1` + * Software triangle done in `EE Core` +* Optimized math functions via `VU0` coprocessor +* Background music and sound effects support +* Pad support +* `.wav` Audio file support +* `.obj` 3D file support +* `.md2` 3D file support +* `.png` Texture file support + +### Branches +* `master` - stable releases - tested on PS2 & PCSX2. +* `develop` - daily builds. + +See the [open issues](https://github.com/h4570/tyra/issues) for a list of proposed features (and known issues). + +
+ +## Contributing + +Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**. + +1. Fork the Project +2. Create your Feature Branch (`git checkout -b feature/amazing-feature`) +3. Commit your Changes (`git commit -m 'Add some amazing-feature'`) +4. Push to the Branch (`git push origin feature/amazing-feature`) +5. Open a Pull Request + +
+ +## License + +Distributed under the Apache License 2.0 License. See `LICENSE` for more information. + +
+ +## Built With + +* [PS2DEV](https://github.com/ps2dev/ps2dev) +* [VCLPP](https://github.com/glampert/vclpp) +* Sony VCL + +
+ +## Acronyms +* EE (Emotion Engine) - whole set of processors and subsystems that make up the PlayStation 2 +* EE Core - main PS2 CPU (c++ done here) +* GS (Graphic synthesizer) - configurable rasterizer and texture mapper. Has only 2MB~ memory for textures, but for the opposite have very high transfer rate, so you can switch textures in the blink +* VU0 - programmable (ASM) vector processor that is accessed by inline assembly code injected into C program. +* VU1 - programmable (ASM) vector processor, which is similar to vertex shader. Accessed via DMA. +* IOP - I/O processor which enables access to peripheral devices, such the game controller + +
+ +## Credits + +Without these guys, Tyra would not happen: +* Dr Henry Fortuna - for code sources, PS2 academy tutorials +* Rick Gaiser, fjtrujy - for maintaining PS2DEV +* Wellington Carvalho - for testing, contributing to Tyra and sharing cool ideas! +* Lukasz D.K. - for huge archive of PS2 stuff +* Guilherme Lampert - for code sources +* Jesper Svennevid, Daniel Collin - for openvcl's code samples +* Whole PS2DEV team +* Manieq - for nice splash screens! +* And so many other guys. Thanks! + +Project Link: [https://github.com/h4570/tyra](https://github.com/h4570/tyra) +Sandro Sobczyński - sandro.sobczynski@gmail.com +[![LinkedIn][linkedin-shield]](https://linkedin.com/in/sandro-sobczyński-28820b15a) + +
+ + Logo + + +[contributors-shield]: https://img.shields.io/github/contributors/h4570/tyra.svg?style=flat-square +[contributors-url]: https://github.com/h4570/tyra/graphs/contributors +[linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=flat-square&logo=linkedin&colorB=555 +[license-shield]: https://img.shields.io/github/license/h4570/tyra.svg?style=flat-square +[license-url]: https://github.com/h4570/tyra/blob/master/LICENSE \ No newline at end of file diff --git a/ROADMAP.txt b/ROADMAP.txt new file mode 100644 index 0000000..48c8771 --- /dev/null +++ b/ROADMAP.txt @@ -0,0 +1,23 @@ +------------ Tyra's v2.0 roadmap to publish on GitHub ------------ +- [General] Readme Credits: clipping, obj loader +- [Video] How to setup environment +- [Video] How to work with Tyra +- [Video] How to create own game +- [Video] How to cook assets (audio, textures, obj) +- [Video] Tutorial videos +- [Video] How to run game from USB + +------------ Github issues for Tyra v2 ------------ +- [Demo] BBox constructors +- [General] Add cpp lint checker in GitHub / static code analysis +- [General] Smart pointers and std::array instead of raw pointers +- [General] Control generated id to avoid duplication. Maybe Just increment from 0? Add interface IIdentificable? +- [renderer] fog +- [General] CI in Github via docker image +- [MD2] Refactor +- [2D] Add zbuffer support (z-index) +- [3DUtility] Add zbuffer support (z-index), cupMesh->translation.translateZ(10.0F) - wylaczyc zeby widziec problem +- [2D] Fixed font support +- [File] Async file loading +- [tyrdat] Custom 3D data file with precalculated bboxes with support of async loading +- [Renderer] Interlacing, and then 640x448 resolution diff --git a/demo/Makefile b/demo/Makefile new file mode 100644 index 0000000..cd99cc7 --- /dev/null +++ b/demo/Makefile @@ -0,0 +1,33 @@ +TARGET := demo.elf +ENGINEDIR := ../engine + +#The Directories, Source, Includes, Objects, Binary and Resources +SRCDIR := src +INCDIR := inc +BUILDDIR := obj +TARGETDIR := bin +RESDIR := res +SRCEXT := cpp +VSMEXT := vsm +VCLEXT := vcl +VCLPPEXT := vclpp +DEPEXT := d +OBJEXT := o + +#Flags, Libraries and Includes +CFLAGS := +LIB := -ltyra +LIBDIRS := -L$(ENGINEDIR)/bin +INC := -I$(INCDIR) -I$(ENGINEDIR)/inc +INCDEP := -I$(INCDIR) -I$(ENGINEDIR)/inc + +include ../Makefile.base + +clean-engine: + cd $(ENGINEDIR) && $(MAKE) cleaner + +build-engine: + cd $(ENGINEDIR) && $(MAKE) + +build-release-engine: + cd $(ENGINEDIR) && $(MAKE) release diff --git a/src/samples/floors/bin/.gitignore b/demo/bin/.gitignore similarity index 95% rename from src/samples/floors/bin/.gitignore rename to demo/bin/.gitignore index 86d0cb2..44c5ea8 100644 --- a/src/samples/floors/bin/.gitignore +++ b/demo/bin/.gitignore @@ -1,4 +1,4 @@ -# Ignore everything in this directory -* -# Except this file +# Ignore everything in this directory +* +# Except this file !.gitignore \ No newline at end of file diff --git a/demo/inc/demo_game.hpp b/demo/inc/demo_game.hpp new file mode 100644 index 0000000..bae41fb --- /dev/null +++ b/demo/inc/demo_game.hpp @@ -0,0 +1,34 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "state/state_manager.hpp" + +using Tyra::Engine; +using Tyra::Game; + +namespace Demo { + +class DemoGame : public Game { + public: + DemoGame(Engine* engine); + ~DemoGame(); + + void init(); + void loop(); + + private: + Engine* engine; + StateManager stateManager; +}; + +} // namespace Demo diff --git a/demo/inc/game_settings.hpp b/demo/inc/game_settings.hpp new file mode 100644 index 0000000..48f8ac0 --- /dev/null +++ b/demo/inc/game_settings.hpp @@ -0,0 +1,17 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +namespace Demo { + +const bool IS_REAL_PS2 = false; + +} // namespace Demo diff --git a/demo/inc/state/global_state_type.hpp b/demo/inc/state/global_state_type.hpp new file mode 100644 index 0000000..6b34be4 --- /dev/null +++ b/demo/inc/state/global_state_type.hpp @@ -0,0 +1,17 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +namespace Demo { + +enum GlobalStateType { STATE_INTRO, STATE_LOADING, STATE_GAME, STATE_EXIT }; + +} // namespace Demo diff --git a/demo/inc/state/state.hpp b/demo/inc/state/state.hpp new file mode 100644 index 0000000..1bc18c0 --- /dev/null +++ b/demo/inc/state/state.hpp @@ -0,0 +1,40 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include + +using Tyra::Engine; + +namespace Demo { + +template +class State { + public: + State(Engine* t_engine) : engine(t_engine) {} + virtual ~State() {} + + virtual const StateTypeT& getState() const = 0; + + virtual const bool& wantFinish() const = 0; + + virtual void onStart() = 0; + + virtual void update() = 0; + + /** @return Next game state */ + virtual StateTypeT onFinish() = 0; + + protected: + Engine* engine; +}; + +} // namespace Demo diff --git a/demo/inc/state/state_manager.hpp b/demo/inc/state/state_manager.hpp new file mode 100644 index 0000000..1bc7179 --- /dev/null +++ b/demo/inc/state/state_manager.hpp @@ -0,0 +1,99 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "./state.hpp" +#include "./global_state_type.hpp" + +namespace Demo { + +template +class StateManager { + public: + StateManager(const StateTypeT& t_initialState, + const StateTypeT& t_exitState) { + stateInitialized = false; + currentState = t_initialState; + exitState = t_exitState; + } + + ~StateManager() { freeAll(); } + + const StateTypeT& getCurrentState() const { return currentState; } + + const StateTypeT& getExitState() const { return exitState; } + + bool finished() const { return currentState == exitState; } + + std::vector*>* getAll() { return &states; } + + State* get(const StateTypeT& stateType) { + for (auto& state : states) { + if (state->getState() == stateType) { + return state; + } + } + return nullptr; + } + + void add(State* state) { states.push_back(state); } + + /** remove (without free) */ + void remove(const State* state) { + states.erase(std::remove(states.begin(), states.end(), state), + states.end()); + } + + /** free and remove */ + void free(const State* state) { + auto* found = get(state); + if (!found) return; + + remove(found); + delete found; + } + + /** free and remove all */ + void freeAll() { + for (auto& state : states) { + delete state; + } + states.clear(); + } + + void update() { + for (auto& state : states) { + if (state->getState() == currentState) { + if (state->wantFinish()) { + currentState = state->onFinish(); + stateInitialized = false; + break; + } + + if (!stateInitialized) { + state->onStart(); + stateInitialized = true; + } + + state->update(); + break; + } + } + } + + private: + bool stateInitialized; + std::vector*> states; + StateTypeT currentState, exitState; +}; + +} // namespace Demo diff --git a/demo/inc/states/game/enemy/enemy.hpp b/demo/inc/states/game/enemy/enemy.hpp new file mode 100644 index 0000000..993faec --- /dev/null +++ b/demo/inc/states/game/enemy/enemy.hpp @@ -0,0 +1,63 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "states/game/renderer/renderer_dynamic_pair.hpp" +#include "states/game/terrain/heightmap.hpp" +#include "states/game/player/player_shoot_action.hpp" +#include "./enemy_info.hpp" + +using Tyra::AnimationSequenceCallback; +using Tyra::Audio; +using Tyra::DynamicMesh; +using Tyra::DynPipOptions; +using Tyra::Engine; +using Tyra::Renderer; +using Tyra::Renderer3DUtility; +using Tyra::TextureRepository; +using Tyra::Vec4; + +namespace Demo { + +class Enemy { + public: + Enemy(Engine* engine, const EnemyInfo& info); + ~Enemy(); + + DynamicMesh* mesh; + DynPipOptions* options; + RendererDynamicPair* pair; + + void update(const Heightmap& heightmap, const Vec4& playerPosition, + const PlayerShootAction& shootAction); + + private: + std::vector walkSequence; + std::vector fightSequence; + + void allocateOptions(); + void walk(const Heightmap& heightmap, const Vec4& positionDiff); + void animationCallback(const AnimationSequenceCallback& callback); + void fight(); + void handlePlayerShoot(const PlayerShootAction& shootAction); + void setMeshToSpawn(); + + bool isWalking = true; + bool isFighting = false; + Vec4 terrainLeftUp; + Vec4 terrainRightDown; + + Audio* audio; + EnemyInfo info; +}; + +} // namespace Demo diff --git a/demo/inc/states/game/enemy/enemy_info.hpp b/demo/inc/states/game/enemy/enemy_info.hpp new file mode 100644 index 0000000..2da3d85 --- /dev/null +++ b/demo/inc/states/game/enemy/enemy_info.hpp @@ -0,0 +1,33 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include + +using Tyra::DynamicMesh; +using Tyra::Texture; +using Tyra::Vec4; + +namespace Demo { + +struct EnemyInfo { + u8 adpcmChannel; + audsrv_adpcm_t* adpcmPunch; + audsrv_adpcm_t* adpcmDeath; + DynamicMesh* motherMesh; + Texture* bodyTexture; + Texture* clothTexture; + Vec4 terrainLeftUp; + Vec4 terrainRightDown; +}; + +} // namespace Demo diff --git a/demo/inc/states/game/enemy/enemy_manager.hpp b/demo/inc/states/game/enemy/enemy_manager.hpp new file mode 100644 index 0000000..acb0db2 --- /dev/null +++ b/demo/inc/states/game/enemy/enemy_manager.hpp @@ -0,0 +1,45 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include "states/game/terrain/heightmap.hpp" +#include "states/game/player/player_shoot_action.hpp" +#include "./enemy.hpp" + +using Tyra::DynamicMesh; +using Tyra::Engine; +using Tyra::Texture; +using Tyra::TextureRepository; +using Tyra::Vec4; + +namespace Demo { + +class EnemyManager { + public: + EnemyManager(Engine* engine, const Heightmap& heightmap); + ~EnemyManager(); + + void update(const Heightmap& heightmap, const Vec4& playerPosition, + const PlayerShootAction& shootAction); + + std::vector getPairs() const; + + private: + TextureRepository* textureRepo; + std::vector enemies; + DynamicMesh* motherMesh; + Texture* bodyTexture; + Texture* clothTexture; +}; + +} // namespace Demo diff --git a/demo/inc/states/game/game_state.hpp b/demo/inc/states/game/game_state.hpp new file mode 100644 index 0000000..800480e --- /dev/null +++ b/demo/inc/states/game/game_state.hpp @@ -0,0 +1,58 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "state/state.hpp" +#include "state/global_state_type.hpp" +#include "./player/player.hpp" +#include "./renderer/game_renderer.hpp" +#include "./terrain/terrain.hpp" +#include "./skybox/skybox.hpp" +#include "./ship/ship.hpp" +#include "./hud/hud.hpp" +#include "./enemy/enemy_manager.hpp" + +using std::unique_ptr; + +namespace Demo { + +class GameState : public State { + public: + GameState(Engine* t_engine); + ~GameState(); + + const GlobalStateType& getState() const { return state; } + + const bool& wantFinish() const { return _wantFinish; }; + + void onStart(); + + void update(); + + /** @return Next game state */ + GlobalStateType onFinish(); + + private: + GlobalStateType state; + bool _wantFinish; + bool initialized; + u8 fpsChecker; + + GameRenderer renderer; + unique_ptr player; + unique_ptr enemyManager; + unique_ptr terrain; + unique_ptr skybox; + unique_ptr ship; + unique_ptr hud; +}; + +} // namespace Demo diff --git a/demo/inc/states/game/hud/hud.hpp b/demo/inc/states/game/hud/hud.hpp new file mode 100644 index 0000000..b13ac1a --- /dev/null +++ b/demo/inc/states/game/hud/hud.hpp @@ -0,0 +1,39 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include + +using std::unique_ptr; +using Tyra::Sprite; +using Tyra::Texture; +using Tyra::TextureRepository; + +namespace Demo { + +class Hud { + public: + Hud(TextureRepository* repo); + ~Hud(); + + TextureRepository* repo; + + unique_ptr hpSprite; + unique_ptr crosshairSprite; + unique_ptr soldierSprite; + + Texture* hpTexture; + Texture* crosshairTexture; + Texture* soldierTexture; +}; + +} // namespace Demo diff --git a/demo/inc/states/game/player/camera.hpp b/demo/inc/states/game/player/camera.hpp new file mode 100644 index 0000000..1e31f18 --- /dev/null +++ b/demo/inc/states/game/player/camera.hpp @@ -0,0 +1,40 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include + +using Tyra::CameraInfo3D; +using Tyra::Pad; +using Tyra::Vec4; + +namespace Demo { + +class Camera { + public: + Camera(Pad* pad); + ~Camera(); + + Vec4 lookAt; + Vec4 position; + Vec4 unitCircle; + + CameraInfo3D getCameraInfo() { return CameraInfo3D(&position, &lookAt); } + + void update(const Vec4& playerPosition, const float& terrainHeight); + + private: + float circleRotation, lengthFromOrigin, height; + + Pad* pad; +}; + +} // namespace Demo diff --git a/demo/inc/states/game/player/player.hpp b/demo/inc/states/game/player/player.hpp new file mode 100644 index 0000000..1eb4b66 --- /dev/null +++ b/demo/inc/states/game/player/player.hpp @@ -0,0 +1,53 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "states/game/renderer/renderer_dynamic_pair.hpp" +#include "states/game/renderer/renderer_static_pair.hpp" +#include "states/game/terrain/heightmap.hpp" +#include "./weapon.hpp" +#include "./camera.hpp" +#include "./player_shoot_action.hpp" +#include + +using Tyra::Engine; +using Tyra::Pad; +using Tyra::Renderer3DUtility; +using Tyra::Vec4; + +namespace Demo { + +class Player { + public: + Player(Engine* engine); + ~Player(); + + const Vec4& getPosition() const { return position; } + CameraInfo3D getCameraInfo() { return camera.getCameraInfo(); } + + RendererStaticPair* pair; + + void update(const Heightmap& heightmap); + + PlayerShootAction getShootAction() const; + + private: + void handlePlayerPosition(const Heightmap& heightmap, + const float& terrainHeight); + + float speed; + Pad* pad; + Vec4 position; + Weapon weapon; + Camera camera; +}; + +} // namespace Demo diff --git a/demo/inc/states/game/player/player_shoot_action.hpp b/demo/inc/states/game/player/player_shoot_action.hpp new file mode 100644 index 0000000..5227866 --- /dev/null +++ b/demo/inc/states/game/player/player_shoot_action.hpp @@ -0,0 +1,25 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include + +using Tyra::Ray; + +namespace Demo { + +struct PlayerShootAction { + bool isShooting = false; + std::optional ray; +}; + +} // namespace Demo diff --git a/demo/inc/states/game/player/weapon.hpp b/demo/inc/states/game/player/weapon.hpp new file mode 100644 index 0000000..5a3be04 --- /dev/null +++ b/demo/inc/states/game/player/weapon.hpp @@ -0,0 +1,54 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include + +using Tyra::Audio; +using Tyra::Engine; +using Tyra::Pad; +using Tyra::Renderer; +using Tyra::StaPipOptions; +using Tyra::StaticMesh; +using Tyra::TextureRepository; +using Tyra::Timer; +using Tyra::Vec4; + +namespace Demo { + +class Weapon { + public: + Weapon(Engine* engine); + ~Weapon(); + + StaticMesh* mesh; + StaPipOptions* options; + bool isShooting = false; + + void update(); + + private: + bool isShootAnimation1, isShootAnimation2; + Pad* pad; + Audio* audio; + Timer shootTimer; + Vec4 initialPosition; + u8 adpcmCurrentChannel; + u8 adpcmChannelsCount; + + audsrv_adpcm_t* shootAdpcm; + + void shoot(); + void allocateOptions(); + u8 getShootChannel(); +}; + +} // namespace Demo diff --git a/demo/inc/states/game/renderer/game_renderer.hpp b/demo/inc/states/game/renderer/game_renderer.hpp new file mode 100644 index 0000000..2fa36f2 --- /dev/null +++ b/demo/inc/states/game/renderer/game_renderer.hpp @@ -0,0 +1,52 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "./renderer_static_pair.hpp" +#include "./renderer_dynamic_pair.hpp" + +using Tyra::CoreBBox; +using Tyra::DynamicPipeline; +using Tyra::Renderer; +using Tyra::Sprite; +using Tyra::StaticPipeline; + +namespace Demo { + +class GameRenderer { + public: + GameRenderer(Renderer* renderer); + ~GameRenderer(); + + void add(std::vector staticPairs); + void add(std::vector dynamicPairs); + void add(RendererStaticPair* staticPair); + void add(RendererDynamicPair* dynamicPair); + void add(Sprite* sprite); + void add(const CoreBBox& bbox); + + void clear(); + void render(); + + private: + Renderer* renderer; + + StaticPipeline stpip; + DynamicPipeline dypip; + + std::vector staticPairs; + std::vector dynamicPairs; + std::vector sprites; + std::vector bboxes; +}; + +} // namespace Demo diff --git a/demo/inc/states/game/renderer/renderer_dynamic_pair.hpp b/demo/inc/states/game/renderer/renderer_dynamic_pair.hpp new file mode 100644 index 0000000..3e90e4e --- /dev/null +++ b/demo/inc/states/game/renderer/renderer_dynamic_pair.hpp @@ -0,0 +1,25 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include + +using Tyra::DynamicMesh; +using Tyra::DynPipOptions; + +namespace Demo { + +struct RendererDynamicPair { + DynamicMesh* mesh; + DynPipOptions* options; +}; + +} // namespace Demo diff --git a/demo/inc/states/game/renderer/renderer_static_pair.hpp b/demo/inc/states/game/renderer/renderer_static_pair.hpp new file mode 100644 index 0000000..2d1547c --- /dev/null +++ b/demo/inc/states/game/renderer/renderer_static_pair.hpp @@ -0,0 +1,25 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include + +using Tyra::StaPipOptions; +using Tyra::StaticMesh; + +namespace Demo { + +struct RendererStaticPair { + StaticMesh* mesh; + StaPipOptions* options; +}; + +} // namespace Demo diff --git a/demo/inc/states/game/ship/ship.hpp b/demo/inc/states/game/ship/ship.hpp new file mode 100644 index 0000000..4b50637 --- /dev/null +++ b/demo/inc/states/game/ship/ship.hpp @@ -0,0 +1,37 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "states/game/renderer/renderer_static_pair.hpp" + +using Tyra::Renderer; +using Tyra::StaPipOptions; +using Tyra::StaticMesh; +using Tyra::TextureRepository; +using Tyra::Vec4; + +namespace Demo { + +class Ship { + public: + Ship(TextureRepository* repo); + ~Ship(); + + StaticMesh* mesh; + StaPipOptions* options; + RendererStaticPair* pair; + + private: + void allocateOptions(); +}; + +} // namespace Demo diff --git a/demo/inc/states/game/skybox/skybox.hpp b/demo/inc/states/game/skybox/skybox.hpp new file mode 100644 index 0000000..510b590 --- /dev/null +++ b/demo/inc/states/game/skybox/skybox.hpp @@ -0,0 +1,39 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "states/game/renderer/renderer_static_pair.hpp" + +using Tyra::Renderer; +using Tyra::StaPipOptions; +using Tyra::StaticMesh; +using Tyra::TextureRepository; +using Tyra::Vec4; + +namespace Demo { + +class Skybox { + public: + Skybox(TextureRepository* repo); + ~Skybox(); + + StaticMesh* mesh; + StaPipOptions* options; + RendererStaticPair* pair; + + void update(const Vec4& playerPosition); + + private: + void allocateOptions(); +}; + +} // namespace Demo diff --git a/demo/inc/states/game/terrain/heightmap.hpp b/demo/inc/states/game/terrain/heightmap.hpp new file mode 100644 index 0000000..d79bc53 --- /dev/null +++ b/demo/inc/states/game/terrain/heightmap.hpp @@ -0,0 +1,43 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include + +using Tyra::Vec4; + +namespace Demo { + +class Heightmap { + public: + Heightmap(const float& minHeight, const float& maxHeight, const Vec4& leftUp, + const Vec4& rightDown); + ~Heightmap(); + + const float& getHeightOffset(const Vec4& playerPosition) const; + + bool isOutside(const Vec4& position) const; + + float** map; + s16 mapWidth, mapHeight; + float minHeight, maxHeight; + Vec4 leftUp, rightDown; + + private: + float getWidthPercentage(const Vec4& playerPosition) const; + float getHeightPercentage(const Vec4& playerPosition) const; + void allocateMap(const unsigned char* data, const int& width, + const int& height); + float getGameHeight(const u8& inputColor, const u8& minColor, + const u8& maxColor) const; +}; + +} // namespace Demo diff --git a/demo/inc/states/game/terrain/terrain.hpp b/demo/inc/states/game/terrain/terrain.hpp new file mode 100644 index 0000000..5eb5bf4 --- /dev/null +++ b/demo/inc/states/game/terrain/terrain.hpp @@ -0,0 +1,40 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "states/game/renderer/renderer_static_pair.hpp" +#include "./heightmap.hpp" + +using Tyra::StaPipOptions; +using Tyra::StaticMesh; +using Tyra::TextureRepository; +using Tyra::Vec4; + +namespace Demo { + +class Terrain { + public: + Terrain(TextureRepository* repo); + ~Terrain(); + + Heightmap heightmap; + StaticMesh* mesh; + StaPipOptions* options; + RendererStaticPair* pair; + + float getHeightOffset(const Vec4& playerPosition); + + private: + void allocateOptions(); +}; + +} // namespace Demo diff --git a/demo/inc/states/intro/intro_state.hpp b/demo/inc/states/intro/intro_state.hpp new file mode 100644 index 0000000..b70d26b --- /dev/null +++ b/demo/inc/states/intro/intro_state.hpp @@ -0,0 +1,44 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "state/state.hpp" +#include "state/global_state_type.hpp" +#include "state/state_manager.hpp" +#include "./intro_state_type.hpp" + +namespace Demo { + +class IntroState : public State { + public: + IntroState(Engine* t_engine); + ~IntroState(); + + const GlobalStateType& getState() const { return state; } + + const bool& wantFinish() const { return _wantFinish; }; + + void onStart(); + + void update(); + + /** @return Next game state */ + GlobalStateType onFinish(); + + private: + GlobalStateType state; + bool _wantFinish; + bool initialized; + + StateManager stateManager; +}; + +} // namespace Demo diff --git a/demo/inc/states/intro/intro_state_type.hpp b/demo/inc/states/intro/intro_state_type.hpp new file mode 100644 index 0000000..8bb5a51 --- /dev/null +++ b/demo/inc/states/intro/intro_state_type.hpp @@ -0,0 +1,22 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +namespace Demo { + +enum IntroStateType { + STATE_PS2DEV, + STATE_TYRA, + STATE_PRESS_KEY, + STATE_INTRO_END +}; + +} // namespace Demo diff --git a/demo/inc/states/intro/states/intro_press_key_state.hpp b/demo/inc/states/intro/states/intro_press_key_state.hpp new file mode 100644 index 0000000..cbc6c44 --- /dev/null +++ b/demo/inc/states/intro/states/intro_press_key_state.hpp @@ -0,0 +1,74 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "state/state.hpp" +#include "../intro_state_type.hpp" +#include + +using Tyra::Sprite; +using Tyra::Texture; +using Tyra::Timer; +using Tyra::Vec2; + +namespace Demo { + +class IntroPressKeyState : public State { + public: + IntroPressKeyState(Engine* t_engine); + ~IntroPressKeyState(); + + const IntroStateType& getState() const { return state; } + + const bool& wantFinish() const { return _wantFinish; }; + + void onStart(); + + /** @return Next game state */ + IntroStateType onFinish(); + + void update(); + + private: + void renderFiller(); + void updateMap(); + + IntroStateType state; + bool _wantFinish; + bool initialized; + bool mapFadeIn; + bool fillerFadeIn; + bool showPressKey; + bool pressKeyAlphaToggle; + u8 pressKeyAlphaDelayer; + + float fillersOffset; + constexpr static float textureWidthHeight = 512.0F; + const static u8 mapRows = 3; + const static u8 mapCols = 3; + + Vec2 mapPosition; + u8 mapDirection; + + Texture* fillerTexture; + Sprite* fillerSprite; + + Texture* logoTexture; + Sprite* logoSprite; + + Texture* pressKeyTexture; + Sprite* pressKeySprite; + + Texture* mapTextures[mapRows][mapCols]; + Sprite* mapSprites[mapRows][mapCols]; +}; + +} // namespace Demo diff --git a/demo/inc/states/intro/states/intro_ps2dev_state.hpp b/demo/inc/states/intro/states/intro_ps2dev_state.hpp new file mode 100644 index 0000000..4607f0e --- /dev/null +++ b/demo/inc/states/intro/states/intro_ps2dev_state.hpp @@ -0,0 +1,54 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "state/state.hpp" +#include "../intro_state_type.hpp" +#include + +using Tyra::Sprite; +using Tyra::Texture; +using Tyra::Timer; + +namespace Demo { + +class IntroPs2DevState : public State { + public: + IntroPs2DevState(Engine* t_engine); + ~IntroPs2DevState(); + + const IntroStateType& getState() const { return state; } + + const bool& wantFinish() const { return _wantFinish; }; + + void onStart(); + + void update(); + + /** @return Next game state */ + IntroStateType onFinish(); + + private: + IntroStateType state; + bool _wantFinish; + + Texture* texture; + Timer initialDelayTimer; + bool initialized; + bool initialDelayElapsed; + bool fadeinActivated; + bool fadeoutActivated; + u8 frameSkipper; + + Sprite* sprite; +}; + +} // namespace Demo diff --git a/demo/inc/states/intro/states/intro_tyra_state.hpp b/demo/inc/states/intro/states/intro_tyra_state.hpp new file mode 100644 index 0000000..f0058f6 --- /dev/null +++ b/demo/inc/states/intro/states/intro_tyra_state.hpp @@ -0,0 +1,63 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "state/state.hpp" +#include "../intro_state_type.hpp" +#include + +using Tyra::Sprite; +using Tyra::Texture; +using Tyra::Timer; + +namespace Demo { + +class IntroTyraState : public State { + public: + IntroTyraState(Engine* t_engine); + ~IntroTyraState(); + + const IntroStateType& getState() const { return state; } + + const bool& wantFinish() const { return _wantFinish; }; + + void onStart(); + + void update(); + + /** @return Next game state */ + IntroStateType onFinish(); + + private: + IntroStateType state; + bool _wantFinish; + + Texture* tyraTexture; + Texture* bgTexture; + Texture* bg2Texture; + Texture* fillerTexture; + + Timer initialDelayTimer; + bool initialized; + bool initialDelayElapsed; + bool animActivated; + bool fadeoutActivated; + u8 frameSkipper; + + Sprite* tyraSprite; + Sprite* bgSprite; + Sprite* bg2Sprite; + Sprite* fillerSprite; + + void renderFillers(); +}; + +} // namespace Demo diff --git a/demo/inc/states/loading/loading_state.hpp b/demo/inc/states/loading/loading_state.hpp new file mode 100644 index 0000000..9d010ca --- /dev/null +++ b/demo/inc/states/loading/loading_state.hpp @@ -0,0 +1,41 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "state/state.hpp" +#include "state/global_state_type.hpp" +#include "state/state_manager.hpp" + +namespace Demo { + +class LoadingState : public State { + public: + LoadingState(Engine* t_engine); + ~LoadingState(); + + const GlobalStateType& getState() const { return state; } + + const bool& wantFinish() const { return _wantFinish; }; + + void onStart(); + + void update(); + + /** @return Next game state */ + GlobalStateType onFinish(); + + private: + GlobalStateType state; + bool _wantFinish; + bool initialized; +}; + +} // namespace Demo diff --git a/src/samples/cube/bin/.gitignore b/demo/res/.gitignore similarity index 95% rename from src/samples/cube/bin/.gitignore rename to demo/res/.gitignore index 86d0cb2..44c5ea8 100644 --- a/src/samples/cube/bin/.gitignore +++ b/demo/res/.gitignore @@ -1,4 +1,4 @@ -# Ignore everything in this directory -* -# Except this file +# Ignore everything in this directory +* +# Except this file !.gitignore \ No newline at end of file diff --git a/demo/run.ps1 b/demo/run.ps1 new file mode 100644 index 0000000..58035c6 --- /dev/null +++ b/demo/run.ps1 @@ -0,0 +1,4 @@ +$ConfigFile = Join-Path $PSScriptRoot '../windows-pcsx2.ps1' +. $ConfigFile + +RunPCSX2 diff --git a/demo/src/demo_game.cpp b/demo/src/demo_game.cpp new file mode 100644 index 0000000..9767d5c --- /dev/null +++ b/demo/src/demo_game.cpp @@ -0,0 +1,35 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "demo_game.hpp" +#include "states/intro/intro_state.hpp" +#include "states/loading/loading_state.hpp" +#include "states/game/game_state.hpp" + +namespace Demo { + +DemoGame::DemoGame(Engine* t_engine) + : engine(t_engine), stateManager(STATE_INTRO, STATE_EXIT) {} +DemoGame::~DemoGame() {} + +void DemoGame::init() { + stateManager.add(new IntroState(engine)); + stateManager.add(new LoadingState(engine)); + stateManager.add(new GameState(engine)); +} +void DemoGame::loop() { + stateManager.update(); + + if (stateManager.finished()) { + exit(0); + } +} + +} // namespace Demo diff --git a/demo/src/main.cpp b/demo/src/main.cpp new file mode 100644 index 0000000..08cc626 --- /dev/null +++ b/demo/src/main.cpp @@ -0,0 +1,29 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include +#include "demo_game.hpp" +#include "game_settings.hpp" + +int main() { + Tyra::EngineOptions options; + + if (Demo::IS_REAL_PS2) { + options.writeLogsToFile = true; + options.loadUsbDriver = true; + } + + Tyra::Engine engine(options); + + Demo::DemoGame game(&engine); + engine.run(&game); + SleepThread(); + return 0; +} diff --git a/demo/src/states/game/enemy/enemy.cpp b/demo/src/states/game/enemy/enemy.cpp new file mode 100644 index 0000000..86070af --- /dev/null +++ b/demo/src/states/game/enemy/enemy.cpp @@ -0,0 +1,159 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "states/game/enemy/enemy.hpp" +#include + +using Tyra::Color; +using Tyra::Math; + +namespace Demo { + +Enemy::Enemy(Engine* engine, const EnemyInfo& t_info) { + info = t_info; + + mesh = new DynamicMesh(*info.motherMesh); + + auto* bodyMaterial = mesh->getMaterialByName("BodyMaterial"); + auto* clothMaterial = mesh->getMaterialByName("ClothMaterial"); + + TYRA_ASSERT(bodyMaterial != nullptr && clothMaterial != nullptr, + "Body and cloth materials not found!"); + + info.bodyTexture->addLink(bodyMaterial->id); + info.clothTexture->addLink(clothMaterial->id); + + float r = Math::randomf(75.0F, 128.0F); + float g = Math::randomf(75.0F, 128.0F); + float b = Math::randomf(75.0F, 128.0F); + + bodyMaterial->ambient.set(r, g, b); + clothMaterial->ambient.set(r, g, b); + + walkSequence = {0, 1, 2}; + fightSequence = {3, 4, 5}; + + terrainLeftUp = info.terrainLeftUp; + terrainRightDown = info.terrainRightDown; + + setMeshToSpawn(); + + mesh->animation.setSequence(walkSequence); + mesh->animation.loop = true; + mesh->animation.setCallback( + std::bind(&Enemy::animationCallback, this, std::placeholders::_1)); + mesh->translation.translateY(-5.0F); + + audio = &engine->audio; + audio->adpcm.setVolume(30, info.adpcmChannel); + + allocateOptions(); + + pair = new RendererDynamicPair{mesh, options}; +} + +Enemy::~Enemy() { + delete mesh; + delete options; + delete pair; +} + +void Enemy::setMeshToSpawn() { + auto spawnPoint = + Vec4(Math::randomf(terrainLeftUp.x, terrainRightDown.x), 0.0F, + Math::randomf(terrainLeftUp.z, terrainRightDown.z), 1.0F); + + mesh->setPosition(spawnPoint); +} + +void Enemy::update(const Heightmap& heightmap, const Vec4& playerPosition, + const PlayerShootAction& shootAction) { + auto* enemyPosition = mesh->getPosition(); + + handlePlayerShoot(shootAction); + + auto diff = *enemyPosition - playerPosition; + auto ang = Math::atan2(diff.x, diff.z); + + if (diff.length() > 150.0F) { + walk(heightmap, diff); + } else { + fight(); + } + + const float naturalRotation = 3.1F; + mesh->rotation.identity(); + ang += naturalRotation; + mesh->rotation.rotateByAngle(ang, Vec4(0.0F, 1.0F, 0.0F, 0.0F)); + + mesh->update(); +} + +void Enemy::handlePlayerShoot(const PlayerShootAction& shootAction) { + if (!shootAction.isShooting) { + return; + } + + const auto& ray = shootAction.ray.value(); + + auto bbox = + mesh->getCurrentBoundingBox().getTransformed(mesh->getModelMatrix()); + + auto isOnEnemy = ray.intersectBox(bbox.min(), bbox.max()); + + if (isOnEnemy) { + setMeshToSpawn(); + audio->adpcm.tryPlay(info.adpcmDeath, info.adpcmChannel); + } +} + +void Enemy::walk(const Heightmap& heightmap, const Vec4& positionDiff) { + if (isFighting) { + mesh->animation.setSequence(walkSequence); + } + + isFighting = false; + isWalking = true; + + auto* enemyPosition = mesh->getPosition(); + auto normalized = positionDiff; + normalized.normalize(); + const float speed = 2.5F; + auto nextPos = *enemyPosition - normalized * speed; + nextPos.y = heightmap.getHeightOffset(nextPos) - 60.0F; + + mesh->translation.identity(); + mesh->translation.translate(nextPos); +} + +void Enemy::fight() { + if (isWalking) { + mesh->animation.setSequence(fightSequence); + } + + isFighting = true; + isWalking = false; +} + +void Enemy::animationCallback(const AnimationSequenceCallback& callback) { + if (callback == AnimationSequenceCallback::AnimationSequenceCallback_Loop) { + if (isFighting) { + audio->adpcm.tryPlay(info.adpcmPunch, info.adpcmChannel); + } + } +} + +void Enemy::allocateOptions() { + options = new DynPipOptions(); + options->frustumCulling = + Tyra::PipelineFrustumCulling::PipelineFrustumCulling_None; +} + +} // namespace Demo diff --git a/demo/src/states/game/enemy/enemy_manager.cpp b/demo/src/states/game/enemy/enemy_manager.cpp new file mode 100644 index 0000000..62f30a7 --- /dev/null +++ b/demo/src/states/game/enemy/enemy_manager.cpp @@ -0,0 +1,92 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "states/game/enemy/enemy_manager.hpp" +#include +#include "game_settings.hpp" + +using Tyra::FileUtils; +using Tyra::Math; +using Tyra::ObjLoader; +using Tyra::ObjLoaderOptions; + +namespace Demo { + +EnemyManager::EnemyManager(Engine* engine, const Heightmap& heightmap) { + textureRepo = &engine->renderer.core.texture.repository; + + ObjLoader loader; + ObjLoaderOptions objOptions; + objOptions.animation.count = 6; + objOptions.flipUVs = true; + objOptions.scale = 250.0F; + + auto data = loader.load(FileUtils::fromCwd("game/models/zombie/zombie.obj"), + objOptions); + data->normalsEnabled = false; + motherMesh = new DynamicMesh(data.get()); + + bodyTexture = textureRepo->add( + FileUtils::fromCwd("game/models/zombie/BodyMaterial.png")); + + clothTexture = textureRepo->add( + FileUtils::fromCwd("game/models/zombie/ClothMaterial.png")); + + auto* punch = engine->audio.adpcm.load( + FileUtils::fromCwd("game/models/zombie/punch.adpcm")); + + auto* death = engine->audio.adpcm.load( + FileUtils::fromCwd("game/models/zombie/death.adpcm")); + + const int enemyCount = IS_REAL_PS2 ? 8 : 12; + for (int i = 0; i < enemyCount; i++) { + EnemyInfo info; + info.adpcmChannel = 9 + i; + info.adpcmPunch = punch; + info.adpcmDeath = death; + info.motherMesh = motherMesh; + info.clothTexture = clothTexture; + info.bodyTexture = bodyTexture; + info.terrainLeftUp = heightmap.leftUp; + info.terrainRightDown = heightmap.rightDown; + enemies.push_back(new Enemy(engine, info)); + } +} + +EnemyManager::~EnemyManager() { + for (auto* enemy : enemies) { + delete enemy; + } + + delete motherMesh; + + textureRepo->free(bodyTexture->id); + textureRepo->free(clothTexture->id); +} + +std::vector EnemyManager::getPairs() const { + std::vector result; + + for (auto* enemy : enemies) { + result.push_back(enemy->pair); + } + + return result; +} + +void EnemyManager::update(const Heightmap& heightmap, + const Vec4& playerPosition, + const PlayerShootAction& shootAction) { + for (auto* enemy : enemies) { + enemy->update(heightmap, playerPosition, shootAction); + } +} + +} // namespace Demo diff --git a/demo/src/states/game/game_state.cpp b/demo/src/states/game/game_state.cpp new file mode 100644 index 0000000..75121e5 --- /dev/null +++ b/demo/src/states/game/game_state.cpp @@ -0,0 +1,97 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "states/game/game_state.hpp" +#include "game_settings.hpp" + +using std::make_unique; +using Tyra::FileUtils; + +namespace Demo { + +GameState::GameState(Engine* t_engine) + : State(t_engine), renderer(&t_engine->renderer) { + state = STATE_GAME; + _wantFinish = false; + initialized = false; + fpsChecker = 0; +} + +GameState::~GameState() {} + +void GameState::onStart() { + TYRA_LOG("Game. RAM: ", engine->info.getAvailableRAM(), "MB"); + + engine->audio.song.stop(); + engine->audio.song.inLoop = true; + engine->audio.song.load(FileUtils::fromCwd("game/game-audio.wav")); + engine->audio.song.setVolume(0); + engine->audio.song.play(); + + auto* repository = &engine->renderer.core.texture.repository; + player = make_unique(engine); + terrain = make_unique(repository); + enemyManager = make_unique(engine, terrain->heightmap); + ship = make_unique(repository); + skybox = make_unique(repository); + hud = make_unique(repository); + + engine->audio.song.setVolume(85); + + if (IS_REAL_PS2) engine->renderer.setFrameLimit(false); + + initialized = true; +} + +GlobalStateType GameState::onFinish() { + if (!initialized) return STATE_EXIT; + + initialized = false; + + return STATE_EXIT; +} + +void GameState::update() { + // Check fps + if (fpsChecker++ > 50) { + TYRA_LOG("FPS: ", engine->info.getFps(), + " RAM: ", engine->info.getAvailableRAM()); + fpsChecker = 0; + } + + // Game logic + player->update(terrain->heightmap); + skybox->update(player->getPosition()); + auto shootAction = player->getShootAction(); + enemyManager->update(terrain->heightmap, player->getPosition(), shootAction); + auto* firstEnemyMesh = enemyManager->getPairs().front()->mesh; + + // Render + engine->renderer.beginFrame(player->getCameraInfo()); + { + renderer.clear(); + { + renderer.add(skybox->pair); // First, because of ALLPASS + renderer.add(ship->pair); + renderer.add(player->pair); + renderer.add(enemyManager->getPairs()); + renderer.add(terrain->pair); + renderer.add(firstEnemyMesh->getCurrentBoundingBox().getTransformed( + firstEnemyMesh->getModelMatrix())); + renderer.add(hud->crosshairSprite.get()); + renderer.add(hud->hpSprite.get()); + renderer.add(hud->soldierSprite.get()); + } + renderer.render(); + } + engine->renderer.endFrame(); +} + +} // namespace Demo diff --git a/demo/src/states/game/hud/hud.cpp b/demo/src/states/game/hud/hud.cpp new file mode 100644 index 0000000..7563b5d --- /dev/null +++ b/demo/src/states/game/hud/hud.cpp @@ -0,0 +1,51 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "states/game/hud/hud.hpp" + +using Tyra::FileUtils; + +namespace Demo { + +Hud::Hud(TextureRepository* t_repo) { + repo = t_repo; + + soldierSprite = std::make_unique(); + soldierSprite->mode = Tyra::MODE_STRETCH; + soldierSprite->size.set(64.0F, 64.0F); + soldierSprite->position.set(5.0F, 448.0F - 64.0F - 5.0F); + + soldierTexture = repo->add(FileUtils::fromCwd("game/soldier.png")); + soldierTexture->addLink(soldierSprite->id); + + hpSprite = std::make_unique(); + hpSprite->mode = Tyra::MODE_STRETCH; + hpSprite->size.set(128.0F, 64.0F); + hpSprite->position.set(70.0F, 448.0F - 64.0F - 5.0F); + + hpTexture = repo->add(FileUtils::fromCwd("game/health_bar.png")); + hpTexture->addLink(hpSprite->id); + + crosshairSprite = std::make_unique(); + crosshairSprite->mode = Tyra::MODE_STRETCH; + crosshairSprite->size.set(16.0F, 16.0F); + crosshairSprite->position.set(512.0F / 2.0F - 16.0F / 2, + 448.0F / 2.0F - 16.0F / 2); + + crosshairTexture = repo->add(FileUtils::fromCwd("game/crosshair.png")); + crosshairTexture->addLink(crosshairSprite->id); +} + +Hud::~Hud() { + repo->free(crosshairTexture->id); + repo->free(hpTexture->id); +} + +} // namespace Demo diff --git a/demo/src/states/game/player/camera.cpp b/demo/src/states/game/player/camera.cpp new file mode 100644 index 0000000..f4caa66 --- /dev/null +++ b/demo/src/states/game/player/camera.cpp @@ -0,0 +1,49 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "states/game/player/camera.hpp" + +namespace Demo { + +Camera::Camera(Pad* t_pad) : lookAt(0.0F), position(0.0F), pad(t_pad) { + lengthFromOrigin = 30.0F; + circleRotation = -3.5F; + height = 1.5F; +} + +Camera::~Camera() {} + +void Camera::update(const Vec4& playerPosition, const float& terrainHeight) { + const float rotationOffset = 0.045F; + const float heightOffset = 0.5F; + + const auto& rightJoy = pad->getRightJoyPad(); + + if (rightJoy.h <= 100) { + circleRotation -= rotationOffset; + } else if (rightJoy.h >= 200) { + circleRotation += rotationOffset; + } + + if (rightJoy.v <= 100) { + height -= heightOffset; + } else if (rightJoy.v >= 200) { + height += heightOffset; + } + + unitCircle.x = (sin(circleRotation) * lengthFromOrigin); + unitCircle.y = height; + unitCircle.z = (cos(circleRotation) * lengthFromOrigin); + + position = playerPosition; + lookAt = unitCircle + playerPosition; +} + +} // namespace Demo diff --git a/demo/src/states/game/player/player.cpp b/demo/src/states/game/player/player.cpp new file mode 100644 index 0000000..0940d52 --- /dev/null +++ b/demo/src/states/game/player/player.cpp @@ -0,0 +1,77 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "states/game/player/player.hpp" + +namespace Demo { + +Player::Player(Engine* engine) + : position(0.0F), weapon(engine), camera(&engine->pad) { + pair = new RendererStaticPair{weapon.mesh, weapon.options}; + pad = &engine->pad; + position = Vec4(3.0F, 50.0F, 0.0F); + camera.lookAt = Vec4(0.0F, 0.0F, -30.0F); + speed = 6.0F; +} + +Player::~Player() { delete pair; } + +void Player::update(const Heightmap& heightmap) { + float terrainHeight = heightmap.getHeightOffset(getPosition()); + + handlePlayerPosition(heightmap, terrainHeight); + camera.update(position, terrainHeight); + weapon.update(); +} + +PlayerShootAction Player::getShootAction() const { + PlayerShootAction action; + action.isShooting = weapon.isShooting; + + if (action.isShooting) { + action.ray = + Ray(camera.position, (camera.lookAt - camera.position).getNormalized()); + } + + return action; +} + +void Player::handlePlayerPosition(const Heightmap& heightmap, + const float& terrainHeight) { + const auto& leftJoy = pad->getLeftJoyPad(); + + auto normalizedCamera = Vec4(camera.unitCircle); + normalizedCamera.normalize(); + normalizedCamera *= speed; + + Vec4 nextPosition(position); + nextPosition.y = terrainHeight + 50.0F; + + if (leftJoy.v <= 100) { + nextPosition.x += normalizedCamera.x; + nextPosition.z += normalizedCamera.z; + } else if (leftJoy.v >= 200) { + nextPosition.x += -normalizedCamera.x; + nextPosition.z += -normalizedCamera.z; + } + if (leftJoy.h <= 100) { + nextPosition.x += normalizedCamera.z; + nextPosition.z += -normalizedCamera.x; + } else if (leftJoy.h >= 200) { + nextPosition.x += -normalizedCamera.z; + nextPosition.z += normalizedCamera.x; + } + + if (!heightmap.isOutside(nextPosition)) position = nextPosition; + + camera.position = position; +} + +} // namespace Demo diff --git a/demo/src/states/game/player/weapon.cpp b/demo/src/states/game/player/weapon.cpp new file mode 100644 index 0000000..c3144e6 --- /dev/null +++ b/demo/src/states/game/player/weapon.cpp @@ -0,0 +1,131 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "states/game/player/weapon.hpp" + +using Tyra::FileUtils; +using Tyra::ObjLoader; +using Tyra::ObjLoaderOptions; + +namespace Demo { + +Weapon::Weapon(Engine* engine) { + ObjLoader loader; + + ObjLoaderOptions objOptions; + objOptions.flipUVs = true; + objOptions.scale = .5F; + + pad = &engine->pad; + audio = &engine->audio; + auto* repo = &engine->renderer.core.texture.repository; + auto data = + loader.load(FileUtils::fromCwd("game/models/ak47/ak47.obj"), objOptions); + data->normalsEnabled = false; + mesh = new StaticMesh(data.get()); + + mesh->translation.translateX(2.85F); + mesh->translation.translateY(-3.40F); + mesh->translation.translateZ(-10.50F); + + mesh->rotation.rotateY(1.60F); + mesh->rotation.rotateZ(-6.30F); + + mesh->scale.scale(0.5F); + + repo->addByMesh(mesh, FileUtils::fromCwd("game/models/ak47/"), "png"); + + initialPosition = *mesh->getPosition(); + + allocateOptions(); + + shootAdpcm = + audio->adpcm.load(FileUtils::fromCwd("game/models/ak47/ak47.adpcm")); + + isShootAnimation1 = isShootAnimation2 = false; + + adpcmChannelsCount = 8; + adpcmCurrentChannel = 0; + + const u8 shootVolume = 25; + for (u8 i = 0; i < adpcmChannelsCount; i++) { + audio->adpcm.setVolume(shootVolume, i); + } +} + +Weapon::~Weapon() { + delete mesh; + delete options; + delete shootAdpcm; +} + +u8 Weapon::getShootChannel() { + auto result = adpcmCurrentChannel++; + + if (adpcmCurrentChannel >= adpcmChannelsCount) { + adpcmCurrentChannel = 0; + } + return result; +} + +void Weapon::update() { + isShooting = false; + + if (!isShootAnimation1 && !isShootAnimation2 && pad->getPressed().Cross) { + shoot(); + } + + auto* position = mesh->getPosition(); + + const float recoil = 0.5F; + const float speed = 500; + + if (isShootAnimation1) { + position->z += recoil; + position->y -= recoil / 4; + if (shootTimer.getTimeDelta() > speed) { + isShootAnimation1 = false; + shootTimer.prime(); + isShootAnimation2 = true; + } + } + + if (isShootAnimation2) { + position->z -= recoil / 2; + position->y += recoil / 8; + if (shootTimer.getTimeDelta() > speed * 2) { + isShootAnimation2 = false; + *position = initialPosition; + if (pad->getPressed().Cross) { + shoot(); + } + } + } +} + +void Weapon::shoot() { + isShooting = true; + shootTimer.prime(); + audio->adpcm.tryPlay(shootAdpcm, getShootChannel()); + isShootAnimation1 = true; +} + +void Weapon::allocateOptions() { + options = new StaPipOptions(); + options->textureMappingType = Tyra::TyraNearest; + options->shadingType = Tyra::TyraShadingFlat; + options->blendingEnabled = false; + options->fullClipChecks = false; + options->frustumCulling = Tyra::PipelineFrustumCulling_None; + options->transformationType = Tyra::TyraMP; + options->antiAliasingEnabled = false; +} + +} // namespace Demo diff --git a/demo/src/states/game/renderer/game_renderer.cpp b/demo/src/states/game/renderer/game_renderer.cpp new file mode 100644 index 0000000..9be33c0 --- /dev/null +++ b/demo/src/states/game/renderer/game_renderer.cpp @@ -0,0 +1,89 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "states/game/renderer/game_renderer.hpp" + +using Tyra::Threading; + +namespace Demo { + +GameRenderer::GameRenderer(Renderer* t_renderer) { + renderer = t_renderer; + + stpip.setRenderer(&renderer->core); + dypip.setRenderer(&renderer->core); +} + +GameRenderer::~GameRenderer() {} + +void GameRenderer::add(std::vector t_staticPairs) { + staticPairs.insert(staticPairs.end(), t_staticPairs.begin(), + t_staticPairs.end()); +} + +void GameRenderer::add(std::vector t_dynamicPairs) { + dynamicPairs.insert(dynamicPairs.end(), t_dynamicPairs.begin(), + t_dynamicPairs.end()); +} + +void GameRenderer::add(Sprite* sprite) { sprites.push_back(sprite); } + +void GameRenderer::add(const CoreBBox& bbox) { bboxes.push_back(bbox); } + +void GameRenderer::add(RendererStaticPair* staticPair) { + staticPairs.push_back(staticPair); +} + +void GameRenderer::add(RendererDynamicPair* dynamicPair) { + dynamicPairs.push_back(dynamicPair); +} + +void GameRenderer::clear() { + staticPairs.clear(); + dynamicPairs.clear(); + sprites.clear(); + bboxes.clear(); +} + +void GameRenderer::render() { + // Render static stuff + if (staticPairs.size()) { + renderer->renderer3D.usePipeline(&stpip); + + for (auto& pair : staticPairs) { + stpip.render(pair->mesh, pair->options); + } + } + + Threading::switchThread(); // give some time for audio thread + + // Render animated stuff + if (dynamicPairs.size()) { + renderer->renderer3D.usePipeline(&dypip); + + for (auto& pair : dynamicPairs) { + dypip.render(pair->mesh, pair->options); + } + } + + Threading::switchThread(); + + // Render debug stuff after stapip/dynpip, otherwise it will not be visible + for (auto& bbox : bboxes) { + renderer->renderer3D.utility.drawBBox(bbox); + } + + // Render 2D + for (auto& sprite : sprites) { + renderer->renderer2D.render(sprite); + } +} + +} // namespace Demo diff --git a/demo/src/states/game/ship/ship.cpp b/demo/src/states/game/ship/ship.cpp new file mode 100644 index 0000000..37fee41 --- /dev/null +++ b/demo/src/states/game/ship/ship.cpp @@ -0,0 +1,50 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "states/game/ship/ship.hpp" + +using Tyra::FileUtils; +using Tyra::ObjLoader; +using Tyra::ObjLoaderOptions; + +namespace Demo { + +Ship::Ship(TextureRepository* repo) { + ObjLoader loader; + + ObjLoaderOptions objOptions; + objOptions.flipUVs = true; + objOptions.scale = 200.0F; + + auto data = + loader.load(FileUtils::fromCwd("game/models/ship/ship.obj"), objOptions); + mesh = new StaticMesh(data.get()); + + for (std::size_t i = 0; i < mesh->materials.size(); i++) { + mesh->materials[i]->ambient /= 2.0F; + mesh->materials[i]->ambient.a = 128.0F; + } + + mesh->setPosition(Vec4(-800.0F, 10.0F, -2500.0F)); + + allocateOptions(); + + pair = new RendererStaticPair{mesh, options}; +} + +Ship::~Ship() { + delete mesh; + delete options; + delete pair; +} + +void Ship::allocateOptions() { options = new StaPipOptions(); } + +} // namespace Demo diff --git a/demo/src/states/game/skybox/skybox.cpp b/demo/src/states/game/skybox/skybox.cpp new file mode 100644 index 0000000..a59acc4 --- /dev/null +++ b/demo/src/states/game/skybox/skybox.cpp @@ -0,0 +1,59 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "states/game/skybox/skybox.hpp" + +using Tyra::FileUtils; +using Tyra::ObjLoader; +using Tyra::ObjLoaderOptions; + +namespace Demo { + +Skybox::Skybox(TextureRepository* repo) { + ObjLoader loader; + + ObjLoaderOptions objOptions; + objOptions.flipUVs = true; + objOptions.scale = 100.0F; + + auto data = loader.load(FileUtils::fromCwd("game/models/skybox/skybox.obj"), + objOptions); + data->normalsEnabled = false; + mesh = new StaticMesh(data.get()); + + repo->addByMesh(mesh, FileUtils::fromCwd("game/models/skybox/"), "png"); + + allocateOptions(); + + pair = new RendererStaticPair{mesh, options}; +} + +Skybox::~Skybox() { + delete mesh; + delete options; + delete pair; +} + +void Skybox::update(const Vec4& playerPosition) { + mesh->translation.identity(); + mesh->translation.translate(playerPosition); +} + +void Skybox::allocateOptions() { + options = new StaPipOptions(); + options->frustumCulling = Tyra::PipelineFrustumCulling_None; + options->shadingType = Tyra::TyraShadingGouraud; + options->zTestType = Tyra::PipelineZTest_AllPass; + options->textureMappingType = Tyra::TyraNearest; + options->blendingEnabled = true; + options->antiAliasingEnabled = false; +} + +} // namespace Demo diff --git a/demo/src/states/game/terrain/heightmap.cpp b/demo/src/states/game/terrain/heightmap.cpp new file mode 100644 index 0000000..95d7506 --- /dev/null +++ b/demo/src/states/game/terrain/heightmap.cpp @@ -0,0 +1,113 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "states/game/terrain/heightmap.hpp" + +using Tyra::FileUtils; +using Tyra::PngLoader; +using Tyra::PngPixel3; +using Tyra::Vec4; + +namespace Demo { + +Heightmap::Heightmap(const float& t_minHeight, const float& t_maxHeight, + const Vec4& t_leftUp, const Vec4& t_rightDown) + : minHeight(t_minHeight), + maxHeight(t_maxHeight), + leftUp(t_leftUp), + rightDown(t_rightDown) { + PngLoader loader; + auto* data = + loader.load(FileUtils::fromCwd("game/models/terrain/heightmap.png")); + + allocateMap(data->data, data->width, data->height); + + delete data; +} + +bool Heightmap::isOutside(const Vec4& position) const { + return position.x <= leftUp.x || position.x >= rightDown.x || + position.z <= leftUp.z || position.z >= rightDown.z; +} + +Heightmap::~Heightmap() { + if (map) { + for (int i = 0; i < mapHeight; i++) { + delete[] map[i]; + } + delete[] map; + } +} + +const float& Heightmap::getHeightOffset(const Vec4& playerPosition) const { + float widthPercentage = getWidthPercentage(playerPosition); + float heightPercentage = getHeightPercentage(playerPosition); + + auto x = static_cast(widthPercentage * mapWidth); + auto y = static_cast(heightPercentage * mapHeight); + + TYRA_ASSERT(x >= 0 && x < mapWidth, "x is out of range"); + TYRA_ASSERT(y >= 0 && y < mapHeight, "y is out of range"); + + return map[x][y]; +} + +float Heightmap::getWidthPercentage(const Vec4& playerPosition) const { + return (playerPosition.x - leftUp.x) / (rightDown.x - leftUp.x); +} + +float Heightmap::getHeightPercentage(const Vec4& playerPosition) const { + return (playerPosition.z - leftUp.z) / (rightDown.z - leftUp.z); +} + +void Heightmap::allocateMap(const unsigned char* data, const int& width, + const int& height) { + auto* pixels = (struct PngPixel3*)data; + + u8 min = pixels[0].r; // in grayscale every r,g,b is the same + u8 max = pixels[0].r; + + // Get min and max + for (int i = 0; i < width * height; i++) { + const auto& value = pixels[i].r; + if (value < min) { + min = value; + } + if (value > max) { + max = value; + } + } + + // Allocate + mapWidth = width; + mapHeight = height; + map = new float*[width]; + for (int i = 0; i < width; i++) { + map[i] = new float[height]; + } + + // Fill + int k = 0; + for (int j = 0; j < height; j++) { + for (int i = 0; i < width; i++) { + map[i][j] = getGameHeight(pixels[k++].r, min, max); + } + } +} + +float Heightmap::getGameHeight(const u8& inputColor, const u8& minColor, + const u8& maxColor) const { + const float mapRange = maxColor - minColor; + const float gameRange = maxHeight - minHeight; + + return (inputColor - minColor) / mapRange * gameRange + minHeight; +} + +} // namespace Demo diff --git a/demo/src/states/game/terrain/terrain.cpp b/demo/src/states/game/terrain/terrain.cpp new file mode 100644 index 0000000..6848bfc --- /dev/null +++ b/demo/src/states/game/terrain/terrain.cpp @@ -0,0 +1,60 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "states/game/terrain/terrain.hpp" + +using Tyra::FileUtils; +using Tyra::ObjLoader; +using Tyra::ObjLoaderOptions; + +namespace Demo { +Terrain::Terrain(TextureRepository* repo) + : heightmap(-70.0F, // Min height + 240.0F, // Max height + Vec4(-750.0F, 0.0F, -1400.0F, 1.0F), // Left up + Vec4(920.0F, 0.0F, 1520.0F, 1.0F) // Right down + ) { + ObjLoader loader; + + ObjLoaderOptions objOptions; + objOptions.flipUVs = true; + objOptions.scale = 100.0F; + + auto data = loader.load(FileUtils::fromCwd("game/models/terrain/terrain.obj"), + objOptions); + data->normalsEnabled = false; + mesh = new StaticMesh(data.get()); + + repo->addByMesh(mesh, FileUtils::fromCwd("game/models/terrain/"), "png"); + + allocateOptions(); + + pair = new RendererStaticPair{mesh, options}; +} + +float Terrain::getHeightOffset(const Vec4& playerPosition) { + return heightmap.getHeightOffset(playerPosition); +} + +Terrain::~Terrain() { + delete mesh; + delete options; + delete pair; +} + +void Terrain::allocateOptions() { + options = new StaPipOptions(); + options->frustumCulling = Tyra::PipelineFrustumCulling_None; + options->shadingType = Tyra::TyraShadingGouraud; + options->blendingEnabled = true; + options->antiAliasingEnabled = false; +} + +} // namespace Demo diff --git a/demo/src/states/intro/intro_state.cpp b/demo/src/states/intro/intro_state.cpp new file mode 100644 index 0000000..c4560b1 --- /dev/null +++ b/demo/src/states/intro/intro_state.cpp @@ -0,0 +1,62 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "states/intro/intro_state.hpp" + +#include "states/intro/states/intro_ps2dev_state.hpp" +#include "states/intro/states/intro_tyra_state.hpp" +#include "states/intro/states/intro_press_key_state.hpp" + +using Tyra::FileUtils; + +namespace Demo { + +IntroState::IntroState(Engine* t_engine) + : State(t_engine), stateManager(STATE_PS2DEV, STATE_INTRO_END) { + state = STATE_INTRO; + _wantFinish = false; + initialized = false; +} + +IntroState::~IntroState() {} + +void IntroState::onStart() { + TYRA_LOG("Intro. RAM: ", engine->info.getAvailableRAM(), "MB"); + + engine->audio.song.load(FileUtils::fromCwd("intro/intro.wav")); + engine->audio.song.inLoop = false; + engine->audio.song.setVolume(80); + engine->audio.song.play(); + + stateManager.add(new IntroPs2DevState(engine)); + stateManager.add(new IntroTyraState(engine)); + stateManager.add(new IntroPressKeyState(engine)); + + initialized = true; +} + +GlobalStateType IntroState::onFinish() { + if (!initialized) return STATE_LOADING; + + stateManager.freeAll(); + + initialized = false; + return STATE_LOADING; +} + +void IntroState::update() { + stateManager.update(); + + if (stateManager.finished()) { + _wantFinish = true; + } +} + +} // namespace Demo diff --git a/demo/src/states/intro/states/intro_press_key_state.cpp b/demo/src/states/intro/states/intro_press_key_state.cpp new file mode 100644 index 0000000..8e7b691 --- /dev/null +++ b/demo/src/states/intro/states/intro_press_key_state.cpp @@ -0,0 +1,198 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "states/intro/states/intro_press_key_state.hpp" +#include + +using Tyra::FileUtils; +using Tyra::Math; +using Tyra::PngLoader; +using Tyra::SpriteMode; +using Tyra::Threading; + +namespace Demo { + +IntroPressKeyState::IntroPressKeyState(Engine* t_engine) + : State(t_engine), mapPosition(0.0F, 0.0F) { + state = STATE_PRESS_KEY; + _wantFinish = false; + mapDirection = 0; + mapFadeIn = true; + fillerFadeIn = false; + showPressKey = false; + pressKeyAlphaToggle = false; + pressKeyAlphaDelayer = 0; + fillersOffset = -512.0F; +} + +IntroPressKeyState::~IntroPressKeyState() {} + +void IntroPressKeyState::onStart() { + TYRA_LOG("Intro - presskey. RAM: ", engine->info.getAvailableRAM(), "MB"); + + for (u8 i = 0; i < mapRows; i++) { + for (u8 j = 0; j < mapCols; j++) { + mapSprites[i][j] = new Sprite; + mapSprites[i][j]->color.a = 0.0F; + mapSprites[i][j]->mode = SpriteMode::MODE_STRETCH; + mapSprites[i][j]->size.set(textureWidthHeight, textureWidthHeight); + mapSprites[i][j]->position.set(i * textureWidthHeight, + j * textureWidthHeight); + + std::string filename = + "map-" + std::to_string(i) + "-" + std::to_string(j); + std::string path = "intro/map/" + filename + ".png"; + + mapTextures[i][j] = engine->renderer.core.texture.repository.add( + FileUtils::fromCwd(path)); + mapTextures[i][j]->addLink(mapSprites[i][j]->id); + } + } + + fillerSprite = new Sprite; + fillerSprite->size.set(256.0F, 50.0F); + fillerSprite->position.set(0.0F, 224.0F - 25.0F); + + fillerTexture = engine->renderer.core.texture.repository.add( + FileUtils::fromCwd("intro/filler.png")); + fillerTexture->addLink(fillerSprite->id); + + pressKeySprite = new Sprite; + pressKeySprite->size.set(256.0F, 64.0F); + pressKeySprite->scale = 0.5F; + pressKeySprite->position.set(192.0F, 380.0F); + + pressKeyTexture = engine->renderer.core.texture.repository.add( + FileUtils::fromCwd("intro/press-key.png")); + pressKeyTexture->addLink(pressKeySprite->id); + + logoSprite = new Sprite; + logoSprite->size.set(256.0F, 128.0F); + logoSprite->position.set(256.0F - 128.0F, 224.0F - 64.0F); + + logoTexture = engine->renderer.core.texture.repository.add( + FileUtils::fromCwd("intro/lastalive.png")); + logoTexture->addLink(logoSprite->id); + + initialized = true; +} + +IntroStateType IntroPressKeyState::onFinish() { + if (!initialized) return STATE_INTRO_END; + + for (u8 i = 0; i < mapRows; i++) + for (u8 j = 0; j < mapCols; j++) { + engine->renderer.core.texture.repository.free(mapTextures[i][j]->id); + delete mapSprites[i][j]; + } + + engine->renderer.core.texture.repository.free(fillerTexture->id); + delete fillerSprite; + + engine->renderer.core.texture.repository.free(logoTexture->id); + delete logoSprite; + + engine->renderer.core.texture.repository.free(pressKeyTexture->id); + delete pressKeySprite; + + initialized = false; + return STATE_INTRO_END; +} + +void IntroPressKeyState::update() { + engine->renderer.beginFrame(); + + if (mapDirection == 0 && + mapPosition.x >= textureWidthHeight * (mapRows - 1) && + mapPosition.y >= textureWidthHeight * (mapCols - 1)) { + mapDirection = 1; + } else if (mapDirection == 1 && mapPosition.x <= 0.0F && + mapPosition.y <= 0.0F) { + mapDirection = 0; + } + + if (engine->pad.getClicked().Cross) { + _wantFinish = true; + } + + const float offset = 0.1F; + if (mapDirection == 0) { + mapPosition += offset; + } else if (mapDirection == 1) { + mapPosition -= offset; + } + + if (mapFadeIn) { + for (u8 i = 0; i < mapRows; i++) { + for (u8 j = 0; j < mapCols; j++) { + auto* sprite = mapSprites[i][j]; + if (sprite->color.a >= 16.0F && sprite->color.a < 32.0F) { + fillerFadeIn = true; + } + if (sprite->color.a < 96.0F) { + sprite->color.a += 0.2F; + } else { + mapFadeIn = false; + } + } + } + } + + if (fillerFadeIn) { + if (fillersOffset < -1.0F) { + fillersOffset += 4.0F; + } else { + fillerFadeIn = false; + showPressKey = true; + } + } + + updateMap(); + + Threading::switchThread(); + + for (u8 i = 0; i < mapRows; i++) + for (u8 j = 0; j < mapCols; j++) + engine->renderer.renderer2D.render(mapSprites[i][j]); + + renderFiller(); + engine->renderer.renderer2D.render(logoSprite); + + if (showPressKey) { + if (pressKeyAlphaDelayer++ > 50) { + pressKeyAlphaToggle = !pressKeyAlphaToggle; + pressKeyAlphaDelayer = 0; + } + + if (pressKeyAlphaToggle) { + engine->renderer.renderer2D.render(pressKeySprite); + } + } + + engine->renderer.endFrame(); +} + +void IntroPressKeyState::renderFiller() { + fillerSprite->position.x = -1.0F + fillersOffset; + engine->renderer.renderer2D.render(fillerSprite); + fillerSprite->position.x = 255.0F + fillersOffset; + engine->renderer.renderer2D.render(fillerSprite); +} + +void IntroPressKeyState::updateMap() { + for (u8 i = 0; i < mapRows; i++) + for (u8 j = 0; j < mapCols; j++) { + mapSprites[i][j]->position.x = + i * (textureWidthHeight + 1.0F) - mapPosition.x; + mapSprites[i][j]->position.y = + j * (textureWidthHeight + 1.0F) - mapPosition.y; + } +} +} // namespace Demo diff --git a/demo/src/states/intro/states/intro_ps2dev_state.cpp b/demo/src/states/intro/states/intro_ps2dev_state.cpp new file mode 100644 index 0000000..e5cad85 --- /dev/null +++ b/demo/src/states/intro/states/intro_ps2dev_state.cpp @@ -0,0 +1,104 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "states/intro/states/intro_ps2dev_state.hpp" + +using Tyra::FileUtils; +using Tyra::PngLoader; +using Tyra::Threading; + +namespace Demo { + +IntroPs2DevState::IntroPs2DevState(Engine* t_engine) : State(t_engine) { + state = STATE_PS2DEV; + _wantFinish = false; + initialized = false; + initialDelayElapsed = false; + frameSkipper = 0; + fadeinActivated = true; + fadeoutActivated = false; +} + +IntroPs2DevState::~IntroPs2DevState() {} + +void IntroPs2DevState::onStart() { + TYRA_LOG("Intro - ps2dev. RAM: ", engine->info.getAvailableRAM(), "MB"); + + const auto& settings = engine->renderer.core.getSettings(); + + initialDelayTimer.prime(); + + sprite = new Sprite; + sprite->size.set(256.0F, 64.0F); + sprite->position.set(settings.getWidth() / 2 - sprite->size.x / 2, + settings.getHeight() / 2 - sprite->size.y / 2); + sprite->color.a = 0; + + Threading::switchThread(); + + texture = engine->renderer.core.texture.repository.add( + FileUtils::fromCwd("intro/ps2dev.png")); + texture->addLink(sprite->id); + + initialized = true; +} + +IntroStateType IntroPs2DevState::onFinish() { + if (!initialized) return STATE_TYRA; + + delete sprite; + engine->renderer.core.texture.repository.free(texture->id); + + initialized = false; + return STATE_TYRA; +} + +void IntroPs2DevState::update() { + engine->renderer.beginFrame(); + + if (initialDelayTimer.getTimeDelta() >= 60000) initialDelayElapsed = true; + + if (engine->pad.getClicked().Cross) { + _wantFinish = true; + } + + frameSkipper++; + if (frameSkipper > 3) { + frameSkipper = 0; + } + + if (fadeinActivated && initialDelayElapsed && frameSkipper == 0) { + if (sprite->color.a < 128.0F) + sprite->color.a += 2.0F; + else { + fadeoutActivated = true; + fadeinActivated = false; + } + if (sprite->color.a >= 96.0F && sprite->color.a < 128.0F) { + sprite->color.g -= 6.0F; + sprite->color.b -= 6.0F; + } + } + + Threading::switchThread(); + + if (fadeoutActivated && frameSkipper == 0) { + if (sprite->color.a > 0) + sprite->color.a -= 4; + else + _wantFinish = true; + } + + engine->renderer.renderer2D.render(sprite); + + engine->renderer.endFrame(); +} + +} // namespace Demo diff --git a/demo/src/states/intro/states/intro_tyra_state.cpp b/demo/src/states/intro/states/intro_tyra_state.cpp new file mode 100644 index 0000000..5cbdde8 --- /dev/null +++ b/demo/src/states/intro/states/intro_tyra_state.cpp @@ -0,0 +1,180 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "states/intro/states/intro_tyra_state.hpp" + +using Tyra::FileUtils; +using Tyra::Math; +using Tyra::PngLoader; +using Tyra::Threading; + +namespace Demo { + +IntroTyraState::IntroTyraState(Engine* t_engine) : State(t_engine) { + state = STATE_TYRA; + _wantFinish = false; + initialized = false; + initialDelayElapsed = false; + animActivated = true; + fadeoutActivated = false; + frameSkipper = 0; +} + +IntroTyraState::~IntroTyraState() {} + +void IntroTyraState::onStart() { + TYRA_LOG("Intro - tyra. RAM: ", engine->info.getAvailableRAM(), "MB"); + + const auto& settings = engine->renderer.core.getSettings(); + + initialDelayTimer.prime(); + + tyraSprite = new Sprite; + tyraSprite->size.set(256.0F, 64.0F); + tyraSprite->position.set(settings.getWidth() / 2 - tyraSprite->size.x / 2, + settings.getHeight() / 2 - tyraSprite->size.y / 2); + + bgSprite = new Sprite; + bgSprite->size.set(256.0F, 256.0F); + bgSprite->position.set(settings.getWidth() / 2 - bgSprite->size.x / 2, + settings.getHeight() / 3 * 2.0F); + + bg2Sprite = new Sprite; + bg2Sprite->size.set(256.0F, 256.0F); + bg2Sprite->position.set( + settings.getWidth() / 2 - bg2Sprite->size.x / 2, + (settings.getHeight() / 3 * 2.0F) + bg2Sprite->size.y + 1.0F); + + fillerSprite = new Sprite; + fillerSprite->size.set(256.0F, 256.0F); + fillerSprite->position.set(0.0F, 0.0F); + + tyraTexture = engine->renderer.core.texture.repository.add( + FileUtils::fromCwd("intro/tyra.png")); + tyraTexture->addLink(tyraSprite->id); + + bgTexture = engine->renderer.core.texture.repository.add( + FileUtils::fromCwd("intro/tyra_bg.png")); + bgTexture->addLink(bgSprite->id); + + Threading::switchThread(); + + bg2Texture = engine->renderer.core.texture.repository.add( + FileUtils::fromCwd("intro/tyra_bg2.png")); + bg2Texture->addLink(bg2Sprite->id); + + fillerTexture = engine->renderer.core.texture.repository.add( + FileUtils::fromCwd("intro/filler.png")); + fillerTexture->addLink(fillerSprite->id); + + initialized = true; +} + +IntroStateType IntroTyraState::onFinish() { + if (!initialized) return STATE_PRESS_KEY; + + engine->renderer.core.texture.repository.free(tyraTexture->id); + engine->renderer.core.texture.repository.free(bgTexture->id); + engine->renderer.core.texture.repository.free(bg2Texture->id); + engine->renderer.core.texture.repository.free(fillerTexture->id); + + delete tyraSprite; + delete bgSprite; + delete bg2Sprite; + delete fillerSprite; + + initialized = false; + return STATE_PRESS_KEY; +} + +void IntroTyraState::update() { + engine->renderer.beginFrame(); + + if (initialDelayTimer.getTimeDelta() >= 15000) initialDelayElapsed = true; + + frameSkipper++; + if (frameSkipper > 3) { + frameSkipper = 0; + } + + if (engine->pad.getClicked().Cross) { + _wantFinish = true; + } + + const float slideUpMaxPost = -128.0F; + + if (initialDelayElapsed) { + if (bgSprite->position.y <= 32.0F) fadeoutActivated = true; + + float offset = 1.0F; + if (bgSprite->position.y > slideUpMaxPost && bgSprite->position.y <= 64.0F) + offset /= 1.6F; + else if (bgSprite->position.y > 64.0F && bgSprite->position.y <= 128.0F) + offset /= 1.2F; + + if (bgSprite->position.y > 32.0F && bgSprite->position.y <= 64.0F && + bgSprite->color.g > 0.0F) { + const float colorOffset = 1.5F; + bgSprite->color.g -= colorOffset; + bgSprite->color.b -= colorOffset; + bg2Sprite->color.g -= colorOffset; + bg2Sprite->color.b -= colorOffset; + } + + if (bgSprite->position.y > slideUpMaxPost) { + bgSprite->position.y -= offset; + bg2Sprite->position.y -= offset; + } + } + + if (fadeoutActivated && frameSkipper == 0) { + if (bgSprite->color.a > 0) { + bgSprite->color.a -= 4.0F; + bg2Sprite->color.a -= 4.0F; + } else + _wantFinish = true; + } + + Threading::switchThread(); + + engine->renderer.renderer2D.render(bgSprite); + engine->renderer.renderer2D.render(bg2Sprite); + engine->renderer.renderer2D.render(tyraSprite); + + renderFillers(); + + engine->renderer.endFrame(); +} + +void IntroTyraState::renderFillers() { + // Up + fillerSprite->position.set(0.0F, -63.0F); + engine->renderer.renderer2D.render(fillerSprite); + + fillerSprite->position.set(256.0F, -63.0F); + engine->renderer.renderer2D.render(fillerSprite); + + // Left + fillerSprite->position.set(-124.0F, 128.0F); + engine->renderer.renderer2D.render(fillerSprite); + + // Down + fillerSprite->position.set(0.0F, 256.0F); + engine->renderer.renderer2D.render(fillerSprite); + + fillerSprite->position.set(256.0F, 256.0F); + engine->renderer.renderer2D.render(fillerSprite); + + // Right + fillerSprite->position.set(386.0F, 128.0F); + engine->renderer.renderer2D.render(fillerSprite); +} + +} // namespace Demo diff --git a/demo/src/states/loading/loading_state.cpp b/demo/src/states/loading/loading_state.cpp new file mode 100644 index 0000000..21b8c59 --- /dev/null +++ b/demo/src/states/loading/loading_state.cpp @@ -0,0 +1,72 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include +#include "states/loading/loading_state.hpp" +#include + +using std::make_unique; +using std::unique_ptr; +using Tyra::FileUtils; +using Tyra::Sprite; + +namespace Demo { + +LoadingState::LoadingState(Engine* t_engine) : State(t_engine) { + state = STATE_LOADING; + _wantFinish = false; + initialized = false; +} + +LoadingState::~LoadingState() {} + +void LoadingState::onStart() { + TYRA_LOG("Loading. RAM: ", engine->info.getAvailableRAM(), "MB"); + + auto* repo = &engine->renderer.core.texture.repository; + + auto fillerTexture = repo->add(FileUtils::fromCwd("loading/filler.png")); + auto loadingTexture = repo->add(FileUtils::fromCwd("loading/loading.png")); + + auto fillerSprite = make_unique(); + auto loadingSprite = make_unique(); + + fillerSprite->position.set(0.0F, 0.0F); + fillerSprite->size.set(600.0F, 600.0F); + fillerSprite->mode = Tyra::MODE_STRETCH; + + loadingSprite->size.set(128.0F, 64.0F); + loadingSprite->mode = Tyra::MODE_STRETCH; + loadingSprite->position.set(5.0F, 448.0F - 64.0F - 5.0F); + + fillerTexture->addLink(fillerSprite->id); + loadingTexture->addLink(loadingSprite->id); + + engine->renderer.beginFrame(); + engine->renderer.renderer2D.render(fillerSprite.get()); + engine->renderer.renderer2D.render(loadingSprite.get()); + engine->renderer.endFrame(); + + repo->free(fillerTexture->id); + repo->free(loadingTexture->id); + + initialized = true; +} + +GlobalStateType LoadingState::onFinish() { + if (!initialized) return STATE_GAME; + + initialized = false; + return STATE_GAME; +} + +void LoadingState::update() { _wantFinish = true; } + +} // namespace Demo diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..ff8ece3 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,14 @@ +version: "3.9" +volumes: + tyra-volume: +services: + compiler: + environment: + TERM: xterm-256color + network_mode: host + image: "h4570/tyra" + tty: true + container_name: tyra-compiler + volumes: + - tyra-volume:/src + - ./:/host diff --git a/docs/install.md b/docs/install.md deleted file mode 100644 index dc05168..0000000 --- a/docs/install.md +++ /dev/null @@ -1,254 +0,0 @@ -# Installation tutorial - -This tutorial will show you, how to: - -- Setup your WSL machine for PS2DEV -- Install entire PS2DEV+Tyra environment -- Setup VSCode with Intelisense -- Setup PCSX2 - -So let's get started! - ---- - -
- -## VSCode and WSL - - -- Install VSCode from - https://code.visualstudio.com/ -- Install WSL https://docs.microsoft.com/en-us/windows/wsl/install-win10 `Info: Please choose Ubuntu-20.04` -- Set root as default WSL user. - Open ` cmd.exe` and type: - ` ubuntu2004 config --default-user root` - - ---- - -
- -## Ubuntu configuration and PS2DEV+Tyra - -- Open WSL terminal (Windows search -> wsl)`Info: Be sure that are you logged as a root!` -- Type these commands - -``` -apt-get update && apt-get upgrade -y -apt-get install -y build-essential make texinfo cmake bison flex gettext libgmp3-dev libmpfr-dev libmpc-dev libz-dev wget patch -``` - -- Configure git (replace your name and email) - -``` -git config --global user.email "your@email.com" -git config --global user.name "Your Name" -``` - -- Create directories - -``` -mkdir /ps2dev -mkdir /ps2dev/built -mkdir /ps2dev/source -mkdir /repos -mkdir /repos/tyra -``` - -- Clone repos - -``` -git clone https://github.com/ps2dev/ps2dev.git /ps2dev/source/ -git clone https://github.com/h4570/tyra.git /repos/tyra/ -``` - -- Open bashrc via `nano ~/.bashrc` and add these lines at the end of file. Be sure that they are 1:1, so don't add additional spaces! - -``` -export PS2DEV=/ps2dev/built -export PS2SDK=$PS2DEV/ps2sdk -export GSKIT=$PS2DEV/gsKit -export PATH=$PATH:$PS2DEV/bin:$PS2DEV/ee/bin:$PS2DEV/iop/bin:$PS2DEV/dvp/bin:$PS2SDK/bin -export PS2HOSTNAME=192.168.0.200 -export TYRA=/repos/tyra -export WSL_MAKE_WINDOWS=\\\\\\\\wsl\$\$\\\\Ubuntu-20.04 -export WSL_LINUX_PCSX2=/mnt/c/Program\\\ Files\\\ \\\(x86\\\)/PCSX2 -``` - -- Refresh env variables via -> `. ~/.bashrc` -- Close wsl terminal - ---- - -
- -## Mapping WSL directories to your Windows machine - -- Open cmd and type `wsl.exe --list``Info: Remember your distribution name from this list. My is "Ubuntu-20.04"` -- Click at the windows logo on your keyboard, type "This PC" and open -- At the upper menu click "Map disk drive"`Info: Replace my name with your WSL name!` - - Folder: \\\\wsl$\\Ubuntu-20.04 - - Click OK - -`Info: You will have now new disk on your PC, this is the WSL filesystem.` - ---- - -
- -## Configuring VSCode - -- Open VSCode -- Install extension "Remote - WSL" -- Install extension "C/C++" -- Restart VSCode if required -- VSCode: Click on "File" -> "Open folder in WSL" - - Open "repos/tyra" -- VSCode: Click on "Terminal" -> "New terminal" - -`Info: New terminal should appear. This is the same WSL terminal :)` - ---- - -
- -## PS2DEV installation - -- In VSCode's WSL terminal type: - -``` -cd /ps2dev/source -unset ZLIB -unset LIBTIFF -unset LIBJPEG -unset LIBPNG -./build-all.sh -``` - -`Info: This can take some time...` - -- And open again .bashrc via `nano ~/.bashrc` and add these lines at the end of file. - -``` -export ZLIB=${PS2SDK}/ports -export LIBTIFF=${PS2SDK}/ports -export LIBJPEG=${PS2SDK}/ports -export LIBPNG=${PS2SDK}/ports -``` - -- Refresh env variables via `. ~/.bashrc` - -### Please don't forgot to remove/refresh these 4 exports when you will want to update PS2DEV (./build-all.sh), because there is circular dependency between these libs and gsKit which is included in PS2DEV!!! - ---- - -
- -## Build Tyra - -- Just hit make all on the root of tyra folder or you can go via `cd /src/engine` and hit `make all` there. -- If you wanna build the debug build or rebuild the engine, just `make rebuild-engine ` on the root of tyra or `make rebuild-dbg-engine` to build debug version or go to one of the samples via `cd /repos/tyra/src/samples/floors `and do the same process above - -
- -## Install & configure PCSX2 - -- Download & install PCSX2 from (1.6+ version)https://pcsx2.net/ -- Extract bios files fromhttps://romsmania.cc/bios/pcsx2-playstation-2-bios-3to `C:\Users%USERNAME%\Documents\PCSX2\bios` -- Close `PCSX2` if you have opened! -- Open `C:\Users\hasto\Documents\PCSX2\inis\PCSX2_vm.ini` in notepad - -``` -HostFs=enabled -``` - -- Open PCSX2 and map pad to your keyboard, for example: - -``` -WASD = Left joy -Arrows = Right joy -Space = X -Circle = C -``` - ---- - -
- -## Run one of the samples - Method 1 - -- Add assets for "floors" sample -- Download assets from https://github.com/h4570/tyra/tree/master/src/samples/floors -- Windows: Open your WSL folder (This PC -> WSL folder) -- Extract assets to /repos/tyra/src/samples/floors/bin/ (create bin folder if not exists) -- Compile sample via `make``Info: Elf file should be produced in /bin ` -- Run sample in PCSX2 via `make run-pcsx2` - -## Run one of the samples Method 2 - -- Run `make floors` on the root of tyra project or change directory to the sampels via `cd src/samples/floors` and do the `make install` command - ---- - -
- -## How to code? - -Do some changes in your sample and just type `make clean all run-pcsx2` in your sample folder. -You can create your own sample, by just copying cube folder. - ---- - -
- -## Setup Intelisense - - -- Download - http://apgcglz.cluster028.hosting.ovh.net/tyra/intellisense.zip -- Unpack .vscode folder to WSL's `/repos/tyra/Info: This configuration is set for cube sample, but you can change it in tasks.json file` - - ---- - -
- -## Advanced: Compiling VU1 programs - -`Info: Based on https://github.com/microsoft/wsl/issues/2468#issuecomment-374904520` - -- Download VCL - http://lukasz.dk/files/vcl.1.4.beta7.x86.tgz -- Rename `vcl_14beta7_x86` binary to `vcl` -- Put `vcl` to WSL's `/usr/bin` - -``` -apt-get install qemu qemu-user-static binfmt-support -update-binfmts --install i386 /usr/bin/qemu-i386-static --magic '\x7fELF\x01\x01\x01\x03\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x03\x00\x01\x00\x00\x00' --mask '\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xf8\xff\xff\xff\xff\xff\xff\xff' -dpkg --add-architecture i386 -apt-get update -apt-get install libstdc++5:i386 -chmod 755 /usr/bin/vcl -``` - -`Info: In Ubuntu 18.04 I was obligated to install lib32ncurses5 also` - -- Add this line to `~/.bashrc` - -``` -service binfmt-support start &>/dev/null -``` - -- Uncomment `.vsm`/`.vcl` recipe from Tyra's engine `Makefile` -- Download & install VCL preprocessor - -``` -mkdir temp && cd temp -git clone https://github.com/glampert/vclpp . -make -cp vclpp /usr/bin/ -chmod 755 /usr/bin/vclpp -cd .. && rm -rf ./temp -``` - -- Uncomment `.vclpp`/`.vcl` recipe from Tyra's engine `Makefile` diff --git a/docs/install/README.MD b/docs/install/README.MD new file mode 100644 index 0000000..ba2237e --- /dev/null +++ b/docs/install/README.MD @@ -0,0 +1,25 @@ +# Installing Tyra + +[![](https://img.shields.io/badge/Install%20time-5%20minutes-brightgreen)](#) + +## Prerequisites: +1. Git +2. VSCode +3. Docker with PowerShell as a default terminal +4. [PCSX2](https://github.com/h4570/tyra/blob/master/docs/install/pcsx2.md#) + +--- + +## Steps: +1. Download [intellisense package](http://apgcglz.cluster028.hosting.ovh.net/tyra/ps2dev-intellisense.rar) and unzip it somewhere in your computer. +2. Open terminal in your favourite repositories directory and execute: +``` +docker pull h4570/tyra +git clone https://github.com/h4570/tyra.git +``` +3. Open `VSCode` and open previously cloned directory. +4. In `VSCode` open `.vscode/configurations/windows-docker` and copy configuration files into `.vscode/` +5. In `c_cpp_properties.json` fix all `YOUR-INTELLISENSE-PATH` with path from point 2. +6. Click `CTRL+SHIFT+P`, type `Tasks: Run task` and run `Start docker container` - Repeat this step every time you want to start working with Tyra (every reboot) +7. Click `CTRL+SHIFT+P`, type `Tasks: Run build task` +8. Tyra should automatically compile engine, `demo` game and run `PCSX2`. If you want to compile & run tutorials, please change `buildDirectory` in `settings.json` to example `tutorials/01-hello` \ No newline at end of file diff --git a/docs/install/pcsx2.md b/docs/install/pcsx2.md new file mode 100644 index 0000000..f2d5d7b --- /dev/null +++ b/docs/install/pcsx2.md @@ -0,0 +1,21 @@ +## Install & configure PCSX2 + +- Download & install PCSX2 (1.6+ version) from https://pcsx2.net/ +- Extract bios files from https://romsmania.cc/bios/pcsx2-playstation-2-bios-3 to `%UserProfile%\Documents\PCSX2\bios` +- Close `PCSX2` if you have opened! +- Open `%UserProfile%\Documents\PCSX2\inis\PCSX2_vm.ini` in notepad + +``` +HostFs=enabled +``` + +- Open PCSX2 and map pad to your keyboard, for example: + +``` +WASD = Left joy +Arrows = Right joy +Space = X +Circle = C +``` + +- Enable **"EE timing hack"** in PCSX2 hacks! \ No newline at end of file diff --git a/engine/Makefile b/engine/Makefile new file mode 100644 index 0000000..a0bb104 --- /dev/null +++ b/engine/Makefile @@ -0,0 +1,26 @@ +TARGET := libtyra.a + +#The Directories, Source, Includes, Objects, Binary and Resources +SRCDIR := src +INCDIR := inc +BUILDDIR := obj +TARGETDIR := bin +RESDIR := res +SRCEXT := cpp +VSMEXT := vsm +VCLEXT := vcl +VCLPPEXT := vclpp +DEPEXT := d +OBJEXT := o + +#Flags, Libraries and Includes +CFLAGS := +LIB := +LIBDIRS := +INC := -I$(INCDIR) +INCDEP := -I$(INCDIR) + +include ../Makefile.base + +$(TARGET): $(OBJECTS) $(VCL_OBJECTS) $(VU_OBJECTS_VCL) $(VU_OBJECTS_VSM) $(IRXEM_OBJECTS) + $(AR) rcs $(TARGETDIR)/$(TARGET) $(OBJECTS) $(VCL_OBJECTS) $(VU_OBJECTS_VCL) $(VU_OBJECTS_VSM) $(IRXEM_OBJECTS) diff --git a/src/unit_tests/bin/.gitignore b/engine/bin/.gitignore similarity index 95% rename from src/unit_tests/bin/.gitignore rename to engine/bin/.gitignore index 86d0cb2..44c5ea8 100644 --- a/src/unit_tests/bin/.gitignore +++ b/engine/bin/.gitignore @@ -1,4 +1,4 @@ -# Ignore everything in this directory -* -# Except this file +# Ignore everything in this directory +* +# Except this file !.gitignore \ No newline at end of file diff --git a/engine/inc/audio/adpcm_result.hpp b/engine/inc/audio/adpcm_result.hpp new file mode 100644 index 0000000..7505c69 --- /dev/null +++ b/engine/inc/audio/adpcm_result.hpp @@ -0,0 +1,28 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022-2022, Tyra - https://github.com/h4570/tyrav2 +# Licensed under Apache License 2.0 +# Sandro Sobczyński +# Wellinator Carvalho +*/ + +#pragma once + +namespace Tyra { + +enum AdpcmResult { + ADPCM_OK, + + /** When provided channel by user is currently in use */ + ADPCM_CHANNEL_USED, + + /** When user did not provided channel and all are in use */ + ADPCM_NO_FREE_CHANNELS, + + ADPCM_ERROR +}; + +} // namespace Tyra diff --git a/engine/inc/audio/audio.hpp b/engine/inc/audio/audio.hpp new file mode 100644 index 0000000..68c39b3 --- /dev/null +++ b/engine/inc/audio/audio.hpp @@ -0,0 +1,42 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022-2022, Tyra - https://github.com/h4570/tyrav2 +# Licensed under Apache License 2.0 +# Sandro Sobczyński +# Wellinator Carvalho +*/ + +#pragma once + +#include "./audio_adpcm.hpp" +#include "./audio_song.hpp" + +namespace Tyra { + +/** Class responsible for audio. */ +class Audio { + public: + Audio(); + ~Audio(); + + void init(); + + AudioSong song; + AudioAdpcm adpcm; + + void work(); + + private: + ee_thread_t thread; + int threadId; + static const u16 threadStackSize; + u8* threadStack; + + void initAUDSRV(); + void initThread(); +}; + +} // namespace Tyra diff --git a/engine/inc/audio/audio_adpcm.hpp b/engine/inc/audio/audio_adpcm.hpp new file mode 100644 index 0000000..ea2091a --- /dev/null +++ b/engine/inc/audio/audio_adpcm.hpp @@ -0,0 +1,77 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022-2022, Tyra - https://github.com/h4570/tyrav2 +# Licensed under Apache License 2.0 +# Sandro Sobczyński +# Wellinator Carvalho +*/ + +#pragma once + +#include "./audio_listener_ref.hpp" +#include "./adpcm_result.hpp" +#include +#include + +namespace Tyra { + +/** + * Class responsible for playing ADPCM samples. + * ADPCM sample can't be stopped. + */ +class AudioAdpcm { + public: + AudioAdpcm(); + ~AudioAdpcm(); + + void init(); + + /** + * Load ADPCM sample. + * ADPCM sample is an output from "Convert WAV to ADPCM" task (adpenc tool). + * Adpenc expects 22kHz 16bit file. + * @param t_path Example: "host:hit.adpcm" or "host:folder/jump.adpcm" + */ + audsrv_adpcm_t* load(const char* t_path); + audsrv_adpcm_t* load(const std::string& t_path); + + /** + * Frees up all memory taken by samples, and stops all voices from + * being played. + */ + void reset(); + + /** + * Try play ADPCM sample if channel(s) is not occupied. + * @param t_adpcm ADPCM data, created by load(); + * @param t_ch Channel (0-23). Type -1 for use any free channel. + */ + AdpcmResult tryPlay(audsrv_adpcm_t* t_adpcm); + AdpcmResult tryPlay(audsrv_adpcm_t* t_adpcm, const s8& t_ch); + + /** + * Play ADPCM sample, if channel is occupied, wait for it. + * If not used properly, can hugely reduce performance. + * @param t_adpcm ADPCM data, created by load(); + * @param t_ch Channel (0-23). Type -1 for use any free channel. + */ + void playWait(audsrv_adpcm_t* t_adpcm); + void playWait(audsrv_adpcm_t* t_adpcm, const s8& t_ch); + + /** + * Set ADPCM volume. + * @param t_vol Value 0-100 + * @param t_ch Channel (0-23) + */ + void setVolume(const u8& t_vol, const s8& t_ch) { + audsrv_adpcm_set_volume(t_ch, t_vol); + } + + private: + void initAUDSRV(); +}; + +} // namespace Tyra diff --git a/engine/inc/audio/audio_listener.hpp b/engine/inc/audio/audio_listener.hpp new file mode 100644 index 0000000..e286f51 --- /dev/null +++ b/engine/inc/audio/audio_listener.hpp @@ -0,0 +1,25 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022-2022, Tyra - https://github.com/h4570/tyrav2 +# Licensed under Apache License 2.0 +# Sandro Sobczyński +# Wellinator Carvalho +*/ + +#pragma once + +namespace Tyra { + +class AudioListener { + public: + virtual ~AudioListener(){}; + virtual void onAudioTick() = 0; + virtual void onAudioFinish() = 0; + + private: +}; + +} // namespace Tyra diff --git a/engine/inc/audio/audio_listener_ref.hpp b/engine/inc/audio/audio_listener_ref.hpp new file mode 100644 index 0000000..0b25f05 --- /dev/null +++ b/engine/inc/audio/audio_listener_ref.hpp @@ -0,0 +1,24 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022-2022, Tyra - https://github.com/h4570/tyrav2 +# Licensed under Apache License 2.0 +# Sandro Sobczyński +# Wellinator Carvalho +*/ + +#pragma once + +#include "./audio_listener.hpp" +#include + +namespace Tyra { + +struct AudioListenerRef { + AudioListener* listener; + u32 id; +}; + +} // namespace Tyra diff --git a/engine/inc/audio/audio_song.hpp b/engine/inc/audio/audio_song.hpp new file mode 100644 index 0000000..e05e029 --- /dev/null +++ b/engine/inc/audio/audio_song.hpp @@ -0,0 +1,90 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022-2022, Tyra - https://github.com/h4570/tyrav2 +# Licensed under Apache License 2.0 +# Sandro Sobczyński +# Wellinator Carvalho +*/ + +#pragma once + +#include "./audio_listener_ref.hpp" +#include +#include +#include +#include + +namespace Tyra { + +/** Class responsible for background audio playing. */ +class AudioSong { + public: + AudioSong(); + ~AudioSong(); + + void init(); + + bool inLoop; + + /** + * Load 16bit 22kHz Stereo WAV. + * Can be used multiple times for song switching. + * @param t_path Example: "host:song.wav" or "host:folder/song.wav" + */ + void load(const char* t_path); + void load(const std::string& t_path); + + void play(); + + void stop(); + + const bool& isPlaying() const; + + const bool& isLoaded() const; + + const u8& getVolume() const; + + /** + * Set song volume. + * @param t_vol Value 0-100 + */ + void setVolume(const u8& t_vol); + + /** + * If you want to synchronize some actions with + * background song, add audio listener. + * @returns Listener id. + */ + u32 addListener(AudioListener* t_listener); + + /** Remove song listener. */ + void removeListener(const u32& t_id); + + std::size_t getListenersCount() const; + + void work(); + + private: + bool songLoaded, songPlaying, songFinished; + u8 tyraVolume, audsrvVolume; + FILE* wav; + audsrv_fmt_t format; + std::vector songListeners; + + ee_sema_t sema; + s32 fillbufferSema; + static const u16 chunkSize; + char* chunk; + s32 chunkReadStatus; + + void initSema(); + void initAUDSRV(); + void setSongFormat(); + void unloadSong(); + void rewindSongToStart(); +}; + +} // namespace Tyra diff --git a/engine/inc/debug/debug.hpp b/engine/inc/debug/debug.hpp new file mode 100644 index 0000000..d919b0e --- /dev/null +++ b/engine/inc/debug/debug.hpp @@ -0,0 +1,117 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#ifdef NDEBUG +#define TYRA_LOG(...) ((void)0) +#define TYRA_WARN(...) ((void)0) +#define TYRA_ERROR(...) ((void)0) +#define TYRA_TRAP(...) ((void)0) +#define TYRA_ASSERT(condition, ...) ((void)0) + +#else // IF Debug + +#include +#include +#include +#include +#include +#include + +#include "file/file_utils.hpp" +#include "info/info.hpp" + +#define TYRA_LOG(...) TyraDebug::writeLines("LOG: ", ##__VA_ARGS__, "\n") +#define TYRA_WARN(...) TyraDebug::writeLines("==WARN: ", ##__VA_ARGS__, "\n") +#define TYRA_ERROR(...) TyraDebug::writeLines("====ERR: ", ##__VA_ARGS__, "\n") +#define TYRA_TRAP(...) TyraDebug::trap(__FILE__, __LINE__, ##__VA_ARGS__) +#define TYRA_BREAKPOINT() TyraDebug::trap(__FILE__, __LINE__, "Breakpoint") +#define TYRA_ASSERT(condition, ...) \ + if (!(condition)) TyraDebug::trap(__FILE__, __LINE__, ##__VA_ARGS__) + +class TyraDebug { + public: + template + static void writeLines(Arg&& arg, Args&&... args) { + std::stringstream ss; + + ss << std::forward(arg); + using expander = int[]; + (void)expander{0, (void(ss << std::forward(args)), 0)...}; + + if (Tyra::Info::writeLogsToFile) { + auto* logFile = getLogFile(); + *logFile << ss.str(); + logFile->flush(); + } else { + printf("%s", ss.str().c_str()); + } + } + + template + static void trap(const char* file, int line, Args... args) { + std::stringstream ss1; + ss1 << "\n"; + ss1 << "============== TYRA ==============\n"; + ss1 << "| Assertion failed!\n"; + ss1 << "|\n"; + + if (Tyra::Info::writeLogsToFile) { + auto* logFile = getLogFile(); + *logFile << ss1.str(); + logFile->flush(); + } else { + printf("%s", ss1.str().c_str()); + } + + writeAssertLines(args...); + + std::stringstream ss2; + ss2 << "|\n"; + ss2 << "| File : " << file << ":" << line << "\n"; + ss2 << "====================================\n\n"; + + if (Tyra::Info::writeLogsToFile) { + auto* logFile = getLogFile(); + *logFile << ss2.str(); + logFile->flush(); + } else { + printf("%s", ss2.str().c_str()); + } + + for (;;) { + } + } + + private: + static std::unique_ptr logFile; + static std::ofstream* getLogFile(); + + template + static void writeAssertLines(Arg&& arg, Args&&... args) { + std::stringstream ss; + + ss << "| " << std::forward(arg) << "\n"; + using expander = int[]; + (void)expander{ + 0, (void(ss << "| " << std::forward(args) << "\n"), 0)...}; + + if (Tyra::Info::writeLogsToFile) { + auto* logfile = getLogFile(); + *logfile << ss.str(); + logFile->flush(); + } else { + printf("%s", ss.str().c_str()); + } + } +}; + +#endif // NDEBUG \ No newline at end of file diff --git a/engine/inc/engine.hpp b/engine/inc/engine.hpp new file mode 100644 index 0000000..0344edc --- /dev/null +++ b/engine/inc/engine.hpp @@ -0,0 +1,56 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "./renderer/renderer.hpp" +#include "./pad/pad.hpp" +#include "./audio/audio.hpp" +#include "./irx/irx_loader.hpp" +#include "./info/info.hpp" +#include "./info/banner.hpp" +#include "./game.hpp" + +namespace Tyra { + +struct EngineOptions { + /** + * True -> logs will be written to file. + * False -> logs will be displayed in console + */ + bool writeLogsToFile = false; + + bool loadUsbDriver = false; +}; + +class Engine { + public: + Engine(); + Engine(const EngineOptions& options); + ~Engine(); + + Renderer renderer; + Pad pad; + Audio audio; + Info info; + + void run(Game* t_game); + + private: + IrxLoader irx; + + Game* game; + Banner banner; + + void realLoop(); + void initAll(const bool& loadUsbDriver); +}; + +} // namespace Tyra diff --git a/engine/inc/file/file_utils.hpp b/engine/inc/file/file_utils.hpp new file mode 100644 index 0000000..7d66d75 --- /dev/null +++ b/engine/inc/file/file_utils.hpp @@ -0,0 +1,47 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Wellington Carvalho +*/ + +#pragma once + +#include + +namespace Tyra { + +class FileUtils { + public: + FileUtils(); + ~FileUtils(); + + /** + * Get current working directory. + * Example: "host:" or "mass:" + */ + static std::string getCwd(); + + /** + * Add current working directory prefix to path + * Example: "host:..." or "mass:..." + */ + static std::string fromCwd(const std::string& relativePath); + static std::string fromCwd(const char* relativePath); + + const char* getElfName() const { return elfName; }; + const char* getElfPath() const { return elfPath; }; + + private: + // Argv name+path & just path + char cwd[255]; + char elfName[255]; + char elfPath[255 - 14]; + + void setPathInfo(const char* path); +}; + +} // namespace Tyra diff --git a/engine/inc/game.hpp b/engine/inc/game.hpp new file mode 100644 index 0000000..2e64268 --- /dev/null +++ b/engine/inc/game.hpp @@ -0,0 +1,21 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +namespace Tyra { + +class Game { + public: + virtual void init() = 0; + virtual void loop() = 0; +}; + +} // namespace Tyra diff --git a/engine/inc/info/banner.hpp b/engine/inc/info/banner.hpp new file mode 100644 index 0000000..2f01de4 --- /dev/null +++ b/engine/inc/info/banner.hpp @@ -0,0 +1,25 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Wellington Carvalho +*/ + +#pragma once + +#include "renderer/renderer.hpp" + +namespace Tyra { + +class Banner { + public: + Banner(); + ~Banner(); + + void show(Renderer* renderer); +}; + +} // namespace Tyra diff --git a/engine/inc/info/info.hpp b/engine/inc/info/info.hpp new file mode 100644 index 0000000..d0c75ef --- /dev/null +++ b/engine/inc/info/info.hpp @@ -0,0 +1,47 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Wellington Carvalho +*/ + +#pragma once + +#include +#include +#include "time/timer.hpp" +#include "./version.hpp" + +namespace Tyra { + +class Info { + public: + Info(); + ~Info(); + + Version version; + + static bool writeLogsToFile; + + /** Called by engine */ + void update(); + + const u32& getFps() const { return fps; }; + + /** @return Available RAM in MB */ + float getAvailableRAM(); + + private: + float calcFps(); + void* allocateLargestFreeRAMBlock(size_t* size); + size_t getFreeRAMSize(); + + u8 fpsDelayer; + u32 fps; + Timer timer; +}; + +} // namespace Tyra diff --git a/engine/inc/info/version.hpp b/engine/inc/info/version.hpp new file mode 100644 index 0000000..e23546a --- /dev/null +++ b/engine/inc/info/version.hpp @@ -0,0 +1,33 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# André Guilherme +*/ + +#pragma once + +#include +#include + +namespace Tyra { + +class Version { + public: + Version() {} + ~Version() {} + + static const u8 major = 2; + static const u8 minor = 0; + static const u8 patch = 0; + + static std::string toString() { + return std::to_string(major) + "." + std::to_string(minor) + "." + + std::to_string(patch); + } +}; + +} // namespace Tyra diff --git a/engine/inc/irx/irx_loader.hpp b/engine/inc/irx/irx_loader.hpp new file mode 100644 index 0000000..a9aa19f --- /dev/null +++ b/engine/inc/irx/irx_loader.hpp @@ -0,0 +1,38 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Wellington Carvalho +*/ + +#pragma once + +#include + +namespace Tyra { + +class IrxLoader { + public: + IrxLoader(); + ~IrxLoader(); + + void loadAll(const bool& withUsb, const bool& isLoggingToFile); + + private: + static bool isLoaded; + + void loadSio2man(const bool& verbose); + void loadPadman(const bool& verbose); + void loadLibsd(const bool& verbose); + void loadUsbModules(const bool& verbose); + void loadAudsrv(const bool& verbose); + + int applyRpcPatches(); + void waitUntilUsbDeviceIsReady(); + void delay(int count); +}; + +} // namespace Tyra diff --git a/engine/inc/loaders/3d/builder/mesh_builder_data.hpp b/engine/inc/loaders/3d/builder/mesh_builder_data.hpp new file mode 100644 index 0000000..0affd4a --- /dev/null +++ b/engine/inc/loaders/3d/builder/mesh_builder_data.hpp @@ -0,0 +1,34 @@ + +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "./mesh_builder_material_data.hpp" + +namespace Tyra { + +/** + * Data needed for constructing mesh class. + * All dynamic data ownership is moved to mesh class, so + * verts, coords.. are not deallocated! + */ +class MeshBuilderData { + public: + MeshBuilderData(); + ~MeshBuilderData(); + + std::vector materials; + + bool textureCoordsEnabled, normalsEnabled, lightMapEnabled; +}; + +} // namespace Tyra diff --git a/engine/inc/loaders/3d/builder/mesh_builder_material_data.hpp b/engine/inc/loaders/3d/builder/mesh_builder_material_data.hpp new file mode 100644 index 0000000..ecde268 --- /dev/null +++ b/engine/inc/loaders/3d/builder/mesh_builder_material_data.hpp @@ -0,0 +1,31 @@ + +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include "./mesh_builder_material_frame_data.hpp" +#include "renderer/models/color.hpp" + +namespace Tyra { + +class MeshBuilderMaterialData { + public: + MeshBuilderMaterialData(); + ~MeshBuilderMaterialData(); + + std::vector frames; + std::string name; + Color ambient; +}; + +} // namespace Tyra diff --git a/engine/inc/loaders/3d/builder/mesh_builder_material_frame_data.hpp b/engine/inc/loaders/3d/builder/mesh_builder_material_frame_data.hpp new file mode 100644 index 0000000..23303d9 --- /dev/null +++ b/engine/inc/loaders/3d/builder/mesh_builder_material_frame_data.hpp @@ -0,0 +1,30 @@ + +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "math/vec4.hpp" +#include "renderer/models/color.hpp" + +namespace Tyra { + +class MeshBuilderMaterialFrameData { + public: + MeshBuilderMaterialFrameData(); + ~MeshBuilderMaterialFrameData(); + + u32 count; + Vec4 *vertices, *textureCoords, *normals; + Color* colors; +}; + +} // namespace Tyra diff --git a/engine/inc/loaders/3d/md2_loader/anorms.hpp b/engine/inc/loaders/3d/md2_loader/anorms.hpp new file mode 100644 index 0000000..220c4fa --- /dev/null +++ b/engine/inc/loaders/3d/md2_loader/anorms.hpp @@ -0,0 +1,103 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +See the GNU General Public License for more details. +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#pragma once + +namespace Tyra { + +const float ANORMS[162][3] = { + {-0.525731f, 0.000000f, 0.850651f}, {-0.442863f, 0.238856f, 0.864188f}, + {-0.295242f, 0.000000f, 0.955423f}, {-0.309017f, 0.500000f, 0.809017f}, + {-0.162460f, 0.262866f, 0.951056f}, {0.000000f, 0.000000f, 1.000000f}, + {0.000000f, 0.850651f, 0.525731f}, {-0.147621f, 0.716567f, 0.681718f}, + {0.147621f, 0.716567f, 0.681718f}, {0.000000f, 0.525731f, 0.850651f}, + {0.309017f, 0.500000f, 0.809017f}, {0.525731f, 0.000000f, 0.850651f}, + {0.295242f, 0.000000f, 0.955423f}, {0.442863f, 0.238856f, 0.864188f}, + {0.162460f, 0.262866f, 0.951056f}, {-0.681718f, 0.147621f, 0.716567f}, + {-0.809017f, 0.309017f, 0.500000f}, {-0.587785f, 0.425325f, 0.688191f}, + {-0.850651f, 0.525731f, 0.000000f}, {-0.864188f, 0.442863f, 0.238856f}, + {-0.716567f, 0.681718f, 0.147621f}, {-0.688191f, 0.587785f, 0.425325f}, + {-0.500000f, 0.809017f, 0.309017f}, {-0.238856f, 0.864188f, 0.442863f}, + {-0.425325f, 0.688191f, 0.587785f}, {-0.716567f, 0.681718f, -0.147621f}, + {-0.500000f, 0.809017f, -0.309017f}, {-0.525731f, 0.850651f, 0.000000f}, + {0.000000f, 0.850651f, -0.525731f}, {-0.238856f, 0.864188f, -0.442863f}, + {0.000000f, 0.955423f, -0.295242f}, {-0.262866f, 0.951056f, -0.162460f}, + {0.000000f, 1.000000f, 0.000000f}, {0.000000f, 0.955423f, 0.295242f}, + {-0.262866f, 0.951056f, 0.162460f}, {0.238856f, 0.864188f, 0.442863f}, + {0.262866f, 0.951056f, 0.162460f}, {0.500000f, 0.809017f, 0.309017f}, + {0.238856f, 0.864188f, -0.442863f}, {0.262866f, 0.951056f, -0.162460f}, + {0.500000f, 0.809017f, -0.309017f}, {0.850651f, 0.525731f, 0.000000f}, + {0.716567f, 0.681718f, 0.147621f}, {0.716567f, 0.681718f, -0.147621f}, + {0.525731f, 0.850651f, 0.000000f}, {0.425325f, 0.688191f, 0.587785f}, + {0.864188f, 0.442863f, 0.238856f}, {0.688191f, 0.587785f, 0.425325f}, + {0.809017f, 0.309017f, 0.500000f}, {0.681718f, 0.147621f, 0.716567f}, + {0.587785f, 0.425325f, 0.688191f}, {0.955423f, 0.295242f, 0.000000f}, + {1.000000f, 0.000000f, 0.000000f}, {0.951056f, 0.162460f, 0.262866f}, + {0.850651f, -0.525731f, 0.000000f}, {0.955423f, -0.295242f, 0.000000f}, + {0.864188f, -0.442863f, 0.238856f}, {0.951056f, -0.162460f, 0.262866f}, + {0.809017f, -0.309017f, 0.500000f}, {0.681718f, -0.147621f, 0.716567f}, + {0.850651f, 0.000000f, 0.525731f}, {0.864188f, 0.442863f, -0.238856f}, + {0.809017f, 0.309017f, -0.500000f}, {0.951056f, 0.162460f, -0.262866f}, + {0.525731f, 0.000000f, -0.850651f}, {0.681718f, 0.147621f, -0.716567f}, + {0.681718f, -0.147621f, -0.716567f}, {0.850651f, 0.000000f, -0.525731f}, + {0.809017f, -0.309017f, -0.500000f}, {0.864188f, -0.442863f, -0.238856f}, + {0.951056f, -0.162460f, -0.262866f}, {0.147621f, 0.716567f, -0.681718f}, + {0.309017f, 0.500000f, -0.809017f}, {0.425325f, 0.688191f, -0.587785f}, + {0.442863f, 0.238856f, -0.864188f}, {0.587785f, 0.425325f, -0.688191f}, + {0.688191f, 0.587785f, -0.425325f}, {-0.147621f, 0.716567f, -0.681718f}, + {-0.309017f, 0.500000f, -0.809017f}, {0.000000f, 0.525731f, -0.850651f}, + {-0.525731f, 0.000000f, -0.850651f}, {-0.442863f, 0.238856f, -0.864188f}, + {-0.295242f, 0.000000f, -0.955423f}, {-0.162460f, 0.262866f, -0.951056f}, + {0.000000f, 0.000000f, -1.000000f}, {0.295242f, 0.000000f, -0.955423f}, + {0.162460f, 0.262866f, -0.951056f}, {-0.442863f, -0.238856f, -0.864188f}, + {-0.309017f, -0.500000f, -0.809017f}, {-0.162460f, -0.262866f, -0.951056f}, + {0.000000f, -0.850651f, -0.525731f}, {-0.147621f, -0.716567f, -0.681718f}, + {0.147621f, -0.716567f, -0.681718f}, {0.000000f, -0.525731f, -0.850651f}, + {0.309017f, -0.500000f, -0.809017f}, {0.442863f, -0.238856f, -0.864188f}, + {0.162460f, -0.262866f, -0.951056f}, {0.238856f, -0.864188f, -0.442863f}, + {0.500000f, -0.809017f, -0.309017f}, {0.425325f, -0.688191f, -0.587785f}, + {0.716567f, -0.681718f, -0.147621f}, {0.688191f, -0.587785f, -0.425325f}, + {0.587785f, -0.425325f, -0.688191f}, {0.000000f, -0.955423f, -0.295242f}, + {0.000000f, -1.000000f, 0.000000f}, {0.262866f, -0.951056f, -0.162460f}, + {0.000000f, -0.850651f, 0.525731f}, {0.000000f, -0.955423f, 0.295242f}, + {0.238856f, -0.864188f, 0.442863f}, {0.262866f, -0.951056f, 0.162460f}, + {0.500000f, -0.809017f, 0.309017f}, {0.716567f, -0.681718f, 0.147621f}, + {0.525731f, -0.850651f, 0.000000f}, {-0.238856f, -0.864188f, -0.442863f}, + {-0.500000f, -0.809017f, -0.309017f}, {-0.262866f, -0.951056f, -0.162460f}, + {-0.850651f, -0.525731f, 0.000000f}, {-0.716567f, -0.681718f, -0.147621f}, + {-0.716567f, -0.681718f, 0.147621f}, {-0.525731f, -0.850651f, 0.000000f}, + {-0.500000f, -0.809017f, 0.309017f}, {-0.238856f, -0.864188f, 0.442863f}, + {-0.262866f, -0.951056f, 0.162460f}, {-0.864188f, -0.442863f, 0.238856f}, + {-0.809017f, -0.309017f, 0.500000f}, {-0.688191f, -0.587785f, 0.425325f}, + {-0.681718f, -0.147621f, 0.716567f}, {-0.442863f, -0.238856f, 0.864188f}, + {-0.587785f, -0.425325f, 0.688191f}, {-0.309017f, -0.500000f, 0.809017f}, + {-0.147621f, -0.716567f, 0.681718f}, {-0.425325f, -0.688191f, 0.587785f}, + {-0.162460f, -0.262866f, 0.951056f}, {0.442863f, -0.238856f, 0.864188f}, + {0.162460f, -0.262866f, 0.951056f}, {0.309017f, -0.500000f, 0.809017f}, + {0.147621f, -0.716567f, 0.681718f}, {0.000000f, -0.525731f, 0.850651f}, + {0.425325f, -0.688191f, 0.587785f}, {0.587785f, -0.425325f, 0.688191f}, + {0.688191f, -0.587785f, 0.425325f}, {-0.955423f, 0.295242f, 0.000000f}, + {-0.951056f, 0.162460f, 0.262866f}, {-1.000000f, 0.000000f, 0.000000f}, + {-0.850651f, 0.000000f, 0.525731f}, {-0.955423f, -0.295242f, 0.000000f}, + {-0.951056f, -0.162460f, 0.262866f}, {-0.864188f, 0.442863f, -0.238856f}, + {-0.951056f, 0.162460f, -0.262866f}, {-0.809017f, 0.309017f, -0.500000f}, + {-0.864188f, -0.442863f, -0.238856f}, {-0.951056f, -0.162460f, -0.262866f}, + {-0.809017f, -0.309017f, -0.500000f}, {-0.681718f, 0.147621f, -0.716567f}, + {-0.681718f, -0.147621f, -0.716567f}, {-0.850651f, 0.000000f, -0.525731f}, + {-0.688191f, 0.587785f, -0.425325f}, {-0.587785f, 0.425325f, -0.688191f}, + {-0.425325f, 0.688191f, -0.587785f}, {-0.425325f, -0.688191f, -0.587785f}, + {-0.587785f, -0.425325f, -0.688191f}, {-0.688191f, -0.587785f, -0.425325f}}; + +} diff --git a/engine/inc/loaders/3d/md2_loader/md2_loader.hpp b/engine/inc/loaders/3d/md2_loader/md2_loader.hpp new file mode 100644 index 0000000..da6d9a4 --- /dev/null +++ b/engine/inc/loaders/3d/md2_loader/md2_loader.hpp @@ -0,0 +1,36 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "../../loader.hpp" +#include "../builder/mesh_builder_data.hpp" +#include +#include + +namespace Tyra { + +struct MD2LoaderOptions { + bool flipUVs = false; + float scale = 1.0F; +}; + +/** Class responsible for loading & parsing Quake's II ".md2" 3D files */ +class MD2Loader : public Loader { + public: + static std::unique_ptr load(const char* fullpath); + static std::unique_ptr load(const char* fullpath, + MD2LoaderOptions options); + static std::unique_ptr load(const std::string& fullpath); + static std::unique_ptr load(const std::string& fullpath, + MD2LoaderOptions options); +}; + +} // namespace Tyra diff --git a/engine/inc/loaders/3d/obj_loader/mapbox/earcut.hpp b/engine/inc/loaders/3d/obj_loader/mapbox/earcut.hpp new file mode 100644 index 0000000..ef95ee2 --- /dev/null +++ b/engine/inc/loaders/3d/obj_loader/mapbox/earcut.hpp @@ -0,0 +1,853 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace mapbox { + +namespace util { + +template +struct nth { + inline static typename std::tuple_element::type get(const T& t) { + return std::get(t); + }; +}; + +} // namespace util + +namespace detail { + +template +class Earcut { + public: + std::vector indices; + std::size_t vertices = 0; + + template + void operator()(const Polygon& points); + + private: + struct Node { + Node(N index, double x_, double y_) : i(index), x(x_), y(y_) {} + Node(const Node&) = delete; + Node& operator=(const Node&) = delete; + Node(Node&&) = delete; + Node& operator=(Node&&) = delete; + + const N i; + const double x; + const double y; + + // previous and next vertice nodes in a polygon ring + Node* prev = nullptr; + Node* next = nullptr; + + // z-order curve value + int32_t z = 0; + + // previous and next nodes in z-order + Node* prevZ = nullptr; + Node* nextZ = nullptr; + + // indicates whether this is a steiner point + bool steiner = false; + }; + + template + Node* linkedList(const Ring& points, const bool clockwise); + Node* filterPoints(Node* start, Node* end = nullptr); + void earcutLinked(Node* ear, int pass = 0); + bool isEar(Node* ear); + bool isEarHashed(Node* ear); + Node* cureLocalIntersections(Node* start); + void splitEarcut(Node* start); + template + Node* eliminateHoles(const Polygon& points, Node* outerNode); + Node* eliminateHole(Node* hole, Node* outerNode); + Node* findHoleBridge(Node* hole, Node* outerNode); + bool sectorContainsSector(const Node* m, const Node* p); + void indexCurve(Node* start); + Node* sortLinked(Node* list); + int32_t zOrder(const double x_, const double y_); + Node* getLeftmost(Node* start); + bool pointInTriangle(double ax, double ay, double bx, double by, double cx, + double cy, double px, double py) const; + bool isValidDiagonal(Node* a, Node* b); + double area(const Node* p, const Node* q, const Node* r) const; + bool equals(const Node* p1, const Node* p2); + bool intersects(const Node* p1, const Node* q1, const Node* p2, + const Node* q2); + bool onSegment(const Node* p, const Node* q, const Node* r); + int sign(double val); + bool intersectsPolygon(const Node* a, const Node* b); + bool locallyInside(const Node* a, const Node* b); + bool middleInside(const Node* a, const Node* b); + Node* splitPolygon(Node* a, Node* b); + template + Node* insertNode(std::size_t i, const Point& p, Node* last); + void removeNode(Node* p); + + bool hashing; + double minX, maxX; + double minY, maxY; + double inv_size = 0; + + template > + class ObjectPool { + public: + ObjectPool() {} + ObjectPool(std::size_t blockSize_) { reset(blockSize_); } + ~ObjectPool() { clear(); } + template + T* construct(Args&&... args) { + if (currentIndex >= blockSize) { + currentBlock = alloc_traits::allocate(alloc, blockSize); + allocations.emplace_back(currentBlock); + currentIndex = 0; + } + T* object = ¤tBlock[currentIndex++]; + alloc_traits::construct(alloc, object, std::forward(args)...); + return object; + } + void reset(std::size_t newBlockSize) { + for (auto allocation : allocations) { + alloc_traits::deallocate(alloc, allocation, blockSize); + } + allocations.clear(); + blockSize = std::max(1, newBlockSize); + currentBlock = nullptr; + currentIndex = blockSize; + } + void clear() { reset(blockSize); } + + private: + T* currentBlock = nullptr; + std::size_t currentIndex = 1; + std::size_t blockSize = 1; + std::vector allocations; + Alloc alloc; + typedef typename std::allocator_traits alloc_traits; + }; + ObjectPool nodes; +}; + +template +template +void Earcut::operator()(const Polygon& points) { + // reset + indices.clear(); + vertices = 0; + + if (points.empty()) return; + + double x; + double y; + int threshold = 80; + std::size_t len = 0; + + for (size_t i = 0; threshold >= 0 && i < points.size(); i++) { + threshold -= static_cast(points[i].size()); + len += points[i].size(); + } + + // estimate size of nodes and indices + nodes.reset(len * 3 / 2); + indices.reserve(len + points[0].size()); + + Node* outerNode = linkedList(points[0], true); + if (!outerNode || outerNode->prev == outerNode->next) return; + + if (points.size() > 1) outerNode = eliminateHoles(points, outerNode); + + // if the shape is not too simple, we'll use z-order curve hash later; + // calculate polygon bbox + hashing = threshold < 0; + if (hashing) { + Node* p = outerNode->next; + minX = maxX = outerNode->x; + minY = maxY = outerNode->y; + do { + x = p->x; + y = p->y; + minX = std::min(minX, x); + minY = std::min(minY, y); + maxX = std::max(maxX, x); + maxY = std::max(maxY, y); + p = p->next; + } while (p != outerNode); + + // minX, minY and size are later used to transform coords into integers for + // z-order calculation + inv_size = std::max(maxX - minX, maxY - minY); + inv_size = inv_size != .0 ? (1. / inv_size) : .0; + } + + earcutLinked(outerNode); + + nodes.clear(); +} + +// create a circular doubly linked list from polygon points in the specified +// winding order +template +template +typename Earcut::Node* Earcut::linkedList(const Ring& points, + const bool clockwise) { + using Point = typename Ring::value_type; + double sum = 0; + const std::size_t len = points.size(); + std::size_t i, j; + Node* last = nullptr; + + // calculate original winding order of a polygon ring + for (i = 0, j = len > 0 ? len - 1 : 0; i < len; j = i++) { + const auto& p1 = points[i]; + const auto& p2 = points[j]; + const double p20 = util::nth<0, Point>::get(p2); + const double p10 = util::nth<0, Point>::get(p1); + const double p11 = util::nth<1, Point>::get(p1); + const double p21 = util::nth<1, Point>::get(p2); + sum += (p20 - p10) * (p11 + p21); + } + + // link points into circular doubly-linked list in the specified winding order + if (clockwise == (sum > 0)) { + for (i = 0; i < len; i++) last = insertNode(vertices + i, points[i], last); + } else { + for (i = len; i-- > 0;) last = insertNode(vertices + i, points[i], last); + } + + if (last && equals(last, last->next)) { + removeNode(last); + last = last->next; + } + + vertices += len; + + return last; +} + +// eliminate colinear or duplicate points +template +typename Earcut::Node* Earcut::filterPoints(Node* start, Node* end) { + if (!end) end = start; + + Node* p = start; + bool again; + do { + again = false; + + if (!p->steiner && (equals(p, p->next) || area(p->prev, p, p->next) == 0)) { + removeNode(p); + p = end = p->prev; + + if (p == p->next) break; + again = true; + + } else { + p = p->next; + } + } while (again || p != end); + + return end; +} + +// main ear slicing loop which triangulates a polygon (given as a linked list) +template +void Earcut::earcutLinked(Node* ear, int pass) { + if (!ear) return; + + // interlink polygon nodes in z-order + if (!pass && hashing) indexCurve(ear); + + Node* stop = ear; + Node* prev; + Node* next; + + int iterations = 0; + + // iterate through ears, slicing them one by one + while (ear->prev != ear->next) { + iterations++; + prev = ear->prev; + next = ear->next; + + if (hashing ? isEarHashed(ear) : isEar(ear)) { + // cut off the triangle + indices.emplace_back(prev->i); + indices.emplace_back(ear->i); + indices.emplace_back(next->i); + + removeNode(ear); + + // skipping the next vertice leads to less sliver triangles + ear = next->next; + stop = next->next; + + continue; + } + + ear = next; + + // if we looped through the whole remaining polygon and can't find any more + // ears + if (ear == stop) { + // try filtering points and slicing again + if (!pass) earcutLinked(filterPoints(ear), 1); + + // if this didn't work, try curing all small self-intersections locally + else if (pass == 1) { + ear = cureLocalIntersections(filterPoints(ear)); + earcutLinked(ear, 2); + + // as a last resort, try splitting the remaining polygon into two + } else if (pass == 2) + splitEarcut(ear); + + break; + } + } +} + +// check whether a polygon node forms a valid ear with adjacent nodes +template +bool Earcut::isEar(Node* ear) { + const Node* a = ear->prev; + const Node* b = ear; + const Node* c = ear->next; + + if (area(a, b, c) >= 0) return false; // reflex, can't be an ear + + // now make sure we don't have other points inside the potential ear + Node* p = ear->next->next; + + while (p != ear->prev) { + if (pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) && + area(p->prev, p, p->next) >= 0) + return false; + p = p->next; + } + + return true; +} + +template +bool Earcut::isEarHashed(Node* ear) { + const Node* a = ear->prev; + const Node* b = ear; + const Node* c = ear->next; + + if (area(a, b, c) >= 0) return false; // reflex, can't be an ear + + // triangle bbox; min & max are calculated like this for speed + const double minTX = std::min(a->x, std::min(b->x, c->x)); + const double minTY = std::min(a->y, std::min(b->y, c->y)); + const double maxTX = std::max(a->x, std::max(b->x, c->x)); + const double maxTY = std::max(a->y, std::max(b->y, c->y)); + + // z-order range for the current triangle bbox; + const int32_t minZ = zOrder(minTX, minTY); + const int32_t maxZ = zOrder(maxTX, maxTY); + + // first look for points inside the triangle in increasing z-order + Node* p = ear->nextZ; + + while (p && p->z <= maxZ) { + if (p != ear->prev && p != ear->next && + pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) && + area(p->prev, p, p->next) >= 0) + return false; + p = p->nextZ; + } + + // then look for points in decreasing z-order + p = ear->prevZ; + + while (p && p->z >= minZ) { + if (p != ear->prev && p != ear->next && + pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) && + area(p->prev, p, p->next) >= 0) + return false; + p = p->prevZ; + } + + return true; +} + +// go through all polygon nodes and cure small local self-intersections +template +typename Earcut::Node* Earcut::cureLocalIntersections(Node* start) { + Node* p = start; + do { + Node* a = p->prev; + Node* b = p->next->next; + + // a self-intersection where edge (v[i-1],v[i]) intersects (v[i+1],v[i+2]) + if (!equals(a, b) && intersects(a, p, p->next, b) && locallyInside(a, b) && + locallyInside(b, a)) { + indices.emplace_back(a->i); + indices.emplace_back(p->i); + indices.emplace_back(b->i); + + // remove two nodes involved + removeNode(p); + removeNode(p->next); + + p = start = b; + } + p = p->next; + } while (p != start); + + return filterPoints(p); +} + +// try splitting polygon into two and triangulate them independently +template +void Earcut::splitEarcut(Node* start) { + // look for a valid diagonal that divides the polygon into two + Node* a = start; + do { + Node* b = a->next->next; + while (b != a->prev) { + if (a->i != b->i && isValidDiagonal(a, b)) { + // split the polygon in two by the diagonal + Node* c = splitPolygon(a, b); + + // filter colinear points around the cuts + a = filterPoints(a, a->next); + c = filterPoints(c, c->next); + + // run earcut on each half + earcutLinked(a); + earcutLinked(c); + return; + } + b = b->next; + } + a = a->next; + } while (a != start); +} + +// link every hole into the outer loop, producing a single-ring polygon without +// holes +template +template +typename Earcut::Node* Earcut::eliminateHoles(const Polygon& points, + Node* outerNode) { + const size_t len = points.size(); + + std::vector queue; + for (size_t i = 1; i < len; i++) { + Node* list = linkedList(points[i], false); + if (list) { + if (list == list->next) list->steiner = true; + queue.push_back(getLeftmost(list)); + } + } + std::sort(queue.begin(), queue.end(), + [](const Node* a, const Node* b) { return a->x < b->x; }); + + // process holes from left to right + for (size_t i = 0; i < queue.size(); i++) { + outerNode = eliminateHole(queue[i], outerNode); + outerNode = filterPoints(outerNode, outerNode->next); + } + + return outerNode; +} + +// find a bridge between vertices that connects hole with an outer ring and and +// link it +template +typename Earcut::Node* Earcut::eliminateHole(Node* hole, + Node* outerNode) { + Node* bridge = findHoleBridge(hole, outerNode); + if (!bridge) { + return outerNode; + } + + Node* bridgeReverse = splitPolygon(bridge, hole); + + // filter collinear points around the cuts + Node* filteredBridge = filterPoints(bridge, bridge->next); + filterPoints(bridgeReverse, bridgeReverse->next); + + // Check if input node was removed by the filtering + return outerNode == bridge ? filteredBridge : outerNode; +} + +// David Eberly's algorithm for finding a bridge between hole and outer polygon +template +typename Earcut::Node* Earcut::findHoleBridge(Node* hole, + Node* outerNode) { + Node* p = outerNode; + double hx = hole->x; + double hy = hole->y; + double qx = -std::numeric_limits::infinity(); + Node* m = nullptr; + + // find a segment intersected by a ray from the hole's leftmost Vertex to the + // left; segment's endpoint with lesser x will be potential connection Vertex + do { + if (hy <= p->y && hy >= p->next->y && p->next->y != p->y) { + double x = p->x + (hy - p->y) * (p->next->x - p->x) / (p->next->y - p->y); + if (x <= hx && x > qx) { + qx = x; + if (x == hx) { + if (hy == p->y) return p; + if (hy == p->next->y) return p->next; + } + m = p->x < p->next->x ? p : p->next; + } + } + p = p->next; + } while (p != outerNode); + + if (!m) return 0; + + if (hx == qx) return m; // hole touches outer segment; pick leftmost endpoint + + // look for points inside the triangle of hole Vertex, segment intersection + // and endpoint; if there are no points found, we have a valid connection; + // otherwise choose the Vertex of the minimum angle with the ray as connection + // Vertex + + const Node* stop = m; + double tanMin = std::numeric_limits::infinity(); + double tanCur = 0; + + p = m; + double mx = m->x; + double my = m->y; + + do { + if (hx >= p->x && p->x >= mx && hx != p->x && + pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, + p->x, p->y)) { + tanCur = std::abs(hy - p->y) / (hx - p->x); // tangential + + if (locallyInside(p, hole) && + (tanCur < tanMin || + (tanCur == tanMin && (p->x > m->x || sectorContainsSector(m, p))))) { + m = p; + tanMin = tanCur; + } + } + + p = p->next; + } while (p != stop); + + return m; +} + +// whether sector in vertex m contains sector in vertex p in the same +// coordinates +template +bool Earcut::sectorContainsSector(const Node* m, const Node* p) { + return area(m->prev, m, p->prev) < 0 && area(p->next, m, m->next) < 0; +} + +// interlink polygon nodes in z-order +template +void Earcut::indexCurve(Node* start) { + assert(start); + Node* p = start; + + do { + p->z = p->z ? p->z : zOrder(p->x, p->y); + p->prevZ = p->prev; + p->nextZ = p->next; + p = p->next; + } while (p != start); + + p->prevZ->nextZ = nullptr; + p->prevZ = nullptr; + + sortLinked(p); +} + +// Simon Tatham's linked list merge sort algorithm +// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html +template +typename Earcut::Node* Earcut::sortLinked(Node* list) { + assert(list); + Node* p; + Node* q; + Node* e; + Node* tail; + int i, numMerges, pSize, qSize; + int inSize = 1; + + for (;;) { + p = list; + list = nullptr; + tail = nullptr; + numMerges = 0; + + while (p) { + numMerges++; + q = p; + pSize = 0; + for (i = 0; i < inSize; i++) { + pSize++; + q = q->nextZ; + if (!q) break; + } + + qSize = inSize; + + while (pSize > 0 || (qSize > 0 && q)) { + if (pSize == 0) { + e = q; + q = q->nextZ; + qSize--; + } else if (qSize == 0 || !q) { + e = p; + p = p->nextZ; + pSize--; + } else if (p->z <= q->z) { + e = p; + p = p->nextZ; + pSize--; + } else { + e = q; + q = q->nextZ; + qSize--; + } + + if (tail) + tail->nextZ = e; + else + list = e; + + e->prevZ = tail; + tail = e; + } + + p = q; + } + + tail->nextZ = nullptr; + + if (numMerges <= 1) return list; + + inSize *= 2; + } +} + +// z-order of a Vertex given coords and size of the data bounding box +template +int32_t Earcut::zOrder(const double x_, const double y_) { + // coords are transformed into non-negative 15-bit integer range + int32_t x = static_cast(32767.0 * (x_ - minX) * inv_size); + int32_t y = static_cast(32767.0 * (y_ - minY) * inv_size); + + x = (x | (x << 8)) & 0x00FF00FF; + x = (x | (x << 4)) & 0x0F0F0F0F; + x = (x | (x << 2)) & 0x33333333; + x = (x | (x << 1)) & 0x55555555; + + y = (y | (y << 8)) & 0x00FF00FF; + y = (y | (y << 4)) & 0x0F0F0F0F; + y = (y | (y << 2)) & 0x33333333; + y = (y | (y << 1)) & 0x55555555; + + return x | (y << 1); +} + +// find the leftmost node of a polygon ring +template +typename Earcut::Node* Earcut::getLeftmost(Node* start) { + Node* p = start; + Node* leftmost = start; + do { + if (p->x < leftmost->x || (p->x == leftmost->x && p->y < leftmost->y)) + leftmost = p; + p = p->next; + } while (p != start); + + return leftmost; +} + +// check if a point lies within a convex triangle +template +bool Earcut::pointInTriangle(double ax, double ay, double bx, double by, + double cx, double cy, double px, + double py) const { + return (cx - px) * (ay - py) - (ax - px) * (cy - py) >= 0 && + (ax - px) * (by - py) - (bx - px) * (ay - py) >= 0 && + (bx - px) * (cy - py) - (cx - px) * (by - py) >= 0; +} + +// check if a diagonal between two polygon nodes is valid (lies in polygon +// interior) +template +bool Earcut::isValidDiagonal(Node* a, Node* b) { + return a->next->i != b->i && a->prev->i != b->i && + !intersectsPolygon(a, b) && // dones't intersect other edges + ((locallyInside(a, b) && locallyInside(b, a) && + middleInside(a, b) && // locally visible + (area(a->prev, a, b->prev) != 0.0 || + area(a, b->prev, b) != + 0.0)) || // does not create opposite-facing sectors + (equals(a, b) && area(a->prev, a, a->next) > 0 && + area(b->prev, b, b->next) > 0)); // special zero-length case +} + +// signed area of a triangle +template +double Earcut::area(const Node* p, const Node* q, const Node* r) const { + return (q->y - p->y) * (r->x - q->x) - (q->x - p->x) * (r->y - q->y); +} + +// check if two points are equal +template +bool Earcut::equals(const Node* p1, const Node* p2) { + return p1->x == p2->x && p1->y == p2->y; +} + +// check if two segments intersect +template +bool Earcut::intersects(const Node* p1, const Node* q1, const Node* p2, + const Node* q2) { + int o1 = sign(area(p1, q1, p2)); + int o2 = sign(area(p1, q1, q2)); + int o3 = sign(area(p2, q2, p1)); + int o4 = sign(area(p2, q2, q1)); + + if (o1 != o2 && o3 != o4) return true; // general case + + if (o1 == 0 && onSegment(p1, p2, q1)) + return true; // p1, q1 and p2 are collinear and p2 lies on p1q1 + if (o2 == 0 && onSegment(p1, q2, q1)) + return true; // p1, q1 and q2 are collinear and q2 lies on p1q1 + if (o3 == 0 && onSegment(p2, p1, q2)) + return true; // p2, q2 and p1 are collinear and p1 lies on p2q2 + if (o4 == 0 && onSegment(p2, q1, q2)) + return true; // p2, q2 and q1 are collinear and q1 lies on p2q2 + + return false; +} + +// for collinear points p, q, r, check if point q lies on segment pr +template +bool Earcut::onSegment(const Node* p, const Node* q, const Node* r) { + return q->x <= std::max(p->x, r->x) && + q->x >= std::min(p->x, r->x) && + q->y <= std::max(p->y, r->y) && + q->y >= std::min(p->y, r->y); +} + +template +int Earcut::sign(double val) { + return (0.0 < val) - (val < 0.0); +} + +// check if a polygon diagonal intersects any polygon segments +template +bool Earcut::intersectsPolygon(const Node* a, const Node* b) { + const Node* p = a; + do { + if (p->i != a->i && p->next->i != a->i && p->i != b->i && + p->next->i != b->i && intersects(p, p->next, a, b)) + return true; + p = p->next; + } while (p != a); + + return false; +} + +// check if a polygon diagonal is locally inside the polygon +template +bool Earcut::locallyInside(const Node* a, const Node* b) { + return area(a->prev, a, a->next) < 0 + ? area(a, b, a->next) >= 0 && area(a, a->prev, b) >= 0 + : area(a, b, a->prev) < 0 || area(a, a->next, b) < 0; +} + +// check if the middle Vertex of a polygon diagonal is inside the polygon +template +bool Earcut::middleInside(const Node* a, const Node* b) { + const Node* p = a; + bool inside = false; + double px = (a->x + b->x) / 2; + double py = (a->y + b->y) / 2; + do { + if (((p->y > py) != (p->next->y > py)) && p->next->y != p->y && + (px < (p->next->x - p->x) * (py - p->y) / (p->next->y - p->y) + p->x)) + inside = !inside; + p = p->next; + } while (p != a); + + return inside; +} + +// link two polygon vertices with a bridge; if the vertices belong to the same +// ring, it splits polygon into two; if one belongs to the outer ring and +// another to a hole, it merges it into a single ring +template +typename Earcut::Node* Earcut::splitPolygon(Node* a, Node* b) { + Node* a2 = nodes.construct(a->i, a->x, a->y); + Node* b2 = nodes.construct(b->i, b->x, b->y); + Node* an = a->next; + Node* bp = b->prev; + + a->next = b; + b->prev = a; + + a2->next = an; + an->prev = a2; + + b2->next = a2; + a2->prev = b2; + + bp->next = b2; + b2->prev = bp; + + return b2; +} + +// create a node and util::optionally link it with previous one (in a circular +// doubly linked list) +template +template +typename Earcut::Node* Earcut::insertNode(std::size_t i, const Point& pt, + Node* last) { + Node* p = nodes.construct(static_cast(i), util::nth<0, Point>::get(pt), + util::nth<1, Point>::get(pt)); + + if (!last) { + p->prev = p; + p->next = p; + + } else { + assert(last); + p->next = last->next; + p->prev = last; + last->next->prev = p; + last->next = p; + } + return p; +} + +template +void Earcut::removeNode(Node* p) { + p->next->prev = p->prev; + p->prev->next = p->next; + + if (p->prevZ) p->prevZ->nextZ = p->nextZ; + if (p->nextZ) p->nextZ->prevZ = p->prevZ; +} +} // namespace detail + +template +std::vector earcut(const Polygon& poly) { + mapbox::detail::Earcut earcut; + earcut(poly); + return std::move(earcut.indices); +} +} // namespace mapbox \ No newline at end of file diff --git a/engine/inc/loaders/3d/obj_loader/obj_loader.hpp b/engine/inc/loaders/3d/obj_loader/obj_loader.hpp new file mode 100644 index 0000000..6282f91 --- /dev/null +++ b/engine/inc/loaders/3d/obj_loader/obj_loader.hpp @@ -0,0 +1,67 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "../../loader.hpp" +#include "../builder/mesh_builder_data.hpp" +#include +#include "renderer/models/color.hpp" +#include "loaders/3d/obj_loader/tiny_obj_loader.hpp" +#include + +namespace Tyra { + +struct ObjLoaderAnimationOptions { + u16 count = 1; + u16 startingIndex = 1; +}; + +struct ObjLoaderOptions { + bool flipUVs = false; + float scale = 1.0F; + ObjLoaderAnimationOptions animation; +}; + +struct MaterialVertexCount { + size_t materialId; + int count; +}; + +/** Class responsible for loading & parsing obj files */ +class ObjLoader : public Loader { + public: + static std::unique_ptr load(const char* fullpath); + static std::unique_ptr load(const char* fullpath, + const ObjLoaderOptions& options); + static std::unique_ptr load(const std::string& fullpath); + static std::unique_ptr load(const std::string& fullpath, + const ObjLoaderOptions& options); + + private: + static void addOutputMaterialsAndFrames( + MeshBuilderData* output, const tinyobj::attrib_t& attrib, + const std::vector& shapes, + const std::vector& materials, const u16& framesCount, + std::vector& materialVertexCounts); + + static std::vector scan( + const std::vector& shapes, + const std::vector& materials); + + static void importFrame(MeshBuilderData* output, + const tinyobj::attrib_t& attrib, + const std::vector& shapes, + const std::vector& materials, + const u16& frameIndex, const float& scale, + const bool& invertY, const u16& count); +}; + +} // namespace Tyra diff --git a/engine/inc/loaders/3d/obj_loader/tiny_obj_loader.hpp b/engine/inc/loaders/3d/obj_loader/tiny_obj_loader.hpp new file mode 100644 index 0000000..a6b14ea --- /dev/null +++ b/engine/inc/loaders/3d/obj_loader/tiny_obj_loader.hpp @@ -0,0 +1,3339 @@ +/* +The MIT License (MIT) + +Copyright (c) 2012-Present, Syoyo Fujita and many contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +// +// version 2.0.0 : Add new object oriented API. 1.x API is still provided. +// * Support line primitive. +// * Support points primitive. +// * Support multiple search path for .mtl(v1 API). +// * Support vertex weight `vw`(as an tinyobj extension) +// * Support escaped whitespece in mtllib +// * Add robust triangulation using Mapbox +// earcut(TINYOBJLOADER_USE_MAPBOX_EARCUT). +// version 1.4.0 : Modifed ParseTextureNameAndOption API +// version 1.3.1 : Make ParseTextureNameAndOption API public +// version 1.3.0 : Separate warning and error message(breaking API of LoadObj) +// version 1.2.3 : Added color space extension('-colorspace') to tex opts. +// version 1.2.2 : Parse multiple group names. +// version 1.2.1 : Added initial support for line('l') primitive(PR #178) +// version 1.2.0 : Hardened implementation(#175) +// version 1.1.1 : Support smoothing groups(#162) +// version 1.1.0 : Support parsing vertex color(#144) +// version 1.0.8 : Fix parsing `g` tag just after `usemtl`(#138) +// version 1.0.7 : Support multiple tex options(#126) +// version 1.0.6 : Add TINYOBJLOADER_USE_DOUBLE option(#124) +// version 1.0.5 : Ignore `Tr` when `d` exists in MTL(#43) +// version 1.0.4 : Support multiple filenames for 'mtllib'(#112) +// version 1.0.3 : Support parsing texture options(#85) +// version 1.0.2 : Improve parsing speed by about a factor of 2 for large +// files(#105) +// version 1.0.1 : Fixes a shape is lost if obj ends with a 'usemtl'(#104) +// version 1.0.0 : Change data structure. Change license from BSD to MIT. +// + +// +// Use this in *one* .cc +// #define TINYOBJLOADER_IMPLEMENTATION +// #include "tiny_obj_loader.h" +// + +#ifndef TINY_OBJ_LOADER_H_ +#define TINY_OBJ_LOADER_H_ + +#include +#include +#include + +namespace tinyobj { + +// TODO(syoyo): Better C++11 detection for older compiler +#if __cplusplus > 199711L +#define TINYOBJ_OVERRIDE override +#else +#define TINYOBJ_OVERRIDE +#endif + +#ifdef __clang__ +#pragma clang diagnostic push +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif + +#pragma clang diagnostic ignored "-Wpadded" + +#endif + +// https://en.wikipedia.org/wiki/Wavefront_.obj_file says ... +// +// -blendu on | off # set horizontal texture blending +// (default on) +// -blendv on | off # set vertical texture blending +// (default on) +// -boost real_value # boost mip-map sharpness +// -mm base_value gain_value # modify texture map values (default +// 0 1) +// # base_value = brightness, +// gain_value = contrast +// -o u [v [w]] # Origin offset (default +// 0 0 0) +// -s u [v [w]] # Scale (default +// 1 1 1) +// -t u [v [w]] # Turbulence (default +// 0 0 0) +// -texres resolution # texture resolution to create +// -clamp on | off # only render texels in the clamped +// 0-1 range (default off) +// # When unclamped, textures are +// repeated across a surface, +// # when clamped, only texels which +// fall within the 0-1 +// # range are rendered. +// -bm mult_value # bump multiplier (for bump maps +// only) +// +// -imfchan r | g | b | m | l | z # specifies which channel of the file +// is used to +// # create a scalar or bump texture. +// r:red, g:green, +// # b:blue, m:matte, l:luminance, +// z:z-depth.. +// # (the default for bump is 'l' and +// for decal is 'm') +// bump -imfchan r bumpmap.tga # says to use the red channel of +// bumpmap.tga as the bumpmap +// +// For reflection maps... +// +// -type sphere # specifies a sphere for a "refl" +// reflection map +// -type cube_top | cube_bottom | # when using a cube map, the texture +// file for each +// cube_front | cube_back | # side of the cube is specified +// separately +// cube_left | cube_right +// +// TinyObjLoader extension. +// +// -colorspace SPACE # Color space of the texture. e.g. +// 'sRGB` or 'linear' +// + +#ifdef TINYOBJLOADER_USE_DOUBLE +//#pragma message "using double" +typedef double real_t; +#else +//#pragma message "using float" +typedef float real_t; +#endif + +typedef enum { + TEXTURE_TYPE_NONE, // default + TEXTURE_TYPE_SPHERE, + TEXTURE_TYPE_CUBE_TOP, + TEXTURE_TYPE_CUBE_BOTTOM, + TEXTURE_TYPE_CUBE_FRONT, + TEXTURE_TYPE_CUBE_BACK, + TEXTURE_TYPE_CUBE_LEFT, + TEXTURE_TYPE_CUBE_RIGHT +} texture_type_t; + +struct texture_option_t { + texture_type_t type; // -type (default TEXTURE_TYPE_NONE) + real_t sharpness; // -boost (default 1.0?) + real_t brightness; // base_value in -mm option (default 0) + real_t contrast; // gain_value in -mm option (default 1) + real_t origin_offset[3]; // -o u [v [w]] (default 0 0 0) + real_t scale[3]; // -s u [v [w]] (default 1 1 1) + real_t turbulence[3]; // -t u [v [w]] (default 0 0 0) + int texture_resolution; // -texres resolution (No default value in the spec. + // We'll use -1) + bool clamp; // -clamp (default false) + char imfchan; // -imfchan (the default for bump is 'l' and for decal is 'm') + bool blendu; // -blendu (default on) + bool blendv; // -blendv (default on) + real_t bump_multiplier; // -bm (for bump maps only, default 1.0) + + // extension + std::string colorspace; // Explicitly specify color space of stored texel + // value. Usually `sRGB` or `linear` (default empty). +}; + +struct material_t { + std::string name; + + real_t ambient[3]; + real_t diffuse[3]; + real_t specular[3]; + real_t transmittance[3]; + real_t emission[3]; + real_t shininess; + real_t ior; // index of refraction + real_t dissolve; // 1 == opaque; 0 == fully transparent + // illumination model (see http://www.fileformat.info/format/material/) + int illum; + + int dummy; // Suppress padding warning. + + std::string ambient_texname; // map_Ka + std::string diffuse_texname; // map_Kd + std::string specular_texname; // map_Ks + std::string specular_highlight_texname; // map_Ns + std::string bump_texname; // map_bump, map_Bump, bump + std::string displacement_texname; // disp + std::string alpha_texname; // map_d + std::string reflection_texname; // refl + + texture_option_t ambient_texopt; + texture_option_t diffuse_texopt; + texture_option_t specular_texopt; + texture_option_t specular_highlight_texopt; + texture_option_t bump_texopt; + texture_option_t displacement_texopt; + texture_option_t alpha_texopt; + texture_option_t reflection_texopt; + + // PBR extension + // http://exocortex.com/blog/extending_wavefront_mtl_to_support_pbr + real_t roughness; // [0, 1] default 0 + real_t metallic; // [0, 1] default 0 + real_t sheen; // [0, 1] default 0 + real_t clearcoat_thickness; // [0, 1] default 0 + real_t clearcoat_roughness; // [0, 1] default 0 + real_t anisotropy; // aniso. [0, 1] default 0 + real_t anisotropy_rotation; // anisor. [0, 1] default 0 + real_t pad0; + std::string roughness_texname; // map_Pr + std::string metallic_texname; // map_Pm + std::string sheen_texname; // map_Ps + std::string emissive_texname; // map_Ke + std::string normal_texname; // norm. For normal mapping. + + texture_option_t roughness_texopt; + texture_option_t metallic_texopt; + texture_option_t sheen_texopt; + texture_option_t emissive_texopt; + texture_option_t normal_texopt; + + int pad2; + + std::map unknown_parameter; + +#ifdef TINY_OBJ_LOADER_PYTHON_BINDING + // For pybind11 + std::array GetDiffuse() { + std::array values; + values[0] = double(diffuse[0]); + values[1] = double(diffuse[1]); + values[2] = double(diffuse[2]); + + return values; + } + + std::array GetSpecular() { + std::array values; + values[0] = double(specular[0]); + values[1] = double(specular[1]); + values[2] = double(specular[2]); + + return values; + } + + std::array GetTransmittance() { + std::array values; + values[0] = double(transmittance[0]); + values[1] = double(transmittance[1]); + values[2] = double(transmittance[2]); + + return values; + } + + std::array GetEmission() { + std::array values; + values[0] = double(emission[0]); + values[1] = double(emission[1]); + values[2] = double(emission[2]); + + return values; + } + + std::array GetAmbient() { + std::array values; + values[0] = double(ambient[0]); + values[1] = double(ambient[1]); + values[2] = double(ambient[2]); + + return values; + } + + void SetDiffuse(std::array& a) { + diffuse[0] = real_t(a[0]); + diffuse[1] = real_t(a[1]); + diffuse[2] = real_t(a[2]); + } + + void SetAmbient(std::array& a) { + ambient[0] = real_t(a[0]); + ambient[1] = real_t(a[1]); + ambient[2] = real_t(a[2]); + } + + void SetSpecular(std::array& a) { + specular[0] = real_t(a[0]); + specular[1] = real_t(a[1]); + specular[2] = real_t(a[2]); + } + + void SetTransmittance(std::array& a) { + transmittance[0] = real_t(a[0]); + transmittance[1] = real_t(a[1]); + transmittance[2] = real_t(a[2]); + } + + std::string GetCustomParameter(const std::string& key) { + std::map::const_iterator it = + unknown_parameter.find(key); + + if (it != unknown_parameter.end()) { + return it->second; + } + return std::string(); + } + +#endif +}; + +struct tag_t { + std::string name; + + std::vector intValues; + std::vector floatValues; + std::vector stringValues; +}; + +struct joint_and_weight_t { + int joint_id; + real_t weight; +}; + +struct skin_weight_t { + int vertex_id; // Corresponding vertex index in `attrib_t::vertices`. + // Compared to `index_t`, this index must be positive and + // start with 0(does not allow relative indexing) + std::vector weightValues; +}; + +// Index struct to support different indices for vtx/normal/texcoord. +// -1 means not used. +struct index_t { + int vertex_index; + int normal_index; + int texcoord_index; +}; + +struct mesh_t { + std::vector indices; + std::vector + num_face_vertices; // The number of vertices per + // face. 3 = triangle, 4 = quad, + // ... Up to 255 vertices per face. + std::vector material_ids; // per-face material ID + std::vector smoothing_group_ids; // per-face smoothing group + // ID(0 = off. positive value + // = group id) + std::vector tags; // SubD tag +}; + +// struct path_t { +// std::vector indices; // pairs of indices for lines +//}; + +struct lines_t { + // Linear flattened indices. + std::vector indices; // indices for vertices(poly lines) + std::vector num_line_vertices; // The number of vertices per line. +}; + +struct points_t { + std::vector indices; // indices for points +}; + +struct shape_t { + std::string name; + mesh_t mesh; + lines_t lines; + points_t points; +}; + +// Vertex attributes +struct attrib_t { + std::vector vertices; // 'v'(xyz) + + // For backward compatibility, we store vertex weight in separate array. + std::vector vertex_weights; // 'v'(w) + std::vector normals; // 'vn' + std::vector texcoords; // 'vt'(uv) + + // For backward compatibility, we store texture coordinate 'w' in separate + // array. + std::vector texcoord_ws; // 'vt'(w) + std::vector colors; // extension: vertex colors + + // + // TinyObj extension. + // + + // NOTE(syoyo): array index is based on the appearance order. + // To get a corresponding skin weight for a specific vertex id `vid`, + // Need to reconstruct a look up table: `skin_weight_t::vertex_id` == `vid` + // (e.g. using std::map, std::unordered_map) + std::vector skin_weights; + + attrib_t() {} + + // + // For pybind11 + // + const std::vector& GetVertices() const { return vertices; } + + const std::vector& GetVertexWeights() const { return vertex_weights; } +}; + +struct callback_t { + // W is optional and set to 1 if there is no `w` item in `v` line + void (*vertex_cb)(void* user_data, real_t x, real_t y, real_t z, real_t w); + void (*normal_cb)(void* user_data, real_t x, real_t y, real_t z); + + // y and z are optional and set to 0 if there is no `y` and/or `z` item(s) in + // `vt` line. + void (*texcoord_cb)(void* user_data, real_t x, real_t y, real_t z); + + // called per 'f' line. num_indices is the number of face indices(e.g. 3 for + // triangle, 4 for quad) + // 0 will be passed for undefined index in index_t members. + void (*index_cb)(void* user_data, index_t* indices, int num_indices); + // `name` material name, `material_id` = the array index of material_t[]. -1 + // if + // a material not found in .mtl + void (*usemtl_cb)(void* user_data, const char* name, int material_id); + // `materials` = parsed material data. + void (*mtllib_cb)(void* user_data, const material_t* materials, + int num_materials); + // There may be multiple group names + void (*group_cb)(void* user_data, const char** names, int num_names); + void (*object_cb)(void* user_data, const char* name); + + callback_t() + : vertex_cb(NULL), + normal_cb(NULL), + texcoord_cb(NULL), + index_cb(NULL), + usemtl_cb(NULL), + mtllib_cb(NULL), + group_cb(NULL), + object_cb(NULL) {} +}; + +class MaterialReader { + public: + MaterialReader() {} + virtual ~MaterialReader(); + + virtual bool operator()(const std::string& matId, + std::vector* materials, + std::map* matMap, std::string* warn, + std::string* err) = 0; +}; + +/// +/// Read .mtl from a file. +/// +class MaterialFileReader : public MaterialReader { + public: + // Path could contain separator(';' in Windows, ':' in Posix) + explicit MaterialFileReader(const std::string& mtl_basedir) + : m_mtlBaseDir(mtl_basedir) {} + virtual ~MaterialFileReader() TINYOBJ_OVERRIDE {} + virtual bool operator()(const std::string& matId, + std::vector* materials, + std::map* matMap, std::string* warn, + std::string* err) TINYOBJ_OVERRIDE; + + private: + std::string m_mtlBaseDir; +}; + +/// +/// Read .mtl from a stream. +/// +class MaterialStreamReader : public MaterialReader { + public: + explicit MaterialStreamReader(std::istream& inStream) + : m_inStream(inStream) {} + virtual ~MaterialStreamReader() TINYOBJ_OVERRIDE {} + virtual bool operator()(const std::string& matId, + std::vector* materials, + std::map* matMap, std::string* warn, + std::string* err) TINYOBJ_OVERRIDE; + + private: + std::istream& m_inStream; +}; + +// v2 API +struct ObjReaderConfig { + bool triangulate; // triangulate polygon? + + // Currently not used. + // "simple" or empty: Create triangle fan + // "earcut": Use the algorithm based on Ear clipping + std::string triangulation_method; + + /// Parse vertex color. + /// If vertex color is not present, its filled with default value. + /// false = no vertex color + /// This will increase memory of parsed .obj + bool vertex_color; + + /// + /// Search path to .mtl file. + /// Default = "" = search from the same directory of .obj file. + /// Valid only when loading .obj from a file. + /// + std::string mtl_search_path; + + ObjReaderConfig() + : triangulate(true), triangulation_method("simple"), vertex_color(true) {} +}; + +/// +/// Wavefront .obj reader class(v2 API) +/// +class ObjReader { + public: + ObjReader() : valid_(false) {} + + /// + /// Load .obj and .mtl from a file. + /// + /// @param[in] filename wavefront .obj filename + /// @param[in] config Reader configuration + /// + bool ParseFromFile(const std::string& filename, + const ObjReaderConfig& config = ObjReaderConfig()); + + /// + /// Parse .obj from a text string. + /// Need to supply .mtl text string by `mtl_text`. + /// This function ignores `mtllib` line in .obj text. + /// + /// @param[in] obj_text wavefront .obj filename + /// @param[in] mtl_text wavefront .mtl filename + /// @param[in] config Reader configuration + /// + bool ParseFromString(const std::string& obj_text, const std::string& mtl_text, + const ObjReaderConfig& config = ObjReaderConfig()); + + /// + /// .obj was loaded or parsed correctly. + /// + bool Valid() const { return valid_; } + + const attrib_t& GetAttrib() const { return attrib_; } + + const std::vector& GetShapes() const { return shapes_; } + + const std::vector& GetMaterials() const { return materials_; } + + /// + /// Warning message(may be filled after `Load` or `Parse`) + /// + const std::string& Warning() const { return warning_; } + + /// + /// Error message(filled when `Load` or `Parse` failed) + /// + const std::string& Error() const { return error_; } + + private: + bool valid_; + + attrib_t attrib_; + std::vector shapes_; + std::vector materials_; + + std::string warning_; + std::string error_; +}; + +/// ==>>========= Legacy v1 API ============================================= + +/// Loads .obj from a file. +/// 'attrib', 'shapes' and 'materials' will be filled with parsed shape data +/// 'shapes' will be filled with parsed shape data +/// Returns true when loading .obj become success. +/// Returns warning message into `warn`, and error message into `err` +/// 'mtl_basedir' is optional, and used for base directory for .mtl file. +/// In default(`NULL'), .mtl file is searched from an application's working +/// directory. +/// 'triangulate' is optional, and used whether triangulate polygon face in .obj +/// or not. +/// Option 'default_vcols_fallback' specifies whether vertex colors should +/// always be defined, even if no colors are given (fallback to white). +bool LoadObj(attrib_t* attrib, std::vector* shapes, + std::vector* materials, std::string* warn, + std::string* err, const char* filename, + const char* mtl_basedir = NULL, bool triangulate = true, + bool default_vcols_fallback = true); + +/// Loads .obj from a file with custom user callback. +/// .mtl is loaded as usual and parsed material_t data will be passed to +/// `callback.mtllib_cb`. +/// Returns true when loading .obj/.mtl become success. +/// Returns warning message into `warn`, and error message into `err` +/// See `examples/callback_api/` for how to use this function. +bool LoadObjWithCallback(std::istream& inStream, const callback_t& callback, + void* user_data = NULL, + MaterialReader* readMatFn = NULL, + std::string* warn = NULL, std::string* err = NULL); + +/// Loads object from a std::istream, uses `readMatFn` to retrieve +/// std::istream for materials. +/// Returns true when loading .obj become success. +/// Returns warning and error message into `err` +bool LoadObj(attrib_t* attrib, std::vector* shapes, + std::vector* materials, std::string* warn, + std::string* err, std::istream* inStream, + MaterialReader* readMatFn = NULL, bool triangulate = true, + bool default_vcols_fallback = true); + +/// Loads materials into std::map +void LoadMtl(std::map* material_map, + std::vector* materials, std::istream* inStream, + std::string* warning, std::string* err); + +/// +/// Parse texture name and texture option for custom texture parameter through +/// material::unknown_parameter +/// +/// @param[out] texname Parsed texture name +/// @param[out] texopt Parsed texopt +/// @param[in] linebuf Input string +/// +bool ParseTextureNameAndOption(std::string* texname, texture_option_t* texopt, + const char* linebuf); + +/// =<<========== Legacy v1 API ============================================= + +} // namespace tinyobj + +#endif // TINY_OBJ_LOADER_H_ + +#ifdef TINYOBJLOADER_IMPLEMENTATION +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef TINYOBJLOADER_USE_MAPBOX_EARCUT + +#ifdef TINYOBJLOADER_DONOT_INCLUDE_MAPBOX_EARCUT +// Assume earcut.hpp is included outside of tiny_obj_loader.h +#else + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Weverything" +#endif + +#include +#include "./mapbox/earcut.hpp" + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif + +#endif // TINYOBJLOADER_USE_MAPBOX_EARCUT + +namespace tinyobj { + +MaterialReader::~MaterialReader() {} + +struct vertex_index_t { + int v_idx, vt_idx, vn_idx; + vertex_index_t() : v_idx(-1), vt_idx(-1), vn_idx(-1) {} + explicit vertex_index_t(int idx) : v_idx(idx), vt_idx(idx), vn_idx(idx) {} + vertex_index_t(int vidx, int vtidx, int vnidx) + : v_idx(vidx), vt_idx(vtidx), vn_idx(vnidx) {} +}; + +// Internal data structure for face representation +// index + smoothing group. +struct face_t { + unsigned int + smoothing_group_id; // smoothing group id. 0 = smoothing groupd is off. + int pad_; + std::vector vertex_indices; // face vertex indices. + + face_t() : smoothing_group_id(0), pad_(0) {} +}; + +// Internal data structure for line representation +struct __line_t { + // l v1/vt1 v2/vt2 ... + // In the specification, line primitrive does not have normal index, but + // TinyObjLoader allow it + std::vector vertex_indices; +}; + +// Internal data structure for points representation +struct __points_t { + // p v1 v2 ... + // In the specification, point primitrive does not have normal index and + // texture coord index, but TinyObjLoader allow it. + std::vector vertex_indices; +}; + +struct tag_sizes { + tag_sizes() : num_ints(0), num_reals(0), num_strings(0) {} + int num_ints; + int num_reals; + int num_strings; +}; + +struct obj_shape { + std::vector v; + std::vector vn; + std::vector vt; +}; + +// +// Manages group of primitives(face, line, points, ...) +struct PrimGroup { + std::vector faceGroup; + std::vector<__line_t> lineGroup; + std::vector<__points_t> pointsGroup; + + void clear() { + faceGroup.clear(); + lineGroup.clear(); + pointsGroup.clear(); + } + + bool IsEmpty() const { + return faceGroup.empty() && lineGroup.empty() && pointsGroup.empty(); + } + + // TODO(syoyo): bspline, surface, ... +}; + +// See +// http://stackoverflow.com/questions/6089231/getting-std-ifstream-to-handle-lf-cr-and-crlf +static std::istream& safeGetline(std::istream& is, std::string& t) { + t.clear(); + + // The characters in the stream are read one-by-one using a std::streambuf. + // That is faster than reading them one-by-one using the std::istream. + // Code that uses streambuf this way must be guarded by a sentry object. + // The sentry object performs various tasks, + // such as thread synchronization and updating the stream state. + + std::istream::sentry se(is, true); + std::streambuf* sb = is.rdbuf(); + + if (se) { + for (;;) { + int c = sb->sbumpc(); + switch (c) { + case '\n': + return is; + case '\r': + if (sb->sgetc() == '\n') sb->sbumpc(); + return is; + case EOF: + // Also handle the case when the last line has no line ending + if (t.empty()) is.setstate(std::ios::eofbit); + return is; + default: + t += static_cast(c); + } + } + } + + return is; +} + +#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t')) +#define IS_DIGIT(x) \ + (static_cast((x) - '0') < static_cast(10)) +#define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0')) + +// Make index zero-base, and also support relative index. +static inline bool fixIndex(int idx, int n, int* ret) { + if (!ret) { + return false; + } + + if (idx > 0) { + (*ret) = idx - 1; + return true; + } + + if (idx == 0) { + // zero is not allowed according to the spec. + return false; + } + + if (idx < 0) { + (*ret) = n + idx; // negative value = relative + return true; + } + + return false; // never reach here. +} + +static inline std::string parseString(const char** token) { + std::string s; + (*token) += strspn((*token), " \t"); + size_t e = strcspn((*token), " \t\r"); + s = std::string((*token), &(*token)[e]); + (*token) += e; + return s; +} + +static inline int parseInt(const char** token) { + (*token) += strspn((*token), " \t"); + int i = atoi((*token)); + (*token) += strcspn((*token), " \t\r"); + return i; +} + +// Tries to parse a floating point number located at s. +// +// s_end should be a location in the string where reading should absolutely +// stop. For example at the end of the string, to prevent buffer overflows. +// +// Parses the following EBNF grammar: +// sign = "+" | "-" ; +// END = ? anything not in digit ? +// digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; +// integer = [sign] , digit , {digit} ; +// decimal = integer , ["." , integer] ; +// float = ( decimal , END ) | ( decimal , ("E" | "e") , integer , END ) ; +// +// Valid strings are for example: +// -0 +3.1417e+2 -0.0E-3 1.0324 -1.41 11e2 +// +// If the parsing is a success, result is set to the parsed value and true +// is returned. +// +// The function is greedy and will parse until any of the following happens: +// - a non-conforming character is encountered. +// - s_end is reached. +// +// The following situations triggers a failure: +// - s >= s_end. +// - parse failure. +// +static bool tryParseDouble(const char* s, const char* s_end, double* result) { + if (s >= s_end) { + return false; + } + + double mantissa = 0.0; + // This exponent is base 2 rather than 10. + // However the exponent we parse is supposed to be one of ten, + // thus we must take care to convert the exponent/and or the + // mantissa to a * 2^E, where a is the mantissa and E is the + // exponent. + // To get the final double we will use ldexp, it requires the + // exponent to be in base 2. + int exponent = 0; + + // NOTE: THESE MUST BE DECLARED HERE SINCE WE ARE NOT ALLOWED + // TO JUMP OVER DEFINITIONS. + char sign = '+'; + char exp_sign = '+'; + char const* curr = s; + + // How many characters were read in a loop. + int read = 0; + // Tells whether a loop terminated due to reaching s_end. + bool end_not_reached = false; + bool leading_decimal_dots = false; + + /* + BEGIN PARSING. + */ + + // Find out what sign we've got. + if (*curr == '+' || *curr == '-') { + sign = *curr; + curr++; + if ((curr != s_end) && (*curr == '.')) { + // accept. Somethig like `.7e+2`, `-.5234` + leading_decimal_dots = true; + } + } else if (IS_DIGIT(*curr)) { /* Pass through. */ + } else if (*curr == '.') { + // accept. Somethig like `.7e+2`, `-.5234` + leading_decimal_dots = true; + } else { + goto fail; + } + + // Read the integer part. + end_not_reached = (curr != s_end); + if (!leading_decimal_dots) { + while (end_not_reached && IS_DIGIT(*curr)) { + mantissa *= 10; + mantissa += static_cast(*curr - 0x30); + curr++; + read++; + end_not_reached = (curr != s_end); + } + + // We must make sure we actually got something. + if (read == 0) goto fail; + } + + // We allow numbers of form "#", "###" etc. + if (!end_not_reached) goto assemble; + + // Read the decimal part. + if (*curr == '.') { + curr++; + read = 1; + end_not_reached = (curr != s_end); + while (end_not_reached && IS_DIGIT(*curr)) { + static const double pow_lut[] = { + 1.0, 0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001, + }; + const int lut_entries = sizeof pow_lut / sizeof pow_lut[0]; + + // NOTE: Don't use powf here, it will absolutely murder precision. + mantissa += static_cast(*curr - 0x30) * + (read < lut_entries ? pow_lut[read] : std::pow(10.0, -read)); + read++; + curr++; + end_not_reached = (curr != s_end); + } + } else if (*curr == 'e' || *curr == 'E') { + } else { + goto assemble; + } + + if (!end_not_reached) goto assemble; + + // Read the exponent part. + if (*curr == 'e' || *curr == 'E') { + curr++; + // Figure out if a sign is present and if it is. + end_not_reached = (curr != s_end); + if (end_not_reached && (*curr == '+' || *curr == '-')) { + exp_sign = *curr; + curr++; + } else if (IS_DIGIT(*curr)) { /* Pass through. */ + } else { + // Empty E is not allowed. + goto fail; + } + + read = 0; + end_not_reached = (curr != s_end); + while (end_not_reached && IS_DIGIT(*curr)) { + // To avoid annoying MSVC's min/max macro definiton, + // Use hardcoded int max value + if (exponent > + (2147483647 / 10)) { // 2147483647 = std::numeric_limits::max() + // Integer overflow + goto fail; + } + exponent *= 10; + exponent += static_cast(*curr - 0x30); + curr++; + read++; + end_not_reached = (curr != s_end); + } + exponent *= (exp_sign == '+' ? 1 : -1); + if (read == 0) goto fail; + } + +assemble: + *result = (sign == '+' ? 1 : -1) * + (exponent ? std::ldexp(mantissa * std::pow(5.0, exponent), exponent) + : mantissa); + return true; +fail: + return false; +} + +static inline real_t parseReal(const char** token, double default_value = 0.0) { + (*token) += strspn((*token), " \t"); + const char* end = (*token) + strcspn((*token), " \t\r"); + double val = default_value; + tryParseDouble((*token), end, &val); + real_t f = static_cast(val); + (*token) = end; + return f; +} + +static inline bool parseReal(const char** token, real_t* out) { + (*token) += strspn((*token), " \t"); + const char* end = (*token) + strcspn((*token), " \t\r"); + double val; + bool ret = tryParseDouble((*token), end, &val); + if (ret) { + real_t f = static_cast(val); + (*out) = f; + } + (*token) = end; + return ret; +} + +static inline void parseReal2(real_t* x, real_t* y, const char** token, + const double default_x = 0.0, + const double default_y = 0.0) { + (*x) = parseReal(token, default_x); + (*y) = parseReal(token, default_y); +} + +static inline void parseReal3(real_t* x, real_t* y, real_t* z, + const char** token, const double default_x = 0.0, + const double default_y = 0.0, + const double default_z = 0.0) { + (*x) = parseReal(token, default_x); + (*y) = parseReal(token, default_y); + (*z) = parseReal(token, default_z); +} + +static inline void parseV(real_t* x, real_t* y, real_t* z, real_t* w, + const char** token, const double default_x = 0.0, + const double default_y = 0.0, + const double default_z = 0.0, + const double default_w = 1.0) { + (*x) = parseReal(token, default_x); + (*y) = parseReal(token, default_y); + (*z) = parseReal(token, default_z); + (*w) = parseReal(token, default_w); +} + +// Extension: parse vertex with colors(6 items) +static inline bool parseVertexWithColor(real_t* x, real_t* y, real_t* z, + real_t* r, real_t* g, real_t* b, + const char** token, + const double default_x = 0.0, + const double default_y = 0.0, + const double default_z = 0.0) { + (*x) = parseReal(token, default_x); + (*y) = parseReal(token, default_y); + (*z) = parseReal(token, default_z); + + const bool found_color = + parseReal(token, r) && parseReal(token, g) && parseReal(token, b); + + if (!found_color) { + (*r) = (*g) = (*b) = 1.0; + } + + return found_color; +} + +static inline bool parseOnOff(const char** token, bool default_value = true) { + (*token) += strspn((*token), " \t"); + const char* end = (*token) + strcspn((*token), " \t\r"); + + bool ret = default_value; + if ((0 == strncmp((*token), "on", 2))) { + ret = true; + } else if ((0 == strncmp((*token), "off", 3))) { + ret = false; + } + + (*token) = end; + return ret; +} + +static inline texture_type_t parseTextureType( + const char** token, texture_type_t default_value = TEXTURE_TYPE_NONE) { + (*token) += strspn((*token), " \t"); + const char* end = (*token) + strcspn((*token), " \t\r"); + texture_type_t ty = default_value; + + if ((0 == strncmp((*token), "cube_top", strlen("cube_top")))) { + ty = TEXTURE_TYPE_CUBE_TOP; + } else if ((0 == strncmp((*token), "cube_bottom", strlen("cube_bottom")))) { + ty = TEXTURE_TYPE_CUBE_BOTTOM; + } else if ((0 == strncmp((*token), "cube_left", strlen("cube_left")))) { + ty = TEXTURE_TYPE_CUBE_LEFT; + } else if ((0 == strncmp((*token), "cube_right", strlen("cube_right")))) { + ty = TEXTURE_TYPE_CUBE_RIGHT; + } else if ((0 == strncmp((*token), "cube_front", strlen("cube_front")))) { + ty = TEXTURE_TYPE_CUBE_FRONT; + } else if ((0 == strncmp((*token), "cube_back", strlen("cube_back")))) { + ty = TEXTURE_TYPE_CUBE_BACK; + } else if ((0 == strncmp((*token), "sphere", strlen("sphere")))) { + ty = TEXTURE_TYPE_SPHERE; + } + + (*token) = end; + return ty; +} + +static tag_sizes parseTagTriple(const char** token) { + tag_sizes ts; + + (*token) += strspn((*token), " \t"); + ts.num_ints = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return ts; + } + + (*token)++; // Skip '/' + + (*token) += strspn((*token), " \t"); + ts.num_reals = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return ts; + } + (*token)++; // Skip '/' + + ts.num_strings = parseInt(token); + + return ts; +} + +// Parse triples with index offsets: i, i/j/k, i//k, i/j +static bool parseTriple(const char** token, int vsize, int vnsize, int vtsize, + vertex_index_t* ret) { + if (!ret) { + return false; + } + + vertex_index_t vi(-1); + + if (!fixIndex(atoi((*token)), vsize, &(vi.v_idx))) { + return false; + } + + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + (*ret) = vi; + return true; + } + (*token)++; + + // i//k + if ((*token)[0] == '/') { + (*token)++; + if (!fixIndex(atoi((*token)), vnsize, &(vi.vn_idx))) { + return false; + } + (*token) += strcspn((*token), "/ \t\r"); + (*ret) = vi; + return true; + } + + // i/j/k or i/j + if (!fixIndex(atoi((*token)), vtsize, &(vi.vt_idx))) { + return false; + } + + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + (*ret) = vi; + return true; + } + + // i/j/k + (*token)++; // skip '/' + if (!fixIndex(atoi((*token)), vnsize, &(vi.vn_idx))) { + return false; + } + (*token) += strcspn((*token), "/ \t\r"); + + (*ret) = vi; + + return true; +} + +// Parse raw triples: i, i/j/k, i//k, i/j +static vertex_index_t parseRawTriple(const char** token) { + vertex_index_t vi(static_cast(0)); // 0 is an invalid index in OBJ + + vi.v_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return vi; + } + (*token)++; + + // i//k + if ((*token)[0] == '/') { + (*token)++; + vi.vn_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + return vi; + } + + // i/j/k or i/j + vi.vt_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { + return vi; + } + + // i/j/k + (*token)++; // skip '/' + vi.vn_idx = atoi((*token)); + (*token) += strcspn((*token), "/ \t\r"); + return vi; +} + +bool ParseTextureNameAndOption(std::string* texname, texture_option_t* texopt, + const char* linebuf) { + // @todo { write more robust lexer and parser. } + bool found_texname = false; + std::string texture_name; + + const char* token = linebuf; // Assume line ends with NULL + + while (!IS_NEW_LINE((*token))) { + token += strspn(token, " \t"); // skip space + if ((0 == strncmp(token, "-blendu", 7)) && IS_SPACE((token[7]))) { + token += 8; + texopt->blendu = parseOnOff(&token, /* default */ true); + } else if ((0 == strncmp(token, "-blendv", 7)) && IS_SPACE((token[7]))) { + token += 8; + texopt->blendv = parseOnOff(&token, /* default */ true); + } else if ((0 == strncmp(token, "-clamp", 6)) && IS_SPACE((token[6]))) { + token += 7; + texopt->clamp = parseOnOff(&token, /* default */ true); + } else if ((0 == strncmp(token, "-boost", 6)) && IS_SPACE((token[6]))) { + token += 7; + texopt->sharpness = parseReal(&token, 1.0); + } else if ((0 == strncmp(token, "-bm", 3)) && IS_SPACE((token[3]))) { + token += 4; + texopt->bump_multiplier = parseReal(&token, 1.0); + } else if ((0 == strncmp(token, "-o", 2)) && IS_SPACE((token[2]))) { + token += 3; + parseReal3(&(texopt->origin_offset[0]), &(texopt->origin_offset[1]), + &(texopt->origin_offset[2]), &token); + } else if ((0 == strncmp(token, "-s", 2)) && IS_SPACE((token[2]))) { + token += 3; + parseReal3(&(texopt->scale[0]), &(texopt->scale[1]), &(texopt->scale[2]), + &token, 1.0, 1.0, 1.0); + } else if ((0 == strncmp(token, "-t", 2)) && IS_SPACE((token[2]))) { + token += 3; + parseReal3(&(texopt->turbulence[0]), &(texopt->turbulence[1]), + &(texopt->turbulence[2]), &token); + } else if ((0 == strncmp(token, "-type", 5)) && IS_SPACE((token[5]))) { + token += 5; + texopt->type = parseTextureType((&token), TEXTURE_TYPE_NONE); + } else if ((0 == strncmp(token, "-texres", 7)) && IS_SPACE((token[7]))) { + token += 7; + // TODO(syoyo): Check if arg is int type. + texopt->texture_resolution = parseInt(&token); + } else if ((0 == strncmp(token, "-imfchan", 8)) && IS_SPACE((token[8]))) { + token += 9; + token += strspn(token, " \t"); + const char* end = token + strcspn(token, " \t\r"); + if ((end - token) == 1) { // Assume one char for -imfchan + texopt->imfchan = (*token); + } + token = end; + } else if ((0 == strncmp(token, "-mm", 3)) && IS_SPACE((token[3]))) { + token += 4; + parseReal2(&(texopt->brightness), &(texopt->contrast), &token, 0.0, 1.0); + } else if ((0 == strncmp(token, "-colorspace", 11)) && + IS_SPACE((token[11]))) { + token += 12; + texopt->colorspace = parseString(&token); + } else { +// Assume texture filename +#if 0 + size_t len = strcspn(token, " \t\r"); // untile next space + texture_name = std::string(token, token + len); + token += len; + + token += strspn(token, " \t"); // skip space +#else + // Read filename until line end to parse filename containing whitespace + // TODO(syoyo): Support parsing texture option flag after the filename. + texture_name = std::string(token); + token += texture_name.length(); +#endif + + found_texname = true; + } + } + + if (found_texname) { + (*texname) = texture_name; + return true; + } else { + return false; + } +} + +static void InitTexOpt(texture_option_t* texopt, const bool is_bump) { + if (is_bump) { + texopt->imfchan = 'l'; + } else { + texopt->imfchan = 'm'; + } + texopt->bump_multiplier = static_cast(1.0); + texopt->clamp = false; + texopt->blendu = true; + texopt->blendv = true; + texopt->sharpness = static_cast(1.0); + texopt->brightness = static_cast(0.0); + texopt->contrast = static_cast(1.0); + texopt->origin_offset[0] = static_cast(0.0); + texopt->origin_offset[1] = static_cast(0.0); + texopt->origin_offset[2] = static_cast(0.0); + texopt->scale[0] = static_cast(1.0); + texopt->scale[1] = static_cast(1.0); + texopt->scale[2] = static_cast(1.0); + texopt->turbulence[0] = static_cast(0.0); + texopt->turbulence[1] = static_cast(0.0); + texopt->turbulence[2] = static_cast(0.0); + texopt->texture_resolution = -1; + texopt->type = TEXTURE_TYPE_NONE; +} + +static void InitMaterial(material_t* material) { + InitTexOpt(&material->ambient_texopt, /* is_bump */ false); + InitTexOpt(&material->diffuse_texopt, /* is_bump */ false); + InitTexOpt(&material->specular_texopt, /* is_bump */ false); + InitTexOpt(&material->specular_highlight_texopt, /* is_bump */ false); + InitTexOpt(&material->bump_texopt, /* is_bump */ true); + InitTexOpt(&material->displacement_texopt, /* is_bump */ false); + InitTexOpt(&material->alpha_texopt, /* is_bump */ false); + InitTexOpt(&material->reflection_texopt, /* is_bump */ false); + InitTexOpt(&material->roughness_texopt, /* is_bump */ false); + InitTexOpt(&material->metallic_texopt, /* is_bump */ false); + InitTexOpt(&material->sheen_texopt, /* is_bump */ false); + InitTexOpt(&material->emissive_texopt, /* is_bump */ false); + InitTexOpt(&material->normal_texopt, + /* is_bump */ false); // @fixme { is_bump will be true? } + material->name = ""; + material->ambient_texname = ""; + material->diffuse_texname = ""; + material->specular_texname = ""; + material->specular_highlight_texname = ""; + material->bump_texname = ""; + material->displacement_texname = ""; + material->reflection_texname = ""; + material->alpha_texname = ""; + for (int i = 0; i < 3; i++) { + material->ambient[i] = static_cast(0.0); + material->diffuse[i] = static_cast(0.0); + material->specular[i] = static_cast(0.0); + material->transmittance[i] = static_cast(0.0); + material->emission[i] = static_cast(0.0); + } + material->illum = 0; + material->dissolve = static_cast(1.0); + material->shininess = static_cast(1.0); + material->ior = static_cast(1.0); + + material->roughness = static_cast(0.0); + material->metallic = static_cast(0.0); + material->sheen = static_cast(0.0); + material->clearcoat_thickness = static_cast(0.0); + material->clearcoat_roughness = static_cast(0.0); + material->anisotropy_rotation = static_cast(0.0); + material->anisotropy = static_cast(0.0); + material->roughness_texname = ""; + material->metallic_texname = ""; + material->sheen_texname = ""; + material->emissive_texname = ""; + material->normal_texname = ""; + + material->unknown_parameter.clear(); +} + +// code from https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html +template +static int pnpoly(int nvert, T* vertx, T* verty, T testx, T testy) { + int i, j, c = 0; + for (i = 0, j = nvert - 1; i < nvert; j = i++) { + if (((verty[i] > testy) != (verty[j] > testy)) && + (testx < + (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + + vertx[i])) + c = !c; + } + return c; +} + +// TODO(syoyo): refactor function. +static bool exportGroupsToShape(shape_t* shape, const PrimGroup& prim_group, + const std::vector& tags, + const int material_id, const std::string& name, + bool triangulate, const std::vector& v, + std::string* warn) { + if (prim_group.IsEmpty()) { + return false; + } + + shape->name = name; + + // polygon + if (!prim_group.faceGroup.empty()) { + // Flatten vertices and indices + for (size_t i = 0; i < prim_group.faceGroup.size(); i++) { + const face_t& face = prim_group.faceGroup[i]; + + size_t npolys = face.vertex_indices.size(); + + if (npolys < 3) { + // Face must have 3+ vertices. + if (warn) { + (*warn) += "Degenerated face found\n."; + } + continue; + } + + if (triangulate) { + if (npolys == 4) { + vertex_index_t i0 = face.vertex_indices[0]; + vertex_index_t i1 = face.vertex_indices[1]; + vertex_index_t i2 = face.vertex_indices[2]; + vertex_index_t i3 = face.vertex_indices[3]; + + size_t vi0 = size_t(i0.v_idx); + size_t vi1 = size_t(i1.v_idx); + size_t vi2 = size_t(i2.v_idx); + size_t vi3 = size_t(i3.v_idx); + + if (((3 * vi0 + 2) >= v.size()) || ((3 * vi1 + 2) >= v.size()) || + ((3 * vi2 + 2) >= v.size()) || ((3 * vi3 + 2) >= v.size())) { + // Invalid triangle. + // FIXME(syoyo): Is it ok to simply skip this invalid triangle? + if (warn) { + (*warn) += "Face with invalid vertex index found.\n"; + } + continue; + } + + real_t v0x = v[vi0 * 3 + 0]; + real_t v0y = v[vi0 * 3 + 1]; + real_t v0z = v[vi0 * 3 + 2]; + real_t v1x = v[vi1 * 3 + 0]; + real_t v1y = v[vi1 * 3 + 1]; + real_t v1z = v[vi1 * 3 + 2]; + real_t v2x = v[vi2 * 3 + 0]; + real_t v2y = v[vi2 * 3 + 1]; + real_t v2z = v[vi2 * 3 + 2]; + real_t v3x = v[vi3 * 3 + 0]; + real_t v3y = v[vi3 * 3 + 1]; + real_t v3z = v[vi3 * 3 + 2]; + + // There are two candidates to split the quad into two triangles. + // + // Choose the shortest edge. + // TODO: Is it better to determine the edge to split by calculating + // the area of each triangle? + // + // +---+ + // |\ | + // | \ | + // | \| + // +---+ + // + // +---+ + // | /| + // | / | + // |/ | + // +---+ + + real_t e02x = v2x - v0x; + real_t e02y = v2y - v0y; + real_t e02z = v2z - v0z; + real_t e13x = v3x - v1x; + real_t e13y = v3y - v1y; + real_t e13z = v3z - v1z; + + real_t sqr02 = e02x * e02x + e02y * e02y + e02z * e02z; + real_t sqr13 = e13x * e13x + e13y * e13y + e13z * e13z; + + index_t idx0, idx1, idx2, idx3; + + idx0.vertex_index = i0.v_idx; + idx0.normal_index = i0.vn_idx; + idx0.texcoord_index = i0.vt_idx; + idx1.vertex_index = i1.v_idx; + idx1.normal_index = i1.vn_idx; + idx1.texcoord_index = i1.vt_idx; + idx2.vertex_index = i2.v_idx; + idx2.normal_index = i2.vn_idx; + idx2.texcoord_index = i2.vt_idx; + idx3.vertex_index = i3.v_idx; + idx3.normal_index = i3.vn_idx; + idx3.texcoord_index = i3.vt_idx; + + if (sqr02 < sqr13) { + // [0, 1, 2], [0, 2, 3] + shape->mesh.indices.push_back(idx0); + shape->mesh.indices.push_back(idx1); + shape->mesh.indices.push_back(idx2); + + shape->mesh.indices.push_back(idx0); + shape->mesh.indices.push_back(idx2); + shape->mesh.indices.push_back(idx3); + } else { + // [0, 1, 3], [1, 2, 3] + shape->mesh.indices.push_back(idx0); + shape->mesh.indices.push_back(idx1); + shape->mesh.indices.push_back(idx3); + + shape->mesh.indices.push_back(idx1); + shape->mesh.indices.push_back(idx2); + shape->mesh.indices.push_back(idx3); + } + + // Two triangle faces + shape->mesh.num_face_vertices.push_back(3); + shape->mesh.num_face_vertices.push_back(3); + + shape->mesh.material_ids.push_back(material_id); + shape->mesh.material_ids.push_back(material_id); + + shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id); + shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id); + + } else { + vertex_index_t i0 = face.vertex_indices[0]; + vertex_index_t i1(-1); + vertex_index_t i2 = face.vertex_indices[1]; + + // find the two axes to work in + size_t axes[2] = {1, 2}; + for (size_t k = 0; k < npolys; ++k) { + i0 = face.vertex_indices[(k + 0) % npolys]; + i1 = face.vertex_indices[(k + 1) % npolys]; + i2 = face.vertex_indices[(k + 2) % npolys]; + size_t vi0 = size_t(i0.v_idx); + size_t vi1 = size_t(i1.v_idx); + size_t vi2 = size_t(i2.v_idx); + + if (((3 * vi0 + 2) >= v.size()) || ((3 * vi1 + 2) >= v.size()) || + ((3 * vi2 + 2) >= v.size())) { + // Invalid triangle. + // FIXME(syoyo): Is it ok to simply skip this invalid triangle? + continue; + } + real_t v0x = v[vi0 * 3 + 0]; + real_t v0y = v[vi0 * 3 + 1]; + real_t v0z = v[vi0 * 3 + 2]; + real_t v1x = v[vi1 * 3 + 0]; + real_t v1y = v[vi1 * 3 + 1]; + real_t v1z = v[vi1 * 3 + 2]; + real_t v2x = v[vi2 * 3 + 0]; + real_t v2y = v[vi2 * 3 + 1]; + real_t v2z = v[vi2 * 3 + 2]; + real_t e0x = v1x - v0x; + real_t e0y = v1y - v0y; + real_t e0z = v1z - v0z; + real_t e1x = v2x - v1x; + real_t e1y = v2y - v1y; + real_t e1z = v2z - v1z; + real_t cx = std::fabs(e0y * e1z - e0z * e1y); + real_t cy = std::fabs(e0z * e1x - e0x * e1z); + real_t cz = std::fabs(e0x * e1y - e0y * e1x); + const real_t epsilon = std::numeric_limits::epsilon(); + // std::cout << "cx " << cx << ", cy " << cy << ", cz " << cz << + // "\n"; + if (cx > epsilon || cy > epsilon || cz > epsilon) { + // std::cout << "corner\n"; + // found a corner + if (cx > cy && cx > cz) { + // std::cout << "pattern0\n"; + } else { + // std::cout << "axes[0] = 0\n"; + axes[0] = 0; + if (cz > cx && cz > cy) { + // std::cout << "axes[1] = 1\n"; + axes[1] = 1; + } + } + break; + } + } + +#ifdef TINYOBJLOADER_USE_MAPBOX_EARCUT + using Point = std::array; + + // first polyline define the main polygon. + // following polylines define holes(not used in tinyobj). + std::vector > polygon; + + std::vector polyline; + + // Fill polygon data(facevarying vertices). + for (size_t k = 0; k < npolys; k++) { + i0 = face.vertex_indices[k]; + size_t vi0 = size_t(i0.v_idx); + + assert(((3 * vi0 + 2) < v.size())); + + real_t v0x = v[vi0 * 3 + axes[0]]; + real_t v0y = v[vi0 * 3 + axes[1]]; + + polyline.push_back({v0x, v0y}); + } + + polygon.push_back(polyline); + std::vector indices = mapbox::earcut(polygon); + // => result = 3 * faces, clockwise + + assert(indices.size() % 3 == 0); + + // Reconstruct vertex_index_t + for (size_t k = 0; k < indices.size() / 3; k++) { + { + index_t idx0, idx1, idx2; + idx0.vertex_index = face.vertex_indices[indices[3 * k + 0]].v_idx; + idx0.normal_index = + face.vertex_indices[indices[3 * k + 0]].vn_idx; + idx0.texcoord_index = + face.vertex_indices[indices[3 * k + 0]].vt_idx; + idx1.vertex_index = face.vertex_indices[indices[3 * k + 1]].v_idx; + idx1.normal_index = + face.vertex_indices[indices[3 * k + 1]].vn_idx; + idx1.texcoord_index = + face.vertex_indices[indices[3 * k + 1]].vt_idx; + idx2.vertex_index = face.vertex_indices[indices[3 * k + 2]].v_idx; + idx2.normal_index = + face.vertex_indices[indices[3 * k + 2]].vn_idx; + idx2.texcoord_index = + face.vertex_indices[indices[3 * k + 2]].vt_idx; + + shape->mesh.indices.push_back(idx0); + shape->mesh.indices.push_back(idx1); + shape->mesh.indices.push_back(idx2); + + shape->mesh.num_face_vertices.push_back(3); + shape->mesh.material_ids.push_back(material_id); + shape->mesh.smoothing_group_ids.push_back( + face.smoothing_group_id); + } + } + +#else // Built-in ear clipping triangulation + + face_t remainingFace = face; // copy + size_t guess_vert = 0; + vertex_index_t ind[3]; + real_t vx[3]; + real_t vy[3]; + + // How many iterations can we do without decreasing the remaining + // vertices. + size_t remainingIterations = face.vertex_indices.size(); + size_t previousRemainingVertices = + remainingFace.vertex_indices.size(); + + while (remainingFace.vertex_indices.size() > 3 && + remainingIterations > 0) { + // std::cout << "remainingIterations " << remainingIterations << + // "\n"; + + npolys = remainingFace.vertex_indices.size(); + if (guess_vert >= npolys) { + guess_vert -= npolys; + } + + if (previousRemainingVertices != npolys) { + // The number of remaining vertices decreased. Reset counters. + previousRemainingVertices = npolys; + remainingIterations = npolys; + } else { + // We didn't consume a vertex on previous iteration, reduce the + // available iterations. + remainingIterations--; + } + + for (size_t k = 0; k < 3; k++) { + ind[k] = remainingFace.vertex_indices[(guess_vert + k) % npolys]; + size_t vi = size_t(ind[k].v_idx); + if (((vi * 3 + axes[0]) >= v.size()) || + ((vi * 3 + axes[1]) >= v.size())) { + // ??? + vx[k] = static_cast(0.0); + vy[k] = static_cast(0.0); + } else { + vx[k] = v[vi * 3 + axes[0]]; + vy[k] = v[vi * 3 + axes[1]]; + } + } + + // + // area is calculated per face + // + real_t e0x = vx[1] - vx[0]; + real_t e0y = vy[1] - vy[0]; + real_t e1x = vx[2] - vx[1]; + real_t e1y = vy[2] - vy[1]; + real_t cross = e0x * e1y - e0y * e1x; + // std::cout << "axes = " << axes[0] << ", " << axes[1] << "\n"; + // std::cout << "e0x, e0y, e1x, e1y " << e0x << ", " << e0y << ", " + // << e1x << ", " << e1y << "\n"; + + real_t area = + (vx[0] * vy[1] - vy[0] * vx[1]) * static_cast(0.5); + // std::cout << "cross " << cross << ", area " << area << "\n"; + // if an internal angle + if (cross * area < static_cast(0.0)) { + // std::cout << "internal \n"; + guess_vert += 1; + // std::cout << "guess vert : " << guess_vert << "\n"; + continue; + } + + // check all other verts in case they are inside this triangle + bool overlap = false; + for (size_t otherVert = 3; otherVert < npolys; ++otherVert) { + size_t idx = (guess_vert + otherVert) % npolys; + + if (idx >= remainingFace.vertex_indices.size()) { + // std::cout << "???0\n"; + // ??? + continue; + } + + size_t ovi = size_t(remainingFace.vertex_indices[idx].v_idx); + + if (((ovi * 3 + axes[0]) >= v.size()) || + ((ovi * 3 + axes[1]) >= v.size())) { + // std::cout << "???1\n"; + // ??? + continue; + } + real_t tx = v[ovi * 3 + axes[0]]; + real_t ty = v[ovi * 3 + axes[1]]; + if (pnpoly(3, vx, vy, tx, ty)) { + // std::cout << "overlap\n"; + overlap = true; + break; + } + } + + if (overlap) { + // std::cout << "overlap2\n"; + guess_vert += 1; + continue; + } + + // this triangle is an ear + { + index_t idx0, idx1, idx2; + idx0.vertex_index = ind[0].v_idx; + idx0.normal_index = ind[0].vn_idx; + idx0.texcoord_index = ind[0].vt_idx; + idx1.vertex_index = ind[1].v_idx; + idx1.normal_index = ind[1].vn_idx; + idx1.texcoord_index = ind[1].vt_idx; + idx2.vertex_index = ind[2].v_idx; + idx2.normal_index = ind[2].vn_idx; + idx2.texcoord_index = ind[2].vt_idx; + + shape->mesh.indices.push_back(idx0); + shape->mesh.indices.push_back(idx1); + shape->mesh.indices.push_back(idx2); + + shape->mesh.num_face_vertices.push_back(3); + shape->mesh.material_ids.push_back(material_id); + shape->mesh.smoothing_group_ids.push_back( + face.smoothing_group_id); + } + + // remove v1 from the list + size_t removed_vert_index = (guess_vert + 1) % npolys; + while (removed_vert_index + 1 < npolys) { + remainingFace.vertex_indices[removed_vert_index] = + remainingFace.vertex_indices[removed_vert_index + 1]; + removed_vert_index += 1; + } + remainingFace.vertex_indices.pop_back(); + } + + // std::cout << "remainingFace.vi.size = " << + // remainingFace.vertex_indices.size() << "\n"; + if (remainingFace.vertex_indices.size() == 3) { + i0 = remainingFace.vertex_indices[0]; + i1 = remainingFace.vertex_indices[1]; + i2 = remainingFace.vertex_indices[2]; + { + index_t idx0, idx1, idx2; + idx0.vertex_index = i0.v_idx; + idx0.normal_index = i0.vn_idx; + idx0.texcoord_index = i0.vt_idx; + idx1.vertex_index = i1.v_idx; + idx1.normal_index = i1.vn_idx; + idx1.texcoord_index = i1.vt_idx; + idx2.vertex_index = i2.v_idx; + idx2.normal_index = i2.vn_idx; + idx2.texcoord_index = i2.vt_idx; + + shape->mesh.indices.push_back(idx0); + shape->mesh.indices.push_back(idx1); + shape->mesh.indices.push_back(idx2); + + shape->mesh.num_face_vertices.push_back(3); + shape->mesh.material_ids.push_back(material_id); + shape->mesh.smoothing_group_ids.push_back( + face.smoothing_group_id); + } + } +#endif + } // npolys + } else { + for (size_t k = 0; k < npolys; k++) { + index_t idx; + idx.vertex_index = face.vertex_indices[k].v_idx; + idx.normal_index = face.vertex_indices[k].vn_idx; + idx.texcoord_index = face.vertex_indices[k].vt_idx; + shape->mesh.indices.push_back(idx); + } + + shape->mesh.num_face_vertices.push_back( + static_cast(npolys)); + shape->mesh.material_ids.push_back(material_id); // per face + shape->mesh.smoothing_group_ids.push_back( + face.smoothing_group_id); // per face + } + } + + shape->mesh.tags = tags; + } + + // line + if (!prim_group.lineGroup.empty()) { + // Flatten indices + for (size_t i = 0; i < prim_group.lineGroup.size(); i++) { + for (size_t j = 0; j < prim_group.lineGroup[i].vertex_indices.size(); + j++) { + const vertex_index_t& vi = prim_group.lineGroup[i].vertex_indices[j]; + + index_t idx; + idx.vertex_index = vi.v_idx; + idx.normal_index = vi.vn_idx; + idx.texcoord_index = vi.vt_idx; + + shape->lines.indices.push_back(idx); + } + + shape->lines.num_line_vertices.push_back( + int(prim_group.lineGroup[i].vertex_indices.size())); + } + } + + // points + if (!prim_group.pointsGroup.empty()) { + // Flatten & convert indices + for (size_t i = 0; i < prim_group.pointsGroup.size(); i++) { + for (size_t j = 0; j < prim_group.pointsGroup[i].vertex_indices.size(); + j++) { + const vertex_index_t& vi = prim_group.pointsGroup[i].vertex_indices[j]; + + index_t idx; + idx.vertex_index = vi.v_idx; + idx.normal_index = vi.vn_idx; + idx.texcoord_index = vi.vt_idx; + + shape->points.indices.push_back(idx); + } + } + } + + return true; +} + +// Split a string with specified delimiter character and escape character. +// https://rosettacode.org/wiki/Tokenize_a_string_with_escaping#C.2B.2B +static void SplitString(const std::string& s, char delim, char escape, + std::vector& elems) { + std::string token; + + bool escaping = false; + for (size_t i = 0; i < s.size(); ++i) { + char ch = s[i]; + if (escaping) { + escaping = false; + } else if (ch == escape) { + escaping = true; + continue; + } else if (ch == delim) { + if (!token.empty()) { + elems.push_back(token); + } + token.clear(); + continue; + } + token += ch; + } + + elems.push_back(token); +} + +static std::string JoinPath(const std::string& dir, + const std::string& filename) { + if (dir.empty()) { + return filename; + } else { + // check '/' + char lastChar = *dir.rbegin(); + if (lastChar != '/') { + return dir + std::string("/") + filename; + } else { + return dir + filename; + } + } +} + +void LoadMtl(std::map* material_map, + std::vector* materials, std::istream* inStream, + std::string* warning, std::string* err) { + (void)err; + + // Create a default material anyway. + material_t material; + InitMaterial(&material); + + // Issue 43. `d` wins against `Tr` since `Tr` is not in the MTL specification. + bool has_d = false; + bool has_tr = false; + + // has_kd is used to set a default diffuse value when map_Kd is present + // and Kd is not. + bool has_kd = false; + + std::stringstream warn_ss; + + size_t line_no = 0; + std::string linebuf; + while (inStream->peek() != -1) { + safeGetline(*inStream, linebuf); + line_no++; + + // Trim trailing whitespace. + if (linebuf.size() > 0) { + linebuf = linebuf.substr(0, linebuf.find_last_not_of(" \t") + 1); + } + + // Trim newline '\r\n' or '\n' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\n') + linebuf.erase(linebuf.size() - 1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\r') + linebuf.erase(linebuf.size() - 1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char* token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') continue; // empty line + + if (token[0] == '#') continue; // comment line + + // new mtl + if ((0 == strncmp(token, "newmtl", 6)) && IS_SPACE((token[6]))) { + // flush previous material. + if (!material.name.empty()) { + material_map->insert(std::pair( + material.name, static_cast(materials->size()))); + materials->push_back(material); + } + + // initial temporary material + InitMaterial(&material); + + has_d = false; + has_tr = false; + + // set new mtl name + token += 7; + { + std::stringstream sstr; + sstr << token; + material.name = sstr.str(); + } + continue; + } + + // ambient + if (token[0] == 'K' && token[1] == 'a' && IS_SPACE((token[2]))) { + token += 2; + real_t r, g, b; + parseReal3(&r, &g, &b, &token); + material.ambient[0] = r; + material.ambient[1] = g; + material.ambient[2] = b; + continue; + } + + // diffuse + if (token[0] == 'K' && token[1] == 'd' && IS_SPACE((token[2]))) { + token += 2; + real_t r, g, b; + parseReal3(&r, &g, &b, &token); + material.diffuse[0] = r; + material.diffuse[1] = g; + material.diffuse[2] = b; + has_kd = true; + continue; + } + + // specular + if (token[0] == 'K' && token[1] == 's' && IS_SPACE((token[2]))) { + token += 2; + real_t r, g, b; + parseReal3(&r, &g, &b, &token); + material.specular[0] = r; + material.specular[1] = g; + material.specular[2] = b; + continue; + } + + // transmittance + if ((token[0] == 'K' && token[1] == 't' && IS_SPACE((token[2]))) || + (token[0] == 'T' && token[1] == 'f' && IS_SPACE((token[2])))) { + token += 2; + real_t r, g, b; + parseReal3(&r, &g, &b, &token); + material.transmittance[0] = r; + material.transmittance[1] = g; + material.transmittance[2] = b; + continue; + } + + // ior(index of refraction) + if (token[0] == 'N' && token[1] == 'i' && IS_SPACE((token[2]))) { + token += 2; + material.ior = parseReal(&token); + continue; + } + + // emission + if (token[0] == 'K' && token[1] == 'e' && IS_SPACE(token[2])) { + token += 2; + real_t r, g, b; + parseReal3(&r, &g, &b, &token); + material.emission[0] = r; + material.emission[1] = g; + material.emission[2] = b; + continue; + } + + // shininess + if (token[0] == 'N' && token[1] == 's' && IS_SPACE(token[2])) { + token += 2; + material.shininess = parseReal(&token); + continue; + } + + // illum model + if (0 == strncmp(token, "illum", 5) && IS_SPACE(token[5])) { + token += 6; + material.illum = parseInt(&token); + continue; + } + + // dissolve + if ((token[0] == 'd' && IS_SPACE(token[1]))) { + token += 1; + material.dissolve = parseReal(&token); + + if (has_tr) { + warn_ss << "Both `d` and `Tr` parameters defined for \"" + << material.name + << "\". Use the value of `d` for dissolve (line " << line_no + << " in .mtl.)\n"; + } + has_d = true; + continue; + } + if (token[0] == 'T' && token[1] == 'r' && IS_SPACE(token[2])) { + token += 2; + if (has_d) { + // `d` wins. Ignore `Tr` value. + warn_ss << "Both `d` and `Tr` parameters defined for \"" + << material.name + << "\". Use the value of `d` for dissolve (line " << line_no + << " in .mtl.)\n"; + } else { + // We invert value of Tr(assume Tr is in range [0, 1]) + // NOTE: Interpretation of Tr is application(exporter) dependent. For + // some application(e.g. 3ds max obj exporter), Tr = d(Issue 43) + material.dissolve = static_cast(1.0) - parseReal(&token); + } + has_tr = true; + continue; + } + + // PBR: roughness + if (token[0] == 'P' && token[1] == 'r' && IS_SPACE(token[2])) { + token += 2; + material.roughness = parseReal(&token); + continue; + } + + // PBR: metallic + if (token[0] == 'P' && token[1] == 'm' && IS_SPACE(token[2])) { + token += 2; + material.metallic = parseReal(&token); + continue; + } + + // PBR: sheen + if (token[0] == 'P' && token[1] == 's' && IS_SPACE(token[2])) { + token += 2; + material.sheen = parseReal(&token); + continue; + } + + // PBR: clearcoat thickness + if (token[0] == 'P' && token[1] == 'c' && IS_SPACE(token[2])) { + token += 2; + material.clearcoat_thickness = parseReal(&token); + continue; + } + + // PBR: clearcoat roughness + if ((0 == strncmp(token, "Pcr", 3)) && IS_SPACE(token[3])) { + token += 4; + material.clearcoat_roughness = parseReal(&token); + continue; + } + + // PBR: anisotropy + if ((0 == strncmp(token, "aniso", 5)) && IS_SPACE(token[5])) { + token += 6; + material.anisotropy = parseReal(&token); + continue; + } + + // PBR: anisotropy rotation + if ((0 == strncmp(token, "anisor", 6)) && IS_SPACE(token[6])) { + token += 7; + material.anisotropy_rotation = parseReal(&token); + continue; + } + + // ambient texture + if ((0 == strncmp(token, "map_Ka", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.ambient_texname), + &(material.ambient_texopt), token); + continue; + } + + // diffuse texture + if ((0 == strncmp(token, "map_Kd", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.diffuse_texname), + &(material.diffuse_texopt), token); + + // Set a decent diffuse default value if a diffuse texture is specified + // without a matching Kd value. + if (!has_kd) { + material.diffuse[0] = static_cast(0.6); + material.diffuse[1] = static_cast(0.6); + material.diffuse[2] = static_cast(0.6); + } + + continue; + } + + // specular texture + if ((0 == strncmp(token, "map_Ks", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.specular_texname), + &(material.specular_texopt), token); + continue; + } + + // specular highlight texture + if ((0 == strncmp(token, "map_Ns", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.specular_highlight_texname), + &(material.specular_highlight_texopt), token); + continue; + } + + // bump texture + if ((0 == strncmp(token, "map_bump", 8)) && IS_SPACE(token[8])) { + token += 9; + ParseTextureNameAndOption(&(material.bump_texname), + &(material.bump_texopt), token); + continue; + } + + // bump texture + if ((0 == strncmp(token, "map_Bump", 8)) && IS_SPACE(token[8])) { + token += 9; + ParseTextureNameAndOption(&(material.bump_texname), + &(material.bump_texopt), token); + continue; + } + + // bump texture + if ((0 == strncmp(token, "bump", 4)) && IS_SPACE(token[4])) { + token += 5; + ParseTextureNameAndOption(&(material.bump_texname), + &(material.bump_texopt), token); + continue; + } + + // alpha texture + if ((0 == strncmp(token, "map_d", 5)) && IS_SPACE(token[5])) { + token += 6; + material.alpha_texname = token; + ParseTextureNameAndOption(&(material.alpha_texname), + &(material.alpha_texopt), token); + continue; + } + + // displacement texture + if ((0 == strncmp(token, "disp", 4)) && IS_SPACE(token[4])) { + token += 5; + ParseTextureNameAndOption(&(material.displacement_texname), + &(material.displacement_texopt), token); + continue; + } + + // reflection map + if ((0 == strncmp(token, "refl", 4)) && IS_SPACE(token[4])) { + token += 5; + ParseTextureNameAndOption(&(material.reflection_texname), + &(material.reflection_texopt), token); + continue; + } + + // PBR: roughness texture + if ((0 == strncmp(token, "map_Pr", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.roughness_texname), + &(material.roughness_texopt), token); + continue; + } + + // PBR: metallic texture + if ((0 == strncmp(token, "map_Pm", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.metallic_texname), + &(material.metallic_texopt), token); + continue; + } + + // PBR: sheen texture + if ((0 == strncmp(token, "map_Ps", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.sheen_texname), + &(material.sheen_texopt), token); + continue; + } + + // PBR: emissive texture + if ((0 == strncmp(token, "map_Ke", 6)) && IS_SPACE(token[6])) { + token += 7; + ParseTextureNameAndOption(&(material.emissive_texname), + &(material.emissive_texopt), token); + continue; + } + + // PBR: normal map texture + if ((0 == strncmp(token, "norm", 4)) && IS_SPACE(token[4])) { + token += 5; + ParseTextureNameAndOption(&(material.normal_texname), + &(material.normal_texopt), token); + continue; + } + + // unknown parameter + const char* _space = strchr(token, ' '); + if (!_space) { + _space = strchr(token, '\t'); + } + if (_space) { + std::ptrdiff_t len = _space - token; + std::string key(token, static_cast(len)); + std::string value = _space + 1; + material.unknown_parameter.insert( + std::pair(key, value)); + } + } + // flush last material. + material_map->insert(std::pair( + material.name, static_cast(materials->size()))); + materials->push_back(material); + + if (warning) { + (*warning) = warn_ss.str(); + } +} + +bool MaterialFileReader::operator()(const std::string& matId, + std::vector* materials, + std::map* matMap, + std::string* warn, std::string* err) { + if (!m_mtlBaseDir.empty()) { + // ---Tyra patch: + // #ifdef _WIN32 + char sep = ';'; + // #else + // char sep = ':'; + // #endif + // --- Tyra patch end + + // https://stackoverflow.com/questions/5167625/splitting-a-c-stdstring-using-tokens-e-g + std::vector paths; + std::istringstream f(m_mtlBaseDir); + + std::string s; + while (getline(f, s, sep)) { + paths.push_back(s); + } + + for (size_t i = 0; i < paths.size(); i++) { + std::string filepath = JoinPath(paths[i], matId); + + std::ifstream matIStream(filepath.c_str()); + if (matIStream) { + LoadMtl(matMap, materials, &matIStream, warn, err); + + return true; + } + } + + std::stringstream ss; + ss << "Material file [ " << matId + << " ] not found in a path : " << m_mtlBaseDir << "\n"; + if (warn) { + (*warn) += ss.str(); + } + return false; + + } else { + std::string filepath = matId; + std::ifstream matIStream(filepath.c_str()); + if (matIStream) { + LoadMtl(matMap, materials, &matIStream, warn, err); + + return true; + } + + std::stringstream ss; + ss << "Material file [ " << filepath + << " ] not found in a path : " << m_mtlBaseDir << "\n"; + if (warn) { + (*warn) += ss.str(); + } + + return false; + } +} + +bool MaterialStreamReader::operator()(const std::string& matId, + std::vector* materials, + std::map* matMap, + std::string* warn, std::string* err) { + (void)err; + (void)matId; + if (!m_inStream) { + std::stringstream ss; + ss << "Material stream in error state. \n"; + if (warn) { + (*warn) += ss.str(); + } + return false; + } + + LoadMtl(matMap, materials, &m_inStream, warn, err); + + return true; +} + +bool LoadObj(attrib_t* attrib, std::vector* shapes, + std::vector* materials, std::string* warn, + std::string* err, const char* filename, const char* mtl_basedir, + bool triangulate, bool default_vcols_fallback) { + attrib->vertices.clear(); + attrib->normals.clear(); + attrib->texcoords.clear(); + attrib->colors.clear(); + shapes->clear(); + + std::stringstream errss; + + std::ifstream ifs(filename); + if (!ifs) { + errss << "Cannot open file [" << filename << "]\n"; + if (err) { + (*err) = errss.str(); + } + return false; + } + + std::string baseDir = mtl_basedir ? mtl_basedir : ""; + if (!baseDir.empty()) { +#ifndef _WIN32 + const char dirsep = '/'; +#else + const char dirsep = '\\'; +#endif + if (baseDir[baseDir.length() - 1] != dirsep) baseDir += dirsep; + } + MaterialFileReader matFileReader(baseDir); + + return LoadObj(attrib, shapes, materials, warn, err, &ifs, &matFileReader, + triangulate, default_vcols_fallback); +} + +bool LoadObj(attrib_t* attrib, std::vector* shapes, + std::vector* materials, std::string* warn, + std::string* err, std::istream* inStream, + MaterialReader* readMatFn /*= NULL*/, bool triangulate, + bool default_vcols_fallback) { + std::stringstream errss; + + std::vector v; + std::vector vn; + std::vector vt; + std::vector vc; + std::vector vw; + std::vector tags; + PrimGroup prim_group; + std::string name; + + // material + std::set material_filenames; + std::map material_map; + int material = -1; + + // smoothing group id + unsigned int current_smoothing_id = + 0; // Initial value. 0 means no smoothing. + + int greatest_v_idx = -1; + int greatest_vn_idx = -1; + int greatest_vt_idx = -1; + + shape_t shape; + + bool found_all_colors = true; + + size_t line_num = 0; + std::string linebuf; + while (inStream->peek() != -1) { + safeGetline(*inStream, linebuf); + + line_num++; + + // Trim newline '\r\n' or '\n' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\n') + linebuf.erase(linebuf.size() - 1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\r') + linebuf.erase(linebuf.size() - 1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char* token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') continue; // empty line + + if (token[0] == '#') continue; // comment line + + // vertex + if (token[0] == 'v' && IS_SPACE((token[1]))) { + token += 2; + real_t x, y, z; + real_t r, g, b; + + found_all_colors &= parseVertexWithColor(&x, &y, &z, &r, &g, &b, &token); + + v.push_back(x); + v.push_back(y); + v.push_back(z); + + if (found_all_colors || default_vcols_fallback) { + vc.push_back(r); + vc.push_back(g); + vc.push_back(b); + } + + continue; + } + + // normal + if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) { + token += 3; + real_t x, y, z; + parseReal3(&x, &y, &z, &token); + vn.push_back(x); + vn.push_back(y); + vn.push_back(z); + continue; + } + + // texcoord + if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) { + token += 3; + real_t x, y; + parseReal2(&x, &y, &token); + vt.push_back(x); + vt.push_back(y); + continue; + } + + // skin weight. tinyobj extension + if (token[0] == 'v' && token[1] == 'w' && IS_SPACE((token[2]))) { + token += 3; + + // vw ... + // example: + // vw 0 0 0.25 1 0.25 2 0.5 + + // TODO(syoyo): Add syntax check + int vid = 0; + vid = parseInt(&token); + + skin_weight_t sw; + + sw.vertex_id = vid; + + while (!IS_NEW_LINE(token[0])) { + real_t j, w; + // joint_id should not be negative, weight may be negative + // TODO(syoyo): # of elements check + parseReal2(&j, &w, &token, -1.0); + + if (j < static_cast(0)) { + if (err) { + std::stringstream ss; + ss << "Failed parse `vw' line. joint_id is negative. " + "line " + << line_num << ".)\n"; + (*err) += ss.str(); + } + return false; + } + + joint_and_weight_t jw; + + jw.joint_id = int(j); + jw.weight = w; + + sw.weightValues.push_back(jw); + + size_t n = strspn(token, " \t\r"); + token += n; + } + + vw.push_back(sw); + } + + // line + if (token[0] == 'l' && IS_SPACE((token[1]))) { + token += 2; + + __line_t line; + + while (!IS_NEW_LINE(token[0])) { + vertex_index_t vi; + if (!parseTriple(&token, static_cast(v.size() / 3), + static_cast(vn.size() / 3), + static_cast(vt.size() / 2), &vi)) { + if (err) { + std::stringstream ss; + ss << "Failed parse `l' line(e.g. zero value for vertex index. " + "line " + << line_num << ".)\n"; + (*err) += ss.str(); + } + return false; + } + + line.vertex_indices.push_back(vi); + + size_t n = strspn(token, " \t\r"); + token += n; + } + + prim_group.lineGroup.push_back(line); + + continue; + } + + // points + if (token[0] == 'p' && IS_SPACE((token[1]))) { + token += 2; + + __points_t pts; + + while (!IS_NEW_LINE(token[0])) { + vertex_index_t vi; + if (!parseTriple(&token, static_cast(v.size() / 3), + static_cast(vn.size() / 3), + static_cast(vt.size() / 2), &vi)) { + if (err) { + std::stringstream ss; + ss << "Failed parse `p' line(e.g. zero value for vertex index. " + "line " + << line_num << ".)\n"; + (*err) += ss.str(); + } + return false; + } + + pts.vertex_indices.push_back(vi); + + size_t n = strspn(token, " \t\r"); + token += n; + } + + prim_group.pointsGroup.push_back(pts); + + continue; + } + + // face + if (token[0] == 'f' && IS_SPACE((token[1]))) { + token += 2; + token += strspn(token, " \t"); + + face_t face; + + face.smoothing_group_id = current_smoothing_id; + face.vertex_indices.reserve(3); + + while (!IS_NEW_LINE(token[0])) { + vertex_index_t vi; + if (!parseTriple(&token, static_cast(v.size() / 3), + static_cast(vn.size() / 3), + static_cast(vt.size() / 2), &vi)) { + if (err) { + std::stringstream ss; + ss << "Failed parse `f' line(e.g. zero value for face index. line " + << line_num << ".)\n"; + (*err) += ss.str(); + } + return false; + } + + greatest_v_idx = greatest_v_idx > vi.v_idx ? greatest_v_idx : vi.v_idx; + greatest_vn_idx = + greatest_vn_idx > vi.vn_idx ? greatest_vn_idx : vi.vn_idx; + greatest_vt_idx = + greatest_vt_idx > vi.vt_idx ? greatest_vt_idx : vi.vt_idx; + + face.vertex_indices.push_back(vi); + size_t n = strspn(token, " \t\r"); + token += n; + } + + // replace with emplace_back + std::move on C++11 + prim_group.faceGroup.push_back(face); + + continue; + } + + // use mtl + if ((0 == strncmp(token, "usemtl", 6))) { + token += 6; + std::string namebuf = parseString(&token); + + int newMaterialId = -1; + std::map::const_iterator it = + material_map.find(namebuf); + if (it != material_map.end()) { + newMaterialId = it->second; + } else { + // { error!! material not found } + if (warn) { + (*warn) += "material [ '" + namebuf + "' ] not found in .mtl\n"; + } + } + + if (newMaterialId != material) { + // Create per-face material. Thus we don't add `shape` to `shapes` at + // this time. + // just clear `faceGroup` after `exportGroupsToShape()` call. + exportGroupsToShape(&shape, prim_group, tags, material, name, + triangulate, v, warn); + prim_group.faceGroup.clear(); + material = newMaterialId; + } + + continue; + } + + // load mtl + if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) { + if (readMatFn) { + token += 7; + + std::vector filenames; + SplitString(std::string(token), ' ', '\\', filenames); + + if (filenames.empty()) { + if (warn) { + std::stringstream ss; + ss << "Looks like empty filename for mtllib. Use default " + "material (line " + << line_num << ".)\n"; + + (*warn) += ss.str(); + } + } else { + bool found = false; + for (size_t s = 0; s < filenames.size(); s++) { + if (material_filenames.count(filenames[s]) > 0) { + found = true; + continue; + } + + std::string warn_mtl; + std::string err_mtl; + bool ok = (*readMatFn)(filenames[s].c_str(), materials, + &material_map, &warn_mtl, &err_mtl); + if (warn && (!warn_mtl.empty())) { + (*warn) += warn_mtl; + } + + if (err && (!err_mtl.empty())) { + (*err) += err_mtl; + } + + if (ok) { + found = true; + material_filenames.insert(filenames[s]); + break; + } + } + + if (!found) { + if (warn) { + (*warn) += + "Failed to load material file(s). Use default " + "material.\n"; + } + } + } + } + + continue; + } + + // group name + if (token[0] == 'g' && IS_SPACE((token[1]))) { + // flush previous face group. + bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name, + triangulate, v, warn); + (void)ret; // return value not used. + + if (shape.mesh.indices.size() > 0) { + shapes->push_back(shape); + } + + shape = shape_t(); + + // material = -1; + prim_group.clear(); + + std::vector names; + + while (!IS_NEW_LINE(token[0])) { + std::string str = parseString(&token); + names.push_back(str); + token += strspn(token, " \t\r"); // skip tag + } + + // names[0] must be 'g' + + if (names.size() < 2) { + // 'g' with empty names + if (warn) { + std::stringstream ss; + ss << "Empty group name. line: " << line_num << "\n"; + (*warn) += ss.str(); + name = ""; + } + } else { + std::stringstream ss; + ss << names[1]; + + // tinyobjloader does not support multiple groups for a primitive. + // Currently we concatinate multiple group names with a space to get + // single group name. + + for (size_t i = 2; i < names.size(); i++) { + ss << " " << names[i]; + } + + name = ss.str(); + } + + continue; + } + + // object name + if (token[0] == 'o' && IS_SPACE((token[1]))) { + // flush previous face group. + bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name, + triangulate, v, warn); + (void)ret; // return value not used. + + if (shape.mesh.indices.size() > 0 || shape.lines.indices.size() > 0 || + shape.points.indices.size() > 0) { + shapes->push_back(shape); + } + + // material = -1; + prim_group.clear(); + shape = shape_t(); + + // @todo { multiple object name? } + token += 2; + std::stringstream ss; + ss << token; + name = ss.str(); + + continue; + } + + if (token[0] == 't' && IS_SPACE(token[1])) { + const int max_tag_nums = 8192; // FIXME(syoyo): Parameterize. + tag_t tag; + + token += 2; + + tag.name = parseString(&token); + + tag_sizes ts = parseTagTriple(&token); + + if (ts.num_ints < 0) { + ts.num_ints = 0; + } + if (ts.num_ints > max_tag_nums) { + ts.num_ints = max_tag_nums; + } + + if (ts.num_reals < 0) { + ts.num_reals = 0; + } + if (ts.num_reals > max_tag_nums) { + ts.num_reals = max_tag_nums; + } + + if (ts.num_strings < 0) { + ts.num_strings = 0; + } + if (ts.num_strings > max_tag_nums) { + ts.num_strings = max_tag_nums; + } + + tag.intValues.resize(static_cast(ts.num_ints)); + + for (size_t i = 0; i < static_cast(ts.num_ints); ++i) { + tag.intValues[i] = parseInt(&token); + } + + tag.floatValues.resize(static_cast(ts.num_reals)); + for (size_t i = 0; i < static_cast(ts.num_reals); ++i) { + tag.floatValues[i] = parseReal(&token); + } + + tag.stringValues.resize(static_cast(ts.num_strings)); + for (size_t i = 0; i < static_cast(ts.num_strings); ++i) { + tag.stringValues[i] = parseString(&token); + } + + tags.push_back(tag); + + continue; + } + + if (token[0] == 's' && IS_SPACE(token[1])) { + // smoothing group id + token += 2; + + // skip space. + token += strspn(token, " \t"); // skip space + + if (token[0] == '\0') { + continue; + } + + if (token[0] == '\r' || token[1] == '\n') { + continue; + } + + if (strlen(token) >= 3 && token[0] == 'o' && token[1] == 'f' && + token[2] == 'f') { + current_smoothing_id = 0; + } else { + // assume number + int smGroupId = parseInt(&token); + if (smGroupId < 0) { + // parse error. force set to 0. + // FIXME(syoyo): Report warning. + current_smoothing_id = 0; + } else { + current_smoothing_id = static_cast(smGroupId); + } + } + + continue; + } // smoothing group id + + // Ignore unknown command. + } + + // not all vertices have colors, no default colors desired? -> clear colors + if (!found_all_colors && !default_vcols_fallback) { + vc.clear(); + } + + if (greatest_v_idx >= static_cast(v.size() / 3)) { + if (warn) { + std::stringstream ss; + ss << "Vertex indices out of bounds (line " << line_num << ".)\n\n"; + (*warn) += ss.str(); + } + } + if (greatest_vn_idx >= static_cast(vn.size() / 3)) { + if (warn) { + std::stringstream ss; + ss << "Vertex normal indices out of bounds (line " << line_num + << ".)\n\n"; + (*warn) += ss.str(); + } + } + if (greatest_vt_idx >= static_cast(vt.size() / 2)) { + if (warn) { + std::stringstream ss; + ss << "Vertex texcoord indices out of bounds (line " << line_num + << ".)\n\n"; + (*warn) += ss.str(); + } + } + + bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name, + triangulate, v, warn); + // exportGroupsToShape return false when `usemtl` is called in the last + // line. + // we also add `shape` to `shapes` when `shape.mesh` has already some + // faces(indices) + if (ret || shape.mesh.indices + .size()) { // FIXME(syoyo): Support other prims(e.g. lines) + shapes->push_back(shape); + } + prim_group.clear(); // for safety + + if (err) { + (*err) += errss.str(); + } + + attrib->vertices.swap(v); + attrib->vertex_weights.swap(v); + attrib->normals.swap(vn); + attrib->texcoords.swap(vt); + attrib->texcoord_ws.swap(vt); + attrib->colors.swap(vc); + attrib->skin_weights.swap(vw); + + return true; +} + +bool LoadObjWithCallback(std::istream& inStream, const callback_t& callback, + void* user_data /*= NULL*/, + MaterialReader* readMatFn /*= NULL*/, + std::string* warn, /* = NULL*/ + std::string* err /*= NULL*/) { + std::stringstream errss; + + // material + std::set material_filenames; + std::map material_map; + int material_id = -1; // -1 = invalid + + std::vector indices; + std::vector materials; + std::vector names; + names.reserve(2); + std::vector names_out; + + std::string linebuf; + while (inStream.peek() != -1) { + safeGetline(inStream, linebuf); + + // Trim newline '\r\n' or '\n' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\n') + linebuf.erase(linebuf.size() - 1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size() - 1] == '\r') + linebuf.erase(linebuf.size() - 1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char* token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') continue; // empty line + + if (token[0] == '#') continue; // comment line + + // vertex + if (token[0] == 'v' && IS_SPACE((token[1]))) { + token += 2; + // TODO(syoyo): Support parsing vertex color extension. + real_t x, y, z, w; // w is optional. default = 1.0 + parseV(&x, &y, &z, &w, &token); + if (callback.vertex_cb) { + callback.vertex_cb(user_data, x, y, z, w); + } + continue; + } + + // normal + if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) { + token += 3; + real_t x, y, z; + parseReal3(&x, &y, &z, &token); + if (callback.normal_cb) { + callback.normal_cb(user_data, x, y, z); + } + continue; + } + + // texcoord + if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) { + token += 3; + real_t x, y, z; // y and z are optional. default = 0.0 + parseReal3(&x, &y, &z, &token); + if (callback.texcoord_cb) { + callback.texcoord_cb(user_data, x, y, z); + } + continue; + } + + // face + if (token[0] == 'f' && IS_SPACE((token[1]))) { + token += 2; + token += strspn(token, " \t"); + + indices.clear(); + while (!IS_NEW_LINE(token[0])) { + vertex_index_t vi = parseRawTriple(&token); + + index_t idx; + idx.vertex_index = vi.v_idx; + idx.normal_index = vi.vn_idx; + idx.texcoord_index = vi.vt_idx; + + indices.push_back(idx); + size_t n = strspn(token, " \t\r"); + token += n; + } + + if (callback.index_cb && indices.size() > 0) { + callback.index_cb(user_data, &indices.at(0), + static_cast(indices.size())); + } + + continue; + } + + // use mtl + if ((0 == strncmp(token, "usemtl", 6)) && IS_SPACE((token[6]))) { + token += 7; + std::stringstream ss; + ss << token; + std::string namebuf = ss.str(); + + int newMaterialId = -1; + std::map::const_iterator it = + material_map.find(namebuf); + if (it != material_map.end()) { + newMaterialId = it->second; + } else { + // { warn!! material not found } + if (warn && (!callback.usemtl_cb)) { + (*warn) += "material [ " + namebuf + " ] not found in .mtl\n"; + } + } + + if (newMaterialId != material_id) { + material_id = newMaterialId; + } + + if (callback.usemtl_cb) { + callback.usemtl_cb(user_data, namebuf.c_str(), material_id); + } + + continue; + } + + // load mtl + if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) { + if (readMatFn) { + token += 7; + + std::vector filenames; + SplitString(std::string(token), ' ', '\\', filenames); + + if (filenames.empty()) { + if (warn) { + (*warn) += + "Looks like empty filename for mtllib. Use default " + "material. \n"; + } + } else { + bool found = false; + for (size_t s = 0; s < filenames.size(); s++) { + if (material_filenames.count(filenames[s]) > 0) { + found = true; + continue; + } + + std::string warn_mtl; + std::string err_mtl; + bool ok = (*readMatFn)(filenames[s].c_str(), &materials, + &material_map, &warn_mtl, &err_mtl); + + if (warn && (!warn_mtl.empty())) { + (*warn) += warn_mtl; // This should be warn message. + } + + if (err && (!err_mtl.empty())) { + (*err) += err_mtl; + } + + if (ok) { + found = true; + material_filenames.insert(filenames[s]); + break; + } + } + + if (!found) { + if (warn) { + (*warn) += + "Failed to load material file(s). Use default " + "material.\n"; + } + } else { + if (callback.mtllib_cb) { + callback.mtllib_cb(user_data, &materials.at(0), + static_cast(materials.size())); + } + } + } + } + + continue; + } + + // group name + if (token[0] == 'g' && IS_SPACE((token[1]))) { + names.clear(); + + while (!IS_NEW_LINE(token[0])) { + std::string str = parseString(&token); + names.push_back(str); + token += strspn(token, " \t\r"); // skip tag + } + + assert(names.size() > 0); + + if (callback.group_cb) { + if (names.size() > 1) { + // create const char* array. + names_out.resize(names.size() - 1); + for (size_t j = 0; j < names_out.size(); j++) { + names_out[j] = names[j + 1].c_str(); + } + callback.group_cb(user_data, &names_out.at(0), + static_cast(names_out.size())); + + } else { + callback.group_cb(user_data, NULL, 0); + } + } + + continue; + } + + // object name + if (token[0] == 'o' && IS_SPACE((token[1]))) { + // @todo { multiple object name? } + token += 2; + + std::stringstream ss; + ss << token; + std::string object_name = ss.str(); + + if (callback.object_cb) { + callback.object_cb(user_data, object_name.c_str()); + } + + continue; + } + +#if 0 // @todo + if (token[0] == 't' && IS_SPACE(token[1])) { + tag_t tag; + + token += 2; + std::stringstream ss; + ss << token; + tag.name = ss.str(); + + token += tag.name.size() + 1; + + tag_sizes ts = parseTagTriple(&token); + + tag.intValues.resize(static_cast(ts.num_ints)); + + for (size_t i = 0; i < static_cast(ts.num_ints); ++i) { + tag.intValues[i] = atoi(token); + token += strcspn(token, "/ \t\r") + 1; + } + + tag.floatValues.resize(static_cast(ts.num_reals)); + for (size_t i = 0; i < static_cast(ts.num_reals); ++i) { + tag.floatValues[i] = parseReal(&token); + token += strcspn(token, "/ \t\r") + 1; + } + + tag.stringValues.resize(static_cast(ts.num_strings)); + for (size_t i = 0; i < static_cast(ts.num_strings); ++i) { + std::stringstream ss; + ss << token; + tag.stringValues[i] = ss.str(); + token += tag.stringValues[i].size() + 1; + } + + tags.push_back(tag); + } +#endif + + // Ignore unknown command. + } + + if (err) { + (*err) += errss.str(); + } + + return true; +} + +bool ObjReader::ParseFromFile(const std::string& filename, + const ObjReaderConfig& config) { + std::string mtl_search_path; + + if (config.mtl_search_path.empty()) { + // + // split at last '/'(for unixish system) or '\\'(for windows) to get + // the base directory of .obj file + // + size_t pos = filename.find_last_of("/\\"); + if (pos != std::string::npos) { + mtl_search_path = filename.substr(0, pos); + } + } else { + mtl_search_path = config.mtl_search_path; + } + + valid_ = LoadObj(&attrib_, &shapes_, &materials_, &warning_, &error_, + filename.c_str(), mtl_search_path.c_str(), + config.triangulate, config.vertex_color); + + return valid_; +} + +bool ObjReader::ParseFromString(const std::string& obj_text, + const std::string& mtl_text, + const ObjReaderConfig& config) { + std::stringbuf obj_buf(obj_text); + std::stringbuf mtl_buf(mtl_text); + + std::istream obj_ifs(&obj_buf); + std::istream mtl_ifs(&mtl_buf); + + MaterialStreamReader mtl_ss(mtl_ifs); + + valid_ = LoadObj(&attrib_, &shapes_, &materials_, &warning_, &error_, + &obj_ifs, &mtl_ss, config.triangulate, config.vertex_color); + + return valid_; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +} // namespace tinyobj + +#endif \ No newline at end of file diff --git a/engine/inc/loaders/loader.hpp b/engine/inc/loaders/loader.hpp new file mode 100644 index 0000000..5aac03b --- /dev/null +++ b/engine/inc/loaders/loader.hpp @@ -0,0 +1,25 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include + +namespace Tyra { + +class Loader { + protected: + static std::string getFilenameFromPath(const std::string& path); + static std::string getPathFromFilename(const std::string& path); + static std::string getFilenameWithoutExtension(const std::string& filename); + static std::string getExtensionOfFilename(const std::string& filename); +}; + +} // namespace Tyra diff --git a/engine/inc/loaders/texture/base/texture_loader.hpp b/engine/inc/loaders/texture/base/texture_loader.hpp new file mode 100644 index 0000000..bb52d4a --- /dev/null +++ b/engine/inc/loaders/texture/base/texture_loader.hpp @@ -0,0 +1,35 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "loaders/loader.hpp" +#include "loaders/texture/builder/texture_builder_data.hpp" +#include "renderer/core/texture/models/texture_bpp.hpp" +#include + +namespace Tyra { +class TextureLoader : public Loader { + public: + /** + * @brief Loads texture data from file. + * Sets size, name and data. + * @param fullpath Full path to texture file. Example: "host:texture.png" + */ + virtual TextureBuilderData* load(const char* fullpath) = 0; + + inline TextureBuilderData* load(const std::string& fullpath) { + return load(fullpath.c_str()); + } + + u32 getTextureSize(const u32& width, const u32& height, + const TextureBpp& bpp); +}; +} // namespace Tyra diff --git a/engine/inc/loaders/texture/base/texture_loader_selector.hpp b/engine/inc/loaders/texture/base/texture_loader_selector.hpp new file mode 100644 index 0000000..9fa82c5 --- /dev/null +++ b/engine/inc/loaders/texture/base/texture_loader_selector.hpp @@ -0,0 +1,34 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "loaders/texture/base/texture_loader.hpp" +#include "loaders/texture/png_loader.hpp" +#include + +namespace Tyra { +class TextureLoaderSelector { + public: + TextureLoaderSelector(); + ~TextureLoaderSelector(); + + TextureLoader& getLoaderByFileName(const char* fullpath); + + inline TextureLoader& getLoaderByFileName(const std::string& fullpath) { + return getLoaderByFileName(fullpath.c_str()); + } + + TextureLoader& getLoaderByExtension(const std::string& extension); + + private: + PngLoader pngLoader; +}; +} // namespace Tyra diff --git a/engine/inc/loaders/texture/builder/texture_builder_data.hpp b/engine/inc/loaders/texture/builder/texture_builder_data.hpp new file mode 100644 index 0000000..c6b515d --- /dev/null +++ b/engine/inc/loaders/texture/builder/texture_builder_data.hpp @@ -0,0 +1,36 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include "renderer/core/texture/models/texture_bpp.hpp" + +namespace Tyra { + +class TextureBuilderData { + public: + TextureBuilderData(); + ~TextureBuilderData(); + + std::string name; + + int width, height; + unsigned char* data; + TextureBpp bpp; + unsigned char gsComponents; + + int clutWidth, clutHeight; + unsigned char* clut; + TextureBpp clutBpp; + unsigned char clutGsComponents; +}; +} // namespace Tyra diff --git a/engine/inc/loaders/texture/png_loader.hpp b/engine/inc/loaders/texture/png_loader.hpp new file mode 100644 index 0000000..cdbf1ef --- /dev/null +++ b/engine/inc/loaders/texture/png_loader.hpp @@ -0,0 +1,68 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "loaders/texture/base/texture_loader.hpp" +#include "renderer/core/texture/models/texture.hpp" + +#ifdef INTELLISENSE +typedef void* png_structp; +typedef void* png_bytep; +typedef void* png_infop; +typedef void* png_colorp; +#else +#include +#endif + +namespace Tyra { + +struct PngPixel3 { + u8 r, g, b; +}; + +struct PngPixel4 { + u8 r, g, b, a; +}; + +class PngLoader : public TextureLoader { + public: + PngLoader(); + ~PngLoader(); + + inline TextureBuilderData* load(const std::string& fullpath) { + return load(fullpath.c_str()); + } + + TextureBuilderData* load(const char* fullpath); + + private: + void handle32bpp(TextureBuilderData* result, png_structp pngPtr, + png_infop infoPtr, png_bytep* rowPointers); + + void handle24bpp(TextureBuilderData* result, png_structp pngPtr, + png_infop infoPtr, png_bytep* rowPointers); + + void handlePalletized(TextureBuilderData* result, png_structp pngPtr, + png_infop infoPtr, png_bytep* rowPointers, + const int& bitDepth); + + void handle8bppPalletized(TextureBuilderData* result, png_structp pngPtr, + png_infop infoPtr, png_bytep* rowPointers, + png_colorp palette, png_bytep trans, + const int& numPallete, const int& numTrans); + + void handle4bppPalletized(TextureBuilderData* result, png_structp pngPtr, + png_infop infoPtr, png_bytep* rowPointers, + png_colorp palette, png_bytep trans, + const int& numPallete, const int& numTrans); +}; + +} // namespace Tyra diff --git a/engine/inc/math/m4x4.hpp b/engine/inc/math/m4x4.hpp new file mode 100644 index 0000000..207372c --- /dev/null +++ b/engine/inc/math/m4x4.hpp @@ -0,0 +1,116 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "math/vec4.hpp" +#include "math/math.hpp" +#include + +namespace Tyra { + +class M4x4 { + public: + MATRIX data alignas(sizeof(float) * 16); + + static const M4x4 Identity; + + /** Create matrix with random values */ + M4x4() {} + + M4x4(const M4x4& v) { copy(this, v); } + + explicit M4x4(const float* v) { copy(this, v); } + + M4x4(const float& m11, const float& m12, const float& m13, const float& m14, + const float& m21, const float& m22, const float& m23, const float& m24, + const float& m31, const float& m32, const float& m33, const float& m34, + const float& m41, const float& m42, const float& m43, const float& m44); + + static void copy(M4x4* out, const float* in); + static void copy(M4x4* out, const M4x4& in); + + void operator=(const M4x4& v); + Vec4 operator*(const Vec4& v) const; + M4x4 operator*(const M4x4& v) const; + void operator*=(const M4x4& v); + float& operator[](const u8& index); + + /** + * 1 0 0 0 + * 0 1 0 0 + * 0 0 1 0 + * 0 0 0 1 + */ + void identity(); + + inline void unit() { identity(); } + + void set(const float& m11, const float& m12, const float& m13, + const float& m14, const float& m21, const float& m22, + const float& m23, const float& m24, const float& m31, + const float& m32, const float& m33, const float& m34, + const float& m41, const float& m42, const float& m43, + const float& m44); + + void translate(const Vec4& v); + void translateX(const float& v); + void translateY(const float& v); + void translateZ(const float& v); + + void rotateByAngle(const float& angle, const Vec4& axis); + void rotate(const Vec4& v); + void rotateX(const float& radians); + void rotateY(const float& radians); + void rotateZ(const float& radians); + + void scale(const float& v); + void scale(const Vec4& v); + void scaleX(const float& v); + void scaleY(const float& v); + void scaleZ(const float& v); + + /** Create perspective projection M4x4 (gluPerspective) */ + static M4x4 perspective(const float& fov, const float& width, + const float& height, const float& projectionScale, + const float& aspectRatio, const float& near, + const float& far); + + /** + * Create a view M4x4 that transforms coordinates in + * such a way that the user looks at a target vector + * direction from a position vector (glLookAt) + */ + static M4x4 lookAt(const Vec4& position, const Vec4& target); + static void lookAt(M4x4* res, const Vec4& position, const Vec4& target); + + void print() const; + void print(const char* name) const; + void print(const std::string& name) const { print(name.c_str()); } + std::string getPrint(const char* name = nullptr) const; + + private: + static float upVec[4] alignas(sizeof(float) * 4); + static float viewVec[4] alignas(sizeof(float) * 4); + + static void cross(float res[16], const float a[16], const float b[16]); + void rotationX(const float& v); + void rotationY(const float& v); + void rotationZ(const float& v); + void rotationByAngle(const float& angle, const Vec4& axis); + void translationX(const float& v); + void translationY(const float& v); + void translationZ(const float& v); + void setScale(const Vec4& val); + static M4x4 setCamera(const float pos[4], const float vz[4], + const float vy[4]); +}; + +} // namespace Tyra diff --git a/engine/inc/math/math.hpp b/engine/inc/math/math.hpp new file mode 100644 index 0000000..2aa502a --- /dev/null +++ b/engine/inc/math/math.hpp @@ -0,0 +1,44 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +extern "C" { +#include +} + +#include + +namespace Tyra { + +class Math { + public: + constexpr static float HALF_ANG2RAD = 3.14159265358979323846F / 360.0F; + constexpr static float ANG2RAD = 3.14159265358979323846F / 180.0F; + constexpr static float PI = 3.1415926535897932384626433832795F; + constexpr static float HALF_PI = 1.5707963267948966192313216916398F; + static float cos(float x); + static float asin(float x); + static float atan2(float y, float x); + static float mod(const float& x, const float& y); + static float acos(const float& x); + static float sin(const float& x); + static float tan(const float& x); + static float invSqrt(const float& x); + static float randomf(const float& min, const float& max); + static int randomi(const int& min, const int& max); + static bool equalf(const float& a, const float& b, + const float& epsilon = 0.00001F); + + private: + Math(); +}; + +} // namespace Tyra diff --git a/engine/inc/math/plane.hpp b/engine/inc/math/plane.hpp new file mode 100644 index 0000000..826d685 --- /dev/null +++ b/engine/inc/math/plane.hpp @@ -0,0 +1,37 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "./vec4.hpp" +#include + +namespace Tyra { + +class Plane { + public: + Vec4 normal; + float distance; + + Plane(); + Plane(const Vec4& a, const Vec4& b, const Vec4& c); + ~Plane(); + + void update(const Vec4& a, const Vec4& b, const Vec4& c); + + float distanceTo(const Vec4& t_vec) const; + + void print() const; + void print(const char* name) const; + void print(const std::string& name) const { print(name.c_str()); } + std::string getPrint(const char* name = nullptr) const; +}; + +} // namespace Tyra diff --git a/engine/inc/math/vec2.hpp b/engine/inc/math/vec2.hpp new file mode 100644 index 0000000..ec34529 --- /dev/null +++ b/engine/inc/math/vec2.hpp @@ -0,0 +1,70 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +extern "C" { +#include +#include +} + +#include +#include "math/math.hpp" + +namespace Tyra { + +class Vec2 { + public: + union { + struct { + float x; + float y; + }; + float xy[2] alignas(sizeof(float) * 2); + }; + + Vec2(const float& t_x, const float& t_y); + Vec2(const Vec2& v); + Vec2(); + ~Vec2(); + + void operator=(const Vec2& v); + + Vec2 operator+(const Vec2& v) const; + Vec2 operator-(const Vec2& v) const; + Vec2 operator*(const Vec2& v) const; + Vec2 operator/(const Vec2& v) const; + + Vec2 operator+(const float& v) const; + Vec2 operator-(const float& v) const; + Vec2 operator*(const float& v) const; + Vec2 operator/(const float& v) const; + + void operator+=(const Vec2& v); + void operator-=(const Vec2& v); + void operator*=(const Vec2& v); + void operator/=(const Vec2& v); + + void operator+=(const float& v); + void operator-=(const float& v); + void operator*=(const float& v); + void operator/=(const float& v); + + void set(const float& t_x, const float& t_y); + void set(const Vec2& v); + void rotate(const float& t_angle, const float& t_x, const float& t_y); + + void print() const; + void print(const char* name) const; + void print(const std::string& name) const { print(name.c_str()); } + std::string getPrint(const char* name = nullptr) const; +}; + +} // namespace Tyra diff --git a/engine/inc/math/vec4.hpp b/engine/inc/math/vec4.hpp new file mode 100644 index 0000000..e0ebd52 --- /dev/null +++ b/engine/inc/math/vec4.hpp @@ -0,0 +1,161 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +extern "C" { +#include +#include +} + +#include +#include +#include "math/math.hpp" + +namespace Tyra { + +class Vec4 { + public: + union { + struct { + float x; + float y; + float z; + float w; + }; + VECTOR xyzw alignas(sizeof(float) * 4); + }; + + static void copy(Vec4* out, const float* in); + static inline void copy(Vec4* out, const Vec4& in) { copy(out, in.xyzw); } + + static const Vec4 Identity; + + /** Initialize Vec4 without setting default values */ + Vec4() {} + + /** Initialize Vec4 with provided values */ + Vec4(const float& x, const float& y = 0.0F, const float& z = 0.0F, + const float& w = 1.0F) + : x(x), y(y), z(z), w(w) {} + + /** Initialize Vec4 with other Vec4 values */ + Vec4(const Vec4& v) { copy(this, v); } + + /** Initialize Vec4 with float[4] values */ + explicit Vec4(const float* v) { copy(this, v); } + + /** copy */ + void operator=(const Vec4& v); + + /** negate xyz */ + Vec4 operator-(void) const; + + /** xyz + xyz */ + Vec4 operator+(const Vec4& v) const; + void operator+=(const Vec4& v); + + /** xyz - xyz */ + Vec4 operator-(const Vec4& v) const; + void operator-=(const Vec4& v); + + /** xyzw * xyzw */ + Vec4 operator*(const Vec4& v) const; + void operator*=(const Vec4& v); + + /** xyzw / xyzw */ + Vec4 operator/(const Vec4& v) const; + void operator/=(const Vec4& v); + + /** xyz * v */ + Vec4 operator*(const float& v) const; + void operator*=(const float& v); + + /** xyz / v */ + Vec4 operator/(const float& v) const; + void operator/=(const float& v); + + /** (0,0,0,1) */ + void unit(); + + inline void set(const Vec4& v) { copy(this, v.xyzw); } + inline void set(const float* v) { copy(this, v); } + void set(const float& x, const float& y = 0.0F, const float& z = 0.0F, + const float& w = 1.0F); + + Vec4 cross(const Vec4& v) const; + + void rotateZ(const int& angle); + + int getRelativeCosBetween(const Vec4& v) const; + int getRelativeAngleBetween(const Vec4& v) const; + + float innerProduct(const Vec4& v) const; + inline float dot3(const Vec4& v) const { return innerProduct(v); } + + /** Get vector length */ + float length() const; + + /** Normalize vector */ + void normalize(); + + Vec4 getNormalized() const; + + /** Returns distance between two vectors */ + float distanceTo(const Vec4& v) const; + + /** + * Checks intersection with given box + * @param min Opposite min vertex (ex. near, left, down vertex of bounding + * box) + * @param max Opposite max vertex (ex. far, right, up vertex of bounding + * box) + */ + bool collidesBox(const Vec4& min, const Vec4& max) const; + + /** + * Checks if this vector is on given box (this->y >= box.y) + * @param min Opposite min vertex (ex. near, left, down vertex of bounding + * box) + * @param max Opposite max vertex (ex. far, right, up vertex of bounding + * box) + */ + bool isOnBox(const Vec4& min, const Vec4& max) const; + + /** Check if given triangle should be backface culled */ + static u8 shouldBeBackfaceCulled(const Vec4* cameraPos, const Vec4* v0, + const Vec4* v1, const Vec4* v2); + + /** + * Update this vector by linear interpolation between two vertices + * @param v1 Before vertex + * @param v2 After vertex + * @param interp State of interpolation + */ + void lerp(const Vec4& v1, const Vec4& v2, const float& interp); + + /** + * Get vector by linear interpolation between two vertices + * @param v1 Before vertex + * @param v2 After vertex + * @param interp State of interpolation + */ + static Vec4 getByLerp(const Vec4& v1, const Vec4& v2, const float& interp); + + void print() const; + void print(const char* name) const; + void print(const std::string& name) const { print(name.c_str()); } + std::string getPrint(const char* name = nullptr) const; + + static void setLerp(Vec4* output, const Vec4& v1, const Vec4& v2, + const float& interp); +}; + +} // namespace Tyra diff --git a/engine/inc/packet2/packet2_tyra_utils.hpp b/engine/inc/packet2/packet2_tyra_utils.hpp new file mode 100644 index 0000000..0d3f504 --- /dev/null +++ b/engine/inc/packet2/packet2_tyra_utils.hpp @@ -0,0 +1,48 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "math/m4x4.hpp" +#include "renderer/models/color.hpp" + +namespace Tyra { + +class Packet2TyraUtils { + public: + inline static void addUnpackData(packet2_t* packet2, + const u32& t_dest_address, + const void* t_data, const u32& t_size, + const u8& t_use_top) { + packet2_chain_ref(packet2, t_data, t_size, 0, 0, 0); + packet2_vif_stcycl(packet2, 0, 0x0101, 0); + packet2_vif_open_unpack(packet2, P2_UNPACK_V4_32, t_dest_address, t_use_top, + 0, 1, 0); + packet2_vif_close_unpack_manual(packet2, t_size); + } + + inline static void addM4x4(packet2_t* packet2, const M4x4& val) { + *(reinterpret_cast(packet2->next)) = val; + packet2_advance_next(packet2, sizeof(MATRIX)); + } + + inline static void addVec4(packet2_t* packet2, const Vec4& val) { + *(reinterpret_cast(packet2->next)) = val; + packet2_advance_next(packet2, sizeof(VECTOR)); + } + + inline static void addColor(packet2_t* packet2, const Color& val) { + *(reinterpret_cast(packet2->next)) = val; + packet2_advance_next(packet2, sizeof(VECTOR)); + } +}; + +} // namespace Tyra diff --git a/engine/inc/pad/pad.hpp b/engine/inc/pad/pad.hpp new file mode 100644 index 0000000..196d636 --- /dev/null +++ b/engine/inc/pad/pad.hpp @@ -0,0 +1,58 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022-2022, tyra - https://github.com/h4570/tyrav2 +# Licensed under Apache License 2.0 +# Sandro Sobczyński +# Wellington Carvalho +*/ + +#include +#include + +#pragma once + +namespace Tyra { + +struct PadButtons { + u8 Cross, Square, Triangle, Circle, DpadUp, DpadDown, DpadLeft, DpadRight, L1, + L2, L3, R1, R2, R3, Start, Select; +}; + +struct PadJoy { + u8 h, v, isCentered, isMoved; +}; + +/** Class responsible for player pad */ +class Pad { + public: + Pad(); + ~Pad(); + + void init(); + void update(); + + inline const PadButtons& getClicked() const { return clicked; } + inline const PadButtons& getPressed() const { return pressed; } + inline const PadJoy& getLeftJoyPad() const { return leftJoyPad; } + inline const PadJoy& getRightJoyPad() const { return rightJoyPad; } + + private: + char padBuf[256] alignas(sizeof(char) * 256); + char actAlign[6]; + int actuators, ret, port, slot; + padButtonStatus buttons; + u32 padData, oldPad, newPad; + PadButtons pressed, clicked; + PadJoy leftJoyPad, rightJoyPad; + + void reset(); + void handleClickedButtons(); + void handlePressedButtons(); + int waitPadReady(); + int initPad(); +}; + +} // namespace Tyra \ No newline at end of file diff --git a/engine/inc/physics/ray.hpp b/engine/inc/physics/ray.hpp new file mode 100644 index 0000000..4ed667f --- /dev/null +++ b/engine/inc/physics/ray.hpp @@ -0,0 +1,63 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022-2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Wellington Carvalho +*/ + +#include "math/vec4.hpp" +#include + +#pragma once + +namespace Tyra { + +/** + * Class for raycasting. + */ +class Ray { + public: + /** @brief Constructor create a ampty ray */ + Ray(); + + /** + * @param origin The origin of the ray + * @param direction The direction of the ray (normalized Vec4) + */ + Ray(const Vec4& origin, const Vec4& direction); + ~Ray(); + + Vec4 origin; + Vec4 direction; + + /** + * @return Vec4 that is a given distance along this Ray + * @param t - the distance along the Ray to retrieve a position for. + */ + Vec4 at(const float& t) const; + + /** @return Distance from the Vec4 point to the origin */ + float distanceToPoint(const Vec4& point) const; + + /** + * @param minCorner - pointer to min corner position. (bottom left) + * @param maxCorner - pointer to max corner position. (top right) + * @param outputDistance - optional - distance the box to intersect with. + * @return Vec4 point of intersection + */ + bool intersectBox(const Vec4& minCorner, const Vec4& maxCorner, + float* outputDistance = nullptr) const; + + /** Returns inverse direction */ + Vec4 invDir() const; + + void print() const; + void print(const char* name) const; + void print(const std::string& name) const { print(name.c_str()); } + std::string getPrint(const char* name = nullptr) const; +}; + +} // namespace Tyra \ No newline at end of file diff --git a/engine/inc/renderer/2d/renderer_2d.hpp b/engine/inc/renderer/2d/renderer_2d.hpp new file mode 100644 index 0000000..83bafab --- /dev/null +++ b/engine/inc/renderer/2d/renderer_2d.hpp @@ -0,0 +1,31 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "renderer/core/2d/sprite/sprite.hpp" +#include "renderer/core/renderer_core.hpp" + +namespace Tyra { + +class Renderer2D { + public: + Renderer2D(); + ~Renderer2D(); + + void init(RendererCore* rendererCore); + void render(const Sprite* sprite); + void render(const Sprite& sprite); + + private: + RendererCore* core; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/bbox/bbox.hpp b/engine/inc/renderer/3d/bbox/bbox.hpp new file mode 100644 index 0000000..0cdeb3e --- /dev/null +++ b/engine/inc/renderer/3d/bbox/bbox.hpp @@ -0,0 +1,93 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "./bbox_face.hpp" +#include "renderer/core/3d/bbox/core_bbox.hpp" +#include "math/vec4.hpp" + +namespace Tyra { + +/** Bounding box with more features */ +class BBox : public CoreBBox { + public: + BBox(const BBox& t_bbox); + explicit BBox(CoreBBox** t_bboxes, const u32& count); + explicit BBox(const Vec4* t_vertices, const u32* faces, const u32& t_count); + explicit BBox(const Vec4* t_vertices, const u32& t_count); + explicit BBox(const BBox& t_bbox, const M4x4& t_matrix); + explicit BBox(const Vec4* t_vertices); + + static BBox create(const Vec4& center, const float& size); + + void operator=(const BBox& v); + + const float& getHeight() const { return _height; } + const float& getDepth() const { return _depth; } + const float& getWidth() const { return _width; } + + /** @returns the vector directly in middle of the bounding box. */ + const Vec4& getCenter() const { return _centerVector; } + + /** @returns the front face (further on z-axis) */ + const BBoxFace& getFrontFace() const { return _frontFace; } + + /** @returns the back face (nearer on z-axis) */ + const BBoxFace& getBackFace() const { return _backFace; } + + /** @returns the left face (further on x-axis) */ + const BBoxFace& getLeftFace() const { return _leftFace; } + + /** @returns the right face (nearer on x-axis) */ + const BBoxFace& getRightFace() const { return _rightFace; } + + /** @returns the top face (further on y-axis) */ + const BBoxFace& getTopFace() const { return _topFace; } + + /** @returns the bottom face (nearer on y-axis) */ + const BBoxFace& getBottomFace() const { return _bottomFace; } + + /** @returns the lower (x, y, z) boundary of the box. */ + Vec4 min() const; + /** @returns the upper (x, y, z) boundary of the box. */ + Vec4 max() const; + + /** + * @param res_min Vec4 to store the min result + * @param res_max Vec4 to store the min result + * @brief Calc and stores the min and max points of box at a single loop + * */ + void getMinMax(Vec4* res_min, Vec4* res_max) const; + + /** Get new transformed BBox by model matrix */ + BBox getTransformed(const M4x4& t_matrix) const; + + protected: + float _height, _depth, _width; + Vec4 _centerVector; + /** Front face (further on z-axis) */ + BBoxFace _frontFace; + /** Back face (nearer on z-axis) */ + BBoxFace _backFace; + /** Left face (nearer on x-axis) */ + BBoxFace _leftFace; + /** Right face (further on x-axis) */ + BBoxFace _rightFace; + /** Top face (further on y-axis) */ + BBoxFace _topFace; + /** Bottom face (nearer on y-axis) */ + BBoxFace _bottomFace; + + private: + void setData(); +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/bbox/bbox_face.hpp b/engine/inc/renderer/3d/bbox/bbox_face.hpp new file mode 100644 index 0000000..db80fcb --- /dev/null +++ b/engine/inc/renderer/3d/bbox/bbox_face.hpp @@ -0,0 +1,35 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "math/vec4.hpp" + +namespace Tyra { + +/** BBox face */ +class BBoxFace { + public: + BBoxFace() {} + BBoxFace(const Vec4& t_minCorner, const Vec4& t_maxCorner, float t_axisPos) { + minCorner = t_minCorner; + maxCorner = t_maxCorner; + axisPosition = t_axisPos; + } + + /** Position of the face on it's respective axis. */ + float axisPosition; + /** Corner of the face with lower coordinates */ + Vec4 minCorner; + /** Corner of the face with higher coordinates */ + Vec4 maxCorner; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/mesh/dynamic/animation_sequence_callback.hpp b/engine/inc/renderer/3d/mesh/dynamic/animation_sequence_callback.hpp new file mode 100644 index 0000000..25d0cb7 --- /dev/null +++ b/engine/inc/renderer/3d/mesh/dynamic/animation_sequence_callback.hpp @@ -0,0 +1,25 @@ + +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +namespace Tyra { + +enum AnimationSequenceCallback { + /** On frame change */ + AnimationSequenceCallback_NextFrame, + /** When animation in loop = false will end */ + AnimationSequenceCallback_End, + /** When animation in loop = true will start from beginning */ + AnimationSequenceCallback_Loop +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/mesh/dynamic/dynamic_mesh.hpp b/engine/inc/renderer/3d/mesh/dynamic/dynamic_mesh.hpp new file mode 100644 index 0000000..4fb994d --- /dev/null +++ b/engine/inc/renderer/3d/mesh/dynamic/dynamic_mesh.hpp @@ -0,0 +1,38 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "../mesh_frame.hpp" +#include "./dynamic_mesh_animation.hpp" +#include "../mesh.hpp" + +namespace Tyra { + +class DynamicMesh : public Mesh { + public: + explicit DynamicMesh(const MeshBuilderData* data); + DynamicMesh(const DynamicMesh& mesh); + ~DynamicMesh(); + + std::vector frames; + + DynamicMeshAnimation animation; + + /** @returns bounding box object of current frame. */ + const BBox& getCurrentBoundingBox() const { + return *frames[animation.getState().currentFrame]->bbox; + } + + /** Update animation */ + inline void update() { animation.update(); } +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/mesh/dynamic/dynamic_mesh_anim_state.hpp b/engine/inc/renderer/3d/mesh/dynamic/dynamic_mesh_anim_state.hpp new file mode 100644 index 0000000..6b528f9 --- /dev/null +++ b/engine/inc/renderer/3d/mesh/dynamic/dynamic_mesh_anim_state.hpp @@ -0,0 +1,24 @@ + +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include + +namespace Tyra { + +struct DynamicMeshAnimState { + float interpolation; + u32 currentFrame; + u32 nextFrame; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/mesh/dynamic/dynamic_mesh_animation.hpp b/engine/inc/renderer/3d/mesh/dynamic/dynamic_mesh_animation.hpp new file mode 100644 index 0000000..3e4016e --- /dev/null +++ b/engine/inc/renderer/3d/mesh/dynamic/dynamic_mesh_animation.hpp @@ -0,0 +1,72 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "./dynamic_mesh_anim_state.hpp" +#include "./animation_sequence_callback.hpp" +#include "../mesh_frame.hpp" +#include +#include + +namespace Tyra { + +class DynamicMeshAnimation { + public: + DynamicMeshAnimation(); + ~DynamicMeshAnimation(); + + bool loop; + float speed; + + /** + * Update animation. + * Should be called every frame if you want animation running. + */ + void update(); + + /** Set animation sequence (indices of frames) */ + void setSequence(const std::vector& sequence); + + /** Start animation from beginning */ + void restart(); + + /** + * @brief Set animation callback. + * It will push animation info on every update() call. + */ + void setCallback( + const std::function& callback); + + const DynamicMeshAnimState& getState() const; + + void resetAll(const std::vector& frames); + + private: + u32 framesCount; + u32 currentFrameSequenceIndex; + DynamicMeshAnimState state; + + std::function callback; + std::vector sequence; + + void updateLoopState(AnimationSequenceCallback* callbackInfo); + + /** + * @return true Frame changed + * @return false No changes + */ + bool updateNoLoopState(AnimationSequenceCallback* callbackInfo); + + u32 getNextSequenceIndexFrom(const u32& index) const; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/mesh/mesh.hpp b/engine/inc/renderer/3d/mesh/mesh.hpp new file mode 100644 index 0000000..afb293f --- /dev/null +++ b/engine/inc/renderer/3d/mesh/mesh.hpp @@ -0,0 +1,50 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "math/m4x4.hpp" +#include "./mesh_material.hpp" +#include +#include "debug/debug.hpp" + +namespace Tyra { + +class Mesh { + public: + explicit Mesh(const MeshBuilderData* data); + Mesh(const Mesh& mesh); + ~Mesh(); + + u8 isMother; + + u32 id; + + M4x4 translation, rotation, scale; + + /** nullptr if not found */ + MeshMaterial* getMaterialByName(const std::string& name); + + std::vector materials; + + M4x4 getModelMatrix() const; + + /** Get position from translation matrix */ + inline Vec4* getPosition() { + return reinterpret_cast(&translation.data[3 * 4]); + } + + void setPosition(const Vec4& v); + + protected: + void init(); +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/mesh/mesh_frame.hpp b/engine/inc/renderer/3d/mesh/mesh_frame.hpp new file mode 100644 index 0000000..7fdca9e --- /dev/null +++ b/engine/inc/renderer/3d/mesh/mesh_frame.hpp @@ -0,0 +1,37 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "./mesh_material.hpp" +#include "loaders/3d/builder/mesh_builder_data.hpp" +#include "renderer/3d/bbox/bbox.hpp" + +namespace Tyra { + +class MeshFrame { + public: + explicit MeshFrame(const MeshBuilderData& data, const u32& index); + explicit MeshFrame(const MeshFrame& frame); + ~MeshFrame(); + + u8 isMother; + + u32 id; + + BBox* bbox; + + void print() const; + void print(const char* name) const; + void print(const std::string& name) const { print(name.c_str()); } + std::string getPrint(const char* name = nullptr) const; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/mesh/mesh_material.hpp b/engine/inc/renderer/3d/mesh/mesh_material.hpp new file mode 100644 index 0000000..2d8b5e8 --- /dev/null +++ b/engine/inc/renderer/3d/mesh/mesh_material.hpp @@ -0,0 +1,43 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "debug/debug.hpp" +#include "./mesh_material_frame.hpp" +#include "loaders/3d/builder/mesh_builder_data.hpp" + +namespace Tyra { + +class MeshMaterial { + public: + explicit MeshMaterial(const MeshBuilderData& data, const u32& materialIndex); + explicit MeshMaterial(const MeshMaterial& material); + ~MeshMaterial(); + + bool isMother, lightmapFlag; + + u32 id; + + std::string name; + + Color ambient; + + std::vector frames; + + const BBox& getBBox(const u32& frame) const; + + void print() const; + void print(const char* name) const; + void print(const std::string& name) const { print(name.c_str()); } + std::string getPrint(const char* name = nullptr) const; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/mesh/mesh_material_frame.hpp b/engine/inc/renderer/3d/mesh/mesh_material_frame.hpp new file mode 100644 index 0000000..2aaf0f1 --- /dev/null +++ b/engine/inc/renderer/3d/mesh/mesh_material_frame.hpp @@ -0,0 +1,41 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "loaders/3d/builder/mesh_builder_data.hpp" +#include "./renderer/3d/bbox/bbox.hpp" + +namespace Tyra { + +class MeshMaterialFrame { + public: + explicit MeshMaterialFrame(const MeshBuilderData& data, const u32& frameIndex, + const u32& materialIndex); + explicit MeshMaterialFrame(const MeshMaterialFrame& frame); + ~MeshMaterialFrame(); + + u8 isMother; + + u32 id, count; + + Vec4 *vertices, *textureCoords, *normals; + + Color* colors; + + BBox* bbox; + + void print() const; + void print(const char* name) const; + void print(const std::string& name) const { print(name.c_str()); } + std::string getPrint(const char* name = nullptr) const; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/mesh/static/static_mesh.hpp b/engine/inc/renderer/3d/mesh/static/static_mesh.hpp new file mode 100644 index 0000000..d991f29 --- /dev/null +++ b/engine/inc/renderer/3d/mesh/static/static_mesh.hpp @@ -0,0 +1,28 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "../mesh.hpp" +#include "../mesh_frame.hpp" +#include "../mesh_material.hpp" + +namespace Tyra { + +class StaticMesh : public Mesh { + public: + explicit StaticMesh(const MeshBuilderData* data); + StaticMesh(const StaticMesh& mesh); + ~StaticMesh(); + + MeshFrame* frame; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/dynamic/core/bag/dynpip_bag.hpp b/engine/inc/renderer/3d/pipeline/dynamic/core/bag/dynpip_bag.hpp new file mode 100644 index 0000000..c4fcfe9 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/dynamic/core/bag/dynpip_bag.hpp @@ -0,0 +1,67 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "math/vec4.hpp" + +#include "./dynpip_info_bag.hpp" +#include "./dynpip_color_bag.hpp" +#include "./dynpip_lighting_bag.hpp" +#include "./dynpip_texture_bag.hpp" +#include "renderer/core/texture/models/texture.hpp" + +namespace Tyra { + +/** + * @brief 3D Animated render data bag. + * Supports frustum culling, simple clipping (culling), lighting, + * texture and single color / many colors. + */ +class DynPipBag { + public: + DynPipBag(); + ~DynPipBag(); + + /** Mandatory. Object info. */ + DynPipInfoBag* info; + + /** Mandatory. Object color(s). */ + DynPipColorBag* color; + + /** Mandatory. Vertex count per frame. */ + u32 count; + + /** Mandatory. From (frame) vertices */ + Vec4* verticesFrom; + + /** Mandatory. To (frame) vertices */ + Vec4* verticesTo; + + /** + * Mandatory. + * State of animation interpolation + * (between from and to) + */ + float interpolation; + + /** Optional. Texture coordinates and image. */ + DynPipTextureBag* texture; + + /** Optional. Object lighting. */ + DynPipLightingBag* lighting; + + void print() const; + void print(const char* name) const; + void print(const std::string& name) const { print(name.c_str()); } + std::string getPrint(const char* name = nullptr) const; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/dynamic/core/bag/dynpip_color_bag.hpp b/engine/inc/renderer/3d/pipeline/dynamic/core/bag/dynpip_color_bag.hpp new file mode 100644 index 0000000..2e58e93 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/dynamic/core/bag/dynpip_color_bag.hpp @@ -0,0 +1,29 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "renderer/models/color.hpp" + +namespace Tyra { + +/** + * @brief Color data. At least one color data is required (single/many). + */ +class DynPipColorBag { + public: + DynPipColorBag(); + ~DynPipColorBag(); + + /** Mandatory */ + const Color* single; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/dynamic/core/bag/dynpip_info_bag.hpp b/engine/inc/renderer/3d/pipeline/dynamic/core/bag/dynpip_info_bag.hpp new file mode 100644 index 0000000..acc0e26 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/dynamic/core/bag/dynpip_info_bag.hpp @@ -0,0 +1,23 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "renderer/3d/pipeline/shared/bag/pipeline_info_bag.hpp" + +namespace Tyra { + +class DynPipInfoBag : public PipelineInfoBag { + public: + DynPipInfoBag() {} + ~DynPipInfoBag() {} +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/dynamic/core/bag/dynpip_lighting_bag.hpp b/engine/inc/renderer/3d/pipeline/dynamic/core/bag/dynpip_lighting_bag.hpp new file mode 100644 index 0000000..0d84d39 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/dynamic/core/bag/dynpip_lighting_bag.hpp @@ -0,0 +1,36 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "math/vec4.hpp" +#include "renderer/3d/pipeline/shared/bag/pipeline_dir_lights_bag.hpp" + +namespace Tyra { + +class DynPipLightingBag { + public: + DynPipLightingBag(); + ~DynPipLightingBag(); + + /** Mandatory. Model matrix for lights. */ + M4x4* lightMatrix; + + /** Mandatory. Lighting normals per vertex. */ + Vec4* normalsFrom; + Vec4* normalsTo; + + /** Mandatory. Directional lights */ + PipelineDirLightsBag* dirLights; + + void freeNormals(); +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/dynamic/core/bag/dynpip_texture_bag.hpp b/engine/inc/renderer/3d/pipeline/dynamic/core/bag/dynpip_texture_bag.hpp new file mode 100644 index 0000000..18142aa --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/dynamic/core/bag/dynpip_texture_bag.hpp @@ -0,0 +1,33 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "math/vec4.hpp" +#include "renderer/core/texture/models/texture.hpp" + +namespace Tyra { + +class DynPipTextureBag { + public: + DynPipTextureBag(); + ~DynPipTextureBag(); + + /** Mandatory. Texture coordinates per vertex. */ + Vec4* coordinatesFrom; + Vec4* coordinatesTo; + + /** Mandatory. Texture image. */ + Texture* texture; + + void freeCoords(); +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/dynamic/core/dynpip_core.hpp b/engine/inc/renderer/3d/pipeline/dynamic/core/dynpip_core.hpp new file mode 100644 index 0000000..674376d --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/dynamic/core/dynpip_core.hpp @@ -0,0 +1,71 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "./bag/dynpip_bag.hpp" +#include "renderer/core/renderer_core.hpp" +#include "./dynpip_programs_repository.hpp" +#include "./dynpip_renderer.hpp" + +namespace Tyra { + +class DynPipCore { + public: + DynPipCore(); + ~DynPipCore(); + + DynPipProgramsRepository repository; + + void init(RendererCore* t_core); + + /** Force starting VU1 program instead of continueing */ + void begin(PipelineInfoBag* bag); + + /** + * Send model matrix, lighting data and other + * repetitve stuff to VU1 + */ + void sendObjectDataToVU1(DynPipBag* data); + + /** Render 3D via "bags" */ + void render(DynPipBag** bags, const u32& count); + + /** Get max vert count of VU1 qbuffer (for optimizations) */ + u32 getMaxVertCountByParams(const bool& isLightingEnabled, + const bool& isTextureEnabled); + + /** + * - Uploads standard VU1 programs. + * - Sends static "Tyra Renderer3D" VU1 data. + * - Sets double buffers exactly for "Tyra Renderer3D" + * Should be called if VU1 was used by your non standard programs. + */ + void reinitVU1Programs(); + + void allocateOnUse(const u32& t_packetSize) { + qbufferRenderer.allocateOnUse(t_packetSize); + } + void deallocateOnUse() { qbufferRenderer.deallocateOnUse(); } + + private: + void setPrim(); + void setLod(); + + prim_t prim; + lod_t lod; + + M4x4 mvp; + RendererCore* rendererCore; + DynPipRenderer qbufferRenderer; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/dynamic/core/dynpip_program_name.hpp b/engine/inc/renderer/3d/pipeline/dynamic/core/dynpip_program_name.hpp new file mode 100644 index 0000000..a620187 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/dynamic/core/dynpip_program_name.hpp @@ -0,0 +1,24 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +namespace Tyra { + +enum DynPipProgramName { + DynPipUndefinedProgram, + + DynPipColor, + DynPipDirLights, + DynPipTextureDirLights, + DynPipTextureColor, +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/dynamic/core/dynpip_programs_repository.hpp b/engine/inc/renderer/3d/pipeline/dynamic/core/dynpip_programs_repository.hpp new file mode 100644 index 0000000..048a039 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/dynamic/core/dynpip_programs_repository.hpp @@ -0,0 +1,41 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "debug/debug.hpp" +#include "renderer/core/paths/path1/vu1_program.hpp" +#include "./bag/dynpip_bag.hpp" + +#include "./programs/dynpip_c_vu1_program.hpp" +#include "./programs/dynpip_d_vu1_program.hpp" +#include "./programs/dynpip_td_vu1_program.hpp" +#include "./programs/dynpip_tc_vu1_program.hpp" + +namespace Tyra { + +class DynPipProgramsRepository { + public: + DynPipProgramsRepository(); + ~DynPipProgramsRepository(); + + DynPipVU1Program* getProgram(const DynPipProgramName& name); + DynPipVU1Program* getProgramByParams(const bool& isLightingEnabled, + const bool& isTextureEnabled); + DynPipVU1Program* getProgramByBag(const DynPipBag* bag); + + private: + DynPipCVU1Program color; + DynPipDVU1Program dirLights; + DynPipTDVU1Program textureDirLights; + DynPipTCVU1Program textureColor; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/dynamic/core/dynpip_renderer.hpp b/engine/inc/renderer/3d/pipeline/dynamic/core/dynpip_renderer.hpp new file mode 100644 index 0000000..31a8fc7 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/dynamic/core/dynpip_renderer.hpp @@ -0,0 +1,71 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "renderer/core/renderer_core.hpp" +#include "./dynpip_programs_repository.hpp" + +namespace Tyra { + +class DynPipRenderer { + public: + DynPipRenderer(); + ~DynPipRenderer(); + + void init(RendererCore* t_core, DynPipProgramsRepository* t_programRepo, + prim_t* prim, lod_t* lod); + + void reinitVU1(); + + void sendObjectData(DynPipBag* bag, M4x4* mvp, + RendererCoreTextureBuffers* texBuffers) const; + + void render(DynPipBag** bags, const u32& count); + + void clearLastProgramName(); + + const u16& getBufferSize() { return bufferSize; } + + void allocateOnUse(const u32& t_packetSize); + void deallocateOnUse(); + + private: + void sendStaticData() const; + void setProgramsCache(); + void uploadPrograms(); + void setDoubleBuffer(); + + void addBufferDataToPacket(DynPipVU1Program* program, DynPipBag** bags, + const u32& count); + void sendPacket(); + + prim_t* prim; + lod_t* lod; + u16 packetSize; + + packet2_t* packets[2]; + packet2_t* programsPacket; + packet2_t* currentPacket; + packet2_t* staticDataPacket; + packet2_t* objectDataPacket; + + DynPipProgramsRepository* programsRepo; + RendererCore* rendererCore; + Path1* path1; + + DynPipProgramName lastProgramName; + + u16 bufferSize; + u8 context; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/dynamic/core/dynpip_vu1_program.hpp b/engine/inc/renderer/3d/pipeline/dynamic/core/dynpip_vu1_program.hpp new file mode 100644 index 0000000..b687d3e --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/dynamic/core/dynpip_vu1_program.hpp @@ -0,0 +1,48 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "./dynpip_program_name.hpp" +#include "renderer/core/paths/path1/vu1_program.hpp" +#include "./programs/dynpip_vu1_shared_defines.h" +#include "./bag/dynpip_bag.hpp" + +namespace Tyra { + +class DynPipVU1Program : public VU1Program { + public: + DynPipVU1Program(const DynPipProgramName& name, u32* start, u32* end, + const u32& t_reglist, const u8& t_reglistCount, + const u8& t_elementsPerVertex); + ~DynPipVU1Program(); + + u32& getReglist(); + + const DynPipProgramName& getName() const; + + u16 getMaxVertCount(const u16& vu1DBufferSize) const; + + void addBufferDataToPacket(packet2_t* packet, DynPipBag* bag, prim_t* prim); + + protected: + DynPipProgramName name; + u8 reglistCount, elementsPerVertex; + u32 destinationAddress, reglist; + + virtual void addProgramQBufferDataToPacket(packet2_t* packet, + DynPipBag* bag) const = 0; + + private: + void addStandardBufferDataToPacket(packet2_t* packet, DynPipBag* bag, + prim_t* prim); +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/dynamic/core/programs/dynpip_c_vu1_program.hpp b/engine/inc/renderer/3d/pipeline/dynamic/core/programs/dynpip_c_vu1_program.hpp new file mode 100644 index 0000000..d99778c --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/dynamic/core/programs/dynpip_c_vu1_program.hpp @@ -0,0 +1,28 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include "../dynpip_vu1_program.hpp" + +namespace Tyra { + +class DynPipCVU1Program : public DynPipVU1Program { + public: + DynPipCVU1Program(); + ~DynPipCVU1Program(); + + std::string getStringName() const; + void addProgramQBufferDataToPacket(packet2_t* packet, DynPipBag* bag) const; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/dynamic/core/programs/dynpip_d_vu1_program.hpp b/engine/inc/renderer/3d/pipeline/dynamic/core/programs/dynpip_d_vu1_program.hpp new file mode 100644 index 0000000..f153d79 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/dynamic/core/programs/dynpip_d_vu1_program.hpp @@ -0,0 +1,28 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include "../dynpip_vu1_program.hpp" + +namespace Tyra { + +class DynPipDVU1Program : public DynPipVU1Program { + public: + DynPipDVU1Program(); + ~DynPipDVU1Program(); + + std::string getStringName() const; + void addProgramQBufferDataToPacket(packet2_t* packet, DynPipBag* bag) const; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/dynamic/core/programs/dynpip_tc_vu1_program.hpp b/engine/inc/renderer/3d/pipeline/dynamic/core/programs/dynpip_tc_vu1_program.hpp new file mode 100644 index 0000000..4b2e22f --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/dynamic/core/programs/dynpip_tc_vu1_program.hpp @@ -0,0 +1,28 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include "../dynpip_vu1_program.hpp" + +namespace Tyra { + +class DynPipTCVU1Program : public DynPipVU1Program { + public: + DynPipTCVU1Program(); + ~DynPipTCVU1Program(); + + std::string getStringName() const; + void addProgramQBufferDataToPacket(packet2_t* packet, DynPipBag* bag) const; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/dynamic/core/programs/dynpip_td_vu1_program.hpp b/engine/inc/renderer/3d/pipeline/dynamic/core/programs/dynpip_td_vu1_program.hpp new file mode 100644 index 0000000..96ed768 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/dynamic/core/programs/dynpip_td_vu1_program.hpp @@ -0,0 +1,28 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include "../dynpip_vu1_program.hpp" + +namespace Tyra { + +class DynPipTDVU1Program : public DynPipVU1Program { + public: + DynPipTDVU1Program(); + ~DynPipTDVU1Program(); + + std::string getStringName() const; + void addProgramQBufferDataToPacket(packet2_t* packet, DynPipBag* bag) const; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/dynamic/core/programs/dynpip_vu1_shared_defines.h b/engine/inc/renderer/3d/pipeline/dynamic/core/programs/dynpip_vu1_shared_defines.h new file mode 100644 index 0000000..15939fc --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/dynamic/core/programs/dynpip_vu1_shared_defines.h @@ -0,0 +1,25 @@ +// +// ______ ____ ___ +// | \/ ____| |___| +// | | | \ | | +//----------------------------------------------------------------------- +// Copyright 2022, tyra - https://github.com/h4570/tyra +// Licensed under Apache License 2.0 +// Sandro Sobczyński +// + +// Updated once per mesh +#define VU1_MVP_MATRIX_ADDR 0 +#define VU1_LIGHTS_MATRIX_ADDR 4 +#define VU1_SINGLE_COLOR_ADDR 7 +#define VU1_OPTIONS_ADDR 8 +#define VU1_LOD_ADDR 9 +#define VU1_Z_TESTS_ADDR 10 +#define VU1_CLUT_ADDR 11 +#define VU1_LIGHTS_DIRS_ADDR 12 +#define VU1_LIGHTS_COLORS_ADDR 15 +#define VU1_SET_GIFTAG_ADDR 19 +#define VU1_DYNPIP_LAST_ITEM_ADDR 19 + +// Buffer data (xtop) +#define VU1_DYNPIP_VERT_DATA_ADDR 2 diff --git a/engine/inc/renderer/3d/pipeline/dynamic/dynamic_pipeline.hpp b/engine/inc/renderer/3d/pipeline/dynamic/dynamic_pipeline.hpp new file mode 100644 index 0000000..9fd03bd --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/dynamic/dynamic_pipeline.hpp @@ -0,0 +1,91 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "../renderer_3d_pipeline.hpp" +#include "./dynpip_options.hpp" +#include "./core/dynpip_core.hpp" +#include "renderer/core/renderer_core.hpp" +#include "renderer/3d/mesh/dynamic/dynamic_mesh.hpp" + +namespace Tyra { + +/** + * Pipeline for animated models (DynamicMesh). + * Supports: + * - Simple PS2 clipping (culling) + * - Frustum culling + * - Modes: color, texture+color, dir lights, texture + dir lights + */ +class DynamicPipeline : public Renderer3DPipeline { + public: + DynamicPipeline(); + ~DynamicPipeline(); + + static const u32 buffersCount; + + DynPipCore core; + + void setRenderer(RendererCore* core); + + void onUse(); + + void onFrameEnd(); + + void onUseEnd(); + + /** + * Render dynamic model. + * This render() method is a bridge to core.render() method. + */ + void render(const DynamicMesh* mesh); + void render(const DynamicMesh* mesh, const DynPipOptions& options); + void render(const DynamicMesh* mesh, const DynPipOptions* options); + + private: + RendererCore* rendererCore; + Vec4* colorsCache; + DynPipBag* buffers; + static const u32 halfBuffersCount; + + void setBuffer(DynPipBag* buffers, DynPipBag* buffer, u16* bufferIndex); + + void sendRestOfBuffers(DynPipBag* buffers, u16* bufferIndex); + + void addVertices(const MeshMaterialFrame* materialFrameFrom, + const MeshMaterialFrame* materialFrameTo, DynPipBag* bag, + const u32& startIndex) const; + + DynPipInfoBag* getInfoBag(const DynamicMesh* mesh, + const DynPipOptions* options, M4x4* model) const; + + DynPipColorBag* getColorBag(const MeshMaterial* material) const; + + DynPipTextureBag* getTextureBag(Texture* texture, + const MeshMaterialFrame* materialFrameFrom, + const MeshMaterialFrame* materialFrameTo, + const u32& startIndex); + + DynPipLightingBag* getLightingBag(const MeshMaterialFrame* materialFrameFrom, + const MeshMaterialFrame* materialFrameTo, + M4x4* model, const DynPipOptions* options, + PipelineDirLightsBag* dirLightsBag, + const u32& startIndex) const; + + void setLightingColorsCache(PipelineLightingOptions* lightingOptions); + void freeBuffer(DynPipBag* bag); + void setBuffersDefaultVars(DynPipBag* buffers, const DynamicMesh* mesh, + DynPipInfoBag* infoBag); + void setBuffersColorBag(DynPipBag* buffers, DynPipColorBag* colorBag); +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/dynamic/dynpip_options.hpp b/engine/inc/renderer/3d/pipeline/dynamic/dynpip_options.hpp new file mode 100644 index 0000000..9eb1aef --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/dynamic/dynpip_options.hpp @@ -0,0 +1,23 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "renderer/3d/pipeline/shared/pipeline_options.hpp" + +namespace Tyra { + +class DynPipOptions : public PipelineOptions { + public: + DynPipOptions() {} + ~DynPipOptions() {} +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/minecraft/data/mcpip_block_data.hpp b/engine/inc/renderer/3d/pipeline/minecraft/data/mcpip_block_data.hpp new file mode 100644 index 0000000..717ea7f --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/minecraft/data/mcpip_block_data.hpp @@ -0,0 +1,31 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "math/vec4.hpp" + +namespace Tyra { + +class McpipBlockData { + public: + McpipBlockData(); + ~McpipBlockData(); + + u32 count; + float offset; + u32 getComboCount() const { return count * 2; } + + Tyra::Vec4* comboData; + Tyra::Vec4* vertices; + Tyra::Vec4* textureCoords; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/minecraft/data/mcpip_multi_tex_block_data.hpp b/engine/inc/renderer/3d/pipeline/minecraft/data/mcpip_multi_tex_block_data.hpp new file mode 100644 index 0000000..0c9e7e5 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/minecraft/data/mcpip_multi_tex_block_data.hpp @@ -0,0 +1,35 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "debug/debug.hpp" +#include "./mcpip_block_data.hpp" +#include "string" + +namespace Tyra { + +class McpipMultiTexBlockData : public McpipBlockData { + public: + McpipMultiTexBlockData(); + ~McpipMultiTexBlockData(); + + private: + Vec4* tempVerts; + Vec4* tempTexCoords; + u32* tempVertFaces; + u32* tempTexCoordsFaces; + + void allocateTempData(); + void unroll(); + void dellocateTempData(); +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/minecraft/data/mcpip_single_tex_block_data.hpp b/engine/inc/renderer/3d/pipeline/minecraft/data/mcpip_single_tex_block_data.hpp new file mode 100644 index 0000000..8ba8d1b --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/minecraft/data/mcpip_single_tex_block_data.hpp @@ -0,0 +1,35 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "debug/debug.hpp" +#include "./mcpip_block_data.hpp" +#include "string" + +namespace Tyra { + +class McpipSingleTexBlockData : public McpipBlockData { + public: + McpipSingleTexBlockData(); + ~McpipSingleTexBlockData(); + + private: + Vec4* tempVerts; + Vec4* tempTexCoords; + u32* tempVertFaces; + u32* tempTexCoordsFaces; + + void allocateTempData(); + void unroll(); + void dellocateTempData(); +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/minecraft/mcpip_block.hpp b/engine/inc/renderer/3d/pipeline/minecraft/mcpip_block.hpp new file mode 100644 index 0000000..0842eb2 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/minecraft/mcpip_block.hpp @@ -0,0 +1,34 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "math/m4x4.hpp" +#include "math/vec4.hpp" +#include "renderer/models/color.hpp" + +namespace Tyra { + +class McpipBlock { + public: + McpipBlock() { + model = nullptr; + color = nullptr; + textureOffset = nullptr; + } + ~McpipBlock() {} + + M4x4* model; + Color* color; + Vec4* textureOffset; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/minecraft/minecraft_pipeline.hpp b/engine/inc/renderer/3d/pipeline/minecraft/minecraft_pipeline.hpp new file mode 100644 index 0000000..a89a312 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/minecraft/minecraft_pipeline.hpp @@ -0,0 +1,94 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "./mcpip_block.hpp" +#include "./programs/mcpip_programs_manager.hpp" +#include "renderer/3d/pipeline/renderer_3d_pipeline.hpp" +#include "renderer/core/3d/bbox/core_bbox_frustum.hpp" +#include "renderer/core/3d/bbox/render_bbox.hpp" + +namespace Tyra { + +/** + * Pipeline specialized in fast rendering of voxels + * Supports: + * - Full "against each plane" clipping + * - Frustum culling (on fullClipChecks = true) + */ +class MinecraftPipeline : public Renderer3DPipeline { + public: + MinecraftPipeline(); + ~MinecraftPipeline(); + + void setRenderer(RendererCore* core); + + void onUse(); + void onUseEnd(); + void onFrameEnd(); + + /** + * @brief Render voxels + * + * @param blocks array of McpipBlock pointers + * @param t_tex texture to use + * @param isMulti is this a 6 texture voxel? + * @param fullClipChecks false = faster, simple PS2 clipping. True = slower, + * experimental "against each plane" clipping. + */ + void render(std::vector blocks, const Texture* t_tex, + const bool& isMulti = false, const bool& fullClipChecks = false); + + inline const float& getTextureOffset() const { + return manager.getTextureOffset(); + } + + const McpipBlockData& getBlockData() const { return manager.getBlockData(); } + + private: + void setPrim(); + void setLod(); + + prim_t prim; + lod_t lod; + + BlockizerProgramsManager manager; + RendererCore* rendererCore; + RenderBBox* bbox; + McpipProgramName latestMode; + + McpipBlock*** spamBuffers; + u32* spamCounts; + u32 spamBuffersCount; + u32 spammerIndex; + + void initBBox(); + + void changeMode(const McpipProgramName& requestedMode, const u8& force); + + void cull(std::vector blocks, const std::vector& indexes, + RendererCoreTextureBuffers* texBuffers, const bool& isCullOnly, + const bool& isMulti = false); + + void clip(std::vector blocks, const std::vector& indexes, + RendererCoreTextureBuffers* texBuffers, + const bool& isMulti = false); + + Tyra::CoreBBoxFrustum isInFrustum(const McpipBlock& block) const; + + void addToSpammer(McpipBlock** blockPointerArray, const u32& count, + RendererCoreTextureBuffers* texBuffers, + const bool& isMulti); + void flushSpammer(RendererCoreTextureBuffers* texBuffers, + const bool& isMulti); +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/minecraft/programs/as_is/mcpip_as_is_vu1_program.hpp b/engine/inc/renderer/3d/pipeline/minecraft/programs/as_is/mcpip_as_is_vu1_program.hpp new file mode 100644 index 0000000..7983ec9 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/minecraft/programs/as_is/mcpip_as_is_vu1_program.hpp @@ -0,0 +1,28 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include "debug/debug.hpp" +#include "renderer/3d/pipeline/minecraft/programs/mcpip_program.hpp" + +namespace Tyra { + +class McpipAsIsVU1Program : public McpipProgram { + public: + McpipAsIsVU1Program(); + ~McpipAsIsVU1Program(); + + std::string getStringName() const; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/minecraft/programs/as_is/mcpip_clip.hpp b/engine/inc/renderer/3d/pipeline/minecraft/programs/as_is/mcpip_clip.hpp new file mode 100644 index 0000000..41803ef --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/minecraft/programs/as_is/mcpip_clip.hpp @@ -0,0 +1,74 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "debug/debug.hpp" +#include "renderer/renderer.hpp" +#include "packet2/packet2_tyra_utils.hpp" +#include "../mcpip_programs_repository.hpp" +#include "../../mcpip_block.hpp" +#include "../../data/mcpip_block_data.hpp" +#include "./mcpip_vu1_as_is_shared_defines.h" +#include "renderer/core/3d/clipper/planes_clip_algorithm.hpp" + +namespace Tyra { + +class McpipClip { + public: + McpipClip(); + ~McpipClip(); + + PlanesClipAlgorithm algorithm; + EEClipAlgorithmSettings algoSettings; + + void init(RendererCore* core, McpipBlockData* t_singleBlockData, + McpipBlockData* t_multiBlockData, prim_t* prim, lod_t* lod); + + u32 uploadVU1Program(McpipProgramsRepository* repo, const u32& addr); + + void configureVU1AndSendStaticData(); + + void addData(McpipBlock* block, const bool& isMulti, + RendererCoreTextureBuffers* texBuffers, packet2_t* packet, + const u8& context); + + private: + prim_t* prim; + lod_t* lod; + + RendererCore* rendererCore; + McpipBlockData* singleBlockData; + McpipBlockData* multiBlockData; + packet2_t* staticPacket; + u16 vu1DBufferSize; + + Vec4 inputVerts[3]; + PlanesClipVertexPtrs inputTriangle[3]; + PlanesClipVertex clippedTriangle[9]; + + Vec4 vertexBuffers[2][108]; + Vec4 texCoordBuffers[2][108]; + + void addCorrections(std::vector* vertices, + McpipBlock* block); + void moveDataToBuffer(std::vector* vertices, + const u8& context); + void addDataToPacket(packet2_t* packet, const u8& context, McpipBlock* block, + const int& count, + RendererCoreTextureBuffers* texBuffers); + + void initStaticPacket(); + void sendVU1StaticData(); + void setDBufferSize(); +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/minecraft/programs/as_is/mcpip_vu1_as_is_shared_defines.h b/engine/inc/renderer/3d/pipeline/minecraft/programs/as_is/mcpip_vu1_as_is_shared_defines.h new file mode 100644 index 0000000..93d4b49 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/minecraft/programs/as_is/mcpip_vu1_as_is_shared_defines.h @@ -0,0 +1,22 @@ +// +// ______ ____ ___ +// | \/ ____| |___| +// | | | \ | | +//----------------------------------------------------------------------- +// Copyright 2022, tyra - https://github.com/h4570/tyra +// Licensed under Apache License 2.0 +// Sandro Sobczyński +// + +// Static data for blockizer program + +#define VU1_MCPIP_AS_IS_STATIC_LOD 0 +#define VU1_MCPIP_AS_IS_STATIC_SET_TAG 1 +#define VU1_MCPIP_AS_IS_STATIC_LAST_DATA_ADDR 1 + +// Dynamic data (unpack per VU1 call) +#define VU1_MCPIP_AS_IS_DYNAMIC_SCALE 0 +#define VU1_MCPIP_AS_IS_DYNAMIC_PRIM 1 +#define VU1_MCPIP_AS_IS_DYNAMIC_CLUT 2 +#define VU1_MCPIP_AS_IS_DYNAMIC_COLOR 3 +#define VU1_MCPIP_AS_IS_DYNAMIC_VERTEX_DATA_ADDR 4 diff --git a/engine/inc/renderer/3d/pipeline/minecraft/programs/cull/mcpip_cull.hpp b/engine/inc/renderer/3d/pipeline/minecraft/programs/cull/mcpip_cull.hpp new file mode 100644 index 0000000..a95170a --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/minecraft/programs/cull/mcpip_cull.hpp @@ -0,0 +1,55 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "debug/debug.hpp" +#include "renderer/renderer.hpp" +#include "packet2/packet2_tyra_utils.hpp" +#include "../mcpip_programs_repository.hpp" +#include "../../mcpip_block.hpp" +#include "../../data/mcpip_block_data.hpp" +#include "./mcpip_vu1_cull_shared_defines.h" + +namespace Tyra { + +class McpipCull { + public: + McpipCull(); + ~McpipCull(); + + void init(RendererCore* core, McpipBlockData* t_blockData, prim_t* prim, + lod_t* lod); + + u32 uploadVU1Program(McpipProgramsRepository* repo, const u32& addr); + + void configureVU1AndSendStaticData(); + + u32 getMaxBlocksCountPerQBuffer() const; + + void addData(packet2_t* packet, McpipBlock** blockPointerArray, + u32 blockPointerArrayCount, + RendererCoreTextureBuffers* texBuffers, bool isMulti); + + private: + prim_t* prim; + lod_t* lod; + RendererCore* rendererCore; + u16 vu1DBufferSize; + McpipBlockData* blockData; + packet2_t* staticPacket; + + void initStaticPacket(); + void sendVU1StaticData(); + void setDBufferSize(); +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/minecraft/programs/cull/mcpip_cull_vu1_program.hpp b/engine/inc/renderer/3d/pipeline/minecraft/programs/cull/mcpip_cull_vu1_program.hpp new file mode 100644 index 0000000..37b9c5a --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/minecraft/programs/cull/mcpip_cull_vu1_program.hpp @@ -0,0 +1,28 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include "debug/debug.hpp" +#include "renderer/3d/pipeline/minecraft/programs/mcpip_program.hpp" + +namespace Tyra { + +class McpipCullVU1Program : public McpipProgram { + public: + McpipCullVU1Program(); + ~McpipCullVU1Program(); + + std::string getStringName() const; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/minecraft/programs/cull/mcpip_vu1_cull_shared_defines.h b/engine/inc/renderer/3d/pipeline/minecraft/programs/cull/mcpip_vu1_cull_shared_defines.h new file mode 100644 index 0000000..951134c --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/minecraft/programs/cull/mcpip_vu1_cull_shared_defines.h @@ -0,0 +1,33 @@ +// +// ______ ____ ___ +// | \/ ____| |___| +// | | | \ | | +//----------------------------------------------------------------------- +// Copyright 2022, tyra - https://github.com/h4570/tyra +// Licensed under Apache License 2.0 +// Sandro Sobczyński +// + +// Static data for blockizer program + +#define VU1_MCPIP_CULL_VERTEX_COUNT 36 +#define VU1_MCPIP_CULL_QWORDS_PER_BLOCK 6 + +#define VU1_MCPIP_CULL_STATIC_LOD 0 +#define VU1_MCPIP_CULL_STATIC_PRIM 1 +#define VU1_MCPIP_CULL_STATIC_SET_TAG 2 +#define VU1_MCPIP_CULL_STATIC_VU1_OPTIONS 3 +#define VU1_MCPIP_CULL_STATIC_VERTEX_DATA 4 +#define VU1_MCPIP_CULL_STATIC_TEX_COORD_DATA 4 + 36 +#define VU1_MCPIP_CULL_STATIC_LAST_DATA_ADDR \ + VU1_MCPIP_CULL_STATIC_TEX_COORD_DATA + 36 + +// Dynamic data (unpack per VU1 call) +#define VU1_MCPIP_CULL_DYNAMIC_SCALE_AND_BLOCKS_COUNT_ADDR 0 +#define VU1_MCPIP_CULL_DYNAMIC_CLUT_TEX 1 +#define VU1_MCPIP_CULL_DYNAMIC_VIEW_PROJ_MATRIX_ADDR 2 +#define VU1_MCPIP_CULL_DYNAMIC_BLOCKS_DATA 6 + +// Output mini double buffer inside VU1 mem +#define VU1_MCPIP_CULL_DYNAMIC_OUTPUT_DOUBLE_BUFF1_ADDR 774 +#define VU1_MCPIP_CULL_DYNAMIC_OUTPUT_DOUBLE_BUFF2_ADDR 887 diff --git a/engine/inc/renderer/3d/pipeline/minecraft/programs/mcpip_program.hpp b/engine/inc/renderer/3d/pipeline/minecraft/programs/mcpip_program.hpp new file mode 100644 index 0000000..93dadef --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/minecraft/programs/mcpip_program.hpp @@ -0,0 +1,29 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "./mcpip_program_name.hpp" +#include "renderer/core/paths/path1/vu1_program.hpp" + +namespace Tyra { + +class McpipProgram : public VU1Program { + public: + McpipProgram(const McpipProgramName& name, u32* start, u32* end); + ~McpipProgram(); + + const McpipProgramName& getName() const; + + protected: + McpipProgramName name; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/minecraft/programs/mcpip_program_name.hpp b/engine/inc/renderer/3d/pipeline/minecraft/programs/mcpip_program_name.hpp new file mode 100644 index 0000000..3e195d3 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/minecraft/programs/mcpip_program_name.hpp @@ -0,0 +1,21 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +namespace Tyra { + +enum McpipProgramName { + UndefinedMcpipProgram, + McPipCull, + McPipAsIs, +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/minecraft/programs/mcpip_programs_manager.hpp b/engine/inc/renderer/3d/pipeline/minecraft/programs/mcpip_programs_manager.hpp new file mode 100644 index 0000000..f773e8c --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/minecraft/programs/mcpip_programs_manager.hpp @@ -0,0 +1,83 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "debug/debug.hpp" +#include "renderer/renderer.hpp" +#include "./cull/mcpip_cull.hpp" +#include "./as_is/mcpip_clip.hpp" +#include "./mcpip_programs_repository.hpp" +#include "../data/mcpip_single_tex_block_data.hpp" +#include "../data/mcpip_multi_tex_block_data.hpp" +#include "../mcpip_block.hpp" + +namespace Tyra { + +enum McpipStaticBlockData { + BlockNotUploaded, + BlockMultiUploaded, + BlockSingleUploaded +}; + +class BlockizerProgramsManager { + public: + BlockizerProgramsManager(); + ~BlockizerProgramsManager(); + + McpipCull culler; + McpipClip clipper; + + void init(RendererCore* core, prim_t* prim, lod_t* lod); + + void uploadVU1Programs(); + + void clearLastProgram() { lastProgramName = UndefinedMcpipProgram; } + + void cullSpam(McpipBlock*** blockPointerArrays, u32* blockPointerArrayCounts, + u32 blockPointerArraysCount, + RendererCoreTextureBuffers* texBuffers, const bool& isMulti); + + void cull(McpipBlock** blockPointerArray, u32 blockPointerArrayCount, + RendererCoreTextureBuffers* texBuffers, const bool& isMulti); + + void clip(McpipBlock* block, RendererCoreTextureBuffers* texBuffers, + const bool& isMulti); + + inline const float& getTextureOffset() const { + return singleTexBlockData.offset; + } + + const McpipBlockData& getBlockData() const { return singleTexBlockData; } + + void allocateOnUse(); + void deallocateOnUse(); + + private: + McpipProgramsRepository repo; + RendererCore* rendererCore; + McpipSingleTexBlockData singleTexBlockData; + McpipMultiTexBlockData multiTexBlockData; + McpipProgramName lastProgramName; + + packet2_t* programsPacket; + packet2_t* staticPacket; + packet2_t* dynamicPackets[2]; + u8 context; + McpipStaticBlockData vu1BlockData; + + void setProgramsCache(); + void uploadBlock(bool isMulti); + void addProgram(McpipProgram* program); + void sendPacket(McpipProgram* program); +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/minecraft/programs/mcpip_programs_repository.hpp b/engine/inc/renderer/3d/pipeline/minecraft/programs/mcpip_programs_repository.hpp new file mode 100644 index 0000000..4fa9fe0 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/minecraft/programs/mcpip_programs_repository.hpp @@ -0,0 +1,32 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "debug/debug.hpp" +#include "./mcpip_program.hpp" +#include "cull/mcpip_cull_vu1_program.hpp" +#include "as_is/mcpip_as_is_vu1_program.hpp" + +namespace Tyra { + +class McpipProgramsRepository { + public: + McpipProgramsRepository(); + ~McpipProgramsRepository(); + + McpipProgram* getProgram(const McpipProgramName& name); + + private: + McpipCullVU1Program cull; + McpipAsIsVU1Program asIs; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/renderer_3d_pipeline.hpp b/engine/inc/renderer/3d/pipeline/renderer_3d_pipeline.hpp new file mode 100644 index 0000000..ef6f26a --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/renderer_3d_pipeline.hpp @@ -0,0 +1,29 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "renderer/core/renderer_core.hpp" + +namespace Tyra { + +class Renderer3DPipeline { + public: + Renderer3DPipeline() { onDestroy = nullptr; } + ~Renderer3DPipeline() {} + + virtual void setRenderer(RendererCore* core) = 0; + virtual void onUse() = 0; + virtual void onFrameEnd() = 0; + virtual void onUseEnd() = 0; + std::function onDestroy; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/shared/bag/pipeline_dir_lights_bag.hpp b/engine/inc/renderer/3d/pipeline/shared/bag/pipeline_dir_lights_bag.hpp new file mode 100644 index 0000000..469150e --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/shared/bag/pipeline_dir_lights_bag.hpp @@ -0,0 +1,53 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "renderer/models/color.hpp" +#include "math/m4x4.hpp" +#include "math/vec4.hpp" + +namespace Tyra { + +enum PipelineDirLightsBagMode { Auto, Manual }; + +class PipelineDirLightsBag { + public: + explicit PipelineDirLightsBag(const bool& manual = false); + ~PipelineDirLightsBag(); + + void setAmbientColor(const Color& color); + void setDirectionalLightColors(Color* colors, const u8& count); + void setDirectionalLightDirections(Vec4* directions, const u8& count); + void setDirectionalLightColor(const Color& color, const u8& index); + void setDirectionalLightDirection(const Vec4& direction, const u8& index); + + void setLightsManually(Vec4* colors, Vec4* directions); + void disableManualMode(); + + Vec4* getLightColors() { return lightColors; } + + Vec4* getLightDirections() { return lightDirections; } + + void forceDeallocateColors(); + void forceDeallocateDirections(); + + private: + void allocate(); + void deallocate(); + void forceDeallocate(); + u8 isAllocated; + PipelineDirLightsBagMode mode; + + Vec4* lightColors; + Vec4* lightDirections; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/shared/bag/pipeline_info_bag.hpp b/engine/inc/renderer/3d/pipeline/shared/bag/pipeline_info_bag.hpp new file mode 100644 index 0000000..6a78254 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/shared/bag/pipeline_info_bag.hpp @@ -0,0 +1,63 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "math/m4x4.hpp" +#include "math/vec4.hpp" +#include "../pipeline_shading_type.hpp" +#include "../pipeline_texture_mapping_type.hpp" +#include "../pipeline_transformation_type.hpp" +#include "../pipeline_z_test.hpp" +#include "./pipeline_info_bag_frustum_culling.hpp" + +namespace Tyra { + +class PipelineInfoBag { + public: + PipelineInfoBag() { + shadingType = TyraShadingFlat; + transformationType = TyraMVP; + textureMappingType = TyraLinear; + blendingEnabled = true; + antiAliasingEnabled = false; + model = nullptr; + frustumCulling = PipelineInfoBagFrustumCulling_None; + zTestType = PipelineZTest_Standard; + } + ~PipelineInfoBag() {} + + /** Mandatory. Model matrix */ + M4x4* model; + + /** Flat or gouraud */ + PipelineShadingType shadingType; + + /** Linear or nearest */ + PipelineTextureMappingType textureMappingType; + + /** Multiply by model matrix by view-projection or projection matrix */ + PipelineTransformationType transformationType; + + /** Blending texture with color */ + bool blendingEnabled; + + /** Anti-aliasing */ + bool antiAliasingEnabled; + + /** Type of z buffer testing. */ + PipelineZTest zTestType; + + /** Type of frustum culling */ + PipelineInfoBagFrustumCulling frustumCulling; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/shared/bag/pipeline_info_bag_frustum_culling.hpp b/engine/inc/renderer/3d/pipeline/shared/bag/pipeline_info_bag_frustum_culling.hpp new file mode 100644 index 0000000..b09984b --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/shared/bag/pipeline_info_bag_frustum_culling.hpp @@ -0,0 +1,22 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +namespace Tyra { + +enum PipelineInfoBagFrustumCulling { + /** No frustum culling */ + PipelineInfoBagFrustumCulling_None = 0, + /** Frustum culling of parts of an object */ + PipelineInfoBagFrustumCulling_Precise = 2, +}; + +} diff --git a/engine/inc/renderer/3d/pipeline/shared/pipeline_frustum_culling.hpp b/engine/inc/renderer/3d/pipeline/shared/pipeline_frustum_culling.hpp new file mode 100644 index 0000000..99ceaf1 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/shared/pipeline_frustum_culling.hpp @@ -0,0 +1,24 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +namespace Tyra { + +enum PipelineFrustumCulling { + /** No frustum culling */ + PipelineFrustumCulling_None = 0, + /** Frustum culling of whole object */ + PipelineFrustumCulling_Simple = 1, + /** Frustum culling of parts of an object */ + PipelineFrustumCulling_Precise = 2, +}; + +} diff --git a/engine/inc/renderer/3d/pipeline/shared/pipeline_lighting_options.hpp b/engine/inc/renderer/3d/pipeline/shared/pipeline_lighting_options.hpp new file mode 100644 index 0000000..1709d98 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/shared/pipeline_lighting_options.hpp @@ -0,0 +1,44 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "math/vec4.hpp" +#include "renderer/models/color.hpp" + +namespace Tyra { + +class PipelineLightingOptions { + public: + PipelineLightingOptions() {} + ~PipelineLightingOptions() {} + + /** + * Mandatory. + * Default 128.0F, 128.0F, 128.0F, 128.0F + */ + Color* ambientColor; + + /** + * Mandatory. + * Min/max length - 3. + * Example color value: 64.0F, 0.0F, 0.0F, 1.0F + */ + Color* directionalColors; + + /** + * Mandatory. + * Min/max length - 3. + * Example dir value: 1.0F, 0.0F, 0.0F, 1.0F + */ + Vec4* directionalDirections; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/shared/pipeline_options.hpp b/engine/inc/renderer/3d/pipeline/shared/pipeline_options.hpp new file mode 100644 index 0000000..6621089 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/shared/pipeline_options.hpp @@ -0,0 +1,60 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "../shared/pipeline_shading_type.hpp" +#include "../shared/pipeline_lighting_options.hpp" +#include "../shared/pipeline_texture_mapping_type.hpp" +#include "../shared/pipeline_transformation_type.hpp" +#include "../shared/pipeline_z_test.hpp" +#include "./pipeline_frustum_culling.hpp" + +namespace Tyra { + +class PipelineOptions { + public: + PipelineOptions() { + lighting = nullptr; + antiAliasingEnabled = false; + blendingEnabled = true; + shadingType = TyraShadingFlat; + textureMappingType = TyraLinear; + transformationType = TyraMVP; + zTestType = PipelineZTest_Standard; + } + ~PipelineOptions() {} + + /** Type of frustum culling */ + PipelineFrustumCulling frustumCulling; + + /** Flat or gouraud */ + PipelineShadingType shadingType; + + /** Linear or nearest */ + PipelineTextureMappingType textureMappingType; + + /** Blending texture with color */ + bool blendingEnabled; + + /** Anti-aliasing */ + bool antiAliasingEnabled; + + /** Type of z-buffer testing. */ + PipelineZTest zTestType; + + /** Multiply by model matrix by view-projection or projection matrix */ + PipelineTransformationType transformationType; + + /** Optional */ + PipelineLightingOptions* lighting; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/shared/pipeline_shading_type.hpp b/engine/inc/renderer/3d/pipeline/shared/pipeline_shading_type.hpp new file mode 100644 index 0000000..12d5f71 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/shared/pipeline_shading_type.hpp @@ -0,0 +1,20 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +namespace Tyra { + +enum PipelineShadingType { + TyraShadingFlat, + TyraShadingGouraud, +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/shared/pipeline_texture_mapping_type.hpp b/engine/inc/renderer/3d/pipeline/shared/pipeline_texture_mapping_type.hpp new file mode 100644 index 0000000..61e2a97 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/shared/pipeline_texture_mapping_type.hpp @@ -0,0 +1,20 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +namespace Tyra { + +enum PipelineTextureMappingType { + TyraNearest, + TyraLinear, +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/shared/pipeline_transformation_type.hpp b/engine/inc/renderer/3d/pipeline/shared/pipeline_transformation_type.hpp new file mode 100644 index 0000000..5638234 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/shared/pipeline_transformation_type.hpp @@ -0,0 +1,22 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +namespace Tyra { + +enum PipelineTransformationType { + /** Multiplies model by view and projection matrix */ + TyraMVP, + /** Multiplies model by only projection matrix */ + TyraMP, +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/shared/pipeline_z_test.hpp b/engine/inc/renderer/3d/pipeline/shared/pipeline_z_test.hpp new file mode 100644 index 0000000..b8ea74d --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/shared/pipeline_z_test.hpp @@ -0,0 +1,20 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +namespace Tyra { + +enum PipelineZTest { + PipelineZTest_Standard = 0, + PipelineZTest_AllPass = 1, +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/bag/packaging/stapip_bag_package.hpp b/engine/inc/renderer/3d/pipeline/static/core/bag/packaging/stapip_bag_package.hpp new file mode 100644 index 0000000..0c4cec4 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/bag/packaging/stapip_bag_package.hpp @@ -0,0 +1,50 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "../stapip_bag.hpp" +#include "renderer/core/3d/bbox/core_bbox_frustum.hpp" + +namespace Tyra { + +class StaPipBagPackage { + public: + StaPipBagPackage(); + ~StaPipBagPackage(); + + StaPipBag* bag; + + const Vec4* vertices; + const Vec4* sts; + const Vec4* normals; + const Vec4* colors; + /** maxVertCount is max value, because we decided to put max maxVertCount + * verts to single quad buffer in VU1 */ + u16 size; + CoreBBoxFrustum isInFrustum; + + /** + * We are creating StaPipBagPackagesBBox which checks CoreBBox for every + * maxVertCount / 3. So this variable is index of starting + * StaPipBagPackagesBBox's CoreBBox. If package have <= maxVertCount / 3 + * verts, we will need only single (starting) bbox. if package have + * maxVertCount verts, we will calculate CoreBBox from 3 + * StaPipBagPackagesBBox's bboxes. + */ + u32 indexOf1By3BBox; + + void print() const; + void print(const char* name) const; + void print(const std::string& name) const { print(name.c_str()); } + std::string getPrint(const char* name = nullptr) const; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/bag/packaging/stapip_bag_packager.hpp b/engine/inc/renderer/3d/pipeline/static/core/bag/packaging/stapip_bag_packager.hpp new file mode 100644 index 0000000..7e6184d --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/bag/packaging/stapip_bag_packager.hpp @@ -0,0 +1,52 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "renderer/core/3d/bbox/core_bbox.hpp" +#include "renderer/core/3d/renderer_3d_frustum_planes.hpp" +#include "renderer/core/3d/clipper/planes_clip_algorithm.hpp" +#include "./stapip_bag_packages_bbox.hpp" +#include "./stapip_bag_package.hpp" +#include "../stapip_bag.hpp" + +namespace Tyra { + +class StaPipBagPackager { + public: + StaPipBagPackager(); + ~StaPipBagPackager(); + + void init(Renderer3DFrustumPlanes* frustumPlanes); + void setRenderBBox(StaPipBagPackagesBBox* bbox) { renderBBox = bbox; } + void setMaxVertCount(const u32& count); + + /** + * @brief Create render packages from provided render data + * + * @param size Max maxVertCount verts (VU1 buffer size) + */ + StaPipBagPackage* create(u16* o_size, StaPipBag* data, u16 size); + /** + * @brief Split render package to smaller packages + * + * @param size Max maxVertCount verts (VU1 buffer size) + */ + StaPipBagPackage* create(u16* o_size, const StaPipBagPackage& pkg, u16 size); + + CoreBBoxFrustum checkFrustum(const StaPipBagPackage& pkg); + + private: + u32 maxVertCount; + Renderer3DFrustumPlanes* frustumPlanes; + StaPipBagPackagesBBox* renderBBox; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/bag/packaging/stapip_bag_packages_bbox.hpp b/engine/inc/renderer/3d/pipeline/static/core/bag/packaging/stapip_bag_packages_bbox.hpp new file mode 100644 index 0000000..7be3bd4 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/bag/packaging/stapip_bag_packages_bbox.hpp @@ -0,0 +1,71 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "renderer/core/3d/bbox/render_bbox.hpp" + +namespace Tyra { + +/** + * Splits all 3D input vertices into 16vert parts and creates child bboxes for + * it + */ +class StaPipBagPackagesBBox { + public: + StaPipBagPackagesBBox(const Vec4* t_vertices, u32* t_faces, + const u32& t_facesCount, const u32& t_maxVertCount); + StaPipBagPackagesBBox(const Vec4* t_vertices, const u32& t_counts, + const u32& t_maxVertCount); + ~StaPipBagPackagesBBox(); + + void setMaxVertCount(const u32& count); + + /** + * @param index Index of part + */ + const RenderBBox& getChildBBox1By3(const u32& index) const; + + /** @brief CoreBBox created from all of vertices */ + RenderBBox* getMainBBox(); + + /** @brief Get amount of child Bbox1/3 parts */ + const u32& getPartsCount() const; + + /** @brief Get amount of vertices */ + const u32& getVertexCount() const; + + const std::vector& getParts() const { return *bboxParts; } + + /** + * @brief For example if we want to build a bbox from 96-112 vertices, we + * should input index = 3, partsSize = 1 + * @param index Index of part + * @param partsSize How many 1/3 parts + */ + RenderBBox createChildBBox(const u32& index, const u16& partsSize) const; + + void print() const; + void print(const char* name) const; + void print(const std::string& name) const { print(name.c_str()); } + std::string getPrint(const char* name = nullptr) const; + + private: + u32 maxVertCount; + u32 vertexCount, partsCount; + + /** @brief CoreBBox of all vertices */ + RenderBBox* mainBBox; + + /** @brief Bounding boxes of 1/3 vertices */ + std::vector* bboxParts; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/bag/stapip_bag.hpp b/engine/inc/renderer/3d/pipeline/static/core/bag/stapip_bag.hpp new file mode 100644 index 0000000..ce1f83e --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/bag/stapip_bag.hpp @@ -0,0 +1,62 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "math/vec4.hpp" +#include "./stapip_info_bag.hpp" +#include "./stapip_color_bag.hpp" +#include "./stapip_lighting_bag.hpp" +#include "./stapip_texture_bag.hpp" +#include "renderer/core/texture/models/texture.hpp" +#include "./packaging/stapip_bag_packages_bbox.hpp" + +namespace Tyra { + +/** + * @brief 3D Render data bag. + * Supports frustum culling, full plane clipping, lighting, + * texture and single color / many colors. + */ +class StaPipBag { + public: + StaPipBag(); + ~StaPipBag(); + + /** Mandatory. Object info. */ + StaPipInfoBag* info; + + /** Mandatory. Object color(s). */ + StaPipColorBag* color; + + /** Mandatory. Vertex count. */ + u32 count; + + /** Mandatory. Vertices. */ + Vec4* vertices; + + /** Optional. Texture coordinates and image. */ + StaPipTextureBag* texture; + + /** Optional. Object lighting. */ + StaPipLightingBag* lighting; + + /** + * @param maxVertCount This parameter is available in renderer API. + */ + StaPipBagPackagesBBox calculateBbox(const u32& maxVertCount); + + void print() const; + void print(const char* name) const; + void print(const std::string& name) const { print(name.c_str()); } + std::string getPrint(const char* name = nullptr) const; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/bag/stapip_color_bag.hpp b/engine/inc/renderer/3d/pipeline/static/core/bag/stapip_color_bag.hpp new file mode 100644 index 0000000..a93e520 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/bag/stapip_color_bag.hpp @@ -0,0 +1,32 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "renderer/models/color.hpp" + +namespace Tyra { + +/** + * @brief Color data. At least one color data is required (single/many). + */ +class StaPipColorBag { + public: + StaPipColorBag(); + ~StaPipColorBag(); + + /** Optional. Single color for all vertices. */ + const Color* single; + + /** Optional. Color per vertex. */ + const Color* many; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/bag/stapip_info_bag.hpp b/engine/inc/renderer/3d/pipeline/static/core/bag/stapip_info_bag.hpp new file mode 100644 index 0000000..105031c --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/bag/stapip_info_bag.hpp @@ -0,0 +1,34 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "renderer/3d/pipeline/shared/bag/pipeline_info_bag.hpp" + +namespace Tyra { + +class StaPipInfoBag : public PipelineInfoBag { + public: + StaPipInfoBag() { fullClipChecks = false; } + ~StaPipInfoBag() {} + + /** + * @brief Experimental! False -> disables "clip against each plane" algorithm. + * Default: True. + * + * Full clip checks are slow, but they are + * preventing visual artifacts, which can happen + * for big 3D objects (or objects near camera eyes) + * Force enabled in dynamic pipe, because of efficiency. + */ + bool fullClipChecks; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/bag/stapip_lighting_bag.hpp b/engine/inc/renderer/3d/pipeline/static/core/bag/stapip_lighting_bag.hpp new file mode 100644 index 0000000..7c04bed --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/bag/stapip_lighting_bag.hpp @@ -0,0 +1,33 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "math/vec4.hpp" +#include "renderer/3d/pipeline/shared/bag/pipeline_dir_lights_bag.hpp" + +namespace Tyra { + +class StaPipLightingBag { + public: + StaPipLightingBag(); + ~StaPipLightingBag(); + + /** Mandatory. Model matrix for lights. */ + M4x4* lightMatrix; + + /** Mandatory. Lighting normals per vertex. */ + Vec4* normals; + + /** Mandatory. Directional lights */ + PipelineDirLightsBag* dirLights; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/bag/stapip_texture_bag.hpp b/engine/inc/renderer/3d/pipeline/static/core/bag/stapip_texture_bag.hpp new file mode 100644 index 0000000..86cf9b8 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/bag/stapip_texture_bag.hpp @@ -0,0 +1,30 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "math/vec4.hpp" +#include "renderer/core/texture/models/texture.hpp" + +namespace Tyra { + +class StaPipTextureBag { + public: + StaPipTextureBag(); + ~StaPipTextureBag(); + + /** Mandatory. Texture coordinates per vertex. */ + Vec4* coordinates; + + /** Mandatory. Texture image. */ + Texture* texture; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_c_vu1_program.hpp b/engine/inc/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_c_vu1_program.hpp new file mode 100644 index 0000000..6ff0dbb --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_c_vu1_program.hpp @@ -0,0 +1,30 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include "../../stapip_vu1_program.hpp" + +namespace Tyra { + +class StaPipAsIsCVU1Program : public StaPipVU1Program { + public: + StaPipAsIsCVU1Program(); + ~StaPipAsIsCVU1Program(); + + std::string getStringName() const; + + void addProgramQBufferDataToPacket(packet2_t* packet, + StaPipQBuffer* qbuffer) const; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_d_vu1_program.hpp b/engine/inc/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_d_vu1_program.hpp new file mode 100644 index 0000000..b92f291 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_d_vu1_program.hpp @@ -0,0 +1,29 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include "../../stapip_vu1_program.hpp" + +namespace Tyra { + +class StaPipAsIsDVU1Program : public StaPipVU1Program { + public: + StaPipAsIsDVU1Program(); + ~StaPipAsIsDVU1Program(); + + std::string getStringName() const; + void addProgramQBufferDataToPacket(packet2_t* packet, + StaPipQBuffer* qbuffer) const; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_tc_vu1_program.hpp b/engine/inc/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_tc_vu1_program.hpp new file mode 100644 index 0000000..ab15718 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_tc_vu1_program.hpp @@ -0,0 +1,29 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include "../../stapip_vu1_program.hpp" + +namespace Tyra { + +class StaPipAsIsTCVU1Program : public StaPipVU1Program { + public: + StaPipAsIsTCVU1Program(); + ~StaPipAsIsTCVU1Program(); + + std::string getStringName() const; + void addProgramQBufferDataToPacket(packet2_t* packet, + StaPipQBuffer* qbuffer) const; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_td_vu1_program.hpp b/engine/inc/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_td_vu1_program.hpp new file mode 100644 index 0000000..af27d14 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_td_vu1_program.hpp @@ -0,0 +1,29 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include "../../stapip_vu1_program.hpp" + +namespace Tyra { + +class StaPipAsIsTDVU1Program : public StaPipVU1Program { + public: + StaPipAsIsTDVU1Program(); + ~StaPipAsIsTDVU1Program(); + + std::string getStringName() const; + void addProgramQBufferDataToPacket(packet2_t* packet, + StaPipQBuffer* qbuffer) const; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_c_vu1_program.hpp b/engine/inc/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_c_vu1_program.hpp new file mode 100644 index 0000000..b1e68cf --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_c_vu1_program.hpp @@ -0,0 +1,29 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include "../../stapip_vu1_program.hpp" + +namespace Tyra { + +class StaPipCullCVU1Program : public StaPipVU1Program { + public: + StaPipCullCVU1Program(); + ~StaPipCullCVU1Program(); + + std::string getStringName() const; + void addProgramQBufferDataToPacket(packet2_t* packet, + StaPipQBuffer* qbuffer) const; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_d_vu1_program.hpp b/engine/inc/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_d_vu1_program.hpp new file mode 100644 index 0000000..a1caa9c --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_d_vu1_program.hpp @@ -0,0 +1,29 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include "../../stapip_vu1_program.hpp" + +namespace Tyra { + +class StaPipCullDVU1Program : public StaPipVU1Program { + public: + StaPipCullDVU1Program(); + ~StaPipCullDVU1Program(); + + std::string getStringName() const; + void addProgramQBufferDataToPacket(packet2_t* packet, + StaPipQBuffer* qbuffer) const; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_tc_vu1_program.hpp b/engine/inc/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_tc_vu1_program.hpp new file mode 100644 index 0000000..77db017 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_tc_vu1_program.hpp @@ -0,0 +1,29 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include "../../stapip_vu1_program.hpp" + +namespace Tyra { + +class StaPipCullTCVU1Program : public StaPipVU1Program { + public: + StaPipCullTCVU1Program(); + ~StaPipCullTCVU1Program(); + + std::string getStringName() const; + void addProgramQBufferDataToPacket(packet2_t* packet, + StaPipQBuffer* qbuffer) const; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_td_vu1_program.hpp b/engine/inc/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_td_vu1_program.hpp new file mode 100644 index 0000000..8983e75 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_td_vu1_program.hpp @@ -0,0 +1,29 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include "../../stapip_vu1_program.hpp" + +namespace Tyra { + +class StaPipCullTDVU1Program : public StaPipVU1Program { + public: + StaPipCullTDVU1Program(); + ~StaPipCullTDVU1Program(); + + std::string getStringName() const; + void addProgramQBufferDataToPacket(packet2_t* packet, + StaPipQBuffer* qbuffer) const; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/programs/stapip_vu1_shared_defines.h b/engine/inc/renderer/3d/pipeline/static/core/programs/stapip_vu1_shared_defines.h new file mode 100644 index 0000000..759a1d3 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/programs/stapip_vu1_shared_defines.h @@ -0,0 +1,25 @@ +// +// ______ ____ ___ +// | \/ ____| |___| +// | | | \ | | +//----------------------------------------------------------------------- +// Copyright 2022, tyra - https://github.com/h4570/tyra +// Licensed under Apache License 2.0 +// Sandro Sobczyński +// + +// Updated once per mesh +#define VU1_MVP_MATRIX_ADDR 0 +#define VU1_LIGHTS_MATRIX_ADDR 4 +#define VU1_SINGLE_COLOR_ADDR 7 +#define VU1_OPTIONS_ADDR 8 +#define VU1_LOD_ADDR 9 +#define VU1_Z_TESTS_ADDR 10 +#define VU1_CLUT_ADDR 11 +#define VU1_LIGHTS_DIRS_ADDR 12 +#define VU1_LIGHTS_COLORS_ADDR 15 +#define VU1_SET_GIFTAG_ADDR 19 +#define VU1_STAPIP_LAST_ITEM_ADDR 19 + +// Buffer data (xtop) +#define VU1_STAPIP_VERT_DATA_ADDR 2 diff --git a/engine/inc/renderer/3d/pipeline/static/core/stapip_bag_bboxes_cacher.hpp b/engine/inc/renderer/3d/pipeline/static/core/stapip_bag_bboxes_cacher.hpp new file mode 100644 index 0000000..22ee0d3 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/stapip_bag_bboxes_cacher.hpp @@ -0,0 +1,47 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "./bag/packaging/stapip_bag_packages_bbox.hpp" +#include "renderer/3d/mesh/mesh.hpp" +#include +#include + +namespace Tyra { + +struct StapipBagBBoxesCacheItem { + u32 vu1MaxVertCount; + u32 id; + std::unique_ptr bboxes; + int framesLeftToDestroy; +}; + +class StapipBagBBoxesCacher { + public: + StapipBagBBoxesCacher(); + ~StapipBagBBoxesCacher(); + + const int cacheFramesCount = 50; + const int cacheSecondsCount = 5; + + void onFrameEnd(); + + StaPipBagPackagesBBox* getBBoxes(const Vec4* vertices, const u32& count, + const u32& id, const u32& maxVertCount); + + private: + StapipBagBBoxesCacheItem* getCache(const u32& maxVertCount, const u32& id); + + std::vector storage; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/stapip_clipper.hpp b/engine/inc/renderer/3d/pipeline/static/core/stapip_clipper.hpp new file mode 100644 index 0000000..d6e4c13 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/stapip_clipper.hpp @@ -0,0 +1,51 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "debug/debug.hpp" +#include "./stapip_qbuffer.hpp" +#include "renderer/renderer_settings.hpp" +#include "renderer/core/3d/clipper/planes_clip_algorithm.hpp" + +namespace Tyra { + +/** + * @brief This class requires VU1 buffer with max buffsize/3 vertices. + * It will clip triangles and fill the buffer. + * + * To be honest clipping algorithm should be moved to VU1 and "AsIs" VU1 program + * should be renamed to "Clip" - I don't want to do it now, too much time. + */ +class StaPipClipper { + public: + StaPipClipper(); + ~StaPipClipper(); + void clip(StaPipQBuffer* buffer); + void init(const RendererSettings& settings); + void setMaxVertCount(const u32& count); + void setMVP(M4x4* mvp); + + private: + u32 maxVertCount; + PlanesClipAlgorithm algorithm; + M4x4* mvp; + + Vec4 inputVerts[3]; + PlanesClipVertexPtrs inputTriangle[3]; + PlanesClipVertex clippedTriangle[9]; + + void perspectiveDivide(std::vector* vertices); + void moveDataToBuffer(const std::vector& vertices, + StaPipQBuffer* buffer); +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/stapip_core.hpp b/engine/inc/renderer/3d/pipeline/static/core/stapip_core.hpp new file mode 100644 index 0000000..bd57b53 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/stapip_core.hpp @@ -0,0 +1,73 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "./bag/stapip_bag.hpp" +#include "./bag/packaging/stapip_bag_packages_bbox.hpp" +#include "./bag/packaging/stapip_bag_package.hpp" +#include "./bag/packaging/stapip_bag_packager.hpp" +#include "./stapip_qbuffer_renderer.hpp" +#include "./stapip_bag_bboxes_cacher.hpp" +#include "renderer/3d/pipeline/shared/pipeline_frustum_culling.hpp" + +namespace Tyra { + +class StaPipCore { + public: + StaPipCore(); + ~StaPipCore(); + + void init(RendererCore* t_core); + + void onFrameEnd(); + + /** Render 3D via "bags" */ + void render(StaPipBag* bag); + + /** Get max vert count of VU1 qbuffer (for optimizations) */ + u32 getMaxVertCountByParams(const bool& isSingleColor, + const bool& isLightingEnabled, + const bool& isTextureEnabled); + + /** Get max vert count of VU1 qbuffer (for optimizations) */ + u32 getMaxVertCountByBag(const StaPipBag* bag); + + /** + * - Uploads standard VU1 programs. + * - Sends static "Tyra Renderer3D" VU1 data. + * - Sets double buffers exactly for "Tyra Renderer3D" + * Should be called if VU1 was used by your non standard programs. + */ + void reinitVU1Programs(); + + void allocateOnUse() { qbufferRenderer.allocateOnUse(); } + void deallocateOnUse() { qbufferRenderer.deallocateOnUse(); } + + private: + void setPrim(); + void setLod(); + + prim_t prim; + lod_t lod; + + u32 maxVertCount; + RendererCore* rendererCore; + StapipBagBBoxesCacher cacher; + + void setMaxVertCount(const u32& count); + StaPipBagPackager packager; + StaPipQBufferRenderer qbufferRenderer; + void renderPkgs(StaPipBagPackage* packages, const bool& doClip, u16 count); + void renderSubpkgs(StaPipBagPackage* packages, u16 count); +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/stapip_program_name.hpp b/engine/inc/renderer/3d/pipeline/static/core/stapip_program_name.hpp new file mode 100644 index 0000000..f2e9b4c --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/stapip_program_name.hpp @@ -0,0 +1,31 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +namespace Tyra { + +enum StaPipProgramName { + StaPipUndefinedProgram, + + StaPipCullColor, + StaPipAsIsColor, + + StaPipCullDirLights, + StaPipAsIsDirLights, + + StaPipCullTextureDirLights, + StaPipAsIsTextureDirLights, + + StaPipCullTextureColor, + StaPipAsIsTextureColor, +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/stapip_program_type.hpp b/engine/inc/renderer/3d/pipeline/static/core/stapip_program_type.hpp new file mode 100644 index 0000000..7140c57 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/stapip_program_type.hpp @@ -0,0 +1,22 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +namespace Tyra { + +enum StaPipProgramType { + StaPipVU1Color, + StaPipVU1DirLights, + StaPipVU1TextureDirLights, + StaPipVU1TextureColor, +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/stapip_programs_repository.hpp b/engine/inc/renderer/3d/pipeline/static/core/stapip_programs_repository.hpp new file mode 100644 index 0000000..780efb0 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/stapip_programs_repository.hpp @@ -0,0 +1,46 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "debug/debug.hpp" +#include "renderer/core/paths/path1/vu1_program.hpp" + +#include "./programs/as_is/stapip_as_is_c_vu1_program.hpp" +#include "./programs/as_is/stapip_as_is_d_vu1_program.hpp" +#include "./programs/as_is/stapip_as_is_td_vu1_program.hpp" +#include "./programs/as_is/stapip_as_is_tc_vu1_program.hpp" + +#include "./programs/cull/stapip_cull_c_vu1_program.hpp" +#include "./programs/cull/stapip_cull_d_vu1_program.hpp" +#include "./programs/cull/stapip_cull_td_vu1_program.hpp" +#include "./programs/cull/stapip_cull_tc_vu1_program.hpp" + +namespace Tyra { + +class StaPipProgramsRepository { + public: + StaPipProgramsRepository(); + ~StaPipProgramsRepository(); + + StaPipVU1Program* getProgram(const StaPipProgramName& name); + + private: + StaPipAsIsCVU1Program asIsColor; + StaPipCullCVU1Program cullColor; + StaPipAsIsDVU1Program asIsDirLights; + StaPipCullDVU1Program cullDirLights; + StaPipAsIsTDVU1Program asIsTextureDirLights; + StaPipCullTDVU1Program cullTextureDirLights; + StaPipAsIsTCVU1Program asIsTextureColor; + StaPipCullTCVU1Program cullTextureColor; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/stapip_qbuffer.hpp b/engine/inc/renderer/3d/pipeline/static/core/stapip_qbuffer.hpp new file mode 100644 index 0000000..33d6f00 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/stapip_qbuffer.hpp @@ -0,0 +1,83 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include "debug/debug.hpp" +#include "./bag/packaging/stapip_bag_package.hpp" +#include "./bag/stapip_bag.hpp" + +namespace Tyra { + +class StaPipQBuffer { + public: + StaPipQBuffer(); + ~StaPipQBuffer(); + + void setMaxVertCount(const u32& count); + + /** + * @brief Dont allocate any dynamic data in buffer. + * Just copy pointers to input data. + */ + void fillByPointer(const StaPipBagPackage& pkg); + + /** + * @brief Allocate dynamic data in buffer + * And copy input data to it. + */ + void fillByCopyMax(const StaPipBagPackage& pkg1, const StaPipBagPackage& pkg2, + const StaPipBagPackage& pkg3); + + /** + * @brief Allocate dynamic data in buffer + * And copy input data to it. + */ + void fillByCopy1By2(const StaPipBagPackage& pkg1, + const StaPipBagPackage& pkg2); + + /** + * @brief Allocate dynamic data in buffer + * And copy input data to it. + */ + void fillByCopy1By3(const StaPipBagPackage& pkg); + + /** + * @brief Deallocate dynamic data if it was allocated and allocate new data + * specified by size. + * @param size 48 is max + */ + void reallocateManually(const u16& size); + + bool any() const; + + StaPipBag* bag; + + Vec4* vertices; + Vec4* sts; + Vec4* colors; + Vec4* normals; + u32 size; + + void print() const; + void print(const char* name) const; + void print(const std::string& name) const { print(name.c_str()); } + std::string getPrint(const char* name = nullptr) const; + + private: + u32 maxVertCount; + void deallocateDynamicData(); + void allocateDynamicData(u16 size, StaPipBag* bag); + u8 _isDynamicallyAllocated, _stAllocated, _colorAllocated, _normalAllocated; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/stapip_qbuffer_renderer.hpp b/engine/inc/renderer/3d/pipeline/static/core/stapip_qbuffer_renderer.hpp new file mode 100644 index 0000000..ec32c7d --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/stapip_qbuffer_renderer.hpp @@ -0,0 +1,114 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include +#include "debug/debug.hpp" +#include "math/m4x4.hpp" +#include "renderer/renderer_settings.hpp" +#include "renderer/models/color.hpp" +#include "./stapip_qbuffer.hpp" +#include "./stapip_program_type.hpp" +#include "./stapip_program_name.hpp" +#include "./stapip_programs_repository.hpp" +#include "./stapip_clipper.hpp" +#include "renderer/core/paths/path1/path1.hpp" +#include "renderer/core/renderer_core.hpp" +#include "renderer/core/texture/renderer_core_texture_buffers.hpp" + +namespace Tyra { + +class StaPipQBufferRenderer { + public: + StaPipQBufferRenderer(); + ~StaPipQBufferRenderer(); + + void init(RendererCore* t_core, prim_t* prim, lod_t* lod); + + void reinitVU1(); + + void setClipperMVP(M4x4* mvp) { clipper.setMVP(mvp); } + + StaPipQBuffer* getBuffer(); + + void sendObjectData(StaPipBag* bag, M4x4* mvp, + RendererCoreTextureBuffers* texBuffers) const; + + void setMaxVertCount(const u32& count); + + void setInfo(PipelineInfoBag* bag); + + /** Fast render with culling */ + void cull(StaPipQBuffer* buffer); + + /** Slower render with clipping */ + void clip(StaPipQBuffer* buffer); + + void flushBuffers(); + + void clearLastProgramName(); + + StaPipVU1Program* getCullProgramByBag(const StaPipBag* bag); + + StaPipVU1Program* getCullProgramByParams(const bool& isLightingEnabled, + const bool& isTextureEnabled); + + const u16& getBufferSize() { return bufferSize; } + + void allocateOnUse(); + void deallocateOnUse(); + + private: + prim_t* prim; + lod_t* lod; + + bool is1stDBufferFlushTime(); + bool is2ndDBufferFlushTime(); + + void sendStaticData() const; + void setProgramsCache(); + void uploadPrograms(); + void setDoubleBuffer(); + u16 getQBufferIndex(StaPipQBuffer* buffer); + u16 qbuffersPacketSize; + + static const u16 buffersCount; + + StaPipVU1Program* getProgramByName(const StaPipProgramName& name); + void addBuffersDataToPacket(const u32& from, const u32& to); + void sendPacket(); + StaPipVU1Program* getAsIsProgramByBag(const StaPipBag* bag); + StaPipVU1Program* getCullProgramByType(const StaPipProgramType& programType); + StaPipProgramType getDrawProgramTypeByBag(const StaPipBag* bag) const; + StaPipProgramType getDrawProgramTypeByParams( + const bool& isLightingEnabled, const bool& isTextureEnabled) const; + packet2_t* programsPacket; + + packet2_t** packets; + StaPipVU1Program** dBufferPrograms; + StaPipQBuffer** buffers; + packet2_t* staticDataPacket; + packet2_t* objectDataPacket; + + RendererCore* rendererCore; + + StaPipProgramName lastProgramName; + Path1* path1; + StaPipClipper clipper; + StaPipProgramsRepository repository; + + u16 bufferSize, nextBufferIndex, currentBufferIndex; + u8 context; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/core/stapip_vu1_program.hpp b/engine/inc/renderer/3d/pipeline/static/core/stapip_vu1_program.hpp new file mode 100644 index 0000000..eda6c02 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/core/stapip_vu1_program.hpp @@ -0,0 +1,50 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "./stapip_program_name.hpp" +#include "renderer/core/paths/path1/vu1_program.hpp" +#include "./stapip_qbuffer.hpp" +#include "./programs/stapip_vu1_shared_defines.h" + +namespace Tyra { + +class StaPipVU1Program : public VU1Program { + public: + StaPipVU1Program(const StaPipProgramName& name, u32* start, u32* end, + const u32& t_reglist, const u8& t_reglistCount, + const u8& t_elementsPerVertex); + ~StaPipVU1Program(); + + u32& getReglist(); + + const StaPipProgramName& getName() const; + + u16 getMaxVertCount(const bool& singleColorEnabled, + const u16& vu1DBufferSize) const; + + void addBufferDataToPacket(packet2_t* packet, StaPipQBuffer* buffer, + prim_t* prim); + + protected: + StaPipProgramName name; + u8 reglistCount, elementsPerVertex; + u32 destinationAddress, reglist; + + virtual void addProgramQBufferDataToPacket(packet2_t* packet, + StaPipQBuffer* qbuffer) const = 0; + + private: + void addStandardBufferDataToPacket(packet2_t* packet, StaPipQBuffer* buffer, + prim_t* prim); +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/stapip_options.hpp b/engine/inc/renderer/3d/pipeline/static/stapip_options.hpp new file mode 100644 index 0000000..5c27feb --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/stapip_options.hpp @@ -0,0 +1,37 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "renderer/3d/pipeline/shared/pipeline_options.hpp" + +namespace Tyra { + +class StaPipOptions : public PipelineOptions { + public: + StaPipOptions() { fullClipChecks = false; } + ~StaPipOptions() {} + + /** + * @brief Experimental! True -> enables "clip against each plane" algorithm. + * Mandatory, default: False. + * + * Full clip checks are slow, but they are + * preventing visual artifacts, which can happen + * for big 3D objects (or objects near camera eyes). + * + * There is other way to prevent these glitches. Just convert your triangles + * to smaller triangles (for example 1 big triangle to 10 smaller). It will + * be way faster than enabling this option... + */ + bool fullClipChecks; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/pipeline/static/static_pipeline.hpp b/engine/inc/renderer/3d/pipeline/static/static_pipeline.hpp new file mode 100644 index 0000000..05b8ef4 --- /dev/null +++ b/engine/inc/renderer/3d/pipeline/static/static_pipeline.hpp @@ -0,0 +1,78 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "../renderer_3d_pipeline.hpp" +#include "../shared/pipeline_lighting_options.hpp" +#include "renderer/core/renderer_core.hpp" +#include "renderer/3d/mesh/static/static_mesh.hpp" +#include "./core/stapip_core.hpp" +#include "./stapip_options.hpp" + +namespace Tyra { + +/** + * Pipeline for static models (StaticMesh). + * Supports: + * - Full "against each plane" clipping and simple PS2 clipping + * (fullClipChecks), + * - Force enabled precise frustum culling (checks parts of given mesh) + * - Modes: color(s), texture+color(s), dir lights, texture + dir lights + */ +class StaticPipeline : public Renderer3DPipeline { + public: + StaticPipeline(); + ~StaticPipeline(); + + StaPipCore core; + + void setRenderer(RendererCore* core); + + void onUse(); + void onUseEnd(); + void onFrameEnd(); + + /** + * Render static model + * This render() method is a bridge to core.render() method. + */ + void render(const StaticMesh* mesh); + void render(const StaticMesh* mesh, const StaPipOptions& options); + void render(const StaticMesh* mesh, const StaPipOptions* options); + + private: + RendererCore* rendererCore; + Vec4* colorsCache; + + void addVertices(const MeshMaterialFrame* materialFrame, + StaPipBag* bag) const; + + StaPipInfoBag* getInfoBag(const StaticMesh* mesh, + const StaPipOptions* options, M4x4* model) const; + + StaPipColorBag* getColorBag(const MeshMaterial* material, + const MeshMaterialFrame* materialFrame) const; + + StaPipTextureBag* getTextureBag(const MeshMaterial* material, + const MeshMaterialFrame* materialFrame); + + StaPipLightingBag* getLightingBag(const MeshMaterialFrame* materialFrame, + PipelineDirLightsBag* dirLightsBag, + M4x4* model, + const StaPipOptions* options) const; + + void deallocDrawBags(StaPipBag* bag, const MeshMaterial* material) const; + + void setLightingColorsCache(PipelineLightingOptions* lightingOptions); +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/renderer_3d.hpp b/engine/inc/renderer/3d/renderer_3d.hpp new file mode 100644 index 0000000..7825f8c --- /dev/null +++ b/engine/inc/renderer/3d/renderer_3d.hpp @@ -0,0 +1,41 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "./pipeline/renderer_3d_pipeline.hpp" +#include "./renderer_3d_utility.hpp" +#include "../core/renderer_core.hpp" + +namespace Tyra { + +class Renderer3D { + public: + Renderer3D(); + ~Renderer3D(); + + Renderer3DUtility utility; + + /** Deinitialize previous pipeline and initialize new pipeline */ + void usePipeline(Renderer3DPipeline* pipeline); + void usePipeline(Renderer3DPipeline& pipeline); + + /** Called by engine */ + void init(RendererCore* core); + + /** Called by engine */ + void onFrameEnd(); + + private: + Renderer3DPipeline* currentPipeline; + void onDestroy(Renderer3DPipeline* pipeline); +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/3d/renderer_3d_utility.hpp b/engine/inc/renderer/3d/renderer_3d_utility.hpp new file mode 100644 index 0000000..4d48171 --- /dev/null +++ b/engine/inc/renderer/3d/renderer_3d_utility.hpp @@ -0,0 +1,67 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "math/vec4.hpp" +#include "renderer/models/color.hpp" +#include "renderer/core/3d/bbox/core_bbox.hpp" +#include "../core/renderer_core.hpp" +#include "renderer/core/3d/clipper/planes_clip_algorithm.hpp" + +namespace Tyra { + +/** + * Debug functions, without z buffer, with bad performance. + * + * Remember to use these functions AFTER all 3D rendering, + * otherwise lines will be overwritten! There is Github issue about that. + */ +class Renderer3DUtility { + public: + Renderer3DUtility(); + ~Renderer3DUtility(); + + void init(RendererCore* core); + + void drawBox(const Vec4& v, const float& size); + void drawBox(const Vec4& v, const float& size, const Color& color); + + void drawLine(const Vec4& from, const Vec4& to); + void drawLine(const Vec4& from, const Vec4& to, const Color& color); + + void drawBBox(const CoreBBox& v); + void drawBBox(const CoreBBox& v, const Color& color); + + private: + std::array clippedVerts; + std::array clipInput; + + RendererCore* core; + prim_t prim; + + Vec4 convertVertices(const Vec4& v, const Vec4& scale); + + void fillBBoxVertices(std::array, 6>& v, + const CoreBBox& bbox); + + color_t getGSColor(const Color& color); + + /** + * @return true - To draw + * @return false - To skip (outside view frustum) + */ + bool calcLineVertices(xyz_t* outputArray, const Vec4& a, const Vec4& b, + const Vec4& scale); + + PlanesClipAlgorithm planesClipAlgorithm; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/core/2d/renderer_core_2d.hpp b/engine/inc/renderer/core/2d/renderer_core_2d.hpp new file mode 100644 index 0000000..aaa1d4d --- /dev/null +++ b/engine/inc/renderer/core/2d/renderer_core_2d.hpp @@ -0,0 +1,50 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "debug/debug.hpp" +#include "renderer/core/2d/sprite/sprite.hpp" +#include "renderer/core/texture/renderer_core_texture_buffers.hpp" +#include "renderer/core/texture/models/texture.hpp" +#include "renderer/renderer_settings.hpp" +#include +#include + +namespace Tyra { + +class RendererCore2D { + public: + RendererCore2D(); + ~RendererCore2D(); + + void init(RendererSettings* settings, clutbuffer_t* clutBuffer); + + void render(const Sprite& sprite, + const RendererCoreTextureBuffers& texBuffers, Texture* texture); + + private: + void setPrim(); + void setLod(); + + prim_t prim; + lod_t lod; + + static const float GS_DRAW_AREA; + static const float SCREEN_CENTER; + + u8 context; + RendererSettings* settings; + clutbuffer_t* clutBuffer; + packet2_t* packets[2]; + texrect_t* rects[2]; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/core/2d/sprite/sprite.hpp b/engine/inc/renderer/core/2d/sprite/sprite.hpp new file mode 100644 index 0000000..6580a2d --- /dev/null +++ b/engine/inc/renderer/core/2d/sprite/sprite.hpp @@ -0,0 +1,37 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include "./sprite_mode.hpp" +#include "math/vec2.hpp" +#include "renderer/models/color.hpp" + +namespace Tyra { + +class Sprite { + public: + Sprite(); + ~Sprite(); + + u32 id; + Vec2 position, size; + float scale; + Color color; + SpriteMode mode; + bool flipHorizontal, flipVertical; + + private: + void setDefaultColor(); +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/core/2d/sprite/sprite_mode.hpp b/engine/inc/renderer/core/2d/sprite/sprite_mode.hpp new file mode 100644 index 0000000..16be08f --- /dev/null +++ b/engine/inc/renderer/core/2d/sprite/sprite_mode.hpp @@ -0,0 +1,17 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +namespace Tyra { + +enum SpriteMode { MODE_STRETCH, MODE_REPEAT }; + +} diff --git a/engine/inc/renderer/core/3d/bbox/core_bbox.hpp b/engine/inc/renderer/core/3d/bbox/core_bbox.hpp new file mode 100644 index 0000000..9c05911 --- /dev/null +++ b/engine/inc/renderer/core/3d/bbox/core_bbox.hpp @@ -0,0 +1,91 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include "./core_bbox_frustum.hpp" +#include "math/m4x4.hpp" +#include "math/plane.hpp" +#include + +namespace Tyra { + +/** Bounding box */ +class CoreBBox { + public: + CoreBBox(); + CoreBBox(const CoreBBox& t_bbox); + explicit CoreBBox(const Vec4* t_vertices, const u32* faces, + const u32& t_count); + explicit CoreBBox(const Vec4* t_vertices, const u32& t_count); + explicit CoreBBox(const Vec4* t_vertices); + explicit CoreBBox(CoreBBox** t_bboxes, const u32& count); + explicit CoreBBox(const std::vector& t_bboxes, + const u32& startIndex, const u32& stopIndex); + explicit CoreBBox(const CoreBBox& t_bbox, const M4x4& t_matrix); + + static CoreBBox create(const Vec4& center, const float& size); + + /** + * 0 - lowX, lowY, lowZ + * 1 - lowX, lowY, hiZ + * 2 - lowX, hiY, lowZ + * 3 - lowX, hiY, hiZ + * 4 - hiX, lowY, lowZ + * 5 - hiX, lowY, hiZ + * 6 - hiX, hiY, lowZ + * 7 - hiX, hiY, hiZ + */ + Vec4 vertices[8]; + + void operator=(const CoreBBox& v); + + const Vec4& operator[](const u8& i) const { return vertices[i]; } + + const u8 getVertexCount() const { return 8; } + + void print() const; + void print(const char* name) const; + void print(const std::string& name) const { print(name.c_str()); } + std::string getPrint(const char* name = nullptr) const; + + /** Get new transformed BBox by model matrix */ + CoreBBox getTransformed(const M4x4& t_matrix) const; + + /** + * @brief Check if bbox is in/partially/outside view frustum + * + * @param frustumPlanes Available in + * engine.renderer.core.renderer3D.frustumPlanes + * @param model Model matrix if you want to fix bbox by model matrix + * @param margins Optional margins + */ + CoreBBoxFrustum frustumCheck(const Plane* frustumPlanes, const M4x4& model, + const float* margins = nullptr) const; + CoreBBoxFrustum frustumCheck(const Plane* frustumPlanes, + const float* margins = nullptr) const; + + /** + * @brief Check if bbox is in view frustum + * + * @param frustumPlanes Available in + * engine.renderer.core.renderer3D.frustumPlanes + * @param model Model matrix if you want to fix bbox by model matrix + */ + bool isInFrustum(const Plane* frustumPlanes, const M4x4& model) const; + bool isInFrustum(const Plane* frustumPlanes) const; + + private: + static std::array frustumCheckVertices; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/core/3d/bbox/core_bbox_frustum.hpp b/engine/inc/renderer/core/3d/bbox/core_bbox_frustum.hpp new file mode 100644 index 0000000..a429bcf --- /dev/null +++ b/engine/inc/renderer/core/3d/bbox/core_bbox_frustum.hpp @@ -0,0 +1,17 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +namespace Tyra { + +enum CoreBBoxFrustum { IN_FRUSTUM, OUTSIDE_FRUSTUM, PARTIALLY_IN_FRUSTUM }; + +} // namespace Tyra diff --git a/engine/inc/renderer/core/3d/bbox/render_bbox.hpp b/engine/inc/renderer/core/3d/bbox/render_bbox.hpp new file mode 100644 index 0000000..4cd4b04 --- /dev/null +++ b/engine/inc/renderer/core/3d/bbox/render_bbox.hpp @@ -0,0 +1,37 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "./core_bbox.hpp" + +namespace Tyra { + +/** Bounding box */ +class RenderBBox : public CoreBBox { + public: + explicit RenderBBox(const Vec4* t_vertices, const u32* faces, + const u32& t_count); + explicit RenderBBox(const Vec4* t_vertices, const u32& t_count); + explicit RenderBBox(const Vec4* t_vertices); + explicit RenderBBox(CoreBBox** t_bboxes, const u32& count); + explicit RenderBBox(const std::vector& t_bboxes, + const u32& startIndex, const u32& stopIndex); + explicit RenderBBox(const RenderBBox& t_bbox, const M4x4& t_matrix); + + CoreBBoxFrustum clipFrustumCheck(const Plane* frustumPlanes, + const M4x4& model) const; + + /** Get new transformed BBox by model matrix */ + RenderBBox getTransformed(const M4x4& t_matrix) const; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/core/3d/camera_info_3d.hpp b/engine/inc/renderer/core/3d/camera_info_3d.hpp new file mode 100644 index 0000000..dd1bd08 --- /dev/null +++ b/engine/inc/renderer/core/3d/camera_info_3d.hpp @@ -0,0 +1,29 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "math/vec4.hpp" + +namespace Tyra { + +class CameraInfo3D { + public: + CameraInfo3D(const Vec4* cameraPosition, const Vec4* cameraLooksAt, + const Vec4* cameraUp = nullptr); + ~CameraInfo3D(); + + const Vec4 *position, *looksAt, *up; + + private: + static Vec4 defaultCameraUp; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/core/3d/clipper/planes_clip_algorithm.hpp b/engine/inc/renderer/core/3d/clipper/planes_clip_algorithm.hpp new file mode 100644 index 0000000..80b5161 --- /dev/null +++ b/engine/inc/renderer/core/3d/clipper/planes_clip_algorithm.hpp @@ -0,0 +1,52 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "./planes_clip_vertex.hpp" +#include "debug/debug.hpp" +#include "renderer/renderer_settings.hpp" + +namespace Tyra { + +struct EEClipAlgorithmSettings { + bool lerpNormals, lerpTexCoords, lerpColors; +}; + +class PlanesClipAlgorithm { + public: + PlanesClipAlgorithm(); + ~PlanesClipAlgorithm(); + + void init(const RendererSettings& settings); + + u8 clip(PlanesClipVertex* o_vertices, PlanesClipVertexPtrs* i_vertices, + const EEClipAlgorithmSettings& settings); + + static float clipMargin; + + private: + float halfWidth, halfHeight, near, far; + PlanesClipVertex* tempVertices; + + float getValueByPlane(const PlanesClipVertex& v, const int& plane); + + bool isInside(const int& plane, const float& v, const float& w, + const float& planeLimitValue); + + /** @return clipped size */ + u8 clipAgainstPlane(PlanesClipVertex* original, const u8& originalSize, + PlanesClipVertex* clipped, const int& plane, + const float& planeLimitValue, + const EEClipAlgorithmSettings& settings); +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/core/3d/clipper/planes_clip_vertex.hpp b/engine/inc/renderer/core/3d/clipper/planes_clip_vertex.hpp new file mode 100644 index 0000000..b6cf407 --- /dev/null +++ b/engine/inc/renderer/core/3d/clipper/planes_clip_vertex.hpp @@ -0,0 +1,25 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "math/vec4.hpp" + +namespace Tyra { + +struct PlanesClipVertex { + Vec4 position, normal, st, color; +}; + +struct PlanesClipVertexPtrs { + Vec4 *position, *normal, *st, *color; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/core/3d/renderer_3d_frustum_planes.hpp b/engine/inc/renderer/core/3d/renderer_3d_frustum_planes.hpp new file mode 100644 index 0000000..c8450ed --- /dev/null +++ b/engine/inc/renderer/core/3d/renderer_3d_frustum_planes.hpp @@ -0,0 +1,45 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "renderer/renderer_settings.hpp" +#include "./camera_info_3d.hpp" +#include "math/plane.hpp" + +namespace Tyra { + +class Renderer3DFrustumPlanes { + public: + Renderer3DFrustumPlanes(); + ~Renderer3DFrustumPlanes(); + + void init(RendererSettings* settings, const float& fov); + void update(const CameraInfo3D& cameraInfo, const float& fov); + const Plane& get(u8 index) const { return frustumPlanes[index]; } + const Plane* getAll() const { return frustumPlanes; } + const Plane& operator[](u8 index) const { return frustumPlanes[index]; } + + void print() const; + void print(const char* name) const; + void print(const std::string& name) const { print(name.c_str()); } + std::string getPrint(const char* name = nullptr) const; + + private: + void computeStaticData(const float& fov); + float lastFov; + RendererSettings* settings; + Plane frustumPlanes[6]; + float nearHeight, nearWidth, farHeight, farWidth; + Vec4 nearCenter, farCenter, X, Y, Z, ntl, ntr, nbl, nbr, ftl, fbr, ftr, fbl; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/core/3d/renderer_core_3d.hpp b/engine/inc/renderer/core/3d/renderer_core_3d.hpp new file mode 100644 index 0000000..ec67ea6 --- /dev/null +++ b/engine/inc/renderer/core/3d/renderer_core_3d.hpp @@ -0,0 +1,98 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "renderer/renderer_settings.hpp" +#include "./renderer_3d_frustum_planes.hpp" +#include "./camera_info_3d.hpp" +#include "renderer/core/texture/models/texture.hpp" +#include "renderer/core/3d/bbox/core_bbox.hpp" +#include "renderer/core/paths/path1/path1.hpp" + +namespace Tyra { + +class RendererCore3D { + public: + RendererCore3D(); + ~RendererCore3D(); + + /** Current camera frustum planes. */ + Renderer3DFrustumPlanes frustumPlanes; + + /** Called by renderer. */ + void init(RendererSettings* settings, Path1* t_path1); + + const float& getFov() const { return fov; } + + void setFov(const float& t_fov); + + /** + * Called by beginFrame(); + * Sets 3D support to off + */ + void update(); + + /** + * Called by beginFrame(); + * Updates camera info, to get proper frustum culling. + * Sets 3D support to on + */ + void update(const CameraInfo3D& cameraInfo); + + /** Get projection (screen) matrix */ + const M4x4& getProjection() { return projection; } + + /** + * Get view (camera) matrix + * Updated at every beginFrame() + */ + const M4x4& getView(); + + /** + * Get projection * view matrix + * Updated at every beginFrame() + */ + const M4x4& getViewProj(); + + /** + * @brief + * Upload VU1 program. + * Please pay attention that you will be REPLACING + * current VU1 programs + * + * @param address Starting address of your program. + * @return Address of the end of your program, so next program can start from + * this + 1 + */ + u32 uploadVU1Program(VU1Program* program, const u32& address); + + /** + * @brief Set VU1 double buffer + * + * @param startingAddress Starting address. Example 10. + * @param bufferSize Buffer size. Example 490, so second buffer will start + * from 490+10 + */ + void setVU1DoubleBuffers(const u16& startingAddress, const u16& bufferSize); + + private: + M4x4 view, projection, viewProj; + float fov; + bool is3DSupportEnabled; + + RendererSettings* settings; + + Path1* path1; + void setProjection(); +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/core/gs/renderer_core_gs.hpp b/engine/inc/renderer/core/gs/renderer_core_gs.hpp new file mode 100644 index 0000000..bfad7e3 --- /dev/null +++ b/engine/inc/renderer/core/gs/renderer_core_gs.hpp @@ -0,0 +1,52 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "renderer/renderer_settings.hpp" +#include "./renderer_core_gs_vram.hpp" +#include "../renderer_core_sync.hpp" + +namespace Tyra { + +class RendererCoreGS { + public: + RendererCoreGS(); + ~RendererCoreGS(); + + zbuffer_t zBuffer; + RendererCoreGSVRam vram; + + void init(RendererSettings* settings); + + void flipBuffers(); + + void enableZTests(); + + private: + constexpr static float gsCenter = 4096.0F; + constexpr static float screenCenter = gsCenter / 2.0F; + + RendererSettings* settings; + framebuffer_t frameBuffers[2]; + packet2_t* flipPacket; + packet2_t* zTestPacket; + u8 context; + u8 currentField; + + void allocateBuffers(); + void initDrawingEnvironment(); + void initChannels(); + void updateCurrentField(); + qword_t* setXYOffset(qword_t* q, const int& drawContext, const float& x, + const float& y); +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/core/gs/renderer_core_gs_vram.hpp b/engine/inc/renderer/core/gs/renderer_core_gs_vram.hpp new file mode 100644 index 0000000..ecd3921 --- /dev/null +++ b/engine/inc/renderer/core/gs/renderer_core_gs_vram.hpp @@ -0,0 +1,48 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "renderer/renderer_settings.hpp" +#include "renderer/core/texture/models/texture.hpp" + +namespace Tyra { + +class RendererCoreGSVRam { + public: + RendererCoreGSVRam(); + ~RendererCoreGSVRam(); + + const float& getFreeSpaceInMB(); + + float getSizeInMB(const Texture& texture); + float getSizeInMB(const TextureData& texData); + float getSizeInMB(int width, const int& height, const int& psm, + const int& alignment); + + int allocate(const TextureData& texData); + int allocateBuffer(const int& width, const int& height, const int& psm); + int allocate(const int& width, const int& height, const int& psm, + const int& alignment); + + /** Free texture, FIFO order */ + void free(const int& address); + + private: + int getSize(int width, const int& height, const int& psm, + const int& alignment); + + static constexpr float ptr2MB = 262144.0F; + bool touched; + int pointer; + float cachedFreeSpace; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/core/paths/path1/path1.hpp b/engine/inc/renderer/core/paths/path1/path1.hpp new file mode 100644 index 0000000..3df6a82 --- /dev/null +++ b/engine/inc/renderer/core/paths/path1/path1.hpp @@ -0,0 +1,45 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include "debug/debug.hpp" +#include "./vu1_program.hpp" + +namespace Tyra { + +class Path1 { + public: + Path1(); + ~Path1(); + + u32 uploadProgram(VU1Program* program, const u32& address); + + void sendDrawFinishTag(); + + void addDrawFinishTag(packet2_t* packet); + + packet2_t* createProgramsCache(VU1Program** programs, const u32& count, + const u32& address); + + void setDoubleBuffer(const u16& startingAddress, const u16& bufferSize); + + private: + void uploadDrawFinishProgram(); + void prepareDrawFinishPacket(); + + packet2_t* doubleBufferPacket; + packet2_t* drawFinishPacket; + u32 drawFinishAddr; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/core/paths/path1/vu1_program.hpp b/engine/inc/renderer/core/paths/path1/vu1_program.hpp new file mode 100644 index 0000000..93393a1 --- /dev/null +++ b/engine/inc/renderer/core/paths/path1/vu1_program.hpp @@ -0,0 +1,41 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include + +namespace Tyra { + +class VU1Program { + public: + VU1Program(u32* start, u32* end); + ~VU1Program(); + + const u32& getPacketSize() const; + const u32& getProgramSize() const; + const u32& getDestinationAddress() const; + + u32* getStart() const; + u32* getEnd() const; + + virtual std::string getStringName() const = 0; + + void setDestinationAddress(const u32& addr); + + protected: + u32 packetSize, destinationAddress, programSize; + u32 *start, *end; + u32 calculateProgramSize() const; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/core/paths/path3/path3.hpp b/engine/inc/renderer/core/paths/path3/path3.hpp new file mode 100644 index 0000000..bb673c4 --- /dev/null +++ b/engine/inc/renderer/core/paths/path3/path3.hpp @@ -0,0 +1,42 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include +#include "renderer/core/texture/models/texture.hpp" +#include "renderer/renderer_settings.hpp" +#include "renderer/models/color.hpp" +#include "renderer/core/texture/renderer_core_texture_buffers.hpp" + +namespace Tyra { + +class Path3 { + public: + Path3(); + ~Path3(); + + void init(RendererSettings* settings); + + void sendDrawFinishTag(); + void clearScreen(zbuffer_t* z, const Color& color); + void sendTexture(const Texture* texture, + const RendererCoreTextureBuffers& texBuffers); + + private: + packet2_t* drawFinishPacket; + packet2_t* clearScreenPacket; + packet2_t* texturePacket; + RendererSettings* settings; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/core/renderer_core.hpp b/engine/inc/renderer/core/renderer_core.hpp new file mode 100644 index 0000000..149e29e --- /dev/null +++ b/engine/inc/renderer/core/renderer_core.hpp @@ -0,0 +1,76 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "./2d/renderer_core_2d.hpp" +#include "./3d/renderer_core_3d.hpp" +#include "./gs/renderer_core_gs.hpp" +#include "./texture/renderer_core_texture.hpp" +#include "./paths/path3/path3.hpp" +#include "./paths/path1/path1.hpp" +#include "./renderer_core_sync.hpp" + +namespace Tyra { + +class RendererCore { + public: + RendererCore(); + ~RendererCore(); + + /** Responsible for initializing GS. */ + RendererCoreGS gs; + + /** All logic responsible for 3D drawing. */ + RendererCore3D renderer3D; + + /** All logic responsible for 2D drawing. */ + RendererCore2D renderer2D; + + /** Texture transferring. */ + RendererCoreTexture texture; + + /** EE <-> VU1 synchronization */ + RendererCoreSync sync; + + /** Called by renderer */ + void init(); + + /** World background color */ + void setClearScreenColor(const Color& color); + + /** Clear screen and update view frustum for frustum culling. NO 3D support */ + void beginFrame(); + + /** Clear screen and update view frustum for frustum culling. 3D support */ + void beginFrame(const CameraInfo3D& cameraInfo); + + /** VSync and swap frame double buffer. */ + void endFrame(); + + void setFrameLimit(const bool& onoff) { isFrameLimitOn = onoff; } + + /** Get screen settings */ + const RendererSettings& getSettings() const { return settings; } + + Path1* getPath1() { return &path1; } + + Path3* getPath3() { return &path3; } + + private: + bool isFrameLimitOn; + Color bgColor; + RendererSettings settings; + Path3 path3; + Path1 path1; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/core/renderer_core_sync.hpp b/engine/inc/renderer/core/renderer_core_sync.hpp new file mode 100644 index 0000000..878547e --- /dev/null +++ b/engine/inc/renderer/core/renderer_core_sync.hpp @@ -0,0 +1,58 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include "./paths/path3/path3.hpp" +#include "./paths/path1/path1.hpp" + +namespace Tyra { + +/** + * Synchronization class. + * Mainly between VU1 and EE. + * + * For example you can set texture, render X vertices, then add() wait, and + * wait() for it. Without it, there is risk for example to send new texture + * during drawing with previous one. + */ +class RendererCoreSync { + public: + RendererCoreSync(); + ~RendererCoreSync(); + + void init(Path3* path3, Path1* path1); + + // --- Auto + + /** clear() -> sendPath1Req() -> waitAndClear() */ + void align3D(); + + /** clear() -> sendPath3Req() -> waitAndClear() */ + void align2D(); + + // --- Manual + + u8 check(); + void clear(); + void waitAndClear(); + void sendPath1Req(); + void sendPath3Req(); + + void addPath1Req(packet2_t* packet); + + private: + Path3* path3; + Path1* path1; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/core/texture/models/texture.hpp b/engine/inc/renderer/core/texture/models/texture.hpp new file mode 100644 index 0000000..ce58589 --- /dev/null +++ b/engine/inc/renderer/core/texture/models/texture.hpp @@ -0,0 +1,105 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include +#include "./texture_link.hpp" +#include "./texture_wrap.hpp" +#include "../texture_data.hpp" +#include "loaders/texture/builder/texture_builder_data.hpp" +#include "debug/debug.hpp" + +namespace Tyra { + +/** + * Class which contains texture data. + * Textures are paired with meshes/sprites via addLink() and + * removeLink() functions which use meshId/spriteId and materialId (for mesh). + */ +class Texture { + public: + Texture(TextureBuilderData* data); + ~Texture(); + + u32 id; + std::string name; + TextureData* core; + TextureData* clut; + + /** Array of texture links with sprites/meshes */ + std::vector links; + + inline const int& getWidth() const { return core->width; } + + inline const int& getHeight() const { return core->height; } + + float getSizeInMB() const; + + inline const texwrap_t* getWrapSettings() const { return &wrap; } + + inline const std::vector& getTextureLinks() const { + return links; + } + + /** + * Returns index of link. + * -1 if not found. + * @param t_id + * For 3D: MeshMaterial id. + * For 2D: Sprite id. + */ + const s32 getIndexOfLink(const u32& t_id) const; + + /** Set texture wrapping */ + void setWrapSettings(const TextureWrap t_horizontal, + const TextureWrap t_vertical); + + // ---- + // Other + // ---- + + /** Assign texture to Sprite.Id or MeshMaterial.Id. */ + void addLink(const u32& t_id); + + u32 getTextureSize() const; + + /** + * Check if texture is linked with MeshMaterial/Sprite. + * @param t_id + * For 3D: MeshMaterial material id. + * For 2D: Sprite id. + */ + const u8 isLinkedWith(const u32& t_id) const; + + void removeLinkByIndex(const u32& t_index); + + /** + * Remove texture link with given MeshMaterial/Sprite. + * @param t_id + * For 3D: MeshMaterial material id. + * For 2D: Sprite id. + */ + void removeLinkById(const u32& t_id); + + void print() const; + void print(const char* name) const; + void print(const std::string& name) const { print(name.c_str()); } + std::string getPrint(const char* name = nullptr) const; + + private: + void setPsm(); + void setDefaultWrapSettings(); + + texwrap_t wrap; +}; +} // namespace Tyra diff --git a/engine/inc/renderer/core/texture/models/texture_bpp.hpp b/engine/inc/renderer/core/texture/models/texture_bpp.hpp new file mode 100644 index 0000000..609513b --- /dev/null +++ b/engine/inc/renderer/core/texture/models/texture_bpp.hpp @@ -0,0 +1,38 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +namespace Tyra { + +enum TextureBpp { + + /** + * @brief 32-bit RGBA - Slowest + */ + bpp32 = 32, + + /** + * @brief 24-bit RGB - Slow + */ + bpp24 = 24, + + /** + * @brief 8-bit palletized (indexed) - Super fast + */ + bpp8 = 8, + + /** + * @brief 4-bit palletized (indexed) - Super, super fast + */ + bpp4 = 4, +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/core/texture/models/texture_link.hpp b/engine/inc/renderer/core/texture/models/texture_link.hpp new file mode 100644 index 0000000..c2ae733 --- /dev/null +++ b/engine/inc/renderer/core/texture/models/texture_link.hpp @@ -0,0 +1,23 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include + +namespace Tyra { +struct TextureLink { + /** + * For 3D: MeshMaterial material id. + * For 2D: Sprite id. + */ + u32 id; +}; +} // namespace Tyra diff --git a/engine/inc/renderer/core/texture/models/texture_wrap.hpp b/engine/inc/renderer/core/texture/models/texture_wrap.hpp new file mode 100644 index 0000000..879d473 --- /dev/null +++ b/engine/inc/renderer/core/texture/models/texture_wrap.hpp @@ -0,0 +1,15 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +namespace Tyra { +enum TextureWrap { Repeat = 0, Clamp = 1, RegionClamp = 2, RegionRepeat = 3 }; +} diff --git a/engine/inc/renderer/core/texture/renderer_core_texture.hpp b/engine/inc/renderer/core/texture/renderer_core_texture.hpp new file mode 100644 index 0000000..98a05b5 --- /dev/null +++ b/engine/inc/renderer/core/texture/renderer_core_texture.hpp @@ -0,0 +1,51 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include "./texture_repository.hpp" +#include "./renderer_core_texture_sender.hpp" +#include "renderer/core/paths/path3/path3.hpp" +#include "./renderer_core_texture_buffers.hpp" + +namespace Tyra { + +class RendererCoreTexture { + public: + RendererCoreTexture(); + ~RendererCoreTexture(); + + clutbuffer_t clut; + TextureRepository repository; + + RendererCoreTextureBuffers useTexture(const Texture* t_tex); + + /** Called by renderer during initialization */ + void init(RendererCoreGS* gs, Path3* path3); + + /** Called by renderer during rendering */ + void updateClutBuffer(texbuffer_t* clutBuffer); + + private: + std::vector currentAllocations; + + void initClut(); + void registerAllocation(const RendererCoreTextureBuffers& t_buffers); + void unregisterAllocation(const u32& textureId); + RendererCoreTextureBuffers getAllocatedBuffersByTextureId(const u32& id); + + RendererCoreGS* gs; + RendererCoreTextureSender sender; + Path3* path3; +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/core/texture/renderer_core_texture_buffers.hpp b/engine/inc/renderer/core/texture/renderer_core_texture_buffers.hpp new file mode 100644 index 0000000..0aaceed --- /dev/null +++ b/engine/inc/renderer/core/texture/renderer_core_texture_buffers.hpp @@ -0,0 +1,35 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include + +namespace Tyra { + +struct RendererCoreTextureBuffers { + /** Texture id */ + u32 id; + + /** + * Texture data. + * Used in: 4bpp, 8bpp, 24bpp, 32bpp. + */ + texbuffer_t* core; + + /** + * Texture pallete data. + * Used in: 4bpp, 8bpp (otherwise nullptr). + */ + texbuffer_t* clut; +}; + +} // namespace Tyra \ No newline at end of file diff --git a/engine/inc/renderer/core/texture/renderer_core_texture_sender.hpp b/engine/inc/renderer/core/texture/renderer_core_texture_sender.hpp new file mode 100644 index 0000000..ef8dfb1 --- /dev/null +++ b/engine/inc/renderer/core/texture/renderer_core_texture_sender.hpp @@ -0,0 +1,44 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include +#include "./models/texture.hpp" +#include "renderer/core/paths/path3/path3.hpp" +#include "renderer/core/gs/renderer_core_gs.hpp" +#include "./renderer_core_texture_buffers.hpp" + +namespace Tyra { + +class RendererCoreTextureSender { + public: + RendererCoreTextureSender(); + ~RendererCoreTextureSender(); + + void init(Path3* path3, RendererCoreGS* gs); + + RendererCoreTextureBuffers allocate(const Texture* t_texture); + + void deallocate(const RendererCoreTextureBuffers& texBuffers); + + float getSizeInMB(texbuffer_t* texBuffer); + + private: + RendererCoreGS* gs; + Path3* path3; + TextureBpp getBppByPsm(const u32& psm); + texbuffer_t* allocateTextureCore(const Texture* t_texture); + texbuffer_t* allocateTextureClut(const Texture* t_texture); +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/core/texture/texture_data.hpp b/engine/inc/renderer/core/texture/texture_data.hpp new file mode 100644 index 0000000..1c601eb --- /dev/null +++ b/engine/inc/renderer/core/texture/texture_data.hpp @@ -0,0 +1,40 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include "renderer/core/texture/models/texture_bpp.hpp" + +namespace Tyra { + +class TextureData { + public: + TextureData(unsigned char* data, const TextureBpp& bpp, + const unsigned char& gsComponents, const int& width, + const int& height); + ~TextureData(); + + int width, height; + u32 psm; + unsigned char* data; + TextureBpp bpp; + unsigned char components; + + void print() const; + void print(const unsigned char* name) const; + void print(const std::string& name) const { print(name.c_str()); } + std::string getPrint(const unsigned char* name = nullptr) const; + + private: + u32 getPsmByBpp(const TextureBpp& bpp); +}; +} // namespace Tyra diff --git a/engine/inc/renderer/core/texture/texture_repository.hpp b/engine/inc/renderer/core/texture/texture_repository.hpp new file mode 100644 index 0000000..519b3cc --- /dev/null +++ b/engine/inc/renderer/core/texture/texture_repository.hpp @@ -0,0 +1,115 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include +#include +#include "./models/texture.hpp" +#include "renderer/3d/mesh/mesh.hpp" +#include "renderer/core/2d/sprite/sprite.hpp" +#include "loaders/texture/base/texture_loader_selector.hpp" +#include + +namespace Tyra { +class TextureRepository { + public: + TextureRepository(); + ~TextureRepository(); + + /** Returns all repository textures. */ + std::vector* getAll() { return &textures; } + + u32 getTexturesCount() const { return static_cast(textures.size()); } + + /** + * Returns single texture. + * nullptr if not found. + */ + Texture* getBySpriteId(const u32& t_id) const; + + /** + * Returns single texture. + * nullptr if not found. + */ + Texture* getByMeshMaterialId(const u32& t_id) const; + + /** + * Returns single texture. + * nullptr if not found. + */ + Texture* getByTextureId(const u32& t_id) const; + + /** + * Returns index of link. + * -1 if not found. + */ + const s32 getIndexOf(const u32& t_texId) const; + + /** + * Add unlinked texture. + * @param fullpath Full path to texture file. Example: "host:texture.png" + */ + Texture* add(const char* fullpath); + + /** + * Add unlinked texture. + * @param fullpath Full path to texture file. Example: "host:texture.png" + */ + inline Texture* add(const std::string& fullpath) { + return add(fullpath.c_str()); + } + + /** + * Add unlinked texture. + * @param texture Your own texture + */ + Texture* add(Texture* texture); + + /** + * Add linked textures in given path for mesh material names. + */ + void addByMesh(const Mesh* mesh, const char* directory, + const char* extension); + + /** + * Add linked textures in given path for mesh material names. + */ + inline void addByMesh(const Mesh* mesh, const std::string& directory, + const char* extension) { + addByMesh(mesh, directory.c_str(), extension); + } + + /** + * Remove texture from repository. + * Texture IS destructed. + */ + void free(const u32& texId); + void free(const Texture* tex); + void free(const Texture& tex); + void freeBySprite(const Sprite& sprite); + void freeByMesh(const Mesh& mesh); + void freeByMesh(const Mesh* mesh); + + /** + * Remove texture from repository. + * Texture is NOT destructed. + * Not recommended. + */ + void removeById(const u32& t_texId); + + private: + void removeByIndex(const u32& t_index); + + std::vector textures; + TextureLoaderSelector texLoaderSelector; +}; +} // namespace Tyra diff --git a/engine/inc/renderer/models/color.hpp b/engine/inc/renderer/models/color.hpp new file mode 100644 index 0000000..069951c --- /dev/null +++ b/engine/inc/renderer/models/color.hpp @@ -0,0 +1,92 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "math/vec4.hpp" + +namespace Tyra { + +class Color { + public: + union { + struct { + /** 0-255 */ + float r; + /** 0-255 */ + float g; + /** 0-255 */ + float b; + /** 0-128 */ + float a; + }; + VECTOR rgba alignas(sizeof(float) * 4); + }; + + static void copy(Color* out, const float* in); + static inline void copy(Color* out, const Color& in) { copy(out, in.rgba); } + + /** Initialize Color without setting default values */ + Color() {} + + /** Initialize Color with provided values */ + Color(const float& r, const float& g = 255.0F, const float& b = 255.0F, + const float& a = 128.0F) + : r(r), g(g), b(b), a(a) {} + + /** Initialize Color with other Color values */ + Color(const Color& v) { copy(this, v); } + + /** Initialize Color with float[4] values */ + explicit Color(const float* v) { copy(this, v); } + + void operator=(const Color& v); + void operator+=(const float& v); + void operator-=(const float& v); + void operator*=(const float& v); + void operator/=(const float& v); + Color operator+(const float& v) const; + Color operator-(const float& v) const; + Color operator*(const float& v) const; + Color operator/(const float& v) const; + + inline void set(const Color& v) { copy(this, v.rgba); } + inline void set(const float* v) { copy(this, v); } + void set(const float& r, const float& g = 255.0F, const float& b = 255.0F, + const float& a = 128.0F); + + /** + * Update this vector by linear interpolation between two vertices + * @param v1 Before vertex + * @param v2 After vertex + * @param interp State of interpolation + */ + void lerp(const Color& v1, const Color& v2, const float& interp); + + /** + * Get vector by linear interpolation between two vertices + * @param v1 Before vertex + * @param v2 After vertex + * @param interp State of interpolation + */ + static Color getByLerp(const Color& v1, const Color& v2, const float& interp); + + void print() const; + void print(const char* name) const; + void print(const std::string& name) const { print(name.c_str()); } + std::string getPrint(const char* name = nullptr) const; + + private: + static void setLerp(Color* output, const Color& v1, const Color& v2, + const float& interp); +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/renderer.hpp b/engine/inc/renderer/renderer.hpp new file mode 100644 index 0000000..e152e20 --- /dev/null +++ b/engine/inc/renderer/renderer.hpp @@ -0,0 +1,52 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include "./core/renderer_core.hpp" +#include "./core/3d/camera_info_3d.hpp" +#include "./3d/renderer_3d.hpp" +#include "./2d/renderer_2d.hpp" + +namespace Tyra { + +class Renderer { + public: + Renderer(); + ~Renderer(); + + Renderer2D renderer2D; + Renderer3D renderer3D; + + RendererCore core; + + void init(); + + /** World background color */ + void setClearScreenColor(const Color& color) { + core.setClearScreenColor(color); + } + + TextureRepository& getTextureRepository() { return core.texture.repository; } + + void setFrameLimit(const bool& onoff) { core.setFrameLimit(onoff); } + + /** Update view frustum for frustum culling. 3D support - off */ + void beginFrame(); + + /** Update view frustum for frustum culling. 3D support - on */ + void beginFrame(const CameraInfo3D& cameraInfo); + + /** VSync and swap frame double buffer. */ + void endFrame(); +}; + +} // namespace Tyra diff --git a/engine/inc/renderer/renderer_settings.hpp b/engine/inc/renderer/renderer_settings.hpp new file mode 100644 index 0000000..f5889ca --- /dev/null +++ b/engine/inc/renderer/renderer_settings.hpp @@ -0,0 +1,54 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include + +namespace Tyra { + +class RendererSettings { + public: + RendererSettings() + : width(512.0F), + height(448.0F), + interlacedHeightF(height / 2), + near(0.1F), + far(8192.0F), + projectionScale(4096.0F), + aspectRatio(width / height), + interlacedHeightUI(static_cast(interlacedHeightF)) {} + ~RendererSettings(); + + const float& getWidth() const { return width; } + const float& getHeight() const { return height; } + const float& getNear() const { return near; } + const float& getFar() const { return far; } + const float& getProjectionScale() const { return projectionScale; } + const float& getAspectRatio() const { return aspectRatio; } + const float& getInterlacedHeightF() const { return interlacedHeightF; } + const unsigned int& getInterlacedHeightUI() const { + return interlacedHeightUI; + } + + static void copy(RendererSettings* out, const RendererSettings* in); + void set(const RendererSettings& v); + + void print() const; + std::string getPrint() const; + + private: + float width, height, interlacedHeightF, near, far, projectionScale, + aspectRatio; + unsigned int interlacedHeightUI; +}; + +} // namespace Tyra diff --git a/engine/inc/thread/threading.hpp b/engine/inc/thread/threading.hpp new file mode 100644 index 0000000..30e4f27 --- /dev/null +++ b/engine/inc/thread/threading.hpp @@ -0,0 +1,32 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include + +namespace Tyra { + +class Threading { + public: + Threading(); + ~Threading(); + + static void sleep(const u32& ms); + static void sleep(const timespec& tv); + + static void switchThread(); + + private: + static timespec tv; +}; + +} // namespace Tyra diff --git a/engine/inc/time/timer.hpp b/engine/inc/time/timer.hpp new file mode 100644 index 0000000..eb4ee8e --- /dev/null +++ b/engine/inc/time/timer.hpp @@ -0,0 +1,30 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include +#include + +namespace Tyra { + +class Timer { + public: + Timer(); + ~Timer(); + + u32 getTimeDelta(); + inline void prime() { lastTime = *T3_COUNT; } + + private: + u32 lastTime, time, change; +}; + +} // namespace Tyra diff --git a/engine/inc/tyra b/engine/inc/tyra new file mode 100644 index 0000000..9bf9f36 --- /dev/null +++ b/engine/inc/tyra @@ -0,0 +1,27 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#pragma once + +#include "./engine.hpp" +#include "./debug/debug.hpp" +#include "./file/file_utils.hpp" +#include "./loaders/3d/md2_loader/md2_loader.hpp" +#include "./loaders/3d/obj_loader/obj_loader.hpp" +#include "./loaders/texture/png_loader.hpp" +#include "./packet2/packet2_tyra_utils.hpp" +#include "./physics/ray.hpp" +#include "./renderer/3d/pipeline/dynamic/dynamic_pipeline.hpp" +#include "./renderer/3d/pipeline/static/static_pipeline.hpp" +#include "./renderer/3d/pipeline/minecraft/minecraft_pipeline.hpp" +#include "./renderer/3d/mesh/dynamic/dynamic_mesh.hpp" +#include "./renderer/3d/mesh/static/static_mesh.hpp" +#include "./thread/threading.hpp" +#include "./time/timer.hpp" diff --git a/src/samples/dolphin/bin/.gitignore b/engine/obj/.gitignore similarity index 95% rename from src/samples/dolphin/bin/.gitignore rename to engine/obj/.gitignore index 86d0cb2..44c5ea8 100644 --- a/src/samples/dolphin/bin/.gitignore +++ b/engine/obj/.gitignore @@ -1,4 +1,4 @@ -# Ignore everything in this directory -* -# Except this file +# Ignore everything in this directory +* +# Except this file !.gitignore \ No newline at end of file diff --git a/engine/src/audio/audio.cpp b/engine/src/audio/audio.cpp new file mode 100644 index 0000000..0328a24 --- /dev/null +++ b/engine/src/audio/audio.cpp @@ -0,0 +1,71 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +# Sandro Sobczyński +*/ + +#include "audio/audio.hpp" +#include "debug/debug.hpp" +#include "thread/threading.hpp" +#include +#include + +extern void* _gp; + +void audioThread(Tyra::Audio* audio) { + while (true) audio->work(); +} + +namespace Tyra { + +const u16 Audio::threadStackSize = 2 * 1024; + +Audio::Audio() { + threadStack = static_cast(memalign(sizeof(u8), threadStackSize)); +} + +Audio::~Audio() { + if (threadStack) delete[] threadStack; +} + +void Audio::init() { + initAUDSRV(); + + song.init(); + adpcm.init(); + + initThread(); + + TYRA_LOG("Audio initialized!"); +} + +void Audio::initAUDSRV() { + int ret = audsrv_init(); + + TYRA_ASSERT(ret >= 0, + "AUDSRV returned error string: ", audsrv_get_error_string()); +} + +void Audio::initThread() { + thread.gp_reg = &_gp; + thread.func = reinterpret_cast(audioThread); + thread.stack = threadStack; + thread.stack_size = threadStackSize; + thread.initial_priority = 0x5; + threadId = CreateThread(&thread); + TYRA_ASSERT(threadId >= 0, "Create audio thread failed!"); + StartThread(threadId, this); +} + +void Audio::work() { + Threading::switchThread(); + + song.work(); +} + +} // namespace Tyra diff --git a/engine/src/audio/audio_adpcm.cpp b/engine/src/audio/audio_adpcm.cpp new file mode 100644 index 0000000..07cb640 --- /dev/null +++ b/engine/src/audio/audio_adpcm.cpp @@ -0,0 +1,95 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +# Sandro Sobczyński +*/ + +#include "audio/audio_adpcm.hpp" +#include "debug/debug.hpp" +#include +#include +#include +#include +#include +#include "thread/threading.hpp" + +namespace Tyra { + +AudioAdpcm::AudioAdpcm() {} + +AudioAdpcm::~AudioAdpcm() {} + +void AudioAdpcm::init() { initAUDSRV(); } + +void AudioAdpcm::initAUDSRV() { + int ret = audsrv_adpcm_init(); + + TYRA_ASSERT(ret >= 0, + "AUDSRV returned error string:", audsrv_get_error_string()); +} + +void AudioAdpcm::reset() { audsrv_adpcm_init(); } + +audsrv_adpcm_t* AudioAdpcm::load(const char* t_path) { + FILE* file = fopen(t_path, "rb"); + fseek(file, 0, SEEK_END); + u32 adpcmFileSize = ftell(file); + u8 data[adpcmFileSize]; + rewind(file); + fread(data, sizeof(u8), adpcmFileSize, file); + auto* result = new audsrv_adpcm_t(); + result->size = 0; + result->buffer = 0; + result->loop = 0; + result->pitch = 0; + result->channels = 0; + + if (audsrv_load_adpcm(result, data, adpcmFileSize)) { + TYRA_ERROR("AUDSRV returned error string: ", audsrv_get_error_string()); + } + + fclose(file); + return result; +} + +audsrv_adpcm_t* AudioAdpcm::load(const std::string& t_path) { + return load(t_path.c_str()); +} + +AdpcmResult AudioAdpcm::tryPlay(audsrv_adpcm_t* t_adpcm) { + return tryPlay(t_adpcm, -1); +} + +AdpcmResult AudioAdpcm::tryPlay(audsrv_adpcm_t* t_adpcm, const s8& t_ch) { + int res = audsrv_ch_play_adpcm(t_ch, t_adpcm); + if (res >= 0) { + return AdpcmResult::ADPCM_OK; + } else if (res == -AUDSRV_ERR_NO_MORE_CHANNELS) { + if (t_ch < 0) { + return AdpcmResult::ADPCM_NO_FREE_CHANNELS; + } else { + return AdpcmResult::ADPCM_CHANNEL_USED; + } + } else { + return AdpcmResult::ADPCM_ERROR; + } +} + +void AudioAdpcm::playWait(audsrv_adpcm_t* t_adpcm) { playWait(t_adpcm, -1); } + +void AudioAdpcm::playWait(audsrv_adpcm_t* t_adpcm, const s8& t_ch) { + int res = tryPlay(t_adpcm, t_ch); + + while (res == AdpcmResult::ADPCM_NO_FREE_CHANNELS || + res == AdpcmResult::ADPCM_CHANNEL_USED) { + Threading::switchThread(); + res = tryPlay(t_adpcm, t_ch); + } +} + +} // namespace Tyra diff --git a/engine/src/audio/audio_song.cpp b/engine/src/audio/audio_song.cpp new file mode 100644 index 0000000..7844c8d --- /dev/null +++ b/engine/src/audio/audio_song.cpp @@ -0,0 +1,185 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +# Sandro Sobczyński +*/ + +#include "audio/audio_song.hpp" +#include "debug/debug.hpp" +#include +#include +#include +#include + +namespace Tyra { + +const u16 AudioSong::chunkSize = 4 * 1024; + +AudioSong::AudioSong() { + chunkReadStatus = 0; + tyraVolume = 0; + audsrvVolume = 0; + + songLoaded = false; + songPlaying = false; + inLoop = false; + songFinished = false; + + chunk = nullptr; +} + +AudioSong::~AudioSong() { + if (chunk) delete[] chunk; +} + +void AudioSong::init() { + chunk = static_cast(memalign(sizeof(char), chunkSize)); + + initSema(); + initAUDSRV(); + setSongFormat(); +} + +void AudioSong::load(const char* t_path) { + if (songLoaded) unloadSong(); + wav = fopen(t_path, "rb"); + TYRA_ASSERT(wav != nullptr, "Failed to open wav file!"); + rewindSongToStart(); + songLoaded = true; +} + +void AudioSong::load(const std::string& t_path) { load(t_path.c_str()); } + +void AudioSong::play() { + TYRA_ASSERT(songLoaded, "Cant play song because was not loaded!"); + if (songFinished) rewindSongToStart(); + tyraVolume = audsrvVolume; + audsrv_set_volume(tyraVolume); + songPlaying = true; +} + +void AudioSong::stop() { + tyraVolume = 0; + audsrv_set_volume(tyraVolume); + songPlaying = false; +} + +const bool& AudioSong::isPlaying() const { return songPlaying; } + +const bool& AudioSong::isLoaded() const { return songLoaded; } + +const u8& AudioSong::getVolume() const { return tyraVolume; } + +std::size_t AudioSong::getListenersCount() const { + return songListeners.size(); +} + +void AudioSong::initAUDSRV() { + int ret = audsrv_on_fillbuf(chunkSize, (audsrv_callback_t)iSignalSema, + (void*)fillbufferSema); + + TYRA_ASSERT(ret >= 0, + "AUDSRV returned error string:", audsrv_get_error_string()); +} + +/** Initialize semaphore which will wait until chunk of the song is not + * finished. */ +void AudioSong::initSema() { + TYRA_LOG("Creating audio semaphore"); + sema.init_count = 0; + sema.max_count = 1; + sema.option = 0; + fillbufferSema = CreateSema(&sema); + TYRA_LOG("AudioSong semaphore created"); +} + +/** + * Close file. + * Delete song path from memory. + */ +void AudioSong::unloadSong() { + songLoaded = false; + fclose(wav); +} + +/** Fseek on wav. */ +void AudioSong::rewindSongToStart() { + if (wav != nullptr) fseek(wav, 0x30, SEEK_SET); + chunkReadStatus = 0; + songFinished = false; +} + +/** Set WAV format to 16bit, 22050Hz, stereo. */ +void AudioSong::setSongFormat() { + format.bits = 16; + format.freq = 22050; + format.channels = 2; + + if (audsrv_set_format(&format)) { + TYRA_ERROR("AUDSRV returned error string: ", audsrv_get_error_string()); + } +} + +void AudioSong::setVolume(const u8& t_vol) { + audsrvVolume = t_vol; + if (songPlaying) tyraVolume = t_vol; + + if (audsrv_set_volume(tyraVolume)) { + TYRA_ERROR("AUDSRV returned error string: ", audsrv_get_error_string()); + } +} + +void AudioSong::work() { + if (!songPlaying || !songLoaded) return; + if (songFinished) { + if (inLoop) { + for (u32 i = 0; i < getListenersCount(); i++) + songListeners[i]->listener->onAudioFinish(); + rewindSongToStart(); + } else { + stop(); + return; + } + } + + if (chunkReadStatus > 0) { + WaitSema(fillbufferSema); // wait until previous chunk wasn't finished + audsrv_play_audio(chunk, chunkReadStatus); + for (u32 i = 0; i < getListenersCount(); i++) + songListeners[i]->listener->onAudioTick(); + } + + chunkReadStatus = fread(chunk, 1, chunkSize, wav); + + if (chunkReadStatus < (s32)chunkSize) songFinished = true; +} + +u32 AudioSong::addListener(AudioListener* t_listener) { + AudioListenerRef* ref = new AudioListenerRef; + ref->id = rand() % 1000000; + ref->listener = t_listener; + songListeners.push_back(ref); + return ref->id; +} + +void AudioSong::removeListener(const u32& t_id) { + s32 index = -1; + for (u32 i = 0; i < songListeners.size(); i++) + if (songListeners[i]->id == t_id) { + index = i; + break; + } + + TYRA_ASSERT(index != -1, + "Cant remove listener because given id was not found!"); + + delete songListeners[index]; + songListeners.erase(songListeners.begin() + index); +} + +} // namespace Tyra diff --git a/engine/src/debug/debug.cpp b/engine/src/debug/debug.cpp new file mode 100644 index 0000000..292a10a --- /dev/null +++ b/engine/src/debug/debug.cpp @@ -0,0 +1,25 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Wellington Carvalho +*/ + +#include "debug/debug.hpp" + +std::unique_ptr TyraDebug::logFile; + +std::ofstream* TyraDebug::getLogFile() { + if (logFile) { + return logFile.get(); + } else { + logFile = std::make_unique(); + logFile->open(Tyra::FileUtils::fromCwd("log.txt"), + std::ofstream::out | std::ofstream::app); + return logFile.get(); + } + +} // namespace Tyra diff --git a/engine/src/engine.cpp b/engine/src/engine.cpp new file mode 100644 index 0000000..92ada7e --- /dev/null +++ b/engine/src/engine.cpp @@ -0,0 +1,47 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "engine.hpp" + +namespace Tyra { + +Engine::Engine() { initAll(false); } + +Engine::Engine(const EngineOptions& options) { + info.writeLogsToFile = options.writeLogsToFile; + initAll(options.loadUsbDriver); +} + +Engine::~Engine() {} + +void Engine::run(Game* t_game) { + game = t_game; + game->init(); + while (true) { + realLoop(); + } +} + +void Engine::realLoop() { + pad.update(); + game->loop(); + info.update(); +} + +void Engine::initAll(const bool& loadUsbDriver) { + srand(time(nullptr)); + irx.loadAll(loadUsbDriver, info.writeLogsToFile); + renderer.init(); + banner.show(&renderer); + audio.init(); + pad.init(); +} + +} // namespace Tyra diff --git a/engine/src/file/file_utils.cpp b/engine/src/file/file_utils.cpp new file mode 100644 index 0000000..e4e30a8 --- /dev/null +++ b/engine/src/file/file_utils.cpp @@ -0,0 +1,67 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Wellington Carvalho +*/ + +#include "debug/debug.hpp" +#include +#include +#include +#include +#include +#include +#include +#include "file/file_utils.hpp" + +namespace Tyra { + +FileUtils::FileUtils() { + getcwd(cwd, sizeof(cwd)); + setPathInfo(cwd); +} + +FileUtils::~FileUtils() {} + +void FileUtils::setPathInfo(const char* path) { + char* ptr; + + strcpy(this->elfName, path); + strcpy(this->elfPath, path); + + ptr = strrchr(this->elfPath, '/'); + if (ptr == nullptr) { + ptr = strrchr(this->elfPath, '\\'); + if (ptr == nullptr) { + ptr = strrchr(this->elfPath, ':'); + if (ptr == nullptr) { + TYRA_TRAP("Did not find path! PATH: ", path); + } + } + } + + ptr++; + *ptr = '\0'; +} + +std::string FileUtils::getCwd() { + std::string result; + char _cwd[NAME_MAX]; + getcwd(_cwd, sizeof(_cwd)); + result = _cwd; + return result; +} + +std::string FileUtils::fromCwd(const std::string& relativePath) { + return fromCwd(relativePath.c_str()); +} + +std::string FileUtils::fromCwd(const char* file) { + auto cwd = getCwd(); + return cwd + file; +} +} // namespace Tyra diff --git a/engine/src/info/banner.cpp b/engine/src/info/banner.cpp new file mode 100644 index 0000000..5a08e16 --- /dev/null +++ b/engine/src/info/banner.cpp @@ -0,0 +1,72 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022-2022, tyra - https://github.com/h4570/tyrav2 +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "info/banner.hpp" +#include "info/version.hpp" +#include +#include +#include "./banner_data.cpp" + +namespace Tyra { + +Banner::Banner() {} + +Banner::~Banner() {} + +void Banner::show(Renderer* renderer) { + auto* bannerData = ___createTyraSplashBanner(); + + TextureBuilderData tbd; + tbd.bpp = bpp32; + tbd.gsComponents = TEXTURE_COMPONENTS_RGBA; + tbd.width = 128; + tbd.height = 32; + tbd.clut = nullptr; + tbd.data = reinterpret_cast(bannerData); + + Sprite sprite; + sprite.size.x = 128; + sprite.size.y = 32; + sprite.position.x = + (renderer->core.getSettings().getWidth() / 2) - (sprite.size.x / 2); + sprite.position.y = + (renderer->core.getSettings().getHeight() / 2) - (sprite.size.y / 2); + + auto texture = Texture(&tbd); + texture.addLink(sprite.id); + renderer->core.texture.repository.add(&texture); + + for (int i = 0; i < 2; i++) { + renderer->beginFrame(); + renderer->renderer2D.render(&sprite); + renderer->endFrame(); + } + + renderer->core.texture.repository.removeById(texture.id); + texture.core->data = nullptr; + delete[] bannerData; + + std::cout << "\n"; + std::cout << "-----------------------------------------\n"; + std::cout << " _____ ____ ___\n"; + std::cout << " | \\/ ____| |___|\n"; + std::cout << " | | | \\ | |\n"; + std::cout << "-----------------------------------------\n"; + std::cout << "Copyright 2022\n"; + std::cout << "Repository: https://github.com/h4570/tyra\n"; + std::cout << "Licensed under Apache License 2.0\n"; + std::cout << "Version: "; + std::cout << Version::toString().c_str(); + std::cout << "\n"; + std::cout << "-----------------------------------------\n"; + std::cout << "\n"; +} + +} // Namespace Tyra \ No newline at end of file diff --git a/engine/src/info/banner_data.cpp b/engine/src/info/banner_data.cpp new file mode 100644 index 0000000..f47f7f5 --- /dev/null +++ b/engine/src/info/banner_data.cpp @@ -0,0 +1,2734 @@ +unsigned int* ___createTyraSplashBanner() { + return new unsigned int[]{ + 0, 59191554, 59191554, 59191554, 59191554, 59191554, + 59191554, 59191554, 59191554, 59191554, 59191554, 59191554, + 59191554, 59191554, 59191554, 59191554, 59191554, 59191554, + 59191554, 59191554, 59191554, 59191554, 59191554, 59191554, + 59191554, 59191554, 59191554, 25702919, 0, 59191554, + 59191554, 59191554, 59191554, 59191554, 59191554, 59191554, + 59191554, 59191554, 42414339, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 42414338, 59191554, 59191554, + 59191554, 59191554, 59191554, 59191554, 59191554, 59191554, + 25637124, 0, 49521697, 66298913, 66298913, 66298913, + 66298913, 66298913, 66298913, 66298913, 66298913, 66298913, + 66298913, 66298913, 66298913, 66298913, 66298913, 66298913, + 32744481, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 32744482, 66298913, 66298913, 66298913, 66298913, 66298913, + 66298913, 66298913, 66298913, 66298913, 32744483, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 42414338, 2072457216, 2106011648, 2106011648, + 2106011648, 2106011648, 2106011648, 2106011648, 2106011648, 2106011648, + 2106011648, 2106011648, 2106011648, 2106011648, 2106011648, 2106011648, + 2106011648, 2106011648, 2106011648, 2106011648, 2106011648, 2106011648, + 2106011648, 2106011648, 2106011648, 2106011648, 2106011648, 629616640, + 25636864, 1602695168, 2106011648, 2106011648, 2106011648, 2106011648, + 2106011648, 2106011648, 2106011648, 2106011648, 1887907840, 109522944, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 260517888, 2022125568, + 2106011648, 2106011648, 2106011648, 2106011648, 2106011648, 2106011648, + 2106011648, 2089234432, 562507776, 15967264, 1710466080, 2113119264, + 2113119264, 2113119264, 2113119264, 2113119264, 2113119264, 2113119264, + 2113119264, 2113119264, 2113119264, 2113119264, 2113119264, 2113119264, + 2113119264, 2079564832, 1895015456, 1576248352, 1056154656, 368288800, + 15967264, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1307812896, 2113119264, 2113119264, 2113119264, + 2113119264, 2113119264, 2113119264, 2113119264, 2113119264, 2113119264, + 854828064, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 42414338, 2106011648, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 646393856, 0, 461844480, 2106011648, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 948383744, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1300705280, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 1468477440, 8859648, 15967264, + 1744020512, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2129896480, 1525916704, 401843232, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 150184992, 2012455968, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 1660134432, 32744480, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 42414338, 2106011648, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 646393856, 0, 8859648, + 1334259712, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 1921462272, 109522944, 0, + 0, 0, 0, 0, 0, 0, + 0, 344403968, 2089234432, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2072457216, 327626752, + 0, 15967264, 1744020512, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2079564832, + 938714144, 32744480, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 838050848, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2129896480, 385066016, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 42414338, 2106011648, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 646393856, + 0, 0, 243740672, 2005348352, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 948383744, 0, 0, 0, 0, 0, + 0, 0, 8859648, 1418145792, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 1166487552, 0, 0, 15967264, 1744020512, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2146673696, 1056154656, 15967264, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 15967264, 1643357216, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 1190372384, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 42414338, 2106011648, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 646393856, 0, 0, 0, 1015492608, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 1904685056, 109522944, 0, 0, + 0, 0, 0, 0, 445067264, 2106011648, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 1938239488, 159854592, 0, 0, 15967264, + 1744020512, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2129896480, + 687055904, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 368288800, 2129896480, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 1945347104, 83076128, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 42414338, 2106011648, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 646393856, 0, 0, + 0, 92745728, 1837576192, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 948383744, + 0, 0, 0, 0, 0, 8859648, + 1518809088, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 864497664, 0, 0, + 0, 15967264, 1744020512, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2146673696, 905159712, 536060960, 536060960, 804496416, 2129896480, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 1895015456, 116630560, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1173595168, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2129896480, 2079564832, + 2146673696, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 703833120, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 42414338, 2106011648, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 646393856, + 0, 0, 0, 0, 713502720, 2139566080, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 1904685056, 109522944, 0, 0, 0, + 0, 545730560, 2122788864, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 1736912896, 59191296, + 0, 0, 0, 15967264, 1744020512, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2129896480, 301179936, 0, 0, + 183739424, 2113119264, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 871605280, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 83076128, + 1928569888, 2163450912, 2163450912, 2163450912, 2163450912, 1760797728, + 468952096, 166962208, 687055904, 1995678752, 2163450912, 2163450912, + 2163450912, 2163450912, 1509139488, 15967264, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 25637124, 1149710336, + 1166487552, 1166487552, 1166487552, 1166487552, 1166487552, 1166487552, + 1166487552, 1283928064, 2139566080, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 1569140736, 1166487552, + 1166487552, 1166487552, 1166487552, 1166487552, 1166487552, 1166487552, + 1166487552, 344403968, 0, 0, 0, 0, + 25636864, 1585917952, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 948383744, 0, + 0, 0, 25636864, 1636249600, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2122788864, + 579284992, 0, 0, 0, 0, 15967264, + 1744020512, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2129896480, 301179936, + 0, 0, 183739424, 2113119264, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 1593025568, 15967264, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 687055904, 2146673696, 2163450912, 2163450912, 2163450912, + 2129896480, 401843232, 0, 0, 0, 871605280, + 2163450912, 2163450912, 2163450912, 2163450912, 2096342048, 267625504, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 260517888, 2122788864, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 881274880, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 428290048, 2106011648, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 1904685056, 109522944, 0, 0, 663171072, 2139566080, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 1468477440, 8859648, 0, 0, 0, + 0, 15967264, 1744020512, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2062787616, 1291035680, 1257481248, + 1408476192, 1173595168, 32744480, 15967264, 1056154656, 1458807840, + 1257481248, 1274258464, 2029233184, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2029233184, 66298912, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 15967264, 1492362272, 2163450912, 2163450912, + 2163450912, 2163450912, 2062787616, 49521696, 0, 0, + 0, 452174880, 2146673696, 2163450912, 2163450912, 2163450912, + 2163450912, 1039377440, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 260517888, + 2122788864, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 881274880, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1283928064, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 948383744, 0, 42414080, + 1736912896, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2055680000, 327626752, 0, 0, + 0, 0, 0, 15967264, 1744020512, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 1710466080, + 15967264, 0, 0, 972268576, 1173595168, 1072931872, + 1106486304, 32744480, 0, 0, 1559471136, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2129896480, + 250848288, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 250848288, 2096342048, + 2163450912, 2163450912, 2163450912, 2163450912, 2129896480, 536060960, + 0, 0, 0, 1005823008, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 1827906592, 49521696, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 260517888, 2122788864, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 881274880, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 210186240, 1988571136, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 1904685056, + 109522944, 780611584, 2139566080, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 1166487552, 0, + 0, 0, 0, 0, 0, 15967264, + 1744020512, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 1710466080, 15967264, 0, 0, 32744480, + 1542693920, 1676911648, 49521696, 0, 0, 0, + 1559471136, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2129896480, 334734368, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1005823008, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 1911792672, 737387552, 368288800, 972268576, 2062787616, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2146673696, + 552838176, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 260517888, 2122788864, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 881274880, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 981938176, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 1015492608, 1837576192, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 1938239488, + 159854592, 0, 0, 0, 0, 0, + 0, 15967264, 1744020512, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 1710466080, 15967264, 0, + 15967264, 1056154656, 1089709088, 972268576, 1190372384, 32744480, + 0, 0, 1559471136, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2129896480, 234071072, 0, + 0, 0, 0, 0, 0, 0, + 0, 32744480, 1811129376, 2163450912, 1777574944, 687055904, + 485729312, 1291035680, 2146673696, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2079564832, 1005823008, 452174880, 854828064, + 1978901536, 2163450912, 1358144544, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 260517888, + 2122788864, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 881274880, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 75968512, 1804021760, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2106011648, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 864497664, 0, 0, 0, 0, + 0, 0, 0, 15967264, 1744020512, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2079564832, + 1408476192, 1374921760, 1509139488, 1089709088, 15967264, 0, + 972268576, 1559471136, 1374921760, 1391698976, 2046010400, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2012455968, + 66298912, 0, 0, 0, 0, 0, + 0, 0, 0, 536060960, 2146673696, 2062787616, + 267625504, 0, 0, 15967264, 1442030624, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 972268576, 0, + 0, 0, 653501472, 2146673696, 2029233184, 166962208, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 260517888, 2122788864, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 881274880, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 663171072, 2139566080, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 1720135680, 42414080, 0, 0, + 0, 0, 0, 0, 0, 15967264, + 1744020512, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2129896480, 301179936, + 0, 0, 183739424, 2113119264, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 1559471136, 15967264, 0, 0, 0, + 0, 0, 0, 0, 0, 1341367328, + 2163450912, 1710466080, 15967264, 0, 0, 0, + 854828064, 2163450912, 2163450912, 2163450912, 2163450912, 2129896480, + 401843232, 0, 0, 0, 99853344, 2113119264, + 2163450912, 871605280, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 260517888, 2122788864, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 881274880, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 25636864, 1552363520, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2122788864, 562507776, 0, + 0, 0, 0, 0, 0, 0, + 0, 15967264, 1744020512, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2129896480, 301179936, 0, 0, 183739424, 2113119264, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 821273632, 0, 0, + 0, 0, 0, 0, 0, 0, + 150184992, 2029233184, 2163450912, 1978901536, 133407776, 0, + 0, 0, 1240704032, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 754164768, 0, 0, 0, + 452174880, 2129896480, 2163450912, 1693688864, 32744480, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 260517888, + 2122788864, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 881274880, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 394735616, 2089234432, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 1451700224, + 8859648, 0, 0, 0, 0, 0, + 0, 0, 0, 15967264, 1744020512, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2146673696, 1005823008, 653501472, 653501472, + 905159712, 2129896480, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 1861461024, 99853344, + 0, 0, 0, 0, 0, 0, + 0, 0, 854828064, 2163450912, 2163450912, 2163450912, + 1458807840, 284402720, 150184992, 838050848, 2096342048, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 1928569888, 569615392, + 133407776, 435397664, 1760797728, 2163450912, 2163450912, 2129896480, + 401843232, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 260517888, 2122788864, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 881274880, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1250373632, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2055680000, 327626752, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 15967264, + 1744020512, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2113119264, + 636724256, 0, 0, 0, 0, 0, + 0, 0, 0, 15967264, 1676911648, 2163450912, + 2163450912, 2163450912, 2163450912, 2096342048, 2046010400, 2163450912, + 2163450912, 2079564832, 1190372384, 821273632, 1408476192, 2129896480, + 2163450912, 2146673696, 2029233184, 2129896480, 2163450912, 2163450912, + 2163450912, 2163450912, 1207149600, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 260517888, 2122788864, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 881274880, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 193409024, 1971793920, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 1149710336, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 15967264, 1744020512, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2129896480, 972268576, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 385066016, + 2129896480, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2146673696, 787719200, 0, 0, + 15967264, 1257481248, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 1945347104, 99853344, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 260517888, + 2122788864, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 881274880, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 931606528, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 1921462272, 143077376, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 15967264, 1744020512, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2046010400, 838050848, 15967264, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1190372384, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2079564832, 83076128, + 0, 0, 0, 485729312, 2146673696, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 720610336, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 260517888, 2122788864, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 881274880, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 59191296, 1770467328, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 847720448, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 15967264, + 1744020512, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 1525916704, 334734368, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 83076128, 1945347104, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2113119264, 250848288, 0, 0, 0, 687055904, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 1542693920, 15967264, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 260517888, 2122788864, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 881274880, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1065824256, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2106011648, 126300160, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 15967264, 1744020512, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2113119264, 1995678752, + 1995678752, 2096342048, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 1425253408, 32744480, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 703833120, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 1492362272, 150184992, 0, + 317957152, 1811129376, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2096342048, + 284402720, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 260517888, + 2122788864, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 881274880, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1049047040, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2106011648, 109522944, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 15967264, 1744020512, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 1542693920, 99853344, 99853344, 720610336, 2129896480, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2146673696, 821273632, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 15967264, + 1525916704, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2012455968, 1794352160, 2079564832, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 1056154656, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 260517888, 2122788864, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 881274880, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1049047040, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2106011648, 109522944, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 15967264, + 1744020512, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 1525916704, 0, 0, 15967264, + 1291035680, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2012455968, 317957152, 0, + 0, 0, 0, 0, 0, 0, + 0, 267625504, 2096342048, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 1844683808, 49521696, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 260517888, 2122788864, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 881274880, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1049047040, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2106011648, 109522944, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 15967264, 1744020512, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 1525916704, 0, + 0, 0, 133407776, 1827906592, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 1643357216, 66298912, 0, 0, 0, 0, + 0, 0, 0, 1039377440, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2146673696, 569615392, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 260517888, + 2122788864, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 881274880, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1049047040, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2106011648, 109522944, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 15967264, 1744020512, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 1525916704, 0, 0, 0, 0, 502506528, + 2096342048, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 1072931872, 0, 0, + 0, 0, 0, 0, 49521696, 1827906592, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 1374921760, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 260517888, 2122788864, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 881274880, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1049047040, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2106011648, 109522944, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 15967264, + 1744020512, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 1525916704, 0, 0, 0, + 0, 0, 1072931872, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2096342048, + 502506528, 0, 0, 0, 0, 0, + 552838176, 2146673696, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2079564832, 2062787616, + 2062787616, 2062787616, 2062787616, 2062787616, 2062787616, 2062787616, + 2062787616, 2062787616, 2096342048, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2046010400, + 183739424, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 260517888, 2122788864, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 881274880, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1049047040, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2106011648, 109522944, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 15967264, 1744020512, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 1525916704, 0, + 0, 0, 0, 0, 66298912, 1660134432, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 1827906592, 133407776, 0, 0, + 0, 0, 1374921760, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 1978901536, + 166962208, 83076128, 83076128, 83076128, 83076128, 83076128, + 83076128, 83076128, 83076128, 83076128, 468952096, 2129896480, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 888382496, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 260517888, + 2122788864, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 881274880, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1049047040, 2156343296, 2156343296, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2106011648, 109522944, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 15967264, 1744020512, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 1525916704, 0, 0, 0, 0, 0, + 0, 334734368, 2029233184, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 1307812896, + 15967264, 0, 0, 166962208, 2046010400, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 1257481248, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 32744480, 1710466080, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 1710466080, 32744481, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 260517888, 2122788864, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 881274880, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1049047040, 2156343296, 2156343296, 2156343296, + 2156343296, 2156343296, 2156343296, 2156343296, 2106011648, 109522944, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 15967264, + 1744020512, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 1525916704, 0, 0, 0, + 0, 0, 0, 0, 854828064, 2146673696, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2129896480, 703833120, 0, 0, 888382496, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2163450912, 2163450912, 2129896480, 452174880, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 921936928, 2163450912, 2163450912, + 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, 2163450912, + 2129896480, 418620448, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 260517888, 2089234432, 2106011648, + 2106011648, 2106011648, 2106011648, 2106011648, 2106011648, 2106011648, + 864497664, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1032269824, 2106011648, + 2106011648, 2106011648, 2106011648, 2106011648, 2106011648, 2106011648, + 2072457216, 109522944, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 15967264, 1710466080, 2113119264, 2113119264, 2113119264, + 2113119264, 2113119264, 2113119264, 2113119264, 1492362272, 0, + 0, 0, 0, 0, 0, 0, + 32744480, 1458807840, 2113119264, 2113119264, 2113119264, 2113119264, + 2113119264, 2113119264, 2113119264, 2113119264, 1928569888, 234071072, + 15967264, 1660134432, 2113119264, 2113119264, 2113119264, 2113119264, + 2113119264, 2113119264, 2113119264, 2113119264, 1727243296, 32744480, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 200516640, + 2029233184, 2113119264, 2113119264, 2113119264, 2113119264, 2113119264, + 2113119264, 2113119264, 2113119264, 1207149600, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 8926224, + 59191554, 59191554, 59191554, 59191554, 59191554, 59191554, + 59191554, 59191554, 25637125, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 25637124, 59191554, 59191554, 59191554, 59191554, 59191554, + 59191554, 59191554, 59191554, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 49521697, 66298913, + 66298913, 66298913, 66298913, 66298913, 66298913, 66298913, + 49521697, 0, 0, 0, 0, 0, + 0, 0, 0, 32744482, 66298913, 66298913, + 66298913, 66298913, 66298913, 66298913, 66298913, 66298913, + 66298913, 32744483, 0, 66298913, 66298913, 66298913, + 66298913, 66298913, 66298913, 66298913, 66298913, 66298913, + 49521697, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 66298913, 66298913, 66298913, 66298913, + 66298913, 66298913, 66298913, 66298913, 66298913, 49521697, + 0, 0, 0, 0, 0, 0, + 0, 76281, 2822320, 2822320, 3111616, 3112144, + 3112672, 3113200, 3113728, 3114256, 3114784, 3115312, + 3115840, 3116368, 3116896, 3117424, 3117952, 3118480, + 3119008, 3119536, 3120064, 3120592, 3121120, 3121648, + 3122176, 3122704, 3123232, 3123760, 3124288, 3124816, + 3125344, 3125872, 3082784, 3083312, 0, 0, + 0, 16208, 2822272, 2822272, 109523202, 109523202, + 109523202, 109523202, 109523202, 109523202, 109523202, 109523202, + 109523202, 109523202, 109523202, 109523202, 109523202, 109523202, + 109523202, 109523202, 109523202, 109523202, 109523202, 109523202, + 109523202, 109523202, 109523202, 109523202, 109523202, 42480135, + 0, 109523202, 109523202, 109523202, 109523202, 109523202, + 109523202, 109523202, 109523202, 109523202, 92745987, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 92745986, + 109523202, 109523202, 109523202, 109523202, 109523202, 109523202, + 109523202, 109523202, 59191556, 0, 99853345, 116630561, + 116630561, 116630561, 116630561, 116630561, 116630561, 116630561, + 116630561, 116630561, 116630561, 116630561, 116630561, 116630561, + 116630561, 116630561, 66298913, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 66298914, 116630561, 116630561, 116630561, + 116630561, 116630561, 116630561, 116630561, 116630561, 116630561, + 49521699, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 528, 528, 92745986, 4136054784, 4219940864, 4219940864, + 4219940864, 4219940864, 4219940864, 4219940864, 4219940864, 4219940864, + 4219940864, 4219940864, 4219940864, 4219940864, 4219940864, 4219940864, + 4219940864, 4219940864, 4219940864, 4219940864, 4219940864, 4219940864, + 4219940864, 4219940864, 4219940864, 4219940864, 4219940864, 1250373632, + 42414080, 3196530688, 4219940864, 4219940864, 4219940864, 4219940864, + 4219940864, 4219940864, 4219940864, 4219940864, 3783733248, 226963456, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 528953344, 4035391488, + 4219940864, 4219940864, 4219940864, 4219940864, 4219940864, 4219940864, + 4219940864, 4186386432, 1116155904, 32744480, 3404964896, 4227048480, + 4227048480, 4227048480, 4227048480, 4227048480, 4227048480, 4227048480, + 4227048480, 4227048480, 4227048480, 4227048480, 4227048480, 4227048480, + 4227048480, 4143162400, 3774063648, 3136529440, 2096342048, 720610336, + 32744480, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 2599658528, 4227048480, 4227048480, 4227048480, + 4227048480, 4227048480, 4227048480, 4227048480, 4227048480, 4227048480, + 1693688864, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1056, 528, 92745986, 4203163648, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 1283928064, + 0, 931606528, 4219940864, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 1887907840, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2592550912, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 2928095232, 25636864, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4243825696, + 3035866144, 804496416, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 284402720, 4025721888, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 3321078816, 49521696, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1584, 528, 92745986, 4203163648, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 1283928064, + 0, 25636864, 2676436992, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 3834064896, + 210186240, 0, 0, 0, 0, 0, + 0, 0, 0, 696725504, 4169609216, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4136054784, 663171072, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4143162400, 1861461024, 49521696, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1660134432, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4243825696, 770941984, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 2112, 528, 92745986, 4203163648, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 1283928064, + 0, 0, 478621696, 4018614272, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 1887907840, 0, 0, 0, 0, 0, + 0, 0, 25636864, 2827431936, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 2340892672, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4277380128, 2113119264, 32744480, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 32744480, 3287524384, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 2364777504, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 2640, 528, 92745986, 4203163648, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 1283928064, + 0, 0, 0, 2038902784, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 3817287680, 210186240, 0, 0, 0, 0, + 0, 0, 881274880, 4219940864, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 3867619328, + 310849536, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4243825696, 1374921760, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 720610336, 4243825696, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 3874726944, 166962208, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 3168, 528, 92745986, 4203163648, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 1283928064, + 0, 0, 0, 193409024, 3683069952, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 1887907840, 0, 0, 0, 0, + 0, 25636864, 3045535744, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 1736912896, + 0, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4277380128, 1794352160, 1072931872, 1072931872, + 1593025568, 4260602912, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 3790840864, 217293856, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 2331223072, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4260602912, 4143162400, 4277380128, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 1391698976, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 3696, 528, 92745986, 4203163648, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 1283928064, + 0, 0, 0, 0, 1418145792, 4270272512, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 3817287680, 210186240, 0, 0, 0, + 0, 1082601472, 4253495296, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 3464966144, 109522944, + 0, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4243825696, 603169824, 0, 0, + 351511584, 4227048480, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 1727243296, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 150184992, + 3841172512, 4294157344, 4294157344, 4294157344, 4294157344, 3522405408, + 938714144, 317957152, 1374921760, 3975390240, 4294157344, 4294157344, + 4294157344, 4294157344, 3019088928, 32744480, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 4224, 528, 59191556, 2290561024, 2324115456, 2324115456, + 2324115456, 2324115456, 2324115456, 2324115456, 2324115456, 2575773696, + 4270272512, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 3129421824, 2324115456, 2324115456, 2324115456, + 2324115456, 2324115456, 2324115456, 2324115456, 2324115456, 696725504, + 0, 0, 0, 0, 42414080, 3179753472, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 1887907840, 0, 0, 0, + 59191296, 3280416768, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4253495296, 1149710336, 0, + 0, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4243825696, 603169824, 0, 0, + 351511584, 4227048480, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 3170083872, + 32744480, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1358144544, + 4277380128, 4294157344, 4294157344, 4294157344, 4260602912, 787719200, + 0, 0, 0, 1727243296, 4294157344, 4294157344, + 4294157344, 4294157344, 4176716832, 519283744, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 4752, 528, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 528953344, + 4236718080, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 1753690112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 864497664, + 4203163648, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 3817287680, 210186240, 0, 0, + 1317482496, 4270272512, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 2928095232, 25636864, 0, + 0, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4126385184, + 2582881312, 2498995232, 2800985120, 2331223072, 66298912, 32744480, + 2113119264, 2918425632, 2498995232, 2549326880, 4042499104, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4059276320, + 133407776, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 32744480, 2985534496, + 4294157344, 4294157344, 4294157344, 4294157344, 4109607968, 99853344, + 0, 0, 0, 905159712, 4277380128, 4294157344, + 4294157344, 4294157344, 4294157344, 2062787616, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 5280, 528, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 528953344, + 4236718080, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 1753690112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 2575773696, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 1887907840, 0, 92745728, + 3481743360, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4119277568, 646393856, 0, 0, + 0, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 3421742112, + 32744480, 0, 0, 1928569888, 2331223072, 2129896480, + 2213782560, 49521696, 0, 0, 3102975008, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4243825696, + 502506528, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 485729312, 4176716832, + 4294157344, 4294157344, 4294157344, 4294157344, 4260602912, 1056154656, + 0, 0, 0, 1995678752, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 3639845920, 83076128, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 5808, 528, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 528953344, + 4236718080, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 1753690112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 428290048, 3985059840, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 3817287680, 210186240, 1552363520, + 4270272512, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 2324115456, 0, 0, 0, + 0, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 3404964896, + 32744480, 0, 0, 49521696, 3086197792, 3337856032, + 83076128, 0, 0, 0, 3102975008, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4260602912, + 653501472, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2012455968, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 3824395296, + 1475585056, 737387552, 1928569888, 4126385184, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4277380128, 1089709088, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 6336, 528, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 528953344, + 4236718080, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 1753690112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1955016704, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 2022125568, 3666292736, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 3867619328, 310849536, 0, 0, 0, + 0, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 3421742112, + 32744480, 0, 32744480, 2113119264, 2163450912, 1945347104, + 2381554720, 66298912, 0, 0, 3119752224, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4243825696, + 468952096, 0, 0, 0, 0, 0, + 0, 0, 0, 66298912, 3606291488, 4294157344, + 3539182624, 1358144544, 972268576, 2582881312, 4277380128, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4143162400, 2012455968, + 905159712, 1710466080, 3958613024, 4294157344, 2717099040, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 6864, 528, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 528953344, + 4236718080, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 1753690112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 159854592, 3615961088, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4203163648, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 1720135680, 0, 0, 0, 0, + 0, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4159939616, + 2817762336, 2733876256, 3019088928, 2180228128, 32744480, 0, + 1945347104, 3102975008, 2733876256, 2784207904, 4092830752, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4025721888, + 116630560, 0, 0, 0, 0, 0, + 0, 0, 0, 1056154656, 4277380128, 4109607968, + 519283744, 0, 0, 32744480, 2884871200, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 1945347104, 0, + 0, 0, 1307812896, 4277380128, 4059276320, 317957152, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 7392, 528, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 528953344, + 4236718080, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 1753690112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1334259712, 4270272512, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 3448188928, 92745728, 0, 0, 0, 0, + 0, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4243825696, 603169824, 0, 0, + 351511584, 4227048480, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 3102975008, + 32744480, 0, 0, 0, 0, 0, + 0, 0, 0, 2683544608, 4294157344, 3421742112, + 32744480, 0, 0, 0, 1710466080, 4294157344, + 4294157344, 4294157344, 4294157344, 4260602912, 787719200, 0, + 0, 0, 183739424, 4210271264, 4294157344, 1744020512, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 7920, 528, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 528953344, + 4236718080, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 1753690112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 42414080, 3095867392, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4253495296, + 1132933120, 0, 0, 0, 0, 0, + 0, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4243825696, 603169824, 0, 0, + 351511584, 4227048480, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 1643357216, + 0, 0, 0, 0, 0, 0, + 0, 0, 301179936, 4042499104, 4294157344, 3958613024, + 250848288, 0, 0, 0, 2465440800, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 1509139488, 0, + 0, 0, 888382496, 4260602912, 4294157344, 3371410464, + 49521696, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 8448, 528, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 528953344, + 4236718080, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 1753690112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 780611584, 4169609216, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 2911318016, + 25636864, 0, 0, 0, 0, 0, + 0, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4277380128, 2012455968, 1307812896, 1307812896, + 1811129376, 4260602912, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 3706954784, 183739424, + 0, 0, 0, 0, 0, 0, + 0, 0, 1710466080, 4294157344, 4294157344, 4294157344, + 2918425632, 552838176, 301179936, 1676911648, 4176716832, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 3857949728, 1123263520, + 250848288, 854828064, 3522405408, 4294157344, 4294157344, 4260602912, + 804496416, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 8976, 528, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 528953344, + 4236718080, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 1753690112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2491887616, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 4119277568, 646393856, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4227048480, 1257481248, 0, + 0, 0, 0, 0, 0, 0, + 0, 32744480, 3337856032, 4294157344, 4294157344, 4294157344, + 4294157344, 4193494048, 4076053536, 4294157344, 4294157344, 4143162400, + 2364777504, 1643357216, 2817762336, 4260602912, 4294157344, 4277380128, + 4042499104, 4243825696, 4294157344, 4294157344, 4294157344, 4294157344, + 2415109152, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 9504, 528, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 528953344, + 4236718080, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 1753690112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 377958400, 3951505408, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 4287049728, 2307338240, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4260602912, 1945347104, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 770941984, 4243825696, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4277380128, 1576248352, + 0, 0, 32744480, 2515772448, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 3891504160, 183739424, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 10032, 528, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 528953344, + 4236718080, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 1753690112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1871130624, + 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 3850842112, 294072320, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4076053536, 1660134432, 32744480, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 2381554720, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4143162400, 166962208, + 0, 0, 0, 972268576, 4277380128, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 1442030624, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 10560, 528, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 528953344, + 4236718080, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 1753690112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 126300160, + 3548852224, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4287049728, 1703358464, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 3035866144, 653501472, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 166962208, 3874726944, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4227048480, 502506528, + 0, 0, 0, 1374921760, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 3069420576, 32744480, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 11088, 528, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 528953344, + 4236718080, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 1753690112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 2122788864, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4219940864, 260517888, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4210271264, 3992167456, 3992167456, 4193494048, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 2834539552, 49521696, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1408476192, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 2968757280, + 301179936, 0, 619947040, 3606291488, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4193494048, 552838176, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 11616, 528, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 528953344, + 4236718080, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 1753690112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 2089234432, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4203163648, 226963456, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 3086197792, 183739424, 183739424, 1425253408, 4260602912, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4277380128, 1643357216, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 32744480, + 3035866144, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4025721888, 3572737056, 4143162400, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 2096342048, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 12144, 528, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 528953344, + 4236718080, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 1753690112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 2089234432, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4203163648, 226963456, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 3035866144, 0, 0, 32744480, 2582881312, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4025721888, 636724256, 0, 0, 0, + 0, 0, 0, 0, 0, 536060960, + 4193494048, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 3673400352, 83076128, 0, 0, + 0, 0, 0, 0, 0, 0, + 12672, 528, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 528953344, + 4236718080, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 1753690112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 2089234432, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4203163648, 226963456, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 3035866144, 0, 0, 0, 250848288, 3639845920, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 3270747168, 116630560, 0, 0, + 0, 0, 0, 0, 0, 2062787616, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4277380128, 1123263520, 0, 0, + 0, 0, 0, 0, 0, 0, + 13200, 528, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 528953344, + 4236718080, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 1753690112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 2089234432, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4203163648, 226963456, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 3035866144, 0, 0, 0, 0, 989045792, + 4176716832, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 2129896480, 0, 0, + 0, 0, 0, 0, 83076128, 3656623136, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 2750653472, 0, 0, + 0, 0, 0, 0, 0, 0, + 13728, 528, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 528953344, + 4236718080, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 1753690112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 2089234432, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4203163648, 226963456, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 3035866144, 0, 0, 0, 0, 0, + 2146673696, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4176716832, 989045792, 0, + 0, 0, 0, 0, 1106486304, 4277380128, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4143162400, 4109607968, 4109607968, 4109607968, + 4109607968, 4109607968, 4109607968, 4109607968, 4109607968, 4109607968, + 4176716832, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4076053536, 351511584, 0, + 0, 0, 0, 0, 0, 0, + 14256, 528, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 528953344, + 4236718080, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 1753690112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 2089234432, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4203163648, 226963456, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 3035866144, 0, 0, 0, 0, 0, + 116630560, 3321078816, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 3639845920, 267625504, + 0, 0, 0, 0, 2733876256, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 3958613024, 334734368, 166962208, 166962208, 166962208, + 166962208, 166962208, 166962208, 166962208, 166962208, 166962208, + 938714144, 4260602912, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 1777574944, 0, + 0, 0, 0, 0, 0, 0, + 14784, 528, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 528953344, + 4236718080, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 1753690112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 2089234432, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4203163648, 226963456, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 3035866144, 0, 0, 0, 0, 0, + 0, 670278688, 4042499104, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 2616435744, + 32744480, 0, 0, 334734368, 4076053536, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 2515772448, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 49521696, 3421742112, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 3404964896, 49521697, + 0, 0, 0, 0, 0, 0, + 15312, 528, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 528953344, + 4236718080, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 1753690112, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 2089234432, 4287049728, 4287049728, 4287049728, 4287049728, 4287049728, + 4287049728, 4287049728, 4203163648, 226963456, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32744480, 3472073760, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 3035866144, 0, 0, 0, 0, 0, + 0, 0, 1710466080, 4277380128, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4260602912, + 1408476192, 0, 0, 1760797728, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, 4294157344, + 4260602912, 905159712, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1827906592, 4294157344, 4294157344, 4294157344, 4294157344, + 4294157344, 4294157344, 4294157344, 4294157344, 4260602912, 838050848, + 0, 0, 0, 0, 0, 0, + 0, 368, 2821736, 2821736, 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, + 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, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 16352, 8848, 2684485632, 1936548716, + 12292, 1920233069, 541214546, 542792024, 134276615, 352324096, + 201333504, 1886610273, 1413894989, 0, 0, 0, + 0, 0, 0, 3606446080, 256, 768802816, + 1936548716, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 218103808, 1668506980, 536936448, 1073741824, 1953656931, 1610678272, + 905969664, 1953526903, 2550202368, 335544320, 1684105315, 2885746688, + 738197504, 1515804786, 3623944192, 335544320, 1515804770, 3959488512, + 335544320, 1515804775, 131072, 335544320, 1129469042, 335675392, + 536870912, 1129469031, 335675392, 536870912, 1129469026, 335675392, + 536870912, 1836214371, 872546304, 603979776, 1684958564, 1476526080, + 603979776, 1684303204, 2080505856, 603979776, 1668639853, 0, + 16777216, 201326592, 1398107749, 603979776, 469762048, 1224754944, + 1342196992, 1644175360, 1761637632, 1946184704, 1761619200, 536899072, + 1375761152, 1107314432, 1668639853, 0, 16777216, 201326592, + 1398107749, 436207616, 469762048, 1962954752, 1811964416, 1660971264, + 1140858880, 1828744960, 1761632512, 28160, 542792024, 0, + 3606446080, 256, 768802816, 842229363, 0, 1108082944, + 3724869632, 636747775, 2466709504, 2432499712, 2717646847, 2734555135, + 3691184128, 1858076672, 542792024, 0, 2691629056, 4114087936, + 2416115712, 542792024, 0, 2669936640, 2215575552, 3300261888, + 542792024, 0, 2539782144, 2276917248, 3642228736, 1634886000, + 0, 768, 1717961216, 2817654784, 1494024192, 3490906112, + 1527382016, 1836214371, 0, 768, 3617783808, 2085879808, + 3444310016, 2593718272, 1730543616, 1544486912, 1668639853, 0, + 16777216, 201326592, 1398107749, 134217728, 469762048, 1224754944, + 1342196992, 1668639853, 0, 16777216, 201326592, 1398107749, + 134217728, 469762048, 1375761152, 1107314432, 808464432, 942682160, + 942682160, 942682160, 1717973040, 1711945828, 808478054, 875573552, + 875967585, 808858681, 808529968, 808464433, 808529968, 808529968, + 1714434096, 811754598, 808662064, 808988720, 808857654, 808857655, + 808988725, 808923191, 809054263, 171454521, 1664114992, 1680880689, + 1647338288, 1664115248, 842086705, 1714434865, 1680946225, 1714512177, + 1680958769, 1664180529, 808608561, 1697788978, 808597298, 1664234034, + 1664168754, 942826289, 959592243, 808674098, 858862346, 859058996, + 845558068, 859386679, 859321188, 845361970, 858993509, 1714565940, + 811754598, 808662064, 809054257, 809054265, 811741283, 808989027, + 828649572, 842150712, 845361457, 858927921, 842205746, 842215987, + 842215987, 842215987, 842215987, 842215987, 842215987, 842215987, + 842215987, 842215987, 842215987, 842215987, 842215987, 842215987, + 842215987, 842215987, 842215987, 842215987, 856306227, 858927922, + 858927922, 858927922, 858927922, 858927922, 1714565938, 808477542, + 808530224, 875573304, 808529968, 808661040, 808596017, 825372720, + 808529969, 808530227, 1667655217, 825241652, 170930278, 825241648, + 825242928, 825241904, 825241904, 808464688, 808464432, 808464432, + 808464432, 825241648, 858796592, 892351536, 925906480, 959461424, + 1647337776, 878929510, 895627312, 808464433, 825242160, 808661002, + 808595507, 808661044, 808792117, 808726580, 808464432, 811874097, + 808595505, 808464435, 808530228, 842150197, 875639601, 825634865, + 909194547, 842477617, 825308978, 942814004, 1630615857, 942672433, + 842281778, 828584290, 842347825, 812003684, 858993714, 842478134, + 959459896, 909205808, 942749489, 1630615857, 909260082, 942815026, + 1630681394, 892548147, 926103091, 959658035, 859070771, 873083956, + 875967541, 876098615, 895562809, 892613939, 892745013, 892876087, + 912340281, 909391411, 909522485, 909653559, 929117753, 926168883, + 926299957, 926431031, 945895225, 942946355, 943077429, 171456567, + 1631074616, 859386425, 892941369, 926496313, 960051257, 845242681, + 878785377, 912340321, 945895265, 1633761633, 862073442, 895628386, + 929183330, 962738274, 845373794, 878916451, 912471395, 946026339, + 1664705290, 1681024097, 1681155123, 1681286197, 1681417271, 1700881465, + 1697801521, 1697932595, 1698063669, 1698194743, 1717658937, 1714578993, + 1714710067, 1714841141, 1714972215, 1717659193, 808739686, 812003632, + 808454705, 825242416, 825241904, 825241904, 825241904, 825241904, + 808464432, 808464432, 808464432, 842019120, 875574064, 909129008, + 942683952, 1630550320, 1717985840, 808465507, 825308514, 842018864, + 805974320, 808726578, 808661044, 808923188, 808726581, 808464436, + 926036017, 808464439, 808595505, 808530227, 842346548, 808530737, + 875704630, 808531249, 925972023, 842215729, 942814002, 825765937, + 171062324, 828453177, 828584290, 858929456, 842347315, 892416102, + 842478134, 1630548324, 875705905, 828716083, 828781874, 942749489, + 1630615857, 926037554, 959592498, 892559666, 926103091, 959658035, + 859070771, 875836426, 875967541, 876098615, 895562809, 892613939, + 892745013, 892876087, 912340281, 909391411, 909522485, 909653559, + 929117753, 926168883, 926299957, 926431031, 945895225, 942880818, + 943011892, 926419510, 959985720, 842621240, 876163897, 909718841, + 943273785, 1631140153, 862007905, 895562849, 929117793, 962672737, + 845308257, 878850914, 912405858, 945960802, 1633827170, 862138979, + 895693923, 1661613667, 1664639799, 1684103993, 1681089586, 1681220660, + 1681351734, 1681482808, 1697801569, 1697932595, 1698063669, 1698194743, + 1717658937, 1714644530, 1714775604, 1714906678, 1715037752, 1684432481, + 808464481, 171126883, 808464688, 825307696, 825307952, 1714630704, + 845557808, 909588324, 1664235319, 875706211, 943076196, 1700934241, + 828782690, 1631072816, 811677746, 1631072816, 811677746, 892547888, + 925983537, 1701131826, 959787274, 808859748, 943142498, 828466787, + 959722851, 1630746677, 1633969206, 942957109, 862282083, 1664562533, + 1684157750, 1698246963, 1684223332, 1633837365, 842347873, 1647665456, + 1701208627, 878851640, 1647905381, 892494649, 828662838, 909468770, + 892560182, 1684103728, 912680242, 1650680371, 1664563507, 943219297, + 828519270, 909653606, 825505379, 842544944, 946157616, 909468724, + 1633825377, 1714708789, 906638900, 828520245, 1667510372, 1647731558, + 1684222310, 862139746, 1684419892, 1650602338, 959669558, 875782758, + 912405296, 929392183, 892625977, 1647339110, 929260131, 812017203, + 909194288, 962815590, 171128887, 808478310, 929326136, 1650537778, + 1700934499, 1647600484, 1697735266, 1664509493, 962802999, 859387185, + 925918262, 1698062692, 1681012273, 926376548, 1664694070, 912406326, + 912613942, 942748006, 1697920823, 1647796746, 895891507, 929391204, + 943023206, 959853926, 842347829, 1667446625, 1698062694, 1633826615, + 1681417785, 825516902, 1650733669, 1647392819, 1700935733, 842293862, + 1650603875, 1714774627, 875771442, 962726500, 1664299826, 1664639329, + 828662886, 875772213, 1714762037, 909390132, 895562297, 892351792, + 862335076, 1681154354, 1697932643, 1647469364, 1667641444, 808935986, + 1664312626, 842425906, 929445173, 856307252, 1650746211, 1714632291, + 862086200, 825648437, 1681209441, 943088177, 909468979, 858940004, + 1701078071, 1667511091, 1684158006, 811807537, 812017252, 909259312, + 1714894948, 1714709092, 1680879718, 174340145, 1681483060, 1650799670, + 892494438, 1714762084, 942879334, 812003686, 1697669686, 929380193, + 859005286, 845230689, 1647468856, 828780642, 808989232, 959787319, + 912351588, 912351842, 1700935781, 912668469, 1664432138, 1697855846, + 909600054, 1664639799, 912472420, 811873075, 825583153, 892559669, + 825581874, 895706166, 825582643, 842097972, 959723828, 1697735777, + 895628899, 1647863396, 1681154867, 862020658, 909445731, 1717723490, + 895564132, 1650735155, 962881074, 1681339233, 862348130, 1664168291, + 825831782, 929314918, 845494576, 959997491, 808478310, 1667379249, + 943153715, 1647587682, 963011169, 959721529, 1628071270, 1650865718, + 945960243, 809002596, 1664562995, 959472226, 926038065, 929325873, + 959799860, 1701142884, 1684420409, 862008674, 959865653, 926377318, + 912601913, 1684431973, 1684289125, 862140516, 174405168, 1697724729, + 828585273, 1650680120, 875903329, 876032824, 895563108, 1717842532, + 1714829113, 962935097, 862335030, 878862643, 892941921, 1697986868, + 1647797810, 862347877, 845571685, 1714567475, 1697986662, 862270730, + 812017209, 1647337776, 879060535, 1714512738, 1664102502, 1714971958, + 942682214, 1697998133, 1717975347, 929181793, 1647600998, 1717973347, + 1650800227, 946168931, 960063073, 811754803, 1714959462, 808454758, + 895825208, 1715024741, 1647337830, 879060535, 1714512738, 1698063206, + 1681285730, 895705650, 929194291, 1667653944, 825647667, 1650549303, + 963011381, 1714958950, 925905715, 892625507, 1701001059, 1711945524, + 1680947248, 926233657, 943077688, 1714774325, 909127782, 862074468, + 929130038, 1701067110, 1647928884, 929456738, 926376505, 1630548790, + 912351797, 895563572, 1684103735, 959668791, 1647326516, 174340451, + 862205749, 1684419892, 1647666743, 909206841, 943208247, 859190370, + 1698051380, 1698116966, 929326649, 875639909, 892612917, 929260087, + 942761315, 909272371, 859322470, 1717711461, 1681012784, 1630745697, + 1634022922, 1664246372, 1717843557, 828585317, 943076966, 926508600, + 858874680, 842216294, 842478137, 1715025973, 929390902, 828728934, + 943143223, 1701197669, 1717842488, 959459430, 925918770, 1647404646, + 962923105, 926245687, 859255606, 943143265, 1701142838, 845427300, + 842229299, 909326647, 1681155126, 926298211, 878798128, 943141478, + 1680881765, 892942391, 912483127, 859060022, 929315172, 1633968482, + 1711956277, 959459430, 1715037798, 1634100067, 929129316, 1684353329, + 1634021431, 943154738, 845560165, 1701198181, 858940981, 1667643236, + 828793906, 912482872, 929128757, 1684355128, 1700881202, 1681143095, + 174272612, 929456697, 862086704, 1630745187, 825307954, 925905252, + 943010103, 1647404593, 879060535, 1647732321, 912680546, 1717986917, + 878784560, 912535910, 825779760, 879060531, 811742007, 808478310, + 1715025506, 845243914, 929194340, 909337954, 962815590, 929326389, + 1684366903, 812017252, 959735344, 1717646181, 879125299, 1664563043, + 862074421, 812005218, 1698183012, 876045925, 842163300, 862086707, + 926179637, 1697974885, 845559907, 959538741, 942750008, 962867814, + 943023155, 1700869990, 1650864946, 862348596, 1647797606, 862283319, + 1667642209, 1700946482, 929380454, 808478310, 1714631986, 1717973557, + 912404528, 1711957557, 859189857, 909338209, 1700947041, 1647653218, + 1717844326, 946038116, 808793702, 875914598, 909718583, 1667379763, + 825701988, 825375075, 1664180835, 862270565, 895771492, 962683192, + 1714894433, 171128931, 1667641957, 960063031, 892822113, 876033126, + 876044849, 1717842529, 959919158, 892417331, 845428321, 926246245, + 892953954, 862073189, 942944825, 942761315, 925905718, 845505841, + 1717711202, 1717908578, 1701196554, 1714905655, 862008165, 1647469414, + 859136565, 809068134, 1717723959, 862336824, 1717777713, 926496565, + 895760441, 1630550369, 909392225, 959865908, 878995044, 845374565, + 842216035, 1681273656, 842336823, 912680548, 929391673, 912679782, + 808478310, 926168931, 892680294, 942825780, 909338209, 926037303, + 959997491, 892810850, 825439796, 1633903928, 859060067, 1667512161, + 912352358, 1698063204, 1678402615, 1684431154, 825451878, 845505380, + 929326177, 959854387, 912668215, 909193785, 892940597, 959931955, + 1681351735, 1700870451, 1684156985, 909206374, 1633956658, 862073700, + 1698063460, 945961271, 171270456, 1681013091, 859190835, 959984946, + 1664628274, 808597347, 1698259299, 892547937, 1633903925, 1667588707, + 926311735, 926115429, 929261157, 862269542, 1717778481, 895760486, + 1647468898, 845428065, 1631138616, 895629578, 842228065, 842609461, + 1714971192, 875640372, 959787317, 1684103481, 942694756, 962879844, + 943011380, 926364517, 1681089126, 1634089008, 912536676, 1630626401, + 859254837, 859123769, 1664693048, 892930658, 926366001, 1684419379, + 828716641, 1650734433, 909588322, 1701001267, 842424887, 1714906210, + 1717842019, 909259366, 1714894948, 1714709092, 942761062, 862270820, + 1667577143, 909141305, 808478310, 856305977, 1714643766, 929129573, + 1664640358, 862347574, 962671155, 842414387, 926037298, 1714709090, + 858796134, 1681469748, 811742258, 1647587684, 1667653986, 828651833, + 909588021, 1633772130, 842425911, 174340197, 945893687, 1697855799, + 892942135, 929445730, 912417335, 1664235365, 1700869937, 1684104752, + 828651574, 1667654965, 825701177, 1697800502, 963011427, 875772001, + 1664693345, 929314105, 1630614326, 1680958006, 1664299274, 926300469, + 926377014, 1714905906, 825778486, 959919927, 962750002, 1700934500, + 1698193969, 892692016, 962946661, 892548405, 959538745, 943077476, + 1667326310, 1697789495, 811743027, 1698260579, 862325348, 1647470128, + 892351845, 876111415, 1701012837, 876044855, 943142753, 895693665, + 812017201, 1681351736, 1684419385, 1684366896, 943089203, 1717986916, + 1681010736, 1681274423, 929194596, 929380452, 889874021, 892679223, + 812017251, 959656240, 1647916596, 1630953780, 909588324, 1717724518, + 859191091, 828716897, 1681469749, 929183797, 1698117424, 1714894133, + 845570661, 825636661, 875640116, 825571125, 171391075, 943154232, + 1701197669, 1647458100, 808478310, 926311014, 808478310, 912536161, + 1634023778, 828782948, 895902773, 895563362, 1647653477, 1650614882, + 1664301364, 875706467, 895629668, 825833062, 842163001, 1664301066, + 1631020337, 943010616, 828781924, 909654116, 959865913, 1684288866, + 926311782, 828728164, 1681404725, 926038064, 926508130, 926364773, + 1680893495, 1681285938, 1714578785, 1697801778, 1714959717, 1714686519, + 862086198, 1681340771, 1681273955, 1664181092, 1680946995, 1697736240, + 962934114, 1681470775, 959852897, 946103863, 892559714, 1715037538, + 959919973, 909469028, 1701078629, 1650746422, 828531513, 956982582, + 1650799417, 1684103989, 943208294, 1650603366, 1714513463, 912341300, + 1714577764, 811688292, 1681285941, 1633891426, 1717909042, 909141092, + 959669811, 1664170289, 895890533, 1631085669, 1630691686, 174220083, + 828453688, 1684224048, 1717854518, 1717921076, 828531046, 892416870, + 828520806, 959985764, 1714446691, 1717646388, 946168417, 1647470178, + 811886181, 828780900, 926443106, 892822834, 942891620, 878851378, + 1684289034, 912417843, 811754597, 1714434149, 825701171, 1667654453, + 808989795, 825241651, 895903027, 828453730, 1714895158, 1633826916, + 1700934963, 929392185, 1701067063, 1717909045, 1681286500, 1664705124, + 909183586, 859388261, 1630888549, 1697985843, 1647731046, 1647796793, + 892483891, 895628386, 875913830, 1681416805, 962998370, 926101816, + 858993207, 1697723238, 959526704, 892888627, 1647785015, 808935729, + 839530849, 1681286241, 1701208373, 959657058, 1684169783, 845429044, + 1647338552, 1698248805, 812017209, 1717973040, 1701078583, 1717647413, + 929325360, 1717711927, 1681220453, 862271030, 812017204, 1667380016, + 171075173, 1701197410, 1698050918, 895837028, 876032820, 895891811, + 1647601249, 926167142, 1701132344, 1650734391, 845494579, 1681220194, + 1650733924, 1684300854, 808728115, 926102374, 929248817, 808477027, + 808465200, 1697722378, 1681470822, 1697788262, 912602723, 1700999781, + 1701143907, 929445938, 1681273140, 1701013090, 811820087, 1667523638, + 1714565173, 1714709553, 892953907, 1698181475, 878915893, 892940645, + 876034102, 1714883172, 1634100835, 1681076838, 1633837874, 845361973, + 1684288054, 895891760, 895890276, 929326645, 1650669881, 858863671, + 926180710, 1714446899, 959865446, 808478310, 1633956449, 1700935522, + 1717974579, 1661612080, 1684354361, 1701197623, 1717986404, 875573350, + 1630758201, 812003683, 1667643186, 909600056, 812017201, 862205488, + 892626534, 1714828642, 1681285943, 842622566, 1700881506, 1650746982, + 812017250, 171533616, 892822323, 929248102, 909194084, 959669559, + 808478310, 1714698595, 1717711972, 926508133, 959997286, 1667392824, + 1684169060, 862271282, 1667655225, 1684419641, 1701208628, 1714895204, + 943274085, 1684234853, 809001226, 1680957747, 1701196595, 828780852, + 1714644279, 895771491, 962683234, 1714894433, 1697855587, 929261106, + 1631140198, 1714763618, 926429493, 1664116070, 925983795, 943141989, + 1698116966, 1631009075, 859114041, 1717973813, 809054256, 1717723959, + 862336824, 1717777713, 859060021, 1717975393, 946024496, 1714775347, + 962999139, 929390904, 946037345, 1717986147, 1664626736, 1714644066, + 926365237, 1701195830, 1695168304, 892612961, 926233649, 892822329, + 1681274160, 858863973, 909719910, 1681012325, 845559906, 929391206, + 959735137, 959984947, 1631086132, 909653813, 875704628, 1664104246, + 1664180531, 909391669, 174208561, 1630626406, 1681219896, 960061747, + 929117749, 858940517, 962671414, 1631072865, 962945586, 808609336, + 845296694, 825439329, 875706681, 825571379, 845493348, 960051554, + 959919414, 842216545, 842479668, 1631019786, 909468473, 862074466, + 878797362, 912470327, 1630549857, 1667512678, 929313075, 895694897, + 926233398, 960051000, 842479157, 1667578209, 1650669156, 1701196646, + 859137634, 845361508, 828650036, 1698040421, 1697984869, 811940195, + 963012150, 1664496433, 1684366899, 1701197665, 1630954296, 1633825126, + 1714697830, 1714893616, 1647917155, 1717973302, 1681272880, 879126067, + 892678966, 1714500965, 1698117475, 1628071481, 1647850337, 1717985843, + 1697986359, 862021218, 1630691635, 1633761330, 929314662, 1633957476, + 1664705590, 926365497, 959918647, 926167095, 1717789752, 1664693346, + 808989750, 1664170035, 842151270, 171468130, 959734325, 1715037237, + 859385907, 845296441, 828531556, 926233908, 1700933986, 878982754, + 862282593, 878862946, 1667445561, 1664365112, 1681351781, 926299233, + 859321392, 929378659, 892549217, 876098102, 892560394, 1680880695, + 1650604083, 845374515, 1717844322, 1650800689, 946103906, 859005282, + 925972791, 1681155379, 945960038, 1714643558, 1650604387, 892745779, + 878994532, 811872561, 1700869990, 1667391800, 1667369524, 1680881461, + 1697735523, 1650603314, 845570360, 1684365925, 1700868917, 862217315, + 825637175, 1664562995, 1714971192, 808924217, 811808819, 1647469414, + 808662840, 1630811235, 1714578488, 1714828599, 1711945057, 895891298, + 879112292, 1667445299, 1647719475, 929445476, 1647863097, 926376501, + 825779814, 812017252, 912417072, 876033331, 1697670451, 1717710948, + 895628898, 862336313, 1667392613, 942760549, 174469986, 963000374, + 862271078, 1650745650, 808542519, 1698193719, 1717777764, 1633761077, + 1630757687, 1701196388, 862009699, 828466483, 1714829157, 1698062950, + 926377523, 1647392610, 858994227, 1664444001, 1715024742, 1647469322, + 811807587, 912666933, 845428068, 892625462, 1701208673, 1714709602, + 1667445089, 1633837622, 959920179, 1681078580, 1647863093, 1717974885, + 929378864, 892613942, 926233649, 1715025252, 859201841, 943196727, + 926180198, 828728374, 892559972, 892679737, 926036838, 1684419385, + 959669044, 1698116402, 1684289584, 808858470, 808988984, 1684222775, + 946092086, 1647666788, 909467958, 1684287799, 959734116, 873084517, + 926298673, 1684365878, 942879538, 1697723442, 1681090096, 1633759540, + 912351588, 912340280, 1697997413, 912668469, 929183032, 895837241, + 926299958, 1650681187, 862282552, 942695475, 892417126, 174274102, + 1681285942, 1650734178, 1684355123, 858940466, 811938406, 1647535672, + 825701173, 962803763, 845558834, 1634023735, 859202612, 926233905, + 912417124, 1650680933, 1717711716, 1717974374, 808464432, 1697932644, + 1650866186, 845231153, 1681090105, 1684354406, 1650812470, 845559142, + 892691250, 1650811447, 1681285681, 1701011764, 1647600180, 1667643490, + 875706467, 879048291, 909402980, 825503799, 1698194225, 825778487, + 842402357, 895770936, 895759457, 1631074617, 1697801526, 859267685, + 1667642979, 1717975344, 858927152, 926442553, 878863462, 808478310, + 1681273188, 1717854773, 1714905649, 1717646437, 1717723702, 1717909094, + 805987942, 1714708784, 1664443441, 912471609, 1717843557, 895693413, + 1667511650, 1684353378, 929378872, 842622519, 825778790, 912417892, + 926114608, 926180401, 895640883, 862283316, 812017206, 892953392, + 171402341, 1684366903, 1717986916, 959721520, 1717646181, 1684104248, + 845440052, 811939937, 1714512230, 842282295, 1650549089, 892560692, + 875902769, 946223413, 1717974885, 892481584, 842360371, 808478310, + 1714763362, 845243914, 1717646134, 1717646899, 946233911, 812004705, + 895706722, 926049589, 895758694, 895563366, 959854177, 1681286500, + 1698259809, 929260853, 845230950, 845505333, 859124786, 942879587, + 875914291, 1630931558, 1714631525, 909390181, 929380454, 825779558, + 963012147, 925905203, 808478310, 1667326769, 1697932387, 1664365366, + 808478310, 1664561209, 1714972213, 892547942, 929129782, 811885410, + 1667655265, 923415859, 878798388, 808804709, 926234982, 859189303, + 1698062647, 912471605, 945959269, 878785079, 1664640312, 878993971, + 895890737, 1714894897, 862138469, 1698115940, 1714960180, 862271285, + 962672441, 171258677, 963012147, 1650669360, 1714894950, 1664430387, + 909587814, 1631008311, 1717974321, 959983664, 859399474, 862206260, + 862335286, 1701143862, 895824691, 895825505, 1684366133, 1714971185, + 808739634, 929118309, 912548362, 812017249, 942826288, 1664181860, + 811886182, 1717974834, 808597042, 862283366, 879047993, 1714894390, + 1697986147, 1650550329, 811754035, 858809913, 1664300390, 1631085924, + 1714959462, 942682214, 1647381045, 1715024741, 875585894, 808478310, + 878916709, 1667655217, 1714958903, 825571430, 959669602, 808478310, + 1714696289, 1664378214, 1717973300, 929247280, 1701012018, 1714970931, + 845231923, 858940514, 822764902, 946222644, 1701197669, 1714630968, + 959459430, 925905203, 1664181862, 1701196641, 1714828337, 1714906424, + 858863717, 859399782, 1714892849, 825241702, 808477027, 845230947, + 1647468856, 1714971237, 174272561, 1714840633, 943023462, 811820599, + 895575650, 929313846, 929118007, 858863718, 828794165, 809056313, + 912537701, 943154489, 929248610, 1650876985, 1664431203, 1701012790, + 862348595, 1701144112, 892953913, 1714894602, 909390181, 929380454, + 825779558, 812017203, 825440560, 1717974832, 1717658417, 929260345, + 1667393126, 895836724, 858929510, 862139492, 959473207, 1714840881, + 962815285, 1714827365, 959459430, 909314609, 1701196643, 1714905444, + 912472165, 1714643809, 825571430, 959669602, 808478310, 1714696289, + 1664378214, 1717973300, 929247280, 828531250, 1667379556, 945907251, + 926300262, 912405812, 895890020, 923416628, 1633827171, 909599288, + 1701065829, 1664640097, 825635170, 842621283, 808673587, 1681221221, + 926169395, 1717842278, 1634023265, 1647535672, 1717985843, 1697986359, + 862021218, 929326386, 862282291, 174483001, 825831472, 1717974579, + 1701195824, 1717975396, 946155568, 1700869475, 862085432, 1684157798, + 1650877744, 1631138915, 1634087988, 1647916596, 1647916849, 825702711, + 1650669410, 1633903668, 1633958242, 1714958691, 878916106, 1631085872, + 929325623, 1631074658, 875586918, 1714512998, 1664562277, 858875238, + 845505638, 1633773113, 1717789542, 812015922, 1650603575, 1647862886, + 1717658465, 859268665, 946091109, 1715036771, 926157410, 1650604387, + 909457459, 811885156, 878981937, 1717646950, 1700869430, 1701197616, + 1714828337, 1714906424, 858863717, 808478310, 808530745, 828794423, + 1684365667, 1714435174, 943142704, 862139193, 822764898, 926049890, + 845428277, 1684235618, 929129520, 912417638, 875848294, 1717724726, + 859386679, 892680038, 942750008, 1630549042, 842216038, 1714774882, + 912679474, 962868019, 1701209189, 929326645, 171401573, 1664694114, + 962998326, 929183545, 895758904, 962946614, 1634100836, 946157925, + 1664443956, 1664640613, 1714566199, 1684104293, 1667381553, 1714840120, + 1634099507, 1681351474, 929392185, 1664639588, 1701130850, 878798090, + 859333936, 876045410, 926233653, 909457250, 1630954297, 845361460, + 859005493, 895561827, 875902517, 1633760865, 876033844, 1680881719, + 1681417272, 895575395, 1680947511, 878785889, 875980087, 909249126, + 912340535, 858992741, 959721528, 828781669, 1630613604, 1647851366, + 942957108, 1681285938, 1633956409, 909326692, 960050228, 962748772, + 959526706, 1634023731, 1684235319, 1650669110, 1650602341, 856308023, + 909718627, 1667588454, 1650669364, 1681023289, 808936804, 1697853795, + 859137334, 929444406, 811938403, 1697669431, 842424886, 811743330, + 926103601, 912602936, 1701066341, 926443110, 962737510, 171533924, + 959669560, 959918646, 876034355, 1667642933, 1714775607, 845230130, + 828465464, 1714762341, 943141936, 878917474, 892625250, 828649570, + 1664574514, 959603299, 959919974, 1667393124, 1714829368, 862151012, + 1684420106, 875574885, 962670646, 1681209701, 1631139891, 828453222, + 1701012532, 909260596, 1714435889, 892625714, 1697920309, 812017203, + 895692848, 1647468902, 1717973304, 1647392056, 1715024741, 1630548070, + 1714686512, 1664378214, 1717973300, 929247280, 1717975090, 892874800, + 862282289, 1634100793, 1717974064, 879046704, 1714500707, 842490726, + 1717724002, 1715037285, 1698129253, 812017203, 859203120, 1647338086, + 956982630, 828716901, 875587174, 945907301, 1681274977, 1684419635, + 1664365366, 1698181986, 1697986404, 1630954293, 1715026228, 876164915, + 842491237, 828728627, 929456740, 879124788, 1650538849, 929118308, + 171128115, 1631138360, 943153509, 959591733, 859267426, 1647783991, + 842413921, 912417634, 929314355, 912537393, 842479460, 1633826659, + 1681285687, 1647600998, 858940773, 828728630, 862271032, 862269793, + 945960548, 946221322, 1717985892, 1647785266, 1717986357, 1714894690, + 1680879718, 1698182962, 1630626914, 929391458, 1714828133, 1664102502, + 1684354361, 1701197623, 1717986404, 875573350, 1630758201, 862072934, + 959865143, 942934581, 892822627, 1714644070, 1717776741, 962802273, + 962748722, 892941109, 828651315, 1714906470, 1717842022, 1717975352, + 670052, 12960, 2822272, 2822272, 543517801, 1701869940, + 1769497888, 1695154278, 174483832, 538976288, 842281780, 926233610, + 909719096, 808464438, 876164144, 811676217, 808988720, 808464432, + 811675696, 808464432, 808726577, 808529968, 808464432, 808466480, + 808464432, 808529968, 808726577, 808529968, 808464432, 808585776, + 808464432, 842018864, 858796336, 858796080, 808464432, 909652016, + 808464432, 842084400, 858796336, 825241648, 808464432, 825241648, + 808464432, 1630613552, 892350768, 825241648, 808464432, 940191792, + 808464483, 825241648, 808530018, 808464437, 808464433, 959459376, + 808464436, 842018864, 808529976, 808464435, 808464433, 808464432, + 808464435, 858796080, 808529969, 808464434, 808464484, 170930224, + 808477497, 808464432, 825242163, 808464944, 808465457, 808464432, + 808477025, 808464432, 926431542, 808465456, 808464688, 808464432, + 808478050, 808464432, 808464484, 808464432, 808466480, 808466480, + 808988682, 808923952, 808464434, 808726832, 808464432, 808923952, + 808464434, 808726832, 808464432, 876033072, 895759417, 858796592, + 862270002, 842019633, 858927973, 808464436, 858927920, 858927920, + 1630734898, 942878771, 825450803, 808595507, 858993203, 842228019, + 1630746675, 875769907, 825241648, 825241648, 858796129, 825241648, + 808464432, 825241648, 808464432, 808464432, 808464432, 942682160, + 805974064, 808529968, 808464436, 808464433, 808464432, 808529968, + 808464432, 808529969, 808464436, 808464433, 875573296, 808464432, + 808464432, 808529970, 808464435, 808464435, 858796080, 808529974, + 170930224, 825242416, 808465200, 808464688, 808464432, 808465968, + 808464432, 825243184, 808465200, 808464688, 808464432, 808465968, + 808464432, 825242929, 808465200, 808464688, 808464432, 808465200, + 808464432, 808529930, 808726578, 808529968, 808464432, 811807536, + 808464433, 808595504, 808726578, 808529968, 808464432, 808739376, + 808464486, 808464432, 808464432, 808988720, 808988720, 808988720, + 1684432432, 1717963320, 808464485, 1630810161, 959723060, 808465972, + 825241904, 808464432, 808464688, 808464688, 1717973040, 808477284, + 808465204, 909129776, 925906480, 892352048, 925906992, 925906736, + 959461680, 805976112, 828584033, 811872308, 811741283, 828584034, + 825372985, 828780595, 828649780, 828780897, 828649829, 828584289, + 842019427, 845492788, 842019383, 845361714, 828584243, 859320931, + 842609207, 170931043, 875770163, 875770931, 926049841, 1681078579, + 842217523, 1697801011, 875770675, 1717973555, 808477284, 825242420, + 959461680, 1664104752, 1664115248, 1680881713, 942761008, 825373235, + 825385777, 842215987, 858927882, 858927922, 858927922, 858927922, + 858927922, 858927922, 858927922, 858927922, 858927922, 858927922, + 858927922, 858927922, 858927922, 858927922, 858927922, 858927922, + 858927922, 858927922, 842205746, 842215987, 842215987, 842215987, + 842215987, 842215987, 1717973555, 808464483, 942682417, 808726576, + 808464688, 825242416, 808464946, 825307696, 858796336, 825241905, + 878929510, 1714499632, 805974064, 808529968, 808529973, 808529969, + 808529969, 808464433, 808464432, 808464432, 808464432, 808529968, + 808661042, 808792116, 808923190, 809054264, 1717710945, 808739686, + 825582128, 808464432, 170995762, 858796848, 875573808, 892351280, + 875574576, 808465456, 825241648, 825254967, 858796592, 875573296, + 892350769, 825373233, 825504051, 858863152, 825635125, 842151728, + 875639095, 825766451, 828453177, 842543114, 1647457331, 825320241, + 1681012021, 842032689, 909325108, 942815026, 809054258, 825635169, + 825766199, 845230393, 842412597, 842543671, 862007865, 859124532, + 859255606, 859386680, 875770977, 892602932, 926168628, 959723572, + 859136308, 892679221, 926234165, 959789109, 859201845, 892744758, + 926299702, 959854646, 859267382, 892810295, 926365239, 959920183, + 859332919, 892875832, 926430776, 940193848, 962672697, 959658290, + 959789364, 959920438, 960051512, 1630691681, 1630822707, 1630953781, + 1631084855, 1650549049, 1647534642, 1647665716, 1647796790, 1647927864, + 1664246625, 1664377651, 1664508725, 171467575, 1633892707, 862204516, + 895759460, 929314404, 962869348, 828727652, 862270053, 895824997, + 929379941, 962934885, 828793189, 862335590, 895890534, 929445478, + 963000422, 1717985638, 808465507, 825255473, 808464394, 808529971, + 808529969, 808529969, 808529969, 808529969, 808464432, 808464432, + 808464432, 808595505, 808726579, 808857653, 808988727, 811675705, + 1667655266, 1647325236, 808530229, 808595504, 842009137, 875574320, + 875574064, 892352304, 875574320, 825241648, 926364208, 825241648, + 858796592, 875573553, 825374000, 909127987, 825504305, 925905205, + 825700662, 842150705, 825766451, 875640880, 956969524, 1647403313, + 808543025, 858993209, 1714566451, 909455664, 1681012530, 828452913, + 859058742, 842097972, 825321013, 825766199, 845230393, 842478134, + 842609208, 859124577, 859255606, 859386680, 171127905, 892613684, + 926168628, 959723572, 859136308, 892679221, 926234165, 959789109, + 859201845, 892744758, 926299702, 959854646, 859267382, 892810295, + 926365239, 959920183, 842555703, 876098360, 909653304, 943142922, + 943274040, 959592801, 959723827, 959854901, 959985975, 1633761593, + 1630757170, 1630888244, 1631019318, 1631150392, 1647469153, 1647600179, + 1647731253, 1647862327, 1667326521, 1664312114, 1664443188, 929237558, + 962803811, 845439331, 878981988, 912536932, 946091876, 1633958244, + 862270053, 895824997, 929379941, 962934885, 845570405, 879113062, + 912668006, 946222950, 1634089318, 1633969766, 1664102448, 805974832, + 808464433, 808530226, 808530227, 812004144, 1681024560, 926299959, + 1667445303, 1681142327, 1631073843, 1650811442, 808543800, 845232178, + 808476984, 845232178, 808476984, 825570099, 842477923, 174417206, + 1681470769, 1647326776, 1664628534, 1664180582, 892941365, 912339768, + 895575140, 1664627810, 1697867105, 912471861, 862216757, 1684355377, + 895771445, 1633772129, 808596789, 862074209, 946169442, 1697931830, + 962738442, 909455971, 1647404132, 909522276, 808792931, 845439330, + 859203173, 862085986, 1633892153, 1714960482, 1714512435, 1664497718, + 808530998, 808597559, 876111160, 1630942564, 895574578, 879113313, + 892734006, 1680958007, 1717789744, 1717712483, 1650746161, 875782965, + 1650746933, 912417329, 1715024741, 808727394, 926310963, 959931750, + 1714762852, 1667379302, 859267938, 808478310, 1714827572, 926507878, + 1711944504, 942682214, 842490980, 1667391797, 1684365875, 1650603107, + 895824226, 929248870, 825844533, 909326645, 1681338468, 828716641, + 1684288054, 909588322, 912472375, 909533751, 1714840930, 926429489, + 174404663, 862074722, 1681221176, 1714906466, 1714959716, 892941877, + 1630680373, 1717789495, 929379937, 962683447, 1717844070, 1697723491, + 862086194, 895627576, 1717920312, 1664234594, 1667392055, 845559138, + 1681142582, 842621450, 1633891123, 1717778529, 892429412, 892613433, + 879113521, 959853617, 808804658, 1681207349, 842229296, 1667511393, + 879047781, 1684157027, 845375024, 842020706, 845362021, 892483174, + 876045877, 1664289334, 1667392611, 946221878, 892559972, 1630615141, + 828650808, 859321954, 1681274213, 926102114, 862282852, 912483379, + 828662326, 1680892723, 808478310, 1681273394, 1684420408, 1717974114, + 828649520, 873096248, 912537957, 1717724468, 1681207906, 1717974321, + 1714959154, 909141553, 1634021474, 1714906423, 1630745441, 942825778, + 1650602593, 808543792, 925906994, 1681470769, 1647731041, 1698062690, + 895836728, 171337271, 1717777720, 912601913, 926300005, 1684224099, + 859202361, 825254963, 892417382, 842347361, 909194593, 859136868, + 875640164, 875704677, 1631138873, 1667576164, 1681220150, 862074982, + 845427811, 1664311652, 1647719690, 1684431457, 859136313, 845308984, + 1631151206, 1650734899, 1664312931, 1717776689, 1714501937, 808936504, + 858940729, 1715026022, 825241702, 862151216, 1647851362, 1633825841, + 960063074, 1715024944, 912329317, 862086710, 1681416757, 858798182, + 1650669367, 825831522, 825700920, 876045411, 1681470818, 962946401, + 1650746935, 892559669, 1715025507, 959919973, 1698063667, 1701078628, + 1684300854, 808674104, 956982582, 962933049, 942760757, 1633837921, + 942945593, 1681143603, 1681219893, 963011634, 962999863, 909731129, + 859006512, 1630823009, 875903286, 845493561, 1700935526, 1697867362, + 858941030, 1717973561, 174404920, 959669557, 808478310, 929181793, + 1647600998, 1717973347, 912470064, 1717975141, 892874800, 862270821, + 1634100793, 1714905648, 1667380325, 1667655217, 1667392822, 1631085924, + 859388262, 1714446949, 1717975092, 942682122, 1697998133, 1717975347, + 929181793, 1647600998, 1717973347, 1650800227, 845428322, 859136866, + 943153761, 862152289, 925972066, 895639906, 1715037795, 862337074, + 1664561203, 1664431202, 879059767, 811993655, 962867512, 943142196, + 892876345, 1717974369, 1681272880, 909337142, 1714905446, 879060025, + 1650604390, 959932002, 909588322, 895561779, 875979106, 926245175, + 929325410, 876163938, 1667379253, 889873465, 875783223, 929326645, + 962737510, 926298469, 1647851575, 875771444, 1717909045, 962934581, + 1698128998, 892612916, 926233649, 1664574306, 859320677, 1714827877, + 1697855544, 812016178, 1633956408, 174142260, 1684104502, 1700999778, + 1701209142, 1714512693, 943207990, 943143270, 1714631011, 959591219, + 892483378, 912668984, 1714906465, 925984102, 1698182969, 946169399, + 1717986354, 842608688, 1714892902, 1633825126, 926508298, 909587811, + 1630746419, 909653817, 1684366689, 858940466, 926036838, 909521721, + 1667511396, 808924720, 1714708837, 1698182962, 929312824, 926234936, + 909534051, 1681077303, 1647797305, 895575137, 1717963361, 1715023920, + 1667643750, 1684104803, 825712995, 929326385, 845243696, 1698183014, + 1697801785, 895837753, 1681076838, 845375031, 942761572, 892756834, + 943153505, 845440312, 929390947, 1684288565, 956982064, 808937058, + 1664311910, 845230898, 1680945459, 926363697, 825767217, 929182054, + 1630823782, 1650603622, 1698063974, 812017254, 1714708784, 808870961, + 858863718, 926180710, 1714446899, 1647325286, 174471478, 1681023334, + 1647796833, 1714828133, 892953446, 926377061, 1684301158, 808478310, + 1698247782, 862347571, 1664378467, 895694647, 1647534646, 1680893495, + 1701132343, 1681143654, 858927716, 892559974, 1698116705, 1667577098, + 892495416, 943272294, 1714958649, 859399218, 1714959716, 845504823, + 878863923, 1714644581, 929183589, 1630758246, 845375027, 1717920354, + 1714906424, 842018918, 895890229, 812017202, 892756528, 1634077286, + 1630746162, 1630942054, 1650811492, 1717712177, 1684431929, 1714971493, + 1714435382, 926168421, 859191604, 1684234802, 1664169782, 1664168505, + 1700999522, 1681089844, 943023203, 1631150433, 1667643190, 1695167288, + 929261106, 1631140198, 1714763618, 825505588, 1630812002, 912679986, + 859387700, 1630875957, 1697801270, 1647785317, 1697986917, 959668785, + 1664627762, 909652325, 825700403, 1647469925, 1650876977, 174482740, + 929392179, 1701197666, 1714643251, 895627875, 1714632034, 925907302, + 946233955, 825452087, 895902517, 959920439, 1630889016, 1633759289, + 875967545, 1681471076, 1697932390, 1664246628, 942814002, 929314355, + 1681011978, 959866470, 1714906468, 1714841187, 1664102502, 1714893879, + 875902264, 1631072865, 926298982, 859255349, 1647917158, 875902774, + 942748470, 1667326821, 1630745655, 1717789751, 1681285476, 929379939, + 845417060, 1717855841, 1680946021, 1630692707, 859268196, 926496311, + 959866422, 892743986, 859126065, 926496614, 862205796, 962945337, + 1717854770, 842412387, 1684104243, 1681089075, 929379940, 943219257, + 1661613409, 862204473, 842217014, 842610741, 1667446838, 1664102967, + 1634023777, 892678963, 1667326821, 929260898, 1698117221, 1698116454, + 1714905958, 825451824, 1717986104, 1647666232, 1633825377, 942826549, + 174143795, 1630888505, 892482401, 942815539, 879114338, 892612918, + 960050481, 1684300129, 1681404001, 876176481, 1698182454, 1714894643, + 811873122, 1684104760, 1630954548, 895562082, 959657776, 942880048, + 1650669875, 825571594, 859256633, 1633969715, 1630627126, 1650615349, + 859191095, 929391416, 1647457890, 1667643236, 1717986352, 1681273394, + 1684420408, 1717974114, 1681404260, 926115125, 962815285, 1714827365, + 959459430, 909314609, 1701196643, 1714905444, 912472165, 859006561, + 859398450, 842151481, 1647784501, 1717974114, 875769904, 845429041, + 1680892468, 1650603057, 962815585, 892429369, 1647720246, 929128802, + 1697789542, 923427896, 926441777, 929379129, 1647655223, 926377527, + 1698062946, 828584503, 811950391, 912548198, 892429368, 962815589, + 909195059, 1667576417, 1631151715, 1630810936, 962804020, 909599797, + 912339251, 174338402, 895693617, 909588025, 842479460, 912668515, + 925972577, 842610487, 1681482342, 828727859, 811939938, 1697985894, + 892953958, 959787829, 1681469798, 1714959928, 929259873, 862270006, + 1664115255, 1684355430, 808674826, 1700934246, 926232629, 1697921126, + 929391461, 1630812002, 1631074103, 825582387, 942696038, 962869092, + 811886131, 862217574, 1681405542, 812017254, 929313328, 1684289078, + 1681351266, 1698129208, 926222950, 1664431412, 808478310, 876163889, + 878852406, 1684092513, 1714829111, 862347877, 1630746167, 892429623, + 895760689, 808935992, 895825719, 1701197621, 892495458, 875640375, + 892612917, 1664169271, 940193592, 1698183012, 879060535, 1717711415, + 1714434150, 1714894434, 1630548070, 1647731762, 1684104505, 892429881, + 1647666788, 1697997110, 1650603314, 878862946, 1667445561, 1681142328, + 1714774585, 959527222, 171061859, 828584760, 945895269, 1681405235, + 1680959029, 959854648, 1647916644, 1717855285, 1681340005, 892429667, + 811874355, 1647784504, 1698117988, 926365492, 845426790, 1633957475, + 845558373, 1701130854, 929445941, 912667658, 1664311908, 1667512121, + 1684289076, 862138723, 811872567, 1650798950, 926508341, 1633958197, + 926496305, 1647862886, 1647653729, 1701198181, 1681471287, 1698051429, + 912614502, 962749540, 909206115, 960039525, 895640883, 1717854563, + 1714960439, 929194549, 879112550, 1681285433, 1684419169, 892363105, + 1650734691, 845243188, 1684432182, 859189348, 825832294, 1700999481, + 1697998388, 1717647460, 862007905, 940204643, 808542515, 912548664, + 879125601, 1717986661, 1714512481, 1714762035, 1680958009, 1664694328, + 879112289, 1634099508, 1647863138, 1700934246, 1680893030, 1647404593, + 842479718, 1681209189, 842543970, 171205173, 862217270, 1698062948, + 1697669732, 862335024, 892417843, 1667458659, 858798132, 858861616, + 1647666789, 909205811, 1684420409, 862020152, 962945589, 926377318, + 895837241, 1684432182, 1684289125, 1650669922, 1698050314, 1697855801, + 862008674, 1717908789, 962737761, 862074722, 1647653433, 1714774580, + 1697920354, 1650735202, 943285808, 926364465, 1714631474, 811938099, + 859386167, 926234726, 828520244, 1630549857, 1630669369, 895759972, + 1650812513, 926495540, 878994020, 942826553, 1700933732, 962935096, + 808478310, 929457712, 895837286, 812015928, 926377057, 1701208628, + 912536931, 875783478, 808478310, 1701012019, 1644835430, 1717921334, + 1684354611, 875914595, 1664366387, 1630889529, 1717711974, 943141936, + 929391928, 862086197, 1647469881, 1684288866, 912417843, 862217316, + 1714435126, 825701171, 1664574262, 808464481, 170930227, 1717907760, + 1717844277, 1667576369, 1698063670, 1667588914, 845505893, 876045880, + 1650734641, 929391462, 909140836, 895706212, 828781104, 862336100, + 1664432485, 895825969, 1697932081, 909457713, 1681143608, 1667643146, + 1717659238, 845427506, 895574627, 909271859, 811885618, 1681221177, + 892692019, 959931494, 929194809, 1714630968, 859255909, 1717973090, + 1715025506, 1630548070, 1650549810, 862282295, 812017206, 962791984, + 929326389, 1684366903, 1717986916, 959721520, 1667314533, 842032689, + 946038327, 825636709, 808478310, 1714644022, 1647653990, 929445429, + 1717843555, 1647458662, 1717920100, 1650615398, 808478310, 856308069, + 1714763619, 1681351475, 926298419, 1715024741, 1664102502, 1684419641, + 1701208628, 1714895204, 943274085, 1684234853, 845439585, 959669559, + 962815590, 878994996, 1684366946, 1701197625, 1698183480, 174351202, + 858798177, 862204257, 879060531, 925984305, 1667642213, 1647666275, + 1631150433, 1667643190, 845493048, 1714905958, 1650538809, 895890743, + 1714894897, 862138469, 1698115940, 1714960180, 862271285, 962672441, + 892548362, 812017203, 925907248, 946233955, 825452087, 895902517, + 1630745655, 812017209, 859333424, 1667642725, 943285811, 1631020385, + 1664639842, 812017251, 1650669616, 895890276, 909588278, 811951664, + 1634011703, 825570353, 959919412, 808793955, 1701066293, 1714630969, + 1698052409, 1650733622, 1714579000, 1631020386, 859386981, 876165173, + 895563878, 875968567, 909390385, 862138423, 895693153, 825635895, + 1711956534, 945893730, 862205281, 892942689, 1698128182, 909324900, + 1631150387, 845232178, 943285602, 909128294, 1630691892, 959525684, + 859058745, 1680946488, 1647469876, 909719865, 1631139637, 875705140, + 171063096, 962672483, 1647719779, 842228278, 926179682, 1630954289, + 1717645367, 862151737, 825713713, 909468472, 943142195, 892942647, + 1630680886, 1684235577, 1717723958, 1650812467, 1681077606, 875717425, + 1697735730, 1701131786, 1667577137, 909141305, 825845350, 862139955, + 1633969510, 946169399, 1717646947, 1717658161, 812004406, 1667643187, + 912406840, 812017201, 862205488, 909403750, 1697985843, 1667641653, + 962934583, 1633749606, 862074931, 929457762, 1650799927, 859005286, + 845230689, 1717657912, 1681351735, 912352310, 962804068, 926365495, + 926496562, 943141936, 1650877284, 912472372, 858798132, 1717776696, + 1647456821, 889862245, 892941410, 862337380, 959658288, 1681023539, + 875651683, 1647785269, 1650811441, 1630823478, 1647535459, 959734370, + 946037555, 1701000242, 1633957732, 808924724, 1664301108, 1631020337, + 909456184, 171194418, 926233444, 862203956, 862085688, 1647469412, + 828793913, 1650615608, 1647862886, 926102369, 859255097, 1717843045, + 1714971188, 1667642210, 862085689, 1681208888, 825517156, 1714447409, + 946168119, 878928481, 895705610, 1667510327, 845492579, 945971765, + 1697801825, 895772002, 1667588403, 926114916, 858863161, 946026295, + 963000418, 858797876, 1714447160, 945959523, 1664103223, 945894452, + 929444452, 1634088501, 1650854453, 1681221175, 859072048, 862151474, + 1684158004, 959931958, 895629413, 1714894690, 1680947302, 808478310, + 859202145, 859060021, 1684353125, 1650876976, 959799862, 1697867317, + 1701012068, 1647849826, 906651187, 1715037752, 842229046, 929195105, + 925905249, 1684355169, 895902517, 929128759, 1684091747, 1667589682, + 859005241, 1697735013, 1717974583, 862271074, 1647785830, 862073143, + 1630745398, 1717777766, 174471475, 1667379811, 892363571, 1681286705, + 909272117, 1630876770, 1650812514, 1634088036, 912483121, 862020194, + 876164920, 895759161, 1700935781, 812017207, 909600050, 825570357, + 1681339700, 828782901, 926103137, 1714960394, 909587555, 1680958820, + 959787874, 1714763062, 959918643, 878994995, 842609507, 811939635, + 1717855288, 942683699, 925906993, 912548659, 1681417272, 912405862, + 926299489, 1684300849, 1698247777, 825494070, 909588018, 845440354, + 842543923, 811938100, 878981990, 1684103473, 943087969, 1698062645, + 895825250, 943089207, 959930933, 909469028, 1664562743, 945972069, + 859006307, 1714958436, 909455668, 906650422, 1650734691, 862086196, + 845440312, 1714631268, 942695730, 895628134, 858863411, 842621752, + 926049844, 878798137, 825439844, 1681339701, 1698062945, 1684169572, + 1717985843, 812017205, 1680879664, 174404709, 828532280, 959602996, + 1717842790, 912549173, 1717724518, 842163765, 926233955, 828532066, + 878982754, 879059809, 1650603106, 1667458616, 1664365112, 1681155382, + 926299235, 825308208, 929380451, 892418145, 942814730, 1630889057, + 959800372, 912341049, 1701130853, 1664300898, 811820598, 812017209, + 959656496, 1714894948, 1714709092, 1680879718, 895759921, 828793954, + 1701197666, 912679220, 1717985890, 1717986614, 808454758, 828781665, + 962803044, 1698063158, 1701209142, 1647665970, 1650680885, 946103601, + 926377266, 1714567526, 1680947298, 808870500, 825701219, 859255908, + 875913829, 909337958, 808478310, 1697986915, 923416420, 1684301158, + 812017254, 1698247728, 946233651, 878993764, 1630692452, 1714447672, + 929444193, 1630680117, 878862689, 825570149, 892613943, 1698195001, + 812017207, 859124272, 1714566502, 1647325286, 174470454, 909271398, + 862347571, 929456438, 1631086178, 1647339061, 892691302, 1714893413, + 1714775089, 1630888246, 1681471030, 1633957477, 895826275, 1714905957, + 892494131, 842163555, 1664300340, 859321139, 1714697572, 1700869642, + 1701196595, 1714828337, 1714906424, 858863717, 859399782, 1714892849, + 825241702, 1667457379, 912602212, 1717777459, 959459430, 895694640, + 1717975142, 909456179, 1647796581, 1630561379, 862152294, 876022325, + 1697931622, 1714435425, 926364985, 926103088, 895825505, 1698063158, + 926442033, 942956850, 862140517, 825517154, 825583157, 1701197624, + 1681089328, 879048497, 895891511, 959669559, 892952887, 856306995, + 809068134, 1717723959, 862336824, 1717777713, 926299957, 828454710, + 812017205, 842610736, 875772261, 909337657, 909338161, 862283109, + 1630889267, 892691766, 828663139, 845559906, 1697657955, 171401528, + 1630954594, 808478310, 1681404515, 1717776742, 842032230, 845571639, + 1714434614, 959669606, 909403445, 1667643190, 962934070, 862085478, + 959472226, 1714630758, 1684222773, 1717647461, 1717975092, 892874800, + 1700933898, 1717975347, 1714696289, 1697656934, 825516852, 929261158, + 1717975090, 1647392056, 1715024741, 1630548070, 1717974064, 878916709, + 812017201, 842490672, 862282594, 862337121, 1647468855, 1714631268, + 875629157, 1698194998, 946169399, 1717973809, 859385904, 1714892849, + 1633890662, 828728883, 946222644, 1701197669, 1714630968, 825440614, + 1717974832, 1664167984, 1664102497, 942825779, 1700934241, 828782690, + 956982064, 1717974628, 926430565, 1647338342, 909468006, 926377012, + 1714905399, 892547384, 959538789, 1697659192, 959865912, 1647851365, + 959931189, 1667393122, 912471348, 862282597, 808674917, 962946406, + 171260261, 1701197623, 1714828337, 1714906424, 858863717, 808478310, + 808530745, 828794423, 963010915, 1714905955, 878928486, 1714775394, + 1681076793, 926114612, 825831526, 895891045, 1698259813, 1717974576, + 825831472, 1664496394, 1684366899, 1701197665, 1630954296, 1717973859, + 1647392056, 1715024741, 1630548070, 1717974064, 878916709, 812017201, + 842490672, 1680958050, 862151217, 1714970982, 876033592, 1681285685, + 875914802, 1664551480, 945906233, 1698051938, 1634034740, 1650669668, + 1664169521, 858929505, 1697657697, 862205286, 1714893881, 1634100273, + 945906999, 862073702, 929457762, 1650799927, 842228070, 859268197, + 959669602, 805987942, 858863920, 812017206, 1684366896, 812017209, + 1664640304, 946168117, 1714643553, 811885109, 1667393125, 878786868, + 878798388, 828520758, 929184055, 1647392569, 878863159, 1650549604, + 1667327033, 174471217, 808739634, 929118309, 1647797346, 1717647417, + 1714696293, 1701196132, 1717778228, 1714631013, 959604068, 1717657958, + 845570915, 925918817, 1717723702, 1633826916, 963010915, 1697855334, + 1664640052, 1650866530, 1664562186, 862085689, 1681274168, 825255010, + 1714709555, 912679222, 811950389, 828728887, 946222644, 1701197669, + 1714630968, 959459430, 925905203, 1664181862, 1717855585, 812003380, + 959985463, 1647534899, 1647381093, 892809830, 1647469622, 811885413, + 1714905444, 1714840163, 909390946, 929456742, 1714633011, 943011127, + 842543417, 1717645364, 1647457074, 845559139, 859203170, 1698260019, + 895837796, 1698128998, 1644836705, 912472375, 960063024, 943153719, + 909468722, 1681483110, 1700882022, 876111161, 1701000550, 929249382, + 1701196340, 828662116, 946037305, 862336610, 845244001, 962869091, + 1681352038, 1650669666, 174417202, 808739173, 1647523941, 892614500, + 1647785268, 959853879, 878786147, 892494641, 1664299874, 892690736, + 1630811446, 878797110, 926168887, 946090040, 1667512420, 926245221, + 1633956153, 926179637, 1714697829, 926298634, 1698062646, 942879536, + 1698247728, 1680959028, 1717645616, 878852151, 842544226, 962868835, + 1684104242, 875967289, 1681471796, 842621537, 859386167, 929129785, + 912548708, 1700946742, 929194545, 1664289337, 1714829620, 878929249, + 962749239, 1684288097, 1664104293, 912601905, 909325669, 1664575026, + 925918514, 912601185, 1647457890, 825254456, 943141688, 1698063671, + 1717920822, 1714894950, 1681482293, 940194150, 909718373, 859387698, + 892614457, 929261110, 845559142, 942825776, 1697735009, 812004658, + 1647851316, 1647600439, 1647653985, 842097712, 1667446628, 1715024482, + 1681471287, 946037350, 1684420152, 171139937, 1701078582, 909389878, + 1698259248, 862205241, 1717647672, 875651377, 879059812, 825635383, + 845557815, 892679267, 862270517, 808478310, 1714774832, 945959521, + 946234929, 1700933941, 1717975347, 811675696, 1717974026, 878916709, + 812017201, 842490672, 812017208, 825571376, 959669602, 811689574, + 812017204, 1664378160, 1717973300, 1647458147, 1701208675, 1701198180, + 862271333, 808478310, 1714632294, 1717710946, 1698237029, 1714513207, + 1697919078, 1631084902, 862205496, 912549428, 1650668595, 1684355123, + 895825207, 878786147, 862337337, 1697921335, 858928997, 1680958821, + 876045922, 1630824033, 1684169017, 859267384, 940192565, 1700870450, + 892876641, 1647915573, 926103393, 1633826608, 1647457847, 859202147, + 825713718, 1681286199, 1664235319, 929129015, 1717843554, 1700934757, + 909324901, 942761317, 1630758198, 1681089841, 171467318, 1681417777, + 845571682, 895629109, 1650878052, 1717974839, 845426736, 1650800695, + 1650536804, 1698129251, 1717974579, 962801712, 929326389, 1684366903, + 1717986916, 959721520, 1717646181, 926114352, 892941921, 1664627722, + 1714763620, 1701196644, 1634100017, 842621746, 892953185, 859126067, + 1714512951, 1717974885, 946234416, 1684432441, 2617, 0, + 0, 0, 8864, 4096, 978079064, 778923875, + 1651467361, 1836592741, 112, 1886928700, 1701536609, 1700929652, + 1030646119, 3216764706, 1684611106, 894902845, 1884106829, 1768449347, + 1702001224, 1414429267, 1667988067, 1059218489, 2017200702, 1886222394, + 1635018093, 1819113504, 2017096558, 1684087357, 979722863, 1832547182, + 794915941, 980951074, 1953525112, 1478638955, 1126191181, 543519343, + 775171636, 2017799472, 573732457, 1008732734, 979788914, 541475922, + 1852599672, 1685207667, 1747074406, 980448372, 2004299567, 863448695, + 1735552814, 960049455, 842018617, 758264367, 761685106, 1953397107, + 1848473697, 1042424691, 1008738314, 979788914, 1668506948, 1953524082, + 544108393, 979788914, 1970233953, 572669300, 538976266, 1819113504, + 2017096558, 1296920685, 1952981565, 792359028, 779316783, 1651467361, + 1868770917, 1635266413, 774975344, 1835872048, 537535023, 2015371296, + 1936616557, 1165259578, 574452854, 1886680168, 1848586042, 1684090483, + 778396271, 795701091, 795894136, 791686705, 1886999667, 1699884901, + 1920298867, 1984259427, 594832997, 538970658, 1836589088, 980643436, + 574448484, 1886680168, 1882140474, 778859125, 795308655, 1697604452, + 1701668204, 796095598, 791752241, 538970658, 1836589088, 980643436, + 1347242311, 1952981565, 792359028, 2004317999, 1835624238, 1919889008, + 1836592999, 170012528, 538976288, 1852599672, 1752185459, 1936684143, + 1030778728, 1953785890, 791624304, 1630434158, 1700949860, 1836016430, + 1869115439, 1752395636, 825192559, 573517870, 538976266, 1819113504, + 1949987694, 1030121065, 1953785890, 791624304, 1630434158, 1700949860, + 1836016430, 1718187055, 774975334, 170012464, 538976288, 1852599672, + 1836595827, 1747074416, 980448372, 1936600879, 1868849454, 1663984994, + 2016374127, 825192545, 573517870, 538976266, 1299213688, 1866742349, + 1701672291, 1145664622, 1684087357, 979722863, 1768124260, 1752185444, + 1936684143, 980447080, 943142451, 1684158003, 1714774573, 912403762, + 942486324, 758265904, 876033843, 946156593, 926364004, 538970658, + 1886222368, 1228557645, 1635021678, 1231381358, 2015509828, 1764651117, + 842687593, 1630889060, 761542705, 1681482035, 892679213, 892939617, + 942486066, 895770932, 942826339, 573649720, 538976266, 1299213688, + 1917794893, 1852401513, 1866755169, 1701672291, 1145664622, 1836589629, + 1768173168, 842349156, 842479927, 925720888, 758343012, 942946610, + 1681471533, 1684286817, 862151477, 1650615649, 170015033, 1679826976, + 1868970595, 1952542066, 1835606589, 795174753, 577203824, 538976266, + 1347242311, 1229996346, 775037501, 537535024, 1229398048, 1345998925, + 1718903148, 1030582895, 1852397346, 1937207140, 538970658, 1296647968, + 1767127632, 1951622509, 1030778209, 909521186, 909521200, 909391928, + 959656497, 537535025, 1229398048, 1446662221, 1769173605, 574451311, + 808529458, 573846062, 538976266, 1953458288, 1869116271, 1866676848, + 1299345260, 1030055023, 170013474, 1881153568, 1869901672, 1886349427, + 1128483130, 1718579792, 1030057065, 1196585762, 1162420290, 959526467, + 841823798, 170012974, 1948262432, 979789417, 1701409359, 1952543854, + 1030647657, 170012962, 2015371296, 1127903341, 1952540018, 1952531557, + 841104741, 758133296, 825045553, 825381941, 976827706, 808138291, + 808466993, 538970658, 1886222368, 1701987130, 1919906913, 1819242324, + 1229398589, 840978509, 573583662, 538976266, 980446584, 1635018061, + 1635017060, 1702125892, 808591933, 825045042, 892415282, 976302676, + 859453749, 825240374, 573583418, 538976266, 980446584, 1768189773, + 1631877478, 574449012, 808595506, 758264109, 844379441, 959789617, + 724972346, 809120048, 171844144, 1008738336, 1299213688, 1766341197, + 1919906931, 537542265, 1008738336, 979788914, 1047618899, 538976266, + 1916543008, 1815766628, 538970729, 538976288, 1984263283, 1667316340, + 1852795252, 1919099453, 1702125925, 537535076, 538976288, 1165259552, + 1765438582, 1635021678, 1231381358, 2015509828, 1764651117, 893019241, + 926496562, 761346098, 862282807, 876163629, 959982904, 1680695652, + 1667446116, 1650811187, 574175586, 538976266, 1931485216, 1953908084, + 1718580026, 1918990196, 1701265765, 574452846, 1651467329, 1750081637, + 1936684143, 544239464, 840975171, 540619056, 1852397352, 1937207140, + 537535017, 538976288, 1165259552, 2000319606, 1030645096, 842019362, + 842083632, 1412772141, 893006130, 909326905, 976302123, 790769712, + 538970686, 1008738336, 979788914, 537553260, 538976288, 1165259552, + 1631220854, 1869182051, 1931623790, 1684371041, 538970658, 538976288, + 1984263283, 1751333492, 1701277281, 790773092, 538970658, 538976288, + 1984263283, 1852390004, 1851880563, 1145660771, 1836589629, 1768500848, + 825834084, 1667654758, 1714237796, 761671781, 1714709813, 1647534381, + 845491510, 892548145, 858939701, 170013488, 538976288, 1953701920, + 980710981, 1952870259, 1701994871, 1852139329, 1092762996, 1700949860, + 1869107232, 1752395636, 1126199407, 808591427, 673200433, 1684957527, + 695433071, 538970658, 538976288, 1984263283, 1752644212, 574451301, + 808595506, 758264109, 844379441, 959789617, 724972346, 809120048, + 1043276336, 538976266, 1916543008, 1815766628, 538970729, 538976288, + 1984263283, 1667316340, 1852795252, 1634935357, 577004918, 538976266, + 1931485216, 1953908084, 1634231098, 1684367214, 573514301, 538976266, + 1931485216, 1953908084, 1936615738, 1668178292, 1027885413, 1886222370, + 1684629806, 909272634, 892757303, 862072120, 875389744, 761357154, + 862072929, 862204717, 808923233, 892810293, 537535075, 538976288, + 1165259552, 1933210742, 2004117103, 1097167457, 1953391975, 1766269501, + 840986733, 540029230, 1852397352, 1937207140, 537535017, 538976288, + 1165259552, 2000319606, 1030645096, 842019362, 942681394, 1412444461, + 842674994, 875575864, 171847458, 538976288, 1685204796, 1699953254, + 537542257, 792469536, 1299213688, 1766341197, 1919906931, 537542265, + 1915698208, 1144677988, 1919120229, 1769238633, 171863663, 1915698208, + 1379559012, 171853380, 980954940, 1836084600, 1046574181, 538976266, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538970656, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 537534496, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 169877536, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976266, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538970656, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 537534496, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 169877536, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976266, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538970656, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 537534496, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 169877536, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976266, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538970656, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 537534496, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 169877536, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976266, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538970656, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 537534496, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 169877536, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976266, 538976288, 538976288, 538976288, 538976288, 538976288, + 538976288, 2017410058, 1801675120, 1696625765, 574448750, 1044324983, + 38160, 576, 0, 0, 0, 0, + 0, 0, 0, 16777216, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 25703440, 109523202, 109523202, 109523202, 109523202, + 109523202, 109523202, 109523202, 109523202, 59191557, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 59191556, 109523202, 109523202, 109523202, + 109523202, 109523202, 109523202, 109523202, 109523202, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 99853345, 116630561, 116630561, 116630561, 116630561, 116630561, + 116630561, 116630561, 83076129, 0, 0, 0, + 0, 0, 0, 0, 0, 66298914, + 116630561, 116630561, 116630561, 116630561, 116630561, 116630561, + 116630561, 116630561, 116630561, 49521699, 0, 116630561, + 116630561, 116630561, 116630561, 116630561, 116630561, 116630561, + 116630561, 116630561, 83076129, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 116630561, 116630561, + 116630561, 116630561, 116630561, 116630561, 116630561, 116630561, + 116630561, 83076129, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 38736, 576, 0, 0, 0, 0, + 0, 0, 0, 16777216, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 25703440, 109523202, 109523202, 109523202, 109523202, + 109523202, 109523202, 109523202, 109523202, 59191557, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 59191556, 109523202, 109523202, 109523202, + 109523202, 109523202, 109523202, 109523202, 109523202, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 99853345, 116630561, 116630561, 116630561, 116630561, 116630561, + 116630561, 116630561, 83076129, 0, 0, 0, + 0, 0, 0, 0, 0, 66298914, + 116630561, 116630561, 116630561, 116630561, 116630561, 116630561, + 116630561, 116630561, 116630561, 49521699, 0, 116630561, + 116630561, 116630561, 116630561, 116630561, 116630561, 116630561, + 116630561, 116630561, 83076129, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 116630561, 116630561, + 116630561, 116630561, 116630561, 116630561, 116630561, 116630561, + 116630561, 83076129, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 39312, 32784, 1, 2268135936, 6, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 16844032, + 2026830332, 2268136190, 6, 0, 0, 0, + 0, 0, 0, 0, 256, 2043674111, + 251, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2268135936, + 5, 1, 0, 0, 0, 0, + 0, 0, 512, 2043673853, 4087620093, 5, + 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 224190461, 253, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 4087620096, 65283, 3, 0, + 0, 0, 0, 0, 0, 0, + 512, 224189948, 254, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 822214912, 4294837639, + 61696, 1280, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 20224, 47104, 48128, 15616, + 0, 0, 0, 0, 0, 0, + 0, 58880, 3489672192, 62329, 0, 0, + 0, 0, 0, 0, 0, 0, + 805306368, 8071, 53504, 2816, 0, 0, + 0, 0, 0, 0, 65024, 1948272896, + 49004, 51456, 12544, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 64256, 59904, + 55808, 49664, 44544, 1558238976, 65293, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2753560576, 39667, + 24832, 0, 0, 0, 0, 0, + 0, 0, 0, 1558210816, 39949, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 131072, 0, 262144, 262144, 262144, 262144, + 262144, 262144, 262144, 262144, 262144, 262144, + 262144, 262144, 262144, 262144, 262144, 262144, + 262144, 262144, 262144, 262144, 262144, 262144, + 262144, 262144, 262144, 262144, 131072, 16677328, + 7929856, 0, 262144, 262144, 262144, 262144, + 262144, 262144, 262144, 1966080, 6488064, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 8060928, 983040, 262144, + 262144, 262144, 262144, 262144, 262144, 262144, + 11862016, 12517376, 0, 262144, 262144, 262144, + 262144, 262144, 262144, 262144, 262144, 262144, + 262144, 262144, 262144, 262144, 262144, 262144, + 589824, 2031616, 4521984, 8585216, 13762560, 548601856, + 3142564, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 536870912, + 1110948, 5570560, 262144, 262144, 262144, 262144, + 262144, 262144, 262144, 262144, 262144, 543227904, + 193444, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 33554432, 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, 3388997632, 2751463424, 0, 0, + 0, 0, 0, 0, 0, 0, + 1946157056, 210186240, 0, 0, 0, 0, + 0, 0, 0, 0, 696725504, 1577058304, + 0, 0, 0, 0, 0, 0, + 0, 4143972352, 2030043136, 4286173184, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 50331648, 1258291200, 3338665984, 1861461024, 49521696, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1375731712, 268435456, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 922746880, 721420288, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, + 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, 2043674624, 255, + 125, 240, 0, 0, 0, 0, + 0, 0, 0, 27, 100, 0, + 0, 0, 0, 0, 0, 2268069888, + 1, 127, 7, 0, 0, 0, + 0, 0, 0, 0, 2043674773, 217, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 9, + 144, 4087619707, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 4087619584, 1, 97, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 95, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 512, 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, 3489660928, 58489, 35328, 0, 0, + 0, 0, 0, 0, 0, 0, + 805335808, 3207, 0, 0, 0, 0, + 0, 0, 13056, 21248, 0, 0, + 0, 0, 0, 0, 0, 59136, + 34560, 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, 256, 32512, 20480, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 10496, 14592, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 2753583616, 2547, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 131072, 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, 9568256, + 14417920, 0, 0, 0, 0, 0, + 0, 0, 1835008, 6553600, 0, 0, + 0, 0, 0, 100144, 8454144, 262144, + 0, 0, 0, 0, 0, 0, + 0, 8454144, 15628752, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 16711680, 7012352, + 4194304, 4194304, 6225920, 16646144, 0, 0, + 0, 0, 0, 0, 0, 196608, + 546308096, 848804, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 6291456, 196608, 0, 0, + 0, 0, 16646144, 16187392, 16711680, 0, + 0, 0, 0, 1638400, 4784128, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 33554432, + 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, 4118401024, 2030043136, 4278190080, 0, 0, + 0, 0, 0, 0, 0, 1929379840, + 210186240, 0, 0, 0, 0, 1056964608, + 1207959552, 0, 0, 0, 0, 0, + 0, 0, 3472883712, 2667577344, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 4261412864, 3103784960, 3238878432, 3238878432, 3053453312, 4261412864, + 0, 0, 0, 0, 0, 0, + 0, 0, 503316480, 1509949440, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 150184992, 1509949440, 0, + 0, 0, 0, 3523215360, 973078528, 469762048, + 1392508928, 3976200192, 0, 0, 0, 0, + 1627389952, 32744480, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 516, 65278, 142, 2, + 0, 0, 0, 0, 0, 0, + 15, 101, 1, 0, 0, 0, + 0, 0, 0, 187, 208, 0, + 0, 0, 0, 0, 0, 0, + 221, 0, 0, 0, 0, 174, + 191, 66, 0, 0, 0, 0, + 0, 0, 28, 100, 144, 0, + 2268069888, 3, 131, 2, 0, 0, + 0, 0, 0, 0, 254, 2043674742, + 250, 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, + 4087619670, 224190619, 255, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 72, 26, 0, 0, 0, 254, + 224190557, 210, 0, 4087619759, 21, 153, + 0, 0, 0, 69, 29, 226, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3489399808, 64889, + 30720, 0, 0, 0, 0, 0, + 0, 805306368, 8071, 25344, 768, 0, + 0, 0, 0, 0, 0, 3489705472, + 39033, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 3489660928, 805371513, 30343, 50944, 1280, 0, + 0, 0, 0, 0, 0, 805335808, + 3489700999, 62585, 0, 19200, 15104, 0, + 0, 0, 0, 0, 0, 0, + 45312, 48384, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 62976, 41984, 64256, 4608, + 2753586944, 31219, 65024, 26880, 45568, 59136, + 768, 22784, 3840, 0, 0, 0, + 0, 0, 13568, 1536, 63744, 0, + 0, 0, 0, 0, 0, 0, + 2753560576, 499, 24832, 256, 0, 0, + 0, 63232, 55040, 0, 0, 0, + 52992, 65280, 256, 0, 0, 1792, + 23552, 34304, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 131072, 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, 0, 13466064, 10420224, + 0, 0, 0, 0, 0, 0, + 0, 1835008, 6553600, 0, 362288, 8454144, + 65536, 0, 0, 0, 0, 0, + 0, 16121856, 7864320, 16742864, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 14024704, 3764912128, + 3765177692, 5901660, 15204352, 8847360, 8192000, 393216, + 3763666944, 3765177692, 6884700, 13107200, 0, 0, + 0, 0, 0, 0, 720896, 1441792, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1769472, 4653056, 0, + 0, 0, 0, 589824, 3735552, 0, + 0, 0, 4259840, 65536, 0, 0, + 0, 0, 543031296, 324516, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 67108864, 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, 0, + 0, 2147483648, 1409286144, 301989888, 0, 0, + 0, 0, 0, 0, 1929379840, 2626105344, + 1342177280, 788529152, 0, 0, 0, 0, + 0, 0, 0, 2499805184, 3665416192, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 4278190080, 0, 0, 0, 2415919104, 3036676096, + 251658240, 1040187392, 4262288608, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 16777216, 150994944, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1526726656, + 117440512, 0, 0, 0, 0, 33554432, + 2768240640, 1962124320, 3556769792, 1191182336, 2130706432, 0, + 0, 0, 0, 0, 637534208, 1006632960, + 3221225472, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, + 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, 0, 2043674624, 231, 135, + 0, 0, 0, 0, 0, 0, + 0, 28, 108, 126, 1, 0, + 0, 0, 0, 0, 0, 231, + 136, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 4087619584, + 1, 123, 201, 173, 4087619721, 3, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 255, 245, 0, + 0, 0, 0, 0, 0, 0, + 4087619584, 3, 95, 0, 211, 81, + 58, 154, 255, 28, 168, 212, + 141, 10, 247, 120, 54, 102, + 236, 1, 97, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1024, 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, 0, 0, + 0, 38144, 25344, 10240, 0, 0, + 0, 0, 0, 0, 33280, 1280, + 0, 0, 0, 0, 0, 0, + 0, 3489693696, 61049, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 11264, + 2753603072, 64499, 4352, 52736, 1558216704, 2753625869, + 29683, 2753606912, 60147, 768, 14848, 0, + 0, 0, 0, 0, 0, 62208, + 60160, 0, 0, 0, 0, 0, + 0, 0, 0, 15104, 10240, 62720, + 1558203392, 57869, 2753560576, 51443, 4608, 21504, + 0, 0, 0, 0, 1558215936, 36109, + 0, 2753612544, 59635, 45312, 2753581056, 1558188787, + 60941, 0, 0, 0, 0, 0, + 0, 0, 0, 131072, 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, + 0, 0, 0, 16218576, 7864320, 16711680, + 0, 0, 0, 0, 0, 0, + 327680, 0, 0, 0, 0, 0, + 0, 0, 13500416, 10420224, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 524288, 5767168, 6094848, 4784128, 3768713216, + 16715100, 0, 10551296, 4390912, 6094848, 5898240, + 786432, 0, 0, 0, 0, 0, + 0, 13172736, 16449536, 0, 0, 0, + 0, 0, 0, 0, 0, 6356992, + 65536, 14090240, 14876672, 0, 3758096384, 16715100, + 12189696, 0, 0, 0, 0, 16646144, + 12255232, 0, 0, 0, 12386304, 16515072, + 917504, 5570560, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 33554432, + 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, 0, 0, 0, 0, + 3003121664, 3120562176, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 4261412864, 1979711488, 4219064320, + 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, 0, 2835349504, 4279065824, 0, + 0, 0, 0, 0, 0, 0, + 301179936, 1358954496, 0, 536870912, 218103808, 0, + 0, 0, 754974720, 0, 0, 0, + 0, 33554432, 721420288, 0, 0, 0, + 704643072, 50331648, 0, 1627389952, 49521696, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 4, 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, 0, + 0, 0, 2043674624, 2268070142, 118, 64, + 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 176, 190, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 4087619668, 214, + 0, 30, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 221, + 169, 0, 0, 0, 0, 0, + 0, 0, 0, 84, 15, 0, + 20, 4087619743, 115, 241, 82, 102, + 0, 0, 0, 0, 0, 4087619724, + 233, 204, 36, 157, 2, 0, + 53, 45, 209, 0, 0, 0, + 0, 0, 0, 0, 1024, 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, 0, 0, 0, 0, 3489660928, + 805360249, 40071, 27392, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 62976, 3489691904, 65401, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 256, + 34816, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 64512, 1558212096, 62989, 0, 0, 0, + 0, 0, 0, 2753560576, 499, 24832, + 0, 0, 0, 20992, 19456, 63744, + 3328, 0, 63232, 38400, 54528, 17920, + 22016, 6656, 48128, 61952, 3072, 768, + 0, 0, 512, 24576, 28928, 0, + 0, 0, 0, 0, 0, 0, + 131072, 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, 0, 0, 0, + 0, 0, 0, 8519680, 15466496, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 9699328, 14318032, 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, 16646144, 3765960704, 11930972, 0, 0, + 0, 0, 0, 0, 0, 0, + 2883584, 3538944, 0, 0, 0, 0, + 393216, 851968, 0, 16711680, 3764846592, 3765701980, + 10423644, 5898240, 9961472, 0, 65536, 983040, + 196608, 0, 0, 0, 0, 542638080, + 717732, 0, 0, 0, 0, 0, + 0, 0, 33554432, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0}; +} \ No newline at end of file diff --git a/engine/src/info/info.cpp b/engine/src/info/info.cpp new file mode 100644 index 0000000..c51c748 --- /dev/null +++ b/engine/src/info/info.cpp @@ -0,0 +1,107 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022-2022, tyra - https://github.com/h4570/tyrav2 +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "info/info.hpp" +#include "strings.h" +#include + +namespace Tyra { + +bool Info::writeLogsToFile = false; + +Info::Info() { + fps = 0; + fpsDelayer = 0; +} + +Info::~Info() {} + +void Info::update() { + if (fpsDelayer++ >= 4) { + fps = calcFps(); + fpsDelayer = 0; + } + timer.prime(); +} + +float Info::calcFps() { + u32 timeDelta = timer.getTimeDelta(); + + if (timeDelta == 0) return -1.0F; + + return 15625.0F / (float)timeDelta; // PAL +} + +float Info::getAvailableRAM() { + size_t bits = getFreeRAMSize(); + return bits / 1024.0F / 1024.0F; +} + +void* Info::allocateLargestFreeRAMBlock(size_t* Size) { + size_t s0, s1; + void* p; + + s0 = ~(size_t)0 ^ (~(size_t)0 >> 1); + + while (s0 && (p = malloc(s0)) == nullptr) s0 >>= 1; + + if (p) free(p); + + s1 = s0 >> 1; + + while (s1) { + if ((p = malloc(s0 + s1)) != nullptr) { + s0 += s1; + free(p); + } + s1 >>= 1; + } + + while (s0 && (p = malloc(s0)) == nullptr) s0 ^= s0 & -s0; + + *Size = s0; + return p; +} + +size_t Info::getFreeRAMSize() { + size_t total = 0; + void* pFirst = nullptr; + void* pLast = nullptr; + + for (;;) { + size_t largest; + void* p = allocateLargestFreeRAMBlock(&largest); + + if (largest < sizeof(void*)) { + if (p != nullptr) free(p); + break; + } + + *(void**)p = nullptr; + + total += largest; + + if (pFirst == nullptr) pFirst = p; + + if (pLast != nullptr) *(void**)pLast = p; + + pLast = p; + } + + while (pFirst != nullptr) { + void* p = *(void**)pFirst; + free(pFirst); + pFirst = p; + } + + return total; +} + +} // Namespace Tyra \ No newline at end of file diff --git a/engine/src/irx/audsrv.irx-em b/engine/src/irx/audsrv.irx-em new file mode 100644 index 0000000..04b6d1b --- /dev/null +++ b/engine/src/irx/audsrv.irx-em @@ -0,0 +1,2 @@ +$PS2SDK/iop/irx/audsrv.irx +audsrv_irx diff --git a/engine/src/irx/bdm.irx-em b/engine/src/irx/bdm.irx-em new file mode 100644 index 0000000..2eb8b4f --- /dev/null +++ b/engine/src/irx/bdm.irx-em @@ -0,0 +1,2 @@ +$PS2SDK/iop/irx/bdm.irx +bdm_irx diff --git a/engine/src/irx/bdmfs_fatfs.irx-em b/engine/src/irx/bdmfs_fatfs.irx-em new file mode 100644 index 0000000..438f958 --- /dev/null +++ b/engine/src/irx/bdmfs_fatfs.irx-em @@ -0,0 +1,2 @@ +$PS2SDK/iop/irx/bdmfs_fatfs.irx +bdmfs_fatfs_irx diff --git a/engine/src/irx/irx_loader.cpp b/engine/src/irx/irx_loader.cpp new file mode 100644 index 0000000..c36f9b8 --- /dev/null +++ b/engine/src/irx/irx_loader.cpp @@ -0,0 +1,196 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Wellington Carvalho +*/ + +#include "irx/irx_loader.hpp" +#include "debug/debug.hpp" +#include +#include +#include +#include +#include +#include +#include +#include "file/file_utils.hpp" + +// external IRX modules + +extern u8 sio2man_irx[]; +extern int size_sio2man_irx; + +extern u8 padman_irx[]; +extern int size_padman_irx; + +extern u8 audsrv_irx[]; +extern int size_audsrv_irx; + +extern u8 libsd_irx[]; +extern int size_libsd_irx; + +extern u8 bdm_irx[]; +extern int size_bdm_irx; + +extern u8 bdmfs_fatfs_irx[]; +extern int size_bdmfs_fatfs_irx; + +extern u8 usbd_irx[]; +extern int size_usbd_irx; + +extern u8 usbmass_bd_irx[]; +extern int size_usbmass_bd_irx; + +namespace Tyra { + +bool IrxLoader::isLoaded = false; + +IrxLoader::IrxLoader() { + SifInitRpc(0); + + while (!SifIopReset("", 0)) { + }; + while (!SifIopSync()) { + }; + + SifInitRpc(0); + + this->applyRpcPatches(); +} + +IrxLoader::~IrxLoader() {} + +void IrxLoader::loadAll(const bool& withUsb, const bool& isLoggingToFile) { + if (isLoaded) { + TYRA_LOG("IRX modules already loaded!"); + return; + } + + loadSio2man(!isLoggingToFile); + loadPadman(!isLoggingToFile); + loadLibsd(!isLoggingToFile); + + if (withUsb) { + loadUsbModules(!isLoggingToFile); + } + + loadAudsrv(true); + + isLoaded = true; +} + +/** + * @brief Apply the SBV LMB patch to allow modules to be loaded from a buffer in + * EE RAM. + * + */ +int IrxLoader::applyRpcPatches() { + int ret; + + ret = sbv_patch_enable_lmb(); + TYRA_ASSERT(ret >= 0, + "Failed to load Applying SBV Patches sbv_patch_enable_lmb"); + + ret = sbv_patch_disable_prefix_check(); + TYRA_ASSERT( + ret >= 0, + "Failed to load Applying SBV Patches sbv_patch_disable_prefix_check"); + + ret = sbv_patch_fileio(); + TYRA_ASSERT(ret >= 0, "Failed to load Applying SBV Patches sbv_patch_fileio"); + + return ret; +} + +void IrxLoader::loadLibsd(const bool& verbose) { + if (verbose) TYRA_LOG("IRX: Loading libsd..."); + + int ret; + SifExecModuleBuffer(&libsd_irx, size_libsd_irx, 0, nullptr, &ret); + TYRA_ASSERT(ret >= 0, "Failed to load module: libsd_irx"); + + if (verbose) TYRA_LOG("IRX: Libsd loaded!"); +} + +void IrxLoader::loadUsbModules(const bool& verbose) { + if (verbose) TYRA_LOG("IRX: Loading usb modules..."); + + int ret; + + SifExecModuleBuffer(&usbd_irx, size_usbd_irx, 0, nullptr, &ret); + TYRA_ASSERT(ret >= 0, "Failed to load module: usbd_irx"); + + SifExecModuleBuffer(&bdm_irx, size_bdm_irx, 0, nullptr, &ret); + TYRA_ASSERT(ret >= 0, "Failed to load module: bdm_irx"); + + SifExecModuleBuffer(&bdmfs_fatfs_irx, size_bdmfs_fatfs_irx, 0, nullptr, &ret); + TYRA_ASSERT(ret >= 0, "Failed to load module: bdmfs_fatfs"); + + SifExecModuleBuffer(&usbmass_bd_irx, size_usbmass_bd_irx, 0, nullptr, &ret); + TYRA_ASSERT(ret >= 0, "Failed to load module: usbmass"); + + waitUntilUsbDeviceIsReady(); + + if (verbose) TYRA_LOG("IRX: Usb modules loaded!"); +} + +void IrxLoader::loadAudsrv(const bool& verbose) { + if (verbose) TYRA_LOG("IRX: Loading audsrv..."); + + int ret; + SifExecModuleBuffer(&audsrv_irx, size_audsrv_irx, 0, nullptr, &ret); + TYRA_ASSERT(ret >= 0, "Failed to load module: audsrv_irx"); + + if (verbose) TYRA_LOG("IRX: Audsrv loaded!"); +} + +void IrxLoader::loadSio2man(const bool& verbose) { + if (verbose) TYRA_LOG("IRX: Loading sio2man..."); + + int ret; + SifExecModuleBuffer(&sio2man_irx, size_sio2man_irx, 0, nullptr, &ret); + TYRA_ASSERT(ret >= 0, "Failed to load module: sio2man_irx"); + + if (verbose) TYRA_LOG("IRX: Sio2man loaded!"); +} + +void IrxLoader::loadPadman(const bool& verbose) { + if (verbose) TYRA_LOG("IRX: Loading padman..."); + + int ret; + SifExecModuleBuffer(&padman_irx, size_padman_irx, 0, nullptr, &ret); + TYRA_ASSERT(ret >= 0, "Failed to load module: padman_irx"); + + if (verbose) TYRA_LOG("IRX: Padman loaded!"); +} + +void IrxLoader::delay(int count) { + int i; + int ret; + for (i = 0; i < count; i++) { + ret = 0x01000000; + while (ret--) asm("nop\nnop\nnop\nnop"); + } +} + +void IrxLoader::waitUntilUsbDeviceIsReady() { + struct stat buffer; + int ret = -1; + int retries = 50; + + delay(5); // some delay is required by usb mass storage driver + + while (ret != 0 && retries > 0) { + ret = stat("mass:/", &buffer); + /* Wait until the device is ready */ + nopdelay(); + + retries--; + } +} + +} // namespace Tyra diff --git a/engine/src/irx/libsd.irx-em b/engine/src/irx/libsd.irx-em new file mode 100644 index 0000000..346ebc7 --- /dev/null +++ b/engine/src/irx/libsd.irx-em @@ -0,0 +1,2 @@ +$PS2SDK/iop/irx/libsd.irx +libsd_irx diff --git a/engine/src/irx/padman.irx-em b/engine/src/irx/padman.irx-em new file mode 100644 index 0000000..82b2fd7 --- /dev/null +++ b/engine/src/irx/padman.irx-em @@ -0,0 +1,2 @@ +$PS2SDK/iop/irx/padman.irx +padman_irx diff --git a/engine/src/irx/sio2man.irx-em b/engine/src/irx/sio2man.irx-em new file mode 100644 index 0000000..52eb9ea --- /dev/null +++ b/engine/src/irx/sio2man.irx-em @@ -0,0 +1,2 @@ +$PS2SDK/iop/irx/sio2man.irx +sio2man_irx diff --git a/engine/src/irx/usbd.irx-em b/engine/src/irx/usbd.irx-em new file mode 100644 index 0000000..0ce6689 --- /dev/null +++ b/engine/src/irx/usbd.irx-em @@ -0,0 +1,2 @@ +$PS2SDK/iop/irx/usbd.irx +usbd_irx diff --git a/engine/src/irx/usbmass_bd.irx-em b/engine/src/irx/usbmass_bd.irx-em new file mode 100644 index 0000000..a0d4467 --- /dev/null +++ b/engine/src/irx/usbmass_bd.irx-em @@ -0,0 +1,2 @@ +$PS2SDK/iop/irx/usbmass_bd.irx +usbmass_bd_irx diff --git a/engine/src/loaders/3d/builder/mesh_builder_data.cpp b/engine/src/loaders/3d/builder/mesh_builder_data.cpp new file mode 100644 index 0000000..eb9fb0d --- /dev/null +++ b/engine/src/loaders/3d/builder/mesh_builder_data.cpp @@ -0,0 +1,28 @@ + +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "loaders/3d/builder/mesh_builder_data.hpp" + +namespace Tyra { + +MeshBuilderData::MeshBuilderData() { + textureCoordsEnabled = false; + normalsEnabled = false; + lightMapEnabled = false; +} + +MeshBuilderData::~MeshBuilderData() { + for (auto& material : materials) { + delete material; + } +} + +} // namespace Tyra diff --git a/engine/src/loaders/3d/builder/mesh_builder_material_data.cpp b/engine/src/loaders/3d/builder/mesh_builder_material_data.cpp new file mode 100644 index 0000000..9b22ac8 --- /dev/null +++ b/engine/src/loaders/3d/builder/mesh_builder_material_data.cpp @@ -0,0 +1,25 @@ + +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "loaders/3d/builder/mesh_builder_material_data.hpp" + +namespace Tyra { + +MeshBuilderMaterialData::MeshBuilderMaterialData() { + ambient.set(128.0F, 128.0F, 128.0F, 128.0F); +} +MeshBuilderMaterialData::~MeshBuilderMaterialData() { + for (auto& frame : frames) { + delete frame; + } +} + +} // namespace Tyra diff --git a/engine/src/loaders/3d/builder/mesh_builder_material_frame_data.cpp b/engine/src/loaders/3d/builder/mesh_builder_material_frame_data.cpp new file mode 100644 index 0000000..3d3ec56 --- /dev/null +++ b/engine/src/loaders/3d/builder/mesh_builder_material_frame_data.cpp @@ -0,0 +1,24 @@ + +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "loaders/3d/builder/mesh_builder_material_frame_data.hpp" + +namespace Tyra { + +MeshBuilderMaterialFrameData::MeshBuilderMaterialFrameData() { + vertices = nullptr; + textureCoords = nullptr; + normals = nullptr; + colors = nullptr; +} +MeshBuilderMaterialFrameData::~MeshBuilderMaterialFrameData() {} + +} // namespace Tyra diff --git a/engine/src/loaders/3d/md2_loader/md2_loader.cpp b/engine/src/loaders/3d/md2_loader/md2_loader.cpp new file mode 100644 index 0000000..7309379 --- /dev/null +++ b/engine/src/loaders/3d/md2_loader/md2_loader.cpp @@ -0,0 +1,228 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "loaders/3d/md2_loader/md2_loader.hpp" +#include +#include +#include "debug/debug.hpp" +#include "loaders/3d/md2_loader/anorms.hpp" +#include "loaders/loader.hpp" + +namespace Tyra { + +// magic number "IDP2" or 844121161 +#define MD2_IDENT (('2' << 24) + ('P' << 16) + ('D' << 8) + 'I') + +// model version +#define MD2_VERSION 8 + +typedef struct { + int ident; // magic number. must be equal to "IDP2" + int version; // md2 version. must be equal to 8 + + int skinwidth; // width of the texture + int skinheight; // height of the texture + int framesize; // size of one frame in bytes + + int num_skins; // number of textures + int num_xyz; // number of vertices + int num_st; // number of texture coordinates + int num_tris; // number of triangles + int num_glcmds; // number of opengl commands + int num_frames; // total number of frames + + int ofs_skins; // offset to skin names (64 bytes each) + int ofs_st; // offset to s-t texture coordinates + int ofs_tris; // offset to triangles + int ofs_frames; // offset to frame data + int ofs_glcmds; // offset to opengl commands + int ofs_end; // offset to end of file +} md2_t; + +typedef struct { + unsigned char v[3]; // compressed vertex (x, y, z) coordinates + unsigned char lightnormalindex; // index to a normal vector for the lighting +} mvertex_t; + +typedef struct { + float scale[3]; // scale values + float translate[3]; // translation vector + char name[16]; // frame name + mvertex_t verts[1]; // first vertex of this frame +} frame_t; + +typedef float vec3_t[3]; + +typedef struct { + s16 index_xyz[3]; // indexes to triangle's vertices + s16 index_st[3]; // indexes to vertices' texture coorinates +} triangle_t; + +typedef struct { + s16 s; + s16 t; +} texCoord_t; + +std::unique_ptr MD2Loader::load(const char* fullpath) { + return load(fullpath, MD2LoaderOptions()); +} + +std::unique_ptr MD2Loader::load(const std::string& fullpath) { + return load(fullpath.c_str(), MD2LoaderOptions()); +} + +std::unique_ptr MD2Loader::load(const std::string& fullpath, + MD2LoaderOptions options) { + return load(fullpath.c_str(), options); +} + +std::unique_ptr MD2Loader::load(const char* fullpath, + MD2LoaderOptions options) { + std::string path = fullpath; + TYRA_ASSERT(!path.empty(), "Provided path is empty!"); + + auto filename = getFilenameFromPath(path); + + FILE* file = fopen(fullpath, "rb"); + TYRA_ASSERT(file != nullptr, "Failed to load: ", filename); + md2_t header; + + fread(reinterpret_cast(&header), sizeof(md2_t), 1, file); + + TYRA_ASSERT((header.ident == MD2_IDENT) && (header.version == MD2_VERSION), + "This MD2 file is not in correct format!"); + + u32 framesCount = header.num_frames; + u32 vertexCount = header.num_xyz; + u32 stsCount = header.num_st; + u32 trianglesCount = header.num_tris; + + auto framesBufferSize = framesCount * header.framesize; + auto framesBuffer = new char[framesBufferSize]; + fseek(file, header.ofs_frames, SEEK_SET); + fread(framesBuffer, framesBufferSize, 1, file); + + auto stsBuffer = new char[stsCount * sizeof(texCoord_t)]; + fseek(file, header.ofs_st, SEEK_SET); + fread(stsBuffer, stsCount * sizeof(texCoord_t), 1, file); + + auto trianglesBuffer = new char[trianglesCount * sizeof(triangle_t)]; + fseek(file, header.ofs_tris, SEEK_SET); + fread(trianglesBuffer, trianglesCount * sizeof(triangle_t), 1, file); + + fclose(file); + + auto result = std::make_unique(); + + auto* material = new MeshBuilderMaterialData(); + material->name = getFilenameWithoutExtension(filename); + + result->materials.push_back(material); + result->normalsEnabled = true; + result->textureCoordsEnabled = true; + result->lightMapEnabled = false; + + Vec4** tempVertices = new Vec4*[framesCount]; + Vec4** tempNormals = new Vec4*[framesCount]; + Vec4** tempTexCoords = new Vec4*[framesCount]; + + for (u32 i = 0; i < framesCount; i++) { + auto* outputFrame = new MeshBuilderMaterialFrameData(); + material->frames.push_back(outputFrame); + + tempVertices[i] = new Vec4[vertexCount]; + tempNormals[i] = new Vec4[vertexCount]; + tempTexCoords[i] = new Vec4[stsCount]; + } + + Vec4 temp(0.0F, 0.0F, 0.0F, 1.0F); + + for (u32 frameIndex = 0; frameIndex < framesCount; frameIndex++) { + auto* frame = reinterpret_cast( + &framesBuffer[header.framesize * frameIndex]); + + for (u32 vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++) { + temp.set(((frame->verts[vertexIndex].v[0] * frame->scale[0]) + + frame->translate[0]) * + options.scale, + ((frame->verts[vertexIndex].v[1] * frame->scale[1]) + + frame->translate[1]) * + options.scale, + ((frame->verts[vertexIndex].v[2] * frame->scale[2]) + + frame->translate[2]) * + options.scale); + + tempVertices[frameIndex][vertexIndex].set(temp); + + temp.set(ANORMS[frame->verts[vertexIndex].lightnormalindex][0], + ANORMS[frame->verts[vertexIndex].lightnormalindex][1], + ANORMS[frame->verts[vertexIndex].lightnormalindex][2]); + + tempNormals[frameIndex][vertexIndex].set(temp); + } + } + + for (u32 i = 0; i < stsCount; i++) { + auto* texCoord = + reinterpret_cast(&stsBuffer[sizeof(texCoord_t) * i]); + + temp.set(static_cast(texCoord->s) / header.skinwidth, + static_cast(texCoord->t) / header.skinheight, 1.0F, 0.0F); + + if (options.flipUVs) temp.y = 1.0F - temp.y; + + for (u32 j = 0; j < framesCount; j++) tempTexCoords[j][i].set(temp); + } + + for (u32 x = 0; x < framesCount; x++) { + material->frames[x]->count = trianglesCount * 3; + material->frames[x]->vertices = new Vec4[trianglesCount * 3]; + material->frames[x]->normals = new Vec4[trianglesCount * 3]; + material->frames[x]->textureCoords = new Vec4[trianglesCount * 3]; + } + + triangle_t* triangle; + for (u32 i = 0; i < trianglesCount; i++) { + triangle = + reinterpret_cast(&trianglesBuffer[sizeof(triangle_t) * i]); + + for (u32 x = 0; x < framesCount; x++) { + auto* workFrame = material->frames[x]; + + for (u8 j = 0; j < 3; j++) { + workFrame->vertices[i * 3 + j] = + tempVertices[x][triangle->index_xyz[j]]; + + workFrame->normals[i * 3 + j] = tempNormals[x][triangle->index_xyz[j]]; + + workFrame->textureCoords[i * 3 + j] = + tempTexCoords[x][triangle->index_st[j]]; + } + } + } + + for (u32 i = 0; i < framesCount; i++) { + delete[] tempVertices[i]; + delete[] tempNormals[i]; + delete[] tempTexCoords[i]; + } + + delete[] tempVertices; + delete[] tempNormals; + delete[] tempTexCoords; + + delete[] framesBuffer; + delete[] stsBuffer; + delete[] trianglesBuffer; + + return result; +} + +} // namespace Tyra diff --git a/engine/src/loaders/3d/obj_loader/obj_loader.cpp b/engine/src/loaders/3d/obj_loader/obj_loader.cpp new file mode 100644 index 0000000..dd7e890 --- /dev/null +++ b/engine/src/loaders/3d/obj_loader/obj_loader.cpp @@ -0,0 +1,253 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include +#include +#include +#include +#include "math/vec2.hpp" +#include "math/vec4.hpp" +#include "renderer/models/color.hpp" +#include "debug/debug.hpp" +#include "loaders/3d/obj_loader/obj_loader.hpp" + +#define TINYOBJLOADER_USE_MAPBOX_EARCUT +#define TINYOBJLOADER_IMPLEMENTATION +#include "loaders/3d/obj_loader/tiny_obj_loader.hpp" + +namespace Tyra { + +std::unique_ptr ObjLoader::load(const char* fullpath) { + return load(fullpath, ObjLoaderOptions()); +} + +std::unique_ptr ObjLoader::load(const std::string& fullpath) { + return load(fullpath.c_str(), ObjLoaderOptions()); +} + +std::unique_ptr ObjLoader::load( + const std::string& fullpath, const ObjLoaderOptions& options) { + return load(fullpath.c_str(), options); +} + +std::unique_ptr ObjLoader::load( + const char* fullpath, const ObjLoaderOptions& options) { + std::string path = fullpath; + std::string basePath = getPathFromFilename(path); + + TYRA_ASSERT(!path.empty(), "Provided path is empty!"); + + auto rawFilename = getFilenameWithoutExtension(path); + auto extension = getExtensionOfFilename(path); + auto result = std::make_unique(); + + tinyobj::ObjReaderConfig readerConfig; + readerConfig.triangulate = options.animation.count == 1; + readerConfig.triangulation_method = + options.animation.count == 1 ? "earcut" : "simple"; + readerConfig.mtl_search_path = basePath; + + for (auto i = 1; i <= options.animation.count; i++) { + int indexStringLength = std::to_string(i).length(); + auto numbersWithLeadingZeros = + std::string(6 - std::min(6, indexStringLength), '0') + + std::to_string(i); + + std::string filePath = + rawFilename + "_" + numbersWithLeadingZeros + "." + extension; + if (options.animation.count == 1) filePath = path; + + tinyobj::ObjReader reader; + + if (!reader.ParseFromFile(filePath, readerConfig)) { + if (!reader.Error().empty()) { + TYRA_TRAP("TinyObjLoader: ", reader.Error()); + } + TYRA_TRAP("Unknown TinyObjLoader error!"); + } + + if (!reader.Warning().empty()) { + TYRA_WARN("TinyObjReader: ", reader.Warning()); + } + + auto& attrib = reader.GetAttrib(); + auto& shapes = reader.GetShapes(); + auto& materials = reader.GetMaterials(); + + TYRA_ASSERT( + materials.size() > 0, + "No material data found! Please add .mtl file(s) and assign them via " + "mtlib in obj file"); + + if (i == 1) { + auto scanResult = scan(shapes, materials); + addOutputMaterialsAndFrames(result.get(), attrib, shapes, materials, + options.animation.count, scanResult); + } + + importFrame(result.get(), attrib, shapes, materials, i - 1, options.scale, + options.flipUVs, options.animation.count); + } + + return result; +} + +std::vector ObjLoader::scan( + const std::vector& shapes, + const std::vector& materials) { + std::vector result; + + for (size_t i = 0; i < materials.size(); i++) { + MaterialVertexCount counter = {i, 0}; + result.push_back(counter); + } + + for (size_t s = 0; s < shapes.size(); s++) { + const auto& mesh = shapes[s].mesh; + + for (size_t f = 0; f < mesh.num_face_vertices.size(); f++) { + const auto& materialId = mesh.material_ids[f]; + const auto& vertCountPerFace = size_t(mesh.num_face_vertices[f]); + + TYRA_ASSERT(vertCountPerFace == 3, + "TinyObjLoader should triangulate mesh, internal error!"); + + result[materialId].count += vertCountPerFace; + } + } + + return result; +} + +void ObjLoader::addOutputMaterialsAndFrames( + MeshBuilderData* output, const tinyobj::attrib_t& attrib, + const std::vector& shapes, + const std::vector& materials, const u16& framesCount, + std::vector& materialVertexCounts) { + if (attrib.texcoords.size()) output->textureCoordsEnabled = true; + + if (attrib.normals.size()) output->normalsEnabled = true; + + TYRA_ASSERT(materials.size() > 0, + "No material data found! Please add .mtl " + "file(s) and assign them via mtlib in obj " + "file"); + + for (size_t i = 0; i < materials.size(); i++) { + auto* material = new MeshBuilderMaterialData(); + + material->name = materials[i].name; + + material->ambient.set(materials[i].diffuse[0] * 128.0F, + materials[i].diffuse[1] * 128.0F, + materials[i].diffuse[2] * 128.0F, 128.0F); + + for (size_t j = 0; j < framesCount; j++) { + auto* frame = new MeshBuilderMaterialFrameData(); + + const auto& counter = materialVertexCounts[i]; + + frame->count = counter.count; + frame->vertices = new Vec4[counter.count]; + + if (output->textureCoordsEnabled) + frame->textureCoords = new Vec4[counter.count]; + + if (output->normalsEnabled) frame->normals = new Vec4[counter.count]; + + material->frames.push_back(frame); + } + + output->materials.push_back(material); + } +} + +void ObjLoader::importFrame(MeshBuilderData* output, + const tinyobj::attrib_t& attrib, + const std::vector& shapes, + const std::vector& materials, + const u16& frameIndex, const float& scale, + const bool& invertY, const u16& count) { + struct MaterialInsertControl { + size_t materialId; + int inserted; + }; + + std::vector materialInsertControls; + for (size_t i = 0; i < materials.size(); i++) { + MaterialInsertControl control = {i, 0}; + materialInsertControls.push_back(control); + } + + // Loop over shapes + for (size_t s = 0; s < shapes.size(); s++) { + const auto& mesh = shapes[s].mesh; + + size_t index_offset = 0; + // Loop over faces + for (size_t f = 0; f < mesh.num_face_vertices.size(); f++) { + auto materialId = mesh.material_ids[f]; + auto& materialInsertControl = materialInsertControls[materialId]; + size_t vertCountPerFace = size_t(mesh.num_face_vertices[f]); + + auto* outFrame = output->materials[materialId]->frames[frameIndex]; + + TYRA_ASSERT(count == 1 || vertCountPerFace == 3, + "Please triangulate obj files if you are animating!", + "Recommended Blender options: ", + "- Obj exporting: triangulate off, keep vertex order", + "- Object modifiers: triangulate (as first!), then other " + "modifiers"); + + // Loop over vertices in the face. + for (size_t v = 0; v < vertCountPerFace; v++) { + // access to vertex + tinyobj::index_t idx = mesh.indices[index_offset + v]; + tinyobj::real_t vx = attrib.vertices[3 * size_t(idx.vertex_index) + 0]; + tinyobj::real_t vy = attrib.vertices[3 * size_t(idx.vertex_index) + 1]; + tinyobj::real_t vz = attrib.vertices[3 * size_t(idx.vertex_index) + 2]; + + outFrame->vertices[materialInsertControl.inserted].set(vx, vy, vz, + 1.0F); + outFrame->vertices[materialInsertControl.inserted] *= scale; + + // Check if `normal_index` is zero or positive. negative = no normal + // data + if (idx.normal_index >= 0) { + tinyobj::real_t nx = attrib.normals[3 * size_t(idx.normal_index) + 0]; + tinyobj::real_t ny = attrib.normals[3 * size_t(idx.normal_index) + 1]; + tinyobj::real_t nz = attrib.normals[3 * size_t(idx.normal_index) + 2]; + + outFrame->normals[materialInsertControl.inserted].set(nx, ny, nz, + 1.0F); + } + + // Check if `texcoord_index` is zero or positive. negative = + // notexcoord data + if (idx.texcoord_index >= 0) { + tinyobj::real_t tx = + attrib.texcoords[2 * size_t(idx.texcoord_index) + 0]; + tinyobj::real_t ty = + attrib.texcoords[2 * size_t(idx.texcoord_index) + 1]; + + auto finalY = invertY ? 1.0F - ty : ty; + outFrame->textureCoords[materialInsertControl.inserted].set( + tx, finalY, 1.0F, 0.0F); + } + + materialInsertControl.inserted++; + } + + index_offset += vertCountPerFace; + } + } +} + +} // namespace Tyra diff --git a/engine/src/loaders/loader.cpp b/engine/src/loaders/loader.cpp new file mode 100644 index 0000000..e63bf55 --- /dev/null +++ b/engine/src/loaders/loader.cpp @@ -0,0 +1,42 @@ + +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "loaders/loader.hpp" + +namespace Tyra { + +std::string Loader::getFilenameFromPath(const std::string& path) { + std::string filename = path.substr(path.find_last_of("/\\") + 1); + if (filename.size() == path.size()) { + filename = path.substr(path.find_last_of(":\\") + 1); + } + return filename; +} + +std::string Loader::getPathFromFilename(const std::string& path) { + std::string basepath = path.substr(0, path.find_last_of("/\\")); + if (basepath.size() == path.size()) { + basepath = path.substr(0, path.find_last_of(":\\")); + } + return basepath; +} + +std::string Loader::getFilenameWithoutExtension(const std::string& filename) { + auto lastindex = filename.find_last_of("."); + return filename.substr(0, lastindex); +} + +std::string Loader::getExtensionOfFilename(const std::string& filename) { + auto lastindex = filename.find_last_of("."); + return filename.substr(lastindex + 1); +} + +} // namespace Tyra diff --git a/engine/src/loaders/texture/base/texture_builder_data.cpp b/engine/src/loaders/texture/base/texture_builder_data.cpp new file mode 100644 index 0000000..0f3c88b --- /dev/null +++ b/engine/src/loaders/texture/base/texture_builder_data.cpp @@ -0,0 +1,32 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "loaders/texture/builder/texture_builder_data.hpp" +#include + +namespace Tyra { + +TextureBuilderData::TextureBuilderData() { + width = 0; + height = 0; + data = nullptr; + bpp = bpp32; + gsComponents = TEXTURE_COMPONENTS_RGBA; + + clut = nullptr; + clutWidth = 0; + clutHeight = 0; + clutBpp = bpp32; + clutGsComponents = TEXTURE_COMPONENTS_RGBA; +} + +TextureBuilderData::~TextureBuilderData() {} + +} // namespace Tyra diff --git a/engine/src/loaders/texture/base/texture_loader.cpp b/engine/src/loaders/texture/base/texture_loader.cpp new file mode 100644 index 0000000..7e47eab --- /dev/null +++ b/engine/src/loaders/texture/base/texture_loader.cpp @@ -0,0 +1,35 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include +#include "debug/debug.hpp" +#include "loaders/texture/base/texture_loader.hpp" + +namespace Tyra { + +u32 TextureLoader::getTextureSize(const u32& width, const u32& height, + const TextureBpp& bpp) { + switch (bpp) { + case bpp32: + return (width * height * 4); + case bpp24: + return (width * height * 3); + case bpp8: + return (width * height); + case bpp4: + return (width * height / 2); + default: + TYRA_TRAP("Unknown texture bpp"); + } + + return -1; +} + +} // namespace Tyra diff --git a/engine/src/loaders/texture/base/texture_loader_selector.cpp b/engine/src/loaders/texture/base/texture_loader_selector.cpp new file mode 100644 index 0000000..ca577f4 --- /dev/null +++ b/engine/src/loaders/texture/base/texture_loader_selector.cpp @@ -0,0 +1,47 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include +#include +#include "debug/debug.hpp" +#include "renderer/core/texture/models/texture.hpp" +#include "loaders/texture/base/texture_loader_selector.hpp" + +namespace Tyra { + +TextureLoaderSelector::TextureLoaderSelector() {} + +TextureLoaderSelector::~TextureLoaderSelector() {} + +// ---- +// Methods +// ---- + +TextureLoader& TextureLoaderSelector::getLoaderByFileName( + const char* fullpath) { + std::string path = fullpath; + std::string extension = path.substr(path.find_last_of(".") + 1); + return getLoaderByExtension(extension); +} + +TextureLoader& TextureLoaderSelector::getLoaderByExtension( + const std::string& extension) { + std::string extensionLower = extension; + std::transform(extensionLower.begin(), extensionLower.end(), + extensionLower.begin(), ::tolower); + if (extensionLower == "png") { + return pngLoader; + } else { + TYRA_TRAP("There is no texture loader for extension: ", extensionLower); + return pngLoader; + } +} + +} // namespace Tyra diff --git a/engine/src/loaders/texture/png_loader.cpp b/engine/src/loaders/texture/png_loader.cpp new file mode 100644 index 0000000..f0551d9 --- /dev/null +++ b/engine/src/loaders/texture/png_loader.cpp @@ -0,0 +1,306 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "debug/debug.hpp" +#include +#include +#include +#include +#include +#include +#include "loaders/texture/png_loader.hpp" + +namespace Tyra { + +PngLoader::PngLoader() {} + +PngLoader::~PngLoader() {} + +struct PngClut { + u8 r, g, b, a; +}; + +/** Based on GsKit texture loading - thank you guys! */ +TextureBuilderData* PngLoader::load(const char* fullPath) { + std::string path = fullPath; + TYRA_ASSERT(!path.empty(), "Provided path is empty!"); + + auto filename = getFilenameFromPath(path); + + FILE* file = fopen(fullPath, "rb"); + TYRA_ASSERT(file != nullptr, "Failed to load ", fullPath); + + png_structp pngPtr; + png_infop infoPtr; + png_uint_32 width, height; + png_bytep* rowPointers = nullptr; + + u32 sigRead = 0; + int bitDepth, colorType, interlaceType; + + pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) nullptr, + nullptr, nullptr); + TYRA_ASSERT(pngPtr, "PNG read struct init failed for: ", filename); + + infoPtr = png_create_info_struct(pngPtr); + TYRA_ASSERT(infoPtr, "PNG read struct init failed for: ", filename); + + TYRA_ASSERT(!setjmp(png_jmpbuf(pngPtr)), "PNG read error for: ", filename); + + png_init_io(pngPtr, file); + png_set_sig_bytes(pngPtr, sigRead); + png_read_info(pngPtr, infoPtr); + png_get_IHDR(pngPtr, infoPtr, &width, &height, &bitDepth, &colorType, + &interlaceType, nullptr, nullptr); + + if (bitDepth == 16) png_set_strip_16(pngPtr); + if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 4) png_set_expand(pngPtr); + + png_set_filler(pngPtr, 0xff, PNG_FILLER_AFTER); + + png_read_update_info(pngPtr, infoPtr); + + auto* result = new TextureBuilderData(); + result->width = width; + result->height = height; + result->name = filename; + + auto updatedColorType = png_get_color_type(pngPtr, infoPtr); + + if (updatedColorType == PNG_COLOR_TYPE_PALETTE) { + handlePalletized(result, pngPtr, infoPtr, rowPointers, bitDepth); + } else if (updatedColorType == PNG_COLOR_TYPE_RGB_ALPHA) { + handle32bpp(result, pngPtr, infoPtr, rowPointers); + } else if (updatedColorType == PNG_COLOR_TYPE_RGB) { + handle24bpp(result, pngPtr, infoPtr, rowPointers); + } else + TYRA_TRAP("This texture depth is not supported!"); + + png_read_end(pngPtr, nullptr); + png_destroy_read_struct(&pngPtr, &infoPtr, nullptr); + fclose(file); + + return result; +} + +void PngLoader::handle32bpp(TextureBuilderData* result, png_structp pngPtr, + png_infop infoPtr, png_bytep* rowPointers) { + int rowBytes = png_get_rowbytes(pngPtr, infoPtr); + + result->gsComponents = TEXTURE_COMPONENTS_RGBA; + result->bpp = bpp32; + result->data = static_cast(memalign( + 128, getTextureSize(result->width, result->height, result->bpp))); + + rowPointers = + static_cast(calloc(result->height, sizeof(png_bytep))); + + for (int row = 0; row < result->height; row++) + rowPointers[row] = static_cast(malloc(rowBytes)); + + png_read_image(pngPtr, rowPointers); + + struct PngPixel4* pixels = (struct PngPixel4*)result->data; + + int k = 0; + for (int i = 0; i < result->height; i++) { + for (int j = 0; j < result->width; j++) { + pixels[k].r = rowPointers[i][4 * j]; + pixels[k].g = rowPointers[i][4 * j + 1]; + pixels[k].b = rowPointers[i][4 * j + 2]; + pixels[k++].a = ((int)rowPointers[i][4 * j + 3] * 128 / 255); + } + } + + for (int row = 0; row < result->height; row++) free(rowPointers[row]); + + free(rowPointers); +} + +void PngLoader::handle24bpp(TextureBuilderData* result, png_structp pngPtr, + png_infop infoPtr, png_bytep* rowPointers) { + int rowBytes = png_get_rowbytes(pngPtr, infoPtr); + + result->gsComponents = TEXTURE_COMPONENTS_RGB; + result->bpp = bpp24; + result->data = static_cast(memalign( + 128, getTextureSize(result->width, result->height, result->bpp))); + + rowPointers = + static_cast(calloc(result->height, sizeof(png_bytep))); + + for (int row = 0; row < result->height; row++) + rowPointers[row] = static_cast(malloc(rowBytes)); + + png_read_image(pngPtr, rowPointers); + + struct PngPixel3* pixels = (struct PngPixel3*)result->data; + + int k = 0; + for (int i = 0; i < result->height; i++) { + for (int j = 0; j < result->width; j++) { + pixels[k].r = rowPointers[i][4 * j]; + pixels[k].g = rowPointers[i][4 * j + 1]; + pixels[k++].b = rowPointers[i][4 * j + 2]; + } + } + + for (int row = 0; row < result->height; row++) free(rowPointers[row]); + + free(rowPointers); +} + +void PngLoader::handlePalletized(TextureBuilderData* result, png_structp pngPtr, + png_infop infoPtr, png_bytep* rowPointers, + const int& bitDepth) { + png_colorp palette = nullptr; + png_bytep trans = nullptr; + int numPallete = 0; + int numTrans = 0; + + png_get_PLTE(pngPtr, infoPtr, &palette, &numPallete); + png_get_tRNS(pngPtr, infoPtr, &trans, &numTrans, nullptr); + result->clutBpp = bpp32; + result->clutGsComponents = TEXTURE_COMPONENTS_RGBA; + + if (bitDepth == 4) { + handle4bppPalletized(result, pngPtr, infoPtr, rowPointers, palette, trans, + numPallete, numTrans); + } else if (bitDepth == 8) { + handle8bppPalletized(result, pngPtr, infoPtr, rowPointers, palette, trans, + numPallete, numTrans); + } else { + TYRA_TRAP("Only 4 and 8 bits palettes are supported"); + } +} + +void PngLoader::handle8bppPalletized(TextureBuilderData* result, + png_structp pngPtr, png_infop infoPtr, + png_bytep* rowPointers, png_colorp palette, + png_bytep trans, const int& numPallete, + const int& numTrans) { + int rowBytes = png_get_rowbytes(pngPtr, infoPtr); + result->bpp = bpp8; + result->clutWidth = 16; + result->clutHeight = 16; + + result->gsComponents = TEXTURE_COMPONENTS_RGBA; + result->data = static_cast(memalign( + 128, getTextureSize(result->width, result->height, result->bpp))); + + rowPointers = + static_cast(calloc(result->height, sizeof(png_bytep))); + + for (int row = 0; row < result->height; row++) + rowPointers[row] = static_cast(malloc(rowBytes)); + + png_read_image(pngPtr, rowPointers); + + result->clut = + static_cast(memalign(128, getTextureSize(16, 16, bpp32))); + memset(result->clut, 0, getTextureSize(16, 16, bpp32)); + + auto* pixel = static_cast(result->data); + struct PngClut* clut = (struct PngClut*)result->clut; + + for (int i = numPallete; i < 256; i++) { + memset(&clut[i], 0, sizeof(clut[i])); + } + + for (int i = 0; i < numPallete; i++) { + clut[i].r = palette[i].red; + clut[i].g = palette[i].green; + clut[i].b = palette[i].blue; + clut[i].a = 0x80; + } + + for (int i = 0; i < numTrans; i++) clut[i].a = trans[i] >> 1; + + // rotate clut + for (int i = 0; i < numPallete; i++) { + if ((i & 0x18) == 8) { + struct PngClut tmp = clut[i]; + clut[i] = clut[i + 8]; + clut[i + 8] = tmp; + } + } + + int k = 0; + for (int i = 0; i < result->height; i++) { + for (int j = 0; j < result->width; j++) { + memcpy(&pixel[k++], &rowPointers[i][1 * j], 1); + } + } + + for (int row = 0; row < result->height; row++) free(rowPointers[row]); + + free(rowPointers); +} + +void PngLoader::handle4bppPalletized(TextureBuilderData* result, + png_structp pngPtr, png_infop infoPtr, + png_bytep* rowPointers, png_colorp palette, + png_bytep trans, const int& numPallete, + const int& numTrans) { + int rowBytes = png_get_rowbytes(pngPtr, infoPtr); + result->bpp = bpp4; + result->clutWidth = 8; + result->clutHeight = 2; + result->gsComponents = TEXTURE_COMPONENTS_RGBA; + result->data = static_cast(memalign( + 128, getTextureSize(result->width, result->height, result->bpp))); + + rowPointers = + static_cast(calloc(result->height, sizeof(png_bytep))); + + for (int row = 0; row < result->height; row++) + rowPointers[row] = static_cast(malloc(rowBytes)); + + png_read_image(pngPtr, rowPointers); + + result->clut = + static_cast(memalign(128, getTextureSize(8, 2, bpp32))); + memset(result->clut, 0, getTextureSize(8, 2, bpp32)); + + auto* pixel = static_cast(result->data); + struct PngClut* clut = (struct PngClut*)result->clut; + + for (int i = numPallete; i < 16; i++) { + memset(&clut[i], 0, sizeof(clut[i])); + } + + for (int i = 0; i < numPallete; i++) { + clut[i].r = palette[i].red; + clut[i].g = palette[i].green; + clut[i].b = palette[i].blue; + clut[i].a = 0x80; + } + + for (int i = 0; i < numTrans; i++) clut[i].a = trans[i] >> 1; + + int k = 0; + for (int i = 0; i < result->height; i++) { + for (int j = 0; j < result->width / 2; j++) + memcpy(&pixel[k++], &rowPointers[i][1 * j], 1); + } + unsigned char* tmpdst = (unsigned char*)result->data; + unsigned char* tmpsrc = (unsigned char*)pixel; + + for (u32 byte = 0; + byte < getTextureSize(result->width, result->height, result->bpp); + byte++) + tmpdst[byte] = (tmpsrc[byte] << 4) | (tmpsrc[byte] >> 4); + + for (int row = 0; row < result->height; row++) free(rowPointers[row]); + + free(rowPointers); +} + +} // namespace Tyra diff --git a/engine/src/math/m4x4.cpp b/engine/src/math/m4x4.cpp new file mode 100644 index 0000000..620e9ce --- /dev/null +++ b/engine/src/math/m4x4.cpp @@ -0,0 +1,491 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include +#include +#include +#include "math/m4x4.hpp" + +namespace Tyra { + +VECTOR M4x4::upVec = {0.0F, 1.0F, 0.0F, 1.0F}; +VECTOR M4x4::viewVec = {0.0F, 0.0F, 0.0F, 1.0F}; + +const M4x4 M4x4::Identity = + M4x4(1.0F, 0.0F, 0.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F, 0.0F, 0.0F, 1.0F, 0.0F, + 0.0F, 0.0F, 0.0F, 1.0F); + +M4x4::M4x4(const float& m11, const float& m12, const float& m13, + const float& m14, const float& m21, const float& m22, + const float& m23, const float& m24, const float& m31, + const float& m32, const float& m33, const float& m34, + const float& m41, const float& m42, const float& m43, + const float& m44) { + set(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, + m44); +} + +void M4x4::copy(M4x4* out, const float* in) { + asm volatile( + "lqc2 $vf1, 0x00(%1) \n" + "lqc2 $vf2, 0x10(%1) \n" + "lqc2 $vf3, 0x20(%1) \n" + "lqc2 $vf4, 0x30(%1) \n" + "sqc2 $vf1, 0x00(%0) \n" + "sqc2 $vf2, 0x10(%0) \n" + "sqc2 $vf3, 0x20(%0) \n" + "sqc2 $vf4, 0x30(%0) \n" + : + : "r"(out->data), "r"(in)); +} + +void M4x4::copy(M4x4* out, const M4x4& in) { copy(out, in.data); } + +void M4x4::operator=(const M4x4& v) { copy(this, v); } + +Vec4 M4x4::operator*(const Vec4& v) const { + Vec4 result; + asm volatile( + "lqc2 $vf1, 0x00(%2) \n" + "lqc2 $vf2, 0x10(%2) \n" + "lqc2 $vf3, 0x20(%2) \n" + "lqc2 $vf4, 0x30(%2) \n" + "lqc2 $vf5, 0x00(%1) \n" + "vmulaw $ACC, $vf4, $vf0\n" + "vmaddax $ACC, $vf1, $vf5\n" + "vmadday $ACC, $vf2, $vf5\n" + "vmaddz $vf6, $vf3, $vf5\n" + "sqc2 $vf6, 0x00(%0) \n" + : + : "r"(result.xyzw), "r"(v.xyzw), "r"(this->data)); + return result; +} + +M4x4 M4x4::operator*(const M4x4& v) const { + M4x4 result; + cross(result.data, this->data, v.data); + return result; +} + +void M4x4::operator*=(const M4x4& v) { cross(this->data, this->data, v.data); } + +float& M4x4::operator[](const u8& index) { return data[index]; } + +void M4x4::set(const float& m11, const float& m12, const float& m13, + const float& m14, const float& m21, const float& m22, + const float& m23, const float& m24, const float& m31, + const float& m32, const float& m33, const float& m34, + const float& m41, const float& m42, const float& m43, + const float& m44) { + data[0] = m11; + data[1] = m12; + data[2] = m13; + data[3] = m14; + + data[4] = m21; + data[5] = m22; + data[6] = m23; + data[7] = m24; + + data[8] = m31; + data[9] = m32; + data[10] = m33; + data[11] = m34; + + data[12] = m41; + data[13] = m42; + data[14] = m43; + data[15] = m44; +} + +void M4x4::identity() { + asm volatile( + "vsub.xyzw $vf4, $vf0, $vf0 \n\t" + "vadd.w $vf4, $vf4, $vf0 \n\t" + "vmr32.xyzw $vf5, $vf4 \n\t" + "vmr32.xyzw $vf6, $vf5 \n\t" + "vmr32.xyzw $vf7, $vf6 \n\t" + "sqc2 $vf4, 0x30(%0) \n\t" + "sqc2 $vf5, 0x20(%0) \n\t" + "sqc2 $vf6, 0x10(%0) \n\t" + "sqc2 $vf7, 0x0(%0) \n\t" + : + : "r"(this->data)); +} + +void M4x4::translate(const Vec4& v) { + M4x4 temp = M4x4::Identity; + temp.translationX(v.x); + temp.translationY(v.y); + temp.translationZ(v.z); + cross(this->data, temp.data, this->data); +} + +void M4x4::translateX(const float& v) { + M4x4 temp = M4x4::Identity; + temp.translationX(v); + cross(this->data, temp.data, this->data); +} + +void M4x4::translateY(const float& v) { + M4x4 temp = M4x4::Identity; + temp.translationY(v); + cross(this->data, temp.data, this->data); +} + +void M4x4::translateZ(const float& v) { + M4x4 temp = M4x4::Identity; + temp.translationZ(v); + cross(this->data, temp.data, this->data); +} + +void M4x4::rotate(const Vec4& v) { + M4x4 temp = M4x4::Identity; + + temp.rotationZ(v.z); + cross(this->data, temp.data, this->data); + + temp.identity(); + temp.rotationY(v.y); + cross(this->data, temp.data, this->data); + + temp.identity(); + temp.rotationX(v.x); + cross(this->data, temp.data, this->data); +} + +void M4x4::rotateX(const float& radians) { + M4x4 temp = M4x4::Identity; + temp.rotationX(radians); + cross(this->data, temp.data, this->data); +} + +void M4x4::rotateY(const float& radians) { + M4x4 temp = M4x4::Identity; + temp.rotationY(radians); + cross(this->data, temp.data, this->data); +} + +void M4x4::rotateZ(const float& radians) { + M4x4 temp = M4x4::Identity; + temp.rotationZ(radians); + cross(this->data, temp.data, this->data); +} + +void M4x4::rotateByAngle(const float& angle, const Vec4& axis) { + M4x4 temp; + temp.rotationByAngle(angle, axis); + cross(this->data, temp.data, this->data); +} + +void M4x4::scale(const float& v) { scale(Vec4(v, v, v, 1.0F)); } + +void M4x4::scale(const Vec4& v) { + M4x4 temp = M4x4::Identity; + temp.setScale(v); + cross(this->data, temp.data, this->data); +} + +void M4x4::scaleX(const float& v) { scale(Vec4(v, 1.0F, 1.0F, 1.0F)); } + +void M4x4::scaleY(const float& v) { scale(Vec4(1.0F, v, 1.0F, 1.0F)); } + +void M4x4::scaleZ(const float& v) { scale(Vec4(1.0F, 1.0F, v, 1.0F)); } + +M4x4 M4x4::perspective(const float& fov, const float& width, + const float& height, const float& projectionScale, + const float& aspectRatio, const float& near, + const float& far) { + M4x4 res; + float fovYdiv2 = Math::HALF_ANG2RAD * fov; + float cotFOV = 1.0F / (Math::sin(fovYdiv2) / Math::cos(fovYdiv2)); + float w = cotFOV * (width / projectionScale) / aspectRatio; + float h = cotFOV * (height / projectionScale); + + res.data[0] = w; + res.data[1] = 0.0F; + res.data[2] = 0.0F; + res.data[3] = 0.0F; + + res.data[4] = 0.0F; + res.data[5] = -h; + res.data[6] = 0.0F; + res.data[7] = 0.0F; + + res.data[8] = 0.0F; + res.data[9] = 0.0F; + res.data[10] = (far + near) / (far - near); + res.data[11] = -1.0F; + + res.data[12] = 0.0F; + res.data[13] = 0.0F; + res.data[14] = (2.0F * far * near) / (far - near); + res.data[15] = 0.0F; + return res; +} + +M4x4 M4x4::lookAt(const Vec4& position, const Vec4& target) { + M4x4 res = M4x4::Identity; + lookAt(&res, position, target); + return res; +} + +void M4x4::lookAt(M4x4* res, const Vec4& position, const Vec4& target) { + float eye[4] alignas(sizeof(float) * 4) = {position.x, position.y, position.z, + 1.0F}; + + float obj[4] alignas(sizeof(float) * 4) = {target.x, target.y, target.z, + 1.0F}; + + asm volatile( + // eye + "lqc2 $vf4, 0x00(%2) \n\t" + // obj + "lqc2 $vf5, 0x00(%3) \n\t" + // view_vec = $vf7 + "vsub.xyz $vf7, $vf4, $vf5 \n\t" + "vmove.xyzw $vf6, $vf0 \n\t" + // $vf6 = { 0.0f, 1.0f, 0.0f, 1.0f } + "vaddw.y $vf6, $vf0, $vf0 \n\t" + "vopmula.xyz $ACC, $vf6, $vf7 \n\t" + // vec = $vf9 + "vopmsub.xyz $vf9, $vf7, $vf6 \n\t" + "vopmula.xyz $ACC, $vf7, $vf9 \n\t" + // up_vec = $vf8 + "vopmsub.xyz $vf8, $vf9, $vf7 \n\t" + // view_vec + "sqc2 $vf7, 0x00(%0) \n\t" + // up_vec + "sqc2 $vf6, 0x00(%1) \n\t" + : + : "r"(viewVec), "r"(upVec), "r"(eye), "r"(obj)); + + M4x4 temp = setCamera(eye, viewVec, upVec); + res->identity(); + + cross(res->data, res->data, temp.data); +} + +void M4x4::cross(float res[16], const float a[16], const float b[16]) { + asm volatile( + "lqc2 $vf1, 0x00(%1) \n\t" + "lqc2 $vf2, 0x10(%1) \n\t" + "lqc2 $vf3, 0x20(%1) \n\t" + "lqc2 $vf4, 0x30(%1) \n\t" + "lqc2 $vf5, 0x00(%2) \n\t" + "lqc2 $vf6, 0x10(%2) \n\t" + "lqc2 $vf7, 0x20(%2) \n\t" + "lqc2 $vf8, 0x30(%2) \n\t" + "vmulax.xyzw $ACC, $vf5, $vf1 \n\t" + "vmadday.xyzw $ACC, $vf6, $vf1 \n\t" + "vmaddaz.xyzw $ACC, $vf7, $vf1 \n\t" + "vmaddw.xyzw $vf1, $vf8, $vf1 \n\t" + "vmulax.xyzw $ACC, $vf5, $vf2 \n\t" + "vmadday.xyzw $ACC, $vf6, $vf2 \n\t" + "vmaddaz.xyzw $ACC, $vf7, $vf2 \n\t" + "vmaddw.xyzw $vf2, $vf8, $vf2 \n\t" + "vmulax.xyzw $ACC, $vf5, $vf3 \n\t" + "vmadday.xyzw $ACC, $vf6, $vf3 \n\t" + "vmaddaz.xyzw $ACC, $vf7, $vf3 \n\t" + "vmaddw.xyzw $vf3, $vf8, $vf3 \n\t" + "vmulax.xyzw $ACC, $vf5, $vf4 \n\t" + "vmadday.xyzw $ACC, $vf6, $vf4 \n\t" + "vmaddaz.xyzw $ACC, $vf7, $vf4 \n\t" + "vmaddw.xyzw $vf4, $vf8, $vf4 \n\t" + "sqc2 $vf1, 0x00(%0) \n\t" + "sqc2 $vf2, 0x10(%0) \n\t" + "sqc2 $vf3, 0x20(%0) \n\t" + "sqc2 $vf4, 0x30(%0) \n\t" + : + : "r"(res), "r"(b), "r"(a) + : "memory"); +} + +void M4x4::rotationX(const float& v) { + float c = Math::cos(v); + float s = Math::sin(v); + this->data[5] = c; // 1,1 + this->data[6] = s; // 1,2 + this->data[9] = -s; // 2,1 + this->data[10] = c; // 2,2 +} + +void M4x4::rotationY(const float& v) { + float c = Math::cos(v); + float s = Math::sin(v); + this->data[0] = c; // 0,0 + this->data[2] = -s; // 0,3 + this->data[8] = s; // 2,0 + this->data[10] = c; // 2,2 +} + +void M4x4::rotationZ(const float& v) { + float c = Math::cos(v); + float s = Math::sin(v); + this->data[0] = c; // 0,0 + this->data[1] = s; // 0,1 + this->data[4] = -s; // 1,0 + this->data[5] = c; // 1,1 +} + +void M4x4::rotationByAngle(const float& angle, const Vec4& axis) { + Vec4 localAxis = Vec4(axis); + localAxis.normalize(); + const float& x = localAxis.x; + const float& y = localAxis.y; + const float& z = localAxis.z; + + float c = Math::cos(angle); + float s = Math::sin(angle); + + this->data[0] = x * x * (1 - c) + c; + this->data[1] = y * x * (1 - c) + z * s; + this->data[2] = x * z * (1 - c) - y * s; + this->data[3] = 0.0F; + + this->data[4] = x * y * (1 - c) - z * s; + this->data[5] = y * y * (1 - c) + c; + this->data[6] = y * z * (1 - c) + x * s; + this->data[7] = 0.0F; + + this->data[8] = x * z * (1 - c) + y * s; + this->data[9] = y * z * (1 - c) - x * s; + this->data[10] = z * z * (1 - c) + c; + this->data[11] = 0.0F; + + this->data[12] = 0.0F; + this->data[13] = 0.0F; + this->data[14] = 0.0F; + this->data[15] = 1.0F; +} + +void M4x4::translationX(const float& val) { + this->data[12] = val; // 3,0 +} + +void M4x4::translationY(const float& val) { + this->data[13] = val; // 3,1 +} + +void M4x4::translationZ(const float& val) { + this->data[14] = val; // 3,2 +} + +void M4x4::setScale(const Vec4& val) { + this->data[0] = val.x; + this->data[5] = val.y; + this->data[10] = val.z; + this->data[15] = 1.0F; +} + +M4x4 M4x4::setCamera(const float pos[4], const float vz[4], const float vy[4]) { + M4x4 res; + // M4x4 $vf4, $vf5, $vf6, $vf7 + // pos $vf8 + // vz $vf9 + // vy $vf10 + // vtmp $vf11 + asm volatile( + "lqc2 $vf9, 0x00(%2) \n\t" + // mtmp.unit() + "lqc2 $vf10, 0x00(%3) \n\t" + // mtmp[1][PW] = 0.0F + "vsub.w $vf5, $vf0, $vf0 \n\t" + // vtmp.outerProduct(vy, vz); + "vopmula.xyz $ACC, $vf10, $vf9 \n\t" + "vopmsub.xyz $vf11, $vf9, $vf10 \n\t" + // mtmp[0] = vtmp.normalize(); + "vmul.xyz $vf12, $vf11, $vf11 \n\t" + "vaddy.x $vf12, $vf12, $vf12 \n\t" + "vaddz.x $vf12, $vf12, $vf12 \n\t" + "vrsqrt $Q, $vf0w, $vf12x \n\t" + "vsub.xyzw $vf4, $vf0, $vf0 \n\t" + "vwaitq \n\t" + "vmulq.xyz $vf4, $vf11, $Q \n\t" + // mtmp[2] = vz.normalize(); + "vmul.xyz $vf12, $vf9, $vf9 \n\t" + "vaddy.x $vf12, $vf12, $vf12 \n\t" + "vaddz.x $vf12, $vf12, $vf12 \n\t" + "vrsqrt $Q, $vf0w, $vf12x \n\t" + "vsub.xyzw $vf6, $vf0, $vf0 \n\t" + "vwaitq \n\t" + "vmulq.xyz $vf6, $vf9, $Q \n\t" + // mtmp[1].outerProduct(mtmp[2], mtmp[0]); + "vopmula.xyz $ACC, $vf6, $vf4 \n\t" + "vopmsub.xyz $vf5, $vf4, $vf6 \n\t" + // mtmp.transpose(pos); + "lqc2 $vf7, 0x00(%1) \n\t" + // m = mtmp.inverse(); + "qmfc2.ni $11, $vf0 \n\t" + "qmfc2.ni $8, $vf4 \n\t" + "qmfc2.ni $9, $vf5 \n\t" + "qmfc2.ni $10, $vf6 \n\t" + + "pextlw $12, $9, $8 \n\t" + "pextuw $13, $9, $8 \n\t" + "pextlw $14, $11, $10 \n\t" + "pextuw $15, $11, $10 \n\t" + "pcpyld $8, $14, $12 \n\t" + "pcpyud $9, $12, $14 \n\t" + "pcpyld $10, $15, $13 \n\t" + + "qmtc2.ni $8, $vf16 \n\t" + "qmtc2.ni $9, $vf17 \n\t" + "qmtc2.ni $10, $vf18 \n\t" + "vmulax.xyz $ACC, $vf16, $vf7 \n\t" + "vmadday.xyz $ACC, $vf17, $vf7 \n\t" + "vmaddz.xyz $vf5, $vf18, $vf7 \n\t" + "vsub.xyzw $vf5, $vf0, $vf5 \n\t" + + "sq $8, 0x00(%0) \n\t" + "sq $9, 0x10(%0) \n\t" + "sq $10, 0x20(%0) \n\t" + "sqc2 $vf5, 0x30(%0) \n\t" + : + : "r"(res.data), "r"(pos), "r"(vz), "r"(vy)); + return res; +} + +void M4x4::print() const { + auto text = getPrint(nullptr); + printf("%s\n", text.c_str()); +} + +void M4x4::print(const char* name) const { + auto text = getPrint(name); + printf("%s\n", text.c_str()); +} + +std::string M4x4::getPrint(const char* name) const { + std::stringstream res; + if (name) { + res << name << "("; + } else { + res << "M4x4("; + } + res << std::fixed << std::setprecision(2); + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + auto index = (i * 4) + j; + res << data[index]; + if (index != 15) { + res << ", "; + } + } + + if (i != 3) { + res << std::endl; + } + } + res << ")"; + return res.str(); +} + +} // namespace Tyra diff --git a/engine/src/math/math.cpp b/engine/src/math/math.cpp new file mode 100644 index 0000000..7546e45 --- /dev/null +++ b/engine/src/math/math.cpp @@ -0,0 +1,295 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#ifdef __INTELLISENSE__ +#pragma diag_suppress 1118 +#endif + +#include "math/math.hpp" +#include + +extern volatile const u32 TYRA_MATH_ATAN_TABLE[9] alignas(sizeof(float)) = { + 0x3f7ffff5, 0xbeaaa61c, 0x3e4c40a6, 0xbe0e6c63, 0x3dc577df, + 0xbd6501c4, 0x3cb31652, 0xbb84d7e7, 0x3f490fdb, +}; + +extern volatile const float TYRA_MATH_ATAN_TABLE2[8] = { + 0.0f, + (Tyra::Math::PI / 2.0f), + (Tyra::Math::PI / 2.0f), + (Tyra::Math::PI), + (-Tyra::Math::PI), + (-Tyra::Math::PI / 2.0f), + (-Tyra::Math::PI / 2.0f), + 0.0f, +}; + +namespace Tyra { + +float Math::cos(float x) { + float r; + asm volatile( + "lui $9, 0x3f00 \n\t" + ".set noreorder \n\t" + ".align 3 \n\t" + "abs.s %0, %1 \n\t" + "lui $8, 0xbe22 \n\t" + "mtc1 $9, $f1 \n\t" + "ori $8, $8, 0xf983 \n\t" + "mtc1 $8, $f8 \n\t" + "lui $9, 0x4b00 \n\t" + "mtc1 $9, $f3 \n\t" + "lui $8, 0x3f80 \n\t" + "mtc1 $8, $f2 \n\t" + "mula.s %0, $f8 \n\t" + "msuba.s $f3, $f2 \n\t" + "madda.s $f3, $f2 \n\t" + "lui $8, 0x40c9 \n\t" + "msuba.s %0, $f8 \n\t" + "ori $8, 0x0fdb \n\t" + "msub.s %0, $f1, $f2 \n\t" + "lui $9, 0xc225 \n\t" + "abs.s %0, %0 \n\t" + "lui $10, 0x3e80 \n\t" + "mtc1 $10, $f7 \n\t" + "ori $9, 0x5de1 \n\t" + "sub.s %0, %0, $f7 \n\t" + "lui $10, 0x42a3 \n\t" + "mtc1 $8, $f3 \n\t" + "ori $10, 0x3458 \n\t" + "mtc1 $9, $f4 \n\t" + "lui $8, 0xc299 \n\t" + "mtc1 $10, $f5 \n\t" + "ori $8, 0x2663 \n\t" + "mul.s $f8, %0, %0 \n\t" + "lui $9, 0x421e \n\t" + "mtc1 $8, $f6 \n\t" + "ori $9, 0xd7bb \n\t" + "mtc1 $9, $f7 \n\t" + "nop \n\t" + "mul.s $f1, %0, $f8 \n\t" + "mul.s $f9, $f8, $f8 \n\t" + "mula.s $f3, %0 \n\t" + "mul.s $f2, $f1, $f8 \n\t" + "madda.s $f4, $f1 \n\t" + "mul.s $f1, $f1, $f9 \n\t" + "mul.s %0, $f2, $f9 \n\t" + "madda.s $f5, $f2 \n\t" + "madda.s $f6, $f1 \n\t" + "madd.s %0, $f7, %0 \n\t" + ".set reorder \n\t" + : "=&f"(r) + : "f"(x) + : "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", "$8", + "$9", "$10"); + return r; +} + +float Math::invSqrt(const float& x) { return 1.0F / sqrt(x); } + +float Math::atan2(float y, float x) { + float r; + asm volatile( + "mtc1 $0, %0 \n\t" + "abs.s $f1, %1 \n\t" + "abs.s $f2, %2 \n\t" + "c.lt.s %2, %0 \n\t" + "move $9, $0 \n\t" + "bc1f _atan_00 \n\t" + "addiu $9, $9, 4 \n\t" + "_atan_00: \n\t" + "c.eq.s %2, %0 \n\t" + "bc1f _atan_00_1 \n\t" + "c.eq.s %1, %2 \n\t" + "bc1t _atan_06 \n\t" + "c.lt.s %1, %0 \n\t" + "bc1f _atan_00_1 \n\t" + "addiu $9, $0, 3 \n\t" + "_atan_00_1: \n\t" + "mul.s %1, %1, %2 \n\t" + "c.lt.s %1, %0 \n\t" + "bc1f _atan_01 \n\t" + "addiu $9, $9, 2 \n\t" + "c.lt.s $f2, $f1 \n\t" + "bc1f _atan_02 \n\t" + "addiu $9, $9, 1 \n\t" + "b _atan_02 \n\t" + "_atan_01: \n\t" + "c.lt.s $f1, $f2 \n\t" + "bc1f _atan_02 \n\t" + "addiu $9, $9, 1 \n\t" + "_atan_02: \n\t" + "c.lt.s $f1, $f2 \n\t" + "bc1f _atan_03 \n\t" + "mov.s %1, $f2 \n\t" + "mov.s %2, $f1 \n\t" + "b _atan_04 \n\t" + "_atan_03: \n\t" + "mov.s %1, $f1 \n\t" + "mov.s %2, $f2 \n\t" + "_atan_04: \n\t" + "mfc1 $6, %1 \n\t" + "mfc1 $7, %2 \n\t" + "la $8, TYRA_MATH_ATAN_TABLE \n\t" + "lqc2 $vf4, 0x0($8) \n\t" + "lqc2 $vf5, 0x10($8) \n\t" + "lqc2 $vf6, 0x20($8) \n\t" + "qmtc2 $6, $vf21 \n\t" + "qmtc2 $7, $vf22 \n\t" + "vadd.x $vf23, $vf21, $vf22 \n\t" + "vsub.x $vf22, $vf22, $vf21 \n\t" + "vdiv $Q, $vf22x, $vf23x \n\t" + "vwaitq \n\t" + "vaddq.x $vf21, $vf0, $Q \n\t" + "vmul.x $vf22, $vf21, $vf21 \n\t" + "vmulax.x $ACC, $vf21, $vf4 \n\t" + "vmul.x $vf21, $vf21, $vf22 \n\t" + "vmadday.x $ACC, $vf21, $vf4 \n\t" + "vmul.x $vf21, $vf21, $vf22 \n\t" + "vmaddaz.x $ACC, $vf21, $vf4 \n\t" + "vmul.x $vf21, $vf21, $vf22 \n\t" + "vmaddaw.x $ACC, $vf21, $vf4 \n\t" + "vmul.x $vf21, $vf21, $vf22 \n\t" + "vmaddax.x $ACC, $vf21, $vf5 \n\t" + "vmul.x $vf21, $vf21, $vf22 \n\t" + "vmadday.x $ACC, $vf21, $vf5 \n\t" + "vmul.x $vf21, $vf21, $vf22 \n\t" + "vmaddaz.x $ACC, $vf21, $vf5 \n\t" + "vmul.x $vf21, $vf21, $vf22 \n\t" + "vmaddaw.x $ACC, $vf21, $vf5 \n\t" + "vmaddw.x $vf21, $vf6, $vf0 \n\t" + "qmfc2 $6, $vf21 \n\t" + "mtc1 $6, %0 \n\t" + "andi $8, $9, 1 \n\t" + "sll $9, $9, 2 \n\t" + "la $7, TYRA_MATH_ATAN_TABLE2 \n\t" + "add $9, $9, $7 \n\t" + "lw $7, 0x0($9) \n\t" + "mtc1 $7, %1 \n\t" + "beq $8, $0, _atan_05 \n\t" + "sub.s %0, %1, %0 \n\t" + "b _atan_06 \n\t" + "_atan_05: \n\t" + "add.s %0, %1, %0 \n\t" + "_atan_06: \n\t" + : "=&f"(r) + : "f"(x), "f"(y) + : "$6", "$7", "$8", "$9", "$f0", "$f1", "$f2"); + + return r; +} + +float Math::randomf(const float& min, const float& max) { + float random = ((float)rand()) / (float)RAND_MAX; + float diff = max - min; + float r = random * diff; + return min + r; +} + +int Math::randomi(const int& min, const int& max) { + return rand() % (max - min + 1) + min; +} + +float Math::asin(float x) { + float r; + asm volatile( + "lui $9, 0x3f00 \n\t" + ".set noreorder \n\t" + ".align 3 \n\t" + "abs.s %0, %1 \n\t" + "lui $8, 0xbe22 \n\t" + "mtc1 $9, $f1 \n\t" + "ori $8, $8, 0xf983 \n\t" + "mtc1 $8, $f8 \n\t" + "lui $9, 0x4b00 \n\t" + "mtc1 $9, $f3 \n\t" + "lui $8, 0x3f80 \n\t" + "mtc1 $8, $f2 \n\t" + "mula.s %0, $f8 \n\t" + "msuba.s $f3, $f2 \n\t" + "madda.s $f3, $f2 \n\t" + "lui $8, 0x40c9 \n\t" + "msuba.s %0, $f8 \n\t" + "ori $8, 0x0fdb \n\t" + "msub.s %0, $f1, $f2 \n\t" + "lui $9, 0xc225 \n\t" + "abs.s %0, %0 \n\t" + "lui $10, 0x3e80 \n\t" + "mtc1 $10, $f7 \n\t" + "ori $9, 0x5de1 \n\t" + "sub.s %0, %0, $f7 \n\t" + "lui $10, 0x42a3 \n\t" + "mtc1 $8, $f3 \n\t" + "ori $10, 0x3458 \n\t" + "mtc1 $9, $f4 \n\t" + "lui $8, 0xc299 \n\t" + "mtc1 $10, $f5 \n\t" + "ori $8, 0x2663 \n\t" + "mul.s $f8, %0, %0 \n\t" + "lui $9, 0x421e \n\t" + "mtc1 $8, $f6 \n\t" + "ori $9, 0xd7bb \n\t" + "mtc1 $9, $f7 \n\t" + "nop \n\t" + "mul.s $f1, %0, $f8 \n\t" + "mul.s $f9, $f8, $f8 \n\t" + "mula.s $f3, %0 \n\t" + "mul.s $f2, $f1, $f8 \n\t" + "madda.s $f4, $f1 \n\t" + "mul.s $f1, $f1, $f9 \n\t" + "mul.s %0, $f2, $f9 \n\t" + "madda.s $f5, $f2 \n\t" + "madda.s $f6, $f1 \n\t" + "madd.s %0, $f7, %0 \n\t" + ".set reorder \n\t" + : "=&f"(r) + : "f"(x) + : "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", "$8", + "$9", "$10"); + return r; +} + +bool Math::equalf(const float& a, const float& b, const float& epsilon) { + return fabs(a - b) < epsilon; +} + +float Math::mod(const float& x, const float& y) { + /* + * Portable fmod(x,y) implementation for systems + * that don't have it. Adapted from code found here: + * http://www.opensource.apple.com/source/python/python-3/python/Python/fmod.c + */ + float i, f; + + if (fabs(y) < 0.00001F) { + return 0.0F; + } + + i = floorf(x / y); + f = x - i * y; + + if ((x < 0.0f) != (y < 0.0f)) { + f = f - y; + } + + return f; +} + +float Math::acos(const float& x) { + float y = sqrt(1.0f - x * x); + float t = atan2(y, x); + return t; +} + +float Math::sin(const float& x) { return cos(x - HALF_PI); } + +float Math::tan(const float& x) { return sin(x) / cos(x); } + +} // namespace Tyra diff --git a/engine/src/math/plane.cpp b/engine/src/math/plane.cpp new file mode 100644 index 0000000..7a415d1 --- /dev/null +++ b/engine/src/math/plane.cpp @@ -0,0 +1,61 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "math/vec4.hpp" +#include +#include +#include "math/plane.hpp" + +namespace Tyra { + +Plane::Plane() { this->distance = 0; } + +Plane::Plane(const Vec4& a, const Vec4& b, const Vec4& c) { + this->update(a, b, c); +} + +Plane::~Plane() {} + +float Plane::distanceTo(const Vec4& t_vec) const { + return this->distance + this->normal.innerProduct(t_vec); +} + +void Plane::update(const Vec4& a, const Vec4& b, const Vec4& c) { + Vec4 aux1 = a - b; + Vec4 aux2 = c - b; + this->normal = aux2.cross(aux1); + this->normal.normalize(); + this->distance = -this->normal.innerProduct(b); +} + +void Plane::print() const { + auto text = getPrint(nullptr); + printf("%s\n", text.c_str()); +} + +void Plane::print(const char* name) const { + auto text = getPrint(name); + printf("%s\n", text.c_str()); +} + +std::string Plane::getPrint(const char* name) const { + std::stringstream res; + if (name) { + res << name << "("; + } else { + res << "Plane("; + } + + res << std::fixed << std::setprecision(4); + res << "distance: " << distance << ", " << normal.getPrint("normal") << ")"; + return res.str(); +} + +} // namespace Tyra diff --git a/engine/src/math/vec2.cpp b/engine/src/math/vec2.cpp new file mode 100644 index 0000000..bd761e2 --- /dev/null +++ b/engine/src/math/vec2.cpp @@ -0,0 +1,128 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "math/vec2.hpp" +#include + +namespace Tyra { + +Vec2::Vec2(const float& t_x, const float& t_y) { + x = t_x; + y = t_y; +} + +Vec2::Vec2(const Vec2& v) { + x = v.x; + y = v.y; +} + +Vec2::Vec2() { + x = 0; + y = 0; +} + +Vec2::~Vec2() {} + +void Vec2::set(const float& t_x, const float& t_y) { + x = t_x; + y = t_y; +} + +void Vec2::set(const Vec2& v) { + x = v.x; + y = v.y; +} + +void Vec2::rotate(const float& t_angle, const float& t_x, const float& t_y) { + float s = Math::sin(t_angle); + float c = Math::cos(t_angle); + + x -= t_x; + y -= t_y; + + float xnew = x * c - y * s; + float ynew = x * s + y * c; + + x = xnew + t_x; + y = ynew + t_y; +} + +void Vec2::operator=(const Vec2& v) { + x = v.x; + y = v.y; +} + +Vec2 Vec2::operator+(const Vec2& v) const { return Vec2(x + v.x, y + v.y); } +Vec2 Vec2::operator-(const Vec2& v) const { return Vec2(x - v.x, y - v.y); } +Vec2 Vec2::operator*(const Vec2& v) const { return Vec2(x * v.x, y * v.y); } +Vec2 Vec2::operator/(const Vec2& v) const { return Vec2(x / v.x, y / v.y); } + +Vec2 Vec2::operator+(const float& v) const { return Vec2(x + v, y + v); } +Vec2 Vec2::operator-(const float& v) const { return Vec2(x - v, y - v); } +Vec2 Vec2::operator*(const float& v) const { return Vec2(x * v, y * v); } +Vec2 Vec2::operator/(const float& v) const { return Vec2(x / v, y / v); } + +void Vec2::operator+=(const Vec2& v) { + x += v.x; + y += v.y; +} +void Vec2::operator-=(const Vec2& v) { + x -= v.x; + y -= v.y; +} +void Vec2::operator*=(const Vec2& v) { + x *= v.x; + y *= v.y; +} +void Vec2::operator/=(const Vec2& v) { + x /= v.x; + y /= v.y; +} + +void Vec2::operator+=(const float& v) { + x += v; + y += v; +} +void Vec2::operator-=(const float& v) { + x -= v; + y -= v; +} +void Vec2::operator*=(const float& v) { + x *= v; + y *= v; +} +void Vec2::operator/=(const float& v) { + x /= v; + y /= v; +} + +void Vec2::print() const { + auto text = getPrint(nullptr); + printf("%s\n", text.c_str()); +} + +void Vec2::print(const char* name) const { + auto text = getPrint(name); + printf("%s\n", text.c_str()); +} + +std::string Vec2::getPrint(const char* name) const { + std::stringstream res; + if (name) { + res << name << "("; + } else { + res << "Vec2("; + } + res << std::fixed << std::setprecision(4); + res << x << ", " << y << ")"; + return res.str(); +} + +} // namespace Tyra diff --git a/engine/src/math/vec4.cpp b/engine/src/math/vec4.cpp new file mode 100644 index 0000000..125fcbd --- /dev/null +++ b/engine/src/math/vec4.cpp @@ -0,0 +1,364 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "math/vec4.hpp" +#include +#include +#include + +namespace Tyra { + +void Vec4::set(const float& t_x, const float& t_y, const float& t_z, + const float& t_w) { + x = t_x; + y = t_y; + z = t_z; + w = t_w; +} + +const Vec4 Vec4::Identity = Vec4(0.0F, 0.0F, 0.0F, 1.0F); + +void Vec4::operator=(const Vec4& v) { copy(this, v); } + +Vec4 Vec4::operator-(void) const { return Vec4(-x, -y, -z, w); } + +Vec4 Vec4::operator+(const Vec4& v) const { + Vec4 res; + asm volatile( + "lqc2 $vf4, 0x0(%1) \n\t" + "lqc2 $vf5, 0x0(%2) \n\t" + "vadd.xyz $vf6, $vf4, $vf5 \n\t" + "sqc2 $vf6, 0x0(%0) \n\t" + : + : "r"(res.xyzw), "r"(this->xyzw), "r"(v.xyzw)); + return res; +} + +void Vec4::operator+=(const Vec4& v) { + asm volatile( + "lqc2 $vf4, 0x0(%0) \n\t" + "lqc2 $vf5, 0x0(%1) \n\t" + "vadd.xyz $vf4, $vf4, $vf5 \n\t" + "sqc2 $vf4, 0x0(%0) \n\t" + : + : "r"(this->xyzw), "r"(v.xyzw)); +} + +Vec4 Vec4::operator-(const Vec4& v) const { + Vec4 res; + asm volatile( + "lqc2 $vf4, 0x0(%1) \n\t" + "lqc2 $vf5, 0x0(%2) \n\t" + "vsub.xyz $vf6, $vf4, $vf5 \n\t" + "sqc2 $vf6, 0x0(%0) \n\t" + : + : "r"(res.xyzw), "r"(this->xyzw), "r"(v.xyzw)); + return res; +} + +void Vec4::operator-=(const Vec4& v) { + asm volatile( + "lqc2 $vf4, 0x0(%0) \n\t" + "lqc2 $vf5, 0x0(%1) \n\t" + "vsub.xyz $vf4, $vf4, $vf5 \n\t" + "sqc2 $vf4, 0x0(%0) \n\t" + : + : "r"(this->xyzw), "r"(v.xyzw)); +} + +Vec4 Vec4::operator*(const Vec4& v) const { + Vec4 res; + asm volatile( + "lqc2 $vf4, 0x0(%1) \n\t" + "lqc2 $vf5, 0x0(%2) \n\t" + "vmul.xyzw $vf6, $vf4, $vf5 \n\t" + "sqc2 $vf6, 0x0(%0) \n\t" + : + : "r"(res.xyzw), "r"(this->xyzw), "r"(v.xyzw)); + return res; +} + +void Vec4::operator*=(const Vec4& v) { + asm volatile( + "lqc2 $vf4, 0x0(%0) \n\t" + "lqc2 $vf5, 0x0(%1) \n\t" + "vmul.xyzw $vf6, $vf4, $vf5 \n\t" + "sqc2 $vf6, 0x0(%0) \n\t" + : + : "r"(this->xyzw), "r"(v.xyzw)); +} + +Vec4 Vec4::operator/(const Vec4& v) const { + return Vec4(x / v.x, y / v.y, z / v.z, w / v.w); +} + +void Vec4::operator/=(const Vec4& v) { + x /= v.x; + y /= v.y; + z /= v.z; + w /= v.w; +} + +Vec4 Vec4::operator*(const float& v) const { + Vec4 res; + asm volatile( + "lqc2 $vf4, 0x0(%1) \n\t" + "mfc1 $8, %2 \n\t" + "qmtc2 $8, $vf5 \n\t" + "vmulx.xyz $vf6, $vf4, $vf5 \n\t" + "vmove.w $vf6, $vf4 \n\t" + "sqc2 $vf6, 0x0(%0) \n\t" + : + : "r"(res.xyzw), "r"(this->xyzw), "f"(v)); + return res; +} + +void Vec4::operator*=(const float& v) { + asm volatile( + "lqc2 $vf4, 0x0(%0) \n\t" + "mfc1 $8, %1 \n\t" + "qmtc2 $8, $vf5 \n\t" + "vmulx.xyz $vf4, $vf4, $vf5 \n\t" + "sqc2 $vf4, 0x0(%0) \n\t" + : + : "r"(this->xyzw), "f"(v)); +} + +Vec4 Vec4::operator/(const float& v) const { + Vec4 res; + asm volatile( + "mfc1 $8, %2 \n\t" + "qmtc2 $8, $vf5 \n\t" + "vdiv $Q, $vf0w, $vf5x \n\t" + "lqc2 $vf4, 0x00(%1) \n\t" + "vwaitq \n\t" + "vmulq.xyz $vf4, $vf4, $Q\n\t" + "sqc2 $vf4, 0x00(%0) \n\t" + : + : "r"(res.xyzw), "r"(this->xyzw), "f"(v) + : "$8"); + return res; +} + +void Vec4::operator/=(const float& v) { + asm volatile( + "mfc1 $8, %1 \n\t" + "qmtc2 $8, $vf5 \n\t" + "vdiv $Q, $vf0w, $vf5x \n\t" + "lqc2 $vf4, 0x00(%0) \n\t" + "vwaitq \n\t" + "vmulq.xyz $vf4, $vf4, $Q\n\t" + "sqc2 $vf4, 0x00(%0) \n\t" + : + : "r"(this->xyzw), "f"(v) + : "$8"); +} + +void Vec4::unit() { + asm volatile("sqc2 $vf0, 0x00(%0) \n" : : "r"(this->xyzw)); +} + +void Vec4::copy(Vec4* out, const float* in) { + asm volatile( + "lqc2 $vf1, 0x00(%1) \n" + "sqc2 $vf1, 0x00(%0) \n" + : + : "r"(out->xyzw), "r"(in)); +} + +Vec4 Vec4::cross(const Vec4& v) const { + Vec4 res; + asm volatile( + "lqc2 $vf4, 0x0(%1) \n\t" + "lqc2 $vf5, 0x0(%2) \n\t" + "vopmula.xyz $ACC, $vf4, $vf5 \n\t" + "vopmsub.xyz $vf8, $vf5, $vf4 \n\t" + "vsub.w $vf8, $vf0, $vf0 \n\t" + "sqc2 $vf8, 0x0(%0) \n\t" + : + : "r"(res.xyzw), "r"(this->xyzw), "r"(v.xyzw)); + return res; +} + +void Vec4::rotateZ(const int& angle) { + auto s = Math::sin(angle); + auto c = Math::cos(angle); + x = x * c - y * s; + y = x * s + y * c; +} + +int Vec4::getRelativeCosBetween(const Vec4& v) const { + return dot3(v) / (length() * v.length()); +} +int Vec4::getRelativeAngleBetween(const Vec4& v) const { + return acos(getRelativeCosBetween(v)); +} + +bool Vec4::collidesBox(const Vec4& min, const Vec4& max) const { + return ((this->x <= max.x && this->x >= min.x) && + (this->y < max.y && this->y >= min.y) && + (this->z <= max.z && this->z >= min.z)) + ? 1 + : 0; +} + +bool Vec4::isOnBox(const Vec4& min, const Vec4& max) const { + return ((this->x <= max.x && this->x >= min.x) && (this->y >= max.y) && + (this->z <= max.z && this->z >= min.z)) + ? 1 + : 0; +} + +float Vec4::innerProduct(const Vec4& v) const { + float result; + asm volatile( + "lqc2 $vf4, 0x0(%1) \n\t" + "lqc2 $vf5, 0x0(%2) \n\t" + "vmul.xyz $vf6, $vf4, $vf5 \n\t" + "vaddy.x $vf6, $vf6, $vf6 \n\t" + "vaddz.x $vf6, $vf6, $vf6 \n\t" + "qmfc2 $2, $vf6 \n\t" + "mtc1 $2, %0 \n\t" + : "=f"(result) + : "r"(this->xyzw), "r"(v.xyzw)); + return result; +} + +float Vec4::length() const { + float result; + asm volatile( + "lqc2 $vf4, 0x0(%1) \n\t" + "vmul.xyz $vf5, $vf4, $vf4 \n\t" + "vaddy.x $vf5, $vf5, $vf5 \n\t" + "vaddz.x $vf5, $vf5, $vf5 \n\t" + "vsqrt $Q , $vf5x \n\t" + "vwaitq \n\t" + "vaddq.x $vf8, $vf0, $Q \n\t" + "qmfc2 $2, $vf8 \n\t" + "mtc1 $2, %0 \n\t" + : "=f"(result) + : "r"(this->xyzw)); + return result; +} + +void Vec4::normalize() { + asm volatile( + "lqc2 $vf4, 0x0(%0) \n\t" + "vmul.xyz $vf5, $vf4, $vf4 \n\t" + "vaddy.x $vf5, $vf5, $vf5 \n\t" + "vaddz.x $vf5, $vf5, $vf5 \n\t" + "vrsqrt $Q, $vf0w, $vf5x \n\t" + "vwaitq \n\t" + "vsub.xyz $vf6, $vf0, $vf0 \n\t" + "vaddw.xyz $vf6, $vf6, $vf4 \n\t" + "vwaitq \n\t" + "vmulq.xyz $vf6, $vf4, $Q \n\t" + "sqc2 $vf6, 0x0(%0) \n\t" + : + : "r"(this->xyzw)); +} + +Vec4 Vec4::getNormalized() const { + Vec4 result(*this); + result.normalize(); + return result; +} + +float Vec4::distanceTo(const Vec4& v) const { + float result; + asm volatile( + "lqc2 $vf4, 0x0(%1) \n\t" + "lqc2 $vf5, 0x0(%2) \n\t" + "vsub.xyz $vf6, $vf4, $vf5 \n\t" + "vmul.xyz $vf7, $vf6, $vf6 \n\t" + "vaddy.x $vf7, $vf7, $vf7 \n\t" + "vaddz.x $vf7, $vf7, $vf7 \n\t" + "vsqrt $Q , $vf7x \n\t" + "vwaitq \n\t" + "vaddq.x $vf8, $vf0, $Q \n\t" + "qmfc2 $2, $vf8 \n\t" + "mtc1 $2, %0 \n\t" + : "=f"(result) + : "r"(this->xyzw), "r"(v.xyzw)); + return result; +} + +u8 Vec4::shouldBeBackfaceCulled(const Vec4* cameraPos, const Vec4* v0, + const Vec4* v1, const Vec4* v2) { + float dot; + asm volatile( + "lqc2 $vf4, 0x0(%1) \n\t" // $vf4 = cameraPos + "lqc2 $vf5, 0x0(%2) \n\t" // $vf5 = v0 + "lqc2 $vf6, 0x0(%3) \n\t" // $vf6 = v1 + "lqc2 $vf7, 0x0(%4) \n\t" // $vf7 = v2 + "vsub.xyz $vf8, $vf7, $vf5 \n\t" // $vf8 = $vf7(v2) - $vf5(v0) + "vsub.xyz $vf9, $vf6, $vf5 \n\t" // $vf9 = $vf6(v1) - $vf5(v0) + "vopmula.xyz $ACC, $vf8, $vf9 \n\t" // $vf6 = cross($vf8, $vf9) + "vopmsub.xyz $vf6, $vf9, $vf8 \n\t" + "vsub.w $vf6, $vf6, $vf6 \n\t" + "vsub.xyz $vf7, $vf5, $vf4 \n\t" // $vf7 = $vf5(v0) - $vf4(cameraPos) + "vmul.xyz $vf5, $vf7, $vf6 \n\t" // $vf5 = dot($vf7, $vf6) + "vaddy.x $vf5, $vf5, $vf5 \n\t" + "vaddz.x $vf5, $vf5, $vf5 \n\t" + "qmfc2 $2, $vf5 \n\t" // store result on `dot` variable + "mtc1 $2, %0 \n\t" + : "=f"(dot) + : "r"(cameraPos->xyzw), "r"(v0->xyzw), "r"(v1->xyzw), "r"(v2->xyzw)); + return dot <= 0.0F; +} + +void Vec4::lerp(const Vec4& v1, const Vec4& v2, const float& interp) { + setLerp(this, v1, v2, interp); +} + +Vec4 Vec4::getByLerp(const Vec4& v1, const Vec4& v2, const float& interp) { + Vec4 result; + setLerp(&result, v1, v2, interp); + return result; +} + +void Vec4::setLerp(Vec4* output, const Vec4& v1, const Vec4& v2, + const float& interp) { + asm volatile( + "lqc2 $vf4, 0x0(%1) \n\t" // $vf4 = v1 + "lqc2 $vf5, 0x0(%2) \n\t" // $vf5 = v2 + "mfc1 $8, %3 \n\t" // $vf6 = t + "qmtc2 $8, $vf6 \n\t" // lerp: + "vsub.xyzw $vf7, $vf5, $vf4 \n\t" // $vf7 = v2 - v1 + "vmulx.xyzw $vf8, $vf7, $vf6 \n\t" // $vf8 = $vf7 * t + "vadd.xyzw $vf9, $vf8, $vf4 \n\t" // $vf9 = $vf8 + $vf4 + "sqc2 $vf9, 0x0(%0) \n\t" // v0 = $vf9 + : + : "r"(&output->xyzw), "r"(&v1.xyzw), "r"(&v2.xyzw), "f"(interp)); +} + +void Vec4::print() const { + auto text = getPrint(nullptr); + printf("%s\n", text.c_str()); +} + +void Vec4::print(const char* name) const { + auto text = getPrint(name); + printf("%s\n", text.c_str()); +} + +std::string Vec4::getPrint(const char* name) const { + std::stringstream res; + if (name) { + res << name << "("; + } else { + res << "Vec4("; + } + res << std::fixed << std::setprecision(4); + res << x << ", " << y << ", " << z << ", " << w << ")"; + return res.str(); +} + +} // namespace Tyra diff --git a/engine/src/pad/pad.cpp b/engine/src/pad/pad.cpp new file mode 100644 index 0000000..684d795 --- /dev/null +++ b/engine/src/pad/pad.cpp @@ -0,0 +1,229 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022-2022, tyra - https://github.com/h4570/tyrav2 +# Licensed under Apache License 2.0 +# Sandro Sobczyński +# Wellington Carvalho +*/ + +#include +#include +#include +#include +#include +#include "debug/debug.hpp" +#include "pad/pad.hpp" + +namespace Tyra { + +/** Init vars, load modules, opens pad port and initializes pad */ +Pad::Pad() {} + +Pad::~Pad() {} + +// ---- +// Methods +// ---- + +void Pad::init() { + this->oldPad = 0; + padInit(0); + this->port = 0; // 0 -> Connector 1, 1 -> Connector 2 + this->slot = 0; // Always zero if not using multitap + + this->ret = padPortOpen(this->port, this->slot, padBuf); + TYRA_ASSERT(this->ret != 0, + "padPortOpen failed! padPortOpen returned: ", this->ret); + TYRA_ASSERT(this->initPad(), "initPad failed!"); +} + +/** Wait when pad will be ready (stable and ready) */ +int Pad::waitPadReady() { + int state; + int lastState; + char* stateString = new char[16]; + state = padGetState(this->port, this->slot); + lastState = -1; + while ((state != PAD_STATE_STABLE) && (state != PAD_STATE_FINDCTP1)) { + if (state != lastState) { + padStateInt2String(state, stateString); + TYRA_LOG("Pad state changed"); + printf("Curent pad(%d,%d) status: %s\n", this->port, this->slot, + stateString); + } + lastState = state; + state = padGetState(this->port, this->slot); + } + // Were the pad ever 'out of sync'? + if (lastState != -1) TYRA_LOG("Pad is ready!"); + + delete[] stateString; + return 0; +} + +/** Initializes and checks type of pad */ +int Pad::initPad() { + TYRA_LOG("Initializing pad"); + this->waitPadReady(); + + int modes = padInfoMode(this->port, this->slot, PAD_MODETABLE, -1); + TYRA_ASSERT(modes, "Connected device is not a dual shock controller!"); + + // Verify that the controller has a DUAL SHOCK mode + int i = 0; + do { + if (padInfoMode(this->port, this->slot, PAD_MODETABLE, i) == + PAD_TYPE_DUALSHOCK) + break; + i++; + } while (i < modes); + + TYRA_ASSERT(i < modes, "Connected device is not a dual shock controller!"); + + // If ExId != 0x0 => This controller has actuator engines + // This check should always pass if the Dual Shock test above passed + this->ret = padInfoMode(this->port, this->slot, PAD_MODECUREXID, 0); + TYRA_ASSERT(this->ret, "Connected device is not a dual shock controller!"); + + TYRA_LOG("Enabling dual shock functions."); + + // When using MMODE_LOCK, user cant change mode with Select button + padSetMainMode(this->port, this->slot, PAD_MMODE_DUALSHOCK, PAD_MMODE_LOCK); + + this->waitPadReady(); + TYRA_LOG("Pad has pressure sensitive buttons? ", + padInfoPressMode(this->port, this->slot)); + this->waitPadReady(); + padEnterPressMode(this->port, this->slot); // Set pressure sensitive mode + this->waitPadReady(); + this->actuators = padInfoAct(this->port, this->slot, -1, 0); + TYRA_LOG("# of actuators: ", this->actuators); + if (actuators != 0) { + this->actAlign[0] = 0; // Enable small engine + this->actAlign[1] = 1; // Enable big engine + this->actAlign[2] = 0xff; + this->actAlign[3] = 0xff; + this->actAlign[4] = 0xff; + this->actAlign[5] = 0xff; + this->waitPadReady(); + TYRA_LOG("padSetActAlign: ", + padSetActAlign(this->port, this->slot, actAlign)); + } else + TYRA_LOG("Did not find any actuators."); + this->waitPadReady(); + TYRA_LOG("Pad initialized!"); + return 1; +} + +/** Updates state of joys/buttons. Called by engine */ +void Pad::update() { + int x = 0; + this->ret = padGetState(this->port, this->slot); + while ((this->ret != PAD_STATE_STABLE) && (this->ret != PAD_STATE_FINDCTP1)) { + if (this->ret == PAD_STATE_DISCONN) + printf("Pad(%d, %d) is disconnected\n", this->port, this->slot); + this->ret = padGetState(this->port, this->slot); + } + if (x == 1) TYRA_LOG("Pad: OK!\n"); + + this->ret = padRead(this->port, this->slot, &this->buttons); + + if (this->ret != 0) { + this->padData = 0xffff ^ this->buttons.btns; + + this->newPad = this->padData & ~this->oldPad; + this->oldPad = this->padData; + this->reset(); + + // Digital buttons + this->rightJoyPad.h = this->buttons.rjoy_h; + this->rightJoyPad.v = this->buttons.rjoy_v; + this->leftJoyPad.h = this->buttons.ljoy_h; + this->leftJoyPad.v = this->buttons.ljoy_v; + + this->rightJoyPad.isCentered = + this->buttons.rjoy_h == 127 && this->buttons.rjoy_v == 127; + this->rightJoyPad.isMoved = !this->rightJoyPad.isCentered; + + this->leftJoyPad.isCentered = + this->buttons.ljoy_h == 127 && this->buttons.ljoy_v == 127; + this->leftJoyPad.isMoved = !this->leftJoyPad.isCentered; + + this->handleClickedButtons(); + this->handlePressedButtons(); + } +} + +/** Update clicked buttons state */ +void Pad::handleClickedButtons() { + if (this->newPad & PAD_CROSS) this->clicked.Cross = 1; + if (this->newPad & PAD_SQUARE) this->clicked.Square = 1; + if (this->newPad & PAD_TRIANGLE) this->clicked.Triangle = 1; + if (this->newPad & PAD_CIRCLE) this->clicked.Circle = 1; + if (this->newPad & PAD_UP) this->clicked.DpadUp = 1; + if (this->newPad & PAD_DOWN) this->clicked.DpadDown = 1; + if (this->newPad & PAD_LEFT) this->clicked.DpadLeft = 1; + if (this->newPad & PAD_RIGHT) this->clicked.DpadRight = 1; + if (this->newPad & PAD_L1) this->clicked.L1 = 1; + if (this->newPad & PAD_L2) this->clicked.L2 = 1; + if (this->newPad & PAD_L3) this->clicked.L3 = 1; + if (this->newPad & PAD_R1) this->clicked.R1 = 1; + if (this->newPad & PAD_R2) this->clicked.R2 = 1; + if (this->newPad & PAD_R3) this->clicked.R3 = 1; + if (this->newPad & PAD_START) this->clicked.Start = 1; + if (this->newPad & PAD_SELECT) this->clicked.Select = 1; +} + +/** Update pressed buttons state */ +void Pad::handlePressedButtons() { + if (this->buttons.cross_p) this->pressed.Cross = 1; + if (this->buttons.square_p) this->pressed.Square = 1; + if (this->buttons.triangle_p) this->pressed.Triangle = 1; + if (this->buttons.circle_p) this->pressed.Circle = 1; + if (this->buttons.up_p) this->pressed.DpadUp = 1; + if (this->buttons.down_p) this->pressed.DpadDown = 1; + if (this->buttons.left_p) this->pressed.DpadLeft = 1; + if (this->buttons.right_p) this->pressed.DpadRight = 1; + if (this->buttons.l1_p) this->pressed.L1 = 1; + if (this->buttons.l2_p) this->pressed.L2 = 1; + if (this->buttons.r1_p) this->pressed.R1 = 1; + if (this->buttons.r2_p) this->pressed.R2 = 1; +} + +/** Resets state of joys/buttons */ +void Pad::reset() { + this->clicked.Cross = 0; + this->clicked.Square = 0; + this->clicked.Triangle = 0; + this->clicked.Circle = 0; + this->clicked.DpadUp = 0; + this->clicked.DpadDown = 0; + this->clicked.DpadLeft = 0; + this->clicked.DpadRight = 0; + this->clicked.L1 = 0; + this->clicked.L2 = 0; + this->clicked.L3 = 0; + this->clicked.R1 = 0; + this->clicked.R2 = 0; + this->clicked.R3 = 0; + this->clicked.Start = 0; + this->clicked.Select = 0; + + this->pressed.Cross = 0; + this->pressed.Square = 0; + this->pressed.Triangle = 0; + this->pressed.Circle = 0; + this->pressed.DpadUp = 0; + this->pressed.DpadDown = 0; + this->pressed.DpadLeft = 0; + this->pressed.DpadRight = 0; + this->pressed.L1 = 0; + this->pressed.L2 = 0; + this->pressed.R1 = 0; + this->pressed.R2 = 0; +} + +} // Namespace Tyra \ No newline at end of file diff --git a/engine/src/physics/ray.cpp b/engine/src/physics/ray.cpp new file mode 100644 index 0000000..94edf6b --- /dev/null +++ b/engine/src/physics/ray.cpp @@ -0,0 +1,104 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022-2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Wellinator Carvalho +*/ + +#include "physics/ray.hpp" +#include +#include +#include +#include +#include + +namespace Tyra { + +Ray::Ray() {} +Ray::Ray(const Vec4& t_origin, const Vec4& t_direction) { + origin.set(t_origin); + direction.set(t_direction); +} + +Ray::~Ray() {} + +Vec4 Ray::at(const float& t) const { return (direction * t) + origin; } + +float Ray::distanceToPoint(const Vec4& point) const { + return origin.distanceTo(point); +} + +bool Ray::intersectBox(const Vec4& minCorner, const Vec4& maxCorner, + float* outputDistance) const { + auto min = (minCorner - origin) / direction; + auto max = (maxCorner - origin) / direction; + + float tmin = + std::max(std::max(std::min(min.x, max.x), std::min(min.y, max.y)), + std::min(min.z, max.z)); + float tmax = + std::min(std::min(std::max(min.x, max.x), std::max(min.y, max.y)), + std::max(min.z, max.z)); + + // if tmax < 0, ray (line) is intersecting AABB, but whole AABB is behing us + if (tmax < 0) { + if (outputDistance != nullptr) { + *outputDistance = -1.0f; + } + return false; + } + + // if tmin > tmax, ray doesn't intersect AABB + if (tmin > tmax) { + if (outputDistance != nullptr) { + *outputDistance = -1.0f; + } + return false; + } + + if (tmin < 0) { + if (outputDistance != nullptr) { + *outputDistance = tmax; + } + return true; + } + + if (outputDistance != nullptr) { + *outputDistance = tmin; + } + + return true; +} + +Vec4 Ray::invDir() const { + return Vec4(1 / this->direction.x, 1 / this->direction.y, + 1 / this->direction.z, 1); +} + +void Ray::print() const { + auto text = getPrint(nullptr); + printf("%s\n", text.c_str()); +} + +void Ray::print(const char* name) const { + auto text = getPrint(name); + printf("%s\n", text.c_str()); +} + +std::string Ray::getPrint(const char* name) const { + std::stringstream res; + if (name) { + res << name << "("; + } else { + res << "Ray("; + } + res << std::fixed << std::setprecision(4); + res << origin.getPrint("origin") << ", " << direction.getPrint("direction") + << ")"; + return res.str(); +} + +} // Namespace Tyra \ No newline at end of file diff --git a/engine/src/renderer/2d/renderer_2d.cpp b/engine/src/renderer/2d/renderer_2d.cpp new file mode 100644 index 0000000..c65c946 --- /dev/null +++ b/engine/src/renderer/2d/renderer_2d.cpp @@ -0,0 +1,34 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/2d/renderer_2d.hpp" + +namespace Tyra { + +Renderer2D::Renderer2D() {} +Renderer2D::~Renderer2D() {} + +void Renderer2D::init(RendererCore* t_rendererCore) { core = t_rendererCore; } + +void Renderer2D::render(const Sprite* sprite) { render(*sprite); } + +void Renderer2D::render(const Sprite& sprite) { + auto* texture = core->texture.repository.getBySpriteId(sprite.id); + + TYRA_ASSERT( + texture, "Texture for sprite with id: ", sprite.id, + "Was not found in texture repository! Did you forget to add texture?"); + + auto texBuffers = core->texture.useTexture(texture); + core->texture.updateClutBuffer(texBuffers.clut); + core->renderer2D.render(sprite, texBuffers, texture); +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/bbox/bbox.cpp b/engine/src/renderer/3d/bbox/bbox.cpp new file mode 100644 index 0000000..4c3b598 --- /dev/null +++ b/engine/src/renderer/3d/bbox/bbox.cpp @@ -0,0 +1,136 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/bbox/bbox.hpp" + +namespace Tyra { + +BBox::BBox(CoreBBox** t_bboxes, const u32& count) : CoreBBox(t_bboxes, count) { + setData(); +} + +BBox::BBox(const Vec4* t_vertices, const u32& count) + : CoreBBox(t_vertices, count) { + setData(); +} + +BBox::BBox(const Vec4* t_vertices, const u32* faces, const u32& count) + : CoreBBox(t_vertices, faces, count) { + setData(); +} + +BBox::BBox(const BBox& t_bbox) : CoreBBox(t_bbox) { setData(); } + +BBox::BBox(const BBox& t_bbox, const M4x4& t_matrix) + : CoreBBox(t_bbox, t_matrix) { + setData(); +} + +BBox::BBox(const Vec4* t_vertices) : CoreBBox(t_vertices) { setData(); } + +BBox BBox::getTransformed(const M4x4& t_matrix) const { + return BBox(*this, t_matrix); +} + +void BBox::setData() { + // This might be shortened with Vec4 operator overloading, but current + // implementation is more human readable. + _height = vertices[0].y - vertices[2].y; + _width = vertices[0].x - vertices[4].x; + _depth = vertices[0].z - vertices[1].z; + + _centerVector = vertices[0]; + _centerVector.x += (_width / 2); + _centerVector.y += (_height / 2); + _centerVector.z += (_depth / 2); + + // Z-Axis faces + _frontFace = BBoxFace(vertices[1], vertices[7], vertices[1].z); + _backFace = BBoxFace(vertices[0], vertices[6], vertices[0].z); + // X-Axis faces + _leftFace = BBoxFace(vertices[0], vertices[3], vertices[0].x); + _rightFace = BBoxFace(vertices[4], vertices[7], vertices[4].x); + // Y-Axis faces + _topFace = BBoxFace(vertices[2], vertices[7], vertices[2].y); + _bottomFace = BBoxFace(vertices[0], vertices[5], vertices[0].y); +} + +Vec4 BBox::min() const { + Vec4 temp, _min; + u8 isInitialized = 0; + + for (u8 i = 0; i < 8; i++) { + temp.set(vertices[i].x, vertices[i].y, vertices[i].z, 1.0F); + if (isInitialized == 0) { + isInitialized = 1; + _min.set(temp); + } + + if (_min.x > temp.x) _min.x = temp.x; + if (_min.y > temp.y) _min.y = temp.y; + if (_min.z > temp.z) _min.z = temp.z; + } + + return _min; +} + +Vec4 BBox::max() const { + Vec4 temp, _max; + u8 isInitialized = 0; + + for (u8 i = 0; i < 8; i++) { + temp.set(vertices[i].x, vertices[i].y, vertices[i].z, 1.0F); + if (isInitialized == 0) { + isInitialized = 1; + _max.set(temp); + } + + if (temp.x > _max.x) _max.x = temp.x; + if (temp.y > _max.y) _max.y = temp.y; + if (temp.z > _max.z) _max.z = temp.z; + } + + return _max; +} + +BBox BBox::create(const Vec4& center, const float& size) { + auto core = CoreBBox::create(center, size); + return BBox(core.vertices); +} + +void BBox::operator=(const BBox& v) { + for (auto i = 0; i < 8; i++) Vec4::copy(&vertices[i], v.vertices[i].xyzw); + setData(); +} + +void BBox::getMinMax(Vec4* res_min, Vec4* res_max) const { + Vec4 temp = Vec4(); + + u8 isInitialized = 0; + for (u8 i = 0; i < 8; i++) { + temp.set(vertices[i].x, vertices[i].y, vertices[i].z, 1.0F); + if (isInitialized == 0) { + isInitialized = 1; + res_min->set(temp); + res_max->set(temp); + } + + if (res_min->x > temp.x) res_min->x = temp.x; + if (temp.x > res_max->x) res_max->x = temp.x; + + if (res_min->y > temp.y) res_min->y = temp.y; + if (temp.y > res_max->y) res_max->y = temp.y; + + if (res_min->z > temp.z) res_min->z = temp.z; + if (temp.z > res_max->z) res_max->z = temp.z; + } +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/mesh/dynamic/dynamic_mesh.cpp b/engine/src/renderer/3d/mesh/dynamic/dynamic_mesh.cpp new file mode 100644 index 0000000..c4a16e1 --- /dev/null +++ b/engine/src/renderer/3d/mesh/dynamic/dynamic_mesh.cpp @@ -0,0 +1,46 @@ + +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include +#include "math/m4x4.hpp" +#include "renderer/3d/mesh/dynamic/dynamic_mesh.hpp" + +namespace Tyra { + +DynamicMesh::DynamicMesh(const MeshBuilderData* data) : Mesh(data) { + if (data->materials[0]->frames.size() == 1) { + TYRA_WARN( + "Frames count should be greater than 1 for DynamicMesh! Maybe you " + "should use StaticMesh?"); + } + + for (u32 i = 0; i < data->materials[0]->frames.size(); i++) { + frames.push_back(new MeshFrame(*data, i)); + } + + animation.resetAll(frames); +} + +DynamicMesh::DynamicMesh(const DynamicMesh& mesh) : Mesh(mesh) { + for (u32 i = 0; i < mesh.frames.size(); i++) { + frames.push_back(new MeshFrame(*mesh.frames[i])); + } + + animation.resetAll(frames); +} + +DynamicMesh::~DynamicMesh() { + for (u32 i = 0; i < frames.size(); i++) { + delete frames[i]; + } +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/mesh/dynamic/dynamic_mesh_animation.cpp b/engine/src/renderer/3d/mesh/dynamic/dynamic_mesh_animation.cpp new file mode 100644 index 0000000..aa8fb85 --- /dev/null +++ b/engine/src/renderer/3d/mesh/dynamic/dynamic_mesh_animation.cpp @@ -0,0 +1,145 @@ + +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "math/m4x4.hpp" +#include "renderer/3d/mesh/dynamic/dynamic_mesh_animation.hpp" +#include "debug/debug.hpp" + +namespace Tyra { + +DynamicMeshAnimation::DynamicMeshAnimation() { + callback = nullptr; + currentFrameSequenceIndex = 0; + framesCount = 0; +} + +DynamicMeshAnimation::~DynamicMeshAnimation() {} + +void DynamicMeshAnimation::resetAll(const std::vector& frames) { + framesCount = frames.size(); + speed = 0.1F; + loop = true; + + state.interpolation = 0.0F; + state.currentFrame = 0; + state.nextFrame = 0; + + sequence.clear(); + for (std::size_t i = 0; i < frames.size(); i++) { + sequence.push_back(i); + } + + restart(); +} + +void DynamicMeshAnimation::setSequence(const std::vector& t_sequence) { + TYRA_ASSERT(framesCount != 1, + "Cant set sequence, because this mesh have only one frame."); + + TYRA_ASSERT(sequence.size() > 0, + "Cant set sequence, because sequence is empty."); + + for (std::size_t i = 0; i < t_sequence.size(); i++) { + TYRA_ASSERT(t_sequence[i] < framesCount && t_sequence[i] >= 0, + "Cant set sequence, because value: ", t_sequence[i], + " At index: ", i, " Is out of range!"); + } + + sequence = t_sequence; + + restart(); +} + +const DynamicMeshAnimState& DynamicMeshAnimation::getState() const { + return state; +} + +void DynamicMeshAnimation::update() { + AnimationSequenceCallback callbackInfo = + AnimationSequenceCallback::AnimationSequenceCallback_NextFrame; + bool sendCallback = true; + + state.interpolation += speed; + + if (state.interpolation >= 1.0F) { + state.interpolation = 0.0F; + + if (loop) { + updateLoopState(&callbackInfo); + } else { + auto anythingChanged = updateNoLoopState(&callbackInfo); + if (!anythingChanged) { + sendCallback = false; + } + } + } + + if (callback != nullptr && sendCallback) callback(callbackInfo); +} + +void DynamicMeshAnimation::restart() { + currentFrameSequenceIndex = 0; + + auto firstIndex = sequence[0]; + auto secondIndex = sequence.size() > 1 ? sequence[1] : firstIndex; + + state.currentFrame = sequence[firstIndex]; + state.nextFrame = sequence[secondIndex]; +} + +void DynamicMeshAnimation::updateLoopState( + AnimationSequenceCallback* callbackInfo) { + auto n1SequenceIndex = getNextSequenceIndexFrom(currentFrameSequenceIndex); + + state.currentFrame = state.nextFrame; + + auto isN1SequenceIndexEndOfSequence = n1SequenceIndex == sequence.size() - 1; + if (isN1SequenceIndexEndOfSequence) { + *callbackInfo = AnimationSequenceCallback::AnimationSequenceCallback_Loop; + } + + state.nextFrame = sequence[getNextSequenceIndexFrom(n1SequenceIndex)]; + currentFrameSequenceIndex = n1SequenceIndex; +} + +bool DynamicMeshAnimation::updateNoLoopState( + AnimationSequenceCallback* callbackInfo) { + if (state.currentFrame == state.nextFrame) { + return false; // Animation is finished. + } + + auto n1SequenceIndex = getNextSequenceIndexFrom(currentFrameSequenceIndex); + + state.currentFrame = state.nextFrame; + + auto isN1SequenceIndexEndOfSequence = n1SequenceIndex == sequence.size() - 1; + if (isN1SequenceIndexEndOfSequence) { + state.nextFrame = sequence[sequence.size() - 1]; + *callbackInfo = AnimationSequenceCallback::AnimationSequenceCallback_End; + currentFrameSequenceIndex = sequence.size() - 1; + } else { + state.nextFrame = sequence[getNextSequenceIndexFrom(n1SequenceIndex)]; + currentFrameSequenceIndex = n1SequenceIndex; + } + + return true; +} + +u32 DynamicMeshAnimation::getNextSequenceIndexFrom(const u32& index) const { + return index == sequence.size() - 1 ? 0 : index + 1; +} + +void DynamicMeshAnimation::setCallback( + const std::function& t_callback) { + callback = t_callback; +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/mesh/mesh.cpp b/engine/src/renderer/3d/mesh/mesh.cpp new file mode 100644 index 0000000..58c6dec --- /dev/null +++ b/engine/src/renderer/3d/mesh/mesh.cpp @@ -0,0 +1,78 @@ + +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/mesh/mesh.hpp" + +namespace Tyra { + +Mesh::Mesh(const MeshBuilderData* data) { + init(); + + TYRA_ASSERT(data->materials.size() > 0, + "Materials count must be greater than 0"); + + for (u32 i = 0; i < data->materials.size(); i++) { + auto* material = new MeshMaterial(*data, i); + + if (material->frames.size() == 0) { + TYRA_WARN("Found empty material: ", material->name, ". Skipping..."); + delete material; + continue; + } + + materials.push_back(material); + } + + isMother = true; +} + +Mesh::Mesh(const Mesh& mesh) { + init(); + + for (u32 i = 0; i < mesh.materials.size(); i++) { + materials.push_back(new MeshMaterial(*mesh.materials[i])); + } + + isMother = false; +} + +M4x4 Mesh::getModelMatrix() const { return translation * rotation * scale; } + +MeshMaterial* Mesh::getMaterialByName(const std::string& name) { + for (auto* material : materials) { + if (material->name == name) { + return material; + } + } + + return nullptr; +} + +Mesh::~Mesh() { + for (u32 i = 0; i < materials.size(); i++) { + delete materials[i]; + } +} + +void Mesh::init() { + id = rand() % 1000000; + translation = M4x4::Identity; + rotation = M4x4::Identity; + scale = M4x4::Identity; + translation.translate(Vec4(0.0F, 0.0F, 0.0F, 1.0F)); +} + +void Mesh::setPosition(const Vec4& v) { + TYRA_ASSERT(v.w == 1.0F, "Vec4 must be homogeneous"); + reinterpret_cast(&translation.data[3 * 4])->set(v); +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/mesh/mesh_frame.cpp b/engine/src/renderer/3d/mesh/mesh_frame.cpp new file mode 100644 index 0000000..1e6b1c0 --- /dev/null +++ b/engine/src/renderer/3d/mesh/mesh_frame.cpp @@ -0,0 +1,79 @@ + +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "debug/debug.hpp" +#include +#include +#include +#include "math/vec4.hpp" +#include "renderer/models/color.hpp" +#include "renderer/3d/mesh/mesh_frame.hpp" + +namespace Tyra { + +MeshFrame::MeshFrame(const MeshBuilderData& data, const u32& index) { + id = rand() % 1000000; + + auto bboxes = new CoreBBox*[data.materials.size()]; + for (u32 i = 0; i < data.materials.size(); i++) { + bboxes[i] = new CoreBBox(data.materials[i]->frames[index]->vertices, + data.materials[i]->frames[index]->count); + } + + bbox = new BBox(bboxes, data.materials.size()); + + for (u32 i = 0; i < data.materials.size(); i++) delete bboxes[i]; + delete[] bboxes; + + isMother = true; +} + +MeshFrame::MeshFrame(const MeshFrame& frame) { + id = rand() % 1000000; + + bbox = frame.bbox; + + isMother = false; +} + +MeshFrame::~MeshFrame() { + if (isMother) { + delete bbox; + } +} + +void MeshFrame::print() const { + auto text = getPrint(nullptr); + printf("%s\n", text.c_str()); +} + +void MeshFrame::print(const char* name) const { + auto text = getPrint(name); + printf("%s\n", text.c_str()); +} + +std::string MeshFrame::getPrint(const char* name) const { + std::stringstream res; + if (name) { + res << name << "("; + } else { + res << "MeshFrame("; + } + res << std::fixed << std::setprecision(2); + + res << "Id: " << id << ", " << std::endl; + res << "BBox: " << bbox->getPrint() << ", " << std::endl; + res << ")"; + + return res.str(); +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/mesh/mesh_material.cpp b/engine/src/renderer/3d/mesh/mesh_material.cpp new file mode 100644 index 0000000..79d83ed --- /dev/null +++ b/engine/src/renderer/3d/mesh/mesh_material.cpp @@ -0,0 +1,123 @@ + +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include +#include +#include +#include +#include "renderer/3d/mesh/mesh_material.hpp" + +namespace Tyra { + +MeshMaterial::MeshMaterial(const MeshBuilderData& data, + const u32& materialIndex) { + TYRA_ASSERT(materialIndex < data.materials.size(), "Provided index \"", + materialIndex, "\" is out of range"); + + auto* material = data.materials[materialIndex]; + + TYRA_ASSERT(material->frames.size() > 0, + "Material must have at least one frame"); + + id = rand() % 1000000; + + if (data.lightMapEnabled) { + lightmapFlag = true; + TYRA_ASSERT(material->frames[0]->colors != nullptr, + "Colors faces are required"); + } else { + lightmapFlag = false; + } + + ambient.set(material->ambient); + + name = material->name; + TYRA_ASSERT(name.length() > 0, "MeshMaterial name cannot be empty"); + + u32 lastVertexCount = 0; + + for (u32 i = 0; i < material->frames.size(); i++) { + if (material->frames[i]->count > 0) { + frames.push_back(new MeshMaterialFrame(data, i, materialIndex)); + + if (i > 0) { + TYRA_ASSERT(frames[i]->count == lastVertexCount, + "Vertex count must be the same for all frames"); + } + + lastVertexCount = frames[i]->count; + } else { // We will not use it, lets clean it up + auto* frame = material->frames[i]; + if (frame->vertices != nullptr) delete[] frame->vertices; + if (frame->normals != nullptr) delete[] frame->normals; + if (frame->textureCoords != nullptr) delete[] frame->textureCoords; + if (frame->colors != nullptr) delete[] frame->colors; + } + } + + isMother = true; +} + +MeshMaterial::MeshMaterial(const MeshMaterial& mesh) { + id = rand() % 1000000; + + lightmapFlag = mesh.lightmapFlag; + name = mesh.name; + + ambient.set(128.0F, 128.0F, 128.0F, 128.0F); + + for (u32 i = 0; i < mesh.frames.size(); i++) { + frames.push_back(new MeshMaterialFrame(*mesh.frames[i])); + } + + isMother = false; +} + +MeshMaterial::~MeshMaterial() { + for (u32 i = 0; i < frames.size(); i++) { + delete frames[i]; + } +} + +const BBox& MeshMaterial::getBBox(const u32& frame) const { + return *frames[frame]->bbox; +} + +void MeshMaterial::print() const { + auto text = getPrint(nullptr); + printf("%s\n", text.c_str()); +} + +void MeshMaterial::print(const char* name) const { + auto text = getPrint(name); + printf("%s\n", text.c_str()); +} + +std::string MeshMaterial::getPrint(const char* name) const { + std::stringstream res; + if (name) { + res << name << "("; + } else { + res << "MeshMaterial("; + } + + res << std::endl; + res << std::fixed << std::setprecision(2); + res << "Id: " << id << ", " << std::endl; + res << "Name: " << name << ", " << std::endl; + res << "Frames count: " << frames.size() << ", " << std::endl; + res << "Single color?: " << static_cast(lightmapFlag) << std::endl; + res << ")"; + + return res.str(); +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/mesh/mesh_material_frame.cpp b/engine/src/renderer/3d/mesh/mesh_material_frame.cpp new file mode 100644 index 0000000..9ec0a8c --- /dev/null +++ b/engine/src/renderer/3d/mesh/mesh_material_frame.cpp @@ -0,0 +1,147 @@ + +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "debug/debug.hpp" +#include +#include +#include +#include "renderer/models/color.hpp" +#include "renderer/3d/mesh/mesh_material_frame.hpp" + +namespace Tyra { + +MeshMaterialFrame::MeshMaterialFrame(const MeshBuilderData& data, + const u32& frameIndex, + const u32& materialIndex) { + auto* material = data.materials[materialIndex]; + + TYRA_ASSERT(materialIndex < data.materials.size(), "Provided index \"", + materialIndex, "\" is out of range"); + + TYRA_ASSERT(frameIndex < material->frames.size(), "Provided index \"", + frameIndex, "\" is out of range"); + + id = rand() % 1000000; + + auto* frame = material->frames[frameIndex]; + + TYRA_ASSERT(frame->count > 0, "Vertex count must be greater than 0", + "Material name: ", material->name); + TYRA_ASSERT(frame->vertices != nullptr, "Vertex array can't be null"); + TYRA_ASSERT(!data.normalsEnabled || frame->normals != nullptr, + "Normal array can't be null"); + TYRA_ASSERT(!data.textureCoordsEnabled || frame->textureCoords != nullptr, + "Texture coordinate array can't be null"); + TYRA_ASSERT(!data.lightMapEnabled || frame->colors != nullptr, + "Color array can't be null"); + + bbox = new BBox(frame->vertices, frame->count); + + count = frame->count; + vertices = frame->vertices; + + if (data.normalsEnabled) { + normals = frame->normals; + } else { + if (frame->normals != nullptr) delete[] frame->normals; + + normals = nullptr; + } + + if (data.textureCoordsEnabled) { + textureCoords = frame->textureCoords; + } else { + if (frame->textureCoords != nullptr) delete[] frame->textureCoords; + + textureCoords = nullptr; + } + + if (data.lightMapEnabled) { + colors = frame->colors; + } else { + if (frame->colors != nullptr) delete[] frame->colors; + + colors = nullptr; + } + + isMother = true; +} + +MeshMaterialFrame::MeshMaterialFrame(const MeshMaterialFrame& frame) { + id = rand() % 1000000; + + count = frame.count; + + vertices = frame.vertices; + normals = frame.normals; + textureCoords = frame.textureCoords; + colors = frame.colors; + + bbox = frame.bbox; + + isMother = false; +} + +MeshMaterialFrame::~MeshMaterialFrame() { + if (isMother) { + delete[] vertices; + if (normals) delete[] normals; + if (textureCoords) delete[] textureCoords; + if (colors) delete[] colors; + delete bbox; + } +} + +std::string MeshMaterialFrame::getPrint(const char* name) const { + std::stringstream res; + if (name) { + res << name << "("; + } else { + res << "MeshMaterialFrame("; + } + res << std::fixed << std::setprecision(2); + + res << "Id: " << id << ", " << std::endl; + res << "Vertex count: " << count << ", " << std::endl; + res << "BBox: " << bbox->getPrint() << ", " << std::endl; + + res << "Vertices: "; + for (u32 i = 0; i < count; i++) { + res << vertices[i].getPrint() << ", " << std::endl; + } + + if (normals) { + res << "Normals: "; + for (u32 i = 0; i < count; i++) { + res << normals[i].getPrint() << ", " << std::endl; + } + } + + if (textureCoords) { + res << "TextureCoords: "; + for (u32 i = 0; i < count; i++) { + res << textureCoords[i].getPrint() << ", " << std::endl; + } + } + + if (colors) { + res << "Colors: "; + for (u32 i = 0; i < count; i++) { + res << colors[i].getPrint() << ", " << std::endl; + } + } + + res << ")"; + + return res.str(); +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/mesh/static/static_mesh.cpp b/engine/src/renderer/3d/mesh/static/static_mesh.cpp new file mode 100644 index 0000000..c465400 --- /dev/null +++ b/engine/src/renderer/3d/mesh/static/static_mesh.cpp @@ -0,0 +1,30 @@ + +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/mesh/static/static_mesh.hpp" + +namespace Tyra { + +StaticMesh::StaticMesh(const MeshBuilderData* data) : Mesh(data) { + if (data->materials[0]->frames.size() > 1) + TYRA_WARN("Static meshes should have only one frame, but ", + data->materials[0]->frames.size(), " frames were found"); + + frame = new MeshFrame(*data, 0); +} + +StaticMesh::StaticMesh(const StaticMesh& mesh) : Mesh(mesh) { + frame = new MeshFrame(*mesh.frame); +} + +StaticMesh::~StaticMesh() { delete frame; } + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/dynamic/core/bag/dynpip_bag.cpp b/engine/src/renderer/3d/pipeline/dynamic/core/bag/dynpip_bag.cpp new file mode 100644 index 0000000..53965f6 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/dynamic/core/bag/dynpip_bag.cpp @@ -0,0 +1,87 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/dynamic/core/bag/dynpip_bag.hpp" +#include +#include + +namespace Tyra { + +DynPipBag::DynPipBag() { + info = nullptr; + color = nullptr; + texture = nullptr; + lighting = nullptr; + verticesFrom = nullptr; + verticesTo = nullptr; +} + +DynPipBag::~DynPipBag() {} + +void DynPipBag::print() const { + auto text = getPrint(nullptr); + printf("%s\n", text.c_str()); +} + +void DynPipBag::print(const char* name) const { + auto text = getPrint(name); + printf("%s\n", text.c_str()); +} + +std::string DynPipBag::getPrint(const char* name) const { + std::stringstream res; + if (name) { + res << name << "("; + } else { + res << "DynPipBag("; + } + res << std::fixed << std::setprecision(4); + res << std::endl; + res << "Count: " << count << ", " << std::endl; + res << "Vertices from present: " << (verticesFrom != nullptr ? "Yes" : "No") + << ", " << std::endl; + res << "Vertices to present: " << (verticesTo != nullptr ? "Yes" : "No") + << ", " << std::endl; + res << "Info present: " << (info != nullptr ? "Yes" : "No") << ", " + << std::endl; + res << "Color present: " << (color != nullptr ? "Yes" : "No") << ", " + << std::endl; + res << "Texture present: " << (texture != nullptr ? "Yes" : "No") << ", " + << std::endl; + res << "Lighting present: " << (lighting != nullptr ? "Yes" : "No") << ", " + << std::endl; + res << "Model matrix: " << info->model->getPrint() << ", " << std::endl; + if (color->single) { + res << "Color single: " << color->single->getPrint() << ", " << std::endl; + } + if (texture) { + res << "Texture coords from present: " + << (texture->coordinatesFrom != nullptr ? "Yes" : "No") << ", " + << std::endl; + res << "Texture coords to present: " + << (texture->coordinatesTo != nullptr ? "Yes" : "No") << ", " + << std::endl; + res << "Texture: " << texture->texture->getPrint() << ", " << std::endl; + } + + if (lighting) { + res << "Lighting normals from present: " + << (lighting->normalsFrom ? "Yes" : "No") << ", " << std::endl; + res << "Lighting normals to present: " + << (lighting->normalsTo ? "Yes" : "No") << ", " << std::endl; + res << "Lighting matrix: " << lighting->lightMatrix->getPrint() << ", " + << std::endl; + } + res << ")"; + + return res.str(); +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/dynamic/core/bag/dynpip_color_bag.cpp b/engine/src/renderer/3d/pipeline/dynamic/core/bag/dynpip_color_bag.cpp new file mode 100644 index 0000000..c61d5e5 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/dynamic/core/bag/dynpip_color_bag.cpp @@ -0,0 +1,19 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/dynamic/core/bag/dynpip_color_bag.hpp" + +namespace Tyra { + +DynPipColorBag::DynPipColorBag() { single = nullptr; } + +DynPipColorBag::~DynPipColorBag() {} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/dynamic/core/bag/dynpip_lighting_bag.cpp b/engine/src/renderer/3d/pipeline/dynamic/core/bag/dynpip_lighting_bag.cpp new file mode 100644 index 0000000..4a0ca06 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/dynamic/core/bag/dynpip_lighting_bag.cpp @@ -0,0 +1,29 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/dynamic/core/bag/dynpip_lighting_bag.hpp" + +namespace Tyra { + +DynPipLightingBag::DynPipLightingBag() { + lightMatrix = nullptr; + normalsFrom = nullptr; + normalsTo = nullptr; + dirLights = nullptr; +} + +DynPipLightingBag::~DynPipLightingBag() {} + +void DynPipLightingBag::freeNormals() { + if (normalsFrom) delete[] normalsFrom; + if (normalsTo) delete[] normalsTo; +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/dynamic/core/bag/dynpip_texture_bag.cpp b/engine/src/renderer/3d/pipeline/dynamic/core/bag/dynpip_texture_bag.cpp new file mode 100644 index 0000000..566b0c2 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/dynamic/core/bag/dynpip_texture_bag.cpp @@ -0,0 +1,28 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/dynamic/core/bag/dynpip_texture_bag.hpp" + +namespace Tyra { + +DynPipTextureBag::DynPipTextureBag() { + coordinatesFrom = nullptr; + coordinatesTo = nullptr; + texture = nullptr; +} + +DynPipTextureBag::~DynPipTextureBag() {} + +void DynPipTextureBag::freeCoords() { + if (coordinatesFrom) delete[] coordinatesFrom; + if (coordinatesTo) delete[] coordinatesTo; +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/dynamic/core/dynpip_core.cpp b/engine/src/renderer/3d/pipeline/dynamic/core/dynpip_core.cpp new file mode 100644 index 0000000..05bfc02 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/dynamic/core/dynpip_core.cpp @@ -0,0 +1,142 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/dynamic/core/dynpip_core.hpp" +#include +#include +#include "thread/threading.hpp" + +namespace Tyra { + +DynPipCore::DynPipCore() { + setPrim(); + setLod(); +} + +DynPipCore::~DynPipCore() {} + +void DynPipCore::init(RendererCore* t_core) { + rendererCore = t_core; + qbufferRenderer.init(t_core, &repository, &prim, &lod); +} + +void DynPipCore::setPrim() { + prim.type = PRIM_TRIANGLE; + prim.shading = PRIM_SHADE_GOURAUD; + prim.mapping = DRAW_ENABLE; + prim.fogging = DRAW_DISABLE; + prim.blending = DRAW_ENABLE; + prim.antialiasing = DRAW_DISABLE; + prim.mapping_type = PRIM_MAP_ST; + prim.colorfix = PRIM_UNFIXED; +} + +void DynPipCore::setLod() { + lod.calculation = LOD_USE_K; + lod.max_level = 0; + lod.mag_filter = LOD_MAG_LINEAR; + lod.min_filter = LOD_MIN_LINEAR; + lod.mipmap_select = LOD_MIPMAP_REGISTER; + lod.l = 0; + lod.k = 0.0F; +} + +void DynPipCore::reinitVU1Programs() { qbufferRenderer.reinitVU1(); } + +u32 DynPipCore::getMaxVertCountByParams(const bool& isLightingEnabled, + const bool& isTextureEnabled) { + return repository.getProgramByParams(isLightingEnabled, isTextureEnabled) + ->getMaxVertCount(qbufferRenderer.getBufferSize()); +} + +void DynPipCore::sendObjectDataToVU1(DynPipBag* bag) { + RendererCoreTextureBuffers* texBuffers = nullptr; + if (bag->texture) { + auto temp = rendererCore->texture.useTexture(bag->texture->texture); + texBuffers = new RendererCoreTextureBuffers{temp.id, temp.core, temp.clut}; + } + + if (bag->info->transformationType == TyraMP) { + mvp = rendererCore->renderer3D.getProjection() * *bag->info->model; + } else { + mvp = rendererCore->renderer3D.getViewProj() * *bag->info->model; + } + + qbufferRenderer.sendObjectData(bag, &mvp, texBuffers); + + delete texBuffers; +} + +void DynPipCore::begin(PipelineInfoBag* bag) { + qbufferRenderer.clearLastProgramName(); + + prim.antialiasing = bag->antiAliasingEnabled; + prim.blending = bag->blendingEnabled; + prim.shading = bag->shadingType; + + if (bag->textureMappingType == TyraLinear) { + lod.mag_filter = LOD_MAG_LINEAR; + lod.min_filter = LOD_MIN_LINEAR; + } else { + lod.mag_filter = LOD_MAG_NEAREST; + lod.min_filter = LOD_MIN_NEAREST; + } +} + +void DynPipCore::render(DynPipBag** bags, const u32& count) { + if (count <= 0) return; + + TYRA_ASSERT( + bags[0]->verticesFrom != nullptr && bags[0]->verticesTo != nullptr, + "Vertices are required in 3D render bag!"); + TYRA_ASSERT(bags[0]->info != nullptr, + "Info bag is required in 3D render bag!"); + TYRA_ASSERT(bags[0]->info->model != nullptr, + "Info bag's model pointer is empty!"); + TYRA_ASSERT(bags[0]->color != nullptr, + "Color bag is required in 3D render bag!"); + TYRA_ASSERT(bags[0]->color->single, "Color is required in 3D render bag!"); + TYRA_ASSERT( + !bags[0]->lighting || + (bags[0]->lighting->lightMatrix && bags[0]->lighting->normalsFrom && + bags[0]->lighting->normalsTo && bags[0]->lighting->dirLights), + "If you want lighting, please provide light matrix normals and dir " + "lights!"); + TYRA_ASSERT(!bags[0]->texture || (bags[0]->texture->texture && + bags[0]->texture->coordinatesFrom && + bags[0]->texture->coordinatesTo), + "If you want texture, please provide texture and coordinates!"); + + if (bags[0]->info->frustumCulling == PipelineInfoBagFrustumCulling_None) { + qbufferRenderer.render(bags, count); + return; + } + + DynPipBag** bagsToRender = new DynPipBag*[count]; + u32 inserted = 0; + + for (u32 i = 0; i < count; i++) { + auto* bag = bags[i]; + + CoreBBox bbox(bag->verticesTo, bag->count); + if (bbox.frustumCheck(rendererCore->renderer3D.frustumPlanes.getAll(), + *bag->info->model) == + CoreBBoxFrustum::OUTSIDE_FRUSTUM) { + continue; + } + + bagsToRender[inserted++] = bag; + } + + qbufferRenderer.render(bagsToRender, inserted); + delete[] bagsToRender; +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/dynamic/core/dynpip_programs_repository.cpp b/engine/src/renderer/3d/pipeline/dynamic/core/dynpip_programs_repository.cpp new file mode 100644 index 0000000..f421a66 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/dynamic/core/dynpip_programs_repository.cpp @@ -0,0 +1,54 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/dynamic/core/dynpip_programs_repository.hpp" + +namespace Tyra { + +DynPipProgramsRepository::DynPipProgramsRepository() {} + +DynPipProgramsRepository::~DynPipProgramsRepository() {} + +DynPipVU1Program* DynPipProgramsRepository::getProgramByBag( + const DynPipBag* bag) { + return getProgramByParams(bag->lighting, bag->texture); +} + +DynPipVU1Program* DynPipProgramsRepository::getProgramByParams( + const bool& isLightingEnabled, const bool& isTextureEnabled) { + if (isLightingEnabled && isTextureEnabled) + return &textureDirLights; + else if (isLightingEnabled) + return &dirLights; + else if (isTextureEnabled) + return &textureColor; + else + return &color; +} + +DynPipVU1Program* DynPipProgramsRepository::getProgram( + const DynPipProgramName& name) { + switch (name) { + case DynPipProgramName::DynPipColor: + return &color; + case DynPipProgramName::DynPipDirLights: + return &dirLights; + case DynPipProgramName::DynPipTextureDirLights: + return &textureDirLights; + case DynPipProgramName::DynPipTextureColor: + return &textureColor; + + default: + TYRA_TRAP("Unknown VU1 program name"); + return &color; + } +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/dynamic/core/dynpip_renderer.cpp b/engine/src/renderer/3d/pipeline/dynamic/core/dynpip_renderer.cpp new file mode 100644 index 0000000..17c1bed --- /dev/null +++ b/engine/src/renderer/3d/pipeline/dynamic/core/dynpip_renderer.cpp @@ -0,0 +1,223 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/dynamic/core/dynpip_renderer.hpp" +#include "renderer/3d/pipeline/dynamic/core/programs/dynpip_vu1_shared_defines.h" +#include +#include +#include "packet2/packet2_tyra_utils.hpp" + +namespace Tyra { + +DynPipRenderer::DynPipRenderer() { + context = 0; + bufferSize = 0; + lastProgramName = DynPipProgramName::DynPipUndefinedProgram; + + programsPacket = nullptr; +} + +DynPipRenderer::~DynPipRenderer() { + if (programsPacket) packet2_free(programsPacket); +} + +void DynPipRenderer::allocateOnUse(const u32& t_packetSize) { + staticDataPacket = packet2_create(3, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); + objectDataPacket = packet2_create(20, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); + + packetSize = t_packetSize; + + for (u16 i = 0; i < 2; i++) + packets[i] = + packet2_create(t_packetSize, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); + + sendStaticData(); +} + +void DynPipRenderer::deallocateOnUse() { + packet2_free(staticDataPacket); + packet2_free(objectDataPacket); + + for (u16 i = 0; i < 2; i++) packet2_free(packets[i]); +} + +void DynPipRenderer::init(RendererCore* t_core, + DynPipProgramsRepository* t_programRepo, + prim_t* t_prim, lod_t* t_lod) { + path1 = t_core->getPath1(); + prim = t_prim; + lod = t_lod; + rendererCore = t_core; + programsRepo = t_programRepo; + + dma_channel_initialize(DMA_CHANNEL_VIF1, nullptr, 0); + + setProgramsCache(); + + reinitVU1(); + + TYRA_LOG("DynPipRenderer initialized"); +} + +void DynPipRenderer::reinitVU1() { + uploadPrograms(); + setDoubleBuffer(); +} + +void DynPipRenderer::setProgramsCache() { + VU1Program** programs = new VU1Program*[4]; + programs[0] = programsRepo->getProgram(DynPipProgramName::DynPipColor); + programs[1] = programsRepo->getProgram(DynPipProgramName::DynPipDirLights); + programs[2] = programsRepo->getProgram(DynPipProgramName::DynPipTextureColor); + programs[3] = + programsRepo->getProgram(DynPipProgramName::DynPipTextureDirLights); + programsPacket = path1->createProgramsCache(programs, 4, 0); + delete[] programs; +} + +void DynPipRenderer::sendStaticData() const { + packet2_reset(staticDataPacket, false); + packet2_utils_vu_open_unpack(staticDataPacket, VU1_SET_GIFTAG_ADDR, false); + { packet2_utils_gif_add_set(staticDataPacket, 1); } + packet2_utils_vu_close_unpack(staticDataPacket); + + packet2_utils_vu_add_end_tag(staticDataPacket); + dma_channel_wait(DMA_CHANNEL_VIF1, 0); + dma_channel_send_packet2(staticDataPacket, DMA_CHANNEL_VIF1, true); +} + +void DynPipRenderer::sendObjectData( + DynPipBag* bag, M4x4* mvp, RendererCoreTextureBuffers* texBuffers) const { + packet2_reset(objectDataPacket, false); + packet2_utils_vu_add_unpack_data(objectDataPacket, VU1_MVP_MATRIX_ADDR, + mvp->data, 4, false); + + if (bag->lighting) { + packet2_utils_vu_add_unpack_data(objectDataPacket, VU1_LIGHTS_MATRIX_ADDR, + bag->lighting->lightMatrix, 3, false); + + packet2_utils_vu_add_unpack_data( + objectDataPacket, VU1_LIGHTS_DIRS_ADDR, + bag->lighting->dirLights->getLightDirections(), 3, false); + + packet2_utils_vu_add_unpack_data(objectDataPacket, VU1_LIGHTS_COLORS_ADDR, + bag->lighting->dirLights->getLightColors(), + 4, false); + } + + u8 singleColorEnabled = bag->color->single != nullptr; + + if (singleColorEnabled) // Color is placed in 4th slot of + // VU1_LIGHTS_MATRIX_ADDR + Packet2TyraUtils::addUnpackData(objectDataPacket, VU1_SINGLE_COLOR_ADDR, + bag->color->single->rgba, 1, false); + + packet2_utils_vu_open_unpack(objectDataPacket, VU1_OPTIONS_ADDR, false); + { + packet2_add_u32(objectDataPacket, + singleColorEnabled); // Single color enabled. + packet2_add_float(objectDataPacket, + bag->interpolation); // Interpolation value + packet2_add_u32(objectDataPacket, 0); // not used, padding + packet2_add_u32(objectDataPacket, 0); // not used, padding + + packet2_utils_gs_add_lod(objectDataPacket, lod); + + if (bag->info->zTestType == PipelineZTest_AllPass) { + packet2_add_2x_s64(objectDataPacket, + GS_SET_TEST(0, 0, 0, 0, 0, 0, 0, ZTEST_METHOD_ALLPASS), + GS_REG_TEST); + } else { + packet2_add_2x_s64( + objectDataPacket, + GS_SET_TEST(DRAW_ENABLE, ATEST_METHOD_NOTEQUAL, 0x00, + ATEST_KEEP_FRAMEBUFFER, DRAW_DISABLE, DRAW_DISABLE, + DRAW_ENABLE, rendererCore->gs.zBuffer.method), + GS_REG_TEST); + } + + if (texBuffers != nullptr) { + rendererCore->texture.updateClutBuffer(texBuffers->clut); + + packet2_utils_gs_add_texbuff_clut(objectDataPacket, texBuffers->core, + &rendererCore->texture.clut); + } + } + packet2_utils_vu_close_unpack(objectDataPacket); + + packet2_utils_vu_add_end_tag(objectDataPacket); + dma_channel_wait(DMA_CHANNEL_VIF1, 0); + dma_channel_send_packet2(objectDataPacket, DMA_CHANNEL_VIF1, true); +} + +void DynPipRenderer::render(DynPipBag** bags, const u32& count) { + if (count <= 0) return; + + auto* program = programsRepo->getProgramByBag(bags[0]); + addBufferDataToPacket(program, bags, count); + sendPacket(); +} + +void DynPipRenderer::addBufferDataToPacket(DynPipVU1Program* program, + DynPipBag** bags, const u32& count) { + currentPacket = packets[context]; + packet2_reset(currentPacket, false); + + for (u32 i = 0; i < count; i++) { + if (bags[i]->count <= 0) continue; + + program->addBufferDataToPacket(currentPacket, bags[i], prim); + + if (lastProgramName != program->getName()) { + packet2_utils_vu_add_start_program(currentPacket, + program->getDestinationAddress()); + lastProgramName = program->getName(); + } else { + packet2_utils_vu_add_continue_program(currentPacket); + } + } + + packet2_utils_vu_add_end_tag(currentPacket); +} + +void DynPipRenderer::sendPacket() { + dma_channel_wait(DMA_CHANNEL_VIF1, 0); + // dma_wait_fast(); // This have no impact on performance + dma_channel_send_packet2(currentPacket, DMA_CHANNEL_VIF1, true); + + TYRA_ASSERT(packet2_get_qw_count(currentPacket) <= packetSize, + "Packet is too big. Internal error."); + + // Switch packet, so we can proceed during DMA transfer + context = !context; +} + +void DynPipRenderer::clearLastProgramName() { + lastProgramName = DynPipUndefinedProgram; +} + +void DynPipRenderer::uploadPrograms() { + dma_channel_wait(DMA_CHANNEL_VIF1, 0); + dma_channel_send_packet2(programsPacket, DMA_CHANNEL_VIF1, true); + dma_channel_wait(DMA_CHANNEL_VIF1, 0); +} + +void DynPipRenderer::setDoubleBuffer() { + u16 startingAddr = VU1_DYNPIP_LAST_ITEM_ADDR + 1; + const u16 bufferMaxSize = 1000; + bufferSize = (bufferMaxSize - startingAddr) / 2; + + path1->setDoubleBuffer(startingAddr, bufferSize); + + bufferSize -= 1; // Because we don't want to upload anything from first + // buffer, to first addr of second buffer +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/dynamic/core/dynpip_vu1_program.cpp b/engine/src/renderer/3d/pipeline/dynamic/core/dynpip_vu1_program.cpp new file mode 100644 index 0000000..a368a87 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/dynamic/core/dynpip_vu1_program.cpp @@ -0,0 +1,78 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/dynamic/core/dynpip_vu1_program.hpp" + +namespace Tyra { + +DynPipVU1Program::DynPipVU1Program(const DynPipProgramName& t_name, + u32* t_start, u32* t_end, + const u32& t_reglist, + const u8& t_reglistCount, + const u8& t_elementsPerVertex) + : VU1Program(t_start, t_end), + name(t_name), + reglistCount(t_reglistCount), + elementsPerVertex(t_elementsPerVertex), + reglist(t_reglist) { + packetSize = packet2_utils_get_packet_size_for_program(start, end); + programSize = calculateProgramSize(); +} + +DynPipVU1Program::~DynPipVU1Program() {} + +const DynPipProgramName& DynPipVU1Program::getName() const { return name; } + +u32& DynPipVU1Program::getReglist() { return reglist; } + +void DynPipVU1Program::addBufferDataToPacket(packet2_t* packet, DynPipBag* bag, + prim_t* prim) { + addStandardBufferDataToPacket(packet, bag, prim); + addProgramQBufferDataToPacket(packet, bag); +} + +void DynPipVU1Program::addStandardBufferDataToPacket(packet2_t* packet, + DynPipBag* bag, + prim_t* prim) { + if (bag->texture) + prim->mapping = 1; + else + prim->mapping = 0; + + packet2_utils_vu_open_unpack(packet, 0, true); + { + packet2_add_float(packet, 2048.0F); // scale + packet2_add_float(packet, 2048.0F); // scale + packet2_add_float(packet, static_cast(0xFFFFFF) / 32.0F); // scale + packet2_add_u32(packet, bag->count); // vertex count + + packet2_utils_gs_add_prim_giftag(packet, prim, bag->count, reglist, + reglistCount, 0); + } + packet2_utils_vu_close_unpack(packet); +} + +u16 DynPipVU1Program::getMaxVertCount(const u16& bufferSize) const { + u16 res = bufferSize - 7; // 7 because of -> StoreTyraGifTags{} + res /= (elementsPerVertex + reglistCount); + + // Buffer size = VU1 double buffer size (xtop) + // QBufferSize = res (it is placed inside VU1) + + // Animation = 2 verts for final vert + res = res / 2; + + // Triangle = 3 verts + res = res / 3; + res = res * 3; + return res; +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/dynamic/core/programs/dynpip_c_vu1.vclpp b/engine/src/renderer/3d/pipeline/dynamic/core/programs/dynpip_c_vu1.vclpp new file mode 100644 index 0000000..3ee07f8 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/dynamic/core/programs/dynpip_c_vu1.vclpp @@ -0,0 +1,130 @@ +; _____ ____ ___ +; | \/ ____| |___| +; | | | \ | | +;--------------------------------------------------------------- +; Copyright 2022, tyra - https://github.com/h4570/tyra +; Licensed under Apache License 2.0 +; Sandro Sobczyński +; +;--------------------------------------------------------------- +; Triangle list +; Cull = Standard PS2 way. clipw polys are culled. +; Animation +; Color +;--------------------------------------------------------------- + +.syntax new +.name DynPipVU1_C +.vu +.init_vf_all +.init_vi_all + +#include "src/renderer/3d/pipeline/shared/vcl_sml.i" +#include "src/renderer/3d/pipeline/shared/tyra_macros.i" +#include "inc/renderer/3d/pipeline/dynamic/core/programs/dynpip_vu1_shared_defines.h" + +#define RGBA_STORE_OFFSET 0 +#define XYZ2_STORE_OFFSET 1 + +--enter +--endenter + +#vuprog DynPipVU1C + + ResetClipFlags{ } + LoadTyraStaticData{ gifSetTag } + MatrixLoad{ mvp, VU1_MVP_MATRIX_ADDR, vi00 } + LoadTyraSingleColor{ singleColor, singleColorEnabled, VU1_SINGLE_COLOR_ADDR, VU1_OPTIONS_ADDR } + LoadTyraTags{ lodGifTag, testsTag, VU1_LOD_ADDR, VU1_Z_TESTS_ADDR } + FixColor{ singleColor } + +begin: + xtop buffer + LoadTyraPrimTag{ primTag, buffer } + + ilw.w vertexCount, 0(buffer) + iaddiu vertexDataFrom, buffer, VU1_DYNPIP_VERT_DATA_ADDR + + iadd kickAddress, vertexDataFrom, vertexCount + iadd destAddress, kickAddress, vertexCount + iadd kickAddress, kickAddress, vertexCount + + StoreTyraGifTags{ gifSetTag, lodGifTag, primTag, testsTag, destAddress } + LoadTyraLerpValue{ interp, VU1_OPTIONS_ADDR } + LoadTyraScaleValue{ scale, buffer } + + ;--- Loop + iadd vertexCounter, buffer, vertexCount +vertexLoop: + + iadd vertexDataTo, vertexDataFrom, vertexCount + + ;--- Vertex 1 - from-to -> lerp + lq vertex1From, (vertexDataFrom) + lq vertex1To, (vertexDataTo) + Lerp{ vertex1, vertex1From, vertex1To, interp } + + ;--- Vertex 1 - Calculate + MatrixMultiplyVertex{ vertex1, mvp, vertex1 } + PerformClipCheck{ vertex1, destAddress, XYZ2_STORE_OFFSET } + VertexPersCorr{ vertex1, vertex1 } + ScaleVertexToGSFormat{ scale, vertex1 } + + ;--- Vertex 1 - Store + sq singleColor, RGBA_STORE_OFFSET(destAddress) + sq.xyz vertex1, XYZ2_STORE_OFFSET(destAddress) + + ; --------------------------------------- + + ;--- Vertex 2 - from-to -> lerp + lq vertex2From, 1(vertexDataFrom) + lq vertex2To, 1(vertexDataTo) + Lerp{ vertex2, vertex2From, vertex2To, interp } + + ;--- Vertex 2 - Calculate + MatrixMultiplyVertex{ vertex2, mvp, vertex2 } + PerformClipCheck{ vertex2, destAddress, XYZ2_STORE_OFFSET+2 } + VertexPersCorr{ vertex2, vertex2 } + ScaleVertexToGSFormat{ scale, vertex2 } + + ;--- Vertex 2 - Store + sq singleColor, RGBA_STORE_OFFSET+2(destAddress) + sq.xyz vertex2, XYZ2_STORE_OFFSET+2(destAddress) + + ; --------------------------------------- + + ;--- Vertex 3 - from-to -> lerp + lq vertex3From, 2(vertexDataFrom) + lq vertex3To, 2(vertexDataTo) + Lerp{ vertex3, vertex3From, vertex3To, interp } + + ;--- Vertex 3 - Calculate + MatrixMultiplyVertex{ vertex3, mvp, vertex3 } + PerformClipCheck{ vertex3, destAddress, XYZ2_STORE_OFFSET+4 } + VertexPersCorr{ vertex3, vertex3 } + ScaleVertexToGSFormat{ scale, vertex3 } + + ;--- Vertex 3 - Store + sq singleColor, RGBA_STORE_OFFSET+4(destAddress) + sq.xyz vertex3, XYZ2_STORE_OFFSET+4(destAddress) + + ;------------------------------- + + iaddiu vertexDataFrom, vertexDataFrom, 3 + iaddiu destAddress, destAddress, 6 + + ;--- Fix loop + iaddi vertexCounter, vertexCounter, -3 ; decrement the loop counter + ibne vertexCounter, buffer, vertexLoop ; and repeat if needed + + xgkick kickAddress ; dispatch to the GS rasterizer. + +--barrier ; Why the hell I must add barrier AFTER XGKICK? VCL does not adds E bit without it... +--cont + + b begin + +#endvuprog + +--exit +--endexit diff --git a/engine/src/renderer/3d/pipeline/dynamic/core/programs/dynpip_c_vu1_program.cpp b/engine/src/renderer/3d/pipeline/dynamic/core/programs/dynpip_c_vu1_program.cpp new file mode 100644 index 0000000..c17d62e --- /dev/null +++ b/engine/src/renderer/3d/pipeline/dynamic/core/programs/dynpip_c_vu1_program.cpp @@ -0,0 +1,42 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "debug/debug.hpp" +#include "renderer/3d/pipeline/dynamic/core/programs/dynpip_c_vu1_program.hpp" + +extern u32 DynPipVU1_C_CodeStart __attribute__((section(".vudata"))); +extern u32 DynPipVU1_C_CodeEnd __attribute__((section(".vudata"))); + +namespace Tyra { + +DynPipCVU1Program::DynPipCVU1Program() + : DynPipVU1Program( + DynPipColor, &DynPipVU1_C_CodeStart, &DynPipVU1_C_CodeEnd, + ((u64)GIF_REG_RGBAQ) << 0 | ((u64)GIF_REG_XYZ2) << 4, 2, 1) {} + +DynPipCVU1Program::~DynPipCVU1Program() {} + +std::string DynPipCVU1Program::getStringName() const { + return std::string("DynPip - C"); +} + +void DynPipCVU1Program::addProgramQBufferDataToPacket(packet2_t* packet, + DynPipBag* bag) const { + u32 addr = VU1_DYNPIP_VERT_DATA_ADDR; + + // Add vertices + packet2_utils_vu_add_unpack_data(packet, addr, bag->verticesFrom, bag->count, + true); + addr += bag->count; + packet2_utils_vu_add_unpack_data(packet, addr, bag->verticesTo, bag->count, + true); +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/dynamic/core/programs/dynpip_d_vu1.vclpp b/engine/src/renderer/3d/pipeline/dynamic/core/programs/dynpip_d_vu1.vclpp new file mode 100644 index 0000000..71ed079 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/dynamic/core/programs/dynpip_d_vu1.vclpp @@ -0,0 +1,154 @@ +; _____ ____ ___ +; | \/ ____| |___| +; | | | \ | | +;--------------------------------------------------------------- +; Copyright 2022, tyra - https://github.com/h4570/tyra +; Licensed under Apache License 2.0 +; Sandro Sobczyński +; +;--------------------------------------------------------------- +; Triangle list +; Cull = Standard PS2 way. clipw polys are culled. +; Animation +; Directional lights +;--------------------------------------------------------------- + +.syntax new +.name DynPipVU1_D +.vu +.init_vf_all +.init_vi_all + +#include "src/renderer/3d/pipeline/shared/vcl_sml.i" +#include "src/renderer/3d/pipeline/shared/tyra_macros.i" +#include "inc/renderer/3d/pipeline/dynamic/core/programs/dynpip_vu1_shared_defines.h" + +#define RGBA_STORE_OFFSET 0 +#define XYZ2_STORE_OFFSET 1 + +--enter +--endenter + +#vuprog DynPipVU1D + + ResetClipFlags{ } + LoadTyraStaticData{ gifSetTag } + MatrixLoad{ mvp, VU1_MVP_MATRIX_ADDR, vi00 } + LoadTyraTags{ lodGifTag, testsTag, VU1_LOD_ADDR, VU1_Z_TESTS_ADDR } + +begin: + xtop buffer + LoadTyraPrimTag{ primTag, buffer } + + ilw.w vertexCount, 0(buffer) + iaddiu vertexDataFrom, buffer, VU1_DYNPIP_VERT_DATA_ADDR + + iadd normalDataFrom, vertexDataFrom, vertexCount + iadd normalDataFrom, normalDataFrom, vertexCount + + iadd kickAddress, normalDataFrom, vertexCount + iadd destAddress, kickAddress, vertexCount + iadd kickAddress, kickAddress, vertexCount + + StoreTyraGifTags{ gifSetTag, lodGifTag, primTag, testsTag, destAddress } + LoadTyraLerpValue{ interp, VU1_OPTIONS_ADDR } + LoadTyraScaleValue{ scale, buffer } + + ;--- Loop + iadd vertexCounter, buffer, vertexCount +vertexLoop: + + iadd vertexDataTo, vertexDataFrom, vertexCount + iadd normalDataTo, normalDataFrom, vertexCount + + ;--- Vertex 1 - from-to -> lerp + lq vertex1From, (vertexDataFrom) + lq vertex1To, (vertexDataTo) + Lerp{ vertex1, vertex1From, vertex1To, interp } + + lq.xyz normal1From, (normalDataFrom) + lq.xyz normal1To, (normalDataTo) + LerpXYZ{ normal1, normal1From, normal1To, interp } + + ;--- Vertex 1 - Calculate + MatrixMultiplyVertex{ vertex1, mvp, vertex1 } + PerformClipCheck{ vertex1, destAddress, XYZ2_STORE_OFFSET } + VertexPersCorr{ vertex1, vertex1 } + ScaleVertexToGSFormat{ scale, vertex1 } + LoadTyraDirectionalLights{ lightMatrix, lightDirections, lightColors, ambientColor, VU1_LIGHTS_DIRS_ADDR, VU1_LIGHTS_COLORS_ADDR, VU1_LIGHTS_MATRIX_ADDR } + CalculateTyraDirectionalLights{ outputColor1, normal1, lightDirections, lightColors, lightMatrix, ambientColor } + FixColor{ outputColor1 } + + ;--- Vertex 1 - Store + sq outputColor1, RGBA_STORE_OFFSET(destAddress) + sq.xyz vertex1, XYZ2_STORE_OFFSET(destAddress) + + ; --------------------------------------- + + ;--- Vertex 2 - from-to -> lerp + lq vertex2From, 1(vertexDataFrom) + lq vertex2To, 1(vertexDataTo) + Lerp{ vertex2, vertex2From, vertex2To, interp } + + lq.xyz normal2From, 1(normalDataFrom) + lq.xyz normal2To, 1(normalDataTo) + LerpXYZ{ normal2, normal2From, normal2To, interp } + + ;--- Vertex 2 - Calculate + MatrixMultiplyVertex{ vertex2, mvp, vertex2 } + PerformClipCheck{ vertex2, destAddress, XYZ2_STORE_OFFSET } + VertexPersCorr{ vertex2, vertex2 } + ScaleVertexToGSFormat{ scale, vertex2 } + LoadTyraDirectionalLights{ lightMatrix, lightDirections, lightColors, ambientColor, VU1_LIGHTS_DIRS_ADDR, VU1_LIGHTS_COLORS_ADDR, VU1_LIGHTS_MATRIX_ADDR } + CalculateTyraDirectionalLights{ outputColor2, normal2, lightDirections, lightColors, lightMatrix, ambientColor } + FixColor{ outputColor2 } + + ;--- Vertex 2 - Store + sq outputColor2, RGBA_STORE_OFFSET+2(destAddress) + sq.xyz vertex2, XYZ2_STORE_OFFSET+2(destAddress) + + ; --------------------------------------- + + ;--- Vertex 3 - from-to -> lerp + lq vertex3From, 2(vertexDataFrom) + lq vertex3To, 2(vertexDataTo) + Lerp{ vertex3, vertex3From, vertex3To, interp } + + lq.xyz normal3From, 2(normalDataFrom) + lq.xyz normal3To, 2(normalDataTo) + LerpXYZ{ normal3, normal3From, normal3To, interp } + + ;--- Vertex 3 - Calculate + MatrixMultiplyVertex{ vertex3, mvp, vertex3 } + PerformClipCheck{ vertex3, destAddress, XYZ2_STORE_OFFSET } + VertexPersCorr{ vertex3, vertex3 } + ScaleVertexToGSFormat{ scale, vertex3 } + LoadTyraDirectionalLights{ lightMatrix, lightDirections, lightColors, ambientColor, VU1_LIGHTS_DIRS_ADDR, VU1_LIGHTS_COLORS_ADDR, VU1_LIGHTS_MATRIX_ADDR } + CalculateTyraDirectionalLights{ outputColor3, normal3, lightDirections, lightColors, lightMatrix, ambientColor } + FixColor{ outputColor3 } + + ;--- Vertex 3 - Store + sq outputColor3, RGBA_STORE_OFFSET+4(destAddress) + sq.xyz vertex3, XYZ2_STORE_OFFSET+4(destAddress) + + ;------------------------------- + + iaddiu vertexDataFrom, vertexDataFrom, 3 + iaddiu normalDataFrom, normalDataFrom, 3 + iaddiu destAddress, destAddress, 6 + + ;--- Fix loop + iaddi vertexCounter, vertexCounter, -3 ; decrement the loop counter + ibne vertexCounter, buffer, vertexLoop ; and repeat if needed + + xgkick kickAddress ; dispatch to the GS rasterizer. + +--barrier ; Why the hell I must add barrier AFTER XGKICK? VCL does not adds E bit without it... +--cont + + b begin + +#endvuprog + +--exit +--endexit diff --git a/engine/src/renderer/3d/pipeline/dynamic/core/programs/dynpip_d_vu1_program.cpp b/engine/src/renderer/3d/pipeline/dynamic/core/programs/dynpip_d_vu1_program.cpp new file mode 100644 index 0000000..da94b7f --- /dev/null +++ b/engine/src/renderer/3d/pipeline/dynamic/core/programs/dynpip_d_vu1_program.cpp @@ -0,0 +1,53 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "debug/debug.hpp" +#include "renderer/3d/pipeline/dynamic/core/programs/dynpip_d_vu1_program.hpp" + +extern u32 DynPipVU1_D_CodeStart __attribute__((section(".vudata"))); +extern u32 DynPipVU1_D_CodeEnd __attribute__((section(".vudata"))); + +namespace Tyra { + +DynPipDVU1Program::DynPipDVU1Program() + : DynPipVU1Program( + DynPipDirLights, &DynPipVU1_D_CodeStart, &DynPipVU1_D_CodeEnd, + ((u64)GIF_REG_RGBAQ) << 0 | ((u64)GIF_REG_XYZ2) << 4, 2, 2) {} + +DynPipDVU1Program::~DynPipDVU1Program() {} + +std::string DynPipDVU1Program::getStringName() const { + return std::string("DynPip - D"); +} + +void DynPipDVU1Program::addProgramQBufferDataToPacket(packet2_t* packet, + DynPipBag* bag) const { + u32 addr = VU1_DYNPIP_VERT_DATA_ADDR; + + // Add vertices + packet2_utils_vu_add_unpack_data(packet, addr, bag->verticesFrom, bag->count, + true); + addr += bag->count; + packet2_utils_vu_add_unpack_data(packet, addr, bag->verticesTo, bag->count, + true); + addr += bag->count; + + if (bag->lighting) { + // Add normal + packet2_utils_vu_add_unpack_data(packet, addr, bag->lighting->normalsFrom, + bag->count, true); + addr += bag->count; + packet2_utils_vu_add_unpack_data(packet, addr, bag->lighting->normalsTo, + bag->count, true); + addr += bag->count; + } +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/dynamic/core/programs/dynpip_tc_vu1.vclpp b/engine/src/renderer/3d/pipeline/dynamic/core/programs/dynpip_tc_vu1.vclpp new file mode 100644 index 0000000..6da773f --- /dev/null +++ b/engine/src/renderer/3d/pipeline/dynamic/core/programs/dynpip_tc_vu1.vclpp @@ -0,0 +1,154 @@ +; _____ ____ ___ +; | \/ ____| |___| +; | | | \ | | +;--------------------------------------------------------------- +; Copyright 2022, tyra - https://github.com/h4570/tyra +; Licensed under Apache License 2.0 +; Sandro Sobczyński +; +;--------------------------------------------------------------- +; Triangle list +; Cull = Standard PS2 way. clipw polys are culled. +; Animation +; Lighting, texture, color +;--------------------------------------------------------------- + +.syntax new +.name DynPipVU1_TC +.vu +.init_vf_all +.init_vi_all + +#include "src/renderer/3d/pipeline/shared/vcl_sml.i" +#include "src/renderer/3d/pipeline/shared/tyra_macros.i" +#include "inc/renderer/3d/pipeline/dynamic/core/programs/dynpip_vu1_shared_defines.h" + +#define STQ_STORE_OFFSET 0 +#define RGBA_STORE_OFFSET 1 +#define XYZ2_STORE_OFFSET 2 + +--enter +--endenter + +#vuprog DynPipVU1TC + + ResetClipFlags{ } + LoadTyraStaticData{ gifSetTag } + MatrixLoad{ mvp, VU1_MVP_MATRIX_ADDR, vi00 } + LoadTyraSingleColor{ singleColor, singleColorEnabled, VU1_SINGLE_COLOR_ADDR, VU1_OPTIONS_ADDR } + LoadTyraTagsTexture{ lodGifTag, testsTag, texBufferClutGifTag, VU1_LOD_ADDR, VU1_Z_TESTS_ADDR, VU1_CLUT_ADDR } + FixColor{ singleColor } + +begin: + xtop buffer + LoadTyraPrimTag{ primTag, buffer } + + ilw.w vertexCount, 0(buffer) + iaddiu vertexDataFrom, buffer, VU1_DYNPIP_VERT_DATA_ADDR + + iadd stqDataFrom, vertexDataFrom, vertexCount + iadd stqDataFrom, stqDataFrom, vertexCount + + iadd kickAddress, stqDataFrom, vertexCount + iadd destAddress, kickAddress, vertexCount + iadd kickAddress, kickAddress, vertexCount + + StoreTyraGifTagsTexture{ gifSetTag, lodGifTag, texBufferClutGifTag, primTag, testsTag, destAddress } + LoadTyraLerpValue{ interp, VU1_OPTIONS_ADDR } + LoadTyraScaleValue{ scale, buffer } + + ;--- Loop + iadd vertexCounter, buffer, vertexCount +vertexLoop: + + iadd vertexDataTo, vertexDataFrom, vertexCount + iadd stqDataTo, stqDataFrom, vertexCount + + ;--- Vertex 1 - from-to -> lerp + lq vertex1From, (vertexDataFrom) + lq vertex1To, (vertexDataTo) + Lerp{ vertex1, vertex1From, vertex1To, interp } + + lq stq1From, (stqDataFrom) + lq stq1To, (stqDataTo) + Lerp{ stq1, stq1From, stq1To, interp } + + ;--- Vertex 1 - Calculate + MatrixMultiplyVertex{ vertex1, mvp, vertex1 } + PerformClipCheck{ vertex1, destAddress, XYZ2_STORE_OFFSET } + VertexPersCorr{ vertex1, vertex1 } + ScaleVertexToGSFormat{ scale, vertex1 } + PerformTexturePerspectiveCorrection{ outputStq1, stq1 } + + ;--- Vertex 1 - Store + sq outputStq1, STQ_STORE_OFFSET(destAddress) + sq singleColor, RGBA_STORE_OFFSET(destAddress) + sq.xyz vertex1, XYZ2_STORE_OFFSET(destAddress) + + ; --------------------------------------- + + ;--- Vertex 2 - from-to -> lerp + lq vertex2From, 1(vertexDataFrom) + lq vertex2To, 1(vertexDataTo) + Lerp{ vertex2, vertex2From, vertex2To, interp } + + lq stq2From, 1(stqDataFrom) + lq stq2To, 1(stqDataTo) + Lerp{ stq2, stq2From, stq2To, interp } + + ;--- Vertex 2 - Calculate + MatrixMultiplyVertex{ vertex2, mvp, vertex2 } + PerformClipCheck{ vertex2, destAddress, XYZ2_STORE_OFFSET+3 } + VertexPersCorr{ vertex2, vertex2 } + ScaleVertexToGSFormat{ scale, vertex2 } + PerformTexturePerspectiveCorrection{ outputStq2, stq2 } + + ;--- Vertex 2 - Store + sq outputStq2, STQ_STORE_OFFSET+3(destAddress) + sq singleColor, RGBA_STORE_OFFSET+3(destAddress) + sq.xyz vertex2, XYZ2_STORE_OFFSET+3(destAddress) + + ; --------------------------------------- + + ;--- Vertex 3 - from-to -> lerp + lq vertex3From, 2(vertexDataFrom) + lq vertex3To, 2(vertexDataTo) + Lerp{ vertex3, vertex3From, vertex3To, interp } + + lq stq3From, 2(stqDataFrom) + lq stq3To, 2(stqDataTo) + Lerp{ stq3, stq3From, stq3To, interp } + + ;--- Vertex 3 - Calculate + MatrixMultiplyVertex{ vertex3, mvp, vertex3 } + PerformClipCheck{ vertex3, destAddress, XYZ2_STORE_OFFSET+6 } + VertexPersCorr{ vertex3, vertex3 } + ScaleVertexToGSFormat{ scale, vertex3 } + PerformTexturePerspectiveCorrection{ outputStq3, stq3 } + + ;--- Vertex 3 - Store + sq outputStq3, STQ_STORE_OFFSET+6(destAddress) + sq singleColor, RGBA_STORE_OFFSET+6(destAddress) + sq.xyz vertex3, XYZ2_STORE_OFFSET+6(destAddress) + + ;------------------------------- + + iaddiu vertexDataFrom, vertexDataFrom, 3 + iaddiu stqDataFrom, stqDataFrom, 3 + iaddiu destAddress, destAddress, 9 + + ;--- Fix loop + iaddi vertexCounter, vertexCounter, -3 ; decrement the loop counter + ibne vertexCounter, buffer, vertexLoop ; and repeat if needed + + xgkick kickAddress ; dispatch to the GS rasterizer. + +--barrier ; Why the hell I must add barrier AFTER XGKICK? VCL does not adds E bit without it... +--cont + + b begin + +#endvuprog + +--exit +--endexit diff --git a/engine/src/renderer/3d/pipeline/dynamic/core/programs/dynpip_tc_vu1_program.cpp b/engine/src/renderer/3d/pipeline/dynamic/core/programs/dynpip_tc_vu1_program.cpp new file mode 100644 index 0000000..5facc93 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/dynamic/core/programs/dynpip_tc_vu1_program.cpp @@ -0,0 +1,55 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "debug/debug.hpp" +#include "renderer/3d/pipeline/dynamic/core/programs/dynpip_tc_vu1_program.hpp" + +extern u32 DynPipVU1_TC_CodeStart __attribute__((section(".vudata"))); +extern u32 DynPipVU1_TC_CodeEnd __attribute__((section(".vudata"))); + +namespace Tyra { + +DynPipTCVU1Program::DynPipTCVU1Program() + : DynPipVU1Program(DynPipTextureColor, &DynPipVU1_TC_CodeStart, + &DynPipVU1_TC_CodeEnd, + ((u64)GIF_REG_ST) << 0 | ((u64)GIF_REG_RGBAQ) << 4 | + ((u64)GIF_REG_XYZ2) << 8, + 3, 2) {} + +DynPipTCVU1Program::~DynPipTCVU1Program() {} + +std::string DynPipTCVU1Program::getStringName() const { + return std::string("DynPip - TC"); +} + +void DynPipTCVU1Program::addProgramQBufferDataToPacket(packet2_t* packet, + DynPipBag* bag) const { + u32 addr = VU1_DYNPIP_VERT_DATA_ADDR; + + // Add vertices + packet2_utils_vu_add_unpack_data(packet, addr, bag->verticesFrom, bag->count, + true); + addr += bag->count; + packet2_utils_vu_add_unpack_data(packet, addr, bag->verticesTo, bag->count, + true); + addr += bag->count; + + if (bag->texture) { + // Add sts + packet2_utils_vu_add_unpack_data( + packet, addr, bag->texture->coordinatesFrom, bag->count, true); + addr += bag->count; + packet2_utils_vu_add_unpack_data(packet, addr, bag->texture->coordinatesTo, + bag->count, true); + addr += bag->count; + } +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/dynamic/core/programs/dynpip_td_vu1.vclpp b/engine/src/renderer/3d/pipeline/dynamic/core/programs/dynpip_td_vu1.vclpp new file mode 100644 index 0000000..ce9a7f7 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/dynamic/core/programs/dynpip_td_vu1.vclpp @@ -0,0 +1,178 @@ +; _____ ____ ___ +; | \/ ____| |___| +; | | | \ | | +;--------------------------------------------------------------- +; Copyright 2022, tyra - https://github.com/h4570/tyra +; Licensed under Apache License 2.0 +; Sandro Sobczyński +; +;--------------------------------------------------------------- +; Triangle list +; Cull = Standard PS2 way. clipw polys are culled. +; Animation +; Texture, directional lights +;--------------------------------------------------------------- + +.syntax new +.name DynPipVU1_TD +.vu +.init_vf_all +.init_vi_all + +#include "src/renderer/3d/pipeline/shared/vcl_sml.i" +#include "src/renderer/3d/pipeline/shared/tyra_macros.i" +#include "inc/renderer/3d/pipeline/dynamic/core/programs/dynpip_vu1_shared_defines.h" + +#define STQ_STORE_OFFSET 0 +#define RGBA_STORE_OFFSET 1 +#define XYZ2_STORE_OFFSET 2 + +--enter +--endenter + +#vuprog DynPipVU1TD + + ResetClipFlags{ } + LoadTyraStaticData{ gifSetTag } + MatrixLoad{ mvp, VU1_MVP_MATRIX_ADDR, vi00 } + LoadTyraTagsTexture{ lodGifTag, testsTag, texBufferClutGifTag, VU1_LOD_ADDR, VU1_Z_TESTS_ADDR, VU1_CLUT_ADDR } + +begin: + xtop buffer + LoadTyraPrimTag{ primTag, buffer } + + ilw.w vertexCount, 0(buffer) + iaddiu vertexDataFrom, buffer, VU1_DYNPIP_VERT_DATA_ADDR + + iadd stqDataFrom, vertexDataFrom, vertexCount + iadd stqDataFrom, stqDataFrom, vertexCount + + iadd normalDataFrom, stqDataFrom, vertexCount + iadd normalDataFrom, normalDataFrom, vertexCount + + iadd kickAddress, normalDataFrom, vertexCount + iadd destAddress, kickAddress, vertexCount + iadd kickAddress, kickAddress, vertexCount + + StoreTyraGifTagsTexture{ gifSetTag, lodGifTag, texBufferClutGifTag, primTag, testsTag, destAddress } + LoadTyraLerpValue{ interp, VU1_OPTIONS_ADDR } + LoadTyraScaleValue{ scale, buffer } + + ;--- Loop + iadd vertexCounter, buffer, vertexCount +vertexLoop: + + iadd vertexDataTo, vertexDataFrom, vertexCount + iadd stqDataTo, stqDataFrom, vertexCount + iadd normalDataTo, normalDataFrom, vertexCount + + ;--- Vertex 1 - from-to -> lerp + lq vertex1From, (vertexDataFrom) + lq vertex1To, (vertexDataTo) + Lerp{ vertex1, vertex1From, vertex1To, interp } + + lq stq1From, (stqDataFrom) + lq stq1To, (stqDataTo) + Lerp{ stq1, stq1From, stq1To, interp } + + lq.xyz normal1From, (normalDataFrom) + lq.xyz normal1To, (normalDataTo) + LerpXYZ{ normal1, normal1From, normal1To, interp } + + ;--- Vertex 1 - Calculate + MatrixMultiplyVertex{ vertex1, mvp, vertex1 } + PerformClipCheck{ vertex1, destAddress, XYZ2_STORE_OFFSET } + VertexPersCorr{ vertex1, vertex1 } + ScaleVertexToGSFormat{ scale, vertex1 } + PerformTexturePerspectiveCorrection{ outputStq1, stq1 } + LoadTyraDirectionalLights{ lightMatrix, lightDirections, lightColors, ambientColor, VU1_LIGHTS_DIRS_ADDR, VU1_LIGHTS_COLORS_ADDR, VU1_LIGHTS_MATRIX_ADDR } + CalculateTyraDirectionalLights{ outputColor1, normal1, lightDirections, lightColors, lightMatrix, ambientColor } + FixColor{ outputColor1 } + + ;--- Vertex 1 - Store + sq outputStq1, STQ_STORE_OFFSET(destAddress) + sq outputColor1, RGBA_STORE_OFFSET(destAddress) + sq.xyz vertex1, XYZ2_STORE_OFFSET(destAddress) + + ; --------------------------------------- + + ;--- Vertex 2 - from-to -> lerp + lq vertex2From, 1(vertexDataFrom) + lq vertex2To, 1(vertexDataTo) + Lerp{ vertex2, vertex2From, vertex2To, interp } + + lq stq2From, 1(stqDataFrom) + lq stq2To, 1(stqDataTo) + Lerp{ stq2, stq2From, stq2To, interp } + + lq.xyz normal2From, 1(normalDataFrom) + lq.xyz normal2To, 1(normalDataTo) + LerpXYZ{ normal2, normal2From, normal2To, interp } + + ;--- Vertex 2 - Calculate + MatrixMultiplyVertex{ vertex2, mvp, vertex2 } + PerformClipCheck{ vertex2, destAddress, XYZ2_STORE_OFFSET+3 } + VertexPersCorr{ vertex2, vertex2 } + ScaleVertexToGSFormat{ scale, vertex2 } + PerformTexturePerspectiveCorrection{ outputStq2, stq2 } + LoadTyraDirectionalLights{ lightMatrix, lightDirections, lightColors, ambientColor, VU1_LIGHTS_DIRS_ADDR, VU1_LIGHTS_COLORS_ADDR, VU1_LIGHTS_MATRIX_ADDR } + CalculateTyraDirectionalLights{ outputColor2, normal2, lightDirections, lightColors, lightMatrix, ambientColor } + FixColor{ outputColor2 } + + ;--- Vertex 2 - Store + sq outputStq2, STQ_STORE_OFFSET+3(destAddress) + sq outputColor2, RGBA_STORE_OFFSET+3(destAddress) + sq.xyz vertex2, XYZ2_STORE_OFFSET+3(destAddress) + + ; --------------------------------------- + + ;--- Vertex 3 - from-to -> lerp + lq vertex3From, 2(vertexDataFrom) + lq vertex3To, 2(vertexDataTo) + Lerp{ vertex3, vertex3From, vertex3To, interp } + + lq stq3From, 2(stqDataFrom) + lq stq3To, 2(stqDataTo) + Lerp{ stq3, stq3From, stq3To, interp } + + lq.xyz normal3From, 2(normalDataFrom) + lq.xyz normal3To, 2(normalDataTo) + LerpXYZ{ normal3, normal3From, normal3To, interp } + + ;--- Vertex 3 - Calculate + MatrixMultiplyVertex{ vertex3, mvp, vertex3 } + PerformClipCheck{ vertex3, destAddress, XYZ2_STORE_OFFSET+6 } + VertexPersCorr{ vertex3, vertex3 } + ScaleVertexToGSFormat{ scale, vertex3 } + PerformTexturePerspectiveCorrection{ outputStq3, stq3 } + LoadTyraDirectionalLights{ lightMatrix, lightDirections, lightColors, ambientColor, VU1_LIGHTS_DIRS_ADDR, VU1_LIGHTS_COLORS_ADDR, VU1_LIGHTS_MATRIX_ADDR } + CalculateTyraDirectionalLights{ outputColor3, normal3, lightDirections, lightColors, lightMatrix, ambientColor } + FixColor{ outputColor3 } + + ;--- Vertex 3 - Store + sq outputStq3, STQ_STORE_OFFSET+6(destAddress) + sq outputColor3, RGBA_STORE_OFFSET+6(destAddress) + sq.xyz vertex3, XYZ2_STORE_OFFSET+6(destAddress) + + ;------------------------------- + + iaddiu vertexDataFrom, vertexDataFrom, 3 + iaddiu stqDataFrom, stqDataFrom, 3 + iaddiu normalDataFrom, normalDataFrom, 3 + iaddiu destAddress, destAddress, 9 + + ;--- Fix loop + iaddi vertexCounter, vertexCounter, -3 ; decrement the loop counter + ibne vertexCounter, buffer, vertexLoop ; and repeat if needed + + xgkick kickAddress ; dispatch to the GS rasterizer. + +--barrier ; Why the hell I must add barrier AFTER XGKICK? VCL does not adds E bit without it... +--cont + + b begin + +#endvuprog + +--exit +--endexit diff --git a/engine/src/renderer/3d/pipeline/dynamic/core/programs/dynpip_td_vu1_program.cpp b/engine/src/renderer/3d/pipeline/dynamic/core/programs/dynpip_td_vu1_program.cpp new file mode 100644 index 0000000..32c4372 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/dynamic/core/programs/dynpip_td_vu1_program.cpp @@ -0,0 +1,65 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "debug/debug.hpp" +#include "renderer/3d/pipeline/dynamic/core/programs/dynpip_td_vu1_program.hpp" + +extern u32 DynPipVU1_TD_CodeStart __attribute__((section(".vudata"))); +extern u32 DynPipVU1_TD_CodeEnd __attribute__((section(".vudata"))); + +namespace Tyra { + +DynPipTDVU1Program::DynPipTDVU1Program() + : DynPipVU1Program(DynPipTextureDirLights, &DynPipVU1_TD_CodeStart, + &DynPipVU1_TD_CodeEnd, + ((u64)GIF_REG_ST) << 0 | ((u64)GIF_REG_RGBAQ) << 4 | + ((u64)GIF_REG_XYZ2) << 8, + 3, 3) {} + +DynPipTDVU1Program::~DynPipTDVU1Program() {} + +std::string DynPipTDVU1Program::getStringName() const { + return std::string("DynPip - TD"); +} + +void DynPipTDVU1Program::addProgramQBufferDataToPacket(packet2_t* packet, + DynPipBag* bag) const { + u32 addr = VU1_DYNPIP_VERT_DATA_ADDR; + + // Add vertices + packet2_utils_vu_add_unpack_data(packet, addr, bag->verticesFrom, bag->count, + true); + addr += bag->count; + packet2_utils_vu_add_unpack_data(packet, addr, bag->verticesTo, bag->count, + true); + addr += bag->count; + + if (bag->texture) { + // Add sts + packet2_utils_vu_add_unpack_data( + packet, addr, bag->texture->coordinatesFrom, bag->count, true); + addr += bag->count; + packet2_utils_vu_add_unpack_data(packet, addr, bag->texture->coordinatesTo, + bag->count, true); + addr += bag->count; + } + + if (bag->lighting) { + // Add normal + packet2_utils_vu_add_unpack_data(packet, addr, bag->lighting->normalsFrom, + bag->count, true); + addr += bag->count; + packet2_utils_vu_add_unpack_data(packet, addr, bag->lighting->normalsTo, + bag->count, true); + addr += bag->count; + } +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/dynamic/dynamic_pipeline.cpp b/engine/src/renderer/3d/pipeline/dynamic/dynamic_pipeline.cpp new file mode 100644 index 0000000..35983d0 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/dynamic/dynamic_pipeline.cpp @@ -0,0 +1,302 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/dynamic/dynamic_pipeline.hpp" +#include "renderer/3d/pipeline/shared/bag/pipeline_info_bag.hpp" + +namespace Tyra { + +const u32 DynamicPipeline::buffersCount = 64; +const u32 DynamicPipeline::halfBuffersCount = buffersCount / 2; + +DynamicPipeline::DynamicPipeline() {} + +DynamicPipeline::~DynamicPipeline() { + if (onDestroy) onDestroy(this); +} + +void DynamicPipeline::setRenderer(RendererCore* t_core) { + rendererCore = t_core; + + core.init(t_core); +} + +void DynamicPipeline::onUse() { + dma_channel_fast_waits(DMA_CHANNEL_VIF1); + + colorsCache = new Vec4[4]; + + buffers = new DynPipBag[buffersCount]; + + auto packetSize = + buffersCount * 5.1F; // 5.1 = packet2_get_qw_count / buffersCount + + core.allocateOnUse(static_cast(packetSize)); + core.reinitVU1Programs(); +} + +void DynamicPipeline::onUseEnd() { + delete[] colorsCache; + + for (u32 i = 0; i < buffersCount; i++) freeBuffer(&buffers[i]); + delete[] buffers; + + core.deallocateOnUse(); +} + +void DynamicPipeline::onFrameEnd() {} + +void DynamicPipeline::render(const DynamicMesh* mesh) { render(mesh, nullptr); } + +void DynamicPipeline::render(const DynamicMesh* mesh, + const DynPipOptions& options) { + render(mesh, &options); +} + +void DynamicPipeline::render(const DynamicMesh* mesh, + const DynPipOptions* options) { + bool optionsManuallyAllocated = false; + + if (!options) { + options = new DynPipOptions(); + optionsManuallyAllocated = true; + } + + auto model = mesh->getModelMatrix(); + auto* infoBag = getInfoBag(mesh, options, &model); + PipelineDirLightsBag* dirLights = nullptr; + + if (options->frustumCulling == PipelineFrustumCulling_Simple) { + auto* frameTo = mesh->frames[mesh->animation.getState().nextFrame]; + if (frameTo->bbox->frustumCheck( + rendererCore->renderer3D.frustumPlanes.getAll(), model) == + CoreBBoxFrustum::OUTSIDE_FRUSTUM) { + return; + } + } + + if (options && options->lighting) { + setLightingColorsCache(options->lighting); + dirLights = new PipelineDirLightsBag(true); + dirLights->setLightsManually(colorsCache, + options->lighting->directionalDirections); + } + + u16 bufferIndex = 0; + + setBuffersDefaultVars(buffers, mesh, infoBag); + core.begin(infoBag); + + for (u32 i = 0; i < mesh->materials.size(); i++) { + auto* material = mesh->materials[i]; + auto* frameFrom = material->frames[mesh->animation.getState().currentFrame]; + auto* frameTo = material->frames[mesh->animation.getState().nextFrame]; + + auto partSize = core.getMaxVertCountByParams( + options && options->lighting, material->frames[0]->textureCoords); + + u32 partsCount = ceil(frameFrom->count / static_cast(partSize)); + + auto* colorBag = getColorBag(material); + + setBuffersColorBag(buffers, colorBag); + u8 isPartInitialized = false; + + auto* texture = + rendererCore->texture.repository.getByMeshMaterialId(material->id); + + TYRA_ASSERT(texture, "Texture for material: ", material->name, + "Id: ", material->id, + "Was not found in texture repository! Did you forget to add " + "texture or disable texture coords loading in mesh?"); + + for (u32 k = 0; k < partsCount; k++) { + auto& buffer = buffers[bufferIndex]; + + freeBuffer(&buffer); + buffer.count = + k == partsCount - 1 ? frameFrom->count - k * partSize : partSize; + + u32 startIndex = k * partSize; + + addVertices(frameFrom, frameTo, &buffer, startIndex); + buffer.texture = getTextureBag(texture, frameFrom, frameTo, startIndex); + buffer.lighting = getLightingBag(frameFrom, frameTo, &model, options, + dirLights, startIndex); + + if (!isPartInitialized) { + core.sendObjectDataToVU1(&buffer); + isPartInitialized = true; + } + + setBuffer(buffers, &buffer, &bufferIndex); + } + + delete colorBag; + } + + sendRestOfBuffers(buffers, &bufferIndex); + + if (dirLights) { + delete dirLights; + } + + delete infoBag; + + if (optionsManuallyAllocated) delete options; +} + +void DynamicPipeline::setBuffer(DynPipBag* buffers, DynPipBag* buffer, + u16* bufferIndex) { + auto isEndOf1stDBuffer = *bufferIndex == halfBuffersCount - 1; + auto isEndOf2ndDBuffer = *bufferIndex == buffersCount - 1; + + if (isEndOf1stDBuffer || isEndOf2ndDBuffer) { + u32 offset = isEndOf1stDBuffer ? 0 : halfBuffersCount; + + DynPipBag** sendBuffers = new DynPipBag*[halfBuffersCount]; + + for (u32 i = 0; i < halfBuffersCount; i++) + sendBuffers[i] = &buffers[offset + i]; + + core.render(sendBuffers, halfBuffersCount); + + delete[] sendBuffers; + } + + if (isEndOf2ndDBuffer) + *bufferIndex = 0; + else + *bufferIndex += 1; +} + +void DynamicPipeline::sendRestOfBuffers(DynPipBag* buffers, u16* bufferIndex) { + auto isEndOf1stDBuffer = *bufferIndex <= halfBuffersCount - 1; + + u32 offset = isEndOf1stDBuffer ? 0 : halfBuffersCount; + u32 size = *bufferIndex - offset; + + if (size <= 0) return; + + DynPipBag** sendBuffers = new DynPipBag*[size]; + for (u32 i = 0; i < size; i++) { + sendBuffers[i] = &buffers[offset + i]; + } + + core.render(sendBuffers, size); + + delete[] sendBuffers; +} + +void DynamicPipeline::setBuffersDefaultVars(DynPipBag* buffers, + const DynamicMesh* mesh, + DynPipInfoBag* infoBag) { + for (u32 i = 0; i < buffersCount; i++) { + buffers[i].info = infoBag; + buffers[i].interpolation = mesh->animation.getState().interpolation; + } +} + +void DynamicPipeline::setBuffersColorBag(DynPipBag* buffers, + DynPipColorBag* colorBag) { + for (u32 i = 0; i < buffersCount; i++) { + buffers[i].color = colorBag; + } +} + +void DynamicPipeline::freeBuffer(DynPipBag* bag) { + if (bag->texture) { + delete bag->texture; + } + + if (bag->lighting) { + delete bag->lighting; + } +} + +DynPipInfoBag* DynamicPipeline::getInfoBag(const DynamicMesh* mesh, + const DynPipOptions* options, + M4x4* model) const { + auto* result = new DynPipInfoBag(); + + result->antiAliasingEnabled = options->antiAliasingEnabled; + result->blendingEnabled = options->blendingEnabled; + result->shadingType = options->shadingType; + result->textureMappingType = options->textureMappingType; + result->transformationType = options->transformationType; + result->zTestType = options->zTestType; + result->frustumCulling = + options->frustumCulling == PipelineFrustumCulling_Precise + ? PipelineInfoBagFrustumCulling_Precise + : PipelineInfoBagFrustumCulling_None; + result->model = model; + + return result; +} + +void DynamicPipeline::addVertices(const MeshMaterialFrame* materialFrameFrom, + const MeshMaterialFrame* materialFrameTo, + DynPipBag* bag, const u32& startIndex) const { + bag->verticesFrom = &materialFrameFrom->vertices[startIndex]; + bag->verticesTo = &materialFrameTo->vertices[startIndex]; +} + +DynPipColorBag* DynamicPipeline::getColorBag( + const MeshMaterial* material) const { + auto* result = new DynPipColorBag(); + result->single = &material->ambient; + return result; +} + +DynPipTextureBag* DynamicPipeline::getTextureBag( + Texture* texture, const MeshMaterialFrame* materialFrameFrom, + const MeshMaterialFrame* materialFrameTo, const u32& startIndex) { + if (!materialFrameFrom->textureCoords) return nullptr; + + auto* result = new DynPipTextureBag(); + + result->texture = texture; + + result->coordinatesFrom = &materialFrameFrom->textureCoords[startIndex]; + result->coordinatesTo = &materialFrameTo->textureCoords[startIndex]; + + return result; +} + +DynPipLightingBag* DynamicPipeline::getLightingBag( + const MeshMaterialFrame* materialFrameFrom, + const MeshMaterialFrame* materialFrameTo, M4x4* model, + const DynPipOptions* options, PipelineDirLightsBag* dirLightsBag, + const u32& startIndex) const { + if (!materialFrameFrom->normals || options == nullptr || + options->lighting == nullptr) + return nullptr; + + auto* result = new DynPipLightingBag(); + + result->lightMatrix = model; + result->dirLights = dirLightsBag; + + result->normalsFrom = &materialFrameFrom->normals[startIndex]; + result->normalsTo = &materialFrameTo->normals[startIndex]; + + return result; +} + +void DynamicPipeline::setLightingColorsCache( + PipelineLightingOptions* lightingOptions) { + for (int i = 0; i < 3; i++) { + colorsCache[i] = + reinterpret_cast(lightingOptions->directionalColors[i]); + } + colorsCache[3] = reinterpret_cast(*lightingOptions->ambientColor); +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/minecraft/data/mcpip_block_data.cpp b/engine/src/renderer/3d/pipeline/minecraft/data/mcpip_block_data.cpp new file mode 100644 index 0000000..2ccb11f --- /dev/null +++ b/engine/src/renderer/3d/pipeline/minecraft/data/mcpip_block_data.cpp @@ -0,0 +1,25 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/minecraft/data/mcpip_block_data.hpp" + +namespace Tyra { + +McpipBlockData::McpipBlockData() { + vertices = nullptr; + textureCoords = nullptr; + comboData = nullptr; + offset = 0.0F; + count = 0; +} + +McpipBlockData::~McpipBlockData() {} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/minecraft/data/mcpip_multi_tex_block_data.cpp b/engine/src/renderer/3d/pipeline/minecraft/data/mcpip_multi_tex_block_data.cpp new file mode 100644 index 0000000..51c7533 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/minecraft/data/mcpip_multi_tex_block_data.cpp @@ -0,0 +1,135 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0F +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/minecraft/data/mcpip_multi_tex_block_data.hpp" + +namespace Tyra { + +McpipMultiTexBlockData::McpipMultiTexBlockData() { + allocateTempData(); + unroll(); + dellocateTempData(); +} + +McpipMultiTexBlockData::~McpipMultiTexBlockData() { + if (comboData != nullptr) { + delete[] comboData; + } +} + +void McpipMultiTexBlockData::allocateTempData() { + u32 tempVertsCount = 24; + u32 tempStsCount = 28; + + tempVerts = new Tyra::Vec4[tempVertsCount]; + tempVerts[0].set(-1.0F, -1.0F, -1.0F); + tempVerts[1].set(1.0F, -1.0F, -1.0F); + tempVerts[2].set(1.0F, -1.0F, 1.0F); + tempVerts[3].set(-1.0F, -1.0F, 1.0F); + tempVerts[4].set(1.0F, -1.0F, 1.0F); + tempVerts[5].set(1.0F, 1.0F, 1.0F); + tempVerts[6].set(-1.0F, 1.0F, 1.0F); + tempVerts[7].set(-1.0F, -1.0F, 1.0F); + tempVerts[8].set(-1.0F, -1.0F, 1.0F); + tempVerts[9].set(-1.0F, 1.0F, 1.0F); + tempVerts[10].set(-1.0F, 1.0F, -1.0F); + tempVerts[11].set(-1.0F, -1.0F, -1.0F); + tempVerts[12].set(1.0F, -1.0F, -1.0F); + tempVerts[13].set(1.0F, 1.0F, -1.0F); + tempVerts[14].set(1.0F, 1.0F, 1.0F); + tempVerts[15].set(1.0F, -1.0F, 1.0F); + tempVerts[16].set(-1.0F, -1.0F, -1.0F); + tempVerts[17].set(-1.0F, 1.0F, -1.0F); + tempVerts[18].set(1.0F, 1.0F, -1.0F); + tempVerts[19].set(1.0F, -1.0F, -1.0F); + tempVerts[20].set(1.0F, 1.0F, -1.0F); + tempVerts[21].set(-1.0F, 1.0F, -1.0F); + tempVerts[22].set(-1.0F, 1.0F, 1.0F); + tempVerts[23].set(1.0F, 1.0F, 1.0F); + + tempTexCoords = new Tyra::Vec4[tempStsCount]; + // Y = 1.0F - Y + tempTexCoords[0].set(0.0000F, 0.3750F, 1.0000F, 0.0000F); + tempTexCoords[1].set(0.0625F, 0.3750F, 1.0000F, 0.0000F); + tempTexCoords[2].set(0.0625F, 0.3125F, 1.0000F, 0.0000F); + tempTexCoords[3].set(0.0000F, 0.3125F, 1.0000F, 0.0000F); + tempTexCoords[4].set(0.0625F, 0.2500F, 1.0000F, 0.0000F); + tempTexCoords[5].set(0.0625F, 0.2500F, 1.0000F, 0.0000F); + tempTexCoords[6].set(0.0625F, 0.1875F, 1.0000F, 0.0000F); + tempTexCoords[7].set(0.0000F, 0.1875F, 1.0000F, 0.0000F); + tempTexCoords[8].set(0.0000F, 0.1875F, 1.0000F, 0.0000F); + tempTexCoords[9].set(0.0000F, 0.2500F, 1.0000F, 0.0000F); + tempTexCoords[10].set(0.0625F, 0.1875F, 1.0000F, 0.0000F); + tempTexCoords[11].set(0.0625F, 0.1250F, 1.0000F, 0.0000F); + tempTexCoords[12].set(0.0000F, 0.1250F, 1.0000F, 0.0000F); + tempTexCoords[13].set(0.0000F, 0.1875F, 1.0000F, 0.0000F); + tempTexCoords[14].set(0.0625F, 0.3125F, 1.0000F, 0.0000F); + tempTexCoords[15].set(0.0625F, 0.3125F, 1.0000F, 0.0000F); + tempTexCoords[16].set(0.0625F, 0.2500F, 1.0000F, 0.0000F); + tempTexCoords[17].set(0.0000F, 0.2500F, 1.0000F, 0.0000F); + tempTexCoords[18].set(0.0000F, 0.2500F, 1.0000F, 0.0000F); + tempTexCoords[19].set(0.0000F, 0.3125F, 1.0000F, 0.0000F); + tempTexCoords[20].set(0.0625F, 0.1250F, 1.0000F, 0.0000F); + tempTexCoords[21].set(0.0625F, 0.0625F, 1.0000F, 0.0000F); + tempTexCoords[22].set(0.0000F, 0.0625F, 1.0000F, 0.0000F); + tempTexCoords[23].set(0.0000F, 0.1250F, 1.0000F, 0.0000F); + tempTexCoords[24].set(0.0000F, 0.0625F, 1.0000F, 0.0000F); + tempTexCoords[25].set(0.0625F, 0.0625F, 1.0000F, 0.0000F); + tempTexCoords[26].set(0.0625F, 0.0000F, 1.0000F, 0.0000F); + tempTexCoords[27].set(0.0000F, 0.0000F, 1.0000F, 0.0000F); + + // Because 16 blocks can fit in single column of 256x256 tex atlas + offset = 1.0F / 16.0F; + + tempVertFaces = new u32[36]; + tempTexCoordsFaces = new u32[36]; + + std::string vertexFaces = + "1,2,3,1,3,4,5,6,7,5,7,8,9,10,11,9,11,12,13,14,15,13,15,16,17,18,19,17," + "19,20,21,22,23,21,23,24"; + std::stringstream ssVertexFaces(vertexFaces); + + std::string texCoordFaces = + "1,2,3,1,3,4,5,7,8,6,9,10,11,12,13,11,13,14,15,17,18,16,19,20,21,22,23," + "21,23,24,25,26,27,25,27,28"; + std::stringstream ssTexCoordFaces(texCoordFaces); + + int i = 0; + std::string item; + + while (std::getline(ssVertexFaces, item, ',')) + tempVertFaces[i++] = std::stoi(item) - 1; + + i = 0; + + while (std::getline(ssTexCoordFaces, item, ',')) + tempTexCoordsFaces[i++] = std::stoi(item) - 1; +} + +void McpipMultiTexBlockData::unroll() { + count = 36; + comboData = new Tyra::Vec4[36 * 2]; + vertices = &comboData[0]; + textureCoords = &comboData[36]; + + for (u32 i = 0; i < count; i++) { + vertices[i] = tempVerts[tempVertFaces[i]]; + textureCoords[i] = tempTexCoords[tempTexCoordsFaces[i]]; + } +} + +void McpipMultiTexBlockData::dellocateTempData() { + delete[] tempVerts; + delete[] tempTexCoords; + delete[] tempVertFaces; + delete[] tempTexCoordsFaces; +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/minecraft/data/mcpip_single_tex_block_data.cpp b/engine/src/renderer/3d/pipeline/minecraft/data/mcpip_single_tex_block_data.cpp new file mode 100644 index 0000000..fe3fe98 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/minecraft/data/mcpip_single_tex_block_data.cpp @@ -0,0 +1,130 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0F +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/minecraft/data/mcpip_single_tex_block_data.hpp" + +namespace Tyra { + +McpipSingleTexBlockData::McpipSingleTexBlockData() { + allocateTempData(); + unroll(); + dellocateTempData(); +} + +McpipSingleTexBlockData::~McpipSingleTexBlockData() { + if (comboData != nullptr) { + delete[] comboData; + } +} + +void McpipSingleTexBlockData::allocateTempData() { + u32 tempVertsStsCount = 24; + + tempVerts = new Tyra::Vec4[tempVertsStsCount]; + tempVerts[0].set(-1.0F, -1.0F, -1.0F); + tempVerts[1].set(1.0F, -1.0F, -1.0F); + tempVerts[2].set(1.0F, -1.0F, 1.0F); + tempVerts[3].set(-1.0F, -1.0F, 1.0F); + tempVerts[4].set(1.0F, -1.0F, 1.0F); + tempVerts[5].set(1.0F, 1.0F, 1.0F); + tempVerts[6].set(-1.0F, 1.0F, 1.0F); + tempVerts[7].set(-1.0F, -1.0F, 1.0F); + tempVerts[8].set(-1.0F, -1.0F, 1.0F); + tempVerts[9].set(-1.0F, 1.0F, 1.0F); + tempVerts[10].set(-1.0F, 1.0F, -1.0F); + tempVerts[11].set(-1.0F, -1.0F, -1.0F); + tempVerts[12].set(1.0F, -1.0F, -1.0F); + tempVerts[13].set(1.0F, 1.0F, -1.0F); + tempVerts[14].set(1.0F, 1.0F, 1.0F); + tempVerts[15].set(1.0F, -1.0F, 1.0F); + tempVerts[16].set(-1.0F, -1.0F, -1.0F); + tempVerts[17].set(-1.0F, 1.0F, -1.0F); + tempVerts[18].set(1.0F, 1.0F, -1.0F); + tempVerts[19].set(1.0F, -1.0F, -1.0F); + tempVerts[20].set(1.0F, 1.0F, -1.0F); + tempVerts[21].set(-1.0F, 1.0F, -1.0F); + tempVerts[22].set(-1.0F, 1.0F, 1.0F); + tempVerts[23].set(1.0F, 1.0F, 1.0F); + + tempTexCoords = new Tyra::Vec4[tempVertsStsCount]; + // Y = 1.0F - Y + tempTexCoords[0].set(0.0000F, 0.0625F, 1.0000F, 0.0000F); + tempTexCoords[1].set(0.0625F, 0.0625F, 1.0000F, 0.0000F); + tempTexCoords[2].set(0.0625F, 0.0000F, 1.0000F, 0.0000F); + tempTexCoords[3].set(0.0000F, 0.0000F, 1.0000F, 0.0000F); + tempTexCoords[4].set(0.0625F, 0.0625F, 1.0000F, 0.0000F); + tempTexCoords[5].set(0.0625F, 0.0000F, 1.0000F, 0.0000F); + tempTexCoords[6].set(0.0000F, 0.0000F, 1.0000F, 0.0000F); + tempTexCoords[7].set(0.0000F, 0.0625F, 1.0000F, 0.0000F); + tempTexCoords[8].set(0.0625F, 0.0625F, 1.0000F, 0.0000F); + tempTexCoords[9].set(0.0625F, 0.0000F, 1.0000F, 0.0000F); + tempTexCoords[10].set(0.0000F, 0.0000F, 1.0000F, 0.0000F); + tempTexCoords[11].set(0.0000F, 0.0625F, 1.0000F, 0.0000F); + tempTexCoords[12].set(0.0625F, 0.0625F, 1.0000F, 0.0000F); + tempTexCoords[13].set(0.0625F, 0.0000F, 1.0000F, 0.0000F); + tempTexCoords[14].set(0.0000F, 0.0000F, 1.0000F, 0.0000F); + tempTexCoords[15].set(0.0000F, 0.0625F, 1.0000F, 0.0000F); + tempTexCoords[16].set(0.0625F, 0.0625F, 1.0000F, 0.0000F); + tempTexCoords[17].set(0.0625F, 0.0000F, 1.0000F, 0.0000F); + tempTexCoords[18].set(0.0000F, 0.0000F, 1.0000F, 0.0000F); + tempTexCoords[19].set(0.0000F, 0.0625F, 1.0000F, 0.0000F); + tempTexCoords[20].set(0.0000F, 0.0625F, 1.0000F, 0.0000F); + tempTexCoords[21].set(0.0625F, 0.0625F, 1.0000F, 0.0000F); + tempTexCoords[22].set(0.0625F, 0.0000F, 1.0000F, 0.0000F); + tempTexCoords[23].set(0.0000F, 0.0000F, 1.0000F, 0.0000F); + + // Because 16 blocks can fit in single column of 256x256 tex atlas + offset = 1.0F / 16.0F; + + tempVertFaces = new u32[36]; + tempTexCoordsFaces = new u32[36]; + + std::string vertexFaces = + "1,2,3,1,3,4,5,6,7,5,7,8,9,10,11,9,11,12,13,14,15,13,15,16,17,18,19,17," + "19,20,21,22,23,21,23,24"; + std::stringstream ssVertexFaces(vertexFaces); + + std::string texCoordFaces = + "1,2,3,1,3,4,5,6,7,5,7,8,9,10,11,9,11,12,13,14,15,13,15,16,17,18,19,17," + "19,20,21,22,23,21,23,24"; + std::stringstream ssTexCoordFaces(texCoordFaces); + + int i = 0; + std::string item; + + while (std::getline(ssVertexFaces, item, ',')) + tempVertFaces[i++] = std::stoi(item) - 1; + + i = 0; + + while (std::getline(ssTexCoordFaces, item, ',')) + tempTexCoordsFaces[i++] = std::stoi(item) - 1; +} + +void McpipSingleTexBlockData::unroll() { + count = 36; + comboData = new Tyra::Vec4[36 * 2]; + vertices = &comboData[0]; + textureCoords = &comboData[36]; + + for (u32 i = 0; i < count; i++) { + vertices[i] = tempVerts[tempVertFaces[i]]; + textureCoords[i] = tempTexCoords[tempTexCoordsFaces[i]]; + } +} + +void McpipSingleTexBlockData::dellocateTempData() { + delete[] tempVerts; + delete[] tempTexCoords; + delete[] tempVertFaces; + delete[] tempTexCoordsFaces; +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/minecraft/minecraft_pipeline.cpp b/engine/src/renderer/3d/pipeline/minecraft/minecraft_pipeline.cpp new file mode 100644 index 0000000..a4cdd80 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/minecraft/minecraft_pipeline.cpp @@ -0,0 +1,228 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include +#include "renderer/3d/pipeline/minecraft/minecraft_pipeline.hpp" +#include "thread/threading.hpp" + +namespace Tyra { + +MinecraftPipeline::MinecraftPipeline() { + latestMode = UndefinedMcpipProgram; + spamBuffersCount = 4; + spammerIndex = 0; + setPrim(); + setLod(); +} + +MinecraftPipeline::~MinecraftPipeline() { + if (onDestroy) onDestroy(this); + if (bbox) { + delete bbox; + } +} + +void MinecraftPipeline::setRenderer(RendererCore* core) { + rendererCore = core; + manager.init(core, &prim, &lod); + + initBBox(); +} + +void MinecraftPipeline::setPrim() { + prim.type = PRIM_TRIANGLE; + prim.shading = PRIM_SHADE_FLAT; + prim.mapping = DRAW_ENABLE; + prim.fogging = DRAW_DISABLE; + prim.blending = DRAW_ENABLE; + prim.antialiasing = DRAW_DISABLE; + prim.mapping_type = PRIM_MAP_ST; + prim.colorfix = PRIM_UNFIXED; +} + +void MinecraftPipeline::setLod() { + lod.calculation = LOD_USE_K; + lod.max_level = 0; + lod.mag_filter = LOD_MAG_NEAREST; + lod.min_filter = LOD_MIN_NEAREST; + lod.mipmap_select = LOD_MIPMAP_REGISTER; + lod.l = 0; + lod.k = 0.0F; +} + +void MinecraftPipeline::onUse() { + dma_channel_fast_waits(DMA_CHANNEL_VIF1); + + spamBuffers = new McpipBlock**[spamBuffersCount]; + spamCounts = new u32[spamBuffersCount]; + + rendererCore->gs.enableZTests(); + + manager.allocateOnUse(); + + manager.uploadVU1Programs(); + + changeMode(McPipCull, true); +} + +void MinecraftPipeline::onUseEnd() { + delete[] spamBuffers; + delete[] spamCounts; + manager.deallocateOnUse(); +} + +void MinecraftPipeline::onFrameEnd() {} + +void MinecraftPipeline::initBBox() { + const auto& block = manager.getBlockData(); + bbox = new RenderBBox(block.vertices, block.count); +} + +void MinecraftPipeline::render(std::vector blocks, + const Texture* t_tex, const bool& isMulti, + const bool& fullClipChecks) { + auto texBuffers = rendererCore->texture.useTexture(t_tex); + + manager.clearLastProgram(); + std::vector cullIndexes; + + if (!fullClipChecks) { + for (u32 i = 0; i < blocks.size(); i++) cullIndexes.push_back(i); + cull(blocks, cullIndexes, &texBuffers, true, isMulti); + return; + } + + u32 culled = 0, clipped = 0; + std::vector clipIndexes; + + for (u32 i = 0; i < blocks.size(); i++) { + auto frustum = isInFrustum(*blocks[i]); + if (frustum == CoreBBoxFrustum::IN_FRUSTUM) { + cullIndexes.push_back(i); + culled++; + } else if (frustum == CoreBBoxFrustum::PARTIALLY_IN_FRUSTUM) { + clipIndexes.push_back(i); + clipped++; + } + } + + if (culled > 0) cull(blocks, cullIndexes, &texBuffers, false, isMulti); + if (clipped > 0) clip(blocks, clipIndexes, &texBuffers, isMulti); +} + +CoreBBoxFrustum MinecraftPipeline::isInFrustum(const McpipBlock& block) const { + const auto* frustumPlanes = rendererCore->renderer3D.frustumPlanes.getAll(); + return bbox->clipFrustumCheck(frustumPlanes, *block.model); +} + +void MinecraftPipeline::cull(std::vector blocks, + const std::vector& indexes, + RendererCoreTextureBuffers* texBuffers, + const bool& isCullOnly, const bool& isMulti) { + changeMode(McPipCull, false); + + auto maxBlocksPerQBuffer = manager.culler.getMaxBlocksCountPerQBuffer(); + auto partsCount = static_cast( + ceil(indexes.size() / static_cast(maxBlocksPerQBuffer))); + + for (u32 i = 0; i < partsCount; i++) { + u32 subArraySize = i != partsCount - 1 + ? maxBlocksPerQBuffer + : indexes.size() - i * maxBlocksPerQBuffer; + + McpipBlock** blockPointerArray = new McpipBlock*[subArraySize]; + u32 blockPointerArrayCount = 0; + for (u32 j = 0; j < subArraySize; j++) { + blockPointerArray[blockPointerArrayCount++] = + blocks[indexes[i * maxBlocksPerQBuffer + j]]; + } + + if (isCullOnly) { + addToSpammer(blockPointerArray, blockPointerArrayCount, texBuffers, + isMulti); + } else { + manager.cull(blockPointerArray, blockPointerArrayCount, texBuffers, + isMulti); + delete[] blockPointerArray; + } + } + + if (isCullOnly) { + flushSpammer(texBuffers, isMulti); + } +} + +// -- 2nd qbuff = 36 * 3 (ST,RGBA,STQ) +// * 2 (We will have at least 2x more verts after clip) +// + Set, lod, set, clut, prim = 221 +// -- 1st qbuff: 500 - 221 = 279 +// Tags: 279 - for example 20 = 259 +// Vert + ST from EE = 259 / 2 = 129 verts | OK! +void MinecraftPipeline::clip(std::vector blocks, + const std::vector& indexes, + RendererCoreTextureBuffers* texBuffers, + const bool& isMulti) { + changeMode(McPipAsIs, false); + + for (u32 i = 0; i < indexes.size(); i++) { + manager.clip(blocks[indexes[i]], texBuffers, isMulti); + } +} + +void MinecraftPipeline::changeMode(const McpipProgramName& requestedMode, + const u8& force) { + if (!force) { + if (latestMode == requestedMode) return; + } + + if (requestedMode == McPipCull) { + manager.culler.configureVU1AndSendStaticData(); + latestMode = McPipCull; + } else { + manager.clipper.configureVU1AndSendStaticData(); + latestMode = McPipAsIs; + } +} + +void MinecraftPipeline::addToSpammer(McpipBlock** blockPointerArray, + const u32& count, + RendererCoreTextureBuffers* texBuffers, + const bool& isMulti) { + spamBuffers[spammerIndex] = blockPointerArray; + spamCounts[spammerIndex] = count; + + spammerIndex++; + + if (spammerIndex == spamBuffersCount) { + spammerIndex = 0; + + manager.cullSpam(spamBuffers, spamCounts, spamBuffersCount, texBuffers, + isMulti); + + for (u32 i = 0; i < spamBuffersCount; i++) { + delete[] spamBuffers[i]; + } + } +} + +void MinecraftPipeline::flushSpammer(RendererCoreTextureBuffers* texBuffers, + const bool& isMulti) { + if (spammerIndex == 0) return; + + manager.cullSpam(spamBuffers, spamCounts, spammerIndex, texBuffers, isMulti); + + for (u32 i = 0; i < spammerIndex; i++) { + delete[] spamBuffers[i]; + } + + spammerIndex = 0; +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/minecraft/programs/as_is/macros.i b/engine/src/renderer/3d/pipeline/minecraft/programs/as_is/macros.i new file mode 100644 index 0000000..25c2611 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/minecraft/programs/as_is/macros.i @@ -0,0 +1,34 @@ +;//-------------------------------------------------------------------------------- +;// MinecraftPipeline cull macros library +;//-------------------------------------------------------------------------------- + +;//--------------------------------------------------------- +;// LoadStaticData - Load lod, set and viewproj matrix +;//--------------------------------------------------------- +#macro LoadStaticData: t_lod, t_set + lq t_lod, VU1_MCPIP_AS_IS_STATIC_LOD(vi00) + lq t_set, VU1_MCPIP_AS_IS_STATIC_SET_TAG(vi00) +#endmacro + +;//--------------------------------------------------------- +;// LoadDynamicData - Load scale, prim and clut +;//--------------------------------------------------------- +#macro LoadDynamicData: t_scale, t_prim, t_clut, t_color, t_vertexCount, t_buffer + lq t_scale, VU1_MCPIP_AS_IS_DYNAMIC_SCALE(t_buffer) + lq t_prim, VU1_MCPIP_AS_IS_DYNAMIC_PRIM(t_buffer) + lq t_clut, VU1_MCPIP_AS_IS_DYNAMIC_CLUT(t_buffer) + lq t_color, VU1_MCPIP_AS_IS_DYNAMIC_COLOR(t_buffer) + ilw.w t_vertexCount, VU1_MCPIP_AS_IS_DYNAMIC_SCALE(t_buffer) +#endmacro + +;//--------------------------------------------------------- +;// StoreTags - Store lod, prim, clut +;//--------------------------------------------------------- +#macro StoreTags: t_lodTag, t_setTag, t_primTag, t_clut, t_destAddress + sq t_setTag, 0(t_destAddress) + sq t_lodTag, 1(t_destAddress) + sq t_setTag, 2(t_destAddress) + sq t_clut, 3(t_destAddress) + sq t_primTag, 4(t_destAddress) + iaddiu t_destAddress, t_destAddress, 5 +#endmacro diff --git a/engine/src/renderer/3d/pipeline/minecraft/programs/as_is/mcpip_as_is_vu1.vclpp b/engine/src/renderer/3d/pipeline/minecraft/programs/as_is/mcpip_as_is_vu1.vclpp new file mode 100644 index 0000000..1e05840 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/minecraft/programs/as_is/mcpip_as_is_vu1.vclpp @@ -0,0 +1,118 @@ +; _____ ____ ___ +; | \/ ____| |___| +; | | | \ | | +;--------------------------------------------------------------- +; Copyright 2022, tyra - https://github.com/h4570/tyra +; Licensed under Apache License 2.0 +; Sandro Sobczyński +; +;--------------------------------------------------------------- +; Super fast renderer of minecraft blocks. +; Block data is statically allocated in vi00 +; +; - Triangle list +; - AsIs = NO TRANSFORM +; - Colors +;--------------------------------------------------------------- + +.syntax new +.name VU1BlocksAsIs +.vu +.init_vf_all +.init_vi_all + +#include "src/renderer/3d/pipeline/shared/vcl_sml.i" +#include "inc/renderer/3d/pipeline/minecraft/programs/as_is/mcpip_vu1_as_is_shared_defines.h" +#include "src/renderer/3d/pipeline/minecraft/programs/as_is/macros.i" + +#define STQ_STORE_OFFSET 0 +#define RGBA_STORE_OFFSET 1 +#define XYZ2_STORE_OFFSET 2 + +--enter +--endenter + +#vuprog VU1BlocksAsIs + + LoadStaticData{ lodTag, setTag } + +begin: + + xtop buffer + LoadDynamicData{ scale, primTag, clut, color, vertexCount, buffer } + + iaddiu vertexData, buffer, VU1_MCPIP_AS_IS_DYNAMIC_VERTEX_DATA_ADDR + iadd stqData, vertexData, vertexCount + iadd destAddress, stqData, vertexCount + iadd kickAddress, stqData, vertexCount + + StoreTags{ lodTag, setTag, primTag, clut, destAddress } + FixColor{ color } + + ;--- Loop + iadd vertexCounter, buffer, vertexCount +vertexLoop: + + ;--- Load vertex1 + lq vertex1, (vertexData) + lq stq1, (stqData) + + ;--- Load vertex2 + lq vertex2, 1(vertexData) + lq stq2, 1(stqData) + + ;--- Load vertex3 + lq vertex3, 2(vertexData) + lq stq3, 2(stqData) + + ;--- Calculate vertex1 + ScaleVertexToGSFormat{ scale, vertex1 } + div q, vf00[w], vertex1[w] + PerformTexturePerspectiveCorrection{ outputStq1, stq1 } + + ;--- Calculate vertex2 + ScaleVertexToGSFormat{ scale, vertex2 } + div q, vf00[w], vertex2[w] + PerformTexturePerspectiveCorrection{ outputStq2, stq2 } + + ;--- Calculate vertex3 + ScaleVertexToGSFormat{ scale, vertex3 } + div q, vf00[w], vertex3[w] + PerformTexturePerspectiveCorrection{ outputStq3, stq3 } + + ;--- Store vertex1 + sq outputStq1, STQ_STORE_OFFSET(destAddress) + sq color, RGBA_STORE_OFFSET(destAddress) + sq.xyz vertex1, XYZ2_STORE_OFFSET(destAddress) + + ;--- Store vertex2 + sq outputStq2, STQ_STORE_OFFSET+3(destAddress) + sq color, RGBA_STORE_OFFSET+3(destAddress) + sq.xyz vertex2, XYZ2_STORE_OFFSET+3(destAddress) + + ;--- Store vertex3 + sq outputStq3, STQ_STORE_OFFSET+6(destAddress) + sq color, RGBA_STORE_OFFSET+6(destAddress) + sq.xyz vertex3, XYZ2_STORE_OFFSET+6(destAddress) + + ;------------------------------- + + iaddiu vertexData, vertexData, 3 + iaddiu stqData, stqData, 3 + iaddiu destAddress, destAddress, 9 + + ;--- Fix loop + iaddi vertexCounter, vertexCounter, -3 ; decrement the loop counter + ibne vertexCounter, buffer, vertexLoop ; and repeat if needed + + xgkick kickAddress ; dispatch to the GS rasterizer. + +--barrier ; Why the hell I must add barrier AFTER XGKICK? VCL does not adds E bit without it... +--cont + + b begin + +#endvuprog + +--exit +--endexit diff --git a/engine/src/renderer/3d/pipeline/minecraft/programs/as_is/mcpip_as_is_vu1_program.cpp b/engine/src/renderer/3d/pipeline/minecraft/programs/as_is/mcpip_as_is_vu1_program.cpp new file mode 100644 index 0000000..19578c5 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/minecraft/programs/as_is/mcpip_as_is_vu1_program.cpp @@ -0,0 +1,28 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/minecraft/programs/as_is/mcpip_as_is_vu1_program.hpp" + +extern u32 VU1BlocksAsIs_CodeStart __attribute__((section(".vudata"))); +extern u32 VU1BlocksAsIs_CodeEnd __attribute__((section(".vudata"))); + +namespace Tyra { + +McpipAsIsVU1Program::McpipAsIsVU1Program() + : McpipProgram(McpipProgramName::McPipAsIs, &VU1BlocksAsIs_CodeStart, + &VU1BlocksAsIs_CodeEnd) {} + +McpipAsIsVU1Program::~McpipAsIsVU1Program() {} + +std::string McpipAsIsVU1Program::getStringName() const { + return std::string("McPip - As is"); +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/minecraft/programs/as_is/mcpip_clip.cpp b/engine/src/renderer/3d/pipeline/minecraft/programs/as_is/mcpip_clip.cpp new file mode 100644 index 0000000..16125df --- /dev/null +++ b/engine/src/renderer/3d/pipeline/minecraft/programs/as_is/mcpip_clip.cpp @@ -0,0 +1,161 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/minecraft/programs/as_is/mcpip_clip.hpp" + +namespace Tyra { + +McpipClip::McpipClip() { + staticPacket = packet2_create(8, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); + algoSettings.lerpColors = false; + algoSettings.lerpTexCoords = true; + algoSettings.lerpNormals = false; +} + +McpipClip::~McpipClip() { packet2_free(staticPacket); } + +void McpipClip::init(RendererCore* core, McpipBlockData* t_singleBlockData, + McpipBlockData* t_multiBlockData, prim_t* t_prim, + lod_t* t_lod) { + prim = t_prim; + lod = t_lod; + singleBlockData = t_singleBlockData; + multiBlockData = t_multiBlockData; + rendererCore = core; + algorithm.init(rendererCore->getSettings()); + setDBufferSize(); + initStaticPacket(); +} + +u32 McpipClip::uploadVU1Program(McpipProgramsRepository* repo, + const u32& addr) { + auto* program = repo->getProgram(McpipProgramName::McPipAsIs); + return rendererCore->renderer3D.uploadVU1Program(program, addr); +} + +void McpipClip::configureVU1AndSendStaticData() { + u16 start = VU1_MCPIP_AS_IS_STATIC_LAST_DATA_ADDR + 1; + rendererCore->renderer3D.setVU1DoubleBuffers(start, vu1DBufferSize); + sendVU1StaticData(); +} + +void McpipClip::initStaticPacket() { + packet2_utils_vu_open_unpack(staticPacket, VU1_MCPIP_AS_IS_STATIC_LOD, false); + { + packet2_utils_gs_add_lod(staticPacket, lod); + packet2_utils_gif_add_set(staticPacket, 1); + } + packet2_utils_vu_close_unpack(staticPacket); + + packet2_utils_vu_add_end_tag(staticPacket); +} + +void McpipClip::addData(McpipBlock* block, const bool& isMulti, + RendererCoreTextureBuffers* texBuffers, + packet2_t* packet, const u8& context) { + std::vector clippedVertices; + auto mvp = rendererCore->renderer3D.getViewProj() * (*block->model); + + const auto* blockData = isMulti ? multiBlockData : singleBlockData; + + for (u32 i = 0; i < blockData->count / 3; i++) { + for (u8 j = 0; j < 3; j++) { + inputVerts[j] = mvp * blockData->vertices[i * 3 + j]; + inputTriangle[j] = {&inputVerts[j], nullptr, + &blockData->textureCoords[i * 3 + j], nullptr}; + } + + u8 clippedSize = + algorithm.clip(clippedTriangle, inputTriangle, algoSettings); + + if (clippedSize == 0) continue; + + auto va = clippedTriangle[0]; + for (u8 j = 1; j <= clippedSize - 2; j++) { + auto vb = clippedTriangle[j]; + auto vc = clippedTriangle[(j + 1) % clippedSize]; + clippedVertices.push_back(va); + clippedVertices.push_back(vb); + clippedVertices.push_back(vc); + } + } + + addCorrections(&clippedVertices, block); + moveDataToBuffer(&clippedVertices, context); + addDataToPacket(packet, context, block, clippedVertices.size(), texBuffers); +} + +void McpipClip::addCorrections(std::vector* vertices, + McpipBlock* block) { + for (u32 i = 0; i < vertices->size(); i++) { + (*vertices)[i].position /= (*vertices)[i].position.w; // Perspective divide + (*vertices)[i].st += *block->textureOffset; // Texture offset + } +} + +void McpipClip::moveDataToBuffer(std::vector* vertices, + const u8& context) { + for (u32 i = 0; i < vertices->size(); i++) { + vertexBuffers[context][i].set(vertices->at(i).position); + texCoordBuffers[context][i].set(vertices->at(i).st); + } +} + +void McpipClip::addDataToPacket(packet2_t* packet, const u8& context, + McpipBlock* block, const int& count, + RendererCoreTextureBuffers* texBuffers) { + packet2_reset(packet, false); + + rendererCore->texture.updateClutBuffer(texBuffers->clut); + + packet2_utils_vu_open_unpack(packet, VU1_MCPIP_AS_IS_DYNAMIC_SCALE, true); + { + packet2_add_float(packet, 2048.0F); // scale + packet2_add_float(packet, 2048.0F); // scale + packet2_add_float(packet, + static_cast(0xFFFFFF) / 32.0F); // scale + packet2_add_s32(packet, count); // vertex count + + packet2_utils_gs_add_prim_giftag(packet, prim, count, + ((u64)GIF_REG_ST) << 0 | + ((u64)GIF_REG_RGBAQ) << 4 | + ((u64)GIF_REG_XYZ2) << 8, + 3, 0); + + packet2_utils_gs_add_texbuff_clut(packet, texBuffers->core, + &rendererCore->texture.clut); + + Packet2TyraUtils::addColor(packet, *block->color); + } + packet2_utils_vu_close_unpack(packet); + + u32 addr = VU1_MCPIP_AS_IS_DYNAMIC_VERTEX_DATA_ADDR; + + packet2_utils_vu_add_unpack_data(packet, addr, vertexBuffers[context], count, + true); + addr += count; + + packet2_utils_vu_add_unpack_data(packet, addr, texCoordBuffers[context], + count, true); +} + +void McpipClip::setDBufferSize() { + vu1DBufferSize = 1000; // VU1 mem size + vu1DBufferSize -= VU1_MCPIP_AS_IS_STATIC_LAST_DATA_ADDR; // static data + vu1DBufferSize -= 1; + vu1DBufferSize /= 2; // xtop double buffer +} + +void McpipClip::sendVU1StaticData() { + dma_channel_wait(DMA_CHANNEL_VIF1, 0); + dma_channel_send_packet2(staticPacket, DMA_CHANNEL_VIF1, true); +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/minecraft/programs/cull/macros.i b/engine/src/renderer/3d/pipeline/minecraft/programs/cull/macros.i new file mode 100644 index 0000000..ccb8bb2 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/minecraft/programs/cull/macros.i @@ -0,0 +1,93 @@ +;//-------------------------------------------------------------------------------- +;// MinecraftPipeline cull macros library +;//-------------------------------------------------------------------------------- + +;//--------------------------------------------------------- +;// StoreBlockizerStaticData - Load and store lod, clut and prim. +;// Push dest address by 5 qwords +;//--------------------------------------------------------- +#macro StoreBlockizerLodClutTexPrim: t_destAddr, t_clutTex + lq setTag, VU1_MCPIP_CULL_STATIC_SET_TAG(vi00) + lq lodTag, VU1_MCPIP_CULL_STATIC_LOD(vi00) + sq setTag, 0(t_destAddr) + sq lodTag, 1(t_destAddr) + sq setTag, 2(t_destAddr) + sq t_clutTex, 3(t_destAddr) + lq primTag, VU1_MCPIP_CULL_STATIC_PRIM(vi00) + sq primTag, 4(t_destAddr) + iaddiu t_destAddr, t_destAddr, 5 +#endmacro + +;//--------------------------------------------------------- +;// GetDestinationAddress - Load VU1 options and check +;// in which double buffer we are. If 0, return first double buff +;// if 1, return second double buffer. +;// Also toggle VU1 dbuff option, so next call of this macro will result +;// opposite buffer. +;//--------------------------------------------------------- +#macro GetDestinationAddress: t_destAddr, t_kickAddr + ilw.w static1, VU1_MCPIP_CULL_STATIC_VU1_OPTIONS(vi00) + ilw.x currDBufferOffset, VU1_MCPIP_CULL_STATIC_VU1_OPTIONS(vi00) + ibgtz currDBufferOffset, get_dest_addr_second + + get_dest_addr_first: + iaddiu t_destAddr, vi00, VU1_MCPIP_CULL_DYNAMIC_OUTPUT_DOUBLE_BUFF1_ADDR + isw.x static1, VU1_MCPIP_CULL_STATIC_VU1_OPTIONS(vi00) + b get_dest_addr_finish + + get_dest_addr_second: + iaddiu t_destAddr, vi00, VU1_MCPIP_CULL_DYNAMIC_OUTPUT_DOUBLE_BUFF2_ADDR + isw.x vi00, VU1_MCPIP_CULL_STATIC_VU1_OPTIONS(vi00) + + get_dest_addr_finish: + iaddiu t_kickAddr, t_destAddr, 0 +#endmacro + +;//--------------------------------------------------------- +;// LoadScaleAndBlocksCount - Load scale vec3 and blocks count +;// from w component +;//--------------------------------------------------------- +#macro LoadBufferDynamicData: t_buffer, t_scale, t_clutTex, t_blocksCount, t_viewProj + lq.xyz t_scale, VU1_MCPIP_CULL_DYNAMIC_SCALE_AND_BLOCKS_COUNT_ADDR(t_buffer) + ilw.w t_blocksCount, VU1_MCPIP_CULL_DYNAMIC_SCALE_AND_BLOCKS_COUNT_ADDR(t_buffer) + lq t_clutTex, VU1_MCPIP_CULL_DYNAMIC_CLUT_TEX(t_buffer) + lq t_viewProj[0], 0+VU1_MCPIP_CULL_DYNAMIC_VIEW_PROJ_MATRIX_ADDR(t_buffer) + lq t_viewProj[1], 1+VU1_MCPIP_CULL_DYNAMIC_VIEW_PROJ_MATRIX_ADDR(t_buffer) + lq t_viewProj[2], 2+VU1_MCPIP_CULL_DYNAMIC_VIEW_PROJ_MATRIX_ADDR(t_buffer) + lq t_viewProj[3], 3+VU1_MCPIP_CULL_DYNAMIC_VIEW_PROJ_MATRIX_ADDR(t_buffer) +#endmacro + +;//--------------------------------------------------------- +;// GetVertAndStData - Get static vertex data and tex coords +;//--------------------------------------------------------- +#macro GetVertAndStData: t_vertData, t_stData + iaddiu t_vertData, vi00, VU1_MCPIP_CULL_STATIC_VERTEX_DATA + iaddiu t_stData, vi00, VU1_MCPIP_CULL_STATIC_TEX_COORD_DATA +#endmacro + +;//--------------------------------------------------------- +;// GetBlockData - Get mvp matrix, color, st offset for single block +;//--------------------------------------------------------- +#macro GetBlockData: t_blockData, t_model, t_color, t_stOffset + lq t_model[0], 0(t_blockData) + lq t_model[1], 1(t_blockData) + lq t_model[2], 2(t_blockData) + lq t_model[3], 3(t_blockData) + lq t_color, 4(t_blockData) + lq t_stOffset, 5(t_blockData) +#endmacro + +;//--------------------------------------------------------- +;// GetVertexData - Get vertex and tex coord +;//--------------------------------------------------------- +#macro GetVertexData: t_vertData, t_stqData, t_vertex, t_stq, t_offset + lq t_vertex, t_offset(t_vertData) + lq t_stq, t_offset(t_stqData) +#endmacro + +;//--------------------------------------------------------- +;// GetVertexData - Get vertex and tex coord +;//--------------------------------------------------------- +#macro AddSTOffset: t_stq, t_stqOffset + add t_stq, t_stq, t_stqOffset +#endmacro diff --git a/engine/src/renderer/3d/pipeline/minecraft/programs/cull/mcpip_cull.cpp b/engine/src/renderer/3d/pipeline/minecraft/programs/cull/mcpip_cull.cpp new file mode 100644 index 0000000..3175121 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/minecraft/programs/cull/mcpip_cull.cpp @@ -0,0 +1,146 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/minecraft/programs/cull/mcpip_cull.hpp" + +namespace Tyra { + +McpipCull::McpipCull() { + staticPacket = packet2_create(8, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); +} + +McpipCull::~McpipCull() { packet2_free(staticPacket); } + +void McpipCull::init(RendererCore* core, McpipBlockData* t_blockData, + prim_t* t_prim, lod_t* t_lod) { + prim = t_prim; + lod = t_lod; + blockData = t_blockData; + rendererCore = core; + initStaticPacket(); + setDBufferSize(); +} + +void McpipCull::setDBufferSize() { + vu1DBufferSize = 1000; // VU1 mem size + vu1DBufferSize -= VU1_MCPIP_CULL_STATIC_LAST_DATA_ADDR; // static data + + // Our additional, mini output double buffer at the bottom of VU1 mem + u16 miniOutputDoubleBufferSize = + blockData->count * 3 + + 5; // 36 * (ST, XYZ2, RGBAQ) + Set, lod, set, clut, prim + + vu1DBufferSize -= miniOutputDoubleBufferSize; // First + vu1DBufferSize -= miniOutputDoubleBufferSize; // Second + + TYRA_ASSERT(1000 - (miniOutputDoubleBufferSize * 2) == + VU1_MCPIP_CULL_DYNAMIC_OUTPUT_DOUBLE_BUFF1_ADDR, + "There is mismatch in output dbuffer1 size. Should be: ", + 1000 - (miniOutputDoubleBufferSize * 2), + "but is: ", VU1_MCPIP_CULL_DYNAMIC_OUTPUT_DOUBLE_BUFF1_ADDR); + + TYRA_ASSERT(1000 - miniOutputDoubleBufferSize == + VU1_MCPIP_CULL_DYNAMIC_OUTPUT_DOUBLE_BUFF2_ADDR, + "There is mismatch in output dbuffer2 size. Should be: ", + 1000 - miniOutputDoubleBufferSize, + "but is: ", VU1_MCPIP_CULL_DYNAMIC_OUTPUT_DOUBLE_BUFF2_ADDR); + + vu1DBufferSize /= 2; // xtop double buffer +} + +u32 McpipCull::uploadVU1Program(McpipProgramsRepository* repo, + const u32& addr) { + auto* program = repo->getProgram(McpipProgramName::McPipCull); + return rendererCore->renderer3D.uploadVU1Program(program, addr); +} + +void McpipCull::configureVU1AndSendStaticData() { + rendererCore->renderer3D.setVU1DoubleBuffers( + VU1_MCPIP_CULL_STATIC_LAST_DATA_ADDR, vu1DBufferSize); + + sendVU1StaticData(); +} + +u32 McpipCull::getMaxBlocksCountPerQBuffer() const { + u32 result = vu1DBufferSize; + result -= 1; // VU1_MCPIP_CULL_DYNAMIC_SCALE_AND_BLOCKS_COUNT; + result -= 1; // Lod tag + result -= 4; // View proj + + result /= VU1_MCPIP_CULL_QWORDS_PER_BLOCK; + + return result; +} + +void McpipCull::initStaticPacket() { + packet2_utils_vu_open_unpack(staticPacket, VU1_MCPIP_CULL_STATIC_LOD, false); + { + packet2_utils_gs_add_lod(staticPacket, lod); + + packet2_utils_gs_add_prim_giftag(staticPacket, prim, 36, + ((u64)GIF_REG_ST) << 0 | + ((u64)GIF_REG_RGBAQ) << 4 | + ((u64)GIF_REG_XYZ2) << 8, + 3, 0); + packet2_utils_gif_add_set(staticPacket, 1); + + packet2_add_u32(staticPacket, 0); // Param1 - Mini double buffer switcher + packet2_add_u32(staticPacket, 0); + packet2_add_u32(staticPacket, 0); + packet2_add_u32(staticPacket, + 1); // static 1 - used in VU1's GetDestinationAddress{} + } + packet2_utils_vu_close_unpack(staticPacket); + + packet2_utils_vu_add_end_tag(staticPacket); +} + +void McpipCull::sendVU1StaticData() { + dma_channel_wait(DMA_CHANNEL_VIF1, 0); + dma_channel_send_packet2(staticPacket, DMA_CHANNEL_VIF1, true); +} + +void McpipCull::addData(packet2_t* packet, McpipBlock** blockPointerArray, + u32 blockPointerArrayCount, + RendererCoreTextureBuffers* texBuffers, bool isMulti) { + rendererCore->texture.updateClutBuffer(texBuffers->clut); + + packet2_utils_vu_open_unpack( + packet, VU1_MCPIP_CULL_DYNAMIC_SCALE_AND_BLOCKS_COUNT_ADDR, true); + { + packet2_add_float(packet, 2048.0F); // scale + packet2_add_float(packet, 2048.0F); // scale + packet2_add_float(packet, + static_cast(0xFFFFFF) / 32.0F); // scale + packet2_add_u32(packet, blockPointerArrayCount); // blocks count + + packet2_utils_gs_add_texbuff_clut(packet, texBuffers->core, + &rendererCore->texture.clut); + + Packet2TyraUtils::addM4x4(packet, rendererCore->renderer3D.getViewProj()); + } + packet2_utils_vu_close_unpack(packet); + + u32 addr = VU1_MCPIP_CULL_DYNAMIC_BLOCKS_DATA; + + for (u32 i = 0; i < blockPointerArrayCount; i++) { + packet2_utils_vu_add_unpack_data(packet, addr, blockPointerArray[i]->model, + 4, true); + addr += 4; + packet2_utils_vu_add_unpack_data(packet, addr, blockPointerArray[i]->color, + 1, true); + addr += 1; + packet2_utils_vu_add_unpack_data( + packet, addr, blockPointerArray[i]->textureOffset, 1, true); + addr += 1; + } +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/minecraft/programs/cull/mcpip_cull_vu1.vclpp b/engine/src/renderer/3d/pipeline/minecraft/programs/cull/mcpip_cull_vu1.vclpp new file mode 100644 index 0000000..6f38180 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/minecraft/programs/cull/mcpip_cull_vu1.vclpp @@ -0,0 +1,129 @@ +; _____ ____ ___ +; | \/ ____| |___| +; | | | \ | | +;--------------------------------------------------------------- +; Copyright 2022, tyra - https://github.com/h4570/tyra +; Licensed under Apache License 2.0 +; Sandro Sobczyński +; +;--------------------------------------------------------------- +; Super fast renderer of minecraft blocks. +; Block data is statically allocated in vi00 +; +; - Triangle list +; - Cull = transform +; - Colors +;--------------------------------------------------------------- + +.syntax new +.name VU1BlocksCull +.vu +.init_vf_all +.init_vi_all + +#include "src/renderer/3d/pipeline/shared/vcl_sml.i" +#include "inc/renderer/3d/pipeline/minecraft/programs/cull/mcpip_vu1_cull_shared_defines.h" +#include "src/renderer/3d/pipeline/minecraft/programs/cull/macros.i" + +#define STQ_STORE_OFFSET 0 +#define RGBA_STORE_OFFSET 1 +#define XYZ2_STORE_OFFSET 2 + +--enter +--endenter + +#vuprog VU1BlocksCull + +GetVertAndStData{ staticVertexData, staticStqData } +ResetClipFlags{ } + +begin: + +xtop buffer +iaddiu blockData, buffer, VU1_MCPIP_CULL_DYNAMIC_BLOCKS_DATA +LoadBufferDynamicData{ buffer, scale, clutTex, blocksCount, viewProj } + +;--- Loop +iadd blockCounter, buffer, blocksCount + +blocksLoop: + + GetBlockData{ blockData, model, color, stOffset } + MatrixMultiply{ mvp, model, viewProj } + FixColor{ color } + GetDestinationAddress{ destAddress, kickAddress } + StoreBlockizerLodClutTexPrim{ destAddress, clutTex } + iaddiu vertexData, staticVertexData, 0 + iaddiu stqData, staticStqData, 0 + + iaddiu vertexCounter, buffer, VU1_MCPIP_CULL_VERTEX_COUNT +vertexLoop: + + GetVertexData{ vertexData, stqData, vertex1, stq1, 0 } + GetVertexData{ vertexData, stqData, vertex2, stq2, 1 } + GetVertexData{ vertexData, stqData, vertex3, stq3, 2 } + + ;--- Calculate vertex1 + MatrixMultiplyVertex{ vertex1, mvp, vertex1 } + PerformClipCheck{ vertex1, destAddress, XYZ2_STORE_OFFSET } + VertexPersCorr{ vertex1, vertex1 } + ScaleVertexToGSFormat{ scale, vertex1 } + AddSTOffset{ stq1, stOffset } + PerformTexturePerspectiveCorrection{ outputStq1, stq1 } + + ;--- Calculate vertex2 + MatrixMultiplyVertex{ vertex2, mvp, vertex2 } + PerformClipCheck{ vertex2, destAddress, XYZ2_STORE_OFFSET+3 } + VertexPersCorr{ vertex2, vertex2 } + ScaleVertexToGSFormat{ scale, vertex2 } + AddSTOffset{ stq2, stOffset } + PerformTexturePerspectiveCorrection{ outputStq2, stq2 } + + ;--- Calculate vertex3 + MatrixMultiplyVertex{ vertex3, mvp, vertex3 } + PerformClipCheck{ vertex3, destAddress, XYZ2_STORE_OFFSET+6 } + VertexPersCorr{ vertex3, vertex3 } + ScaleVertexToGSFormat{ scale, vertex3 } + AddSTOffset{ stq3, stOffset } + PerformTexturePerspectiveCorrection{ outputStq3, stq3 } + + ;--- Store vertex1 + sq outputStq1, STQ_STORE_OFFSET(destAddress) + sq color, RGBA_STORE_OFFSET(destAddress) + sq.xyz vertex1, XYZ2_STORE_OFFSET(destAddress) + + ;--- Store vertex2 + sq outputStq2, STQ_STORE_OFFSET+3(destAddress) + sq color, RGBA_STORE_OFFSET+3(destAddress) + sq.xyz vertex2, XYZ2_STORE_OFFSET+3(destAddress) + + ;--- Store vertex3 + sq outputStq3, STQ_STORE_OFFSET+6(destAddress) + sq color, RGBA_STORE_OFFSET+6(destAddress) + sq.xyz vertex3, XYZ2_STORE_OFFSET+6(destAddress) + + iaddiu vertexData, vertexData, 3 + iaddiu stqData, stqData, 3 + iaddiu destAddress, destAddress, 9 + + iaddi vertexCounter, vertexCounter, -3 + ibne vertexCounter, buffer, vertexLoop + ; End of vertex loop + +--barrier + + xgkick kickAddress + + iaddiu blockData, blockData, VU1_MCPIP_CULL_QWORDS_PER_BLOCK + iaddi blockCounter, blockCounter, -1 + ibne blockCounter, buffer, blocksLoop + ; End of block loop + +--cont + +b begin + +#endvuprog + +--exit +--endexit diff --git a/engine/src/renderer/3d/pipeline/minecraft/programs/cull/mcpip_cull_vu1_program.cpp b/engine/src/renderer/3d/pipeline/minecraft/programs/cull/mcpip_cull_vu1_program.cpp new file mode 100644 index 0000000..8e10508 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/minecraft/programs/cull/mcpip_cull_vu1_program.cpp @@ -0,0 +1,28 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/minecraft/programs/cull/mcpip_cull_vu1_program.hpp" + +extern u32 VU1BlocksCull_CodeStart __attribute__((section(".vudata"))); +extern u32 VU1BlocksCull_CodeEnd __attribute__((section(".vudata"))); + +namespace Tyra { + +McpipCullVU1Program::McpipCullVU1Program() + : McpipProgram(McpipProgramName::McPipCull, &VU1BlocksCull_CodeStart, + &VU1BlocksCull_CodeEnd) {} + +McpipCullVU1Program::~McpipCullVU1Program() {} + +std::string McpipCullVU1Program::getStringName() const { + return std::string("McPip - Cull"); +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/minecraft/programs/mcpip_program.cpp b/engine/src/renderer/3d/pipeline/minecraft/programs/mcpip_program.cpp new file mode 100644 index 0000000..35471de --- /dev/null +++ b/engine/src/renderer/3d/pipeline/minecraft/programs/mcpip_program.cpp @@ -0,0 +1,23 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/minecraft/programs/mcpip_program.hpp" + +namespace Tyra { + +McpipProgram::McpipProgram(const McpipProgramName& t_name, u32* t_start, + u32* t_end) + : VU1Program(t_start, t_end), name(t_name) {} + +McpipProgram::~McpipProgram() {} + +const McpipProgramName& McpipProgram::getName() const { return name; } + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/minecraft/programs/mcpip_programs_manager.cpp b/engine/src/renderer/3d/pipeline/minecraft/programs/mcpip_programs_manager.cpp new file mode 100644 index 0000000..248a7a6 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/minecraft/programs/mcpip_programs_manager.cpp @@ -0,0 +1,177 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/minecraft/programs/mcpip_programs_manager.hpp" + +namespace Tyra { + +BlockizerProgramsManager::BlockizerProgramsManager() { + lastProgramName = UndefinedMcpipProgram; + context = 0; + vu1BlockData = BlockNotUploaded; + + dma_channel_initialize(DMA_CHANNEL_VIF1, nullptr, 0); + + setProgramsCache(); +} + +void BlockizerProgramsManager::allocateOnUse() { + dynamicPackets[0] = packet2_create(800, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); + dynamicPackets[1] = packet2_create(800, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); + staticPacket = packet2_create(2, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); +} + +void BlockizerProgramsManager::deallocateOnUse() { + packet2_free(dynamicPackets[0]); + packet2_free(dynamicPackets[1]); + packet2_free(staticPacket); +} + +BlockizerProgramsManager::~BlockizerProgramsManager() { + packet2_free(programsPacket); +} + +void BlockizerProgramsManager::init(RendererCore* core, prim_t* prim, + lod_t* lod) { + rendererCore = core; + culler.init(core, &singleTexBlockData, prim, lod); + clipper.init(core, &singleTexBlockData, &multiTexBlockData, prim, lod); +} + +void BlockizerProgramsManager::setProgramsCache() { + VU1Program** programs = new VU1Program*[2]; + programs[0] = repo.getProgram(McpipProgramName::McPipCull); + programs[1] = repo.getProgram(McpipProgramName::McPipAsIs); + programsPacket = + rendererCore->getPath1()->createProgramsCache(programs, 2, 0); + delete[] programs; +} + +void BlockizerProgramsManager::uploadVU1Programs() { + dma_channel_wait(DMA_CHANNEL_VIF1, 0); + dma_channel_send_packet2(programsPacket, DMA_CHANNEL_VIF1, true); + dma_channel_wait(DMA_CHANNEL_VIF1, 0); + lastProgramName = UndefinedMcpipProgram; + vu1BlockData = BlockNotUploaded; +} + +void BlockizerProgramsManager::uploadBlock(bool isMulti) { + if (vu1BlockData != BlockNotUploaded) { + if (isMulti && vu1BlockData == BlockMultiUploaded) { + return; + } + } else { + if (!isMulti && vu1BlockData == BlockSingleUploaded) { + return; + } + } + + packet2_reset(staticPacket, false); + + const McpipBlockData& blockData = + isMulti ? static_cast(multiTexBlockData) + : static_cast(singleTexBlockData); + + packet2_utils_vu_add_unpack_data( + staticPacket, VU1_MCPIP_CULL_STATIC_VERTEX_DATA, blockData.comboData, + blockData.getComboCount(), false); + + packet2_utils_vu_add_end_tag(staticPacket); + + vu1BlockData = isMulti ? BlockMultiUploaded : BlockSingleUploaded; + dma_channel_wait(DMA_CHANNEL_VIF1, 0); + dma_channel_send_packet2(staticPacket, DMA_CHANNEL_VIF1, true); +} + +void BlockizerProgramsManager::cullSpam(McpipBlock*** blockPointerArrays, + u32* blockPointerArrayCounts, + u32 blockPointerArraysCount, + RendererCoreTextureBuffers* texBuffers, + const bool& isMulti) { + uploadBlock(isMulti); + + auto* currentPacket = dynamicPackets[context]; + + auto* program = repo.getProgram(McpipProgramName::McPipCull); + + packet2_reset(currentPacket, false); + + for (u32 i = 0; i < blockPointerArraysCount; i++) { + auto* blockPointerArray = blockPointerArrays[i]; + auto blockPointerArrayCount = blockPointerArrayCounts[i]; + + culler.addData(currentPacket, blockPointerArray, blockPointerArrayCount, + texBuffers, isMulti); + + addProgram(program); + } + + sendPacket(program); +} + +void BlockizerProgramsManager::cull(McpipBlock** blockPointerArray, + u32 blockPointerArrayCount, + RendererCoreTextureBuffers* texBuffers, + const bool& isMulti) { + uploadBlock(isMulti); + + auto* currentPacket = dynamicPackets[context]; + + auto* program = repo.getProgram(McpipProgramName::McPipCull); + + packet2_reset(currentPacket, false); + + culler.addData(currentPacket, blockPointerArray, blockPointerArrayCount, + texBuffers, isMulti); + + addProgram(program); + sendPacket(program); +} + +void BlockizerProgramsManager::clip(McpipBlock* block, + RendererCoreTextureBuffers* texBuffers, + const bool& isMulti) { + vu1BlockData = BlockNotUploaded; + + auto* currentPacket = dynamicPackets[context]; + + auto* program = repo.getProgram(McpipProgramName::McPipAsIs); + + clipper.addData(block, isMulti, texBuffers, currentPacket, context); + + addProgram(program); + sendPacket(program); +} + +void BlockizerProgramsManager::addProgram(McpipProgram* program) { + auto* currentPacket = dynamicPackets[context]; + + if (lastProgramName != program->getName()) { + packet2_utils_vu_add_start_program(currentPacket, + program->getDestinationAddress()); + lastProgramName = program->getName(); + } else { + packet2_utils_vu_add_continue_program(currentPacket); + } +} + +void BlockizerProgramsManager::sendPacket(McpipProgram* program) { + auto* currentPacket = dynamicPackets[context]; + + packet2_utils_vu_add_end_tag(currentPacket); + + dma_channel_wait(DMA_CHANNEL_VIF1, 0); + // dma_wait_fast(); // This have no impact on performance + + dma_channel_send_packet2(currentPacket, DMA_CHANNEL_VIF1, true); + context = !context; +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/minecraft/programs/mcpip_programs_repository.cpp b/engine/src/renderer/3d/pipeline/minecraft/programs/mcpip_programs_repository.cpp new file mode 100644 index 0000000..2c96c92 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/minecraft/programs/mcpip_programs_repository.cpp @@ -0,0 +1,33 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/minecraft/programs/mcpip_programs_repository.hpp" + +namespace Tyra { + +McpipProgramsRepository::McpipProgramsRepository() {} + +McpipProgramsRepository::~McpipProgramsRepository() {} + +McpipProgram* McpipProgramsRepository::getProgram( + const McpipProgramName& name) { + switch (name) { + case McpipProgramName::McPipCull: + return &cull; + case McpipProgramName::McPipAsIs: + return &asIs; + + default: + TYRA_TRAP("Unknown VU1 program name"); + return &cull; + } +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/shared/bag/pipeline_dir_lights_bag.cpp b/engine/src/renderer/3d/pipeline/shared/bag/pipeline_dir_lights_bag.cpp new file mode 100644 index 0000000..0706e34 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/shared/bag/pipeline_dir_lights_bag.cpp @@ -0,0 +1,120 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "debug/debug.hpp" +#include "renderer/3d/pipeline/shared/bag/pipeline_dir_lights_bag.hpp" + +namespace Tyra { + +PipelineDirLightsBag::PipelineDirLightsBag(const bool& manual) { + isAllocated = false; + mode = Auto; + lightColors = nullptr; + lightDirections = nullptr; + if (manual) { + mode = Manual; + } else { + allocate(); + } +} + +PipelineDirLightsBag::~PipelineDirLightsBag() { deallocate(); } + +void PipelineDirLightsBag::setAmbientColor(const Color& color) { + TYRA_ASSERT(mode != Manual, "Ambient color cannot be set in manual mode"); + lightColors[3].set(reinterpret_cast(color)); +} + +void PipelineDirLightsBag::setDirectionalLightColors(Color* colors, + const u8& count) { + for (u8 i = 0; i < count; i++) setDirectionalLightColor(colors[i], i); +} + +void PipelineDirLightsBag::setDirectionalLightDirections(Vec4* directions, + const u8& count) { + for (u8 i = 0; i < count; i++) setDirectionalLightDirection(directions[i], i); +} + +void PipelineDirLightsBag::setDirectionalLightColor(const Color& color, + const u8& index) { + TYRA_ASSERT(mode != Manual, + "Directional lights cannot be set in manual mode"); + TYRA_ASSERT(index < 3, "There are max 3 directional lights"); + lightColors[index].set(reinterpret_cast(color)); +} + +void PipelineDirLightsBag::setDirectionalLightDirection(const Vec4& direction, + const u8& index) { + TYRA_ASSERT(mode != Manual, + "Directional lights cannot be set in manual mode"); + TYRA_ASSERT(index < 3, "There are max 3 directional lights"); + + lightDirections[index].set(direction); +} + +void PipelineDirLightsBag::setLightsManually(Vec4* colors, Vec4* directions) { + deallocate(); + lightColors = colors; + lightDirections = directions; + mode = Manual; +} + +void PipelineDirLightsBag::disableManualMode() { + allocate(); + mode = Auto; +} + +void PipelineDirLightsBag::allocate() { + if (isAllocated) return; + + lightColors = new Vec4[4]; + lightDirections = new Vec4[3]; + + for (u8 i = 0; i < 3; i++) { + lightColors[i].set(0.0F, 0.0F, 0.0F, 1.0F); + } + + lightColors[3].set(.5F, .5F, .5F, 1.0F); // Ambient + + for (u8 i = 0; i < 3; i++) { + lightDirections[i].set(1.0F, 1.0F, 1.0F, 1.0F); + } + + isAllocated = true; +} + +void PipelineDirLightsBag::deallocate() { + if (!isAllocated) return; + + forceDeallocate(); +} + +void PipelineDirLightsBag::forceDeallocate() { + forceDeallocateColors(); + forceDeallocateDirections(); + + isAllocated = false; +} + +void PipelineDirLightsBag::forceDeallocateColors() { + if (lightColors != nullptr) { + delete[] lightColors; + lightColors = nullptr; + } +} + +void PipelineDirLightsBag::forceDeallocateDirections() { + if (lightDirections != nullptr) { + delete[] lightDirections; + lightDirections = nullptr; + } +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/shared/tyra_macros.i b/engine/src/renderer/3d/pipeline/shared/tyra_macros.i new file mode 100644 index 0000000..8d03acd --- /dev/null +++ b/engine/src/renderer/3d/pipeline/shared/tyra_macros.i @@ -0,0 +1,167 @@ +;//-------------------------------------------------------------------------------- +;// Tyra's standard macros library +;//-------------------------------------------------------------------------------- + +;//--------------------------------------------------------- +;// LoadTyraStaticData - Load "Set" gif tag +;//--------------------------------------------------------- +#macro LoadTyraStaticData: t_gifSetTagName + lq t_gifSetTagName, VU1_SET_GIFTAG_ADDR(vi00) +#endmacro + +;//--------------------------------------------------------- +;// LoadTyraLightMatrix - Loads single color. Color is placed in 4th slot of Lights matrix +;//--------------------------------------------------------- +#macro LoadTyraSingleColor: t_singleColor, t_singleColorEnabled, t_singleColorAddr, t_optionsAddr + lq t_singleColor, t_singleColorAddr(vi00) + ilw.x t_singleColorEnabled, t_optionsAddr(vi00) +#endmacro + +;//--------------------------------------------------------- +;// LoadTyraLerpValue - Loads interpolation value. +;//--------------------------------------------------------- +#macro LoadTyraLerpValue: t_lerpValue, t_optionsAddr + lq.y t_lerpValue, t_optionsAddr(vi00) +#endmacro + +;//--------------------------------------------------------- +;// LoadTyraScaleValue - Loads screen scales. +;//--------------------------------------------------------- +#macro LoadTyraScaleValue: t_scale, t_buffer + lq.xyz t_scale, 0(t_buffer) +#endmacro + +;//--------------------------------------------------------- +;// LoadTyraTags - Load lod, texture buffer and clut +;// 1 - GIF tag - texture LOD +;// 2 - GIF tag - Z buffer tests method +;// 3 - GIF tag - texture buffer & CLUT +;//--------------------------------------------------------- +#macro LoadTyraTagsTexture: t_lodGifTag, t_testsGifTag, t_texBufferClutGifTag, t_lodAddr, t_testsAddr, t_ClutAddr + lq t_lodGifTag, t_lodAddr(vi00) + lq t_testsGifTag, t_testsAddr(vi00) + lq t_texBufferClutGifTag, t_ClutAddr(vi00) +#endmacro + +;//--------------------------------------------------------- +;// LoadTyraTags - Load lod, texture buffer and clut +;// 1 - GIF tag - texture LOD +;// 2 - GIF tag - Z buffer tests method +;//--------------------------------------------------------- +#macro LoadTyraTags: t_lodGifTag, t_testsGifTag, t_lodAddr, t_testsAddr + lq t_lodGifTag, t_lodAddr(vi00) + lq t_testsGifTag, t_testsAddr(vi00) +#endmacro + +;//--------------------------------------------------------- +;// LoadTyraPrimTag - Load prim tag +;// 2 - GIF tag - tell GS how many data we will send +;//--------------------------------------------------------- +#macro LoadTyraPrimTag: t_primTag, t_buffer + lq t_primTag, 1(t_buffer) +#endmacro + +;//--------------------------------------------------------- +;// LoadTyraBufferTags - Load scales and prim tag +;// 1 - float : X, Y, Z - scale vector that we will use to scale the verts after projecting them, float : W - vert count. +;// 2 - GIF tag - tell GS how many data we will send +;//--------------------------------------------------------- +#macro LoadTyraBufferTags: t_scale, t_primTag, t_buffer + lq.xyz t_scale, 0(t_buffer) + lq t_primTag, 1(t_buffer) +#endmacro + +;//--------------------------------------------------------- +;// LoadTyraDirectionalLights - Load directions and colors. All are always present +;// - 3 directional lights directions +;// - 3 directional lights colors + ambient color +;//--------------------------------------------------------- +#macro LoadTyraDirectionalLights: t_lightMatrix, t_lightDirections, t_lightsColors, t_ambientColor, t_dirOffset, t_colorOffset, t_matrixOffset + lq.xyz t_lightMatrix[0], t_matrixOffset+0(vi00) + lq.xyz t_lightMatrix[1], t_matrixOffset+1(vi00) + lq.xyz t_lightMatrix[2], t_matrixOffset+2(vi00) + lq.xyz t_lightDirections[0], t_dirOffset(vi00) + lq.xyz t_lightDirections[1], t_dirOffset+1(vi00) + lq.xyz t_lightDirections[2], t_dirOffset+2(vi00) + lq.xyz t_lightsColors[0], t_colorOffset(vi00) + lq.xyz t_lightsColors[1], t_colorOffset+1(vi00) + lq.xyz t_lightsColors[2], t_colorOffset+2(vi00) + lq.xyz t_ambientColor, t_colorOffset+3(vi00) +#endmacro + +;//--------------------------------------------------------- +;// StoreTyraGifTagsTexture - Store gif tags. +;// Not using sqi instruction, because VCL cannot optimize it. +;// Primtag contains information about how many polys we will send +;//--------------------------------------------------------- +#macro StoreTyraGifTagsTexture: t_gifSetTag, t_lodGifTag, t_texBufferClutGifTag, t_primTag, t_testsTag, t_destAddress + sq t_gifSetTag, 0(t_destAddress) + sq t_testsTag, 1(t_destAddress) + sq t_gifSetTag, 2(t_destAddress) + sq t_lodGifTag, 3(t_destAddress) + sq t_gifSetTag, 4(t_destAddress) + sq t_texBufferClutGifTag, 5(t_destAddress) + sq t_primTag, 6(t_destAddress) + iaddiu t_destAddress, t_destAddress, 7 +#endmacro + +;//--------------------------------------------------------- +;// StoreTyraGifTags - Store gif tags. +;// Not using sqi instruction, because VCL cannot optimize it. +;// Primtag contains information about how many polys we will send +;//--------------------------------------------------------- +#macro StoreTyraGifTags: t_gifSetTag, t_lodGifTag, t_primTag, t_testsTag, t_destAddress + sq t_gifSetTag, 0(t_destAddress) + sq t_testsTag, 1(t_destAddress) + sq t_gifSetTag, 2(t_destAddress) + sq t_lodGifTag, 3(t_destAddress) + sq t_primTag, 4(t_destAddress) + iaddiu t_destAddress, t_destAddress, 5 +#endmacro + +;//--------------------------------------------------------- +;// CalculateLights - Based on Dr Fortuna's work +;// +;// 1. Transform by the rotation part of the world matrix +;// 2. "Transform" the normal by the light direction matrix +;// 3. Four intensities, one for each light. +;// 4. Clamp the intensity to 0..1 +;// 5. Transform the intensities by the light colour matrix +;// 6. Load 128 and put it into the alpha value +;// 7. Clamp result to 0-128 values +;// 8. And write to the output buffer +;//--------------------------------------------------------- +#macro CalculateTyraDirectionalLights: t_outputColor, t_normal, t_lightDirections, t_lightColors, t_lightMatrix, t_ambientColor + mul.xyz acc, t_lightMatrix[0], t_normal[x] + madd.xyz acc, t_lightMatrix[1], t_normal[y] + madd.xyz t_normal, t_lightMatrix[2], t_normal[z] + mula.xyz acc, t_lightDirections[0], t_normal[x] + madd.xyz acc, t_lightDirections[1], t_normal[y] + madd.xyz t_outputColor, t_lightDirections[2], t_normal[z] + mini.xyz t_outputColor, t_outputColor, vf00[w] + max.xyz t_outputColor, t_outputColor, vf00[x] + mula.xyz acc, t_lightColors[0], t_outputColor[x] + madda.xyz acc, t_lightColors[1], t_outputColor[y] + madda.xyz acc, t_lightColors[2], t_outputColor[z] + madd.xyz t_outputColor, t_ambientColor, vf00[w] + loi 128 + addi.w t_outputColor, vf00, i +#endmacro + +;//--------------------------------------------------------- +;// LerpXYZ - Linear interpolation between two points +;//--------------------------------------------------------- +#macro LerpXYZ: t_output, t_from, t_to, t_interp + sub.xyz temp1, t_to, t_from + mul.xyz temp2, temp1, t_interp[y] + add.xyz t_output, temp2, t_from +#endmacro + +;//--------------------------------------------------------- +;// Lerp - Linear interpolation between two points +;//--------------------------------------------------------- +#macro Lerp: t_output, t_from, t_to, t_interp + sub temp1, t_to, t_from + mul temp2, temp1, t_interp[y] + add t_output, temp2, t_from +#endmacro \ No newline at end of file diff --git a/engine/src/renderer/3d/pipeline/shared/vcl_sml.i b/engine/src/renderer/3d/pipeline/shared/vcl_sml.i new file mode 100644 index 0000000..92e1123 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/shared/vcl_sml.i @@ -0,0 +1,1430 @@ +;//-------------------------------------------------------------------------------- +;// VCLSML - VCL Standard Macros Library +;// Version 1.4 +;// +;// Geoff Audy, January 17th 2002 Initial macro set +;// Geoff Audy, March 26th 2002 Fixed some macros that were broken +;// Geoff Audy, March 27th 2002 Added some macros, most from Colin Hughes (SCEE) +;// Geoff Audy, April 2002 Added some macros, from Dave Etherton (Angel +;// Studios) +;// Geoff Audy, May 16th 2002 Added the macro "MatrixMultiplyVertexW1", from +;// Mike Healey (Rebellion) +;// Geoff Audy, June 2002 Added "MatrixInverse" from Adrian Stephen +;// (Luxoflux, via newsgroup) +;// Geoff Audy, July 2002 Added macros "Arccos", "QuaternionSlerp" and +;// "DistanceVertexToPlane" +;// Geoff Audy, October 7th 2002 Added macros "VertexLightDir3W1" and +;// "VertexLightDir3AmbW1" +;// Geoff Audy, March 19th 2004 Added a better accuracy "Arccos", from +;// Morten Mikkelsen (IO Interactive) +;// Geoff Audy, March 19th 2004 Added macro "Arcsin", from Morten Mikkelsen +;// (IO Interactive) +;// Geoff Audy, June 10th 2004 Fixed a bug in the macro "VectorDotProductACC". +;// "[z]" was missing at the end of the last line +;// Sandro S., June 18th 2022 Thank you guys for your work... +;// +;// Copyright (C) 2002-2004, Sony Computer Entertainment America Inc. +;// All rights reserved. +;// +;// Note: Some macros generate the following temporary variables: +;// vclsmlftemp: Temporary float register +;// vclsmlitemp: Temporary integer register +;// Some macros generate more temporary variables +;//-------------------------------------------------------------------------------- + +;//-------------------------------------------------------------------- +;// MatrixLoad - Load "matrix" from VU mem location "vumemlocation" + +;// "offset" +;//-------------------------------------------------------------------- +#macro MatrixLoad: matrix, offset, vumemlocation + lq matrix[0], offset+0(vumemlocation) + lq matrix[1], offset+1(vumemlocation) + lq matrix[2], offset+2(vumemlocation) + lq matrix[3], offset+3(vumemlocation) +#endmacro + +;//-------------------------------------------------------------------- +;// MatrixSave - Save "matrix" to VU mem location "vumemlocation" + +;// "offset" +;//-------------------------------------------------------------------- +#macro MatrixSave: matrix,offset,vumemlocation + sq matrix[0], offset+0(vumemlocation) + sq matrix[1], offset+1(vumemlocation) + sq matrix[2], offset+2(vumemlocation) + sq matrix[3], offset+3(vumemlocation) +#endmacro + +;//-------------------------------------------------------------------- +;// MatrixIdentity - Set "matrix" to be an identity matrix +;// Thanks to Colin Hughes (SCEE) for that one +;//-------------------------------------------------------------------- +#macro MatrixIdentity: matrix + add.x matrix[0], vf00, vf00[w] + mfir.yzw matrix[0], vi00 + + mfir.xzw matrix[1], vi00 + add.y matrix[1], vf00, vf00[w] + + mr32 matrix[2], vf00 + + max matrix[3], vf00, vf00 +#endmacro + +;//-------------------------------------------------------------------- +;// MatrixCopy - Copy "matrixsrc" to "matrixdest" +;// Thanks to Colin Hughes (SCEE) for that one +;//-------------------------------------------------------------------- +#macro MatrixCopy: matrixdest, matrixsrc + max matrixdest[0], matrixsrc[0], matrixsrc[0] + move matrixdest[1], matrixsrc[1] + max matrixdest[2], matrixsrc[2], matrixsrc[2] + move matrixdest[3], matrixsrc[3] +#endmacro + +;//-------------------------------------------------------------------- +;// MatrixSwap - Swap the content of "matrix1" and "matrix2" +;// The implementation seems lame, but VCL will convert moves to maxes +;// if it sees fit +;//-------------------------------------------------------------------- +#macro MatrixSwap: matrix1, matrix2 + move vclsmlftemp, matrix1[0] + move matrix1[0], matrix2[0] + move matrix2[0], vclsmlftemp + + move vclsmlftemp, matrix1[1] + move matrix1[1], matrix2[1] + move matrix2[1], vclsmlftemp + + move vclsmlftemp, matrix1[2] + move matrix1[2], matrix2[2] + move matrix2[2], vclsmlftemp + + move vclsmlftemp, matrix1[3] + move matrix1[3], matrix2[3] + move matrix2[3], vclsmlftemp +#endmacro + +;//-------------------------------------------------------------------- +;// MatrixTranspose - Transpose "matrixsrc" to "matresult". It is safe +;// for "matrixsrc" and "matresult" to be the same. +;// Thanks to Colin Hughes (SCEE) for that one +;// Had to modify it though, it was too... smart. +;//-------------------------------------------------------------------- +#macro MatrixTranspose: matresult, matrixsrc + mr32.y vclsmlftemp, matrixsrc[1] + add.z matresult[1], vf00, matrixsrc[2][y] + move.y matresult[2], vclsmlftemp + mr32.y vclsmlftemp, matrixsrc[0] + add.z matresult[0], vf00, matrixsrc[2][x] + mr32.z vclsmlftemp, matrixsrc[1] + mul.w matresult[1], vf00, matrixsrc[3][y] + mr32.x vclsmlftemp, matrixsrc[0] + add.y matresult[0], vf00, matrixsrc[1][x] + move.x matresult[1], vclsmlftemp + mul.w vclsmlftemp, vf00, matrixsrc[3][z] + mr32.z matresult[3], matrixsrc[2] + move.w matresult[2], vclsmlftemp + mr32.w vclsmlftemp, matrixsrc[3] + add.x matresult[3], vf00, matrixsrc[0][w] + move.w matresult[0], vclsmlftemp + mr32.y matresult[3], vclsmlftemp + add.x matresult[2], vf00, vclsmlftemp[y] + + move.x matresult[0], matrixsrc[0] ;// These 4 instructions will be + move.y matresult[1], matrixsrc[1] ;// removed if "matrixsrc" and + move.z matresult[2], matrixsrc[2] ;// "matresult" are the same + move.w matresult[3], matrixsrc[3] ;// +#endmacro + +;//-------------------------------------------------------------------- +;// MatrixMultiply - Multiply 2 matrices, "matleft" and "matright", and +;// output the result in "matresult". Dont forget matrix multipli- +;// cations arent commutative, i.e. left X right wont give you the +;// same result as right X left. +;// +;// Note: ACC register is modified +;//-------------------------------------------------------------------- +#macro MatrixMultiply: matresult, matleft, matright + mul acc, matright[0], matleft[0][x] + madd acc, matright[1], matleft[0][y] + madd acc, matright[2], matleft[0][z] + madd matresult[0], matright[3], matleft[0][w] + mul acc, matright[0], matleft[1][x] + madd acc, matright[1], matleft[1][y] + madd acc, matright[2], matleft[1][z] + madd matresult[1], matright[3], matleft[1][w] + mul acc, matright[0], matleft[2][x] + madd acc, matright[1], matleft[2][y] + madd acc, matright[2], matleft[2][z] + madd matresult[2], matright[3], matleft[2][w] + mul acc, matright[0], matleft[3][x] + madd acc, matright[1], matleft[3][y] + madd acc, matright[2], matleft[3][z] + madd matresult[3], matright[3], matleft[3][w] +#endmacro + +;//---------------------------------------------------- +;// MatrixInverse - Does a full-fledge matrix inversion +;// of "matsrc", and output the result to "matdest". +;// Thanks to Adrian Stephen (Luxoflux) for that one +;// (via newsgroup) +;// +;// Note: ACC and Q registers are modified +;//---------------------------------------------------- +#macro MatrixInverse: matdest, matsrc + opmula.xyz acc, matsrc[2], matsrc[3] ;c0 = src.z.xyz() ^ src.w.xyz(); + opmsub.xyz c0, matsrc[3], matsrc[2] + mul.xyz acc, matsrc[2], matsrc[3][w] ;c1 = src.z.xyz() * src.w.w() - src.w.xyz() * src.z.w(); + msub.xyz c1, matsrc[3], matsrc[2][w] + + mul.xyz t0, c0, matsrc[1] ;dst.x = Vector((src.y.xyz() ^ c1) + c0 * src.y.w()).setw(-DotProd(c0,src.y.xyz())); + + opmula.xyz acc, matsrc[1], c1 + madd.xyz acc, c0, matsrc[1][w] + opmsub.xyz matdest[0], c1, matsrc[1] + + mul.w acc, vf00, vf00[x] + msub.w acc, vf00, t0[x] + msub.w acc, vf00, t0[y] + msub.w matdest[0], vf00, t0[z] + + mul.xyz t0, c0, matsrc[0] ;dst.y = Vector((c1 ^ src.x.xyz()) - c0 * src.x.w()).setw( DotProd(c0,src.x.xyz())); + + opmula.xyz acc, c1, matsrc[0] + msub.xyz acc, c0, matsrc[0][w] + opmsub.xyz matdest[1], matsrc[0], c1 + + mul det, matsrc[0], matdest[0] ; for determinant calc + + mul.w acc, vf00, t0[x] + madd.w acc, vf00, t0[y] + madd.w matdest[1], vf00, t0[z] + + add.w acc, det, det[x] + madd.w acc, vf00, det[y] + madd.w det, vf00, det[z] + + opmula.xyz acc, matsrc[0], matsrc[1] ;c0 = src.x.xyz() ^ src.y.xyz(); + opmsub.xyz c0, matsrc[1], matsrc[0] + mul.xyz acc, matsrc[0], matsrc[1][w] ;c1 = src.x.xyz() * src.y.w() - src.y.xyz() * src.x.w(); + msub.xyz c1, matsrc[1], matsrc[0][w] + + div Q, vf00[w], det[w] + + mul.xyz t0, c0, matsrc[3] ;dst.z = Vector((src.w.xyz() ^ c1) + c0 * src.w.w()).setw(-DotProd(c0,src.w.xyz())); + + opmula.xyz acc, matsrc[3], c1 + madd.xyz acc, c0, matsrc[3][w] + opmsub.xyz matdest[2], c1, matsrc[3] + + mul.w acc, vf00, vf00[x] + msub.w acc, vf00, t0[x] + msub.w acc, vf00, t0[y] + msub.w matdest[2], vf00, t0[z] + + mul.xyz t0, c0, matsrc[2] ;dst.w = Vector((c1 ^ src.z.xyz()) - c0 * src.z.w()).setw( DotProd(c0,src.z.xyz())); + + opmula.xyz acc, c1, matsrc[2] + msub.xyz acc, c0, matsrc[2][w] + opmsub.xyz matdest[3], matsrc[2], c1 + + mul.w acc, vf00, t0[x] + madd.w acc, vf00, t0[y] + madd.w matdest[3], vf00, t0[z] + + mul matdest[0], matdest[0], Q + mul matdest[1], matdest[1], Q + mul matdest[2], matdest[2], Q + mul matdest[3], matdest[3], Q +#endmacro + +;//-------------------------------------------------------------------- +;// LocalizeLightMatrix - Transform the light matrix "lightmatrix" into +;// local space, as described by "matrix", and output the result in +;// "locallightmatrix" +;// +;// Note: ACC register is modified +;//-------------------------------------------------------------------- +#macro LocalizeLightMatrix: locallightmatrix, matrix, lightmatrix + mul acc, lightmatrix[0], matrix[0][x] + madd acc, lightmatrix[1], matrix[0][y] + madd acc, lightmatrix[2], matrix[0][z] + madd locallightmatrix[0], lightmatrix[3], matrix[0][w] + + mul acc, lightmatrix[0], matrix[1][x] + madd acc, lightmatrix[1], matrix[1][y] + madd acc, lightmatrix[2], matrix[1][z] + madd locallightmatrix[1], lightmatrix[3], matrix[1][w] + + mul acc, lightmatrix[0], matrix[2][x] + madd acc, lightmatrix[1], matrix[2][y] + madd acc, lightmatrix[2], matrix[2][z] + madd locallightmatrix[2], lightmatrix[3], matrix[2][w] + + move locallightmatrix[3], lightmatrix[3] +#endmacro + +;//-------------------------------------------------------------------- +;// MatrixMultiplyVertex - Multiply "matrix" by "vertex", and output +;// the result in "vertexresult" +;// +;// Note: Apply rotation, scale and translation +;// Note: ACC register is modified +;//-------------------------------------------------------------------- +#macro MatrixMultiplyVertex: vertexresult, matrix, vertex + mul acc, matrix[0], vertex[x] + madd acc, matrix[1], vertex[y] + madd acc, matrix[2], vertex[z] + madd vertexresult, matrix[3], vertex[w] +#endmacro + +;//-------------------------------------------------------------------- +;// MatrixMultiplyVertexW1 - Multiply "matrix" by "vertex", and output +;// the result in "vertexresult". Assumes 1.f for W field, which will +;// allow for better optimization in most cases, and leaves W free for +;// other uses (ADC flags, scale, etc). +;// +;// Note: Apply rotation, scale and translation +;// Note: ACC register is modified +;//-------------------------------------------------------------------- +#macro MatrixMultiplyVertexW1: vertexresult, matrix, vertex + mul acc, matrix[3], vf00[w] + madd acc, matrix[0], vertex[x] + madd acc, matrix[1], vertex[y] + madd vertexresult, matrix[2], vertex[z] +#endmacro + +;//--------------------------------------------------------------------- +;// MatrixMultiplyVertexXYZ1 - Multiply "matrix" by "vertex", and output +;// the result in "vertexresult" +;// +;// Note: Apply rotation, scale and translation +;// Note: ACC register is modified +;//--------------------------------------------------------------------- +#macro MatrixMultiplyVertexXYZ1: vertexresult, matrix, vertex + mul acc, matrix[0], vertex[x] + madd acc, matrix[1], vertex[y] + madd acc, matrix[2], vertex[z] + madd vertexresult, matrix[3], vf00[w] +#endmacro + +;//-------------------------------------------------------------------- +;// MatrixMultiplyVector - Multiply "matrix" by "vector", and output +;// the result in "vectorresult" +;// +;// Note: Apply rotation and scale, but no translation +;// Note: ACC register is modified +;//-------------------------------------------------------------------- +#macro MatrixMultiplyVector: vectorresult, matrix, vector + mul acc, matrix[0], vector[x] + madd acc, matrix[1], vector[y] + madd vectorresult, matrix[2], vector[z] +#endmacro + +;//-------------------------------------------------------------------- +;// VectorLoad - Load "vector" from VU mem location "vumemlocation" + +;// "offset" +;//-------------------------------------------------------------------- +#macro VectorLoad: vector, offset, vumemlocation + lq vector, offset(vumemlocation) +#endmacro + +;//-------------------------------------------------------------------- +;// VectorSave - Save "vector" to VU mem location "vumemlocation" + +;// "offset" +;//-------------------------------------------------------------------- +#macro VectorSave: vector, offset, vumemlocation + sq vector, offset(vumemlocation) +#endmacro + +;//-------------------------------------------------------------------- +;// VectorAdd - Add 2 vectors, "vector1" and "vector2" and output the +;// result in "vectorresult" +;//-------------------------------------------------------------------- +#macro VectorAdd: vectorresult, vector1, vector2 + add vectorresult, vector1, vector2 +#endmacro + +;//-------------------------------------------------------------------- +;// VectorSub - Subtract "vector2" from "vector1", and output the +;// result in "vectorresult" +;//-------------------------------------------------------------------- +#macro VectorSub: vectorresult, vector1, vector2 + sub vectorresult, vector1, vector2 +#endmacro + +;//-------------------------------------------------------------------- +;// VertexLoad - Load "vertex" from VU mem location "vumemlocation" + +;// "offset" +;//-------------------------------------------------------------------- +#macro VertexLoad: vertex, offset, vumemlocation + lq vertex, offset(vumemlocation) +#endmacro + +;//-------------------------------------------------------------------- +;// VertexSave - Save "vertex" to VU mem location "vumemlocation" + +;// "offset" +;//-------------------------------------------------------------------- +#macro VertexSave: vertex, offset, vumemlocation + sq vertex, offset(vumemlocation) +#endmacro + +;//-------------------------------------------------------------------- +;// VertexPersCorr - Apply perspective correction onto "vertex" and +;// output the result in "vertexoutput" +;// +;// Note: Q register is modified +;//-------------------------------------------------------------------- +#macro VertexPersCorr: vertexoutput, vertex + div q, vf00[w], vertex[w] + mul.xyz vertexoutput, vertex, q +; mul vertexoutput, vertex, q +#endmacro + +;//-------------------------------------------------------------------- +;// VertexPersCorrST - Apply perspective correction onto "vertex" and +;// "st", and output the result in "vertexoutput" and "stoutput" +;// +;// Note: Q register is modified +;//-------------------------------------------------------------------- +#macro VertexPersCorrST: vertexoutput, stoutput, vertex, st + div q, vf00[w], vertex[w] + mul.xyz vertexoutput, vertex, q + move.w vertexoutput, vertex +; mul vertexoutput, vertex, q + mul stoutput, st, q +#endmacro + +;//-------------------------------------------------------------------- +;// VertexFPtoGsXYZ2 - Convert an XYZW, floating-point vertex to GS +;// XYZ2 format (ADC bit isnt set) +;//-------------------------------------------------------------------- +#macro VertexFpToGsXYZ2: outputxyz, vertex + ftoi4.xy outputxyz, vertex + ftoi0.z outputxyz, vertex + mfir.w outputxyz, vi00 +#endmacro + +;//-------------------------------------------------------------------- +;// VertexFPtoGsXYZ2Adc - Convert an XYZW, floating-point vertex to GS +;// XYZ2 format (ADC bit is set) +;//-------------------------------------------------------------------- +#macro VertexFpToGsXYZ2Adc: outputxyz, vertex + ftoi4.xy outputxyz, vertex + ftoi0.z outputxyz, vertex + ftoi15.w outputxyz, vf00 +#endmacro + +;//-------------------------------------------------------------------- +;// VertexFpToGsXYZF2 - Convert an XYZF, floating-point vertex to GS +;// XYZF2 format (ADC bit isnt set) +;//-------------------------------------------------------------------- +#macro VertexFpToGsXYZF2: outputxyz, vertex + ftoi4 outputxyz, vertex +#endmacro + +;//-------------------------------------------------------------------- +;// VertexFpToGsXYZF2Adc - Convert an XYZF, floating-point vertex to GS +;// XYZF2 format (ADC bit is set) +;//-------------------------------------------------------------------- +#macro VertexFpToGsXYZF2Adc: outputxyz, vertex + ftoi4 outputxyz, vertex + mtir vclsmlitemp, outputxyz[w] + iaddiu vclsmlitemp, 0x7FFF + iaddi vclsmlitemp, 1 + mfir.w outputxyz, vclsmlitemp +#endmacro + +;//-------------------------------------------------------------------- +;// ColorFPtoGsRGBAQ - Convert an RGBA, floating-point color to GS +;// RGBAQ format +;//-------------------------------------------------------------------- +#macro ColorFPtoGsRGBAQ: outputrgba, color + ftoi0 outputrgba, color +#endmacro + +;//-------------------------------------------------------------------- +;// ColorGsRGBAQtoFP - Convert an RGBA, GS RGBAQ format to floating- +;// point color +;//-------------------------------------------------------------------- +#macro ColorGsRGBAQtoFP: outputrgba, color + itof0 outputrgba, color +#endmacro + +;//-------------------------------------------------------------------- +;// CreateGsPRIM - Create a GS-packed-format PRIM command, according to +;// a specified immediate value "prim" +;// +;// Note: Meant more for debugging purposes than for a final solution +;//-------------------------------------------------------------------- +#macro CreateGsPRIM: outputprim, prim + iaddiu vclsmlitemp, vi00, prim + mfir outputprim, vclsmlitemp +#endmacro + +;//-------------------------------------------------------------------- +;// CreateGsRGBA - Create a GS-packed-format RGBA command, according to +;// specified immediate values "r", "g", "b" and "a" (integer 0-255) +;// +;// Note: Meant more for debugging purposes than for a final solution +;//-------------------------------------------------------------------- +#macro CreateGsRGBA: outputrgba, r, g, b, a + iaddiu vclsmlitemp, vi00, r + mfir.x outputrgba, vclsmlitemp + iaddiu vclsmlitemp, vi00, g + mfir.y outputrgba, vclsmlitemp + iaddiu vclsmlitemp, vi00, b + mfir.z outputrgba, vclsmlitemp + iaddiu vclsmlitemp, vi00, a + mfir.w outputrgba, vclsmlitemp +#endmacro + +;//-------------------------------------------------------------------- +;// CreateGsSTQ - Create a GS-packed-format STQ command, according to +;// specified immediate values "s", "t" and "q" (floats) +;// +;// Note: I register is modified +;// Note: Meant more for debugging purposes than for a final solution +;//-------------------------------------------------------------------- +#macro CreateGsSTQ: outputstq, s, t, q + loi s + add.x outputstq, vf00, i + loi t + add.y outputstq, vf00, i + loi q + add.z outputstq, vf00, i +#endmacro + +;//-------------------------------------------------------------------- +;// CreateGsUV - Create a GS-packed-format VU command, according to +;// specified immediate values "u" and "v" (integer -32768 - 32768, +;// with 4 LSB as precision) +;// +;// Note: Meant more for debugging purposes than for a final solution +;//-------------------------------------------------------------------- +#macro CreateGsUV: outputuv, u, v + iaddiu vclsmlitemp, vi00, u + mfir.x outputuv, vclsmlitemp + iaddiu vclsmlitemp, vi00, v + mfir.y outputuv, vclsmlitemp +#endmacro + +;//-------------------------------------------------------------------- +;// CreateGsRGBA - Create a GS-packed-format RGBA command, according to +;// a specified immediate value "fog" (integer 0-255) +;// +;// Note: Meant more for debugging purposes than for a final solution +;//-------------------------------------------------------------------- +#macro CreateGsFOG: outputfog, fog + iaddiu vclsmlitemp, vi00, fog * 16 + mfir.w outputfog, vclsmlitemp +#endmacro + +;//-------------------------------------------------------------------- +;// CreateGifTag - Create a packed-mode giftag, according to specified +;// immediate values. Currently only support up to 4 registers. +;// +;// Note: I register is modified +;// Note: Definitely meant for debugging purposes, NOT for a final +;// solution +;//-------------------------------------------------------------------- +;// MIGHT NOT BE IMPLEMENTABLE AFTER ALL (AT LEAST NOT UNTIL VCL EVALUATES CONSTANTS!) +;// THAT WOULD HAVE BEEN KINDA COOL... DAMN. --GEOFF +;//#macro CreateGifTag outputgiftag,nloop,prim,nreg,reg1,reg2,reg3,reg4 +;// iaddiu vclsmlitemp, vi00, nloop + 0x8000 +;// mfir.x outputgiftag, vclsmlitemp +;// loi 0x00004000 + (prim * 0x8000) + (nreg * 0x10000000) +;// add.y outputgiftag, vf00, i +;// iaddiu vclsmlitemp, vi00, reg1 + (reg2 * 16) + (reg3 * 256) + (reg4 * 4096) +;// mfir.z outputgiftag, vclsmlitemp +;//#endmacro + +;//-------------------------------------------------------------------- +;// VectorDotProduct - Calculate the dot product of "vector1" and +;// "vector2", and output to "dotproduct"[x] +;//-------------------------------------------------------------------- +#macro VectorDotProduct: dotproduct, vector1, vector2 + mul.xyz dotproduct, vector1, vector2 + add.x dotproduct, dotproduct, dotproduct[y] + add.x dotproduct, dotproduct, dotproduct[z] +#endmacro + +;//-------------------------------------------------------------------- +;// VectorDotProductACC - Calculate the dot product of "vector1" and +;// "vector2", and output to "dotproduct"[x]. This one does it using +;// the ACC register which, depending on the case, might turn out to be +;// faster or slower. +;// +;// Note: ACC register is modified +;//-------------------------------------------------------------------- +#macro VectorDotProductACC: dotproduct, vector1, vector2 + max Vector1111, vf00, vf00[w] + mul vclsmlftemp, vector1, vector2 + add.x acc, vclsmlftemp, vclsmlftemp[y] + madd.x dotproduct, Vector1111, vclsmlftemp[z] +#endmacro + +;//-------------------------------------------------------------------- +;// VectorCrossProduct - Calculate the cross product of "vector1" and +;// "vector2", and output to "vectoroutput" +;// +;// Note: ACC register is modified +;//-------------------------------------------------------------------- +#macro VectorCrossProduct: vectoroutput, vector1, vector2 + opmula.xyz ACC, vector1, vector2 + opmsub.xyz vectoroutput, vector2, vector1 + sub.w vectoroutput, vf00, vf00 +#endmacro + +;//-------------------------------------------------------------------- +;// VectorNormalize - Bring the length of "vector" to 1.f, and output +;// it to "vectoroutput" +;// +;// Note: Q register is modified +;//-------------------------------------------------------------------- +#macro VectorNormalize: vecoutput, vector + mul.xyz vclsmlftemp, vector, vector + add.x vclsmlftemp, vclsmlftemp, vclsmlftemp[y] + add.x vclsmlftemp, vclsmlftemp, vclsmlftemp[z] + rsqrt q, vf00[w], vclsmlftemp[x] + sub.w vecoutput, vf00, vf00 + mul.xyz vecoutput, vector, q +#endmacro + +;//-------------------------------------------------------------------- +;// VectorNormalizeXYZ - Bring the length of "vector" to 1.f, and out- +;// put it to "vectoroutput". The "w" field isn't transfered. +;// +;// Note: Q register is modified +;//-------------------------------------------------------------------- +#macro VectorNormalizeXYZ: vecoutput, vector + mul.xyz vclsmlftemp, vector, vector + add.x vclsmlftemp, vclsmlftemp, vclsmlftemp[y] + add.x vclsmlftemp, vclsmlftemp, vclsmlftemp[z] + rsqrt q, vf00[w], vclsmlftemp[x] + mul.xyz vecoutput, vector, q +#endmacro + +;//-------------------------------------------------------------------- +;// VertexLightAmb - Apply ambient lighting "ambientrgba" to a vertex +;// of color "vertexrgba", and output the result in "outputrgba" +;//-------------------------------------------------------------------- +#macro VertexLightAmb: rgbaout,vertexrgba,ambientrgba + mul rgbaout, vertexrgba, ambientrgba +#endmacro + +;//-------------------------------------------------------------------- +;// VertexLightDir3 - Apply up to 3 directional lights contained in a +;// light matrix "lightmatrix" to a vertex of color "vertexrgba" and +;// having a normal "vertexnormal", and output the result in +;// "outputrgba" +;// +;// Note: ACC register is modified +;//-------------------------------------------------------------------- +#macro VertexLightDir3: rgbaout, vertexrgba, vertexnormal, lightcolors, lightnormals + mul acc, lightnormals[0], vertexnormal[x] + madd acc, lightnormals[1], vertexnormal[y] + madd acc, lightnormals[2], vertexnormal[z] + madd rgbaout, lightnormals[3], vertexnormal[w] ;// Here "rgbaout" is the dot product for the 3 lights + max rgbaout, rgbaout, vf00[x] ;// Here "rgbaout" is the dot product for the 3 lights + mul acc, lightcolors[0], rgbaout[x] + madd acc, lightcolors[1], rgbaout[y] + madd rgbaout, lightcolors[2], rgbaout[z] ;// Here "rgbaout" is the light applied on the vertex + mul rgbaout, vertexrgba, rgbaout ;// Here "rgbaout" is the amount of light reflected by the vertex +#endmacro + +;//-------------------------------------------------------------------- +;// VertexLightDir3W1 - Apply up to 3 directional lights contained in a +;// light matrix "lightmatrix" to a vertex of color "vertexrgba" and +;// having a normal "vertexnormal", and output the result in +;// "outputrgba". Assumes 1.0 for the normal's W field +;// +;// Note: ACC register is modified +;//-------------------------------------------------------------------- +#macro VertexLightDir3W1: rgbaout, vertexrgba, vertexnormal, lightcolors, lightnormals + mul acc, lightnormals[0], vertexnormal[x] + madd acc, lightnormals[1], vertexnormal[y] + madd acc, lightnormals[2], vertexnormal[z] + madd rgbaout, lightnormals[3], vf00[w] ;// Here "rgbaout" is the dot product for the 3 lights + max rgbaout, rgbaout, vf00[x] ;// Here "rgbaout" is the dot product for the 3 lights + mul acc, lightcolors[0], rgbaout[x] + madd acc, lightcolors[1], rgbaout[y] + madd rgbaout, lightcolors[2], rgbaout[z] ;// Here "rgbaout" is the light applied on the vertex + mul rgbaout, vertexrgba, rgbaout ;// Here "rgbaout" is the amount of light reflected by the vertex +#endmacro + +;//-------------------------------------------------------------------- +;// VertexLightDir3Amb - Apply up to 3 directional lights, plus an +;// ambient light contained in a light matrix "lightmatrix" to a vertex +;// of color "vertexrgba" and having a normal "vertexnormal", and +;// output the result in "outputrgba" +;// +;// Note: ACC register is modified +;//-------------------------------------------------------------------- +#macro VertexLightDir3Amb: rgbaout, vertexrgba, vertexnormal, lightcolors, lightnormals + mul acc, lightnormals[0], vertexnormal[x] + madd acc, lightnormals[1], vertexnormal[y] + madd acc, lightnormals[2], vertexnormal[z] + madd rgbaout, lightnormals[3], vertexnormal[w] ;// Here "rgbaout" is the dot product for the 3 lights + max rgbaout, rgbaout, vf00[x] ;// Here "rgbaout" is the dot product for the 3 lights + mul acc, lightcolors[0], rgbaout[x] + madd acc, lightcolors[1], rgbaout[y] + madd acc, lightcolors[2], rgbaout[z] + madd rgbaout, lightcolors[3], rgbaout[w] ;// Here "rgbaout" is the light applied on the vertex + mul.xyz rgbaout, vertexrgba, rgbaout ;// Here "rgbaout" is the amount of light reflected by the vertex +#endmacro + +;//-------------------------------------------------------------------- +;// VertexLightDir3AmbW1 - Apply up to 3 directional lights, plus an +;// ambient light contained in a light matrix "lightmatrix" to a vertex +;// of color "vertexrgba" and having a normal "vertexnormal", and +;// output the result in "outputrgba". Assumes 1.0 for the normal's +;// W field. +;// +;// Note: ACC register is modified +;//-------------------------------------------------------------------- +#macro VertexLightDir3AmbW1: rgbaout, vertexrgba, vertexnormal, lightcolors, lightnormals + mul acc, lightnormals[0], vertexnormal[x] + madd acc, lightnormals[1], vertexnormal[y] + madd acc, lightnormals[2], vertexnormal[z] + madd rgbaout, lightnormals[3], vf00[w] ;// Here "rgbaout" is the dot product for the 3 lights + max rgbaout, rgbaout, vf00[x] ;// Here "rgbaout" is the dot product for the 3 lights + mul acc, lightcolors[0], rgbaout[x] + madd acc, lightcolors[1], rgbaout[y] + madd acc, lightcolors[2], rgbaout[z] + madd rgbaout, lightcolors[3], rgbaout[w] ;// Here "rgbaout" is the light applied on the vertex + mul.xyz rgbaout, vertexrgba, rgbaout ;// Here "rgbaout" is the amount of light reflected by the vertex +#endmacro + +;//-------------------------------------------------------------------- +;// FogSetup - Set up fog "fogparams", by specifying "nearfog" and +;// "farfog". "fogparams" will afterward be ready to be used by fog- +;// related macros, like "VertexFogLinear" for example. +;// +;// Note: I register is modified +;//-------------------------------------------------------------------- +#macro FogSetup: fogparams, nearfogz, farfogz + sub fogparams, vf00, vf00 ;// Set XYZW to 0 + loi farfogz ;// + add.w fogparams, fogparams, i ;// fogparam[w] is farfogz + loi nearfogz + add.z fogparams, fogparams, fogparams[w] + sub.z fogparams, fogparams, i + loi 255.0 + add.xy fogparams, fogparams, i ;// fogparam[y] is 255.0 + sub.x fogparams, fogparams, vf00[w] ;// fogparam[x] is 254.0 + div q, fogparams[y], fogparams[z] + sub.z fogparams, fogparams, fogparams + add.z fogparams, fogparams, q ;// fogparam[z] is 255.f / (farfogz - nearfogz) +#endmacro + +;//-------------------------------------------------------------------- +;// VertexFogLinear - Apply fog "fogparams" to a vertex "xyzw", and +;// output the result in "xyzfoutput". "xyzw" [w] is assumed to be +;// the distance from the camera. "fogparams" must contain farfogz in +;// [w], and (255.f / (farfogz - nearfogz)) in [z]. "xyzfoutputf" [w] +;// will contain a float value between 0.0 and 255.0, inclusively. +;//-------------------------------------------------------------------- +#macro VertexFogLinear: xyzfoutput, xyzw, fogparams + move.xyz xyzfoutput, xyzw ;// XYZ part won't be modified + sub.w xyzfoutput, fogparams, xyzw[w] ;// fog = (farfogz - z) * 255.0 / + mul.w xyzfoutput, xyzfoutput, fogparams[z] ;// (farfogz - nearfogz) + max.w xyzfoutput, xyzfoutput, vf00[x] ;// Clamp fog values outside the range 0.0-255.0 + mini.w xyzfoutput, xyzfoutput, fogparams[y] ;// +#endmacro + +;//-------------------------------------------------------------------- +;// VertexFogRemove - Remove any effect of fog to "xyzf". "fogparams" +;// [ x ] must be set to 254.0. "xyzf" will be modified directly. +;//-------------------------------------------------------------------- +#macro VertexFogRemove: xyzf, fogparams + add.w xyzf, vf00, fogparams[x] ;// xyzw[w] = 1.0 + 254.0 = 255.0 = no fog +#endmacro + +;//-------------------------------------------------------------------- +;// PushInteger1 - Push "integer1" on "stackptr" +;// +;// Note: "stackptr" is updated +;//-------------------------------------------------------------------- +#macro PushInteger1: stackptr, integer1 + isubiu stackptr, stackptr, 1 + iswr.x integer1, (stackptr):VCLSML_STACK +#endmacro + +;//-------------------------------------------------------------------- +;// PushInteger2 - Push "integer1" and "integer2" on "stackptr" +;// +;// Note: "stackptr" is updated +;//-------------------------------------------------------------------- +#macro PushInteger2: stackptr, integer1, integer2 + isubiu stackptr, stackptr, 1 + iswr.x integer1, (stackptr):VCLSML_STACK + iswr.y integer2, (stackptr):VCLSML_STACK +#endmacro + +;//-------------------------------------------------------------------- +;// PushInteger3 - Push "integer1", "integer2" and "integer3" on +;// "stackptr" +;// +;// Note: "stackptr" is updated +;//-------------------------------------------------------------------- +#macro PushInteger3: stackptr, integer1, integer2, integer3 + isubiu stackptr, stackptr, 1 + iswr.x integer1, (stackptr):VCLSML_STACK + iswr.y integer2, (stackptr):VCLSML_STACK + iswr.z integer3, (stackptr):VCLSML_STACK +#endmacro + +;//-------------------------------------------------------------------- +;// PushInteger4 - Push "integer1", "integer2", "integer3" and +;// "integer4" on "stackptr" +;// +;// Note: "stackptr" is updated +;//-------------------------------------------------------------------- +#macro PushInteger4: stackptr, integer1, integer2, integer3, integer4 + isubiu stackptr, stackptr, 1 + iswr.x integer1, (stackptr):VCLSML_STACK + iswr.y integer2, (stackptr):VCLSML_STACK + iswr.z integer3, (stackptr):VCLSML_STACK + iswr.w integer4, (stackptr):VCLSML_STACK +#endmacro + +;//-------------------------------------------------------------------- +;// PopInteger1 - Pop "integer1" on "stackptr" +;// +;// Note: "stackptr" is updated +;//-------------------------------------------------------------------- +#macro PopInteger1: stackptr, integer1 + ilwr.x integer1, (stackptr):VCLSML_STACK + iaddiu stackptr, stackptr, 1 +#endmacro + +;//-------------------------------------------------------------------- +;// PopInteger2 - Pop "integer1" and "integer2" on "stackptr" +;// +;// Note: "stackptr" is updated +;//-------------------------------------------------------------------- +#macro PopInteger2: stackptr, integer1, integer2 + ilwr.y integer2, (stackptr):VCLSML_STACK + ilwr.x integer1, (stackptr):VCLSML_STACK + iaddiu stackptr, stackptr, 1 +#endmacro + +;//-------------------------------------------------------------------- +;// PopInteger3 - Pop "integer1", "integer2" and "integer3" on +;// "stackptr" +;// +;// Note: "stackptr" is updated +;//-------------------------------------------------------------------- +#macro PopInteger3: stackptr, integer1, integer2, integer3 + ilwr.z integer3, (stackptr):VCLSML_STACK + ilwr.y integer2, (stackptr):VCLSML_STACK + ilwr.x integer1, (stackptr):VCLSML_STACK + iaddiu stackptr, stackptr, 1 +#endmacro + +;//-------------------------------------------------------------------- +;// PopInteger4 - Pop "integer1", "integer2", "integer3" and +;// "integer4" on "stackptr" +;// +;// Note: "stackptr" is updated +;//-------------------------------------------------------------------- +#macro PopInteger4: stackptr, integer1, integer2, integer3, integer4 + ilwr.w integer4, (stackptr):VCLSML_STACK + ilwr.z integer3, (stackptr):VCLSML_STACK + ilwr.y integer2, (stackptr):VCLSML_STACK + ilwr.x integer1, (stackptr):VCLSML_STACK + iaddiu stackptr, stackptr, 1 +#endmacro + +;//-------------------------------------------------------------------- +;// PushMatrix - Push "matrix" onto the "stackptr" +;// +;// Note: "stackptr" is updated +;//-------------------------------------------------------------------- +#macro PushMatrix: stackptr, matrix + sq matrix[0], -1(stackptr):VCLSML_STACK + sq matrix[1], -2(stackptr):VCLSML_STACK + sq matrix[2], -3(stackptr):VCLSML_STACK + sq matrix[3], -4(stackptr):VCLSML_STACK + iaddi stackptr, stackptr, -4 +#endmacro + +;//-------------------------------------------------------------------- +;// PopMatrix - Pop "matrix" out of the "stackptr" +;// +;// Note: "stackptr" is updated +;//-------------------------------------------------------------------- +#macro PopMatrix: stackptr, matrix + lq matrix[0], 0(stackptr):VCLSML_STACK + lq matrix[1], 1(stackptr):VCLSML_STACK + lq matrix[2], 2(stackptr):VCLSML_STACK + lq matrix[3], 3(stackptr):VCLSML_STACK + iaddi stackptr, stackptr, 4 +#endmacro + +;//-------------------------------------------------------------------- +;// PushVector - Push "vector" onto the "stackptr" +;// +;// Note: "stackptr" is updated +;//-------------------------------------------------------------------- +#macro PushVector: stackptr, vector + sqd vector, (--stackptr):VCLSML_STACK +#endmacro + +;//-------------------------------------------------------------------- +;// PopVector - Pop "vector" out of the "stackptr" +;// +;// Note: "stackptr" is updated +;//-------------------------------------------------------------------- +#macro PopVector: stackptr, vector + lqi vector, (stackptr++):VCLSML_STACK +#endmacro + +;//-------------------------------------------------------------------- +;// PushVertex - Push "vector" onto the "stackptr" +;// +;// Note: "stackptr" is updated +;//-------------------------------------------------------------------- +#macro PushVertex: stackptr, vertex + sqd vertex, (--stackptr):VCLSML_STACK +#endmacro + +;//-------------------------------------------------------------------- +;// PopVertex - Pop "vertex" out of the "stackptr" +;// +;// Note: "stackptr" is updated +;//-------------------------------------------------------------------- +#macro PopVertex: stackptr, vertex + lqi vertex, (stackptr++):VCLSML_STACK +#endmacro + +;//-------------------------------------------------------------------- +;// AngleSinCos - Returns the sin and cos of up to 2 angles, which must +;// be contained in the X and Z elements of "angle". The sin/cos pair +;// will be contained in the X/Y elements of "sincos" for the first +;// angle, and Z/W for the second one. +;// Thanks to Colin Hughes (SCEE) for that one +;// +;// Note: ACC and I registers are modified, and a bunch of temporary +;// variables are created... Maybe bad for VCL register pressure +;//-------------------------------------------------------------------- +#macro AngleSinCos: angle, sincos + move.xz sincos, angle ; To avoid modifying the original angles... + + mul.w sincos, vf00, sincos[z] ; Copy angle from z to w + add.y sincos, vf00, sincos[x] ; Copy angle from x to y + + loi 1.570796 ; Phase difference for sin as cos ( PI/2 ) + sub.xz sincos, sincos, I ; + + abs sincos, sincos ; Mirror cos around zero + + max Vector1111, vf00, vf00[w] ; Initialise all 1s + + loi -0.159155 ; Scale so single cycle is range 0 to -1 ( *-1/2PI ) + mul ACC, sincos, I ; + + loi 12582912.0 ; Apply bias to remove fractional part + msub ACC, Vector1111, I ; + madd ACC, Vector1111, I ; Remove bias to leave original int part + + loi -0.159155 ; Apply original number to leave fraction range only + msub ACC, sincos, I ; + + loi 0.5 ; Ajust range: -0.5 to +0.5 + msub sincos, Vector1111, I ; + + abs sincos, sincos ; Clamp: 0 to +0.5 + + loi 0.25 ; Ajust range: -0.25 to +0.25 + sub sincos, sincos, I ; + + mul anglepower2, sincos, sincos ; a^2 + + loi -76.574959 ; + mul k4angle, sincos, I ; k4 a + + loi -41.341675 ; + mul k2angle, sincos, I ; k2 a + + loi 81.602226 ; + mul k3angle, sincos, I ; k3 a + + mul anglepower4, anglepower2, anglepower2 ; a^4 + mul k4angle, k4angle, anglepower2 ; k4 a^3 + mul ACC, k2angle, anglepower2 ; + k2 a^3 + + loi 39.710659 ; k5 a + mul k2angle, sincos, I ; + + mul anglepower8, anglepower4, anglepower4 ; a^8 + madd ACC, k4angle, anglepower4 ; + k4 a^7 + madd ACC, k3angle, anglepower4 ; + k3 a^5 + loi 6.283185 ; + madd ACC, sincos, I ; + k1 a + madd sincos, k2angle, anglepower8 ; + k5 a^9 +#endmacro + +;//-------------------------------------------------------------------- +;// ArcsinAccurate - Returns an accurate arcsin angle of a value, which +;// must be contained in the X element of "value". X element of "asin" +;// will contain, on return, the angle corresponding to the value. +;// Thanks to Morten Mikkelsen (IO Interactive) for that one +;// +;// Note: ACC, I registers are modified, and a bunch of temporary +;// variables are created... Maybe bad for VCL register pressure +;//-------------------------------------------------------------------- +#macro ArcsinAccurate: value, asin + + add.x acc, vf00, vf00[w] + msub.x Xc, value, value + sqrt Q, Xc[x] ; Xc = sqrt (1 - value * value) + add.x Xc, vf00, q + + mr32.w bflip, value ; Sign in w field of bflip + abs.x Xs, value ; Xs = fabs (value) + + loi 0x3f3504f3 + subi.x bflip, Xs, i ; bflip = (Xs - sqrt (0.5f)) * I + loi 0z7F800000 ; I = big float + mul.xw bflip, bflip, i ; + mini.xw bflip, bflip, vf00[w] ; Minf (&bflip, bflip, 1), Minf (&Sign, Sign, 1) sign should only be zeroif bflip is, so offs should not be affected by this case + + loi -1 ; I = -1.0 + max.xw bflip, bflip, i ; Maxf (&bflip, bflip, -1), Maxf (&Sign, Sign, -1) if x is already zero, then scaling by zero will not matter either when sign is applied + + add.x acc, vf00, bflip[w] + madd.x offs, bflip, bflip[w] ; offs = Sign + Sign * bflip + mul.x bflip, bflip, bflip[w] ; bflip *= Sign + + mini.x temp, Xc, Xs ; temp = fmin (Xc, Xs) + mul.x temp, temp, bflip ; temp *= bflip + + loi 0x3f490fdb ; + mul.x acc, offs, i ; MULA (offs, piquat) + + loi -1.0 ; s1 = -1 (0xbf800000) + madd.x acc, temp, i ; MADDA (s1, temp) + + mul.x x2, temp, temp ; x2 = temp * temp + loi 0xbe2aaaab ; s2 = -1 / 6 + mul.x S2, temp, i ; S2 = s2 * temp + + madd.x acc, S2, x2 ; MADDA (S2, x2) + + mul.x x3, temp, x2 ; x3 = temp * x2 + loi 0xbd36db6e ; s4 = -5 / 112 + mul.x S4, x3, i ; S4 = s4 * x3 + mul.x x5, x2, x3 ; x5 = x2 * x3 + mul.x x4, x2, x2 ; x4 = x2 * x2 + + loi 0xbcf8e38e ; s5 = -35 / 1152 + mul.x S5, x4, i ; S5 = s5 * x4 + + loi 0xbd99999a ; s3 = -3 / 40 + mul.x S3, x2, i ; S3 = s3 * x2 + + madd.x acc, S3, x3 ; MADDA (S3, x3) + madd.x acc, S4, x4 ; MADDA (S4, x4) + madd.x asin, S5, x5 ; MADD (&r, S5, x5) + +#endmacro + +;//-------------------------------------------------------------------- +;// ArccosAccurate - Returns an accurate arccos angle of a value, which +;// must be contained in the X element of "value". X element of "acos" +;// will contain, on return, the angle corresponding to the value. +;// Thanks to Morten Mikkelsen (IO Interactive) for that one +;// +;// Note: ACC, I registers are modified, and a bunch of temporary +;// variables are created... Maybe bad for VCL register pressure +;//-------------------------------------------------------------------- +#macro ArccosAccurate: value, acos + + add.x acc, vf00, vf00[w] + msub.x Xc, value, value + sqrt Q, Xc[x] ; Xc = sqrt (1 - value * value) + add.x Xc, vf00, q ; + + mr32.w bflip, value ; Sign in w field of bflip + abs.x Xs, value ; Xs = fabs (value) + + loi 0x3f3504f3 + subi.x bflip, Xs, i ; bflip = (Xs - sqrt (0.5f)) * I + loi 0z7F800000 ; I = big float + mul.xw bflip, bflip, i ; + mini.xw bflip, bflip, vf00[w] ; Minf (&bflip, bflip, 1), Minf (&Sign, Sign, 1) sign should only be zeroif bflip is, so offs should not be affected by this case + + loi -1 ; I = -1.0 + max.xw bflip, bflip, i ; Maxf (&bflip, bflip, -1), Maxf (&Sign, Sign, -1) if x is already zero, then scaling by zero will not matter either when sign is applied + + mul.x bflip, bflip, bflip[w] ; bflip *= sign + loi 2.0 + sub.w bflip, bflip, i ; (Sign - 2) + add.x offs, bflip, bflip[w] ; offs = (Sign - 2) + Sign * bflip + + mini.x temp, Xc, Xs ; temp = fmin (Xc, Xs) + mul.x temp, temp, bflip ; temp *= bflip + + loi 0xbf490fdb + mul.x acc, offs, i ; MULA (offs, -piquat) + + loi 1.0 ; s1 = 1 (0x3f800000) + madd.x acc, temp, i ; MADDA (s1, temp) + + mul.x x2, temp, temp ; x2 = temp * temp + loi 0x3e2aaaab ; s2 = 1 / 6 + mul.x S2, temp, i ; S2 = s2 * temp + + madd.x acc, S2, x2 ; MADDA (S2, x2) + + mul.x x3, temp, x2 ; x3 = temp * x2 + loi 0x3d36db6e ; s4 = 5 / 112 + mul.x S4, x3, i ; S4 = s4 * x3 + mul.x x5, x2, x3 ; x5 = x2 * x3 + mul.x x4, x2, x2 ; x4 = x2 * x2 + + loi 0x3cf8e38e ; s5 = 35 / 1152 + mul.x S5, x4, i ; S5 = s5 * x4 + + loi 0x3d99999a ; s3 = 3 / 40 + mul.x S3, x2, i ; S3 = s3 * x2 + + madd.x acc, S3, x3 ; MADDA (S3, x3) + madd.x acc, S4, x4 ; MADDA (S4, x4) + madd.x acos, S5, x5 ; MADD (&r, S5, x5) + +#endmacro + +;//-------------------------------------------------------------------- +;// Arccos - Returns the arccos angle of up to 2 values, which must be +;// contained in the X and Z elements of "value". X and Z elements of +;// "acos" will contain, on return, the angles corresponding to the 2 +;// values. +;// +;// ARCCOS(value) may be approximated with the following: +;// mirror = value * -HALFPI + HALFPI; +;// ARCCOS(value) = 2 * mirror - +;// (sin (value * HALFPI) * -HALFPI + HALFPI); +;// +;// Note: ACC and I registers are modified, and a bunch of temporary +;// variables are created... Maybe bad for VCL register pressure +;//-------------------------------------------------------------------- +#macro Arccos: value, acos + loi 1.570796326 ; value * HALFPI + mul.xz acos, value, i ; + + move.xz mirror, value ; Important to do it here, or else it would be invalid for "value" & "acos" to be the same + + ;//// This part is really just a copy of AngleSinCos + loi 1.570796326 ; Phase difference for sin as cos ( PI/2 ) + sub.xz acos, acos, I ; + + abs.xz acos, acos ; Mirror cos around zero + + max.xz Vector1111, vf00, vf00[w] ; Initialise all 1s + + loi -0.159155 ; Scale so single cycle is range 0 to -1 ( *-1/2PI ) + mul.xz ACC, acos, I ; + + loi 12582912.0 ; Apply bias to remove fractional part + msub.xz ACC, Vector1111, I ; + madd.xz ACC, Vector1111, I ; Remove bias to leave original int part + + loi -0.159155 ; Apply original number to leave fraction range only + msub.xz ACC, acos, I ; + + loi 0.5 ; Ajust range: -0.5 to +0.5 + msub.xz acos, Vector1111, I ; + + abs.xz acos, acos ; Clamp: 0 to +0.5 + + loi 0.25 ; Ajust range: -0.25 to +0.25 + sub.xz acos, acos, I ; + + mul.xz anglepower2, acos, acos ; a^2 + + loi -76.574959 ; + mul.xz k4angle, acos, I ; k4 a + + loi -41.341675 ; + mul.xz k2angle, acos, I ; k2 a + + loi 81.602226 ; + mul.xz k3angle, acos, I ; k3 a + + mul.xz anglepower4, anglepower2, anglepower2 ; a^4 + mul.xz k4angle, k4angle, anglepower2 ; k4 a^3 + mul.xz ACC, k2angle, anglepower2 ; + k2 a^3 + + loi 39.710659 ; k5 a + mul.xz k2angle, acos, I ; + + mul.xz anglepower8, anglepower4, anglepower4 ; a^8 + madd.xz ACC, k4angle, anglepower4 ; + k4 a^7 + madd.xz ACC, k3angle, anglepower4 ; + k3 a^5 + loi 6.283185 ; + madd.xz ACC, acos, I ; + k1 a + madd.xz acos, k2angle, anglepower8 ; + k5 a^9 + ;//// This part was really just a copy of AngleSinCos + + loi -1.570796326 ; mirror = value * -HALFPI + HALFPI + mul.xz mirror, mirror, i ; + sub.xz mirror, mirror, i ; + + mul.xz acos, acos, i ; + sub.xz acos, acos, i ; + + add.xz mirror, mirror, mirror ; acos = 2 * mirror - (sin (value * HALFPI) * -HALFPI + HALFPI) + sub.xz acos, mirror, acos ; Final result in "x" +#endmacro + +;//------------------------------------------------------------------------------ +;// QuaternionSlerp - Spherical interpolation between 2 quaternions. "quatfrom" +;// corresponds to time 0.0, and "quatto" corresponds to time 1.0. The X element +;// of "qtime" must contain the desired time value (0.0 - 1.0). The result will +;// be returned in "quatdest". +;// +;// Note: ACC, I and Q registers are modified +;//------------------------------------------------------------------------------ +#macro QuaternionSlerp: quatdest, quatfrom, quatto, qtime + mul vclsmlftemp, quatfrom, quatto ; vclsmlftemp.x = dotproduct4 (quatfrom, quatto) + add.x vclsmlftemp, vclsmlftemp, vclsmlftemp[y] ; + add.x vclsmlftemp, vclsmlftemp, vclsmlftemp[z] ; + add.x vclsmlftemp, vclsmlftemp, vclsmlftemp[w] ; + + loi -1.0 ; + + move QSLquatto1, quatto ; We want to keep the angle between the 2 vectors <= PI + iaddiu vclsmlitemp, vi00, 0x80 ; (vclsmlftemp >= 0.0) + fmand vclsmlitemp, vclsmlitemp ; + ibeq vclsmlitemp, vi00, QSL1@ ; + + mul.x vclsmlftemp, vclsmlftemp, i ; Inverse the "quatto" vector, so the angle between the + mul QSLquatto1, QSLquatto1, i ; 2 vectors will become < PI + +QSL1@: + loi 0.999 ; If the angle is too small, we gotta do a linear + sub.x vf00, vclsmlftemp, i ; interpolation, because the slerp will fail + iaddiu vclsmlitemp, vi00, 0x80 ; (if (0.999 - vclsmlftemp.x < 0.0) it is too small) + fmand vclsmlitemp, vclsmlitemp ; + ibne vclsmlitemp, vi00, QSL2@ ; + + add.x vclsmlftemp, vf00, qtime ; vclsmlftemp.x = qtime.x + add.z vclsmlftemp, vf00, vf00[w] ; vclsmlftemp.z = 1.0 - qtime.x + sub.z vclsmlftemp, vclsmlftemp, qtime[x] ; + + b QSL3@ ; Go straight to the weighting part + +QSL2@: + Arccos vclsmlftemp, QSLangle ; QSLangle.x = acos (vclsmlftemp.x) + AngleSinCos QSLangle, QSLsinom ; QSLsinom.x = sin (QSLangle.x) + + add.z qtime, vf00, vf00[w] ; qtime.z = 1.0 - qtime.x + sub.z qtime, qtime, qtime[x] ; + + mul.xz vclsmlftemp, qtime, QSLangle[x] ; vclsmlftemp.x = sin (time * QSLangle) + AngleSinCos vclsmlftemp, vclsmlftemp ; vclsmlftemp.z = sin ((1.0 - time) * QSLangle) + + div q, vf00[w], QSLsinom[x] ; vclsmlftemp.x = vclsmlftemp.x / QSLsinom.x + mul.xz vclsmlftemp, vclsmlftemp, q ; vclsmlftemp.z = vclsmlftemp.z / QSLsinom.x + +QSL3@: + mul acc, quatfrom, vclsmlftemp[z] ; Now that we have the src and dest scale (0.0 - 1.0), get the final result + madd quatdest, QSLquatto1, vclsmlftemp[x] ; + +#endmacro + +;//-------------------------------------------------------------------- +;// QuaternionToMatrix - Converts a quaternion rotation to a matrix +;// Thanks to Colin Hughes (SCEE) for that one +;// +;// Note: ACC and I registers are modified +;//-------------------------------------------------------------------- +#macro QuaternionToMatrix: matresult, quaternion + mula.xyz ACC, quaternion, quaternion ; xx yy zz + + loi 1.414213562 + muli vclsmlftemp, quaternion, I ; x sqrt2 y sqrt2 z sqrt2 w sqrt2 + + mr32.w matresult[0], vf00 ; Set rhs matrix line 0 to 0 + mr32.w matresult[1], vf00 ; + mr32.w matresult[2], vf00 ; Set rhs matrix + move matresult[3], vf00 ; Set bottom line to 0 0 0 1 + + madd.xyz vcl_2qq, quaternion, quaternion ; 2xx 2yy 2zz + addw.xyz Vector111, vf00, vf00 ; 1 1 1 - + + opmula.xyz ACC, vclsmlftemp, vclsmlftemp ; 2yz 2xz 2xy - + msubw.xyz vclsmlftemp2, vclsmlftemp, vclsmlftemp ; 2yz-2xw 2xz-2yz 2xy-2zw - + maddw.xyz vclsmlftemp3, vclsmlftemp, vclsmlftemp ; 2yz+2xw 2xz+2yz 2xy+2zw - + addaw.xyz ACC, vf00, vf00 ; 1 1 1 - + msubax.yz ACC, Vector111, vcl_2qq ; 1 1-2xx 1-2xx + + msuby.z matresult[2], Vector111, vcl_2qq ; - - 1-2xx-2yy - + msubay.x ACC, Vector111, vcl_2qq ; 1-2yy 1-2xx 1-2xx-2yy - + msubz.y matresult[1], Vector111, vcl_2qq ; - 1-2xx-2zz - - + mr32.y matresult[0], vclsmlftemp2 + msubz.x matresult[0], Vector111, vcl_2qq ; 1-2yy-2zz - - - + mr32.x matresult[2], vclsmlftemp2 + addy.z matresult[0], vf00, vclsmlftemp3 + mr32.w vclsmlftemp, vclsmlftemp2 + mr32.z matresult[1], vclsmlftemp + addx.y matresult[2], vf00, vclsmlftemp3 + mr32.y vclsmlftemp3, vclsmlftemp3 + mr32.x matresult[1], vclsmlftemp3 + +#endmacro + +;//-------------------------------------------------------------------- +;// QuaternionMultiply - Multiplies "quaternion1" and "quaternion2", +;// and puts the result in "quatresult". +;// Thanks to Colin Hughes (SCEE) for that one +;// +;// Note: ACC register is modified +;//-------------------------------------------------------------------- +#macro QuaternionMultiply: quatresult, quaternion1, quaternion2 + mul vclsmlftemp, quaternion1, quaternion2 ; xx yy zz ww + + opmula.xyz ACC, quaternion1, quaternion2 ; Start Outerproduct + madd.xyz ACC, quaternion1, quaternion2[w]; Add w2.xyz1 + madd.xyz ACC, quaternion2, quaternion1[w]; Add w1.xyz2 + opmsub.xyz quatresult, quaternion2, quaternion1 ; Finish Outerproduct + + sub.w ACC, vclsmlftemp, vclsmlftemp[z] ; ww - zz + msub.w ACC, vf00, vclsmlftemp[y] ; ww - zz - yy + msub.w quatresult, vf00, vclsmlftemp[x] ; ww - zz - yy - xx +#endmacro + +;//-------------------------------------------------------------------- +;// TriangleWinding - Compute winding of triangle relative to "eyepos" +;// result is nonzero if winding is CW (actually depends on your +;// coordinate system) +;// Thanks to David Etherton (Angel Studios) for that one +;// +;// Note: ACC register is modified +;//-------------------------------------------------------------------- +#macro TriangleWinding: result, vert1, vert2, vert3, eyepos + sub.xyz tw_vert12, vert2, vert1 + sub.xyz tw_vert13, vert3, vert1 + + opmula.xyz ACC, tw_vert12, tw_vert13 + opmsub.xyz tw_normal, tw_vert13, tw_vert12 + + sub.xyz tw_dot, eyepos, vert1 + + mul.xyz tw_dot, tw_dot, tw_normal + add.x tw_dot, tw_dot, tw_dot[y] + add.x tw_dot, tw_dot, tw_dot[z] + + fsand result, 0x2 +#endmacro + +;//-------------------------------------------------------------------- +;// STATUSFLAGS_BGTZ - Branch if status shows "greater than zero". +;// Thanks to David Etherton (Angel Studios) for that one +;//-------------------------------------------------------------------- +#macro STATUSFLAGS_BGTZ: label + fsand vclsmlitemp, 0x3 ; NEG | ZERO + ibeq vclsmlitemp, VI00, label ; Jump if NEITHER NEG NOR ZERO +#endmacro + +;//-------------------------------------------------------------------- +;// STATUSFLAGS_BGEZ - Branch if status shows "greater or equal to +;// zero". +;// Thanks to David Etherton (Angel Studios) for that one +;//-------------------------------------------------------------------- +#macro STATUSFLAGS_BGEZ: label + fsand vclsmlitemp, 0x2 ; NEG + ibeq vclsmlitemp, VI00, label ; Jump if NOT NEG +#endmacro + +;//-------------------------------------------------------------------- +;// STATUSFLAGS_BLEZ - Branch if status shows "less or equal to zero". +;// Thanks to David Etherton (Angel Studios) for that one +;//-------------------------------------------------------------------- +#macro STATUSFLAGS_BLEZ: label + fsand vclsmlitemp, 0x3 ; NEG | ZERO + ibne vclsmlitemp, VI00, label ; Jump if NEG OR ZERO +#endmacro + +;//-------------------------------------------------------------------- +;// STATUSFLAGS_BLTZ - Branch if status shows "less than zero". +;// Thanks to David Etherton (Angel Studios) for that one +;//-------------------------------------------------------------------- +#macro STATUSFLAGS_BLTZ: label + fsand vclsmlitemp, 0x2 ; NEG + ibne vclsmlitemp, VI00, label ; Jump if NEG +#endmacro + +;//--------------------------------------------------------- +;// DistanceVertexToPlane - Return the distance between a +;// homegeneous vertex "vertex" and a plane (described as +;// ABCD) "plane", and the result is returned in "distance". +;//--------------------------------------------------------- +#macro DistanceVertexToPlane: distance, vertex, plane + mul distance, vertex, plane + add.x distance, distance, distance[y] + add.x distance, distance, distance[z] + add.x distance, distance, distance[w] +#endmacro + +;//--------------------------------------------------------- +;// ResetClipFlags - +;// VCL won't let us use CLIP without first zeroing +;//--------------------------------------------------------- +#macro ResetClipFlags + fcset 0x000000 +#endmacro + +;//--------------------------------------------------------- +;// PerformClipCheck - checks if the vertex is outside the viewing frustum. +;// If it is, then the appropriate clipping flags are set. +;// 2 - Bitwise AND the clipping flags with 0x3FFFF, this makes sure that +;// we get the clipping judgement for the last three verts +;// (i.e. that make up the triangle we are about to draw) +;// 3 - Add 0x7FFF. If any of the clipping flags were set this will +;// cause the triangle not to be drawn (any values above 0x8000 +;// that are stored in the w component of XYZ2 will set the ADC +;// bit, which tells the GS not to perform a drawing kick on this +;// triangle. +;//--------------------------------------------------------- +#macro PerformClipCheck: t_vertex, t_destAddress, t_destAddressOffset + clipw.xyz t_vertex, t_vertex + fcand VI01, 0x3FFFF + iaddiu adcBit, VI01, 0x7FFF + isw.w adcBit, t_destAddressOffset(t_destAddress) +#endmacro + +;//--------------------------------------------------------- +;// ScaleVertexToGSFormat - Scale vertex to GS screen space +;// 2 - Multiply and add the scales -> vert = vert * scale + scale +;// 3 - Convert vertex to 12:4 fixed point format +;//--------------------------------------------------------- +#macro ScaleVertexToGSFormat: t_scale, t_vertex + mula.xyz acc, t_scale, vf00[w] + madd.xyz t_vertex, t_vertex, t_scale + ftoi4.xyz t_vertex, t_vertex +#endmacro + +;//--------------------------------------------------------- +;// PerformTexturePerspectiveCorrection +;//--------------------------------------------------------- +#macro PerformTexturePerspectiveCorrection: t_resultStq, t_stq + mulq t_resultStq, t_stq, q +#endmacro + +;//--------------------------------------------------------- +;// FixColor - Clamp colors to 0-255 and convert to integer +;// +;// 1. Load 255 and put it into the alpha value +;// 2. Clamp result to 0-255 values +;// 3. And write to the output buffer +;//--------------------------------------------------------- +#macro FixColor: t_color + loi 255 + mini.xyz t_color, t_color, i + max.xyz t_color, t_color, vf00[x] + ftoi0 t_color, t_color +#endmacro diff --git a/engine/src/renderer/3d/pipeline/static/core/bag/packaging/stapip_bag_package.cpp b/engine/src/renderer/3d/pipeline/static/core/bag/packaging/stapip_bag_package.cpp new file mode 100644 index 0000000..07fe04a --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/bag/packaging/stapip_bag_package.cpp @@ -0,0 +1,90 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include +#include +#include +#include +#include "renderer/3d/pipeline/static/core/bag/packaging/stapip_bag_package.hpp" + +namespace Tyra { + +StaPipBagPackage::StaPipBagPackage() { + size = 0; + bag = nullptr; + vertices = nullptr; + sts = nullptr; + normals = nullptr; + colors = nullptr; +} +StaPipBagPackage::~StaPipBagPackage() {} + +void StaPipBagPackage::print() const { + auto text = getPrint(nullptr); + printf("%s\n", text.c_str()); +} + +void StaPipBagPackage::print(const char* name) const { + auto text = getPrint(name); + printf("%s\n", text.c_str()); +} + +std::string StaPipBagPackage::getPrint(const char* name) const { + std::stringstream res; + if (name) { + res << name << "("; + } else { + res << "StaPipBagPackage("; + } + res << std::fixed << std::setprecision(2); + res << std::endl; + res << "Size: " << static_cast(size) << std::endl; + + res << "Vectors: " << std::endl; + for (u32 i = 0; i < size; i++) { + res << i << ": " << vertices[i].getPrint() << std::endl; + } + + if (sts != nullptr) { + res << "STs: " << std::endl; + for (u32 i = 0; i < size; i++) + res << i << ": " << sts[i].getPrint() << std::endl; + } + + if (colors != nullptr) { + res << "Colors: " << std::endl; + for (u32 i = 0; i < size; i++) + res << i << ": " << colors[i].getPrint() << std::endl; + } + + if (normals != nullptr) { + res << "Normals: " << std::endl; + for (u32 i = 0; i < size; i++) + res << i << ": " << normals[i].getPrint() << std::endl; + } + + res << "Is in frustum: "; + switch (isInFrustum) { + case CoreBBoxFrustum::IN_FRUSTUM: + res << "Yes"; + break; + case CoreBBoxFrustum::OUTSIDE_FRUSTUM: + res << "No"; + break; + case CoreBBoxFrustum::PARTIALLY_IN_FRUSTUM: + res << "Partially"; + break; + } + + res << ")"; + return res.str(); +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/static/core/bag/packaging/stapip_bag_packager.cpp b/engine/src/renderer/3d/pipeline/static/core/bag/packaging/stapip_bag_packager.cpp new file mode 100644 index 0000000..b8044a6 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/bag/packaging/stapip_bag_packager.cpp @@ -0,0 +1,124 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include +#include +#include "debug/debug.hpp" +#include "renderer/3d/pipeline/static/core/bag/packaging/stapip_bag_packager.hpp" + +namespace Tyra { + +StaPipBagPackager::StaPipBagPackager() {} + +StaPipBagPackager::~StaPipBagPackager() {} + +void StaPipBagPackager::init(Renderer3DFrustumPlanes* t_frustumPlanes) { + frustumPlanes = t_frustumPlanes; +} + +/** + * @brief Create render packages from provided render data + * + * @param size Max maxVertCount verts (VU1 buffer size) + */ +StaPipBagPackage* StaPipBagPackager::create(u16* o_size, StaPipBag* data, + u16 size) { + TYRA_ASSERT(size <= maxVertCount, "StaPipBagPackage can have max ", + maxVertCount, " verts. Provided \"", size, "\""); + + *o_size = ceil(data->count / static_cast(size)); + StaPipBagPackage* result = new StaPipBagPackage[*o_size]; + + for (u16 i = 0; i < *o_size; i++) { + result[i].bag = data; + result[i].vertices = &data->vertices[i * size]; + + if (data->texture) result[i].sts = &data->texture->coordinates[i * size]; + + if (data->color->many) + result[i].colors = + reinterpret_cast(&data->color->many[i * size]); + + if (data->lighting) result[i].normals = &data->lighting->normals[i * size]; + + result[i].indexOf1By3BBox = (i * size) / (maxVertCount / 3); + + if (i == *o_size - 1) { + result[i].size = data->count - i * size; + } else { + result[i].size = size; + } + + result[i].isInFrustum = checkFrustum(result[i]); + } + + return result; +} + +/** + * @brief Split render package to smaller packages + * + * @param size Max maxVertCount verts (VU1 buffer size) + */ +StaPipBagPackage* StaPipBagPackager::create(u16* o_count, + const StaPipBagPackage& pkg, + u16 size) { + TYRA_ASSERT(size <= maxVertCount, "StaPipBagPackage can have max ", + maxVertCount, " verts. Provided \"", size, "\""); + + *o_count = ceil(pkg.size / static_cast(size)); + auto* result = new StaPipBagPackage[*o_count]; + + for (u16 i = 0; i < *o_count; i++) { + result[i].bag = pkg.bag; + result[i].vertices = &pkg.vertices[i * size]; + + if (pkg.bag->texture) result[i].sts = &pkg.sts[i * size]; + + if (pkg.bag->color->many) result[i].colors = &pkg.colors[i * size]; + + if (pkg.bag->lighting) result[i].normals = &pkg.normals[i * size]; + + result[i].indexOf1By3BBox = + pkg.indexOf1By3BBox + ((i * size) / (maxVertCount / 3)); + + if (i == *o_count - 1) { + result[i].size = pkg.size - i * size; + } else { + result[i].size = size; + } + + result[i].isInFrustum = checkFrustum(result[i]); + } + + return result; +} + +CoreBBoxFrustum StaPipBagPackager::checkFrustum(const StaPipBagPackage& pkg) { + if (!renderBBox) return CoreBBoxFrustum::OUTSIDE_FRUSTUM; + + if (pkg.size <= (maxVertCount / 3)) { // Is subpackage + auto& bbox = renderBBox->getChildBBox1By3(pkg.indexOf1By3BBox); + return bbox.clipFrustumCheck(frustumPlanes->getAll(), + *pkg.bag->info->model); + } else { // Is package + const auto& indexOfPart = pkg.indexOf1By3BBox; + auto partSize = ceil(pkg.size / static_cast(maxVertCount / 3)); + auto bbox = renderBBox->createChildBBox(indexOfPart, partSize); + return bbox.clipFrustumCheck(frustumPlanes->getAll(), + *pkg.bag->info->model); + } +} + +void StaPipBagPackager::setMaxVertCount(const u32& count) { + maxVertCount = count; +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/static/core/bag/packaging/stapip_bag_packages_bbox.cpp b/engine/src/renderer/3d/pipeline/static/core/bag/packaging/stapip_bag_packages_bbox.cpp new file mode 100644 index 0000000..c415ad6 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/bag/packaging/stapip_bag_packages_bbox.cpp @@ -0,0 +1,115 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include +#include +#include +#include +#include +#include "debug/debug.hpp" +#include "renderer/3d/pipeline/static/core/bag/packaging/stapip_bag_packages_bbox.hpp" + +namespace Tyra { + +StaPipBagPackagesBBox::StaPipBagPackagesBBox(const Vec4* t_vertices, + u32* t_faces, + const u32& t_facesCount, + const u32& t_maxVertCount) { + u32 splitPartSize = t_maxVertCount / 3; + vertexCount = t_facesCount; + partsCount = ceil(vertexCount / static_cast(splitPartSize)); + + bboxParts = new std::vector; + for (u32 i = 0; i < partsCount; i++) { + u32 partSize = + i == partsCount - 1 ? t_facesCount - i * splitPartSize : splitPartSize; + bboxParts->push_back( + CoreBBox(t_vertices, t_faces + i * splitPartSize, partSize)); + } + mainBBox = new RenderBBox(*bboxParts, 0, partsCount); +} + +StaPipBagPackagesBBox::StaPipBagPackagesBBox(const Vec4* t_vertices, + const u32& t_count, + const u32& t_maxVertCount) { + u32 splitPartSize = t_maxVertCount / 3; + vertexCount = t_count; + partsCount = ceil(vertexCount / static_cast(splitPartSize)); + + bboxParts = new std::vector; + for (u32 i = 0; i < partsCount; i++) { + u32 partSize = + i == partsCount - 1 ? t_count - i * splitPartSize : splitPartSize; + bboxParts->push_back(RenderBBox(t_vertices + i * splitPartSize, partSize)); + } + + mainBBox = new RenderBBox(*bboxParts, 0, partsCount); +} + +StaPipBagPackagesBBox::~StaPipBagPackagesBBox() { + delete bboxParts; + delete mainBBox; +} + +const RenderBBox& StaPipBagPackagesBBox::getChildBBox1By3( + const u32& index) const { + TYRA_ASSERT(index < partsCount, + "Index out of range. Provided index: ", index); + return static_cast(bboxParts->at(index)); +} + +RenderBBox* StaPipBagPackagesBBox::getMainBBox() { return mainBBox; } + +const u32& StaPipBagPackagesBBox::getPartsCount() const { return partsCount; } + +const u32& StaPipBagPackagesBBox::getVertexCount() const { return vertexCount; } + +RenderBBox StaPipBagPackagesBBox::createChildBBox(const u32& index, + const u16& partsSize) const { + return RenderBBox(*bboxParts, index, index + partsSize); +} + +void StaPipBagPackagesBBox::print() const { + auto text = getPrint(nullptr); + printf("%s\n", text.c_str()); +} + +void StaPipBagPackagesBBox::print(const char* name) const { + auto text = getPrint(name); + printf("%s\n", text.c_str()); +} + +std::string StaPipBagPackagesBBox::getPrint(const char* name) const { + std::stringstream res; + if (name) { + res << name << "("; + } else { + res << "StaPipBagPackagesBBox("; + } + res << std::fixed << std::setprecision(2); + res << std::endl; + res << "Vertices count: " << static_cast(vertexCount) << std::endl; + + res << "Main CoreBBox: " << std::endl; + res << mainBBox->getPrint() << std::endl; + + res << "Child BBoxes: " << std::endl; + for (u32 i = 0; i < partsCount; i++) { + res << i << ": " << bboxParts->at(i).getPrint(); + if (i != partsCount - 1) { + res << std::endl; + } + } + + res << ")"; + return res.str(); +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/static/core/bag/stapip_bag.cpp b/engine/src/renderer/3d/pipeline/static/core/bag/stapip_bag.cpp new file mode 100644 index 0000000..34aa3bf --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/bag/stapip_bag.cpp @@ -0,0 +1,86 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/static/core/bag/stapip_bag.hpp" +#include +#include + +namespace Tyra { + +StaPipBag::StaPipBag() { + info = nullptr; + color = nullptr; + texture = nullptr; + lighting = nullptr; +} + +StaPipBag::~StaPipBag() {} + +StaPipBagPackagesBBox StaPipBag::calculateBbox(const u32& maxVertCount) { + TYRA_ASSERT(vertices != nullptr, "Vertices are required to calculate bbox"); + TYRA_ASSERT(count > 0, "Count must be greater than 0 to calculate bbox"); + return StaPipBagPackagesBBox(vertices, count, maxVertCount); +} + +void StaPipBag::print() const { + auto text = getPrint(nullptr); + printf("%s\n", text.c_str()); +} + +void StaPipBag::print(const char* name) const { + auto text = getPrint(name); + printf("%s\n", text.c_str()); +} + +std::string StaPipBag::getPrint(const char* name) const { + std::stringstream res; + if (name) { + res << name << "("; + } else { + res << "StaPipBag("; + } + res << std::fixed << std::setprecision(4); + res << std::endl; + res << "Count: " << count << ", " << std::endl; + res << "Vertices present: " << (vertices != nullptr ? "Yes" : "No") << ", " + << std::endl; + res << "Info present: " << (info != nullptr ? "Yes" : "No") << ", " + << std::endl; + res << "Color present: " << (color != nullptr ? "Yes" : "No") << ", " + << std::endl; + res << "Texture present: " << (texture != nullptr ? "Yes" : "No") << ", " + << std::endl; + res << "Lighting present: " << (lighting != nullptr ? "Yes" : "No") << ", " + << std::endl; + res << "Model matrix: " << info->model->getPrint() << ", " << std::endl; + if (color->single) { + res << "Color single: " << color->single->getPrint() << ", " << std::endl; + } else { + res << "Color many present: " << (color->many != nullptr ? "Yes" : "No") + << ", " << std::endl; + } + if (texture) { + res << "Texture coords present: " + << (texture->coordinates != nullptr ? "Yes" : "No") << ", " + << std::endl; + res << "Texture: " << texture->texture->getPrint() << ", " << std::endl; + } + if (lighting) { + res << "Lighting normals present: " << (lighting->normals ? "Yes" : "No") + << ", " << std::endl; + res << "Lighting matrix: " << lighting->lightMatrix->getPrint() << ", " + << std::endl; + } + res << ")"; + + return res.str(); +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/static/core/bag/stapip_color_bag.cpp b/engine/src/renderer/3d/pipeline/static/core/bag/stapip_color_bag.cpp new file mode 100644 index 0000000..aa4bc2a --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/bag/stapip_color_bag.cpp @@ -0,0 +1,22 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/static/core/bag/stapip_color_bag.hpp" + +namespace Tyra { + +StaPipColorBag::StaPipColorBag() { + single = nullptr; + many = nullptr; +} + +StaPipColorBag::~StaPipColorBag() {} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/static/core/bag/stapip_lighting_bag.cpp b/engine/src/renderer/3d/pipeline/static/core/bag/stapip_lighting_bag.cpp new file mode 100644 index 0000000..f5818b7 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/bag/stapip_lighting_bag.cpp @@ -0,0 +1,23 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/static/core/bag/stapip_lighting_bag.hpp" + +namespace Tyra { + +StaPipLightingBag::StaPipLightingBag() { + lightMatrix = nullptr; + normals = nullptr; + dirLights = nullptr; +} + +StaPipLightingBag::~StaPipLightingBag() {} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/static/core/bag/stapip_texture_bag.cpp b/engine/src/renderer/3d/pipeline/static/core/bag/stapip_texture_bag.cpp new file mode 100644 index 0000000..5139a50 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/bag/stapip_texture_bag.cpp @@ -0,0 +1,22 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/static/core/bag/stapip_texture_bag.hpp" + +namespace Tyra { + +StaPipTextureBag::StaPipTextureBag() { + coordinates = nullptr; + texture = nullptr; +} + +StaPipTextureBag::~StaPipTextureBag() {} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_c_vu1.vclpp b/engine/src/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_c_vu1.vclpp new file mode 100644 index 0000000..c695d92 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_c_vu1.vclpp @@ -0,0 +1,130 @@ +; _____ ____ ___ +; | \/ ____| |___| +; | | | \ | | +;--------------------------------------------------------------- +; Copyright 2022, tyra - https://github.com/h4570/tyra +; Licensed under Apache License 2.0 +; Sandro Sobczyński +; +;--------------------------------------------------------------- +; Triangle list +; AsIs = NO TRANSFORM +; Colors +;--------------------------------------------------------------- + +.syntax new +.name StaPipVU1As_Is_C +.vu +.init_vf_all +.init_vi_all + +#include "src/renderer/3d/pipeline/shared/vcl_sml.i" +#include "src/renderer/3d/pipeline/shared/tyra_macros.i" +#include "inc/renderer/3d/pipeline/static/core/programs/stapip_vu1_shared_defines.h" + +#define RGBA_STORE_OFFSET 0 +#define XYZ2_STORE_OFFSET 1 + +--enter +--endenter + +#vuprog StaPipVU1AsIsC + + LoadTyraStaticData{ gifSetTag } + LoadTyraSingleColor{ singleColor, singleColorEnabled, VU1_SINGLE_COLOR_ADDR, VU1_OPTIONS_ADDR } + LoadTyraTags{ lodGifTag, testsTag, VU1_LOD_ADDR, VU1_Z_TESTS_ADDR } + +begin: + xtop buffer + LoadTyraBufferTags{ scale, primTag, buffer } + + iaddiu vertexData, buffer, VU1_STAPIP_VERT_DATA_ADDR + ilw.w vertexCount, 0(buffer) + iadd colorData, vertexData, vertexCount + iblez singleColorEnabled, setDestAddrMultiColor + iadd kickAddress, vertexData, vertexCount + b setDestAddr +setDestAddrMultiColor: + iadd kickAddress, colorData, vertexCount +setDestAddr: + iaddiu destAddress, kickAddress, 0 + + StoreTyraGifTags{ gifSetTag, lodGifTag, primTag, testsTag, destAddress } + + ;--- Loop + iadd vertexCounter, buffer, vertexCount +vertexLoop: + + iblez singleColorEnabled, multiColor + ;--- Load vertices single color + add color1, vf00, singleColor + add color2, vf00, singleColor + add color3, vf00, singleColor + b processing + +multiColor: + ;--- Load vertices colors + lq color1, (colorData) + lq color2, 1(colorData) + lq color3, 2(colorData) + +processing: + ;--- Load vertex1 + lq.xyz vertex1, (vertexData) + + ;--- Load vertex2 + lq.xyz vertex2, 1(vertexData) + + ;--- Load vertex3 + lq.xyz vertex3, 2(vertexData) + + ;--- Calculate vertex1 + ScaleVertexToGSFormat{ scale, vertex1 } + FixColor{ color1 } + + ;--- Calculate vertex2 + ScaleVertexToGSFormat{ scale, vertex2 } + FixColor{ color2 } + + ;--- Calculate vertex3 + ScaleVertexToGSFormat{ scale, vertex3 } + FixColor{ color3 } + + iaddiu adcBit, VI00, 0x0 + isw.w adcBit, XYZ2_STORE_OFFSET(destAddress) + isw.w adcBit, XYZ2_STORE_OFFSET+2(destAddress) + isw.w adcBit, XYZ2_STORE_OFFSET+4(destAddress) + + ;--- Store vertex1 + sq color1, RGBA_STORE_OFFSET(destAddress) + sq.xyz vertex1, XYZ2_STORE_OFFSET(destAddress) + + ;--- Store vertex2 + sq color2, RGBA_STORE_OFFSET+2(destAddress) + sq.xyz vertex2, XYZ2_STORE_OFFSET+2(destAddress) + + ;--- Store vertex3 + sq color3, RGBA_STORE_OFFSET+4(destAddress) + sq.xyz vertex3, XYZ2_STORE_OFFSET+4(destAddress) + + ;------------------------------- + + iaddiu vertexData, vertexData, 3 + iaddiu colorData, colorData, 3 + iaddiu destAddress, destAddress, 6 + + ;--- Fix loop + iaddi vertexCounter, vertexCounter, -3 ; decrement the loop counter + ibne vertexCounter, buffer, vertexLoop ; and repeat if needed + + xgkick kickAddress ; dispatch to the GS rasterizer. + +--barrier ; Why the hell I must add barrier AFTER XGKICK? VCL does not adds E bit without it... +--cont + + b begin + +#endvuprog + +--exit +--endexit diff --git a/engine/src/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_c_vu1_program.cpp b/engine/src/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_c_vu1_program.cpp new file mode 100644 index 0000000..4cef9bb --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_c_vu1_program.cpp @@ -0,0 +1,47 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "debug/debug.hpp" +#include "renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_c_vu1_program.hpp" + +extern u32 StaPipVU1As_Is_C_CodeStart __attribute__((section(".vudata"))); +extern u32 StaPipVU1As_Is_C_CodeEnd __attribute__((section(".vudata"))); + +namespace Tyra { + +StaPipAsIsCVU1Program::StaPipAsIsCVU1Program() + : StaPipVU1Program(StaPipAsIsColor, &StaPipVU1As_Is_C_CodeStart, + &StaPipVU1As_Is_C_CodeEnd, + ((u64)GIF_REG_RGBAQ) << 0 | ((u64)GIF_REG_XYZ2) << 4, 2, + 2) {} + +StaPipAsIsCVU1Program::~StaPipAsIsCVU1Program() {} + +std::string StaPipAsIsCVU1Program::getStringName() const { + return std::string("StaPip - As is - C"); +} + +void StaPipAsIsCVU1Program::addProgramQBufferDataToPacket( + packet2_t* packet, StaPipQBuffer* qbuffer) const { + u32 addr = VU1_STAPIP_VERT_DATA_ADDR; + + // Add vertices + packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->vertices, + qbuffer->size, true); + + // Add colors + if (qbuffer->bag->color->single == nullptr) { + addr += qbuffer->size; + packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->colors, + qbuffer->size, true); + } +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_d_vu1.vclpp b/engine/src/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_d_vu1.vclpp new file mode 100644 index 0000000..8d0fc07 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_d_vu1.vclpp @@ -0,0 +1,116 @@ +; _____ ____ ___ +; | \/ ____| |___| +; | | | \ | | +;--------------------------------------------------------------- +; Copyright 2022, tyra - https://github.com/h4570/tyra +; Licensed under Apache License 2.0 +; Sandro Sobczyński +; +;--------------------------------------------------------------- +; Triangle list +; AsIs = NO TRANSFORM +; Directional lights +;--------------------------------------------------------------- + +.syntax new +.name StaPipVU1As_Is_D +.vu +.init_vf_all +.init_vi_all + +#include "src/renderer/3d/pipeline/shared/vcl_sml.i" +#include "src/renderer/3d/pipeline/shared/tyra_macros.i" +#include "inc/renderer/3d/pipeline/static/core/programs/stapip_vu1_shared_defines.h" + +#define RGBA_STORE_OFFSET 0 +#define XYZ2_STORE_OFFSET 1 + +--enter +--endenter + +#vuprog StaPipVU1AsIsD + + LoadTyraStaticData{ gifSetTag } + LoadTyraDirectionalLights{ lightMatrix, lightDirections, lightColors, ambientColor, VU1_LIGHTS_DIRS_ADDR, VU1_LIGHTS_COLORS_ADDR, VU1_LIGHTS_MATRIX_ADDR } + LoadTyraTags{ lodGifTag, testsTag, VU1_LOD_ADDR, VU1_Z_TESTS_ADDR } + +begin: + xtop buffer + LoadTyraBufferTags{ scale, primTag, buffer } + + iaddiu vertexData, buffer, VU1_STAPIP_VERT_DATA_ADDR + ilw.w vertexCount, 0(buffer) + iadd normalData, vertexData, vertexCount + iadd kickAddress, normalData, vertexCount + iadd destAddress, normalData, vertexCount + + StoreTyraGifTags{ gifSetTag, lodGifTag, primTag, testsTag, destAddress } + + ;--- Loop + iadd vertexCounter, buffer, vertexCount +vertexLoop: + ;--- Load vertex1 + lq.xyz vertex1, (vertexData) + lq.xyz normal1, (normalData) + + ;--- Load vertex2 + lq.xyz vertex2, 1(vertexData) + lq.xyz normal2, 1(normalData) + + ;--- Load vertex3 + lq.xyz vertex3, 2(vertexData) + lq.xyz normal3, 2(normalData) + + ;--- Calculate vertex1 + ScaleVertexToGSFormat{ scale, vertex1 } + CalculateTyraDirectionalLights{ outputColor1, normal1, lightDirections, lightColors, lightMatrix, ambientColor } + FixColor{ outputColor1 } + + ;--- Calculate vertex2 + ScaleVertexToGSFormat{ scale, vertex2 } + CalculateTyraDirectionalLights{ outputColor2, normal2, lightDirections, lightColors, lightMatrix, ambientColor } + FixColor{ outputColor2 } + + ;--- Calculate vertex3 + ScaleVertexToGSFormat{ scale, vertex3 } + CalculateTyraDirectionalLights{ outputColor3, normal3, lightDirections, lightColors, lightMatrix, ambientColor } + FixColor{ outputColor3 } + + iaddiu adcBit, VI00, 0x0 + isw.w adcBit, XYZ2_STORE_OFFSET(destAddress) + isw.w adcBit, XYZ2_STORE_OFFSET+2(destAddress) + isw.w adcBit, XYZ2_STORE_OFFSET+4(destAddress) + + ;--- Store vertex1 + sq outputColor1, RGBA_STORE_OFFSET(destAddress) + sq.xyz vertex1, XYZ2_STORE_OFFSET(destAddress) + + ;--- Store vertex2 + sq outputColor2, RGBA_STORE_OFFSET+2(destAddress) + sq.xyz vertex2, XYZ2_STORE_OFFSET+2(destAddress) + + ;--- Store vertex3 + sq outputColor3, RGBA_STORE_OFFSET+4(destAddress) + sq.xyz vertex3, XYZ2_STORE_OFFSET+4(destAddress) + + ;------------------------------- + + iaddiu vertexData, vertexData, 3 + iaddiu normalData, normalData, 3 + iaddiu destAddress, destAddress, 6 + + ;--- Fix loop + iaddi vertexCounter, vertexCounter, -3 ; decrement the loop counter + ibne vertexCounter, buffer, vertexLoop ; and repeat if needed + + xgkick kickAddress ; dispatch to the GS rasterizer. + +--barrier ; Why the hell I must add barrier AFTER XGKICK? VCL does not adds E bit without it... +--cont + + b begin + +#endvuprog + +--exit +--endexit diff --git a/engine/src/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_d_vu1_program.cpp b/engine/src/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_d_vu1_program.cpp new file mode 100644 index 0000000..db11cbe --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_d_vu1_program.cpp @@ -0,0 +1,52 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "debug/debug.hpp" +#include "renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_d_vu1_program.hpp" + +extern u32 StaPipVU1As_Is_D_CodeStart __attribute__((section(".vudata"))); +extern u32 StaPipVU1As_Is_D_CodeEnd __attribute__((section(".vudata"))); + +namespace Tyra { + +StaPipAsIsDVU1Program::StaPipAsIsDVU1Program() + : StaPipVU1Program(StaPipAsIsDirLights, &StaPipVU1As_Is_D_CodeStart, + &StaPipVU1As_Is_D_CodeEnd, + ((u64)GIF_REG_RGBAQ) << 0 | ((u64)GIF_REG_XYZ2) << 4, 2, + 3) {} + +StaPipAsIsDVU1Program::~StaPipAsIsDVU1Program() {} + +std::string StaPipAsIsDVU1Program::getStringName() const { + return std::string("StaPip - As is - D"); +} + +void StaPipAsIsDVU1Program::addProgramQBufferDataToPacket( + packet2_t* packet, StaPipQBuffer* qbuffer) const { + u32 addr = VU1_STAPIP_VERT_DATA_ADDR; + + // Add vertices + packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->vertices, + qbuffer->size, true); + addr += qbuffer->size; + + // Add normal + packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->normals, + qbuffer->size, true); + + // Add colors + if (qbuffer->bag->color->single == nullptr) { + addr += qbuffer->size; + packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->colors, + qbuffer->size, true); + } +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_tc_vu1.vclpp b/engine/src/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_tc_vu1.vclpp new file mode 100644 index 0000000..ea2ec89 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_tc_vu1.vclpp @@ -0,0 +1,145 @@ +; _____ ____ ___ +; | \/ ____| |___| +; | | | \ | | +;--------------------------------------------------------------- +; Copyright 2022, tyra - https://github.com/h4570/tyra +; Licensed under Apache License 2.0 +; Sandro Sobczyński +; +;--------------------------------------------------------------- +; Triangle list +; AsIs = NO TRANSFORM +; Texture, colors +;--------------------------------------------------------------- + +.syntax new +.name StaPipVU1As_Is_TC +.vu +.init_vf_all +.init_vi_all + +#include "src/renderer/3d/pipeline/shared/vcl_sml.i" +#include "src/renderer/3d/pipeline/shared/tyra_macros.i" +#include "inc/renderer/3d/pipeline/static/core/programs/stapip_vu1_shared_defines.h" + +#define STQ_STORE_OFFSET 0 +#define RGBA_STORE_OFFSET 1 +#define XYZ2_STORE_OFFSET 2 + +--enter +--endenter + +#vuprog StaPipVU1AsIsTC + + LoadTyraStaticData{ gifSetTag } + LoadTyraSingleColor{ singleColor, singleColorEnabled, VU1_SINGLE_COLOR_ADDR, VU1_OPTIONS_ADDR } + LoadTyraTagsTexture{ lodGifTag, testsTag, texBufferClutGifTag, VU1_LOD_ADDR, VU1_Z_TESTS_ADDR, VU1_CLUT_ADDR } + +begin: + xtop buffer + LoadTyraBufferTags{ scale, primTag, buffer } + + iaddiu vertexData, buffer, VU1_STAPIP_VERT_DATA_ADDR + ilw.w vertexCount, 0(buffer) + iadd stqData, vertexData, vertexCount + iadd colorData, stqData, vertexCount + iblez singleColorEnabled, setDestAddrMultiColor + iadd kickAddress, stqData, vertexCount + b setDestAddr +setDestAddrMultiColor: + iadd kickAddress, colorData, vertexCount +setDestAddr: + iaddiu destAddress, kickAddress, 0 + + StoreTyraGifTagsTexture{ gifSetTag, lodGifTag, texBufferClutGifTag, primTag, testsTag, destAddress } + + ;--- Loop + iadd vertexCounter, buffer, vertexCount +vertexLoop: + + iblez singleColorEnabled, multiColor + ;--- Load vertices single color + add color1, vf00, singleColor + add color2, vf00, singleColor + add color3, vf00, singleColor + b processing + +multiColor: + ;--- Load vertices colors + lq color1, (colorData) + lq color2, 1(colorData) + lq color3, 2(colorData) + +processing: + ;--- Load vertex1 + lq vertex1, (vertexData) + lq stq1, (stqData) + + ;--- Load vertex2 + lq vertex2, 1(vertexData) + lq stq2, 1(stqData) + + ;--- Load vertex3 + lq vertex3, 2(vertexData) + lq stq3, 2(stqData) + + ;--- Calculate vertex1 + ScaleVertexToGSFormat{ scale, vertex1 } + div q, vf00[w], vertex1[w] + PerformTexturePerspectiveCorrection{ outputStq1, stq1 } + FixColor{ color1 } + + ;--- Calculate vertex2 + ScaleVertexToGSFormat{ scale, vertex2 } + div q, vf00[w], vertex2[w] + PerformTexturePerspectiveCorrection{ outputStq2, stq2 } + FixColor{ color2 } + + ;--- Calculate vertex3 + ScaleVertexToGSFormat{ scale, vertex3 } + div q, vf00[w], vertex3[w] + PerformTexturePerspectiveCorrection{ outputStq3, stq3 } + FixColor{ color3 } + + iaddiu adcBit, VI00, 0x0 + isw.w adcBit, XYZ2_STORE_OFFSET(destAddress) + isw.w adcBit, XYZ2_STORE_OFFSET+3(destAddress) + isw.w adcBit, XYZ2_STORE_OFFSET+6(destAddress) + + ;--- Store vertex1 + sq outputStq1, STQ_STORE_OFFSET(destAddress) + sq color1, RGBA_STORE_OFFSET(destAddress) + sq.xyz vertex1, XYZ2_STORE_OFFSET(destAddress) + + ;--- Store vertex2 + sq outputStq2, STQ_STORE_OFFSET+3(destAddress) + sq color2, RGBA_STORE_OFFSET+3(destAddress) + sq.xyz vertex2, XYZ2_STORE_OFFSET+3(destAddress) + + ;--- Store vertex3 + sq outputStq3, STQ_STORE_OFFSET+6(destAddress) + sq color3, RGBA_STORE_OFFSET+6(destAddress) + sq.xyz vertex3, XYZ2_STORE_OFFSET+6(destAddress) + + ;------------------------------- + + iaddiu vertexData, vertexData, 3 + iaddiu stqData, stqData, 3 + iaddiu colorData, colorData, 3 + iaddiu destAddress, destAddress, 9 + + ;--- Fix loop + iaddi vertexCounter, vertexCounter, -3 ; decrement the loop counter + ibne vertexCounter, buffer, vertexLoop ; and repeat if needed + + xgkick kickAddress ; dispatch to the GS rasterizer. + +--barrier ; Why the hell I must add barrier AFTER XGKICK? VCL does not adds E bit without it... +--cont + + b begin + +#endvuprog + +--exit +--endexit diff --git a/engine/src/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_tc_vu1_program.cpp b/engine/src/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_tc_vu1_program.cpp new file mode 100644 index 0000000..f43000c --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_tc_vu1_program.cpp @@ -0,0 +1,53 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "debug/debug.hpp" +#include "renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_tc_vu1_program.hpp" + +extern u32 StaPipVU1As_Is_TC_CodeStart __attribute__((section(".vudata"))); +extern u32 StaPipVU1As_Is_TC_CodeEnd __attribute__((section(".vudata"))); + +namespace Tyra { + +StaPipAsIsTCVU1Program::StaPipAsIsTCVU1Program() + : StaPipVU1Program(StaPipAsIsTextureColor, &StaPipVU1As_Is_TC_CodeStart, + &StaPipVU1As_Is_TC_CodeEnd, + ((u64)GIF_REG_ST) << 0 | ((u64)GIF_REG_RGBAQ) << 4 | + ((u64)GIF_REG_XYZ2) << 8, + 3, 3) {} + +StaPipAsIsTCVU1Program::~StaPipAsIsTCVU1Program() {} + +std::string StaPipAsIsTCVU1Program::getStringName() const { + return std::string("StaPip - As is - TC"); +} + +void StaPipAsIsTCVU1Program::addProgramQBufferDataToPacket( + packet2_t* packet, StaPipQBuffer* qbuffer) const { + u32 addr = VU1_STAPIP_VERT_DATA_ADDR; + + // Add vertices + packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->vertices, + qbuffer->size, true); + addr += qbuffer->size; + + // Add sts + packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->sts, qbuffer->size, + true); + + // Add colors + if (qbuffer->bag->color->single == nullptr) { + addr += qbuffer->size; + packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->colors, + qbuffer->size, true); + } +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_td_vu1.vclpp b/engine/src/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_td_vu1.vclpp new file mode 100644 index 0000000..d976aab --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_td_vu1.vclpp @@ -0,0 +1,131 @@ +; _____ ____ ___ +; | \/ ____| |___| +; | | | \ | | +;--------------------------------------------------------------- +; Copyright 2022, tyra - https://github.com/h4570/tyra +; Licensed under Apache License 2.0 +; Sandro Sobczyński +; +;--------------------------------------------------------------- +; Triangle list +; AsIs = NO TRANSFORM +; Texture, directional lights +;--------------------------------------------------------------- + +.syntax new +.name StaPipVU1As_Is_TD +.vu +.init_vf_all +.init_vi_all + +#include "src/renderer/3d/pipeline/shared/vcl_sml.i" +#include "src/renderer/3d/pipeline/shared/tyra_macros.i" +#include "inc/renderer/3d/pipeline/static/core/programs/stapip_vu1_shared_defines.h" + +#define STQ_STORE_OFFSET 0 +#define RGBA_STORE_OFFSET 1 +#define XYZ2_STORE_OFFSET 2 + +--enter +--endenter + +#vuprog StaPipVU1AsIsTD + + LoadTyraStaticData{ gifSetTag } + LoadTyraDirectionalLights{ lightMatrix, lightDirections, lightColors, ambientColor, VU1_LIGHTS_DIRS_ADDR, VU1_LIGHTS_COLORS_ADDR, VU1_LIGHTS_MATRIX_ADDR } + LoadTyraTagsTexture{ lodGifTag, testsTag, texBufferClutGifTag, VU1_LOD_ADDR, VU1_Z_TESTS_ADDR, VU1_CLUT_ADDR } + +begin: + xtop buffer + LoadTyraBufferTags{ scale, primTag, buffer } + + iaddiu vertexData, buffer, VU1_STAPIP_VERT_DATA_ADDR + ilw.w vertexCount, 0(buffer) + iadd stqData, vertexData, vertexCount + iadd normalData, stqData, vertexCount + iadd kickAddress, normalData, vertexCount + iadd destAddress, normalData, vertexCount + + StoreTyraGifTagsTexture{ gifSetTag, lodGifTag, texBufferClutGifTag, primTag, testsTag, destAddress } + + ;--- Loop + iadd vertexCounter, buffer, vertexCount +vertexLoop: + ;--- Load vertex1 + lq vertex1, (vertexData) + lq stq1, (stqData) + lq.xyz normal1, (normalData) + + ;--- Load vertex2 + lq vertex2, 1(vertexData) + lq stq2, 1(stqData) + lq.xyz normal2, 1(normalData) + + ;--- Load vertex3 + lq vertex3, 2(vertexData) + lq stq3, 2(stqData) + lq.xyz normal3, 2(normalData) + + ;--- Calculate vertex1 + ScaleVertexToGSFormat{ scale, vertex1 } + div q, vf00[w], vertex1[w] + PerformTexturePerspectiveCorrection{ outputStq1, stq1 } + CalculateTyraDirectionalLights{ outputColor1, normal1, lightDirections, lightColors, lightMatrix, ambientColor } + FixColor{ outputColor1 } + + ;--- Calculate vertex2 + ScaleVertexToGSFormat{ scale, vertex2 } + div q, vf00[w], vertex2[w] + PerformTexturePerspectiveCorrection{ outputStq2, stq2 } + CalculateTyraDirectionalLights{ outputColor2, normal2, lightDirections, lightColors, lightMatrix, ambientColor } + FixColor{ outputColor2 } + + ;--- Calculate vertex3 + ScaleVertexToGSFormat{ scale, vertex3 } + div q, vf00[w], vertex3[w] + PerformTexturePerspectiveCorrection{ outputStq3, stq3 } + CalculateTyraDirectionalLights{ outputColor3, normal3, lightDirections, lightColors, lightMatrix, ambientColor } + FixColor{ outputColor3 } + + iaddiu adcBit, VI00, 0x0 + isw.w adcBit, XYZ2_STORE_OFFSET(destAddress) + isw.w adcBit, XYZ2_STORE_OFFSET+3(destAddress) + isw.w adcBit, XYZ2_STORE_OFFSET+6(destAddress) + + ;--- Store vertex1 + sq outputStq1, STQ_STORE_OFFSET(destAddress) + sq outputColor1, RGBA_STORE_OFFSET(destAddress) + sq.xyz vertex1, XYZ2_STORE_OFFSET(destAddress) + + ;--- Store vertex2 + sq outputStq2, STQ_STORE_OFFSET+3(destAddress) + sq outputColor2, RGBA_STORE_OFFSET+3(destAddress) + sq.xyz vertex2, XYZ2_STORE_OFFSET+3(destAddress) + + ;--- Store vertex3 + sq outputStq3, STQ_STORE_OFFSET+6(destAddress) + sq outputColor3, RGBA_STORE_OFFSET+6(destAddress) + sq.xyz vertex3, XYZ2_STORE_OFFSET+6(destAddress) + + ;------------------------------- + + iaddiu vertexData, vertexData, 3 + iaddiu stqData, stqData, 3 + iaddiu normalData, normalData, 3 + iaddiu destAddress, destAddress, 9 + + ;--- Fix loop + iaddi vertexCounter, vertexCounter, -3 ; decrement the loop counter + ibne vertexCounter, buffer, vertexLoop ; and repeat if needed + + xgkick kickAddress ; dispatch to the GS rasterizer. + +--barrier ; Why the hell I must add barrier AFTER XGKICK? VCL does not adds E bit without it... +--cont + + b begin + +#endvuprog + +--exit +--endexit diff --git a/engine/src/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_td_vu1_program.cpp b/engine/src/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_td_vu1_program.cpp new file mode 100644 index 0000000..8cbd509 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_td_vu1_program.cpp @@ -0,0 +1,58 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "debug/debug.hpp" +#include "renderer/3d/pipeline/static/core/programs/as_is/stapip_as_is_td_vu1_program.hpp" + +extern u32 StaPipVU1As_Is_TD_CodeStart __attribute__((section(".vudata"))); +extern u32 StaPipVU1As_Is_TD_CodeEnd __attribute__((section(".vudata"))); + +namespace Tyra { + +StaPipAsIsTDVU1Program::StaPipAsIsTDVU1Program() + : StaPipVU1Program(StaPipAsIsTextureDirLights, &StaPipVU1As_Is_TD_CodeStart, + &StaPipVU1As_Is_TD_CodeEnd, + ((u64)GIF_REG_ST) << 0 | ((u64)GIF_REG_RGBAQ) << 4 | + ((u64)GIF_REG_XYZ2) << 8, + 3, 4) {} + +StaPipAsIsTDVU1Program::~StaPipAsIsTDVU1Program() {} + +std::string StaPipAsIsTDVU1Program::getStringName() const { + return std::string("StaPip - As is - TD"); +} + +void StaPipAsIsTDVU1Program::addProgramQBufferDataToPacket( + packet2_t* packet, StaPipQBuffer* qbuffer) const { + u32 addr = VU1_STAPIP_VERT_DATA_ADDR; + + // Add vertices + packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->vertices, + qbuffer->size, true); + addr += qbuffer->size; + + // Add sts + packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->sts, qbuffer->size, + true); + addr += qbuffer->size; + + // Add normal + packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->normals, + qbuffer->size, true); + + // Add colors + if (qbuffer->bag->color->single == nullptr) { + addr += qbuffer->size; + packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->colors, + qbuffer->size, true); + } +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_c_vu1.vclpp b/engine/src/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_c_vu1.vclpp new file mode 100644 index 0000000..335c65b --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_c_vu1.vclpp @@ -0,0 +1,136 @@ +; _____ ____ ___ +; | \/ ____| |___| +; | | | \ | | +;--------------------------------------------------------------- +; Copyright 2022, tyra - https://github.com/h4570/tyra +; Licensed under Apache License 2.0 +; Sandro Sobczyński +; +;--------------------------------------------------------------- +; Triangle list +; Cull = Standard PS2 way. clipw polys are culled. +; Colors +;--------------------------------------------------------------- + +.syntax new +.name StaPipVU1Cull_C +.vu +.init_vf_all +.init_vi_all + +#include "src/renderer/3d/pipeline/shared/vcl_sml.i" +#include "src/renderer/3d/pipeline/shared/tyra_macros.i" +#include "inc/renderer/3d/pipeline/static/core/programs/stapip_vu1_shared_defines.h" + +#define RGBA_STORE_OFFSET 0 +#define XYZ2_STORE_OFFSET 1 + +--enter +--endenter + +#vuprog StaPipVU1CullC + + ResetClipFlags{ } + LoadTyraStaticData{ gifSetTag } + MatrixLoad{ mvp, VU1_MVP_MATRIX_ADDR, vi00 } + LoadTyraSingleColor{ singleColor, singleColorEnabled, VU1_SINGLE_COLOR_ADDR, VU1_OPTIONS_ADDR } + LoadTyraTags{ lodGifTag, testsTag, VU1_LOD_ADDR, VU1_Z_TESTS_ADDR } + +begin: + xtop buffer + LoadTyraBufferTags{ scale, primTag, buffer } + + iaddiu vertexData, buffer, VU1_STAPIP_VERT_DATA_ADDR + ilw.w vertexCount, 0(buffer) + iadd colorData, vertexData, vertexCount + iblez singleColorEnabled, setDestAddrMultiColor + iadd kickAddress, vertexData, vertexCount + b setDestAddr +setDestAddrMultiColor: + iadd kickAddress, colorData, vertexCount +setDestAddr: + iaddiu destAddress, kickAddress, 0 + + StoreTyraGifTags{ gifSetTag, lodGifTag, primTag, testsTag, destAddress } + + ;--- Loop + iadd vertexCounter, buffer, vertexCount +vertexLoop: + + iblez singleColorEnabled, multiColor + ;--- Load vertices single color + add color1, vf00, singleColor + add color2, vf00, singleColor + add color3, vf00, singleColor + b processing + +multiColor: + ;--- Load vertices colors + lq color1, (colorData) + lq color2, 1(colorData) + lq color3, 2(colorData) + +processing: + ;--- Load vertex1 + lq vertex1, (vertexData) + + ;--- Load vertex2 + lq vertex2, 1(vertexData) + + ;--- Load vertex3 + lq vertex3, 2(vertexData) + + ;--- Calculate vertex1 + MatrixMultiplyVertex{ vertex1, mvp, vertex1 } + PerformClipCheck{ vertex1, destAddress, XYZ2_STORE_OFFSET } + VertexPersCorr{ vertex1, vertex1 } + ScaleVertexToGSFormat{ scale, vertex1 } + FixColor{ color1 } + + ;--- Calculate vertex2 + MatrixMultiplyVertex{ vertex2, mvp, vertex2 } + PerformClipCheck{ vertex2, destAddress, XYZ2_STORE_OFFSET+2 } + VertexPersCorr{ vertex2, vertex2 } + ScaleVertexToGSFormat{ scale, vertex2 } + FixColor{ color2 } + + ;--- Calculate vertex3 + MatrixMultiplyVertex{ vertex3, mvp, vertex3 } + PerformClipCheck{ vertex3, destAddress, XYZ2_STORE_OFFSET+4 } + VertexPersCorr{ vertex3, vertex3 } + ScaleVertexToGSFormat{ scale, vertex3 } + FixColor{ color3 } + + ;--- Store vertex1 + sq color1, RGBA_STORE_OFFSET(destAddress) + sq.xyz vertex1, XYZ2_STORE_OFFSET(destAddress) + + ;--- Store vertex2 + sq color2, RGBA_STORE_OFFSET+2(destAddress) + sq.xyz vertex2, XYZ2_STORE_OFFSET+2(destAddress) + + ;--- Store vertex3 + sq color3, RGBA_STORE_OFFSET+4(destAddress) + sq.xyz vertex3, XYZ2_STORE_OFFSET+4(destAddress) + + ;------------------------------- + + iaddiu vertexData, vertexData, 3 + iaddiu colorData, colorData, 3 + iaddiu destAddress, destAddress, 6 + + ;--- Fix loop + iaddi vertexCounter, vertexCounter, -3 ; decrement the loop counter + ibne vertexCounter, buffer, vertexLoop ; and repeat if needed + + xgkick kickAddress ; dispatch to the GS rasterizer. + +--barrier ; Why the hell I must add barrier AFTER XGKICK? VCL does not adds E bit without it... +--cont + + b begin + +#endvuprog + +--exit +--endexit diff --git a/engine/src/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_c_vu1_program.cpp b/engine/src/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_c_vu1_program.cpp new file mode 100644 index 0000000..cdacdeb --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_c_vu1_program.cpp @@ -0,0 +1,46 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "debug/debug.hpp" +#include "renderer/3d/pipeline/static/core/programs/cull/stapip_cull_c_vu1_program.hpp" + +extern u32 StaPipVU1Cull_C_CodeStart __attribute__((section(".vudata"))); +extern u32 StaPipVU1Cull_C_CodeEnd __attribute__((section(".vudata"))); + +namespace Tyra { + +StaPipCullCVU1Program::StaPipCullCVU1Program() + : StaPipVU1Program( + StaPipCullColor, &StaPipVU1Cull_C_CodeStart, &StaPipVU1Cull_C_CodeEnd, + ((u64)GIF_REG_RGBAQ) << 0 | ((u64)GIF_REG_XYZ2) << 4, 2, 2) {} + +StaPipCullCVU1Program::~StaPipCullCVU1Program() {} + +std::string StaPipCullCVU1Program::getStringName() const { + return std::string("StaPip - Cull - C"); +} + +void StaPipCullCVU1Program::addProgramQBufferDataToPacket( + packet2_t* packet, StaPipQBuffer* qbuffer) const { + u32 addr = VU1_STAPIP_VERT_DATA_ADDR; + + // Add vertices + packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->vertices, + qbuffer->size, true); + + // Add colors + if (qbuffer->bag->color->single == nullptr) { + addr += qbuffer->size; + packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->colors, + qbuffer->size, true); + } +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_d_vu1.vclpp b/engine/src/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_d_vu1.vclpp new file mode 100644 index 0000000..dd2532f --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_d_vu1.vclpp @@ -0,0 +1,122 @@ +; _____ ____ ___ +; | \/ ____| |___| +; | | | \ | | +;--------------------------------------------------------------- +; Copyright 2022, tyra - https://github.com/h4570/tyra +; Licensed under Apache License 2.0 +; Sandro Sobczyński +; +;--------------------------------------------------------------- +; Triangle list +; Cull = Standard PS2 way. clipw polys are culled. +; Directional lights +;--------------------------------------------------------------- + +.syntax new +.name StaPipVU1Cull_D +.vu +.init_vf_all +.init_vi_all + +#include "src/renderer/3d/pipeline/shared/vcl_sml.i" +#include "src/renderer/3d/pipeline/shared/tyra_macros.i" +#include "inc/renderer/3d/pipeline/static/core/programs/stapip_vu1_shared_defines.h" + +#define RGBA_STORE_OFFSET 0 +#define XYZ2_STORE_OFFSET 1 + +--enter +--endenter + +#vuprog StaPipVU1CullD + + ResetClipFlags{ } + LoadTyraStaticData{ gifSetTag } + MatrixLoad{ mvp, VU1_MVP_MATRIX_ADDR, vi00 } + LoadTyraDirectionalLights{ lightMatrix, lightDirections, lightColors, ambientColor, VU1_LIGHTS_DIRS_ADDR, VU1_LIGHTS_COLORS_ADDR, VU1_LIGHTS_MATRIX_ADDR } + LoadTyraTags{ lodGifTag, testsTag, VU1_LOD_ADDR, VU1_Z_TESTS_ADDR } + +begin: + xtop buffer + LoadTyraBufferTags{ scale, primTag, buffer } + + iaddiu vertexData, buffer, VU1_STAPIP_VERT_DATA_ADDR + ilw.w vertexCount, 0(buffer) + iadd normalData, vertexData, vertexCount + iadd kickAddress, normalData, vertexCount + iadd destAddress, normalData, vertexCount + + StoreTyraGifTags{ gifSetTag, lodGifTag, primTag, testsTag, destAddress } + + ;--- Loop + iadd vertexCounter, buffer, vertexCount +vertexLoop: + ;--- Load vertex1 + lq vertex1, (vertexData) + lq.xyz normal1, (normalData) + + ;--- Load vertex2 + lq vertex2, 1(vertexData) + lq.xyz normal2, 1(normalData) + + ;--- Load vertex3 + lq vertex3, 2(vertexData) + lq.xyz normal3, 2(normalData) + + ;--- Calculate vertex1 + MatrixMultiplyVertex{ vertex1, mvp, vertex1 } + PerformClipCheck{ vertex1, destAddress, XYZ2_STORE_OFFSET } + VertexPersCorr{ vertex1, vertex1 } + ScaleVertexToGSFormat{ scale, vertex1 } + CalculateTyraDirectionalLights{ outputColor1, normal1, lightDirections, lightColors, lightMatrix, ambientColor } + FixColor{ outputColor1 } + + ;--- Calculate vertex2 + MatrixMultiplyVertex{ vertex2, mvp, vertex2 } + PerformClipCheck{ vertex2, destAddress, XYZ2_STORE_OFFSET+2 } + VertexPersCorr{ vertex2, vertex2 } + ScaleVertexToGSFormat{ scale, vertex2 } + CalculateTyraDirectionalLights{ outputColor2, normal2, lightDirections, lightColors, lightMatrix, ambientColor } + FixColor{ outputColor2 } + + ;--- Calculate vertex3 + MatrixMultiplyVertex{ vertex3, mvp, vertex3 } + PerformClipCheck{ vertex3, destAddress, XYZ2_STORE_OFFSET+4 } + VertexPersCorr{ vertex3, vertex3 } + ScaleVertexToGSFormat{ scale, vertex3 } + CalculateTyraDirectionalLights{ outputColor3, normal3, lightDirections, lightColors, lightMatrix, ambientColor } + FixColor{ outputColor3 } + + ;--- Store vertex1 + sq outputColor1, RGBA_STORE_OFFSET(destAddress) + sq.xyz vertex1, XYZ2_STORE_OFFSET(destAddress) + + ;--- Store vertex2 + sq outputColor2, RGBA_STORE_OFFSET+2(destAddress) + sq.xyz vertex2, XYZ2_STORE_OFFSET+2(destAddress) + + ;--- Store vertex3 + sq outputColor3, RGBA_STORE_OFFSET+4(destAddress) + sq.xyz vertex3, XYZ2_STORE_OFFSET+4(destAddress) + + ;------------------------------- + + iaddiu vertexData, vertexData, 3 + iaddiu normalData, normalData, 3 + iaddiu destAddress, destAddress, 6 + + ;--- Fix loop + iaddi vertexCounter, vertexCounter, -3 ; decrement the loop counter + ibne vertexCounter, buffer, vertexLoop ; and repeat if needed + + xgkick kickAddress ; dispatch to the GS rasterizer. + +--barrier ; Why the hell I must add barrier AFTER XGKICK? VCL does not adds E bit without it... +--cont + + b begin + +#endvuprog + +--exit +--endexit diff --git a/engine/src/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_d_vu1_program.cpp b/engine/src/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_d_vu1_program.cpp new file mode 100644 index 0000000..1442bdf --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_d_vu1_program.cpp @@ -0,0 +1,52 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "debug/debug.hpp" +#include "renderer/3d/pipeline/static/core/programs/cull/stapip_cull_d_vu1_program.hpp" + +extern u32 StaPipVU1Cull_D_CodeStart __attribute__((section(".vudata"))); +extern u32 StaPipVU1Cull_D_CodeEnd __attribute__((section(".vudata"))); + +namespace Tyra { + +StaPipCullDVU1Program::StaPipCullDVU1Program() + : StaPipVU1Program(StaPipCullDirLights, &StaPipVU1Cull_D_CodeStart, + &StaPipVU1Cull_D_CodeEnd, + ((u64)GIF_REG_RGBAQ) << 0 | ((u64)GIF_REG_XYZ2) << 4, 2, + 3) {} + +StaPipCullDVU1Program::~StaPipCullDVU1Program() {} + +std::string StaPipCullDVU1Program::getStringName() const { + return std::string("StaPip - Cull - D"); +} + +void StaPipCullDVU1Program::addProgramQBufferDataToPacket( + packet2_t* packet, StaPipQBuffer* qbuffer) const { + u32 addr = VU1_STAPIP_VERT_DATA_ADDR; + + // Add vertices + packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->vertices, + qbuffer->size, true); + addr += qbuffer->size; + + // Add normal + packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->normals, + qbuffer->size, true); + + // Add colors + if (qbuffer->bag->color->single == nullptr) { + addr += qbuffer->size; + packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->colors, + qbuffer->size, true); + } +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_tc_vu1.vclpp b/engine/src/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_tc_vu1.vclpp new file mode 100644 index 0000000..fcd3ed4 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_tc_vu1.vclpp @@ -0,0 +1,148 @@ +; _____ ____ ___ +; | \/ ____| |___| +; | | | \ | | +;--------------------------------------------------------------- +; Copyright 2022, tyra - https://github.com/h4570/tyra +; Licensed under Apache License 2.0 +; Sandro Sobczyński +; +;--------------------------------------------------------------- +; Triangle list +; Cull = Standard PS2 way. clipw polys are culled. +; Lighting, texture, colors +;--------------------------------------------------------------- + +.syntax new +.name StaPipVU1Cull_TC +.vu +.init_vf_all +.init_vi_all + +#include "src/renderer/3d/pipeline/shared/vcl_sml.i" +#include "src/renderer/3d/pipeline/shared/tyra_macros.i" +#include "inc/renderer/3d/pipeline/static/core/programs/stapip_vu1_shared_defines.h" + +#define STQ_STORE_OFFSET 0 +#define RGBA_STORE_OFFSET 1 +#define XYZ2_STORE_OFFSET 2 + +--enter +--endenter + +#vuprog StaPipVU1CullTC + + ResetClipFlags{ } + LoadTyraStaticData{ gifSetTag } + MatrixLoad{ mvp, VU1_MVP_MATRIX_ADDR, vi00 } + LoadTyraSingleColor{ singleColor, singleColorEnabled, VU1_SINGLE_COLOR_ADDR, VU1_OPTIONS_ADDR } + LoadTyraTagsTexture{ lodGifTag, testsTag, texBufferClutGifTag, VU1_LOD_ADDR, VU1_Z_TESTS_ADDR, VU1_CLUT_ADDR } + +begin: + xtop buffer + LoadTyraBufferTags{ scale, primTag, buffer } + + iaddiu vertexData, buffer, VU1_STAPIP_VERT_DATA_ADDR + ilw.w vertexCount, 0(buffer) + iadd stqData, vertexData, vertexCount + iadd colorData, stqData, vertexCount + iblez singleColorEnabled, setDestAddrMultiColor + iadd kickAddress, stqData, vertexCount + b setDestAddr +setDestAddrMultiColor: + iadd kickAddress, colorData, vertexCount +setDestAddr: + iaddiu destAddress, kickAddress, 0 + + StoreTyraGifTagsTexture{ gifSetTag, lodGifTag, texBufferClutGifTag, primTag, testsTag, destAddress } + + ;--- Loop + iadd vertexCounter, buffer, vertexCount +vertexLoop: + + iblez singleColorEnabled, multiColor + ;--- Load vertices single color + add color1, vf00, singleColor + add color2, vf00, singleColor + add color3, vf00, singleColor + b processing + +multiColor: + ;--- Load vertices colors + lq color1, (colorData) + lq color2, 1(colorData) + lq color3, 2(colorData) + +processing: + ;--- Load vertex1 + lq vertex1, (vertexData) + lq stq1, (stqData) + + ;--- Load vertex2 + lq vertex2, 1(vertexData) + lq stq2, 1(stqData) + + ;--- Load vertex3 + lq vertex3, 2(vertexData) + lq stq3, 2(stqData) + + ;--- Calculate vertex1 + MatrixMultiplyVertex{ vertex1, mvp, vertex1 } + PerformClipCheck{ vertex1, destAddress, XYZ2_STORE_OFFSET } + VertexPersCorr{ vertex1, vertex1 } + ScaleVertexToGSFormat{ scale, vertex1 } + PerformTexturePerspectiveCorrection{ outputStq1, stq1 } + FixColor{ color1 } + + ;--- Calculate vertex2 + MatrixMultiplyVertex{ vertex2, mvp, vertex2 } + PerformClipCheck{ vertex2, destAddress, XYZ2_STORE_OFFSET+3 } + VertexPersCorr{ vertex2, vertex2 } + ScaleVertexToGSFormat{ scale, vertex2 } + PerformTexturePerspectiveCorrection{ outputStq2, stq2 } + FixColor{ color2 } + + ;--- Calculate vertex3 + MatrixMultiplyVertex{ vertex3, mvp, vertex3 } + PerformClipCheck{ vertex3, destAddress, XYZ2_STORE_OFFSET+6 } + VertexPersCorr{ vertex3, vertex3 } + ScaleVertexToGSFormat{ scale, vertex3 } + PerformTexturePerspectiveCorrection{ outputStq3, stq3 } + FixColor{ color3 } + + ;--- Store vertex1 + sq outputStq1, STQ_STORE_OFFSET(destAddress) + sq color1, RGBA_STORE_OFFSET(destAddress) + sq.xyz vertex1, XYZ2_STORE_OFFSET(destAddress) + + ;--- Store vertex2 + sq outputStq2, STQ_STORE_OFFSET+3(destAddress) + sq color2, RGBA_STORE_OFFSET+3(destAddress) + sq.xyz vertex2, XYZ2_STORE_OFFSET+3(destAddress) + + ;--- Store vertex3 + sq outputStq3, STQ_STORE_OFFSET+6(destAddress) + sq color3, RGBA_STORE_OFFSET+6(destAddress) + sq.xyz vertex3, XYZ2_STORE_OFFSET+6(destAddress) + + ;------------------------------- + + iaddiu vertexData, vertexData, 3 + iaddiu stqData, stqData, 3 + iaddiu colorData, colorData, 3 + iaddiu destAddress, destAddress, 9 + + ;--- Fix loop + iaddi vertexCounter, vertexCounter, -3 ; decrement the loop counter + ibne vertexCounter, buffer, vertexLoop ; and repeat if needed + + xgkick kickAddress ; dispatch to the GS rasterizer. + +--barrier ; Why the hell I must add barrier AFTER XGKICK? VCL does not adds E bit without it... +--cont + + b begin + +#endvuprog + +--exit +--endexit diff --git a/engine/src/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_tc_vu1_program.cpp b/engine/src/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_tc_vu1_program.cpp new file mode 100644 index 0000000..f4e9ce9 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_tc_vu1_program.cpp @@ -0,0 +1,53 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "debug/debug.hpp" +#include "renderer/3d/pipeline/static/core/programs/cull/stapip_cull_tc_vu1_program.hpp" + +extern u32 StaPipVU1Cull_TC_CodeStart __attribute__((section(".vudata"))); +extern u32 StaPipVU1Cull_TC_CodeEnd __attribute__((section(".vudata"))); + +namespace Tyra { + +StaPipCullTCVU1Program::StaPipCullTCVU1Program() + : StaPipVU1Program(StaPipCullTextureColor, &StaPipVU1Cull_TC_CodeStart, + &StaPipVU1Cull_TC_CodeEnd, + ((u64)GIF_REG_ST) << 0 | ((u64)GIF_REG_RGBAQ) << 4 | + ((u64)GIF_REG_XYZ2) << 8, + 3, 3) {} + +StaPipCullTCVU1Program::~StaPipCullTCVU1Program() {} + +std::string StaPipCullTCVU1Program::getStringName() const { + return std::string("StaPip - Cull - TC"); +} + +void StaPipCullTCVU1Program::addProgramQBufferDataToPacket( + packet2_t* packet, StaPipQBuffer* qbuffer) const { + u32 addr = VU1_STAPIP_VERT_DATA_ADDR; + + // Add vertices + packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->vertices, + qbuffer->size, true); + addr += qbuffer->size; + + // Add sts + packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->sts, qbuffer->size, + true); + + // Add colors + if (qbuffer->bag->color->single == nullptr) { + addr += qbuffer->size; + packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->colors, + qbuffer->size, true); + } +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_td_vu1.vclpp b/engine/src/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_td_vu1.vclpp new file mode 100644 index 0000000..1fc509f --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_td_vu1.vclpp @@ -0,0 +1,134 @@ +; _____ ____ ___ +; | \/ ____| |___| +; | | | \ | | +;--------------------------------------------------------------- +; Copyright 2022, tyra - https://github.com/h4570/tyra +; Licensed under Apache License 2.0 +; Sandro Sobczyński +; +;--------------------------------------------------------------- +; Triangle list +; Cull = Standard PS2 way. clipw polys are culled. +; Texture, directional lights +;--------------------------------------------------------------- + +.syntax new +.name StaPipVU1Cull_TD +.vu +.init_vf_all +.init_vi_all + +#include "src/renderer/3d/pipeline/shared/vcl_sml.i" +#include "src/renderer/3d/pipeline/shared/tyra_macros.i" +#include "inc/renderer/3d/pipeline/static/core/programs/stapip_vu1_shared_defines.h" + +#define STQ_STORE_OFFSET 0 +#define RGBA_STORE_OFFSET 1 +#define XYZ2_STORE_OFFSET 2 + +--enter +--endenter + +#vuprog StaPipVU1CullTD + + ResetClipFlags{ } + LoadTyraStaticData{ gifSetTag } + MatrixLoad{ mvp, VU1_MVP_MATRIX_ADDR, vi00 } + LoadTyraDirectionalLights{ lightMatrix, lightDirections, lightColors, ambientColor, VU1_LIGHTS_DIRS_ADDR, VU1_LIGHTS_COLORS_ADDR, VU1_LIGHTS_MATRIX_ADDR } + LoadTyraTagsTexture{ lodGifTag, testsTag, texBufferClutGifTag, VU1_LOD_ADDR, VU1_Z_TESTS_ADDR, VU1_CLUT_ADDR } + +begin: + xtop buffer + LoadTyraBufferTags{ scale, primTag, buffer } + + iaddiu vertexData, buffer, VU1_STAPIP_VERT_DATA_ADDR + ilw.w vertexCount, 0(buffer) + iadd stqData, vertexData, vertexCount + iadd normalData, stqData, vertexCount + iadd kickAddress, normalData, vertexCount + iadd destAddress, normalData, vertexCount + + StoreTyraGifTagsTexture{ gifSetTag, lodGifTag, texBufferClutGifTag, primTag, testsTag, destAddress } + + ;--- Loop + iadd vertexCounter, buffer, vertexCount +vertexLoop: + ;--- Load vertex1 + lq vertex1, (vertexData) + lq stq1, (stqData) + lq.xyz normal1, (normalData) + + ;--- Load vertex2 + lq vertex2, 1(vertexData) + lq stq2, 1(stqData) + lq.xyz normal2, 1(normalData) + + ;--- Load vertex3 + lq vertex3, 2(vertexData) + lq stq3, 2(stqData) + lq.xyz normal3, 2(normalData) + + ;--- Calculate vertex1 + MatrixMultiplyVertex{ vertex1, mvp, vertex1 } + PerformClipCheck{ vertex1, destAddress, XYZ2_STORE_OFFSET } + VertexPersCorr{ vertex1, vertex1 } + ScaleVertexToGSFormat{ scale, vertex1 } + PerformTexturePerspectiveCorrection{ outputStq1, stq1 } + CalculateTyraDirectionalLights{ outputColor1, normal1, lightDirections, lightColors, lightMatrix, ambientColor } + FixColor{ outputColor1 } + + ;--- Calculate vertex2 + MatrixMultiplyVertex{ vertex2, mvp, vertex2 } + PerformClipCheck{ vertex2, destAddress, XYZ2_STORE_OFFSET+3 } + VertexPersCorr{ vertex2, vertex2 } + ScaleVertexToGSFormat{ scale, vertex2 } + PerformTexturePerspectiveCorrection{ outputStq2, stq2 } + CalculateTyraDirectionalLights{ outputColor2, normal2, lightDirections, lightColors, lightMatrix, ambientColor } + FixColor{ outputColor2 } + + ;--- Calculate vertex3 + MatrixMultiplyVertex{ vertex3, mvp, vertex3 } + PerformClipCheck{ vertex3, destAddress, XYZ2_STORE_OFFSET+6 } + VertexPersCorr{ vertex3, vertex3 } + ScaleVertexToGSFormat{ scale, vertex3 } + PerformTexturePerspectiveCorrection{ outputStq3, stq3 } + CalculateTyraDirectionalLights{ outputColor3, normal3, lightDirections, lightColors, lightMatrix, ambientColor } + FixColor{ outputColor3 } + + ;--- Store vertex1 + sq outputStq1, STQ_STORE_OFFSET(destAddress) + sq outputColor1, RGBA_STORE_OFFSET(destAddress) + sq.xyz vertex1, XYZ2_STORE_OFFSET(destAddress) + + ;--- Store vertex2 + sq outputStq2, STQ_STORE_OFFSET+3(destAddress) + sq outputColor2, RGBA_STORE_OFFSET+3(destAddress) + sq.xyz vertex2, XYZ2_STORE_OFFSET+3(destAddress) + + ;--- Store vertex3 + sq outputStq3, STQ_STORE_OFFSET+6(destAddress) + sq outputColor3, RGBA_STORE_OFFSET+6(destAddress) + sq.xyz vertex3, XYZ2_STORE_OFFSET+6(destAddress) + + ;------------------------------- + + iaddiu vertexData, vertexData, 3 + iaddiu stqData, stqData, 3 + iaddiu normalData, normalData, 3 + iaddiu destAddress, destAddress, 9 + + ;--- Fix loop + iaddi vertexCounter, vertexCounter, -3 ; decrement the loop counter + ibne vertexCounter, buffer, vertexLoop ; and repeat if needed + + xgkick kickAddress ; dispatch to the GS rasterizer. + +--barrier ; Why the hell I must add barrier AFTER XGKICK? VCL does not adds E bit without it... +--cont + + b begin + +#endvuprog + +--exit +--endexit diff --git a/engine/src/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_td_vu1_program.cpp b/engine/src/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_td_vu1_program.cpp new file mode 100644 index 0000000..494692b --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/programs/cull/stapip_cull_td_vu1_program.cpp @@ -0,0 +1,58 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "debug/debug.hpp" +#include "renderer/3d/pipeline/static/core/programs/cull/stapip_cull_td_vu1_program.hpp" + +extern u32 StaPipVU1Cull_TD_CodeStart __attribute__((section(".vudata"))); +extern u32 StaPipVU1Cull_TD_CodeEnd __attribute__((section(".vudata"))); + +namespace Tyra { + +StaPipCullTDVU1Program::StaPipCullTDVU1Program() + : StaPipVU1Program(StaPipCullTextureDirLights, &StaPipVU1Cull_TD_CodeStart, + &StaPipVU1Cull_TD_CodeEnd, + ((u64)GIF_REG_ST) << 0 | ((u64)GIF_REG_RGBAQ) << 4 | + ((u64)GIF_REG_XYZ2) << 8, + 3, 4) {} + +StaPipCullTDVU1Program::~StaPipCullTDVU1Program() {} + +std::string StaPipCullTDVU1Program::getStringName() const { + return std::string("StaPip - Cull - TD"); +} + +void StaPipCullTDVU1Program::addProgramQBufferDataToPacket( + packet2_t* packet, StaPipQBuffer* qbuffer) const { + u32 addr = VU1_STAPIP_VERT_DATA_ADDR; + + // Add vertices + packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->vertices, + qbuffer->size, true); + addr += qbuffer->size; + + // Add sts + packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->sts, qbuffer->size, + true); + addr += qbuffer->size; + + // Add normal + packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->normals, + qbuffer->size, true); + + // Add colors + if (qbuffer->bag->color->single == nullptr) { + addr += qbuffer->size; + packet2_utils_vu_add_unpack_data(packet, addr, qbuffer->colors, + qbuffer->size, true); + } +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/static/core/stapip_bag_bboxes_cacher.cpp b/engine/src/renderer/3d/pipeline/static/core/stapip_bag_bboxes_cacher.cpp new file mode 100644 index 0000000..19483bf --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/stapip_bag_bboxes_cacher.cpp @@ -0,0 +1,65 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/static/core/stapip_bag_bboxes_cacher.hpp" +#include + +namespace Tyra { + +StapipBagBBoxesCacher::StapipBagBBoxesCacher() {} + +StapipBagBBoxesCacher::~StapipBagBBoxesCacher() {} + +void StapipBagBBoxesCacher::onFrameEnd() { + for (auto& item : storage) { + if (item.framesLeftToDestroy > 0) { + item.framesLeftToDestroy--; + } + } + + storage.erase(std::remove_if(storage.begin(), storage.end(), + [](const StapipBagBBoxesCacheItem& item) { + return item.framesLeftToDestroy <= 0; + }), + storage.end()); +} + +StaPipBagPackagesBBox* StapipBagBBoxesCacher::getBBoxes( + const Vec4* vertices, const u32& count, const u32& id, + const u32& maxVertCount) { + auto* cache = getCache(maxVertCount, id); + + if (cache) { + cache->framesLeftToDestroy = cacheFramesCount * cacheSecondsCount; + return cache->bboxes.get(); + } + + auto bboxes = + std::make_unique(vertices, count, maxVertCount); + + storage.push_back( + StapipBagBBoxesCacheItem{maxVertCount, id, std::move(bboxes), + cacheFramesCount * cacheSecondsCount}); + + return storage.back().bboxes.get(); +} + +StapipBagBBoxesCacheItem* StapipBagBBoxesCacher::getCache( + const u32& maxVertCount, const u32& id) { + for (auto& item : storage) { + if (item.vu1MaxVertCount == maxVertCount && item.id == id) { + return &item; + } + } + + return nullptr; +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/static/core/stapip_clipper.cpp b/engine/src/renderer/3d/pipeline/static/core/stapip_clipper.cpp new file mode 100644 index 0000000..46ca129 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/stapip_clipper.cpp @@ -0,0 +1,86 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/static/core/stapip_clipper.hpp" + +namespace Tyra { + +StaPipClipper::StaPipClipper() {} +StaPipClipper::~StaPipClipper() {} + +void StaPipClipper::setMVP(M4x4* t_mvp) { mvp = t_mvp; } + +void StaPipClipper::init(const RendererSettings& settings) { + algorithm.init(settings); +} + +void StaPipClipper::setMaxVertCount(const u32& count) { maxVertCount = count; } + +void StaPipClipper::clip(StaPipQBuffer* buffer) { + TYRA_ASSERT(buffer->size <= maxVertCount / 3, "Buffer should have max ", + maxVertCount / 3, " verts if we want to clip it."); + + EEClipAlgorithmSettings algoSettings = {buffer->bag->lighting != nullptr, + buffer->bag->texture != nullptr, + buffer->bag->color->many != nullptr}; + + std::vector clippedVertices; + + for (u32 i = 0; i < buffer->size / 3; i++) { + for (u8 j = 0; j < 3; j++) { + inputVerts[j] = *mvp * buffer->vertices[i * 3 + j]; + + inputTriangle[j] = { + &inputVerts[j], + buffer->bag->lighting ? &buffer->normals[i * 3 + j] : nullptr, + buffer->bag->texture ? &buffer->sts[i * 3 + j] : nullptr, + buffer->bag->color->many ? &buffer->colors[i * 3 + j] : nullptr}; + } + + u8 clippedSize = + algorithm.clip(clippedTriangle, inputTriangle, algoSettings); + + if (clippedSize == 0) continue; + + auto va = clippedTriangle[0]; + for (u8 j = 1; j <= clippedSize - 2; j++) { + auto vb = clippedTriangle[j]; + auto vc = clippedTriangle[(j + 1) % clippedSize]; + clippedVertices.push_back(va); + clippedVertices.push_back(vb); + clippedVertices.push_back(vc); + } + } + + perspectiveDivide(&clippedVertices); + moveDataToBuffer(clippedVertices, buffer); +} + +void StaPipClipper::perspectiveDivide(std::vector* vertices) { + for (u32 i = 0; i < vertices->size(); i++) { + (*vertices)[i].position /= (*vertices)[i].position.w; + } +} + +void StaPipClipper::moveDataToBuffer( + const std::vector& vertices, StaPipQBuffer* buffer) { + buffer->reallocateManually(vertices.size()); + + for (u32 i = 0; i < vertices.size(); i++) { + auto& vertex = vertices.at(i); + buffer->vertices[i] = vertex.position; + + if (buffer->bag->texture) buffer->sts[i] = vertex.st; + if (buffer->bag->color->many) buffer->colors[i] = vertex.color; + if (buffer->bag->lighting) buffer->normals[i] = vertex.normal; + } +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/static/core/stapip_core.cpp b/engine/src/renderer/3d/pipeline/static/core/stapip_core.cpp new file mode 100644 index 0000000..b394292 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/stapip_core.cpp @@ -0,0 +1,294 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/static/core/stapip_core.hpp" +#include "renderer/core/renderer_core.hpp" +#include "thread/threading.hpp" + +// #define TYRA_RENDERER_VERBOSE_LOG 1 + +#ifdef TYRA_RENDERER_VERBOSE_LOG +#define Verbose(...) TyraDebug::writeLines("VRB: ", ##__VA_ARGS__, "\n") +#else +#define Verbose(...) ((void)0) +#endif + +namespace Tyra { + +StaPipCore::StaPipCore() { + maxVertCount = 0; + setPrim(); + setLod(); +} + +StaPipCore::~StaPipCore() {} + +void StaPipCore::init(RendererCore* t_core) { + rendererCore = t_core; + qbufferRenderer.init(t_core, &prim, &lod); + packager.init(&rendererCore->renderer3D.frustumPlanes); +} + +void StaPipCore::setPrim() { + prim.type = PRIM_TRIANGLE; + prim.shading = PRIM_SHADE_GOURAUD; + prim.mapping = DRAW_ENABLE; + prim.fogging = DRAW_DISABLE; + prim.blending = DRAW_ENABLE; + prim.antialiasing = DRAW_DISABLE; + prim.mapping_type = PRIM_MAP_ST; + prim.colorfix = PRIM_UNFIXED; +} + +void StaPipCore::setLod() { + lod.calculation = LOD_USE_K; + lod.max_level = 0; + lod.mag_filter = LOD_MAG_LINEAR; + lod.min_filter = LOD_MIN_LINEAR; + lod.mipmap_select = LOD_MIPMAP_REGISTER; + lod.l = 0; + lod.k = 0.0F; +} + +void StaPipCore::onFrameEnd() { cacher.onFrameEnd(); } + +void StaPipCore::reinitVU1Programs() { qbufferRenderer.reinitVU1(); } + +u32 StaPipCore::getMaxVertCountByBag(const StaPipBag* bag) { + return qbufferRenderer.getCullProgramByBag(bag)->getMaxVertCount( + bag->color->many == nullptr, qbufferRenderer.getBufferSize()); +} + +u32 StaPipCore::getMaxVertCountByParams(const bool& isSingleColor, + const bool& isLightingEnabled, + const bool& isTextureEnabled) { + return qbufferRenderer + .getCullProgramByParams(isLightingEnabled, isTextureEnabled) + ->getMaxVertCount(isSingleColor, qbufferRenderer.getBufferSize()); +} + +void StaPipCore::render(StaPipBag* bag) { + if (bag->count <= 0) return; + + bool frustumCull = + bag->info->frustumCulling == PipelineInfoBagFrustumCulling_Precise; + + TYRA_ASSERT(bag->vertices != nullptr, + "Vertices are required in 3D render bag!"); + TYRA_ASSERT(bag->info != nullptr, "Info bag is required in 3D render bag!"); + TYRA_ASSERT(bag->info->model != nullptr, + "Info bag's model pointer is empty!"); + TYRA_ASSERT(bag->color != nullptr, "Color bag is required in 3D render bag!"); + TYRA_ASSERT(bag->color->single || bag->color->many, + "At least one color is required in 3D render bag!"); + TYRA_ASSERT((!bag->color->many && !bag->lighting) || + (bag->color->many && !bag->lighting) || + (!bag->color->many && bag->lighting), + "Multicolor is not supported with lighting, please choose one!"); + TYRA_ASSERT( + !bag->lighting || (bag->lighting->lightMatrix && bag->lighting->normals && + bag->lighting->dirLights), + "If you want lighting, please provide light matrix normals and dir " + "lights!"); + TYRA_ASSERT( + !bag->texture || (bag->texture->texture && bag->texture->coordinates), + "If you want texture, please provide texture and coordinates!"); + TYRA_ASSERT(bag->info->transformationType == TyraMVP || + (!bag->info->fullClipChecks && !frustumCull), + "Please disable clip checks and frustum culling if not using MVP " + "matrix!"); + TYRA_ASSERT(!(!frustumCull && bag->info->fullClipChecks == true), + "Full clip checks are not supported with frustum culling = off!"); + + u32 maxVertCount = getMaxVertCountByBag(bag); + + StaPipBagPackagesBBox* bbox = nullptr; + if (bag->info->frustumCulling == PipelineInfoBagFrustumCulling_Precise) { + bbox = cacher.getBBoxes(bag->vertices, bag->count, + reinterpret_cast(bag->vertices), maxVertCount); + } + + setMaxVertCount(maxVertCount); + + CoreBBoxFrustum frustumCheck = OUTSIDE_FRUSTUM; + + if (frustumCull) { + frustumCheck = bbox->getMainBBox()->clipFrustumCheck( + rendererCore->renderer3D.frustumPlanes.getAll(), *bag->info->model); + + if (frustumCheck == OUTSIDE_FRUSTUM) { + return; + } + } + + packager.setRenderBBox(bbox); + + M4x4 mvp; + + if (bag->info->transformationType == TyraMP) { + mvp = rendererCore->renderer3D.getProjection() * *bag->info->model; + } else { + mvp = rendererCore->renderer3D.getViewProj() * *bag->info->model; + } + + RendererCoreTextureBuffers* texBuffers = nullptr; + if (bag->texture) { + auto temp = rendererCore->texture.useTexture(bag->texture->texture); + texBuffers = new RendererCoreTextureBuffers{temp.id, temp.core, temp.clut}; + } + + qbufferRenderer.clearLastProgramName(); + + qbufferRenderer.sendObjectData(bag, &mvp, texBuffers); + + qbufferRenderer.setClipperMVP(&mvp); + + qbufferRenderer.setInfo(bag->info); + + auto checkYesFrustumInClipYes = // cull all + frustumCull && frustumCheck == IN_FRUSTUM && bag->info->fullClipChecks; + + auto checkYesFrustumPartialClipYes = // pkgs, cull + clip + frustumCull && frustumCheck == PARTIALLY_IN_FRUSTUM && + bag->info->fullClipChecks; + + auto checkYesFrustumInClipNo = // cull all + frustumCull && frustumCheck == IN_FRUSTUM && !bag->info->fullClipChecks; + + auto checkYesFrustumPartialClipNo = // pkgs, cull all + frustumCull && frustumCheck == PARTIALLY_IN_FRUSTUM && + !bag->info->fullClipChecks; + + auto checkNoClipNo = // cull all + !frustumCull && !bag->info->fullClipChecks; + + if (checkYesFrustumInClipYes || checkYesFrustumInClipNo || checkNoClipNo) { + u16 packagesCount = 0; + auto* biggerPkgs = packager.create(&packagesCount, bag, maxVertCount); + Verbose("Material - in frustum. Pkgs: ", packagesCount, + " size: ", static_cast(biggerPkgs[0].size)); + for (u16 i = 0; i < packagesCount; i++) { + Verbose(i, " package - cull by data pointer"); + auto buffer = qbufferRenderer.getBuffer(); + buffer->fillByPointer(biggerPkgs[i]); + qbufferRenderer.cull(buffer); + } + delete[] biggerPkgs; + } else if (checkYesFrustumPartialClipYes || checkYesFrustumPartialClipNo) { + u16 packagesCount = 0; + auto doClip = checkYesFrustumPartialClipYes; + if (!doClip || bag->count >= maxVertCount * 2) { + auto packages = packager.create(&packagesCount, bag, maxVertCount); + Verbose("Material - partial. Packages: ", packagesCount); + renderPkgs(packages, doClip, packagesCount); + delete[] packages; + } else { + auto subpkgs = packager.create(&packagesCount, bag, maxVertCount / 3); + Verbose("Material - partial. Subpackages: ", packagesCount); + renderSubpkgs(subpkgs, packagesCount); + delete[] subpkgs; + } + } + + if (texBuffers) delete texBuffers; + + qbufferRenderer.flushBuffers(); + + Verbose("Render finished"); +} + +void StaPipCore::renderPkgs(StaPipBagPackage* packages, const bool& doClip, + u16 count) { + for (u16 i = 0; i < count; i++) { + auto cull = (doClip && packages[i].isInFrustum == IN_FRUSTUM) || !doClip; + auto doSubpkgs = doClip && packages[i].isInFrustum == PARTIALLY_IN_FRUSTUM; + + if (cull) { + Verbose(i, " - package in frustum -> cull"); + auto buffer = qbufferRenderer.getBuffer(); + buffer->fillByPointer(packages[i]); + qbufferRenderer.cull(buffer); + } else if (doSubpkgs) { + u16 subpkgsSize = 0; + auto packages1By3 = + packager.create(&subpkgsSize, packages[i], maxVertCount / 3); + Verbose(i, " - partial package. Created subpkgs: ", subpkgsSize); + + renderSubpkgs(packages1By3, subpkgsSize); + delete[] packages1By3; + } + Verbose(i, " - package skipped (outside)"); + } +} + +void StaPipCore::renderSubpkgs(StaPipBagPackage* subpkgs, u16 count) { + std::vector doneIndexes; + std::vector loadedIndexes; + + // Check if some subpkgs are full in frustum + for (u16 i = 0; i < count; i++) { + if (subpkgs[i].isInFrustum == IN_FRUSTUM) { + if (loadedIndexes.size() <= 1) { + Verbose(i, " - subpackage in frustum -> load"); + loadedIndexes.push_back(i); + } else { // Hmm, this will never happen? + Verbose(i, " - subpackage in frustum, cull all 3 subpkgs"); + auto buffer = qbufferRenderer.getBuffer(); + buffer->fillByCopyMax(subpkgs[loadedIndexes[0]], + subpkgs[loadedIndexes[1]], subpkgs[i]); + qbufferRenderer.cull(buffer); + doneIndexes.push_back(loadedIndexes[0]); + doneIndexes.push_back(loadedIndexes[1]); + doneIndexes.push_back(i); + loadedIndexes.clear(); + } + } + } + + if (loadedIndexes.size() == 2) { + Verbose("2 in frustum subpkgs left -> cull them"); + auto buffer = qbufferRenderer.getBuffer(); + buffer->fillByCopy1By2(subpkgs[loadedIndexes[0]], + subpkgs[loadedIndexes[1]]); + qbufferRenderer.cull(buffer); + doneIndexes.push_back(loadedIndexes[0]); + doneIndexes.push_back(loadedIndexes[1]); + } else if (loadedIndexes.size() == 1) { + Verbose("1 in frustum subpkg left -> cull it"); + auto buffer = qbufferRenderer.getBuffer(); + buffer->fillByPointer(subpkgs[loadedIndexes[0]]); + qbufferRenderer.cull(buffer); + doneIndexes.push_back(loadedIndexes[0]); + } + + for (u16 i = 0; i < count; i++) { + bool isSkip = subpkgs[i].isInFrustum == OUTSIDE_FRUSTUM || + std::find(doneIndexes.begin(), doneIndexes.end(), i) != + doneIndexes.end(); + + if (isSkip) { + Verbose(i, " - subpkg skipped, already rendered/outside"); + continue; + } + + auto buffer = qbufferRenderer.getBuffer(); + buffer->fillByCopy1By3(subpkgs[i]); + Verbose(i, " - subpkg out/partial -> send to clipper"); + qbufferRenderer.clip(buffer); + } +} + +void StaPipCore::setMaxVertCount(const u32& count) { + maxVertCount = count; + packager.setMaxVertCount(count); + qbufferRenderer.setMaxVertCount(count); +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/static/core/stapip_programs_repository.cpp b/engine/src/renderer/3d/pipeline/static/core/stapip_programs_repository.cpp new file mode 100644 index 0000000..f670339 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/stapip_programs_repository.cpp @@ -0,0 +1,48 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/static/core/stapip_programs_repository.hpp" + +namespace Tyra { + +StaPipProgramsRepository::StaPipProgramsRepository() {} + +StaPipProgramsRepository::~StaPipProgramsRepository() {} + +StaPipVU1Program* StaPipProgramsRepository::getProgram( + const StaPipProgramName& name) { + switch (name) { + case StaPipProgramName::StaPipAsIsColor: + return &asIsColor; + case StaPipProgramName::StaPipCullColor: + return &cullColor; + + case StaPipProgramName::StaPipAsIsDirLights: + return &asIsDirLights; + case StaPipProgramName::StaPipCullDirLights: + return &cullDirLights; + + case StaPipProgramName::StaPipAsIsTextureDirLights: + return &asIsTextureDirLights; + case StaPipProgramName::StaPipCullTextureDirLights: + return &cullTextureDirLights; + + case StaPipProgramName::StaPipAsIsTextureColor: + return &asIsTextureColor; + case StaPipProgramName::StaPipCullTextureColor: + return &cullTextureColor; + + default: + TYRA_TRAP("Unknown VU1 program name"); + return &cullTextureDirLights; + } +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/static/core/stapip_qbuffer.cpp b/engine/src/renderer/3d/pipeline/static/core/stapip_qbuffer.cpp new file mode 100644 index 0000000..a43fb0a --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/stapip_qbuffer.cpp @@ -0,0 +1,273 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/static/core/stapip_qbuffer.hpp" +#include +#include + +namespace Tyra { + +StaPipQBuffer::StaPipQBuffer() { + size = 0; + _isDynamicallyAllocated = false; + _stAllocated = false; + _colorAllocated = false; + _normalAllocated = false; + + vertices = nullptr; + colors = nullptr; + sts = nullptr; + normals = nullptr; +} + +StaPipQBuffer::~StaPipQBuffer() { deallocateDynamicData(); } + +void StaPipQBuffer::setMaxVertCount(const u32& count) { maxVertCount = count; } + +void StaPipQBuffer::fillByPointer(const StaPipBagPackage& pkg) { + TYRA_ASSERT(pkg.size <= maxVertCount, "VU1 buffer supports only ", + maxVertCount, " verts. Provided: ", pkg.size); + + deallocateDynamicData(); + + // Too bad, but in reality const is not violated. + // This class needs refactor + vertices = const_cast(pkg.vertices); + sts = const_cast(pkg.sts); + colors = const_cast(pkg.colors); + normals = const_cast(pkg.normals); + size = pkg.size; + bag = pkg.bag; +} + +void StaPipQBuffer::fillByCopyMax(const StaPipBagPackage& pkg1, + const StaPipBagPackage& pkg2, + const StaPipBagPackage& pkg3) { + TYRA_ASSERT(pkg1.size <= maxVertCount / 3, + "Wrong package size (1). Provided: ", pkg1.size); + TYRA_ASSERT(pkg2.size <= maxVertCount / 3, + "Wrong package size (2). Provided: ", pkg2.size); + TYRA_ASSERT(pkg3.size <= maxVertCount / 3, + "Wrong package size (3). Provided: ", pkg3.size); + + deallocateDynamicData(); + size = pkg1.size + pkg2.size + pkg3.size; + allocateDynamicData(size, pkg1.bag); + + for (u16 i = 0; i < pkg1.size; i++) { + vertices[i].set(pkg1.vertices[i]); + + if (pkg1.bag->texture) sts[i].set(pkg1.sts[i]); + + if (pkg1.bag->color->many) + colors[i].set(reinterpret_cast(pkg1.colors[i])); + + if (pkg1.bag->lighting) normals[i].set(pkg1.normals[i]); + } + + for (u16 i = 0; i < pkg2.size; i++) { + vertices[i + pkg1.size].set(pkg2.vertices[i]); + + if (pkg1.bag->texture) sts[i + pkg1.size].set(pkg2.sts[i]); + + if (pkg1.bag->color->many) + colors[i + pkg1.size].set(reinterpret_cast(pkg2.colors[i])); + + if (pkg1.bag->lighting) normals[i + pkg1.size].set(pkg2.normals[i]); + } + + for (u16 i = 0; i < pkg3.size; i++) { + vertices[i + pkg1.size + pkg2.size].set(pkg3.vertices[i]); + + if (pkg1.bag->texture) sts[i + pkg1.size + pkg2.size].set(pkg3.sts[i]); + + if (pkg1.bag->color->many) + colors[i + pkg1.size + pkg2.size].set( + reinterpret_cast(pkg3.colors[i])); + + if (pkg1.bag->lighting) + normals[i + pkg1.size + pkg2.size].set(pkg3.normals[i]); + } + + bag = pkg1.bag; +} + +void StaPipQBuffer::fillByCopy1By2(const StaPipBagPackage& pkg1, + const StaPipBagPackage& pkg2) { + TYRA_ASSERT(pkg1.size <= maxVertCount / 3, + "Wrong package size (1). Provided: ", pkg1.size); + TYRA_ASSERT(pkg2.size <= maxVertCount / 3, + "Wrong package size (2). Provided: ", pkg2.size); + + deallocateDynamicData(); + size = pkg1.size + pkg2.size; + allocateDynamicData(size, pkg1.bag); + + for (u16 i = 0; i < pkg1.size; i++) { + vertices[i].set(pkg1.vertices[i]); + + if (pkg1.bag->texture) sts[i].set(pkg1.sts[i]); + + if (pkg1.bag->color->many) + colors[i].set(reinterpret_cast(pkg1.colors[i])); + + if (pkg1.bag->lighting) normals[i].set(pkg1.normals[i]); + } + + for (u16 i = 0; i < pkg2.size; i++) { + vertices[i + pkg1.size].set(pkg2.vertices[i]); + + if (pkg1.bag->texture) sts[i + pkg1.size].set(pkg2.sts[i]); + + if (pkg1.bag->color->many) + colors[i + pkg1.size].set(reinterpret_cast(pkg2.colors[i])); + + if (pkg1.bag->lighting) normals[i + pkg1.size].set(pkg2.normals[i]); + } + + bag = pkg1.bag; +} + +void StaPipQBuffer::fillByCopy1By3(const StaPipBagPackage& pkg) { + TYRA_ASSERT(pkg.size <= maxVertCount / 3, + "Wrong package size (1). Provided: ", pkg.size); + + deallocateDynamicData(); + size = pkg.size; + allocateDynamicData(size, pkg.bag); + + for (u16 i = 0; i < pkg.size; i++) { + vertices[i].set(pkg.vertices[i]); + + if (pkg.bag->texture) sts[i].set(pkg.sts[i]); + + if (pkg.bag->color->many) + colors[i].set(reinterpret_cast(pkg.colors[i])); + + if (pkg.bag->lighting) normals[i].set(pkg.normals[i]); + } + + bag = pkg.bag; +} + +void StaPipQBuffer::reallocateManually(const u16& t_size) { + deallocateDynamicData(); + allocateDynamicData(t_size, bag); + size = t_size; +} + +void StaPipQBuffer::deallocateDynamicData() { + if (!_isDynamicallyAllocated) return; + + delete[] vertices; + + if (_stAllocated) { + delete[] sts; + _stAllocated = false; + } + + if (_colorAllocated) { + delete[] colors; + _colorAllocated = false; + } + + if (_normalAllocated) { + delete[] normals; + _normalAllocated = false; + } + + _isDynamicallyAllocated = false; +} + +/** + * When we not receive maxVertCount vertices, we must align it by ourself. + * Too bad - not efficient. + */ +void StaPipQBuffer::allocateDynamicData(u16 size, StaPipBag* bag) { + TYRA_ASSERT(size <= maxVertCount, "Wrong size. Max buffer size in VU1 is ", + maxVertCount, ". Provided: ", size); + TYRA_ASSERT(!_isDynamicallyAllocated, "Buffer is already allocated"); + + if (size == 0) return; + + vertices = new Vec4[size]; + + if (bag->texture != nullptr) { + sts = new Vec4[size]; + _stAllocated = true; + } + + if (bag->color->many != nullptr) { + colors = new Vec4[size]; + _colorAllocated = true; + } + + if (bag->lighting != nullptr) { + normals = new Vec4[size]; + _normalAllocated = true; + } + + _isDynamicallyAllocated = true; +} + +bool StaPipQBuffer::any() const { return size > 0; } + +void StaPipQBuffer::print() const { + auto text = getPrint(nullptr); + printf("%s\n", text.c_str()); +} + +void StaPipQBuffer::print(const char* name) const { + auto text = getPrint(name); + printf("%s\n", text.c_str()); +} + +std::string StaPipQBuffer::getPrint(const char* name) const { + std::stringstream res; + if (name) { + res << name << "("; + } else { + res << "StaPipQBuffer("; + } + res << std::fixed << std::setprecision(2); + res << std::endl; + res << "Size: " << static_cast(size) << std::endl; + + res << "Vertices: " << std::endl; + for (u32 i = 0; i < size; i++) + res << i << ": " << vertices[i].getPrint() << std::endl; + + if (bag->texture != nullptr) { + res << "STs: " << std::endl; + for (u32 i = 0; i < size; i++) + res << i << ": " << sts[i].getPrint() << std::endl; + } + + if (bag->color->many != nullptr) { + res << "Colors: " << std::endl; + for (u32 i = 0; i < size; i++) + res << i << ": " << colors[i].getPrint() << std::endl; + } + + if (bag->lighting != nullptr) { + res << "Normals: " << std::endl; + for (u32 i = 0; i < size; i++) { + res << i << ": " << normals[i].getPrint(); + if (i < size - 1) { + res << std::endl; + } + } + } + + res << ")"; + return res.str(); +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/static/core/stapip_qbuffer_renderer.cpp b/engine/src/renderer/3d/pipeline/static/core/stapip_qbuffer_renderer.cpp new file mode 100644 index 0000000..1bf1adc --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/stapip_qbuffer_renderer.cpp @@ -0,0 +1,445 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/static/core/stapip_qbuffer_renderer.hpp" +#include "renderer/3d/pipeline/static/core/programs/stapip_vu1_shared_defines.h" +#include "packet2/packet2_tyra_utils.hpp" + +// #define TYRA_QBUFF_RENDERER_VERBOSE_LOG 1 + +#ifdef TYRA_QBUFF_RENDERER_VERBOSE_LOG +#define Verbose(...) TyraDebug::writeLines("VRB: ", ##__VA_ARGS__, "\n") +#else +#define Verbose(...) ((void)0) +#endif + +namespace Tyra { + +/** + * VU1 = 1000 vert + * + * Quadbuffering: + * 2 main buffers = 1000 / 2 = 500 vert + * 2 kick buffers = 500 / 2 = 250 vert + * + * Vert data: + * Pos + Normal + ST + Color = 4 + * = 4 * 48 = 192 + * + * Other data: + * mvp matrix, light matrix, tags = 14 + * 20 light vectors, light intesities = 25 + * = 14 + 25 = 39 + * + * All data: + * = 192 + 39 = 231 + * + */ + +const u16 StaPipQBufferRenderer::buffersCount = 32; + +StaPipQBufferRenderer::StaPipQBufferRenderer() { + currentBufferIndex = 0; + nextBufferIndex = 0; + context = 0; + lastProgramName = StaPipUndefinedProgram; + + qbuffersPacketSize = 4 * buffersCount; + programsPacket = nullptr; +} + +void StaPipQBufferRenderer::allocateOnUse() { + staticDataPacket = packet2_create(3, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); + objectDataPacket = packet2_create(20, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); + + packets = new packet2_t*[2]; + for (u16 i = 0; i < 2; i++) + packets[i] = + packet2_create(qbuffersPacketSize, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); + + buffers = new StaPipQBuffer*[buffersCount]; + for (u16 i = 0; i < buffersCount; i++) { + buffers[i] = new StaPipQBuffer(); + } + + dBufferPrograms = new StaPipVU1Program*[buffersCount]; + + sendStaticData(); +} + +void StaPipQBufferRenderer::deallocateOnUse() { + packet2_free(staticDataPacket); + packet2_free(objectDataPacket); + + for (u16 i = 0; i < 2; i++) packet2_free(packets[i]); + delete[] packets; + + for (u16 i = 0; i < buffersCount; i++) delete buffers[i]; + delete[] buffers; + + delete[] dBufferPrograms; +} + +StaPipQBufferRenderer::~StaPipQBufferRenderer() { + if (programsPacket) packet2_free(programsPacket); +} + +void StaPipQBufferRenderer::init(RendererCore* t_core, prim_t* t_prim, + lod_t* t_lod) { + path1 = t_core->getPath1(); + clipper.init(t_core->getSettings()); + rendererCore = t_core; + prim = t_prim; + lod = t_lod; + + dma_channel_initialize(DMA_CHANNEL_VIF1, nullptr, 0); + + setProgramsCache(); + + reinitVU1(); + + TYRA_LOG("StaPipQBufferRenderer initialized"); +} + +void StaPipQBufferRenderer::reinitVU1() { + uploadPrograms(); + setDoubleBuffer(); +} + +void StaPipQBufferRenderer::sendObjectData( + StaPipBag* bag, M4x4* mvp, RendererCoreTextureBuffers* texBuffers) const { + packet2_reset(objectDataPacket, false); + packet2_utils_vu_add_unpack_data(objectDataPacket, VU1_MVP_MATRIX_ADDR, + mvp->data, 4, false); + + if (bag->lighting) { + packet2_utils_vu_add_unpack_data(objectDataPacket, VU1_LIGHTS_MATRIX_ADDR, + bag->lighting->lightMatrix, 3, false); + + packet2_utils_vu_add_unpack_data( + objectDataPacket, VU1_LIGHTS_DIRS_ADDR, + bag->lighting->dirLights->getLightDirections(), 3, false); + + packet2_utils_vu_add_unpack_data(objectDataPacket, VU1_LIGHTS_COLORS_ADDR, + bag->lighting->dirLights->getLightColors(), + 4, false); + } + + u8 singleColorEnabled = bag->color->single != nullptr; + + if (singleColorEnabled) // Color is placed in 4th slot of + // VU1_LIGHTS_MATRIX_ADDR + Packet2TyraUtils::addUnpackData(objectDataPacket, VU1_SINGLE_COLOR_ADDR, + bag->color->single->rgba, 1, false); + + packet2_utils_vu_open_unpack(objectDataPacket, VU1_OPTIONS_ADDR, false); + { + packet2_add_u32(objectDataPacket, + singleColorEnabled); // Single color enabled. + packet2_add_u32(objectDataPacket, 0); // not used, padding + packet2_add_u32(objectDataPacket, 0); // not used, padding + packet2_add_u32(objectDataPacket, 0); // not used, padding + + packet2_utils_gs_add_lod(objectDataPacket, lod); + + if (bag->info->zTestType == PipelineZTest_AllPass) { + packet2_add_2x_s64(objectDataPacket, + GS_SET_TEST(0, 0, 0, 0, 0, 0, 0, ZTEST_METHOD_ALLPASS), + GS_REG_TEST); + } else { + packet2_add_2x_s64( + objectDataPacket, + GS_SET_TEST(DRAW_ENABLE, ATEST_METHOD_NOTEQUAL, 0x00, + ATEST_KEEP_FRAMEBUFFER, DRAW_DISABLE, DRAW_DISABLE, + DRAW_ENABLE, rendererCore->gs.zBuffer.method), + GS_REG_TEST); + } + + if (texBuffers != nullptr) { + rendererCore->texture.updateClutBuffer(texBuffers->clut); + + packet2_utils_gs_add_texbuff_clut(objectDataPacket, texBuffers->core, + &rendererCore->texture.clut); + } + } + packet2_utils_vu_close_unpack(objectDataPacket); + + packet2_utils_vu_add_end_tag(objectDataPacket); + dma_channel_wait(DMA_CHANNEL_VIF1, 0); + dma_channel_send_packet2(objectDataPacket, DMA_CHANNEL_VIF1, true); +} + +void StaPipQBufferRenderer::setInfo(PipelineInfoBag* bag) { + prim->antialiasing = bag->antiAliasingEnabled; + prim->blending = bag->blendingEnabled; + prim->shading = bag->shadingType; + + if (bag->textureMappingType == TyraLinear) { + lod->mag_filter = LOD_MAG_LINEAR; + lod->min_filter = LOD_MIN_LINEAR; + } else { + lod->mag_filter = LOD_MAG_NEAREST; + lod->min_filter = LOD_MIN_NEAREST; + } +} + +void StaPipQBufferRenderer::sendStaticData() const { + packet2_reset(staticDataPacket, false); + packet2_utils_vu_open_unpack(staticDataPacket, VU1_SET_GIFTAG_ADDR, false); + { packet2_utils_gif_add_set(staticDataPacket, 1); } + packet2_utils_vu_close_unpack(staticDataPacket); + + packet2_utils_vu_add_end_tag(staticDataPacket); + dma_channel_wait(DMA_CHANNEL_VIF1, 0); + dma_channel_send_packet2(staticDataPacket, DMA_CHANNEL_VIF1, true); +} + +void StaPipQBufferRenderer::setProgramsCache() { + VU1Program** programs = new VU1Program*[8]; + programs[0] = repository.getProgram(StaPipCullColor); + programs[1] = repository.getProgram(StaPipAsIsColor); + programs[2] = repository.getProgram(StaPipCullDirLights); + programs[3] = repository.getProgram(StaPipAsIsDirLights); + programs[4] = repository.getProgram(StaPipCullTextureDirLights); + programs[5] = repository.getProgram(StaPipAsIsTextureDirLights); + programs[6] = repository.getProgram(StaPipCullTextureColor); + programs[7] = repository.getProgram(StaPipAsIsTextureColor); + programsPacket = path1->createProgramsCache(programs, 8, 0); + delete[] programs; +} + +void StaPipQBufferRenderer::uploadPrograms() { + dma_channel_wait(DMA_CHANNEL_VIF1, 0); + dma_channel_send_packet2(programsPacket, DMA_CHANNEL_VIF1, true); + dma_channel_wait(DMA_CHANNEL_VIF1, 0); +} + +void StaPipQBufferRenderer::setDoubleBuffer() { + u16 startingAddr = VU1_STAPIP_LAST_ITEM_ADDR + 1; + const u16 bufferMaxSize = 1000; + bufferSize = (bufferMaxSize - startingAddr) / 2; + + path1->setDoubleBuffer(startingAddr, bufferSize); + + bufferSize -= 1; // Because we don't want to upload anything from first + // buffer, to first addr of second buffer +} + +StaPipQBuffer* StaPipQBufferRenderer::getBuffer() { + currentBufferIndex = nextBufferIndex++; + Verbose("Proposing buffer: ", currentBufferIndex); + auto* result = buffers[currentBufferIndex]; + if (nextBufferIndex >= buffersCount) { + Verbose("Rollup - clearing buffer indices. currentBufferIndex: ", + currentBufferIndex, " (before)nextBufferIndex: ", nextBufferIndex); + nextBufferIndex = 0; + } + return result; +} + +u16 StaPipQBufferRenderer::getQBufferIndex(StaPipQBuffer* buffer) { + for (u16 i = 0; i < buffersCount; i++) { + if (buffers[i] == buffer) return i; + } + TYRA_TRAP("Buffer not found!"); + return 0; +} + +bool StaPipQBufferRenderer::is1stDBufferFlushTime() { + return nextBufferIndex == buffersCount / 2; +} + +bool StaPipQBufferRenderer::is2ndDBufferFlushTime() { + return nextBufferIndex == 0; +} + +void StaPipQBufferRenderer::flushBuffers() { + auto is1stDBuffer = is1stDBufferFlushTime(); + auto is2ndDBuffer = is2ndDBufferFlushTime(); + + if (!is1stDBuffer && !is2ndDBuffer) { + auto offset = currentBufferIndex >= buffersCount / 2 ? buffersCount / 2 : 0; + auto size = (currentBufferIndex + 1) - offset; + Verbose("-- End flush. from: ", offset, " to: ", offset + size); + addBuffersDataToPacket(offset, offset + size); + sendPacket(); + } + + currentBufferIndex = 0; + nextBufferIndex = 0; + + Verbose("End flush - zeroing buffer indices."); +} + +void StaPipQBufferRenderer::cull(StaPipQBuffer* buffer) { + if (buffer->size == 0) { + return; + } + + dBufferPrograms[getQBufferIndex(buffer)] = getCullProgramByBag(buffer->bag); + + Verbose("Add cull[", getQBufferIndex(buffer), "]: ", buffer->size); + + auto is1stDBuffer = is1stDBufferFlushTime(); + auto is2ndDBuffer = is2ndDBufferFlushTime(); + + if (is1stDBuffer || is2ndDBuffer) { + auto from = is1stDBuffer ? 0 : buffersCount / 2; + auto to = from + buffersCount / 2; + + Verbose("-- Half flush at ", getQBufferIndex(buffer), ". from: ", from, + " to: ", to); + + addBuffersDataToPacket(from, to); + sendPacket(); + } +} + +void StaPipQBufferRenderer::clip(StaPipQBuffer* buffer) { + if (buffer->size == 0) { + return; + } + + dBufferPrograms[getQBufferIndex(buffer)] = getAsIsProgramByBag(buffer->bag); + + clipper.clip(buffer); + + Verbose("Add clip[", getQBufferIndex(buffer), "]: ", buffer->size); + + auto is1stDBuffer = is1stDBufferFlushTime(); + auto is2ndDBuffer = is2ndDBufferFlushTime(); + + if (is1stDBuffer || is2ndDBuffer) { + auto from = is1stDBuffer ? 0 : buffersCount / 2; + auto to = from + buffersCount / 2; + + Verbose("-- Half flush at ", getQBufferIndex(buffer), ". from: ", from, + " to: ", to); + + addBuffersDataToPacket(from, to); + sendPacket(); + } +} + +void StaPipQBufferRenderer::clearLastProgramName() { + lastProgramName = StaPipUndefinedProgram; +} + +void StaPipQBufferRenderer::addBuffersDataToPacket(const u32& from, + const u32& to) { + auto* currentPacket = packets[context]; + packet2_reset(currentPacket, false); + + for (u32 i = from; i < to; i++) { + if (!buffers[i]->any()) continue; + + auto* program = dBufferPrograms[i]; + + program->addBufferDataToPacket(currentPacket, buffers[i], prim); + + Verbose("Send ", program->getStringName(), "[", i, "]: ", buffers[i]->size); + + if (lastProgramName != program->getName()) { + packet2_utils_vu_add_start_program(currentPacket, + program->getDestinationAddress()); + lastProgramName = program->getName(); + } else { + packet2_utils_vu_add_continue_program(currentPacket); + } + } + + packet2_utils_vu_add_end_tag(currentPacket); +} + +void StaPipQBufferRenderer::sendPacket() { + auto* currentPacket = packets[context]; + + TYRA_ASSERT(packet2_get_qw_count(currentPacket) <= qbuffersPacketSize, + "Packet is too big. Internal error"); + + dma_channel_wait(DMA_CHANNEL_VIF1, 0); + // dma_wait_fast(); // This have no impact on performance + + dma_channel_send_packet2(currentPacket, DMA_CHANNEL_VIF1, true); + + // Switch packet, so we can proceed during DMA transfer + context = !context; +} + +void StaPipQBufferRenderer::setMaxVertCount(const u32& count) { + for (u32 i = 0; i < buffersCount; i++) { + buffers[i]->setMaxVertCount(count); + } + clipper.setMaxVertCount(count); +} + +StaPipVU1Program* StaPipQBufferRenderer::getAsIsProgramByBag( + const StaPipBag* bag) { + auto programType = getDrawProgramTypeByBag(bag); + + if (programType == StaPipVU1TextureDirLights) + return getProgramByName(StaPipAsIsTextureDirLights); + else if (programType == StaPipVU1DirLights) + return getProgramByName(StaPipAsIsDirLights); + else if (programType == StaPipVU1TextureColor) + return getProgramByName(StaPipAsIsTextureColor); + else + return getProgramByName(StaPipAsIsColor); +} + +StaPipVU1Program* StaPipQBufferRenderer::getCullProgramByBag( + const StaPipBag* bag) { + auto programType = getDrawProgramTypeByBag(bag); + return getCullProgramByType(programType); +} + +StaPipVU1Program* StaPipQBufferRenderer::getProgramByName( + const StaPipProgramName& name) { + return repository.getProgram(name); +} + +StaPipVU1Program* StaPipQBufferRenderer::getCullProgramByParams( + const bool& isLightingEnabled, const bool& isTextureEnabled) { + auto type = getDrawProgramTypeByParams(isLightingEnabled, isTextureEnabled); + return getCullProgramByType(type); +} + +StaPipVU1Program* StaPipQBufferRenderer::getCullProgramByType( + const StaPipProgramType& programType) { + if (programType == StaPipVU1TextureDirLights) + return getProgramByName(StaPipCullTextureDirLights); + else if (programType == StaPipVU1DirLights) + return getProgramByName(StaPipCullDirLights); + else if (programType == StaPipVU1TextureColor) + return getProgramByName(StaPipCullTextureColor); + else + return getProgramByName(StaPipCullColor); +} + +StaPipProgramType StaPipQBufferRenderer::getDrawProgramTypeByBag( + const StaPipBag* bag) const { + auto isLightingEnabled = bag->lighting != nullptr; + auto isTextureEnabled = bag->texture != nullptr; + return getDrawProgramTypeByParams(isLightingEnabled, isTextureEnabled); +} + +StaPipProgramType StaPipQBufferRenderer::getDrawProgramTypeByParams( + const bool& isLightingEnabled, const bool& isTextureEnabled) const { + if (isLightingEnabled && isTextureEnabled) + return StaPipVU1TextureDirLights; + else if (isLightingEnabled) + return StaPipVU1DirLights; + else if (isTextureEnabled) + return StaPipVU1TextureColor; + else + return StaPipVU1Color; +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/static/core/stapip_vu1_program.cpp b/engine/src/renderer/3d/pipeline/static/core/stapip_vu1_program.cpp new file mode 100644 index 0000000..9908a66 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/core/stapip_vu1_program.cpp @@ -0,0 +1,82 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/static/core/stapip_vu1_program.hpp" + +namespace Tyra { + +StaPipVU1Program::StaPipVU1Program(const StaPipProgramName& t_name, + u32* t_start, u32* t_end, + const u32& t_reglist, + const u8& t_reglistCount, + const u8& t_elementsPerVertex) + : VU1Program(t_start, t_end), + name(t_name), + reglistCount(t_reglistCount), + elementsPerVertex(t_elementsPerVertex), + reglist(t_reglist) { + packetSize = packet2_utils_get_packet_size_for_program(start, end); + programSize = calculateProgramSize(); +} + +StaPipVU1Program::~StaPipVU1Program() {} + +const StaPipProgramName& StaPipVU1Program::getName() const { return name; } + +u32& StaPipVU1Program::getReglist() { return reglist; } + +void StaPipVU1Program::addBufferDataToPacket(packet2_t* packet, + StaPipQBuffer* buffer, + prim_t* prim) { + addStandardBufferDataToPacket(packet, buffer, prim); + addProgramQBufferDataToPacket(packet, buffer); +} + +void StaPipVU1Program::addStandardBufferDataToPacket(packet2_t* packet, + StaPipQBuffer* buffer, + prim_t* prim) { + if (buffer->bag->texture) + prim->mapping = 1; + else + prim->mapping = 0; + + packet2_utils_vu_open_unpack(packet, 0, true); + { + packet2_add_float(packet, 2048.0F); // scale + packet2_add_float(packet, 2048.0F); // scale + packet2_add_float(packet, static_cast(0xFFFFFF) / 32.0F); // scale + packet2_add_u32(packet, buffer->size); // vertex count + + packet2_utils_gs_add_prim_giftag(packet, prim, buffer->size, reglist, + reglistCount, 0); + } + packet2_utils_vu_close_unpack(packet); +} + +u16 StaPipVU1Program::getMaxVertCount(const bool& singleColorEnabled, + const u16& bufferSize) const { + u16 res = bufferSize - 7; // 7 because of -> StoreTyraGifTags{} + u8 colorElementsPerVertex = + singleColorEnabled ? elementsPerVertex - 1 : elementsPerVertex; + res /= (colorElementsPerVertex + reglistCount); + + // Buffer size = VU1 double buffer size (xtop) + // QBufferSize = res (it is placed inside VU1) + + // Must be dividable by 3 and the result also dividable by 3. Why? + // 1st dividable reason - triangle, and packaging system in 3d rendering + // 2nd dividable reason - subpackaging system. We are splitting packages into + // 3 subpackages in 3d renderer. + res = res / 3 / 3; + res = res * 3 * 3; + return res; +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/pipeline/static/static_pipeline.cpp b/engine/src/renderer/3d/pipeline/static/static_pipeline.cpp new file mode 100644 index 0000000..9c2e127 --- /dev/null +++ b/engine/src/renderer/3d/pipeline/static/static_pipeline.cpp @@ -0,0 +1,208 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/pipeline/static/static_pipeline.hpp" +#include "debug/debug.hpp" +#include "renderer/3d/pipeline/static/core/bag/stapip_info_bag.hpp" +#include +namespace Tyra { + +StaticPipeline::StaticPipeline() {} + +StaticPipeline::~StaticPipeline() { + if (onDestroy) onDestroy(this); +} + +void StaticPipeline::setRenderer(RendererCore* t_core) { + rendererCore = t_core; + core.init(t_core); +} + +void StaticPipeline::onUse() { + dma_channel_fast_waits(DMA_CHANNEL_VIF1); + + colorsCache = new Vec4[4]; + core.allocateOnUse(); + core.reinitVU1Programs(); +} + +void StaticPipeline::onUseEnd() { + delete[] colorsCache; + + core.deallocateOnUse(); +} + +void StaticPipeline::onFrameEnd() { core.onFrameEnd(); } + +void StaticPipeline::render(const StaticMesh* mesh) { render(mesh, nullptr); } + +void StaticPipeline::render(const StaticMesh* mesh, + const StaPipOptions& options) { + render(mesh, &options); +} + +void StaticPipeline::render(const StaticMesh* mesh, + const StaPipOptions* options) { + bool optionsManuallyAllocated = false; + + if (!options) { + options = new StaPipOptions(); + optionsManuallyAllocated = true; + } + + auto model = mesh->getModelMatrix(); + auto* infoBag = getInfoBag(mesh, options, &model); + auto dirLightsBag = std::make_unique(true); + + TYRA_ASSERT( + !(options->frustumCulling != PipelineFrustumCulling_Precise && + infoBag->fullClipChecks == true), + "Full clip checks are only supported with frustum culling == Precise!"); + TYRA_ASSERT(options->transformationType == TyraMVP || + (!options->fullClipChecks && + options->frustumCulling == PipelineFrustumCulling_None), + "Please disable clip checks and frustum culling if not using MVP " + "matrix!"); + + if (options->frustumCulling == PipelineFrustumCulling_Simple) { + auto* frame = mesh->frame; + if (frame->bbox->frustumCheck( + rendererCore->renderer3D.frustumPlanes.getAll(), model) == + CoreBBoxFrustum::OUTSIDE_FRUSTUM) { + return; + } + } + + if (options && options->lighting) setLightingColorsCache(options->lighting); + + for (u32 i = 0; i < mesh->materials.size(); i++) { + auto* material = mesh->materials[i]; + auto* materialFrame = material->frames[0]; + StaPipBag bag; + addVertices(materialFrame, &bag); + bag.info = infoBag; + bag.color = getColorBag(material, materialFrame); + bag.texture = getTextureBag(material, materialFrame); + bag.lighting = + getLightingBag(materialFrame, dirLightsBag.get(), &model, options); + + core.render(&bag); + + deallocDrawBags(&bag, material); + } + + delete infoBag; + + if (optionsManuallyAllocated) delete options; +} + +void StaticPipeline::addVertices(const MeshMaterialFrame* materialFrame, + StaPipBag* bag) const { + bag->count = materialFrame->count; + bag->vertices = materialFrame->vertices; +} + +StaPipInfoBag* StaticPipeline::getInfoBag(const StaticMesh* mesh, + const StaPipOptions* options, + M4x4* model) const { + auto* result = new StaPipInfoBag(); + + result->antiAliasingEnabled = options->antiAliasingEnabled; + result->blendingEnabled = options->blendingEnabled; + result->shadingType = options->shadingType; + result->textureMappingType = options->textureMappingType; + result->transformationType = options->transformationType; + result->frustumCulling = + options->frustumCulling == PipelineFrustumCulling_Precise + ? PipelineInfoBagFrustumCulling_Precise + : PipelineInfoBagFrustumCulling_None; + result->fullClipChecks = options->fullClipChecks; + result->zTestType = options->zTestType; + result->model = model; + + return result; +} + +StaPipColorBag* StaticPipeline::getColorBag( + const MeshMaterial* material, + const MeshMaterialFrame* materialFrame) const { + auto* result = new StaPipColorBag(); + + if (material->lightmapFlag) { + result->many = materialFrame->colors; + } else { + result->single = &material->ambient; + } + + return result; +} + +StaPipTextureBag* StaticPipeline::getTextureBag( + const MeshMaterial* material, const MeshMaterialFrame* materialFrame) { + if (!materialFrame->textureCoords) return nullptr; + + auto* result = new StaPipTextureBag(); + + result->texture = + rendererCore->texture.repository.getByMeshMaterialId(material->id); + + TYRA_ASSERT(result->texture, "Texture for material: ", material->name, + "Id: ", material->id, + "Was not found in texture repository! Did you forget to add " + "texture or disable texture coords loading in mesh?"); + + result->coordinates = materialFrame->textureCoords; + + return result; +} + +StaPipLightingBag* StaticPipeline::getLightingBag( + const MeshMaterialFrame* materialFrame, PipelineDirLightsBag* dirLightsBag, + M4x4* model, const StaPipOptions* options) const { + if (!materialFrame->normals || options == nullptr || + options->lighting == nullptr) + return nullptr; + + auto* result = new StaPipLightingBag(); + + result->dirLights = dirLightsBag; + result->lightMatrix = model; + + result->dirLights->setLightsManually( + colorsCache, options->lighting->directionalDirections); + + result->normals = materialFrame->normals; + + return result; +} + +void StaticPipeline::setLightingColorsCache( + PipelineLightingOptions* lightingOptions) { + for (int i = 0; i < 3; i++) { + colorsCache[i] = + reinterpret_cast(lightingOptions->directionalColors[i]); + } + colorsCache[3] = reinterpret_cast(*lightingOptions->ambientColor); +} + +void StaticPipeline::deallocDrawBags(StaPipBag* bag, + const MeshMaterial* material) const { + if (bag->texture) { + delete bag->texture; + } + + if (bag->lighting) { + delete bag->lighting; + } + + delete bag->color; +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/renderer_3d.cpp b/engine/src/renderer/3d/renderer_3d.cpp new file mode 100644 index 0000000..b227acd --- /dev/null +++ b/engine/src/renderer/3d/renderer_3d.cpp @@ -0,0 +1,49 @@ + +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/renderer_3d.hpp" + +namespace Tyra { + +Renderer3D::Renderer3D() { currentPipeline = nullptr; } + +Renderer3D::~Renderer3D() {} + +void Renderer3D::init(RendererCore* core) { utility.init(core); } + +void Renderer3D::onFrameEnd() { + if (currentPipeline != nullptr) { + currentPipeline->onFrameEnd(); + } +} + +void Renderer3D::usePipeline(Renderer3DPipeline& pipeline) { + usePipeline(&pipeline); +} + +void Renderer3D::usePipeline(Renderer3DPipeline* pipeline) { + if (currentPipeline != pipeline) { + if (currentPipeline) currentPipeline->onUseEnd(); + currentPipeline = pipeline; + currentPipeline->onDestroy = + std::bind(&Renderer3D::onDestroy, this, std::placeholders::_1); + currentPipeline->onUse(); + } +} + +void Renderer3D::onDestroy(Renderer3DPipeline* pipeline) { + if (currentPipeline == pipeline) { + currentPipeline->onUseEnd(); + currentPipeline = nullptr; + } +} + +} // namespace Tyra diff --git a/engine/src/renderer/3d/renderer_3d_utility.cpp b/engine/src/renderer/3d/renderer_3d_utility.cpp new file mode 100644 index 0000000..62a90d9 --- /dev/null +++ b/engine/src/renderer/3d/renderer_3d_utility.cpp @@ -0,0 +1,315 @@ + +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/3d/renderer_3d_utility.hpp" +#include "debug/debug.hpp" +#include +#include +#include +#include +#include + +namespace Tyra { + +Renderer3DUtility::Renderer3DUtility() {} + +Renderer3DUtility::~Renderer3DUtility() {} + +#define TYRA_UTILS_LINE_REGLIST \ + ((u64)GIF_REG_XYZ2) << 0 | ((u64)GIF_REG_XYZ2) << 4 + +void Renderer3DUtility::init(RendererCore* t_core) { + core = t_core; + + prim.type = PRIM_LINE; + prim.shading = PRIM_SHADE_FLAT; + prim.mapping = DRAW_DISABLE; + prim.fogging = DRAW_DISABLE; + prim.blending = DRAW_DISABLE; + prim.antialiasing = DRAW_ENABLE; + prim.mapping_type = PRIM_MAP_ST; + prim.colorfix = PRIM_UNFIXED; + + const auto& settings = core->getSettings(); + planesClipAlgorithm.init(settings); +} + +void Renderer3DUtility::drawBox(const Vec4& v, const float& size) { + drawBox(v, size, Color(192.0F, 32.0F, 32.0F, 128.0F)); +} + +void Renderer3DUtility::drawLine(const Vec4& from, const Vec4& to) { + drawLine(from, to, Color(192.0F, 32.0F, 32.0F, 128.0F)); +} + +void Renderer3DUtility::drawBBox(const CoreBBox& v) { + drawBBox(v, Color(192.0F, 32.0F, 32.0F, 128.0F)); +} + +void Renderer3DUtility::drawBox(const Vec4& v, const float& size, + const Color& color) { + auto bbox = CoreBBox::create(v, size); + drawBBox(bbox, color); +} + +void Renderer3DUtility::drawLine(const Vec4& from, const Vec4& to, + const Color& color) { + const u8 vertCount = 2; + const s8 thickness = 2; + s16 packetSize = 8 * thickness; + auto gsColor = getGSColor(color); + + auto* packet = + packet2_create(packetSize, P2_TYPE_NORMAL, P2_MODE_CHAIN, false); + + std::array inputVerts; + inputVerts[0] = from; + inputVerts[1] = to; + + std::array outputVerts; + + packet2_chain_open_end(packet, 0, 0); + packet2_update(packet, draw_prim_start(packet->next, 0, &prim, &gsColor)); + + for (s8 i = 0; i < thickness; i++) { + Vec4 scale(2048.0F + i, 2048.0F + i, static_cast(0xFFFFFF) / 32.0F, + 1.0F); + + auto draw = calcLineVertices(outputVerts.data(), inputVerts[0], + inputVerts[1], scale); + + if (!draw) { + packet2_free(packet); + return; + } + + packet2_add_u64(packet, outputVerts[0].xyz); + packet2_add_u64(packet, outputVerts[1].xyz); + } + + packet2_pad128(packet, 0); + + packet2_update(packet, + draw_prim_end(packet->next, 2, TYRA_UTILS_LINE_REGLIST)); + + packet2_update(packet, draw_finish(packet->next)); + + packet2_chain_close_tag(packet); + + dma_channel_wait(DMA_CHANNEL_GIF, 0); + dma_channel_send_packet2(packet, DMA_CHANNEL_GIF, true); + dma_channel_wait(DMA_CHANNEL_GIF, 0); + + packet2_free(packet); +} + +void Renderer3DUtility::drawBBox(const CoreBBox& v, const Color& color) { + const u8 stripsCount = 6; + const u8 vertCount = 4; + const s8 thickness = 2; + s16 packetSize = 150 * thickness; + auto gsColor = getGSColor(color); + + auto* packet = + packet2_create(packetSize, P2_TYPE_NORMAL, P2_MODE_CHAIN, false); + + std::array, stripsCount> inputVerts; + fillBBoxVertices(inputVerts, v); + + packet2_chain_open_end(packet, 0, 0); + + bool drawedSomething = false; + + for (s8 i = 0; i < thickness; i++) { + Vec4 scale(2048.0F + i, 2048.0F + i, static_cast(0xFFFFFF) / 32.0F, + 1.0F); + + for (s8 j = 0; j < stripsCount; j++) { + for (s8 k = 0; k < vertCount; k++) { + auto index1 = k; + auto index2 = (k + 1) % vertCount; + + std::array outputVerts; + auto draw = calcLineVertices(outputVerts.data(), inputVerts[j][index1], + inputVerts[j][index2], scale); + + if (!draw) { + continue; + } + + drawedSomething = true; + + packet2_update(packet, + draw_prim_start(packet->next, 0, &prim, &gsColor)); + + packet2_add_u64(packet, outputVerts[0].xyz); + packet2_add_u64(packet, outputVerts[1].xyz); + + packet2_update(packet, + draw_prim_end(packet->next, 2, TYRA_UTILS_LINE_REGLIST)); + + packet2_pad128(packet, 0); + } + } + } + + if (!drawedSomething) { + packet2_free(packet); + return; + } + + packet2_update(packet, draw_finish(packet->next)); + + packet2_chain_close_tag(packet); + + dma_channel_wait(DMA_CHANNEL_GIF, 0); + dma_channel_send_packet2(packet, DMA_CHANNEL_GIF, true); + dma_channel_wait(DMA_CHANNEL_GIF, 0); + + packet2_free(packet); +} + +void Renderer3DUtility::fillBBoxVertices(std::array, 6>& v, + const CoreBBox& bbox) { + // Up + /** + * 2 - lowX, hiY, lowZ + * 3 - lowX, hiY, hiZ + * 7 - hiX, hiY, hiZ + * 6 - hiX, hiY, lowZ + */ + v[1][0] = bbox.vertices[2]; + v[1][1] = bbox.vertices[3]; + v[1][2] = bbox.vertices[7]; + v[1][3] = bbox.vertices[6]; + + // Down + /** + * 0 - lowX, lowY, lowZ + * 1 - lowX, lowY, hiZ + * 5 - hiX, lowY, hiZ + * 4 - hiX, lowY, lowZ + */ + v[0][0] = bbox.vertices[0]; + v[0][1] = bbox.vertices[1]; + v[0][2] = bbox.vertices[5]; + v[0][3] = bbox.vertices[4]; + + // Near + /** + * 0 - lowX, lowY, lowZ + * 2 - lowX, hiY, lowZ + * 6 - hiX, hiY, lowZ + * 4 - hiX, lowY, lowZ + */ + v[2][0] = bbox.vertices[0]; + v[2][1] = bbox.vertices[2]; + v[2][2] = bbox.vertices[6]; + v[2][3] = bbox.vertices[4]; + + // Far + /** + * 1 - lowX, lowY, hiZ + * 3 - lowX, hiY, hiZ + * 7 - hiX, hiY, hiZ + * 5 - hiX, lowY, hiZ + */ + v[3][0] = bbox.vertices[1]; + v[3][1] = bbox.vertices[3]; + v[3][2] = bbox.vertices[7]; + v[3][3] = bbox.vertices[5]; + + // Left + /** + * 0 - lowX, lowY, lowZ + * 1 - lowX, lowY, hiZ + * 3 - lowX, hiY, hiZ + * 2 - lowX, hiY, lowZ + */ + v[4][0] = bbox.vertices[0]; + v[4][1] = bbox.vertices[1]; + v[4][2] = bbox.vertices[3]; + v[4][3] = bbox.vertices[2]; + + // Right + /** + * 4 - hiX, lowY, lowZ + * 5 - hiX, lowY, hiZ + * 7 - hiX, hiY, hiZ + * 6 - hiX, hiY, lowZ + */ + v[5][0] = bbox.vertices[4]; + v[5][1] = bbox.vertices[5]; + v[5][2] = bbox.vertices[7]; + v[5][3] = bbox.vertices[6]; +} + +color_t Renderer3DUtility::getGSColor(const Color& color) { + color_t gsColor; + gsColor.r = static_cast(color.r); + gsColor.g = static_cast(color.g); + gsColor.b = static_cast(color.b); + gsColor.a = static_cast(color.a); + return gsColor; +} + +Vec4 Renderer3DUtility::convertVertices(const Vec4& v, const Vec4& scale) { + Vec4 output; + + /** Perspective divide + add screen scale */ + asm volatile( + "lqc2 $vf4, 0x0(%1) \n\t" + "lqc2 $vf5, 0x0(%2) \n\t" + "vdiv $Q, $vf0w, $vf4w \n\t" + "vwaitq \n\t" + "vmulq.xyz $vf4, $vf4, $Q \n\t" + "vmulaw.xyz $ACC, $vf5, $vf0w \n\t" + "vmadd.xyz $vf4, $vf4, $vf5 \n\t" + "sqc2 $vf4, 0x0(%0) \n\t" + : + : "r"(output.xyzw), "r"(v.xyzw), "r"(scale.xyzw)); + + return output; +} + +bool Renderer3DUtility::calcLineVertices(xyz_t* outputArray, const Vec4& a, + const Vec4& b, const Vec4& scale) { + const auto& mvp = core->renderer3D.getViewProj(); + Vec4 tmpA = mvp * a; + Vec4 tmpB = mvp * b; + + clipInput[0].position = &tmpA; + clipInput[1].position = &tmpB; + clipInput[2].position = &tmpA; + + auto clippedSize = planesClipAlgorithm.clip( + clippedVerts.data(), clipInput.data(), {false, false, false}); + + if (clippedSize == 0) { + return false; + } + + // To screen space + auto converted1 = convertVertices(clippedVerts[0].position, scale); + auto converted2 = convertVertices(clippedVerts[1].position, scale); + + outputArray[0].x = static_cast(ftoi4(converted1.x)); + outputArray[0].y = static_cast(ftoi4(converted1.y)); + outputArray[0].z = static_cast(ftoi4(converted1.z)); + + outputArray[1].x = static_cast(ftoi4(converted2.x)); + outputArray[1].y = static_cast(ftoi4(converted2.y)); + outputArray[1].z = static_cast(ftoi4(converted2.z)); + + return true; +} + +} // namespace Tyra diff --git a/engine/src/renderer/core/2d/renderer_core_2d.cpp b/engine/src/renderer/core/2d/renderer_core_2d.cpp new file mode 100644 index 0000000..3f4f397 --- /dev/null +++ b/engine/src/renderer/core/2d/renderer_core_2d.cpp @@ -0,0 +1,134 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/core/2d/renderer_core_2d.hpp" +#include +#include + +namespace Tyra { + +RendererCore2D::RendererCore2D() { + context = 0; + packets[0] = packet2_create(16, P2_TYPE_NORMAL, P2_MODE_NORMAL, 0); + packets[1] = packet2_create(16, P2_TYPE_NORMAL, P2_MODE_NORMAL, 0); + rects[0] = new texrect_t; + rects[1] = new texrect_t; + + setPrim(); + setLod(); +} + +RendererCore2D::~RendererCore2D() { + packet2_free(packets[0]); + packet2_free(packets[1]); + delete rects[0]; + delete rects[1]; +} + +const float RendererCore2D::GS_DRAW_AREA = 4096.0F; +const float RendererCore2D::SCREEN_CENTER = 4096.0F / 2.0F; + +void RendererCore2D::setPrim() { + prim.type = PRIM_TRIANGLE; + prim.shading = PRIM_SHADE_GOURAUD; + prim.mapping = DRAW_ENABLE; + prim.fogging = DRAW_DISABLE; + prim.blending = DRAW_ENABLE; + prim.antialiasing = DRAW_DISABLE; + prim.mapping_type = PRIM_MAP_ST; + prim.colorfix = PRIM_UNFIXED; +} + +void RendererCore2D::setLod() { + lod.calculation = LOD_USE_K; + lod.max_level = 0; + lod.mag_filter = LOD_MAG_LINEAR; + lod.min_filter = LOD_MIN_LINEAR; + lod.mipmap_select = LOD_MIPMAP_REGISTER; + lod.l = 0; + lod.k = 0.0F; +} + +void RendererCore2D::init(RendererSettings* t_settings, + clutbuffer_t* t_clutBuffer) { + settings = t_settings; + clutBuffer = t_clutBuffer; +} + +void RendererCore2D::render(const Sprite& sprite, + const RendererCoreTextureBuffers& texBuffers, + Texture* texture) { + auto* rect = rects[context]; + float sizeX, sizeY; + + if (sprite.mode == MODE_REPEAT) { + sizeX = sprite.size.x; + sizeY = sprite.size.y; + } else { + sizeX = static_cast(texture->getWidth()); + sizeY = static_cast(texture->getHeight()); + } + + float texS, texT; + float texMax = texT = texS = sizeX > sizeY ? sizeX : sizeY; + + if (sizeX > sizeY) + texT = texMax / (sizeX / sizeY); + else if (sizeY > sizeX) + texS = texMax / (sizeY / sizeX); + + rect->t0.s = sprite.flipHorizontal ? texS : 0.0F; + rect->t0.t = sprite.flipVertical ? texT : 0.0F; + rect->t1.s = sprite.flipHorizontal ? 0.0F : texS; + rect->t1.t = sprite.flipVertical ? 0.0F : texT; + + rect->color.r = sprite.color.r; + rect->color.g = sprite.color.g; + rect->color.b = sprite.color.b; + rect->color.a = sprite.color.a; + rect->color.q = 0; + + rect->v0.x = sprite.position.x; + rect->v0.y = sprite.position.y; + // rect->v0.y /= 2.0F; // interlacing + rect->v0.z = (u32)-1; + + rect->v1.x = (sprite.size.x * sprite.scale) + sprite.position.x; + rect->v1.y = (sprite.size.y * sprite.scale) + sprite.position.y; + // rect->v1.y /= 2.0F; // interlacing + rect->v1.z = (u32)-1; + + auto* packet = packets[context]; + + packet2_reset(packet, false); + packet2_update(packet, draw_primitive_xyoffset(packet->base, 0, SCREEN_CENTER, + SCREEN_CENTER)); + + packet2_utils_gif_add_set(packet, 1); + packet2_utils_gs_add_lod(packet, &lod); + packet2_utils_gif_add_set(packet, 1); + packet2_utils_gs_add_texbuff_clut(packet, texBuffers.core, clutBuffer); + draw_enable_blending(); + packet2_update(packet, draw_rect_textured(packet->next, 0, rect)); + + packet2_update(packet, draw_primitive_xyoffset( + packet->next, 0, + SCREEN_CENTER - (settings->getWidth() / 2.0F), + SCREEN_CENTER - (settings->getHeight() / 2.0F))); + draw_disable_blending(); + packet2_update(packet, draw_finish(packet->next)); + + dma_channel_wait(DMA_CHANNEL_GIF, 0); + dma_channel_send_packet2(packet, DMA_CHANNEL_GIF, true); + + context = !context; +} + +} // namespace Tyra diff --git a/engine/src/renderer/core/2d/sprite/sprite.cpp b/engine/src/renderer/core/2d/sprite/sprite.cpp new file mode 100644 index 0000000..59a0e86 --- /dev/null +++ b/engine/src/renderer/core/2d/sprite/sprite.cpp @@ -0,0 +1,39 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/core/2d/sprite/sprite.hpp" + +namespace Tyra { + +Sprite::Sprite() { + id = rand() % 1000000; + flipHorizontal = false; + flipVertical = false; + size.set(32.0F, 32.0F); + position.set(100.0F, 100.0F); + scale = 1.0F; + mode = MODE_REPEAT; + setDefaultColor(); +} + +Sprite::~Sprite() {} + +// ---- +// Methods +// ---- + +void Sprite::setDefaultColor() { + color.r = 128; + color.g = 128; + color.b = 128; + color.a = 128; +} + +} // namespace Tyra \ No newline at end of file diff --git a/engine/src/renderer/core/3d/bbox/core_bbox.cpp b/engine/src/renderer/core/3d/bbox/core_bbox.cpp new file mode 100644 index 0000000..c668618 --- /dev/null +++ b/engine/src/renderer/core/3d/bbox/core_bbox.cpp @@ -0,0 +1,317 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include +#include +#include +#include "renderer/core/3d/bbox/core_bbox.hpp" + +namespace Tyra { + +std::array CoreBBox::frustumCheckVertices; + +CoreBBox::CoreBBox() { + for (u32 i = 0; i < 8; i++) { + vertices[i] = Vec4(0.0F, 0.0F, 0.0F, 1.0F); + } +} + +CoreBBox::CoreBBox(CoreBBox** t_bboxes, const u32& count) { + float lowX = t_bboxes[0]->vertices[0].x; + float lowY = t_bboxes[0]->vertices[0].y; + float lowZ = t_bboxes[0]->vertices[0].z; + + float hiX = t_bboxes[0]->vertices[7].x; + float hiY = t_bboxes[0]->vertices[7].y; + float hiZ = t_bboxes[0]->vertices[7].z; + + for (u32 i = 0; i < count; i++) { + if (lowX > t_bboxes[i]->vertices[0].x) lowX = t_bboxes[i]->vertices[0].x; + if (hiX < t_bboxes[i]->vertices[7].x) hiX = t_bboxes[i]->vertices[7].x; + + if (lowY > t_bboxes[i]->vertices[0].y) lowY = t_bboxes[i]->vertices[0].y; + if (hiY < t_bboxes[i]->vertices[7].y) hiY = t_bboxes[i]->vertices[7].y; + + if (lowZ > t_bboxes[i]->vertices[0].z) lowZ = t_bboxes[i]->vertices[0].z; + if (hiZ < t_bboxes[i]->vertices[7].z) hiZ = t_bboxes[i]->vertices[7].z; + } + + vertices[0].set(lowX, lowY, lowZ); + vertices[1].set(lowX, lowY, hiZ); + vertices[2].set(lowX, hiY, lowZ); + vertices[3].set(lowX, hiY, hiZ); + + vertices[4].set(hiX, lowY, lowZ); + vertices[5].set(hiX, lowY, hiZ); + vertices[6].set(hiX, hiY, lowZ); + vertices[7].set(hiX, hiY, hiZ); +} + +CoreBBox::CoreBBox(const std::vector& t_bboxes, const u32& startIndex, + const u32& stopIndex) { + float lowX = t_bboxes[startIndex].vertices[0].x; + float lowY = t_bboxes[startIndex].vertices[0].y; + float lowZ = t_bboxes[startIndex].vertices[0].z; + + float hiX = t_bboxes[startIndex].vertices[7].x; + float hiY = t_bboxes[startIndex].vertices[7].y; + float hiZ = t_bboxes[startIndex].vertices[7].z; + + for (u32 i = startIndex; i < stopIndex; i++) { + if (lowX > t_bboxes[i].vertices[0].x) lowX = t_bboxes[i].vertices[0].x; + if (hiX < t_bboxes[i].vertices[7].x) hiX = t_bboxes[i].vertices[7].x; + + if (lowY > t_bboxes[i].vertices[0].y) lowY = t_bboxes[i].vertices[0].y; + if (hiY < t_bboxes[i].vertices[7].y) hiY = t_bboxes[i].vertices[7].y; + + if (lowZ > t_bboxes[i].vertices[0].z) lowZ = t_bboxes[i].vertices[0].z; + if (hiZ < t_bboxes[i].vertices[7].z) hiZ = t_bboxes[i].vertices[7].z; + } + + vertices[0].set(lowX, lowY, lowZ); + vertices[1].set(lowX, lowY, hiZ); + vertices[2].set(lowX, hiY, lowZ); + vertices[3].set(lowX, hiY, hiZ); + + vertices[4].set(hiX, lowY, lowZ); + vertices[5].set(hiX, lowY, hiZ); + vertices[6].set(hiX, hiY, lowZ); + vertices[7].set(hiX, hiY, hiZ); +} + +CoreBBox::CoreBBox(const Vec4* t_vertices, const u32* faces, const u32& count) { + float lowX, lowY, lowZ, hiX, hiY, hiZ; + lowX = hiX = t_vertices[faces[0]].x; + lowY = hiY = t_vertices[faces[0]].y; + lowZ = hiZ = t_vertices[faces[0]].z; + for (u32 i = 0; i < count; i++) { + if (lowX > t_vertices[faces[i]].x) lowX = t_vertices[faces[i]].x; + if (hiX < t_vertices[faces[i]].x) hiX = t_vertices[faces[i]].x; + + if (lowY > t_vertices[faces[i]].y) lowY = t_vertices[faces[i]].y; + if (hiY < t_vertices[faces[i]].y) hiY = t_vertices[faces[i]].y; + + if (lowZ > t_vertices[faces[i]].z) lowZ = t_vertices[faces[i]].z; + if (hiZ < t_vertices[faces[i]].z) hiZ = t_vertices[faces[i]].z; + } + + vertices[0].set(lowX, lowY, lowZ); + vertices[1].set(lowX, lowY, hiZ); + vertices[2].set(lowX, hiY, lowZ); + vertices[3].set(lowX, hiY, hiZ); + + vertices[4].set(hiX, lowY, lowZ); + vertices[5].set(hiX, lowY, hiZ); + vertices[6].set(hiX, hiY, lowZ); + vertices[7].set(hiX, hiY, hiZ); +} + +CoreBBox::CoreBBox(const Vec4* t_vertices, const u32& count) { + float lowX, lowY, lowZ, hiX, hiY, hiZ; + lowX = hiX = t_vertices[0].x; + lowY = hiY = t_vertices[0].y; + lowZ = hiZ = t_vertices[0].z; + for (u32 i = 0; i < count; i++) { + if (lowX > t_vertices[i].x) lowX = t_vertices[i].x; + if (hiX < t_vertices[i].x) hiX = t_vertices[i].x; + + if (lowY > t_vertices[i].y) lowY = t_vertices[i].y; + if (hiY < t_vertices[i].y) hiY = t_vertices[i].y; + + if (lowZ > t_vertices[i].z) lowZ = t_vertices[i].z; + if (hiZ < t_vertices[i].z) hiZ = t_vertices[i].z; + } + + vertices[0].set(lowX, lowY, lowZ); + vertices[1].set(lowX, lowY, hiZ); + vertices[2].set(lowX, hiY, lowZ); + vertices[3].set(lowX, hiY, hiZ); + + vertices[4].set(hiX, lowY, lowZ); + vertices[5].set(hiX, lowY, hiZ); + vertices[6].set(hiX, hiY, lowZ); + vertices[7].set(hiX, hiY, hiZ); +} + +CoreBBox::CoreBBox(const CoreBBox& t_bbox, const M4x4& t_matrix) { + for (u32 i = 0; i < 8; i++) { + vertices[i] = t_matrix * t_bbox.vertices[i]; + } +} + +CoreBBox::CoreBBox(const CoreBBox& t_bbox) { + for (auto i = 0; i < 8; i++) + Vec4::copy(&vertices[i], t_bbox.vertices[i].xyzw); +} + +CoreBBox CoreBBox::getTransformed(const M4x4& t_matrix) const { + return CoreBBox(*this, t_matrix); +} + +void CoreBBox::operator=(const CoreBBox& v) { + for (auto i = 0; i < 8; i++) Vec4::copy(&vertices[i], v.vertices[i].xyzw); +} + +CoreBBox::CoreBBox(const Vec4* t_vertices) { + for (auto i = 0; i < 8; i++) Vec4::copy(&vertices[i], t_vertices[i].xyzw); +} + +void CoreBBox::print() const { + auto text = getPrint(nullptr); + printf("%s\n", text.c_str()); +} + +void CoreBBox::print(const char* name) const { + auto text = getPrint(name); + printf("%s\n", text.c_str()); +} + +std::string CoreBBox::getPrint(const char* name) const { + std::stringstream res; + if (name) { + res << name << "("; + } else { + res << "CoreBBox("; + } + res << std::fixed << std::setprecision(4); + res << std::endl; + for (auto i = 0; i < 8; i++) { + res << i << ": " << vertices[i].x << ", " << vertices[i].y << ", " + << vertices[i].z << ", " << vertices[i].w; + + if (i != 7) + res << std::endl; + else + res << ")"; + } + return res.str(); +} + +CoreBBox CoreBBox::create(const Vec4& center, const float& size) { + CoreBBox bbox; + + float lowX = center.x - size; + float lowY = center.y - size; + float lowZ = center.z - size; + + float hiX = center.x + size; + float hiY = center.y + size; + float hiZ = center.z + size; + + bbox.vertices[0].set(lowX, lowY, lowZ); + bbox.vertices[1].set(lowX, lowY, hiZ); + bbox.vertices[2].set(lowX, hiY, lowZ); + bbox.vertices[3].set(lowX, hiY, hiZ); + + bbox.vertices[4].set(hiX, lowY, lowZ); + bbox.vertices[5].set(hiX, lowY, hiZ); + bbox.vertices[6].set(hiX, hiY, lowZ); + bbox.vertices[7].set(hiX, hiY, hiZ); + + return bbox; +} + +CoreBBoxFrustum CoreBBox::frustumCheck(const Plane* frustumPlanes, + const M4x4& model, + const float* margins) const { + CoreBBoxFrustum result = IN_FRUSTUM; + u8 boxIn = 0, boxOut = 0; + s8 calculatedBboxVertexIndex = -1; + + for (u8 i = 0; i < 6; i++) { + const auto margin = margins == nullptr ? 0.0F : margins[i]; + boxOut = 0; + boxIn = 0; + + // for each corner of the box do ... + // get out of the cycle as soon as a box as corners + // both inside and out of the frustum + for (s8 y = 0; y < 8 && (boxIn == 0 || boxOut == 0); y++) { + if (y > calculatedBboxVertexIndex) { + frustumCheckVertices[y] = model * vertices[y]; + calculatedBboxVertexIndex = y; + } + + auto isOut = + frustumPlanes[i].distanceTo(frustumCheckVertices[y]) <= margin; + + if (isOut) + boxOut++; + else + boxIn++; + } + + // if all corners are out + if (!boxIn) + return OUTSIDE_FRUSTUM; + else if (boxOut) + result = PARTIALLY_IN_FRUSTUM; + } + return result; +} + +CoreBBoxFrustum CoreBBox::frustumCheck(const Plane* frustumPlanes, + const float* margins) const { + CoreBBoxFrustum result = IN_FRUSTUM; + u8 boxIn = 0, boxOut = 0; + + for (u8 i = 0; i < 6; i++) { + const auto margin = margins == nullptr ? 0.0F : margins[i]; + boxOut = 0; + boxIn = 0; + + for (s8 y = 0; y < 8 && (boxIn == 0 || boxOut == 0); y++) { + auto isOut = frustumPlanes[i].distanceTo(vertices[y]) <= margin; + + if (isOut) + boxOut++; + else + boxIn++; + } + + // if all corners are out + if (!boxIn) + return OUTSIDE_FRUSTUM; + else if (boxOut) + result = PARTIALLY_IN_FRUSTUM; + } + return result; +} + +bool CoreBBox::isInFrustum(const Plane* frustumPlanes, + const M4x4& model) const { + s8 calculatedBboxVertexIndex = -1; + + for (u8 i = 0; i < 6; i++) { + for (s8 y = 0; y < 8; y++) { + if (y > calculatedBboxVertexIndex) { + frustumCheckVertices[y] = model * vertices[y]; + calculatedBboxVertexIndex = y; + } + + auto isIn = frustumPlanes[i].distanceTo(frustumCheckVertices[y]) > 0.0F; + if (isIn) return true; + } + } + return false; +} + +bool CoreBBox::isInFrustum(const Plane* frustumPlanes) const { + for (u8 i = 0; i < 6; i++) { + for (s8 y = 0; y < 8; y++) { + auto isIn = frustumPlanes[i].distanceTo(vertices[y]) > 0.0F; + if (isIn) return true; + } + } + + return false; +} + +} // namespace Tyra diff --git a/engine/src/renderer/core/3d/bbox/render_bbox.cpp b/engine/src/renderer/core/3d/bbox/render_bbox.cpp new file mode 100644 index 0000000..c97c458 --- /dev/null +++ b/engine/src/renderer/core/3d/bbox/render_bbox.cpp @@ -0,0 +1,70 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include +#include +#include "renderer/core/3d/bbox/render_bbox.hpp" + +namespace Tyra { + +RenderBBox::RenderBBox(CoreBBox** t_bboxes, const u32& count) + : CoreBBox(t_bboxes, count) {} + +RenderBBox::RenderBBox(const std::vector& t_bboxes, + const u32& startIndex, const u32& stopIndex) + : CoreBBox(t_bboxes, startIndex, stopIndex) {} + +RenderBBox::RenderBBox(const Vec4* t_vertices, const u32* faces, + const u32& count) + : CoreBBox(t_vertices, faces, count) {} + +RenderBBox::RenderBBox(const Vec4* t_vertices, const u32& count) + : CoreBBox(t_vertices, count) {} + +RenderBBox::RenderBBox(const Vec4* t_vertices) : CoreBBox(t_vertices) {} + +RenderBBox::RenderBBox(const RenderBBox& t_bbox, const M4x4& t_matrix) + : CoreBBox(t_bbox, t_matrix) {} + +RenderBBox RenderBBox::getTransformed(const M4x4& t_matrix) const { + return RenderBBox(*this, t_matrix); +} + +/** + * @brief Frustum checker for renderer. + * Background: We want to really put as low as possible polys to clipper. + * So we are doing magic trick. If BBox is partially inside frustum (clipper), + * we are adding some margins, and checking again if it really needs clipping, + * because "Cull" renderer can handle easy clip cases and its faster. + */ +CoreBBoxFrustum RenderBBox::clipFrustumCheck(const Plane* frustumPlanes, + const M4x4& model) const { + auto result = frustumCheck(frustumPlanes, model); + + if (result != PARTIALLY_IN_FRUSTUM) { + return result; + } + + // Oh no, it probably needs clipping + + // This is crappy guard band, but it works xd + float guardBand[6]; // This probably needs more calibration + + guardBand[0] = -15.0F; // Top + guardBand[1] = -10.0F; // BOTTOM + guardBand[2] = -25.0F; // LEFT + guardBand[3] = -25.0F; // RIGHT + guardBand[4] = -10.0F; // NEAR + guardBand[5] = -10.0F; // FAR + + return frustumCheck(frustumPlanes, model, guardBand); // Let's check it again +} + +} // namespace Tyra diff --git a/engine/src/renderer/core/3d/camera_info_3d.cpp b/engine/src/renderer/core/3d/camera_info_3d.cpp new file mode 100644 index 0000000..71cfb91 --- /dev/null +++ b/engine/src/renderer/core/3d/camera_info_3d.cpp @@ -0,0 +1,32 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/core/3d/camera_info_3d.hpp" + +namespace Tyra { + +Vec4 CameraInfo3D::defaultCameraUp = Vec4(0.0F, 1.0F, 0.0F); + +CameraInfo3D::CameraInfo3D(const Vec4* t_cameraPosition, + const Vec4* t_cameraLooksAt, + const Vec4* t_cameraUp) { + position = t_cameraPosition; + looksAt = t_cameraLooksAt; + + if (t_cameraUp == nullptr) { + up = &defaultCameraUp; + } else { + up = t_cameraUp; + } +} + +CameraInfo3D::~CameraInfo3D() {} + +} // namespace Tyra diff --git a/engine/src/renderer/core/3d/clipper/planes_clip_algorithm.cpp b/engine/src/renderer/core/3d/clipper/planes_clip_algorithm.cpp new file mode 100644 index 0000000..6adbd6d --- /dev/null +++ b/engine/src/renderer/core/3d/clipper/planes_clip_algorithm.cpp @@ -0,0 +1,137 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/core/3d/clipper/planes_clip_algorithm.hpp" + +namespace Tyra { + +PlanesClipAlgorithm::PlanesClipAlgorithm() { + tempVertices = new PlanesClipVertex[9]; +} + +PlanesClipAlgorithm::~PlanesClipAlgorithm() { delete[] tempVertices; } + +float PlanesClipAlgorithm::clipMargin = -10.0F; + +void PlanesClipAlgorithm::init(const RendererSettings& settings) { + halfWidth = 0.5F; + halfHeight = 0.5F; + near = settings.getNear() - (-clipMargin); + far = -settings.getFar(); +} + +u8 PlanesClipAlgorithm::clip(PlanesClipVertex* o_vertices, + PlanesClipVertexPtrs* i_vertices, + const EEClipAlgorithmSettings& settings) { + for (int i = 0; i < 3; i++) { + o_vertices[i].position = *i_vertices[i].position; + if (settings.lerpColors) o_vertices[i].color = *i_vertices[i].color; + if (settings.lerpNormals) o_vertices[i].normal = *i_vertices[i].normal; + if (settings.lerpTexCoords) o_vertices[i].st = *i_vertices[i].st; + } + + u8 tempVerticesSize = 0; + u8 outputSize = 0; + + tempVerticesSize = + clipAgainstPlane(o_vertices, 3, tempVertices, 1, halfWidth, settings); + + outputSize = clipAgainstPlane(tempVertices, tempVerticesSize, o_vertices, 1, + -halfWidth, settings); + + tempVerticesSize = clipAgainstPlane(o_vertices, outputSize, tempVertices, 2, + halfHeight, settings); + + outputSize = clipAgainstPlane(tempVertices, tempVerticesSize, o_vertices, 2, + -halfHeight, settings); + + tempVerticesSize = + clipAgainstPlane(o_vertices, outputSize, tempVertices, 3, near, settings); + + outputSize = clipAgainstPlane(tempVertices, tempVerticesSize, o_vertices, 4, + far, settings); + + return outputSize; +} + +float PlanesClipAlgorithm::getValueByPlane(const PlanesClipVertex& v, + const int& plane) { + switch (plane) { + case 1: + return v.position.x; // x plane + case 2: + return v.position.y; // y plane + case 3: // z near + case 4: + return v.position.z; // z far + default: + return 0; + } +} + +bool PlanesClipAlgorithm::isInside(const int& plane, const float& v, + const float& w, + const float& planeLimitValue) { + switch (plane) { + case 3: + return v <= planeLimitValue; // near z plane + case 4: + return v >= planeLimitValue; // far z plane + default: + return (planeLimitValue < 0) ? (v >= planeLimitValue * w) + : (v <= planeLimitValue * w); + } +} + +u8 PlanesClipAlgorithm::clipAgainstPlane( + PlanesClipVertex* original, const u8& originalSize, + PlanesClipVertex* clipped, const int& plane, const float& planeLimitValue, + const EEClipAlgorithmSettings& settings) { + int clippedSize = 0; + + for (u32 i = 0; i < originalSize; i++) { + auto a = original[i]; + auto b = original[(i + 1) % originalSize]; + auto apx = getValueByPlane(a, plane); + auto bpx = getValueByPlane(b, plane); + auto aIsInside = isInside(plane, apx, a.position.w, planeLimitValue); + auto bIsInside = isInside(plane, bpx, b.position.w, planeLimitValue); + + if (aIsInside) { + clipped[clippedSize++] = a; + } + + if (aIsInside != bIsInside) { + auto p = + (plane >= 3) + ? (planeLimitValue - a.position.z) / (b.position.z - a.position.z) + : (-a.position.w * planeLimitValue + apx) / + ((b.position.w - a.position.w) * planeLimitValue - + (bpx - apx)); + + auto index = clippedSize++; + + clipped[index].position = Vec4::getByLerp(a.position, b.position, p); + + if (settings.lerpNormals) + clipped[index].normal = Vec4::getByLerp(a.normal, b.normal, p); + + if (settings.lerpTexCoords) + clipped[index].st = Vec4::getByLerp(a.st, b.st, p); + + if (settings.lerpColors) + clipped[index].color = Vec4::getByLerp(a.color, b.color, p); + } + } + + return clippedSize; +} + +} // namespace Tyra diff --git a/engine/src/renderer/core/3d/renderer_3d_frustum_planes.cpp b/engine/src/renderer/core/3d/renderer_3d_frustum_planes.cpp new file mode 100644 index 0000000..a98dde0 --- /dev/null +++ b/engine/src/renderer/core/3d/renderer_3d_frustum_planes.cpp @@ -0,0 +1,108 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "debug/debug.hpp" +#include +#include +#include "renderer/core/3d/renderer_3d_frustum_planes.hpp" + +namespace Tyra { + +Renderer3DFrustumPlanes::Renderer3DFrustumPlanes() { lastFov = 0.0F; } +Renderer3DFrustumPlanes::~Renderer3DFrustumPlanes() {} + +void Renderer3DFrustumPlanes::init(RendererSettings* t_settings, + const float& fov) { + settings = t_settings; + computeStaticData(fov); + + TYRA_LOG("Frustum planes initialized!"); +} + +void Renderer3DFrustumPlanes::update(const CameraInfo3D& cameraInfo, + const float& fov) { + computeStaticData(fov); + + // compute the Z axis of camera + Z = *cameraInfo.position - *cameraInfo.looksAt; + Z.normalize(); + + // X axis of camera of given "up" vector and Z axis + X = cameraInfo.up->cross(Z); + X.normalize(); + + // the real "up" vector is the cross product of Z and X + Y = Z.cross(X); + + // compute the center of the near and far planes + nearCenter = *cameraInfo.position - Z * settings->getNear(); + farCenter = *cameraInfo.position - Z * settings->getFar(); + + // compute the 8 corners of the frustum + ntl = nearCenter + Y * nearHeight - X * nearWidth; + ntr = nearCenter + Y * nearHeight + X * nearWidth; + nbl = nearCenter - Y * nearHeight - X * nearWidth; + nbr = nearCenter - Y * nearHeight + X * nearWidth; + + ftl = farCenter + Y * farHeight - X * farWidth; + fbr = farCenter - Y * farHeight + X * farWidth; + ftr = farCenter + Y * farHeight + X * farWidth; + fbl = farCenter - Y * farHeight - X * farWidth; + + frustumPlanes[0].update(ntr, ntl, ftl); // Top + frustumPlanes[1].update(nbl, nbr, fbr); // BOTTOM + frustumPlanes[2].update(ntl, nbl, fbl); // LEFT + frustumPlanes[3].update(nbr, ntr, fbr); // RIGHT + frustumPlanes[4].update(ntl, ntr, nbr); // NEAR + frustumPlanes[5].update(ftr, ftl, fbl); // FAR +} + +void Renderer3DFrustumPlanes::computeStaticData(const float& fov) { + if (fabs(fov - lastFov) < 0.00001F) return; + + lastFov = fov; + float tang = tanf(fov * Math::HALF_ANG2RAD); + nearHeight = tang * settings->getNear(); + nearWidth = nearHeight * settings->getAspectRatio(); + farHeight = tang * settings->getFar(); + farWidth = farHeight * settings->getAspectRatio(); +} + +void Renderer3DFrustumPlanes::print() const { + auto text = getPrint(nullptr); + printf("%s\n", text.c_str()); +} + +void Renderer3DFrustumPlanes::print(const char* name) const { + auto text = getPrint(name); + printf("%s\n", text.c_str()); +} + +std::string Renderer3DFrustumPlanes::getPrint(const char* name) const { + std::stringstream res; + if (name) { + res << name << "("; + } else { + res << "Renderer3DFrustumPlanes("; + } + res << std::fixed << std::setprecision(2); + res << std::endl; + + res << frustumPlanes[0].getPrint("Top") << std::endl; + res << frustumPlanes[1].getPrint("Bottom") << std::endl; + res << frustumPlanes[2].getPrint("Left") << std::endl; + res << frustumPlanes[3].getPrint("Right") << std::endl; + res << frustumPlanes[4].getPrint("Near") << std::endl; + res << frustumPlanes[5].getPrint("Far") << ")"; + + return res.str(); +} + +} // namespace Tyra diff --git a/engine/src/renderer/core/3d/renderer_core_3d.cpp b/engine/src/renderer/core/3d/renderer_core_3d.cpp new file mode 100644 index 0000000..19a1b73 --- /dev/null +++ b/engine/src/renderer/core/3d/renderer_core_3d.cpp @@ -0,0 +1,73 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/core/3d/renderer_core_3d.hpp" + +namespace Tyra { + +RendererCore3D::RendererCore3D() { + fov = 60.0F; + is3DSupportEnabled = false; +} +RendererCore3D::~RendererCore3D() {} + +void RendererCore3D::update() { is3DSupportEnabled = false; } + +void RendererCore3D::update(const CameraInfo3D& cameraInfo) { + frustumPlanes.update(cameraInfo, fov); + M4x4::lookAt(&view, *cameraInfo.position, *cameraInfo.looksAt); + viewProj = projection * view; + is3DSupportEnabled = true; +} + +void RendererCore3D::init(RendererSettings* t_settings, Path1* t_path1) { + settings = t_settings; + path1 = t_path1; + frustumPlanes.init(settings, fov); + setProjection(); + TYRA_LOG("RendererCore3D initialized!"); +} + +const M4x4& RendererCore3D::getView() { + TYRA_ASSERT(is3DSupportEnabled, + "You can't compute 3D without camera information. Please correct " + "your beginFrame()"); + return view; +} + +const M4x4& RendererCore3D::getViewProj() { + TYRA_ASSERT(is3DSupportEnabled, + "You can't compute 3D without camera information. Please correct " + "your beginFrame()"); + return viewProj; +} + +void RendererCore3D::setFov(const float& t_fov) { + fov = t_fov; + setProjection(); +} + +void RendererCore3D::setProjection() { + projection = M4x4::perspective( + fov, settings->getWidth(), settings->getHeight(), + settings->getProjectionScale(), settings->getAspectRatio(), + settings->getNear(), settings->getFar()); +} + +u32 RendererCore3D::uploadVU1Program(VU1Program* program, const u32& address) { + return path1->uploadProgram(program, address); +} + +void RendererCore3D::setVU1DoubleBuffers(const u16& startingAddress, + const u16& bufferSize) { + path1->setDoubleBuffer(startingAddress, bufferSize); +} + +} // namespace Tyra diff --git a/engine/src/renderer/core/gs/renderer_core_gs.cpp b/engine/src/renderer/core/gs/renderer_core_gs.cpp new file mode 100644 index 0000000..583df96 --- /dev/null +++ b/engine/src/renderer/core/gs/renderer_core_gs.cpp @@ -0,0 +1,166 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include +#include +#include +#include +#include +#include +#include +#include "debug/debug.hpp" +#include "renderer/core/gs/renderer_core_gs.hpp" + +namespace Tyra { + +RendererCoreGS::RendererCoreGS() { + context = 0; + currentField = 0; +} + +RendererCoreGS::~RendererCoreGS() { + if (flipPacket) { + packet2_free(flipPacket); + } + if (zTestPacket) { + packet2_free(zTestPacket); + } +} + +void RendererCoreGS::init(RendererSettings* t_settings) { + settings = t_settings; + + initChannels(); + flipPacket = packet2_create(4, P2_TYPE_UNCACHED_ACCL, P2_MODE_NORMAL, 0); + zTestPacket = packet2_create(8, P2_TYPE_NORMAL, P2_MODE_NORMAL, 0); + allocateBuffers(); + initDrawingEnvironment(); + + TYRA_LOG("Renderer core initialized!"); +} + +void RendererCoreGS::initChannels() { + dma_channel_initialize(DMA_CHANNEL_GIF, nullptr, 0); +} + +void RendererCoreGS::allocateBuffers() { + frameBuffers[0].width = static_cast(settings->getWidth()); + frameBuffers[0].height = static_cast(settings->getHeight()); + frameBuffers[0].mask = 0; + frameBuffers[0].psm = GS_PSM_32; + frameBuffers[0].address = vram.allocateBuffer( + frameBuffers[0].width, frameBuffers[0].height, frameBuffers[0].psm); + + frameBuffers[1].width = frameBuffers[0].width; + frameBuffers[1].height = frameBuffers[0].height; + frameBuffers[1].mask = frameBuffers[0].mask; + frameBuffers[1].psm = frameBuffers[0].psm; + frameBuffers[1].address = vram.allocateBuffer( + frameBuffers[1].width, frameBuffers[1].height, frameBuffers[1].psm); + + zBuffer.enable = DRAW_ENABLE; + zBuffer.mask = 0; + zBuffer.method = ZTEST_METHOD_GREATER_EQUAL; + zBuffer.zsm = GS_ZBUF_32; + zBuffer.address = vram.allocateBuffer(frameBuffers[0].width, + frameBuffers[0].height, zBuffer.zsm); + + graph_initialize(frameBuffers[1].address, frameBuffers[1].width, + frameBuffers[1].height, frameBuffers[1].psm, 0, 0); + + // Interlacing tests + // graph_set_mode(GRAPH_MODE_INTERLACED, GRAPH_MODE_NTSC, GRAPH_MODE_FRAME, + // GRAPH_ENABLE); + // graph_set_screen(0, 0, static_cast(settings->getWidth()), + // static_cast(settings->getHeight())); + // graph_set_bgcolor(0, 0, 0); + // graph_set_framebuffer_filtered(frameBuffers[1].address, + // frameBuffers[1].width, + // frameBuffers[1].psm, 0, 0); + // graph_enable_output(); + + TYRA_LOG("Framebuffers, zBuffer set and allocated!"); +} + +void RendererCoreGS::enableZTests() { + packet2_reset(zTestPacket, false); + packet2_update(zTestPacket, + draw_enable_tests(zTestPacket->base, 0, &zBuffer)); + packet2_update(zTestPacket, draw_finish(zTestPacket->next)); + dma_channel_wait(DMA_CHANNEL_GIF, 0); + dma_channel_send_packet2(zTestPacket, DMA_CHANNEL_GIF, true); +} + +void RendererCoreGS::initDrawingEnvironment() { + packet2_t* packet2 = packet2_create(20, P2_TYPE_NORMAL, P2_MODE_NORMAL, 0); + packet2_update(packet2, draw_setup_environment(packet2->base, 0, frameBuffers, + &zBuffer)); + packet2_update(packet2, draw_primitive_xyoffset( + packet2->next, 0, + screenCenter - (settings->getWidth() / 2.0F), + screenCenter - (settings->getHeight() / 2.0F))); + packet2_update(packet2, draw_finish(packet2->next)); + dma_channel_send_packet2(packet2, DMA_CHANNEL_GIF, true); + dma_channel_wait(DMA_CHANNEL_GIF, 0); + packet2_free(packet2); + TYRA_LOG("Drawing environment initialized!"); +} + +qword_t* RendererCoreGS::setXYOffset(qword_t* q, const int& drawContext, + const float& x, const float& y) { + PACK_GIFTAG(q, GIF_SET_TAG(1, 0, 0, 0, GIF_FLG_PACKED, 1), GIF_REG_AD); + q++; + + int yOffset = currentField == GRAPH_FIELD_ODD ? 8 : 0; + + PACK_GIFTAG(q, + GS_SET_XYOFFSET(static_cast(x * 16.0F), + static_cast((y * 16.0F + yOffset))), + GS_REG_XYOFFSET + drawContext); + q++; + + return q; +} + +void RendererCoreGS::flipBuffers() { + graph_set_framebuffer_filtered(frameBuffers[context].address, + frameBuffers[context].width, + frameBuffers[context].psm, 0, 0); + + context ^= 1; + + packet2_update(flipPacket, + draw_framebuffer(flipPacket->base, 0, &frameBuffers[context])); + // Interlacing test + // packet2_update( + // flipPacket, + // setXYOffset(flipPacket->next, 0, + // screenCenter - (settings->getWidth() / 2.0F), + // screenCenter - (settings->getInterlacedHeightF() / 2.0F))); + + packet2_update(flipPacket, draw_finish(flipPacket->next)); + dma_channel_wait(DMA_CHANNEL_GIF, 0); + dma_channel_send_packet2(flipPacket, DMA_CHANNEL_GIF, true); + draw_wait_finish(); + + // Interlacing test + // updateCurrentField(); +} + +void RendererCoreGS::updateCurrentField() { + if (*GS_REG_CSR & (1 << 13)) { + currentField = GRAPH_FIELD_ODD; + return; + } + + currentField = GRAPH_FIELD_EVEN; +} + +} // namespace Tyra diff --git a/engine/src/renderer/core/gs/renderer_core_gs_vram.cpp b/engine/src/renderer/core/gs/renderer_core_gs_vram.cpp new file mode 100644 index 0000000..2758a25 --- /dev/null +++ b/engine/src/renderer/core/gs/renderer_core_gs_vram.cpp @@ -0,0 +1,149 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include +#include +#include +#include "renderer/core/gs/renderer_core_gs_vram.hpp" + +#define GS_VRAM_TEXTURE_ALIGNMENT GRAPH_ALIGN_BLOCK +#define GS_VRAM_BUFFER_ALIGNMENT GRAPH_ALIGN_PAGE + +namespace Tyra { + +RendererCoreGSVRam::RendererCoreGSVRam() { + touched = false; + pointer = 0; + cachedFreeSpace = getFreeSpaceInMB(); +} + +RendererCoreGSVRam::~RendererCoreGSVRam() {} + +const float& RendererCoreGSVRam::getFreeSpaceInMB() { + if (touched) { + cachedFreeSpace = (GRAPH_VRAM_MAX_WORDS - pointer) / ptr2MB; + touched = false; + } + + return cachedFreeSpace; +} + +float RendererCoreGSVRam::getSizeInMB(const Texture& texture) { + float result = getSizeInMB(*texture.core); + + if (texture.clut != nullptr) { + result += getSizeInMB(*texture.clut); + } + + return result; +} + +float RendererCoreGSVRam::getSizeInMB(const TextureData& texData) { + return getSizeInMB(texData.width, texData.height, texData.psm, + GS_VRAM_TEXTURE_ALIGNMENT); +} + +float RendererCoreGSVRam::getSizeInMB(int width, const int& height, + const int& psm, const int& alignment) { + return getSize(width, height, psm, alignment) / ptr2MB; +} + +int RendererCoreGSVRam::allocate(const TextureData& texData) { + return allocate(texData.width, texData.height, texData.psm, + GS_VRAM_TEXTURE_ALIGNMENT); +} + +int RendererCoreGSVRam::allocateBuffer(const int& width, const int& height, + const int& psm) { + return allocate(width, height, psm, GS_VRAM_BUFFER_ALIGNMENT); +} + +int RendererCoreGSVRam::allocate(const int& width, const int& height, + const int& psm, const int& alignment) { + auto size = getSize(width, height, psm, alignment); + + pointer += size; + + // If the pointer overflows the vram size + if (pointer > GRAPH_VRAM_MAX_WORDS) { + pointer -= size; + return -1; + } + + touched = true; + + return pointer - size; +} + +void RendererCoreGSVRam::free(const int& address) { + pointer = address; + touched = true; +} + +int RendererCoreGSVRam::getSize(int width, const int& height, const int& psm, + const int& alignment) { + int size = 0; + + // First correct the buffer width to be a multiple of 64 or 128 + // If the width is less than or equal to 16, then it's a palette + if (width > 16) { + switch (psm) { + case GS_PSM_8: + case GS_PSM_4: + case GS_PSM_8H: + case GS_PSM_4HL: + case GS_PSM_4HH: + width = -128 & (width + 127); + break; + default: + width = -64 & (width + 63); + break; + } + } + + // Texture storage size is in pixels/word + switch (psm) { + case GS_PSM_4: + size = width * (height >> 3); + break; + case GS_PSM_8: + size = width * (height >> 2); + break; + case GS_PSM_24: + case GS_PSM_32: + case GS_PSM_8H: + case GS_PSM_4HL: + case GS_PSM_4HH: + case GS_PSMZ_24: + case GS_PSMZ_32: + size = width * height; + break; + case GS_PSM_16: + case GS_PSM_16S: + case GS_PSMZ_16: + case GS_PSMZ_16S: + size = width * (height >> 1); + break; + default: + return 0; + } + + if (alignment == GS_VRAM_TEXTURE_ALIGNMENT) { + // TODO: Without this hack, textures are overlapping ourselves + size += 1024 * 2; + } + + // The buffer size is dependent on alignment + size = -alignment & (size + (alignment - 1)); + + return size; +} + +} // namespace Tyra diff --git a/engine/src/renderer/core/paths/path1/draw_finish.vclpp b/engine/src/renderer/core/paths/path1/draw_finish.vclpp new file mode 100644 index 0000000..636d1e2 --- /dev/null +++ b/engine/src/renderer/core/paths/path1/draw_finish.vclpp @@ -0,0 +1,30 @@ + +; _____ ____ ___ +; | \/ ____| |___| +; | | | \ | | +;--------------------------------------------------------------- +; Copyright 2022, tyra - https://github.com/h4570/tyra +; Licensed under Apache License 2.0 +; Sandro Sobczyński +; +;--------------------------------------------------------------- +; Needed for synchronization with draw_wait_finish() +;--------------------------------------------------------------- + +.syntax new +.name VU1DrawFinish +.vu +.init_vf_all +.init_vi_all + +--enter +--endenter + +#vuprog VU1DrawFinish + xtop buffer + iaddiu kickAddress, buffer, 10 + xgkick kickAddress +#endvuprog + +--exit +--endexit \ No newline at end of file diff --git a/engine/src/renderer/core/paths/path1/path1.cpp b/engine/src/renderer/core/paths/path1/path1.cpp new file mode 100644 index 0000000..df5a9a4 --- /dev/null +++ b/engine/src/renderer/core/paths/path1/path1.cpp @@ -0,0 +1,140 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/core/paths/path1/path1.hpp" + +extern u32 VU1DrawFinish_CodeStart __attribute__((section(".vudata"))); +extern u32 VU1DrawFinish_CodeEnd __attribute__((section(".vudata"))); + +namespace Tyra { + +Path1::Path1() { + doubleBufferPacket = packet2_create(2, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); + drawFinishPacket = packet2_create(10, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); + uploadDrawFinishProgram(); + prepareDrawFinishPacket(); +} + +void Path1::uploadDrawFinishProgram() { + int count = (&VU1DrawFinish_CodeEnd - &VU1DrawFinish_CodeStart) / 2; + if (count & 1) count++; + + drawFinishAddr = 1000 - count; + + packet2_t* packet2 = packet2_create(10, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); + packet2_vif_add_micro_program(packet2, drawFinishAddr, + &VU1DrawFinish_CodeStart, + &VU1DrawFinish_CodeEnd); + dma_channel_wait(DMA_CHANNEL_VIF1, 0); + dma_channel_send_packet2(packet2, DMA_CHANNEL_VIF1, true); + packet2_free(packet2); +} + +void Path1::addDrawFinishTag(packet2_t* packet) { + prim_t prim; + prim.type = PRIM_TRIANGLE; + prim.shading = PRIM_SHADE_GOURAUD; + prim.mapping = 1; + prim.fogging = 0; + prim.blending = 1; + prim.antialiasing = 0; + prim.mapping_type = PRIM_MAP_ST; + prim.colorfix = PRIM_UNFIXED; + + packet2_utils_vu_open_unpack(packet, 10, true); + { + packet2_utils_gif_add_set(packet, 1); + packet2_utils_gs_add_draw_finish_giftag(packet); + packet2_utils_gs_add_prim_giftag(packet, &prim, 0, + ((u64)GIF_REG_RGBAQ) << 0, 1, 0); + } + packet2_utils_vu_close_unpack(packet); + + packet2_utils_vu_add_start_program(packet, drawFinishAddr); +} + +void Path1::sendDrawFinishTag() { + dma_channel_wait(DMA_CHANNEL_VIF1, 0); + dma_channel_send_packet2(drawFinishPacket, DMA_CHANNEL_VIF1, true); +} + +Path1::~Path1() { + packet2_free(doubleBufferPacket); + packet2_free(drawFinishPacket); +} + +void Path1::prepareDrawFinishPacket() { + addDrawFinishTag(drawFinishPacket); + packet2_utils_vu_add_end_tag(drawFinishPacket); +} + +u32 Path1::uploadProgram(VU1Program* program, const u32& address) { + // TYRA_LOG("Uploading VU1 program. Size: ", program->getProgramSize(), + // ", name: ", program->getStringName(), ", address:", address); + + auto packetSize = program->getPacketSize() + 1; // + end tag + + packet2_t* packet2 = + packet2_create(packetSize, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); + + packet2_vif_add_micro_program(packet2, address, program->getStart(), + program->getEnd()); + + packet2_utils_vu_add_end_tag(packet2); + + dma_channel_wait(DMA_CHANNEL_VIF1, 0); + dma_channel_send_packet2(packet2, DMA_CHANNEL_VIF1, true); + dma_channel_wait(DMA_CHANNEL_VIF1, 0); + + program->setDestinationAddress(address); + + packet2_free(packet2); + + return address + program->getProgramSize(); +} + +packet2_t* Path1::createProgramsCache(VU1Program** programs, const u32& count, + const u32& address) { + u32 packetSize = 1; // + end tag + for (u32 i = 0; i < count; i++) { + packetSize += programs[i]->getPacketSize(); + } + + packet2_t* packet2 = + packet2_create(packetSize, P2_TYPE_NORMAL, P2_MODE_CHAIN, 1); + + u32 currentAddr = address; + for (u32 i = 0; i < count; i++) { + programs[i]->setDestinationAddress(currentAddr); + packet2_vif_add_micro_program(packet2, currentAddr, programs[i]->getStart(), + programs[i]->getEnd()); + currentAddr += programs[i]->getProgramSize() + 1; + } + + packet2_utils_vu_add_end_tag(packet2); + + return packet2; +} + +/** Set double buffer settings */ +void Path1::setDoubleBuffer(const u16& startingAddress, const u16& bufferSize) { + packet2_reset(doubleBufferPacket, false); + packet2_utils_vu_add_double_buffer(doubleBufferPacket, startingAddress, + bufferSize); + + // TYRA_LOG("VU1 double buffer: starting addr: ", startingAddress, + // ", offset: ", startingAddress + bufferSize, ", size: ", + // bufferSize); + + packet2_utils_vu_add_end_tag(doubleBufferPacket); + dma_channel_send_packet2(doubleBufferPacket, DMA_CHANNEL_VIF1, true); +} + +} // namespace Tyra diff --git a/engine/src/renderer/core/paths/path1/vu1_program.cpp b/engine/src/renderer/core/paths/path1/vu1_program.cpp new file mode 100644 index 0000000..099bf4c --- /dev/null +++ b/engine/src/renderer/core/paths/path1/vu1_program.cpp @@ -0,0 +1,40 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/core/paths/path1/vu1_program.hpp" + +namespace Tyra { + +VU1Program::VU1Program(u32* t_start, u32* t_end) : start(t_start), end(t_end) { + packetSize = packet2_utils_get_packet_size_for_program(start, end); + programSize = calculateProgramSize(); +} + +VU1Program::~VU1Program() {} + +const u32& VU1Program::getPacketSize() const { return packetSize; } +const u32& VU1Program::getProgramSize() const { return programSize; } +const u32& VU1Program::getDestinationAddress() const { + return destinationAddress; +} +void VU1Program::setDestinationAddress(const u32& addr) { + destinationAddress = addr; +} +u32* VU1Program::getStart() const { return start; } +u32* VU1Program::getEnd() const { return end; } + +u32 VU1Program::calculateProgramSize() const { + u32 count = (getEnd() - getStart()) / 2; + if (count & 1) count++; + + return count; +} + +} // namespace Tyra diff --git a/engine/src/renderer/core/paths/path3/path3.cpp b/engine/src/renderer/core/paths/path3/path3.cpp new file mode 100644 index 0000000..42c956a --- /dev/null +++ b/engine/src/renderer/core/paths/path3/path3.cpp @@ -0,0 +1,96 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/core/paths/path3/path3.hpp" + +namespace Tyra { + +Path3::Path3() { + drawFinishPacket = packet2_create(3, P2_TYPE_NORMAL, P2_MODE_CHAIN, false); + clearScreenPacket = packet2_create(36, P2_TYPE_NORMAL, P2_MODE_CHAIN, false); + texturePacket = packet2_create(128, P2_TYPE_NORMAL, P2_MODE_CHAIN, false); + + packet2_chain_open_end(drawFinishPacket, 0, 0); + packet2_update(drawFinishPacket, draw_finish(drawFinishPacket->next)); + packet2_chain_close_tag(drawFinishPacket); +} + +Path3::~Path3() { + packet2_free(drawFinishPacket); + packet2_free(clearScreenPacket); + packet2_free(texturePacket); +} + +void Path3::init(RendererSettings* t_settings) { + settings = t_settings; + + dma_channel_initialize(DMA_CHANNEL_GIF, nullptr, 0); + + TYRA_LOG("Path3 initialized"); +} + +void Path3::sendDrawFinishTag() { + dma_channel_wait(DMA_CHANNEL_GIF, 0); + dma_channel_send_packet2(drawFinishPacket, DMA_CHANNEL_GIF, true); +} + +void Path3::clearScreen(zbuffer_t* z, const Color& color) { + packet2_reset(clearScreenPacket, false); + packet2_chain_open_end(clearScreenPacket, 0, 0); + packet2_update(clearScreenPacket, + draw_disable_tests(clearScreenPacket->next, 0, z)); + packet2_update( + clearScreenPacket, + draw_clear(clearScreenPacket->next, 0, + 2048.0F - (settings->getWidth() / 2), + 2048.0F - (settings->getHeight() / 2), settings->getWidth(), + settings->getHeight(), static_cast(color.r), + static_cast(color.g), static_cast(color.b))); + packet2_update(clearScreenPacket, + draw_enable_tests(clearScreenPacket->next, 0, z)); + packet2_update(clearScreenPacket, draw_finish(clearScreenPacket->next)); + packet2_chain_close_tag(clearScreenPacket); + dma_channel_wait(DMA_CHANNEL_GIF, 0); + dma_channel_send_packet2(clearScreenPacket, DMA_CHANNEL_GIF, true); +} + +void Path3::sendTexture(const Texture* texture, + const RendererCoreTextureBuffers& texBuffers) { + packet2_reset(texturePacket, false); + + int coreWidth = texBuffers.core->width <= 64 ? 64 : texBuffers.core->width; + packet2_update(texturePacket, + draw_texture_transfer(texturePacket->base, texture->core->data, + texture->getWidth(), + texture->getHeight(), texture->core->psm, + texBuffers.core->address, coreWidth)); + + if (texBuffers.clut != nullptr) { + auto* clut = texture->clut; + int clutWidth = texBuffers.clut->width <= 64 ? 64 : texBuffers.clut->width; + packet2_update(texturePacket, + draw_texture_transfer(texturePacket->next, clut->data, + clut->width, clut->height, clut->psm, + texBuffers.clut->address, clutWidth)); + } + + packet2_chain_open_cnt(texturePacket, 0, 0, 0); + packet2_update(texturePacket, + draw_texture_wrapping( + texturePacket->next, 0, + const_cast(texture->getWrapSettings()))); + packet2_chain_close_tag(texturePacket); + + packet2_update(texturePacket, draw_texture_flush(texturePacket->next)); + dma_channel_wait(DMA_CHANNEL_GIF, 0); + dma_channel_send_packet2(texturePacket, DMA_CHANNEL_GIF, true); +} + +} // namespace Tyra diff --git a/engine/src/renderer/core/renderer_core.cpp b/engine/src/renderer/core/renderer_core.cpp new file mode 100644 index 0000000..36968ad --- /dev/null +++ b/engine/src/renderer/core/renderer_core.cpp @@ -0,0 +1,48 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/core/renderer_core.hpp" +#include "thread/threading.hpp" + +namespace Tyra { + +RendererCore::RendererCore() { isFrameLimitOn = true; } +RendererCore::~RendererCore() {} + +void RendererCore::init() { + path3.init(&settings); + sync.init(&path3, &path1); + gs.init(&settings); + texture.init(&gs, &path3); + renderer3D.init(&settings, &path1); + renderer2D.init(&settings, &texture.clut); +} + +void RendererCore::setClearScreenColor(const Color& color) { bgColor = color; } + +void RendererCore::beginFrame() { + renderer3D.update(); + Threading::switchThread(); + path3.clearScreen(&gs.zBuffer, bgColor); +} + +void RendererCore::beginFrame(const CameraInfo3D& cameraInfo) { + renderer3D.update(cameraInfo); + Threading::switchThread(); + path3.clearScreen(&gs.zBuffer, bgColor); +} + +void RendererCore::endFrame() { + Threading::switchThread(); + if (isFrameLimitOn) graph_wait_vsync(); + gs.flipBuffers(); +} + +} // namespace Tyra diff --git a/engine/src/renderer/core/renderer_core_sync.cpp b/engine/src/renderer/core/renderer_core_sync.cpp new file mode 100644 index 0000000..2752743 --- /dev/null +++ b/engine/src/renderer/core/renderer_core_sync.cpp @@ -0,0 +1,53 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/core/renderer_core_sync.hpp" + +namespace Tyra { + +RendererCoreSync::RendererCoreSync() {} +RendererCoreSync::~RendererCoreSync() {} + +void RendererCoreSync::init(Path3* t_path3, Path1* t_path1) { + path3 = t_path3; + path1 = t_path1; +} + +void RendererCoreSync::align3D() { + clear(); + sendPath1Req(); + waitAndClear(); +} + +void RendererCoreSync::align2D() { + clear(); + sendPath3Req(); + waitAndClear(); +} + +void RendererCoreSync::sendPath1Req() { path1->sendDrawFinishTag(); } + +void RendererCoreSync::sendPath3Req() { path3->sendDrawFinishTag(); } + +void RendererCoreSync::addPath1Req(packet2_t* packet) { + path1->addDrawFinishTag(packet); +} + +u8 RendererCoreSync::check() { return *GS_REG_CSR & 2; } + +void RendererCoreSync::clear() { *GS_REG_CSR |= 2; } + +void RendererCoreSync::waitAndClear() { + while (!check()) { + } + clear(); +} + +} // namespace Tyra diff --git a/engine/src/renderer/core/texture/models/texture.cpp b/engine/src/renderer/core/texture/models/texture.cpp new file mode 100644 index 0000000..a0cb309 --- /dev/null +++ b/engine/src/renderer/core/texture/models/texture.cpp @@ -0,0 +1,218 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include +#include +#include +#include +#include +#include +#include +#include "renderer/core/texture/models/texture.hpp" + +namespace Tyra { + +Texture::Texture(TextureBuilderData* t_data) { + id = rand() % 1000000; + + name = t_data->name; + + TYRA_ASSERT(t_data->width <= 512 && t_data->height <= 512, + "Tyra supports only 512x512 textures max!"); + + TYRA_ASSERT(t_data->width == 8 || t_data->width == 16 || + t_data->width == 32 || t_data->width == 64 || + t_data->width == 128 || t_data->width == 256 || + t_data->width == 512, + "Texture width/height should be 8/16/32/64/128/256/512!"); + + TYRA_ASSERT(t_data->height == 8 || t_data->height == 16 || + t_data->height == 32 || t_data->height == 64 || + t_data->height == 128 || t_data->height == 256 || + t_data->height == 512, + "Texture width/height should be 8/16/32/64/128/256/512!"); + + core = new TextureData(t_data->data, t_data->bpp, t_data->gsComponents, + t_data->width, t_data->height); + + clut = + new TextureData(t_data->clut, t_data->clutBpp, t_data->clutGsComponents, + t_data->clutWidth, t_data->clutHeight); + + setDefaultWrapSettings(); +} + +Texture::~Texture() { + if (links.size() > 0) links.clear(); + if (core) delete core; + if (clut) delete clut; +} + +const s32 Texture::getIndexOfLink(const u32& t_id) const { + for (u32 i = 0; i < links.size(); i++) + if (links[i].id == t_id) return i; + return -1; +} + +const u8 Texture::isLinkedWith(const u32& t_id) const { + s32 index = getIndexOfLink(t_id); + if (index != -1) + return true; + else + return false; +} + +void Texture::removeLinkByIndex(const u32& t_index) { + links.erase(links.begin() + t_index); +} + +void Texture::removeLinkById(const u32& t_id) { + s32 index = getIndexOfLink(t_id); + TYRA_ASSERT(index != -1, "Cant remove link, because it was not found!"); + removeLinkByIndex(index); +} + +float Texture::getSizeInMB() const { + return (core->width / 100.0F) * (core->height / 100.0F) * + (core->bpp / 100.0F) / 8.0F; +} + +/** Based on gsKit code, thank you guys! */ +u32 Texture::getTextureSize() const { + int widthBlocks, heightBlocks; + int widthAlign, heightAlign; + + // Calculate the number of blocks width and height + // A block is 256 bytes in size + switch (core->bpp) { + case bpp32: + case bpp24: + // 1 block = 8x8 pixels + widthBlocks = (core->width + 7) / 8; + heightBlocks = (core->height + 7) / 8; + break; + + case bpp8: + // 1 block = 16x16 pixels + widthBlocks = (core->width + 15) / 16; + heightBlocks = (core->height + 15) / 16; + break; + case bpp4: + // 1 block = 32x16 pixels + widthBlocks = (core->width + 31) / 32; + heightBlocks = (core->height + 15) / 16; + break; + default: + TYRA_TRAP("Unknown texture bpp"); + return -1; + } + + // Calculate the minimum block alignment + if (core->bpp == bpp32 || core->bpp == bpp24 || core->bpp == bpp8) { + // 8x4 blocks in a page. + // block traversing order: + // 0145.... + // 2367.... + // ........ + // ........ + if (widthBlocks <= 2 && heightBlocks <= 1) { + widthAlign = 1; + heightAlign = 1; + } else if (widthBlocks <= 4 && heightBlocks <= 2) { + widthAlign = 2; + heightAlign = 2; + } else if (widthBlocks <= 8 && heightBlocks <= 4) { + widthAlign = 4; + heightAlign = 4; + } else { + widthAlign = 8; + heightAlign = 4; + } + } else { + if (widthBlocks <= 1 && heightBlocks <= 2) { + widthAlign = 1; + heightAlign = 1; + } else if (widthBlocks <= 2 && heightBlocks <= 2) { + widthAlign = 2; + heightAlign = 2; + } else if (widthBlocks <= 2 && heightBlocks <= 8) { + widthAlign = 2; + heightAlign = 8; + } else { + widthAlign = 4; + heightAlign = 8; + } + } + + widthBlocks = (-widthAlign) & (widthBlocks + widthAlign - 1); + heightBlocks = (-heightAlign) & (heightBlocks + heightAlign - 1); + + return widthBlocks * heightBlocks * 256; +} + +void Texture::setDefaultWrapSettings() { + wrap.horizontal = WRAP_REPEAT; + wrap.vertical = WRAP_REPEAT; + wrap.maxu = 0; + wrap.maxv = 0; + wrap.minu = 0; + wrap.minv = 0; +} + +void Texture::setWrapSettings(const TextureWrap t_horizontal, + const TextureWrap t_vertical) { + wrap.horizontal = t_horizontal; + wrap.vertical = t_vertical; +} + +void Texture::addLink(const u32& t_id) { + TextureLink link; + link.id = t_id; + links.push_back(link); +} + +void Texture::print() const { + auto text = getPrint(nullptr); + printf("%s\n", text.c_str()); +} + +void Texture::print(const char* name) const { + auto text = getPrint(name); + printf("%s\n", text.c_str()); +} + +std::string Texture::getPrint(const char* objectName) const { + std::stringstream res; + if (objectName) { + res << objectName << "("; + } else { + res << "Texture("; + } + + std::string wrapString; + if (wrap.horizontal == WRAP_REPEAT) + wrapString = "WRAP_REPEAT"; + else if (wrap.horizontal == WRAP_CLAMP) + wrapString = "WRAP_CLAMP"; + + res << "id: " << id << ", " << std::endl; + res << "name: " << name << ", " << std::endl; + res << "core: " << core->getPrint() << ", " << std::endl; + if (clut != nullptr) res << "clut: " << clut->getPrint() << ", " << std::endl; + if (links.size()) { + for (size_t i = 0; i < links.size(); i++) { + res << "link " << i << " for id: " << links[i].id << ", " << std::endl; + } + } + res << "wrap: " << wrapString << ")"; + return res.str(); +} + +} // namespace Tyra diff --git a/engine/src/renderer/core/texture/renderer_core_texture.cpp b/engine/src/renderer/core/texture/renderer_core_texture.cpp new file mode 100644 index 0000000..999effc --- /dev/null +++ b/engine/src/renderer/core/texture/renderer_core_texture.cpp @@ -0,0 +1,93 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/core/texture/renderer_core_texture.hpp" + +namespace Tyra { + +RendererCoreTexture::RendererCoreTexture() {} + +RendererCoreTexture::~RendererCoreTexture() {} + +void RendererCoreTexture::init(RendererCoreGS* t_gs, Path3* t_path3) { + gs = t_gs; + sender.init(t_path3, t_gs); + path3 = t_path3; + initClut(); +} + +void RendererCoreTexture::updateClutBuffer(texbuffer_t* clutBuffer) { + if (clutBuffer == nullptr || clutBuffer->width == 0) { + clut.psm = 0; + clut.load_method = CLUT_NO_LOAD; + clut.address = 0; + } else { + clut.psm = clutBuffer->psm; + clut.load_method = CLUT_LOAD; + clut.address = clutBuffer->address; + } +} + +RendererCoreTextureBuffers RendererCoreTexture::useTexture( + const Texture* t_tex) { + TYRA_ASSERT(t_tex != nullptr, "Provided nullptr texture!"); + + auto allocated = getAllocatedBuffersByTextureId(t_tex->id); + if (allocated.id != 0) return allocated; + + if (gs->vram.getSizeInMB(*t_tex) >= gs->vram.getFreeSpaceInMB()) { + for (int i = currentAllocations.size() - 1; i >= 0; i--) { + sender.deallocate(currentAllocations[i]); + } + currentAllocations.clear(); + } + + auto newTexBuffer = sender.allocate(t_tex); + path3->sendTexture(t_tex, newTexBuffer); + registerAllocation(newTexBuffer); + + return newTexBuffer; +} + +RendererCoreTextureBuffers RendererCoreTexture::getAllocatedBuffersByTextureId( + const u32& t_id) { + for (u32 i = 0; i < currentAllocations.size(); i++) + if (currentAllocations[i].id == t_id) return currentAllocations[i]; + return {0, nullptr, nullptr}; +} + +void RendererCoreTexture::registerAllocation( + const RendererCoreTextureBuffers& t_buffers) { + currentAllocations.push_back(t_buffers); +} + +void RendererCoreTexture::unregisterAllocation(const u32& textureId) { + u32 foundIndex; + + for (u32 i = 0; i < currentAllocations.size(); i++) { + if (currentAllocations[i].id == textureId) { + foundIndex = i; + break; + } + } + + currentAllocations.erase(currentAllocations.begin() + foundIndex); +} + +void RendererCoreTexture::initClut() { + clut.storage_mode = CLUT_STORAGE_MODE1; + clut.start = 0; + clut.psm = 0; + clut.load_method = CLUT_NO_LOAD; + clut.address = 0; + TYRA_LOG("Clut set!"); +} + +} // namespace Tyra diff --git a/engine/src/renderer/core/texture/renderer_core_texture_sender.cpp b/engine/src/renderer/core/texture/renderer_core_texture_sender.cpp new file mode 100644 index 0000000..56c90e5 --- /dev/null +++ b/engine/src/renderer/core/texture/renderer_core_texture_sender.cpp @@ -0,0 +1,109 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/core/texture/renderer_core_texture_sender.hpp" +#include + +namespace Tyra { + +RendererCoreTextureSender::RendererCoreTextureSender() {} +RendererCoreTextureSender::~RendererCoreTextureSender() {} + +void RendererCoreTextureSender::init(Path3* t_path3, RendererCoreGS* t_gs) { + gs = t_gs; + path3 = t_path3; + TYRA_LOG("Renderer texture initialized!"); +} + +RendererCoreTextureBuffers RendererCoreTextureSender::allocate( + const Texture* t_texture) { + texbuffer_t* core = allocateTextureCore(t_texture); + texbuffer_t* clut = nullptr; + + auto texClut = t_texture->clut; + if (texClut != nullptr && texClut->width > 0) { + clut = allocateTextureClut(t_texture); + } + return {t_texture->id, core, clut}; +} + +float RendererCoreTextureSender::getSizeInMB(texbuffer_t* texBuffer) { + auto bpp = getBppByPsm(texBuffer->psm); + auto width = pow(2, texBuffer->info.width); + auto height = pow(2, texBuffer->info.height); + return (width / 100.0F) * (height / 100.0F) * (bpp / 100.0F) / 8.0F; +} + +void RendererCoreTextureSender::deallocate( + const RendererCoreTextureBuffers& texBuffers) { + if (texBuffers.clut != nullptr && texBuffers.clut->width > 0) { + gs->vram.free(texBuffers.clut->address); + delete texBuffers.clut; + } + + gs->vram.free(texBuffers.core->address); + + delete texBuffers.core; +} + +texbuffer_t* RendererCoreTextureSender::allocateTextureCore( + const Texture* t_texture) { + auto* result = new texbuffer_t; + const auto* core = t_texture->core; + + result->width = t_texture->getWidth(); + result->psm = core->psm; + result->info.components = core->components; + + auto address = gs->vram.allocate(*core); + TYRA_ASSERT(address > 0, "Texture buffer allocation error, no memory!"); + result->address = address; + + result->info.width = draw_log2(t_texture->getWidth()); + result->info.height = draw_log2(t_texture->getHeight()); + result->info.function = TEXTURE_FUNCTION_MODULATE; + return result; +} + +texbuffer_t* RendererCoreTextureSender::allocateTextureClut( + const Texture* t_texture) { + auto* result = new texbuffer_t; + const auto* clut = t_texture->clut; + + result->width = clut->width; + result->psm = clut->psm; + result->info.components = clut->components; + + auto address = gs->vram.allocate(*clut); + TYRA_ASSERT(address > 0, "Texture clut buffer allocation error, no memory!"); + result->address = address; + + result->info.width = draw_log2(clut->width); + result->info.height = draw_log2(clut->height); + result->info.function = TEXTURE_FUNCTION_MODULATE; + return result; +} + +TextureBpp RendererCoreTextureSender::getBppByPsm(const u32& psm) { + if (psm == GS_PSM_32) { + return bpp32; + } else if (psm == GS_PSM_24) { + return bpp24; + } else if (psm == GS_PSM_8) { + return bpp8; + } else if (psm == GS_PSM_4) { + return bpp4; + } else { + TYRA_TRAP("Unknown bpp!"); + return bpp32; + } +} + +} // namespace Tyra diff --git a/engine/src/renderer/core/texture/texture_data.cpp b/engine/src/renderer/core/texture/texture_data.cpp new file mode 100644 index 0000000..e635841 --- /dev/null +++ b/engine/src/renderer/core/texture/texture_data.cpp @@ -0,0 +1,94 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/core/texture/texture_data.hpp" +#include "debug/debug.hpp" +#include +#include + +namespace Tyra { + +TextureData::TextureData(unsigned char* t_data, const TextureBpp& t_bpp, + const unsigned char& t_gsComponents, + const int& t_width, const int& t_height) { + data = t_data; + bpp = t_bpp; + components = t_gsComponents; + width = t_width; + height = t_height; + psm = getPsmByBpp(t_bpp); +} + +TextureData::~TextureData() { + if (data) { + delete[] data; + } +} + +u32 TextureData::getPsmByBpp(const TextureBpp& bpp) { + if (bpp == bpp32) { + return GS_PSM_32; + } else if (bpp == bpp24) { + return GS_PSM_24; + } else if (bpp == bpp8) { + return GS_PSM_8; + } else if (bpp == bpp4) { + return GS_PSM_4; + } else { + TYRA_TRAP("Unknown bpp!"); + return 0; + } +} + +void TextureData::print() const { + auto text = getPrint(nullptr); + printf("%s\n", text.c_str()); +} + +void TextureData::print(const unsigned char* name) const { + auto text = getPrint(name); + printf("%s\n", text.c_str()); +} + +std::string TextureData::getPrint(const unsigned char* objectName) const { + std::stringstream res; + if (objectName) { + res << objectName << "("; + } else { + res << "TextureData("; + } + + std::string psmString; + if (psm == GS_PSM_32) + psmString = "GS_PSM_32"; + else if (psm == GS_PSM_24) + psmString = "GS_PSM_24"; + else if (psm == GS_PSM_8) + psmString = "GS_PSM_8"; + else if (psm == GS_PSM_4) + psmString = "GS_PSM_4"; + + std::string componentsString; + if (components == TEXTURE_COMPONENTS_RGBA) + componentsString = "TEXTURE_COMPONENTS_RGBA"; + else if (components == TEXTURE_COMPONENTS_RGB) + componentsString = "TEXTURE_COMPONENTS_RGB"; + + res << "data exist: " << static_cast(data != nullptr) << ", "; + res << "bpp: " << static_cast(bpp) << ", "; + res << "psm: " << psmString << ", "; + res << "width: " << width << ", "; + res << "height: " << height << ", "; + res << "components: " << componentsString << ")"; + + return res.str(); +} + +} // namespace Tyra diff --git a/engine/src/renderer/core/texture/texture_repository.cpp b/engine/src/renderer/core/texture/texture_repository.cpp new file mode 100644 index 0000000..4fa47d5 --- /dev/null +++ b/engine/src/renderer/core/texture/texture_repository.cpp @@ -0,0 +1,131 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/core/texture/texture_repository.hpp" + +namespace Tyra { + +TextureRepository::TextureRepository() {} + +TextureRepository::~TextureRepository() { + TYRA_LOG("Texture repository destructed!"); + if (getTexturesCount() > 0) { + for (u32 i = 0; i < getTexturesCount(); i++) delete textures[i]; + textures.clear(); + } +} + +Texture* TextureRepository::getBySpriteId(const u32& t_id) const { + for (u32 i = 0; i < textures.size(); i++) { + if (textures[i]->isLinkedWith(t_id)) return textures[i]; + } + return nullptr; +} + +Texture* TextureRepository::getByMeshMaterialId(const u32& t_id) const { + for (u32 i = 0; i < textures.size(); i++) { + if (textures[i]->isLinkedWith(t_id)) return textures[i]; + } + return nullptr; +} + +Texture* TextureRepository::getByTextureId(const u32& t_id) const { + for (u32 i = 0; i < textures.size(); i++) + if (t_id == textures[i]->id) return textures[i]; + return nullptr; +} + +const s32 TextureRepository::getIndexOf(const u32& t_texId) const { + for (u32 i = 0; i < textures.size(); i++) + if (textures[i]->id == t_texId) return i; + return -1; +} + +Texture* TextureRepository::add(Texture* texture) { + textures.push_back(texture); + return texture; +} + +void TextureRepository::removeByIndex(const u32& t_index) { + textures.erase(textures.begin() + t_index); +} + +void TextureRepository::removeById(const u32& t_texId) { + s32 index = getIndexOf(t_texId); + TYRA_ASSERT(index != -1, "Cant remove texture, because it was not found!"); + removeByIndex(index); +} + +void TextureRepository::freeByMesh(const Mesh& mesh) { + for (auto* material : mesh.materials) { + auto* texture = getByMeshMaterialId(material->id); + + if (texture != nullptr) { + free(texture); + } + } +} + +void TextureRepository::freeByMesh(const Mesh* mesh) { freeByMesh(*mesh); } + +void TextureRepository::freeBySprite(const Sprite& sprite) { + auto* texture = getBySpriteId(sprite.id); + + if (texture != nullptr) { + free(texture); + } +} + +void TextureRepository::free(const Texture* t_tex) { free(t_tex->id); } + +void TextureRepository::free(const Texture& t_tex) { free(t_tex.id); } + +void TextureRepository::free(const u32& t_texId) { + s32 index = getIndexOf(t_texId); + auto* tex = textures[index]; + + TYRA_ASSERT(index != -1, "Cant remove texture, because it was not found!"); + removeByIndex(index); + + delete tex; +} + +Texture* TextureRepository::add(const char* fullpath) { + TextureLoader& loader = texLoaderSelector.getLoaderByFileName(fullpath); + + auto* data = loader.load(fullpath); + Texture* texture = new Texture(data); + delete data; + + textures.push_back(texture); + return texture; +} + +void TextureRepository::addByMesh(const Mesh* mesh, const char* directory, + const char* extension) { + auto& loader = texLoaderSelector.getLoaderByExtension(extension); + + std::string dirFixed = directory; + if (dirFixed.back() != '/' && dirFixed.back() != ':') dirFixed += "/"; + + for (u32 i = 0; i < mesh->materials.size(); i++) { + std::string fullPath = + dirFixed + mesh->materials[i]->name + "." + extension; + + auto* data = loader.load(fullPath.c_str()); + Texture* texture = new Texture(data); + delete data; + + texture->addLink(mesh->materials[i]->id); + textures.push_back(texture); + } +} + +} // namespace Tyra diff --git a/engine/src/renderer/models/color.cpp b/engine/src/renderer/models/color.cpp new file mode 100644 index 0000000..5723a12 --- /dev/null +++ b/engine/src/renderer/models/color.cpp @@ -0,0 +1,121 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/models/color.hpp" +#include +#include + +namespace Tyra { + +void Color::copy(Color* out, const float* in) { + Vec4::copy(reinterpret_cast(out), in); +} + +void Color::operator=(const Color& v) { copy(this, v); } + +void Color::operator+=(const float& v) { + r += v; + g += v; + b += v; + a += v; +} +void Color::operator-=(const float& v) { + r -= v; + g -= v; + b -= v; + a -= v; +} + +void Color::operator*=(const float& v) { + r *= v; + g *= v; + b *= v; + a *= v; +} + +void Color::operator/=(const float& v) { + r /= v; + g /= v; + b /= v; + a /= v; +} + +Color Color::operator+(const float& v) const { + Color result = *this; + result += v; + return result; +} + +Color Color::operator-(const float& v) const { + Color result = *this; + result -= v; + return result; +} + +Color Color::operator*(const float& v) const { + Color result = *this; + result *= v; + return result; +} + +Color Color::operator/(const float& v) const { + Color result = *this; + result /= v; + return result; +} + +void Color::set(const float& t_r, const float& t_g, const float& t_b, + const float& t_a) { + r = t_r; + g = t_g; + b = t_b; + a = t_a; +} + +void Color::lerp(const Color& v1, const Color& v2, const float& interp) { + setLerp(this, v1, v2, interp); +} + +Color Color::getByLerp(const Color& v1, const Color& v2, const float& interp) { + Color result; + setLerp(&result, v1, v2, interp); + return result; +} + +void Color::print() const { + auto text = getPrint(nullptr); + printf("%s\n", text.c_str()); +} + +void Color::print(const char* name) const { + auto text = getPrint(name); + printf("%s\n", text.c_str()); +} + +std::string Color::getPrint(const char* name) const { + std::stringstream res; + if (name) { + res << name << "("; + } else { + res << "Color("; + } + res << std::fixed << std::setprecision(4); + res << r << ", " << g << ", " << b << ", " << a << ")"; + return res.str(); +} + +void Color::setLerp(Color* output, const Color& v1, const Color& v2, + const float& interp) { + Vec4::setLerp(reinterpret_cast(output), + reinterpret_cast(v1), + reinterpret_cast(v2), interp); +} + +} // namespace Tyra diff --git a/engine/src/renderer/renderer.cpp b/engine/src/renderer/renderer.cpp new file mode 100644 index 0000000..3a94ec5 --- /dev/null +++ b/engine/src/renderer/renderer.cpp @@ -0,0 +1,35 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/renderer.hpp" + +namespace Tyra { + +Renderer::Renderer() {} +Renderer::~Renderer() {} + +void Renderer::init() { + core.init(); + renderer2D.init(&core); + renderer3D.init(&core); +} + +void Renderer::beginFrame() { core.beginFrame(); } + +void Renderer::beginFrame(const CameraInfo3D& cameraInfo) { + core.beginFrame(cameraInfo); +} + +void Renderer::endFrame() { + core.endFrame(); + renderer3D.onFrameEnd(); +} + +} // namespace Tyra diff --git a/engine/src/renderer/renderer_settings.cpp b/engine/src/renderer/renderer_settings.cpp new file mode 100644 index 0000000..d813024 --- /dev/null +++ b/engine/src/renderer/renderer_settings.cpp @@ -0,0 +1,49 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "renderer/renderer_settings.hpp" + +namespace Tyra { + +RendererSettings::~RendererSettings() {} + +void RendererSettings::copy(RendererSettings* out, const RendererSettings* in) { + out->width = in->width; + out->height = in->height; + out->near = in->near; + out->far = in->far; + out->projectionScale = in->projectionScale; + out->aspectRatio = in->aspectRatio; + out->interlacedHeightF = in->interlacedHeightF; + out->interlacedHeightUI = in->interlacedHeightUI; +} + +void RendererSettings::set(const RendererSettings& v) { copy(this, &v); } + +void RendererSettings::print() const { + auto text = getPrint(); + printf("%s\n", text.c_str()); +} + +std::string RendererSettings::getPrint() const { + std::stringstream res; + res << "RendererSettings("; + res << "width: " << width << ", "; + res << "height: " << height << ", "; + res << "near: " << near << ", "; + res << "far: " << far << ", "; + res << "projectionScale: " << projectionScale << ", "; + res << "aspectRatio: " << aspectRatio << ", "; + res << "interlaced height: " << interlacedHeightF; + res << ")"; + return res.str(); +} + +} // namespace Tyra diff --git a/engine/src/thread/threading.cpp b/engine/src/thread/threading.cpp new file mode 100644 index 0000000..ffee60b --- /dev/null +++ b/engine/src/thread/threading.cpp @@ -0,0 +1,32 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022-2022, tyra - https://github.com/h4570/tyrav2 +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "thread/threading.hpp" +#include + +namespace Tyra { + +timespec Threading::tv = {0, 0}; + +void Threading::sleep(const u32& ms) { + tv.tv_sec = ms / 1000; + tv.tv_nsec = (ms % 1000) * 1000000; + nanosleep(&tv, nullptr); +} + +void Threading::sleep(const timespec& t_tv) { nanosleep(&t_tv, nullptr); } + +void Threading::switchThread() { + tv.tv_sec = 0; + tv.tv_nsec = 500000; // 1/2ms + nanosleep(&tv, nullptr); +} + +} // Namespace Tyra \ No newline at end of file diff --git a/engine/src/time/timer.cpp b/engine/src/time/timer.cpp new file mode 100644 index 0000000..d76ee8a --- /dev/null +++ b/engine/src/time/timer.cpp @@ -0,0 +1,29 @@ +/* +# _____ ____ ___ +# | \/ ____| |___| +# | | | \ | | +#----------------------------------------------------------------------- +# Copyright 2022, tyra - https://github.com/h4570/tyra +# Licensed under Apache License 2.0 +# Sandro Sobczyński +*/ + +#include "time/timer.hpp" + +namespace Tyra { + +Timer::Timer() { prime(); } + +Timer::~Timer() {} + +u32 Timer::getTimeDelta() { + time = *T3_COUNT; + + if (time < lastTime) // The counter has wrapped + change = time + (65536 - lastTime); + else + change = time - lastTime; + return change; +} + +} // namespace Tyra diff --git a/src/engine/Makefile b/src/engine/Makefile deleted file mode 100644 index 1b3fca8..0000000 --- a/src/engine/Makefile +++ /dev/null @@ -1,51 +0,0 @@ -TYRA_DIR = ./ - -EE_OBJS = \ - models/math/matrix.o \ - models/math/plane.o \ - models/math/point.o \ - models/math/vector3.o \ - models/mesh_frame.o \ - models/bounding_box.o \ - models/mesh_material.o \ - models/mesh.o \ - models/sprite.o \ - models/texture.o \ - modules/audio.o \ - modules/camera_base.o \ - modules/file_service.o \ - modules/gif_sender.o \ - modules/light.o \ - modules/pad.o \ - modules/renderer.o \ - modules/texture_repository.o \ - modules/timer.o \ - modules/vif_sender.o \ - utils/math.o \ - utils/string.o \ - loaders/bmp_loader.o \ - loaders/dff_loader.o \ - loaders/md2_loader.o \ - loaders/obj_loader.o \ - loaders/png_loader.o \ - vu1_progs/draw3D.o \ - engine.o - -all: $(EE_OBJS) - ar rcs $(LIB_NAME) $(EE_OBJS) - rm -f $(EE_OBJS) - -# %.vcl: %.vclpp -# $(EE_VCLPP) $< $@ - -# %.vsm: %.vcl -# $(EE_VCL) $< >> $@ - -%.o: %.vsm - $(EE_DVP) $< -o $@ - -clean: - rm -f $(EE_OBJS) - rm -f $(LIB_NAME) - -include Makefile.pref \ No newline at end of file diff --git a/src/engine/Makefile.pref b/src/engine/Makefile.pref deleted file mode 100644 index 5f1309d..0000000 --- a/src/engine/Makefile.pref +++ /dev/null @@ -1,11 +0,0 @@ -EE_LIBS := $(EE_LIBS) -ldraw -lcdvd -lgraph -lmath3d -lpacket -ldma -lpacket2 -lpad -laudsrv -lc -lstdc++ -lpng -lz -EE_INCS := -I$(TYRA)/src/engine/include -I$(PS2SDK)/ports/include $(EE_INCS) -EE_LDFLAGS := -L$(PS2SDK)/ports/lib -L$(TYRA)/src/engine $(EE_LDFLAGS) -EE_CXXFLAGS := -DHAVE_LIBJPEG -DHAVE_LIBTIFF -DHAVE_LIBPNG -DHAVE_ZLIB -D_XCDVD $(EE_CXXFLAGS) -EE_DVP = dvp-as -EE_VCL = vcl -EE_VCLPP = vclpp -LIB_NAME = libtyra.a - -include $(PS2SDK)/samples/Makefile.pref -include $(PS2SDK)/samples/Makefile.eeglobal \ No newline at end of file diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp deleted file mode 100644 index 2148dfb..0000000 --- a/src/engine/engine.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "include/engine.hpp" - -#include -#include -#include -#include -#include -#include "include/utils/debug.hpp" - -// ---- -// Constructors/Destructors -// ---- - -Engine::Engine() -{ - setDefaultScreen(); - firePS2(); -} - -Engine::Engine(const ScreenSettings &t_screen) -{ - screen = t_screen; - firePS2(); -} - -Engine::~Engine() {} - -// ---- -// Methods -// ---- - -void Engine::setDefaultScreen() -{ - screen.nearPlaneDist = 2.0F; - screen.farPlaneDist = 2000.0F; - screen.fov = 60.0F; - screen.width = 640.0F; - screen.height = 480.0F; - screen.aspectRatio = screen.width / screen.height; - screen.projectionScale = 4096.0F; // PS2 have 4k drawing area -} - -void Engine::init(Game *t_game, u32 t_gifPacketSize) -{ - assertMsg(!isInitialized, "Engine was already initialized!"); - game = t_game; - renderer = new Renderer(t_gifPacketSize, &screen); - isInitialized = true; - game->onInit(); - gameLoop(); -} - -/** Do not call this method. This is used in gameLoop() to maintain multithreading */ -void Engine::wakeup(s32 t_alarmId, u16 t_time, void *t_common) -{ - (void)t_alarmId; - (void)t_time; - iWakeupThread(*(int *)t_common); - ExitHandler(); -} - -void Engine::firePS2() -{ - SifInitRpc(0); - srand(time(NULL)); - // fileService.startThread(); - // audio.startThread(&fileService); - audio.startThread(NULL); - isInitialized = 0; - mainThreadId = GetThreadId(); -} - -void Engine::gameLoop() -{ - for (;;) - { - pad.update(); - game->onUpdate(); - if (fpsDelayer++ >= 4) - { - fps = timer.getFPS(); - fpsDelayer = 0; - } - timer.prime(); - renderer->endFrame(fps); - /** -6~ FPS */ - SetAlarm(150, &Engine::wakeup, &mainThreadId); - SleepThread(); - } -} diff --git a/src/engine/include/engine.hpp b/src/engine/include/engine.hpp deleted file mode 100644 index 17be5a8..0000000 --- a/src/engine/include/engine.hpp +++ /dev/null @@ -1,52 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_ENGINE_ -#define _TYRA_ENGINE_ - -#include -#include "game.hpp" -#include "models/screen_settings.hpp" -#include "models/math/matrix.hpp" -#include "modules/renderer.hpp" -#include "modules/timer.hpp" -#include "modules/pad.hpp" -#include "modules/audio.hpp" -#include "modules/file_service.hpp" - -class Engine -{ - -public: - Engine(const ScreenSettings &screen); - Engine(); - ~Engine(); - - void init(Game *t_game, u32 t_gifPacketSize); - void setDefaultScreen(); - Renderer *renderer; - // FileService fileService; - Audio audio; - ScreenSettings screen; - Pad pad; - float fps; - -private: - void firePS2(); - u8 fpsDelayer; - Timer timer; - u8 isInitialized; - void gameLoop(); - Game *game; - s32 mainThreadId; - static void wakeup(s32 t_alarmId, u16 t_time, void *t_common); -}; - -#endif diff --git a/src/engine/include/game.hpp b/src/engine/include/game.hpp deleted file mode 100644 index 3803728..0000000 --- a/src/engine/include/game.hpp +++ /dev/null @@ -1,27 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_GAME_ -#define _TYRA_GAME_ - -#include - -class Game -{ - -public: - virtual ~Game(){}; - virtual void onInit() = 0; - virtual void onUpdate() = 0; - -private: -}; - -#endif diff --git a/src/engine/include/loaders/anorms.hpp b/src/engine/include/loaders/anorms.hpp deleted file mode 100644 index 15357c4..0000000 --- a/src/engine/include/loaders/anorms.hpp +++ /dev/null @@ -1,183 +0,0 @@ -/* -Copyright (C) 1997-2001 Id Software, Inc. -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#ifndef _TYRA_ANORMS_ -#define _TYRA_ANORMS_ - -const float ANORMS[162][3] = { - {-0.525731f, 0.000000f, 0.850651f}, - {-0.442863f, 0.238856f, 0.864188f}, - {-0.295242f, 0.000000f, 0.955423f}, - {-0.309017f, 0.500000f, 0.809017f}, - {-0.162460f, 0.262866f, 0.951056f}, - {0.000000f, 0.000000f, 1.000000f}, - {0.000000f, 0.850651f, 0.525731f}, - {-0.147621f, 0.716567f, 0.681718f}, - {0.147621f, 0.716567f, 0.681718f}, - {0.000000f, 0.525731f, 0.850651f}, - {0.309017f, 0.500000f, 0.809017f}, - {0.525731f, 0.000000f, 0.850651f}, - {0.295242f, 0.000000f, 0.955423f}, - {0.442863f, 0.238856f, 0.864188f}, - {0.162460f, 0.262866f, 0.951056f}, - {-0.681718f, 0.147621f, 0.716567f}, - {-0.809017f, 0.309017f, 0.500000f}, - {-0.587785f, 0.425325f, 0.688191f}, - {-0.850651f, 0.525731f, 0.000000f}, - {-0.864188f, 0.442863f, 0.238856f}, - {-0.716567f, 0.681718f, 0.147621f}, - {-0.688191f, 0.587785f, 0.425325f}, - {-0.500000f, 0.809017f, 0.309017f}, - {-0.238856f, 0.864188f, 0.442863f}, - {-0.425325f, 0.688191f, 0.587785f}, - {-0.716567f, 0.681718f, -0.147621f}, - {-0.500000f, 0.809017f, -0.309017f}, - {-0.525731f, 0.850651f, 0.000000f}, - {0.000000f, 0.850651f, -0.525731f}, - {-0.238856f, 0.864188f, -0.442863f}, - {0.000000f, 0.955423f, -0.295242f}, - {-0.262866f, 0.951056f, -0.162460f}, - {0.000000f, 1.000000f, 0.000000f}, - {0.000000f, 0.955423f, 0.295242f}, - {-0.262866f, 0.951056f, 0.162460f}, - {0.238856f, 0.864188f, 0.442863f}, - {0.262866f, 0.951056f, 0.162460f}, - {0.500000f, 0.809017f, 0.309017f}, - {0.238856f, 0.864188f, -0.442863f}, - {0.262866f, 0.951056f, -0.162460f}, - {0.500000f, 0.809017f, -0.309017f}, - {0.850651f, 0.525731f, 0.000000f}, - {0.716567f, 0.681718f, 0.147621f}, - {0.716567f, 0.681718f, -0.147621f}, - {0.525731f, 0.850651f, 0.000000f}, - {0.425325f, 0.688191f, 0.587785f}, - {0.864188f, 0.442863f, 0.238856f}, - {0.688191f, 0.587785f, 0.425325f}, - {0.809017f, 0.309017f, 0.500000f}, - {0.681718f, 0.147621f, 0.716567f}, - {0.587785f, 0.425325f, 0.688191f}, - {0.955423f, 0.295242f, 0.000000f}, - {1.000000f, 0.000000f, 0.000000f}, - {0.951056f, 0.162460f, 0.262866f}, - {0.850651f, -0.525731f, 0.000000f}, - {0.955423f, -0.295242f, 0.000000f}, - {0.864188f, -0.442863f, 0.238856f}, - {0.951056f, -0.162460f, 0.262866f}, - {0.809017f, -0.309017f, 0.500000f}, - {0.681718f, -0.147621f, 0.716567f}, - {0.850651f, 0.000000f, 0.525731f}, - {0.864188f, 0.442863f, -0.238856f}, - {0.809017f, 0.309017f, -0.500000f}, - {0.951056f, 0.162460f, -0.262866f}, - {0.525731f, 0.000000f, -0.850651f}, - {0.681718f, 0.147621f, -0.716567f}, - {0.681718f, -0.147621f, -0.716567f}, - {0.850651f, 0.000000f, -0.525731f}, - {0.809017f, -0.309017f, -0.500000f}, - {0.864188f, -0.442863f, -0.238856f}, - {0.951056f, -0.162460f, -0.262866f}, - {0.147621f, 0.716567f, -0.681718f}, - {0.309017f, 0.500000f, -0.809017f}, - {0.425325f, 0.688191f, -0.587785f}, - {0.442863f, 0.238856f, -0.864188f}, - {0.587785f, 0.425325f, -0.688191f}, - {0.688191f, 0.587785f, -0.425325f}, - {-0.147621f, 0.716567f, -0.681718f}, - {-0.309017f, 0.500000f, -0.809017f}, - {0.000000f, 0.525731f, -0.850651f}, - {-0.525731f, 0.000000f, -0.850651f}, - {-0.442863f, 0.238856f, -0.864188f}, - {-0.295242f, 0.000000f, -0.955423f}, - {-0.162460f, 0.262866f, -0.951056f}, - {0.000000f, 0.000000f, -1.000000f}, - {0.295242f, 0.000000f, -0.955423f}, - {0.162460f, 0.262866f, -0.951056f}, - {-0.442863f, -0.238856f, -0.864188f}, - {-0.309017f, -0.500000f, -0.809017f}, - {-0.162460f, -0.262866f, -0.951056f}, - {0.000000f, -0.850651f, -0.525731f}, - {-0.147621f, -0.716567f, -0.681718f}, - {0.147621f, -0.716567f, -0.681718f}, - {0.000000f, -0.525731f, -0.850651f}, - {0.309017f, -0.500000f, -0.809017f}, - {0.442863f, -0.238856f, -0.864188f}, - {0.162460f, -0.262866f, -0.951056f}, - {0.238856f, -0.864188f, -0.442863f}, - {0.500000f, -0.809017f, -0.309017f}, - {0.425325f, -0.688191f, -0.587785f}, - {0.716567f, -0.681718f, -0.147621f}, - {0.688191f, -0.587785f, -0.425325f}, - {0.587785f, -0.425325f, -0.688191f}, - {0.000000f, -0.955423f, -0.295242f}, - {0.000000f, -1.000000f, 0.000000f}, - {0.262866f, -0.951056f, -0.162460f}, - {0.000000f, -0.850651f, 0.525731f}, - {0.000000f, -0.955423f, 0.295242f}, - {0.238856f, -0.864188f, 0.442863f}, - {0.262866f, -0.951056f, 0.162460f}, - {0.500000f, -0.809017f, 0.309017f}, - {0.716567f, -0.681718f, 0.147621f}, - {0.525731f, -0.850651f, 0.000000f}, - {-0.238856f, -0.864188f, -0.442863f}, - {-0.500000f, -0.809017f, -0.309017f}, - {-0.262866f, -0.951056f, -0.162460f}, - {-0.850651f, -0.525731f, 0.000000f}, - {-0.716567f, -0.681718f, -0.147621f}, - {-0.716567f, -0.681718f, 0.147621f}, - {-0.525731f, -0.850651f, 0.000000f}, - {-0.500000f, -0.809017f, 0.309017f}, - {-0.238856f, -0.864188f, 0.442863f}, - {-0.262866f, -0.951056f, 0.162460f}, - {-0.864188f, -0.442863f, 0.238856f}, - {-0.809017f, -0.309017f, 0.500000f}, - {-0.688191f, -0.587785f, 0.425325f}, - {-0.681718f, -0.147621f, 0.716567f}, - {-0.442863f, -0.238856f, 0.864188f}, - {-0.587785f, -0.425325f, 0.688191f}, - {-0.309017f, -0.500000f, 0.809017f}, - {-0.147621f, -0.716567f, 0.681718f}, - {-0.425325f, -0.688191f, 0.587785f}, - {-0.162460f, -0.262866f, 0.951056f}, - {0.442863f, -0.238856f, 0.864188f}, - {0.162460f, -0.262866f, 0.951056f}, - {0.309017f, -0.500000f, 0.809017f}, - {0.147621f, -0.716567f, 0.681718f}, - {0.000000f, -0.525731f, 0.850651f}, - {0.425325f, -0.688191f, 0.587785f}, - {0.587785f, -0.425325f, 0.688191f}, - {0.688191f, -0.587785f, 0.425325f}, - {-0.955423f, 0.295242f, 0.000000f}, - {-0.951056f, 0.162460f, 0.262866f}, - {-1.000000f, 0.000000f, 0.000000f}, - {-0.850651f, 0.000000f, 0.525731f}, - {-0.955423f, -0.295242f, 0.000000f}, - {-0.951056f, -0.162460f, 0.262866f}, - {-0.864188f, 0.442863f, -0.238856f}, - {-0.951056f, 0.162460f, -0.262866f}, - {-0.809017f, 0.309017f, -0.500000f}, - {-0.864188f, -0.442863f, -0.238856f}, - {-0.951056f, -0.162460f, -0.262866f}, - {-0.809017f, -0.309017f, -0.500000f}, - {-0.681718f, 0.147621f, -0.716567f}, - {-0.681718f, -0.147621f, -0.716567f}, - {-0.850651f, 0.000000f, -0.525731f}, - {-0.688191f, 0.587785f, -0.425325f}, - {-0.587785f, 0.425325f, -0.688191f}, - {-0.425325f, 0.688191f, -0.587785f}, - {-0.425325f, -0.688191f, -0.587785f}, - {-0.587785f, -0.425325f, -0.688191f}, - {-0.688191f, -0.587785f, -0.425325f}}; - -#endif diff --git a/src/engine/include/loaders/bmp_loader.hpp b/src/engine/include/loaders/bmp_loader.hpp deleted file mode 100644 index b386b64..0000000 --- a/src/engine/include/loaders/bmp_loader.hpp +++ /dev/null @@ -1,29 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_BMP_LOADER_ -#define _TYRA_BMP_LOADER_ - -#include -#include -#include "../models/texture.hpp" - -/** Class responsible for loading images in bmp format */ -class BmpLoader -{ - -public: - BmpLoader(); - ~BmpLoader(); - - void load(Texture &o_texture, char *t_subfolder, char *t_name, char *t_extension); -}; - -#endif diff --git a/src/engine/include/loaders/dff_loader.hpp b/src/engine/include/loaders/dff_loader.hpp deleted file mode 100644 index 14d7ce0..0000000 --- a/src/engine/include/loaders/dff_loader.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_DFF_LOADER_ -#define _TYRA_DFF_LOADER_ - -#include "../models/mesh_frame.hpp" -#include "./dff_structure.hpp" - -/** Class responsible for loading&parsing .obj 3D files */ -class DffLoader -{ - -public: - DffLoader(); - ~DffLoader(); - - // void im_not_used_anywhere(MeshFrame *o_result, char *t_fileName, float t_scale, u8 t_invertT); - void load(MeshFrame *o_result, char *t_fileName, float t_scale, u8 t_invertT); - void serialize(MeshFrame *o_result, u8 t_invertT, u8 *t_data, float t_scale); - -private: - // --- - void readFrameListData(RwFrameListData &t_frd, u8 *t_buffer, u32 &t_ptrPos); - void readClumpData(RwClumpData &t_cd, u8 *t_buffer, u32 &t_ptrPos); - void readGeometryListData(RwGeometryListData &t_gld, u8 *t_buffer, u32 &t_ptrPos); - void readGeometryExtension(MeshFrame *o_frame, char **materialNames, u8 *t_buffer, u32 &t_ptrPos); - void readGeometryData(MeshFrame *o_frame, u8 t_invertT, u8 *t_buffer, u32 &t_ptrPos, float t_scale); - void readMaterialListData(RwMaterialListData &t_mld, u8 *t_buffer, u32 &t_ptrPos); - void readMaterialData(RwMaterialData &t_md, u8 *t_buffer, u32 &t_ptrPos); - void readTextureData(RwTextureData &t_td, u8 *t_buffer, u32 &t_ptrPos); - void readStringData(RwString &t_s, u8 *bt_uffer, u32 &t_ptrPos); - void readSectionHeader(RwSectionHeader &t_sh, u8 *t_buffer, u32 &t_ptrPos); - // --- - u8 readByteFromArrayLE(u8 *t_buffer, u32 &t_ptrPos); - u16 readWordFromArrayLE(u8 *t_buffer, u32 &t_ptrPos); - u32 readDwordFromArrayLE(u8 *t_buffer, u32 &t_ptrPos); - float readFloatFromArrayLE(u8 *t_buffer, u32 &t_ptrPos); - char *readString(u8 *t_buffer, u32 &t_ptrPos, u32 t_dataSize = 0); -}; - -#endif diff --git a/src/engine/include/loaders/dff_structure.hpp b/src/engine/include/loaders/dff_structure.hpp deleted file mode 100644 index 6c12b86..0000000 --- a/src/engine/include/loaders/dff_structure.hpp +++ /dev/null @@ -1,342 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_DFF_STRUCTURE_ -#define _TYRA_DFF_STRUCTURE_ - -#include -#include "../models/math/vector3.hpp" - -enum RwGeometryDataFlags -{ - rwOBJECT_VERTEX_TRISTRIP = 0x01, - rwOBJECT_VERTEX_POS = 0x02, - rwOBJECT_VERTEX_TEXTURED = 0x04, - rwOBJECT_VERTEX_PRELIT = 0x08, - rwOBJECT_VERTEX_NORMALS = 0x10, - rwOBJECT_VERTEX_LIGHT = 0x20, - rwOBJECT_VERTEX_MODULATE_MATERIAL_COLOR = 0x40, - rwOBJECT_VERTEX_TEXTURED_2 = 0x80 -}; - -class RwSectionHeader -{ -public: - u32 sectionType; - u32 sectionSize; - u32 versionNumber; -}; - -class RwFrameListChunk -{ -public: - ~RwFrameListChunk() {} - float *rotationalMatrix; // [ROT_MAT_DIM] - float coordinatesOffsetX; - float coordinatesOffsetY; - float coordinatesOffsetZ; - u32 parentFrame; // 0xFFFFFFFF = NONE - u32 unk1; -}; - -// Section: Frame List -class RwFrameListData : public RwSectionHeader -{ -public: - ~RwFrameListData() {} - static const u32 ROT_MAT_DIM = 9; - u32 frameCount; - - RwFrameListChunk *frameInformation; // [frameCount] -}; - -class RwFrame : public RwSectionHeader -{ -public: - ~RwFrame() {} - u8 *frameName; // [sectionSize] - should be interpreted as string -}; - -class RwFrameListExtension : public RwSectionHeader -{ -public: - RwFrame frame; -}; - -class RwFrameList : public RwSectionHeader -{ -public: - RwFrameListData data; - ~RwFrameList() {} - RwFrameListExtension *extensions; -}; -// --- - -class RwGeometryDataHeader -{ -public: - u16 flags; - u16 unk1; - u32 triangleCount; - u32 vertexCount; - u32 morphTargetCount; -}; - -struct RwGeometryDataLightingHeader -{ // IF versionNumber = 4099 - according to not complete documentation - float ambient; - float diffuse; - float specular; -}; - -struct RwGeometryDataColorInformationChunk -{ // if rwOBJECT_VERTEX_PREILIT in flags - - u8 red; - u8 green; - u8 blue; - u8 alpha; -}; - -struct RwGeometryDataTextureMappingInformationChunk -{ // if rwOBJECT_VERTEX_TEXTURED in flags - float u; - float v; -}; - -struct RwGeometryDataFaceInformation -{ - u16 vertex2; // this - u16 vertex1; // is - u16 flags; // weird - u16 vertex3; // order -}; - -class RwGeometryDataNonameInfo -{ -public: - float boundingSphereX; - float boundingSphereY; - float boundingSphereZ; - float boundingSphereR; - u32 hasPosition; - u32 hasNormals; -}; - -#include -#include - -// Section: Geometry -class RwGeometryData : public RwSectionHeader -{ -public: - ~RwGeometryData() - { - // if (dataHeader.flags & rwOBJECT_VERTEX_NORMALS) - // delete[] normalInformation; - // delete[] vertexInformation; - // free(vertexInformation); - // delete[] faceInformation; - // if (dataHeader.flags & rwOBJECT_VERTEX_PRELIT) - // delete[] colorInformation; - // if (dataHeader.flags & rwOBJECT_VERTEX_TEXTURED) - // delete[] textureMappingInformation; - } - RwGeometryDataHeader dataHeader; - - RwGeometryDataLightingHeader lightingHeader; - - RwGeometryDataColorInformationChunk *colorInformation; // [vertexCount] - - RwGeometryDataTextureMappingInformationChunk *textureMappingInformation; // [vertexCount] - - RwGeometryDataFaceInformation *faceInformation; // [triangleCount] - - RwGeometryDataNonameInfo nonameInfo; - - Vector3 *vertexInformation; // [vertexCount] - - Vector3 *normalInformation; // [vertexCount] -}; - -class RwMaterialData : public RwSectionHeader -{ -public: - u32 unk1; - u8 R; - u8 G; - u8 B; - u8 A; - u32 unk2; - u32 textureCount; - float unkPosX; - float unkPosY; - float unkPosZ; -}; - -class RwTextureData : public RwSectionHeader -{ -public: - u16 textureFilterModeFlags; - u16 unk; -}; - -class RwString : public RwSectionHeader -{ -public: - ~RwString() { delete[] text; } - char *text; -}; - -class RwTextureExtension : public RwSectionHeader -{ - // May contain Sky Mipmap Val -}; - -class RwTexture : public RwSectionHeader -{ -public: - RwTextureData data; - RwString textureName; - RwString textureAlphaName; - RwTextureExtension extension; -}; - -class RwMaterialExtension : public RwSectionHeader -{ - // meant to be void.. don't ask -}; - -class RwMaterial : public RwSectionHeader -{ -public: - ~RwMaterial() {} - RwMaterialData data; - RwTexture *textures; - RwMaterialExtension extension; -}; - -class RwMaterialListData : public RwSectionHeader -{ -public: - ~RwMaterialListData() {} - u32 materialCount; - u32 *arrayOfUnks; // Filled with '-1's, [materialCount] - it wasn't mentioned in docs. -}; - -class RwMaterialList : public RwSectionHeader -{ -public: - ~RwMaterialList() {} - RwMaterialListData data; - RwMaterial *materials; -}; - -class RwGeometryListVertexInfoChunk -{ -public: - u32 vertex1; -}; - -class RwGeometryListInfoChunk -{ -public: - ~RwGeometryListInfoChunk() {} - u32 faceIndex; - u32 materialIndex; - - RwGeometryListVertexInfoChunk *vertexInformation; // [faceIndex] -}; - -class RwMaterialSplitHeader -{ -public: - u32 triangleStrip; - u32 splitCount; - u32 faceCount; -}; - -class RwMaterialSplit -{ -public: - ~RwMaterialSplit() {} - RwMaterialSplitHeader header; - - RwGeometryListInfoChunk *splitInformation; // [splitCount] -}; - -class RwGeometryExtension : public RwSectionHeader -{ -public: - RwMaterialSplit materialSplit; -}; - -class RwGeometry : public RwSectionHeader -{ -public: - RwGeometryData data; - RwMaterialList materialList; - RwGeometryExtension extension; -}; -// --- - -// Section: Geometry List -class RwGeometryListData : public RwSectionHeader -{ -public: - u32 geometryCount; -}; - -class RwGeometryList : public RwSectionHeader -{ -public: - ~RwGeometryList() {} - RwGeometryListData data; - RwGeometry *geometries; -}; -// --- - -// Section: Atomic -class RwAtomicData : public RwSectionHeader -{ -public: - u32 frameNumber; - u32 geometryNumber; - u32 unk1; - u32 unk2; -}; - -class RwAtomic : public RwSectionHeader -{ -public: - RwAtomicData data; -}; -// --- - -// Section: Clump -class RwClumpData : public RwSectionHeader -{ -public: - u32 objectCount; - u32 unk1; - u32 unk2; -}; - -class RwClump : public RwSectionHeader -{ -public: - RwClumpData data; - RwFrameList frameList; - RwGeometryList geometryList; - RwAtomic atomic; //multiple?? but how many -}; -// --- - -#endif diff --git a/src/engine/include/loaders/md2_loader.hpp b/src/engine/include/loaders/md2_loader.hpp deleted file mode 100644 index 6044e92..0000000 --- a/src/engine/include/loaders/md2_loader.hpp +++ /dev/null @@ -1,91 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_MD2_LOADER_ -#define _TYRA_MD2_LOADER_ - -#include "../models/mesh_frame.hpp" -#include - -// magic number "IDP2" or 844121161 -#define MD2_IDENT (('2' << 24) + ('P' << 16) + ('D' << 8) + 'I') - -// model version -#define MD2_VERSION 8 - -typedef struct -{ - int ident; // magic number. must be equal to "IDP2" - int version; // md2 version. must be equal to 8 - - int skinwidth; // width of the texture - int skinheight; // height of the texture - int framesize; // size of one frame in bytes - - int num_skins; // number of textures - int num_xyz; // number of vertices - int num_st; // number of texture coordinates - int num_tris; // number of triangles - int num_glcmds; // number of opengl commands - int num_frames; // total number of frames - - int ofs_skins; // offset to skin names (64 bytes each) - int ofs_st; // offset to s-t texture coordinates - int ofs_tris; // offset to triangles - int ofs_frames; // offset to frame data - int ofs_glcmds; // offset to opengl commands - int ofs_end; // offset to end of file - -} md2_t; - -typedef struct -{ - unsigned char v[3]; // compressed vertex (x, y, z) coordinates - unsigned char lightnormalindex; // index to a normal vector for the lighting - -} mvertex_t; - -typedef struct -{ - float scale[3]; // scale values - float translate[3]; // translation vector - char name[16]; // frame name - mvertex_t verts[1]; // first vertex of this frame - -} frame_t; - -typedef float vec3_t[3]; - -typedef struct -{ - short index_xyz[3]; // indexes to triangle's vertices - short index_st[3]; // indexes to vertices' texture coorinates -} triangle_t; - -typedef struct -{ - short s; - short t; -} texCoord_t; - -/** Class responsible for loading&parsing Quake's II ".md2" 3D files */ -class MD2Loader -{ - -public: - MD2Loader(); - ~MD2Loader(); - - MeshFrame *load(u32 &o_framesCount, char *t_subpath, char *t_nameWithoutExtension, float t_scale, u8 t_invertT); - -private: -}; - -#endif diff --git a/src/engine/include/loaders/obj_loader.hpp b/src/engine/include/loaders/obj_loader.hpp deleted file mode 100644 index 951f51a..0000000 --- a/src/engine/include/loaders/obj_loader.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_OBJ_LOADER_ -#define _TYRA_OBJ_LOADER_ - -#include "../models/mesh_frame.hpp" -#include - -/** Class responsible for loading&parsing .obj 3D files */ -class ObjLoader -{ - -public: - ObjLoader(); - ~ObjLoader(); - - /** Parse .obj file, allocate output data and store it. Multitexture support - * Notice: At this moment textures names are MATERIAL names from .obj file! - * Notice 2: Faces MUST be triangulated (check out blender export settings). - */ - void load(MeshFrame *o_result, char *t_fileName, float t_scale, u8 t_invertT); - -private: - void allocateObjMemory(FILE *t_file, MeshFrame *t_result); -}; - -#endif diff --git a/src/engine/include/loaders/png_loader.hpp b/src/engine/include/loaders/png_loader.hpp deleted file mode 100644 index 4af49e1..0000000 --- a/src/engine/include/loaders/png_loader.hpp +++ /dev/null @@ -1,29 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_PNG_LOADER_ -#define _TYRA_BMP_LOADER_ - -#include -#include -#include "../models/texture.hpp" - -/** Class responsible for loading images in bmp format */ -class PngLoader -{ - -public: - PngLoader(); - ~PngLoader(); - - void load(Texture &o_texture, char *t_subfolder, char *t_name, char *t_extension); -}; - -#endif diff --git a/src/engine/include/models/anim_state.hpp b/src/engine/include/models/anim_state.hpp deleted file mode 100644 index c0da8b0..0000000 --- a/src/engine/include/models/anim_state.hpp +++ /dev/null @@ -1,30 +0,0 @@ - -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_ANIM_STATE_ -#define _TYRA_ANIM_STATE_ - -#include - -typedef struct -{ - u32 startFrame; - u32 endFrame; - u32 stayFrame; - u8 isStayFrameSet; - float speed; - float interpolation; - u32 animType; - u32 currentFrame; - u32 nextFrame; -} AnimState; - -#endif diff --git a/src/engine/include/models/audio_listener.hpp b/src/engine/include/models/audio_listener.hpp deleted file mode 100644 index 1fcdeef..0000000 --- a/src/engine/include/models/audio_listener.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_AUDIO_LISTENER_ -#define _TYRA_AUDIO_LISTENER_ - -class AudioListener -{ - -public: - virtual ~AudioListener(){}; - virtual void onAudioTick() = 0; - virtual void onAudioFinish() = 0; - -private: -}; - -#endif diff --git a/src/engine/include/models/bounding_box.hpp b/src/engine/include/models/bounding_box.hpp deleted file mode 100644 index a2f6c44..0000000 --- a/src/engine/include/models/bounding_box.hpp +++ /dev/null @@ -1,94 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Michał Mostowik -*/ - -#ifndef _TYRA_BOUNDING_BOX_ -#define _TYRA_BOUNDING_BOX_ - -#include -#include -#include "math/point.hpp" -#include "math/vector3.hpp" - -/** - * Struct containing face data used in - * bounding box class. - */ -struct BoundingBoxFace -{ - BoundingBoxFace(){ - - }; - BoundingBoxFace(const Vector3 &t_minCorner, const Vector3 &t_maxCorner, float t_axisPos) - { - minCorner = t_minCorner; - maxCorner = t_maxCorner; - axisPosition = t_axisPos; - } - /** Position of the face on it's respective axis. */ - float axisPosition; - /** Corner of the face with lower coordinates */ - Vector3 minCorner; - /** Corner of the face with higher coordinates */ - Vector3 maxCorner; -}; - -/** - * Class containing bounding box data - * which can be used for collision detection. - */ -class BoundingBox -{ -public: - BoundingBox(Vector3 *t_vertices); - ~BoundingBox(); - const float &getHeight() { return _height; }; - const float &getDepth() { return _depth; }; - const float &getWidth() { return _width; }; - /** @returns the vector directly in middle of the bounding box. */ - const Vector3 &getCenter() { return _centerVector; }; - /** @returns the front face (further on z-axis) */ - const BoundingBoxFace &getFrontFace() { return _frontFace; }; - /** @returns the back face (nearer on z-axis) */ - const BoundingBoxFace &getBackFace() { return _backFace; }; - /** @returns the left face (further on x-axis) */ - const BoundingBoxFace &getLeftFace() { return _leftFace; }; - /** @returns the right face (nearer on x-axis) */ - const BoundingBoxFace &getRightFace() { return _rightFace; }; - /** @returns the top face (further on y-axis) */ - const BoundingBoxFace &getTopFace() { return _topFace; }; - /** @returns the bottom face (nearer on y-axis) */ - const BoundingBoxFace &getBottomFace() { return _bottomFace; }; - /** - * @returns bounding box raw vertices array. - * Total length: 8 - */ - const Vector3 &getVertex(const u8 &i) { return _vertices[i]; }; - /** @returns single vertex from raw vertices array.*/ - Vector3 *getVertices() { return _vertices; }; - -private: - Vector3 _vertices[8]; - float _height, _depth, _width; - Vector3 _centerVector; - /** Front face (further on z-axis) */ - BoundingBoxFace _frontFace; - /** Back face (nearer on z-axis) */ - BoundingBoxFace _backFace; - /** Left face (nearer on x-axis) */ - BoundingBoxFace _leftFace; - /** Right face (further on x-axis) */ - BoundingBoxFace _rightFace; - /** Top face (further on y-axis) */ - BoundingBoxFace _topFace; - /** Bottom face (nearer on y-axis) */ - BoundingBoxFace _bottomFace; -}; - -#endif diff --git a/src/engine/include/models/light_bulb.hpp b/src/engine/include/models/light_bulb.hpp deleted file mode 100644 index 7f4100a..0000000 --- a/src/engine/include/models/light_bulb.hpp +++ /dev/null @@ -1,23 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_LIGHT_BULB_ -#define _TYRA_LIGHT_BULB_ - -#include "math/vector3.hpp" -#include - -struct LightBulb -{ - Vector3 position; - u8 intensity; -}; - -#endif diff --git a/src/engine/include/models/math/matrix.hpp b/src/engine/include/models/math/matrix.hpp deleted file mode 100644 index 46b5140..0000000 --- a/src/engine/include/models/math/matrix.hpp +++ /dev/null @@ -1,186 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_MATRIX_ -#define _TYRA_MATRIX_ - -#include "vector3.hpp" -#include "../screen_settings.hpp" -#include - -/** 4x4 Matrix class. */ -class Matrix -{ - -public: - float data[16] __attribute__((aligned(64))); - - // ---- - // Constructors/Destructors - // ---- - - /** Create empty matrix. */ - Matrix(); - - /** - * Create identity/empty matrix. - * @param t_do_identity Identity matrix if true, random matrix values otherwise - */ - Matrix(const u8 &t_do_identity) - { - if (t_do_identity) - identity(); - } - - /** Init matrix with given values. */ - Matrix(const float &m11, const float &m12, const float &m13, const float &m14, - const float &m21, const float &m22, const float &m23, const float &m24, - const float &m31, const float &m32, const float &m33, const float &m34, - const float &m41, const float &m42, const float &m43, const float &m44); - - /** Init matrix with other matrix values. */ - Matrix(const Matrix &v) { memcpy(data, v.data, 16 * sizeof(float)); } - - // ---- - // Operators - // ---- - - Vector3 operator*(const Vector3 &v) const; - - Matrix operator*(const Matrix &v) const - { - Matrix result; - cross(result.data, this->data, v.data); - return result; - } - - inline void operator*=(const Matrix &v) { cross(this->data, this->data, v.data); } - - float &operator[](const u8 &t_index) { return data[t_index]; } - - // ---- - // Functions - // ---- - - /** - * 1 0 0 0 - * 0 1 0 0 - * 0 0 1 0 - * 0 0 0 1 - */ - void identity(); - - /** - * 1 0 0 0 - * 0 1 0 0 - * 0 0 1 0 - * 0 0 0 1 - */ - inline void unit() { identity(); }; - - /** Translate matrix. */ - inline void translate(const Vector3 &t_val) - { - Matrix temp = Matrix(true); - temp.translation(t_val); - cross(this->data, temp.data, this->data); - } - - /** Rotate matrix. */ - inline void rotate(const Vector3 &t_val) - { - Matrix temp = Matrix(true); - - temp.rotationZ(t_val.z); - cross(this->data, temp.data, this->data); - - temp.identity(); - temp.rotationY(t_val.y); - cross(this->data, temp.data, this->data); - - temp.identity(); - temp.rotationX(t_val.x); - cross(this->data, temp.data, this->data); - } - - /** Rotate matrix by X. */ - inline void rotateX(const float &t_radians) - { - Matrix temp = Matrix(true); - temp.rotationX(t_radians); - cross(this->data, temp.data, this->data); - } - - /** Rotate matrix by Y. */ - inline void rotateY(const float &t_radians) - { - Matrix temp = Matrix(true); - temp.rotationY(t_radians); - cross(this->data, temp.data, this->data); - } - - /** Rotate matrix by Z. */ - inline void rotateZ(const float &t_radians) - { - Matrix temp = Matrix(true); - temp.rotationZ(t_radians); - cross(this->data, temp.data, this->data); - } - - /** Rotate matrix by angle. */ - void rotateByAngle(const float &t_angle, const Vector3 &t_axis) - { - Matrix temp; - temp.rotationByAngle(t_angle, t_axis); - cross(this->data, temp.data, this->data); - } - - /** Scale matrix. */ - void scale(const Vector3 &t_val) - { - Matrix temp = Matrix(true); - temp.setScale(t_val); - cross(this->data, temp.data, this->data); - } - - /** - * Create perspective projection matrix. - * - * Complies with OpenGL standard (gluPerspective). - * @see https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml - * @param screen Screen settings - */ - void setPerspective(const ScreenSettings &screen); - - /** - * Create a view matrix that transforms coordinates in - * such a way that the user looks at a target vector - * direction from a position vector. - * - * Complies with OpenGL standard (glLookAt). - * @see https://learnopengl.com/Getting-started/Camera - */ - void lookAt(const Vector3 &t_position, const Vector3 &t_target); - - /** Print matrix (printf). */ - const void print() const; - -private: - void rotationX(const float &t_radians); - void rotationY(const float &t_radians); - void rotationZ(const float &t_radians); - void rotationByAngle(const float &t_angle, const Vector3 &t_axis); - void translation(const Vector3 &t_val); - void setScale(const Vector3 &t_val); - void setCamera(const float t_pos[4], const float t_vz[4], const float t_vy[4]); - void cross(float res[16], const float a[16], const float b[16]) const; -}; - -#endif diff --git a/src/engine/include/models/math/plane.hpp b/src/engine/include/models/math/plane.hpp deleted file mode 100644 index c5cbf61..0000000 --- a/src/engine/include/models/math/plane.hpp +++ /dev/null @@ -1,33 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_PLANE_ -#define _TYRA_PLANE_ - -#include "vector3.hpp" - -/** https://en.wikipedia.org/wiki/Plane_(geometry) */ -class Plane -{ - -public: - Vector3 normal; - float distance; - - Plane(); - Plane(Vector3 &a, Vector3 &b, Vector3 &c); - ~Plane(); - - void update(Vector3 &a, Vector3 &b, Vector3 &c); - inline float distanceTo(Vector3 &t_vec) { return this->distance + this->normal.innerProduct(t_vec); } - const void print() const; -}; - -#endif diff --git a/src/engine/include/models/math/point.hpp b/src/engine/include/models/math/point.hpp deleted file mode 100644 index f12c690..0000000 --- a/src/engine/include/models/math/point.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_POINT_ -#define _TYRA_POINT_ - -/** https://en.wikipedia.org/wiki/Point_(geometry) */ -class Point -{ - -public: - union - { - struct - { - float x; - float y; - }; - float xy[2] __attribute__((__aligned__(16))); - }; - - Point(const float &t_x, const float &t_y); - Point(const Point &v); - Point(); - ~Point(); - - void set(const float &t_x, const float &t_y); - void rotate(const float &t_angle, const float &t_x, const float &t_y); - void set(const Point &v); - const void print() const; -}; - -#endif diff --git a/src/engine/include/models/math/vector3.hpp b/src/engine/include/models/math/vector3.hpp deleted file mode 100644 index 53939af..0000000 --- a/src/engine/include/models/math/vector3.hpp +++ /dev/null @@ -1,123 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_VECTOR3_ -#define _TYRA_VECTOR3_ - -#include -#include - -class Math; // Forward definition - -/** https://en.wikipedia.org/wiki/Vector_(mathematics_and_physics) */ -class Vector3 -{ - -public: - /** This trick will allow use to use vec.x and vex[0] */ - union - { - struct - { - float x; - float y; - float z; - }; - float xyz[3] __attribute__((__aligned__(16))); - }; - - // ---- - // Constructors/Destructors - // ---- - - /** Create empty vector. */ - Vector3(); - - /** Create vector with given vector values. */ - Vector3(const Vector3 &t_v) { set(t_v); } - - /** Create vector with given values. */ - Vector3(const float &t_x, const float &t_y, const float &t_z) { set(t_x, t_y, t_z); } - - // ---- - // Operators - // ---- - - Vector3 operator+(const Vector3 &v) const; - Vector3 operator-(const Vector3 &v) const; - /** Also called "cross product" */ - Vector3 operator*(const Vector3 &v) const; - Vector3 operator*(const float &t) const; - Vector3 operator/(const float &t) const; - Vector3 operator-(void) const { return Vector3(-x, -y, -z); } - void operator+=(const Vector3 &t); - void operator*=(const float &t); - - // ---- - // Functions - // ---- - - /** Set vector values via VU0. */ - void set(const Vector3 &v); - - /** Set vector values. */ - void set(const float &t_x, const float &t_y, const float &t_z); - - /** Also called dot3. */ - float innerProduct(const Vector3 &v) const; - - /** Get vector length */ - float length() const; - - /** Normalize vector. */ - void normalize(); - - /** Returns distance between two vectors */ - float distanceTo(const Vector3 &v) const; - - /** - * Checks intersection with given box - * @param t_min Opposite min vertex (ex. near, left, down vertex of bounding box) - * @param t_max Opposite max vertex (ex. far, right, up vertex of bounding box) - */ - u8 collidesBox(const Vector3 &t_min, const Vector3 &t_max) const - { - return ((this->x <= t_max.x && this->x >= t_min.x) && (this->y < t_max.y && this->y >= t_min.y) && (this->z <= t_max.z && this->z >= t_min.z)) ? 1 : 0; - } - - /** - * Checks if this vector is on given box (this->y >= box.y) - * @param t_min Opposite min vertex (ex. near, left, down vertex of bounding box) - * @param t_max Opposite max vertex (ex. far, right, up vertex of bounding box) - */ - u8 isOnBox(const Vector3 &t_min, const Vector3 &t_max) const - { - return ((this->x <= t_max.x && this->x >= t_min.x) && (this->y >= t_max.y) && (this->z <= t_max.z && this->z >= t_min.z)) ? 1 : 0; - } - - /** Check if given triangle should be backface culled. */ - static u8 shouldBeBackfaceCulled(const Vector3 *t_cameraPos, const Vector3 *t_v0, const Vector3 *t_v1, const Vector3 *t_v2); - - /** - * Set by linear interpolation between two vertices (animation). - * @param t_v1 Before vertex - * @param t_v2 After vertex - * @param t_interp State of interpolation - * @param t_scale Scale - */ - void setByLerp(const Vector3 &t_v1, const Vector3 &t_v2, const float &t_interp, const float &t_scale); - - const void print() const - { - printf("Vector3(%f, %f, %f)\n", x, y, z); - } -}; - -#endif diff --git a/src/engine/include/models/mesh.hpp b/src/engine/include/models/mesh.hpp deleted file mode 100644 index 64983fa..0000000 --- a/src/engine/include/models/mesh.hpp +++ /dev/null @@ -1,215 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_MESH_ -#define _TYRA_MESH_ - -#include "math/vector3.hpp" -#include "math/plane.hpp" -#include "./texture.hpp" -#include "./mesh_frame.hpp" -#include -#include -#include -#include "./anim_state.hpp" - -/** - * Class which have contain 3D object data. - * External data can be loaded via loadXXX() methods. - */ -class Mesh -{ - -public: - Mesh(); - ~Mesh(); - - Vector3 position, rotation; - float scale; - u8 shouldBeLighted; - /** - * When true, invisible triangles of mesh materials are not drawn. - */ - u8 shouldBeBackfaceCulled; - /** - * When true, mesh materials are not drawn when they are outside of view frustum. - */ - u8 shouldBeFrustumCulled; - clutbuffer_t clut; - lod_t lod; - - // ---- - // Getters - // ---- - - /** Auto generated unique Id. */ - const u32 &getId() const { return id; }; - - /** Array of materials. Size of getMaterialsCount() */ - MeshMaterial *getMaterials() const { return frames[0].getMaterials(); }; - - const u32 &getMaterialsCount() const { return frames[0].getMaterialsCount(); }; - - /** Returns material, which is a mesh "subgroup". */ - MeshMaterial &getMaterial(const u32 &i) const { return frames[0].getMaterial(i); }; - - /** Count of frames. Static object (not animated) will have only 1 frame. */ - const u32 &getFramesCount() const { return framesCount; }; - - /** Count of vertices. */ - u32 getVertexCount() { return frames[0].getVertexCount(); }; - - /** Returns single frame. */ - MeshFrame &getFrame(const u32 &i) const { return frames[i]; }; - - /** Array of frames. Size of getFramesCount() */ - MeshFrame *getFrames() const { return frames; }; - - const u32 &getCurrentAnimationFrame() const { return animState.currentFrame; }; - - const u32 &getNextAnimationFrame() const { return animState.nextFrame; }; - - const u32 &getStartAnimationFrame() const { return animState.startFrame; }; - - const u32 &getEndAnimationFrame() const { return animState.endFrame; }; - - const u32 &getStayAnimationFrame() const { return animState.stayFrame; }; - - /** - * Returns material, which is a mesh "subgroup". - * NULL if not found. - */ - MeshMaterial *getMaterialById(const u32 &t_id) const { return frames[0].getMaterialById(t_id); } - - /** - * Returns bounding vertex of current frame. - * @param i 0-7. Because, bounding box have 8 corners - */ - const Vector3 &getCurrentBoundingBoxVertex(const u8 &i) { return frames[animState.currentFrame].getBoundingBoxVertex(i); }; - - /** @returns bounding box vertex array of current frame. Size: 8 */ - const Vector3 *getCurrentBoundingBoxVertices() const { return frames[animState.currentFrame].getBoundingBoxVertices(); }; - - /** @returns bounding box object of current frame. */ - const BoundingBox *getCurrentBoundingBox() const { return frames[animState.currentFrame].getBoundingBox(); }; - - // ---- - // Setters - // ---- - - // ---- - // Other - // ---- - - /** - * Load mesh data from .obj files. Animation supported. - * Be aware that texture names will be grabbed from material name. - * So no .mtl file is needed. Please check if material names in .obj file - * are equal to texture file names. - * @param t_subfolder Relative path. Example "meshes/blocks" - * @param t_objFile File name without extension. Example "sand" - * @param t_scale Scale. For 1:1, type 1.0F - * @param t_framesCount Amount of frames. - * Example: 2. - * Searched files: sand_000001.obj, sand_000002.obj - * @param t_invertT Sometimes textures are in UV format, in this case, invertT should be set to true. - * Converts Y coordinate texture from Y to 1.0F - Y - */ - void loadObj(char *t_subfolder, char *t_objFile, const float &t_scale, const u32 &t_framesCount, const u8 &t_invertT); - - /** - * Load mesh data from .obj file. Animation not supported. - * Be aware that texture names will be grabbed from material name. - * So no .mtl file is needed. Please check if material names in .obj file - * are equal to texture file names. - * @param t_subfolder Relative path. Example "meshes/blocks" - * @param t_objFile File name without extension. Example "sand" - * @param t_scale Scale. For 1:1, type 1.0F - * @param t_invertT Sometimes textures are in UV format, in this case, invertT should be set to true. - * Converts Y coordinate texture from Y to 1.0F - Y - */ - void loadObj(char *t_subfolder, char *t_objFile, const float &t_scale, const u8 &t_invertT); - - /** - * Load mesh data from RenderWare .dff file. Animation not supported - * @param t_subfolder Relative path. Example "meshes/blocks" - * @param t_objFile File name without extension. Example "sand" - * @param t_scale Scale. For 1:1, type 1.0F - * @param t_invertT Sometimes textures are in UV format, in this case, invertT should be set to true. - * Converts Y coordinate texture from Y to 1.0F - Y - */ - void loadDff(char *t_subfolder, char *t_dffFile, const float &t_scale, const u8 &t_invertT); - - /** - * Load mesh data from Quake II .md2 file. Animation supported. - * @param t_subfolder Relative path. Example "meshes/blocks" - * @param t_objFile File name without extension. Example "sand" - * @param t_scale Scale. For 1:1, type 1.0F - * @param t_invertT Sometimes textures are in UV format, in this case, invertT should be set to true. - * Converts Y coordinate texture from Y to 1.0F - Y - */ - void loadMD2(char *t_subfolder, char *t_md2File, const float &t_scale, const u8 &t_invertT); - - /** Copy by reference mesh data from other mesh */ - void loadFrom(const Mesh &t_mesh); - - /** Check if are there any frames */ - u8 isDataLoaded() const { return framesCount > 0; }; - - /** Loop in one frame */ - void playAnimation(const u32 &t_frame) { playAnimation(t_frame, t_frame); } - - /** Play animation in loop from startFrame to endFrame */ - void playAnimation(const u32 &t_startFrame, const u32 &t_endFrame); - - /** Play animation from startFrame to endFrame and after loop in stayFrame */ - void playAnimation(const u32 &t_startFrame, const u32 &t_endFrame, const u32 &t_stayFrame); - - void setAnimSpeed(const float &t_value) { animState.speed = t_value; } - - const u8 &areFramesAllocated() const { return _areFramesAllocated; }; - - /** - * Check if this class loaded mesh data first. - * Meshes which use loadFrom() method have false there. - */ - const u8 &isMother() const { return _isMother; }; - - /** - * Check if this class loaded mesh data first. - * Meshes which use loadFrom() method have false there. - */ - const u8 &isStayAnimationSet() const { return animState.isStayFrameSet; }; - - /** True when mesh is in view frustum */ - u8 isInFrustum(Plane *t_frustumPlanes); - - /** - * Do not call this method unless you know what you do. - * Should be called by renderer. - */ - void animate(); - - /** - * Do not call this method unless you know what you do. - * Should be called by renderer. - */ - u32 getDrawData(u32 t_materialIndex, VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, Vector3 &t_cameraPos); - -private: - AnimState animState; - MeshFrame *frames; - u32 id, framesCount; - u8 _isMother, _areFramesAllocated; - Vector3 calc3Vectors[3]; - void setDefaultLODAndClut(); -}; - -#endif diff --git a/src/engine/include/models/mesh_frame.hpp b/src/engine/include/models/mesh_frame.hpp deleted file mode 100644 index 48cc772..0000000 --- a/src/engine/include/models/mesh_frame.hpp +++ /dev/null @@ -1,182 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_MESH_FRAME_ -#define _TYRA_MESH_FRAME_ - -#include -#include -#include "bounding_box.hpp" -#include "math/point.hpp" -#include "math/vector3.hpp" -#include "./mesh_material.hpp" - -/** - * Class which contains core mesh data - * which are needed for drawing. - * Static object (not animated), will have - * only one instance of this class. - */ -class MeshFrame -{ - -public: - MeshFrame(); - ~MeshFrame(); - - // ---- - // Getters - // ---- - - /** - * Auto generated unique Id. - * Core role of this variable is to select correct texture to draw - */ - const u32 &getId() const { return id; }; - - const u32 &getVertexCount() const { return vertexCount; }; - const u32 &getSTsCount() const { return stsCount; }; - const u32 &getNormalsCount() const { return normalsCount; }; - const u32 &getMaterialsCount() const { return materialsCount; }; - - /** Returns vertex. 3 vertices = 1 triangle. */ - Vector3 &getVertex(const u32 &i) const { return vertices[i]; }; - - /** Returns texture coordinate. */ - Point &getST(const u32 &i) const { return sts[i]; }; - - /** Returns normal vector. Used for lighting. */ - Vector3 &getNormal(const u32 &i) const { return normals[i]; }; - - /** Returns material, which is a mesh "subgroup". */ - MeshMaterial &getMaterial(const u32 &i) const { return materials[i]; }; - - /** - * Returns material, which is a mesh "subgroup". - * NULL if not found. - */ - MeshMaterial *getMaterialById(const u32 &t_id) const - { - for (u32 i = 0; i < materialsCount; i++) - if (materials[i].getId() == t_id) - return &materials[i]; - return NULL; - } - - /** Array of vertices. Size of getVertexCount() */ - Vector3 *getVertices() const { return vertices; }; - - /** Array of vertices. Size of getSTsCount() */ - Point *getSTs() const { return sts; }; - - /** Array of vertices. Size of getNormalsCount() */ - Vector3 *getNormals() const { return normals; }; - - /** Array of materials. Size of getMaterialsCount() */ - MeshMaterial *getMaterials() const { return materials; }; - - /** - * @returns bounding box (AABB). - * Total length: 8 - */ - Vector3 *getBoundingBoxVertices() { return boundingBoxObj->getVertices(); }; - - /** - * @returns bounding box (AABB) vertex. - * Total length: 8 - */ - const Vector3 &getBoundingBoxVertex(const u8 &i) { return boundingBoxObj->getVertex(i); }; - - /** - * @returns bounding box (AABB) object pointer. - */ - BoundingBox *getBoundingBox() { return boundingBoxObj; }; - - // ---- - // Setters - // ---- - - /** - * Do not call this method unless you know what you do. - * Should be called by data loader. - */ - void setVertex(const u32 &t_index, const Vector3 &t_val) { vertices[t_index].set(t_val); } - - /** - * Do not call this method unless you know what you do. - * Should be called by data loader. - */ - void setNormal(const u32 &t_index, const Vector3 &t_val) { normals[t_index].set(t_val); } - - /** - * Do not call this method unless you know what you do. - * Should be called by data loader. - */ - void setST(const u32 &t_index, const Point &t_val) { sts[t_index].set(t_val); } - - // ---- - // Other - // ---- - - /** - * Check if this object is mother. - * Mother = object loaded with loadObj(), loadDff().. - * Have all mother data: vertex, st, etc.. - * Non-mother = object loaded with loadFrom(). - * Have reference copy to mother data: vertex, st, etc.. - * - * When you will destruct mother object, all vertex, st data will be deleted. - * When you will destruct non-mother object, all vertex, st data will be NOT deleted. - */ - const u8 &isMother() const { return _isMother; }; - - const u8 &areSTsAllocated() const { return _areSTsAllocated; }; - const u8 &areVerticesAllocated() const { return _areVerticesAllocated; }; - const u8 &areNormalsAllocated() const { return _areNormalsAllocated; }; - const u8 &areMaterialsAllocated() const { return _areMaterialsAllocated; }; - const u8 &isBoundingBoxCalculated() const { return _isBoundingBoxCalculated; }; - - /** Create reference copy (non-mother) */ - void copyFrom(MeshFrame *t_refCopy); - - /** Set STs count and allocate memory. */ - void allocateSTs(const u32 &t_val); - - /** Set vertex count and allocate memory. */ - void allocateVertices(const u32 &t_val); - - /** Set normals count and allocate memory. */ - void allocateNormals(const u32 &t_val); - - /** Set materials count and allocate memory. */ - void allocateMaterials(const u32 &t_val); - - /** - * Calculates bounding box (AABB) for frame and for materiaals. - * Should be called by data loader, - * so there is no need to run it again. - */ - void calculateBoundingBoxes(); - -private: - BoundingBox *boundingBoxObj; - u8 _isMother, - _areSTsAllocated, - _areVerticesAllocated, - _areNormalsAllocated, - _areMaterialsAllocated, - _isBoundingBoxCalculated; - u32 vertexCount, stsCount, normalsCount, materialsCount, id; - MeshMaterial *materials; - Point __attribute__((aligned(16))) * sts; - Vector3 __attribute__((aligned(16))) * vertices, *normals; -}; - -#endif diff --git a/src/engine/include/models/mesh_material.hpp b/src/engine/include/models/mesh_material.hpp deleted file mode 100644 index 03bbeeb..0000000 --- a/src/engine/include/models/mesh_material.hpp +++ /dev/null @@ -1,176 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_MESH_MATERIAL_ -#define _TYRA_MESH_MATERIAL_ - -#include -#include -#include "bounding_box.hpp" -#include "./math/vector3.hpp" -#include "./math/plane.hpp" - -/** - * Class which contains draw instructions for part of mesh. - * Mesh can have many materials. - * For example, car mesh can have three materials: - * body, tires and windows. - */ -class MeshMaterial -{ - -public: - MeshMaterial(); - ~MeshMaterial(); - - color_t color; - - // ---- - // Getters - // ---- - - /** Material name. */ - char *getName() const { return name; }; - - /** - * Auto generated unique Id. - * Core role of this variable is to select correct texture to draw - */ - const u32 &getId() const { return id; }; - - const u32 &getFacesCount() const { return facesCount; }; - - /** Indexes of vertices. Each 3 faces will give you vertices of next triangle. */ - u32 &getVertexFace(const u32 &i) const { return vertexFaces[i]; }; - - /** Indexes of texture coords. Each 3 faces will give you texture coords of next triangle. */ - u32 &getSTFace(const u32 &i) const { return stFaces[i]; }; - - /** Indexes of normal vectors used for lighting. Each 3 faces will give you normal vectors of next triangle. */ - u32 &getNormalFace(const u32 &i) const { return normalFaces[i]; }; - - /** Array of vertex faces. Size of getFacesCount() */ - u32 *getVertexFaces() const { return vertexFaces; }; - - /** Array of texture coords faces. Size of getFacesCount() */ - u32 *getSTFaces() const { return stFaces; }; - - /** Array of normal vector faces. Size of getFacesCount() */ - u32 *getNormalFaces() const { return normalFaces; }; - - /** - * @returns bounding box (AABB). - * Total length: 8 - */ - Vector3 *getBoundingBoxVertices() { return boundingBoxObj->getVertices(); }; - - /** - * @returns bounding box (AABB) vertex. - * Total length: 8 - */ - const Vector3 &getBoundingBoxVertex(const u8 &i) { return boundingBoxObj->getVertex(i); }; - - /** - * @returns bounding box (AABB) object pointer. - */ - BoundingBox *getBoundingBox() { return boundingBoxObj; }; - - // ---- - // Setters - // ---- - - /** - * Do not call this method unless you know what you do. - * Should be called by data loader. - */ - void setVertexFace(const u32 &t_index, const u32 &t_val) { vertexFaces[t_index] = t_val; } - - /** - * Do not call this method unless you know what you do. - * Should be called by data loader. - */ - void setSTFace(const u32 &t_index, const u32 &t_val) { stFaces[t_index] = t_val; } - - /** - * Do not call this method unless you know what you do. - * Should be called by data loader. - */ - void setNormalFace(const u32 &t_index, const u32 &t_val) { normalFaces[t_index] = t_val; } - - /** Set material name. */ - void setName(char *t_val); - - /** - * Do not call this method unless you know what you do. - * Should be called by data loader. - */ - void setSTsPresent(const u8 &b) { _areSTsPresent = b; }; - - /** - * Do not call this method unless you know what you do. - * Should be called by data loader. - */ - void setNormalsPresent(const u8 &b) { _areNormalsPresent = b; }; - - // ---- - // Other - // ---- - - const u8 &areSTsPresent() const { return _areSTsPresent; }; - - const u8 &areNormalsPresent() const { return _areNormalsPresent; }; - - /** Create reference copy (non-mother) */ - void copyFrom(MeshMaterial *t_refCopy); - - const u8 &isNameSet() const { return _isNameSet; }; - - /** - * Check if this object is mother. - * Mother = object loaded with loadObj(), loadDff().. - * Have all mother data: vertex faces, st faces, etc.. - * Non-mother = object loaded with loadFrom(). - * Have reference copy to mother data: vertex faces, st faces, etc.. - * - * When you will destruct mother object, all faces data will be deleted. - * When you will destruct non-mother object, all faces data will be NOT deleted. - */ - const u8 &isMother() const { return _isMother; }; - - const u8 &areFacesAllocated() const { return _areFacesAllocated; }; - - /** Set faces count and allocate memory. */ - void allocateFaces(const u32 &t_val); - - /** - * Do not call this method unless you know what you do. - * Calculates bounding box (AABB). - * Called automatically in mesh frame class on data loading. - */ - void calculateBoundingBox(Vector3 *t_vertices, u32 t_vertCount); - - /** True when mesh is in view frustum */ - u8 isInFrustum(Plane *t_frustumPlanes, const Vector3 &position); - -private: - void setDefaultColor(); - BoundingBox *boundingBoxObj; - u32 facesCount, id; - u32 *vertexFaces, *stFaces, *normalFaces; - u8 _isMother, - _isNameSet, - _areFacesAllocated, - _isBoundingBoxCalculated, - _areSTsPresent, - _areNormalsPresent; - char *name; -}; - -#endif diff --git a/src/engine/include/models/render_data.hpp b/src/engine/include/models/render_data.hpp deleted file mode 100644 index f4a89c7..0000000 --- a/src/engine/include/models/render_data.hpp +++ /dev/null @@ -1,42 +0,0 @@ - - -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_RENDER_DATA_ -#define _TYRA_RENDER_DATA_ - -#include "light_bulb.hpp" -#include -#include "math/matrix.hpp" -#include "math/plane.hpp" - -struct RenderData -{ - LightBulb *bulbs; - u16 bulbsCount; - /** - * Camera matrix (glLookAt) - * OpenGL name: View - * Sony name: World view - */ - Matrix *view; - /** - * Projection matrix (glPerspective) - * OpenGL name: Projection - * Sony name: View screen - */ - Matrix *projection; - Vector3 *cameraPosition; - Plane *frustumPlanes; - prim_t *prim; -}; - -#endif diff --git a/src/engine/include/models/screen_settings.hpp b/src/engine/include/models/screen_settings.hpp deleted file mode 100644 index 8794799..0000000 --- a/src/engine/include/models/screen_settings.hpp +++ /dev/null @@ -1,27 +0,0 @@ - - -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_SCREEN_SETTINGS_ -#define _TYRA_SCREEN_SETTINGS_ - -struct ScreenSettings -{ - float fov; - float width; - float height; - float aspectRatio; - float nearPlaneDist; - float farPlaneDist; - float projectionScale; -}; - -#endif diff --git a/src/engine/include/models/sprite.hpp b/src/engine/include/models/sprite.hpp deleted file mode 100644 index a606d2c..0000000 --- a/src/engine/include/models/sprite.hpp +++ /dev/null @@ -1,80 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_SPRITE_ -#define _TYRA_SPRITE_ - -#include -#include -#include - -enum SpriteMode -{ - MODE_STRETCH, - MODE_REPEAT -}; - -/** - * Class which have contain 2D image data. - */ -class Sprite -{ - -public: - Sprite(); - ~Sprite(); - - Point position, size; - float scale; - color_t color; - clutbuffer_t clut; - - // ---- - // Getters - // ---- - - /** Auto generated unique Id. */ - inline const u32 &getId() const { return id; }; - - /** Get sprite drawing mode. */ - inline const SpriteMode &getMode() const { return mode; }; - - // ---- - // Setters - // ---- - - /** Set sprite drawing mode. */ - void setMode(const SpriteMode &t_val) { mode = t_val; } - - // ---- - // Other - // ---- - - /** Flip texture horizontally. */ - inline void flipHorizontally(const u8 &t_set) { _flipH = t_set; }; - - /** Flip texture vertically. */ - inline void flipVertically(const u8 &t_set) { _flipV = t_set; }; - - /** Check if texture is vertically flipped. */ - inline const u8 &isFlippedVertically() const { return _flipV; }; - - /** Check if texture is horizontally flipped. */ - inline const u8 &isFlippedHorizontally() const { return _flipH; }; - -private: - u32 id; - SpriteMode mode; - u8 _isSizeSet, _flipH, _flipV; - void setDefaultColor(); - void setDefaultLODAndClut(); -}; - -#endif diff --git a/src/engine/include/models/texture.hpp b/src/engine/include/models/texture.hpp deleted file mode 100644 index 90fff21..0000000 --- a/src/engine/include/models/texture.hpp +++ /dev/null @@ -1,186 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_TEXTURE_ -#define _TYRA_TEXTURE_ - -#include -#include -#include "./texture_wrap_settings.hpp" -#include "./texture_link.hpp" -#include "../include/utils/debug.hpp" -#include -#include - -enum TextureType -{ - TEX_TYPE_RGB = GS_PSM_24, // BMP - TEX_TYPE_RGBA = GS_PSM_32 // PNG -}; - -/** - * Class which contains texture data. - * Textures are paired with meshes/sprites via addLink() and - * removeLink() functions which use meshId/spriteId and materialId (for mesh). - */ -class Texture -{ - -public: - Texture(); - ~Texture(); - - // ---- - // Getters - // ---- - - /** - * Auto generated unique Id. - * Core role of this variable is to dont send - * again texture in renderer, when last sent texture id - * by renderer will be equal to this id. - */ - inline const u32 getId() const { return id; }; - - inline const u16 getWidth() const { return width; }; - - inline const u16 getHeight() const { return height; }; - - inline const TextureType getType() const { return _type; }; - - inline u32 getTextureLinksCount() const { return static_cast(texLinks.size()); }; - - inline texwrap_t *getWrapSettings() { return &wrapSettings; }; - - /** - * Returns always width * width * 3/4. - * 3 for RGB, 4 for RGBA. - */ - inline u32 getDataSize() const { return _type == TEX_TYPE_RGB ? width * height * 3 : width * height * 4; }; - - /** - * Texture data, used by renderer. - * Array of size getDataSize(). - */ - inline unsigned char *getData() const { return data; }; - - /** - * Get texture name. - * For "textures/abc.bmp" result will be: "abc" - */ - inline char *getName() const { return name; }; - - /** Array of texture links. Size of getTextureLinksCount() */ - inline const std::vector &getTextureLinks() const { return texLinks; }; - - /** - * Returns index of link. - * -1 if not found. - * @param t_id - * For 3D: Mesh material id. - * For 2D: Sprite id. - */ - const s32 getIndexOfLink(const u32 &t_id) const - { - for (u32 i = 0; i < texLinks.size(); i++) - if (texLinks[i].id == t_id) - return i; - return -1; - }; - - // ---- - // Setters - // ---- - - /** - * Set texture size and allocate texture data - * Do not call this method unless you know what you do. - * Should be called by data loader. - */ - void setSize(const u8 &t_width, const u8 &t_height, const TextureType &t_type); - - /** - * Do not call this method unless you know what you do. - * Should be called by data loader. - */ - void setHeight(const u8 &t_val) { height = t_val; } - - /** - * Do not call this method unless you know what you do. - * Should be called by data loader. - */ - void setData(const u32 &t_index, const unsigned char &t_val) { data[t_index] = t_val; } - - /** - * Set texture name. - * Should be the file name without extension - */ - void setName(char *t_val); - - /** Set texture wrapping */ - void setWrapSettings(const WrapSettings t_horizontal, const WrapSettings t_vertical); - - // ---- - // Other - // ---- - - /** Assign texture to mesh and mesh material. */ - void addLink(const u32 &t_meshId, const u32 &t_materialId); - - /** Assign texture to sprite. */ - void addLink(const u32 &t_spriteId); - - const u8 &isNameSet() const { return _isNameSet; }; - - const u8 &isSizeSet() const { return _isSizeSet; }; - - /** - * Check if texture is linked with Mesh/Sprite. - * @param t_id - * For 3D: Mesh material id. - * For 2D: Sprite id. - */ - const u8 isLinkedWith(const u32 &t_id) const - { - s32 index = getIndexOfLink(t_id); - if (index != -1) - return true; - else - return false; - }; - - void removeLinkByIndex(const u32 &t_index) { texLinks.erase(texLinks.begin() + t_index); } - - /** - * Remove texture link with given Mesh/Sprite. - * @param t_id - * For 3D: Mesh material id. - * For 2D: Sprite id. - */ - void removeLinkById(const u32 &t_id) - { - s32 index = getIndexOfLink(t_id); - assertMsg(index != -1, "Cant remove link, because it was not found!"); - removeLinkByIndex(index); - } - -private: - void setDefaultWrapSettings(); - texwrap_t wrapSettings; - char *name; - TextureType _type; - std::vector texLinks; - u32 id; - u16 width, height; - u8 _isNameSet, _isSizeSet; - unsigned char *data; -}; - -#endif diff --git a/src/engine/include/models/texture_link.hpp b/src/engine/include/models/texture_link.hpp deleted file mode 100644 index 687c9c0..0000000 --- a/src/engine/include/models/texture_link.hpp +++ /dev/null @@ -1,25 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_TEXTURE_USAGE_ -#define _TYRA_TEXTURE_USAGE_ - -#include - -struct TextureLink -{ - /** - * For 3D: Mesh material id. - * For 2D: Sprite id. - */ - u32 id; -}; - -#endif diff --git a/src/engine/include/models/texture_wrap_settings.hpp b/src/engine/include/models/texture_wrap_settings.hpp deleted file mode 100644 index d012ecc..0000000 --- a/src/engine/include/models/texture_wrap_settings.hpp +++ /dev/null @@ -1,22 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_TEXTURE_WRAP_SETTINGS_ -#define _TYRA_TEXTURE_WRAP_SETTINGS_ - -enum WrapSettings -{ - Repeat = 0, - Clamp = 1, - RegionClamp = 2, - RegionRepeat = 3 -}; - -#endif diff --git a/src/engine/include/modules/audio.hpp b/src/engine/include/modules/audio.hpp deleted file mode 100644 index 1899cd7..0000000 --- a/src/engine/include/modules/audio.hpp +++ /dev/null @@ -1,157 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_AUDIO_ -#define _TYRA_AUDIO_ - -#include "../models/audio_listener.hpp" -#include "./file_service.hpp" -#include -#include -#include -#include -#include - -struct AudioListenerRef -{ - AudioListener *listener; - u32 id; -}; - -/** - * Class responsible for audio playing. - * There are two main features: - * - WAV song (background music) - * - ADPCM samples - */ -class Audio -{ - -public: - /** Constructor is called by the engine. */ - Audio(); - ~Audio(); - - // Song - - /** - * Load 24bit 22050Hz Stereo WAV. - * Can be used multiple times for song switching. - * @param t_path Example: "song.wav" or "folder/song.wav" - */ - void loadSong(char *t_path); - - void playSong(); - - void stopSong(); - - /** - * Set song volume. - * @param t_vol Value 0-100 - */ - void setSongVolume(const u8 &t_vol); - - /** - * If you want to synchronize some actions with - * background song, add audio listener. - * @returns Listener id. - */ - u32 addSongListener(AudioListener *t_listener); - - /** Remove song listener. */ - void removeSongListener(const u32 &t_id); - - const u8 &isSongPlaying() const { return songPlaying; } - - const u8 &isSongLoaded() const { return songLoaded; } - - const u8 &isSongInLoop() const { return songInLoop; } - - u32 getSongListenersCount() const { return songListeners.size(); } - - const u8 &getVolume() const { return volume; } - - /** - * Set song loop/noloop. - * @param t_set false - noloop, true - loop - */ - void setSongLoop(const u8 &t_set) { songInLoop = t_set; } - - // ADPCM - - /** - * Load ADPCM sample. ADPCM sample is an output from - * "adpenc" tool, shipped with PS2SDK. - * @param t_path Example: "hit.adpcm" or "folder/jump.adpcm" - */ - audsrv_adpcm_t *loadADPCM(char *t_path); - - /** - * Play ADPCM sample. - * ADPCM sample can't be stopped. - * @param t_adpcm ADPCM data, created by loadADPCM(); - */ - void playADPCM(audsrv_adpcm_t *t_adpcm); - - /** - * Play ADPCM sample. - * ADPCM sample can't be stopped. - * @param t_adpcm ADPCM data, created by loadADPCM(); - * @param t_ch Channel (0-23). Type -1 for use any free channel. - */ - void playADPCM(audsrv_adpcm_t *t_adpcm, const s8 &t_ch); - - /** - * Set ADPCM volume. - * @param t_vol Value 0-100 - * @param t_ch Channel (0-23) - */ - void setADPCMVolume(u8 t_vol, const s8 &t_ch) { audsrv_adpcm_set_volume(t_ch, t_vol); } - - // Other - - /** - * Start audio thread. - * Do not call this method unless you know what you do. - * Should be called by engine. - */ - void startThread(FileService *t_fileService); - -private: - u8 songLoaded, volume, realVolume, songPlaying, songInLoop, songFinished; - u8 hack; // TODO - std::vector songListeners; - FILE *wav; - audsrv_fmt_t format; - FileService *fileService; - - char wavChunk[2 * 1024] __attribute__((aligned(16))); - s32 chunkReadStatus; - - u8 threadStack[8 * 1024] __attribute__((aligned(16))); - u32 getThreadStackSize() { return 8 * 1024; } - u32 getSongBufferSize() { return 4 * 1024; } - ee_thread_t thread; - int threadId; - ee_sema_t sema; - s32 fillbufferSema; - - void setSongFormat(); - void unloadSong(); - void rewindSongToStart(); - - void initSema(); - void loadModules(); - void initAUDSRV(); - void threadLoop(); - static void mainThread(); -}; - -#endif diff --git a/src/engine/include/modules/camera_base.hpp b/src/engine/include/modules/camera_base.hpp deleted file mode 100644 index b74ff89..0000000 --- a/src/engine/include/modules/camera_base.hpp +++ /dev/null @@ -1,65 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_CAMERA_BASE_ -#define _TYRA_CAMERA_BASE_ - -#include "../models/math/plane.hpp" -#include "../models/math/matrix.hpp" -#include "../models/math/vector3.hpp" -#include "../models/screen_settings.hpp" - -/** Class responsible for frustum culling */ -class CameraBase -{ - -public: - CameraBase(ScreenSettings *t_screen, Vector3 *t_position); - virtual ~CameraBase(){}; - - /** - * Frustum planes. - * Set by lookAt() method. - */ - Plane planes[6]; - - /** - * View matrix - * Set by lookAt() method. - */ - Matrix view; - -protected: - /** Pointer to screen settings */ - ScreenSettings *screen; - - /** - * Adaption of OpenGL lookAt camera. - * Calculates view matrix and update frustum planes - * Should be called every frame. - */ - void lookAt(Vector3 &t_target); - - /** - * Do not call this method unless you know what you do. - * Called via lookAt(). - * Calculate and update frustum planes. - * http://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-extracting-the-planes/ - */ - void updatePlanes(Vector3 t_target); - -private: - Vector3 *p_position; - float farPlaneDist, nearPlaneDist, nearHeight, nearWidth, farHeight, farWidth; - Vector3 ftl, ftr, fbl, fbr, ntl, ntr, nbl, nbr; - Vector3 up; // always 0.0F, 1.0F, 0.0F -}; - -#endif diff --git a/src/engine/include/modules/file_service.hpp b/src/engine/include/modules/file_service.hpp deleted file mode 100644 index 995dea9..0000000 --- a/src/engine/include/modules/file_service.hpp +++ /dev/null @@ -1,115 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_FILE_SERVICE_ -#define _TYRA_FILE_SERVICE_ - -#include -#include -#include -#include - -enum FileServiceTaskType -{ - ReadChunk = 0 -}; - -struct FileServiceTask -{ - FileServiceTaskType type; - - u32 id; - - /** - * Used by types: - * - ReadChunk - */ - FILE *file; - - /** - * Used by types: - * - ReadChunk - */ - s32 readStatus; - - /** - * Used by types: - * - ReadChunk - */ - void *destination; - - /** - * Used by types: - * - ReadChunk - */ - u32 size; - - /** - * Used by types: - * - ReadChunk - */ - u32 n; -}; - -/** Class responsible for background, non-blocking file loading playing. */ -class FileService -{ - -public: - /** Constructor is called by the engine. */ - FileService(); - ~FileService(); - - /** - * Add task to read next chunk. ( fread() ) - * @returns Task id - */ - u32 addReadChunk(FILE *t_file, void *t_destination, const u32 &t_size, const u32 &t_n); - - /** - * Check if given task was done. - * When task is done, this method will return read status. - * After this, task is removed from file service, so this method - * will return something once per task. - * @returns Read status (ex. result of fread()). -2137 if task is not done. - */ - s32 isTaskDone(const u32 &t_taskId); - - /** - * Start file service thread. - * Do not call this method unless you know what you do. - * Should be called by engine. - */ - void startThread(); - - std::vector tasks; - -private: - /** Remove task by index */ - void removeByIndex(const u32 &t_index) { tasks.erase(tasks.begin() + t_index); } - - /** Remove task by id */ - const void removeById(const u32 &t_taskId); - - /** - * Get index of task. - * @returns Index of task. -1 if not found. - */ - const s32 getIndexOf(const u32 &t_taskId); - - u8 threadStack[8 * 1024] __attribute__((aligned(16))); - u32 getThreadStackSize() { return 8 * 1024; } - ee_thread_t thread; - int threadId; - void threadLoop(); - static void mainThread(); -}; - -#endif diff --git a/src/engine/include/modules/gif_sender.hpp b/src/engine/include/modules/gif_sender.hpp deleted file mode 100644 index baeee9c..0000000 --- a/src/engine/include/modules/gif_sender.hpp +++ /dev/null @@ -1,62 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_GIF_SENDER_ -#define _TYRA_GIF_SENDER_ - -#include -#include -#include -#include -#include -#include -#include "./light.hpp" -#include "../models/mesh.hpp" -#include "../models/math/matrix.hpp" -#include "../models/screen_settings.hpp" -#include "../models/light_bulb.hpp" -#include "../models/render_data.hpp" -#include "../models/texture.hpp" - -/** Class responsible for sending data packets via GIF (PATH3) */ -class GifSender -{ - -public: - GifSender(u32 t_packetSize, ScreenSettings *t_screen, Light *t_light); - ~GifSender(); - - void initPacket(u8 context); - void addObject(RenderData *t_renderData, Mesh &t_mesh, u32 vertexCount, VECTOR *vertices, VECTOR *normals, VECTOR *coordinates, LightBulb *t_bulbs, u16 t_bulbsCount, texbuffer_t *textureBuffer, color_t *t_color); - void addClear(zbuffer_t *t_zBuffer, color_t *t_rgb); - void sendPacket(); - void sendClear(zbuffer_t *t_zBuffer, color_t *t_rgb); - static void sendTexture(Texture &texture, texbuffer_t *t_texBuffer); - -private: - Light *light; - xyz_t *xyz; - color_t *rgbaq; - texel_t *st; - u8 isAnyObjectAdded; - ScreenSettings *screen; - packet2_t *packets[2]; - packet2_t *currentPacket; - u8 packetsCount; - int packetSize; - float halfScreenW, halfScreenH; - MATRIX localWorld, localScreen, localLight; - - void calc3DObject(Matrix t_perspective, Mesh &t_mesh, u32 vertexCount, VECTOR *vertices, VECTOR *normals, VECTOR *coordinates, RenderData *t_renderData, LightBulb *t_bulbs, u16 t_bulbsCount, color_t *t_color); - void convertCalcs(u32 t_vertCount, VECTOR *t_vertices, VECTOR *t_colors, VECTOR *t_sts, color_t &t_color); - void addCurrentCalcs(u32 &t_vertexCount); -}; - -#endif diff --git a/src/engine/include/modules/light.hpp b/src/engine/include/modules/light.hpp deleted file mode 100644 index ded1f2a..0000000 --- a/src/engine/include/modules/light.hpp +++ /dev/null @@ -1,36 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_LIGHT_ -#define _TYRA_LIGHT_ - -#include -#include -#include "../models/math/vector3.hpp" -#include "../models/light_bulb.hpp" - -class Light -{ - -public: - Light(); - ~Light(); - - u16 getLightsCount(u32 t_bulbsCount); - - /** Values from 0.0000F to 1.0000F */ - void setAmbientLight(const Vector3 &t_rgb); - void calculateLight(VECTOR *t_lightDirections, VECTOR *t_lightColors, int *t_lightTypes, LightBulb *t_bulbs, u32 t_lightsCount, Vector3 t_objPosition); - -private: - Vector3 ambientLight; -}; - -#endif diff --git a/src/engine/include/modules/pad.hpp b/src/engine/include/modules/pad.hpp deleted file mode 100644 index 739454c..0000000 --- a/src/engine/include/modules/pad.hpp +++ /dev/null @@ -1,43 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_PAD_ -#define _TYRA_PAD_ - -#include -#include - -/** Class responsible for player pad */ -class Pad -{ - -public: - u8 isCrossClicked, isSquareClicked, isTriangleClicked, isCircleClicked; - u8 isDpadUpPressed, isDpadDownPressed, isDpadLeftPressed, isDpadRightPressed; - u8 lJoyH, lJoyV, rJoyH, rJoyV; - - Pad(); - ~Pad(); - void update(); - -private: - char padBuf[256] __attribute__((aligned(64))); - char actAlign[6]; - int actuators, ret, port, slot; - padButtonStatus buttons; - u32 padData, oldPad, newPad; - - void reset(); - void loadModules(); - int waitPadReady(); - int initPad(); -}; - -#endif diff --git a/src/engine/include/modules/renderer.hpp b/src/engine/include/modules/renderer.hpp deleted file mode 100644 index 9066081..0000000 --- a/src/engine/include/modules/renderer.hpp +++ /dev/null @@ -1,171 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_RENDERER_ -#define _TYRA_RENDERER_ - -#include -#include -#include -#include -#include -#include "gif_sender.hpp" -#include "vif_sender.hpp" -#include "light.hpp" -#include "../models/math/plane.hpp" -#include "../models/sprite.hpp" -#include "../models/screen_settings.hpp" -#include "../models/render_data.hpp" -#include "./texture_repository.hpp" - -/** Class responsible for intializing draw env, textures and buffers */ -class Renderer -{ - -public: - Renderer(u32 t_packetSize, ScreenSettings *t_screen); - ~Renderer(); - - framebuffer_t frameBuffers[2]; - u8 context; // TODO - zbuffer_t zBuffer; - prim_t prim; - - void enableVSync() { isVSyncEnabled = true; } - void disableVSync() { isVSyncEnabled = false; } - - /** Reset draw wait flag. */ - inline void resetWaitFlag() - { - *GS_REG_CSR |= 2; - } - - /** Checks if draw wait flag is set */ - inline u8 isWaitFlagSet() const - { - return *GS_REG_CSR & 2; - } - - /** Waits for draw wait flag and reset it. */ - inline void waitForRender() - { - while (!isWaitFlagSet()) - ; - resetWaitFlag(); - } - - /** 2D draw. */ - void draw(Sprite &t_sprite); - - /// --- OBSOLETE - - // /** - // * WARNING: THIS FUNC CAUSE VISUAL ARTIFACTS! - // * Draw many meshes with lighting information. - // * Slowest way of rendering (PATH 3, using EE and GIF). - // * NOTICE: Animation supported, lighting supported - // */ - // void drawByPath3(Mesh *t_meshes, u16 t_amount, LightBulb *t_bulbs, u16 t_bulbsCount); - - // /** - // * WARNING: THIS FUNC CAUSE VISUAL ARTIFACTS! - // * Draw mesh with lighting information. - // * Slowest way of rendering (PATH 3, using EE and GIF). - // * NOTICE: Animation supported, lighting supported - // */ - // void drawByPath3(Mesh &t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount); - - // /** - // * WARNING: THIS FUNC CAUSE VISUAL ARTIFACTS! - // * Draw many meshes without lighting information. - // * Slowest way of rendering (PATH 3, using EE and GIF). - // * NOTICE: Animation supported, lighting supported - // */ - // void drawByPath3(Mesh *t_meshes, u16 t_amount); - - // /** - // * WARNING: THIS FUNC CAUSE VISUAL ARTIFACTS! - // * Draw mesh without lighting information. - // * Slowest way of rendering (PATH 3, using EE and GIF). - // * NOTICE: Animation supported, lighting supported - // */ - // void drawByPath3(Mesh &t_mesh); - - /// --- Draw: PATH1 - - /** - * Draw many meshes with lighting information. - * Draw in array mode, can be A LOT faster than for looping! - * Fastest way of rendering (PATH 1, using VU1). - * NOTICE: Animation supported, lighting NOT supported (at this moment) - */ - void draw(Mesh **t_meshes, u16 t_amount, LightBulb *t_bulbs, u16 t_bulbsCount); - - /** - * Draw mesh with lighting information. - * Fastest way of rendering (PATH 1, using VU1). - * NOTICE: Animation supported, lighting NOT supported (at this moment) - */ - void draw(Mesh &t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount); - - /** - * Draw many meshes without lighting information. - * Draw in array mode, can be A LOT faster than for looping! - * Fastest way of rendering (PATH 1, using VU1). - * NOTICE: Animation supported, lighting NOT supported (at this moment) - */ - void draw(Mesh **t_meshes, u16 t_amount); - - /** - * Draw mesh without lighting information. - * Fastest way of rendering (PATH 1, using VU1). - * NOTICE: Animation supported, lighting NOT supported (at this moment) - */ - void draw(Mesh &t_mesh); - - void setCameraDefinitions(Matrix *t_worldView, Vector3 *t_cameraPos, Plane *t_planes); - - void setWorldColor(const color_t &t_rgb); - - void endFrame(float fps); - - void setAmbientLight(const Vector3 &t_rgb) { light.setAmbientLight(t_rgb); } - - TextureRepository *getTextureRepository() - { - return &textureRepo; - }; - -private: - // We have some GCC bug here. Just try to reorder declarations. For example move worldColor up - game will crash. - void changeTexture(Texture *t_tex); - u32 lastTextureId; - texbuffer_t textureBuffer; - u8 isTextureVRAMAllocated, isVSyncEnabled; - void allocateTextureBuffer(Texture *t_texture); - void deallocateTextureBuffer(); - void flipBuffers(); - void beginFrameIfNeeded(); - u8 isFrameEmpty; - Matrix perspective, camRotation; - Light light; - RenderData renderData; - TextureRepository textureRepo; - ScreenSettings *screen; - GifSender *gifSender; - VifSender *vifSender; - packet2_t *flipPacket; - color_t worldColor; - void allocateBuffers(int t_screenW, int t_screenH); - void initDrawingEnv(); - void setPrim(); -}; - -#endif diff --git a/src/engine/include/modules/texture_repository.hpp b/src/engine/include/modules/texture_repository.hpp deleted file mode 100644 index 4d7dc15..0000000 --- a/src/engine/include/modules/texture_repository.hpp +++ /dev/null @@ -1,132 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_TEXTURE_REPOSITORY_ -#define _TYRA_TEXTURE_REPOSITORY_ - -#include -#include -#include -#include "../models/mesh.hpp" -#include "../models/mesh_frame.hpp" -#include "../loaders/bmp_loader.hpp" -#include "../loaders/png_loader.hpp" - -enum TextureFormat -{ - BMP, - PNG -}; - -/** Class responsible for intializing draw env, textures and buffers */ -class TextureRepository -{ - -public: - TextureRepository(); - ~TextureRepository(); - - // ---- - // Getters - // ---- - - /** Returns all repository textures. */ - std::vector *getAll() { return &textures; } - - u32 getTexturesCount() const { return static_cast(textures.size()); }; - - /** - * Returns single texture. - * NULL if not found. - * @param t_id - * For 3D: Mesh material id. - * For 2D: Sprite id. - */ - Texture *getBySpriteOrMesh(const u32 &t_id) - { - for (u32 i = 0; i < textures.size(); i++) - if (textures[i]->isLinkedWith(t_id)) - return textures[i]; - return NULL; - } - - /** - * Returns single texture. - * NULL if not found. - */ - Texture *getByTextureId(const u32 &t_id) const - { - for (u32 i = 0; i < textures.size(); i++) - if (t_id == textures[i]->getId()) - return textures[i]; - return NULL; - } - - /** - * Returns index of link. - * -1 if not found. - */ - const s32 getIndexOf(const u32 &t_texId) const - { - for (u32 i = 0; i < textures.size(); i++) - if (textures[i]->getId() == t_texId) - return i; - return -1; - }; - - // ---- - // Setters - // ---- - - // ---- - // Other - // ---- - - /** - * Add unlinked texture. - * @param t_subfolder Relative path. Ex.: "textures/" - * @param t_name Filename without extension. Ex.: "water" - * @param t_format if you want to use BMP, be sure that you have - * BMP with RGB 888 24bit, without color information. - */ - Texture *add(char *t_subfolder, char *t_name, TextureFormat t_format); - - /** - * Add linked textures in given subpath for mesh material names. - * @param t_path Relative path where textures should be searched. - * @param t_format if you want to use BMP, be sure that you have - * BMP with RGB 888 24bit, without color information. - */ - void addByMesh(char *t_path, Mesh &mesh, TextureFormat t_format); - - /** - * Remove texture from repository. - * Texture is NOT destructed. - */ - void removeByIndex(const u32 &t_index) { textures.erase(textures.begin() + t_index); } - - /** - * Remove texture from repository. - * Texture is NOT destructed. - */ - const void removeById(const u32 &t_texId) - { - s32 index = getIndexOf(t_texId); - assertMsg(index != -1, "Cant remove texture, because it was not found!"); - removeByIndex(index); - } - -private: - std::vector textures; - BmpLoader bmpLoader; - PngLoader pngLoader; -}; - -#endif diff --git a/src/engine/include/modules/timer.hpp b/src/engine/include/modules/timer.hpp deleted file mode 100644 index 6e9dcd2..0000000 --- a/src/engine/include/modules/timer.hpp +++ /dev/null @@ -1,33 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_TIMER_ -#define _TYRA_TIMER_ - -#include -#include - -/** Class responsible for fps counting */ -class Timer -{ - -public: - Timer(); - ~Timer(); - - u32 getTimeDelta(); - inline void prime() { lastTime = *T3_COUNT; } - float getFPS(); - -private: - u32 lastTime, time, change; -}; - -#endif diff --git a/src/engine/include/modules/vif_sender.hpp b/src/engine/include/modules/vif_sender.hpp deleted file mode 100644 index 65020ab..0000000 --- a/src/engine/include/modules/vif_sender.hpp +++ /dev/null @@ -1,63 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_VIF_SENDER_ -#define _TYRA_VIF_SENDER_ - -#include -#include -#include "../models/render_data.hpp" -#include "./light.hpp" -#include "../models/light_bulb.hpp" -#include "../models/mesh.hpp" -#include "../models/math/matrix.hpp" -#include "../models/math/vector3.hpp" - -/** Class responsible for sending 3D objects via VIF (PATH 1) */ -class VifSender -{ - -public: - VifSender(Light *t_light); - ~VifSender(); - - // TODO refactor - void drawMesh(RenderData *t_renderData, Matrix t_perspective, u32 vertCount2, VECTOR *vertices, VECTOR *normals, VECTOR *coordinates, Mesh &t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount, texbuffer_t *textureBuffer, color_t *t_color, u8 t_rgbaOnly); - void calcMatrix(const RenderData &t_renderData, const Vector3 &t_position, const Vector3 &t_rotation); - void drawTheSameWithOtherMatrices(const RenderData &t_renderData, Mesh **t_meshes, const u32 &t_skip, const u32 &t_count); - void enableWait() { isDrawWaitEnabled = true; } - void disableWait() { isDrawWaitEnabled = false; } - -private: - u32 lastVertCount; // needed for drawTheSameWithOtherMatrices() - u8 isLastRGBAOnly; // needed for drawTheSameWithOtherMatrices() - u8 isDrawWaitEnabled; - Light *light; - void uploadMicroProgram(); - void setDoubleBufferAddStaticData(); - void drawVertices(Mesh &t_mesh, u32 t_start, u32 t_end, VECTOR *t_vertices, VECTOR *t_coordinates, prim_t *t_prim, texbuffer_t *t_textureBuffer, u8 t_addDrawWait, color_t *t_color, u8 t_rgbaOnly); - packet2_t *packets[2] __attribute__((aligned(64))); - packet2_t *currPacket; - /** - * OpenGL name: Model - * Sony name: local world - */ - Matrix model; - /** - * OpenGL name: ModelViewProjection - * Sony name: local screen - */ - Matrix modelViewProj; - u8 context; - VECTOR position, rotation; - u32 vertCount; -}; - -#endif diff --git a/src/engine/include/utils/debug.hpp b/src/engine/include/utils/debug.hpp deleted file mode 100644 index 03428a1..0000000 --- a/src/engine/include/utils/debug.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_DEBUG_ -#define _TYRA_DEBUG_ - -#ifdef NDEBUG -#define consoleLog(message) ((void)0) -#define assertMsg(condition, message) ((void)0) - -#else // IF Debug -#include -class Debug -{ -public: - static void trap(const char *t_text, const char *t_file) - { - printf("\n"); - printf("====================================\n"); - printf("| ERROR: %s\n", t_text); - printf("| File : %s\n", t_file); - printf("====================================\n\n"); - for (;;) - ; - } -}; -#define consoleLog(message) printf("LOG: " message " (" __FILE__ ")\n") -#define assertMsg(condition, message) \ - if (!(condition)) \ - Debug::trap(message, __FILE__) -#endif // NDEBUG - -#endif // _TYRA_DEBUG_ diff --git a/src/engine/include/utils/math.hpp b/src/engine/include/utils/math.hpp deleted file mode 100644 index 5e97299..0000000 --- a/src/engine/include/utils/math.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_MATH_ -#define _TYRA_MATH_ - -#include -#include -#include "../models/math/vector3.hpp" -#include - -class Vector3; // Forward definition - -void manyVec3ToNative(VECTOR *t_result, Vector3 *t_vec, int t_amount, float t_fourthVal); -void vec3ToNative(VECTOR t_result, const Vector3 &t_vec, float t_fourthVal); - -class Math -{ - -public: - constexpr static float HALF_ANG2RAD = 3.14159265358979323846F / 360.0F; - constexpr static float ANG2RAD = 3.14159265358979323846F / 180.0F; - constexpr static float PI = 3.1415926535897932384626433832795F; - constexpr static float HALF_PI = 1.5707963267948966192313216916398F; - static float cos(float x); - static float asin(float x); - static float mod(float x, float y); - static inline float sin(float x) { return cos(x - HALF_PI); }; - static inline float tan(float x) { return sin(x) / cos(x); } - static float invSqrt(float x); - static inline u32 max(u32 a, u32 b) { return (a > b) ? a : b; } - static inline s32 max(s32 a, s32 b) { return (a > b) ? a : b; } - static inline float max(float a, float b) { return (a > b) ? a : b; } - static inline u32 min(u32 a, u32 b) { return (a < b) ? a : b; } - static inline s32 min(s32 a, s32 b) { return (a < b) ? a : b; } - static inline float min(float a, float b) { return (a < b) ? a : b; } - -private: - Math(); -}; - -#endif diff --git a/src/engine/include/utils/string.hpp b/src/engine/include/utils/string.hpp deleted file mode 100644 index ca530c5..0000000 --- a/src/engine/include/utils/string.hpp +++ /dev/null @@ -1,28 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_STRING_ -#define _TYRA_STRING_ - -#include - -class String -{ - -public: - static char *createU32ToString(const u32 a); - static char *createWithLeadingZeros(const char *a); - static char *createCopy(const char *source); - static u32 getLength(const char *a); - static char *createConcatenated(const char *a, const char *b); - static char *createWithoutExtension(const char *source); -}; - -#endif diff --git a/src/engine/loaders/bmp_loader.cpp b/src/engine/loaders/bmp_loader.cpp deleted file mode 100644 index 8652901..0000000 --- a/src/engine/loaders/bmp_loader.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "../include/loaders/bmp_loader.hpp" - -#include "../include/utils/debug.hpp" -#include "../include/utils/string.hpp" -#include - -// ---- -// Constructors/Destructors -// ---- - -BmpLoader::BmpLoader() {} - -BmpLoader::~BmpLoader() {} - -// ---- -// Methods -// ---- - -/** - * @param t_name Without extension. Example "skyfall2" - * @param t_extension With dot and extension. Example ".BMP" - */ -void BmpLoader::load(Texture &o_texture, char *t_subfolder, char *t_name, char *t_extension) -{ - char *path_part1 = String::createConcatenated(t_subfolder, t_name); - char *path_part2 = String::createConcatenated("host:", path_part1); - char *path = String::createConcatenated(path_part2, t_extension); - delete[] path_part1; - delete[] path_part2; - FILE *file = fopen(path, "rb"); - assertMsg(file != NULL, "Failed to load .bmp file!"); - - unsigned char header[54]; - fread(header, sizeof(unsigned char), 54, file); - - u32 width = (u32)header[18]; - u32 height = (u32)header[22]; - u32 bits = (u32)header[28]; - u32 dataOffset = (u32)header[10]; - - assertMsg(bits == 24, "Invalid bits per pixel in .bmp file - expected 24!"); - - o_texture.setSize(width, height, TEX_TYPE_RGB); - printf("BMPLoader - width: %d | height: %d | bits: %d\n", width, height, bits); - - u64 rowPadded = (width * 3 + 3) & (~3); - - unsigned char row[rowPadded]; - - //Offset file stream to raster data - fseek(file, dataOffset, SEEK_SET); - - u32 x = 0; - for (u32 i = 0; i < height; i++) - { - fread(&row, sizeof(unsigned char), rowPadded, file); - for (u32 j = 0; j < width * 3; j += 3) - { - // Convert (B, G, R) to (R, G, B) - o_texture.setData(x, row[j + 2]); - o_texture.setData(x + 1, row[j + 1]); - o_texture.setData(x + 2, row[j]); - x += 3; - } - } - delete[] path; - fclose(file); -} diff --git a/src/engine/loaders/dff_loader.cpp b/src/engine/loaders/dff_loader.cpp deleted file mode 100644 index 66eb7d8..0000000 --- a/src/engine/loaders/dff_loader.cpp +++ /dev/null @@ -1,413 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -/* -* NOTICE: Based on -* https://github.com/mrqo/rw_parse/blob/master/rw_utils/rw_utils.cpp -* rw_utils.cpp Written by Marek Iwaniuk (c). -* Dff structure documentation http://www.chronetal.co.uk/gta/index.php?page=dff -* Created on 02/04/2017 (MM/DD/YYYY) -*/ - -#include "../include/loaders/dff_loader.hpp" -#include "../include/utils/debug.hpp" -#include "../include/utils/math.hpp" -#include "../include/utils/string.hpp" -#include - -// ---- -// Constructors/Destructors -// ---- - -DffLoader::DffLoader() {} - -DffLoader::~DffLoader() {} - -// ---- -// Methods -// ---- - -void DffLoader::load(MeshFrame *o_result, char *t_filename, float t_scale, u8 t_invertT) -{ - consoleLog("Loading dff file"); - char *path = String::createConcatenated("host:", t_filename); - FILE *file = fopen(path, "rb"); - assertMsg(file != NULL, "Failed to load .dff file!"); - fseek(file, 0L, SEEK_END); - long fileSize = ftell(file); - u8 data[fileSize]; - rewind(file); - fread(&data, sizeof(u8), fileSize, file); - fclose(file); - serialize(o_result, t_invertT, data, t_scale); - o_result->calculateBoundingBoxes(); - delete[] path; - consoleLog("Dff file loaded!"); -} - -// void DffLoader::im_not_used_anywhere(MeshFrame *o_result, char *t_filename, float t_scale, u8 t_invertT) -// { -// PRINT_LOG("Loading dff file"); -// char *path = String::createConcatenated("host:", t_filename); -// FILE *file = fopen(path, "rb"); -// if (file == NULL) -// PRINT_ERR("Failed to load .dff file!"); -// fseek(file, 0L, SEEK_END); -// long fileSize = ftell(file); -// u8 data[fileSize]; -// rewind(file); -// fread(&data, sizeof(u8), fileSize, file); -// fclose(file); -// serialize(o_result, t_invertT, data, t_scale); -// o_result->calculateBoundingBoxes(); -// delete[] path; -// PRINT_LOG("Dff file loaded!"); -// } - -void DffLoader::serialize(MeshFrame *o_result, u8 t_invertT, u8 *t_data, float t_scale) -{ - u32 ptrPos = 0; - - // readSectionHeader(t_clump, t_data, ptrPos); - // readSectionHeader(t_clump.data, t_data, ptrPos); - // readClumpData(t_clump.data, t_data, ptrPos); - for (u8 i = 0; i < 3 * 3; i++) - ptrPos += sizeof(u32); - - // readSectionHeader(t_clump.frameList, t_data, ptrPos); - // readSectionHeader(t_clump.frameList.data, t_data, ptrPos); - // readFrameListData(t_clump.frameList.data, t_data, ptrPos); - // t_clump.frameList.extensions = new RwFrameListExtension[t_clump.frameList.data.frameCount]; - // for (u32 i = 0; i < t_clump.frameList.data.frameCount; i++) - // { - // readSectionHeader(t_clump.frameList.extensions[i], t_data, ptrPos); - // ptrPos += t_clump.frameList.extensions[i].sectionSize; - // } - RwSectionHeader header1 = RwSectionHeader(); - readSectionHeader(header1, t_data, ptrPos); - ptrPos += header1.sectionSize; - - // readSectionHeader(t_clump.geometryList, t_data, ptrPos); - // readSectionHeader(t_clump.geometryList.data, t_data, ptrPos); - for (u8 i = 0; i < 2 * 3; i++) - ptrPos += sizeof(u32); - - // readGeometryListData(t_clump.geometryList.data, t_data, ptrPos); - ptrPos += sizeof(u32); - - // readSectionHeader(geometry, t_data, ptrPos); - // readSectionHeader(geometry.data, t_data, ptrPos); - for (size_t i = 0; i < 2 * 3; i++) - ptrPos += sizeof(u32); - - readGeometryData(o_result, t_invertT, t_data, ptrPos, t_scale); - - // readSectionHeader(geometry.materialList, t_data, ptrPos); - // readSectionHeader(geometry.materialList.data, t_data, ptrPos); - for (size_t i = 0; i < 2 * 3; i++) - ptrPos += sizeof(u32); - - RwMaterialListData materialListData = RwMaterialListData(); - readMaterialListData(materialListData, t_data, ptrPos); - u32 materialCount = materialListData.materialCount; - - char **materialNames = new char *[materialCount]; - for (u32 j = 0; j < materialCount; j++) - { - // readSectionHeader(geometry.materialList.materials[j], t_data, ptrPos); - for (size_t i = 0; i < 3; i++) - ptrPos += sizeof(u32); - - // RwMaterialData materialData = RwMaterialData(); - // readSectionHeader(materialData, t_data, ptrPos); - // readMaterialData(materialData, t_data, ptrPos); - RwSectionHeader header1 = RwSectionHeader(); - readSectionHeader(header1, t_data, ptrPos); - ptrPos += header1.sectionSize; - - // for (u32 k = 0; k < textureCount; k++) - // { - - // readSectionHeader(geometry.materialList.materials[j].textures[k], t_data, ptrPos); - // readSectionHeader(geometry.materialList.materials[j].textures[k].data, t_data, ptrPos); - for (size_t i = 0; i < 2 * 3; i++) - ptrPos += sizeof(u32); - - // readTextureData(geometry.materialList.materials[j].textures[k].data, t_data, ptrPos); - ptrPos += sizeof(u32); - - RwSectionHeader header1b = RwSectionHeader(); - readSectionHeader(header1b, t_data, ptrPos); - materialNames[j] = readString(t_data, ptrPos, header1b.sectionSize); - - // readSectionHeader(geometry.materialList.materials[j].textures[k].textureAlphaName, t_data, ptrPos); - // readStringData(geometry.materialList.materials[j].textures[k].textureAlphaName, t_data, ptrPos); - RwSectionHeader header2 = RwSectionHeader(); - readSectionHeader(header2, t_data, ptrPos); - ptrPos += header2.sectionSize; - - // The content of extension is Sky Mipmap Val - // readSectionHeader(geometry.materialList.materials[j].textures[k].extension, t_data, ptrPos); - RwSectionHeader header3 = RwSectionHeader(); - readSectionHeader(header3, t_data, ptrPos); - ptrPos += header3.sectionSize; - // } - - // Probably always void extension - // readSectionHeader(geometry.materialList.materials[j].extension, t_data, ptrPos); - RwSectionHeader header4 = RwSectionHeader(); - readSectionHeader(header4, t_data, ptrPos); - ptrPos += header4.sectionSize; - } - // delete[] materialNames; // TODO - - // For Bin Mesh aka Material split - // readSectionHeader(geometry.extension, t_data, ptrPos); - for (size_t i = 0; i < 3; i++) - ptrPos += sizeof(u32); - readGeometryExtension(o_result, materialNames, t_data, ptrPos); - - for (size_t i = 0; i < materialCount; i++) - delete[] materialNames[i]; - - delete materialNames; - - // ptrPos += geometry.extension.sectionSize; - - // readSectionHeader(t_clump.atomic, t_data, ptrPos); - // readSectionHeader(t_clump.atomic.data, t_data, ptrPos); - // ptrPos += t_clump.atomic.data.sectionSize; -} - -void DffLoader::readSectionHeader(RwSectionHeader &t_sh, u8 *t_buffer, u32 &t_ptrPos) -{ - t_sh.sectionType = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos); - t_sh.sectionSize = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos); - t_sh.versionNumber = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos); -} - -// --- - -void DffLoader::readFrameListData(RwFrameListData &t_frd, u8 *t_buffer, u32 &t_ptrPos) -{ - // t_frd.frameCount = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos); - // printf("Frame count:%d\n", t_frd.frameCount); - // t_frd.frameInformation = new RwFrameListChunk[t_frd.frameCount]; - - // for (u32 i = 0; i < t_frd.frameCount; i++) - // { - // t_frd.frameInformation[i].rotationalMatrix = new float[t_frd.ROT_MAT_DIM]; - // for (u32 j = 0; j < t_frd.ROT_MAT_DIM; j++) - // t_frd.frameInformation[i].rotationalMatrix[j] = readFloatFromArrayLE(t_buffer, t_ptrPos); - - // t_frd.frameInformation[i].coordinatesOffsetX = readFloatFromArrayLE(t_buffer, t_ptrPos); - // t_frd.frameInformation[i].coordinatesOffsetY = readFloatFromArrayLE(t_buffer, t_ptrPos); - // t_frd.frameInformation[i].coordinatesOffsetZ = readFloatFromArrayLE(t_buffer, t_ptrPos); - // t_frd.frameInformation[i] - // .parentFrame = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos); - // t_frd.frameInformation[i].unk1 = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos); - // } -} - -void DffLoader::readClumpData(RwClumpData &t_cd, u8 *t_buffer, u32 &t_ptrPos) -{ - // t_cd.objectCount = readDwordFromArrayLE(t_buffer, t_ptrPos); - // t_cd.unk1 = readDwordFromArrayLE(t_buffer, t_ptrPos); - // t_cd.unk2 = readDwordFromArrayLE(t_buffer, t_ptrPos); -} - -void DffLoader::readGeometryListData(RwGeometryListData &t_gld, u8 *t_buffer, u32 &t_ptrPos) -{ - // t_gld.geometryCount = readDwordFromArrayLE(t_buffer, t_ptrPos); -} - -void DffLoader::readGeometryExtension(MeshFrame *o_frame, char **materialNames, u8 *t_buffer, u32 &t_ptrPos) -{ - for (u8 i = 0; i < 3; i++) - t_ptrPos += sizeof(u32); - - RwMaterialSplitHeader header = RwMaterialSplitHeader(); - header.triangleStrip = readDwordFromArrayLE(t_buffer, t_ptrPos); - header.splitCount = readDwordFromArrayLE(t_buffer, t_ptrPos); - header.faceCount = readDwordFromArrayLE(t_buffer, t_ptrPos); - - o_frame->allocateMaterials(header.splitCount); - for (u32 i = 0; i < header.splitCount; i++) - { - u32 facesCount = readDwordFromArrayLE(t_buffer, t_ptrPos); - u32 materialIndex = readDwordFromArrayLE(t_buffer, t_ptrPos); - o_frame->getMaterial(i).setSTsPresent(true); - o_frame->getMaterial(i).setNormalsPresent(true); - o_frame->getMaterial(i).allocateFaces(facesCount); - o_frame->getMaterial(i).setName(materialNames[materialIndex]); - for (u32 j = 0; j < facesCount; j++) - { - u32 vertex1 = readDwordFromArrayLE(t_buffer, t_ptrPos); - // Inverted insertind due to backface culling - o_frame->getMaterial(i).setVertexFace(facesCount - 1 - j, vertex1); - o_frame->getMaterial(i).setNormalFace(facesCount - 1 - j, vertex1); - o_frame->getMaterial(i).setSTFace(facesCount - 1 - j, vertex1); - } - } -} - -void DffLoader::readGeometryData(MeshFrame *o_frame, u8 t_invertT, u8 *t_buffer, u32 &t_ptrPos, float t_scale) -{ - Vector3 tempVec = Vector3(); - Point tempPoint = Point(); - - RwGeometryDataHeader header; - header.flags = readWordFromArrayLE(t_buffer, t_ptrPos); - header.unk1 = readWordFromArrayLE(t_buffer, t_ptrPos); - header.triangleCount = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos); - header.vertexCount = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos); - header.morphTargetCount = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos); - - if (false) - { // version equals 4099 according to old documentation, disabled as for now - readDwordFromArrayLE(t_buffer, t_ptrPos); // ambient - readDwordFromArrayLE(t_buffer, t_ptrPos); // diffuse - readDwordFromArrayLE(t_buffer, t_ptrPos); // specular - } - - if (header.flags & rwOBJECT_VERTEX_PRELIT) - for (u32 i = 0; i < header.vertexCount; i++) - { - readByteFromArrayLE(t_buffer, t_ptrPos); // r - readByteFromArrayLE(t_buffer, t_ptrPos); // g - readByteFromArrayLE(t_buffer, t_ptrPos); // b - readByteFromArrayLE(t_buffer, t_ptrPos); // a - } - - if (header.flags & rwOBJECT_VERTEX_TEXTURED) - { - o_frame->allocateSTs(header.vertexCount); - for (u32 i = 0; i < header.vertexCount; i++) - { - float u = readFloatFromArrayLE(t_buffer, t_ptrPos); - float v = readFloatFromArrayLE(t_buffer, t_ptrPos); - tempPoint.set(u, v); - if (t_invertT) - tempPoint.y = 1.0F - tempPoint.y; - o_frame->setST(i, tempPoint); - } - } - - for (u32 i = 0; i < header.triangleCount; i++) - { - readWordFromArrayLE(t_buffer, t_ptrPos); // vert2 - readWordFromArrayLE(t_buffer, t_ptrPos); // vert1 - readWordFromArrayLE(t_buffer, t_ptrPos); // flags - readWordFromArrayLE(t_buffer, t_ptrPos); // vert3 - } - - for (size_t i = 0; i < 6; i++) - t_ptrPos += sizeof(u32); - // t_gd.nonameInfo.boundingSphereX = readFloatFromArrayLE(t_buffer, t_ptrPos); - // t_gd.nonameInfo.boundingSphereY = readFloatFromArrayLE(t_buffer, t_ptrPos); - // t_gd.nonameInfo.boundingSphereZ = readFloatFromArrayLE(t_buffer, t_ptrPos); - // t_gd.nonameInfo.boundingSphereR = readFloatFromArrayLE(t_buffer, t_ptrPos); - // t_gd.nonameInfo.hasPosition = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos); - // t_gd.nonameInfo.hasNormals = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos); - - o_frame->allocateVertices(header.vertexCount); - for (u32 i = 0; i < header.vertexCount; i++) - { - float x = readFloatFromArrayLE(t_buffer, t_ptrPos) * t_scale; - float y = readFloatFromArrayLE(t_buffer, t_ptrPos) * t_scale; - float z = readFloatFromArrayLE(t_buffer, t_ptrPos) * t_scale; - tempVec.set(x, y, z); - o_frame->setVertex(i, tempVec); - } - - o_frame->allocateNormals(header.vertexCount); - for (u32 i = 0; i < header.vertexCount; i++) - { - float x = readFloatFromArrayLE(t_buffer, t_ptrPos); - float y = readFloatFromArrayLE(t_buffer, t_ptrPos); - float z = readFloatFromArrayLE(t_buffer, t_ptrPos); - tempVec.set(x, y, z); - o_frame->setNormal(i, tempVec); - } -} - -void DffLoader::readMaterialListData(RwMaterialListData &t_mld, u8 *t_buffer, u32 &t_ptrPos) -{ - t_mld.materialCount = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos); - // t_mld.arrayOfUnks = new u32[t_mld.materialCount]; - for (u32 i = 0; i < t_mld.materialCount; i++) - readDwordFromArrayLE(t_buffer, t_ptrPos); - // t_mld.arrayOfUnks[i] = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos); -} - -void DffLoader::readMaterialData(RwMaterialData &t_md, u8 *t_buffer, u32 &t_ptrPos) -{ - t_md.unk1 = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos); - t_md.R = readByteFromArrayLE(t_buffer, t_ptrPos); - t_md.G = readByteFromArrayLE(t_buffer, t_ptrPos); - t_md.B = readByteFromArrayLE(t_buffer, t_ptrPos); - t_md.A = readByteFromArrayLE(t_buffer, t_ptrPos); - t_md.unk2 = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos); - t_md.textureCount = DffLoader::readDwordFromArrayLE(t_buffer, t_ptrPos); - t_md.unkPosX = readFloatFromArrayLE(t_buffer, t_ptrPos); - t_md.unkPosY = readFloatFromArrayLE(t_buffer, t_ptrPos); - t_md.unkPosZ = readFloatFromArrayLE(t_buffer, t_ptrPos); -} - -void DffLoader::readTextureData(RwTextureData &t_td, u8 *t_buffer, u32 &t_ptrPos) -{ - t_td.textureFilterModeFlags = readWordFromArrayLE(t_buffer, t_ptrPos); - t_td.unk = readWordFromArrayLE(t_buffer, t_ptrPos); -} - -void DffLoader::readStringData(RwString &t_s, u8 *t_buffer, u32 &t_ptrPos) -{ - t_s.text = readString(t_buffer, t_ptrPos, t_s.sectionSize); -} - -// --- - -u8 DffLoader::readByteFromArrayLE(u8 *t_buffer, u32 &t_ptrPos) -{ - return t_buffer[t_ptrPos++]; -} - -u16 DffLoader::readWordFromArrayLE(u8 *t_buffer, u32 &t_ptrPos) -{ - u16 res = (t_buffer[t_ptrPos + 1] << 8) + (t_buffer[t_ptrPos]); - t_ptrPos += sizeof(u16); - return res; -} - -u32 DffLoader::readDwordFromArrayLE(u8 *t_buffer, u32 &t_ptrPos) -{ - u32 res = (t_buffer[t_ptrPos + 3] << 24) + (t_buffer[t_ptrPos + 2] << 16) + (t_buffer[t_ptrPos + 1] << 8) + (t_buffer[t_ptrPos]); - t_ptrPos += sizeof(u32); - return res; -} - -float DffLoader::readFloatFromArrayLE(u8 *t_buffer, u32 &t_ptrPos) -{ - float res; - memcpy(&res, t_buffer + t_ptrPos, sizeof(float)); - t_ptrPos += sizeof(float); - return res; -} - -char *DffLoader::readString(u8 *t_buffer, u32 &t_ptrPos, u32 t_dataSize) -{ - u32 strLength = String::getLength((char *)&t_buffer[t_ptrPos]); - char *result = new char[strLength + 1]; - for (u32 i = 0; i < strLength; i++) - result[i] = (char)t_buffer[t_ptrPos + i]; - result[strLength] = '\0'; - t_ptrPos += t_dataSize; - return result; -} diff --git a/src/engine/loaders/md2_loader.cpp b/src/engine/loaders/md2_loader.cpp deleted file mode 100644 index 24f2698..0000000 --- a/src/engine/loaders/md2_loader.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "../include/loaders/md2_loader.hpp" - -#include "../include/utils/string.hpp" -#include "../include/utils/debug.hpp" -#include "../include/loaders/anorms.hpp" -#include "../include/models/math/vector3.hpp" -#include "../include/models/math/point.hpp" -#include - -// ---- -// Constructors/Destructors -// ---- - -MD2Loader::MD2Loader() {} - -MD2Loader::~MD2Loader() {} - -// ---- -// Methods -// ---- - -int MEM_fread(char *buf, size_t size, size_t n, const FILE *f) -{ - memcpy(buf, f, size * n); - f += size * n; - return n; -} - -/** - * Sandro: Possible PS2SDK bug here? - * When I wanted to fopen() -> fread() -> allocate frames memory (vertices etc) -> fclose() = I had in about 10x errors in console - * When I did fopen() -> fread() -> fclose() -> allocate frames memory = I had no errors 🤨 - * It looks like memory allocation during fopen()-fread()-fclose() is broken. - */ -MeshFrame *MD2Loader::load(u32 &o_framesCount, char *t_subpath, char *t_nameWithoutExtension, float t_scale, u8 t_invertT) -{ - consoleLog("Loading new MD2 file"); - char *part1 = String::createConcatenated(t_subpath, t_nameWithoutExtension); - char *part2 = String::createConcatenated("host:", part1); - char *finalPath = String::createConcatenated(part2, ".md2"); // "folder/object.md2" - delete[] part1; - delete[] part2; - md2_t header; - - FILE *file = fopen(finalPath, "rb"); - assertMsg(file != NULL, "Failed to load .md2 file!"); - - fread((char *)&header, sizeof(md2_t), 1, file); - - assertMsg((header.ident == MD2_IDENT) && (header.version == MD2_VERSION), "This MD2 file was not in correct format!"); - - u32 framesCount = header.num_frames; - u32 vertexCount = header.num_xyz; - u32 stsCount = header.num_st; - u32 trianglesCount = header.num_tris; - - char framesBuffer[framesCount * header.framesize]; - fseek(file, header.ofs_frames, SEEK_SET); - fread(&framesBuffer, framesCount * header.framesize, 1, file); - - char stsBuffer[stsCount * sizeof(texCoord_t)]; - fseek(file, header.ofs_st, SEEK_SET); - fread(&stsBuffer, stsCount * sizeof(texCoord_t), 1, file); - - char trianglesBuffer[trianglesCount * sizeof(triangle_t)]; - fseek(file, header.ofs_tris, SEEK_SET); - fread(&trianglesBuffer, trianglesCount * sizeof(triangle_t), 1, file); - - fclose(file); - - MeshFrame *resultFrames = new MeshFrame[framesCount]; - - frame_t *frame; - Vector3 tempVec = Vector3(); - for (u32 j = 0; j < framesCount; j++) - { - resultFrames[j].allocateVertices(vertexCount); - resultFrames[j].allocateNormals(vertexCount); // can be optimized - resultFrames[j].allocateSTs(stsCount); - resultFrames[j].allocateMaterials(1); - resultFrames[j].getMaterial(0).allocateFaces(trianglesCount * 3); - resultFrames[j].getMaterial(0).setName(t_nameWithoutExtension); - frame = (frame_t *)&framesBuffer[header.framesize * j]; - for (u32 i = 0; i < vertexCount; i++) - { - tempVec.set( - ((frame->verts[i].v[0] * frame->scale[0]) + frame->translate[0]) * t_scale, - ((frame->verts[i].v[1] * frame->scale[1]) + frame->translate[1]) * t_scale, - ((frame->verts[i].v[2] * frame->scale[2]) + frame->translate[2]) * t_scale); - resultFrames[j].setVertex(i, tempVec); - - tempVec.set( - ANORMS[frame->verts[i].lightnormalindex][0], - ANORMS[frame->verts[i].lightnormalindex][1], - ANORMS[frame->verts[i].lightnormalindex][2]); - resultFrames[j].setNormal(i, tempVec); - } - } - - Point tempPoint = Point(); - texCoord_t *texCoord; - for (u32 i = 0; i < stsCount; i++) - { - texCoord = (texCoord_t *)&stsBuffer[sizeof(texCoord_t) * i]; - tempPoint.set( - (float)texCoord->s / header.skinwidth, - (float)texCoord->t / header.skinheight); - if (t_invertT) - tempPoint.y = 1.0F - tempPoint.y; - for (u32 j = 0; j < framesCount; j++) - resultFrames[j].setST(i, tempPoint); - } - - triangle_t *triangle; - for (u32 i = 0; i < trianglesCount; i++) - { - triangle = (triangle_t *)&trianglesBuffer[sizeof(triangle_t) * i]; - for (u8 j = 0; j < 3; j++) - { - for (u32 x = 0; x < framesCount; x++) - { - resultFrames[x].getMaterial(0).setSTsPresent(true); - resultFrames[x].getMaterial(0).setNormalsPresent(true); - resultFrames[x].getMaterial(0).setVertexFace((i * 3) + j, triangle->index_xyz[j]); - resultFrames[x].getMaterial(0).setSTFace((i * 3) + j, triangle->index_st[j]); - resultFrames[x].getMaterial(0).setNormalFace((i * 3) + j, triangle->index_xyz[j]); - } - } - } - - consoleLog("MD2 file loaded!"); - delete[] finalPath; - o_framesCount = framesCount; - for (u32 i = 0; i < framesCount; i++) - resultFrames[i].calculateBoundingBoxes(); - return resultFrames; -} diff --git a/src/engine/loaders/obj_loader.cpp b/src/engine/loaders/obj_loader.cpp deleted file mode 100644 index 4d7a38b..0000000 --- a/src/engine/loaders/obj_loader.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "../include/loaders/obj_loader.hpp" - -#include "../include/utils/debug.hpp" -#include "../include/utils/string.hpp" -#include - -// ---- -// Constructors/Destructors -// ---- - -ObjLoader::ObjLoader() {} - -ObjLoader::~ObjLoader() {} - -// ---- -// Methods -// ---- - -void ObjLoader::load(MeshFrame *o_result, char *t_filename, float t_scale, u8 t_invertT) -{ - char *path = String::createConcatenated("host:", t_filename); - FILE *file = fopen(path, "rb"); - assertMsg(file != NULL, "Failed to load .obj file!"); - allocateObjMemory(file, o_result); - fseek(file, 0, SEEK_SET); - u32 verticesI = 0, cordsI = 0, normalsI = 0, faceI = 0, vertexIndex[3], coordIndex[3], normalIndex[3]; - s16 materialsI = -1; - Vector3 vector = Vector3(); - Point point = Point(); - while (1) - { - char lineHeader[128]; // read the first word of the line - int res = fscanf(file, "%s", lineHeader); - if (res != EOF) - { - if (strcmp(lineHeader, "v") == 0) - { - fscanf(file, "%f %f %f\n", &vector.x, &vector.y, &vector.z); - o_result->setVertex(verticesI++, vector * t_scale); - } - else if (strcmp(lineHeader, "vt") == 0) - { - fscanf(file, "%f %f\n", &point.x, &point.y); - if (t_invertT) - point.y = 1.0F - point.y; - o_result->setST(cordsI++, point); - } - else if (strcmp(lineHeader, "vn") == 0) - { - fscanf(file, "%f %f %f\n", &vector.x, &vector.y, &vector.z); - o_result->setNormal(normalsI++, vector); - } - else if (strcmp(lineHeader, "usemtl") == 0) - { - char temp[30]; - fscanf(file, "%s\n", temp); - o_result->getMaterial(++materialsI).setName(temp); - faceI = 0; - } - else if (strcmp(lineHeader, "f") == 0) - { - int *x = &res; // random assignment, to disable compilation warning - fpos_t start; - fgetpos(file, &start); - int matches = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n", x, x, x, x, x, x, x, x, x); - fsetpos(file, &start); - int newerMatches = 0; - switch (matches) - { - /** Vs, VTs and VNs all set */ - case 9: - { - fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n", - &vertexIndex[0], &coordIndex[0], &normalIndex[0], - &vertexIndex[1], &coordIndex[1], &normalIndex[1], - &vertexIndex[2], &coordIndex[2], &normalIndex[2]); - } - break; - /** Loaded only two digits (V, VT) succesfuly. Not setting VN. */ - case 3: - { - fscanf(file, "%d/%d/ %d/%d/ %d/%d/\n", - &vertexIndex[0], &coordIndex[0], - &vertexIndex[1], &coordIndex[1], - &vertexIndex[2], &coordIndex[2]); - } - break; - /** Only V set. Checking for existance of VT or VN. */ - case 1: - { - /** Check for existance of V/// configuration.. */ - newerMatches = fscanf(file, "%d// %d// %d//\n", x, x, x); - fsetpos(file, &start); - if (newerMatches == 3) - { - /** Configuration confirmed. */ - fscanf(file, "%d// %d// %d//\n", &vertexIndex[0], &vertexIndex[1], &vertexIndex[2]); - } - else - { - /** Failed, checking configuration V//VN */ - newerMatches = fscanf(file, "%d//%d %d//%d %d//%d", x, x, x, x, x, x); - fsetpos(file, &start); - assertMsg(newerMatches == 6, "Unknown .obj face for .obj file!"); - /** Configuration confirmed. */ - newerMatches = fscanf(file, "%d//%d %d//%d %d//%d", - &vertexIndex[0], &normalIndex[0], - &vertexIndex[1], &normalIndex[1], - &vertexIndex[2], &normalIndex[2]); - } - break; - } - break; - default: - { - assertMsg(true == false, "Unknown faces format in .obj file!"); - break; - } - } - - if (matches == 9 || matches == 2 || matches == 1) - { - o_result->getMaterial(materialsI).setVertexFace(faceI, vertexIndex[0] - 1); - o_result->getMaterial(materialsI).setVertexFace(faceI + 1, vertexIndex[1] - 1); - o_result->getMaterial(materialsI).setVertexFace(faceI + 2, vertexIndex[2] - 1); - } - if (matches == 9 || matches == 2) - { - o_result->getMaterial(materialsI).setSTFace(faceI, coordIndex[0] - 1); - o_result->getMaterial(materialsI).setSTFace(faceI + 1, coordIndex[1] - 1); - o_result->getMaterial(materialsI).setSTFace(faceI + 2, coordIndex[2] - 1); - o_result->getMaterial(materialsI).setSTsPresent(true); - } - - if (matches == 9) - { - o_result->getMaterial(materialsI).setNormalFace(faceI, normalIndex[0] - 1); - o_result->getMaterial(materialsI).setNormalFace(faceI + 1, normalIndex[1] - 1); - o_result->getMaterial(materialsI).setNormalFace(faceI + 2, normalIndex[2] - 1); - o_result->getMaterial(materialsI).setNormalsPresent(true); - faceI += 3; - } - else if (matches == 2) - { - faceI += 2; - } - else if (matches == 1) - { - if (newerMatches == 3) - { - faceI += 1; - } - else if (newerMatches == 6) - { - o_result->getMaterial(materialsI).setNormalFace(faceI, normalIndex[0] - 1); - o_result->getMaterial(materialsI).setNormalFace(faceI + 1, normalIndex[1] - 1); - o_result->getMaterial(materialsI).setNormalFace(faceI + 2, normalIndex[2] - 1); - o_result->getMaterial(materialsI).setNormalsPresent(true); - faceI += 2; - } - } - } - } - else - break; - } - - o_result->calculateBoundingBoxes(); - fclose(file); - delete[] path; -} - -/** Calculate how many vertices(v), coordinates(vt), normals(vn) and faces(f) have .obj file */ -void ObjLoader::allocateObjMemory(FILE *t_file, MeshFrame *o_result) -{ - u32 vertexCount = 0; - u32 stsCount = 0; - u32 normalsCount = 0; - u32 materialsCount = 0; - - while (1) - { - char lineHeader[128]; - int res = fscanf(t_file, "%s", lineHeader); - if (res != EOF) - { - if (strcmp(lineHeader, "v") == 0) - vertexCount += 1; - else if (strcmp(lineHeader, "vt") == 0) - stsCount += 1; - else if (strcmp(lineHeader, "vn") == 0) - normalsCount += 1; - else if (strcmp(lineHeader, "usemtl") == 0) - materialsCount += 1; - } - else - break; - } - - o_result->allocateVertices(vertexCount); - o_result->allocateNormals(normalsCount); - o_result->allocateSTs(stsCount); - o_result->allocateMaterials(materialsCount); - - s16 currentMatI = -1; - - fseek(t_file, 0, SEEK_SET); - u32 facesCounter = 0; - while (1) - { - char lineHeader[128]; - int res = fscanf(t_file, "%s", lineHeader); - if (res != EOF) - { - if (strcmp(lineHeader, "usemtl") == 0) - { - if (currentMatI >= 0) // Skip -1 - { - o_result->getMaterial(currentMatI).allocateFaces(facesCounter); - facesCounter = 0; - } - currentMatI++; - } - else if (strcmp(lineHeader, "f") == 0) - facesCounter += 3; - } - else - break; - } - - o_result->getMaterial(currentMatI).allocateFaces(facesCounter); // Allocate last one - - // o_result->isMemoryAllocated = true; -} diff --git a/src/engine/loaders/png_loader.cpp b/src/engine/loaders/png_loader.cpp deleted file mode 100644 index be9eef7..0000000 --- a/src/engine/loaders/png_loader.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "../include/loaders/png_loader.hpp" - -#include "../include/utils/debug.hpp" -#include "../include/utils/string.hpp" -#include -#include - -// ---- -// Constructors/Destructors -// ---- - -PngLoader::PngLoader() {} - -PngLoader::~PngLoader() {} - -// ---- -// Methods -// ---- - -/** - * @param t_name Without extension. Example "skyfall2" - * @param t_extension With dot and extension. Example ".png" - */ -void PngLoader::load(Texture &o_texture, char *t_subfolder, char *t_name, char *t_extension) -{ - char *path_part1 = String::createConcatenated(t_subfolder, t_name); - char *path_part2 = String::createConcatenated("host:", path_part1); - char *path = String::createConcatenated(path_part2, t_extension); - delete[] path_part1; - delete[] path_part2; - - FILE *file = fopen(path, "rb"); - assertMsg(file != NULL, "Failed to open .png file!"); - - png_structp png_ptr; - png_infop info_ptr; - png_uint_32 width, height; - - u32 sig_read = 0, row = 0, i = 0, j = 0; - int bit_depth, color_type, interlace_type; - - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - assertMsg(png_ptr, "PNG read struct init failed!"); - info_ptr = png_create_info_struct(png_ptr); - assertMsg(info_ptr, "PNG info struct init failed!"); - assertMsg(!setjmp(png_jmpbuf(png_ptr)), "PNG reader fatal error!"); - - png_init_io(png_ptr, file); - png_set_sig_bytes(png_ptr, sig_read); - png_read_info(png_ptr, info_ptr); - png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); - png_set_strip_16(png_ptr); - - if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_expand(png_ptr); - - if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) - png_set_expand(png_ptr); - - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) - png_set_tRNS_to_alpha(png_ptr); - - png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); - - png_read_update_info(png_ptr, info_ptr); - - png_byte pngType = png_get_color_type(png_ptr, info_ptr); - TextureType type; - switch (pngType) - { - case PNG_COLOR_TYPE_RGB_ALPHA: - type = TEX_TYPE_RGBA; - break; - case PNG_COLOR_TYPE_RGB: - type = TEX_TYPE_RGB; - break; - default: - assertMsg(true == false, "This png format is not supported! RGB/RGBA only."); - } - - o_texture.setSize(width, height, type); - printf("PNGLoader - width: %d | height: %d\n", width, height); - - size_t row_bytes = png_get_rowbytes(png_ptr, info_ptr); - png_byte *row_pointers[height]; - for (row = 0; row < height; row++) - row_pointers[row] = new png_byte[row_bytes]; - - png_read_image(png_ptr, row_pointers); - - u32 x = 0; - - for (i = 0; i < height; i++) - for (j = 0; j < width; j++) - { - o_texture.setData(x, row_pointers[i][4 * j]); - o_texture.setData(x + 1, row_pointers[i][4 * j + 1]); - o_texture.setData(x + 2, row_pointers[i][4 * j + 2]); - if (type == TEX_TYPE_RGBA) - { - o_texture.setData(x + 3, ((int)row_pointers[i][4 * j + 3] * 128 / 255)); - x += 4; - } - else if (type == TEX_TYPE_RGB) - x += 3; - } - - for (row = 0; row < height; row++) - delete[] row_pointers[row]; - - png_read_end(png_ptr, NULL); - png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); - - delete[] path; - fclose(file); -} diff --git a/src/engine/models/bounding_box.cpp b/src/engine/models/bounding_box.cpp deleted file mode 100644 index 2b22fc9..0000000 --- a/src/engine/models/bounding_box.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Michał Mostowik -*/ - -#include "../include/models/bounding_box.hpp" -#include "../include/utils/debug.hpp" -#include - -/** - * Construct a BoundingBox class - * Allows for user friendly access to bounding box data. - * @param t_vertices Array of 8 Vector3 elements. - */ -BoundingBox::BoundingBox(Vector3 *t_vertices) -{ - //Perform a deep copy of vertex array parameter - memcpy(_vertices, t_vertices, 8 * sizeof(Vector3)); - - //This might be shortened with Vector3 operator overloading, but current - //implementation is more human readable. - _height = _vertices[0].y - _vertices[2].y; - _width = _vertices[0].x - _vertices[4].x; - _depth = _vertices[0].z - _vertices[1].z; - - _centerVector = _vertices[0]; - _centerVector.x += (_width / 2); - _centerVector.y += (_height / 2); - _centerVector.z += (_depth / 2); - - //Z-Axis faces - _frontFace = BoundingBoxFace(_vertices[1], _vertices[7], _vertices[1].z); - _backFace = BoundingBoxFace(_vertices[0], _vertices[6], _vertices[0].z); - //X-Axis faces - _leftFace = BoundingBoxFace(_vertices[0], _vertices[3], _vertices[0].x); - _rightFace = BoundingBoxFace(_vertices[4], _vertices[7], _vertices[4].x); - //Y-Axis faces - _topFace = BoundingBoxFace(_vertices[2], _vertices[7], _vertices[2].y); - _bottomFace = BoundingBoxFace(_vertices[0], _vertices[5], _vertices[0].y); -} - -BoundingBox::~BoundingBox() -{ -} diff --git a/src/engine/models/math/matrix.cpp b/src/engine/models/math/matrix.cpp deleted file mode 100644 index c39ad20..0000000 --- a/src/engine/models/math/matrix.cpp +++ /dev/null @@ -1,371 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "../../include/models/math/matrix.hpp" - -#include "../../include/utils/math.hpp" -#include - -// ---- -// Constructors/Destructors -// ---- - -Matrix::Matrix() -{ - for (u8 i = 0; i < 16; i++) - data[i] = 0.0F; -} - -Matrix::Matrix(const float &m11, const float &m12, const float &m13, const float &m14, - const float &m21, const float &m22, const float &m23, const float &m24, - const float &m31, const float &m32, const float &m33, const float &m34, - const float &m41, const float &m42, const float &m43, const float &m44) -{ - data[0] = m11; - data[1] = m12; - data[2] = m13; - data[3] = m14; - - data[4] = m21; - data[5] = m22; - data[6] = m23; - data[7] = m24; - - data[8] = m31; - data[9] = m32; - data[10] = m33; - data[11] = m34; - - data[12] = m41; - data[13] = m42; - data[14] = m43; - data[15] = m44; -} - -// ---- -// Operators -// ---- - -Vector3 Matrix::operator*(const Vector3 &v) const -{ - float a[4] = {v.x, v.y, v.z, 1.0F}; - float res[4]; - asm volatile( - "lqc2 $vf4, 0x00(%1) \n\t" - "lqc2 $vf5, 0x10(%1) \n\t" - "lqc2 $vf6, 0x20(%1) \n\t" - "lqc2 $vf7, 0x30(%1) \n\t" - "lqc2 $vf8, 0x00(%2) \n\t" - "vmulax.xyzw $ACC, $vf4, $vf8 \n\t" - "vmadday.xyzw $ACC, $vf5, $vf8 \n\t" - "vmaddaz.xyzw $ACC, $vf6, $vf8 \n\t" - "vmaddw.xyzw $vf9, $vf7, $vf8 \n\t" - "sqc2 $vf9, 0x00(%0) \n\t" - : - : "r"(res), "r"(this->data), "r"(a)); - return Vector3(res[0], res[1], res[2]); -} - -// ---- -// Functions -// ---- - -void Matrix::identity() -{ - asm volatile( - "vsub.xyzw $vf4, $vf0, $vf0 \n\t" - "vadd.w $vf4, $vf4, $vf0 \n\t" - "vmr32.xyzw $vf5, $vf4 \n\t" - "vmr32.xyzw $vf6, $vf5 \n\t" - "vmr32.xyzw $vf7, $vf6 \n\t" - "sqc2 $vf4, 0x30(%0) \n\t" - "sqc2 $vf5, 0x20(%0) \n\t" - "sqc2 $vf6, 0x10(%0) \n\t" - "sqc2 $vf7, 0x0(%0) \n\t" - : - : "r"(this->data)); -} - -void Matrix::setPerspective(const ScreenSettings &t_screen) -{ - float fovYdiv2 = Math::HALF_ANG2RAD * t_screen.fov; - float cotFOV = 1.0F / (Math::sin(fovYdiv2) / Math::cos(fovYdiv2)); - float w = cotFOV * (t_screen.width / t_screen.projectionScale) / t_screen.aspectRatio; - float h = cotFOV * (t_screen.height / t_screen.projectionScale); - - this->data[0] = w; - this->data[1] = 0.0F; - this->data[2] = 0.0F; - this->data[3] = 0.0F; - - this->data[4] = 0.0F; - this->data[5] = -h; - this->data[6] = 0.0F; - this->data[7] = 0.0F; - - this->data[8] = 0.0F; - this->data[9] = 0.0F; - this->data[10] = - (t_screen.farPlaneDist + t_screen.nearPlaneDist) / - (t_screen.farPlaneDist - t_screen.nearPlaneDist); - this->data[11] = -1.0F; - - this->data[12] = 0.0F; - this->data[13] = 0.0F; - this->data[14] = - (2.0F * t_screen.farPlaneDist * t_screen.nearPlaneDist) / - (t_screen.farPlaneDist - t_screen.nearPlaneDist); - this->data[15] = 0.0F; -} - -void Matrix::lookAt(const Vector3 &t_position, const Vector3 &t_target) -{ - VECTOR up_vec, view_vec; - VECTOR eye = {t_position.x, t_position.y, t_position.z, 1.0F}; - VECTOR obj = {t_target.x, t_target.y, t_target.z, 1.0F}; - asm volatile( - "lqc2 $vf4, 0x00(%2) # eye \n\t" - "lqc2 $vf5, 0x00(%3) # obj \n\t" - "vsub.xyz $vf7, $vf4, $vf5 # view_vec = $vf7 \n\t" - "vmove.xyzw $vf6, $vf0 \n\t" - "vaddw.y $vf6, $vf0, $vf0 # $vf6 = { 0.0f, 1.0f, 0.0f, 1.0f } \n\t" - "vopmula.xyz $ACC, $vf6, $vf7 \n\t" - "vopmsub.xyz $vf9, $vf7, $vf6 # vec = $vf9 \n\t" - "vopmula.xyz $ACC, $vf7, $vf9 \n\t" - "vopmsub.xyz $vf8, $vf9, $vf7 # up_vec = $vf8 \n\t" - "sqc2 $vf7, 0x00(%0) # view_vec \n\t" - "sqc2 $vf6, 0x00(%1) # up_vec \n\t" - : - : "r"(view_vec), "r"(up_vec), "r"(eye), "r"(obj)); - Matrix temp; - temp.setCamera(eye, view_vec, up_vec); - identity(); - cross(this->data, this->data, temp.data); - - // Vector3 camForward, camUp, camRight; - // Vector3 t_up = Vector3(0.0F, 1.0F, 0.0F); - // camForward = t_position - t_target; - // camForward.normalize(); - // camRight = t_up * camForward; - // camRight.normalize(); - // camUp = camForward * camRight; - - // data[0] = camRight.x; - // data[4] = camRight.y; - // data[8] = camRight.z; - // data[12] = -camRight.innerProduct(t_position); - - // data[1] = camUp.x; - // data[5] = camUp.y; - // data[9] = camUp.z; - // data[13] = -camUp.innerProduct(t_position); - - // data[2] = camForward.x; - // data[6] = camForward.y; - // data[10] = camForward.z; - // data[14] = -camForward.innerProduct(t_position); - - // data[3] = 0; - // data[7] = 0; - // data[11] = 0; - // data[15] = 1; -} - -const void Matrix::print() const -{ - printf("MATRIX(\n%f, %f, %f, %f\n%f, %f, %f, %f\n%f, %f, %f, %f\n%f, %f, %f, %f\n)\n", - data[0], data[1], data[2], data[3], - data[4], data[5], data[6], data[7], - data[8], data[9], data[10], data[11], - data[12], data[13], data[14], data[15]); -} - -// ---- -// Private -// ---- - -void Matrix::rotationX(const float &t_radians) -{ - float c = Math::cos(t_radians); - float s = Math::sin(t_radians); - this->data[5] = c; // 1,1 - this->data[6] = s; // 1,2 - this->data[9] = -s; // 2,1 - this->data[10] = c; // 2,2 -} - -void Matrix::rotationY(const float &t_radians) -{ - float c = Math::cos(t_radians); - float s = Math::sin(t_radians); - this->data[0] = c; // 0,0 - this->data[2] = -s; // 0,3 - this->data[8] = s; // 2,0 - this->data[10] = c; // 2,2 -} - -void Matrix::rotationZ(const float &t_radians) -{ - float c = Math::cos(t_radians); - float s = Math::sin(t_radians); - this->data[0] = c; // 0,0 - this->data[1] = s; // 0,1 - this->data[4] = -s; // 1,0 - this->data[5] = c; // 1,1 -} - -void Matrix::rotationByAngle(const float &t_angle, const Vector3 &t_axis) -{ - Vector3 localAxis = Vector3(t_axis); - localAxis.normalize(); - float x = localAxis.x; - float y = localAxis.y; - float z = localAxis.z; - - float c = Math::cos(t_angle); - float s = Math::sin(t_angle); - - this->data[0] = x * x * (1 - c) + c; - this->data[1] = y * x * (1 - c) + z * s; - this->data[2] = x * z * (1 - c) - y * s; - this->data[3] = 0.0F; - - this->data[4] = x * y * (1 - c) - z * s; - this->data[5] = y * y * (1 - c) + c; - this->data[6] = y * z * (1 - c) + x * s; - this->data[7] = 0.0F; - - this->data[8] = x * z * (1 - c) + y * s; - this->data[9] = y * z * (1 - c) - x * s; - this->data[10] = z * z * (1 - c) + c; - this->data[11] = 0.0F; - - this->data[12] = 0.0F; - this->data[13] = 0.0F; - this->data[14] = 0.0F; - this->data[15] = 1.0F; -} - -void Matrix::translation(const Vector3 &t_val) -{ - this->data[12] = t_val.x; // 3,0 - this->data[13] = t_val.y; // 3,1 - this->data[14] = t_val.z; // 3,2 -} - -void Matrix::setScale(const Vector3 &t_val) -{ - this->data[0] = t_val.x; - this->data[5] = t_val.y; - this->data[10] = t_val.z; - this->data[15] = 1.0F; -} - -void Matrix::setCamera(const float t_pos[4], const float t_vz[4], const float t_vy[4]) -{ - // Matrix $vf4, $vf5, $vf6, $vf7 - // t_pos $vf8 - // t_vz $vf9 - // t_vy $vf10 - // vtmp $vf11 - asm volatile( - "lqc2 $vf9, 0x00(%2) \n\t" - "lqc2 $vf10, 0x00(%3) \n\t" - // mtmp.unit() - "vsub.w $vf5, $vf0, $vf0 # mtmp[1][PW] = 0.0F \n\t" - // vtmp.outerProduct(vy, vz); - "vopmula.xyz $ACC, $vf10, $vf9 \n\t" - "vopmsub.xyz $vf11, $vf9, $vf10 \n\t" - // mtmp[0] = vtmp.normalize(); - "vmul.xyz $vf12, $vf11, $vf11 \n\t" - "vaddy.x $vf12, $vf12, $vf12 \n\t" - "vaddz.x $vf12, $vf12, $vf12 \n\t" - "vrsqrt $Q, $vf0w, $vf12x \n\t" - "vsub.xyzw $vf4, $vf0, $vf0 \n\t" - "vwaitq \n\t" - "vmulq.xyz $vf4, $vf11, $Q \n\t" - // mtmp[2] = vz.normalize(); - "vmul.xyz $vf12, $vf9, $vf9 \n\t" - "vaddy.x $vf12, $vf12, $vf12 \n\t" - "vaddz.x $vf12, $vf12, $vf12 \n\t" - "vrsqrt $Q, $vf0w, $vf12x \n\t" - "vsub.xyzw $vf6, $vf0, $vf0 \n\t" - "vwaitq \n\t" - "vmulq.xyz $vf6, $vf9, $Q \n\t" - // mtmp[1].outerProduct(mtmp[2], mtmp[0]); - "vopmula.xyz $ACC, $vf6, $vf4 \n\t" - "vopmsub.xyz $vf5, $vf4, $vf6 \n\t" - // mtmp.transpose(pos); - "lqc2 $vf7, 0x00(%1) \n\t" - // m = mtmp.inverse(); - "qmfc2.ni $11, $vf0 \n\t" - "qmfc2.ni $8, $vf4 \n\t" - "qmfc2.ni $9, $vf5 \n\t" - "qmfc2.ni $10, $vf6 \n\t" - - "pextlw $12, $9, $8 \n\t" - "pextuw $13, $9, $8 \n\t" - "pextlw $14, $11, $10 \n\t" - "pextuw $15, $11, $10 \n\t" - "pcpyld $8, $14, $12 \n\t" - "pcpyud $9, $12, $14 \n\t" - "pcpyld $10, $15, $13 \n\t" - - "qmtc2.ni $8, $vf16 \n\t" - "qmtc2.ni $9, $vf17 \n\t" - "qmtc2.ni $10, $vf18 \n\t" - "vmulax.xyz $ACC, $vf16, $vf7 \n\t" - "vmadday.xyz $ACC, $vf17, $vf7 \n\t" - "vmaddz.xyz $vf5, $vf18, $vf7 \n\t" - "vsub.xyzw $vf5, $vf0, $vf5 \n\t" - - "sq $8, 0x00(%0) \n\t" - "sq $9, 0x10(%0) \n\t" - "sq $10, 0x20(%0) \n\t" - "sqc2 $vf5, 0x30(%0) \n\t" - : - : "r"(this->data), "r"(t_pos), "r"(t_vz), "r"(t_vy)); -} - -void Matrix::cross(float res[16], const float a[16], const float b[16]) const -{ - asm volatile( - "lqc2 $vf1, 0x00(%1) \n\t" - "lqc2 $vf2, 0x10(%1) \n\t" - "lqc2 $vf3, 0x20(%1) \n\t" - "lqc2 $vf4, 0x30(%1) \n\t" - "lqc2 $vf5, 0x00(%2) \n\t" - "lqc2 $vf6, 0x10(%2) \n\t" - "lqc2 $vf7, 0x20(%2) \n\t" - "lqc2 $vf8, 0x30(%2) \n\t" - "vmulax.xyzw $ACC, $vf5, $vf1 \n\t" - "vmadday.xyzw $ACC, $vf6, $vf1 \n\t" - "vmaddaz.xyzw $ACC, $vf7, $vf1 \n\t" - "vmaddw.xyzw $vf1, $vf8, $vf1 \n\t" - "vmulax.xyzw $ACC, $vf5, $vf2 \n\t" - "vmadday.xyzw $ACC, $vf6, $vf2 \n\t" - "vmaddaz.xyzw $ACC, $vf7, $vf2 \n\t" - "vmaddw.xyzw $vf2, $vf8, $vf2 \n\t" - "vmulax.xyzw $ACC, $vf5, $vf3 \n\t" - "vmadday.xyzw $ACC, $vf6, $vf3 \n\t" - "vmaddaz.xyzw $ACC, $vf7, $vf3 \n\t" - "vmaddw.xyzw $vf3, $vf8, $vf3 \n\t" - "vmulax.xyzw $ACC, $vf5, $vf4 \n\t" - "vmadday.xyzw $ACC, $vf6, $vf4 \n\t" - "vmaddaz.xyzw $ACC, $vf7, $vf4 \n\t" - "vmaddw.xyzw $vf4, $vf8, $vf4 \n\t" - "sqc2 $vf1, 0x00(%0) \n\t" - "sqc2 $vf2, 0x10(%0) \n\t" - "sqc2 $vf3, 0x20(%0) \n\t" - "sqc2 $vf4, 0x30(%0) \n\t" - : - : "r"(res), "r"(b), "r"(a) - : "memory"); -} diff --git a/src/engine/models/math/plane.cpp b/src/engine/models/math/plane.cpp deleted file mode 100644 index bf3394c..0000000 --- a/src/engine/models/math/plane.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "../../include/models/math/plane.hpp" - -#include - -// ---- -// Constructors/Destructors -// ---- - -/** Create empty plane */ -Plane::Plane() { this->distance = 0; } - -/** Create by specyfying 3 points. - * This function assumes that the points - * are given in counter clockwise order - */ -Plane::Plane(Vector3 &a, Vector3 &b, Vector3 &c) { this->update(a, b, c); } - -Plane::~Plane() {} - -// ---- -// Methods -// ---- - -/** Set plane by specyfying 3 points. - * This function assumes that the points - * are given in counter clockwise order - */ -void Plane::update(Vector3 &a, Vector3 &b, Vector3 &c) -{ - Vector3 aux1 = a - b; - Vector3 aux2 = c - b; - this->normal = aux2 * aux1; - this->normal.normalize(); - this->distance = -this->normal.innerProduct(b); -} - -const void Plane::print() const -{ - printf("Plane(Vector3(%f, %f, %f), %f)\n", this->normal.x, this->normal.y, this->normal.z, this->distance); -} diff --git a/src/engine/models/math/point.cpp b/src/engine/models/math/point.cpp deleted file mode 100644 index fa94652..0000000 --- a/src/engine/models/math/point.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "../../include/models/math/point.hpp" -#include "../../include/utils/math.hpp" - -#include - -// ---- -// Constructors/Destructors -// ---- - -/** Create by specifying values */ -Point::Point(const float &t_x, const float &t_y) -{ - x = t_x; - y = t_y; -} - -/** Create with other point values */ -Point::Point(const Point &v) -{ - x = v.x; - y = v.y; -} - -/** Create empty point */ -Point::Point() -{ - x = 0; - y = 0; -} - -Point::~Point() {} - -// ---- -// Methods -// ---- - -void Point::set(const float &t_x, const float &t_y) -{ - x = t_x; - y = t_y; -} - -void Point::set(const Point &v) -{ - x = v.x; - y = v.y; -} - -void Point::rotate(const float &t_angle, const float &t_x, const float &t_y) -{ - float s = Math::sin(t_angle); - float c = Math::cos(t_angle); - - x -= t_x; - y -= t_y; - - float xnew = x * c - y * s; - float ynew = x * s + y * c; - - x = xnew + t_x; - y = ynew + t_y; -} - -const void Point::print() const -{ - printf("Point(%f, %f)\n", x, y); -} diff --git a/src/engine/models/math/vector3.cpp b/src/engine/models/math/vector3.cpp deleted file mode 100644 index 6d71a91..0000000 --- a/src/engine/models/math/vector3.cpp +++ /dev/null @@ -1,254 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "../../include/models/math/vector3.hpp" -#include "../../include/utils/math.hpp" - -// ---- -// Constructors/Destructors -// ---- - -Vector3::Vector3() -{ - x = 0.0F; - y = 0.0F; - z = 0.0F; -} - -// ---- -// Operators -// ---- - -Vector3 Vector3::operator+(const Vector3 &v) const -{ - Vector3 result; - asm volatile( // VU0 Macro program - "lqc2 $vf4, 0x0(%1) \n\t" - "lqc2 $vf5, 0x0(%2) \n\t" - "vadd.xyz $vf6, $vf4, $vf5 \n\t" - "sqc2 $vf6, 0x0(%0) \n\t" - : - : "r"(result.xyz), "r"(this->xyz), "r"(v.xyz)); - return result; -} - -Vector3 Vector3::operator-(const Vector3 &v) const -{ - Vector3 result; - asm volatile( // VU0 Macro program - "lqc2 $vf4, 0x0(%1) \n\t" - "lqc2 $vf5, 0x0(%2) \n\t" - "vsub.xyz $vf6, $vf4, $vf5 \n\t" - "sqc2 $vf6, 0x0(%0) \n\t" - : - : "r"(result.xyz), "r"(this->xyz), "r"(v.xyz)); - return result; -} - -Vector3 Vector3::operator*(const Vector3 &v) const -{ - Vector3 res; - asm volatile( // VU0 Macro program - "lqc2 $vf4, 0x0(%1) \n\t" // $vf4 = this - "lqc2 $vf5, 0x0(%2) \n\t" // $vf5 = v - "vopmula.xyz $ACC, $vf4, $vf5 \n\t" - "vopmsub.xyz $vf8, $vf5, $vf4 \n\t" - "vsub.w $vf8, $vf0, $vf0 \n\t" - "sqc2 $vf8, 0x0(%0) \n\t" // $vf8 = res - : - : "r"(res.xyz), "r"(this->xyz), "r"(v.xyz)); - // result.x = y * v.z - z * v.y; - // result.y = z * v.x - x * v.z; - // result.z = x * v.y - y * v.x; - return res; -} - -Vector3 Vector3::operator*(const float &t) const -{ - Vector3 result; - asm volatile( - "lqc2 $vf4, 0x0(%1) \n\t" - "mfc1 $8, %2 \n\t" - "qmtc2 $8, $vf5 \n\t" - "vmulx.xyz $vf6, $vf4, $vf5 \n\t" - "sqc2 $vf6, 0x0(%0) \n\t" - : - : "r"(result.xyz), "r"(this->xyz), "f"(t)); - return result; -} - -Vector3 Vector3::operator/(const float &t) const -{ - Vector3 result; - result.x = x / t; - result.y = y / t; - result.z = z / t; - return result; -} - -void Vector3::operator+=(const Vector3 &t) -{ - asm volatile( // VU0 Macro program - "lqc2 $vf4, 0x0(%0) \n\t" - "lqc2 $vf5, 0x0(%1) \n\t" - "vadd.xyz $vf4, $vf4, $vf5 \n\t" - "sqc2 $vf4, 0x0(%0) \n\t" - : - : "r"(this->xyz), "r"(t.xyz)); -} - -void Vector3::operator*=(const float &t) -{ - asm volatile( - "lqc2 $vf4, 0x0(%0) \n\t" - "mfc1 $8, %1 \n\t" - "qmtc2 $8, $vf5 \n\t" - "vmulx.xyz $vf4, $vf4, $vf5 \n\t" - "sqc2 $vf4, 0x0(%0) \n\t" - : - : "r"(this->xyz), "f"(t)); -} - -// ---- -// Functions -// ---- - -void Vector3::set(const Vector3 &v) -{ - asm volatile( // VU0 Macro program - "lq $6, 0x0(%1) \n\t" - "sq $6, 0x0(%0) \n\t" - : - : "r"(this->xyz), "r"(v.xyz)); -} - -void Vector3::set(const float &t_x, const float &t_y, const float &t_z) -{ - x = t_x; - y = t_y; - z = t_z; -} - -float Vector3::innerProduct(const Vector3 &v) const -{ - float result; - asm volatile( // VU0 Macro program - "lqc2 $vf4, 0x0(%1) \n\t" - "lqc2 $vf5, 0x0(%2) \n\t" - "vmul.xyz $vf6, $vf4, $vf5 \n\t" - "vaddy.x $vf6, $vf6, $vf6 \n\t" - "vaddz.x $vf6, $vf6, $vf6 \n\t" - "qmfc2 $2, $vf6 \n\t" - "mtc1 $2, %0 \n\t" - : "=f"(result) - : "r"(this->xyz), "r"(v.xyz)); - return result; - // return (x * v.x + y * v.y + z * v.z); -} - -float Vector3::length() const -{ - float result; - asm volatile( // VU0 Macro program - "lqc2 $vf4, 0x0(%1) \n\t" - "vmul.xyz $vf5, $vf4, $vf4 \n\t" - "vaddy.x $vf5, $vf5, $vf5 \n\t" - "vaddz.x $vf5, $vf5, $vf5 \n\t" - "vsqrt $Q , $vf5x \n\t" - "vwaitq \n\t" - "vaddq.x $vf8, $vf0, $Q \n\t" - "qmfc2 $2, $vf8 \n\t" - "mtc1 $2, %0 \n\t" - : "=f"(result) - : "r"(this->xyz)); - return result; - // return Math::sqrt(x * x + y * y + z * z); -} - -void Vector3::normalize() -{ - asm volatile( // VU0 Macro program - "lqc2 $vf4, 0x0(%0) \n\t" - "vmul.xyz $vf5, $vf4, $vf4 \n\t" - "vaddy.x $vf5, $vf5, $vf5 \n\t" - "vaddz.x $vf5, $vf5, $vf5 \n\t" - "vrsqrt $Q, $vf0w, $vf5x \n\t" - "vwaitq \n\t" - "vsub.xyz $vf6, $vf0, $vf0 \n\t" - "vaddw.xyz $vf6, $vf6, $vf4 \n\t" - "vwaitq \n\t" - "vmulq.xyz $vf6, $vf4, $Q \n\t" - "sqc2 $vf6, 0x0(%0) \n\t" - : - : "r"(this->xyz)); -} - -float Vector3::distanceTo(const Vector3 &v) const -{ - register float result; - asm volatile( // VU0 Macro program - "lqc2 $vf4, 0x0(%1) \n\t" - "lqc2 $vf5, 0x0(%2) \n\t" - "vsub.xyz $vf6, $vf4, $vf5 \n\t" - "vmul.xyz $vf7, $vf6, $vf6 \n\t" - "vaddy.x $vf7, $vf7, $vf7 \n\t" - "vaddz.x $vf7, $vf7, $vf7 \n\t" - "vsqrt $Q , $vf7x \n\t" - "vwaitq \n\t" - "vaddq.x $vf8, $vf0, $Q \n\t" - "qmfc2 $2, $vf8 \n\t" - "mtc1 $2, %0 \n\t" - : "=f"(result) - : "r"(this->xyz), "r"(v.xyz)); - return result; - // return Math::sqrt((this->x - v.x) * (this->x - v.x) + - // (this->y - v.y) * (this->y - v.y) + - // (this->z - v.z) * (this->z - v.z)); -} - -u8 Vector3::shouldBeBackfaceCulled(const Vector3 *t_cameraPos, const Vector3 *t_v0, const Vector3 *t_v1, const Vector3 *t_v2) -{ - register float dot; - asm volatile( - "lqc2 $vf4, 0x0(%1) \n\t" // $vf4 = cameraPos - "lqc2 $vf5, 0x0(%2) \n\t" // $vf5 = v0 - "lqc2 $vf6, 0x0(%3) \n\t" // $vf6 = v1 - "lqc2 $vf7, 0x0(%4) \n\t" // $vf7 = v2 - "vsub.xyz $vf8, $vf7, $vf5 \n\t" // $vf8 = $vf7(v2) - $vf5(v0) - "vsub.xyz $vf9, $vf6, $vf5 \n\t" // $vf9 = $vf6(v1) - $vf5(v0) - "vopmula.xyz $ACC, $vf8, $vf9 \n\t" // $vf6 = cross($vf8, $vf9) - "vopmsub.xyz $vf6, $vf9, $vf8 \n\t" - "vsub.w $vf6, $vf6, $vf6 \n\t" - "vsub.xyz $vf7, $vf5, $vf4 \n\t" // $vf7 = $vf5(v0) - $vf4(cameraPos) - "vmul.xyz $vf5, $vf7, $vf6 \n\t" // $vf5 = dot($vf7, $vf6) - "vaddy.x $vf5, $vf5, $vf5 \n\t" - "vaddz.x $vf5, $vf5, $vf5 \n\t" - "qmfc2 $2, $vf5 \n\t" // store result on `dot` variable - "mtc1 $2, %0 \n\t" - : "=f"(dot) - : "r"(t_cameraPos->xyz), "r"(t_v0->xyz), "r"(t_v1->xyz), "r"(t_v2->xyz)); - return dot <= 0.0F; -} - -void Vector3::setByLerp(const Vector3 &t_v1, const Vector3 &t_v2, const float &t_interp, const float &t_scale) -{ - asm volatile( - "lqc2 $vf4, 0x0(%1) \n\t" // $vf4 = v1 - "lqc2 $vf5, 0x0(%2) \n\t" // $vf5 = v2 - "mfc1 $8, %3 \n\t" // $vf6 = t - "qmtc2 $8, $vf6 \n\t" // lerp: - "vsub.xyz $vf7, $vf5, $vf4 \n\t" // $vf7 = v2 - v1 - "vmulx.xyz $vf8, $vf7, $vf6 \n\t" // $vf8 = $vf7 * t - "vadd.xyz $vf9, $vf8, $vf4 \n\t" // $vf9 = $vf8 + $vf4 - "sqc2 $vf9, 0x0(%0) \n\t" // v0 = $vf9 - : - : "r"(&this->xyz), "r"(&t_v1.xyz), "r"(&t_v2.xyz), "f"(t_interp)); - operator*=(t_scale); -} diff --git a/src/engine/models/mesh.cpp b/src/engine/models/mesh.cpp deleted file mode 100644 index 54537b6..0000000 --- a/src/engine/models/mesh.cpp +++ /dev/null @@ -1,386 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "../include/models/mesh.hpp" -#include "../include/loaders/obj_loader.hpp" -#include "../include/loaders/md2_loader.hpp" -#include "../include/loaders/dff_loader.hpp" -#include "../include/loaders/bmp_loader.hpp" -#include "../include/models/texture.hpp" -#include "../include/utils/debug.hpp" -#include "../include/utils/string.hpp" -#include - -// ---- -// Constructors/Destructors -// ---- - -Mesh::Mesh() -{ - id = rand() % 1000000; - shouldBeFrustumCulled = true; - shouldBeBackfaceCulled = false; - shouldBeLighted = false; - _areFramesAllocated = false; - _isMother = false; - scale = 1.0F; - framesCount = 0; - animState.startFrame = 0; - animState.endFrame = 0; - animState.interpolation = 0.0F; - animState.animType = 0; - animState.currentFrame = 0; - animState.stayFrame = 0; - animState.isStayFrameSet = false; - animState.nextFrame = 0; - animState.speed = 0.1F; - setDefaultLODAndClut(); -} - -Mesh::~Mesh() -{ - if (_areFramesAllocated) - delete[] frames; -} - -// ---- -// Methods -// ---- - -void Mesh::loadObj(char *t_subfolder, char *t_objFile, const float &t_scale, const u8 &t_invertT) -{ - ObjLoader loader = ObjLoader(); - framesCount = 1; - frames = new MeshFrame[framesCount]; - _areFramesAllocated = true; - char *part1 = String::createConcatenated(t_subfolder, t_objFile); // "folder/object" - char *finalPath = String::createConcatenated(part1, ".obj"); // "folder/object.obj" - loader.load(&frames[0], finalPath, t_scale, t_invertT); - delete[] part1; - delete[] finalPath; - _isMother = true; -} - -void Mesh::loadObj(char *t_subfolder, char *t_objFile, const float &t_scale, const u32 &t_framesCount, const u8 &t_invertT) -{ - assertMsg(t_framesCount != 0, "Frames count cannot be 0!"); - if (t_framesCount == 1) - loadObj(t_subfolder, t_objFile, t_scale, t_invertT); - else - { - ObjLoader loader = ObjLoader(); - framesCount = t_framesCount; - frames = new MeshFrame[framesCount]; - _areFramesAllocated = true; - char *part1 = String::createConcatenated(t_subfolder, t_objFile); // "folder/object" - char *part2 = String::createConcatenated(part1, "_"); // "folder/object_" - for (u32 i = 0; i < framesCount; i++) - { - char *part3 = String::createU32ToString(i + 1); // 0 -> "1" - char *part4 = String::createWithLeadingZeros(part3); // "000001" - char *part5 = String::createConcatenated(part2, part4); // "folder/object_000001" - char *finalPath = String::createConcatenated(part5, ".obj"); // "folder/object_000001.obj" - loader.load(&frames[i], finalPath, t_scale, t_invertT); - delete[] part3; - delete[] part4; - delete[] part5; - delete[] finalPath; - } - delete[] part2; - delete[] part1; - _isMother = true; - } -} - -void Mesh::loadDff(char *t_subfolder, char *t_dffFile, const float &t_scale, const u8 &t_invertT) -{ - DffLoader loader = DffLoader(); - char *part1 = String::createConcatenated(t_subfolder, t_dffFile); - char *dffPath = String::createConcatenated(part1, ".dff"); - framesCount = 1; - frames = new MeshFrame[1]; - _areFramesAllocated = true; - loader.load(frames, dffPath, t_scale, t_invertT); - delete[] part1; - delete[] dffPath; - _isMother = true; -} - -void Mesh::loadMD2(char *t_subfolder, char *t_md2File, const float &t_scale, const u8 &t_invertT) -{ - MD2Loader loader = MD2Loader(); - frames = loader.load(framesCount, t_subfolder, t_md2File, t_scale, t_invertT); - _isMother = true; -} - -void Mesh::loadFrom(const Mesh &t_mesh) -{ - framesCount = t_mesh.framesCount; - frames = new MeshFrame[framesCount]; - _areFramesAllocated = true; - for (u32 i = 0; i < framesCount; i++) - frames[i].copyFrom(&t_mesh.getFrame(i)); -} - -void Mesh::playAnimation(const u32 &t_startFrame, const u32 &t_endFrame) -{ - assertMsg(framesCount > 0, "Cant play animation, because no mesh data was loaded!"); - assertMsg(framesCount != 1, "Cant play animation, because this mesh have only one frame."); - assertMsg(t_endFrame < framesCount, "End frame value is too high. Valid range: (0, getFramesCount()-1)"); - animState.startFrame = t_startFrame; - animState.endFrame = t_endFrame; - if (animState.currentFrame == t_startFrame) - animState.nextFrame = t_endFrame; - else - animState.nextFrame = t_startFrame; -} - -void Mesh::playAnimation(const u32 &t_startFrame, const u32 &t_endFrame, const u32 &t_stayFrame) -{ - assertMsg(framesCount > 0, "Cant play animation, because no mesh data was loaded!"); - assertMsg(framesCount != 1, "Cant play animation, because this mesh have only one frame."); - assertMsg(t_endFrame < framesCount, "End frame value is too high. Valid range: (0, getFramesCount()-1)"); - animState.startFrame = t_startFrame; - animState.endFrame = t_endFrame; - animState.isStayFrameSet = true; - animState.stayFrame = t_stayFrame; - animState.nextFrame = t_startFrame; -} - -void Mesh::animate() -{ - animState.interpolation += animState.speed; - if (animState.interpolation >= 1.0F) - { - animState.interpolation = 0.0F; - animState.currentFrame = animState.nextFrame; - if (++animState.nextFrame > animState.endFrame) - { - if (animState.isStayFrameSet) - { - animState.isStayFrameSet = false; - animState.nextFrame = animState.stayFrame; - animState.startFrame = animState.stayFrame; - animState.endFrame = animState.stayFrame; - } - else - animState.nextFrame = animState.startFrame; - } - } -} - -u32 Mesh::getDrawData(u32 t_materialIndex, VECTOR *o_vertices, VECTOR *o_normals, VECTOR *o_coordinates, Vector3 &t_cameraPos) -{ - VECTOR ONE_VEC = {1.0F, 1.0F, 1.0F, 1.0F}; - asm volatile( - // VU0 macro program: - // Load vector with 1.0F values to VF21 - "lqc2 $vf21, 0x0(%0) \n\t" // load "one vec" - : - : "r"(ONE_VEC)); - - u32 addedFaces = 0; -#define CURR_FRAME frames[animState.currentFrame] -#define NEXT_FRAME frames[animState.nextFrame] - - MeshMaterial *material = &CURR_FRAME.getMaterial(t_materialIndex); // cache - u32 *vertFaces = material->getVertexFaces(); // cache - u32 *normalFaces = material->getNormalFaces(); // cache - u32 *stFaces = material->getSTFaces(); // cache - Vector3 *verts = CURR_FRAME.getVertices(); // cache - Vector3 *nextVerts = NEXT_FRAME.getVertices(); // cache - Point *sts = CURR_FRAME.getSTs(); // cache - Vector3 *normals = CURR_FRAME.getNormals(); // cache - - for (u32 faceI = 0; faceI < material->getFacesCount(); faceI += 3) - { - if (animState.currentFrame != animState.nextFrame) - { - asm volatile( - // VU0 macro program: - // Calculate lerp() and store data into calc3Vectors - - // Vertex 0 - "lqc2 $vf4, 0x0(%3) \n\t" // $vf4 = v1 - "lqc2 $vf5, 0x0(%6) \n\t" // $vf5 = v2 - "mfc1 $10, %9 \n\t" // $vf6 = t - "qmtc2 $10, $vf6 \n\t" // lerp: - "vsub.xyz $vf7, $vf5, $vf4 \n\t" // $vf7 = v2 - v1 - "vmulx.xyz $vf8, $vf7, $vf6 \n\t" // $vf8 = $vf7 * t - "vadd.xyz $vf9, $vf8, $vf4 \n\t" // $vf9 = $vf8 + $vf4 - "sqc2 $vf9, 0x0(%0) \n\t" // v0 = $vf9 - - // Vertex 1 - "lqc2 $vf4, 0x0(%4) \n\t" // $vf4 = v1 - "lqc2 $vf5, 0x0(%7) \n\t" // $vf5 = v2 - "mfc1 $10, %9 \n\t" // $vf6 = t - "qmtc2 $10, $vf6 \n\t" // lerp: - "vsub.xyz $vf7, $vf5, $vf4 \n\t" // $vf7 = v2 - v1 - "vmulx.xyz $vf8, $vf7, $vf6 \n\t" // $vf8 = $vf7 * t - "vadd.xyz $vf9, $vf8, $vf4 \n\t" // $vf9 = $vf8 + $vf4 - "sqc2 $vf9, 0x0(%1) \n\t" // v0 = $vf9 - - // Vertex 2 - "lqc2 $vf4, 0x0(%5) \n\t" // $vf4 = v1 - "lqc2 $vf5, 0x0(%8) \n\t" // $vf5 = v2 - "mfc1 $10, %9 \n\t" // $vf6 = t - "qmtc2 $10, $vf6 \n\t" // lerp: - "vsub.xyz $vf7, $vf5, $vf4 \n\t" // $vf7 = v2 - v1 - "vmulx.xyz $vf8, $vf7, $vf6 \n\t" // $vf8 = $vf7 * t - "vadd.xyz $vf9, $vf8, $vf4 \n\t" // $vf9 = $vf8 + $vf4 - "sqc2 $vf9, 0x0(%2) \n\t" // v0 = $vf9 - - : - : "r"(calc3Vectors[0].xyz), - "r"(calc3Vectors[1].xyz), - "r"(calc3Vectors[2].xyz), - "r"(verts[vertFaces[faceI]].xyz), - "r"(verts[vertFaces[faceI + 1]].xyz), - "r"(verts[vertFaces[faceI + 2]].xyz), - "r"(nextVerts[vertFaces[faceI]].xyz), - "r"(nextVerts[vertFaces[faceI + 1]].xyz), - "r"(nextVerts[vertFaces[faceI + 2]].xyz), - "f"(animState.interpolation) - : "$10"); - } - else - { - asm volatile( - // VU0 macro program - // Copy 0,1,2 vertices - "lqc2 $vf1, 0x0(%3) \n\t" // load vert - "lqc2 $vf2, 0x0(%4) \n\t" // load normal - "lqc2 $vf3, 0x0(%5) \n\t" // load st - "sqc2 $vf1, 0x0(%0) \n\t" // store vert - "sqc2 $vf2, 0x0(%1) \n\t" // store normal - "sqc2 $vf3, 0x0(%2) \n\t" // store st - : - : "r"(calc3Vectors[0].xyz), - "r"(calc3Vectors[1].xyz), - "r"(calc3Vectors[2].xyz), - "r"(verts[vertFaces[faceI]].xyz), - "r"(verts[vertFaces[faceI + 1]].xyz), - "r"(verts[vertFaces[faceI + 2]].xyz)); - } - - if (!shouldBeBackfaceCulled || - !Vector3::shouldBeBackfaceCulled(&t_cameraPos, &calc3Vectors[2], &calc3Vectors[1], &calc3Vectors[0])) - { - - asm volatile( - // VU0 macro program: - // Copy data and set vert/normal "w" and st "z"+"w" to 1.0F - - // Vertex 0 - "lqc2 $vf1, 0x0(%3) \n\t" // load vert - "lqc2 $vf2, 0x0(%4) \n\t" // load normal - "lqc2 $vf3, 0x0(%5) \n\t" // load st - "vadd.w $vf1, $vf20, $vf21 \n\t" // set vert.w to 1.0F - "vadd.w $vf2, $vf20, $vf21 \n\t" // set normal.W to 1.0F - "vadd.zw $vf3, $vf20, $vf21 \n\t" // set st.zw to 1.0F - "sqc2 $vf1, 0x0(%0) \n\t" // store vert - "sqc2 $vf2, 0x0(%1) \n\t" // store normal - "sqc2 $vf3, 0x0(%2) \n\t" // store st - - // Vertex 1 - "lqc2 $vf1, 0x0(%9) \n\t" // load vert - "lqc2 $vf2, 0x0(%10) \n\t" // load normal - "lqc2 $vf3, 0x0(%11) \n\t" // load st - "vadd.w $vf1, $vf20, $vf21 \n\t" // set vert.w to 1.0F - "vadd.w $vf2, $vf20, $vf21 \n\t" // set normal.W to 1.0F - "vadd.zw $vf3, $vf20, $vf21 \n\t" // set st.zw to 1.0F - "sqc2 $vf1, 0x0(%6) \n\t" // store vert - "sqc2 $vf2, 0x0(%7) \n\t" // store normal - "sqc2 $vf3, 0x0(%8) \n\t" // store st - - // Vertex 2 - "lqc2 $vf1, 0x0(%15) \n\t" // load vert - "lqc2 $vf2, 0x0(%16) \n\t" // load normal - "lqc2 $vf3, 0x0(%17) \n\t" // load st - "vadd.w $vf1, $vf20, $vf21 \n\t" // set vert.w to 1.0F - "vadd.w $vf2, $vf20, $vf21 \n\t" // set normal.W to 1.0F - "vadd.zw $vf3, $vf20, $vf21 \n\t" // set st.zw to 1.0F - "sqc2 $vf1, 0x0(%12) \n\t" // store vert - "sqc2 $vf2, 0x0(%13) \n\t" // store normal - "sqc2 $vf3, 0x0(%14) \n\t" // store st - - : - : "r"(o_vertices[addedFaces]), - "r"(o_normals[addedFaces]), - "r"(o_coordinates[addedFaces]), - "r"(calc3Vectors[0].xyz), - "r"(normals[normalFaces[faceI]].xyz), - "r"(sts[stFaces[faceI]].xy), - "r"(o_vertices[addedFaces + 1]), - "r"(o_normals[addedFaces + 1]), - "r"(o_coordinates[addedFaces + 1]), - "r"(calc3Vectors[1].xyz), - "r"(normals[normalFaces[faceI + 1]].xyz), - "r"(sts[stFaces[faceI + 1]].xy), - "r"(o_vertices[addedFaces + 2]), - "r"(o_normals[addedFaces + 2]), - "r"(o_coordinates[addedFaces + 2]), - "r"(calc3Vectors[2].xyz), - "r"(normals[normalFaces[faceI + 2]].xyz), - "r"(sts[stFaces[faceI + 2]].xy)); - addedFaces += 3; - } - } - return addedFaces; -} - -u8 Mesh::isInFrustum(Plane *t_frustumPlanes) -{ - Vector3 boxCalcTemp; - u8 boxResult = 1, boxIn = 0, boxOut = 0; - const Vector3 *currentBoundingBox = getCurrentBoundingBoxVertices(); - for (int i = 0; i < 6; i++) - { - boxOut = 0; - boxIn = 0; - // for each corner of the box do ... - // get out of the cycle as soon as a box as corners - // both inside and out of the frustum - for (int y = 0; y < 8 && (boxIn == 0 || boxOut == 0); y++) - { - boxCalcTemp.set( - currentBoundingBox[y].x + position.x, - currentBoundingBox[y].y + position.y, - currentBoundingBox[y].z + position.z); - if (t_frustumPlanes[i].distanceTo(boxCalcTemp) < 0) - boxOut++; - else - boxIn++; - } - //if all corners are out - if (boxIn == 0) - return 0; - else if (boxOut) - boxResult = 1; - } - return boxResult; -} - -/** Sets texture level of details settings and CLUT settings */ -void Mesh::setDefaultLODAndClut() -{ - lod.calculation = LOD_USE_K; - lod.max_level = 0; - lod.mag_filter = LOD_MAG_NEAREST; - lod.min_filter = LOD_MIN_NEAREST; - lod.l = 0; - lod.k = 0.0F; - - clut.storage_mode = CLUT_STORAGE_MODE1; - clut.start = 0; - clut.psm = 0; - clut.load_method = CLUT_NO_LOAD; - clut.address = 0; -} diff --git a/src/engine/models/mesh_frame.cpp b/src/engine/models/mesh_frame.cpp deleted file mode 100644 index 258f805..0000000 --- a/src/engine/models/mesh_frame.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include -#include "../include/models/mesh_frame.hpp" -#include "../include/utils/debug.hpp" - -// ---- -// Constructors/Destructors -// ---- - -MeshFrame::MeshFrame() -{ - id = rand() % 1000000; - vertexCount = 0; - stsCount = 0; - normalsCount = 0; - materialsCount = 0; - _areSTsAllocated = false; - _areVerticesAllocated = false; - _areNormalsAllocated = false; - _areMaterialsAllocated = false; - _isMother = true; -} - -MeshFrame::~MeshFrame() -{ - if (_isMother) - { - if (_areSTsAllocated) - delete[] sts; - if (_areVerticesAllocated) - delete[] vertices; - if (_areNormalsAllocated) - delete[] normals; - delete boundingBoxObj; - } - if (_areMaterialsAllocated) - delete[] materials; -} - -// ---- -// Methods -// ---- - -void MeshFrame::allocateSTs(const u32 &t_val) -{ - assertMsg(!_areSTsAllocated, "Can't allocate STs, because were already set!"); - stsCount = t_val; - sts = new Point[t_val]; - _areSTsAllocated = true; -} - -void MeshFrame::allocateVertices(const u32 &t_val) -{ - assertMsg(!_areVerticesAllocated, "Can't allocate vertices, because were already set!"); - vertexCount = t_val; - vertices = new Vector3[t_val]; - _areVerticesAllocated = true; -} - -void MeshFrame::allocateNormals(const u32 &t_val) -{ - assertMsg(!_areNormalsAllocated, "Can't allocate normals, because were already set!"); - normalsCount = t_val; - normals = new Vector3[t_val]; - _areNormalsAllocated = true; -} - -void MeshFrame::allocateMaterials(const u32 &t_val) -{ - assertMsg(!_areMaterialsAllocated, "Can't allocate materials, because were already set!"); - materialsCount = t_val; - materials = new MeshMaterial[t_val]; - _areMaterialsAllocated = true; -} - -void MeshFrame::calculateBoundingBoxes() -{ - assertMsg(_areVerticesAllocated, "Can't calculate bounding box, because vertices were not allocated!"); - for (u32 i = 0; i < materialsCount; i++) - materials[i].calculateBoundingBox(vertices, vertexCount); - - float lowX, lowY, lowZ, hiX, hiY, hiZ; - lowX = hiX = vertices[0].x; - lowY = hiY = vertices[0].y; - lowZ = hiZ = vertices[0].z; - for (u32 i = 0; i < vertexCount; i++) - { - if (lowX > vertices[i].x) - lowX = vertices[i].x; - if (hiX < vertices[i].x) - hiX = vertices[i].x; - - if (lowY > vertices[i].y) - lowY = vertices[i].y; - if (hiY < vertices[i].y) - hiY = vertices[i].y; - - if (lowZ > vertices[i].z) - lowZ = vertices[i].z; - if (hiZ < vertices[i].z) - hiZ = vertices[i].z; - } - - Vector3 boundingBox[8]; - boundingBox[0].set(lowX, lowY, lowZ); - boundingBox[1].set(lowX, lowY, hiZ); - boundingBox[2].set(lowX, hiY, lowZ); - boundingBox[3].set(lowX, hiY, hiZ); - - boundingBox[4].set(hiX, lowY, lowZ); - boundingBox[5].set(hiX, lowY, hiZ); - boundingBox[6].set(hiX, hiY, lowZ); - boundingBox[7].set(hiX, hiY, hiZ); - _isBoundingBoxCalculated = true; - - // BoundingBox is declared on the heap to prevent any ill-formed default - // constructor instantiated BoundingBox objects. - boundingBoxObj = new BoundingBox(boundingBox); -} - -void MeshFrame::copyFrom(MeshFrame *t_refCopy) -{ - vertexCount = t_refCopy->vertexCount; - stsCount = t_refCopy->stsCount; - normalsCount = t_refCopy->normalsCount; - materialsCount = t_refCopy->materialsCount; - materials = new MeshMaterial[materialsCount]; - for (u32 i = 0; i < materialsCount; i++) - materials[i].copyFrom(&t_refCopy->materials[i]); - _areSTsAllocated = true; - _areVerticesAllocated = true; - _areNormalsAllocated = true; - _areMaterialsAllocated = true; - vertices = t_refCopy->vertices; - sts = t_refCopy->sts; - normals = t_refCopy->normals; - - boundingBoxObj = t_refCopy->boundingBoxObj; - _isBoundingBoxCalculated = true; - - _isMother = false; -} diff --git a/src/engine/models/mesh_material.cpp b/src/engine/models/mesh_material.cpp deleted file mode 100644 index 0fb947b..0000000 --- a/src/engine/models/mesh_material.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "../include/models/mesh_material.hpp" -#include "../include/models/bounding_box.hpp" -#include "../include/utils/debug.hpp" -#include "../include/utils/string.hpp" -#include - -// ---- -// Constructors/Destructors -// ---- - -MeshMaterial::MeshMaterial() -{ - id = rand() % 1000000; - facesCount = 0; - _isNameSet = false; - _areFacesAllocated = false; - _isBoundingBoxCalculated = false; - _areSTsPresent = false; - _areNormalsPresent = false; - _isMother = true; - setDefaultColor(); -} - -MeshMaterial::~MeshMaterial() -{ - if (_isMother) - { - if (_areFacesAllocated) - { - delete[] vertexFaces; - delete[] stFaces; - delete[] normalFaces; - } - if (_isNameSet) - delete[] name; - } -} - -// ---- -// Methods -// ---- - -void MeshMaterial::allocateFaces(const u32 &t_val) -{ - assertMsg(!_areFacesAllocated, "Can't allocate faces, because were already set!"); - facesCount = t_val; - stFaces = new u32[t_val]; - normalFaces = new u32[t_val]; - vertexFaces = new u32[t_val]; - _areFacesAllocated = true; -} - -void MeshMaterial::setName(char *t_val) -{ - assertMsg(!_isNameSet, "Can't set name, because was already set!"); - name = String::createCopy(t_val); - _isNameSet = true; -} - -u8 MeshMaterial::isInFrustum(Plane *t_frustumPlanes, const Vector3 &position) -{ - Vector3 boxCalcTemp; - u8 boxResult = 1, boxIn = 0, boxOut = 0; - - for (u8 i = 0; i < 6; i++) - { - boxOut = 0; - boxIn = 0; - // for each corner of the box do ... - // get out of the cycle as soon as a box as corners - // both inside and out of the frustum - for (u8 y = 0; y < 8 && (boxIn == 0 || boxOut == 0); y++) - { - boxCalcTemp.set( - boundingBoxObj->getVertex(y).x + position.x, - boundingBoxObj->getVertex(y).y + position.y, - boundingBoxObj->getVertex(y).z + position.z); - if (t_frustumPlanes[i].distanceTo(boxCalcTemp) < 0) - boxOut++; - else - boxIn++; - } - //if all corners are out - if (boxIn == 0) - return 0; - else if (boxOut) - boxResult = 1; - } - return boxResult; -} - -void MeshMaterial::calculateBoundingBox(Vector3 *t_vertices, u32 t_vertCount) -{ - float lowX, lowY, lowZ, hiX, hiY, hiZ; - lowX = hiX = t_vertices[vertexFaces[0]].x; - lowY = hiY = t_vertices[vertexFaces[0]].y; - lowZ = hiZ = t_vertices[vertexFaces[0]].z; - for (u32 i = 0; i < facesCount; i++) - { - if (lowX > t_vertices[vertexFaces[i]].x) - lowX = t_vertices[vertexFaces[i]].x; - if (hiX < t_vertices[vertexFaces[i]].x) - hiX = t_vertices[vertexFaces[i]].x; - - if (lowY > t_vertices[vertexFaces[i]].y) - lowY = t_vertices[vertexFaces[i]].y; - if (hiY < t_vertices[vertexFaces[i]].y) - hiY = t_vertices[vertexFaces[i]].y; - - if (lowZ > t_vertices[vertexFaces[i]].z) - lowZ = t_vertices[vertexFaces[i]].z; - if (hiZ < t_vertices[vertexFaces[i]].z) - hiZ = t_vertices[vertexFaces[i]].z; - } - - Vector3 boundingBox[8]; - boundingBox[0].set(lowX, lowY, lowZ); - boundingBox[1].set(lowX, lowY, hiZ); - boundingBox[2].set(lowX, hiY, lowZ); - boundingBox[3].set(lowX, hiY, hiZ); - - boundingBox[4].set(hiX, lowY, lowZ); - boundingBox[5].set(hiX, lowY, hiZ); - boundingBox[6].set(hiX, hiY, lowZ); - boundingBox[7].set(hiX, hiY, hiZ); - _isBoundingBoxCalculated = true; - - // BoundingBox is declared on the heap to prevent any ill-formed default - // constructor instantiated BoundingBox objects. - boundingBoxObj = new BoundingBox(boundingBox); -} - -void MeshMaterial::copyFrom(MeshMaterial *t_refCopy) -{ - _isNameSet = true; - name = t_refCopy->name; - - _isBoundingBoxCalculated = true; - boundingBoxObj = t_refCopy->boundingBoxObj; - - vertexFaces = t_refCopy->vertexFaces; - stFaces = t_refCopy->stFaces; - normalFaces = t_refCopy->normalFaces; - facesCount = t_refCopy->facesCount; - _areSTsPresent = t_refCopy->_areSTsPresent; - _areNormalsPresent = t_refCopy->_areNormalsPresent; - _areFacesAllocated = true; - - _isMother = false; -} - -/** Set's default object color + no transparency */ -void MeshMaterial::setDefaultColor() -{ - color.r = 0x80; - color.g = 0x80; - color.b = 0x80; - color.a = 0x80; - color.q = 1.0F; -} diff --git a/src/engine/models/sprite.cpp b/src/engine/models/sprite.cpp deleted file mode 100644 index 5151a0f..0000000 --- a/src/engine/models/sprite.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "../include/models/sprite.hpp" -#include "../include/utils/debug.hpp" -#include "../include/utils/string.hpp" -#include - -// ---- -// Constructors/Destructors -// ---- - -Sprite::Sprite() -{ - id = rand() % 1000000; - _isSizeSet = false; - _flipH = false; - _flipV = false; - scale = 1.0F; - mode = MODE_REPEAT; - setDefaultColor(); - setDefaultLODAndClut(); -} - -Sprite::~Sprite() {} - -// ---- -// Methods -// ---- - -/** Set's default object color + no transparency */ -void Sprite::setDefaultColor() -{ - color.r = 0x80; - color.g = 0x80; - color.b = 0x80; - color.a = 0x80; - color.q = 0.0F; -} - -/** Sets texture level of details settings and CLUT settings */ -void Sprite::setDefaultLODAndClut() -{ - clut.storage_mode = CLUT_STORAGE_MODE1; - clut.start = 0; - clut.psm = 0; - clut.load_method = CLUT_NO_LOAD; - clut.address = 0; -} diff --git a/src/engine/models/texture.cpp b/src/engine/models/texture.cpp deleted file mode 100644 index 107c353..0000000 --- a/src/engine/models/texture.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "../include/models/texture.hpp" -#include "../include/utils/string.hpp" -#include -#include - -// ---- -// Constructors/Destructors -// ---- - -Texture::Texture() -{ - id = rand() % 1000000; - _isSizeSet = false; - _isNameSet = false; - setDefaultWrapSettings(); -} - -Texture::~Texture() -{ - if (getTextureLinksCount() > 0) - texLinks.clear(); - if (_isNameSet) - delete[] name; - if (_isSizeSet) - delete[] data; -} - -// ---- -// Methods -// ---- - -void Texture::setSize(const u8 &t_width, const u8 &t_height, const TextureType &t_type) -{ - assertMsg(!_isSizeSet, "Can't set size, because was already set!"); - assertMsg(t_width <= 256 && t_height <= 256, "Given texture can be too big for PS2. Please strict to 256x256 max. Prefer 128x128."); - width = t_width; - height = t_height; - _type = t_type; - data = new unsigned char[getDataSize()]; - _isSizeSet = true; -} - -void Texture::setName(char *t_val) -{ - assertMsg(!_isNameSet, "Can't set name, because was already set!"); - name = String::createCopy(t_val); - _isNameSet = true; -} - -void Texture::setDefaultWrapSettings() -{ - wrapSettings.horizontal = WRAP_REPEAT; - wrapSettings.vertical = WRAP_REPEAT; - wrapSettings.maxu = 0; - wrapSettings.maxv = 0; - wrapSettings.minu = 0; - wrapSettings.minv = 0; -} - -void Texture::setWrapSettings(const WrapSettings t_horizontal, const WrapSettings t_vertical) -{ - wrapSettings.horizontal = t_horizontal; - wrapSettings.vertical = t_vertical; -} - -void Texture::addLink(const u32 &t_id) -{ - TextureLink link; - link.id = t_id; - texLinks.push_back(link); -} diff --git a/src/engine/modules/audio.cpp b/src/engine/modules/audio.cpp deleted file mode 100644 index d8a6165..0000000 --- a/src/engine/modules/audio.cpp +++ /dev/null @@ -1,308 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "../include/modules/audio.hpp" -#include "../include/utils/string.hpp" -#include "../include/utils/debug.hpp" -#include -#include - -// ---- -// Constructors/Destructors -// ---- - -Audio *audioRef; - -Audio::Audio() -{ - // We must set it to 0 on songStop(); - realVolume = 100; - volume = 100; - chunkReadStatus = 0; - - songLoaded = false; - songPlaying = false; - songInLoop = false; - songFinished = false; - - audioRef = this; - initSema(); - loadModules(); - initAUDSRV(); - setSongFormat(); -} - -Audio::~Audio() {} - -// ---- -// Methods -// ---- - -void Audio::loadSong(char *t_path) -{ - if (songLoaded) - unloadSong(); - char *fullFilename = String::createConcatenated("host:", t_path); - wav = fopen(fullFilename, "rb"); - delete[] fullFilename; - assertMsg(wav != NULL, "Failed to open wav file!"); - rewindSongToStart(); - songLoaded = true; - consoleLog("Song loaded!"); -} - -void Audio::playSong() -{ - assertMsg(songLoaded, "Cant play song because was not loaded!"); - if (songFinished) - rewindSongToStart(); - volume = realVolume; - songPlaying = true; -} - -void Audio::stopSong() -{ - volume = 0; - audsrv_set_volume(volume); - songPlaying = false; -} - -void Audio::setSongVolume(const u8 &t_vol) -{ - realVolume = t_vol; - if (songPlaying) - volume = t_vol; - audsrv_set_volume(volume); -} - -u32 Audio::addSongListener(AudioListener *t_listener) -{ - AudioListenerRef *ref = new AudioListenerRef; - ref->id = rand() % 1000000; - ref->listener = t_listener; - songListeners.push_back(ref); - return ref->id; -} - -void Audio::removeSongListener(const u32 &t_id) -{ - s32 index = -1; - for (u32 i = 0; i < songListeners.size(); i++) - if (songListeners[i]->id == t_id) - { - index = i; - break; - } - assertMsg(index != -1, "Cant remove listener because given id was not found!"); - delete songListeners[index]; - songListeners.erase(songListeners.begin() + index); -} - -// ADPCM - -audsrv_adpcm_t *Audio::loadADPCM(char *t_path) -{ - char *fullFilename = String::createConcatenated("host:", t_path); - FILE *file = fopen(fullFilename, "rb"); - delete[] fullFilename; - fseek(file, 0, SEEK_END); - u32 adpcmFileSize = ftell(file); - u8 data[adpcmFileSize]; - rewind(file); - fread(data, sizeof(u8), adpcmFileSize, file); - audsrv_adpcm_t *result = new audsrv_adpcm_t(); - result->size = 0; - result->buffer = 0; - result->loop = 0; - result->pitch = 0; - result->channels = 0; - if (audsrv_load_adpcm(result, data, adpcmFileSize)) - { - printf("AUDSRV returned error string: %s", audsrv_get_error_string()); - assertMsg(true == false, "audsrv_load_adpcm() failed!"); - } - fclose(file); - return result; -} - -void Audio::playADPCM(audsrv_adpcm_t *t_adpcm) -{ - if (audsrv_play_adpcm(t_adpcm)) - { - printf("AUDSRV returned error string: %s", audsrv_get_error_string()); - assertMsg(true == false, "audsrv_play_adpcm() failed!"); - } -} - -void Audio::playADPCM(audsrv_adpcm_t *t_adpcm, const s8 &t_ch) -{ - if (audsrv_ch_play_adpcm(t_ch, t_adpcm)) - { - printf("AUDSRV returned error string: %s", audsrv_get_error_string()); - assertMsg(true == false, "audsrv_ch_play_adpcm() failed!"); - } -} - -// Other - -void Audio::startThread(FileService *t_fileService) -{ - consoleLog("Creating audio thread"); - // fileService = t_fileService; - extern void *_gp; - thread.func = (void *)Audio::mainThread; - thread.stack = threadStack; - thread.stack_size = getThreadStackSize(); - thread.gp_reg = (void *)&_gp; - thread.initial_priority = 0x17; - threadId = CreateThread(&thread); - assertMsg(threadId >= 0, "Create audio thread failed!"); - consoleLog("Audio thread created"); - StartThread(threadId, NULL); - consoleLog("Audio thread started"); -} - -/** Main thread loop */ -void Audio::threadLoop() -{ - // --- - // TODO - bug here, GCC11 is doing some optimizations and this method probably think that - // "songPlaying" is false + on real PS2 I see that program tries to turn on this - // method as rarely as possible (slow, flickering sound). On GCC 3.2.3 this one was fine lol!. - if (songPlaying) // HACK1 - im not proud of that - songPlaying = 1; - if (songLoaded) - songLoaded = 1; - if (hack == 1) // HACK2 - lets give some work to gcc lol - hack = 2; - else - hack = 1; - // --- - - if (!songPlaying || !songLoaded) - return; - if (songFinished) - { - printf("Audio: Song finished. "); - if (songInLoop) - { - printf("Running again.\n"); - for (u32 i = 0; i < getSongListenersCount(); i++) - songListeners[i]->listener->onAudioFinish(); - rewindSongToStart(); - } - else - { - printf("Stopping song.\n"); - stopSong(); - return; - } - } - - if (chunkReadStatus > 0) - { - WaitSema(fillbufferSema); // wait until previous chunk wasn't finished - audsrv_play_audio(wavChunk, chunkReadStatus); - for (u32 i = 0; i < getSongListenersCount(); i++) - songListeners[i]->listener->onAudioTick(); - } - - chunkReadStatus = fread(wavChunk, 1, sizeof(wavChunk), wav); - - if (chunkReadStatus < (s32)sizeof(wavChunk)) - songFinished = true; -} - -/** - * Close file. - * Delete song path from memory. - */ -void Audio::unloadSong() -{ - songLoaded = false; - fclose(wav); -} - -/** Set WAV format to 16bit, 22050Hz, stereo. */ -void Audio::setSongFormat() -{ - format.bits = 16; - format.freq = 22050; - format.channels = 2; - audsrv_set_format(&format); -} - -/** Fseek on wav. */ -void Audio::rewindSongToStart() -{ - if (wav != NULL) - fseek(wav, 0x30, SEEK_SET); - songFinished = false; -} - -/** Initialize semaphore which will wait until chunk of the song is not finished. */ -void Audio::initSema() -{ - consoleLog("Creating audio semaphore"); - sema.init_count = 0; - sema.max_count = 1; - sema.option = 0; - fillbufferSema = CreateSema(&sema); - consoleLog("Audio semaphore created"); -} - -/** Load LIBSD and AUDSRV modules */ -void Audio::loadModules() -{ - consoleLog("Modules loading started (LIBSD, AUDSRV)"); - int ret = SifLoadModule("rom0:LIBSD", 0, NULL); - assertMsg(ret != -203, "LIBSD loading failed!"); - ret = SifLoadModule("host:AUDSRV.IRX", 0, NULL); - assertMsg(ret != -203, "AUDSRV.IRX loading failed!"); - consoleLog("Audio modules loaded"); -} - -/** - * Initialize AUDSRV main and ADPCM module. - * Install AUDSRV callback. - */ -void Audio::initAUDSRV() -{ - consoleLog("Initializing AUDSRV"); - int ret = audsrv_init(); - if (ret != 0) - { - printf("AUDSRV returned error string: %s", audsrv_get_error_string()); - assertMsg(true == false, "Failed to initialize AUDSRV!"); - } - ret = audsrv_adpcm_init(); - if (ret != 0) - { - printf("AUDSRV returned error string: %s", audsrv_get_error_string()); - assertMsg(true == false, "Failed to initialize AUDSRV ADPCM!"); - } - ret = audsrv_on_fillbuf(getSongBufferSize(), (audsrv_callback_t)iSignalSema, (void *)fillbufferSema); - if (ret != 0) - { - printf("AUDSRV returned error string: %s", audsrv_get_error_string()); - assertMsg(true == false, "Failed to initialize AUDSRV fillbuffer!"); - } - consoleLog("AUDSRV initialized!"); -} - -/** - * Do not call this function. - * This is a audio thread, runned by engine - */ -void Audio::mainThread() -{ - while (true) - audioRef->threadLoop(); -} diff --git a/src/engine/modules/camera_base.cpp b/src/engine/modules/camera_base.cpp deleted file mode 100644 index f6df653..0000000 --- a/src/engine/modules/camera_base.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "../include/modules/camera_base.hpp" - -#include -#include "../include/utils/debug.hpp" -#include "../include/utils/math.hpp" - -// ---- -// Constructors/Destructors -// ---- - -CameraBase::CameraBase(ScreenSettings *t_screen, Vector3 *t_position) - : screen(t_screen) -{ - consoleLog("Initializing frustum"); - farPlaneDist = screen->farPlaneDist; - nearPlaneDist = screen->nearPlaneDist; - float tang = tanf(screen->fov * Math::HALF_ANG2RAD); - nearHeight = tang * nearPlaneDist; - nearWidth = nearHeight * screen->aspectRatio; - farHeight = tang * farPlaneDist; - farWidth = farHeight * screen->aspectRatio; - p_position = t_position; - up.set(0.0F, 1.0F, 0.0F); - consoleLog("CameraBase initialized!"); -} - -// ---- -// Methods -// ---- - -void CameraBase::lookAt(Vector3 &t_target) -{ - updatePlanes(t_target); - view.lookAt(*p_position, t_target); -} - -void CameraBase::updatePlanes(Vector3 t_target) -{ - Vector3 nearCenter, farCenter, X, Y, Z; - // compute the Z axis of camera - Z = *p_position - t_target; - Z.normalize(); - // X axis of camera of given "up" vector and Z axis - X = up * Z; - X.normalize(); - // the real "up" vector is the cross product of Z and X - Y = Z * X; - // compute the center of the near and far planes - nearCenter = *p_position - Z * nearPlaneDist; - farCenter = *p_position - Z * farPlaneDist; - // compute the 8 corners of the frustum - ntl = nearCenter + Y * nearHeight - X * nearWidth; - ntr = nearCenter + Y * nearHeight + X * nearWidth; - nbl = nearCenter - Y * nearHeight - X * nearWidth; - nbr = nearCenter - Y * nearHeight + X * nearWidth; - - ftl = farCenter + Y * farHeight - X * farWidth; - fbr = farCenter - Y * farHeight + X * farWidth; - ftr = farCenter + Y * farHeight + X * farWidth; - fbl = farCenter - Y * farHeight - X * farWidth; - - planes[0].update(ntr, ntl, ftl); // Top - planes[1].update(nbl, nbr, fbr); // BOTTOM - planes[2].update(ntl, nbl, fbl); // LEFT - planes[3].update(nbr, ntr, fbr); // RIGHT - planes[4].update(ntl, ntr, nbr); // NEAR - planes[5].update(ftr, ftl, fbl); // FAR -} diff --git a/src/engine/modules/file_service.cpp b/src/engine/modules/file_service.cpp deleted file mode 100644 index 1cf1c8a..0000000 --- a/src/engine/modules/file_service.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "../include/modules/file_service.hpp" -#include "../include/utils/string.hpp" -#include "../include/utils/debug.hpp" -#include - -// ---- -// Constructors/Destructors -// ---- - -FileService *fsRef; - -FileService::FileService() {} - -FileService::~FileService() {} - -// ---- -// Methods -// ---- - -u32 FileService::addReadChunk(FILE *t_file, void *t_destination, const u32 &t_size, const u32 &t_n) -{ - FileServiceTask task; - task.id = rand() % 1000000; - task.file = t_file; - task.destination = t_destination; - task.size = t_size; - task.n = t_n; - task.readStatus = -2137; - tasks.push_back(task); - return task.id; -} - -s32 FileService::isTaskDone(const u32 &t_taskId) -{ - s32 taskIndex = getIndexOf(t_taskId); - assertMsg(taskIndex != -1, "Task was not found!"); - s32 result = tasks[taskIndex].readStatus; - if (result != -2137) - removeByIndex(taskIndex); - return result; -} - -const void FileService::removeById(const u32 &t_taskId) -{ - s32 index = getIndexOf(t_taskId); - assertMsg(index != -1, "Cant remove task, because it was not found!"); - removeByIndex(index); -} - -const s32 FileService::getIndexOf(const u32 &t_taskId) -{ - for (u32 i = 0; i < tasks.size(); i++) - if (tasks[i].id == t_taskId) - return i; - return -1; -}; - -// Other - -void FileService::startThread() -{ - consoleLog("Creating file service thread"); - extern void *_gp; - thread.func = (void *)FileService::mainThread; - thread.stack = threadStack; - thread.stack_size = getThreadStackSize(); - thread.gp_reg = (void *)&_gp; - thread.initial_priority = 0x12; - threadId = CreateThread(&thread); - assertMsg(threadId >= 0, "Create audio thread failed!"); - consoleLog("File service created"); - StartThread(threadId, NULL); - consoleLog("File service started"); -} - -/** Main thread loop */ -void FileService::threadLoop() -{ - // This will cause an error - // printf("\n\n\n\n\nsize:%d\n", tasks.size()); - // for (size_t i = 0; i < tasks.size(); i++) - // { - // switch (tasks[i].type) - // { - // case ReadChunk: - // tasks[i].readStatus = fread(tasks[i].destination, tasks[i].n, tasks[i].size, tasks[i].file); - // break; - - // default: - // break; - // } - // } - SleepThread(); -} - -/** - * Do not call this function. - * This is an file service thread, runned by engine - */ -void FileService::mainThread() -{ - while (true) - fsRef->threadLoop(); -} diff --git a/src/engine/modules/gif_sender.cpp b/src/engine/modules/gif_sender.cpp deleted file mode 100644 index 2250215..0000000 --- a/src/engine/modules/gif_sender.cpp +++ /dev/null @@ -1,255 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "../include/modules/gif_sender.hpp" - -#include "../include/utils/math.hpp" -#include "../include/utils/debug.hpp" -#include -#include -#include -#include -#include -#include -#include -#include - -// ---- -// Constructors/Destructors -// ---- - -/** Initializes vars and creates data transfer packets - * @param packetSize Size of data packet, should be increased when more data will be rendered - */ -GifSender::GifSender(u32 t_packetSize, ScreenSettings *t_screen, Light *t_light) : screen(t_screen) -{ - consoleLog("Initializing GifSender"); - light = t_light; - packetSize = t_packetSize; - packets[0] = packet2_create(t_packetSize, P2_TYPE_NORMAL, P2_MODE_CHAIN, false); - packets[1] = packet2_create(t_packetSize, P2_TYPE_NORMAL, P2_MODE_CHAIN, false); - consoleLog("GifSender initialized!"); -} - -/** Releases packets memory */ -GifSender::~GifSender() -{ - packet2_free(packets[0]); - packet2_free(packets[1]); -} - -// ---- -// Methods -// ---- - -#include -#include - -/** Send texture via GIF */ -void GifSender::sendTexture(Texture &texture, texbuffer_t *t_texBuffer) -{ - packet2_t *packet2 = packet2_create(15, P2_TYPE_NORMAL, P2_MODE_CHAIN, false); - packet2_update( - packet2, - draw_texture_transfer( - packet2->base, - texture.getData(), - texture.getWidth(), - texture.getHeight(), - texture.getType(), - t_texBuffer->address, - t_texBuffer->width)); - packet2_chain_open_cnt(packet2, 0, 0, 0); - packet2_update(packet2, draw_texture_wrapping(packet2->next, 0, texture.getWrapSettings())); - packet2_chain_close_tag(packet2); - packet2_update(packet2, draw_texture_flush(packet2->next)); - dma_channel_wait(DMA_CHANNEL_GIF, 0); - dma_channel_send_packet2(packet2, DMA_CHANNEL_GIF, true); - dma_channel_wait(DMA_CHANNEL_GIF, 0); - packet2_free(packet2); -} - -void GifSender::sendClear(zbuffer_t *t_zBuffer, color_t *t_rgb) -{ - packet2_t *packet2 = packet2_create(36, P2_TYPE_NORMAL, P2_MODE_CHAIN, false); - packet2_chain_open_end(packet2, 0, 0); - packet2_update(packet2, draw_disable_tests(packet2->next, 0, t_zBuffer)); - packet2_update(packet2, draw_clear(packet2->next, 0, - 2048.0F - (screen->width / 2), 2048.0F - (screen->height / 2), - screen->width, screen->height, - t_rgb->r, t_rgb->g, t_rgb->b)); - packet2_update(packet2, draw_enable_tests(packet2->next, 0, t_zBuffer)); - packet2_update(packet2, draw_finish(packet2->next)); - packet2_chain_close_tag(packet2); - dma_channel_wait(DMA_CHANNEL_GIF, 0); - dma_channel_send_packet2(packet2, DMA_CHANNEL_GIF, true); - dma_channel_wait(DMA_CHANNEL_GIF, 0); - packet2_free(packet2); -} - -/** Used in game loop. - * Switches current packet to next one - */ -void GifSender::initPacket(u8 t_context) -{ - currentPacket = packets[t_context]; - packet2_reset(currentPacket, false); - isAnyObjectAdded = false; -} - -/** Sends packet to GIF. */ -void GifSender::sendPacket() -{ - if (isAnyObjectAdded) - { - packet2_chain_open_end(currentPacket, 0, 0); - packet2_update(currentPacket, draw_finish(currentPacket->next)); - packet2_chain_close_tag(currentPacket); - } - dma_channel_wait(DMA_CHANNEL_GIF, 0); - dma_channel_send_packet2(currentPacket, DMA_CHANNEL_GIF, true); -} - -/** Adds clear screen to current packet */ -void GifSender::addClear(zbuffer_t *t_zBuffer, color_t *t_rgb) -{ - packet2_chain_open_cnt(currentPacket, 0, 0, 0); - packet2_update(currentPacket, draw_disable_tests(currentPacket->next, 0, t_zBuffer)); - packet2_update(currentPacket, draw_clear(currentPacket->next, 0, - 2048.0F - (screen->width / 2), 2048.0F - (screen->height / 2), - screen->width, screen->height, - t_rgb->r, t_rgb->g, t_rgb->b)); - packet2_update(currentPacket, draw_enable_tests(currentPacket->next, 0, t_zBuffer)); - packet2_chain_close_tag(currentPacket); -} - -/** Adds meshes to current packet */ -void GifSender::addObject(RenderData *t_renderData, Mesh &t_mesh, u32 vertexCount, VECTOR *vertices, VECTOR *normals, VECTOR *coordinates, LightBulb *t_bulbs, u16 t_bulbsCount, texbuffer_t *textureBuffer, color_t *t_color) -{ - packet2_chain_open_cnt(currentPacket, 0, 0, 0); - packet2_update(currentPacket, draw_texture_sampling(currentPacket->next, 0, &t_mesh.lod)); - packet2_update(currentPacket, draw_texturebuffer(currentPacket->next, 0, textureBuffer, &t_mesh.clut)); - packet2_update(currentPacket, draw_prim_start(currentPacket->next, 0, t_renderData->prim, t_color)); - xyz = new xyz_t[vertexCount]; - rgbaq = new color_t[vertexCount]; - st = new texel_t[vertexCount]; - calc3DObject(*t_renderData->projection, t_mesh, vertexCount, vertices, normals, coordinates, t_renderData, t_bulbs, t_bulbsCount, t_color); - addCurrentCalcs(vertexCount); - delete[] xyz; - delete[] rgbaq; - delete[] st; - packet2_update(currentPacket, draw_prim_end(currentPacket->next, 3, DRAW_STQ_REGLIST)); - packet2_chain_close_tag(currentPacket); -} - -/** Calculates 3D object data into xyz, rgbq, st - * After it addCurrentCalcs() can be done - */ -void GifSender::calc3DObject(Matrix t_perspective, Mesh &t_mesh, u32 vertexCount, VECTOR *vertices, VECTOR *normals, VECTOR *coordinates, RenderData *t_renderData, LightBulb *t_bulbs, u16 t_bulbsCount, color_t *t_color) -{ - VECTOR *colors = new VECTOR[vertexCount]; - VECTOR position, rotation; - - vec3ToNative(position, t_mesh.position, 1.0F); - vec3ToNative(rotation, t_mesh.rotation, 1.0F); - - create_local_world(localWorld, position, rotation); - - const u8 SHOULD_BE_LIGHTED = t_bulbs != NULL && t_mesh.shouldBeLighted; - - if (SHOULD_BE_LIGHTED) - create_local_light(localLight, rotation); - - // I cant put perspective from renderData here. ee-gcc bug? - create_local_screen(localScreen, localWorld, t_renderData->view->data, t_perspective.data); - - if (SHOULD_BE_LIGHTED) - { - const u16 lightsCount = light->getLightsCount(t_bulbsCount); - VECTOR *lightDirections = new VECTOR[lightsCount]; - VECTOR *lightColors = new VECTOR[lightsCount]; - int *lightTypes = new int[lightsCount]; - - VECTOR *lights = new VECTOR[vertexCount]; - calculate_normals(normals, vertexCount, normals, localLight); - - light->calculateLight(lightDirections, lightColors, lightTypes, t_bulbs, lightsCount, t_mesh.position); - - calculate_lights(lights, vertexCount, normals, lightDirections, lightColors, lightTypes, lightsCount); - - for (u32 i = 0; i < vertexCount; i++) - { - // Apply the light value to the colour. - colors[i][0] = (t_color->r * lights[i][0]); - colors[i][1] = (t_color->g * lights[i][1]); - colors[i][2] = (t_color->b * lights[i][2]); - vector_clamp(colors[i], colors[i], 0.00F, 1.99F); - } - - delete[] lightDirections; - delete[] lightColors; - delete[] lightTypes; - delete[] lights; - } - else - for (u32 i = 0; i < vertexCount; i++) - { - colors[i][0] = t_color->r / 128.0F; - colors[i][1] = t_color->g / 128.0F; - colors[i][2] = t_color->b / 128.0F; - } - - calculate_vertices(vertices, vertexCount, vertices, localScreen); - - convertCalcs(vertexCount, vertices, colors, coordinates, *t_color); - - delete[] colors; -} - -void GifSender::convertCalcs(u32 t_vertexCount, VECTOR *t_vertices, VECTOR *t_colors, VECTOR *t_sts, color_t &t_color) -{ - // TODO get this via screensettings - const s32 centerX = ftoi4(2048); - const s32 centerY = ftoi4(2048); - const u32 maxZ = ftoi4(((float)0xFFFFFF) / 32.0F); - float q = 1.00F; - for (u32 i = 0; i < t_vertexCount; i++) - { - xyz[i].x = (u16)((t_vertices[i][0] + 1.0F) * centerX); - xyz[i].y = (u16)((t_vertices[i][1] + 1.0F) * centerY); - xyz[i].z = (u32)((t_vertices[i][2] + 1.0F) * maxZ); - - if (t_vertices[i][3]) - q = 1 / t_vertices[i][3]; - - st[i].s = t_sts[i][0] * q; - st[i].t = t_sts[i][1] * q; - - rgbaq[i].r = (u8)(t_colors[i][0] * 128.0F); - rgbaq[i].g = (u8)(t_colors[i][1] * 128.0F); - rgbaq[i].b = (u8)(t_colors[i][2] * 128.0F); - rgbaq[i].a = t_color.a; - rgbaq[i].q = q; - } -} - -/** Update q's double words. It may look strange, but this workaround - * use's a 64-bit pointer to simplify adding data to the packet. -*/ -void GifSender::addCurrentCalcs(u32 &t_vertexCount) -{ - for (u32 i = 0; i < t_vertexCount; i++) - { - packet2_add_u64(currentPacket, rgbaq[i].rgbaq); - packet2_add_u64(currentPacket, st[i].uv); - packet2_add_u64(currentPacket, xyz[i].xyz); - } - packet2_pad128(currentPacket, 0); -} diff --git a/src/engine/modules/light.cpp b/src/engine/modules/light.cpp deleted file mode 100644 index 19f2702..0000000 --- a/src/engine/modules/light.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "../include/modules/light.hpp" - -// ---- -// Constructors/Destructors -// ---- - -Light::Light() {} - -Light::~Light() {} - -// ---- -// Methods -// ---- - -const u8 ADDITIONAL_LIGHTS = 1; // Ambient -const float LIGHT_MAX = 255.0F; -const float LIGHT_DIS_MOD = 4.0F; - -void Light::setAmbientLight(const Vector3 &t_rgb) { ambientLight.set(t_rgb); } - -u16 Light::getLightsCount(u32 t_bulbsCount) { return t_bulbsCount + ADDITIONAL_LIGHTS; } - -/** Calculates lighting. Used in gifSender in object 3D calculations */ -void Light::calculateLight(VECTOR *t_lightDirections, VECTOR *t_lightColors, int *t_lightTypes, LightBulb *t_bulbs, u32 t_lightsCount, Vector3 t_objPosition) -{ - // --- Ambient light - - t_lightTypes[0] = LIGHT_AMBIENT; - - t_lightDirections[0][0] = 0.0F; - t_lightDirections[0][1] = 0.0F; - t_lightDirections[0][2] = 0.0F; - t_lightDirections[0][3] = 1.0F; - - t_lightColors[0][0] = ambientLight.x; - t_lightColors[0][1] = ambientLight.y; - t_lightColors[0][2] = ambientLight.z; - t_lightColors[0][3] = 1.0F; - - // --- - - for (u8 i = 1; i < t_lightsCount; i++) - { - t_lightTypes[i] = LIGHT_DIRECTIONAL; - - Vector3 newLight = Vector3(t_objPosition.x - t_bulbs[i - 1].position.x, - t_objPosition.y - t_bulbs[i - 1].position.y, - t_objPosition.z - t_bulbs[i - 1].position.z); - newLight.normalize(); - t_lightDirections[i][0] = newLight.x; - t_lightDirections[i][1] = newLight.y; - t_lightDirections[i][2] = newLight.z; - t_lightDirections[i][3] = 1.0F; - - // Intensity range 0.0F - 1.0F - float intensity = t_bulbs[i - 1].intensity / LIGHT_MAX; - // Distance range 0.0F - LIGHT_MAX * LIGHT_DIS_MOD (1020.0F at this time) - float distance = t_bulbs[i - 1].position.distanceTo(t_objPosition); - // printf("Distance:%f\n", distance); - distance = distance > (LIGHT_MAX - LIGHT_DIS_MOD) * LIGHT_DIS_MOD ? LIGHT_MAX - LIGHT_DIS_MOD : distance; - intensity /= 1.0F + (distance / LIGHT_DIS_MOD); // intensity /= 1.0F - 251.0F - intensity /= 3.0F; // it looks better - t_lightColors[i][0] = intensity; - t_lightColors[i][1] = intensity; - t_lightColors[i][2] = intensity; - t_lightColors[i][3] = 1.0F; - } -} diff --git a/src/engine/modules/pad.cpp b/src/engine/modules/pad.cpp deleted file mode 100644 index edd340e..0000000 --- a/src/engine/modules/pad.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "../include/modules/pad.hpp" - -#include "../include/utils/debug.hpp" -#include -#include -#include -#include - -// ---- -// Constructors/Destructors -// ---- - -/** Init vars, load modules, opens pad port and initializes pad */ -Pad::Pad() -{ - this->oldPad = 0; - this->loadModules(); - padInit(0); - this->port = 0; // 0 -> Connector 1, 1 -> Connector 2 - this->slot = 0; // Always zero if not using multitap - if ((this->ret = padPortOpen(this->port, this->slot, padBuf)) == 0) - { - printf("padPortOpen returned: %d\n", this->ret); - assertMsg(true == false, "padPortOpen failed!"); - } - assertMsg(this->initPad(), "initPad failed!"); -} - -Pad::~Pad() {} - -// ---- -// Methods -// ---- - -/** Load SIO2MAN and PADMAN modules */ -void Pad::loadModules() -{ - consoleLog("Loading pad modules"); - this->ret = SifLoadModule("rom0:SIO2MAN", 0, NULL); - if (this->ret < 0) - { - printf("SifLoadModule returned: %d\n", this->ret); - assertMsg(true == false, "SifLoadModule (SIO2MAN) failed!"); - } - this->ret = SifLoadModule("rom0:PADMAN", 0, NULL); - if (this->ret < 0) - { - printf("SifLoadModule returned: %d\n", this->ret); - assertMsg(true == false, "SifLoadModule (PADMAN) failed!"); - } - consoleLog("Pad modules loaded!"); -} - -/** Wait when pad will be ready (stable and ready) */ -int Pad::waitPadReady() -{ - int state; - int lastState; - char stateString[16]; - state = padGetState(this->port, this->slot); - lastState = -1; - while ((state != PAD_STATE_STABLE) && (state != PAD_STATE_FINDCTP1)) - { - if (state != lastState) - { - padStateInt2String(state, stateString); - consoleLog("Pad state changed"); - printf("Curent pad(%d,%d) status: %s\n", this->port, this->slot, stateString); - } - lastState = state; - state = padGetState(this->port, this->slot); - } - // Were the pad ever 'out of sync'? - if (lastState != -1) - consoleLog("Pad is ready!"); - return 0; -} - -/** Initializes and checks type of pad */ -int Pad::initPad() -{ - consoleLog("Initializing pad"); - this->waitPadReady(); - // How many different modes can this device operate in? - // i.e. get # entrys in the modetable - int modes = padInfoMode(this->port, this->slot, PAD_MODETABLE, -1); - assertMsg(modes, "Connected device is not a dual shock controller!"); // (it has no actuator engines) - - // Verify that the controller has a DUAL SHOCK mode - int i = 0; - do - { - if (padInfoMode(this->port, this->slot, PAD_MODETABLE, i) == PAD_TYPE_DUALSHOCK) - break; - i++; - } while (i < modes); - - assertMsg(i < modes, "Connected device is not a dual shock controller!"); - - // If ExId != 0x0 => This controller has actuator engines - // This check should always pass if the Dual Shock test above passed - this->ret = padInfoMode(this->port, this->slot, PAD_MODECUREXID, 0); - assertMsg(this->ret, "Connected device is not a dual shock controller!"); - - consoleLog("Enabling dual shock functions."); - - // When using MMODE_LOCK, user cant change mode with Select button - padSetMainMode(this->port, this->slot, PAD_MMODE_DUALSHOCK, PAD_MMODE_LOCK); - - this->waitPadReady(); - printf("Pad has pressure sensitive buttons? %d\n", padInfoPressMode(this->port, this->slot)); - this->waitPadReady(); - padEnterPressMode(this->port, this->slot); // Set pressure sensitive mode - this->waitPadReady(); - this->actuators = padInfoAct(this->port, this->slot, -1, 0); - printf("# of actuators: %d\n", this->actuators); - if (actuators != 0) - { - this->actAlign[0] = 0; // Enable small engine - this->actAlign[1] = 1; // Enable big engine - this->actAlign[2] = 0xff; - this->actAlign[3] = 0xff; - this->actAlign[4] = 0xff; - this->actAlign[5] = 0xff; - this->waitPadReady(); - printf("padSetActAlign: %d\n", padSetActAlign(this->port, this->slot, actAlign)); - } - else - printf("Did not find any actuators.\n"); - this->waitPadReady(); - consoleLog("Pad initialized!"); - return 1; -} - -/** Updates state of joys/buttons */ -void Pad::update() -{ - int x = 0; - this->ret = padGetState(this->port, this->slot); - while ((this->ret != PAD_STATE_STABLE) && (this->ret != PAD_STATE_FINDCTP1)) - { - if (this->ret == PAD_STATE_DISCONN) - printf("Pad(%d, %d) is disconnected\n", this->port, this->slot); - this->ret = padGetState(this->port, this->slot); - } - if (x == 1) - printf("Pad: OK!\n"); - - this->ret = padRead(this->port, this->slot, &this->buttons); // this->port, this->slot, this->buttons - - if (this->ret != 0) - { - this->padData = 0xffff ^ this->buttons.btns; - - this->newPad = this->padData & ~this->oldPad; - this->oldPad = this->padData; - this->reset(); - this->rJoyH = this->buttons.rjoy_h; - this->rJoyV = this->buttons.rjoy_v; - this->lJoyH = this->buttons.ljoy_h; - this->lJoyV = this->buttons.ljoy_v; - - if (this->newPad & PAD_CROSS) - this->isCrossClicked = 1; - if (this->newPad & PAD_SQUARE) - this->isSquareClicked = 1; - if (this->newPad & PAD_TRIANGLE) - this->isTriangleClicked = 1; - if (this->newPad & PAD_CIRCLE) - this->isCircleClicked = 1; - - if (this->buttons.up_p > 0) - this->isDpadUpPressed = 1; - if (this->buttons.down_p > 0) - this->isDpadDownPressed = 1; - if (this->buttons.left_p) - this->isDpadLeftPressed = 1; - if (this->buttons.right_p) - this->isDpadRightPressed = 1; - } -} - -/** Resets state of joys/buttons */ -void Pad::reset() -{ - this->isCrossClicked = 0; - this->isSquareClicked = 0; - this->isTriangleClicked = 0; - this->isCircleClicked = 0; - this->isDpadUpPressed = 0; - this->isDpadDownPressed = 0; - this->isDpadLeftPressed = 0; - this->isDpadRightPressed = 0; - this->lJoyH = 0; - this->lJoyV = 0; - this->rJoyH = 0; - this->rJoyV = 0; -} diff --git a/src/engine/modules/renderer.cpp b/src/engine/modules/renderer.cpp deleted file mode 100644 index 92f82d0..0000000 --- a/src/engine/modules/renderer.cpp +++ /dev/null @@ -1,379 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "../include/modules/renderer.hpp" - -#include -#include -#include -#include "../include/utils/debug.hpp" -#include "../include/utils/math.hpp" - -// ---- -// Constructors/Destructors -// ---- - -static const float GS_CENTER = 4096.0F; -static const float SCREEN_CENTER = GS_CENTER / 2.0F; - -/** Initialize DMA<->GIF channel - * Allocate buffers - * Initialize screen - * Initialize drawing environment - * Load/setup textures - * @param screenW Half of screen width - * @param screenH Half of screen height - */ -Renderer::Renderer(u32 t_packetSize, ScreenSettings *t_screen) -{ - consoleLog("Initializing renderer"); - dma_channel_initialize(DMA_CHANNEL_GIF, NULL, 0); // Initialize DMA to enable data transfer - dma_channel_fast_waits(DMA_CHANNEL_GIF); - screen = t_screen; - context = 0; - isTextureVRAMAllocated = false; - isVSyncEnabled = true; - isFrameEmpty = false; - lastTextureId = 0; - flipPacket = packet2_create(4, P2_TYPE_UNCACHED_ACCL, P2_MODE_NORMAL, 0); - allocateBuffers((int)t_screen->width, (int)t_screen->height); - initDrawingEnv(); - setPrim(); - worldColor.r = 0x10; - worldColor.g = 0x10; - worldColor.b = 0x10; - gifSender = new GifSender(t_packetSize, t_screen, &light); - vifSender = new VifSender(&light); - perspective.setPerspective(*t_screen); - renderData.projection = &perspective; - consoleLog("Renderer initialized!"); -} - -Renderer::~Renderer() {} - -// ---- -// Methods -// ---- - -/** Configure and allocate vRAM for texture buffer */ -void Renderer::allocateTextureBuffer(Texture *t_texture) -{ - textureBuffer.width = t_texture->getWidth(); - textureBuffer.psm = t_texture->getType(); - textureBuffer.info.components = textureBuffer.psm == TEX_TYPE_RGBA ? TEXTURE_COMPONENTS_RGBA : TEXTURE_COMPONENTS_RGB; - textureBuffer.address = graph_vram_allocate(t_texture->getWidth(), t_texture->getHeight(), textureBuffer.psm, GRAPH_ALIGN_BLOCK); - assertMsg(textureBuffer.address > 1, "Texture buffer allocation error. No memory!"); - textureBuffer.info.width = draw_log2(t_texture->getWidth()); - textureBuffer.info.height = draw_log2(t_texture->getHeight()); - textureBuffer.info.function = TEXTURE_FUNCTION_MODULATE; - isTextureVRAMAllocated = true; -} - -/** Configure and allocate vRAM for texture buffer */ -void Renderer::deallocateTextureBuffer() -{ - if (isTextureVRAMAllocated) - { - graph_vram_free(textureBuffer.address); - isTextureVRAMAllocated = false; - } -} - -void Renderer::changeTexture(Texture *t_tex) -{ - assertMsg(t_tex != NULL, "Texture was not found in texture repository!"); - if (t_tex->getId() != lastTextureId) - { - lastTextureId = t_tex->getId(); - deallocateTextureBuffer(); - allocateTextureBuffer(t_tex); - GifSender::sendTexture(*t_tex, &textureBuffer); - } -} - -void Renderer::draw(Sprite &t_sprite) -{ - Texture *texture = textureRepo.getBySpriteOrMesh(t_sprite.getId()); - texrect_t rect; - float sizeX, sizeY; - if (t_sprite.getMode() == MODE_REPEAT) - { - sizeX = t_sprite.size.x; - sizeY = t_sprite.size.y; - } - else - { - sizeX = (float)texture->getWidth(); - sizeY = (float)texture->getHeight(); - } - - float texS, texT; - float texMax = texT = texS = sizeX > sizeY ? sizeX : sizeY; - if (sizeX > sizeY) - texT = texMax / (sizeX / sizeY); - else if (sizeY > sizeX) - texS = texMax / (sizeY / sizeX); - rect.t0.s = t_sprite.isFlippedHorizontally() ? texS : 0.0F; - rect.t0.t = t_sprite.isFlippedVertically() ? texT : 0.0F; - rect.t1.s = t_sprite.isFlippedHorizontally() ? 0.0F : texS; - rect.t1.t = t_sprite.isFlippedVertically() ? 0.0F : texT; - rect.color.r = t_sprite.color.r; - rect.color.g = t_sprite.color.g; - rect.color.b = t_sprite.color.b; - rect.color.a = t_sprite.color.a; - rect.color.q = 0; - rect.v0.x = t_sprite.position.x; - rect.v0.y = t_sprite.position.y; - rect.v0.z = (u32)-1; - rect.v1.x = (t_sprite.size.x * t_sprite.scale) + t_sprite.position.x; - rect.v1.y = (t_sprite.size.y * t_sprite.scale) + t_sprite.position.y; - rect.v1.z = (u32)-1; - beginFrameIfNeeded(); - changeTexture(texture); - packet2_t *packet2 = packet2_create(12, P2_TYPE_NORMAL, P2_MODE_NORMAL, 0); - packet2_update(packet2, draw_primitive_xyoffset(packet2->next, 0, SCREEN_CENTER, SCREEN_CENTER)); - packet2_utils_gif_add_set(packet2, 1); - packet2_utils_gs_add_texbuff_clut(packet2, &textureBuffer, &t_sprite.clut); - draw_enable_blending(); - packet2_update(packet2, draw_rect_textured(packet2->next, 0, &rect)); - packet2_update(packet2, - draw_primitive_xyoffset( - packet2->next, - 0, - SCREEN_CENTER - (screen->width / 2.0F), - SCREEN_CENTER - (screen->height / 2.0F))); - draw_disable_blending(); - packet2_update(packet2, draw_finish(packet2->next)); - dma_channel_wait(DMA_CHANNEL_GIF, 0); - dma_channel_send_packet2(packet2, DMA_CHANNEL_GIF, true); - packet2_free(packet2); -} - -/** Initializes drawing environment (1st app packet) */ -void Renderer::initDrawingEnv() -{ - consoleLog("Initializing drawing environment"); - packet2_t *packet2 = packet2_create(20, P2_TYPE_NORMAL, P2_MODE_NORMAL, 0); - packet2_update(packet2, draw_setup_environment(packet2->base, 0, frameBuffers, &(zBuffer))); - packet2_update(packet2, draw_primitive_xyoffset(packet2->next, 0, - SCREEN_CENTER - (screen->width / 2.0F), - SCREEN_CENTER - (screen->height / 2.0F))); - packet2_update(packet2, draw_finish(packet2->next)); - dma_channel_send_packet2(packet2, DMA_CHANNEL_GIF, true); - dma_channel_wait(DMA_CHANNEL_GIF, 0); - packet2_free(packet2); - consoleLog("Drawing environment initialized!"); -} - -/** Sets drawing prim for all 3D objects */ -void Renderer::setPrim() -{ - prim.type = PRIM_TRIANGLE; - prim.shading = PRIM_SHADE_FLAT; - prim.mapping = DRAW_ENABLE; - prim.fogging = DRAW_DISABLE; - prim.blending = DRAW_ENABLE; - prim.antialiasing = DRAW_DISABLE; - prim.mapping_type = PRIM_MAP_ST; - prim.colorfix = PRIM_UNFIXED; - renderData.prim = &prim; - consoleLog("Prim set!"); -} - -void Renderer::setWorldColor(const color_t &t_rgb) -{ - worldColor.r = t_rgb.r; - worldColor.g = t_rgb.g; - worldColor.b = t_rgb.b; -} - -/** Defines and allocates framebuffers and zbuffer */ -void Renderer::allocateBuffers(int t_screenW, int t_screenH) -{ - frameBuffers[0].width = (unsigned int)t_screenW; - frameBuffers[0].height = (unsigned int)t_screenH; - frameBuffers[0].mask = 0; - frameBuffers[0].psm = GS_PSM_32; - frameBuffers[0].address = graph_vram_allocate(t_screenW, t_screenH, frameBuffers[0].psm, GRAPH_ALIGN_PAGE); - - frameBuffers[1].width = (unsigned int)t_screenW; - frameBuffers[1].height = (unsigned int)t_screenH; - frameBuffers[1].mask = 0; - frameBuffers[1].psm = GS_PSM_32; - frameBuffers[1].address = graph_vram_allocate(t_screenW, t_screenH, frameBuffers[1].psm, GRAPH_ALIGN_PAGE); - - zBuffer.enable = DRAW_ENABLE; - zBuffer.mask = 0; - zBuffer.method = ZTEST_METHOD_GREATER_EQUAL; - zBuffer.zsm = GS_ZBUF_24; - zBuffer.address = graph_vram_allocate(t_screenW, t_screenH, zBuffer.zsm, GRAPH_ALIGN_PAGE); - consoleLog("Framebuffers, zBuffer set and allocated!"); - - // Initialize the screen and tie the first framebuffer to the read circuits. - graph_initialize(frameBuffers[0].address, frameBuffers[0].width, frameBuffers[0].height, frameBuffers[0].psm, 0, 0); -} - -/// --- Draw: PATH3 - -// Obsolete -// void Renderer::drawByPath3(Mesh *t_meshes, u16 t_amount, LightBulb *t_bulbs, u16 t_bulbsCount) -// { -// for (u16 i = 0; i < t_amount; i++) -// drawByPath3(t_meshes[i], t_bulbs, t_bulbsCount); -// } - -// Obsolete -// void Renderer::drawByPath3(Mesh &t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount) -// { -// beginFrameIfNeeded(); -// if (!t_mesh.isDataLoaded()) -// PRINT_ERR("Can't draw, because no mesh data was loaded!"); -// if (t_mesh.getCurrentAnimationFrame() != t_mesh.getNextAnimationFrame()) -// t_mesh.animate(); -// for (u32 i = 0; i < t_mesh.getMaterialsCount(); i++) -// { -// MeshMaterial *material = &t_mesh.getMaterial(i); -// if (t_mesh.shouldBeFrustumCulled && !material->isInFrustum(renderData.frustumPlanes, t_mesh.position)) -// return; -// Texture *tex = textureRepo.getBySpriteOrMesh(material->getId()); -// changeTexture(tex); -// gifSender->initPacket(context); -// u32 vertCount = material->getFacesCount(); -// VECTOR *vertices = new VECTOR[vertCount]; -// VECTOR *normals = new VECTOR[vertCount]; -// VECTOR *coordinates = new VECTOR[vertCount]; -// vertCount = t_mesh.getDrawData(i, vertices, normals, coordinates, *renderData.cameraPosition); -// gifSender->addObject(&renderData, t_mesh, vertCount, vertices, normals, coordinates, t_bulbs, t_bulbsCount, &textureBuffer, &material->color); -// gifSender->sendPacket(); -// delete[] vertices; -// delete[] normals; -// delete[] coordinates; -// } -// } - -// Obsolete -// void Renderer::drawByPath3(Mesh *t_meshes, u16 t_amount) { drawByPath3(t_meshes, t_amount, NULL, 0); } - -// Obsolete -// void Renderer::drawByPath3(Mesh &t_mesh) { drawByPath3(t_mesh, NULL, 0); } - -/// --- Draw: PATH1 - -void Renderer::draw(Mesh **t_meshes, u16 t_amount, LightBulb *t_bulbs, u16 t_bulbsCount) -{ - beginFrameIfNeeded(); - assertMsg(t_meshes[0]->isDataLoaded(), "Can't draw, because no mesh data was loaded!"); - if ( - t_amount >= 3 && - !t_meshes[0]->shouldBeBackfaceCulled && - t_meshes[0]->getFramesCount() == 1 && - t_meshes[0]->getMaterialsCount() == 1 && - t_meshes[0]->getFrame(0).getVertexCount() <= 96) - { - vifSender->disableWait(); - Mesh **meshesInFrustum = new Mesh *[t_amount]; - u16 addedMeshes = 0; - for (u16 i = 0; i < t_amount; i++) - if (t_meshes[i]->getMaterial(0).isInFrustum(renderData.frustumPlanes, t_meshes[i]->position)) - meshesInFrustum[addedMeshes++] = t_meshes[i]; - draw(*meshesInFrustum[0], t_bulbs, t_bulbsCount); - draw(*meshesInFrustum[1], t_bulbs, t_bulbsCount); - vifSender->enableWait(); - resetWaitFlag(); - vifSender->drawTheSameWithOtherMatrices(renderData, meshesInFrustum, 2, addedMeshes); - if (isWaitFlagSet()) - resetWaitFlag(); - else - waitForRender(); - delete[] meshesInFrustum; - } - else - for (u16 i = 0; i < t_amount; i++) - draw(*t_meshes[i], t_bulbs, t_bulbsCount); -} - -void Renderer::draw(Mesh &t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount) -{ - beginFrameIfNeeded(); - vifSender->calcMatrix(renderData, t_mesh.position, t_mesh.rotation); - assertMsg(t_mesh.isDataLoaded(), "Can't draw, because no mesh data was loaded!"); - camRotation.identity(); - camRotation.rotate(-t_mesh.rotation); - Vector3 rotatedCamera = Vector3(camRotation * *renderData.cameraPosition); - - if (t_mesh.getCurrentAnimationFrame() != t_mesh.getNextAnimationFrame()) - t_mesh.animate(); - for (u32 i = 0; i < t_mesh.getMaterialsCount(); i++) - { - MeshMaterial *material = &t_mesh.getMaterial(i); - if (t_mesh.shouldBeFrustumCulled && !material->isInFrustum(renderData.frustumPlanes, t_mesh.position)) - return; - u32 vertCount = material->getFacesCount(); - VECTOR vertices[vertCount] __attribute__((aligned(16))); - VECTOR normals[vertCount] __attribute__((aligned(16))); - VECTOR coordinates[vertCount] __attribute__((aligned(16))); - Texture *tex = textureRepo.getBySpriteOrMesh(material->getId()); - changeTexture(tex); - vertCount = t_mesh.getDrawData(i, vertices, normals, coordinates, rotatedCamera); - vifSender->drawMesh(&renderData, perspective, vertCount, vertices, normals, coordinates, t_mesh, t_bulbs, t_bulbsCount, &textureBuffer, &material->color, !material->areSTsPresent()); - } -} - -void Renderer::draw(Mesh **t_meshes, u16 t_amount) { draw(t_meshes, t_amount, NULL, 0); } - -void Renderer::draw(Mesh &t_mesh) { draw(t_mesh, NULL, 0); } - -/// --- - -void Renderer::setCameraDefinitions(Matrix *t_worldView, Vector3 *t_cameraPos, Plane *t_planes) -{ - renderData.view = t_worldView; - renderData.cameraPosition = t_cameraPos; - renderData.frustumPlanes = t_planes; -} - -void Renderer::beginFrameIfNeeded() -{ - if (isFrameEmpty) - { - isFrameEmpty = false; - gifSender->sendClear(&zBuffer, &worldColor); - } -} - -void Renderer::endFrame(float fps) -{ - if (!isFrameEmpty) - { - if (fps > 49.0F && isVSyncEnabled) - graph_wait_vsync(); - flipBuffers(); - } -} - -/** We need to flip buffers outside of the chain, for some reason, - * so we use a separate small packet - * Do not use this method. This is called via packetManager - */ -void Renderer::flipBuffers() -{ - graph_set_framebuffer_filtered( - frameBuffers[context].address, - frameBuffers[context].width, - frameBuffers[context].psm, - 0, - 0); - context ^= 1; - isFrameEmpty = 1; - packet2_update(flipPacket, draw_framebuffer(flipPacket->base, 0, &frameBuffers[context])); - packet2_update(flipPacket, draw_finish(flipPacket->next)); - dma_channel_send_packet2(flipPacket, DMA_CHANNEL_GIF, true); - draw_wait_finish(); -} diff --git a/src/engine/modules/texture_repository.cpp b/src/engine/modules/texture_repository.cpp deleted file mode 100644 index ef35950..0000000 --- a/src/engine/modules/texture_repository.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "../include/modules/texture_repository.hpp" -#include "../include/utils/debug.hpp" - -// ---- -// Constructors/Destructors -// ---- - -TextureRepository::TextureRepository() -{ - consoleLog("Initializing texture repository"); - consoleLog("Texture repository initialized!"); -} - -TextureRepository::~TextureRepository() -{ - if (getTexturesCount() > 0) - { - for (u32 i = 0; i < getTexturesCount(); i++) - delete textures[i]; - textures.clear(); - } -} - -// ---- -// Methods -// ---- - -Texture *TextureRepository::add(char *t_subfolder, char *t_name, TextureFormat t_format) -{ - Texture *texture = new Texture(); - if (t_format == BMP) - bmpLoader.load(*texture, t_subfolder, t_name, ".bmp"); - else - pngLoader.load(*texture, t_subfolder, t_name, ".png"); - texture->setName(t_name); - textures.push_back(texture); - return texture; -} - -void TextureRepository::addByMesh(char *t_path, Mesh &mesh, TextureFormat t_format) -{ - for (u32 i = 0; i < mesh.getMaterialsCount(); i++) - { - Texture *texture = new Texture(); - if (t_format == BMP) - bmpLoader.load(*texture, t_path, mesh.getMaterial(i).getName(), ".bmp"); - else - pngLoader.load(*texture, t_path, mesh.getMaterial(i).getName(), ".png"); - texture->setName(mesh.getMaterial(i).getName()); - texture->addLink(mesh.getMaterial(i).getId()); - textures.push_back(texture); - } -} diff --git a/src/engine/modules/timer.cpp b/src/engine/modules/timer.cpp deleted file mode 100644 index ac20ba8..0000000 --- a/src/engine/modules/timer.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "../include/modules/timer.hpp" - -// ---- -// Constructors/Destructors -// ---- - -Timer::Timer() { prime(); } - -Timer::~Timer() {} - -// ---- -// Methods -// ---- - -u32 Timer::getTimeDelta() -{ - time = *T3_COUNT; - - if (time < lastTime) // The counter has wrapped - change = time + (65536 - lastTime); - else - change = time - lastTime; - return change; -} - -float Timer::getFPS() -{ - u32 timeDelta = this->getTimeDelta(); - - if (timeDelta == 0) - return -1.0F; - - return 15625.0F / (float)timeDelta; // PAL -} diff --git a/src/engine/modules/vif_sender.cpp b/src/engine/modules/vif_sender.cpp deleted file mode 100644 index 544edbc..0000000 --- a/src/engine/modules/vif_sender.cpp +++ /dev/null @@ -1,250 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "../include/modules/vif_sender.hpp" - -#include -#include -#include -#include "../include/utils/math.hpp" -#include "../include/utils/debug.hpp" - -const u32 VU1_PACKAGE_VERTS_PER_BUFF = 96; // Remember to modify buffer size in vu1 also -const u32 VU1_PACKAGES_PER_PACKET = 9; -const u32 VU1_PACKET_SIZE = 256; // should be 128, but 256 is more safe for future -const u8 VU1_PARAMS_ADDRESS = 4; -const u8 VU1_RGBA_ADDRESS = 8; - -// ---- -// Constructors/Destructors -// ---- - -// VU1 micro program -extern u32 VU1Draw3D_CodeStart __attribute__((section(".vudata"))); -extern u32 VU1Draw3D_CodeEnd __attribute__((section(".vudata"))); -// - -VifSender::VifSender(Light *t_light) -{ - consoleLog("Initializing VifSender"); - light = t_light; - lastVertCount = 0; - isDrawWaitEnabled = true; - dma_channel_initialize(DMA_CHANNEL_VIF1, NULL, 0); - dma_channel_fast_waits(DMA_CHANNEL_VIF1); - uploadMicroProgram(); - packets[0] = packet2_create(VU1_PACKET_SIZE, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); - packets[1] = packet2_create(VU1_PACKET_SIZE, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); - context = 0; - setDoubleBufferAddStaticData(); - consoleLog("VifSender initialized!"); -} - -VifSender::~VifSender() -{ - packet2_free(packets[0]); - packet2_free(packets[1]); -} - -// ---- -// Methods -// ---- - -void VifSender::uploadMicroProgram() -{ - packet2_t *packet2 = packet2_create( - packet2_utils_get_packet_size_for_program(&VU1Draw3D_CodeStart, &VU1Draw3D_CodeEnd) + 1, // + end tag - P2_TYPE_NORMAL, - P2_MODE_CHAIN, - 1); - packet2_vif_add_micro_program(packet2, 0, &VU1Draw3D_CodeStart, &VU1Draw3D_CodeEnd); - packet2_utils_vu_add_end_tag(packet2); - dma_channel_wait(DMA_CHANNEL_VIF1, 0); - dma_channel_send_packet2(packet2, DMA_CHANNEL_VIF1, 1); - packet2_free(packet2); -} - -void VifSender::calcMatrix(const RenderData &t_renderData, const Vector3 &t_position, const Vector3 &t_rotation) -{ - model.identity(); - model.rotate(t_rotation); - model.translate(t_position); - - modelViewProj.identity(); - modelViewProj = model * modelViewProj; - modelViewProj = *t_renderData.view * modelViewProj; - modelViewProj = *t_renderData.projection * modelViewProj; -} - -void VifSender::drawMesh(RenderData *t_renderData, Matrix t_perspective, u32 vertCount2, VECTOR *vertices, VECTOR *normals, VECTOR *coordinates, Mesh &t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount, texbuffer_t *textureBuffer, color_t *t_color, u8 t_rgbaOnly) -{ - // we have to split 3D object into small parts, because of small memory of VU1 - - for (u32 i = 0; i < vertCount2;) - { - currPacket = packets[context]; - packet2_reset(currPacket, false); - for (u8 j = 0; j < VU1_PACKAGES_PER_PACKET; j++) // how many "packages" per one packet - { - if (i != 0) // we have to go back to avoid the visual artifacts - i -= 3; - - const u32 endI = i + (VU1_PACKAGE_VERTS_PER_BUFF - 1) > vertCount2 ? vertCount2 : i + (VU1_PACKAGE_VERTS_PER_BUFF - 1); - drawVertices(t_mesh, i, endI, vertices, coordinates, t_renderData->prim, textureBuffer, isDrawWaitEnabled ? endI == vertCount2 : false, t_color, t_rgbaOnly); - if (endI == vertCount2) // if there are no more vertices to draw, break - { - i = vertCount2; - break; - } - i += (VU1_PACKAGE_VERTS_PER_BUFF - 1); - i++; - } - packet2_utils_vu_add_end_tag(currPacket); - dma_channel_send_packet2(currPacket, DMA_CHANNEL_VIF1, 1); - dma_channel_wait(DMA_CHANNEL_VIF1, 0); - context = !context; - } -} - -void VifSender::setDoubleBufferAddStaticData() -{ - packet2_t *settings = packet2_create(10, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); - packet2_utils_vu_open_unpack(settings, 0, false); - { - packet2_utils_gs_add_draw_finish_giftag(settings); - packet2_utils_gif_add_set(settings, 1); - } - packet2_utils_vu_close_unpack(settings); - packet2_utils_vu_add_double_buffer(settings, 10, 498); - packet2_utils_vu_add_end_tag(settings); - dma_channel_send_packet2(settings, DMA_CHANNEL_VIF1, true); - dma_channel_wait(DMA_CHANNEL_VIF1, 0); - packet2_free(settings); -} - -/** Draw using PATH1 */ -void VifSender::drawVertices(Mesh &t_mesh, u32 t_start, u32 t_end, VECTOR *t_vertices, VECTOR *t_coordinates, prim_t *t_prim, texbuffer_t *t_texBuff, u8 t_addDrawWait, color_t *t_color, u8 t_rgbaOnly) -{ - const u32 vertCount = t_end - t_start; - lastVertCount = vertCount; - isLastRGBAOnly = t_rgbaOnly; - packet2_utils_vu_open_unpack(currPacket, 0, true); - packet2_add_data(currPacket, modelViewProj.data, 4); - packet2_add_u32(currPacket, t_addDrawWait); // Draw finish? - packet2_add_u32(currPacket, vertCount); // Vertex count - packet2_add_u32(currPacket, vertCount / 3); // Triangles count - packet2_add_u32(currPacket, t_rgbaOnly); // 0 = STQ+RGBA, 1 = RGBA - packet2_utils_gs_add_lod(currPacket, &t_mesh.lod); - packet2_utils_gs_add_texbuff_clut(currPacket, t_texBuff, &t_mesh.clut); - if (t_rgbaOnly) - packet2_utils_gs_add_prim_giftag(currPacket, t_prim, vertCount, DRAW_RGBAQ_REGLIST, 2, 0); - else - packet2_utils_gs_add_prim_giftag(currPacket, t_prim, vertCount, DRAW_STQ2_REGLIST, 3, 0); - packet2_add_u32(currPacket, t_color->r); - packet2_add_u32(currPacket, t_color->g); - packet2_add_u32(currPacket, t_color->b); - packet2_add_u32(currPacket, t_color->a); - u32 vif_added_bytes = packet2_utils_vu_close_unpack(currPacket); - packet2_utils_vu_add_unpack_data(currPacket, vif_added_bytes, t_vertices + t_start, vertCount, true); - if (!t_rgbaOnly) - { - vif_added_bytes += vertCount; - packet2_utils_vu_add_unpack_data(currPacket, vif_added_bytes, t_coordinates + t_start, vertCount, true); - } - packet2_utils_vu_add_start_program(currPacket, 0); -} - -void VifSender::drawTheSameWithOtherMatrices(const RenderData &t_renderData, Mesh **t_meshes, const u32 &t_skip, const u32 &t_count) -{ - // Standard double buffering (packets) - packet2_t *packet1 = packet2_create(300, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); - packet2_t *packet2 = packet2_create(300, P2_TYPE_NORMAL, P2_MODE_CHAIN, true); - packet2_t *currMPacket = packet1; - u8 currPacketIndex = 1; - - // We are sending 32 matrices max per one VU1 send - u8 switchCounter = 0; - for (u32 i = t_skip; i < t_count; i++) - { - model.identity(); - model.rotate(t_meshes[i]->rotation); - model.translate(t_meshes[i]->position); - - modelViewProj.identity(); - modelViewProj = model * modelViewProj; - modelViewProj = *t_renderData.view * modelViewProj; - modelViewProj = *t_renderData.projection * modelViewProj; - - packet2_utils_vu_open_unpack(currMPacket, 0, true); - { - packet2_add_data(currMPacket, modelViewProj.data, 4); - } - packet2_utils_vu_close_unpack(currMPacket); - packet2_utils_vu_open_unpack(currMPacket, VU1_RGBA_ADDRESS, true); - { - packet2_add_u32(currMPacket, t_meshes[i]->getMaterial(0).color.r); - packet2_add_u32(currMPacket, t_meshes[i]->getMaterial(0).color.g); - packet2_add_u32(currMPacket, t_meshes[i]->getMaterial(0).color.b); - packet2_add_u32(currMPacket, t_meshes[i]->getMaterial(0).color.a); - } - packet2_utils_vu_close_unpack(currMPacket); - - if (i != t_count - 1) // if it is last, we must also add draw wait finish interrupt. - packet2_utils_vu_add_start_program(currMPacket, 0); - - if (switchCounter++ >= 32) - { - switchCounter = 0; - if (i == t_count - 1) // is last - { - packet2_utils_vu_open_unpack(currMPacket, VU1_PARAMS_ADDRESS, true); - { - packet2_add_u32(currMPacket, true); // Draw wait finish? - packet2_add_u32(currMPacket, lastVertCount); // Vertex count - packet2_add_u32(currMPacket, lastVertCount / 3); // Triangles count - packet2_add_u32(currMPacket, isLastRGBAOnly); // 0 = STQ+RGBA, 1 = RGBA - } - packet2_utils_vu_close_unpack(currMPacket); - packet2_utils_vu_add_start_program(currMPacket, 0); // and start program - } - packet2_utils_vu_add_end_tag(currMPacket); - dma_channel_wait(DMA_CHANNEL_VIF1, 0); - dma_channel_send_packet2(currMPacket, DMA_CHANNEL_VIF1, 1); - if (currPacketIndex == 1) // Switch double buffer (packets) - { - currPacketIndex = 2; - currMPacket = packet2; - } - else - { - currPacketIndex = 1; - currMPacket = packet1; - } - packet2_reset(currMPacket, false); - } - } - if (switchCounter != 0) // if there are any not sended matrices - { - packet2_utils_vu_open_unpack(currMPacket, VU1_PARAMS_ADDRESS, true); - { - packet2_add_u32(currMPacket, true); // Draw wait finish? - packet2_add_u32(currMPacket, lastVertCount); // Vertex count - packet2_add_u32(currMPacket, lastVertCount / 3); // Triangles count - packet2_add_u32(currMPacket, isLastRGBAOnly); // 0 = STQ+RGBA, 1 = RGBA - } - packet2_utils_vu_close_unpack(currMPacket); - packet2_utils_vu_add_start_program(currMPacket, 0); - packet2_utils_vu_add_end_tag(currMPacket); - dma_channel_wait(DMA_CHANNEL_VIF1, 0); - dma_channel_send_packet2(currMPacket, DMA_CHANNEL_VIF1, 1); - } - packet2_free(packet1); - packet2_free(packet2); -} diff --git a/src/engine/utils/math.cpp b/src/engine/utils/math.cpp deleted file mode 100644 index e9bd11d..0000000 --- a/src/engine/utils/math.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "../include/utils/math.hpp" - -#include - -float Math::cos(float x) -{ - float r; - asm volatile( - "lui $9, 0x3f00 \n\t" - ".set noreorder \n\t" - ".align 3 \n\t" - "abs.s %0, %1 \n\t" - "lui $8, 0xbe22 \n\t" - "mtc1 $9, $f1 \n\t" - "ori $8, $8, 0xf983 \n\t" - "mtc1 $8, $f8 \n\t" - "lui $9, 0x4b00 \n\t" - "mtc1 $9, $f3 \n\t" - "lui $8, 0x3f80 \n\t" - "mtc1 $8, $f2 \n\t" - "mula.s %0, $f8 \n\t" - "msuba.s $f3, $f2 \n\t" - "madda.s $f3, $f2 \n\t" - "lui $8, 0x40c9 \n\t" - "msuba.s %0, $f8 \n\t" - "ori $8, 0x0fdb \n\t" - "msub.s %0, $f1, $f2 \n\t" - "lui $9, 0xc225 \n\t" - "abs.s %0, %0 \n\t" - "lui $10, 0x3e80 \n\t" - "mtc1 $10, $f7 \n\t" - "ori $9, 0x5de1 \n\t" - "sub.s %0, %0, $f7 \n\t" - "lui $10, 0x42a3 \n\t" - "mtc1 $8, $f3 \n\t" - "ori $10, 0x3458 \n\t" - "mtc1 $9, $f4 \n\t" - "lui $8, 0xc299 \n\t" - "mtc1 $10, $f5 \n\t" - "ori $8, 0x2663 \n\t" - "mul.s $f8, %0, %0 \n\t" - "lui $9, 0x421e \n\t" - "mtc1 $8, $f6 \n\t" - "ori $9, 0xd7bb \n\t" - "mtc1 $9, $f7 \n\t" - "nop \n\t" - "mul.s $f1, %0, $f8 \n\t" - "mul.s $f9, $f8, $f8 \n\t" - "mula.s $f3, %0 \n\t" - "mul.s $f2, $f1, $f8 \n\t" - "madda.s $f4, $f1 \n\t" - "mul.s $f1, $f1, $f9 \n\t" - "mul.s %0, $f2, $f9 \n\t" - "madda.s $f5, $f2 \n\t" - "madda.s $f6, $f1 \n\t" - "madd.s %0, $f7, %0 \n\t" - ".set reorder \n\t" - : "=&f"(r) - : "f"(x) - : "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", "$8", "$9", "$10"); - return r; -} - -float Math::invSqrt(float x) { return 1.0F / sqrt(x); } - -/** Converts Vector3 to PS2SDK's Vector4 */ -void vec3ToNative(VECTOR o_result, const Vector3 &t_vec, float t_fourthVal) -{ - o_result[0] = t_vec.x; - o_result[1] = t_vec.y; - o_result[2] = t_vec.z; - o_result[3] = t_fourthVal; -} - -/** Converts array of Vector3 to array of PS2SDK's Vector4 */ -void manyVec3ToNative(VECTOR *o_result, Vector3 *t_vec, int t_amount, float t_fourthVal) -{ - for (int i = 0; i < t_amount; i++) - vec3ToNative(o_result[i], t_vec[i], t_fourthVal); -} - -float Math::asin(float x) -{ - float r; - asm volatile( - "lui $9, 0x3f00 \n\t" - ".set noreorder \n\t" - ".align 3 \n\t" - "abs.s %0, %1 \n\t" - "lui $8, 0xbe22 \n\t" - "mtc1 $9, $f1 \n\t" - "ori $8, $8, 0xf983 \n\t" - "mtc1 $8, $f8 \n\t" - "lui $9, 0x4b00 \n\t" - "mtc1 $9, $f3 \n\t" - "lui $8, 0x3f80 \n\t" - "mtc1 $8, $f2 \n\t" - "mula.s %0, $f8 \n\t" - "msuba.s $f3, $f2 \n\t" - "madda.s $f3, $f2 \n\t" - "lui $8, 0x40c9 \n\t" - "msuba.s %0, $f8 \n\t" - "ori $8, 0x0fdb \n\t" - "msub.s %0, $f1, $f2 \n\t" - "lui $9, 0xc225 \n\t" - "abs.s %0, %0 \n\t" - "lui $10, 0x3e80 \n\t" - "mtc1 $10, $f7 \n\t" - "ori $9, 0x5de1 \n\t" - "sub.s %0, %0, $f7 \n\t" - "lui $10, 0x42a3 \n\t" - "mtc1 $8, $f3 \n\t" - "ori $10, 0x3458 \n\t" - "mtc1 $9, $f4 \n\t" - "lui $8, 0xc299 \n\t" - "mtc1 $10, $f5 \n\t" - "ori $8, 0x2663 \n\t" - "mul.s $f8, %0, %0 \n\t" - "lui $9, 0x421e \n\t" - "mtc1 $8, $f6 \n\t" - "ori $9, 0xd7bb \n\t" - "mtc1 $9, $f7 \n\t" - "nop \n\t" - "mul.s $f1, %0, $f8 \n\t" - "mul.s $f9, $f8, $f8 \n\t" - "mula.s $f3, %0 \n\t" - "mul.s $f2, $f1, $f8 \n\t" - "madda.s $f4, $f1 \n\t" - "mul.s $f1, $f1, $f9 \n\t" - "mul.s %0, $f2, $f9 \n\t" - "madda.s $f5, $f2 \n\t" - "madda.s $f6, $f1 \n\t" - "madd.s %0, $f7, %0 \n\t" - ".set reorder \n\t" - : "=&f"(r) - : "f"(x) - : "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", "$8", "$9", "$10"); - return r; -} - -float Math::mod(float x, float y) -{ - /* - * Portable fmod(x,y) implementation for systems - * that don't have it. Adapted from code found here: - * http://www.opensource.apple.com/source/python/python-3/python/Python/fmod.c - */ - float i, f; - - if (y == 0.0f) - { - return 0.0f; - } - - i = floorf(x / y); - f = x - i * y; - - if ((x < 0.0f) != (y < 0.0f)) - { - f = f - y; - } - - return f; -} diff --git a/src/engine/utils/string.cpp b/src/engine/utils/string.cpp deleted file mode 100644 index a6d06f1..0000000 --- a/src/engine/utils/string.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "../include/utils/string.hpp" -#include "../include/utils/debug.hpp" -#include -#define CHAR_BIT 8 - -char *String::createU32ToString(const u32 a) -{ - char *result = new char[(((sizeof a) * CHAR_BIT) + 2) / 3 + 2]; - sprintf(result, "%d", a); - return result; -} - -/** Converts "123" to "000123". 6 digits length */ -char *String::createWithLeadingZeros(const char *a) -{ - const u8 digitsAmount = 6; - char *part = createConcatenated("00000000", a); - u16 partLength = getLength(part); - u16 insert = 0; - char *result = new char[digitsAmount + 1]; - for (u16 i = partLength - digitsAmount; i < partLength; i++) - result[insert++] = part[i]; - delete[] part; - result[digitsAmount] = '\0'; - return result; -} - -char *String::createWithoutExtension(const char *source) -{ - u32 length = 0; - for (;; length++) - if (source[length] == '.') - break; - char *res = new char[length + 1]; - for (u32 i = 0; i < length; i++) - res[i] = source[i]; - res[length] = '\0'; - return res; -} - -char *String::createCopy(const char *source) -{ - u32 srcLength = getLength(source); - char *res = new char[srcLength + 1]; - for (u32 i = 0; i < srcLength; i++) - res[i] = source[i]; - res[srcLength] = '\0'; - return res; -} - -// For test\0 will return 4 -u32 String::getLength(const char *a) -{ - if (a == NULL) - return 0; - for (u32 i = 0;; i++) - if (a[i] == '\0') - return i; -} - -char *String::createConcatenated(const char *a, const char *b) -{ - u32 aLength = getLength(a); - u32 bLength = getLength(b); - char *res = new char[aLength + bLength + 1]; // + '\0' - for (u32 i = 0; i < aLength; i++) - res[i] = a[i]; - for (u32 i = 0; i < bLength; i++) - res[aLength + i] = b[i]; - res[aLength + bLength] = '\0'; - return res; -} diff --git a/src/engine/vu1_progs/draw3D.vclpp b/src/engine/vu1_progs/draw3D.vclpp deleted file mode 100644 index 7cbe82a..0000000 --- a/src/engine/vu1_progs/draw3D.vclpp +++ /dev/null @@ -1,190 +0,0 @@ -; ______ ____ ___ -; | \/ ____| |___| -; | | | \ | | -;--------------------------- -; Copyright 2020, tyra - https://github.com/h4570/tyra -; Sandro Sobczyński -; -;--------------------------------------------------------------- -; draw3D.vcl | -;--------------------------------------------------------------- -; First tyra VU1 microprogram. | -; Features: | -; - Draw triangles (no strip) with STQ (textures) and 1 RGBA. | -; This program uses double buffering (xtop) | -; | -; I want to say thank you to: | -; - Dr Henry Fortuna - for teaching how things work | -; - Jesper Svennevid, Daniel Collin - for openvcl samples | -; - Guilherme Lampert - for VU1 idea for PS2 Quake and vclpp | -; - Tyler Daniel - for PS2GL source code for PS2 Linux | -;--------------------------------------------------------------- - -; TODO -; - Add dynamic lighting (feature) -; - Add --cont + MSCNT instead of alltime MSCAL -; - Split this program into two (RBA/STQ), so we can get better performance - -#include "/repos/tyra/src/engine/vu1_progs/geometry.inc" -#include "/repos/tyra/src/engine/vu1_progs/matrix.inc" -#include "/repos/tyra/src/engine/vu1_progs/vector.inc" - -#vuprog draw3D - -.syntax new -.name VU1Draw3D -.vu -.init_vf_all -.init_vi_all - ---enter ---endenter - -;///////////// LOAD STATIC DATA ///////////// -lq gif_draw_finish_tag, 0(vi00) ; GIF tag - wait -lq gif_set_tag, 1(vi00) ; GIF tag - set -;//////////////////////////////////////////// - -xtop double_buffer - -;//////// LOAD CURRENT BUFFER DATA ////////// -MatrixLoad{ matrix, 0, double_buffer } -ilw.x do_draw_finish, 4(double_buffer) ; Add draw finish tag? (sync) -ilw.y vertex_count, 4(double_buffer) ; Vertex count -ilw.z triangles_count, 4(double_buffer) ; Triangles count -ilw.w rgba_only, 4(double_buffer) ; RGBA (1) or STQ+RGBA (0) -lq tex_gif_tag_1, 5(double_buffer) ; GIF tag - texture LOD -lq tex_gif_tag_2, 6(double_buffer) ; GIF tag - texture buffer & CLUT -lq prim_tag, 7(double_buffer) ; GIF tag - tell GS how many data we will send -lq rgba, 8(double_buffer) ; Mesh RGBA - -iaddiu vertex_data, double_buffer, 9 ; pointer to vertex data -iadd stq_data, vertex_data, vertex_count ; pointer to stq -iadd kick_address, stq_data, vertex_count ; pointer for XGKICK -iadd dest_address, stq_data, vertex_count ; helper pointer for data inserting -;//////////////////////////////////////////// - -LoadScaleConstant{ gs_scale } -fcset 0x000000 ; VCL won't let us use CLIP without first zeroing the clip flags - -;/////////////// STORE TAGS ///////////////// -sqi gif_set_tag, (dest_address++) ; -sqi tex_gif_tag_1, (dest_address++) ; texture LOD tag -sqi gif_set_tag, (dest_address++) ; -sqi tex_gif_tag_2, (dest_address++) ; texture buffer & CLUT tag -iblez do_draw_finish, prim_tag_l -sqi gif_set_tag, (dest_address++) ; -sqi gif_draw_finish_tag, (dest_address++) ; do draw_finish is needed -prim_tag_l: -sqi prim_tag, (dest_address++) ; prim + tell gs how many data will be -;//////////////////////////////////////////// - -;//////// FIX ADC BIT FOR CLIPPING ////////// -iaddiu adc_bit, vi00, 0x7FFF -iaddiu adc_bit, adc_bit, 1 -;//////////////////////////////////////////// - -;/////////// START TRIANGLE LOOP //////////// -iaddiu triangle_counter, vi00, 0 ; Reset counter -triangle_loop: --LoopCS 1,3 - - ;//////////////// VERTEX 1 ////////////////// - vec1: - VectorLoad{ vertex, vertex_data, 0 } - MatrixXForm{ xformed_vertex, matrix, vertex } - VectorClip{ gs_vertex, xformed_vertex } - VectorPerspectiveDivide{ xformed_vertex } - VectorAddGSScales{ gs_vertex, xformed_vertex, gs_scale } - - ibgtz rgba_only, vec_1_rgba - - vec_1_stq_rgba: - VectorLoad{ stq1, stq_data, 0 } - VectorTexturePerspectiveCorrection{ pers_stq, stq1 } - VectorStore{ pers_stq, dest_address, 0 } - VectorStore{ rgba, dest_address, 1 } - VectorStore{ gs_vertex, dest_address, 2 } - ibeq vi00, vi00, vec2 - - vec_1_rgba: - VectorStore{ rgba, dest_address, 0 } - VectorStore{ gs_vertex, dest_address, 1 } - - ;//////////////////////////////////////////// - - ;//////////////// VERTEX 2 ////////////////// - vec2: - VectorLoad{ vertex, vertex_data, 1 } - MatrixXForm{ xformed_vertex, matrix, vertex } - VectorClip{ gs_vertex, xformed_vertex } - VectorPerspectiveDivide{ xformed_vertex } - VectorAddGSScales{ gs_vertex, xformed_vertex, gs_scale } - - ibgtz rgba_only, vec_2_rgba - - vec_2_stq_rgba: - VectorLoad{ stq2, stq_data, 1 } - VectorTexturePerspectiveCorrection{ pers_stq, stq2 } - VectorStore{ pers_stq, dest_address, 3 } - VectorStore{ rgba, dest_address, 4 } - VectorStore{ gs_vertex, dest_address, 5 } - ibeq vi00, vi00, vec3 - - vec_2_rgba: - VectorStore{ rgba, dest_address, 2 } - VectorStore{ gs_vertex, dest_address, 3 } - - ;//////////////////////////////////////////// - - ;//////////////// VERTEX 3 ////////////////// - vec3: - VectorLoad{ vertex, vertex_data, 2 } - MatrixXForm{ xformed_vertex, matrix, vertex } - VectorClip{ gs_vertex, xformed_vertex } - VectorPerspectiveDivide{ xformed_vertex } - VectorAddGSScales{ gs_vertex, xformed_vertex, gs_scale } - - fcand vi01, 0x03FFFF - iaddiu new_adc_bit, vi01, 0x7FFF - mfir.w gs_vertex, new_adc_bit - - ibgtz rgba_only, vec_3_rgba - - vec_3_stq_rgba: - VectorLoad{ stq3, stq_data, 2 } - VectorTexturePerspectiveCorrection{ pers_stq, stq3 } - VectorStore{ pers_stq, dest_address, 6 } - VectorStore{ rgba, dest_address, 7 } - VectorStore{ gs_vertex, dest_address, 8 } - iaddiu dest_address, dest_address, 9 // Loop control - ibeq vi00, vi00, loop_ctrl - - vec_3_rgba: - VectorStore{ rgba, dest_address, 4 } - VectorStore{ gs_vertex, dest_address, 5 } - iaddiu dest_address, dest_address, 6 // Loop control - - ;//////////////////////////////////////////// - - ;////////////// LOOP CONTROL //////////////// - loop_ctrl: - iaddiu vertex_data, vertex_data, 3 - iaddiu stq_data, stq_data, 3 - - iaddiu triangle_counter, triangle_counter, 1 // Incrementing this - // by other value than 1 is causing HUGE problems, but.. why? - // My first idea was do vertex_counter and incrementing by 3 - ibne triangle_counter, triangles_count, triangle_loop - ;//////////////////////////////////////////// - -;//////////////////////////////////////////// - ---barrier - - -xgkick kick_address ; dispatch to the GS rasterizer. - ---exit ---endexit - -#endvuprog \ No newline at end of file diff --git a/src/engine/vu1_progs/draw3D.vsm b/src/engine/vu1_progs/draw3D.vsm deleted file mode 100644 index b1c0afa..0000000 --- a/src/engine/vu1_progs/draw3D.vsm +++ /dev/null @@ -1,149 +0,0 @@ -;------------------------- -;------------------------- -;-----VCL CODE------------ -;------------------------- -;------------------------- -; ================================================= -; flowMon::Emit() vcl 1.4beta7 produced this code: - .vu - .align 4 - .global VU1Draw3D_CodeStart - .global VU1Draw3D_CodeEnd -VU1Draw3D_CodeStart: -__v_draw3D_vcl_4: -; _LNOPT_w=[ normal2 ] 27 [27 0] 27 [__v_draw3D_vcl_4] - NOP xtop VI06 - NOP lq VF02,1(VI00) - NOP lq VF01,0(VI00) - NOP ilw.x VI01,4(VI06) - NOP ilw.y VI08,4(VI06) - NOP lq VF03,0(VI06) - NOP lq VF04,1(VI06) - NOP lq VF08,5(VI06) - NOP lq VF10,6(VI06) - NOP lq VF05,2(VI06) - NOP lq VF06,3(VI06) - NOP iaddiu VI04,VI06,0x00000009 - NOP iadd VI05,VI04,VI08 - NOP ilw.z VI02,4(VI06) - NOP iadd VI07,VI05,VI08 - NOP loi 0x44fff000 - NOP ilw.w VI03,4(VI06) - NOP lq VF07,7(VI06) - NOP sqi VF02,(VI07++) - NOP sqi VF08,(VI07++) - NOP sqi VF02,(VI07++) - NOP lq VF08,8(VI06) - NOP iadd VI06,VI05,VI08 - addi.xy VF09,VF00,I loi 0x492aaaaa - NOP fcset 0 - NOP iblez VI01,prim_tag_l - addi.z VF09,VF00,I sqi VF10,(VI07++) -; _LNOPT_w=[ normal2 ] 2 [2 0] 2 [__v_draw3D_vcl_5] - NOP sqi VF02,(VI07++) - NOP sqi VF01,(VI07++) -prim_tag_l: -; _LNOPT_w=[ normal2 ] 4 [4 0] 4 [prim_tag_l] - NOP iaddiu VI08,VI00,0x00007fff - NOP sqi VF07,(VI07++) - NOP iaddiu VI08,VI08,0x00000001 - NOP iaddiu VI09,VI00,0 -triangle_loop: -; _LNOPT_w=[ normal2 ] 11 [27 0] 27 [triangle_loop] - NOP lq VF02,0(VI04) - mulax ACC,VF03,VF02x mfir.w VF01,VI08 ; STALL_LATENCY ?3 - madday ACC,VF04,VF02y NOP - maddaz ACC,VF05,VF02z NOP - maddw VF02,VF06,VF02w NOP - clipw.xyz VF02xyz,VF02w div Q,VF00w,VF02w ; STALL_LATENCY ?3 - mulq.xyz VF02,VF02,Q waitq ; STALL_LATENCY ?6 - mulaw.xyz ACC,VF09,VF00w NOP - madd.xyz VF02,VF02,VF09 NOP ; STALL_LATENCY ?2 - NOP ibgtz VI03,vec_1_rgba - ftoi4.xyz VF01,VF02 NOP ; STALL_LATENCY ?2 -; _LNOPT_w=[ normal2 ] 5 [9 0] 9 [vec_1_stq_rgba] - NOP lq VF02,0(VI05) - mulq VF01,VF02,Q sq VF01,2(VI07) ; STALL_LATENCY ?3 - NOP sq VF08,1(VI07) - NOP b vec2 - NOP sq VF01,0(VI07) ; STALL_LATENCY ?1 -vec_1_rgba: -; _LNOPT_w=[ normal2 ] 4 [2 0] 4 [vec_1_rgba] - NOP NOP - NOP NOP - NOP sq VF08,0(VI07) - NOP sq VF01,1(VI07) -vec2: -; _LNOPT_w=[ normal2 ] 11 [27 0] 27 [vec2] - NOP lq VF02,1(VI04) - mulax ACC,VF03,VF02x mfir.w VF01,VI08 ; STALL_LATENCY ?3 - madday ACC,VF04,VF02y NOP - maddaz ACC,VF05,VF02z NOP - maddw VF02,VF06,VF02w NOP - clipw.xyz VF02xyz,VF02w div Q,VF00w,VF02w ; STALL_LATENCY ?3 - mulq.xyz VF02,VF02,Q waitq ; STALL_LATENCY ?6 - mulaw.xyz ACC,VF09,VF00w NOP - madd.xyz VF02,VF02,VF09 NOP ; STALL_LATENCY ?2 - NOP ibgtz VI03,vec_2_rgba - ftoi4.xyz VF01,VF02 NOP ; STALL_LATENCY ?2 -; _LNOPT_w=[ normal2 ] 5 [9 0] 9 [vec_2_stq_rgba] - NOP lq VF02,1(VI05) - mulq VF01,VF02,Q sq VF01,5(VI07) ; STALL_LATENCY ?3 - NOP sq VF08,4(VI07) - NOP b vec3 - NOP sq VF01,3(VI07) ; STALL_LATENCY ?1 -vec_2_rgba: -; _LNOPT_w=[ normal2 ] 4 [2 0] 4 [vec_2_rgba] - NOP NOP - NOP NOP - NOP sq VF08,2(VI07) - NOP sq VF01,3(VI07) -vec3: -; _LNOPT_w=[ normal2 ] 13 [27 0] 27 [vec3] - NOP lq VF01,2(VI04) - mulax ACC,VF03,VF01x NOP ; STALL_LATENCY ?3 - madday ACC,VF04,VF01y NOP - maddaz ACC,VF05,VF01z NOP - maddw VF01,VF06,VF01w NOP - clipw.xyz VF01xyz,VF01w div Q,VF00w,VF01w ; STALL_LATENCY ?3 - mulq.xyz VF01,VF01,Q waitq ; STALL_LATENCY ?6 - mulaw.xyz ACC,VF09,VF00w NOP - madd.xyz VF01,VF01,VF09 fcand VI01,262143 ; STALL_LATENCY ?2 - NOP iaddiu VI01,VI01,0x00007fff - NOP mfir.w VF01,VI01 - NOP ibgtz VI03,vec_3_rgba - ftoi4.xyz VF01,VF01 NOP -; _LNOPT_w=[ normal2 ] 6 [9 0] 9 [vec_3_stq_rgba] - NOP lq VF02,2(VI05) - mulq VF01,VF02,Q sq VF01,8(VI07) ; STALL_LATENCY ?3 - NOP sq VF08,7(VI07) - NOP iaddiu VI07,VI07,0x00000009 - NOP b loop_ctrl - NOP sq VF01,-3(VI07) -vec_3_rgba: -; _LNOPT_w=[ normal2 ] 4 [3 0] 4 [vec_3_rgba] - NOP NOP - NOP sq VF08,4(VI07) - NOP iaddiu VI07,VI07,0x00000006 - NOP sq VF01,-1(VI07) -loop_ctrl: -; _LNOPT_w=[ normal2 ] 4 [4 0] 4 [loop_ctrl] - NOP iaddiu VI09,VI09,0x00000001 - NOP iaddiu VI04,VI04,0x00000003 - NOP ibne VI09,VI02,triangle_loop - NOP iaddiu VI05,VI05,0x00000003 -; _LNOPT_w=[ normal2 ] 3 [1 0] 3 [__v_draw3D_vcl_21] - NOP xgkick VI06 - NOP[E] NOP - NOP NOP - .align 4 -VU1Draw3D_CodeEnd: -; iCount=103 -; register stats: -; 10 VU User integer -; 11 VU User floating point -;------------------------- -;------------------------- -;------------------------- -;------------------------- -;------------------------- diff --git a/src/engine/vu1_progs/geometry.inc b/src/engine/vu1_progs/geometry.inc deleted file mode 100644 index 2562412..0000000 --- a/src/engine/vu1_progs/geometry.inc +++ /dev/null @@ -1,7 +0,0 @@ -; Load GS offsets to center xformed vertex in gs coord space and color clamping constant -#macro LoadScaleConstant: gs_scale - loi 2047.5 - addi.xy gs_scale, vf00, i - loi 699050.625000 // ((float)0xFFFFFF) / 24.0F - addi.z gs_scale, vf00, i -#endmacro diff --git a/src/engine/vu1_progs/matrix.inc b/src/engine/vu1_progs/matrix.inc deleted file mode 100644 index 47615e5..0000000 --- a/src/engine/vu1_progs/matrix.inc +++ /dev/null @@ -1,13 +0,0 @@ -#macro MatrixLoad: matrix, offset, vumem - lq matrix[0], offset+0(vumem) - lq matrix[1], offset+1(vumem) - lq matrix[2], offset+2(vumem) - lq matrix[3], offset+3(vumem) -#endmacro - -#macro MatrixXForm: output_vertex, matrix, input_vertex - mul acc, matrix[0], input_vertex[x] - madd acc, matrix[1], input_vertex[y] - madd acc, matrix[2], input_vertex[z] - madd output_vertex, matrix[3], input_vertex[w] -#endmacro diff --git a/src/engine/vu1_progs/vector.inc b/src/engine/vu1_progs/vector.inc deleted file mode 100644 index c492916..0000000 --- a/src/engine/vu1_progs/vector.inc +++ /dev/null @@ -1,27 +0,0 @@ -#macro VectorPerspectiveDivide: vertex - div q, vf00[w], vertex[w] - mulq.xyz vertex, vertex, q -#endmacro - -#macro VectorAddGSScales: output_vertex, input_vertex, gs_scale - mula.xyz acc, gs_scale, vf00[w] - madd.xyz output_vertex, input_vertex, gs_scale - ftoi4.xyz output_vertex, output_vertex -#endmacro - -#macro VectorTexturePerspectiveCorrection: output_vertex, input_vertex - mulq output_vertex, input_vertex, q -#endmacro - -#macro VectorStore: vertex, vumem, num - sq vertex, num(vumem) -#endmacro - -#macro VectorClip: output_vertex, input_vertex - clipw.xyz input_vertex, input_vertex - mfir.w output_vertex, adc_bit -#endmacro - -#macro VectorLoad: output_vertex, vumem, offset - lq output_vertex, offset(vumem) -#endmacro diff --git a/src/samples/cube/.gitignore b/src/samples/cube/.gitignore deleted file mode 100644 index d67c0e7..0000000 --- a/src/samples/cube/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.vscode/ -fonts/** \ No newline at end of file diff --git a/src/samples/cube/Makefile b/src/samples/cube/Makefile deleted file mode 100644 index c239b12..0000000 --- a/src/samples/cube/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -# Project settings - -DIR_NAME = cube -EE_LIBS = -ltyra -EE_OBJS = \ - objects/cube.o \ - camera.o \ - cubes.o \ - main.o - -# ---------------- -# Other - -EE_BIN = $(DIR_NAME).elf - -all: $(EE_BIN) - $(EE_STRIP) --strip-all $(EE_BIN) - mv $(EE_BIN) bin/$(EE_BIN) - -rebuild-engine: - cd $(TYRA)/src/engine && make clean && make EE_CXXFLAGS="-DNDEBUG $(EE_CXXFLAGS)" - -rebuild-dbg-engine: - cd $(TYRA)/src/engine && make clean && make - -clean: - rm -f $(EE_OBJS) - -run: - killall -v ps2client || true - ps2client reset - ps2client reset - cd bin/ && ps2client execee host:$(EE_BIN) - -run-pcsx2: - taskkill.exe /f /t /im pcsx2.exe || true - $(WSL_LINUX_PCSX2)/pcsx2.exe --elf=$(WSL_MAKE_WINDOWS)\\repos\\tyra\\src\\samples\\$(DIR_NAME)\\bin\\$(EE_BIN) - -include $(TYRA)/src/engine/Makefile.pref \ No newline at end of file diff --git a/src/samples/cube/README.MD b/src/samples/cube/README.MD deleted file mode 100644 index 0501bc4..0000000 --- a/src/samples/cube/README.MD +++ /dev/null @@ -1,15 +0,0 @@ - -## Cube Sample - -### Features - -- Rotating Cube - -### Assets -You can download assets from [latest release](https://github.com/h4570/tyra/releases/latest) (unpack to `/repos/tyra/src/samples/cube/bin`) - -### Screenshot - -[![Cube screenshot][Cube-screenshot]](#) - -[Cube-screenshot]: http://apgcglz.cluster028.hosting.ovh.net/tyra/cube.gif diff --git a/src/samples/cube/camera.cpp b/src/samples/cube/camera.cpp deleted file mode 100644 index e0d4dc7..0000000 --- a/src/samples/cube/camera.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Wellington Carvalho -*/ - -#include "camera.hpp" - -#include -#include - -const float CAMERA_Y = 30.0F; - -// ---- -// Constructors/Destructors -// ---- - -Camera::Camera(ScreenSettings *t_screen) : CameraBase(t_screen, &position) -{ - consoleLog("Initializing camera"); - verticalLevel = 80.0F; - consoleLog("Camera initialized!"); -} - -Camera::~Camera() {} - -// ---- -// Methods -// ---- - -void Camera::update(Pad &t_pad, Mesh &t_mesh) -{ - rotate(t_pad); - followBy(t_mesh); - lookAt(t_mesh.position); -} - -/** Set camera rotation by pad right joy and update unit circle - * https://en.wikipedia.org/wiki/Unit_circle - * https://www.desmos.com/calculator/3e7iypw4ow - */ -void Camera::rotate(Pad &t_pad) -{ - if (t_pad.rJoyH <= 100) - horizontalLevel -= 0.08; - else if (t_pad.rJoyH >= 200) - horizontalLevel += 0.08; - if (t_pad.rJoyV <= 50 && verticalLevel > 25.0F) - verticalLevel -= 0.9F; - else if (t_pad.rJoyV >= 200 && verticalLevel < 80.0F) - verticalLevel += 0.9F; - unitCirclePosition.x = (sin(horizontalLevel) * verticalLevel); - unitCirclePosition.y = CAMERA_Y; - unitCirclePosition.z = (cos(horizontalLevel) * verticalLevel); -} - -/** Rotate camera around 3D object */ -void Camera::followBy(Mesh &t_mesh) -{ - position.x = unitCirclePosition.x + t_mesh.position.x; - position.y = unitCirclePosition.y + t_mesh.position.y; - position.z = unitCirclePosition.z + t_mesh.position.z; -} diff --git a/src/samples/cube/camera.hpp b/src/samples/cube/camera.hpp deleted file mode 100644 index ab5a263..0000000 --- a/src/samples/cube/camera.hpp +++ /dev/null @@ -1,41 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Wellington Carvalho -*/ - -#ifndef _CAMERA_ -#define _CAMERA_ - -#include -#include -#include -#include -#include -#include - -/** 3D camera which follow by 3D object. Can be rotated via pad */ -class Camera : public CameraBase -{ - -public: - Vector3 up, position, unitCirclePosition; - float horizontalLevel, verticalLevel; - - Camera(ScreenSettings *t_screen); - ~Camera(); - - void update(Pad &t_pad, Mesh &t_mesh); - void rotate(Pad &t_pad); - void followBy(Mesh &t_mesh); - -protected: - Vector3 *getPosition() { return &position; }; - ScreenSettings screen; -}; - -#endif diff --git a/src/samples/cube/cubes.cpp b/src/samples/cube/cubes.cpp deleted file mode 100644 index 653adcc..0000000 --- a/src/samples/cube/cubes.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Wellington Carvalho -*/ - -#include "cubes.hpp" - -Cubes::Cubes(Engine *t_engine) - : engine(t_engine), camera(&t_engine->screen) -{ - consoleLog("Initing cubes sample"); -} - -Cubes::~Cubes() -{ - return; -} - -void Cubes::onInit() -{ - texRepo = engine->renderer->getTextureRepository(); - cube = new Cube(texRepo); - setBgColorAndAmbientColor(); - engine->renderer->setCameraDefinitions(&camera.view, &camera.unitCirclePosition, camera.planes); -} - -void Cubes::onUpdate() -{ - camera.update(engine->pad, cube->mesh); - cube->update(engine->pad, camera); - engine->renderer->draw(cube->mesh); -} - -void Cubes::setBgColorAndAmbientColor() -{ - color_t bgColor; - bgColor.r = 0x20; - bgColor.g = 0x20; - bgColor.b = 0x20; - engine->renderer->setWorldColor(bgColor); - Vector3 ambient = Vector3(0.2F, 0.2F, 0.2F); - engine->renderer->setAmbientLight(ambient); -} \ No newline at end of file diff --git a/src/samples/cube/cubes.hpp b/src/samples/cube/cubes.hpp deleted file mode 100644 index 8950d76..0000000 --- a/src/samples/cube/cubes.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Wellington Carvalho -*/ - -#ifndef _CUBES_ -#define _CUBES_ - -#include -#include -#include -#include "modules/texture_repository.hpp" -#include "camera.hpp" -#include "objects/cube.hpp" - -class Cubes : public Game -{ - - public: - Cubes(Engine *t_engine); - ~Cubes(); - - void onInit(); - void onUpdate(); - - Engine *engine; - - private: - void setBgColorAndAmbientColor(); - TextureRepository *texRepo; - Cube *cube; - Camera camera; -}; - -#endif \ No newline at end of file diff --git a/src/samples/cube/main.cpp b/src/samples/cube/main.cpp deleted file mode 100644 index e2b97df..0000000 --- a/src/samples/cube/main.cpp +++ /dev/null @@ -1,20 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Wellington Carvalho -*/ - -#include "cubes.hpp" - -int main() -{ - Engine engine = Engine(); - Cubes game = Cubes(&engine); - game.engine->init(&game, 128); - SleepThread(); - return 0; -} \ No newline at end of file diff --git a/src/samples/cube/objects/cube.cpp b/src/samples/cube/objects/cube.cpp deleted file mode 100644 index 72be167..0000000 --- a/src/samples/cube/objects/cube.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Wellington Carvalho -*/ - -#include "cube.hpp" -#include -#include -#include - -// ---- -// Constructors/Destructors -// ---- - -Cube::Cube(TextureRepository *t_texRepo) -{ - consoleLog("Creating cube"); - texRepo = t_texRepo; - speed = 1.2F; - - mesh.loadObj("meshes/cube/", "cube", 10.0F, true); - mesh.position.set(20.00F, 40.00F, 10.00F); - mesh.rotation.x = -1.566F; - mesh.rotation.z = 1.566F; - - texRepo->addByMesh("meshes/cube/", mesh, PNG); - - consoleLog("Cube object created!"); -} - -void Cube::update(const Pad &t_pad, const Camera &t_camera) -{ - rotate(t_pad); - Vector3 *nextPos = getNextPosition(t_pad, t_camera); -} - -Vector3 *Cube::getNextPosition(const Pad &t_pad, const Camera &t_camera) -{ - Vector3 *result = new Vector3(mesh.position); - Vector3 normalizedCamera = Vector3(t_camera.unitCirclePosition); - normalizedCamera.normalize(); - normalizedCamera *= speed; - if (t_pad.lJoyV <= 100) - { - result->x += -normalizedCamera.x; - result->z += -normalizedCamera.z; - } - else if (t_pad.lJoyV >= 200) - { - result->x += normalizedCamera.x; - result->z += normalizedCamera.z; - } - if (t_pad.lJoyH <= 100) - { - result->x += -normalizedCamera.z; - result->z += normalizedCamera.x; - } - else if (t_pad.lJoyH >= 200) - { - result->x += normalizedCamera.z; - result->z += -normalizedCamera.x; - } - return result; -} - -void Cube::rotate(const Pad &t_pad) -{ - //if (t_pad.rJoyH >= 200) - //else if (t_pad.rJoyH <= 100) - mesh.rotation.x += (0.01 * speed); - mesh.rotation.y += (0.01 * speed); - mesh.rotation.z += (0.01 * speed); -} \ No newline at end of file diff --git a/src/samples/cube/objects/cube.hpp b/src/samples/cube/objects/cube.hpp deleted file mode 100644 index 77845e9..0000000 --- a/src/samples/cube/objects/cube.hpp +++ /dev/null @@ -1,37 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Wellington Carvalho -*/ - -#ifndef _CUBE_ -#define _CUBE_ - -#include "../camera.hpp" -#include -#include -#include -#include "modules/texture_repository.hpp" - -/** Cube 3D object class */ -class Cube -{ - public: - Mesh mesh; - Cube( TextureRepository *t_texRepo ); - ~Cube(); - - void update(const Pad &t_pad, const Camera &t_camera); - - private: - TextureRepository *texRepo; - Vector3 *getNextPosition(const Pad &t_pad, const Camera &t_camera); - void rotate(const Pad &t_pad); - float speed; -}; - -#endif diff --git a/src/samples/dolphin/.gitignore b/src/samples/dolphin/.gitignore deleted file mode 100644 index 0a019ca..0000000 --- a/src/samples/dolphin/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.vscode/ -fonts/** diff --git a/src/samples/dolphin/Makefile b/src/samples/dolphin/Makefile deleted file mode 100644 index d366f7a..0000000 --- a/src/samples/dolphin/Makefile +++ /dev/null @@ -1,41 +0,0 @@ -# Project settings - -DIR_NAME = dolphin -EE_LIBS = -ltyra -EE_OBJS = \ - camera.o \ - objects/player.o \ - objects/collectible.o \ - objects/mine.o \ - dolphin.o \ - main.o - -# ---------------- -# Other - -EE_BIN = $(DIR_NAME).elf - -all: $(EE_BIN) - $(EE_STRIP) --strip-all $(EE_BIN) - mv $(EE_BIN) bin/$(EE_BIN) - -rebuild-engine: - cd $(TYRA)/src/engine && make clean && make EE_CXXFLAGS="-DNDEBUG $(EE_CXXFLAGS)" - -rebuild-dbg-engine: - cd $(TYRA)/src/engine && make clean && make - -clean: - rm -f $(EE_OBJS) - -run: - killall -v ps2client || true - ps2client reset - ps2client reset - cd bin/ && ps2client execee host:$(EE_BIN) - -run-pcsx2: - taskkill.exe /f /t /im pcsx2.exe || true - $(WSL_LINUX_PCSX2)/pcsx2.exe --elf=$(WSL_MAKE_WINDOWS)\\repos\\tyra\\src\\samples\\$(DIR_NAME)\\bin\\$(EE_BIN) - -include $(TYRA)/src/engine/Makefile.pref diff --git a/src/samples/dolphin/README.MD b/src/samples/dolphin/README.MD deleted file mode 100644 index ff8f936..0000000 --- a/src/samples/dolphin/README.MD +++ /dev/null @@ -1,20 +0,0 @@ -## Dolphin sample - -### Features -- Animated character -- Collectibles and mines -- Big DFF mesh -- Background songs -- Overlay -- Audio effects (ADPCM) -- Transparent 2D UI -- Usage of draw() in array mode (for water tiles, very fast) - -### Assets -You can download assets from [latest release](https://github.com/h4570/tyra/releases/latest) (unpack to `/repos/tyra/src/samples/dolphin/bin`) - -### Screenshot - -[![Dolphin screenshot][dolphin-screenshot]](#) - -[dolphin-screenshot]: http://apgcglz.cluster028.hosting.ovh.net/tyra/dolphin.gif diff --git a/src/samples/dolphin/camera.cpp b/src/samples/dolphin/camera.cpp deleted file mode 100755 index 69d8669..0000000 --- a/src/samples/dolphin/camera.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Michał Mostowik -*/ - -#include "camera.hpp" - -#include - -const float CAMERA_Y = 25.0F; - -Camera::Camera(ScreenSettings *t_screen) : CameraBase(t_screen, &position) -{ - verticalLevel = 30.0F; -} - -Camera::~Camera() {} - -void Camera::update(Pad &t_pad, Mesh &t_mesh) -{ - float cameraRot = (t_mesh.rotation.z * 180 / Math::PI) - (horizontalLevel * 180 / Math::PI); - cameraRot += 180; - cameraRot /= 15; - horizontalLevel += cameraRot / (180 / Math::PI); - rotate(t_pad); - followBy(t_mesh); - Vector3 lookPos = Vector3(t_mesh.position.x, t_mesh.position.y + 10.0F, t_mesh.position.z); - lookAt(lookPos); -} - -void Camera::rotate(Pad &t_pad) -{ - - if (t_pad.rJoyH <= 100) - horizontalLevel -= 0.08; - else if (t_pad.rJoyH >= 200) - horizontalLevel += 0.08; - - unitCirclePosition.x = (Math::sin(horizontalLevel) * verticalLevel); - unitCirclePosition.y = CAMERA_Y; - unitCirclePosition.z = (Math::cos(horizontalLevel) * verticalLevel); -} - -void Camera::followBy(Mesh &t_mesh) -{ - position.x = unitCirclePosition.x + t_mesh.position.x; - position.y = unitCirclePosition.y + t_mesh.position.y; - position.z = unitCirclePosition.z + t_mesh.position.z; -} \ No newline at end of file diff --git a/src/samples/dolphin/camera.hpp b/src/samples/dolphin/camera.hpp deleted file mode 100755 index d13d38c..0000000 --- a/src/samples/dolphin/camera.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Michał Mostowik -*/ - -#ifndef _CAMERA_ -#define _CAMERA_ - -#include -#include -#include -#include -#include -#include - -class Camera : public CameraBase -{ - -public: - Vector3 position, up, unitCirclePosition; - float horizontalLevel, verticalLevel; - - Camera(ScreenSettings *t_screen); - ~Camera(); - - void update(Pad &t_pad, Mesh &t_mesh); - void rotate(Pad &t_pad); - void followBy(Mesh &t_mesh); - -protected: - Vector3 *getPosition() { return &position; }; - ScreenSettings screen; -}; - -#endif diff --git a/src/samples/dolphin/dolphin.cpp b/src/samples/dolphin/dolphin.cpp deleted file mode 100755 index fb19346..0000000 --- a/src/samples/dolphin/dolphin.cpp +++ /dev/null @@ -1,296 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Michał Mostowik -*/ - -#include "dolphin.hpp" -#include "utils/math.hpp" - -float Dolphin::engineFPS = 60.0F; -const float WATER_TILE_SCALE = 6.0F; -const u8 WATER_SIZE = 4; -const u8 MINES_COUNT = 15; -const u8 OYSTERS_COUNT = 5; - -Dolphin::Dolphin(Engine *t_engine) : engine(t_engine), camera(&engine->screen) -{ - oysters = new Collectible[OYSTERS_COUNT]; - mines = new Mine[MINES_COUNT]; -} - -Dolphin::~Dolphin() -{ - delete[] oysters; - delete[] mines; - delete[] waterDrawList; -} - -void Dolphin::onInit() -{ - player.init(engine); - engine->renderer->setCameraDefinitions(&camera.view, &camera.position, camera.planes); - - engine->audio.loadSong("sound/dirediredocks.wav"); - engine->audio.playSong(); - engine->audio.setSongVolume(60); - - surfaceAmbient = engine->audio.loadADPCM("sound/surface.sad"); - underwaterAmbient = engine->audio.loadADPCM("sound/underwater.sad"); - pickupSound = engine->audio.loadADPCM("sound/pickup.sad"); - boomSound = engine->audio.loadADPCM("sound/boom.sad"); - - engine->audio.playADPCM(surfaceAmbient, 0); - engine->audio.playADPCM(underwaterAmbient, 1); - - texRepo = engine->renderer->getTextureRepository(); - - engine->renderer->disableVSync(); - - printf("loading island..\n"); - island.loadDff("sunnyisl/", "sunnyisl", 5.0F, false); - printf("Loaded..\n"); - island.rotation.x = -1.6F; - island.position.set(0.0F, 60.0F, 20.0F); - island.shouldBeBackfaceCulled = true; - island.shouldBeFrustumCulled = false; - - gameOver.size.set(640.0F, 480.0F); - Texture *gameOverTex = texRepo->add("2d/", "gameover", PNG); - gameOver.setMode(MODE_STRETCH); - gameOverTex->addLink(gameOver.getId()); - - printf("Loading water overlay...\n"); - waterOverlay.size.set(640.0F, 480.0F); - Texture *watOverlayTex = texRepo->add("2d/", "underwater_overlay", PNG); - waterOverlay.setMode(MODE_STRETCH); - watOverlayTex->addLink(waterOverlay.getId()); - printf("Loaded.\n"); - - printf("Loading water...\n"); - - u32 spiralOffset = (u32)sqrt(WATER_TILES_COUNT); - waterDrawList = new Mesh *[WATER_TILES_COUNT]; - calcSpiral(spiralOffset, spiralOffset); - water[0].loadObj("water/", "water", WATER_TILE_SCALE, false); - water[0].position.set(0.0F, WATER_LEVEL, 0.0F); - texRepo->addByMesh("water/", water[0], BMP); - water[0].shouldBeFrustumCulled = true; - water[0].shouldBeBackfaceCulled = false; - waterDrawList[0] = &water[0]; - for (size_t i = 1; i < WATER_TILES_COUNT; i++) - { - water[i].loadFrom(water[0]); - water[i].shouldBeFrustumCulled = true; - water[i].shouldBeBackfaceCulled = false; - water[i].position.set(WATER_TILE_SCALE * 2.0F * spirals[i].x, WATER_LEVEL, WATER_TILE_SCALE * 2.0F * spirals[i].y); - texRepo->getBySpriteOrMesh(water[0].getMaterial(0).getId())->addLink(water[i].getMaterial(0).getId()); - waterDrawList[i] = &water[i]; - } - - printf("Loading seabed...\n"); - seabed.loadObj("seabed/", "seabed", 10.0F, false); - seabed.position.set(0, -250.0F, 0); - texRepo->addByMesh("seabed/", seabed, BMP); - seabed.shouldBeBackfaceCulled = false; - seabed.shouldBeFrustumCulled = false; - - skybox.loadObj("skybox/", "skybox", 400.0F, false); - skybox.shouldBeFrustumCulled = false; - - waterbox.loadObj("waterbox/", "waterbox", 250.0F, false); - waterbox.shouldBeFrustumCulled = false; - waterbox.shouldBeBackfaceCulled = false; - waterbox.rotation.x = Math::PI; - waterbox.position.y = -100.F; - - printf("Loading oyster dff\n"); - oysters[0].mesh.loadObj("oyster/", "oyster", 10.F, false); - printf("Loaded."); - oysters[0].mesh.shouldBeBackfaceCulled = false; - oysters[0].mesh.shouldBeFrustumCulled = false; - oysters[0].mesh.position.set(15, 0, 15); - texRepo->addByMesh("oyster/", oysters[0].mesh, BMP); - printf("Adding oyster texture.\n"); - for (int i = 1; i < OYSTERS_COUNT; i++) - { - printf("Processing oyster %d\n", i); - oysters[i].mesh.loadFrom(oysters[0].mesh); - oysters[i].mesh.shouldBeBackfaceCulled = false; - oysters[i].mesh.shouldBeFrustumCulled = false; - texRepo->getBySpriteOrMesh(oysters[0].mesh.getMaterial(0).getId())->addLink(oysters[i].mesh.getMaterial(0).getId()); - oysters[i].mesh.position.set(i * -100, 5.0F, i * -100); - } - - printf("Loading mine .obj\n"); - mines[0].mesh.loadObj("mine/", "mine", 10.F, false); - mines[0].mesh.shouldBeBackfaceCulled = false; - mines[0].mesh.shouldBeFrustumCulled = false; - mines[0].mesh.position.set(5, -15, 32); - texRepo->addByMesh("mine/", mines[0].mesh, BMP); - printf("Adding mine texture.\n"); - for (int i = 1; i < MINES_COUNT; i++) - { - printf("Processing mine %d\n", i); - mines[i].mesh.loadFrom(mines[0].mesh); - mines[i].mesh.shouldBeBackfaceCulled = false; - mines[i].mesh.shouldBeFrustumCulled = false; - texRepo->getBySpriteOrMesh(mines[0].mesh.getMaterial(0).getId())->addLink(mines[i].mesh.getMaterial(0).getId()); - mines[i].mesh.position.set(i * -10, 0.0F, i * -68); - } - - Texture *pLifeTex = texRepo->add("2d/", "life", PNG); - // pLifeTex->addLink(lifeSprites[0].getId()); - - for (int i = 0; i < 3; i++) - { - lifeSprites[i].size.set(64.0F, 64.0F); - lifeSprites[i].setMode(MODE_STRETCH); - lifeSprites[i].position.set(395 + (64 * i), 0); - pLifeTex->addLink(lifeSprites[i].getId()); - } - - texRepo->addByMesh("dolphin/", player.mesh, BMP); - texRepo->addByMesh("sunnyisl/", island, BMP); - texRepo->addByMesh("skybox/", skybox, BMP); - texRepo->addByMesh("waterbox/", waterbox, BMP); - - bulb.intensity = 55; - bulb.position.set(5.0F, 10.0F, 10.0f); - printf("Finished initialization\n"); -} - -void Dolphin::onUpdate() -{ - if (player.getLifes() <= 0) - { - engine->audio.stopSong(); - engine->audio.setADPCMVolume(0, 0); - engine->audio.setADPCMVolume(75, 1); - engine->renderer->draw(gameOver); - return; - } - - Dolphin::engineFPS = engine->fps; - // if (engine->pad.isCrossClicked) - // printf("Delta multiplier: %f\n", 60.0F / engine->fps); - - float xDist = player.mesh.position.x - water[0].position.x; - float zDist = player.mesh.position.z - water[0].position.z; - if (xDist < 0) - xDist *= -1; - if (zDist < 0) - zDist *= -1; - if (xDist > WATER_SIZE * WATER_TILE_SCALE / 4 || - zDist > WATER_SIZE * WATER_TILE_SCALE / 4) - { - for (size_t i = 0; i < WATER_TILES_COUNT; i++) - { - water[i].position.x = player.mesh.position.x + (WATER_TILE_SCALE * 2.0F * spirals[i].x); - water[i].position.z = player.mesh.position.z + (WATER_TILE_SCALE * 2.0F * spirals[i].y); - } - } - - for (int i = 0; i < OYSTERS_COUNT; i++) - { - oysters[i].update(); - Vector3 vecDist = oysters[i].mesh.position - player.mesh.position; - float dist = vecDist.length(); - if (dist < 20.F && player.isJumping() && oysters[i].isActive()) - { - printf("Pickup:%d Dist:%f\n", i, dist); - oysters[i].disappear(); - player.setLife(player.getLifes() + 1); - engine->audio.setADPCMVolume(30, 3); - engine->audio.playADPCM(pickupSound, 3); - } - } - - for (int i = 0; i < MINES_COUNT; i++) - { - mines[i].update(); - Vector3 vecDist = mines[i].mesh.position - player.mesh.position; - float dist = vecDist.length(); - - if (dist < 20.F && !mines[i].getExplosionTicks()) - { - printf("Vecdist: %f,%f,%f\n", vecDist.x, vecDist.y, vecDist.z); - printf("Explode:%d Dist:%f\n", i, dist); - mines[i].explode(); - player.setLife(player.getLifes() - 1); - // Buffer switching to prevent playing two sounds on one buffer - engine->audio.setADPCMVolume(65, Mine::lastSoundBuffer); - engine->audio.playADPCM(boomSound, Mine::lastSoundBuffer); - Mine::lastSoundBuffer = Mine::lastSoundBuffer == 4 ? 5 : 4; - } - } - - if (player.mesh.position.y > WATER_LEVEL - 5) - player.mesh.position.y = WATER_LEVEL - 5; - - player.update(engine->pad); - camera.update(engine->pad, player.mesh); - - skybox.position.set(player.mesh.position.x, +200.0F, player.mesh.position.z); - waterbox.position.set(player.mesh.position.x, -260.0F, player.mesh.position.z); - - engine->renderer->draw(island); - engine->renderer->draw(waterDrawList, WATER_TILES_COUNT); - engine->renderer->draw(skybox); - engine->renderer->draw(waterbox); - engine->renderer->draw(seabed); - - for (u8 i = 0; i < OYSTERS_COUNT; i++) - if (oysters[i].isActive()) - engine->renderer->draw(oysters[i].mesh); - - for (u8 i = 0; i < MINES_COUNT; i++) - if (mines[i].getExplosionTicks() < MINE_EXPLOSION_TICKS) - engine->renderer->draw(mines[i].mesh); - - for (u8 i = 0; i < player.getLifes(); i++) - engine->renderer->draw(lifeSprites[i]); - - engine->renderer->draw(player.mesh); - - if (camera.position.y < WATER_LEVEL) - { - engine->renderer->draw(waterOverlay); - engine->audio.setADPCMVolume(0, 0); // Surface ambient - engine->audio.setADPCMVolume(65, 1); // Underwater ambient - } - else - { - engine->audio.setADPCMVolume(50, 0); //Surface ambient - engine->audio.setADPCMVolume(0, 1); //Underwater ambient - } -} - -void Dolphin::calcSpiral(int X, int Y) -{ - int x, y, dx; - x = y = dx = 0; - int dy = -1; - int t = X > Y ? X : Y; - int maxI = t * t; - for (int i = 0; i < maxI; i++) - { - if ((-X / 2 <= x) && (x <= X / 2) && (-Y / 2 <= y) && (y <= Y / 2)) - { - spirals[i].x = x; - spirals[i].y = y; - } - if ((x == y) || ((x < 0) && (x == -y)) || ((x > 0) && (x == 1 - y))) - { - t = dx; - dx = -dy; - dy = t; - } - x += dx; - y += dy; - } -} diff --git a/src/samples/dolphin/dolphin.hpp b/src/samples/dolphin/dolphin.hpp deleted file mode 100755 index 5ee4d05..0000000 --- a/src/samples/dolphin/dolphin.hpp +++ /dev/null @@ -1,69 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Michał Mostowik -*/ - -#ifndef _DRIVER_ -#define _DRIVER_ - -#include -#include -#include -#include -#include -#include -#include -#include "./camera.hpp" -#include "./objects/player.hpp" -#include "./objects/collectible.hpp" -#include "./objects/mine.hpp" - -class Dolphin : public Game -{ - -public: - Dolphin(Engine *t_engine); - ~Dolphin(); - - void onInit(); - void onUpdate(); - - Engine *engine; - static float engineFPS; - -private: - void calcSpiral(int X, int Y); - static const u16 WATER_TILES_COUNT = 1024; - - Point spirals[WATER_TILES_COUNT]; - Mesh **waterDrawList; - /** - * DO NOT TOUCH ORDER OF DECLARATION! - * GCC BUG CAUSES RENDERING TO FAIL IN ANY OTHER ORDER OF DECLARATION! - */ - Mesh seabed; - Mesh island; - Mesh skybox; - Mesh mine; - LightBulb bulb; - Player player; - Camera camera; - Collectible *oysters; - TextureRepository *texRepo; - Sprite waterOverlay; - Mesh water[WATER_TILES_COUNT]; - Mesh waterbox; - Sprite lifeSprites[3]; - Sprite gameOver; - audsrv_adpcm_t *underwaterAmbient, *surfaceAmbient; - audsrv_adpcm_t *pickupSound; - audsrv_adpcm_t *boomSound; - Mine *mines; -}; - -#endif diff --git a/src/samples/dolphin/main.cpp b/src/samples/dolphin/main.cpp deleted file mode 100755 index fdf11cb..0000000 --- a/src/samples/dolphin/main.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Michał Mostowik -*/ - -#include "dolphin.hpp" - -int main() -{ - Engine engine = Engine(); - engine.screen.fov = 75.F; - Dolphin game = Dolphin(&engine); - game.engine->init(&game, 128); - SleepThread(); - return 0; -} diff --git a/src/samples/dolphin/objects/collectible.cpp b/src/samples/dolphin/objects/collectible.cpp deleted file mode 100644 index 0bdd01c..0000000 --- a/src/samples/dolphin/objects/collectible.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Michał Mostowik -*/ - -#include "collectible.hpp" - -#include -#include -#include -#include -#include - -Collectible::Collectible() -{ - mesh.loadObj("oyster/", "oyster", 10.F, false); - mesh.shouldBeFrustumCulled = false; - mesh.position.set(0.0F, 0.0F, 0.0f); - bActive = true; - bDisappearing = false; -} - -void Collectible::disappear() -{ - bDisappearing = true; - lift = 10; -} - -void Collectible::update() -{ - mesh.rotation.y += 0.08F; - if (bDisappearing) - { - mesh.position.y += lift; - lift = lift > 0 ? lift / 2 : 0; - if (lift < 1) - { - setActive(false); - bDisappearing = false; - } - } -} diff --git a/src/samples/dolphin/objects/collectible.hpp b/src/samples/dolphin/objects/collectible.hpp deleted file mode 100644 index bac0b37..0000000 --- a/src/samples/dolphin/objects/collectible.hpp +++ /dev/null @@ -1,34 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Michał Mostowik -*/ - -#ifndef _COLLECTIBLE_ -#define _COLLECTIBLE_ - -#include "../camera.hpp" -#include - -class Collectible -{ - -public: - float rotation; - Mesh mesh; - Collectible(); - void update(); - void disappear(); - void setActive(const u8 &b) { bActive = b; } - u8 isActive() { return bActive; } - -private: - u8 bActive, bDisappearing; - u8 lift; -}; - -#endif diff --git a/src/samples/dolphin/objects/mine.cpp b/src/samples/dolphin/objects/mine.cpp deleted file mode 100644 index a64da3a..0000000 --- a/src/samples/dolphin/objects/mine.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Michał Mostowik -*/ - -#include "mine.hpp" - -u8 Mine::lastSoundBuffer = 4; - -Mine::Mine() -{ - mesh.position.set(0.0F, 0.0F, 0.0F); - - bExploding = false; - explosionTicks = 0; -} - -void Mine::update() -{ - if (bExploding && explosionTicks < MINE_EXPLOSION_TICKS) - { - explosionTicks++; - mesh.scale++; - } -} diff --git a/src/samples/dolphin/objects/mine.hpp b/src/samples/dolphin/objects/mine.hpp deleted file mode 100644 index 51faa71..0000000 --- a/src/samples/dolphin/objects/mine.hpp +++ /dev/null @@ -1,34 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Michał Mostowik -*/ - -#ifndef _MINE_ -#define _MINE_ - -#include -#include - -#define MINE_EXPLOSION_TICKS 10 - -class Mine -{ -public: - static u8 lastSoundBuffer; - Mesh mesh; - void explode() { bExploding = true; } - void update(); - Mine(); - const u8 &getExplosionTicks() { return explosionTicks; } - -private: - u8 bExploding; - u8 explosionTicks; -}; - -#endif diff --git a/src/samples/dolphin/objects/player.cpp b/src/samples/dolphin/objects/player.cpp deleted file mode 100755 index 718f33a..0000000 --- a/src/samples/dolphin/objects/player.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Michał Mostowik -*/ - -#include "player.hpp" -#include "dolphin.hpp" - -#include -#include -#include -#include -#include - -Player::Player() -{ - mesh.loadMD2("dolphin/", "dolphin", 0.025F, true); - mesh.shouldBeFrustumCulled = false; - mesh.position.set(0.0F, 0.0F, 10.0f); - mesh.rotation.x = -1.6F; - mesh.setAnimSpeed(0.04F); - bIsJumping = false; - lifes = 3; -} - -void Player::init(Engine *t_engine) -{ - pEngine = t_engine; - waterImpact = t_engine->audio.loadADPCM("sound/water_impact.sad"); -} - -void Player::update(Pad &t_pad) -{ - if (lift > 0.0F) - lift -= 0.05F; - if (lift < 0.0F) - lift += 0.05F; - if (lift < 0.1F && lift > -0.1F) - lift = 0; - if (t_pad.lJoyV <= 100) - velocity = 1; - else if (t_pad.lJoyV >= 200) - velocity = -1; - - if (t_pad.lJoyH >= 200) - mesh.rotation.z -= 0.05; - else if (t_pad.lJoyH <= 100) - mesh.rotation.z += 0.05; - - if (t_pad.rJoyV >= 200 && lift <= 1) - lift += 0.2F; - else if (t_pad.rJoyV <= 100 && lift >= -1) - lift -= 0.2F; - - if (t_pad.isCrossClicked && mesh.getCurrentAnimationFrame() <= 14 && WATER_LEVEL - 15 < mesh.position.y) - { - mesh.setAnimSpeed(1.0F); - mesh.playAnimation(14, 58, 0); - } - - if (mesh.getCurrentAnimationFrame() > 25 && mesh.getCurrentAnimationFrame() < 47) - bIsJumping = true; - else - bIsJumping = false; - - if (velocity > 0 && mesh.getCurrentAnimationFrame() == 0) - { - mesh.setAnimSpeed(0.05F); - mesh.playAnimation(1, 14, 0); - } - if (mesh.getCurrentAnimationFrame() == 42) - { - if (!bIsImpactingWater) - { - pEngine->audio.setADPCMVolume(50, 2); - pEngine->audio.playADPCM(waterImpact, 2); - } - bIsImpactingWater = true; - } - else if (bIsImpactingWater) - { - bIsImpactingWater = false; - } - - velocity *= 60.0F / Dolphin::engineFPS; // Moving by deltatime of last frame. - mesh.position.z += - Math::cos(mesh.rotation.z) * velocity * (bIsJumping + 1); - mesh.position.x += - Math::sin(mesh.rotation.z) * velocity * (bIsJumping + 1); - mesh.position.y += lift; - - velocity = 0; -} diff --git a/src/samples/dolphin/objects/player.hpp b/src/samples/dolphin/objects/player.hpp deleted file mode 100755 index 93cde51..0000000 --- a/src/samples/dolphin/objects/player.hpp +++ /dev/null @@ -1,43 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Michał Mostowik -*/ - -#ifndef _PLAYER_ -#define _PLAYER_ - -#define WATER_LEVEL -5.0F - -#include "../camera.hpp" -#include -#include -#include -class Engine; -class Player -{ - -public: - float gravity, velocity, lift; - Mesh mesh; - Player(); - void init(Engine *t_engine); - void update(Pad &t_pad); - const u8 &isJumping() { return bIsJumping; } - const u8 &getLifes() { return lifes; } - void setLife(const u8 &l) { lifes = lifes = l < 4 ? l : 3; } - -private: - u8 bIsJumping; - Vector3 playerNextPosition; - u8 lifes; - audsrv_adpcm_t *waterImpact; - Engine *pEngine; - u8 bIsImpactingWater; -}; - -#endif diff --git a/src/samples/floors/.gitignore b/src/samples/floors/.gitignore deleted file mode 100644 index d67c0e7..0000000 --- a/src/samples/floors/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.vscode/ -fonts/** \ No newline at end of file diff --git a/src/samples/floors/Makefile b/src/samples/floors/Makefile deleted file mode 100644 index 3166fed..0000000 --- a/src/samples/floors/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -# Project settings - -DIR_NAME = floors -EE_LIBS = -ltyra -EE_OBJS = \ - managers/light_manager.o \ - managers/floor_manager.o \ - camera.o \ - objects/enemy.o \ - objects/floor.o \ - objects/player.o \ - ui.o \ - utils.o \ - floors.o \ - main.o - -# ---------------- -# Other - -EE_BIN = $(DIR_NAME).elf - -all: $(EE_BIN) - $(EE_STRIP) --strip-all $(EE_BIN) - mv $(EE_BIN) bin/$(EE_BIN) - -rebuild-engine: - cd $(TYRA)/src/engine && make clean && make EE_CXXFLAGS="-DNDEBUG $(EE_CXXFLAGS)" - -rebuild-dbg-engine: - cd $(TYRA)/src/engine && make clean && make - -clean: - rm -f $(EE_OBJS) - -run: - killall -v ps2client || true - ps2client reset - ps2client reset - cd bin/ && ps2client execee host:$(EE_BIN) - -run-pcsx2: - taskkill.exe /f /t /im pcsx2.exe || true - $(WSL_LINUX_PCSX2)/pcsx2.exe --elf=$(WSL_MAKE_WINDOWS)\\repos\\tyra\\src\\samples\\$(DIR_NAME)\\bin\\$(EE_BIN) - -include $(TYRA)/src/engine/Makefile.pref diff --git a/src/samples/floors/README.MD b/src/samples/floors/README.MD deleted file mode 100644 index f382d3c..0000000 --- a/src/samples/floors/README.MD +++ /dev/null @@ -1,19 +0,0 @@ -## Floors sample - -### Features -- Box collision -- 2 animated characters -- Texture tricks showcase -- Background song -- Audio effects - walking, fighting (ADPCM) -- Transparent 2D UI -- Usage of draw() in array mode (for floors, very fast) - -### Assets -You can download assets from [latest release](https://github.com/h4570/tyra/releases/latest) (unpack to `/repos/tyra/src/samples/dolphin/bin`) - -### Screenshot - -[![Floors screenshot][floors-screenshot]](#) - -[floors-screenshot]: http://apgcglz.cluster028.hosting.ovh.net/tyra/floors.gif diff --git a/src/samples/floors/camera.cpp b/src/samples/floors/camera.cpp deleted file mode 100644 index 01367fd..0000000 --- a/src/samples/floors/camera.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "camera.hpp" - -#include -#include - -const float CAMERA_Y = 30.0F; - -// ---- -// Constructors/Destructors -// ---- - -Camera::Camera(ScreenSettings *t_screen) : CameraBase(t_screen, &position) -{ - consoleLog("Initializing camera"); - verticalLevel = 80.0F; - consoleLog("Camera initialized!"); -} - -Camera::~Camera() {} - -// ---- -// Methods -// ---- - -void Camera::update(Pad &t_pad, Mesh &t_mesh) -{ - rotate(t_pad); - followBy(t_mesh); - lookAt(t_mesh.position); -} - -/** Set camera rotation by pad right joy and update unit circle - * https://en.wikipedia.org/wiki/Unit_circle - * https://www.desmos.com/calculator/3e7iypw4ow - */ -void Camera::rotate(Pad &t_pad) -{ - if (t_pad.rJoyH <= 100) - horizontalLevel -= 0.08; - else if (t_pad.rJoyH >= 200) - horizontalLevel += 0.08; - if (t_pad.rJoyV <= 50 && verticalLevel > 25.0F) - verticalLevel -= 0.9F; - else if (t_pad.rJoyV >= 200 && verticalLevel < 80.0F) - verticalLevel += 0.9F; - unitCirclePosition.x = (sin(horizontalLevel) * verticalLevel); - unitCirclePosition.y = CAMERA_Y; - unitCirclePosition.z = (cos(horizontalLevel) * verticalLevel); -} - -/** Rotate camera around 3D object */ -void Camera::followBy(Mesh &t_mesh) -{ - position.x = unitCirclePosition.x + t_mesh.position.x; - position.y = unitCirclePosition.y + t_mesh.position.y; - position.z = unitCirclePosition.z + t_mesh.position.z; -} diff --git a/src/samples/floors/camera.hpp b/src/samples/floors/camera.hpp deleted file mode 100644 index 49735d2..0000000 --- a/src/samples/floors/camera.hpp +++ /dev/null @@ -1,41 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _CAMERA_ -#define _CAMERA_ - -#include -#include -#include -#include -#include -#include - -/** 3D camera which follow by 3D object. Can be rotated via pad */ -class Camera : public CameraBase -{ - -public: - Vector3 up, position, unitCirclePosition; - float horizontalLevel, verticalLevel; - - Camera(ScreenSettings *t_screen); - ~Camera(); - - void update(Pad &t_pad, Mesh &t_mesh); - void rotate(Pad &t_pad); - void followBy(Mesh &t_mesh); - -protected: - Vector3 *getPosition() { return &position; }; - ScreenSettings screen; -}; - -#endif diff --git a/src/samples/floors/floors.cpp b/src/samples/floors/floors.cpp deleted file mode 100644 index 330c68a..0000000 --- a/src/samples/floors/floors.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "floors.hpp" - -// ---- -// Constructors/Destructors -// ---- - -const u16 FLOORS_COUNT = 144; // Temp change it also in floor_manager.hpp - -Floors::Floors(Engine *t_engine) - : engine(t_engine), floorManager(), camera(&t_engine->screen) -{ - audioTicks = 0; - skip1Beat = 0; -} - -Floors::~Floors() -{ - delete enemy; - delete ui; - delete floorManager; - delete player; -} - -// ---- -// Methods -// ---- - -void Floors::onInit() -{ - texRepo = engine->renderer->getTextureRepository(); - enemy = new Enemy(texRepo); - ui = new Ui(texRepo); - floorManager = new FloorManager(FLOORS_COUNT, texRepo); // we must init FloorManager before starting audio! - player = new Player(&engine->audio, texRepo); - setBgColorAndAmbientColor(); - engine->renderer->setCameraDefinitions(&camera.view, &camera.unitCirclePosition, camera.planes); - engine->audio.addSongListener(this); - engine->audio.loadSong("sounds/mafikizolo-loot.wav"); - engine->audio.playSong(); - engine->audio.setSongVolume(80); -} - -void Floors::onUpdate() -{ - ui->update(*player); - enemy->update(*floorManager); - lightManager.update(); - camera.update(engine->pad, player->mesh); - floorManager->update(*player); - player->update(engine->pad, camera, *floorManager, *enemy); - engine->renderer->draw(player->mesh); - engine->renderer->draw(enemy->getMeshes(), enemy->getMeshesCount()); - - // You can draw array of meshes in draw() function also. It can be A LOT faster than for looping! - // Why? When given mesh is small, is not animated and is not backface culled, vertex data are send once! - engine->renderer->draw(floorManager->getMeshes(), FLOORS_COUNT, lightManager.bulbs, lightManager.bulbsCount); - - ui->render(engine->renderer); // 2D rendering ist LAST step, because layers gonna play there. -} - -void Floors::onAudioTick() -{ - if ((++audioTicks + 20) % 21 == 0) - { - if (skip1Beat) - floorManager->onAudioTick(); - lightManager.onAudioTick(); - skip1Beat = !skip1Beat; - } - if (audioTicks > 10000) - audioTicks = 0; -} - -void Floors::setBgColorAndAmbientColor() -{ - color_t bgColor; - bgColor.r = 0x20; - bgColor.g = 0x20; - bgColor.b = 0x20; - engine->renderer->setWorldColor(bgColor); - Vector3 ambient = Vector3(0.003F, 0.003F, 0.003F); - engine->renderer->setAmbientLight(ambient); -} - -void Floors::onAudioFinish() -{ - audioTicks = 0; -} diff --git a/src/samples/floors/floors.hpp b/src/samples/floors/floors.hpp deleted file mode 100644 index dc9f8b8..0000000 --- a/src/samples/floors/floors.hpp +++ /dev/null @@ -1,52 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _FLOORS_ -#define _FLOORS_ - -#include -#include -#include -#include "managers/floor_manager.hpp" -#include "managers/light_manager.hpp" -#include "modules/texture_repository.hpp" -#include "objects/player.hpp" -#include "objects/enemy.hpp" -#include "./camera.hpp" -#include "./ui.hpp" - -class Floors : public Game, AudioListener -{ - -public: - Floors(Engine *t_engine); - ~Floors(); - - void onInit(); - void onUpdate(); - void onAudioTick(); - void onAudioFinish(); - - Engine *engine; - -private: - void setBgColorAndAmbientColor(); - u32 audioTicks; - u8 skip1Beat; - TextureRepository *texRepo; - LightManager lightManager; - FloorManager *floorManager; - Player *player; - Camera camera; - Ui *ui; - Enemy *enemy; -}; - -#endif diff --git a/src/samples/floors/main.cpp b/src/samples/floors/main.cpp deleted file mode 100644 index f051c73..0000000 --- a/src/samples/floors/main.cpp +++ /dev/null @@ -1,20 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "floors.hpp" - -int main() -{ - Engine engine = Engine(); - Floors game = Floors(&engine); - game.engine->init(&game, 128); - SleepThread(); - return 0; -} diff --git a/src/samples/floors/managers/floor_manager.cpp b/src/samples/floors/managers/floor_manager.cpp deleted file mode 100644 index d7663f2..0000000 --- a/src/samples/floors/managers/floor_manager.cpp +++ /dev/null @@ -1,239 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "floor_manager.hpp" - -#include -#include -#include - -// ---- -// Constructors/Destructors -// ---- - -/** Calculate square spiral offsets and initialize floors - * @param floorAmount must be a number from square root table - */ -FloorManager::FloorManager(int t_floorAmount, TextureRepository *t_texRepo) -{ - meshes = new Mesh *[t_floorAmount]; - texRepo = t_texRepo; - floorAmount = t_floorAmount; - spirals = new Point[t_floorAmount]; - int floorSpiralMaxOffset = (int)sqrt(t_floorAmount); - calcSpiral(floorSpiralMaxOffset, floorSpiralMaxOffset); - initFloors(); - trick = 0.0F; - isTimeForChangeTriggerColor = true; - isTimeForChangeDefaultColor = true; - audioOffset = audioMode = audioTick = trickMode = 0; -} - -FloorManager::~FloorManager() -{ - delete[] spirals; -} - -// ---- -// Methods -// ---- - -/** Calculates square spiral offsets by specyfying max X and Y, fills "spirals" variable - * @param X Max X offset off spiral - * @param Y Max Y offset off spiral -*/ -void FloorManager::calcSpiral(int X, int Y) -{ - consoleLog("Calculating square spiral for floors"); - int x, y, dx; - x = y = dx = 0; - int dy = -1; - int t = X > Y ? X : Y; - int maxI = t * t; - for (int i = 0; i < maxI; i++) - { - if ((-X / 2 <= x) && (x <= X / 2) && (-Y / 2 <= y) && (y <= Y / 2)) - { - spirals[i].x = x; - spirals[i].y = y; - } - if ((x == y) || ((x < 0) && (x == -y)) || ((x > 0) && (x == 1 - y))) - { - t = dx; - dx = -dy; - dy = t; - } - x += dx; - y += dy; - } - consoleLog("Square spiral calculated!"); -} - -/** Initialize all floors by: - * - Setting position (with spirals offset) - * - Anim timer position - */ -void FloorManager::initFloors() -{ - consoleLog("Initializing floors"); - floors[0].mesh.loadObj("meshes/floor/", "floor", 3.0F, false); - floors[0].mesh.shouldBeFrustumCulled = true; - floors[0].mesh.shouldBeLighted = true; - meshes[0] = &floors[0].mesh; - texRepo->addByMesh("meshes/floor/", floors[0].mesh, BMP); - for (u16 i = 1; i < floorAmount; i++) - { - floors[i].mesh.shouldBeFrustumCulled = true; - floors[i].init(floors[0].mesh, spirals[i], i); - texRepo->getBySpriteOrMesh(floors[0].mesh.getMaterial(0).getId())->addLink(floors[i].mesh.getMaterial(0).getId()); - meshes[i] = &floors[i].mesh; - } - consoleLog("Floors initialized!"); -} - -/** Main floor loop. - * - Checks if floor should be rendered (isVisible, frustum culling) - * - Maintain floor animation - * - Fix player position after floor position change - */ -void FloorManager::update(Player &t_player) -{ - if (isTimeForChangeTriggerColor) - { - isTimeForChangeTriggerColor = false; - trigColor.r = rand() % (128 - 64 + 1) + 64; - trigColor.g = rand() % (128 - 64 + 1) + 64; - trigColor.b = rand() % (128 - 64 + 1) + 64; - } - if (isTimeForChangeDefaultColor) - { - isTimeForChangeDefaultColor = false; - defaultColor.r = rand() % (64 + 1); - defaultColor.g = rand() % (64 + 1); - defaultColor.b = rand() % (64 + 1); - } - doTheTrick(); - for (u16 i = 0; i < floorAmount; i++) - { - floors[i].animate(t_player); - MeshMaterial *material = &floors[i].mesh.getMaterial(0); - if (floors[i].isByAudioTriggered) - { - material->color.r = trigColor.r; - material->color.g = trigColor.g; - material->color.b = trigColor.b; - } - else - { - material->color.r = defaultColor.r; - material->color.g = defaultColor.g; - material->color.b = defaultColor.b; - } - } -} - -void FloorManager::doTheTrick() -{ - if (trickMode == 0) - { - if (trick > 3.0F) - { - isTimeForChangeTriggerColor = true; - trickMode = 1; - } - trick += 0.01F; - } - else if (trickMode == 1) - { - if (trick <= 0.1F) - { - isTimeForChangeTriggerColor = true; - trickMode = 0; - } - trick -= 0.01F; - } - floors[0].mesh.getFrames()[0].getST(1).set(trick, trick); - floors[0].mesh.getFrames()[0].getST(4).set(trick, trick); - floors[0].mesh.getFrames()[0].getST(7).set(trick, trick); - floors[0].mesh.getFrames()[0].getST(10).set(trick, trick); - floors[0].mesh.getFrames()[0].getST(13).set(trick, trick); -} - -/** Called by audio thread */ -void FloorManager::onAudioTick() -{ - if (audioTick++ > 19) - { - if (audioMode == 0) - { - for (u16 i = 0; i < floorAmount; i++) - { - if ((i + audioOffset) % 2 == 0) - floors[i].isByAudioTriggered = true; - else - floors[i].isByAudioTriggered = false; - } - if (++audioOffset > 3) - { - audioOffset = 0; - isTimeForChangeDefaultColor = true; - audioMode = 1; - } - } - else if (audioMode == 1) - { - for (u16 i = 0; i < floorAmount; i++) - { - if (i < floorAmount / (audioOffset + 1)) - floors[i].isByAudioTriggered = true; - else - floors[i].isByAudioTriggered = false; - } - if (++audioOffset > 3) - { - audioOffset = 0; - isTimeForChangeDefaultColor = true; - audioMode = 2; - } - } - else if (audioMode == 2) - { - for (u16 i = 0; i < floorAmount; i++) - { - if ((i + audioOffset) % 4 == 0) - floors[i].isByAudioTriggered = true; - else - floors[i].isByAudioTriggered = false; - } - if (++audioOffset > 3) - { - audioOffset = 0; - isTimeForChangeDefaultColor = true; - audioMode = 3; - } - } - else if (audioMode == 3) - { - for (u16 i = 0; i < floorAmount; i++) - { - if (u16(i + 1) > floorAmount / (audioOffset + 1)) - floors[i].isByAudioTriggered = true; - else - floors[i].isByAudioTriggered = false; - } - if (++audioOffset > 3) - { - audioOffset = 0; - isTimeForChangeDefaultColor = true; - audioMode = 0; - } - } - } -} diff --git a/src/samples/floors/managers/floor_manager.hpp b/src/samples/floors/managers/floor_manager.hpp deleted file mode 100644 index 342aefd..0000000 --- a/src/samples/floors/managers/floor_manager.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _FLOOR_MANAGER_ -#define _FLOOR_MANAGER_ - -class Player; // Forward definition - -#include -#include -#include -#include - -#include "../objects/floor.hpp" - -/** Class which is maintaining floors objects */ -class FloorManager -{ - -public: - FloorManager(int t_floorAmount, TextureRepository *t_texRepo); - ~FloorManager(); - Floor floors[144]; // Temp change it also in floors.cpp - u16 floorAmount; - void update(Player &t_player); - void onAudioTick(); - Mesh **getMeshes() { return meshes; } - -private: - Mesh **meshes; - TextureRepository *texRepo; - u8 audioOffset, audioMode; - u32 audioTick; - float trick; - u8 isTimeForChangeTriggerColor, isTimeForChangeDefaultColor; - color_t trigColor, defaultColor; - u8 trickMode; - Point *spirals; - void calcSpiral(int X, int Y); - void doTheTrick(); - void initFloors(); -}; - -#endif diff --git a/src/samples/floors/managers/light_manager.cpp b/src/samples/floors/managers/light_manager.cpp deleted file mode 100644 index ee8ced9..0000000 --- a/src/samples/floors/managers/light_manager.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "light_manager.hpp" -#include - -// ---- -// Constructors/Destructors -// ---- - -LightManager::LightManager() -{ - consoleLog("Creating light manager!"); - bulbsCount = 2; - - bulbs = new LightBulb[2]; - bulb1Dir = 0; - bulbs[0].intensity = 1; - bulbs[0].position.set(30.00F, 30.00F, -30.00F); - - bulb2Dir = 1; - bulbs[1].intensity = 1; - bulbs[1].position.set(-30.00F, 30.00F, 30.00F); - - audioOffset = audioTick = 0; - - consoleLog("Light manager created!"); -} - -LightManager::~LightManager() -{ - delete[] bulbs; -} - -// ---- -// Methods -// ---- - -/** Light bulb moving test */ -void LightManager::update() -{ - updateBulb1(); - updateBulb2(); -} - -void LightManager::updateBulb1() -{ - if (bulb1Dir == 1) - { - if (areLightsInverted) - { - bulbs[0].position.x += 0.6F; - bulbs[0].position.z -= 0.6F; - } - else - { - bulbs[0].position.x += 0.6F; - bulbs[0].position.z += 0.6F; - } - } - else - { - if (areLightsInverted) - { - bulbs[0].position.x -= 0.6F; - bulbs[0].position.z += 0.6F; - } - else - { - bulbs[0].position.x -= 0.6F; - bulbs[0].position.z -= 0.6F; - } - } -} - -void LightManager::updateBulb2() -{ - if (bulb2Dir == 1) - { - if (areLightsInverted) - { - bulbs[1].position.x -= 0.6F; - bulbs[1].position.z += 0.6F; - } - else - { - bulbs[1].position.x += 0.6F; - bulbs[1].position.z += 0.6F; - } - } - else - { - if (areLightsInverted) - { - bulbs[1].position.x += 0.6F; - bulbs[1].position.z -= 0.6F; - } - else - { - bulbs[1].position.x -= 0.6F; - bulbs[1].position.z -= 0.6F; - } - } -} - -/** Called by audio thread */ -void LightManager::onAudioTick() -{ - bulb1Dir = bulb1Dir == 1 ? 0 : 1; - bulb2Dir = bulb2Dir == 1 ? 0 : 1; - if (audioTick++ > 17) - { - if (++audioOffset > 3) - { - audioOffset = 0; - if (areLightsInverted) - { - areLightsInverted = false; - bulbs[0].position.x = 20.0F; - bulbs[0].position.z = -20.0F; - - bulbs[1].position.x = -20.0F; - bulbs[1].position.z = 20.0F; - } - else - { - areLightsInverted = true; - bulbs[0].position.x = 20.0F; - bulbs[0].position.z = 20.0F; - - bulbs[1].position.x = -20.0F; - bulbs[1].position.z = -20.0F; - } - } - } - else - { - bulbs[0].intensity += 9; - bulbs[1].intensity += 9; - } -} diff --git a/src/samples/floors/managers/light_manager.hpp b/src/samples/floors/managers/light_manager.hpp deleted file mode 100644 index dbc3bf8..0000000 --- a/src/samples/floors/managers/light_manager.hpp +++ /dev/null @@ -1,38 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _LIGHT_MANAGER_ -#define _LIGHT_MANAGER_ - -#include -#include - -/** Class which is maintaining floors objects */ -class LightManager -{ - -public: - LightManager(); - ~LightManager(); - - LightBulb *bulbs; - u8 bulbsCount; - void update(); - void onAudioTick(); - -private: - u8 bulb1Dir, bulb2Dir; - void updateBulb1(); - void updateBulb2(); - u8 audioOffset, areLightsInverted; - u32 audioTick; -}; - -#endif diff --git a/src/samples/floors/objects/enemy.cpp b/src/samples/floors/objects/enemy.cpp deleted file mode 100644 index 7905b61..0000000 --- a/src/samples/floors/objects/enemy.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "enemy.hpp" -#include "../utils.hpp" - -#include -#include -#include -#include -#include -#include - -// ---- -// Constructors/Destructors -// ---- - -Enemy::Enemy(TextureRepository *t_texRepo) -{ - consoleLog("Creating enemy object"); - - meshes = new Mesh[getMeshesCount()]; - drawMeshes = new Mesh *[getMeshesCount()]; - - meshes[0].loadMD2("meshes/enemy/", "poss_head", 0.3F, false); - meshes[1].loadMD2("meshes/enemy/", "poss_body", 0.3F, false); - meshes[2].loadMD2("meshes/enemy/", "poss_weapon", 0.3F, false); - - for (u8 i = 0; i < 3; i++) - { - meshes[i].rotation.x = -1.566F; - meshes[i].rotation.z = 1.566F; - meshes[i].shouldBeFrustumCulled = false; - t_texRepo->addByMesh("meshes/enemy/", meshes[i], PNG); - meshes[i].playAnimation(1, 6); - drawMeshes[i] = &meshes[i]; - } - - Vector3 initPos = Vector3(0.00F, 40.00F, 0.00F); - setPosition(initPos); - - isKilled = true; - - consoleLog("Enemy object created!"); -} - -Enemy::~Enemy() -{ - delete[] meshes; -} - -// ---- -// Methods -// ---- - -void Enemy::setPosition(const Vector3 &t_vec) -{ - position.set(t_vec); - for (u8 i = 0; i < getMeshesCount(); i++) - meshes[i].position.set(t_vec); -} - -void Enemy::setPosition(const float &t_y) -{ - position.y = t_y; - for (u8 i = 0; i < getMeshesCount(); i++) - meshes[i].position.y = t_y; -} - -/** Called by player class. */ -void Enemy::kill(const Player &player) -{ - isKilled = true; -} - -void Enemy::update(const FloorManager &floorManager) -{ - if (isKilled) - { - isKilled = false; - int randFloor = rand() % (floorManager.floorAmount + 1); - currentFloor = &floorManager.floors[randFloor]; - setPosition(currentFloor->mesh.position); - } - updateGravity(); -} - -void Enemy::updateGravity() -{ - Utils::getMinMax(currentFloor->mesh, currFloorMin, currFloorMax); - setPosition(currFloorMax.y); -} diff --git a/src/samples/floors/objects/enemy.hpp b/src/samples/floors/objects/enemy.hpp deleted file mode 100644 index 4ed530a..0000000 --- a/src/samples/floors/objects/enemy.hpp +++ /dev/null @@ -1,46 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _ENEMY_ -#define _ENEMY_ - -#include -#include "../managers/floor_manager.hpp" -#include - -/** Player 3D object class */ -class Enemy -{ - -public: - s16 indexOfCurrentFloor; - Enemy(TextureRepository *t_texRepo); - ~Enemy(); - - inline Mesh **getMeshes() const { return drawMeshes; } - inline u8 getMeshesCount() const { return 3; } - inline Vector3 getPosition() const { return position; } - void setPosition(const Vector3 &t_vec); - void setPosition(const float &t_y); - void kill(const Player &player); - void update(const FloorManager &t_floorManager); - -private: - /** 0 - head, 1 - body, 2 - weapon */ - Mesh *meshes; - /** Only for draw() method. */ - Mesh **drawMeshes; - const Floor *currentFloor; - Vector3 position, currFloorMin, currFloorMax; - u8 isKilled; - void updateGravity(); -}; - -#endif diff --git a/src/samples/floors/objects/floor.cpp b/src/samples/floors/objects/floor.cpp deleted file mode 100644 index 61662f4..0000000 --- a/src/samples/floors/objects/floor.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "floor.hpp" - -#include "../utils.hpp" -#include "./player.hpp" -#include -#include - -const int FLOOR_ANIMATION_LENGTH = 100; -const float FLOOR_ANIMATION_Y_MIN = 0.0F; -const float FLOOR_ANIMATION_Y_MAX = 10.0F; - -// ---- -// Constructors/Destructors -// ---- - -Floor::Floor() -{ - animTimer = 0; - animDirection = 0; - initOffset = 0; - isByAudioTriggered = false; -} - -Floor::~Floor() {} - -// ---- -// Methods -// ---- - -void Floor::init(const Mesh &mother, const Point &spiral, const u8 &initOffset) -{ - this->mesh.position.set(0.00F, -10.00F, 0.00F); - this->mesh.loadFrom(mother); - this->initOffset = initOffset; - this->animTimer = rand() % FLOOR_ANIMATION_LENGTH; - this->mesh.shouldBeLighted = true; - this->mesh.shouldBeFrustumCulled = true; - this->mesh.position.x = spiral.x * 80.0F; - this->mesh.position.z = spiral.y * 80.0F; -} - -/** Check and update animation direction and position - * Runs Player::onBeforePlayerFloorMove() method - */ -void Floor::animate(Player &player) -{ - if (this->animDirection == 0) - this->animTimer++; - else - this->animTimer--; - - if (this->animDirection == 0 && this->animTimer >= FLOOR_ANIMATION_LENGTH) - this->animDirection = 1; - else if (this->animDirection == 1 && this->animTimer <= 0) - this->animDirection = 0; - float newY = Utils::expoEaseInOut(this->animTimer, FLOOR_ANIMATION_Y_MIN, FLOOR_ANIMATION_Y_MAX, FLOOR_ANIMATION_LENGTH); - float yDiff = newY - this->mesh.position.y; - if (this->initOffset == player.indexOfCurrentFloor) - player.onBeforePlayerFloorMove(this, yDiff); - this->mesh.position.y = newY; -} diff --git a/src/samples/floors/objects/floor.hpp b/src/samples/floors/objects/floor.hpp deleted file mode 100644 index afd2fae..0000000 --- a/src/samples/floors/objects/floor.hpp +++ /dev/null @@ -1,36 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _FLOOR_ -#define _FLOOR_ - -class Player; // Forward definition - -#include -#include -#include - -/** Floor 3D object class */ -class Floor -{ - -public: - u16 animTimer; - s16 animDirection, initOffset, isByAudioTriggered; - Mesh mesh; - - Floor(); - ~Floor(); - - void init(const Mesh &mother, const Point &spiral, const u8 &initOffset); - void animate(Player &player); -}; - -#endif diff --git a/src/samples/floors/objects/player.cpp b/src/samples/floors/objects/player.cpp deleted file mode 100644 index 0e885a3..0000000 --- a/src/samples/floors/objects/player.cpp +++ /dev/null @@ -1,230 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "player.hpp" -#include "../utils.hpp" - -#include -#include -#include -#include -#include - -// ---- -// Constructors/Destructors -// ---- - -Player::Player(Audio *t_audio, TextureRepository *t_texRepo) -{ - consoleLog("Creating player object"); - texRepo = t_texRepo; - audio = t_audio; - gravity = 0.1F; - lift = -1.0F; - jumpCounter = 0; - speed = 1.0F; - killedEnemies = 0; - isWalking = false; - isFighting = false; - isWalkingAnimationSet = false; - isJumpingAnimationSet = false; - isFightingAnimationSet = false; - - mesh.loadMD2("meshes/player/", "warrior", 0.2F, true); - mesh.position.set(0.00F, 40.00F, 0.00F); - mesh.rotation.x = -1.566F; - mesh.rotation.z = 1.566F; - mesh.shouldBeBackfaceCulled = false; - mesh.shouldBeFrustumCulled = false; - mesh.setAnimSpeed(0.17F); - mesh.playAnimation(0, 0); - - texRepo->addByMesh("meshes/player/", mesh, BMP); - - walkAdpcm = audio->loadADPCM("sounds/walk.adpcm"); - jumpAdpcm = audio->loadADPCM("sounds/jump.adpcm"); - boomAdpcm = audio->loadADPCM("sounds/boom.adpcm"); - audio->setADPCMVolume(70, 0); - - consoleLog("Player object created!"); -} - -Player::~Player() -{ -} - -// ---- -// Methods -// ---- - -void Player::update(const Pad &t_pad, const Camera &t_camera, const FloorManager &floorManager, Enemy &enemy) -{ - Vector3 *nextPos = getNextPosition(t_pad, t_camera); - FloorsCheck *floorsCheck = checkFloors(floorManager, *nextPos); - if (floorsCheck->currentFloor != NULL) - indexOfCurrentFloor = floorsCheck->currentFloor->initOffset; - updatePosition(t_pad, t_camera, floorManager, *floorsCheck, *nextPos, enemy); - updateGravity(floorsCheck); - delete floorsCheck; - delete nextPos; -} - -Vector3 *Player::getNextPosition(const Pad &t_pad, const Camera &t_camera) -{ - Vector3 *result = new Vector3(mesh.position); - Vector3 normalizedCamera = Vector3(t_camera.unitCirclePosition); - normalizedCamera.normalize(); - normalizedCamera *= speed; - if (t_pad.lJoyV <= 100) - { - result->x += -normalizedCamera.x; - result->z += -normalizedCamera.z; - } - else if (t_pad.lJoyV >= 200) - { - result->x += normalizedCamera.x; - result->z += normalizedCamera.z; - } - if (t_pad.lJoyH <= 100) - { - result->x += -normalizedCamera.z; - result->z += normalizedCamera.x; - } - else if (t_pad.lJoyH >= 200) - { - result->x += normalizedCamera.z; - result->z += -normalizedCamera.x; - } - return result; -} - -void Player::updatePosition(const Pad &t_pad, const Camera &t_camera, const FloorManager &t_floorManager, const FloorsCheck &t_floorsCheck, const Vector3 &t_nextPos, Enemy &enemy) -{ - if (t_pad.rJoyH >= 200) - mesh.rotation.z += 0.08; - else if (t_pad.rJoyH <= 100) - mesh.rotation.z -= 0.08; - - isWalking = mesh.position.x != t_nextPos.x || mesh.position.z != t_nextPos.z; - isFighting = isFighting || t_pad.isCircleClicked; - - if (isFighting) - { - if (!isFightingAnimationSet) - { - isFightingAnimationSet = true; - mesh.playAnimation(8, 19, 0); - fightTimer.prime(); - } - if (fightTimer.getTimeDelta() > 25000) - { // end of fighting - float distance = getPosition().distanceTo(enemy.getPosition()); - if (16.0F > distance) - { - enemy.kill(*this); - audio->playADPCM(boomAdpcm); - speed += .5F; - killedEnemies++; - } - isFightingAnimationSet = false; - isFighting = false; - } - } - else if (isWalking) - { - if (!isWalkingAnimationSet) - { - isWalkingAnimationSet = true; - this->mesh.playAnimation(1, 8); - } - if (walkTimer.getTimeDelta() > 8000) - { - walkTimer.prime(); - audio->playADPCM(walkAdpcm, 0); - } - } - else - { - isWalkingAnimationSet = false; - mesh.playAnimation(0, 0); - } - - if (t_floorsCheck.willCollideFloor == NULL && !isFighting) - { - mesh.position.x = t_nextPos.x; - mesh.position.z = t_nextPos.z; - } - - if (t_pad.isCrossClicked == 1) - { - velocity = lift; - audio->playADPCM(jumpAdpcm); - jumpCounter++; - } -} - -/** - * Do not call this. - * This is called by Floor::animate() on player's floor move in Y direction - */ -void Player::onBeforePlayerFloorMove(Floor *t_floor, float &t_newY) -{ - if (t_floor->animDirection == 0 && t_newY > 0.0F) - this->mesh.position.y += t_newY * 1.05F; - else if ((t_floor->animDirection == 1 && -t_newY < 0.0F)) - this->mesh.position.y -= -t_newY * 1.05F; -} - -/** Update player position by gravity and update index of current floor */ -void Player::updateGravity(FloorsCheck *t_floorsCheck) -{ - this->velocity += this->gravity; - this->mesh.position.y -= this->velocity; - u8 isOnFloor = t_floorsCheck->currentFloor != NULL && mesh.position.y < t_floorsCheck->currFloorMax.y; - - if (this->mesh.position.y >= 60.0F || mesh.position.y < -60.0F) - { - this->mesh.position.y = 60.0F; - this->velocity = 0; - } - else if (isOnFloor) - { - this->mesh.position.y = t_floorsCheck->currFloorMax.y; - this->velocity = 0; - } -} - -FloorsCheck *Player::checkFloors(const FloorManager &t_floorManager, const Vector3 &t_nextPos) -{ - FloorsCheck *result = new FloorsCheck; - result->currentFloor = NULL; - result->willCollideFloor = NULL; - Vector3 min = Vector3(); - Vector3 max = Vector3(); - for (u32 i = 0; i < t_floorManager.floorAmount; i++) - { - Utils::getMinMax(t_floorManager.floors[i].mesh, min, max); - if (result->currentFloor == NULL && this->mesh.position.isOnBox(min, max)) - { - result->currentFloor = &t_floorManager.floors[i]; - result->currFloorMin.set(min); - result->currFloorMax.set(max); - } - if (result->willCollideFloor == NULL && t_nextPos.collidesBox(min, max)) - { - result->willCollideFloor = &t_floorManager.floors[i]; - result->willCollideFloorMin.set(min); - result->willCollideFloorMax.set(max); - } - if (result->currentFloor != NULL && result->willCollideFloor != NULL) - break; - } - return result; -} diff --git a/src/samples/floors/objects/player.hpp b/src/samples/floors/objects/player.hpp deleted file mode 100644 index b233a12..0000000 --- a/src/samples/floors/objects/player.hpp +++ /dev/null @@ -1,61 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _PLAYER_ -#define _PLAYER_ - -#include "../managers/floor_manager.hpp" -#include "../camera.hpp" -#include "./enemy.hpp" -#include -#include -#include -#include - -struct FloorsCheck -{ - const Floor *currentFloor, *willCollideFloor; - Vector3 currFloorMin, willCollideFloorMin, currFloorMax, willCollideFloorMax; -}; - -/** Player 3D object class */ -class Player -{ - -public: - float gravity, velocity, lift; - Mesh mesh; - s16 indexOfCurrentFloor; - Player(Audio *t_audio, TextureRepository *t_texRepo); - ~Player(); - - void update(const Pad &t_pad, const Camera &t_camera, const FloorManager &t_floorManager, Enemy &enemy); - void onBeforePlayerFloorMove(Floor *t_floor, float &t_newY); - const inline u32 &getJumpCount() const { return jumpCounter; } - const inline u32 &getKilledEnemiesCount() const { return killedEnemies; } - inline const Vector3 &getPosition() const { return mesh.position; } - -private: - TextureRepository *texRepo; - u32 jumpCounter, killedEnemies; - Vector3 *getNextPosition(const Pad &t_pad, const Camera &t_camera); - FloorsCheck *checkFloors(const FloorManager &t_floorManager, const Vector3 &t_nextPos); - u8 isWalkingAnimationSet, isJumpingAnimationSet, isFightingAnimationSet; - u8 isFighting, isWalking; - Audio *audio; - Timer walkTimer, fightTimer; - audsrv_adpcm_t *walkAdpcm, *jumpAdpcm, *boomAdpcm; - float speed; - void getMinMax(const Mesh &t_mesh, Vector3 &t_min, Vector3 &t_max); - void updatePosition(const Pad &t_pad, const Camera &t_camera, const FloorManager &t_floorManager, const FloorsCheck &t_floorsCheck, const Vector3 &nextPos, Enemy &enemy); - void updateGravity(FloorsCheck *t_floorsCheck); -}; - -#endif diff --git a/src/samples/floors/ui.cpp b/src/samples/floors/ui.cpp deleted file mode 100644 index 7a18403..0000000 --- a/src/samples/floors/ui.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "ui.hpp" - -#include - -// ---- -// Constructors/Destructors -// ---- - -Ui::Ui(TextureRepository *t_texRepo) -{ - consoleLog("Initializing ui"); - - isTask1Done = false; - isTask2Done = false; - - info.size.set(128.0F, 32.0F); - info.position.set(500.0F, 430.0F); - - reward.size.set(128.0F, 128.0F); - reward.position.set(500.0F, 280.0F); - reward.flipVertically(true); - - task1.size.set(128.0F, 32.0F); - task1.position.set(500.0F, 10.0F); - - task2.size.set(128.0F, 32.0F); - task2.position.set(500.0F, 50.0F); - - task1Checkbox.size.set(32.0F, 32.0F); - task1Checkbox.position.set(460.0F, 10.0F); - - task2Checkbox.size.set(32.0F, 32.0F); - task2Checkbox.position.set(460.0F, 50.0F); - - t_texRepo->add("ui/", "reward", BMP)->addLink(reward.getId()); - t_texRepo->add("ui/", "info-text", PNG)->addLink(info.getId()); - t_texRepo->add("ui/", "check1-text", PNG)->addLink(task1.getId()); - t_texRepo->add("ui/", "check2-text", PNG)->addLink(task2.getId()); - grayCheckboxTex = t_texRepo->add("ui/", "gray-checkmark", PNG); - blueCheckboxTex = t_texRepo->add("ui/", "blue-checkmark", PNG); - - grayCheckboxTex->addLink(task1Checkbox.getId()); - grayCheckboxTex->addLink(task2Checkbox.getId()); - - consoleLog("Ui initialized!"); -} - -Ui::~Ui() {} - -// ---- -// Methods -// ---- - -void Ui::update(const Player &player) -{ - if (!isTask1Done && player.getJumpCount() >= 10) - { - isTask1Done = true; - grayCheckboxTex->removeLinkById(task1Checkbox.getId()); - blueCheckboxTex->addLink(task1Checkbox.getId()); - } - if (!isTask2Done && player.getKilledEnemiesCount() >= 10) - { - isTask2Done = true; - grayCheckboxTex->removeLinkById(task2Checkbox.getId()); - blueCheckboxTex->addLink(task2Checkbox.getId()); - } -} - -void Ui::render(Renderer *t_renderer) -{ - if (isTask1Done && isTask2Done) - t_renderer->draw(reward); - t_renderer->draw(info); - t_renderer->draw(task1); - t_renderer->draw(task2); - t_renderer->draw(task1Checkbox); - t_renderer->draw(task2Checkbox); -} diff --git a/src/samples/floors/ui.hpp b/src/samples/floors/ui.hpp deleted file mode 100644 index f96edb9..0000000 --- a/src/samples/floors/ui.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _UI_ -#define _UI_ - -#include -#include -#include "objects/player.hpp" -#include - -class Ui -{ - -public: - Ui(TextureRepository *t_texRepo); - ~Ui(); - - void update(const Player &player); - void render(Renderer *t_renderer); - -private: - u8 isTask1Done, isTask2Done; - Sprite task1, task2, task1Checkbox, task2Checkbox, info, reward; - Texture *grayCheckboxTex, *blueCheckboxTex; -}; - -#endif diff --git a/src/samples/floors/utils.cpp b/src/samples/floors/utils.cpp deleted file mode 100644 index d8b1021..0000000 --- a/src/samples/floors/utils.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#include "./utils.hpp" - -#include - -/** Exponential ease-in-out animation - * @param t Time - * @param b Start value - * @param c Change - * @param d Duration - * @returns Current animation position -*/ -float Utils::expoEaseInOut(float t, float b, float c, float d) -{ - if (t == 0) - return b; - - if (t == d) - return b + c; - - if ((t /= d / 2) < 1) - return c / 2 * powf(2, 10 * (t - 1)) + b; - - return c / 2 * (-powf(2, -10 * --t) + 2) + b; -} - -/** Calculates minimum and maximum X, Y, Z of mesh vertices + current position */ -void Utils::getMinMax(const Mesh &t_mesh, Vector3 &t_min, Vector3 &t_max) -{ - Vector3 calc = Vector3(); - u8 isInitialized = 0; - const Vector3 *boundingBox = t_mesh.getCurrentBoundingBoxVertices(); - for (u32 i = 0; i < 8; i++) - { - calc.set( - boundingBox[i].x + t_mesh.position.x, - boundingBox[i].y + t_mesh.position.y, - boundingBox[i].z + t_mesh.position.z); - if (isInitialized == 0) - { - isInitialized = 1; - t_min.set(calc); - t_max.set(calc); - } - - if (t_min.x > calc.x) - t_min.x = calc.x; - if (calc.x > t_max.x) - t_max.x = calc.x; - - if (t_min.y > calc.y) - t_min.y = calc.y; - if (calc.y > t_max.y) - t_max.y = calc.y; - - if (t_min.z > calc.z) - t_min.z = calc.z; - if (calc.z > t_max.z) - t_max.z = calc.z; - } -} diff --git a/src/samples/floors/utils.hpp b/src/samples/floors/utils.hpp deleted file mode 100644 index 2d7293f..0000000 --- a/src/samples/floors/utils.hpp +++ /dev/null @@ -1,26 +0,0 @@ -/* -# ______ ____ ___ -# | \/ ____| |___| -# | | | \ | | -#----------------------------------------------------------------------- -# Copyright 2020, tyra - https://github.com/h4570/tyra -# Licenced under Apache License 2.0 -# Sandro Sobczyński -*/ - -#ifndef _TYRA_UTILS_ -#define _TYRA_UTILS_ - -#include -#include -#include - -class Utils -{ - -public: - static float expoEaseInOut(float t, float b, float c, float d); - static void getMinMax(const Mesh &t_mesh, Vector3 &t_min, Vector3 &t_max); -}; - -#endif diff --git a/src/unit_tests/.gitignore b/src/unit_tests/.gitignore deleted file mode 100644 index d67c0e7..0000000 --- a/src/unit_tests/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.vscode/ -fonts/** \ No newline at end of file diff --git a/src/unit_tests/Makefile b/src/unit_tests/Makefile deleted file mode 100644 index cceb792..0000000 --- a/src/unit_tests/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -EE_BIN = unit_tests.elf -EE_LIBS = -ltyra -EE_OBJS = \ - tests/utils/math.o \ - main.o - -all: $(EE_BIN) - $(EE_STRIP) --strip-all $(EE_BIN) - mv $(EE_BIN) bin/$(EE_BIN) - rm $(EE_OBJS) - -rebuild-engine: - cd $(TYRA)/src/engine && make clean && make EE_CXXFLAGS="-DNDEBUG $(EE_CXXFLAGS)" - -rebuild-dbg-engine: - cd $(TYRA)/src/engine && make clean && make - -clean: - rm -f $(EE_OBJS) - -run: $(EE_BIN) - killall -v ps2client || true - ps2client reset - ps2client reset - $(EE_STRIP) --strip-all $(EE_BIN) - mv $(EE_BIN) bin/$(EE_BIN) - rm $(EE_OBJS) - cd bin/ && ps2client execee host:$(EE_BIN) - -run-pcsx2: - taskkill.exe /f /t /im pcsx2.exe || true - $(WSL_LINUX_PCSX2)/pcsx2.exe --elf=$(WSL_MAKE_WINDOWS)\\repos\\tyra\\src\\unit_tests\\bin\\unit_tests.elf - -show: - cat bin/test-result.txt - -include $(TYRA)/src/engine/Makefile.pref diff --git a/src/unit_tests/catch.hpp b/src/unit_tests/catch.hpp deleted file mode 100644 index 0b1faa4..0000000 --- a/src/unit_tests/catch.hpp +++ /dev/null @@ -1,17937 +0,0 @@ -/* - * Catch v2.13.6 - * Generated: 2021-04-16 18:23:38.044268 - * ---------------------------------------------------------- - * This file has been merged from multiple headers. Please don't edit it directly - * Copyright (c) 2021 Two Blue Cubes Ltd. All rights reserved. - * - * Distributed under the Boost Software License, Version 1.0. (See accompanying - * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ -#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED -#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED -// start catch.hpp - - -#define CATCH_VERSION_MAJOR 2 -#define CATCH_VERSION_MINOR 13 -#define CATCH_VERSION_PATCH 6 - -#ifdef __clang__ -# pragma clang system_header -#elif defined __GNUC__ -# pragma GCC system_header -#endif - -// start catch_suppress_warnings.h - -#ifdef __clang__ -# ifdef __ICC // icpc defines the __clang__ macro -# pragma warning(push) -# pragma warning(disable: 161 1682) -# else // __ICC -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wpadded" -# pragma clang diagnostic ignored "-Wswitch-enum" -# pragma clang diagnostic ignored "-Wcovered-switch-default" -# endif -#elif defined __GNUC__ - // Because REQUIREs trigger GCC's -Wparentheses, and because still - // supported version of g++ have only buggy support for _Pragmas, - // Wparentheses have to be suppressed globally. -# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details - -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wunused-variable" -# pragma GCC diagnostic ignored "-Wpadded" -#endif -// end catch_suppress_warnings.h -#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) -# define CATCH_IMPL -# define CATCH_CONFIG_ALL_PARTS -#endif - -// In the impl file, we want to have access to all parts of the headers -// Can also be used to sanely support PCHs -#if defined(CATCH_CONFIG_ALL_PARTS) -# define CATCH_CONFIG_EXTERNAL_INTERFACES -# if defined(CATCH_CONFIG_DISABLE_MATCHERS) -# undef CATCH_CONFIG_DISABLE_MATCHERS -# endif -# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) -# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER -# endif -#endif - -#if !defined(CATCH_CONFIG_IMPL_ONLY) -// start catch_platform.h - -// See e.g.: -// https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html -#ifdef __APPLE__ -# include -# if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \ - (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1) -# define CATCH_PLATFORM_MAC -# elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1) -# define CATCH_PLATFORM_IPHONE -# endif - -#elif defined(linux) || defined(__linux) || defined(__linux__) -# define CATCH_PLATFORM_LINUX - -#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) -# define CATCH_PLATFORM_WINDOWS -#endif - -// end catch_platform.h - -#ifdef CATCH_IMPL -# ifndef CLARA_CONFIG_MAIN -# define CLARA_CONFIG_MAIN_NOT_DEFINED -# define CLARA_CONFIG_MAIN -# endif -#endif - -// start catch_user_interfaces.h - -namespace Catch { - unsigned int rngSeed(); -} - -// end catch_user_interfaces.h -// start catch_tag_alias_autoregistrar.h - -// start catch_common.h - -// start catch_compiler_capabilities.h - -// Detect a number of compiler features - by compiler -// The following features are defined: -// -// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? -// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? -// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? -// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? -// **************** -// Note to maintainers: if new toggles are added please document them -// in configuration.md, too -// **************** - -// In general each macro has a _NO_ form -// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. -// Many features, at point of detection, define an _INTERNAL_ macro, so they -// can be combined, en-mass, with the _NO_ forms later. - -#ifdef __cplusplus - -# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) -# define CATCH_CPP14_OR_GREATER -# endif - -# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) -# define CATCH_CPP17_OR_GREATER -# endif - -#endif - -// Only GCC compiler should be used in this block, so other compilers trying to -// mask themselves as GCC should be ignored. -#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) - -# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) - -#endif - -#if defined(__clang__) - -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) - -// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug -// which results in calls to destructors being emitted for each temporary, -// without a matching initialization. In practice, this can result in something -// like `std::string::~string` being called on an uninitialized value. -// -// For example, this code will likely segfault under IBM XL: -// ``` -// REQUIRE(std::string("12") + "34" == "1234") -// ``` -// -// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. -# if !defined(__ibmxl__) && !defined(__CUDACC__) -# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ -# endif - -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ - _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") - -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) - -# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) - -# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) - -# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) - -#endif // __clang__ - -//////////////////////////////////////////////////////////////////////////////// -// Assume that non-Windows platforms support posix signals by default -#if !defined(CATCH_PLATFORM_WINDOWS) - #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS -#endif - -//////////////////////////////////////////////////////////////////////////////// -// We know some environments not to support full POSIX signals -#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) - #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -#endif - -#ifdef __OS400__ -# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -# define CATCH_CONFIG_COLOUR_NONE -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Android somehow still does not support std::to_string -#if defined(__ANDROID__) -# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING -# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Not all Windows environments support SEH properly -#if defined(__MINGW32__) -# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH -#endif - -//////////////////////////////////////////////////////////////////////////////// -// PS4 -#if defined(__ORBIS__) -# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Cygwin -#ifdef __CYGWIN__ - -// Required for some versions of Cygwin to declare gettimeofday -// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin -# define _BSD_SOURCE -// some versions of cygwin (most) do not support std::to_string. Use the libstd check. -// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 -# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ - && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) - -# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING - -# endif -#endif // __CYGWIN__ - -//////////////////////////////////////////////////////////////////////////////// -// Visual C++ -#if defined(_MSC_VER) - -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) - -// Universal Windows platform does not support SEH -// Or console colours (or console at all...) -# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) -# define CATCH_CONFIG_COLOUR_NONE -# else -# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH -# endif - -// MSVC traditional preprocessor needs some workaround for __VA_ARGS__ -// _MSVC_TRADITIONAL == 0 means new conformant preprocessor -// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor -# if !defined(__clang__) // Handle Clang masquerading for msvc -# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) -# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -# endif // MSVC_TRADITIONAL -# endif // __clang__ - -#endif // _MSC_VER - -#if defined(_REENTRANT) || defined(_MSC_VER) -// Enable async processing, as -pthread is specified or no additional linking is required -# define CATCH_INTERNAL_CONFIG_USE_ASYNC -#endif // _MSC_VER - -//////////////////////////////////////////////////////////////////////////////// -// Check if we are compiled with -fno-exceptions or equivalent -#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) -# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED -#endif - -//////////////////////////////////////////////////////////////////////////////// -// DJGPP -#ifdef __DJGPP__ -# define CATCH_INTERNAL_CONFIG_NO_WCHAR -#endif // __DJGPP__ - -//////////////////////////////////////////////////////////////////////////////// -// Embarcadero C++Build -#if defined(__BORLANDC__) - #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN -#endif - -//////////////////////////////////////////////////////////////////////////////// - -// Use of __COUNTER__ is suppressed during code analysis in -// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly -// handled by it. -// Otherwise all supported compilers support COUNTER macro, -// but user still might want to turn it off -#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) - #define CATCH_INTERNAL_CONFIG_COUNTER -#endif - -//////////////////////////////////////////////////////////////////////////////// - -// RTX is a special version of Windows that is real time. -// This means that it is detected as Windows, but does not provide -// the same set of capabilities as real Windows does. -#if defined(UNDER_RTSS) || defined(RTX64_BUILD) - #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH - #define CATCH_INTERNAL_CONFIG_NO_ASYNC - #define CATCH_CONFIG_COLOUR_NONE -#endif - -#if !defined(_GLIBCXX_USE_C99_MATH_TR1) -#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER -#endif - -// Various stdlib support checks that require __has_include -#if defined(__has_include) - // Check if string_view is available and usable - #if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW - #endif - - // Check if optional is available and usable - # if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL - # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) - - // Check if byte is available and usable - # if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # include - # if __cpp_lib_byte > 0 - # define CATCH_INTERNAL_CONFIG_CPP17_BYTE - # endif - # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) - - // Check if variant is available and usable - # if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # if defined(__clang__) && (__clang_major__ < 8) - // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 - // fix should be in clang 8, workaround in libstdc++ 8.2 - # include - # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) - # define CATCH_CONFIG_NO_CPP17_VARIANT - # else - # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT - # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) - # else - # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT - # endif // defined(__clang__) && (__clang_major__ < 8) - # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) -#endif // defined(__has_include) - -#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) -# define CATCH_CONFIG_COUNTER -#endif -#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) -# define CATCH_CONFIG_WINDOWS_SEH -#endif -// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. -#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) -# define CATCH_CONFIG_POSIX_SIGNALS -#endif -// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. -#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) -# define CATCH_CONFIG_WCHAR -#endif - -#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) -# define CATCH_CONFIG_CPP11_TO_STRING -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) -# define CATCH_CONFIG_CPP17_OPTIONAL -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) -# define CATCH_CONFIG_CPP17_STRING_VIEW -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) -# define CATCH_CONFIG_CPP17_VARIANT -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) -# define CATCH_CONFIG_CPP17_BYTE -#endif - -#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) -# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE -#endif - -#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) -# define CATCH_CONFIG_NEW_CAPTURE -#endif - -#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) -# define CATCH_CONFIG_DISABLE_EXCEPTIONS -#endif - -#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) -# define CATCH_CONFIG_POLYFILL_ISNAN -#endif - -#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) -# define CATCH_CONFIG_USE_ASYNC -#endif - -#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) -# define CATCH_CONFIG_ANDROID_LOGWRITE -#endif - -#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) -# define CATCH_CONFIG_GLOBAL_NEXTAFTER -#endif - -// Even if we do not think the compiler has that warning, we still have -// to provide a macro that can be used by the code. -#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION -#endif -#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS -#endif - -// The goal of this macro is to avoid evaluation of the arguments, but -// still have the compiler warn on problems inside... -#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) -# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) -#endif - -#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) -# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS -#elif defined(__clang__) && (__clang_major__ < 5) -# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS -#endif - -#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS -#endif - -#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) -#define CATCH_TRY if ((true)) -#define CATCH_CATCH_ALL if ((false)) -#define CATCH_CATCH_ANON(type) if ((false)) -#else -#define CATCH_TRY try -#define CATCH_CATCH_ALL catch (...) -#define CATCH_CATCH_ANON(type) catch (type) -#endif - -#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) -#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#endif - -// end catch_compiler_capabilities.h -#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line -#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) -#ifdef CATCH_CONFIG_COUNTER -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) -#else -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) -#endif - -#include -#include -#include - -// We need a dummy global operator<< so we can bring it into Catch namespace later -struct Catch_global_namespace_dummy {}; -std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); - -namespace Catch { - - struct CaseSensitive { enum Choice { - Yes, - No - }; }; - - class NonCopyable { - NonCopyable( NonCopyable const& ) = delete; - NonCopyable( NonCopyable && ) = delete; - NonCopyable& operator = ( NonCopyable const& ) = delete; - NonCopyable& operator = ( NonCopyable && ) = delete; - - protected: - NonCopyable(); - virtual ~NonCopyable(); - }; - - struct SourceLineInfo { - - SourceLineInfo() = delete; - SourceLineInfo( char const* _file, std::size_t _line ) noexcept - : file( _file ), - line( _line ) - {} - - SourceLineInfo( SourceLineInfo const& other ) = default; - SourceLineInfo& operator = ( SourceLineInfo const& ) = default; - SourceLineInfo( SourceLineInfo&& ) noexcept = default; - SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; - - bool empty() const noexcept { return file[0] == '\0'; } - bool operator == ( SourceLineInfo const& other ) const noexcept; - bool operator < ( SourceLineInfo const& other ) const noexcept; - - char const* file; - std::size_t line; - }; - - std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); - - // Bring in operator<< from global namespace into Catch namespace - // This is necessary because the overload of operator<< above makes - // lookup stop at namespace Catch - using ::operator<<; - - // Use this in variadic streaming macros to allow - // >> +StreamEndStop - // as well as - // >> stuff +StreamEndStop - struct StreamEndStop { - std::string operator+() const; - }; - template - T const& operator + ( T const& value, StreamEndStop ) { - return value; - } -} - -#define CATCH_INTERNAL_LINEINFO \ - ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) - -// end catch_common.h -namespace Catch { - - struct RegistrarForTagAliases { - RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); - }; - -} // end namespace Catch - -#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION - -// end catch_tag_alias_autoregistrar.h -// start catch_test_registry.h - -// start catch_interfaces_testcase.h - -#include - -namespace Catch { - - class TestSpec; - - struct ITestInvoker { - virtual void invoke () const = 0; - virtual ~ITestInvoker(); - }; - - class TestCase; - struct IConfig; - - struct ITestCaseRegistry { - virtual ~ITestCaseRegistry(); - virtual std::vector const& getAllTests() const = 0; - virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; - }; - - bool isThrowSafe( TestCase const& testCase, IConfig const& config ); - bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); - std::vector const& getAllTestCasesSorted( IConfig const& config ); - -} - -// end catch_interfaces_testcase.h -// start catch_stringref.h - -#include -#include -#include -#include - -namespace Catch { - - /// A non-owning string class (similar to the forthcoming std::string_view) - /// Note that, because a StringRef may be a substring of another string, - /// it may not be null terminated. - class StringRef { - public: - using size_type = std::size_t; - using const_iterator = const char*; - - private: - static constexpr char const* const s_empty = ""; - - char const* m_start = s_empty; - size_type m_size = 0; - - public: // construction - constexpr StringRef() noexcept = default; - - StringRef( char const* rawChars ) noexcept; - - constexpr StringRef( char const* rawChars, size_type size ) noexcept - : m_start( rawChars ), - m_size( size ) - {} - - StringRef( std::string const& stdString ) noexcept - : m_start( stdString.c_str() ), - m_size( stdString.size() ) - {} - - explicit operator std::string() const { - return std::string(m_start, m_size); - } - - public: // operators - auto operator == ( StringRef const& other ) const noexcept -> bool; - auto operator != (StringRef const& other) const noexcept -> bool { - return !(*this == other); - } - - auto operator[] ( size_type index ) const noexcept -> char { - assert(index < m_size); - return m_start[index]; - } - - public: // named queries - constexpr auto empty() const noexcept -> bool { - return m_size == 0; - } - constexpr auto size() const noexcept -> size_type { - return m_size; - } - - // Returns the current start pointer. If the StringRef is not - // null-terminated, throws std::domain_exception - auto c_str() const -> char const*; - - public: // substrings and searches - // Returns a substring of [start, start + length). - // If start + length > size(), then the substring is [start, size()). - // If start > size(), then the substring is empty. - auto substr( size_type start, size_type length ) const noexcept -> StringRef; - - // Returns the current start pointer. May not be null-terminated. - auto data() const noexcept -> char const*; - - constexpr auto isNullTerminated() const noexcept -> bool { - return m_start[m_size] == '\0'; - } - - public: // iterators - constexpr const_iterator begin() const { return m_start; } - constexpr const_iterator end() const { return m_start + m_size; } - }; - - auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; - auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; - - constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { - return StringRef( rawChars, size ); - } -} // namespace Catch - -constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { - return Catch::StringRef( rawChars, size ); -} - -// end catch_stringref.h -// start catch_preprocessor.hpp - - -#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ -#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) -#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) -#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) -#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) -#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) - -#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ -// MSVC needs more evaluations -#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) -#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) -#else -#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) -#endif - -#define CATCH_REC_END(...) -#define CATCH_REC_OUT - -#define CATCH_EMPTY() -#define CATCH_DEFER(id) id CATCH_EMPTY() - -#define CATCH_REC_GET_END2() 0, CATCH_REC_END -#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 -#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 -#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT -#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) -#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) - -#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) - -#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) - -// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, -// and passes userdata as the first parameter to each invocation, -// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) -#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) - -#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) - -#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) -#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ -#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ -#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF -#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) -#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ -#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) -#else -// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF -#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) -#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ -#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) -#endif - -#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ -#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) - -#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) - -#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper()) -#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) -#else -#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper())) -#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) -#endif - -#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ - CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) - -#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) -#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) -#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) -#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) -#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) -#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) -#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6) -#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) -#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) -#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) -#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) - -#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N - -#define INTERNAL_CATCH_TYPE_GEN\ - template struct TypeList {};\ - template\ - constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ - template class...> struct TemplateTypeList{};\ - template class...Cs>\ - constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\ - template\ - struct append;\ - template\ - struct rewrap;\ - template class, typename...>\ - struct create;\ - template class, typename>\ - struct convert;\ - \ - template \ - struct append { using type = T; };\ - template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ - struct append, L2, Rest...> { using type = typename append, Rest...>::type; };\ - template< template class L1, typename...E1, typename...Rest>\ - struct append, TypeList, Rest...> { using type = L1; };\ - \ - template< template class Container, template class List, typename...elems>\ - struct rewrap, List> { using type = TypeList>; };\ - template< template class Container, template class List, class...Elems, typename...Elements>\ - struct rewrap, List, Elements...> { using type = typename append>, typename rewrap, Elements...>::type>::type; };\ - \ - template