diff --git a/apps/Numcraft/.cargo/config.toml b/apps/Numcraft/.cargo/config.toml deleted file mode 100644 index bcf5cc62..00000000 --- a/apps/Numcraft/.cargo/config.toml +++ /dev/null @@ -1,13 +0,0 @@ -[target.thumbv7em-none-eabihf] -runner = 'npm exec --yes -- nwlink@0.0.19 install-nwa' -rustflags = ["-C", "link-arg=--relocatable", "-C", "link-arg=-no-gc-sections", "-C", "link-arg=-L../../api", "-C", "link-arg=-lapi"] - -[target.'cfg(target_os="macos")'] -rustflags = [ - "-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup", "-C", "link-arg=-lSystem" -] - -[target.'cfg(target_os="linux")'] -rustflags = [ - "-C", "link-arg=-Wl,-undefined,dynamic_lookup", "-C", "link-arg=-Wl,-z,undefs" -] diff --git a/apps/Numcraft/.gitattributes b/apps/Numcraft/.gitattributes deleted file mode 100644 index c9f9c448..00000000 --- a/apps/Numcraft/.gitattributes +++ /dev/null @@ -1,4 +0,0 @@ -*.rs text eol=lf -*.toml text eol=lf -*.md text eol=lf -*.json text eol=lf \ No newline at end of file diff --git a/apps/Numcraft/.github/CODE_OF_CONDUCT.md b/apps/Numcraft/.github/CODE_OF_CONDUCT.md deleted file mode 100644 index 2d8e5fb8..00000000 --- a/apps/Numcraft/.github/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,128 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -We as members, contributors, and leaders pledge to make participation in our -community a harassment-free experience for everyone, regardless of age, body -size, visible or invisible disability, ethnicity, sex characteristics, gender -identity and expression, level of experience, education, socio-economic status, -nationality, personal appearance, race, religion, or sexual identity -and orientation. - -We pledge to act and interact in ways that contribute to an open, welcoming, -diverse, inclusive, and healthy community. - -## Our Standards - -Examples of behavior that contributes to a positive environment for our -community include: - -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, - and learning from the experience -* Focusing on what is best not just for us as individuals, but for the - overall community - -Examples of unacceptable behavior include: - -* The use of sexualized language or imagery, and sexual attention or - advances of any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email - address, without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Enforcement Responsibilities - -Community leaders are responsible for clarifying and enforcing our standards of -acceptable behavior and will take appropriate and fair corrective action in -response to any behavior that they deem inappropriate, threatening, offensive, -or harmful. - -Community leaders have the right and responsibility to remove, edit, or reject -comments, commits, code, wiki edits, issues, and other contributions that are -not aligned to this Code of Conduct, and will communicate reasons for moderation -decisions when appropriate. - -## Scope - -This Code of Conduct applies within all community spaces, and also applies when -an individual is officially representing the community in public spaces. -Examples of representing our community include using an official e-mail address, -posting via an official social media account, or acting as an appointed -representative at an online or offline event. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to the community leaders responsible for enforcement at -contact@ynis.fr. -All complaints will be reviewed and investigated promptly and fairly. - -All community leaders are obligated to respect the privacy and security of the -reporter of any incident. - -## Enforcement Guidelines - -Community leaders will follow these Community Impact Guidelines in determining -the consequences for any action they deem in violation of this Code of Conduct: - -### 1. Correction - -**Community Impact**: Use of inappropriate language or other behavior deemed -unprofessional or unwelcome in the community. - -**Consequence**: A private, written warning from community leaders, providing -clarity around the nature of the violation and an explanation of why the -behavior was inappropriate. A public apology may be requested. - -### 2. Warning - -**Community Impact**: A violation through a single incident or series -of actions. - -**Consequence**: A warning with consequences for continued behavior. No -interaction with the people involved, including unsolicited interaction with -those enforcing the Code of Conduct, for a specified period of time. This -includes avoiding interactions in community spaces as well as external channels -like social media. Violating these terms may lead to a temporary or -permanent ban. - -### 3. Temporary Ban - -**Community Impact**: A serious violation of community standards, including -sustained inappropriate behavior. - -**Consequence**: A temporary ban from any sort of interaction or public -communication with the community for a specified period of time. No public or -private interaction with the people involved, including unsolicited interaction -with those enforcing the Code of Conduct, is allowed during this period. -Violating these terms may lead to a permanent ban. - -### 4. Permanent Ban - -**Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an -individual, or aggression toward or disparagement of classes of individuals. - -**Consequence**: A permanent ban from any sort of public interaction within -the community. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], -version 2.0, available at -https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. - -Community Impact Guidelines were inspired by [Mozilla's code of conduct -enforcement ladder](https://github.com/mozilla/diversity). - -[homepage]: https://www.contributor-covenant.org - -For answers to common questions about this code of conduct, see the FAQ at -https://www.contributor-covenant.org/faq. Translations are available at -https://www.contributor-covenant.org/translations. diff --git a/apps/Numcraft/.github/CONTRIBUTING.md b/apps/Numcraft/.github/CONTRIBUTING.md deleted file mode 100644 index e1793435..00000000 --- a/apps/Numcraft/.github/CONTRIBUTING.md +++ /dev/null @@ -1,28 +0,0 @@ -# How to contribute to Numcraft? -## Steps for creating good issues or pull requests. -If your issue is related to a bug, please give the full error message if one is shown. Please describe the context of the bug, the OS version, the calculator model and if possible, the release version or the latest commit. - -If you are asking for an enhancement, please concider the hardware resptrictions : -- Multiplayer is currently impossible -- No sound -- Numcraft must be compatible with N0110, N0115 and N0120. So make sure that the game runs on N0110 or N0115. -- and a lot of other restrictions -- extremelly low amount of ram - -Before reporting a bug please read the `Known bugs` section and the `Roadmap` before asking for features. - -## About vibe codding and AI -Nowdays, vibe codding is more and more used. It's an easy way to write code quickly but AIs have a big problem when it comes to programming on a calculator: they don't know the hardware. This is mainly due to the lack of documentation about this hardware. Moreover, I prefer code that is written by humans. For me, code is an art (and particularly video games) so I encourage handwriting code. - -So please, avoid vibe codding if you can. If you still want to use AI to write your code please: - - Limit the work of the AI to a single function or a few ones. - - Don't let the AI architecturing the project. - - Don't let the AI modifiying existing code when it's not necessary. - - Don't let the AI writing very low level code. - - Carrefully read the generated code. Do not open a pull request if it works, read the entiere generated code before openning it. And be extremelly careful about the rendering. - -## Code guideline -- All the code including, function names, commentaries, structures names, etc... must be in english. -- When a part of your code is not easy to understand or is very abstract, please add comments. Functions like `place_air` and that have only a few lines of code doesn't necessary need comments. -- Please fit your code to the current architecture of the project. Do not refactor the whole project. If you strongly believe that the code needs a complete refactor, please open a discussion thread first. -- If you use the simulator to code your PR, please remember that your code will run on machines that are thousands of time less powerful than your computer. So always try your code on real hardware before openning a new PR. diff --git a/apps/Numcraft/.github/FUNDING.yml b/apps/Numcraft/.github/FUNDING.yml deleted file mode 100644 index 3ff9b6f3..00000000 --- a/apps/Numcraft/.github/FUNDING.yml +++ /dev/null @@ -1,4 +0,0 @@ -# These are supported funding model platforms - -github: [yannis300307] - diff --git a/apps/Numcraft/.github/ISSUE_TEMPLATE/bug_report.md b/apps/Numcraft/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index d2d21547..00000000 --- a/apps/Numcraft/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: "[BUG] " -labels: bug -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Details:** -OS version : -Numworks model (N0110, N0115 or N0120): -Game version or latest commit: - -**Additional context** -Add any other context about the problem here. diff --git a/apps/Numcraft/.github/ISSUE_TEMPLATE/custom.md b/apps/Numcraft/.github/ISSUE_TEMPLATE/custom.md deleted file mode 100644 index 48d5f81f..00000000 --- a/apps/Numcraft/.github/ISSUE_TEMPLATE/custom.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: Custom issue template -about: Describe this issue template's purpose here. -title: '' -labels: '' -assignees: '' - ---- - - diff --git a/apps/Numcraft/.github/ISSUE_TEMPLATE/feature_request.md b/apps/Numcraft/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 11fc491e..00000000 --- a/apps/Numcraft/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: enhancement -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/apps/Numcraft/.github/SECURITY.md b/apps/Numcraft/.github/SECURITY.md deleted file mode 100644 index 77474380..00000000 --- a/apps/Numcraft/.github/SECURITY.md +++ /dev/null @@ -1,4 +0,0 @@ -# Security Policy -## Reporting a Vulnerability - -There is no reason to have a security issue but if you find a way to bypass the exam mode, please report it immediately to the Numworks team. diff --git a/apps/Numcraft/.github/controls.svg b/apps/Numcraft/.github/controls.svg deleted file mode 100644 index 2fa281fb..00000000 --- a/apps/Numcraft/.github/controls.svg +++ /dev/null @@ -1,748 +0,0 @@ - - - -InventoryBreak block -InventoryPlace bLockMove playercursor -Move hotbar's Move cameraFly up and down diff --git a/apps/Numcraft/.github/workflows/build.yml b/apps/Numcraft/.github/workflows/build.yml deleted file mode 100644 index 3949821a..00000000 --- a/apps/Numcraft/.github/workflows/build.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Build -on: [pull_request, push] - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v3 - - uses: carlosperate/arm-none-eabi-gcc-action@v1 - - name: Install nwlink - uses: actions/setup-node@v4 - with: - node-version: 22 - - run: npm install -g nwlink - - run: echo "$HOME/.npm-global/bin" >> $GITHUB_PATH - - name: Install Rust toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: nightly - target: thumbv7em-none-eabihf - - name: Install just - uses: extractions/setup-just@v3 - - name: Build app - run: just build diff --git a/apps/Numcraft/.github/workflows/publish.yml b/apps/Numcraft/.github/workflows/publish.yml deleted file mode 100644 index 769d6f85..00000000 --- a/apps/Numcraft/.github/workflows/publish.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Build and publish -on: - push: - branches: - - main -jobs: - publish: - name: Publish - runs-on: ubuntu-latest - steps: - - name: Get latest code - uses: actions/checkout@v4 - - uses: carlosperate/arm-none-eabi-gcc-action@v1 - - name: Install nwlink - uses: actions/setup-node@v4 - with: - node-version: 22 - - run: npm install -g nwlink - - run: echo "$HOME/.npm-global/bin" >> $GITHUB_PATH - - name: Install Rust toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: nightly - target: thumbv7em-none-eabihf - - name: Install just - uses: extractions/setup-just@v3 - - name: Build app - run: just build - - run: mv target/thumbv7em-none-eabihf/release/Numcraft target/thumbv7em-none-eabihf/release/Numcraft.nwa - - uses: actions/upload-artifact@v4 - with: - name: Numcraft-app - path: target/thumbv7em-none-eabihf/release/Numcraft.nwa \ No newline at end of file diff --git a/apps/Numcraft/.gitignore b/apps/Numcraft/.gitignore deleted file mode 100644 index 352c0474..00000000 --- a/apps/Numcraft/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -/target -/node_modules -.DS_store -/epsilon_simulator -/.vscode \ No newline at end of file diff --git a/apps/Numcraft/Cargo.lock b/apps/Numcraft/Cargo.lock deleted file mode 100644 index 97619534..00000000 --- a/apps/Numcraft/Cargo.lock +++ /dev/null @@ -1,1618 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "Numcraft" -version = "0.1.3" -dependencies = [ - "bresenham", - "cc", - "cortex-m", - "embedded-alloc", - "enum-iterator", - "fastnoise-lite", - "format_no_std", - "heapless 0.8.0", - "image", - "libm", - "lz4_flex", - "nalgebra", - "postcard", - "rand_core 0.9.3", - "rand_xorshift", - "regex", - "serde", - "serde_json", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "aligned-vec" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" -dependencies = [ - "equator", -] - -[[package]] -name = "anyhow" -version = "1.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" - -[[package]] -name = "approx" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" -dependencies = [ - "num-traits", -] - -[[package]] -name = "arbitrary" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" - -[[package]] -name = "arg_enum_proc_macro" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - -[[package]] -name = "atomic-polyfill" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" -dependencies = [ - "critical-section", -] - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "av1-grain" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3efb2ca85bc610acfa917b5aaa36f3fcbebed5b3182d7f877b02531c4b80c8" -dependencies = [ - "anyhow", - "arrayvec", - "log", - "nom", - "num-rational", - "v_frame", -] - -[[package]] -name = "avif-serialize" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19135c0c7a60bfee564dbe44ab5ce0557c6bf3884e5291a50be76a15640c4fbd" -dependencies = [ - "arrayvec", -] - -[[package]] -name = "bare-metal" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" -dependencies = [ - "rustc_version 0.2.3", -] - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "bit_field" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" - -[[package]] -name = "bitfield" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" - -[[package]] -name = "bitstream-io" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" - -[[package]] -name = "bresenham" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfc1116225f66d2ea341a26503f83a6b1205070a6f7199ce1f1550ead91f6fd7" - -[[package]] -name = "built" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" - -[[package]] -name = "bumpalo" -version = "3.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" - -[[package]] -name = "bytemuck" -version = "1.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "byteorder-lite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" - -[[package]] -name = "cc" -version = "1.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" -dependencies = [ - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cfg-expr" -version = "0.15.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" -dependencies = [ - "smallvec", - "target-lexicon", -] - -[[package]] -name = "cfg-if" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" - -[[package]] -name = "cobs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" -dependencies = [ - "thiserror 2.0.12", -] - -[[package]] -name = "color_quant" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" - -[[package]] -name = "const-default" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b396d1f76d455557e1218ec8066ae14bba60b4b36ecd55577ba979f5db7ecaa" - -[[package]] -name = "cortex-m" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" -dependencies = [ - "bare-metal", - "bitfield", - "critical-section", - "embedded-hal", - "volatile-register", -] - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "critical-section" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" - -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crunchy" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "embedded-alloc" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f2de9133f68db0d4627ad69db767726c99ff8585272716708227008d3f1bddd" -dependencies = [ - "const-default", - "critical-section", - "linked_list_allocator", - "rlsf", -] - -[[package]] -name = "embedded-hal" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" -dependencies = [ - "nb 0.1.3", - "void", -] - -[[package]] -name = "embedded-io" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" - -[[package]] -name = "embedded-io" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" - -[[package]] -name = "enum-iterator" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4549325971814bda7a44061bf3fe7e487d447cba01e4220a4b454d630d7a016" -dependencies = [ - "enum-iterator-derive", -] - -[[package]] -name = "enum-iterator-derive" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "equator" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" -dependencies = [ - "equator-macro", -] - -[[package]] -name = "equator-macro" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "exr" -version = "1.73.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" -dependencies = [ - "bit_field", - "half", - "lebe", - "miniz_oxide", - "rayon-core", - "smallvec", - "zune-inflate", -] - -[[package]] -name = "fastnoise-lite" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e5f3c3cc9081e5d0e18bcd50e80cd33cba47fc22f88a9da9c33ecd1c87ea5c0" -dependencies = [ - "num-traits", -] - -[[package]] -name = "fdeflate" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" -dependencies = [ - "simd-adler32", -] - -[[package]] -name = "flate2" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "format_no_std" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ae45e32b0bfe2c62c805f8e87027b5aa08562000326edbc5b421ab6d92873a7" - -[[package]] -name = "getrandom" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.11.1+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" -dependencies = [ - "cfg-if", - "libc", - "r-efi", - "wasi 0.14.2+wasi-0.2.4", -] - -[[package]] -name = "gif" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b" -dependencies = [ - "color_quant", - "weezl", -] - -[[package]] -name = "half" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" -dependencies = [ - "cfg-if", - "crunchy", -] - -[[package]] -name = "hash32" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", -] - -[[package]] -name = "hash32" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" -dependencies = [ - "byteorder", -] - -[[package]] -name = "hashbrown" -version = "0.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" - -[[package]] -name = "heapless" -version = "0.7.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" -dependencies = [ - "atomic-polyfill", - "hash32 0.2.1", - "rustc_version 0.4.1", - "serde", - "spin", - "stable_deref_trait", -] - -[[package]] -name = "heapless" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" -dependencies = [ - "hash32 0.3.1", - "stable_deref_trait", -] - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "image" -version = "0.25.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" -dependencies = [ - "bytemuck", - "byteorder-lite", - "color_quant", - "exr", - "gif", - "image-webp", - "num-traits", - "png", - "qoi", - "ravif", - "rayon", - "rgb", - "tiff", - "zune-core", - "zune-jpeg", -] - -[[package]] -name = "image-webp" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6970fe7a5300b4b42e62c52efa0187540a5bef546c60edaf554ef595d2e6f0b" -dependencies = [ - "byteorder-lite", - "quick-error", -] - -[[package]] -name = "imgref" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" - -[[package]] -name = "indexmap" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "interpolate_name" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "jobserver" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" -dependencies = [ - "getrandom 0.3.3", - "libc", -] - -[[package]] -name = "jpeg-decoder" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07" - -[[package]] -name = "lebe" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" - -[[package]] -name = "libc" -version = "0.2.174" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" - -[[package]] -name = "libfuzzer-sys" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf78f52d400cf2d84a3a973a78a592b4adc535739e0a5597a0da6f0c357adc75" -dependencies = [ - "arbitrary", - "cc", -] - -[[package]] -name = "libm" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" - -[[package]] -name = "linked_list_allocator" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" - -[[package]] -name = "lock_api" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" - -[[package]] -name = "loop9" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" -dependencies = [ - "imgref", -] - -[[package]] -name = "lz4_flex" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08ab2867e3eeeca90e844d1940eab391c9dc5228783db2ed999acbc0a9ed375a" - -[[package]] -name = "maybe-rayon" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" -dependencies = [ - "cfg-if", - "rayon", -] - -[[package]] -name = "memchr" -version = "2.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", - "simd-adler32", -] - -[[package]] -name = "nalgebra" -version = "0.33.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26aecdf64b707efd1310e3544d709c5c0ac61c13756046aaaba41be5c4f66a3b" -dependencies = [ - "approx", - "num-complex", - "num-rational", - "num-traits", - "simba", - "typenum", -] - -[[package]] -name = "nb" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" -dependencies = [ - "nb 1.1.0", -] - -[[package]] -name = "nb" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" - -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "noop_proc_macro" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", - "libm", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - -[[package]] -name = "png" -version = "0.17.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" -dependencies = [ - "bitflags 1.3.2", - "crc32fast", - "fdeflate", - "flate2", - "miniz_oxide", -] - -[[package]] -name = "postcard" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c1de96e20f51df24ca73cafcc4690e044854d803259db27a00a461cb3b9d17a" -dependencies = [ - "cobs", - "embedded-io 0.4.0", - "embedded-io 0.6.1", - "heapless 0.7.17", - "serde", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "proc-macro2" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "profiling" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" -dependencies = [ - "profiling-procmacros", -] - -[[package]] -name = "profiling-procmacros" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" -dependencies = [ - "quote", - "syn 2.0.104", -] - -[[package]] -name = "qoi" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" -dependencies = [ - "bytemuck", -] - -[[package]] -name = "quick-error" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.16", -] - -[[package]] -name = "rand_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" - -[[package]] -name = "rand_xorshift" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" -dependencies = [ - "rand_core 0.9.3", -] - -[[package]] -name = "rav1e" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" -dependencies = [ - "arbitrary", - "arg_enum_proc_macro", - "arrayvec", - "av1-grain", - "bitstream-io", - "built", - "cfg-if", - "interpolate_name", - "itertools", - "libc", - "libfuzzer-sys", - "log", - "maybe-rayon", - "new_debug_unreachable", - "noop_proc_macro", - "num-derive", - "num-traits", - "once_cell", - "paste", - "profiling", - "rand", - "rand_chacha", - "simd_helpers", - "system-deps", - "thiserror 1.0.69", - "v_frame", - "wasm-bindgen", -] - -[[package]] -name = "ravif" -version = "0.11.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5825c26fddd16ab9f515930d49028a630efec172e903483c94796cfe31893e6b" -dependencies = [ - "avif-serialize", - "imgref", - "loop9", - "quick-error", - "rav1e", - "rayon", - "rgb", -] - -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "rgb" -version = "0.8.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" - -[[package]] -name = "rlsf" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222fb240c3286247ecdee6fa5341e7cdad0ffdf8e7e401d9937f2d58482a20bf" -dependencies = [ - "cfg-if", - "const-default", - "libc", - "svgbobdoc", -] - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver 1.0.26", -] - -[[package]] -name = "rustversion" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" - -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "serde_json" -version = "1.0.145" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", - "serde_core", -] - -[[package]] -name = "serde_spanned" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" -dependencies = [ - "serde", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "simba" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3a386a501cd104797982c15ae17aafe8b9261315b5d07e3ec803f2ea26be0fa" -dependencies = [ - "approx", - "num-complex", - "num-traits", - "paste", -] - -[[package]] -name = "simd-adler32" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" - -[[package]] -name = "simd_helpers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" -dependencies = [ - "quote", -] - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "svgbobdoc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2c04b93fc15d79b39c63218f15e3fdffaa4c227830686e3b7c5f41244eb3e50" -dependencies = [ - "base64", - "proc-macro2", - "quote", - "syn 1.0.109", - "unicode-width", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "system-deps" -version = "6.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" -dependencies = [ - "cfg-expr", - "heck", - "pkg-config", - "toml", - "version-compare", -] - -[[package]] -name = "target-lexicon" -version = "0.12.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" -dependencies = [ - "thiserror-impl 2.0.12", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "tiff" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" -dependencies = [ - "flate2", - "jpeg-decoder", - "weezl", -] - -[[package]] -name = "toml" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.22.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - -[[package]] -name = "typenum" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" - -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" - -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - -[[package]] -name = "v_frame" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" -dependencies = [ - "aligned-vec", - "num-traits", - "wasm-bindgen", -] - -[[package]] -name = "vcell" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" - -[[package]] -name = "version-compare" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - -[[package]] -name = "volatile-register" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" -dependencies = [ - "vcell", -] - -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - -[[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" -dependencies = [ - "wit-bindgen-rt", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.104", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "weezl" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" - -[[package]] -name = "winnow" -version = "0.7.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" -dependencies = [ - "memchr", -] - -[[package]] -name = "wit-bindgen-rt" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags 2.9.1", -] - -[[package]] -name = "zerocopy" -version = "0.8.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "zune-core" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" - -[[package]] -name = "zune-inflate" -version = "0.2.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" -dependencies = [ - "simd-adler32", -] - -[[package]] -name = "zune-jpeg" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7384255a918371b5af158218d131530f694de9ad3815ebdd0453a940485cb0fa" -dependencies = [ - "zune-core", -] diff --git a/apps/Numcraft/Cargo.toml b/apps/Numcraft/Cargo.toml deleted file mode 100644 index 83eab407..00000000 --- a/apps/Numcraft/Cargo.toml +++ /dev/null @@ -1,61 +0,0 @@ -cargo-features = ["profile-rustflags"] -[package] -name = "Numcraft" -version = "0.1.3" -authors = ["Yannis300307"] -edition = "2024" - -[[bin]] -name = "Numcraft" -path = "src/main.rs" -test = false -doctest = false -bench = false - -[lib] -path = "src/main.rs" -bench = false -crate-type = ["cdylib"] -name = "numcraft_sim" - -[features] - -debug_ui = [] - -[profile.dev] -panic="abort" -strip=true -opt-level= "z" -lto = true -codegen-units = 1 - -[profile.release] -panic="abort" -strip = true -opt-level = 3 -lto = true -codegen-units = 1 - -[dependencies] -nalgebra = {version = "0.33.2", default-features = false, features = ["libm"]} -libm = "0.2.15" -format_no_std = "1.2.0" -heapless = "0.8.0" -cortex-m = {version="0.7.7", features=["critical-section-single-core"]} -embedded-alloc = "0.6.0" -fastnoise-lite = { version="1.1.1", default-features=false, features = ["libm"] } -bresenham = "0.1.1" -lz4_flex = {version="0.11.5", default-features=false} -postcard = {version = "1.1.2", features=["alloc"]} -serde = {version = "1.0.219", default-features=false} -enum-iterator = "2.3.0" -rand_xorshift = "0.4.0" -rand_core = "0.9.3" - -[build-dependencies] -image = "0.25.6" -cc = "1.2.27" -regex = "1.11.1" -serde_json = "1.0.145" -serde = {version = "1.0.219", features = ["derive"]} -postcard = {version = "1.1.2", features=["alloc"]} diff --git a/apps/Numcraft/README.md b/apps/Numcraft/README.md index 68cfed6f..251b1468 100644 --- a/apps/Numcraft/README.md +++ b/apps/Numcraft/README.md @@ -1,111 +1,11 @@ -Commit 7bff466ca2c10334138275c4aa02241133da121c +# Numcraft -logo +Official repository : https://github.com/yannis300307/NumcraftRust -# [WIP] Numcraft Rust +You can see the complete code on the repository. -Numcraft Rust is a (WIP) cube sandbox game running natively on Numworks calculators. +The version on Upsilon External corresponds to commit [7bacdeeed232611e375070d87c6576afb74b388d](https://github.com/yannis300307/NumcraftRust/commit/7bacdeeed232611e375070d87c6576afb74b388d) -## Screenshot +Have fun! -image - - -screenshot - - - -Numcraft running on actual N0110 Numworks on latest Epsilon (more than 40 FPS on N120) and on the simulator. - -Note that this is not the final result but the current state of the project. - -## Current project state -[See Roadmap below] - -The program runs at 10-20 FPS on N0110 and 30-50 FPS on N0120. It runs perfectly on the simulator (it depends on your hardware though). - -## Support - -NumcraftRust should run on both N120, N115 and N110 models. You will get better performances with the N120 model (N110 and N115 have the same CPU clock speed and same RAM). - -## Roadmap -**Here is the current roadmap for the project :** -- [X] Fix the raycaster -- [ ] Textures -- [X] World deletion -- [X] World creation settings -- [X] Save system with compression -- [X] Collisions -- [X] Better world generation -- [X] Main menu -- [X] Creative menu to select multiple blocks -- [X] Menu to select between multiple worlds -- [ ] Lighting engine -- [ ] Mobs -- [X] Survival mode - -If I have the time: -- [ ] TNT -- [ ] Redstone -- [ ] Commands support -- [ ] Make a tool to convert Minecraft schematics to Numcraft structures -- [ ] Structures such as Villages -- [ ] Upsilon / Omega compatibility -- [ ] Mini games - -Good ideas but I will never have the time to do that : -- [ ] Mod support -- [ ] Multiplayer (impossible at this point in time) - -## Known Bugs: -- Weird beahaviors in the negative coordinates -- Rendering issues with the block selection marker -- Can randomly crash on start on N0120. You have to reset your calculator before downloading a new version (I can't do anything about that, it's related to the OS) -- Rendering issues and memory corruption if too many triangles are shown at the same time on the screen - -## Setup the build environment - -To build this app, you will need to install an embedded ARM rust compiler, the [Arm GCC compiler](https://developer.arm.com/downloads/-/gnu-rm) as well as [Node.js](https://nodejs.org/en/). -The SDK for Epsilon apps is shipped as a npm module called [nwlink](https://www.npmjs.com/package/nwlink) that will automatically be installed at compile time. -**Make sure that `arm-none-eabi-gcc`is in your path.** - -For more explanations on how to install the c sdk, follow [this guide](https://www.numworks.com/engineering/software/build/). - -You might need to create a Python venv in the `epsilon_simulator` folder to install the pip packages on certain Linux distros. - -Then, you can set up the dependencies as follows : -```shell -brew install rustup node # Or equivalent on your OS -rustup-init -rustup target add thumbv7em-none-eabihf -cargo install just # Similar to makefile -``` - -## Build the app -```shell -just build -``` - -## Build and send the app to an actual calculator - -Connect the calculator to your computer and run -```shell -just send -``` - -## Run the app on the simulator - -```shell -just sim -``` -The simulator inputs will be automatically remapped for a better experience. - -Use `w`, `s`, `a` and `d` to move the player, `shift` and `space` to go up and down, arrows to turn the camera, `return` to place a block or select in a menu and `backspace` to break a block or to go back in a menu. - -You can speed up the simulator build by setting the job number. -```shell -just sim 5 -``` - -## Legal info -NumWorks is a registered trademark. +Licensed under GPL 3 diff --git a/apps/Numcraft/app.elf b/apps/Numcraft/app.elf new file mode 100644 index 00000000..5f4b5351 Binary files /dev/null and b/apps/Numcraft/app.elf differ diff --git a/apps/Numcraft/app.icon b/apps/Numcraft/app.icon new file mode 100644 index 00000000..27f3e76a Binary files /dev/null and b/apps/Numcraft/app.icon differ diff --git a/apps/Numcraft/assets/cross.png b/apps/Numcraft/assets/cross.png deleted file mode 100644 index 381edec0..00000000 Binary files a/apps/Numcraft/assets/cross.png and /dev/null differ diff --git a/apps/Numcraft/assets/font.png b/apps/Numcraft/assets/font.png deleted file mode 100644 index 008c2b13..00000000 Binary files a/apps/Numcraft/assets/font.png and /dev/null differ diff --git a/apps/Numcraft/assets/icon.svg b/apps/Numcraft/assets/icon.svg deleted file mode 100644 index dfeb94a4..00000000 --- a/apps/Numcraft/assets/icon.svg +++ /dev/null @@ -1,106 +0,0 @@ - - - - diff --git a/apps/Numcraft/assets/tileset.png b/apps/Numcraft/assets/tileset.png deleted file mode 100644 index 657c560f..00000000 Binary files a/apps/Numcraft/assets/tileset.png and /dev/null differ diff --git a/apps/Numcraft/build.rs b/apps/Numcraft/build.rs deleted file mode 100644 index af8b17c5..00000000 --- a/apps/Numcraft/build.rs +++ /dev/null @@ -1,254 +0,0 @@ -use image::{self, GenericImageView, ImageReader}; -use regex::Regex; -use serde::{Deserialize, Serialize}; -use serde_json::{Map, Value}; -use std::{fs, process::Command}; - -fn convert_image(file_name: &str) { - let img = ImageReader::open(format!("assets/{file_name}.png").as_str()) - .unwrap() - .decode() - .unwrap(); - - let mut converted_pixels: Vec = Vec::new(); - - for pix in img.pixels() { - converted_pixels.push(pix.2.0[0]); - } - - let data = converted_pixels.as_slice(); - - fs::write(format!("target/assets/{file_name}.bin").as_str(), data).unwrap(); -} - -fn patch_simulator() { - println!("cargo:rerun-if-changed=epsilon_simulator/ion/src/simulator/shared/keyboard.cpp"); - let remapped = "constexpr static KeySDLKeyPair sKeyPairs[] = {\ - KeySDLKeyPair(Key::OK, SDL_SCANCODE_RETURN),\ - KeySDLKeyPair(Key::Back, SDL_SCANCODE_BACKSPACE),\ - KeySDLKeyPair(Key::EXE, SDL_SCANCODE_ESCAPE),\ -\ - KeySDLKeyPair(Key::Var, SDL_SCANCODE_I),\ -\ - KeySDLKeyPair(Key::Toolbox, SDL_SCANCODE_W),\ - KeySDLKeyPair(Key::Imaginary, SDL_SCANCODE_A),\ - KeySDLKeyPair(Key::Power, SDL_SCANCODE_D),\ - KeySDLKeyPair(Key::Comma, SDL_SCANCODE_S),\ - KeySDLKeyPair(Key::Shift, SDL_SCANCODE_SPACE),\ - KeySDLKeyPair(Key::Exp, SDL_SCANCODE_LSHIFT),\ -\ - KeySDLKeyPair(Key::Down, SDL_SCANCODE_DOWN),\ - KeySDLKeyPair(Key::Up, SDL_SCANCODE_UP),\ - KeySDLKeyPair(Key::Left, SDL_SCANCODE_LEFT),\ - KeySDLKeyPair(Key::Right, SDL_SCANCODE_RIGHT),\ -};"; - - let file_content = fs::read_to_string("epsilon_simulator/ion/src/simulator/shared/keyboard.cpp") - .expect("Cannot open keyboard.cpp file from emulator. Please check if the simulator is clonned properly."); - - if !file_content.contains(remapped) { - let re = - Regex::new(r"constexpr static KeySDLKeyPair sKeyPairs\[] ?= ?\{[\S\s]*?};").unwrap(); - let result = re.replace(&file_content, remapped); - - fs::write( - "epsilon_simulator/ion/src/simulator/shared/keyboard.cpp", - result.as_bytes(), - ) - .unwrap(); - } -} - -fn convert_tileset() { - let img = ImageReader::open(format!("assets/tileset.png").as_str()) - .unwrap() - .decode() - .unwrap(); - - let mut data: Vec = Vec::new(); - - for pix in img.pixels() { - data.extend( - (((pix.2.0[0] as u16 & 0b11111000) << 8) - | ((pix.2.0[1] as u16 & 0b11111100) << 3) - | (pix.2.0[2] as u16 >> 3)) - .to_be_bytes(), - ); - } - - fs::write(format!("target/assets/tileset.bin").as_str(), data).unwrap(); -} - -fn convert_icon() { - let output = { - if let Ok(out) = Command::new("sh") - .arg("-c") - .arg("npx --yes -- nwlink@0.0.19 png-nwi assets/icon.png target/assets/icon.nwi") - .output() - { - out - } else { - panic!( - "Your OS is not supported! If you're using Windows, please compile Numcraft in WSL." - ); - } - }; - assert!( - output.status.success(), - "{}", - String::from_utf8_lossy(&output.stderr) - ); -} - -#[derive(Serialize, Deserialize, Debug)] -struct StructureFile { - name: String, - size: [u8; 3], - data: Vec>, - palette: Value, -} - -fn convert_struct(file_name: &str) { - let raw = fs::read_to_string(file_name) - .expect(format!("Unable to read the file {}", file_name).as_str()); - let structure_file: StructureFile = - serde_json::from_str(&raw).expect(format!("Invalid Json for file {}", file_name).as_str()); - - let mut data = Vec::new(); - - let palette = structure_file.palette; - - for y in 0..structure_file.size[1] as usize { - for z in 0..structure_file.size[2] as usize { - for x in 0..structure_file.size[0] as usize { - let letter = structure_file.data[y][z].as_bytes()[x]; - let block_id = &palette[str::from_utf8(&[letter]) - .expect(format!("Invalid char for structure in file {}", file_name).as_str())]; - data.push( - block_id.as_u64().expect( - format!("Invalid char for structure in file {}", file_name).as_str(), - ) as u8, - ); - } - } - } - - let mut raw: Vec = Vec::new(); - raw.extend_from_slice(&structure_file.size[0].to_be_bytes()); - raw.extend_from_slice(&structure_file.size[1].to_be_bytes()); - raw.extend_from_slice(&structure_file.size[2].to_be_bytes()); - - raw.extend(data); - - fs::write( - format!("target/structs/{}.bin", structure_file.name).to_string(), - raw, - ) - .expect(format!("Unable to write the structure file for file {}", file_name).as_str()); -} - -#[derive(Serialize, Deserialize, Debug)] -struct CraftFile { - name: String, - pattern: [String; 3], - strict_shape: bool, - palette: Value, - result: u8, - result_amount: u8, -} - -fn convert_craft(file_name: &str) { - let raw = fs::read_to_string(file_name) - .expect(format!("Unable to read the file {}", file_name).as_str()); - let craft_file: CraftFile = - serde_json::from_str(&raw).expect(format!("Invalid Json for file {}", file_name).as_str()); - - let mut data = Vec::new(); - - let palette = craft_file.palette; - - // Check the size of the lines - for i in 0..3 { - assert_eq!( - craft_file.pattern[i].len(), - 3, - "Invalid pattern in craft for file {}", - file_name - ); - } - - for y in 0..3 { - for x in 0..3 { - let letter = craft_file.pattern[y].as_bytes()[x]; - // Check if the letter is a space - if letter == ' ' as u8 { - data.push(0); - } else { - let item_id = &palette[str::from_utf8(&[letter]) - .expect(format!("Invalid char for craft in file {}", file_name).as_str())]; - let item_id_u8 = item_id - .as_u64() - .expect(format!("Invalid char for craft in file {}", file_name).as_str()) - as u8; - data.push(item_id_u8); - } - } - } - - data.push(if craft_file.strict_shape { 1 } else { 0 }); - data.push(craft_file.result); - data.push(craft_file.result_amount); - - fs::write( - format!("target/crafts/{}.bin", craft_file.name).to_string(), - data, - ) - .expect(format!("Unable to write the crafts file for file {}", file_name).as_str()); -} - -fn main() { - // Turn icon.png into icon.nwi - println!("cargo:rerun-if-changed=assets/icon.png"); - convert_icon(); - - // Convert font to usable data - println!("cargo:rerun-if-changed=assets/font.png"); - convert_image("font"); - - // Convert other textures - println!("cargo:rerun-if-changed=assets/cross.png"); - convert_image("cross"); - - // Convert tileset - println!("cargo:rerun-if-changed=assets/tileset.png"); - convert_tileset(); - - println!("cargo:rerun-if-changed=structs"); - - for file in fs::read_dir("structs").unwrap() { - convert_struct( - file.expect("Invalid file in struct directory.") - .path() - .as_os_str() - .to_str() - .unwrap(), - ); - } - - println!("cargo:rerun-if-changed=crafts"); - - for file in fs::read_dir("crafts").unwrap() { - convert_craft( - file.expect("Invalid file in struct directory.") - .path() - .as_os_str() - .to_str() - .unwrap(), - ); - } - - // Compile storage.c - if std::env::var("CARGO_CFG_TARGET_OS").unwrap() != "none" { - patch_simulator(); - } -} diff --git a/apps/Numcraft/crafts/grass.json b/apps/Numcraft/crafts/grass.json deleted file mode 100644 index 830c99cc..00000000 --- a/apps/Numcraft/crafts/grass.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "grass", - "pattern" : [ - "f ", - "d ", - " " - ], - "strict_shape": true, - "palette": { - "f": 8, - "d": 3 - }, - "result": 2, - "result_amount": 1 -} \ No newline at end of file diff --git a/apps/Numcraft/crafts/planks.json b/apps/Numcraft/crafts/planks.json deleted file mode 100644 index 241a3a67..00000000 --- a/apps/Numcraft/crafts/planks.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "planks", - "pattern" : [ - "x ", - " ", - " " - ], - "strict_shape": false, - "palette": { - "x": 7 - }, - "result": 9, - "result_amount": 8 -} \ No newline at end of file diff --git a/apps/Numcraft/crafts/stone.json b/apps/Numcraft/crafts/stone.json deleted file mode 100644 index c7f36dd2..00000000 --- a/apps/Numcraft/crafts/stone.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "stone", - "pattern" : [ - "xx ", - "xx ", - " " - ], - "strict_shape": false, - "palette": { - "x": 5 - }, - "result": 1, - "result_amount": 3 -} \ No newline at end of file diff --git a/apps/Numcraft/assets/icon.png b/apps/Numcraft/icon.png similarity index 100% rename from apps/Numcraft/assets/icon.png rename to apps/Numcraft/icon.png diff --git a/apps/Numcraft/justfile b/apps/Numcraft/justfile deleted file mode 100644 index b1d24719..00000000 --- a/apps/Numcraft/justfile +++ /dev/null @@ -1,48 +0,0 @@ -current_target := shell("rustc -vV | grep \"host:\" | awk '{print $2}'") - -build: setup_target - cargo build --release --bin Numcraft --target=thumbv7em-none-eabihf - -send: setup_target - cargo run --release --bin Numcraft --target=thumbv7em-none-eabihf - -check: setup_target - cargo build --release --bin Numcraft --target=thumbv7em-none-eabihf - cargo build --release --target={{current_target}} --lib - - -setup_target: - mkdir -p target/assets target/structs target/crafts - -[macos] -run_nwb: - ./epsilon_simulator/output/release/simulator/macos/epsilon.app/Contents/MacOS/Epsilon --nwb ./target/{{current_target}}/release/libnumcraft_sim.dylib - -[linux] -run_nwb: - ./epsilon_simulator/output/release/simulator/linux/epsilon.bin --nwb ./target/{{current_target}}/release/libnumcraft_sim.so - -sim jobs="1" features="": setup_target - -git clone https://github.com/numworks/epsilon.git epsilon_simulator -b version-20 # Broken with version 21. Nice! - if [ -n "{{features}}"];then \ - cargo build --release --target={{current_target}} --lib;\ - else \ - cargo build --release --target={{current_target}} --lib --features {{features}};\ - fi - - if [ ! -f "target/simulator_patched" ]; then \ - cd epsilon_simulator && make PLATFORM=simulator -j {{jobs}}; \ - cd ..; \ - echo "yes it is" >> target/simulator_patched; \ - fi - just run_nwb - -[confirm("This will clean the built app AND the simulator. Do you want to continue ?")] -clean-all: - cd ./epsilon_simulator && make clean - cargo clean - -[confirm("This will clean the built app AND DELETE the simulator. Do you want to continue ?")] -clear-all: - rm -rf ./epsilon_simulator - cargo clean diff --git a/apps/Numcraft/package-lock.json b/apps/Numcraft/package-lock.json deleted file mode 100644 index 5b1444ff..00000000 --- a/apps/Numcraft/package-lock.json +++ /dev/null @@ -1,135 +0,0 @@ -{ - "name": "epsilon-sample-app-rust", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "dependencies": { - "nwlink": "^0.0.19" - } - }, - "node_modules/@types/w3c-web-usb": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/w3c-web-usb/-/w3c-web-usb-1.0.6.tgz", - "integrity": "sha512-cSjhgrr8g4KbPnnijAr/KJDNKa/bBa+ixYkywFRvrhvi9n1WEl7yYbtRyzE6jqNQiSxxJxoAW3STaOQwJHndaw==", - "license": "MIT" - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-progress": { - "version": "3.11.2", - "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.11.2.tgz", - "integrity": "sha512-lCPoS6ncgX4+rJu5bS3F/iCz17kZ9MPZ6dpuTtI0KXKABkhyXIdYB3Inby1OpaGti3YlI3EeEkM9AuWpelJrVA==", - "license": "MIT", - "dependencies": { - "string-width": "^4.2.3" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/commander": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.3.0.tgz", - "integrity": "sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw==", - "license": "MIT", - "engines": { - "node": "^12.20.0 || >=14" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/node-addon-api": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", - "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", - "license": "MIT" - }, - "node_modules/node-gyp-build": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", - "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", - "license": "MIT", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, - "node_modules/nwlink": { - "version": "0.0.19", - "resolved": "https://registry.npmjs.org/nwlink/-/nwlink-0.0.19.tgz", - "integrity": "sha512-8o7Ym4wd7zKErwRry9D/U9pD7/wbrMFm0QR5m3KLQUXiMe3/8Km3Z8wU0vGQkeUYIMeoc5uUAx9q3HOZboeLIw==", - "license": "All rights reserved", - "dependencies": { - "cli-progress": "3.11.2", - "commander": "9.3.0", - "usb": "2.4.3" - }, - "bin": { - "nwlink": "bin/nwlink" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/usb": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/usb/-/usb-2.4.3.tgz", - "integrity": "sha512-BmCjjxsriODcrb+TdXdzSDDys+MOUeRvo22ywmyIxYcuVW9YKrr2Wp2gQZUfHrQbvovKu87Po9mk5OPftJdDeQ==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "@types/w3c-web-usb": "1.0.6", - "node-addon-api": "^4.2.0", - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=10.20.0 <11.x || >=12.17.0 <13.0 || >=14.0.0" - } - } - } -} diff --git a/apps/Numcraft/package.json b/apps/Numcraft/package.json deleted file mode 100644 index ddc42391..00000000 --- a/apps/Numcraft/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "dependencies": { - "nwlink": "^0.0.19" - } -} diff --git a/apps/Numcraft/rust-toolchain.toml b/apps/Numcraft/rust-toolchain.toml deleted file mode 100644 index 271800cb..00000000 --- a/apps/Numcraft/rust-toolchain.toml +++ /dev/null @@ -1,2 +0,0 @@ -[toolchain] -channel = "nightly" \ No newline at end of file diff --git a/apps/Numcraft/src/camera.rs b/apps/Numcraft/src/camera.rs deleted file mode 100644 index 11058bdb..00000000 --- a/apps/Numcraft/src/camera.rs +++ /dev/null @@ -1,105 +0,0 @@ -use core::f32::{self, consts::PI}; - -use libm::{cosf, sinf}; -use nalgebra::{Matrix4, UnitQuaternion, Vector3}; - -use crate::{ - constants::{player::ROTATION_SPEED, rendering::FOV}, - eadk, - input_manager::InputManager, -}; - -pub struct Camera { - pos: Vector3, - rotation: Vector3, - has_moved: bool, - fov: f32, -} - -impl Camera { - pub fn new() -> Self { - Camera { - pos: Vector3::new(0., 0., 0.), - rotation: Vector3::new(0., 0., 0.), - has_moved: true, - fov: FOV, - } - } - - pub fn get_fov(&self) -> f32 { - self.fov - } - - pub fn set_fov(&mut self, degrees: f32) { - self.fov = degrees * PI / 180.0; - } - - pub fn update(&mut self, delta: f32, input_manager: &InputManager) { - // Rotation - if input_manager.is_keydown(eadk::input::Key::Right) { - self.rotation.y -= delta * ROTATION_SPEED; - } - if input_manager.is_keydown(eadk::input::Key::Left) { - self.rotation.y += delta * ROTATION_SPEED; - } - if input_manager.is_keydown(eadk::input::Key::Up) { - self.rotation.x -= delta * ROTATION_SPEED; - - if self.rotation.x <= -PI / 2.0 + 0.0001 { - self.rotation.x = -PI / 2.0 + 0.0001 - } - } - if input_manager.is_keydown(eadk::input::Key::Down) { - self.rotation.x += delta * ROTATION_SPEED; - - if self.rotation.x >= PI / 2.0 - 0.0001 { - self.rotation.x = PI / 2.0 - 0.0001 - } - } - } - - pub fn update_pos(&mut self, position: Vector3) { - self.has_moved = self.pos != position; - - self.pos = position; // Updated from player - } - - pub fn get_forward_vector(&self) -> Vector3 { - Vector3::new( - cosf(self.rotation.x) * sinf(self.rotation.y), - -sinf(self.rotation.x), - cosf(self.rotation.x) * cosf(self.rotation.y), - ) - } - - pub fn get_right_vector(&self) -> Vector3 { - Vector3::new(cosf(self.rotation.y), 0.0, -sinf(self.rotation.y)) - } - - pub fn get_up_vector(&self) -> Vector3 { - Vector3::new( - sinf(self.rotation.x) * sinf(self.rotation.y), - cosf(self.rotation.x), - sinf(self.rotation.x) * cosf(self.rotation.y), - ) - } - - pub fn get_rotation_matrix(&self) -> Matrix4 { - let yaw = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), self.rotation.y); - let pitch = UnitQuaternion::from_axis_angle(&Vector3::x_axis(), self.rotation.x); - let orientation = yaw * pitch; - orientation.to_homogeneous() - } - - pub fn get_pos(&self) -> &Vector3 { - &self.pos - } - - pub fn get_has_moved(&self) -> bool { - self.has_moved - } - - pub fn get_rotation(&self) -> &Vector3 { - &self.rotation - } -} diff --git a/apps/Numcraft/src/constants.rs b/apps/Numcraft/src/constants.rs deleted file mode 100644 index 39e57945..00000000 --- a/apps/Numcraft/src/constants.rs +++ /dev/null @@ -1,281 +0,0 @@ -use nalgebra::Vector3; -use serde::{Deserialize, Serialize}; - -use crate::{eadk::Color, physic::BoundingBox, renderer::mesh::QuadDir}; - -pub mod rendering { - pub const SCREEN_WIDTH: usize = 320; - pub const SCREEN_HEIGHT: usize = 240; - - pub const SCREEN_TILE_SUBDIVISION: usize = 2; // Minimum 2 - - pub const MIN_FOV: f32 = 30.; - pub const MAX_FOV: f32 = 110.; - - pub const FOV: f32 = 45.; - - pub const MAX_TRIANGLES: usize = 1300; - - pub const MAX_RENDER_DISTANCE: usize = 2; // You shouldn't go higher - - pub const BLURING_SCREEN_SUBDIVISION: usize = 5; - pub const BLURING_RADIUS: isize = 2; - - pub const MAX_ENTITY_RENDER_DISTANCE: f32 = 10.; - - pub const ITEM_ENTITY_SPRITE_SIZE: f32 = 0.8; -} - -pub mod color_palette { - use crate::eadk::Color; - - pub const MENU_OUTLINE_COLOR: Color = Color::from_888(150, 150, 150); - pub const MENU_ELEMENT_BACKGROUND_COLOR: Color = Color::from_888(230, 230, 230); - pub const MENU_ELEMENT_BACKGROUND_COLOR_HOVER: Color = Color::from_888(190, 190, 190); - pub const MENU_TEXT_COLOR: Color = Color::from_888(0, 0, 0); - pub const MENU_BACKGROUND_COLOR: Color = Color::from_888(255, 255, 255); - - pub const GAMEUI_SLOT_COLOR: Color = Color::from_888(80, 80, 80); - pub const GAMEUI_SLOT_DEFAULT_OUTLINE_COLOR: Color = Color::from_888(120, 120, 120); -} - -pub mod save_manager { - pub const SETTINGS_FILENAME: &str = "settings.ncd"; // NCD = NumCraftData - - pub const WORLD_VERSION: u16 = 0; // Update the version at each world breaking update -} - -pub mod world { - pub const CHUNK_SIZE: usize = 8; // MAX 8 - - pub const MAX_ITEM_MERGING_DISTANCE: f32 = 2.; - pub const ITEM_MAGNET_FORCE: f32 = 10.; - pub const MAX_PLAYER_ITEM_MAGNET_DISTANCE: f32 = 2.2; -} - -pub mod player { - use core::f32::consts::PI; - - pub const ROTATION_SPEED: f32 = PI / 3.0; // rad / sec - pub const FLY_SPEED: f32 = 4.0; - pub const WALK_FORCE: f32 = 20.0; - pub const MAX_WALKING_VELOCITY: f32 = 4.; - pub const JUMP_FORCE: f32 = 5.; -} - -pub mod physic { - use nalgebra::Vector3; - - pub const GRAVITY_FACTOR: f32 = 10.0; - pub const MAX_FALLING_VELOCITY: f32 = 5.; - pub const ON_FLOOR_FRICTION: f32 = 10.; - - pub const BLOCK_COLLISION_SCANNING_SIZE: Vector3 = Vector3::new(2, 3, 2); -} - -#[allow(unreachable_patterns)] -impl EntityType { - pub fn get_bbox(&self) -> Option { - match self { - EntityType::Player => Some(BoundingBox { - offset: Vector3::new(-0.4, -0.5, -0.4), - size: Vector3::new(0.8, 1.8, 0.8), - }), - EntityType::Item => Some(BoundingBox { - offset: Vector3::new(-0.2, -0.2, -0.2), - size: Vector3::new(0.4, 0.4, 0.4), - }), - } - } -} - -#[derive(Clone, Copy, PartialEq, Eq)] -pub enum EntityType { - Player = 0, - Item = 1, -} - -#[derive(Clone, Copy, PartialEq, Eq)] -pub enum BlockType { - Air = 0, - Stone = 1, - Grass = 2, - Dirt = 3, - Sand = 4, - Cobblestone = 5, - Border = 6, - Log = 7, - Leaves = 8, - Planks = 9, -} - -#[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize)] -#[repr(u8)] -pub enum ItemType { - Air = 0, - - StoneBlock = 1, - GrassBlock = 2, - DirtBlock = 3, - SandBlock = 4, - CobblestoneBlock = 5, - BorderBlock = 6, - LogBlock = 7, - LeavesBlock = 8, - PlanksBlock = 9, -} - -impl ItemType { - pub fn get_texture_id(&self) -> u8 { - match *self { - ItemType::Air => 0, - - ItemType::StoneBlock => 1, - ItemType::GrassBlock => 2, - ItemType::DirtBlock => 3, // 4 is the other texture of the grass block - ItemType::SandBlock => 5, - ItemType::CobblestoneBlock => 6, - ItemType::BorderBlock => 7, - ItemType::LogBlock => 8, - ItemType::LeavesBlock => 9, - ItemType::PlanksBlock => 10, - } - } - - pub const fn get_from_id(id: u8) -> Option { - match id { - 0 => Some(ItemType::Air), - - 1 => Some(ItemType::StoneBlock), - 2 => Some(ItemType::GrassBlock), - 3 => Some(ItemType::DirtBlock), - 4 => Some(ItemType::SandBlock), - 5 => Some(ItemType::CobblestoneBlock), - 6 => Some(ItemType::BorderBlock), - 7 => Some(ItemType::LogBlock), - 8 => Some(ItemType::LeavesBlock), - 9 => Some(ItemType::PlanksBlock), - _ => None, - } - } - - pub fn get_max_stack_amount(&self) -> u8 { - match *self { - ItemType::Air => 0, - ItemType::StoneBlock => 64, - ItemType::GrassBlock => 64, - ItemType::DirtBlock => 64, - ItemType::SandBlock => 64, - ItemType::CobblestoneBlock => 64, - ItemType::BorderBlock => 64, - ItemType::LogBlock => 64, - ItemType::LeavesBlock => 64, - ItemType::PlanksBlock => 64, - } - } - - pub fn get_matching_block_type(&self) -> Option { - match self { - ItemType::Air => None, - ItemType::StoneBlock => Some(BlockType::Stone), - ItemType::GrassBlock => Some(BlockType::Grass), - ItemType::DirtBlock => Some(BlockType::Dirt), - ItemType::SandBlock => Some(BlockType::Sand), - ItemType::CobblestoneBlock => Some(BlockType::Cobblestone), - ItemType::BorderBlock => Some(BlockType::Border), - ItemType::LogBlock => Some(BlockType::Log), - ItemType::LeavesBlock => Some(BlockType::Leaves), - ItemType::PlanksBlock => Some(BlockType::Planks), - } - } -} - -impl BlockType { - pub fn is_air(&self) -> bool { - *self == BlockType::Air - } - - pub fn get_texture_id(&self, dir: QuadDir) -> u8 { - match *self { - BlockType::Air => 0, - BlockType::Stone => 1, - BlockType::Grass => { - if dir == QuadDir::Top { - 2 - } else { - 3 - } - } - BlockType::Dirt => 3, - BlockType::Sand => 5, - BlockType::Cobblestone => 6, - BlockType::Border => 7, - BlockType::Log => 8, - BlockType::Leaves => 9, - BlockType::Planks => 10, - } - } - - pub const fn get_from_id(id: u8) -> Option { - match id { - 0 => Some(BlockType::Air), - 1 => Some(BlockType::Stone), - 2 => Some(BlockType::Grass), - 3 => Some(BlockType::Dirt), - 4 => Some(BlockType::Sand), - 5 => Some(BlockType::Cobblestone), - 6 => Some(BlockType::Border), - 7 => Some(BlockType::Log), - 8 => Some(BlockType::Leaves), - 9 => Some(BlockType::Planks), - _ => None, - } - } - - pub const fn get_hardness(&self) -> f32 { - match self { - BlockType::Air => 0., - BlockType::Stone => 2., - BlockType::Grass => 1.2, - BlockType::Dirt => 1., - BlockType::Sand => 1., - BlockType::Cobblestone => 2.2, - BlockType::Border => -1., - BlockType::Log => 1.5, - BlockType::Leaves => 0.3, - BlockType::Planks => 1.2, - } - } - - pub const fn get_dropped_item_type(&self) -> ItemType { - match self { - BlockType::Air => ItemType::Air, - BlockType::Stone => ItemType::CobblestoneBlock, - BlockType::Grass => ItemType::DirtBlock, - BlockType::Dirt => ItemType::DirtBlock, - BlockType::Sand => ItemType::SandBlock, - BlockType::Cobblestone => ItemType::CobblestoneBlock, - BlockType::Border => ItemType::BorderBlock, - BlockType::Log => ItemType::LogBlock, - BlockType::Leaves => ItemType::LeavesBlock, - BlockType::Planks => ItemType::PlanksBlock, - } - } -} - -pub fn get_quad_color_from_texture_id(id: u8) -> Color { - match id { - 1 => Color::from_888(160, 160, 160), - 2 => Color::from_888(21, 147, 0), - 3 => Color::from_888(120, 77, 49), - 5 => Color::from_888(208, 199, 6), - 6 => Color::from_888(178, 178, 178), - 7 => Color::from_888(19, 19, 19), - 8 => Color::from_888(79, 53, 30), - 9 => Color::from_888(36, 75, 37), - 10 => Color::from_888(152, 124, 61), - - _ => Color::from_888(0, 0, 0), - // 255 is reserved for block outline - } -} diff --git a/apps/Numcraft/src/eadk.rs b/apps/Numcraft/src/eadk.rs deleted file mode 100644 index 48890201..00000000 --- a/apps/Numcraft/src/eadk.rs +++ /dev/null @@ -1,562 +0,0 @@ -#[repr(C)] -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct Color { - pub rgb565: u16, -} - -pub const COLOR_BLACK: Color = Color::from_888(0, 0, 0); - -impl Color { - #[inline] - pub const fn from_components(r: u16, g: u16, b: u16) -> Self { - Color { - rgb565: r << 11 | g << 5 | b, - } - } - pub const fn from_888(r: u16, g: u16, b: u16) -> Self { - Color { - rgb565: ((r & 0b11111000) << 8) | ((g & 0b11111100) << 3) | (b >> 3), - } - } - - pub fn apply_light(&self, light_level: u8) -> Self { - let light_level = light_level as u16; - let rgb = self.get_components(); - Color::from_components( - rgb.0 * light_level / 255, - rgb.1 * light_level / 255, - rgb.2 * light_level / 255, - ) - } - - pub const fn get_components(&self) -> (u16, u16, u16) { - let r = self.rgb565 >> 11; - let g = (self.rgb565 & 0b0000011111100000) >> 5; - let b = self.rgb565 & 0b0000000000011111; - - (r, g, b) - } -} - -#[repr(C)] -#[derive(Clone, Copy)] -pub struct Rect { - pub x: u16, - pub y: u16, - pub width: u16, - pub height: u16, -} - -pub const SCREEN_RECT: Rect = Rect { - x: 0, - y: 0, - width: 320, - height: 240, -}; - -#[repr(C)] -#[derive(Clone, Copy)] -pub struct Point { - pub x: u16, - pub y: u16, -} - -pub mod backlight { - pub fn set_brightness(brightness: u8) { - } - pub fn brightness() -> u8 { - 0 - } -} - -pub mod display { - use super::Color; - use super::Point; - use super::Rect; - - #[cfg(target_os = "none")] - use alloc::vec::Vec; - - #[cfg(target_os = "none")] - use alloc::ffi::CString; - - #[cfg(not(target_os = "none"))] - use std::ffi::CString; - - use core::ffi::c_char; - - pub fn push_rect(rect: Rect, pixels: &[Color]) { - unsafe { - extapp_pushRect(rect.x, rect.y, rect.width, rect.height, pixels.as_ptr()); - } - } - - pub fn pull_rect(rect: Rect) -> Vec { - let size = rect.width as usize * rect.height as usize; - let mut vec: Vec = Vec::with_capacity(size); - for _ in 0..size { - use crate::eadk::COLOR_BLACK; - - vec.push(COLOR_BLACK); - } - - unsafe { - extapp_pullRect(rect.x, rect.y, rect.width, rect.height, vec.as_mut_slice().as_mut_ptr()); - } - - vec - } - - pub fn push_rect_uniform(rect: Rect, color: Color) { - unsafe { - extapp_pushRectUniform(rect.x, rect.y, rect.width, rect.height, color); - } - } - - pub fn wait_for_vblank() { - unsafe { - extapp_waitForVBlank(); - } - } - - pub fn draw_string( - text: &str, - point: Point, - large_font: bool, - text_color: Color, - background_color: Color, - ) { - let c_string = - CString::new(text).expect("Can't convert str to C_String. Maybe invalid caracter."); - unsafe { - if large_font { - extapp_drawTextLarge( - c_string.as_ptr(), - point.x, - point.y, - text_color, - background_color, - false, - ) - } else { - extapp_drawTextSmall( - c_string.as_ptr(), - point.x, - point.y, - text_color, - background_color, - false, - ) - } - } - } - - unsafe extern "C" { - fn extapp_pushRectUniform(x: u16, y: u16, w: u16, h: u16, color: Color); - fn extapp_pushRect(x: u16, y: u16, w: u16, h: u16, color: *const Color); - fn extapp_waitForVBlank() -> bool; - fn extapp_pullRect(x: u16, y: u16, w: u16, h: u16, color: *mut Color); - fn extapp_drawTextLarge( - text: *const c_char, - x: u16, - y: u16, - text_color: Color, - background_color: Color, - fake: bool, - ); - fn extapp_drawTextSmall( - text: *const c_char, - x: u16, - y: u16, - text_color: Color, - background_color: Color, - fake: bool, - ); - - } -} - -pub mod timing { - pub fn usleep(us: u32) { - msleep(us / 1000) - } - - pub fn msleep(ms: u32) { - unsafe { - extapp_msleep(ms); - } - } - - pub fn millis() -> u64 { - unsafe { extapp_millis() } - } - - unsafe extern "C" { - fn extapp_msleep(us: u32); - fn extapp_millis() -> u64; - } -} - -pub fn random() -> u32 { - millis() as u32 -} - -pub mod input { - use enum_iterator::Sequence; - - type EadkKeyboardState = u64; - - #[allow(dead_code)] - #[derive(Clone, Copy, PartialEq, Eq, Sequence, Debug)] - #[repr(u8)] - pub enum Key { - Left = 0, - Up = 1, - Down = 2, - Right = 3, - Ok = 4, - Back = 5, - Home = 6, - OnOff = 8, - Shift = 12, - Alpha = 13, - Xnt = 14, - Var = 15, - Toolbox = 16, - Backspace = 17, - Exp = 18, - Ln = 19, - Log = 20, - Imaginary = 21, - Comma = 22, - Power = 23, - Sine = 24, - Cosine = 25, - Tangent = 26, - Pi = 27, - Sqrt = 28, - Square = 29, - Seven = 30, - Eight = 31, - Nine = 32, - LeftParenthesis = 33, - RightParenthesis = 34, - Four = 36, - Five = 37, - Six = 38, - Multiplication = 39, - Division = 40, - One = 42, - Two = 43, - Three = 44, - Plus = 45, - Minus = 46, - Zero = 48, - Dot = 49, - Ee = 50, - Ans = 51, - Exe = 52, - } - - unsafe extern "C" { - fn extapp_scanKeyboard() -> EadkKeyboardState; - } - - #[derive(Clone, Copy)] - pub struct KeyboardState(EadkKeyboardState); - - impl Default for KeyboardState { - fn default() -> Self { - Self::new() - } - } - - impl KeyboardState { - pub fn scan() -> Self { - Self::from_raw(unsafe { extapp_scanKeyboard() }) - } - - pub fn new() -> Self { - KeyboardState(0) - } - - pub fn from_raw(state: EadkKeyboardState) -> Self { - Self(state) - } - - pub fn key_down(&self, key: Key) -> bool { - (self.0 >> (key as u8)) & 1 != 0 - } - - pub fn get_just_pressed(&self, old: KeyboardState) -> Self { - KeyboardState(self.0 & (!old.0)) - } - - pub fn get_just_realeased(&self, old: KeyboardState) -> Self { - KeyboardState((!self.0) & old.0) - } - } - - #[allow(dead_code)] - #[derive(Clone, Copy, PartialEq, Eq)] - #[repr(u16)] - pub enum Event { - Left = 0, - Up = 1, - Down = 2, - Right = 3, - Ok = 4, - Back = 5, - Shift = 12, - Alpha = 13, - Xnt = 14, - Var = 15, - Toolbox = 16, - Backspace = 17, - Exp = 18, - Ln = 19, - Log = 20, - Imaginary = 21, - Comma = 22, - Power = 23, - Sine = 24, - Cosine = 25, - Tangent = 26, - Pi = 27, - Sqrt = 28, - Square = 29, - Seven = 30, - Eight = 31, - Nine = 32, - LeftParenthesis = 33, - RightParenthesis = 34, - Four = 36, - Five = 37, - Six = 38, - Multiplication = 39, - Division = 40, - One = 42, - Two = 43, - Three = 44, - Plus = 45, - Minus = 46, - Zero = 48, - Dot = 49, - Ee = 50, - Ans = 51, - Exe = 52, - ShiftLeft = 54, - ShiftUp = 55, - ShiftDown = 56, - ShiftRight = 57, - AlphaLock = 67, - Cut = 68, - Copy = 69, - Paste = 70, - Clear = 71, - LeftBracket = 72, - RightBracket = 73, - LeftBrace = 74, - RightBrace = 75, - Underscore = 76, - Sto = 77, - Arcsine = 78, - Arccosine = 79, - Arctangent = 80, - Equal = 81, - Lower = 82, - Greater = 83, - Colon = 122, - Semicolon = 123, - DoubleQuotes = 124, - Percent = 125, - LowerA = 126, - LowerB = 127, - LowerC = 128, - LowerD = 129, - LowerE = 130, - LowerF = 131, - LowerG = 132, - LowerH = 133, - LowerI = 134, - LowerJ = 135, - LowerK = 136, - LowerL = 137, - LowerM = 138, - LowerN = 139, - LowerO = 140, - LowerP = 141, - LowerQ = 142, - LowerR = 144, - LowerS = 145, - LowerT = 146, - LowerU = 147, - LowerV = 148, - LowerW = 150, - LowerX = 151, - LowerY = 152, - LowerZ = 153, - Space = 154, - Question = 156, - Exclamation = 157, - UpperA = 180, - UpperB = 181, - UpperC = 182, - UpperD = 183, - UpperE = 184, - UpperF = 185, - UpperG = 186, - UpperH = 187, - UpperI = 188, - UpperJ = 189, - UpperK = 190, - UpperL = 191, - UpperM = 192, - UpperN = 193, - UpperO = 194, - UpperP = 195, - UpperQ = 196, - UpperR = 198, - UpperS = 199, - UpperT = 200, - UpperU = 201, - UpperV = 202, - UpperW = 204, - UpperX = 205, - UpperY = 206, - UpperZ = 207, - } - - impl Event { - pub fn is_digit(&self) -> bool { - matches!( - self, - Event::Zero - | Event::One - | Event::Two - | Event::Three - | Event::Four - | Event::Five - | Event::Six - | Event::Seven - | Event::Eight - | Event::Nine - ) - } - - pub fn to_digit(&self) -> Option { - match self { - Event::Zero => Some(0), - Event::One => Some(1), - Event::Two => Some(2), - Event::Three => Some(3), - Event::Four => Some(4), - Event::Five => Some(5), - Event::Six => Some(6), - Event::Seven => Some(7), - Event::Eight => Some(8), - Event::Nine => Some(9), - _ => None, - } - } - } - - unsafe extern "C" { - fn eadk_event_get(timeout: &i32) -> Event; - } - - pub fn event_get(timeout: i32) -> Event { - unsafe { eadk_event_get(&timeout) } - } -} - -#[cfg(target_os = "none")] -use core::panic::PanicInfo; - -#[cfg(target_os = "none")] -use alloc::string::String; - -use crate::eadk::timing::millis; - -#[cfg(target_os = "none")] -fn write_wrapped(text: &str, limit: usize) { - let mut line_count = 0; - - let mut line = String::new(); - for i in 0..text.len() { - line.push(text.as_bytes()[i] as char); - - if line.len() >= limit || text.as_bytes()[i] as char == '\n' || i >= text.len() - 1 { - display::draw_string( - line.as_str(), - Point { - x: 10, - y: (10 + 20 * line_count) as u16, - }, - false, - Color { rgb565: 65503 }, - Color { rgb565: 63488 }, - ); - line.clear(); - line_count += 1; - } - } -} - -#[cfg(target_os = "none")] -#[panic_handler] -fn panic(panic: &PanicInfo<'_>) -> ! { - use alloc::format; - - display::push_rect_uniform( - Rect { - x: 0, - y: 0, - width: 320, - height: 240, - }, - Color { rgb565: 63488 }, - ); // Show a red screen - - write_wrapped(format!("{}", panic).as_str(), 42); - - loop { - timing::msleep(50); - } // FIXME: Do something better. Exit the app maybe? -} - -pub fn debug_info(text: &str, wait: usize) { - display::draw_string( - text, - Point { x: 10, y: 30 }, - false, - Color::from_888(0, 0, 0), - Color::from_888(255, 255, 255), - ); - timing::msleep(wait as u32); -} - -unsafe extern "C" { - pub static mut _heap_base: u8; - pub static mut _heap_size: u32; -} - -pub static mut HEAP_START: *mut u8 = core::ptr::addr_of_mut!(_heap_base); - -pub fn heap_size() -> usize { - (unsafe { _heap_size }) as usize -} - -#[unsafe(no_mangle)] -pub extern "C" fn setjmp(_: u32) -> u32 { - return 0; -} - -#[unsafe(no_mangle)] -pub extern "C" fn longjmp(_: u32, _: u32) { -} - -#[unsafe(no_mangle)] -pub extern "C" fn extapp_main() { - crate::main(); -} diff --git a/apps/Numcraft/src/entity.rs b/apps/Numcraft/src/entity.rs deleted file mode 100644 index 7e8be327..00000000 --- a/apps/Numcraft/src/entity.rs +++ /dev/null @@ -1,48 +0,0 @@ -use core::any::Any; - -use nalgebra::Vector3; - -use crate::{constants::EntityType, physic::BoundingBox}; - -#[cfg(target_os = "none")] -use alloc::boxed::Box; - -pub mod item; - -pub struct Entity { - id: usize, - entity_type: EntityType, - pub gravity: bool, - pub pos: Vector3, - pub rotation: Vector3, - pub velocity: Vector3, - pub is_on_floor: bool, - pub custom_data: Option>, -} - -impl Entity { - pub fn new(id: usize, entity_type: EntityType, custom_data: Option>) -> Self { - Entity { - id, - entity_type, - gravity: true, - velocity: Vector3::zeros(), - pos: Vector3::zeros(), - rotation: Vector3::zeros(), - is_on_floor: false, - custom_data, - } - } - - pub fn get_id(&self) -> usize { - self.id - } - - pub fn get_type(&self) -> EntityType { - self.entity_type - } - - pub fn get_bbox(&self) -> Option { - Some(self.entity_type.get_bbox()?.transform(self.pos)) - } -} diff --git a/apps/Numcraft/src/entity/item.rs b/apps/Numcraft/src/entity/item.rs deleted file mode 100644 index 347ad0a1..00000000 --- a/apps/Numcraft/src/entity/item.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::{entity::Entity, inventory::ItemStack}; - -pub struct ItemEntityCustomData { - pub item_stack: ItemStack, -} - -impl ItemEntityCustomData { - pub fn get_item_data(entity: &Entity) -> Option<&Self> { - let custom_data = entity.custom_data.as_ref()?; - let item_data = custom_data - .downcast_ref::() - .expect("Item Entity custom data must be an instance of struct ItemEntityCustomData."); - - Some(item_data) - } -} diff --git a/apps/Numcraft/src/game.rs b/apps/Numcraft/src/game.rs deleted file mode 100644 index e3859fd5..00000000 --- a/apps/Numcraft/src/game.rs +++ /dev/null @@ -1,248 +0,0 @@ -#[cfg(target_os = "none")] -use alloc::{ - borrow::ToOwned, - boxed::Box, - format, - string::{String, ToString}, -}; -use nalgebra::{Vector2, Vector3}; -use serde::{Deserialize, Serialize}; - -use crate::{ - constants::{ - color_palette::MENU_BACKGROUND_COLOR, - rendering::{MAX_FOV, MAX_RENDER_DISTANCE, MIN_FOV}, - }, - eadk::{self, Color}, - game::crafting_manager::CraftingManager, - game_ui::GameUI, - hud::Hud, - input_manager::InputManager, - inventory::ItemStack, - menu::{Menu, MenuElement, TextAnchor}, - physic::PhysicEngine, - player::Player, - renderer::Renderer, - save_manager::SaveManager, - settings::Settings, - timing::TimingManager, - world::World, -}; - -mod crafting_manager; -mod game_menus; -pub mod game_uis; - -#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Copy)] -pub enum GameMode { - Survival, - Creative, -} - -pub struct Game { - renderer: Renderer, - world: World, - player: Player, - save_manager: SaveManager, - settings: Settings, - input_manager: InputManager, - hud: Hud, - timing_manager: TimingManager, - physic_engine: PhysicEngine, - crafting_manager: CraftingManager, -} - -impl Game { - pub fn new() -> Self { - let world = World::new(); - let player = Player::new(); - - Game { - renderer: Renderer::new(), - world, - player, - save_manager: SaveManager::new(), - settings: Settings::new(), - input_manager: InputManager::new(), - hud: Hud::new(), - timing_manager: TimingManager::new(), - physic_engine: PhysicEngine::new(), - crafting_manager: CraftingManager::new() - } - } - - pub fn load_world(&mut self, file_name: &String, is_new: bool) -> GameState { - // Load the world or create it if it doesn't exists yet - if is_new { - self.save_manager.set_file_name(file_name); - - self.world.load_area(0, 4, 0, 4, 0, 4); - - let player_spawn_pos = Vector3::new(16.5, 20., 16.5); - - self.player.inventory.fill(ItemStack::void()); - - self.world.get_player_entity_mut().pos = player_spawn_pos; - - self.hud.sync(&self.player); - } else if let Err(error) = self.save_manager.load_from_file(file_name.as_str()) { - Renderer::show_msg( - &[ - "The world seems to be corrupted.", - "If you've created your world", - "in an old version, it", - "is no longer compatible.", - format!("{:?}", error).as_str(), - ], - Color::from_888(255, 100, 100), - ); - self.input_manager.wait_delay_or_ok(15000); - return GameState::GoMainMenu; - } else { - // Add chunks. Maybe move this code into world (TODO) - for x in 0..4 { - for y in 0..4 { - for z in 0..4 { - let chunk = self - .save_manager - .get_chunk_at_pos(Vector3::new(x, y, z)) - .unwrap(); - - self.world.chunks_manager.push_chunk(chunk); - } - } - } - - // Load player data - let player_entity = self.world.get_player_entity_mut(); - player_entity.pos = self.save_manager.get_player_pos(); - player_entity.rotation = self.save_manager.get_player_rot(); - - self.player - .set_inventory(self.save_manager.get_player_inventory()); - - // Load world info - let world_info = self.save_manager.get_current_loaded_world_info(); - self.world.set_seed(world_info.world_seed); - } - - self.save_manager.clean(); // Clear save manager to save memory - - if self.save_manager.get_game_mode() == GameMode::Creative { - self.world.get_player_entity_mut().gravity = false; - } - - // Show a warning message - Renderer::show_msg( - &["To exit, press [EXE]", "DON'T press [Home]"], - Color::from_888(255, 255, 255), - ); - - self.input_manager.wait_delay_or_ok(3000); - GameState::InGame - } - - /// The game loop. Handle physic, rendering etc ... - pub fn game_loop(&mut self) -> GameState { - loop { - self.input_manager.update(); - self.timing_manager.update(); - - if self.input_manager.is_just_pressed(eadk::input::Key::Exe) { - self.exit_world(); - - return GameState::GoMainMenu; - } - if self.input_manager.is_just_pressed(eadk::input::Key::Var) { - if self.save_manager.get_game_mode() == GameMode::Creative { - return GameState::OpenPlayerInventory(game_uis::PlayerInventoryPage::Creative); - } else { - return GameState::OpenPlayerInventory(game_uis::PlayerInventoryPage::Survival); - } - }; - - self.player.update( - self.timing_manager.get_delta_time(), - &self.input_manager, - &mut self.world, - &mut self.renderer.camera, - &self.hud, - self.save_manager.get_game_mode(), - &self.physic_engine, - self.timing_manager.get_delta_time(), - ); - self.hud.update(&self.input_manager, &self.player); - self.hud.sync(&self.player); - - self.renderer - .camera - .update(self.timing_manager.get_delta_time(), &self.input_manager); - - self.world.chunks_manager.check_mesh_regeneration(); - self.world - .update_entities(self.timing_manager.get_delta_time()); - self.physic_engine - .process(&mut self.world, self.timing_manager.get_delta_time()); - - self.renderer.draw_game( - &mut self.world, - &self.player, - self.timing_manager.get_fps(), - &self.hud, - true, - ); - } - } - - pub fn update_settings(&mut self) { - self.renderer.update_fov(self.settings.fov); - self.renderer.enable_vsync = self.settings.vsync; - } - - fn exit_world(&mut self) { - for chunk in self.world.chunks_manager.chunks.iter() { - self.save_manager.set_chunk(chunk); - } - self.world.clear(); - - self.save_manager - .update_player_data(&self.world, &self.player); - - self.save_manager.save_world_to_file(); - - self.save_manager.clean(); - } - - pub fn main_loop(&mut self) { - let mut state = GameState::GoMainMenu; - - self.settings.load(); - self.update_settings(); - - while !matches!(state, GameState::Quit) { - state = match state { - GameState::GoMainMenu => self.main_menu_loop(), - GameState::GoSetting => self.settings_menu_loop(), - GameState::GoSelectWorld => self.worlds_select_menu_loop(), - GameState::LoadWorld(filename, is_new) => self.load_world(&filename, is_new), - GameState::InGame => self.game_loop(), - GameState::DeleteWorld(filename) => self.delete_world_menu_loop(&filename), - GameState::CreateWorld(file_name) => self.create_world_menu_loop(&file_name), - GameState::OpenPlayerInventory(page) => self.player_inventory_loop(page), - GameState::Quit => break, - } - } - } -} - -pub enum GameState { - GoMainMenu, - GoSetting, - GoSelectWorld, - InGame, - OpenPlayerInventory(game_uis::PlayerInventoryPage), - LoadWorld(String, bool), // String: filename, String: world name - CreateWorld(String), // String: file_name - DeleteWorld(String), - Quit, -} diff --git a/apps/Numcraft/src/game/crafting_manager.rs b/apps/Numcraft/src/game/crafting_manager.rs deleted file mode 100644 index 3c1c4392..00000000 --- a/apps/Numcraft/src/game/crafting_manager.rs +++ /dev/null @@ -1,219 +0,0 @@ -use crate::{ - constants::ItemType, - inventory::{Inventory, ItemStack}, -}; - -struct Craft { - pattern: [[ItemType; 3]; 3], - strict_shape: bool, - result: ItemStack, -} - -impl Craft { - pub const fn new(data: &'static [u8]) -> Self { - let mut pattern = [const { [ItemType::Air; 3] }; 3]; - - // 9 bytes : pattern - let mut index = 0; - - // We can't use a for loop because it is not available in const context - while index < 9 { - pattern[index % 3][index / 3] = - ItemType::get_from_id(data[index]).expect("Invalid item id in craft."); - index += 1; - } - - // 1 byte : strict_shape - let strict_shape = data[9] == 1; - - // 1 byte : result - let result_type = ItemType::get_from_id(data[10]).expect("Invalid item id in craft."); - - // 1 byte : result amount - let result_amount = data[11]; - - let result = ItemStack::new(result_type, result_amount, false); - - Craft { - pattern, - strict_shape, - result, - } - } - - pub fn matches(&self, grid: [[ItemType; 3]; 3]) -> bool { - if self.strict_shape { - // Get the tiniest possible rectangle in the grid - - // Get the top left corner x - let mut x1 = 0; - 'scan: while x1 < 3 { - for i in 0..3 { - if grid[x1][i] != ItemType::Air { - break 'scan; - } - } - x1 += 1; - } - if x1 == 3 { - return false; - } - - // Get the top left corner y - let mut y1 = 0; - 'scan: while y1 < 3 { - for i in 0..3 { - if grid[i][y1] != ItemType::Air { - break 'scan; - } - } - y1 += 1; - } - - if y1 == 3 { - return false; - } - - // Get the bottom right corner x - let mut x2 = 2; - 'scan: while x2 > x1 { - for i in 0..3 { - if grid[x2][i] != ItemType::Air { - break 'scan; - } - } - x2 -= 1; - } - - // Get the bottom right corner x - let mut y2 = 2; - 'scan: while y2 > y1 { - for i in 0..3 { - if grid[i][y2] != ItemType::Air { - break 'scan; - } - } - y2 -= 1; - } - - let width = x2 - x1; - let height = y2 - y1; - - // Check if it matches the shape - for x in 0..3 { - for y in 0..3 { - if x <= width && y <= height { - // Check if the pattern is right - if self.pattern[x][y] != grid[x1 + x][y1 + y] { - return false; - } - } else { - // Check if there is no items outside of the pattern - if self.pattern[x][y] != ItemType::Air { - return false; - } - } - } - } - - true - } else { - // The max size is 3*3 - let mut items_craft: heapless::Vec = heapless::Vec::new(); - let mut items_grid: heapless::Vec = heapless::Vec::new(); - - for x in 0..3 { - for y in 0..3 { - let item = self.pattern[x][y]; - // 3 * 3 = 9 so if it fails, mathematics are broken - items_craft.push(item).unwrap(); - let item = grid[x][y]; - items_grid.push(item).unwrap(); - } - } - - // Check if the items are the same - // These loop and sub loops do 162 iterations but can be optimised. TODO - for item in items_grid.iter() { - let count_grid = items_grid.iter().filter(|v| *v == item).count(); - let count_craft = items_craft.iter().filter(|v| *v == item).count(); - - if count_grid != count_craft { - return false; - } - } - - true - } - } -} - -const CRAFTS: [Craft; 3] = [ - Craft::new(include_bytes!("../../target/crafts/planks.bin")), - Craft::new(include_bytes!("../../target/crafts/stone.bin")), - Craft::new(include_bytes!("../../target/crafts/grass.bin")), -]; - -pub struct CraftingManager { - pub crafting_inventory_2x2: Inventory, - pub crafting_inventory_3x3: Inventory, - valid_craft: bool, -} - -impl CraftingManager { - pub fn new() -> Self { - let crafting_inventory_2x2 = Inventory::new(5); - let crafting_inventory_3x3 = Inventory::new(10); - CraftingManager { - crafting_inventory_2x2, - crafting_inventory_3x3, - valid_craft: false, - } - } - - pub fn update_2x2(&mut self) { - // Remove the recipies if the player picked up the item - if self.valid_craft - && self - .crafting_inventory_2x2 - .get_item_type_at_slot_index(4) - .unwrap() - == ItemType::Air - { - for i in 0..=3 { - self.crafting_inventory_2x2.take_one(i); - } - } - - let mut grid = [[ItemType::Air; 3]; 3]; - - // The inventory slots indexes must be from 0 to 3 included - for x in 0..2 { - for y in 0..2 { - grid[x][y] = self - .crafting_inventory_2x2 - .get_item_type_at_slot_index(x + y * 2) - .unwrap(); // If it fails, a cosmic particle just hit the calculators Ram! Incredible! - } - } - - // Check for all crafts to match with our grid - if self.crafting_inventory_2x2.modified { - let mut found_craft = false; - for craft in CRAFTS { - if craft.matches(grid) { - self.crafting_inventory_2x2 - .replace_slot_item_stack(4, craft.result); - self.valid_craft = true; - found_craft = true; - break; - } - } - if !found_craft { - self.crafting_inventory_2x2 - .replace_slot_item_stack(4, ItemStack::void()); - self.valid_craft = false; - } - } - } -} diff --git a/apps/Numcraft/src/game/game_menus.rs b/apps/Numcraft/src/game/game_menus.rs deleted file mode 100644 index e8c94b32..00000000 --- a/apps/Numcraft/src/game/game_menus.rs +++ /dev/null @@ -1,488 +0,0 @@ -use crate::game::*; - -impl Game { - pub fn create_world_menu_loop(&mut self, file_name: &String) -> GameState { - let mut menu = Menu::new(Vector2::new(10, 20), 300, 1) - .with_element(MenuElement::Label { - text: "Create new world".to_string(), - text_anchor: TextAnchor::Center, - allow_margin: true, - }) - .with_element(MenuElement::Entry { - placeholder_text: "World name".to_string(), - value: String::new(), - allow_margin: false, - max_len: 15, - digits_only: false, - id: 0, - }) - .with_element(MenuElement::Entry { - placeholder_text: "World seed".to_string(), - value: format!("{}", eadk::random() % 1_000_000_000), - allow_margin: true, - max_len: 9, - digits_only: true, - id: 1, - }) - .with_element(MenuElement::Button { - text: "Game mode : Survival".to_string(), - is_pressed: false, - allow_margin: true, - id: 2, - }) - .with_element(MenuElement::Button { - text: "Create world".to_string(), - is_pressed: false, - allow_margin: false, - id: 3, - }); - - // Clear the screen - eadk::display::push_rect_uniform(eadk::SCREEN_RECT, MENU_BACKGROUND_COLOR); - - self.timing_manager.reset(); - - let mut game_mode = GameMode::Survival; - - loop { - self.input_manager.update(); - self.timing_manager.update(); - self.input_manager.update_timing(&self.timing_manager); - - // Exit the menu when [Back] is pressed - if self.input_manager.is_keydown(eadk::input::Key::Back) { - return GameState::GoSelectWorld; - } - - // Handle the navigation in the menu - menu.check_inputs(&self.input_manager); - for element in menu.get_elements_mut() { - match element { - MenuElement::Button { - is_pressed: true, - id: 3, - .. - } => { - let mut world_name = String::new(); - let mut seed = "1".to_string(); - for other_element in menu.get_elements() { - if let MenuElement::Entry { value, id: 0, .. } = &other_element { - world_name = value.clone(); - } - if let MenuElement::Entry { value, id: 1, .. } = &other_element { - seed = value.clone(); - } - } - - if world_name.is_empty() { - world_name = "Unnamed".to_string(); - } - - if seed.is_empty() { - seed = format!("{}", eadk::random() % 1_000_000_000); - } - - let world_seed = seed.parse::().unwrap_or(1); - self.world.set_seed(world_seed); - - self.save_manager.set_world_seed(world_seed); - self.save_manager.set_world_name(&world_name); - self.save_manager.set_gamemode(game_mode); - - return GameState::LoadWorld(file_name.clone(), true); - } - MenuElement::Button { - is_pressed: true, - id: 2, - text, - .. - } => { - match game_mode { - GameMode::Survival => { - *text = "Game mode : Creative".to_string(); - game_mode = GameMode::Creative; - } - GameMode::Creative => { - *text = "Game mode : Survival".to_string(); - game_mode = GameMode::Survival; - } - }; - } - _ => (), - } - } - menu.finish_buttons_handling(); - - self.renderer.draw_menu(&mut menu); - eadk::timing::msleep(50); - } - } - - pub fn delete_world_menu_loop(&mut self, world_name: &String) -> GameState { - let mut menu = Menu::new(Vector2::new(10, 70), 300, 2) - .with_element(MenuElement::Label { - text: format!("Delete {}?", world_name), - text_anchor: TextAnchor::Center, - allow_margin: false, - }) - .with_element(MenuElement::Label { - text: "This cannot be undone.".to_string(), - text_anchor: TextAnchor::Center, - allow_margin: true, - }) - .with_element(MenuElement::Button { - text: format!("Yes, delete {}", world_name), - is_pressed: false, - allow_margin: true, - id: 0, - }) - .with_element(MenuElement::Button { - text: "No, go back".to_string(), - is_pressed: false, - allow_margin: false, - id: 1, - }); - - // Clear the screen - eadk::display::push_rect_uniform(eadk::SCREEN_RECT, MENU_BACKGROUND_COLOR); - - self.timing_manager.reset(); - - loop { - self.input_manager.update(); - self.timing_manager.update(); - self.input_manager.update_timing(&self.timing_manager); - - // Exit the menu when [Back] is pressed - if self.input_manager.is_keydown(eadk::input::Key::Back) { - return GameState::GoSelectWorld; - } - - // Handle the navigation in the menu - menu.check_inputs(&self.input_manager); - for element in menu.get_elements() { - match element { - MenuElement::Button { - // Confirm delete - id: 0, - is_pressed: true, - .. - } => { - self.save_manager.delete_world(world_name); - return GameState::GoSelectWorld; - } - MenuElement::Button { - // Cancel delete - id: 1, - is_pressed: true, - .. - } => { - return GameState::GoSelectWorld; - } - _ => (), - } - } - menu.finish_buttons_handling(); - - self.renderer.draw_menu(&mut menu); - eadk::timing::msleep(50); - } - } - - /// The menu the user can go to select the world to load - pub fn worlds_select_menu_loop(&mut self) -> GameState { - // Create a new menu with a title - let mut menu = Menu::new(Vector2::new(10, 20), 300, 1).with_element(MenuElement::Label { - text: "Select a world".to_string(), - text_anchor: TextAnchor::Center, - allow_margin: true, - }); - - // Get the list of all the existing worlds. World name must be "world{i}.ncw" (NCW = "NumCraft World" btw) - let worlds = self.save_manager.get_existing_worlds(); - - // Max 4 worlds because it's enough for the storage memory amount we have and because. I can't fit more than 4 buttons on the screen ;-) - for i in 0..4 { - let filename = format!("world{i}.ncw"); - - let world_name = if let Some(world_info) = self.save_manager.get_world_info(&filename) { - world_info.world_name - } else { - filename.clone() - }; - let world_exists = worlds.contains(&filename); - let button_text = if world_exists { - format!("Load {}", world_name) - } else { - format!("Create world{i}.ncw") - }; - menu.add_element(MenuElement::Button { - text: button_text, - allow_margin: true, - id: i, - is_pressed: false, - }); - if world_exists { - menu.add_element(MenuElement::ButtonOption { - text: "Delete".to_string(), - is_pressed: false, - id: i, - }); - } - } - - // Clear the screen - eadk::display::push_rect_uniform(eadk::SCREEN_RECT, MENU_BACKGROUND_COLOR); - - self.timing_manager.reset(); - - loop { - self.input_manager.update(); - self.timing_manager.update(); - self.input_manager.update_timing(&self.timing_manager); - - // Handle the navigation in the menu - menu.check_inputs(&self.input_manager); - - // Exit the menu when [Back] is pressed - if self.input_manager.is_keydown(eadk::input::Key::Back) { - return GameState::GoMainMenu; - } - - // Handle buttons - for element in menu.get_elements_mut() { - match element { - MenuElement::Button { - id, - is_pressed: true, - .. - } => { - let world_slot = *id; // Please change this if you change the button's id. Not 100% safe but who cares about safety? - let filename = format!("world{world_slot}.ncw"); - - if worlds.contains(&filename) { - // Load the world - return GameState::LoadWorld(filename.to_owned(), false); - } else { - return GameState::CreateWorld(filename.to_owned()); - } - } - MenuElement::ButtonOption { - is_pressed: true, - id, - .. - } => { - let world_slot = *id; // Please change this if you change the button's id. - let filename = format!("world{world_slot}.ncw"); - - // Delete the world - return GameState::DeleteWorld(filename.to_owned()); - } - _ => (), - } - } - - // Set all "is_pressed" to false - menu.finish_buttons_handling(); - - self.renderer.draw_menu(&mut menu); - eadk::timing::msleep(50); - } - } - - pub fn settings_menu_loop(&mut self) -> GameState { - // Temporary variables used to store settings - let mut vsync_enabled = self.settings.vsync; - let mut fov: f32 = self.settings.fov; - let mut render_distance: usize = self.settings.render_distance; - - // Create the menu. - let mut menu = Menu::new(Vector2::new(10, 20), 300, 1) - .with_element(MenuElement::Label { - text: "Settings".to_string(), - text_anchor: TextAnchor::Center, - allow_margin: true, - }) - .with_element(MenuElement::Slider { - text_fn: |value| { - format!( - "Render Distance: {}", - libm::roundf(value * MAX_RENDER_DISTANCE as f32) as usize - ) - }, - value: render_distance as f32 / MAX_RENDER_DISTANCE as f32, - step_size: 0.5, - allow_margin: false, - id: 1, - }) - .with_element(MenuElement::Slider { - text_fn: |value| { - format!( - "Field of view: {}°", - libm::roundf(MIN_FOV + (MAX_FOV - MIN_FOV) * value) - ) - }, - value: (fov - MIN_FOV) / (MAX_FOV - MIN_FOV), // The opposite of the above calculation - step_size: 0.04, - allow_margin: false, - id: 2, - }) - .with_element(MenuElement::Button { - text: if vsync_enabled { - "Vsync: Enabled".to_string() - } else { - "Vsync: Disabled".to_string() - }, - is_pressed: false, - allow_margin: true, - id: 3, - }) - .with_element(MenuElement::Button { - text: "Save".to_string(), - is_pressed: false, - allow_margin: true, - id: 4, - }) - .with_element(MenuElement::Label { - text: format!("Numcraft v{} by Yannis", env!("CARGO_PKG_VERSION")), - text_anchor: TextAnchor::Left, - allow_margin: false, - }); - - // Clear the screen - eadk::display::push_rect_uniform(eadk::SCREEN_RECT, MENU_BACKGROUND_COLOR); - - self.timing_manager.reset(); - - loop { - self.input_manager.update(); - self.timing_manager.update(); - self.input_manager.update_timing(&self.timing_manager); - - if self.input_manager.is_keydown(eadk::input::Key::Back) { - return GameState::GoMainMenu; - } - - menu.check_inputs(&self.input_manager); - - let mut need_redraw = false; - - for element in menu.get_elements_mut() { - match element { - MenuElement::Button { - // Save - id: 4, - is_pressed: true, - .. - } => { - // Save settings - self.settings.fov = fov; - self.settings.render_distance = render_distance; - self.settings.vsync = vsync_enabled; - self.update_settings(); - self.settings.save(); - - return GameState::GoMainMenu; - } - MenuElement::Button { - // Enable / Disable Vsync - text, - is_pressed: true, - id: 3, - .. - } => { - vsync_enabled = !vsync_enabled; - *text = if vsync_enabled { - "Vsync: Enabled".to_string() - } else { - "Vsync: Disabled".to_string() - }; - need_redraw = true; - } - MenuElement::Slider { value, id: 2, .. } => { - fov = libm::roundf(MIN_FOV + (MAX_FOV - MIN_FOV) * *value) - } - MenuElement::Slider { value, id: 1, .. } => { - render_distance = libm::roundf(*value * MAX_RENDER_DISTANCE as f32) as usize - } - _ => (), - } - } - - menu.finish_buttons_handling(); - - if need_redraw { - menu.need_redraw = true; - } - - self.renderer.draw_menu(&mut menu); - eadk::timing::msleep(50); - } - } - - pub fn main_menu_loop(&mut self) -> GameState { - let mut menu = Menu::new(Vector2::new(10, 40), 300, 2) - .with_element(MenuElement::Label { - text: "Numcraft".to_string(), - text_anchor: TextAnchor::Center, - allow_margin: true, - }) - .with_element(MenuElement::Void { allow_margin: true }) - .with_element(MenuElement::Button { - text: "Load world".to_string(), - is_pressed: false, - allow_margin: true, - id: 0, - }) - .with_element(MenuElement::Button { - text: "Settings".to_string(), - is_pressed: false, - allow_margin: true, - id: 1, - }) - .with_element(MenuElement::Label { - text: "Press [Home] to quit".to_string(), - text_anchor: TextAnchor::Center, - allow_margin: true, - }); - - eadk::display::push_rect_uniform(eadk::SCREEN_RECT, MENU_BACKGROUND_COLOR); - - self.timing_manager.reset(); - - loop { - self.input_manager.update(); - self.timing_manager.update(); - self.input_manager.update_timing(&self.timing_manager); - - menu.check_inputs(&self.input_manager); - - if self.input_manager.is_keydown(eadk::input::Key::Home) { - return GameState::Quit; - } - - for element in menu.get_elements_mut() { - match element { - MenuElement::Button { - id: 1, - is_pressed: true, - .. - } => { - return GameState::GoSetting; - } - MenuElement::Button { - id: 0, - is_pressed: true, - .. - } => return GameState::GoSelectWorld, - _ => (), - } - } - - menu.finish_buttons_handling(); - - self.renderer.draw_menu(&mut menu); - eadk::timing::msleep(50); - } - } -} diff --git a/apps/Numcraft/src/game/game_uis.rs b/apps/Numcraft/src/game/game_uis.rs deleted file mode 100644 index 0f554c7c..00000000 --- a/apps/Numcraft/src/game/game_uis.rs +++ /dev/null @@ -1,195 +0,0 @@ -use crate::{ - constants::ItemType, - game::*, - game_ui::{ContainerNeighbors, GameUIElements, NeighborDirection}, - inventory::Inventory, -}; - -pub enum PlayerInventoryPage { - Survival, - Creative, -} - -impl Game { - pub fn player_inventory_loop(&mut self, page: PlayerInventoryPage) -> GameState { - match page { - PlayerInventoryPage::Survival => self.player_inventory_survival_loop(), - PlayerInventoryPage::Creative => self.player_inventory_creative_loop(), - } - - GameState::InGame - } - - fn player_inventory_survival_loop(&mut self) { - // Clear the hud - self.renderer - .draw_game(&mut self.world, &self.player, 0., &self.hud, false); - - let inventories = [ - &mut self.player.inventory, - &mut self.crafting_manager.crafting_inventory_2x2, - ]; - - let mut ui = GameUI::new(true) - .with_slot_grid(Vector2::new(65, 86), 6, 3, 0, 0, 6) - .with_slot_grid(Vector2::new(65, 184), 6, 1, 0, 18, 0) - .with_slot_grid(Vector2::new(97, 16), 2, 2, 1, 24, 0) - .with_element( - GameUIElements::create_one_way_slot_slot(1, 4), - Vector2::new(193, 32), - 28, - ContainerNeighbors::default(), - ) - .with_element( - GameUIElements::Arrow { filling: 0. }, - Vector2::new(161, 32), - 29, - ContainerNeighbors::default(), - ) - .with_links(&[ - (12, 18, NeighborDirection::Bottom), - (13, 19, NeighborDirection::Bottom), - (14, 20, NeighborDirection::Bottom), - (15, 21, NeighborDirection::Bottom), - (16, 22, NeighborDirection::Bottom), - (17, 23, NeighborDirection::Bottom), - (26, 1, NeighborDirection::Bottom), - (27, 2, NeighborDirection::Bottom), - (28, 4, NeighborDirection::Bottom), - (25, 28, NeighborDirection::Right), - (27, 28, NeighborDirection::Right), - ]) - .sync(&inventories); - - ui.selected_amount = None; - - self.timing_manager.reset(); - - loop { - self.input_manager.update(); - self.timing_manager.update(); - self.input_manager.update_timing(&self.timing_manager); - self.crafting_manager.update_2x2(); - - let mut inventories = [ - &mut self.player.inventory, - &mut self.crafting_manager.crafting_inventory_2x2, - ]; - - if !ui.update(&self.input_manager, &mut inventories) { - // Bring the items back in the inventory - for slot in 0..4 { - let item_stack = inventories[1].get_all_slots()[slot].clone(); - if item_stack.get_item_type() != ItemType::Air { - let remaining = inventories[0].add_item_stack(item_stack); - if remaining != 0 { - // Hum... wait?! - // I have no choice... Spawn the item. - // I should be carreful about duplication here... - let pos = self.world.get_player_entity().pos; - self.world.spawn_item_entity( - pos, - ItemStack::new(item_stack.get_item_type(), remaining, false), - ); - } - } - } - - // Then clear the crafting inventory. - inventories[1].fill(ItemStack::void()); - break; - } - - self.renderer.draw_game_ui(&mut ui); - - eadk::display::wait_for_vblank(); - eadk::timing::msleep(50); - } - } - - fn player_inventory_creative_loop(&mut self) { - // Clear the hud - self.renderer - .draw_game(&mut self.world, &self.player, 0., &self.hud, false); - - let mut creative_inventory = Inventory::new(21); - - creative_inventory.fill(ItemStack::new(crate::constants::ItemType::Air, 0, true)); - - creative_inventory.replace_slot_item_stack( - 0, - ItemStack::new(crate::constants::ItemType::StoneBlock, 1, true), - ); - creative_inventory.replace_slot_item_stack( - 1, - ItemStack::new(crate::constants::ItemType::DirtBlock, 1, true), - ); - creative_inventory.replace_slot_item_stack( - 2, - ItemStack::new(crate::constants::ItemType::GrassBlock, 1, true), - ); - creative_inventory.replace_slot_item_stack( - 3, - ItemStack::new(crate::constants::ItemType::SandBlock, 1, true), - ); - creative_inventory.replace_slot_item_stack( - 4, - ItemStack::new(crate::constants::ItemType::CobblestoneBlock, 1, true), - ); - creative_inventory.replace_slot_item_stack( - 5, - ItemStack::new(crate::constants::ItemType::BorderBlock, 1, true), - ); - creative_inventory.replace_slot_item_stack( - 6, - ItemStack::new(crate::constants::ItemType::LogBlock, 1, true), - ); - creative_inventory.replace_slot_item_stack( - 7, - ItemStack::new(crate::constants::ItemType::LeavesBlock, 1, true), - ); - creative_inventory.replace_slot_item_stack( - 8, - ItemStack::new(crate::constants::ItemType::PlanksBlock, 1, true), - ); - - let mut inventories = [&mut self.player.inventory, &mut creative_inventory]; - - let mut ui = GameUI::new(true) - .with_slot_grid(Vector2::new(10, 41), 6, 3, 0, 0, 6) - .with_slot_grid(Vector2::new(10, 139), 6, 1, 0, 18, 0) - .with_slot_grid(Vector2::new(218, 9), 3, 7, 1, 24, 0) - .with_links(&[ - (12, 18, NeighborDirection::Bottom), - (13, 19, NeighborDirection::Bottom), - (14, 20, NeighborDirection::Bottom), - (15, 21, NeighborDirection::Bottom), - (16, 22, NeighborDirection::Bottom), - (17, 23, NeighborDirection::Bottom), - (5, 27, NeighborDirection::Right), - (11, 30, NeighborDirection::Right), - (17, 33, NeighborDirection::Right), - (23, 36, NeighborDirection::Right), - ]) - .sync(&inventories); - - ui.selected_amount = None; - - self.timing_manager.reset(); - - loop { - self.input_manager.update(); - self.timing_manager.update(); - self.input_manager.update_timing(&self.timing_manager); - - if !ui.update(&self.input_manager, &mut inventories) { - break; - } - - self.renderer.draw_game_ui(&mut ui); - - eadk::display::wait_for_vblank(); - eadk::timing::msleep(50); - } - } -} diff --git a/apps/Numcraft/src/game_ui.rs b/apps/Numcraft/src/game_ui.rs deleted file mode 100644 index 89615683..00000000 --- a/apps/Numcraft/src/game_ui.rs +++ /dev/null @@ -1,465 +0,0 @@ -use nalgebra::Vector2; - -use crate::{ - constants::ItemType, - eadk::input, - input_manager::InputManager, - inventory::{Inventory, ItemStack}, -}; - -#[cfg(target_os = "none")] -use alloc::{string::String, vec::Vec}; - -#[allow(unused)] -pub enum GameUIElements { - /// A simple button - Button { - text: String, - is_pressed: bool, - }, - Label { - text: String, - }, - ItemSlot { - item_stack: ItemStack, - inventory_id: usize, - inventory_slot_index: usize, - }, - Arrow { - filling: f32, - }, - OneWayItemSlot { - item_stack: ItemStack, - inventory_id: usize, - inventory_slot_index: usize, - }, -} - -impl GameUIElements { - pub fn create_slot(inventory_id: usize, inventory_slot_index: usize) -> Self { - Self::ItemSlot { - item_stack: ItemStack::void(), - inventory_id, - inventory_slot_index, - } - } - - pub fn create_one_way_slot_slot(inventory_id: usize, inventory_slot_index: usize) -> Self { - Self::OneWayItemSlot { - item_stack: ItemStack::void(), - inventory_id, - inventory_slot_index, - } - } -} - -pub struct AnchorContainer { - pub element: GameUIElements, - - pub pos: Vector2, - pub id: usize, - - pub neighbors: ContainerNeighbors, -} - -pub struct ContainerNeighbors { - pub up_id: Option, - pub down_id: Option, - pub left_id: Option, - pub right_id: Option, -} - -impl Default for ContainerNeighbors { - fn default() -> Self { - ContainerNeighbors { - up_id: None, - down_id: None, - left_id: None, - right_id: None, - } - } -} - -#[allow(unused)] -pub enum NeighborDirection { - Top, - Bottom, - Left, - Right, -} - -pub struct GameUI { - elements: Vec, - pub cursor_id: usize, - pub selected_id: Option, - pub selected_amount: Option, - pub need_complete_redraw: bool, - pub need_redraw: bool, - pub blur_background: bool, - - pub is_selecting_amount: bool, -} - -impl GameUI { - pub fn new(blur_background: bool) -> Self { - let ui = GameUI { - elements: Vec::new(), - cursor_id: 0, - selected_id: None, - selected_amount: None, - need_complete_redraw: true, - need_redraw: true, - blur_background, - is_selecting_amount: false, - }; - ui - } - - /// Sync the the slots with the inventories at the end of the game ui creation pipeline - pub fn sync(mut self, inventories: &[&mut Inventory]) -> Self { - self.update_slots(inventories); - self - } - - pub fn get_elements(&self) -> &Vec { - &self.elements - } - - pub fn with_element( - mut self, - element: GameUIElements, - pos: Vector2, - id: usize, - neighbors: ContainerNeighbors, - ) -> Self { - let container = AnchorContainer { - element, - pos, - id, - neighbors, - }; - - self.elements.push(container); - - self - } - - pub fn with_links(mut self, links: &[(usize, usize, NeighborDirection)]) -> Self { - for id in links { - let elem1 = self.get_element_with_id_mut(id.0).expect("Invalid ID1."); - - match id.2 { - NeighborDirection::Top => elem1.neighbors.up_id = Some(id.1), - NeighborDirection::Bottom => elem1.neighbors.down_id = Some(id.1), - NeighborDirection::Left => elem1.neighbors.left_id = Some(id.1), - NeighborDirection::Right => elem1.neighbors.right_id = Some(id.1), - } - - let elem2 = self.get_element_with_id_mut(id.1).expect("Invalid ID2."); - - match id.2 { - NeighborDirection::Top => elem2.neighbors.down_id = Some(id.0), - NeighborDirection::Bottom => elem2.neighbors.up_id = Some(id.0), - NeighborDirection::Left => elem2.neighbors.right_id = Some(id.0), - NeighborDirection::Right => elem2.neighbors.left_id = Some(id.0), - } - } - self - } - - pub fn add_element( - &mut self, - element: GameUIElements, - pos: Vector2, - id: usize, - neighbors: ContainerNeighbors, - ) { - let container = AnchorContainer { - element, - pos, - id, - neighbors, - }; - - self.elements.push(container); - } - - pub fn get_element_with_id(&self, id: usize) -> Option<&AnchorContainer> { - self.elements.iter().find(|&elem| elem.id == id) - } - - pub fn get_element_with_id_mut(&mut self, id: usize) -> Option<&mut AnchorContainer> { - self.elements.iter_mut().find(|elem| elem.id == id) - } - - fn move_cursor_if_possible(&mut self, input_manager: &InputManager, key: input::Key) { - if !input_manager.is_impulsed_key(key) { - return; - } - - let elem_or_none = self.get_element_with_id(self.cursor_id); - if let Some(elem) = elem_or_none { - let neighbor = match key { - input::Key::Right => elem.neighbors.right_id, - input::Key::Left => elem.neighbors.left_id, - input::Key::Up => elem.neighbors.up_id, - input::Key::Down => elem.neighbors.down_id, - _ => None, - }; - - if let Some(neighbor_id) = neighbor { - self.cursor_id = neighbor_id; - self.ask_redraw(); - } - } - } - - pub fn ask_redraw(&mut self) { - self.need_redraw = true; - } - - pub fn update( - &mut self, - input_manager: &InputManager, - inventories: &mut [&mut Inventory], - ) -> bool { - if self.is_selecting_amount - && let Some(amount) = &mut self.selected_amount - { - if input_manager.is_impulsed_key(input::Key::Right) { - *amount += 1; - self.ask_redraw(); - } else if input_manager.is_impulsed_key(input::Key::Left) { - *amount -= 1; - self.ask_redraw(); - } else if input_manager.is_impulsed_key(input::Key::Up) { - *amount += 4; - self.ask_redraw(); - } else if input_manager.is_impulsed_key(input::Key::Down) { - if *amount > 4 { - *amount -= 4; - } else { - *amount = 1; - } - self.ask_redraw(); - } - } else { - self.move_cursor_if_possible(input_manager, input::Key::Right); - self.move_cursor_if_possible(input_manager, input::Key::Left); - self.move_cursor_if_possible(input_manager, input::Key::Up); - self.move_cursor_if_possible(input_manager, input::Key::Down); - } - - // Check for stack overflow - if let Some(index) = self.selected_id - && let Some(element) = self.get_element_with_id(index) - && let GameUIElements::ItemSlot { item_stack, .. } = &element.element - { - if self.selected_amount.is_some_and(|v| v < 1) { - self.selected_amount = Some(1); - self.ask_redraw(); - } else if self - .selected_amount - .is_some_and(|v| v > item_stack.get_amount() as usize) - { - self.selected_amount = Some(item_stack.get_amount() as usize); - self.ask_redraw(); - } - } - - // Mainly for crafting - for inventory in inventories.iter() { - if inventory.modified { - self.update_slots(inventories); - } - } - - for inventory in &mut *inventories { - inventory.modified = false; - } - - if input_manager.is_just_pressed(input::Key::Ok) { - // If the selected element is the same as the one at the position of the cursor and that the user is not currently selecting an item amount - if self - .selected_id - .is_some_and(|index| index == self.cursor_id) - && !self.is_selecting_amount - { - // If the selected element is an ItemSlot - if let Some(element) = self.get_element_with_id(self.cursor_id) - && let GameUIElements::ItemSlot { item_stack, .. } = &element.element - { - self.selected_amount = Some(item_stack.get_amount() as usize / 2); - self.is_selecting_amount = true; - self.ask_redraw(); - } - } else { - // If the user was selecting an amount, we disable the amount selection - if self.is_selecting_amount { - self.is_selecting_amount = false; - self.ask_redraw(); - - // If an element is selected but it is not the one at the position of the cursor and that both are ItemSlots - } else if let Some(selected_id) = self.selected_id - && selected_id != self.cursor_id - && let Some(start_elem) = self.get_element_with_id(selected_id) - && let Some(end_elem) = self.get_element_with_id(self.cursor_id) - && let GameUIElements::ItemSlot { - inventory_id: start_inventory_id, - inventory_slot_index: start_inventory_slot_index, - .. - } = start_elem.element - && let GameUIElements::ItemSlot { - inventory_id: end_inventory_id, - inventory_slot_index: end_inventory_slot_index, - .. - } = end_elem.element - { - // If the 2 item slots are in the same inventories - if start_inventory_id == end_inventory_id { - inventories[start_inventory_id].move_item( - start_inventory_slot_index, - end_inventory_slot_index, - self.selected_amount, - ); - self.ask_redraw(); - } else { - // Trick to have 2 mutable references to elements in the slice - let (first, second) = if start_inventory_id < end_inventory_id { - let (first, second) = inventories.split_at_mut(end_inventory_id); - (&mut first[start_inventory_id], &mut second[0]) - } else { - let (first, second) = inventories.split_at_mut(start_inventory_id); - (&mut second[0], &mut first[end_inventory_id]) - }; - - first.move_item_in_other_inventory( - second, - start_inventory_slot_index, - end_inventory_slot_index, - self.selected_amount, - ); - self.ask_redraw(); - } - - self.selected_id = None; - self.selected_amount = None; - self.is_selecting_amount = false; - - self.update_slots(inventories); - } else if let Some(element) = self.get_element_with_id(self.cursor_id) - && let GameUIElements::ItemSlot { item_stack, .. } = &element.element - && item_stack.get_item_type() != ItemType::Air - { - self.selected_id = Some(self.cursor_id); - self.ask_redraw(); - } else if let Some(element) = self.get_element_with_id(self.cursor_id) - && let GameUIElements::OneWayItemSlot { - item_stack, - inventory_id, - inventory_slot_index, - .. - } = &element.element - && item_stack.get_item_type() != ItemType::Air - { - // Here, I concider the inventory at index 0 as the player's inventory or the main inventory. - if *inventory_id == 1 { - inventories[0].add_item_stack(item_stack.clone()); - inventories[1] - .replace_slot_item_stack(*inventory_slot_index, ItemStack::void()); - } - } - } - } - if input_manager.is_just_pressed(input::Key::Back) { - if self.selected_id.is_some() { - self.selected_id = None; - self.selected_amount = None; - self.is_selecting_amount = false; - } else { - return false; - } - } - - if input_manager.is_just_pressed(input::Key::Var) { - return false; - } - - true - } - - /// Sync the GameUI slots elements with the matching inventories slots - fn update_slots(&mut self, inventories: &[&mut Inventory]) { - for element in &mut self.elements { - if let GameUIElements::ItemSlot { - item_stack, - inventory_id, - inventory_slot_index, - .. - } - | GameUIElements::OneWayItemSlot { - item_stack, - inventory_id, - inventory_slot_index, - .. - } = &mut element.element - { - let new_item_stack = inventories[*inventory_id] - .get_ref_to_slot(*inventory_slot_index) - .unwrap() - .clone(); - *item_stack = new_item_stack; - } - } - self.ask_redraw(); - } - - pub fn with_slot_grid( - mut self, - pos: Vector2, - width: u16, - height: u16, - inventory_id: usize, - start_id: usize, - start_inventory_index: usize, - ) -> Self { - let mut last_inventory_index = start_inventory_index; - let mut last_element_id = start_id; - - for y in 0..height { - for x in 0..width { - let slot = GameUIElements::create_slot(inventory_id, last_inventory_index); - let neighbors = ContainerNeighbors { - up_id: if y != 0 { - Some(last_element_id - width as usize) - } else { - None - }, - down_id: if y != height - 1 { - Some(last_element_id + width as usize) - } else { - None - }, - left_id: if x != 0 { - Some(last_element_id - 1) - } else { - None - }, - right_id: if x != width - 1 { - Some(last_element_id + 1) - } else { - None - }, - }; - - let slot_pos = Vector2::new(32 * x, 32 * y) + pos; - self.add_element(slot, slot_pos, last_element_id, neighbors); - - last_inventory_index += 1; - last_element_id += 1; - } - } - - self - } -} diff --git a/apps/Numcraft/src/hud.rs b/apps/Numcraft/src/hud.rs deleted file mode 100644 index 7edff6ab..00000000 --- a/apps/Numcraft/src/hud.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::{input_manager::InputManager, inventory::ItemStack, player::Player}; - -pub struct Hud { - slots: [ItemStack; 6], - pub selected_slot: usize, - pub breaking_progress: Option, - pub show_debug: bool, -} - -impl Hud { - pub fn new() -> Self { - Hud { - slots: [const { ItemStack::void() }; 6], - selected_slot: 0, - breaking_progress: None, - show_debug: false, - } - } - pub fn update(&mut self, input_manager: &InputManager, player: &Player) { - if input_manager.is_just_pressed(crate::eadk::input::Key::LeftParenthesis) { - if self.selected_slot == 0 { - self.selected_slot = 5; - } else { - self.selected_slot -= 1; - } - } - if input_manager.is_just_pressed(crate::eadk::input::Key::RightParenthesis) { - if self.selected_slot == 5 { - self.selected_slot = 0; - } else { - self.selected_slot += 1; - } - } - - if input_manager.is_just_pressed(crate::eadk::input::Key::Dot) { - self.show_debug = !self.show_debug; - } - - self.breaking_progress = player.get_block_breaking_progress(); - } - - pub fn sync(&mut self, player: &Player) { - let inventory_slots = player.inventory.get_all_slots(); - for i in 0..6 { - self.slots[i] = inventory_slots[0 + i]; - } - } - - pub fn get_slots(&self) -> &[ItemStack; 6] { - &self.slots - } -} diff --git a/apps/Numcraft/src/input_manager.rs b/apps/Numcraft/src/input_manager.rs deleted file mode 100644 index ebfd8503..00000000 --- a/apps/Numcraft/src/input_manager.rs +++ /dev/null @@ -1,99 +0,0 @@ -use enum_iterator::all; - -use crate::{eadk::{ - self, - input::{Key, KeyboardState}, -}, timing::TimingManager}; - -pub struct InputManager { - keyboard_state: KeyboardState, - last_keyboard_state: KeyboardState, - just_pressed: KeyboardState, - last_pressed: Option, - last_pressed_timer: f32, - impulsed_key_buffer: Option, -} - -impl InputManager { - pub fn new() -> Self { - InputManager { - keyboard_state: KeyboardState::new(), - last_keyboard_state: KeyboardState::new(), - just_pressed: KeyboardState::new(), - - last_pressed: None, - last_pressed_timer: 0., - - impulsed_key_buffer: None - } - } - - pub fn update(&mut self) { - self.last_keyboard_state = self.keyboard_state; - self.keyboard_state = eadk::input::KeyboardState::scan(); - self.just_pressed = self - .keyboard_state - .get_just_pressed(self.last_keyboard_state); - } - - pub fn update_timing(&mut self, timing_manager: &TimingManager) { - self.impulsed_key_buffer = None; - - let last_pressed = self.get_last_pressed(); - if last_pressed.is_some() { - self.last_pressed = last_pressed; - self.last_pressed_timer = 0.5; - self.impulsed_key_buffer = self.last_pressed; - } - - if let Some(key) = self.last_pressed - && !self.is_keydown(key) - { - self.last_pressed = None; - } - - if self.last_pressed.is_some() { - self.last_pressed_timer -= timing_manager.get_delta_time(); - - if self.last_pressed_timer < 0. { - self.last_pressed_timer = 0.06; - self.impulsed_key_buffer = self.last_pressed; - } - } - } - - pub fn get_last_pressed(&self) -> Option { - for k in all::() { - if self.is_just_pressed(k) { - return Some(k); - } - } - None - } - - pub fn is_impulsed_key(&self, key: Key) -> bool { - return self.impulsed_key_buffer.is_some_and(|v| v == key) - } - - pub fn is_just_pressed(&self, key: Key) -> bool { - self.just_pressed.key_down(key) - } - - pub fn is_keydown(&self, key: Key) -> bool { - self.keyboard_state.key_down(key) - } - - pub fn wait_delay_or_ok(&mut self, delay_ms: usize) { - while self.is_keydown(eadk::input::Key::Ok) { - self.update(); - eadk::timing::usleep(100); - } - for _ in 0..delay_ms / 50 { - self.update(); - if self.is_just_pressed(eadk::input::Key::Ok) { - break; - } - eadk::timing::msleep(50); - } - } -} diff --git a/apps/Numcraft/src/inventory.rs b/apps/Numcraft/src/inventory.rs deleted file mode 100644 index 22f03c14..00000000 --- a/apps/Numcraft/src/inventory.rs +++ /dev/null @@ -1,505 +0,0 @@ -use core::{mem, usize}; - -#[cfg(target_os = "none")] -use alloc::vec::Vec; -use serde::{Deserialize, Serialize}; - -use crate::{constants::ItemType, entity::item}; - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct ItemStack { - item_type: ItemType, - amount: u8, - pub(crate) creative_slot: bool, -} - -impl ItemStack { - pub const fn void() -> Self { - ItemStack { - item_type: ItemType::Air, - amount: 0, - creative_slot: false, - } - } - - pub const fn new(item_type: ItemType, amount: u8, creative_slot: bool) -> Self { - ItemStack { - item_type, - amount, - creative_slot, - } - } - - pub fn get_item_type(&self) -> ItemType { - self.item_type - } - pub fn get_amount(&self) -> u8 { - if self.creative_slot { - self.item_type.get_max_stack_amount() - } else { - self.amount - } - } - - pub fn clear(&mut self) { - self.amount = 0; - self.item_type = ItemType::Air; - } -} - -#[derive(Serialize, Deserialize, Clone)] -pub struct Inventory { - slots: Vec, - pub modified: bool, -} - -/// A generic inventory. Can be the player inventory, a chest inventory, etc... -impl Inventory { - pub fn new(size: usize) -> Self { - let mut slots = Vec::with_capacity(size); - for _ in 0..size { - slots.push(ItemStack::void()); - } - Inventory { - slots: slots, - modified: true, - } - } - - pub fn fill(&mut self, item_stack: ItemStack) { - for i in 0..self.slots.len() { - self.slots[i] = item_stack; - } - } - - pub fn move_item_in_other_inventory( - &mut self, - other_inventory: &mut Inventory, - start_slot: usize, - end_slot: usize, - selected_amount_or_none: Option, - ) { - let start_slot_itemstack = self.get_ref_to_slot(start_slot).unwrap().clone(); - let end_slot_itemstack = other_inventory.get_ref_to_slot(end_slot).unwrap().clone(); - - let start_max_stack_amount = - start_slot_itemstack.get_item_type().get_max_stack_amount() as usize; - let end_max_stack_amount = - end_slot_itemstack.get_item_type().get_max_stack_amount() as usize; - - let selected_amount = if let Some(amount) = selected_amount_or_none { - amount - } else { - start_slot_itemstack.get_amount() as usize - }; - - if start_slot_itemstack.creative_slot && !end_slot_itemstack.creative_slot { - if end_slot_itemstack.item_type == start_slot_itemstack.item_type { - other_inventory.replace_slot_item_stack( - end_slot, - ItemStack::new( - start_slot_itemstack.item_type, - (end_slot_itemstack.amount as usize + selected_amount) - .min(start_max_stack_amount) as u8, - false, - ), - ); - } else { - other_inventory.replace_slot_item_stack( - end_slot, - ItemStack::new(start_slot_itemstack.item_type, selected_amount as u8, false), - ); - } - } else if !start_slot_itemstack.creative_slot && end_slot_itemstack.creative_slot { - if selected_amount == start_slot_itemstack.get_amount() as usize { - self.replace_slot_item_stack(start_slot, ItemStack::void()); - } else { - self.replace_slot_item_stack( - start_slot, - ItemStack::new( - start_slot_itemstack.item_type, - start_slot_itemstack.amount - selected_amount as u8, - false, - ), - ); - } - } else if !start_slot_itemstack.creative_slot && !end_slot_itemstack.creative_slot { - if start_slot_itemstack.get_item_type() == end_slot_itemstack.get_item_type() - && start_slot_itemstack.amount as usize != start_max_stack_amount - && end_slot_itemstack.amount as usize != end_max_stack_amount - { - let total_amount = end_slot_itemstack.amount as usize + selected_amount; - - if total_amount < start_max_stack_amount { - if selected_amount == start_slot_itemstack.amount as usize { - self.replace_slot_item_stack(start_slot, ItemStack::void()); - other_inventory.replace_slot_item_stack( - end_slot, - ItemStack::new( - end_slot_itemstack.item_type, - end_slot_itemstack.amount + selected_amount as u8, - false, - ), - ); - } else { - self.replace_slot_item_stack( - start_slot, - ItemStack::new( - start_slot_itemstack.item_type, - start_slot_itemstack.amount - selected_amount as u8, - false, - ), - ); - other_inventory.replace_slot_item_stack( - end_slot, - ItemStack::new( - end_slot_itemstack.item_type, - end_slot_itemstack.amount + selected_amount as u8, - false, - ), - ); - } - } else if total_amount == start_max_stack_amount { - self.replace_slot_item_stack(start_slot, ItemStack::void()); - other_inventory.replace_slot_item_stack( - end_slot, - ItemStack::new( - end_slot_itemstack.item_type, - start_max_stack_amount as u8, - false, - ), - ); - } else { - self.replace_slot_item_stack( - start_slot, - ItemStack::new( - start_slot_itemstack.item_type, - (total_amount - start_max_stack_amount) as u8, - false, - ), - ); - other_inventory.replace_slot_item_stack( - end_slot, - ItemStack::new( - end_slot_itemstack.item_type, - end_max_stack_amount as u8, - false, - ), - ); - } - } else { - if start_slot_itemstack.item_type != ItemType::Air - && end_slot_itemstack.item_type == ItemType::Air - && selected_amount != start_slot_itemstack.get_amount() as usize - { - other_inventory.replace_slot_item_stack( - end_slot, - ItemStack::new( - start_slot_itemstack.item_type, - selected_amount as u8, - false, - ), - ); - self.replace_slot_item_stack( - start_slot, - ItemStack::new( - start_slot_itemstack.item_type, - start_slot_itemstack.get_amount() - selected_amount as u8, - false, - ), - ); - } else { - other_inventory.replace_slot_item_stack(end_slot, start_slot_itemstack); - self.replace_slot_item_stack(start_slot, end_slot_itemstack); - } - } - } - } - - pub fn take_one(&mut self, index: usize) -> Option { - let slot = self.slots.get_mut(index)?; - let item_type = slot.item_type; - if !slot.creative_slot && slot.amount == 1 { - slot.clear(); - } else if !slot.creative_slot && slot.amount > 0 { - slot.amount -= 1; - } - Some(item_type) - } - - pub fn move_item( - &mut self, - start_slot: usize, - end_slot: usize, - selected_amount_or_none: Option, - ) { - if start_slot == end_slot { - return; - } - - let start_slot_itemstack = self.get_ref_to_slot(start_slot).unwrap().clone(); - let end_slot_itemstack = self.get_ref_to_slot(end_slot).unwrap().clone(); - - let start_max_stack_amount = - start_slot_itemstack.get_item_type().get_max_stack_amount() as usize; - let end_max_stack_amount = - end_slot_itemstack.get_item_type().get_max_stack_amount() as usize; - - let selected_amount = if let Some(amount) = selected_amount_or_none { - amount - } else { - start_slot_itemstack.get_amount() as usize - }; - - if start_slot_itemstack.creative_slot && !end_slot_itemstack.creative_slot { - if end_slot_itemstack.item_type == start_slot_itemstack.item_type { - self.replace_slot_item_stack( - end_slot, - ItemStack::new( - start_slot_itemstack.item_type, - (start_slot_itemstack.amount as usize + selected_amount) - .min(start_max_stack_amount) as u8, - false, - ), - ); - } else { - self.replace_slot_item_stack( - end_slot, - ItemStack::new(start_slot_itemstack.item_type, selected_amount as u8, false), - ); - } - } else if !start_slot_itemstack.creative_slot && end_slot_itemstack.creative_slot { - if selected_amount == start_slot_itemstack.get_amount() as usize { - self.replace_slot_item_stack(start_slot, ItemStack::void()); - } else { - self.replace_slot_item_stack( - start_slot, - ItemStack::new( - start_slot_itemstack.item_type, - start_slot_itemstack.amount - selected_amount as u8, - false, - ), - ); - } - } else if !start_slot_itemstack.creative_slot && !end_slot_itemstack.creative_slot { - if start_slot_itemstack.get_item_type() == end_slot_itemstack.get_item_type() - && start_slot_itemstack.amount as usize != start_max_stack_amount - && end_slot_itemstack.amount as usize != end_max_stack_amount - { - let total_amount = end_slot_itemstack.amount as usize + selected_amount; - - if total_amount < start_max_stack_amount { - if selected_amount == start_slot_itemstack.amount as usize { - self.replace_slot_item_stack(start_slot, ItemStack::void()); - self.replace_slot_item_stack( - end_slot, - ItemStack::new( - end_slot_itemstack.item_type, - end_slot_itemstack.amount + selected_amount as u8, - false, - ), - ); - } else { - self.replace_slot_item_stack( - start_slot, - ItemStack::new( - start_slot_itemstack.item_type, - start_slot_itemstack.amount - selected_amount as u8, - false, - ), - ); - self.replace_slot_item_stack( - end_slot, - ItemStack::new( - end_slot_itemstack.item_type, - end_slot_itemstack.amount + selected_amount as u8, - false, - ), - ); - } - } else if total_amount == start_max_stack_amount { - self.replace_slot_item_stack(start_slot, ItemStack::void()); - self.replace_slot_item_stack( - end_slot, - ItemStack::new( - end_slot_itemstack.item_type, - start_max_stack_amount as u8, - false, - ), - ); - } else { - self.replace_slot_item_stack( - start_slot, - ItemStack::new( - start_slot_itemstack.item_type, - (total_amount - start_max_stack_amount) as u8, - false, - ), - ); - self.replace_slot_item_stack( - end_slot, - ItemStack::new( - end_slot_itemstack.item_type, - end_max_stack_amount as u8, - false, - ), - ); - } - } else { - if start_slot_itemstack.item_type != ItemType::Air - && end_slot_itemstack.item_type == ItemType::Air - && selected_amount != start_slot_itemstack.get_amount() as usize - { - self.replace_slot_item_stack( - end_slot, - ItemStack::new( - start_slot_itemstack.item_type, - selected_amount as u8, - false, - ), - ); - self.replace_slot_item_stack( - start_slot, - ItemStack::new( - start_slot_itemstack.item_type, - start_slot_itemstack.get_amount() - selected_amount as u8, - false, - ), - ); - } else { - self.swap_slots(start_slot, end_slot); - } - } - } - } - - pub fn swap_item_stack(&mut self, slot_index: usize, other: &mut ItemStack) -> Option<()> { - if slot_index >= self.slots.len() { - None - } else { - let item_stack = &mut self.slots[slot_index]; - - if other != item_stack { - self.modified = true; - } - - mem::swap(other, item_stack); - - Some(()) - } - } - - pub fn get_ref_to_slot_mut(&mut self, slot_index: usize) -> Option<&mut ItemStack> { - if slot_index >= self.slots.len() { - None - } else { - let item_stack = &mut self.slots[slot_index]; - - Some(item_stack) - } - } - - pub fn get_ref_to_slot(&self, slot_index: usize) -> Option<&ItemStack> { - if slot_index >= self.slots.len() { - None - } else { - let item_stack = &self.slots[slot_index]; - - Some(item_stack) - } - } - - pub fn swap_slots(&mut self, first: usize, second: usize) -> Option<()> { - if first >= self.slots.len() || second >= self.slots.len() { - None - } else { - if first != second { - self.modified = true; - } - self.slots.swap(first, second); - - Some(()) - } - } - - pub fn replace_slot_item_stack( - &mut self, - slot_index: usize, - item_stack: ItemStack, - ) -> Option<()> { - if slot_index >= self.slots.len() { - None - } else { - if self.slots[slot_index] != item_stack { - self.modified = true; - } - - self.slots[slot_index] = item_stack; - - Some(()) - } - } - - pub fn get_all_slots(&self) -> &Vec { - &self.slots - } - - /// Add an item stack to the inventory. Returns the number of remaining items. - pub fn add_item_stack(&mut self, item_stack: ItemStack) -> u8 { - let max_stack = item_stack.get_item_type().get_max_stack_amount(); - let mut amount = item_stack.amount as usize; - - // Check incomplete stacks - for i in 0..self.slots.len() { - if self.slots[i].get_item_type() == item_stack.get_item_type() { - let total = self.slots[i].get_amount() as usize + amount; - - if total <= max_stack as usize { - self.replace_slot_item_stack( - i, - ItemStack::new(item_stack.get_item_type(), total as u8, false), - ); - return 0; - } else { - self.replace_slot_item_stack( - i, - ItemStack::new(item_stack.get_item_type(), max_stack, false), - ); - amount = total - max_stack as usize; - } - } - if amount == 0 { - return 0; - } - } - - // Check for empty slots - for i in 0..self.slots.len() { - if self.slots[i].get_item_type() == ItemType::Air { - if amount <= max_stack as usize { - self.replace_slot_item_stack( - i, - ItemStack::new(item_stack.get_item_type(), amount as u8, false), - ); - return 0; - } else { - self.replace_slot_item_stack( - i, - ItemStack::new(item_stack.get_item_type(), max_stack, false), - ); - amount -= max_stack as usize; - } - } - } - - return amount as u8; - } - - pub fn get_item_stack_at_slot_index(&self, index: usize) -> Option<&ItemStack> { - self.slots.get(index) - } - - pub fn get_item_type_at_slot_index(&self, index: usize) -> Option { - Some(self.get_item_stack_at_slot_index(index)?.get_item_type()) - } -} diff --git a/apps/Numcraft/src/main.rs b/apps/Numcraft/src/main.rs deleted file mode 100644 index 1c361427..00000000 --- a/apps/Numcraft/src/main.rs +++ /dev/null @@ -1,78 +0,0 @@ -#![cfg_attr(target_os = "none", no_std)] -#![no_main] -#![feature(const_index)] -#![feature(const_trait_impl)] - -#[allow(unused_imports)] -#[cfg(target_os = "none")] -use cortex_m; - -#[cfg(target_os = "none")] -use eadk::heap_size; -#[cfg(target_os = "none")] -use embedded_alloc::LlffHeap as Heap; - -#[global_allocator] -#[cfg(target_os = "none")] -static HEAP: Heap = Heap::empty(); - -#[cfg(target_os = "none")] -extern crate alloc; - -mod camera; -pub mod constants; -pub mod eadk; -mod game; -mod renderer; -mod world; -use game::Game; - -mod entity; -mod game_ui; -mod hud; -mod input_manager; -mod inventory; -mod menu; -mod physic; -mod player; -mod save_manager; -mod settings; -mod storage_lib; -mod timing; -pub mod misc; - -#[used] -#[cfg(target_os = "none")] -#[unsafe(link_section = ".rodata.eadk_app_name")] -pub static EADK_APP_NAME: [u8; 9] = *b"Numcraft\0"; - -#[used] -#[cfg(target_os = "none")] -#[unsafe(link_section = ".rodata.eadk_api_level")] -pub static EADK_APP_API_LEVEL: u32 = 0; - -#[used] -#[cfg(target_os = "none")] -#[unsafe(link_section = ".rodata.eadk_app_icon")] -pub static EADK_APP_ICON: [u8; 3437] = *include_bytes!("../target/assets/icon.nwi"); - -#[unsafe(no_mangle)] -fn main() -> isize { - // Init the heap - #[cfg(target_os = "none")] - { - let heap_size: usize = heap_size(); - unsafe { HEAP.init(eadk::HEAP_START as usize, heap_size) } - } - - while eadk::input::KeyboardState::scan().key_down(eadk::input::Key::Ok) { - // Avoid instant click on Ok - eadk::timing::msleep(50); - } - - let mut game = Game::new(); - - game.main_loop(); - - 0 -} diff --git a/apps/Numcraft/src/menu.rs b/apps/Numcraft/src/menu.rs deleted file mode 100644 index fb96cf7b..00000000 --- a/apps/Numcraft/src/menu.rs +++ /dev/null @@ -1,370 +0,0 @@ -#[cfg(target_os = "none")] -use alloc::{ - string::{String, ToString}, - vec::Vec, -}; - -use nalgebra::Vector2; - -use crate::{eadk::input::Key, input_manager::InputManager}; - -pub enum MenuElement { - /// A simple button - Button { - text: String, - is_pressed: bool, - allow_margin: bool, - id: usize, - }, - /// A slider giving values between 0 and 1 - Slider { - text_fn: fn(f32) -> String, - value: f32, - step_size: f32, - allow_margin: bool, - id: usize, - }, - /// A simple text - Label { - text: String, - text_anchor: TextAnchor, - allow_margin: bool, - }, - /// A space - Void { allow_margin: bool }, - - /// An additional button that can be added at the left of an existing button. Must be placed after a Button. - ButtonOption { - text: String, - is_pressed: bool, - id: usize, - }, - - Entry { - placeholder_text: String, - value: String, - allow_margin: bool, - max_len: u8, - digits_only: bool, - id: usize, - }, -} - -#[allow(dead_code)] -pub enum TextAnchor { - Left, - Right, - Center, -} - -pub struct Menu { - elements: Vec, - pub pos: Vector2, - pub width: usize, - pub selected_index: usize, - pub need_redraw: bool, - alpha_active: bool, - shift_active: bool, -} - -impl Menu { - pub fn check_inputs(&mut self, input_manager: &InputManager) { - if input_manager.is_just_pressed(Key::Down) { - self.cursor_down(); - } - if input_manager.is_just_pressed(Key::Up) { - self.cursor_up(); - } - if input_manager.is_just_pressed(Key::Right) { - self.cursor_right(); - } - if input_manager.is_just_pressed(Key::Left) { - self.cursor_left(); - } - - if input_manager.is_just_pressed(Key::Ok) { - self.set_pressed(true); - } - - if input_manager.is_just_pressed(Key::Alpha) { - self.alpha_active = !self.alpha_active; - } - - if input_manager.is_just_pressed(Key::Shift) { - self.shift_active = !self.shift_active; - } - - if let MenuElement::Entry { - value, - max_len, - digits_only, - .. - } = &mut self.elements[self.selected_index] - { - if input_manager.is_impulsed_key(Key::Backspace) && value.len() > 0 { - value.truncate(value.len() - 1); - self.need_redraw = true; - } - for key in [ - Key::Xnt, - Key::Var, - Key::Toolbox, - Key::Backspace, - Key::Exp, - Key::Ln, - Key::Log, - Key::Imaginary, - Key::Comma, - Key::Power, - Key::Sine, - Key::Cosine, - Key::Tangent, - Key::Pi, - Key::Sqrt, - Key::Square, - Key::Seven, - Key::Eight, - Key::Nine, - Key::LeftParenthesis, - Key::RightParenthesis, - Key::Four, - Key::Five, - Key::Six, - Key::Multiplication, - Key::Division, - Key::One, - Key::Two, - Key::Three, - Key::Plus, - Key::Minus, - Key::Zero, - Key::Dot, - ] { - if input_manager.is_impulsed_key(key) && value.len() < *max_len as usize { - if self.alpha_active && !*digits_only { - let mut letter = match key { - Key::Exp => "a", - Key::Ln => "b", - Key::Log => "c", - Key::Imaginary => "d", - Key::Comma => "e", - Key::Power => "f", - Key::Sine => "g", - Key::Cosine => "h", - Key::Tangent => "i", - Key::Pi => "j", - Key::Sqrt => "k", - Key::Square => "l", - Key::Seven => "m", - Key::Eight => "n", - Key::Nine => "o", - Key::LeftParenthesis => "p", - Key::RightParenthesis => "q", - Key::Four => "r", - Key::Five => "s", - Key::Six => "t", - Key::Multiplication => "u", - Key::Division => "v", - Key::One => "w", - Key::Two => "x", - Key::Three => "y", - Key::Plus => "z", - Key::Minus => " ", - Key::Zero => "?", - Key::Dot => "!", - _ => "", - } - .to_string(); - - if self.shift_active { - letter = letter.to_uppercase(); - } - - value.push_str(&letter); - self.need_redraw = true; - } else { - let letter = match key { - Key::One => "1", - Key::Two => "2", - Key::Three => "3", - Key::Four => "4", - Key::Five => "5", - Key::Six => "6", - Key::Seven => "7", - Key::Eight => "8", - Key::Nine => "9", - Key::Zero => "0", - _ => "", - }; - value.push_str(&letter); - self.need_redraw = true; - } - } - } - } - } - pub fn new(pos: Vector2, width: usize, start_index: usize) -> Self { - Menu { - elements: Vec::new(), - pos, - width, - selected_index: start_index, - need_redraw: true, - alpha_active: true, - shift_active: false, - } - } - - pub fn set_pressed(&mut self, state: bool) { - let element = &mut self.elements[self.selected_index]; - if let MenuElement::Button { is_pressed, .. } - | MenuElement::ButtonOption { is_pressed, .. } = element - { - *is_pressed = state - } - } - - pub fn with_element(mut self, element: MenuElement) -> Self { - self.elements.push(element); - self - } - - pub fn add_element(&mut self, element: MenuElement) { - self.elements.push(element); - } - - pub fn finish_buttons_handling(&mut self) { - let mut changed = false; - for element in self.get_elements_mut() { - if let MenuElement::Button { - // Disable all buttons - is_pressed, - .. - } = element - { - if *is_pressed { - changed = true; - } - - *is_pressed = false; - } - } - if changed { - self.need_redraw = true; - } - } - - pub fn cursor_down(&mut self) { - if let MenuElement::Button { is_pressed, .. } = &mut self.elements[self.selected_index] { - *is_pressed = false - } - - // Check if we are at the bottom, go to the top - if self.selected_index == self.elements.len() - 1 { - self.selected_index = 0; - } else { - self.selected_index += 1; - } - - // Counter to avoid infinite loop - let mut counter = 0; - - // Iterate unless the element is not a Label or we made a complete loop - while matches!( - self.elements[self.selected_index], - MenuElement::Label { .. } | MenuElement::Void { .. } | MenuElement::ButtonOption { .. } - ) && counter != self.elements.len() - { - // If we get to the bottom, we go at the top of the elements - if self.selected_index == self.elements.len() - 1 { - self.selected_index = 0; - } else { - self.selected_index += 1; - } - counter += 1; - } - - self.need_redraw = true; - } - - pub fn cursor_up(&mut self) { - if let MenuElement::Button { is_pressed, .. } = &mut self.elements[self.selected_index] { - *is_pressed = false - } - - // Check if we are at the top, go to the bottom - if self.selected_index == 0 { - self.selected_index = self.elements.len() - 1; - } else { - self.selected_index -= 1; - } - - // Counter to avoid infinite loop - let mut counter = 0; - - // Iterate unless the element is not a Label or we made a complete loop - while matches!( - self.elements[self.selected_index], - MenuElement::Label { .. } | MenuElement::Void { .. } | MenuElement::ButtonOption { .. } - ) && counter != self.elements.len() - { - // If we reach the top, go back to the bottom - if self.selected_index == 0 { - self.selected_index = self.elements.len() - 1; - } else { - self.selected_index -= 1; - } - counter += 1; - } - - self.need_redraw = true; - } - - pub fn cursor_right(&mut self) { - if let MenuElement::Slider { - // If we have a cursor - value, - step_size, - .. - } = &mut self.elements[self.selected_index] - { - *value += *step_size; - if *value > 1. { - *value = 1.; - } - self.need_redraw = true; - } else if matches!(self.elements[self.selected_index], MenuElement::Button { .. }) // If the element after the button is a button option - && self.selected_index < self.elements.len() - 1 - && matches!(self.elements[self.selected_index + 1], MenuElement::ButtonOption { .. }) - { - self.selected_index += 1; - self.need_redraw = true; - } - } - - pub fn cursor_left(&mut self) { - if let MenuElement::Slider { - value, step_size, .. - } = &mut self.elements[self.selected_index] - { - *value -= *step_size; - if *value < 0. { - *value = 0.; - } - self.need_redraw = true; - } else if matches!(self.elements[self.selected_index], MenuElement::ButtonOption { .. }) // If the element after the button is a button option - && self.selected_index > 0 - && matches!(self.elements[self.selected_index - 1], MenuElement::Button { .. }) - { - self.selected_index -= 1; - self.need_redraw = true; - } - } - - pub fn get_elements(&self) -> &Vec { - &self.elements - } - pub fn get_elements_mut(&mut self) -> &mut Vec { - &mut self.elements - } -} diff --git a/apps/Numcraft/src/misc.rs b/apps/Numcraft/src/misc.rs deleted file mode 100644 index f915725a..00000000 --- a/apps/Numcraft/src/misc.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub fn div_floor(a: isize, b: isize) -> isize { - let (d, r) = (a / b, a % b); - if (r != 0) && ((r < 0) != (b < 0)) { - d - 1 - } else { - d - } -} \ No newline at end of file diff --git a/apps/Numcraft/src/physic.rs b/apps/Numcraft/src/physic.rs deleted file mode 100644 index 331dc7dc..00000000 --- a/apps/Numcraft/src/physic.rs +++ /dev/null @@ -1,162 +0,0 @@ -use nalgebra::Vector3; - -use crate::{ - constants::physic::{BLOCK_COLLISION_SCANNING_SIZE, GRAVITY_FACTOR, ON_FLOOR_FRICTION}, - world::World, -}; - -#[derive(Clone, Debug)] -pub struct BoundingBox { - pub offset: Vector3, - pub size: Vector3, -} - -pub struct PhysicEngine {} - -impl PhysicEngine { - pub fn new() -> Self { - PhysicEngine {} - } - - pub fn process(&self, world: &mut World, delta_time: f32) { - for entity in world.get_all_entities_mut().iter_mut() { - if entity.gravity { - entity.velocity.y -= GRAVITY_FACTOR * delta_time; - } - } - - for index in 0..world.get_all_entities().len() { - let entity = &world.get_all_entities_mut()[index]; - let id = entity.get_id(); - - let movement = entity.velocity * delta_time; - if movement.y.abs() > 0. { - self.move_entity(world, id, Vector3::new(0., movement.y, 0.)); - } - if movement.x.abs() > 0. { - self.move_entity(world, id, Vector3::new(movement.x, 0., 0.)); - } - if movement.z.abs() > 0. { - self.move_entity(world, id, Vector3::new(0., 0., movement.z)); - } - } - - // Friction - for entity in world.get_all_entities_mut().iter_mut() { - if entity.velocity.norm() > 0. { - let friction_vector = entity.velocity.normalize() * ON_FLOOR_FRICTION * delta_time; - - if entity.velocity.x > 0. { - entity.velocity.x -= friction_vector.x.min(entity.velocity.x); - } else if entity.velocity.x < 0. { - entity.velocity.x -= friction_vector.x.max(entity.velocity.x); - } - - if entity.velocity.z > 0. { - entity.velocity.z -= friction_vector.z.min(entity.velocity.z); - } else if entity.velocity.z < 0. { - entity.velocity.z -= friction_vector.z.max(entity.velocity.z); - } - } - } - } - - pub fn move_entity(&self, world: &mut World, entity_id: usize, movement: Vector3) { - if let Some(state) = self.is_entity_colliding_world(entity_id, world, movement) - && let Some(entity) = world.get_entity_by_id_mut(entity_id) - { - if state { - if movement.y < 0. { - entity.is_on_floor = true; - } - - if movement.y.abs() > 0. { - entity.velocity.y = 0.; - } - if movement.x.abs() > 0. { - entity.velocity.x = 0.; - } - if movement.z.abs() > 0. { - entity.velocity.z = 0.; - } - } else { - entity.pos += movement; - - if movement.y.abs() > 0. { - entity.is_on_floor = false; - } - } - } - } - - pub fn is_entity_colliding_world( - &self, - entity_id: usize, - world: &World, - movement: Vector3, - ) -> Option { - let entity = world.get_entity_by_id(entity_id)?; - - let entity_block_pos = (entity.pos + movement).map(|v| v as isize); - - if let Some(entity_bbox) = entity.get_bbox() { - for bx in (entity_block_pos.x - BLOCK_COLLISION_SCANNING_SIZE.x) - ..=(entity_block_pos.x + BLOCK_COLLISION_SCANNING_SIZE.x) - { - for by in (entity_block_pos.y - BLOCK_COLLISION_SCANNING_SIZE.y) - ..=(entity_block_pos.y + BLOCK_COLLISION_SCANNING_SIZE.y) - { - for bz in (entity_block_pos.z - BLOCK_COLLISION_SCANNING_SIZE.z) - ..=(entity_block_pos.z + BLOCK_COLLISION_SCANNING_SIZE.z) - { - let block_or_none = world.chunks_manager.get_block_in_world(Vector3::new(bx, by, bz)); - if block_or_none.is_none() || block_or_none.is_some_and(|b| !b.is_air()) { - let block_bbox = BoundingBox { - offset: Vector3::new(bx as f32, by as f32, bz as f32), - size: Vector3::repeat(1.0), - }; - - if block_bbox.is_coliding(&entity_bbox.transform(movement)) { - return Some(true); - } - } - } - } - } - } - Some(false) - } - - pub fn can_place_block(&self, world: &World, pos: Vector3) -> bool { - let block_bbox = BoundingBox { - offset: pos.map(|v| v as f32), - size: Vector3::repeat(1.0), - }; - for entity in world.get_all_entities() { - if let Some(bbox) = &entity.get_bbox() - && block_bbox.is_coliding(bbox) - { - return false; - } - } - true - } -} - -impl BoundingBox { - pub fn is_coliding(&self, other: &BoundingBox) -> bool { - self.offset.x < other.offset.x + other.size.x - && self.offset.x + self.size.x > other.offset.x - && self.offset.y < other.offset.y + other.size.y - && self.offset.y + self.size.y > other.offset.y - && self.offset.z < other.offset.z + other.size.z - && self.offset.z + self.size.z > other.offset.z - } - - pub fn transform(&self, vector: Vector3) -> BoundingBox { - BoundingBox { - offset: self.offset + vector, - size: self.size, - } - } -} diff --git a/apps/Numcraft/src/player.rs b/apps/Numcraft/src/player.rs deleted file mode 100644 index c3d4dc57..00000000 --- a/apps/Numcraft/src/player.rs +++ /dev/null @@ -1,357 +0,0 @@ -use core::f32::consts::PI; - -use libm::sincosf; -#[allow(unused_imports)] -use nalgebra::{ComplexField, Vector3}; - -use crate::{ - camera::Camera, - constants::{ - BlockType, EntityType, - player::{FLY_SPEED, JUMP_FORCE, MAX_WALKING_VELOCITY, WALK_FORCE}, - }, - eadk, - entity::{Entity, item::ItemEntityCustomData}, - game::GameMode, - hud::Hud, - input_manager::InputManager, - inventory::{Inventory, ItemStack}, - physic::PhysicEngine, - renderer::mesh::{Mesh, Quad, QuadDir}, - world::World, -}; - -#[cfg(target_os = "none")] -use alloc::boxed::Box; - -pub struct Player { - ray_cast_result: Option, - pub inventory: Inventory, - breaking_state_timer: f32, - breaking_block_pos: Option>, -} - -impl Player { - pub fn new() -> Self { - Player { - ray_cast_result: None, - inventory: Inventory::new(24), - breaking_state_timer: 0., - breaking_block_pos: None, - } - } - - pub fn get_block_marker(&self) -> (Mesh, Vector3) { - let mut mesh = Mesh::new(); - - if let Some(result) = &self.ray_cast_result { - mesh.quads - .push(Quad::new(Vector3::new(0, 0, 0), result.face_dir, 255, 0)); - (mesh, result.block_pos) - } else { - (mesh, Vector3::repeat(0)) - } - } - - pub fn get_block_breaking_progress(&self) -> Option { - if self.breaking_block_pos.is_none() { - return None; - } - let hardness = self.ray_cast_result.as_ref()?.block_type.get_hardness(); - if hardness <= 0. { - return None; - } - - Some((hardness - self.breaking_state_timer) / hardness) - } - - pub fn sync_with_camera(&self, camera: &mut Camera, player_entity: &mut Entity) { - camera.update_pos(player_entity.pos + Vector3::new(0., 1.2, 0.)); - player_entity.rotation = *camera.get_rotation(); - } - - pub fn set_inventory(&mut self, inventory: Inventory) { - self.inventory = inventory - } - - pub fn update( - &mut self, - delta: f32, - input_manager: &InputManager, - world: &mut World, - camera: &mut Camera, - hud: &Hud, - game_mode: GameMode, - physic_engine: &PhysicEngine, - delta_time: f32, - ) { - self.ray_cast_result = self.ray_cast(camera, world, 10); - - let player_entity = world.get_player_entity_mut(); - - self.sync_with_camera(camera, player_entity); - player_entity.rotation = *camera.get_rotation(); - - // Movements - if input_manager.is_keydown(eadk::input::Key::Toolbox) { - // Forward - let translation = sincosf(player_entity.rotation.y); - if game_mode == GameMode::Creative { - player_entity.pos.x += translation.0 * delta * FLY_SPEED; - player_entity.pos.z += translation.1 * delta * FLY_SPEED; - } else { - player_entity.velocity.x += translation.0 * delta * WALK_FORCE; - player_entity.velocity.z += translation.1 * delta * WALK_FORCE; - } - } - if input_manager.is_keydown(eadk::input::Key::Comma) { - // Backward - let translation = sincosf(player_entity.rotation.y); - if game_mode == GameMode::Creative { - player_entity.pos.x -= translation.0 * delta * FLY_SPEED; - player_entity.pos.z -= translation.1 * delta * FLY_SPEED; - } else { - player_entity.velocity.x -= translation.0 * delta * WALK_FORCE; - player_entity.velocity.z -= translation.1 * delta * WALK_FORCE; - } - } - if input_manager.is_keydown(eadk::input::Key::Imaginary) { - // Left - let translation = sincosf(player_entity.rotation.y + PI / 2.0); - if game_mode == GameMode::Creative { - player_entity.pos.x += translation.0 * delta * FLY_SPEED; - player_entity.pos.z += translation.1 * delta * FLY_SPEED; - } else { - player_entity.velocity.x += translation.0 * delta * WALK_FORCE; - player_entity.velocity.z += translation.1 * delta * WALK_FORCE; - } - } - if input_manager.is_keydown(eadk::input::Key::Power) { - // Right - let translation = sincosf(player_entity.rotation.y + PI / 2.0); - if game_mode == GameMode::Creative { - player_entity.pos.x -= translation.0 * delta * FLY_SPEED; - player_entity.pos.z -= translation.1 * delta * FLY_SPEED; - } else { - player_entity.velocity.x -= translation.0 * delta * WALK_FORCE; - player_entity.velocity.z -= translation.1 * delta * WALK_FORCE; - } - } - if input_manager.is_keydown(eadk::input::Key::Shift) { - // Up - if game_mode == GameMode::Creative { - player_entity.pos.y += delta * FLY_SPEED; - } else if player_entity.is_on_floor { - player_entity.velocity.y += JUMP_FORCE; - } - } - if input_manager.is_keydown(eadk::input::Key::Exp) { - // Down - if game_mode == GameMode::Creative { - player_entity.pos.y -= delta * FLY_SPEED; - } - } - - // Limit speed - if player_entity.velocity.xz().norm() > MAX_WALKING_VELOCITY { - let max_velocity = player_entity.velocity.xz().normalize() * MAX_WALKING_VELOCITY; - player_entity.velocity.x = max_velocity.x; - player_entity.velocity.z = max_velocity.y; - } - - // Break Block - if game_mode == GameMode::Creative { - if input_manager.is_just_pressed(eadk::input::Key::Back) { - if let Some(result) = &self.ray_cast_result { - world - .chunks_manager - .set_block_in_world(result.block_pos, BlockType::Air); - } - } - } else { - if input_manager.is_keydown(eadk::input::Key::Back) { - if let Some(ray_cast) = &self.ray_cast_result { - if self - .breaking_block_pos - .is_some_and(|pos| pos == ray_cast.block_pos) - { - self.breaking_state_timer -= delta_time; - if self.breaking_state_timer <= 0. { - world.replace_block_and_drop_item(ray_cast.block_pos, BlockType::Air); - self.breaking_block_pos = None; - self.breaking_state_timer = 0.; - } - } else { - let hardness = ray_cast.block_type.get_hardness(); - if hardness >= 0. { - self.breaking_block_pos = Some(ray_cast.block_pos); - self.breaking_state_timer = ray_cast.block_type.get_hardness(); - } - } - } else { - self.breaking_block_pos = None; - self.breaking_state_timer = 0.; - } - } else { - self.breaking_block_pos = None; - self.breaking_state_timer = 0.; - } - } - - if input_manager.is_just_pressed(eadk::input::Key::Ok) { - // Place Block - if let Some(result) = &self.ray_cast_result { - let block_pos = result.block_pos + result.face_dir.get_normal_vector(); - if world - .chunks_manager - .get_block_in_world(block_pos) - .is_some_and(|b| b.is_air()) - && physic_engine.can_place_block(world, block_pos) - && let Some(item_type) = self.inventory.take_one(0 + hud.selected_slot) - && let Some(block_type) = item_type.get_matching_block_type() - { - world - .chunks_manager - .set_block_in_world(block_pos, block_type); - } - } - } - - let player_entity = world.get_player_entity(); - - if let Some(player_bbox) = player_entity.get_bbox() { - world.get_all_entities_mut().retain_mut(|entity| { - if let EntityType::Item { .. } = entity.get_type() - && entity - .get_bbox() - .is_some_and(|entity_bbox| entity_bbox.is_coliding(&player_bbox)) - { - // Recover the item_stack data from the item entity - let item_data = ItemEntityCustomData::get_item_data(&entity) - .expect("Item Entity must have ItemData as custom data."); - - let item_stack = item_data.item_stack; - - let remain = self.inventory.add_item_stack(item_stack.clone()); - - if remain != 0 { - entity.custom_data = Some(Box::new(ItemEntityCustomData { - item_stack: ItemStack::new(item_stack.get_item_type(), remain, false), - })); - return true; - } - false - } else { - true - } - }); - } - } - - fn ray_cast(&self, camera: &Camera, world: &World, max_lenght: usize) -> Option { - let start_pos = *camera.get_pos(); - let forward_vector = camera.get_forward_vector(); - - let end_pos = start_pos + forward_vector.normalize() * (max_lenght as f32); - - let mut current_voxel_pos = start_pos; - let mut step_dir = -1; - - let dx = (end_pos.x - start_pos.x).signum(); - let delta_x = if dx != 0. { - (dx / (end_pos.x - start_pos.x)).min(10000000.0) - } else { - 10000000.0 - }; - let mut max_x = if dx > 0. { - delta_x * (1.0 - start_pos.x.fract()) - } else { - delta_x * start_pos.x.fract() - }; - - let dy = (end_pos.y - start_pos.y).signum(); - let delta_y = if dy != 0. { - (dy / (end_pos.y - start_pos.y)).min(10000000.0) - } else { - 10000000.0 - }; - let mut max_y = if dy > 0. { - delta_y * (1.0 - start_pos.y.fract()) - } else { - delta_y * start_pos.y.fract() - }; - - let dz = (end_pos.z - start_pos.z).signum(); - let delta_z = if dz != 0. { - (dz / (end_pos.z - start_pos.z)).min(10000000.0) - } else { - 10000000.0 - }; - let mut max_z = if dz > 0. { - delta_z * (1.0 - start_pos.z.fract()) - } else { - delta_z * start_pos.z.fract() - }; - - while !(max_x > 1.0 && max_y > 1.0 && max_z > 1.0) { - let current_voxel_pos_isize = current_voxel_pos.map(|x| x as isize); - let result = world - .chunks_manager - .get_block_in_world(current_voxel_pos_isize); - if let Some(block_type) = result - && !block_type.is_air() - { - let voxel_normal = if step_dir == 0 { - if dx < 0. { - QuadDir::Left - } else { - QuadDir::Right - } - } else if step_dir == 1 { - if dy < 0. { - QuadDir::Top - } else { - QuadDir::Bottom - } - } else if dz < 0. { - QuadDir::Back - } else { - QuadDir::Front - }; - - return Some(RaycastResult { - block_pos: current_voxel_pos_isize, - face_dir: voxel_normal, - block_type: block_type, - }); - } - - if max_x < max_y { - if max_x < max_z { - current_voxel_pos.x += dx; - max_x += delta_x; - step_dir = 0; - } else { - current_voxel_pos.z += dz; - max_z += delta_z; - step_dir = 2; - } - } else if max_y < max_z { - current_voxel_pos.y += dy; - max_y += delta_y; - step_dir = 1; - } else { - current_voxel_pos.z += dz; - max_z += delta_z; - step_dir = 2 - } - } - None - } -} - -struct RaycastResult { - pub block_pos: Vector3, - pub face_dir: QuadDir, - pub block_type: BlockType, -} diff --git a/apps/Numcraft/src/renderer.rs b/apps/Numcraft/src/renderer.rs deleted file mode 100644 index ee5dfcd9..00000000 --- a/apps/Numcraft/src/renderer.rs +++ /dev/null @@ -1,81 +0,0 @@ -#[cfg(target_os = "none")] -use alloc::format; - -#[cfg(target_os = "none")] -use alloc::vec::Vec; - -use nalgebra::{Matrix4, Perspective3, Vector2, Vector3, Vector4}; - -use core::{cmp::Ordering, f32, mem::swap}; - -use crate::{ - camera::Camera, - constants::{rendering::*, world::CHUNK_SIZE}, - eadk::Color, - renderer::mesh::SmallTriangle2D, -}; - -mod engine_3d; -mod hud; -mod menus; -mod ui; -mod frustum; -pub mod mesh; -mod misc; -mod entity; - -// Screen size related constants - -const SCREEN_WIDTHF: f32 = SCREEN_WIDTH as f32; -const SCREEN_HEIGHTF: f32 = SCREEN_HEIGHT as f32; -const HALF_SCREEN_WIDTHF: f32 = SCREEN_WIDTHF / 2.0; -const HALF_SCREEN_HEIGHTF: f32 = SCREEN_HEIGHTF / 2.0; -const HALF_SCREEN: Vector2 = Vector2::new(HALF_SCREEN_WIDTHF, HALF_SCREEN_HEIGHTF); - -// Screen tiling constants -const SCREEN_TILE_WIDTH: usize = SCREEN_WIDTH.div_ceil(SCREEN_TILE_SUBDIVISION); -const SCREEN_TILE_HEIGHT: usize = SCREEN_HEIGHT.div_ceil(SCREEN_TILE_SUBDIVISION); - -// Projection parameters -const ASPECT_RATIO: f32 = SCREEN_WIDTHF / SCREEN_HEIGHTF; - -const ZNEAR: f32 = 1.0; -const ZFAR: f32 = 1000.0; - -// Other -const CHUNK_SIZE_I: isize = CHUNK_SIZE as isize; - -static FONT_DATA: &[u8] = include_bytes!("../target/assets/font.bin"); -const FONT_WIDTH: usize = 1045; -const FONT_HEIGHT: usize = 15; - -static CROSS_DATA: &[u8] = include_bytes!("../target/assets/cross.bin"); -const CROSS_WIDTH: usize = 14; -const CROSS_HEIGHT: usize = 14; - -const FONT_CHAR_WIDTH: usize = 11; -static FONT_ORDER: &str = "!\" $%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^+`abcdefghijklmnopqrstuvwxyz{|}~€"; - -static TILESET_DATA: &[u8] = include_bytes!("../target/assets/tileset.bin"); - -pub struct Renderer { - pub camera: Camera, - triangles_to_render: Vec, - tile_frame_buffer: [Color; SCREEN_TILE_WIDTH * SCREEN_TILE_HEIGHT], - projection_matrix: Perspective3, - pub enable_vsync: bool, -} - -impl Renderer { - pub fn new() -> Self { - let renderer: Renderer = Renderer { - camera: Camera::new(), - projection_matrix: Perspective3::new(ASPECT_RATIO, FOV, ZNEAR, ZFAR), - triangles_to_render: Vec::with_capacity(MAX_TRIANGLES), - tile_frame_buffer: [Color { rgb565: 0 }; SCREEN_TILE_WIDTH * SCREEN_TILE_HEIGHT], - enable_vsync: true, - }; - - renderer - } -} diff --git a/apps/Numcraft/src/renderer/engine_3d.rs b/apps/Numcraft/src/renderer/engine_3d.rs deleted file mode 100644 index 8b740722..00000000 --- a/apps/Numcraft/src/renderer/engine_3d.rs +++ /dev/null @@ -1,596 +0,0 @@ -use crate::{ - constants::get_quad_color_from_texture_id, - eadk::{ - Rect, - display::{push_rect, wait_for_vblank}, - }, - hud::Hud, - player::Player, - renderer::{ - frustum::Frustum, - mesh::{Quad, Triangle, Triangle2D}, - *, - }, - world::World, -}; - -/// Fill a triangle in the frame buffer -pub fn fill_triangle( - mut t0: Vector2, - mut t1: Vector2, - mut t2: Vector2, - frame_buffer: &mut [Color; SCREEN_TILE_WIDTH * SCREEN_TILE_HEIGHT], - color: Color, -) { - if t0.y > t1.y { - swap(&mut t0, &mut t1); - } - if t0.y > t2.y { - swap(&mut t0, &mut t2); - } - if t1.y > t2.y { - swap(&mut t1, &mut t2); - } - - let triangle_height = t2.y - t0.y; - let triangle_heightf = triangle_height as f32; - - 'height_iter: for i in 0..triangle_height { - let second_half = i > (t1.y - t0.y) || (t1.y == t0.y); - let segment_heightf = if second_half { - (t2.y - t1.y) as f32 - } else { - (t1.y - t0.y) as f32 - }; - - let alpha = i as f32 / triangle_heightf; - let beta = if second_half { - (i as f32 - (t1.y - t0.y) as f32) / segment_heightf - } else { - i as f32 / segment_heightf - }; - - let mut a = t0.x as f32 + ((t2 - t0).x as f32 * alpha); - let mut b = if second_half { - t1.x as f32 + ((t2 - t1).x as f32 * beta) - } else { - t0.x as f32 + ((t1 - t0).x as f32 * beta) - }; - - if a > b { - swap(&mut a, &mut b); - } - - let y = t0.y + i; - if y < 0 { - continue 'height_iter; - } - if y >= SCREEN_TILE_HEIGHT as isize { - break 'height_iter; - } - - if (b as usize) < 1 { - // prevent line bug - continue; - } - - for j in (a as usize)..=(b as usize) { - if j >= SCREEN_TILE_WIDTH { - continue 'height_iter; - } - frame_buffer[j + y as usize * SCREEN_TILE_WIDTH] = color; - } - } -} - -// Draw a line in the frame buffer -pub fn draw_line( - pos1: (isize, isize), - pos2: (isize, isize), - frame_buffer: &mut [Color; SCREEN_TILE_WIDTH * SCREEN_TILE_HEIGHT], - color: Color, -) { - for point in bresenham::Bresenham::new(pos1, pos2) { - if point.0 >= 0 - && point.0 < SCREEN_TILE_WIDTH as isize - && point.1 >= 0 - && point.1 < SCREEN_TILE_HEIGHT as isize - { - frame_buffer[(point.0 + point.1 * SCREEN_TILE_WIDTH as isize) as usize] = color; - } - } -} - -// Takes a Triangle2D and draw it as a filled triangle or lines depending of the texture_id -pub fn draw_2d_triangle( - tri: &Triangle2D, - frame_buffer: &mut [Color; SCREEN_TILE_WIDTH * SCREEN_TILE_HEIGHT], -) { - if tri.texture_id == 255 { - // Block marker - draw_line( - (tri.p1.x as isize, tri.p1.y as isize), - (tri.p2.x as isize, tri.p2.y as isize), - frame_buffer, - Color::from_components(0b11111, 0b0, 0b0), - ); - draw_line( - (tri.p2.x as isize, tri.p2.y as isize), - (tri.p3.x as isize, tri.p3.y as isize), - frame_buffer, - Color::from_components(0b11111, 0b0, 0b0), - ); - } else { - // Normal Triangle - fill_triangle( - Vector2::new(tri.p1.x as isize, tri.p1.y as isize), - Vector2::new(tri.p2.x as isize, tri.p2.y as isize), - Vector2::new(tri.p3.x as isize, tri.p3.y as isize), - frame_buffer, - get_quad_color_from_texture_id(tri.texture_id).apply_light(tri.light * 17), - ); - } -} - -pub fn matrix_point_at( - pos: &Vector3, - target: &Vector3, - up: &Vector3, -) -> Matrix4 { - let new_forward = (target - pos).normalize(); - - let new_up = (up - new_forward * up.dot(&new_forward)).normalize(); - let new_right = new_up.cross(&new_forward); - - Matrix4::new( - new_right.x, - new_up.x, - new_forward.x, - pos.x, - new_right.y, - new_up.y, - new_forward.y, - pos.y, - new_right.z, - new_up.z, - new_forward.z, - pos.z, - 0.0, - 0.0, - 0.0, - 1.0, - ) -} - -pub fn vector_intersect_plane( - plane_p: &Vector3, - plane_n: &Vector3, - line_start: &Vector3, - line_end: &Vector3, -) -> Vector3 { - let plane_n = plane_n.normalize(); - let plane_d = -plane_n.dot(plane_p); - let ad = line_start.dot(&plane_n); - let bd = line_end.dot(&plane_n); - let t = (-plane_d - ad) / (bd - ad); - let line_start_to_end = line_end - line_start; - let line_to_intersect = line_start_to_end * t; - line_start + line_to_intersect -} - -pub fn vector_intersect_line( - line_p: &Vector2, - line_n: &Vector2, - line_start: &Vector2, - line_end: &Vector2, -) -> Vector2 { - let line_n = line_n.normalize(); - let line_d = -line_n.dot(line_p); - let ad = line_start.dot(&line_n); - let bd = line_end.dot(&line_n); - let t = (-line_d - ad) / (bd - ad); - let line_start_to_end = line_end - line_start; - let line_to_intersect = line_start_to_end * t; - let coords = line_start + line_to_intersect; - coords.map(|x| x as i16) -} - -pub fn triangle_clip_against_line( - line_p: &Vector2, - line_n: &Vector2, - in_tri: &Triangle2D, -) -> (Option, Option) { - let line_n = line_n.normalize(); - - let dist = |p: Vector2| line_n.x * p.x + line_n.y * p.y - line_n.dot(line_p); - - let binding = Default::default(); - let mut inside_points: [&Vector2; 3] = [&binding; 3]; - let mut n_inside_point_count = 0; - let mut outside_points: [&Vector2; 3] = [&binding; 3]; - let mut n_outside_point_count = 0; - - let p1 = in_tri.p1.map(|x| x as f32); - let p2 = in_tri.p2.map(|x| x as f32); - let p3 = in_tri.p3.map(|x| x as f32); - - let d0 = dist(p1); - let d1 = dist(p2); - let d2 = dist(p3); - - if d0 >= 0.0 { - inside_points[n_inside_point_count] = &p1; - n_inside_point_count += 1; - } else { - outside_points[n_outside_point_count] = &p1; - n_outside_point_count += 1; - } - if d1 >= 0.0 { - inside_points[n_inside_point_count] = &p2; - n_inside_point_count += 1; - } else { - outside_points[n_outside_point_count] = &p2; - n_outside_point_count += 1; - } - if d2 >= 0.0 { - inside_points[n_inside_point_count] = &p3; - n_inside_point_count += 1; - } else { - outside_points[n_outside_point_count] = &p3; - n_outside_point_count += 1; - } - - if n_inside_point_count == 0 { - return (None, None); - } - - if n_inside_point_count == 3 { - return (Some(*in_tri), None); - } - - if n_inside_point_count == 1 && n_outside_point_count == 2 { - let out_tri = Triangle2D { - p1: inside_points[0].map(|x| x as i16), - p2: vector_intersect_line(line_p, &line_n, inside_points[0], outside_points[0]), - p3: vector_intersect_line(line_p, &line_n, inside_points[0], outside_points[1]), - texture_id: in_tri.texture_id, - light: in_tri.light, - }; - - return (Some(out_tri), None); - } - - if n_inside_point_count == 2 && n_outside_point_count == 1 { - let out_tri1 = Triangle2D { - p1: inside_points[0].map(|x| x as i16), - p2: inside_points[1].map(|x| x as i16), - p3: vector_intersect_line(line_p, &line_n, inside_points[0], outside_points[0]), - texture_id: in_tri.texture_id, - light: in_tri.light, - }; - - let out_tri2 = Triangle2D { - p1: inside_points[1].map(|x| x as i16), - p2: out_tri1.p3, - p3: vector_intersect_line(line_p, &line_n, inside_points[1], outside_points[0]), - texture_id: in_tri.texture_id, - light: in_tri.light, - }; - return (Some(out_tri1), Some(out_tri2)); - } - (None, None) -} - -pub fn triangle_clip_against_plane( - plane_p: &Vector3, - plane_n: &Vector3, - in_tri: &Triangle, -) -> (Option, Option) { - let plane_n = plane_n.normalize(); - - let dist = |p: Vector3| { - plane_n.x * p.x + plane_n.y * p.y + plane_n.z * p.z - plane_n.dot(plane_p) - }; - - let binding = Default::default(); - let mut inside_points: [&Vector3; 3] = [&binding; 3]; - let mut n_inside_point_count = 0; - let mut outside_points: [&Vector3; 3] = [&binding; 3]; - let mut n_outside_point_count = 0; - - let d0 = dist(in_tri.p1); - let d1 = dist(in_tri.p2); - let d2 = dist(in_tri.p3); - - if d0 >= 0.0 { - inside_points[n_inside_point_count] = &in_tri.p1; - n_inside_point_count += 1; - } else { - outside_points[n_outside_point_count] = &in_tri.p1; - n_outside_point_count += 1; - } - if d1 >= 0.0 { - inside_points[n_inside_point_count] = &in_tri.p2; - n_inside_point_count += 1; - } else { - outside_points[n_outside_point_count] = &in_tri.p2; - n_outside_point_count += 1; - } - if d2 >= 0.0 { - inside_points[n_inside_point_count] = &in_tri.p3; - n_inside_point_count += 1; - } else { - outside_points[n_outside_point_count] = &in_tri.p3; - n_outside_point_count += 1; - } - - if n_inside_point_count == 0 { - return (None, None); - } - - if n_inside_point_count == 3 { - return (Some(*in_tri), None); - } - - if n_inside_point_count == 1 && n_outside_point_count == 2 { - let out_tri = Triangle { - p1: *inside_points[0], - p2: vector_intersect_plane(plane_p, &plane_n, inside_points[0], outside_points[0]), - p3: vector_intersect_plane(plane_p, &plane_n, inside_points[0], outside_points[1]), - texture_id: in_tri.texture_id, - light: in_tri.light, - }; - - return (Some(out_tri), None); - } - - if n_inside_point_count == 2 && n_outside_point_count == 1 { - let out_tri1 = Triangle { - p1: *inside_points[0], - p2: *inside_points[1], - p3: vector_intersect_plane(plane_p, &plane_n, inside_points[0], outside_points[0]), - texture_id: in_tri.texture_id, - light: in_tri.light, - }; - - let out_tri2 = Triangle { - p1: *inside_points[1], - p2: out_tri1.p3, - p3: vector_intersect_plane(plane_p, &plane_n, inside_points[1], outside_points[0]), - texture_id: in_tri.texture_id, - light: in_tri.light, - }; - return (Some(out_tri1), Some(out_tri2)); - } - (None, None) -} - -impl Renderer { - pub fn update_fov(&mut self, new_fov: f32) { - self.camera.set_fov(new_fov); - self.projection_matrix = - Perspective3::new(ASPECT_RATIO, self.camera.get_fov(), ZNEAR, ZFAR); - } - - pub fn project_point(&self, point: Vector3) -> Vector2 { - self.projection_matrix.project_vector(&point).xy() - } - - pub fn clear_screen(&mut self, color: Color) { - self.tile_frame_buffer.fill(color); - } - - fn get_mat_view(&self) -> Matrix4 { - let up: Vector3 = Vector3::new(0.0, 1.0, 0.0); - let target: Vector3 = Vector3::new(0.0, 0.0, 1.0); - let look_dir = self.camera.get_rotation_matrix() * target.to_homogeneous(); - let target = self.camera.get_pos() + look_dir.xyz(); - - let mat_camera = matrix_point_at(self.camera.get_pos(), &target, &up); - - mat_camera.try_inverse().unwrap() - } - - fn add_3d_triangle_to_render(&mut self, tri: Triangle, mat_view: &Matrix4) { - let mut tri = tri; - - let camera_ray = tri.p1 - self.camera.get_pos(); - - if tri.get_normal().dot(&camera_ray) < 0.0 { - tri.p1 = (mat_view * Vector4::new(tri.p1.x, tri.p1.y, tri.p1.z, 1.0)).xyz(); // try to_homogenous here - tri.p2 = (mat_view * Vector4::new(tri.p2.x, tri.p2.y, tri.p2.z, 1.0)).xyz(); - tri.p3 = (mat_view * Vector4::new(tri.p3.x, tri.p3.y, tri.p3.z, 1.0)).xyz(); - - let clipped_triangles: (Option, Option) = if tri.texture_id != 255 { - triangle_clip_against_plane( - &Vector3::new(0.0, 0.0, 0.1), - &Vector3::new(0.0, 0.0, 1.0), - &tri, - ) - } else { - (Some(tri), None) - }; - - let mut project_and_add = |to_project: Triangle| { - let projected_triangle = Triangle2D { - p1: ((self.project_point(to_project.p1) + Vector2::new(1., 1.)) - .component_mul(&HALF_SCREEN)) - .map(|x| x as i16), - p2: ((self.project_point(to_project.p2) + Vector2::new(1., 1.)) - .component_mul(&HALF_SCREEN)) - .map(|x| x as i16), - p3: ((self.project_point(to_project.p3) + Vector2::new(1., 1.)) - .component_mul(&HALF_SCREEN)) - .map(|x| x as i16), - texture_id: to_project.texture_id, - light: to_project.light, - }; - - let mut clip_buffer: heapless::Deque = heapless::Deque::new(); // 2^4 - - clip_buffer.push_back(projected_triangle).unwrap(); - let mut new_tris = 1; - - let mut clip_triangle = |line_p, line_n| { - while new_tris > 0 { - let test = clip_buffer.pop_front().unwrap(); - new_tris -= 1; - - let clipped = triangle_clip_against_line(&line_p, &line_n, &test); - - if let Some(clipped_tri) = clipped.0 { - clip_buffer.push_back(clipped_tri).unwrap(); - } - if let Some(clipped_tri) = clipped.1 { - clip_buffer.push_back(clipped_tri).unwrap(); - } - } - new_tris = clip_buffer.len(); - }; - - if tri.texture_id != 255 { - clip_triangle(Vector2::new(0.0, 0.0), Vector2::new(0.0, 1.0)); - clip_triangle(Vector2::new(0.0, SCREEN_HEIGHTF), Vector2::new(0.0, -1.0)); - clip_triangle(Vector2::new(0.0, 0.0), Vector2::new(1.0, 0.0)); - clip_triangle( - Vector2::new(SCREEN_WIDTHF - 1.0, 0.0), - Vector2::new(-1.0, 0.0), - ); - } - - for tri in clip_buffer { - self.triangles_to_render.push(tri.to_small()); // Do nothing if overflow - } - }; - - if let Some(clipped) = clipped_triangles.0 { - project_and_add(clipped) - } - if let Some(clipped) = clipped_triangles.1 { - project_and_add(clipped) - } - } - } - - fn draw_triangles(&mut self, tile_x: usize, tile_y: usize) { - let tile_offset = Vector2::new( - -((SCREEN_TILE_WIDTH * tile_x) as i16), - -((SCREEN_TILE_HEIGHT * tile_y) as i16), - ); - for tri in self.triangles_to_render.iter_mut() { - let mut tri_copy = tri.to_tri_2d(); - tri_copy.p1 += tile_offset; - - tri_copy.p2 += tile_offset; - - tri_copy.p3 += tile_offset; - - draw_2d_triangle(&tri_copy, &mut self.tile_frame_buffer); - } - } - - fn add_quad_to_render( - &mut self, - quad: &Quad, - mat_view: &Matrix4, - chunk_block_pos: Vector3, - ) { - let quad_triangles = quad.get_triangles(chunk_block_pos); - self.add_3d_triangle_to_render(quad_triangles.0, mat_view); - self.add_3d_triangle_to_render(quad_triangles.1, mat_view); - } - - pub fn draw_game( - &mut self, - world: &mut World, - player: &Player, - fps_count: f32, - hud: &Hud, - draw_hud: bool, - ) { - self.triangles_to_render.clear(); - - let mat_view = self.get_mat_view(); - - let frustum = Frustum::new( - &self.camera, - ASPECT_RATIO, - self.camera.get_fov(), - ZNEAR, - ZFAR, - ); - - for chunk in world - .chunks_manager - .get_chunks_sorted_by_distance(*self.camera.get_pos()) - { - let chunk_blocks_pos = chunk.get_pos() * CHUNK_SIZE_I; - let chunk_blocks_posf = chunk_blocks_pos.map(|x| x as f32); - let chunk_blocks_pos_maxf = - (chunk_blocks_pos + Vector3::repeat(CHUNK_SIZE_I)).map(|x| x as f32); - - if !(frustum.is_aabb_in_frustum(chunk_blocks_posf, chunk_blocks_pos_maxf)) { - continue; - } - - let need_sorting = chunk.need_sorting || self.camera.get_has_moved(); - - let quads = chunk.get_mesh().get_reference_vec(); - - if need_sorting { - quads.sort_by(|a, b| -> Ordering { - let a_pos = a.get_pos().map(|x| x as isize) + chunk_blocks_pos; - let b_pos = b.get_pos().map(|x| x as isize) + chunk_blocks_pos; - let avec = Vector3::new( - a_pos.x as f32 + 0.5, - a_pos.y as f32 + 0.5, - a_pos.z as f32 + 0.5, - ); - - let bvec = Vector3::new( - b_pos.x as f32 + 0.5, - b_pos.y as f32 + 0.5, - b_pos.z as f32 + 0.5, - ); - - bvec.metric_distance(self.camera.get_pos()) - .total_cmp(&avec.metric_distance(self.camera.get_pos())) - }); - } - for quad in quads { - self.add_quad_to_render(quad, &mat_view, chunk_blocks_pos); - } - } - - // Finally add the player block marker - let mut block_marker = player.get_block_marker(); - for quad in block_marker.0.get_reference_vec() { - self.add_quad_to_render(quad, &mat_view, block_marker.1); - } - - for x in 0..SCREEN_TILE_SUBDIVISION { - for y in 0..SCREEN_TILE_SUBDIVISION { - self.clear_screen(Color::from_components(0b01110, 0b110110, 0b11111)); - self.draw_triangles(x, y); - self.draw_flat_model_entities(world, &mat_view, x, y, &frustum); - - if draw_hud { - self.draw_hud(hud, fps_count, x, y); - } - - push_rect( - Rect { - x: (SCREEN_TILE_WIDTH * x) as u16, - y: (SCREEN_TILE_HEIGHT * y) as u16, - width: SCREEN_TILE_WIDTH as u16, - height: SCREEN_TILE_HEIGHT as u16, - }, - &self.tile_frame_buffer, - ); - } - } - if self.enable_vsync { - wait_for_vblank(); - } - } -} diff --git a/apps/Numcraft/src/renderer/entity.rs b/apps/Numcraft/src/renderer/entity.rs deleted file mode 100644 index 174ff5d9..00000000 --- a/apps/Numcraft/src/renderer/entity.rs +++ /dev/null @@ -1,107 +0,0 @@ -use libm::tanf; - -use crate::{ - constants::EntityType, - entity::item::ItemEntityCustomData, - renderer::{frustum::Frustum, *}, - world::World, -}; - -impl Renderer { - pub fn draw_flat_model_entities( - &mut self, - world: &World, - mat_view: &Matrix4, - tile_x: usize, - tile_y: usize, - frustum: &Frustum, - ) { - for entity in world.get_all_entities() { - if !entity - .get_bbox() - .is_some_and(|bbox| frustum.is_bbox_in_frustum(&bbox)) - || entity.pos.metric_distance(&self.camera.get_pos()) > MAX_ENTITY_RENDER_DISTANCE - { - continue; - } - - if let EntityType::Item { .. } = entity.get_type() { - // Extract the custom data of the entity - let item_data = ItemEntityCustomData::get_item_data(&entity).expect("Item Entity must have ItemData as custom data."); - - let texture_id = item_data.item_stack.get_item_type().get_texture_id(); - - // Transform and project the point - let pos = entity.pos; - let transformed = (mat_view * Vector4::new(pos.x, pos.y, pos.z, 1.0)).xyz(); - let projected = (self.project_point(transformed) + Vector2::new(1., 1.)) - .component_mul(&HALF_SCREEN); - - let tile_offset = Vector2::new( - -((SCREEN_TILE_WIDTH * tile_x) as isize), - -((SCREEN_TILE_HEIGHT * tile_y) as isize), - ); - - let default_size = ITEM_ENTITY_SPRITE_SIZE; - let sprite_size: isize = ((default_size - / self.camera.get_pos().metric_distance(&pos)) - * (SCREEN_HEIGHTF / tanf(2.0 * (FOV / 2.0)))) - as isize; - - let point = projected.map(|v| v as isize) + tile_offset; - - if true - || (point.x > -sprite_size / 2 - && point.y > -sprite_size / 2 - && point.x < SCREEN_TILE_WIDTH as isize + sprite_size / 2 - && point.y < SCREEN_TILE_HEIGHT as isize + sprite_size / 2) - { - self.draw_set_size_tile_on_frame_buffer( - texture_id, - point.map(|v| v - sprite_size / 2), - Vector2::repeat(sprite_size), - ); - } - } - } - } - - fn draw_set_size_tile_on_frame_buffer( - &mut self, - texture_id: u8, - pos: Vector2, - size: Vector2, - ) { - let tileset_x = (texture_id % 16) as usize * 8; - let tileset_y = (texture_id / 16) as usize * 8; - - if pos.x + size.x <= 0 || pos.y + size.y <= 0 { - return; - } - for x in 0..size.x { - let dest_x = x + pos.x; - if dest_x < 0 || dest_x >= SCREEN_TILE_WIDTH as isize { - continue; - } - for y in 0..size.y { - let u = x * 8 / size.x; - let v = y * 8 / size.y; - - let dest_y = y + pos.y; - if dest_y < 0 || dest_y >= SCREEN_TILE_HEIGHT as isize { - continue; - } - - let texture_pixel_index = - ((tileset_x + u as usize) + (tileset_y + v as usize) * 128) * 2; - let pixel = u16::from_be_bytes([ - TILESET_DATA[texture_pixel_index], - TILESET_DATA[texture_pixel_index + 1], - ]); - - self.tile_frame_buffer[dest_x as usize + dest_y as usize * SCREEN_TILE_WIDTH] = - Color { rgb565: pixel }; - } - } - } -} diff --git a/apps/Numcraft/src/renderer/frustum.rs b/apps/Numcraft/src/renderer/frustum.rs deleted file mode 100644 index 46150ae8..00000000 --- a/apps/Numcraft/src/renderer/frustum.rs +++ /dev/null @@ -1,95 +0,0 @@ -use libm::tanf; -use nalgebra::Vector3; - -use crate::{camera::Camera, physic::BoundingBox}; - -struct Plane { - normal: Vector3, - pos: Vector3, -} - -pub struct Frustum { - top_plane: Plane, - bottom_plane: Plane, - - right_plane: Plane, - left_plane: Plane, - - far_plane: Plane, - near_plane: Plane, -} - -impl Frustum { - pub fn new(camera: &Camera, aspect: f32, fov_y: f32, z_near: f32, z_far: f32) -> Self { - let half_vside = z_far * tanf(fov_y * 0.5); - let half_hside = half_vside * aspect; - let front = camera.get_forward_vector(); - let up = camera.get_up_vector(); - let right = camera.get_right_vector(); - let front_mult_far = z_far * front; - - let cam_pos = *camera.get_pos(); - - Frustum { - near_plane: Plane { - pos: cam_pos + z_near * front, - normal: front, - }, - far_plane: Plane { - pos: cam_pos + front_mult_far, - normal: -front, - }, - right_plane: Plane { - pos: cam_pos, - normal: up.cross(&(front_mult_far - right * half_hside)), - }, - left_plane: Plane { - pos: cam_pos, - normal: (front_mult_far + right * half_hside).cross(&up), - }, - top_plane: Plane { - pos: cam_pos, - normal: (front_mult_far - up * half_vside).cross(&right), - }, - bottom_plane: Plane { - pos: cam_pos, - normal: right.cross(&(front_mult_far + up * half_vside)), - }, - } - } - - pub fn is_aabb_in_frustum(&self, min: Vector3, max: Vector3) -> bool { - let corners = [ - Vector3::new(min.x, min.y, min.z), - Vector3::new(max.x, min.y, min.z), - Vector3::new(min.x, max.y, min.z), - Vector3::new(max.x, max.y, min.z), - Vector3::new(min.x, min.y, max.z), - Vector3::new(max.x, min.y, max.z), - Vector3::new(min.x, max.y, max.z), - Vector3::new(max.x, max.y, max.z), - ]; - for plane in [ - &self.far_plane, - &self.near_plane, - &self.right_plane, - &self.left_plane, - &self.top_plane, - &self.bottom_plane, - ] { - if corners - .iter() - .all(|c| (c - plane.pos).dot(&plane.normal) < 0.0) - { - return false; - } - } - true - } - - pub fn is_bbox_in_frustum(&self, bbox: &BoundingBox) -> bool { - let min = bbox.offset; - let max = bbox.offset + bbox.size; - self.is_aabb_in_frustum(min, max) - } -} diff --git a/apps/Numcraft/src/renderer/hud.rs b/apps/Numcraft/src/renderer/hud.rs deleted file mode 100644 index 680ab70e..00000000 --- a/apps/Numcraft/src/renderer/hud.rs +++ /dev/null @@ -1,238 +0,0 @@ -use crate::{ - constants::{ItemType, color_palette::GAMEUI_SLOT_COLOR}, - eadk::Rect, - hud::Hud, - renderer::*, -}; - -impl Renderer { - pub fn draw_hud(&mut self, hud: &Hud, fps_count: f32, tile_x: usize, tile_y: usize) { - if tile_x == 0 && tile_y == 0 { - if hud.show_debug { - self.draw_string( - format!("FPS:{fps_count:.2}").as_str(), - &Vector2::new(10, 10), - ); - - self.draw_string( - format!("Tris:{}", self.triangles_to_render.len()).as_str(), - &Vector2::new(10, 30), - ); - - self.draw_string( - format!( - "{:.1},{:.1},{:.1}", - self.camera.get_pos().x, - self.camera.get_pos().y, - self.camera.get_pos().z - ) - .as_str(), - &Vector2::new(10, 50), - ); - } - } - - let mut draw_cross = |x, y| { - self.draw_image_negate( - CROSS_DATA, - Vector2::new(CROSS_WIDTH as isize, CROSS_HEIGHT as isize), - Vector2::new(x, y), - ); - }; - - if tile_x == 0 && tile_y == 0 { - draw_cross( - (SCREEN_TILE_WIDTH - CROSS_WIDTH / 2) as isize, - (SCREEN_TILE_HEIGHT - CROSS_HEIGHT / 2) as isize, - ) - } - if tile_x == 1 && tile_y == 0 { - draw_cross( - -((CROSS_WIDTH / 2) as isize), - (SCREEN_TILE_HEIGHT - CROSS_HEIGHT / 2) as isize, - ) - } - if tile_x == 1 && tile_y == 1 { - draw_cross( - -((CROSS_WIDTH / 2) as isize), - -((CROSS_HEIGHT / 2) as isize), - ); - } - if tile_x == 0 && tile_y == 1 { - draw_cross( - (SCREEN_TILE_WIDTH - CROSS_WIDTH / 2) as isize, - -((CROSS_HEIGHT / 2) as isize), - ); - - self.draw_slot_frame_buffer(Vector2::new(60, 85), hud, 0); - self.draw_slot_frame_buffer(Vector2::new(94, 85), hud, 1); - self.draw_slot_frame_buffer(Vector2::new(128, 85), hud, 2); - } - if tile_x == 1 && tile_y == 1 { - self.draw_slot_frame_buffer(Vector2::new(2, 85), hud, 3); - self.draw_slot_frame_buffer(Vector2::new(36, 85), hud, 4); - self.draw_slot_frame_buffer(Vector2::new(70, 85), hud, 5); - } - - self.draw_breaking_indicator(tile_x, tile_y, hud); - } - - pub fn draw_breaking_indicator(&mut self, tile_x: usize, tile_y: usize, hud: &Hud) { - if let Some(progress) = hud.breaking_progress { - let bar_len = (40. * progress) as u16; - if tile_x == 0 && tile_y == 1 { - self.push_rect_uniform_on_frame_buffer( - Rect { - x: 138, - y: 18, - width: 22, - height: 9, - }, - Color::from_888(100, 100, 100), - ); - self.push_rect_uniform_on_frame_buffer( - Rect { - x: 140, - y: 20, - width: bar_len.min(20), - height: 5, - }, - Color::from_888(200, 200, 200), - ); - } - if tile_x == 1 && tile_y == 1 { - self.push_rect_uniform_on_frame_buffer( - Rect { - x: 0, - y: 18, - width: 22, - height: 9, - }, - Color::from_888(100, 100, 100), - ); - if bar_len > 20 { - self.push_rect_uniform_on_frame_buffer( - Rect { - x: 0, - y: 20, - width: (bar_len - 20), - height: 5, - }, - Color::from_888(200, 200, 200), - ); - } - } - } - } - - pub fn draw_image_negate( - &mut self, - image: &[u8], - image_size: Vector2, - pos: Vector2, - ) { - for y in 0..image_size.y { - if pos.y + y < 0 || pos.y + y >= SCREEN_TILE_HEIGHT as isize { - continue; - } - for x in 0..image_size.x { - let dest = Vector2::new(x, y) + pos; - - if dest.x < 0 || dest.x >= SCREEN_TILE_WIDTH as isize { - continue; - } - - let pixel = image[(x + image_size.x * y) as usize]; - - if pixel == 0 { - let frame_buff_index = (dest.x + dest.y * SCREEN_TILE_WIDTH as isize) as usize; - let components = self.tile_frame_buffer[frame_buff_index].get_components(); - - let inverted_color = Color::from_components( - 0b11111 - components.0, - 0b111111 - components.1, - 0b11111 - components.2, - ); - self.tile_frame_buffer[frame_buff_index] = inverted_color; - } - } - } - } - - fn draw_scalled_tile_on_frame_buffer( - &mut self, - texture_id: u8, - pos: Vector2, - scale: usize, - ) { - let tileset_x = (texture_id % 16) as usize * 8; - let tileset_y = (texture_id / 16) as usize * 8; - - for x in 0..8 { - for y in 0..8 { - let texture_pixel_index = ((tileset_x + x) + (tileset_y + y) * 128) * 2; - let pixel = u16::from_be_bytes([ - TILESET_DATA[texture_pixel_index], - TILESET_DATA[texture_pixel_index + 1], - ]); - - self.push_rect_uniform_on_frame_buffer( - Rect { - x: pos.x + (x * scale) as u16, - y: pos.y + (y * scale) as u16, - width: scale as u16, - height: scale as u16, - }, - Color { rgb565: pixel }, - ); - } - } - } - - fn draw_slot_frame_buffer(&mut self, pos: Vector2, hud: &Hud, slot_index: usize) { - self.push_rect_uniform_on_frame_buffer( - Rect { - x: pos.x, - y: pos.y, - width: 30, - height: 30, - }, - if hud.selected_slot == slot_index { - Color::from_888(200, 50, 50) - } else { - GAMEUI_SLOT_COLOR - }, - ); - let item_stack = hud.get_slots()[slot_index]; - let texture_id = item_stack.get_item_type().get_texture_id(); - - if texture_id != 0 { - self.draw_scalled_tile_on_frame_buffer(texture_id, pos + Vector2::new(3, 3), 3); - } - - let item_type = item_stack.get_item_type(); - let max_item_count = item_type.get_max_stack_amount(); - - if item_type != ItemType::Air && item_type.get_max_stack_amount() > 1 { - let item_bar_lenght = 24 * item_stack.get_amount() as u16 / max_item_count as u16; - self.push_rect_uniform_on_frame_buffer( - Rect { - x: pos.x + 3, - y: pos.y + 24, - width: item_bar_lenght, - height: 3, - }, - Color::from_888(100, 150, 255), - ); - self.push_rect_uniform_on_frame_buffer( - Rect { - x: pos.x + 3 + item_bar_lenght, - y: pos.y + 24, - width: 24 - item_bar_lenght, - height: 3, - }, - Color::from_888(200, 200, 200), - ); - } - } -} diff --git a/apps/Numcraft/src/renderer/menus.rs b/apps/Numcraft/src/renderer/menus.rs deleted file mode 100644 index 8140c462..00000000 --- a/apps/Numcraft/src/renderer/menus.rs +++ /dev/null @@ -1,271 +0,0 @@ -use crate::{ - constants::color_palette::*, - eadk::{ - Point, Rect, - display::{draw_string, push_rect_uniform, wait_for_vblank}, - }, - menu::{Menu, MenuElement, TextAnchor}, - renderer::*, -}; - -impl Renderer { - pub fn draw_menu(&self, menu: &mut Menu) { - if !menu.need_redraw { - return; - } - - menu.need_redraw = false; - - let mut element_y = menu.pos.y; - - let elements = menu.get_elements(); - for i in 0..elements.len() { - let element = &elements[i]; - - let default_rect = if matches!(&elements[i], MenuElement::Button { .. }) { - if i < elements.len() - 1 - && let MenuElement::ButtonOption { text, .. } = &elements[i + 1] - { - let option_button_width = 20 + text.len() * 10; - Rect { - x: menu.pos.x as u16, - y: element_y as u16, - width: (menu.width - option_button_width - 10) as u16, - height: 30, - } - } else { - Rect { - x: menu.pos.x as u16, - y: element_y as u16, - width: menu.width as u16, - height: 30, - } - } - } else if let MenuElement::ButtonOption { text, .. } = &elements[i] { - let option_button_width = 20 + text.len() * 10; - Rect { - x: (menu.pos.x + menu.width - option_button_width) as u16, - y: element_y as u16, - width: option_button_width as u16, - height: 30, - } - } else { - Rect { - x: menu.pos.x as u16, - y: element_y as u16, - width: menu.width as u16, - height: 30, - } - }; - - let draw_outline = || { - push_rect_uniform( - Rect { - x: default_rect.x - 1, - y: default_rect.y - 1, - width: default_rect.width + 2, - height: 1, - }, - MENU_OUTLINE_COLOR, - ); - push_rect_uniform( - Rect { - x: default_rect.x - 1, - y: default_rect.y + default_rect.height, - width: default_rect.width + 2, - height: 1, - }, - MENU_OUTLINE_COLOR, - ); - push_rect_uniform( - Rect { - x: default_rect.x - 1, - y: default_rect.y, - width: 1, - height: default_rect.height, - }, - MENU_OUTLINE_COLOR, - ); - push_rect_uniform( - Rect { - x: default_rect.x + default_rect.width, - y: default_rect.y, - width: 1, - height: default_rect.height, - }, - MENU_OUTLINE_COLOR, - ); - }; - - let element_bg_color = if i == menu.selected_index { - MENU_ELEMENT_BACKGROUND_COLOR_HOVER - } else { - MENU_ELEMENT_BACKGROUND_COLOR - }; - - match element { - MenuElement::Button { text, .. } => { - push_rect_uniform(default_rect, element_bg_color); - draw_outline(); - let text_x = menu.pos.x + (default_rect.width as usize - 10 * text.len()) / 2; - draw_string( - text, - Point { - x: text_x as u16, - y: (element_y + 6) as u16, - }, - true, - MENU_TEXT_COLOR, - element_bg_color, - ); - } - MenuElement::Slider { text_fn, value, .. } => { - push_rect_uniform(default_rect, element_bg_color); - let text = text_fn(*value); - let cursor_width = 20; - let x_pos = - default_rect.x + (value * (menu.width - cursor_width - 4) as f32) as u16; - let text_x = menu.pos.x + (default_rect.width as usize - 10 * text.len()) / 2; - draw_string( - text.as_str(), - Point { - x: text_x as u16, - y: (element_y + 6) as u16, - }, - true, - MENU_TEXT_COLOR, - element_bg_color, - ); - push_rect_uniform( - Rect { - x: x_pos + 2, - y: default_rect.y + 2, - width: 20, - height: default_rect.height - 4, - }, - Color::from_888(255, 255, 255), - ); - draw_outline(); - } - MenuElement::Label { - text, text_anchor, .. - } => { - let text_y = match text_anchor { - TextAnchor::Left => menu.pos.x + 10, - TextAnchor::Center => menu.pos.x + (menu.width - 10 * text.len()) / 2, - TextAnchor::Right => menu.pos.x + menu.width - 10 * text.len() - 10, - }; - draw_string( - text, - Point { - x: text_y as u16, - y: (element_y + 6) as u16, - }, - true, - MENU_TEXT_COLOR, - MENU_BACKGROUND_COLOR, - ); - } - MenuElement::ButtonOption { text, .. } => { - push_rect_uniform(default_rect, element_bg_color); - draw_outline(); - - draw_string( - text.as_str(), - Point { - x: default_rect.x + 10, - y: (element_y + 6) as u16, - }, - true, - MENU_TEXT_COLOR, - element_bg_color, - ); - } - MenuElement::Void { .. } => {} - MenuElement::Entry { - placeholder_text, - value, - .. - } => { - push_rect_uniform(default_rect, element_bg_color); - draw_outline(); - let text_x = menu.pos.x + 10; - if value.is_empty() { - draw_string( - &placeholder_text, - Point { - x: text_x as u16, - y: (element_y + 6) as u16, - }, - true, - MENU_TEXT_COLOR, - element_bg_color, - ); - } else { - draw_string( - &value, - Point { - x: text_x as u16, - y: (element_y + 6) as u16, - }, - true, - MENU_TEXT_COLOR, - element_bg_color, - ); - } - push_rect_uniform( - Rect { - x: (text_x + value.len() * 10) as u16, - y: (element_y + 6) as u16, - width: 2, - height: 18, - }, - MENU_TEXT_COLOR, - ); - } - } - - element_y += if i < elements.len() - 1 - && matches!(&elements[i + 1], MenuElement::ButtonOption { .. }) - // keep the same y if we have a button option next to a button - { - 0 - } else if matches!( - // If the element needs margin, add and additional margin - &element, - MenuElement::Label { - allow_margin: true, - .. - } | MenuElement::Button { - allow_margin: true, - .. - } | MenuElement::Slider { - allow_margin: true, - .. - } | MenuElement::Void { - allow_margin: true, - .. - } | MenuElement::Entry { - allow_margin: true, - .. - } - ) { - 40 - } else if i > 0 // If the element is a button option and that the previous element is a button requesting for margin, add margin - && matches!( - &elements[i - 1], - MenuElement::Button { - allow_margin: true, - .. - } - ) - { - 40 - } else { - 30 - }; - } - - wait_for_vblank(); - } -} diff --git a/apps/Numcraft/src/renderer/mesh.rs b/apps/Numcraft/src/renderer/mesh.rs deleted file mode 100644 index c6555fad..00000000 --- a/apps/Numcraft/src/renderer/mesh.rs +++ /dev/null @@ -1,421 +0,0 @@ -#[cfg(target_os = "none")] -use alloc::vec::Vec; - -use nalgebra::{Vector2, Vector3}; - -use crate::{ - constants::{world::CHUNK_SIZE, BlockType}, - world::{chunk::Chunk, chunk_manager::ChunksManager}, -}; - -const CHUNK_SIZE_I: isize = CHUNK_SIZE as isize; - -#[repr(u8)] -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub enum QuadDir { - Front = 1, - Back = 2, - Top = 3, - Bottom = 4, - Right = 5, - Left = 6, -} - -impl QuadDir { - pub const fn from_id(id: u8) -> Self { - match id { - 1 => QuadDir::Front, - 2 => QuadDir::Back, - 3 => QuadDir::Top, - 4 => QuadDir::Bottom, - 5 => QuadDir::Right, - 6 => QuadDir::Left, - _ => panic!("Unknown quad direction."), - } - } - - pub const fn get_normal_vector(&self) -> Vector3 { - match *self { - QuadDir::Front => Vector3::new(0, 0, -1), - QuadDir::Back => Vector3::new(0, 0, 1), - QuadDir::Bottom => Vector3::new(0, -1, 0), - QuadDir::Top => Vector3::new(0, 1, 0), - QuadDir::Left => Vector3::new(1, 0, 0), - QuadDir::Right => Vector3::new(-1, 0, 0), - } - } -} - -pub struct Quad { - data: u16, - texture_id: u8, -} - -impl Quad { - pub fn new(pos: Vector3, dir: QuadDir, texture_id: u8, light: u16) -> Self { - // xxx yyy zzz ddd llll - // tttttttt - let x = pos.x; - let y = pos.y; - let z = pos.z; - let dir = dir as u16; - let data = x << 13 | y << 10 | z << 7 | dir << 4 | light; - Quad { data, texture_id } - } - - pub fn get_pos(&self) -> nalgebra::Vector3 { - let x = self.data >> 13; // Equivalent to (self.data & 0b1110000000000000) >> 13 - let y = (self.data & 0b0001110000000000) >> 10; - let z = (self.data & 0b0000001110000000) >> 7; - nalgebra::Vector3::new(x, y, z) - } - pub fn get_light_level(&self) -> u16 { - self.data & 0b0000000000001111 - } - - pub fn get_dir(&self) -> QuadDir { - let dir = (self.data & 0b0000000001110000) >> 4; - QuadDir::from_id(dir as u8) - } -} - -impl Quad { - pub fn get_triangles(&self, chunk_block_pos: Vector3) -> (Triangle, Triangle) { - let pos = self.get_pos().map(|x| x as isize) + chunk_block_pos; - - let pos_x = (pos.x) as f32; - let pos_x_plus_one = pos_x + 1.0; - let pos_y = (pos.y) as f32; - let pos_y_plus_one = pos_y + 1.0; - let pos_z = (pos.z) as f32; - let pos_z_plus_one = pos_z + 1.0; - - let light = self.get_light_level() as u8; - match self.get_dir() { - QuadDir::Front => ( - Triangle { - p1: Vector3::new(pos_x_plus_one, pos_y_plus_one, pos_z), - p2: Vector3::new(pos_x_plus_one, pos_y, pos_z), - p3: Vector3::new(pos_x, pos_y, pos_z), - texture_id: self.texture_id, - light, - }, - Triangle { - p1: Vector3::new(pos_x, pos_y, pos_z), - p2: Vector3::new(pos_x, pos_y_plus_one, pos_z), - p3: Vector3::new(pos_x_plus_one, pos_y_plus_one, pos_z), - texture_id: self.texture_id, - light, - }, - ), - QuadDir::Back => ( - Triangle { - p1: Vector3::new(pos_x, pos_y, pos_z_plus_one), - p2: Vector3::new(pos_x_plus_one, pos_y, pos_z_plus_one), - p3: Vector3::new(pos_x_plus_one, pos_y_plus_one, pos_z_plus_one), - texture_id: self.texture_id, - light, - }, - Triangle { - p1: Vector3::new(pos_x_plus_one, pos_y_plus_one, pos_z_plus_one), - p2: Vector3::new(pos_x, pos_y_plus_one, pos_z_plus_one), - p3: Vector3::new(pos_x, pos_y, pos_z_plus_one), - texture_id: self.texture_id, - light, - }, - ), - QuadDir::Bottom => ( - Triangle { - p1: Vector3::new(pos_x_plus_one, pos_y, pos_z), - p2: Vector3::new(pos_x_plus_one, pos_y, pos_z_plus_one), - p3: Vector3::new(pos_x, pos_y, pos_z_plus_one), - texture_id: self.texture_id, - light, - }, - Triangle { - p1: Vector3::new(pos_x, pos_y, pos_z_plus_one), - p2: Vector3::new(pos_x, pos_y, pos_z), - p3: Vector3::new(pos_x_plus_one, pos_y, pos_z), - texture_id: self.texture_id, - light, - }, - ), - QuadDir::Top => ( - Triangle { - p1: Vector3::new(pos_x, pos_y_plus_one, pos_z_plus_one), - p2: Vector3::new(pos_x_plus_one, pos_y_plus_one, pos_z_plus_one), - p3: Vector3::new(pos_x_plus_one, pos_y_plus_one, pos_z), - texture_id: self.texture_id, - light, - }, - Triangle { - p1: Vector3::new(pos_x_plus_one, pos_y_plus_one, pos_z), - p2: Vector3::new(pos_x, pos_y_plus_one, pos_z), - p3: Vector3::new(pos_x, pos_y_plus_one, pos_z_plus_one), - texture_id: self.texture_id, - light, - }, - ), - QuadDir::Left => ( - Triangle { - p3: Vector3::new(pos_x_plus_one, pos_y_plus_one, pos_z_plus_one), - p2: Vector3::new(pos_x_plus_one, pos_y_plus_one, pos_z), - p1: Vector3::new(pos_x_plus_one, pos_y, pos_z), - texture_id: self.texture_id, - light, - }, - Triangle { - p3: Vector3::new(pos_x_plus_one, pos_y, pos_z), - p2: Vector3::new(pos_x_plus_one, pos_y, pos_z_plus_one), - p1: Vector3::new(pos_x_plus_one, pos_y_plus_one, pos_z_plus_one), - texture_id: self.texture_id, - light, - }, - ), - QuadDir::Right => ( - Triangle { - p1: Vector3::new(pos_x, pos_y_plus_one, pos_z_plus_one), - p2: Vector3::new(pos_x, pos_y_plus_one, pos_z), - p3: Vector3::new(pos_x, pos_y, pos_z), - texture_id: self.texture_id, - light, - }, - Triangle { - p1: Vector3::new(pos_x, pos_y, pos_z), - p2: Vector3::new(pos_x, pos_y, pos_z_plus_one), - p3: Vector3::new(pos_x, pos_y_plus_one, pos_z_plus_one), - texture_id: self.texture_id, - light, - }, - ), - } - } -} - -#[derive(Clone, Copy, Debug)] -pub struct Triangle { - pub p1: Vector3, - pub p2: Vector3, - pub p3: Vector3, - pub texture_id: u8, - pub light: u8, -} - -#[derive(Clone, Copy, Debug)] -pub struct Triangle2D { - pub p1: Vector2, - pub p2: Vector2, - pub p3: Vector2, - pub texture_id: u8, - pub light: u8, -} - -impl Triangle2D { - pub fn to_small(&self) -> SmallTriangle2D { - let value: u64 = ((self.p1.x as u64) << 45) - | ((self.p1.y as u64) << 36) - | ((self.p2.x as u64) << 27) - | ((self.p2.y as u64) << 18) - | ((self.p3.x as u64) << 9) - | (self.p3.y as u64); - - let pos = ( - ((value >> 48) & 0xFF) as u8, - ((value >> 40) & 0xFF) as u8, - ((value >> 32) & 0xFF) as u8, - ((value >> 24) & 0xFF) as u8, - ((value >> 16) & 0xFF) as u8, - ((value >> 8) & 0xFF) as u8, - (value & 0xFF) as u8, - ); - - SmallTriangle2D { - pos, - texture_id: self.texture_id, - light: self.light, - } - } -} - -pub struct SmallTriangle2D { - pub pos: (u8, u8, u8, u8, u8, u8, u8), - pub texture_id: u8, - pub light: u8, -} - -impl SmallTriangle2D { - pub fn to_tri_2d(&self) -> Triangle2D { - // Recompose le u64 à partir des 7 u8 - let value: u64 = ((self.pos.0 as u64) << 48) - | ((self.pos.1 as u64) << 40) - | ((self.pos.2 as u64) << 32) - | ((self.pos.3 as u64) << 24) - | ((self.pos.4 as u64) << 16) - | ((self.pos.5 as u64) << 8) - | (self.pos.6 as u64); - - // Extrait chaque coordonnée sur 9 bits - let p1x = ((value >> 45) & 0x1FF) as i16; - let p1y = ((value >> 36) & 0x1FF) as i16; - let p2x = ((value >> 27) & 0x1FF) as i16; - let p2y = ((value >> 18) & 0x1FF) as i16; - let p3x = ((value >> 9) & 0x1FF) as i16; - let p3y = (value & 0x1FF) as i16; - - Triangle2D { - p1: Vector2::new(p1x, p1y), - p2: Vector2::new(p2x, p2y), - p3: Vector2::new(p3x, p3y), - texture_id: self.texture_id, - light: self.light, - } - } -} - -impl Triangle { - pub fn get_normal(&self) -> Vector3 { - let a = self.p2 - self.p1; - let b = self.p3 - self.p1; - a.cross(&b).normalize() - } -} - -fn get_block_in_chunk_or_world( - pos: Vector3, - chunks_manager: &ChunksManager, - chunk: &Chunk, -) -> Option { - if pos.x < 0 - || pos.x >= CHUNK_SIZE_I - || pos.y < 0 - || pos.y >= CHUNK_SIZE_I - || pos.z < 0 - || pos.z >= CHUNK_SIZE_I - { - chunks_manager.get_block_in_world(pos + *chunk.get_pos() * CHUNK_SIZE_I) - } else { - Some(chunk.get_at_unchecked(pos)) - } -} - -pub struct Mesh { - pub quads: Vec, -} - -impl Default for Mesh { - fn default() -> Self { - Self::new() - } -} - -impl Mesh { - pub fn new() -> Self { - Mesh { quads: Vec::new() } - } - - pub fn get_reference_vec(&mut self) -> &mut Vec { - &mut self.quads - } - - const fn get_light_level_from_dir(dir: QuadDir) -> u16 { - // Please not bellow 2 to avoid negative light. What is neagative light ? - match dir { - QuadDir::Front => 13, - QuadDir::Back => 10, - QuadDir::Top => 15, - QuadDir::Bottom => 6, - QuadDir::Right => 11, - QuadDir::Left => 10, - } - } - - pub fn generate_chunk(chunks_manager: &ChunksManager, chunk: &Chunk) -> Self { - let mut quads = Vec::new(); - - for x in 0..CHUNK_SIZE as isize { - for y in 0..CHUNK_SIZE as isize { - for z in 0..CHUNK_SIZE as isize { - let block_type = chunk.get_at_unchecked(Vector3::new(x, y, z)); - if block_type != BlockType::Air { - let bloc_pos = Vector3::new(x as u16, y as u16, z as u16); - - let grid_additional_light = if (x + y + z) % 2 == 0 { 2 } else { 0 }; // Make one block/2 darker to increase visibility - - if get_block_in_chunk_or_world(Vector3::new(x, y, z - 1), chunks_manager, chunk) - .is_some_and(|block| block.is_air()) - { - quads.push(Quad::new( - bloc_pos, - QuadDir::Front, - block_type.get_texture_id(QuadDir::Front), - Mesh::get_light_level_from_dir(QuadDir::Front) - - grid_additional_light, - )); - } - - if get_block_in_chunk_or_world(Vector3::new(x, y, z + 1), chunks_manager, chunk) - .is_some_and(|block| block.is_air()) - { - quads.push(Quad::new( - bloc_pos, - QuadDir::Back, - block_type.get_texture_id(QuadDir::Back), - Mesh::get_light_level_from_dir(QuadDir::Back) - - grid_additional_light, - )); - } - - if get_block_in_chunk_or_world(Vector3::new(x - 1, y, z), chunks_manager, chunk) - .is_some_and(|block| block.is_air()) - { - quads.push(Quad::new( - bloc_pos, - QuadDir::Right, - block_type.get_texture_id(QuadDir::Right), - Mesh::get_light_level_from_dir(QuadDir::Right) - - grid_additional_light, - )); - } - if get_block_in_chunk_or_world(Vector3::new(x + 1, y, z), chunks_manager, chunk) - .is_some_and(|block| block.is_air()) - { - quads.push(Quad::new( - bloc_pos, - QuadDir::Left, - block_type.get_texture_id(QuadDir::Left), - Mesh::get_light_level_from_dir(QuadDir::Left) - - grid_additional_light, - )); - } - - if get_block_in_chunk_or_world(Vector3::new(x, y + 1, z), chunks_manager, chunk) - .is_some_and(|block| block.is_air()) - { - quads.push(Quad::new( - bloc_pos, - QuadDir::Top, - block_type.get_texture_id(QuadDir::Top), - Mesh::get_light_level_from_dir(QuadDir::Top) - - grid_additional_light, - )); - } - - if get_block_in_chunk_or_world(Vector3::new(x, y - 1, z), chunks_manager, chunk) - .is_some_and(|block| block.is_air()) - { - quads.push(Quad::new( - bloc_pos, - QuadDir::Bottom, - block_type.get_texture_id(QuadDir::Bottom), - Mesh::get_light_level_from_dir(QuadDir::Bottom) - - grid_additional_light, - )); - } - } - } - } - } - - Mesh { quads } - } -} diff --git a/apps/Numcraft/src/renderer/misc.rs b/apps/Numcraft/src/renderer/misc.rs deleted file mode 100644 index d8002e5d..00000000 --- a/apps/Numcraft/src/renderer/misc.rs +++ /dev/null @@ -1,116 +0,0 @@ -use crate::{eadk::{display::{draw_string, pull_rect, push_rect, push_rect_uniform}, Point, Rect, SCREEN_RECT}, renderer::*}; - -pub struct UnBoundedRect { - pub x: isize, - pub y: isize, - pub width: isize, - pub height: isize, -} - -#[allow(dead_code)] -impl Renderer { - pub fn draw_string(&mut self, text: &str, pos: &Vector2) { - let mut text_cursor: usize = 0; - for char in text.chars() { - let font_index = FONT_ORDER.chars().position(|c| c == char).unwrap(); - - let font_pixel_index = font_index * FONT_CHAR_WIDTH; - - for x in 0..FONT_CHAR_WIDTH { - for y in 0..FONT_HEIGHT { - let pixel_value = FONT_DATA[(font_pixel_index + x) + y * FONT_WIDTH]; - - let rgb565 = - Color::from_888(pixel_value as u16, pixel_value as u16, pixel_value as u16); - - let pix_x = pos.x + x + text_cursor; - - if pix_x >= SCREEN_TILE_WIDTH { - continue; - } - - self.tile_frame_buffer[pix_x + (pos.y + y) * SCREEN_TILE_WIDTH] = rgb565; - } - } - text_cursor += FONT_CHAR_WIDTH; - } - } - - fn draw_string_no_bg_on_screen(&mut self, text: &str, pos: Vector2) { - let mut text_cursor: usize = 0; - - let rect_width = FONT_CHAR_WIDTH * text.len(); - let rect = Rect { - x: pos.x as u16, - y: pos.y as u16, - width: rect_width as u16, - height: FONT_HEIGHT as u16, - }; - - let mut bg_pixels = pull_rect(rect); - - for char in text.chars() { - let font_index = FONT_ORDER.chars().position(|c| c == char).unwrap(); - - let font_pixel_index = font_index * FONT_CHAR_WIDTH; - - for x in 0..FONT_CHAR_WIDTH { - for y in 0..FONT_HEIGHT { - let pixel_value = FONT_DATA[(font_pixel_index + x) + y * FONT_WIDTH]; - - let pix_x = x + text_cursor; - - if pix_x >= rect_width { - continue; - } - - let rgb565 = bg_pixels[pix_x + y * rect_width].apply_light(255 - pixel_value); - - bg_pixels[pix_x + y * rect_width] = rgb565; - } - } - text_cursor += FONT_CHAR_WIDTH; - } - - push_rect(rect, &bg_pixels); - } - - pub fn push_rect_uniform_on_frame_buffer(&mut self, rect: Rect, color: Color) { - for x in rect.x..(rect.x + rect.width) { - for y in rect.y..(rect.y + rect.height) { - self.tile_frame_buffer[x as usize + y as usize * SCREEN_TILE_WIDTH] = color; - } - } - } - - pub fn push_unbounded_rect_uniform_on_frame_buffer(&mut self, rect: UnBoundedRect, color: Color) { - if rect.x + rect.width <= 0 || rect.y + rect.height <= 0 { - return; - } - for x in rect.x.max(0)..(rect.x + rect.width).min(SCREEN_TILE_WIDTH as isize) { - for y in rect.y.max(0)..(rect.y + rect.height).min(SCREEN_TILE_HEIGHT as isize) { - self.tile_frame_buffer[x as usize + y as usize * SCREEN_TILE_WIDTH] = color; - } - } - } - - pub fn show_msg(message: &[&str], background_color: Color) { - push_rect_uniform(SCREEN_RECT, background_color); - - let mut y = (SCREEN_HEIGHT - message.len() * 20) / 2; - - for line in message { - draw_string( - line, - Point { - x: ((320 - line.len() * 10) / 2) as u16, - y: y as u16, - }, - true, - Color::from_888(0, 0, 0), - background_color, - ); - y += 20 - } - } -} diff --git a/apps/Numcraft/src/renderer/ui.rs b/apps/Numcraft/src/renderer/ui.rs deleted file mode 100644 index ad4af9ef..00000000 --- a/apps/Numcraft/src/renderer/ui.rs +++ /dev/null @@ -1,375 +0,0 @@ -use crate::{ - constants::{ - ItemType, - color_palette::{GAMEUI_SLOT_COLOR, GAMEUI_SLOT_DEFAULT_OUTLINE_COLOR}, - }, - eadk::{ - self, COLOR_BLACK, Point, Rect, - display::{draw_string, pull_rect, push_rect, push_rect_uniform}, - }, - game_ui::{GameUI, GameUIElements}, - renderer::*, -}; - -impl Renderer { - pub fn blur_screen(&self) { - const BLURING_TILE_WIDTH: usize = SCREEN_WIDTH / BLURING_SCREEN_SUBDIVISION; - const BLURING_TILE_HEIGHT: usize = SCREEN_HEIGHT / BLURING_SCREEN_SUBDIVISION; - - for x in 0..BLURING_SCREEN_SUBDIVISION { - for y in 0..BLURING_SCREEN_SUBDIVISION { - let tile_x = BLURING_TILE_WIDTH * x; - let tile_y = BLURING_TILE_HEIGHT * y; - let rect = Rect { - x: tile_x as u16, - y: tile_y as u16, - width: BLURING_TILE_WIDTH as u16, - height: BLURING_TILE_HEIGHT as u16, - }; - let pixels = pull_rect(rect); - - let mut new_pixels = [COLOR_BLACK; BLURING_TILE_WIDTH * BLURING_TILE_HEIGHT]; - for p_x in 0..BLURING_TILE_WIDTH { - for p_y in 0..BLURING_TILE_HEIGHT { - let mut total_color = (0, 0, 0); - let mut pixels_count = 0; - for neighbor_x in (p_x as isize - BLURING_RADIUS).max(0) as usize - ..(p_x as isize + BLURING_RADIUS).min(BLURING_TILE_WIDTH as isize) - as usize - { - for neighbor_y in (p_y as isize - BLURING_RADIUS).max(0) as usize - ..(p_y as isize + BLURING_RADIUS).min(BLURING_TILE_HEIGHT as isize) - as usize - { - let components = pixels - [neighbor_x + neighbor_y * BLURING_TILE_WIDTH] - .get_components(); - total_color.0 += components.0 as usize; - total_color.1 += components.1 as usize; - total_color.2 += components.2 as usize; - - pixels_count += 1; - } - } - - new_pixels[p_x + p_y * BLURING_TILE_WIDTH] = Color::from_components( - (total_color.0 / pixels_count) as u16, - (total_color.1 / pixels_count) as u16, - (total_color.2 / pixels_count) as u16, - ); - } - } - - push_rect(rect, &new_pixels); - } - } - } - - fn draw_scalled_tile_on_screen(&mut self, texture_id: u8, pos: Vector2, scale: usize) { - let tileset_x = (texture_id % 16) as usize * 8; - let tileset_y = (texture_id / 16) as usize * 8; - //let size = (8*scale).pow(2); - - //let pixels: Vec = Vec::with_capacity(size); - - for x in 0..8 { - for y in 0..8 { - let texture_pixel_index = ((tileset_x + x) + (tileset_y + y) * 128) * 2; - let pixel = u16::from_be_bytes([ - TILESET_DATA[texture_pixel_index], - TILESET_DATA[texture_pixel_index + 1], - ]); - - push_rect_uniform( - Rect { - x: pos.x + (x * scale) as u16, - y: pos.y + (y * scale) as u16, - width: scale as u16, - height: scale as u16, - }, - Color { rgb565: pixel }, - ); - } - } - } - - pub fn draw_game_ui_container(&mut self, game_ui: &mut GameUI, element_id: usize) { - let element = &game_ui.get_elements()[element_id]; - - if !(game_ui.need_redraw || game_ui.need_complete_redraw) { - return; - } - - let x = element.pos.x; - let y = element.pos.y; - - match &element.element { - GameUIElements::ItemSlot { item_stack, .. } => { - // Background - if item_stack.get_item_type() == ItemType::Air { - push_rect_uniform( - Rect { - x: x + 3, - y: y + 3, - width: 24, - height: 24, - }, - GAMEUI_SLOT_COLOR, - ); - } - - let color = if game_ui.selected_id.is_some_and(|id| id == element.id) { - Color::from_888(255, 242, 0) - } else if game_ui.cursor_id == element.id { - Color::from_888(255, 0, 0) - } else { - GAMEUI_SLOT_DEFAULT_OUTLINE_COLOR - }; - // Outline - push_rect_uniform( - Rect { - x: x, - y: y, - width: 3, - height: 30, - }, - color, - ); - push_rect_uniform( - Rect { - x: x, - y: y, - width: 30, - height: 3, - }, - color, - ); - push_rect_uniform( - Rect { - x: x, - y: y + 27, - width: 30, - height: 3, - }, - color, - ); - push_rect_uniform( - Rect { - x: x + 27, - y: y, - width: 3, - height: 30, - }, - color, - ); - - // Item texture - let texture_id = item_stack.get_item_type().get_texture_id(); - - if texture_id != 0 { - self.draw_scalled_tile_on_screen(texture_id, Vector2::new(3 + x, 3 + y), 3); - - if !item_stack.creative_slot - || (game_ui.selected_amount.is_some() - && game_ui.selected_id.is_some_and(|id| id == element_id)) - { - // Item amount - let amount_text = if let Some(selected_id) = game_ui.selected_id - && selected_id == element.id - && let Some(amount) = game_ui.selected_amount - { - format!("{}", amount) - } else { - format!("{}", item_stack.get_amount()) - }; - - draw_string( - amount_text.as_str(), - Point { - x: (30 - 7 * amount_text.len() + x as usize) as u16, - y: y, - }, - false, - Color::from_888(255, 255, 255), - GAMEUI_SLOT_COLOR, - ); - } - } - - // Amount selection bar - if let Some(amount) = game_ui.selected_amount - && game_ui.selected_id.is_some_and(|id| id == element.id) - && item_stack.get_amount() != 0 - { - let amount_bar_lenght = 30 * amount / item_stack.get_amount() as usize; - - push_rect_uniform( - Rect { - x: x, - y: y + 27, - width: amount_bar_lenght as u16, - height: 3, - }, - if game_ui.is_selecting_amount { - Color::from_888(100, 150, 255) - } else { - Color::from_888(50, 100, 255) - }, - ); - push_rect_uniform( - Rect { - x: x + amount_bar_lenght as u16, - y: y + 27, - width: (30 - amount_bar_lenght) as u16, - height: 3, - }, - Color::from_888(100, 100, 100), - ); - } - } - GameUIElements::Button { text, is_pressed } => todo!(), - GameUIElements::Label { text } => { - eadk::display::draw_string( - text, - Point { x, y }, - false, - Color::from_888(0, 0, 0), - Color::from_888(255, 255, 255), - ); - } - GameUIElements::Arrow { filling } => { - eadk::display::push_rect_uniform( - Rect { - x: element.pos.x + 2, - y: element.pos.y + 12, - width: 16, - height: 6, - }, - Color::from_888(150, 150, 150), - ); - - for i in 0..=10 { - eadk::display::push_rect_uniform( - Rect { - x: element.pos.x + 18 + i, - y: element.pos.y - (10 - i) + 2 + 12, - width: 1, - height: (10 - i) * 2 + 2, - }, - Color::from_888(150, 150, 150), - ); - } - } - GameUIElements::OneWayItemSlot { item_stack, .. } => { - // Background - if item_stack.get_item_type() == ItemType::Air { - push_rect_uniform( - Rect { - x: x + 3, - y: y + 3, - width: 24, - height: 24, - }, - GAMEUI_SLOT_COLOR, - ); - } - - let color = if game_ui.selected_id.is_some_and(|id| id == element.id) { - Color::from_888(255, 242, 0) - } else if game_ui.cursor_id == element.id { - Color::from_888(255, 0, 0) - } else { - GAMEUI_SLOT_DEFAULT_OUTLINE_COLOR - }; - // Outline - push_rect_uniform( - Rect { - x: x, - y: y, - width: 3, - height: 30, - }, - color, - ); - push_rect_uniform( - Rect { - x: x, - y: y, - width: 30, - height: 3, - }, - color, - ); - push_rect_uniform( - Rect { - x: x, - y: y + 27, - width: 30, - height: 3, - }, - color, - ); - push_rect_uniform( - Rect { - x: x + 27, - y: y, - width: 3, - height: 30, - }, - color, - ); - - // Item texture - let texture_id = item_stack.get_item_type().get_texture_id(); - - if texture_id != 0 { - self.draw_scalled_tile_on_screen(texture_id, Vector2::new(3 + x, 3 + y), 3); - - if !item_stack.creative_slot - || (game_ui.selected_amount.is_some() - && game_ui.selected_id.is_some_and(|id| id == element_id)) - { - // Item amount - let amount_text = format!("{}", item_stack.get_amount()); - - draw_string( - amount_text.as_str(), - Point { - x: (30 - 7 * amount_text.len() + x as usize) as u16, - y: y, - }, - false, - Color::from_888(255, 255, 255), - GAMEUI_SLOT_COLOR, - ); - } - } - } - } - - #[cfg(feature = "debug_ui")] - { - eadk::display::draw_string( - format!("{}", element_id).as_str(), - Point { x: x + 2, y: y + 2 }, - false, - Color::from_888(0, 0, 0), - Color::from_888(255, 255, 255), - ); - } - } - - pub fn draw_game_ui(&mut self, game_ui: &mut GameUI) { - if game_ui.blur_background && game_ui.need_complete_redraw { - self.blur_screen(); - } - - let elements = game_ui.get_elements(); - - for i in 0..elements.len() { - self.draw_game_ui_container(game_ui, i); - } - game_ui.need_complete_redraw = false; - game_ui.need_redraw = false; - } -} diff --git a/apps/Numcraft/src/save_manager.rs b/apps/Numcraft/src/save_manager.rs deleted file mode 100644 index fb900d34..00000000 --- a/apps/Numcraft/src/save_manager.rs +++ /dev/null @@ -1,381 +0,0 @@ -#[cfg(target_os = "none")] -use alloc::{string::String, vec::Vec}; - -#[cfg(target_os = "none")] -use crate::alloc::borrow::ToOwned; - -use lz4_flex::{compress, compress_prepend_size, decompress, decompress_size_prepended}; -use nalgebra::Vector3; -use postcard::{from_bytes, to_allocvec}; -use serde::{Deserialize, Serialize}; - -use crate::{ - constants::{BlockType, save_manager::WORLD_VERSION, world::CHUNK_SIZE}, - eadk::{self}, - game::GameMode, - inventory::Inventory, - player::Player, - renderer::Renderer, - storage_lib::{ - storage_extapp_file_erase, storage_extapp_file_exists, - storage_extapp_file_list_with_extension, storage_extapp_file_read, - storage_extapp_file_read_header, storage_file_write, - }, - world::{World, chunk::Chunk}, -}; - -#[derive(Serialize, Deserialize)] -pub struct PlayerData { - pub pos: (f32, f32, f32), - pub rotation: (f32, f32), // Only Pitch and Yaw - pub inventory: Inventory, // More in the futur -} - -#[derive(Serialize, Deserialize)] -pub struct WorldInfo { - pub world_version: u16, - pub world_name: String, - pub world_seed: i32, - pub gamemode: GameMode, -} - -impl WorldInfo { - pub fn new() -> Self { - WorldInfo { - world_version: WORLD_VERSION, - world_name: String::new(), - world_seed: 1, - gamemode: GameMode::Survival, - } - } -} - -impl PlayerData { - pub fn new() -> Self { - PlayerData { - pos: (0., 0., 0.), - rotation: (0., 0.), - inventory: Inventory::new(0), - } - } -} - -pub struct SaveManager { - chunks_data: [Vec; 64], - player_data: PlayerData, - world_info: WorldInfo, - pub file_name: Option, -} - -impl SaveManager { - pub fn new() -> Self { - SaveManager { - chunks_data: [const { Vec::new() }; 64], - player_data: PlayerData::new(), - world_info: WorldInfo::new(), - file_name: None, - } - } - - pub fn get_current_loaded_world_info(&self) -> &WorldInfo { - &self.world_info - } - - pub fn set_world_seed(&mut self, seed: i32) { - self.world_info.world_seed = seed; - } - - pub fn set_world_name(&mut self, world_name: &String) { - self.world_info.world_name = world_name.clone(); - } - - pub fn set_gamemode(&mut self, gamemode: GameMode) { - self.world_info.gamemode = gamemode; - } - - pub fn get_game_mode(&self) -> GameMode { - self.world_info.gamemode - } - - pub fn set_chunk(&mut self, chunk: &Chunk) -> bool { - let pos = chunk.get_pos(); - - if pos.x < 0 || pos.x >= 4 || pos.y < 0 || pos.y >= 4 || pos.z < 0 || pos.z >= 4 { - return false; - } - - let compressed = compress(&chunk.get_all_blocks().map(|b| b as u8)); - - let index = (pos.x + pos.y * 4 + pos.z * 16) as usize; - - self.chunks_data[index] = compressed; - - true - } - - pub fn set_file_name(&mut self, file_name: &String) { - self.file_name = Some(file_name.clone()); - } - - pub fn update_player_data(&mut self, world: &World, player: &Player) { - let player_entity = world.get_player_entity(); - - self.player_data.pos.0 = player_entity.pos.x; - self.player_data.pos.1 = player_entity.pos.y; - self.player_data.pos.2 = player_entity.pos.z; - - self.player_data.rotation.0 = player_entity.rotation.x; - self.player_data.rotation.1 = player_entity.rotation.y; - - self.player_data.inventory = player.inventory.clone(); - } - - pub fn get_existing_worlds(&self) -> Vec { - storage_extapp_file_list_with_extension(4, "ncw") - } - - pub fn delete_world(&self, world_name: &String) { - if storage_extapp_file_exists(world_name) { - storage_extapp_file_erase(world_name); - } - } - - pub fn save_world_to_file(&self) { - let data = self.get_raw(); - - if let Some(file_name) = &self.file_name { - if storage_extapp_file_exists(file_name) && !storage_extapp_file_erase(file_name) { - Renderer::show_msg( - &["Unable to save.", "Cannot delete old save!"], - eadk::Color::from_888(255, 100, 100), - ); - eadk::timing::msleep(3000); - } - if !storage_file_write(file_name, &data) { - Renderer::show_msg( - &["Unable to save.", "Writing error!"], - eadk::Color::from_888(255, 100, 100), - ); - eadk::timing::msleep(3000); - } - } else { - Renderer::show_msg(&["Unable to save."], eadk::Color::from_888(255, 100, 100)); - eadk::timing::msleep(3000); - } - } - - fn get_raw(&self) -> Vec { - let mut data: Vec = Vec::new(); - - let raw_world_info = to_allocvec(&self.world_info).unwrap(); - data.extend((raw_world_info.len() as u16).to_be_bytes()); - data.extend(raw_world_info); - - let mut data_to_compress: Vec = Vec::new(); - - for i in 0..self.chunks_data.len() { - let size: u16 = self.chunks_data[i].len() as u16; - data_to_compress.extend_from_slice(&size.to_be_bytes()); - } - - for i in 0..self.chunks_data.len() { - data_to_compress.extend(&self.chunks_data[i]); - } - - let raw_player_data = to_allocvec(&self.player_data).unwrap(); - data_to_compress.extend((raw_player_data.len() as u16).to_be_bytes()); - data_to_compress.extend(raw_player_data); - - data.extend_from_slice(&compress_prepend_size(&data_to_compress)); - - data - } - - fn read_world_info(&mut self, data: &[u8]) -> Result { - let mut world_data_offset = 0; - // If world info is missing, the world is currupted - if world_data_offset + 1 >= data.len() { - return Err(SaveFileLoadError::CorruptedWorld); - } - - // Extract world info - let world_info_size = - u16::from_be_bytes([data[world_data_offset], data[world_data_offset + 1]]) as usize; - - world_data_offset += 2; // world info size - - // Check for overflow - if world_data_offset + world_info_size > data.len() { - return Err(SaveFileLoadError::CorruptedWorld); - } - - // Read the raw data - let world_info_raw = &data[world_data_offset..(world_data_offset + world_info_size)]; - - if let Ok(world_info) = from_bytes::(world_info_raw) { - self.world_info = world_info; - Ok(world_data_offset + world_info_size) - } else { - return Err(SaveFileLoadError::CorruptedWorld); - } - } - - pub fn get_world_info(&self, filename: &String) -> Option { - let raw_data = storage_extapp_file_read_header(filename, 2)?; - let world_info_size = u16::from_be_bytes([raw_data[0], raw_data[1]]); - let raw_data = - &storage_extapp_file_read_header(filename, world_info_size as usize + 2)?[2..]; - - if let Ok(world_info) = from_bytes::(&raw_data) { - Some(world_info) - } else { - None - } - - //Some(WorldInfo::new()) - } - - pub fn load_from_file(&mut self, filename: &str) -> Result<(), SaveFileLoadError> { - self.file_name = Some(filename.to_owned()); - // Read file - if let Some(raw_data) = storage_extapp_file_read(filename) { - if let Ok(world_data_offset) = self.read_world_info(&raw_data) { - // Decompress the entire file - if let Ok(data) = decompress_size_prepended(&raw_data[world_data_offset..]) { - let mut current_pos = 128; - for i in 0..64 { - let size = u16::from_be_bytes([data[i * 2], data[i * 2 + 1]]) as usize; // Get the compressed chunk size from the headers - - if current_pos + size > data.len() { - // Check for corruption. If overflow, the size is wrong and the world is ... unusable ... - return Err(SaveFileLoadError::CorruptedWorld); - } - let raw_chunk = &data[current_pos..(current_pos + size)]; - - self.chunks_data[i] = raw_chunk.to_vec(); - - current_pos += size; - } - - // If player data is missing, the world is currupted - if current_pos + 1 >= data.len() { - return Err(SaveFileLoadError::CorruptedWorld); - } - - // Extract player_data - let player_data_size = - u16::from_be_bytes([data[current_pos], data[current_pos + 1]]) as usize; - - current_pos += 2; // player data size - - // Check for overflow - if current_pos + player_data_size > data.len() { - return Err(SaveFileLoadError::CorruptedWorld); - } - - // Read the raw data - let player_data_raw = &data[current_pos..(current_pos + player_data_size)]; - - if let Ok(player_data) = from_bytes::(player_data_raw) { - self.player_data = player_data; - } else { - return Err(SaveFileLoadError::CorruptedWorld); - } - - Ok(()) - } else { - Err(SaveFileLoadError::CorruptedWorld) - } - } else { - Err(SaveFileLoadError::CorruptedWorld) - } - } else { - Err(SaveFileLoadError::FileNotFound) - } - } - - pub fn get_chunk_at_pos(&self, pos: Vector3) -> Result { - if pos.x < 0 || pos.x >= 4 || pos.y < 0 || pos.y >= 4 || pos.z < 0 || pos.z >= 4 { - return Err(ChunkReadingError::OOBChunk); - } - - let index = (pos.x + pos.y * 4 + pos.z * 16) as usize; - - let raw_chunk = &self.chunks_data[index]; - - if let Ok(chunk_data) = decompress(raw_chunk, 512) { - if chunk_data.len() != 512 { - return Err(ChunkReadingError::CorruptedChunk); - } - - let mut chunk = Chunk::new(pos); - - for x in 0..CHUNK_SIZE { - for y in 0..CHUNK_SIZE { - for z in 0..CHUNK_SIZE { - if let Some(block_type) = BlockType::get_from_id( - chunk_data[x + y * CHUNK_SIZE + z * CHUNK_SIZE * CHUNK_SIZE], - ) { - chunk.set_at(Vector3::new(x, y, z), block_type); - } else { - return Err(ChunkReadingError::CorruptedChunk); - } - } - } - } - - Ok(chunk) - } else { - Err(ChunkReadingError::CorruptedChunk) - } - } - - pub fn get_player_pos(&self) -> Vector3 { - Vector3::new( - self.player_data.pos.0, - self.player_data.pos.1, - self.player_data.pos.2, - ) - } - - pub fn get_player_inventory(&self) -> Inventory { - self.player_data.inventory.clone() - } - - pub fn get_player_rot(&self) -> Vector3 { - Vector3::new(self.player_data.rotation.0, self.player_data.rotation.1, 0.) - } - - pub fn clean(&mut self) { - for chunk in self.chunks_data.iter_mut() { - chunk.clear(); - } - - self.player_data = PlayerData::new(); - } -} - -#[derive(Debug)] -pub enum ChunkReadingError { - OOBChunk, - CorruptedChunk, -} - -#[derive(Debug)] -pub enum SaveFileLoadError { - FileNotFound, - CorruptedWorld, -} - -/* -Save file format. World is 4 x 4 x 4 chunks. - -Header: - 4x4x4 x 2 B array : represent the compressed size of the chunk for each chunk - - 4x4x4 x variable size : chunks data. - - 2 + variable : Player info - - 2 + variable : World Info -*/ diff --git a/apps/Numcraft/src/settings.rs b/apps/Numcraft/src/settings.rs deleted file mode 100644 index d78509fd..00000000 --- a/apps/Numcraft/src/settings.rs +++ /dev/null @@ -1,46 +0,0 @@ -use postcard::from_bytes; -use serde::{Deserialize, Serialize}; - -use crate::{ - constants::{rendering::*, save_manager::*}, - storage_lib::{ - storage_extapp_file_erase, storage_extapp_file_exists, storage_extapp_file_read, - storage_file_write, - }, -}; - -#[derive(Serialize, Deserialize)] -pub struct Settings { - pub render_distance: usize, - pub fov: f32, - pub vsync: bool, -} - -impl Settings { - pub fn new() -> Self { - Settings { - render_distance: MAX_RENDER_DISTANCE, - fov: FOV, - vsync: false, - } - } - - pub fn save(&self) { - if storage_extapp_file_exists(SETTINGS_FILENAME) { - storage_extapp_file_erase(SETTINGS_FILENAME); - } - let raw = postcard::to_allocvec(self).unwrap(); - - storage_file_write(SETTINGS_FILENAME, &raw); - } - - pub fn load(&mut self) { - if storage_extapp_file_exists(SETTINGS_FILENAME) { - let raw = storage_extapp_file_read(SETTINGS_FILENAME).unwrap(); - - let object: Settings = from_bytes(&raw).unwrap(); - - *self = object; - } - } -} diff --git a/apps/Numcraft/src/storage_lib.rs b/apps/Numcraft/src/storage_lib.rs deleted file mode 100644 index dfb5232b..00000000 --- a/apps/Numcraft/src/storage_lib.rs +++ /dev/null @@ -1,123 +0,0 @@ -#[cfg(target_os = "none")] -use core::ffi::CStr; - -#[cfg(target_os = "none")] -use alloc::{ffi, string::String, vec::Vec}; - -#[cfg(target_os = "none")] -pub fn storage_file_write(filename: &str, content: &[u8]) -> bool { - let c_string = ffi::CString::new(filename).unwrap(); - unsafe { extapp_fileWrite(c_string.as_ptr(), content.as_ptr(), content.len(), 0) } -} - -#[cfg(not(target_os = "none"))] -pub fn storage_file_write(_filename: &str, _content: &[u8]) -> bool { - true -} - -#[cfg(target_os = "none")] -pub fn storage_extapp_file_exists(filename: &str) -> bool { - let c_string = ffi::CString::new(filename).unwrap(); - unsafe { extapp_fileExists(c_string.as_ptr(), 0) } -} - -#[cfg(not(target_os = "none"))] -pub fn storage_extapp_file_exists(_filename: &str) -> bool { - false -} - -#[cfg(target_os = "none")] -pub fn storage_extapp_file_read(filename: &str) -> Option> { - let c_string = ffi::CString::new(filename).unwrap(); - let mut lenght: usize = 0; - let array_pointer = unsafe { extapp_fileRead(c_string.as_ptr(), &mut lenght as *mut usize, 0) }; - - if array_pointer.is_null() { - return None; - } - - Some(unsafe { core::slice::from_raw_parts(array_pointer, lenght).to_vec() }) -} - -#[cfg(not(target_os = "none"))] -pub fn storage_extapp_file_read(_filename: &str) -> Option> { - None -} - -#[cfg(target_os = "none")] -pub fn storage_extapp_file_read_header(filename: &str, header_len: usize) -> Option> { - let c_string = ffi::CString::new(filename).unwrap(); - let mut _lenght: usize = 0; - let array_pointer = unsafe { extapp_fileRead(c_string.as_ptr(), &mut _lenght as *mut usize, 0) }; - - if array_pointer.is_null() { - return None; - } - - Some(unsafe { core::slice::from_raw_parts(array_pointer, header_len).to_vec() }) -} - -#[cfg(not(target_os = "none"))] -pub fn storage_extapp_file_read_header(_filename: &str, _header_len: usize) -> Option> { - None -} - -#[cfg(target_os = "none")] -pub fn storage_extapp_file_erase(filename: &str) -> bool { - let c_string = ffi::CString::new(filename).unwrap(); - unsafe { extapp_fileErase(c_string.as_ptr(), 0) } -} - -#[cfg(not(target_os = "none"))] -pub fn storage_extapp_file_erase(_filename: &str) -> bool { - true -} - -#[cfg(target_os = "none")] -pub fn storage_extapp_file_list_with_extension(max_records: usize, extension: &str) -> Vec { - let mut filenames: Vec<*mut u8> = Vec::with_capacity(max_records); - let c_string = ffi::CString::new(extension).unwrap(); - - unsafe { - let final_len = extapp_fileListWithExtension( - filenames.as_mut_slice().as_mut_ptr(), - max_records as isize, - c_string.as_ptr(), - 0 - ); - filenames.set_len(final_len as usize); - - let mut files: Vec = Vec::new(); - for name_ptr in filenames { - if !name_ptr.is_null() { - let name = CStr::from_ptr(name_ptr).to_string_lossy().into_owned(); - files.push(name); - } - } - - files - } -} - -#[cfg(not(target_os = "none"))] -pub fn storage_extapp_file_list_with_extension( - _max_records: usize, - _extension: &str, -) -> Vec { - Vec::new() -} - -#[cfg(target_os = "none")] -unsafe extern "C" { - fn extapp_fileWrite(filename: *const u8, content: *const u8, len: usize, storage: isize) -> bool; - fn extapp_fileExists(filename: *const u8, storage: isize) -> bool; - fn extapp_fileRead(filename: *const u8, len: *mut usize, storage: isize) -> *const u8; - fn extapp_fileErase(filename: *const u8, storage: isize) -> bool; - fn extapp_fileListWithExtension( - filename: *mut *mut u8, - maxrecord: isize, - extension: *const u8, - storage: isize - ) -> isize; - -} diff --git a/apps/Numcraft/src/timing.rs b/apps/Numcraft/src/timing.rs deleted file mode 100644 index e6ae8414..00000000 --- a/apps/Numcraft/src/timing.rs +++ /dev/null @@ -1,33 +0,0 @@ -use crate::eadk; - -pub struct TimingManager { - last_timer: u64, - delta_time: f32, -} - -impl TimingManager { - pub fn new() -> Self { - TimingManager { - last_timer: eadk::timing::millis(), - delta_time: 0.1, - } - } - - pub fn update(&mut self) { - let current = eadk::timing::millis(); - self.delta_time = (current - self.last_timer) as f32 / 1000.0; - self.last_timer = current; - } - - pub fn get_delta_time(&self) -> f32 { - self.delta_time - } - - pub fn get_fps(&self) -> f32 { - return 1. / self.delta_time; - } - pub fn reset(&mut self) { - self.last_timer = eadk::timing::millis(); - self.delta_time = 0.1; - } -} diff --git a/apps/Numcraft/src/world.rs b/apps/Numcraft/src/world.rs deleted file mode 100644 index 4bb3e447..00000000 --- a/apps/Numcraft/src/world.rs +++ /dev/null @@ -1,316 +0,0 @@ -use core::any::Any; - -use crate::constants::world::{ - CHUNK_SIZE, ITEM_MAGNET_FORCE, MAX_ITEM_MERGING_DISTANCE, MAX_PLAYER_ITEM_MAGNET_DISTANCE, -}; -use crate::constants::{BlockType, EntityType, ItemType}; -use crate::entity::Entity; -use crate::entity::item::ItemEntityCustomData; -use crate::inventory::{Inventory, ItemStack}; -use crate::world::chunk_manager::ChunksManager; -use crate::world::world_generator::WorldGenerator; - -#[cfg(target_os = "none")] -use alloc::vec; -#[cfg(target_os = "none")] -use alloc::vec::Vec; - -use nalgebra::Vector3; - -#[cfg(target_os = "none")] -use alloc::boxed::Box; - -pub mod chunk; -pub mod chunk_manager; -mod structures; -pub mod world_generator; - -const CHUNK_SIZE_I: isize = CHUNK_SIZE as isize; - -pub struct World { - pub chunks_manager: ChunksManager, - registered_inventories: Vec, - loaded_entities: Vec, - next_available_entity_id: usize, - world_generator: WorldGenerator, -} - -pub struct RegisteredInventory { - inventory: Inventory, - block_pos: Option>, -} - -impl Default for World { - fn default() -> Self { - Self::new() - } -} - -/// Represents the current world. Contains all the chunks -impl World { - pub fn new() -> Self { - let mut world = World { - chunks_manager: ChunksManager::new(), - registered_inventories: Vec::new(), - loaded_entities: vec![Entity::new(0, EntityType::Player, None)], // The player entity is always loaded and id 0 - next_available_entity_id: 1, - world_generator: WorldGenerator::new(), - }; - - world - } - - pub fn get_player_entity_mut(&mut self) -> &mut Entity { - &mut self.loaded_entities[0] - } - - pub fn get_player_entity(&self) -> &Entity { - &self.loaded_entities[0] - } - - pub fn load_area( - &mut self, - x_start: isize, - x_stop: isize, - y_start: isize, - y_stop: isize, - z_start: isize, - z_stop: isize, - ) { - for x in x_start..x_stop { - for y in y_start..y_stop { - for z in z_start..z_stop { - self.chunks_manager.add_chunk(Vector3::new(x, y, z)); - } - } - } - - for x in x_start..x_stop { - for y in y_start..y_stop { - for z in z_start..z_stop { - self.world_generator - .generate_chunk(&mut self.chunks_manager, Vector3::new(x, y, z)); - } - } - } - } - - pub fn update_entities(&mut self, delta_time: f32) { - // Check for item merging and player magnet - 'first_loop: for i in 0..self.loaded_entities.len() { - if self.loaded_entities[i].get_type() == EntityType::Item { - // Ignore items with custom data = None, they will be removed after - if self.loaded_entities[i].custom_data.is_none() { - continue; - } - - // Get the item_data from the first item - let first_item_data = ItemEntityCustomData::get_item_data(&self.loaded_entities[i]) - .expect("Item Entity must have ItemData as custom data."); - let first_item_stack = first_item_data.item_stack.clone(); - - let max_stack = first_item_stack.get_item_type().get_max_stack_amount(); - - for j in 0..self.loaded_entities.len() { - if i != j - && self.loaded_entities[j].custom_data.is_some() // Ignore items with custom data = None, they will be removed after - && self.loaded_entities[j].get_type() == EntityType::Item - && self.loaded_entities[i] - .pos - .metric_distance(&self.loaded_entities[j].pos) - <= MAX_ITEM_MERGING_DISTANCE - { - // Check if the items can merge - let second_item_data = - ItemEntityCustomData::get_item_data(&self.loaded_entities[j]) - .expect("Item Entity must have ItemData as custom data."); - let second_item_stack = second_item_data.item_stack.clone(); - - if second_item_stack.get_item_type() != first_item_stack.get_item_type() { - continue; - } - - if let Some(first_bbox) = self.loaded_entities[i].get_bbox() - && let Some(second_bbox) = self.loaded_entities[j].get_bbox() - && first_bbox.is_coliding(&second_bbox) - { - if first_item_stack.get_amount() == max_stack - || second_item_stack.get_amount() == max_stack - { - continue; - } - - let total = - first_item_stack.get_amount() + second_item_stack.get_amount(); - if total <= max_stack { - // Merge the two items together and request the deletion of the second one - self.loaded_entities[i].custom_data = - Some(Box::new(ItemEntityCustomData { - item_stack: ItemStack::new( - first_item_stack.get_item_type(), - total, - false, - ), - })); - self.loaded_entities[j].custom_data = None; // Yes, this should be illegal but it can also be a feature. - self.loaded_entities[i].velocity = Vector3::zeros(); - continue 'first_loop; - } else { - self.loaded_entities[i].custom_data = - Some(Box::new(ItemEntityCustomData { - item_stack: ItemStack::new( - first_item_stack.get_item_type(), - max_stack, - false, - ), - })); - self.loaded_entities[j].custom_data = - Some(Box::new(ItemEntityCustomData { - item_stack: ItemStack::new( - first_item_stack.get_item_type(), - total - max_stack, - false, - ), - })); - self.loaded_entities[i].velocity = Vector3::zeros(); - self.loaded_entities[j].velocity = Vector3::zeros(); - } - continue; - } - - // Calculate the direction to the other item - let direction = - (self.loaded_entities[j].pos - self.loaded_entities[i].pos).normalize(); - - self.loaded_entities[i].velocity += - direction * ITEM_MAGNET_FORCE * delta_time; - - // Limit the magnet speed - /*if self.loaded_entities[i].velocity.norm() > ITEM_MAGNET_SPEED { - self.loaded_entities[i].velocity = - self.loaded_entities[i].velocity.normalize() - * ITEM_MAGNET_SPEED - * delta_time; - }*/ - } - } - } - } - - // Player item magnet - for i in 0..self.loaded_entities.len() { - let distance = self.loaded_entities[i] - .pos - .metric_distance(&self.get_player_entity().pos); - if self.loaded_entities[i].get_type() == EntityType::Item - && self.loaded_entities[i].custom_data.is_some() - && distance < MAX_PLAYER_ITEM_MAGNET_DISTANCE - { - let direction = - (self.get_player_entity().pos - self.loaded_entities[i].pos).normalize(); - - self.loaded_entities[i].velocity += direction * ITEM_MAGNET_FORCE * delta_time; - } - } - - // Remove illegal items - self.loaded_entities.retain(|entity| { - entity.get_type() != EntityType::Item - || (entity.get_type() == EntityType::Item && !entity.custom_data.is_none()) - }); - } - - /// Set the world generation seed - pub fn set_seed(&mut self, seed: i32) { - self.world_generator.set_seed(seed); - } - - fn register_inventory(&mut self, inventory: Inventory) { - self.registered_inventories.push(inventory); - } - - pub fn get_all_entities_mut(&mut self) -> &mut Vec { - &mut self.loaded_entities - } - pub fn get_all_entities(&self) -> &Vec { - &self.loaded_entities - } - - pub fn get_entity_by_id_mut(&mut self, id: usize) -> Option<&mut Entity> { - self.loaded_entities - .iter_mut() - .find(|entity| entity.get_id() == id) - } - - pub fn get_entity_by_id(&self, id: usize) -> Option<&Entity> { - self.loaded_entities - .iter() - .find(|entity| entity.get_id() == id) - } - - pub fn spawn_entity(&mut self, mut entity: Entity, pos: Vector3) { - entity.pos = pos; - self.loaded_entities.push(entity); - } - - pub fn get_new_entity_id(&mut self) -> usize { - let id = self.next_available_entity_id; - self.next_available_entity_id += 1; - id - } - - pub fn clear_entities(&mut self) { - if self.loaded_entities.len() > 1 { - for i in 1..self.loaded_entities.len() { - self.loaded_entities.remove(i); - } - } - } - - pub fn spawn_entity_auto( - &mut self, - entity_type: EntityType, - pos: Vector3, - custom_data: Option>, - ) { - let id = self.get_new_entity_id(); - self.spawn_entity(Entity::new(id, entity_type, custom_data), pos); - } - - pub fn spawn_item_entity(&mut self, pos: Vector3, item_stack: ItemStack) { - self.spawn_entity_auto( - EntityType::Item, - pos, - Some(Box::new(ItemEntityCustomData { item_stack })), - ); - } - - pub fn replace_block_and_drop_item(&mut self, pos: Vector3, block_type: BlockType) { - if let Some(current_block) = self.chunks_manager.get_block_in_world(pos) { - let drop_type = current_block.get_dropped_item_type(); - if drop_type != ItemType::Air { - self.chunks_manager.set_block_in_world(pos, block_type); - self.spawn_item_entity( - pos.map(|v| v as f32 + 0.5), - ItemStack::new(drop_type, 1, false), - ); - } - } - } - - pub fn remove_entity(&mut self, id: usize) -> bool { - for i in 0..self.loaded_entities.len() { - if self.loaded_entities[i].get_id() == id { - self.loaded_entities.remove(i); - return true; - } - } - false - } - - /// Clear all the chunks and entities - pub fn clear(&mut self) { - self.chunks_manager.clear(); - self.clear_entities(); - } -} diff --git a/apps/Numcraft/src/world/chunk.rs b/apps/Numcraft/src/world/chunk.rs deleted file mode 100644 index 2aab6578..00000000 --- a/apps/Numcraft/src/world/chunk.rs +++ /dev/null @@ -1,80 +0,0 @@ -use crate::{ - constants::{BlockType, world::*}, - renderer::mesh::Mesh, -}; - -use nalgebra::Vector3; - -const BLOCK_COUNT: usize = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE; -const CHUNK_SIZE_I: isize = CHUNK_SIZE as isize; - -pub struct Chunk { - blocks: [BlockType; BLOCK_COUNT], - pos: Vector3, - pub mesh: Mesh, - pub generated: bool, - pub need_new_mesh: bool, - pub need_sorting: bool, -} - -#[allow(dead_code)] -impl Chunk { - pub fn new(pos: Vector3) -> Self { - Chunk { - blocks: [BlockType::Air; BLOCK_COUNT], - pos, - mesh: Mesh::new(), - generated: false, - need_new_mesh: true, - need_sorting: false, - } - } - - pub fn set_at(&mut self, pos: Vector3, block_type: BlockType) -> bool { - if pos.x < CHUNK_SIZE && pos.y < CHUNK_SIZE && pos.z < CHUNK_SIZE { - self.blocks[pos.x + pos.y * CHUNK_SIZE + pos.z * CHUNK_SIZE * CHUNK_SIZE] = block_type; - true - } else { - false - } - } - - pub fn get_at(&self, pos: Vector3) -> Option { - if pos.x < CHUNK_SIZE_I - && pos.y < CHUNK_SIZE_I - && pos.z < CHUNK_SIZE_I - && pos.x >= 0 - && pos.y >= 0 - && pos.z >= 0 - { - Some( - self.blocks - [(pos.x + pos.y * CHUNK_SIZE_I + pos.z * CHUNK_SIZE_I * CHUNK_SIZE_I) as usize], - ) - } else { - None - } - } - - pub fn get_at_unchecked(&self, pos: Vector3) -> BlockType { - self.blocks[(pos.x + pos.y * CHUNK_SIZE_I + pos.z * CHUNK_SIZE_I * CHUNK_SIZE_I) as usize] - } - - pub fn get_pos(&self) -> &Vector3 { - &self.pos - } - - pub fn get_all_blocks(&self) -> &[BlockType; BLOCK_COUNT] { - &self.blocks - } - - pub fn get_mesh(&mut self) -> &mut Mesh { - &mut self.mesh - } - - pub fn set_mesh(&mut self, new_mesh: Mesh) { - self.mesh = new_mesh; - self.need_new_mesh = false; - self.need_sorting = true; - } -} diff --git a/apps/Numcraft/src/world/chunk_manager.rs b/apps/Numcraft/src/world/chunk_manager.rs deleted file mode 100644 index d4e008f7..00000000 --- a/apps/Numcraft/src/world/chunk_manager.rs +++ /dev/null @@ -1,204 +0,0 @@ -use libm::roundf; -use nalgebra::Vector3; - -use crate::{ - constants::{BlockType, world::CHUNK_SIZE}, - misc::div_floor, - renderer::mesh::Mesh, - world::{CHUNK_SIZE_I, chunk::Chunk, world_generator::WorldGenerator}, -}; - -#[cfg(target_os = "none")] -use alloc::vec::Vec; - -/// Convert the block position from world space to chunk space -pub fn get_chunk_local_coords(pos: Vector3) -> Vector3 { - Vector3::new( - (pos.x % CHUNK_SIZE_I + CHUNK_SIZE_I) % CHUNK_SIZE_I, - (pos.y % CHUNK_SIZE_I + CHUNK_SIZE_I) % CHUNK_SIZE_I, - (pos.z % CHUNK_SIZE_I + CHUNK_SIZE_I) % CHUNK_SIZE_I, - ) -} - -pub struct ChunksManager { - pub chunks: Vec, -} - -impl ChunksManager { - pub fn new() -> Self { - ChunksManager { chunks: Vec::new() } - } - - /// Return the chunk at the given position. Return an Option containing a MUTABLE reference to the chunk - pub fn get_chunk_at_pos_mut(&mut self, pos: Vector3) -> Option<&mut Chunk> { - self.chunks.iter_mut().find(|chunk| *chunk.get_pos() == pos) - } - - /// Return the chunk at the given position. Return an Option containing a reference to the chunk - pub fn get_chunk_at_pos(&self, pos: Vector3) -> Option<&Chunk> { - self.chunks.iter().find(|&chunk| *chunk.get_pos() == pos) - } - - /// Delete all loaded chunks - pub fn clear(&mut self) { - self.chunks.clear(); - } - - /// Add a chunk and return a reference to it as an option - pub fn add_chunk(&mut self, pos: Vector3) { - let chunk = Chunk::new(pos); - self.chunks.push(chunk); - } - - /// Return true if a chunks is loaded at the given coordinates. The position is the position of the chunk and not the position of a block - pub fn get_chunk_exists_at(&self, pos: Vector3) -> bool { - for chunk in &self.chunks { - if *chunk.get_pos() == pos { - return true; - } - } - false - } - - pub fn push_chunk(&mut self, chunk: Chunk) { - self.chunks.push(chunk); - } - - /// Used for rendering priority. Return a Vector of all the loaded chunks from the nearest to the farest - pub fn get_chunks_sorted_by_distance(&mut self, pos: Vector3) -> Vec<&mut Chunk> { - let mut chunks: Vec<&mut Chunk> = self.chunks.iter_mut().collect(); - - chunks.sort_by(|a, b| { - let a_dist = a - .get_pos() - .map(|x| (x * CHUNK_SIZE_I) as f32 + CHUNK_SIZE_I as f32 / 2.) - .metric_distance(&pos); - let b_dist = b - .get_pos() - .map(|x| (x * CHUNK_SIZE_I) as f32 + CHUNK_SIZE_I as f32 / 2.) - .metric_distance(&pos); - b_dist.total_cmp(&a_dist) - }); - - chunks - } - - /// Return the block type of the block at the given position in world blocks space - pub fn get_block_in_world(&self, pos: Vector3) -> Option { - let chunk_pos = Vector3::new( - div_floor(pos.x, CHUNK_SIZE_I), - div_floor(pos.y, CHUNK_SIZE_I), - div_floor(pos.z, CHUNK_SIZE_I), - ); - self.get_chunk_at_pos(chunk_pos) - .map(|chunk| chunk.get_at_unchecked(get_chunk_local_coords(pos))) - } - - /// Request the regeneration of the chunk mesh if this chunk is already loaded - pub fn request_mesh_regen_if_exists(&mut self, pos: Vector3) { - if let Some(chunk) = self.get_chunk_at_pos_mut(pos) { - chunk.need_new_mesh = true; - } - } - - /// Set the block type of the block at the given position in world blocks space. Regenerate chunk mesh if needed - pub fn set_block_in_world(&mut self, pos: Vector3, block_type: BlockType) -> bool { - let chunk_pos = Vector3::new( - div_floor(pos.x, CHUNK_SIZE_I), - div_floor(pos.y, CHUNK_SIZE_I), - div_floor(pos.z, CHUNK_SIZE_I), - ); - if let Some(chunk) = self.get_chunk_at_pos_mut(chunk_pos) { - let local_pos = get_chunk_local_coords(pos); - if chunk.set_at(local_pos.map(|x| x as usize), block_type) { - chunk.need_new_mesh = true; - - if local_pos.x == 0 { - self.request_mesh_regen_if_exists(chunk_pos + Vector3::new(-1, 0, 0)); - } - if local_pos.x == CHUNK_SIZE_I - 1 { - self.request_mesh_regen_if_exists(chunk_pos + Vector3::new(1, 0, 0)); - } - if local_pos.y == 0 { - self.request_mesh_regen_if_exists(chunk_pos + Vector3::new(0, -1, 0)); - } - if local_pos.y == CHUNK_SIZE_I - 1 { - self.request_mesh_regen_if_exists(chunk_pos + Vector3::new(0, 1, 0)); - } - if local_pos.z == 0 { - self.request_mesh_regen_if_exists(chunk_pos + Vector3::new(0, 0, -1)); - } - if local_pos.z == CHUNK_SIZE_I - 1 { - self.request_mesh_regen_if_exists(chunk_pos + Vector3::new(0, 0, 1)); - } - true - } else { - false - } - } else { - false - } - } - - /// Generate the chunks around the given position The position is in global blocks space, not world chunk space - pub fn generate_world_around_pos( - &mut self, - pos: Vector3, - render_distance: isize, - world_generator: &mut WorldGenerator, - ) { - // Convert global block space coordinates to chnuk space - let pos_chunk_coords = Vector3::new( - roundf(pos.x / CHUNK_SIZE as f32) as isize, - roundf(pos.y / CHUNK_SIZE as f32) as isize, - roundf(pos.z / CHUNK_SIZE as f32) as isize, - ); - - // Unload chunks that are no longer in the view distance - self.chunks.retain(|chunk| { - let relative_chunk_pos = chunk.get_pos() - pos_chunk_coords; - !(relative_chunk_pos.x < -render_distance - || relative_chunk_pos.x >= render_distance - || relative_chunk_pos.y < -render_distance - || relative_chunk_pos.y >= render_distance - || relative_chunk_pos.z < -render_distance - || relative_chunk_pos.z >= render_distance) - }); - - // Load chunks around - for x in -render_distance..render_distance { - for y in -render_distance..render_distance { - for z in -render_distance..render_distance { - let chunk_pos: Vector3 = Vector3::new(x, y, z) + pos_chunk_coords; - - // Prevent creating chunks that already exist - if !self.get_chunk_exists_at(chunk_pos) { - self.add_chunk(chunk_pos); - - world_generator.generate_chunk(self, chunk_pos); - - // Reload chunks around this chunk to prevent mesh gap issues - self.request_mesh_regen_if_exists(chunk_pos + Vector3::new(-1, 0, 0)); - self.request_mesh_regen_if_exists(chunk_pos + Vector3::new(1, 0, 0)); - self.request_mesh_regen_if_exists(chunk_pos + Vector3::new(0, -1, 0)); - self.request_mesh_regen_if_exists(chunk_pos + Vector3::new(0, 1, 0)); - self.request_mesh_regen_if_exists(chunk_pos + Vector3::new(0, 0, -1)); - self.request_mesh_regen_if_exists(chunk_pos + Vector3::new(0, 0, 1)); - } - } - } - } - - // Generate or regenerate mesh if needed - self.check_mesh_regeneration(); - } - - pub fn check_mesh_regeneration(&mut self) { - for i in 0..self.chunks.len() { - if self.chunks[i].need_new_mesh { - let new_mesh = Mesh::generate_chunk(self, &self.chunks[i]); - self.chunks[i].set_mesh(new_mesh); - } - } - } -} diff --git a/apps/Numcraft/src/world/structures.rs b/apps/Numcraft/src/world/structures.rs deleted file mode 100644 index a7122f61..00000000 --- a/apps/Numcraft/src/world/structures.rs +++ /dev/null @@ -1,32 +0,0 @@ -use nalgebra::Vector3; - -use crate::constants::BlockType; - -pub struct Structure { - pub size: Vector3, - data: &'static [u8], -} - -impl Structure { - pub const fn new(data: &'static [u8]) -> Self { - let struct_data = data.split_at(3); - Structure { - size: Vector3::new( - u8::from_be_bytes([data[0]]), - u8::from_be_bytes([data[1]]), - u8::from_be_bytes([data[2]]), - ), - data: &struct_data.1, - } - } - - pub fn get_block_at(&self, pos: Vector3) -> Option { - BlockType::get_from_id( - self.data[pos.x as usize - + pos.z as usize * self.size.x as usize - + pos.y as usize * self.size.z as usize * self.size.x as usize], - ) - } -} - -pub const TREE1: Structure = Structure::new(include_bytes!("../../target/structs/tree1.bin")); diff --git a/apps/Numcraft/src/world/world_generator.rs b/apps/Numcraft/src/world/world_generator.rs deleted file mode 100644 index 5002417b..00000000 --- a/apps/Numcraft/src/world/world_generator.rs +++ /dev/null @@ -1,157 +0,0 @@ -use fastnoise_lite::FastNoiseLite; -use libm::roundf; -use nalgebra::Vector3; -use rand_core::{RngCore, SeedableRng}; -use rand_xorshift::XorShiftRng; - -use crate::{ - constants::world::*, - world::{ - chunk_manager::ChunksManager, - structures::{Structure, TREE1}, - }, -}; - -const CHUNK_SIZE_I: isize = CHUNK_SIZE as isize; - -pub struct WorldGenerator { - noise: FastNoiseLite, -} - -impl WorldGenerator { - pub fn new() -> Self { - let mut noise = FastNoiseLite::new(); - noise.set_noise_type(Some(fastnoise_lite::NoiseType::OpenSimplex2)); - WorldGenerator { noise } - } - - pub fn set_seed(&mut self, seed: i32) { - self.noise.set_seed(Some(seed)); - } - - pub fn generate_chunk( - &mut self, - chunks_manager: &mut ChunksManager, - chunk_pos: Vector3, - ) { - let chunk = chunks_manager.get_chunk_at_pos_mut(chunk_pos).unwrap(); // I assume that a valid pos is given to the generator - - if chunk.generated { - return; - } - chunk.generated = true; - - let chunk_block_pos = chunk_pos * CHUNK_SIZE_I; - - let mut height_map = [0isize; CHUNK_SIZE * CHUNK_SIZE]; - - for x in 0..CHUNK_SIZE { - for z in 0..CHUNK_SIZE { - let negative_1_to_1 = self.noise.get_noise_2d( - (x as isize + chunk_block_pos.x) as f32, - (z as isize + chunk_block_pos.z) as f32, - ); - let height = roundf((negative_1_to_1 + 1.) / 2. * 14.0 - 2.0) as isize; - - height_map[x + z * CHUNK_SIZE] = height; - } - } - - for x in 0..CHUNK_SIZE_I { - for z in 0..CHUNK_SIZE_I { - let height = height_map[x as usize + z as usize * CHUNK_SIZE]; - - for y in 0..CHUNK_SIZE_I { - let block_y = chunk_block_pos.y + y; - - if block_y == height { - chunk.set_at( - Vector3::new(x as usize, y as usize, z as usize), - crate::constants::BlockType::Grass, - ); - } - - if block_y < height && block_y >= height - 3 { - chunk.set_at( - Vector3::new(x as usize, y as usize, z as usize), - crate::constants::BlockType::Dirt, - ); - } - - if block_y < height - 3 { - chunk.set_at( - Vector3::new(x as usize, y as usize, z as usize), - crate::constants::BlockType::Stone, - ); - } - } - } - } - - // Generate a pseudo random seed - let seed = ((chunk_pos.x as i64 + 2147483648) * 1000 - + (chunk_pos.y as i64 + 2147483648) * 1000000 - + (chunk_pos.z as i64 + 2147483648) * 1000000000 - + (self.noise.seed as i64 + 2147483648)) as u64; - let mut rng = XorShiftRng::seed_from_u64(seed); - - for x in 0..CHUNK_SIZE_I { - for z in 0..CHUNK_SIZE_I { - let world_pos = Vector3::new( - x + chunk_block_pos.x, - height_map[x as usize + z as usize * CHUNK_SIZE] + 1, - z + chunk_block_pos.z, - ); - if rng.next_u32() < u32::MAX / 64 { - self.place_struct_check_space( - chunks_manager, - &TREE1, - world_pos - Vector3::new(1, 0, 1), - Vector3::new(1, 0, 1), - ); - } - } - } - } - - /// Place a structure only if there is enough space - pub fn place_struct_check_space( - &self, - chunks_manager: &mut ChunksManager, - structure: &'static Structure, - pos: Vector3, - margins: Vector3, - ) { - for y in (-margins.y)..structure.size.y as isize + margins.y { - for x in (-margins.x)..structure.size.x as isize + margins.x { - for z in (-margins.z)..structure.size.z as isize + margins.z { - if !chunks_manager - .get_block_in_world(pos + Vector3::new(x as isize, y as isize, z as isize)) - .is_none_or(|b| b.is_air()) - { - return; - } - } - } - } - self.place_struct(chunks_manager, structure, pos); - } - - pub fn place_struct( - &self, - chunks_manager: &mut ChunksManager, - structure: &'static Structure, - pos: Vector3, - ) { - for y in 0..structure.size.y { - for x in 0..structure.size.x { - for z in 0..structure.size.z { - if let Some(block) = structure.get_block_at(Vector3::new(x, y, z)) { - let dest_pos = pos + Vector3::new(x as isize, y as isize, z as isize); - chunks_manager.set_block_in_world(dest_pos, block); - } - } - } - } - } -} diff --git a/apps/Numcraft/structs/tree1.json b/apps/Numcraft/structs/tree1.json deleted file mode 100644 index 3a417b9a..00000000 --- a/apps/Numcraft/structs/tree1.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "tree1", - "size": [ - 3, - 4, - 3 - ], - "data": [ - [ - "xxx", - "xox", - "xxx" - ], - [ - "xxx", - "xox", - "xxx" - ], - [ - "uuu", - "uou", - "uuu" - ], - [ - "xux", - "uuu", - "xux" - ] - ], - "palette": { - "x": 0, - "o": 7, - "u": 8 - } - -} \ No newline at end of file diff --git a/apps/apps.js b/apps/apps.js index 0af859d7..45901817 100644 --- a/apps/apps.js +++ b/apps/apps.js @@ -20,5 +20,6 @@ angular.module('nwas').service('apps', function() { { name: "HoldemPoker", description: {en: "A Texas Hold'em Poker Game", fr: "Un jeu de Texas Hold'em"} }, { name: "Chess", description: {en: "Chess Game", fr: "Jeu d'échecs"} }, { name: "Video", description: {en: "Play mjpeg videos", fr: "Lisez des vidéos mjpeg"} }, + { name: "Numcraft", description: {en: "A 3D cube sandbox game", fr: "Un jeu bac à sable avec des cubes en 3D"} }, ]; });