diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 49f85e5..0797a4b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,22 +2,21 @@ name: Rust CI on: push: - branches: [ "main" , "master"] - paths-ignore: - - '**.md' - - 'docs/**' - - 'LICENSE*' - - '.gitignore' - - '.github/dependabot.yml' - - 'images/**' + branches: [ "main" , "master" ] + paths: + - '**.rs' + - '**.toml' + - '**.lock' + - '.github/**' + - 'build/**' pull_request: - branches: [ "main" , "master"] - paths-ignore: - - '**.md' - - 'LICENSE*' - - '.gitignore' - - '.github/dependabot.yml' - - 'assets/**' + branches: [ "main" , "master" ] + paths: + - '**.rs' + - '**.toml' + - '**.lock' + - '.github/**' + - 'build/**' workflow_dispatch: env: @@ -26,25 +25,39 @@ env: jobs: check: - name: Check, Build and Test + name: Check, Build and Test (${{ matrix.features }}) runs-on: windows-latest + strategy: + fail-fast: false + matrix: + features: + - "default" + - "f128" steps: - name: Checkout sources uses: actions/checkout@v4 - name: Install stable toolchain uses: dtolnay/rust-toolchain@stable - with: - components: rustfmt, clippy - name: Cache dependencies uses: Swatinem/rust-cache@v2 with: - # Cache key based on Cargo.lock and source files - key: ${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('**/*.rs') }} + # Cache key based on Cargo.lock, source files, and features + key: ${{ matrix.features }}-${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('**/*.rs') }} - - name: Build project + - name: Build project (default features) + if: matrix.features == 'default' run: cargo build --workspace --verbose - - name: Run tests - run: cargo test --all-features --workspace --verbose \ No newline at end of file + - name: Build project (with f128) + if: matrix.features == 'f128' + run: cargo build --workspace --features f128 --verbose + + - name: Run tests (default features) + if: matrix.features == 'default' + run: cargo test --workspace --verbose + + - name: Run tests (with f128) + if: matrix.features == 'f128' + run: cargo test --workspace --features f128 --verbose \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b4ef6bf..335a367 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -186,19 +186,24 @@ jobs: build-and-upload: needs: [ get-version, create-tag ] - name: Build & Release for ${{ matrix.target }} on ${{ matrix.os }} + name: Build & Release for ${{ matrix.target }} (${{ matrix.variant }}) on ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: include: -# - { os: ubuntu-latest, target: x86_64-unknown-linux-gnu, cross: false } - - - { os: windows-latest, target: x86_64-pc-windows-msvc, cross: false } - - { os: windows-latest, target: aarch64-pc-windows-msvc, cross: false } - - - { os: macos-latest, target: x86_64-apple-darwin, cross: false } - - { os: macos-latest, target: aarch64-apple-darwin, cross: false } +# - { os: ubuntu-latest, target: x86_64-unknown-linux-gnu, cross: false, variant: "standard" } +# - { os: ubuntu-latest, target: x86_64-unknown-linux-gnu, cross: false, variant: "f128" } + + - { os: windows-latest, target: x86_64-pc-windows-msvc, cross: false, variant: "standard" } + - { os: windows-latest, target: x86_64-pc-windows-msvc, cross: false, variant: "f128" } + - { os: windows-latest, target: aarch64-pc-windows-msvc, cross: false, variant: "standard" } + - { os: windows-latest, target: aarch64-pc-windows-msvc, cross: false, variant: "f128" } + + - { os: macos-latest, target: x86_64-apple-darwin, cross: false, variant: "standard" } + - { os: macos-latest, target: x86_64-apple-darwin, cross: false, variant: "f128" } + - { os: macos-latest, target: aarch64-apple-darwin, cross: false, variant: "standard" } + - { os: macos-latest, target: aarch64-apple-darwin, cross: false, variant: "f128" } steps: - name: Fetch Repository uses: actions/checkout@v4 @@ -231,36 +236,68 @@ jobs: with: target: ${{ matrix.target }} - - name: Build the binary + - name: Build the binary (standard) + if: matrix.variant == 'standard' run: | cargo build --release --target ${{ matrix.target }} - - name: Rename binary (Linux & macOS) - if: ${{ matrix.os != 'windows-latest' }} + - name: Build the binary (f128) + if: matrix.variant == 'f128' + run: | + cargo build --release --target ${{ matrix.target }} --features f128 + + - name: Rename binary (Linux & macOS - standard) + if: ${{ matrix.os != 'windows-latest' && matrix.variant == 'standard' }} run: | mv target/${{ matrix.target }}/release/Fractals-rs target/${{ matrix.target }}/release/Fractals-rs-${{ matrix.target }} - - name: Rename binary (Windows) - if: ${{ matrix.os == 'windows-latest' }} + - name: Rename binary (Linux & macOS - f128) + if: ${{ matrix.os != 'windows-latest' && matrix.variant == 'f128' }} + run: | + mv target/${{ matrix.target }}/release/Fractals-rs target/${{ matrix.target }}/release/Fractals-rs-${{ matrix.target }}-f128 + + - name: Rename binary (Windows - standard) + if: ${{ matrix.os == 'windows-latest' && matrix.variant == 'standard' }} run: | mv target/${{ matrix.target }}/release/Fractals-rs.exe target/${{ matrix.target }}/release/Fractals-rs-${{ matrix.target }}.exe - - name: Upload release binary (Windows) - if: ${{ matrix.os == 'windows-latest' }} + - name: Rename binary (Windows - f128) + if: ${{ matrix.os == 'windows-latest' && matrix.variant == 'f128' }} + run: | + mv target/${{ matrix.target }}/release/Fractals-rs.exe target/${{ matrix.target }}/release/Fractals-rs-${{ matrix.target }}-f128.exe + + - name: Upload release binary (Windows - standard) + if: ${{ matrix.os == 'windows-latest' && matrix.variant == 'standard' }} uses: actions/upload-artifact@v4 with: name: Fractals-rs-${{ matrix.target }}.exe path: target/${{ matrix.target }}/release/Fractals-rs-${{ matrix.target }}.exe compression-level: '9' - - name: Upload release binary (Linux & macOS) - if: ${{ matrix.os != 'windows-latest' }} + - name: Upload release binary (Windows - f128) + if: ${{ matrix.os == 'windows-latest' && matrix.variant == 'f128' }} + uses: actions/upload-artifact@v4 + with: + name: Fractals-rs-${{ matrix.target }}-f128.exe + path: target/${{ matrix.target }}/release/Fractals-rs-${{ matrix.target }}-f128.exe + compression-level: '9' + + - name: Upload release binary (Linux & macOS - standard) + if: ${{ matrix.os != 'windows-latest' && matrix.variant == 'standard' }} uses: actions/upload-artifact@v4 with: name: Fractals-rs-${{ matrix.target }} path: target/${{ matrix.target }}/release/Fractals-rs-${{ matrix.target }} compression-level: '9' + - name: Upload release binary (Linux & macOS - f128) + if: ${{ matrix.os != 'windows-latest' && matrix.variant == 'f128' }} + uses: actions/upload-artifact@v4 + with: + name: Fractals-rs-${{ matrix.target }}-f128 + path: target/${{ matrix.target }}/release/Fractals-rs-${{ matrix.target }}-f128 + compression-level: '9' + upload-release: name: Create GitHub Release runs-on: ubuntu-latest diff --git a/Cargo.lock b/Cargo.lock index 116d76e..2408d5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,20 +4,24 @@ version = 4 [[package]] name = "Fractals-rs" -version = "1.0.2" +version = "1.0.3" dependencies = [ "criterion", "eframe", "egui", "image", + "paste", "rayon", + "rust_decimal", + "rust_decimal_macros", + "wide", ] [[package]] name = "ab_glyph" -version = "0.2.29" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3672c180e71eeaaac3a541fbbc5f5ad4def8b747c595ad30d674e43049f7b0" +checksum = "01c0457472c38ea5bd1c3b5ada5e368271cb550be7a4ca4a0b4634e9913f6cc2" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", @@ -25,9 +29,9 @@ dependencies = [ [[package]] name = "ab_glyph_rasterizer" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" +checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618" [[package]] name = "adler2" @@ -35,6 +39,17 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.16", + "once_cell", + "version_check", +] + [[package]] name = "ahash" version = "0.8.12" @@ -49,13 +64,22 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] +[[package]] +name = "alloca" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7d05ea6aea7e9e64d25b9156ba2fee3fdd659e34e41063cd2fc7cd020d7f4" +dependencies = [ + "cc", +] + [[package]] name = "android-activity" version = "0.6.0" @@ -63,7 +87,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ "android-properties", - "bitflags 2.9.1", + "bitflags 2.10.0", "cc", "cesu8", "jni", @@ -74,7 +98,7 @@ dependencies = [ "ndk-context", "ndk-sys", "num_enum", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -91,30 +115,36 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstyle" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "arboard" -version = "3.5.0" +version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1df21f715862ede32a0c525ce2ca4d52626bb0007f8c18b87a384503ac33e70" +checksum = "0348a1c054491f4bfe6ab86a7b6ab1e44e45d899005de92f58b3df180b36ddaf" dependencies = [ "clipboard-win", "image", "log", - "objc2 0.6.1", - "objc2-app-kit 0.3.1", + "objc2 0.6.3", + "objc2-app-kit 0.3.2", "objc2-core-foundation", "objc2-core-graphics", - "objc2-foundation 0.3.1", + "objc2-foundation 0.3.2", "parking_lot", "percent-encoding", - "windows-sys 0.59.0", + "windows-sys 0.60.2", "x11rb", ] +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "atomic-waker" version = "1.1.2" @@ -123,9 +153,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bitflags" @@ -135,9 +165,21 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] [[package]] name = "block2" @@ -148,30 +190,75 @@ dependencies = [ "objc2 0.5.2", ] +[[package]] +name = "borsh" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" +dependencies = [ + "borsh-derive", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.112", +] + [[package]] name = "bumpalo" -version = "3.18.1" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] [[package]] name = "bytemuck" -version = "1.23.1" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.9.3" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.112", ] [[package]] @@ -182,9 +269,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" [[package]] name = "calloop" @@ -192,22 +279,35 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "log", "polling", "rustix 0.38.44", "slab", - "thiserror", + "thiserror 1.0.69", +] + +[[package]] +name = "calloop" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb9f6e1368bd4621d2c86baa7e37de77a938adf5221e5dd3d6133340101b309e" +dependencies = [ + "bitflags 2.10.0", + "polling", + "rustix 1.1.3", + "slab", + "tracing", ] [[package]] name = "calloop-wayland-source" -version = "0.3.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" +checksum = "138efcf0940a02ebf0cc8d1eff41a1682a46b431630f4c52450d6265876021fa" dependencies = [ - "calloop", - "rustix 0.38.44", + "calloop 0.14.3", + "rustix 1.1.3", "wayland-backend", "wayland-client", ] @@ -220,10 +320,11 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.26" +version = "1.2.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac" +checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", @@ -237,9 +338,9 @@ checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -285,18 +386,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.40" +version = "4.5.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" +checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.40" +version = "4.5.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" +checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" dependencies = [ "anstyle", "clap_lex", @@ -304,15 +405,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "clipboard-win" -version = "5.4.0" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" +checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4" dependencies = [ "error-code", ] @@ -388,19 +489,20 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] [[package]] name = "criterion" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1c047a62b0cc3e145fa84415a3191f628e980b194c2755aa12300a4e6cbd928" +checksum = "4d883447757bb0ee46f233e9dc22eb84d93a9508c9b868687b274fc431d886bf" dependencies = [ + "alloca", "anes", "cast", "ciborium", @@ -409,6 +511,7 @@ dependencies = [ "itertools", "num-traits", "oorandom", + "page_size", "plotters", "rayon", "regex", @@ -420,9 +523,9 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.6.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b1bcc0dc7dfae599d84ad0b1a55f80cde8af3725da8313b528da95ef783e338" +checksum = "ed943f81ea2faa8dcecbbfa50164acf95d555afec96a27871663b300e387b2e4" dependencies = [ "cast", "itertools", @@ -455,9 +558,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "cursor-icon" @@ -477,8 +580,8 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" dependencies = [ - "bitflags 2.9.1", - "objc2 0.6.1", + "bitflags 2.10.0", + "objc2 0.6.3", ] [[package]] @@ -489,7 +592,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.112", ] [[package]] @@ -503,9 +606,9 @@ dependencies = [ [[package]] name = "document-features" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" dependencies = [ "litrs", ] @@ -524,9 +627,9 @@ checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" [[package]] name = "ecolor" -version = "0.32.3" +version = "0.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94bdf37f8d5bd9aa7f753573fdda9cf7343afa73dd28d7bfe9593bd9798fc07e" +checksum = "71ddb8ac7643d1dba1bb02110e804406dd459a838efcb14011ced10556711a8e" dependencies = [ "bytemuck", "emath", @@ -534,11 +637,11 @@ dependencies = [ [[package]] name = "eframe" -version = "0.32.3" +version = "0.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14d1c15e7bd136b309bd3487e6ffe5f668b354cd9768636a836dd738ac90eb0b" +checksum = "457481173e6db5ca9fa2be93a58df8f4c7be639587aeb4853b526c6cf87db4e6" dependencies = [ - "ahash", + "ahash 0.8.12", "bytemuck", "document-features", "egui", @@ -562,19 +665,18 @@ dependencies = [ "wasm-bindgen-futures", "web-sys", "web-time", - "winapi", - "windows-sys 0.59.0", + "windows-sys 0.61.2", "winit", ] [[package]] name = "egui" -version = "0.32.3" +version = "0.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5d0306cd61ca75e29682926d71f2390160247f135965242e904a636f51c0dc" +checksum = "6a9b567d356674e9a5121ed3fedfb0a7c31e059fe71f6972b691bcd0bfc284e3" dependencies = [ - "ahash", - "bitflags 2.9.1", + "ahash 0.8.12", + "bitflags 2.10.0", "emath", "epaint", "log", @@ -586,15 +688,17 @@ dependencies = [ [[package]] name = "egui-winit" -version = "0.32.3" +version = "0.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f95d0a91f9cb0dc2e732d49c2d521ac8948e1f0b758f306fb7b14d6f5db3927f" +checksum = "ec6687e5bb551702f4ad10ac428bab12acf9d53047ebb1082d4a0ed8c6251a29" dependencies = [ - "ahash", "arboard", "bytemuck", "egui", "log", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-ui-kit", "profiling", "raw-window-handle", "smithay-clipboard", @@ -605,11 +709,10 @@ dependencies = [ [[package]] name = "egui_glow" -version = "0.32.3" +version = "0.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7037813341727937f9e22f78d912f3e29bc3c46e2f40a9e82bb51cbf5e4cfb" +checksum = "6420863ea1d90e750f75075231a260030ad8a9f30a7cef82cdc966492dc4c4eb" dependencies = [ - "ahash", "bytemuck", "egui", "glow", @@ -628,21 +731,21 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "emath" -version = "0.32.3" +version = "0.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45fd7bc25f769a3c198fe1cf183124bf4de3bd62ef7b4f1eaf6b08711a3af8db" +checksum = "491bdf728bf25ddd9ad60d4cf1c48588fa82c013a2440b91aa7fc43e34a07c32" dependencies = [ "bytemuck", ] [[package]] name = "epaint" -version = "0.32.3" +version = "0.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63adcea970b7a13094fe97a36ab9307c35a750f9e24bf00bb7ef3de573e0fddb" +checksum = "009d0dd3c2163823a0abdb899451ecbc78798dec545ee91b43aff1fa790bab62" dependencies = [ "ab_glyph", - "ahash", + "ahash 0.8.12", "bytemuck", "ecolor", "emath", @@ -655,9 +758,9 @@ dependencies = [ [[package]] name = "epaint_default_fonts" -version = "0.32.3" +version = "0.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1537accc50c9cab5a272c39300bdd0dd5dca210f6e5e8d70be048df9596e7ca2" +checksum = "5c4fbe202b6578d3d56428fa185cdf114a05e49da05f477b3c7f0fbb221f1862" [[package]] name = "equivalent" @@ -667,12 +770,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.12" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -698,7 +801,7 @@ checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.112", ] [[package]] @@ -710,11 +813,17 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" + [[package]] name = "flate2" -version = "1.1.2" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" dependencies = [ "crc32fast", "miniz_oxide", @@ -738,7 +847,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.112", ] [[package]] @@ -749,33 +858,50 @@ checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "gethostname" -version = "0.4.3" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" +dependencies = [ + "rustix 1.1.3", + "windows-link", +] + +[[package]] +name = "getrandom" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ + "cfg-if", "libc", - "windows-targets 0.48.5", + "wasi", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", "r-efi", - "wasi", + "wasip2", ] [[package]] @@ -807,17 +933,17 @@ version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12124de845cacfebedff80e877bb37b5b75c34c5a4c89e47e1cdd67fb6041325" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "cfg_aliases", "cgl", "dispatch2", "glutin_egl_sys", "glutin_wgl_sys", "libloading", - "objc2 0.6.1", - "objc2-app-kit 0.3.1", + "objc2 0.6.3", + "objc2-app-kit 0.3.2", "objc2-core-foundation", - "objc2-foundation 0.3.1", + "objc2-foundation 0.3.2", "once_cell", "raw-window-handle", "windows-sys 0.52.0", @@ -856,40 +982,41 @@ dependencies = [ [[package]] name = "half" -version = "2.6.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", + "zerocopy", ] [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] [[package]] -name = "hermit-abi" -version = "0.5.2" +name = "hashbrown" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] -name = "home" -version = "0.5.11" +name = "hermit-abi" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" -dependencies = [ - "windows-sys 0.59.0", -] +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -900,9 +1027,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -913,11 +1040,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -928,42 +1054,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -973,9 +1095,9 @@ dependencies = [ [[package]] name = "idna" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", @@ -994,9 +1116,9 @@ dependencies = [ [[package]] name = "image" -version = "0.25.8" +version = "0.25.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "529feb3e6769d234375c4cf1ee2ce713682b8e76538cb13f9fc23e1400a591e7" +checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a" dependencies = [ "bytemuck", "byteorder-lite", @@ -1004,18 +1126,18 @@ dependencies = [ "num-traits", "png", "tiff", - "zune-core", - "zune-jpeg", + "zune-core 0.5.0", + "zune-jpeg 0.5.8", ] [[package]] name = "indexmap" -version = "2.9.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.16.1", ] [[package]] @@ -1029,9 +1151,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "jni" @@ -1044,7 +1166,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror", + "thiserror 1.0.69", "walkdir", "windows-sys 0.45.0", ] @@ -1057,19 +1179,19 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom", + "getrandom 0.3.4", "libc", ] [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" dependencies = [ "once_cell", "wasm-bindgen", @@ -1083,29 +1205,29 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" [[package]] name = "libc" -version = "0.2.172" +version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "libloading" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-targets 0.53.2", + "windows-link", ] [[package]] name = "libredox" -version = "0.1.3" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "libc", - "redox_syscall 0.5.13", + "redox_syscall 0.7.0", ] [[package]] @@ -1116,49 +1238,48 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" -version = "0.9.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "litrs" -version = "0.4.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.27" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "memmap2" -version = "0.9.5" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" +checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490" dependencies = [ "libc", ] @@ -1184,9 +1305,9 @@ dependencies = [ [[package]] name = "moxcms" -version = "0.7.5" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd32fa8935aeadb8a8a6b6b351e40225570a37c43de67690383d87ef170cd08" +checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97" dependencies = [ "num-traits", "pxfm", @@ -1198,13 +1319,13 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "jni-sys", "log", "ndk-sys", "num_enum", "raw-window-handle", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1239,23 +1360,24 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" dependencies = [ "num_enum_derive", + "rustversion", ] [[package]] name = "num_enum_derive" -version = "0.7.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.112", ] [[package]] @@ -1276,9 +1398,9 @@ dependencies = [ [[package]] name = "objc2" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551" +checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" dependencies = [ "objc2-encode", ] @@ -1289,7 +1411,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "block2", "libc", "objc2 0.5.2", @@ -1301,15 +1423,15 @@ dependencies = [ [[package]] name = "objc2-app-kit" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" +checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ - "bitflags 2.9.1", - "objc2 0.6.1", + "bitflags 2.10.0", + "objc2 0.6.3", "objc2-core-foundation", "objc2-core-graphics", - "objc2-foundation 0.3.1", + "objc2-foundation 0.3.2", ] [[package]] @@ -1318,7 +1440,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "block2", "objc2 0.5.2", "objc2-core-location", @@ -1342,7 +1464,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -1350,24 +1472,24 @@ dependencies = [ [[package]] name = "objc2-core-foundation" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "dispatch2", - "objc2 0.6.1", + "objc2 0.6.3", ] [[package]] name = "objc2-core-graphics" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4" +checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "dispatch2", - "objc2 0.6.1", + "objc2 0.6.3", "objc2-core-foundation", "objc2-io-surface", ] @@ -1408,7 +1530,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "block2", "dispatch", "libc", @@ -1417,23 +1539,23 @@ dependencies = [ [[package]] name = "objc2-foundation" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.9.1", - "objc2 0.6.1", + "bitflags 2.10.0", + "objc2 0.6.3", "objc2-core-foundation", ] [[package]] name = "objc2-io-surface" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7282e9ac92529fa3457ce90ebb15f4ecbc383e8338060960760fa2cf75420c3c" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" dependencies = [ - "bitflags 2.9.1", - "objc2 0.6.1", + "bitflags 2.10.0", + "objc2 0.6.3", "objc2-core-foundation", ] @@ -1455,7 +1577,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -1467,7 +1589,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -1490,7 +1612,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "block2", "objc2 0.5.2", "objc2-cloud-kit", @@ -1522,7 +1644,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "block2", "objc2 0.5.2", "objc2-core-location", @@ -1543,27 +1665,37 @@ checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "orbclient" -version = "0.3.48" +version = "0.3.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba0b26cec2e24f08ed8bb31519a9333140a6599b867dac464bb150bdb796fd43" +checksum = "247ad146e19b9437f8604c21f8652423595cf710ad108af40e77d3ae6e96b827" dependencies = [ "libredox", ] [[package]] name = "owned_ttf_parser" -version = "0.25.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec719bbf3b2a81c109a4e20b1f129b5566b7dce654bc3872f6a05abf82b2c4" +checksum = "36820e9051aca1014ddc75770aab4d68bc1e9e632f0f5627c4086bc216fb583b" dependencies = [ "ttf-parser", ] +[[package]] +name = "page_size" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -1571,22 +1703,28 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.13", + "redox_syscall 0.5.18", "smallvec", - "windows-targets 0.52.6", + "windows-link", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pin-project" @@ -1605,7 +1743,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.112", ] [[package]] @@ -1654,7 +1792,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "crc32fast", "fdeflate", "flate2", @@ -1663,57 +1801,85 @@ dependencies = [ [[package]] name = "polling" -version = "3.8.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b53a684391ad002dd6a596ceb6c74fd004fdce75f4be2e3f615068abbea5fd50" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" dependencies = [ "cfg-if", "concurrent-queue", "hermit-abi", "pin-project-lite", - "rustix 1.0.7", - "tracing", - "windows-sys 0.59.0", + "rustix 1.1.3", + "windows-sys 0.61.2", ] [[package]] name = "potential_utf" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] +[[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-macro-crate" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "9695f8df41bb4f3d222c95a67532365f569318332d03d5f3f67f37b20e6ebdf0" dependencies = [ "unicode-ident", ] [[package]] name = "profiling" -version = "1.0.16" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" + +[[package]] +name = "ptr_meta" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] [[package]] name = "pxfm" -version = "0.1.23" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55f4fedc84ed39cb7a489322318976425e42a147e2be79d8f878e2884f94e84" +checksum = "7186d3822593aa4393561d186d1393b3923e9d6163d3fbfd6e825e3e6cf3e6a8" dependencies = [ "num-traits", ] @@ -1726,27 +1892,63 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quick-xml" -version = "0.37.5" +version = "0.38.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" +checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" dependencies = [ "memchr", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] [[package]] name = "r-efi" -version = "5.2.0" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "radium" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[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", +] + +[[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", +] + +[[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 = "raw-window-handle" @@ -1785,18 +1987,27 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.13" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.10.0", +] + +[[package]] +name = "redox_syscall" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" +checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", ] [[package]] name = "regex" -version = "1.11.1" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -1806,9 +2017,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -1817,9 +2028,73 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "rkyv" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rust_decimal" +version = "1.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35affe401787a9bd846712274d97654355d21b2a2c092a3139aabe31e9022282" +dependencies = [ + "arrayvec", + "borsh", + "bytes", + "num-traits", + "rand", + "rkyv", + "serde", + "serde_json", +] + +[[package]] +name = "rust_decimal_macros" +version = "1.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8c0cb48f413ebe24dc2d148788e0efbe09ba3e011d9277162f2eaf8e1069a3" +dependencies = [ + "quote", + "syn 2.0.112", +] [[package]] name = "rustix" @@ -1827,7 +2102,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "errno", "libc", "linux-raw-sys 0.4.15", @@ -1836,28 +2111,31 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.7" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "errno", "libc", - "linux-raw-sys 0.9.4", - "windows-sys 0.59.0", + "linux-raw-sys 0.11.0", + "windows-sys 0.61.2", ] [[package]] name = "rustversion" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] -name = "ryu" -version = "1.0.20" +name = "safe_arch" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "1f7caad094bd561859bcd467734a720c3c1f5d1f338995351fefe2190c45efed" +dependencies = [ + "bytemuck", +] [[package]] name = "same-file" @@ -1880,36 +2158,53 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + [[package]] name = "serde" -version = "1.0.219" +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 = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.112", ] [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.148" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "3084b546a1dd6289475996f182a22aba973866ea8e8b02c51d9f46b1336a22da" dependencies = [ "itoa", "memchr", - "ryu", "serde", + "serde_core", + "zmij", ] [[package]] @@ -1920,24 +2215,27 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "simd-adler32" -version = "0.3.7" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" + +[[package]] +name = "simdutf8" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "slab" -version = "0.4.9" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "slotmap" -version = "1.0.7" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" dependencies = [ "version_check", ] @@ -1950,24 +2248,26 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "smithay-client-toolkit" -version = "0.19.2" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" +checksum = "0512da38f5e2b31201a93524adb8d3136276fa4fe4aafab4e1f727a82b534cc0" dependencies = [ - "bitflags 2.9.1", - "calloop", + "bitflags 2.10.0", + "calloop 0.14.3", "calloop-wayland-source", "cursor-icon", "libc", "log", "memmap2", - "rustix 0.38.44", - "thiserror", + "rustix 1.1.3", + "thiserror 2.0.17", "wayland-backend", "wayland-client", "wayland-csd-frame", "wayland-cursor", "wayland-protocols", + "wayland-protocols-experimental", + "wayland-protocols-misc", "wayland-protocols-wlr", "wayland-scanner", "xkeysym", @@ -1975,9 +2275,9 @@ dependencies = [ [[package]] name = "smithay-clipboard" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc8216eec463674a0e90f29e0ae41a4db573ec5b56b1c6c1c71615d249b6d846" +checksum = "71704c03f739f7745053bde45fa203a46c58d25bc5c4efba1d9a60e9dba81226" dependencies = [ "libc", "smithay-client-toolkit", @@ -1995,9 +2295,9 @@ dependencies = [ [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "static_assertions" @@ -2007,9 +2307,20 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "syn" -version = "2.0.103" +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.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" +checksum = "21f182278bf2d2bcb3c88b1b08a37df029d71ce3d3ae26168e3c653b213b99d4" dependencies = [ "proc-macro2", "quote", @@ -2024,16 +2335,31 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.112", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "thiserror" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl 2.0.17", ] [[package]] @@ -2044,7 +2370,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.112", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.112", ] [[package]] @@ -2058,14 +2395,14 @@ dependencies = [ "half", "quick-error", "weezl", - "zune-jpeg", + "zune-jpeg 0.4.21", ] [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -2081,38 +2418,67 @@ dependencies = [ "serde_json", ] +[[package]] +name = "tinyvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "toml_datetime" -version = "0.6.11" +version = "0.7.5+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] [[package]] name = "toml_edit" -version = "0.22.27" +version = "0.23.10+spec-1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" dependencies = [ "indexmap", "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +dependencies = [ "winnow", ] [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ + "log", "pin-project-lite", "tracing-core", ] [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" [[package]] name = "ttf-parser" @@ -2122,9 +2488,9 @@ checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-segmentation" @@ -2134,13 +2500,14 @@ checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "url" -version = "2.5.4" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -2149,6 +2516,16 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "uuid" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "version_check" version = "0.9.5" @@ -2167,56 +2544,50 @@ dependencies = [ [[package]] name = "wasi" -version = "0.14.2+wasi-0.2.4" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" 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", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.45" +version = "0.4.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2224,35 +2595,35 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn", - "wasm-bindgen-backend", + "syn 2.0.112", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" dependencies = [ "unicode-ident", ] [[package]] name = "wayland-backend" -version = "0.3.10" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe770181423e5fc79d3e2a7f4410b7799d5aab1de4372853de3c6aa13ca24121" +checksum = "fee64194ccd96bf648f42a65a7e589547096dfa702f7cadef84347b66ad164f9" dependencies = [ "cc", "downcast-rs", - "rustix 0.38.44", + "rustix 1.1.3", "scoped-tls", "smallvec", "wayland-sys", @@ -2260,12 +2631,12 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.10" +version = "0.31.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978fa7c67b0847dbd6a9f350ca2569174974cd4082737054dbb7fbb79d7d9a61" +checksum = "b8e6faa537fbb6c186cb9f1d41f2f811a4120d1b57ec61f50da451a0c5122bec" dependencies = [ - "bitflags 2.9.1", - "rustix 0.38.44", + "bitflags 2.10.0", + "rustix 1.1.3", "wayland-backend", "wayland-scanner", ] @@ -2276,41 +2647,67 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "cursor-icon", "wayland-backend", ] [[package]] name = "wayland-cursor" -version = "0.31.10" +version = "0.31.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a65317158dec28d00416cb16705934070aef4f8393353d41126c54264ae0f182" +checksum = "5864c4b5b6064b06b1e8b74ead4a98a6c45a285fe7a0e784d24735f011fdb078" dependencies = [ - "rustix 0.38.44", + "rustix 1.1.3", "wayland-client", "xcursor", ] [[package]] name = "wayland-protocols" -version = "0.32.8" +version = "0.32.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baeda9ffbcfc8cd6ddaade385eaf2393bd2115a69523c735f12242353c3df4f3" +dependencies = [ + "bitflags 2.10.0", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-experimental" +version = "20250721.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "779075454e1e9a521794fed15886323ea0feda3f8b0fc1390f5398141310422a" +checksum = "40a1f863128dcaaec790d7b4b396cc9b9a7a079e878e18c47e6c2d2c5a8dcbb1" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "wayland-backend", "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-misc" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791c58fdeec5406aa37169dd815327d1e47f334219b523444bc26d70ceb4c34e" +dependencies = [ + "bitflags 2.10.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", "wayland-scanner", ] [[package]] name = "wayland-protocols-wlr" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cb6cdc73399c0e06504c437fe3cf886f25568dd5454473d565085b36d6a8bbf" +checksum = "e9597cdf02cf0c34cd5823786dce6b5ae8598f05c2daf5621b6e178d4f7345f3" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -2319,9 +2716,9 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.31.6" +version = "0.31.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484" +checksum = "5423e94b6a63e68e439803a3e153a9252d5ead12fd853334e2ad33997e3889e3" dependencies = [ "proc-macro2", "quick-xml", @@ -2330,9 +2727,9 @@ dependencies = [ [[package]] name = "wayland-sys" -version = "0.31.6" +version = "0.31.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbcebb399c77d5aa9fa5db874806ee7b4eba4e73650948e8f93963f128896615" +checksum = "1e6dbfc3ac5ef974c92a2235805cc0114033018ae1290a72e474aa8b28cbbdfd" dependencies = [ "dlib", "log", @@ -2342,9 +2739,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" dependencies = [ "js-sys", "wasm-bindgen", @@ -2362,26 +2759,35 @@ dependencies = [ [[package]] name = "webbrowser" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5df295f8451142f1856b1bd86a606dfe9587d439bc036e319c827700dbd555e" +checksum = "00f1243ef785213e3a32fa0396093424a3a6ea566f9948497e5a2309261a4c97" dependencies = [ "core-foundation 0.10.1", - "home", "jni", "log", "ndk-context", - "objc2 0.6.1", - "objc2-foundation 0.3.1", + "objc2 0.6.3", + "objc2-foundation 0.3.2", "url", "web-sys", ] [[package]] name = "weezl" -version = "0.1.10" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" + +[[package]] +name = "wide" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" +checksum = "ac11b009ebeae802ed758530b6496784ebfee7a87b9abfbcaf3bbe25b814eb25" +dependencies = [ + "bytemuck", + "safe_arch", +] [[package]] name = "winapi" @@ -2401,11 +2807,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2414,6 +2820,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + [[package]] name = "windows-sys" version = "0.45.0" @@ -2441,6 +2853,24 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -2456,21 +2886,6 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - [[package]] name = "windows-targets" version = "0.52.6" @@ -2489,18 +2904,19 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.2" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -2509,12 +2925,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -2523,9 +2933,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -2533,12 +2943,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -2547,9 +2951,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -2557,12 +2961,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -2571,9 +2969,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" @@ -2583,9 +2981,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -2593,12 +2991,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -2607,9 +2999,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -2617,12 +3009,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -2631,9 +3017,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -2641,12 +3027,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -2655,9 +3035,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -2665,12 +3045,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -2679,9 +3053,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winit" @@ -2691,9 +3065,9 @@ checksum = "c66d4b9ed69c4009f6321f762d6e61ad8a2389cd431b97cb1e146812e9e6c732" dependencies = [ "android-activity", "atomic-waker", - "bitflags 2.9.1", + "bitflags 2.10.0", "block2", - "calloop", + "calloop 0.13.0", "cfg_aliases", "concurrent-queue", "core-foundation 0.9.4", @@ -2725,50 +3099,56 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.11" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" dependencies = [ "memchr", ] [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags 2.9.1", -] +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] [[package]] name = "x11rb" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" +checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414" dependencies = [ "gethostname", - "rustix 0.38.44", + "rustix 1.1.3", "x11rb-protocol", ] [[package]] name = "x11rb-protocol" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" +checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" [[package]] name = "xcursor" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef33da6b1660b4ddbfb3aef0ade110c8b8a781a3b6382fa5f2b5b040fd55f61" +checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b" [[package]] name = "xkbcommon-dl" @@ -2776,7 +3156,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "dlib", "log", "once_cell", @@ -2791,17 +3171,16 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" [[package]] name = "xml-rs" -version = "0.8.26" +version = "0.8.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62ce76d9b56901b19a74f19431b0d8b3bc7ca4ad685a746dfd78ca8f4fc6bda" +checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -2809,34 +3188,34 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.112", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.25" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.25" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.112", ] [[package]] @@ -2856,15 +3235,15 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.112", "synstructure", ] [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -2873,9 +3252,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.2" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -2884,26 +3263,47 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.112", ] +[[package]] +name = "zmij" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de9211a9f64b825911bdf0240f58b7a8dac217fe260fc61f080a07f61372fbd5" + [[package]] name = "zune-core" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" +[[package]] +name = "zune-core" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "111f7d9820f05fd715df3144e254d6fc02ee4088b0644c0ffd0efc9e6d9d2773" + +[[package]] +name = "zune-jpeg" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" +dependencies = [ + "zune-core 0.4.12", +] + [[package]] name = "zune-jpeg" -version = "0.4.17" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f6fe2e33d02a98ee64423802e16df3de99c43e5cf5ff983767e1128b394c8ac" +checksum = "e35aee689668bf9bd6f6f3a6c60bb29ba1244b3b43adfd50edd554a371da37d5" dependencies = [ - "zune-core", + "zune-core 0.5.0", ] diff --git a/Cargo.toml b/Cargo.toml index 1168150..e873af9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "Fractals-rs" -version = "1.0.2" +version = "1.0.3" edition = "2024" description = "A simple fractal viewer written in Rust using eframe and egui" keywords = ["fractals", "egui", "eframe", "rust", "gui"] @@ -14,13 +14,21 @@ name = "fractals_rs" path = "src/lib.rs" [dependencies] -eframe = { version = "0.32.2", default-features = false, features = ["default_fonts", "glow"] } -egui = { version = "0.32.2", default-features = false, features = ["default_fonts"] } +eframe = { version = "0.33.3", default-features = false, features = ["default_fonts", "glow"] } +egui = { version = "0.33.3", default-features = false, features = ["default_fonts"] } rayon = "1.11.0" image = { version = "0.25.8", default-features = false, features = ["png", "jpeg"] } +rust_decimal = { version = "1.39.0", optional = true } +rust_decimal_macros = { version = "1.39.0", optional = true } +paste = "1.0" +wide = "1.1.1" [dev-dependencies] -criterion = "0.7.0" +criterion = "0.8.1" + +[features] +default = [] # Default feature +f128 = ["rust_decimal", "rust_decimal_macros"] # Feature to enable f128 precision [profile.dev] opt-level = 0 @@ -59,4 +67,4 @@ strip = false [[bench]] name = "benchmark_application" harness = false -path = "src/benches/application_bench.rs" \ No newline at end of file +path = "benches/application_bench.rs" \ No newline at end of file diff --git a/README.md b/README.md index b18520a..d2ab321 100644 --- a/README.md +++ b/README.md @@ -9,13 +9,14 @@

- Fractal - Fractal - Fractal - Fractal - Fractal - Fractal - Fractal + Fractal + Fractal + Fractal + Fractal + Fractal + Fractal + Fractal + Fractal

## πŸ“– Overview @@ -37,7 +38,7 @@ mathematical fractals including the Mandelbrot set, Julia sets, and more. - Real-time parameter adjustment - Color palette customization - **High Performance**: Multi-threaded rendering -- **Precision Control**: Adjustable precision between float64 and float32 +- **Precision Control**: Adjustable precision between float32, float64 and float128 ## πŸ’» Platform Support @@ -72,6 +73,45 @@ git clone https://github.com/Maxime-Cllt/Fractals-rs.git cargo run --release ``` +### Float 128 Support + +To enable float128 features : + +```bash +cargo run --release --features f128 +``` + +## πŸ“¦ Download Pre-built Binaries + +Pre-built binaries are available for each release in **two variants**: + +### Standard Version +- **File naming**: `Fractals-rs-{platform}` +- **Features**: f32 and f64 precision modes +- **Performance**: Faster rendering, smaller file size +- **Use case**: General fractal exploration with excellent quality +- **Recommended for**: Most users + +### F128 Version (Ultra-High Precision) +- **File naming**: `Fractals-rs-{platform}-f128` +- **Features**: f32, f64, and **f128** (128-bit decimal) precision modes +- **Performance**: Slower rendering, larger file size +- **Use case**: Extreme zoom levels (beyond 10^15) requiring maximum precision +- **Recommended for**: Advanced users, deep zoom enthusiasts, scientific visualization + +### Which version should I choose? + +- **Standard**: Perfect for 99% of use cases. Supports zooms up to 10^15 with excellent quality. +- **F128**: Only needed for extreme deep zooms beyond standard floating-point limits. Provides arbitrary precision at the cost of performance. + +### Platform Downloads + +The release artifacts follow this naming convention: +- Windows x64: `Fractals-rs-x86_64-pc-windows-msvc.exe` (standard) / `Fractals-rs-x86_64-pc-windows-msvc-f128.exe` (f128) +- Windows ARM64: `Fractals-rs-aarch64-pc-windows-msvc.exe` (standard) / `Fractals-rs-aarch64-pc-windows-msvc-f128.exe` (f128) +- macOS Intel: `Fractals-rs-x86_64-apple-darwin` (standard) / `Fractals-rs-x86_64-apple-darwin-f128` (f128) +- macOS Apple Silicon: `Fractals-rs-aarch64-apple-darwin` (standard) / `Fractals-rs-aarch64-apple-darwin-f128` (f128) + ## πŸ§ͺ Code Quality ### Unit Tests available diff --git a/assets/mandelbrot.png b/assets/mandelbrot.png index 13fe521..d851aca 100644 Binary files a/assets/mandelbrot.png and b/assets/mandelbrot.png differ diff --git a/assets/snow.png b/assets/snow.png new file mode 100644 index 0000000..1720624 Binary files /dev/null and b/assets/snow.png differ diff --git a/src/benches/application_bench.rs b/benches/application_bench.rs similarity index 89% rename from src/benches/application_bench.rs rename to benches/application_bench.rs index 9957604..46609b4 100644 --- a/src/benches/application_bench.rs +++ b/benches/application_bench.rs @@ -1,5 +1,5 @@ -use criterion::{criterion_group, criterion_main, Criterion}; -use fractals_rs::structs::point::Point; +use criterion::{Criterion, criterion_group, criterion_main}; +use fractals_rs::utils::point::Point; // Test parameters #[allow(unused)] @@ -34,8 +34,8 @@ fn benchmark_fractal_functions(c: &mut Criterion) { group.finish(); } -use fractals_rs::enums::fractal_type::FractalType; -use fractals_rs::enums::precision_mode::PrecisionMode; +use fractals_rs::fractals::fractal_type::FractalType; +use fractals_rs::utils::precision_mode::PrecisionMode; #[allow(unused)] fn mandelbrot_iterations(x: f64, y: f64, max_iter: u16) -> u16 { diff --git a/src/benches/mod.rs b/src/benches/mod.rs deleted file mode 100644 index 70df7c2..0000000 --- a/src/benches/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[cfg(test)] -mod application_bench; diff --git a/src/enums/fractal_type.rs b/src/enums/fractal_type.rs deleted file mode 100644 index af6d6dc..0000000 --- a/src/enums/fractal_type.rs +++ /dev/null @@ -1,254 +0,0 @@ -use crate::enums::precision_mode::PrecisionMode; -use crate::structs::point::Point; -use crate::traits::fractal_float::FractalFloat; - -/// Represents the type of fractal to be generated. -#[derive(Clone, Copy, Debug, PartialEq)] -#[repr(u8)] -pub enum FractalType { - Mandelbrot, - Julia, - BurningShip, - Tricorn, -} - -impl FractalType { - /// Returns the number of iterations with specified precision mode - #[inline] - pub fn iterations( - &self, - cx: f64, - cy: f64, - max_iteration: u16, - julia_c: &Point, - precision: PrecisionMode, - ) -> u16 { - match precision { - PrecisionMode::Fast => { - let cx_f32 = cx as f32; - let cy_f32 = cy as f32; - match self { - Self::Mandelbrot => { - Self::mandelbrot_iterations_generic(&cx_f32, &cy_f32, max_iteration) - } - Self::Julia => { - Self::julia_iterations_generic(cx_f32, cy_f32, max_iteration, julia_c) - } - Self::BurningShip => { - Self::burning_ship_iterations_generic(&cx_f32, &cy_f32, max_iteration) - } - Self::Tricorn => { - Self::tricorn_iterations_generic(&cx_f32, &cy_f32, max_iteration) - } - } - } - PrecisionMode::High => match self { - Self::Mandelbrot => Self::mandelbrot_iterations_generic(&cx, &cy, max_iteration), - Self::Julia => Self::julia_iterations_generic(cx, cy, max_iteration, julia_c), - Self::BurningShip => Self::burning_ship_iterations_generic(&cx, &cy, max_iteration), - Self::Tricorn => Self::tricorn_iterations_generic(&cx, &cy, max_iteration), - }, - } - } - - /// Returns the number of iterations for the Mandelbrot fractal - #[inline] - fn mandelbrot_iterations_generic(cx: &T, cy: &T, max_iteration: u16) -> u16 { - let mut zr = T::zero(); - let mut zi = T::zero(); - let mut iterations = 0u16; - - while iterations < max_iteration { - let zr2 = zr.mul(&zr); - let zi2 = zi.mul(&zi); - - if zr2.add(&zi2) > T::four() { - break; - } - - // z = zΒ² + c - let new_zr = zr2.sub(&zi2).add(cx); - zi = T::two().mul(&zr).mul(&zi).add(cy); - zr = new_zr; - - iterations += 1; - } - - iterations - } - - /// Returns the number of iterations for the Julia fractal - #[inline] - fn julia_iterations_generic( - zx: T, - zy: T, - max_iteration: u16, - c: &Point, - ) -> u16 { - let mut x = zx; - let mut y = zy; - let mut iterations = 0u16; - let cx = T::from_f64(c.x); - let cy = T::from_f64(c.y); - - while iterations < max_iteration { - let x2 = x.mul(&x); - let y2 = y.mul(&y); - - if x2.add(&y2) > T::four() { - break; - } - - let new_y = T::two().mul(&x).mul(&y).add(&cy); - x = x2.sub(&y2).add(&cx); - y = new_y; - - iterations += 1; - } - iterations - } - - /// Returns the number of iterations for the Burning Ship fractal - #[inline] - fn burning_ship_iterations_generic(cx: &T, cy: &T, max_iteration: u16) -> u16 { - let mut x = T::zero(); - let mut y = T::zero(); - let mut iterations = 0u16; - - while iterations < max_iteration { - let x2 = x.mul(&x); - let y2 = y.mul(&y); - - if x2.add(&y2) > T::four() { - break; - } - - let temp = x2.sub(&y2).add(cx); - y = T::two().mul(&x.abs()).mul(&y.abs()).add(cy); - x = temp; - iterations += 1; - } - iterations - } - - /// Returns the number of iterations for the Tricorn fractal - #[inline] - fn tricorn_iterations_generic(cx: &T, cy: &T, max_iteration: u16) -> u16 { - let mut x = T::zero(); - let mut y = T::zero(); - let mut iterations = 0u16; - - while iterations < max_iteration { - let x2 = x.mul(&x); - let y2 = y.mul(&y); - - if x2.add(&y2) > T::four() { - break; - } - - let temp = x2.sub(&y2).add(cx); - y = T::from_f64(-2.0).mul(&x).mul(&y).add(cy); - x = temp; - iterations += 1; - } - iterations - } - - /// Returns the name of the fractal type - #[inline] - #[must_use] - pub const fn name(&self) -> &'static str { - match self { - Self::Mandelbrot => "Mandelbrot Set", - Self::Julia => "Julia Set", - Self::BurningShip => "Burning Ship", - Self::Tricorn => "Tricorn", - } - } - - /// Returns the default center point for the fractal type - #[inline] - #[must_use] - pub const fn default_center(&self) -> Point { - match self { - Self::Mandelbrot => Point::new(-0.5, 0.0), - Self::Julia | Self::Tricorn => Point::new(0.0, 0.0), - Self::BurningShip => Point::new(-0.5, -0.5), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_mandelbrot_iterations() { - let iterations = FractalType::Mandelbrot.iterations( - 0.0, - 0.0, - 1000, - &Point::new(0.0, 0.0), - PrecisionMode::Fast, - ); - assert!(iterations > 0); - } - - #[test] - fn test_julia_iterations() { - let iterations = FractalType::Julia.iterations( - 0.0, - 0.0, - 1000, - &Point::new(0.355, 0.355), - PrecisionMode::Fast, - ); - assert!(iterations > 0); - } - - #[test] - fn test_burning_ship_iterations() { - let iterations = FractalType::BurningShip.iterations( - 0.0, - 0.0, - 1000, - &Point::new(0.0, 0.0), - PrecisionMode::Fast, - ); - assert!(iterations > 0); - } - - #[test] - fn test_tricorn_iterations() { - let iterations = FractalType::Tricorn.iterations( - 0.0, - 0.0, - 1000, - &Point::new(0.0, 0.0), - PrecisionMode::Fast, - ); - assert!(iterations > 0); - } - - #[test] - fn test_fractal_type_name() { - assert_eq!(FractalType::Mandelbrot.name(), "Mandelbrot Set"); - assert_eq!(FractalType::Julia.name(), "Julia Set"); - assert_eq!(FractalType::BurningShip.name(), "Burning Ship"); - assert_eq!(FractalType::Tricorn.name(), "Tricorn"); - } - - #[test] - fn test_fractal_type_default_center() { - assert_eq!( - FractalType::Mandelbrot.default_center(), - Point::new(-0.5, 0.0) - ); - assert_eq!(FractalType::Julia.default_center(), Point::new(0.0, 0.0)); - assert_eq!( - FractalType::BurningShip.default_center(), - Point::new(-0.5, -0.5) - ); - assert_eq!(FractalType::Tricorn.default_center(), Point::new(0.0, 0.0)); - } -} diff --git a/src/enums/mod.rs b/src/enums/mod.rs deleted file mode 100644 index 4444c8c..0000000 --- a/src/enums/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod fractal_type; -pub mod precision_mode; \ No newline at end of file diff --git a/src/structs/fractal_float.rs b/src/fractals/fractal_float.rs similarity index 60% rename from src/structs/fractal_float.rs rename to src/fractals/fractal_float.rs index c88d57c..ca31889 100644 --- a/src/structs/fractal_float.rs +++ b/src/fractals/fractal_float.rs @@ -1,4 +1,15 @@ -use crate::traits::fractal_float::FractalFloat; +/// A trait for representing floating-point numbers in a fractal context. +pub trait FractalFloat: Clone + PartialOrd { + fn zero() -> Self; // Represents the zero value. + fn two() -> Self; // Represents the two value. + fn four() -> Self; // Represents the four value. + fn abs(&self) -> Self; // Returns the absolute value. + fn from_f64(val: f64) -> Self; // Converts a f64 to the implementing type. + fn to_f64(&self) -> f64; // Converts the implementing type to f64. + fn add(&self, other: &Self) -> Self; // Adds two values. + fn sub(&self, other: &Self) -> Self; // Subtracts two values. + fn mul(&self, other: &Self) -> Self; // Multiplies two values. +} /// Implementing the `FractalFloat` trait for f32 (Fast mode) impl FractalFloat for f32 { @@ -96,6 +107,56 @@ impl FractalFloat for f64 { } } +#[cfg(feature = "f128")] +/// Implementation of the `FractalFloat` trait for `rust_decimal::Decimal` (Ultra High Precision Mode). +/// This enables 128-bit decimal precision for extreme zoom levels. +impl FractalFloat for rust_decimal::Decimal { + #[inline] + fn zero() -> Self { + rust_decimal::Decimal::ZERO + } + + #[inline] + fn two() -> Self { + rust_decimal::Decimal::TWO + } + + #[inline] + fn four() -> Self { + rust_decimal_macros::dec!(4) + } + + #[inline] + fn abs(&self) -> Self { + (*self).abs() + } + + #[inline] + fn from_f64(val: f64) -> Self { + rust_decimal::Decimal::from_f64_retain(val).unwrap_or(rust_decimal::Decimal::ZERO) + } + + #[inline] + fn to_f64(&self) -> f64 { + // Call the to_f64 method from ToPrimitive trait via f64::try_from + f64::try_from(*self).unwrap_or(0.0) + } + + #[inline] + fn add(&self, other: &Self) -> Self { + self + other + } + + #[inline] + fn sub(&self, other: &Self) -> Self { + self - other + } + + #[inline] + fn mul(&self, other: &Self) -> Self { + self * other + } +} #[cfg(test)] mod tests { @@ -190,4 +251,35 @@ mod tests { assert_eq!(val_f64.sub(&zero_f64), 5.0_f64); assert_eq!(val_f64.mul(&zero_f64), 0.0_f64); } -} \ No newline at end of file + + #[cfg(feature = "f128")] + #[test] + fn test_fractal_float_decimal() { + use rust_decimal::Decimal; + + let a = Decimal::from_f64_retain(1.5).unwrap(); + let b = Decimal::from_f64_retain(2.5).unwrap(); + + // Test arithmetic operations + let sum = a.add(&b); + assert_eq!(sum.to_f64(), 4.0_f64); + + let diff = a.sub(&b); + assert_eq!(diff.to_f64(), -1.0_f64); + + let prod = a.mul(&b); + assert_eq!(prod.to_f64(), 3.75_f64); + + // Test abs + assert_eq!(a.abs().to_f64(), 1.5_f64); + + // Test conversion functions + let converted = ::from_f64(3.0); + assert_eq!(converted.to_f64(), 3.0_f64); + + // Test constant functions + assert_eq!(::zero().to_f64(), 0.0_f64); + assert_eq!(::two().to_f64(), 2.0_f64); + assert_eq!(::four().to_f64(), 4.0_f64); + } +} diff --git a/src/fractals/fractal_kernels.rs b/src/fractals/fractal_kernels.rs new file mode 100644 index 0000000..be63482 --- /dev/null +++ b/src/fractals/fractal_kernels.rs @@ -0,0 +1,832 @@ +/// Optimized fractal computation kernels with direct f32/f64 implementations. +/// This module replaces the trait-based abstraction for maximum performance. +use crate::utils::point::Point; + +#[cfg(feature = "f128")] +use rust_decimal::Decimal; +#[cfg(feature = "f128")] +use rust_decimal_macros::dec; + +// ============================================================================ +// HELPER FUNCTIONS +// ============================================================================ + +/// Check if a point is in the main cardioid or period-2 bulb of the Mandelbrot set. +/// This early-out optimization skips ~25% of calculations. +#[inline(always)] +fn mandelbrot_early_out_f32(cx: f32, cy: f32) -> bool { + // Check main cardioid: q*(q + (x-0.25)) < 0.25*y^2 where q = (x-0.25)^2 + y^2 + let x_offset = cx - 0.25; + let q = x_offset.mul_add(x_offset, cy * cy); + if q.mul_add(q + x_offset, -(0.25 * cy * cy)) < 0.0 { + return true; + } + + // Check period-2 bulb: (x+1)^2 + y^2 < 0.0625 + let x_plus_one = cx + 1.0; + if x_plus_one.mul_add(x_plus_one, cy * cy) < 0.0625 { + return true; + } + + false +} + +#[inline(always)] +fn mandelbrot_early_out_f64(cx: f64, cy: f64) -> bool { + let x_offset = cx - 0.25; + let q = x_offset.mul_add(x_offset, cy * cy); + if q.mul_add(q + x_offset, -(0.25 * cy * cy)) < 0.0 { + return true; + } + + let x_plus_one = cx + 1.0; + if x_plus_one.mul_add(x_plus_one, cy * cy) < 0.0625 { + return true; + } + + false +} + +// ============================================================================ +// MANDELBROT KERNELS +// ============================================================================ + +/// Highly optimized Mandelbrot iteration kernel for f32. +/// Features: FMA operations, loop unrolling, early bailout, cardioid checking. +#[inline(always)] +pub fn mandelbrot_iterations_f32(cx: f32, cy: f32, max_iteration: u16) -> u16 { + // Early exit for points in main set components + if mandelbrot_early_out_f32(cx, cy) { + return max_iteration; + } + + let mut zr = 0.0f32; + let mut zi = 0.0f32; + let mut iterations = 0u16; + + // Manual loop unrolling: 4 iterations per loop + // This improves ILP (instruction-level parallelism) and reduces branch overhead + while iterations + 4 <= max_iteration { + // Iteration 1 + let zr2 = zr * zr; + let zi2 = zi * zi; + if zr2 + zi2 > 4.0 { + break; + } + let new_zr = zr2.mul_add(1.0, zi2.mul_add(-1.0, cx)); + zi = (2.0 * zr).mul_add(zi, cy); + zr = new_zr; + iterations += 1; + + // Iteration 2 + let zr2 = zr * zr; + let zi2 = zi * zi; + if zr2 + zi2 > 4.0 { + break; + } + let new_zr = zr2.mul_add(1.0, zi2.mul_add(-1.0, cx)); + zi = (2.0 * zr).mul_add(zi, cy); + zr = new_zr; + iterations += 1; + + // Iteration 3 + let zr2 = zr * zr; + let zi2 = zi * zi; + if zr2 + zi2 > 4.0 { + break; + } + let new_zr = zr2.mul_add(1.0, zi2.mul_add(-1.0, cx)); + zi = (2.0 * zr).mul_add(zi, cy); + zr = new_zr; + iterations += 1; + + // Iteration 4 + let zr2 = zr * zr; + let zi2 = zi * zi; + if zr2 + zi2 > 4.0 { + break; + } + let new_zr = zr2.mul_add(1.0, zi2.mul_add(-1.0, cx)); + zi = (2.0 * zr).mul_add(zi, cy); + zr = new_zr; + iterations += 1; + } + + // Handle remaining iterations (< 4) + while iterations < max_iteration { + let zr2 = zr * zr; + let zi2 = zi * zi; + if zr2 + zi2 > 4.0 { + break; + } + let new_zr = zr2.mul_add(1.0, zi2.mul_add(-1.0, cx)); + zi = (2.0 * zr).mul_add(zi, cy); + zr = new_zr; + iterations += 1; + } + + iterations +} + +/// Highly optimized Mandelbrot iteration kernel for f64. +#[inline(always)] +pub fn mandelbrot_iterations_f64(cx: f64, cy: f64, max_iteration: u16) -> u16 { + if mandelbrot_early_out_f64(cx, cy) { + return max_iteration; + } + + let mut zr = 0.0f64; + let mut zi = 0.0f64; + let mut iterations = 0u16; + + // Manual loop unrolling for f64 + while iterations + 4 <= max_iteration { + // Iteration 1 + let zr2 = zr * zr; + let zi2 = zi * zi; + if zr2 + zi2 > 4.0 { + break; + } + let new_zr = zr2.mul_add(1.0, zi2.mul_add(-1.0, cx)); + zi = (2.0 * zr).mul_add(zi, cy); + zr = new_zr; + iterations += 1; + + // Iteration 2 + let zr2 = zr * zr; + let zi2 = zi * zi; + if zr2 + zi2 > 4.0 { + break; + } + let new_zr = zr2.mul_add(1.0, zi2.mul_add(-1.0, cx)); + zi = (2.0 * zr).mul_add(zi, cy); + zr = new_zr; + iterations += 1; + + // Iteration 3 + let zr2 = zr * zr; + let zi2 = zi * zi; + if zr2 + zi2 > 4.0 { + break; + } + let new_zr = zr2.mul_add(1.0, zi2.mul_add(-1.0, cx)); + zi = (2.0 * zr).mul_add(zi, cy); + zr = new_zr; + iterations += 1; + + // Iteration 4 + let zr2 = zr * zr; + let zi2 = zi * zi; + if zr2 + zi2 > 4.0 { + break; + } + let new_zr = zr2.mul_add(1.0, zi2.mul_add(-1.0, cx)); + zi = (2.0 * zr).mul_add(zi, cy); + zr = new_zr; + iterations += 1; + } + + while iterations < max_iteration { + let zr2 = zr * zr; + let zi2 = zi * zi; + if zr2 + zi2 > 4.0 { + break; + } + let new_zr = zr2.mul_add(1.0, zi2.mul_add(-1.0, cx)); + zi = (2.0 * zr).mul_add(zi, cy); + zr = new_zr; + iterations += 1; + } + + iterations +} + +// ============================================================================ +// JULIA KERNELS +// ============================================================================ + +/// Optimized Julia set iteration kernel for f32. +#[inline(always)] +pub fn julia_iterations_f32(zx: f32, zy: f32, max_iteration: u16, c: &Point) -> u16 { + let mut x = zx; + let mut y = zy; + let mut iterations = 0u16; + let cx = c.x as f32; + let cy = c.y as f32; + + // Manual loop unrolling + while iterations + 4 <= max_iteration { + // Iteration 1 + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let new_y = (2.0 * x).mul_add(y, cy); + x = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = new_y; + iterations += 1; + + // Iteration 2 + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let new_y = (2.0 * x).mul_add(y, cy); + x = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = new_y; + iterations += 1; + + // Iteration 3 + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let new_y = (2.0 * x).mul_add(y, cy); + x = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = new_y; + iterations += 1; + + // Iteration 4 + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let new_y = (2.0 * x).mul_add(y, cy); + x = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = new_y; + iterations += 1; + } + + while iterations < max_iteration { + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let new_y = (2.0 * x).mul_add(y, cy); + x = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = new_y; + iterations += 1; + } + + iterations +} + +/// Optimized Julia set iteration kernel for f64. +#[inline(always)] +pub fn julia_iterations_f64(zx: f64, zy: f64, max_iteration: u16, c: &Point) -> u16 { + let mut x = zx; + let mut y = zy; + let mut iterations = 0u16; + let cx = c.x; + let cy = c.y; + + while iterations + 4 <= max_iteration { + // Iteration 1 + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let new_y = (2.0 * x).mul_add(y, cy); + x = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = new_y; + iterations += 1; + + // Iteration 2 + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let new_y = (2.0 * x).mul_add(y, cy); + x = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = new_y; + iterations += 1; + + // Iteration 3 + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let new_y = (2.0 * x).mul_add(y, cy); + x = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = new_y; + iterations += 1; + + // Iteration 4 + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let new_y = (2.0 * x).mul_add(y, cy); + x = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = new_y; + iterations += 1; + } + + while iterations < max_iteration { + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let new_y = (2.0 * x).mul_add(y, cy); + x = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = new_y; + iterations += 1; + } + + iterations +} + +// ============================================================================ +// BURNING SHIP KERNELS +// ============================================================================ + +/// Optimized Burning Ship iteration kernel for f32. +#[inline(always)] +pub fn burning_ship_iterations_f32(cx: f32, cy: f32, max_iteration: u16) -> u16 { + let mut x = 0.0f32; + let mut y = 0.0f32; + let mut iterations = 0u16; + + // Manual loop unrolling + while iterations + 4 <= max_iteration { + // Iteration 1 + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let temp = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = (2.0 * x.abs()).mul_add(y.abs(), cy); + x = temp; + iterations += 1; + + // Iteration 2 + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let temp = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = (2.0 * x.abs()).mul_add(y.abs(), cy); + x = temp; + iterations += 1; + + // Iteration 3 + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let temp = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = (2.0 * x.abs()).mul_add(y.abs(), cy); + x = temp; + iterations += 1; + + // Iteration 4 + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let temp = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = (2.0 * x.abs()).mul_add(y.abs(), cy); + x = temp; + iterations += 1; + } + + while iterations < max_iteration { + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let temp = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = (2.0 * x.abs()).mul_add(y.abs(), cy); + x = temp; + iterations += 1; + } + + iterations +} + +/// Optimized Burning Ship iteration kernel for f64. +#[inline(always)] +pub fn burning_ship_iterations_f64(cx: f64, cy: f64, max_iteration: u16) -> u16 { + let mut x = 0.0f64; + let mut y = 0.0f64; + let mut iterations = 0u16; + + while iterations + 4 <= max_iteration { + // Iteration 1 + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let temp = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = (2.0 * x.abs()).mul_add(y.abs(), cy); + x = temp; + iterations += 1; + + // Iteration 2 + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let temp = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = (2.0 * x.abs()).mul_add(y.abs(), cy); + x = temp; + iterations += 1; + + // Iteration 3 + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let temp = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = (2.0 * x.abs()).mul_add(y.abs(), cy); + x = temp; + iterations += 1; + + // Iteration 4 + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let temp = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = (2.0 * x.abs()).mul_add(y.abs(), cy); + x = temp; + iterations += 1; + } + + while iterations < max_iteration { + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let temp = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = (2.0 * x.abs()).mul_add(y.abs(), cy); + x = temp; + iterations += 1; + } + + iterations +} + +// ============================================================================ +// TRICORN KERNELS +// ============================================================================ + +/// Optimized Tricorn iteration kernel for f32. +#[inline(always)] +pub fn tricorn_iterations_f32(cx: f32, cy: f32, max_iteration: u16) -> u16 { + let mut x = 0.0f32; + let mut y = 0.0f32; + let mut iterations = 0u16; + + // Manual loop unrolling + while iterations + 4 <= max_iteration { + // Iteration 1 + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let temp = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = (-2.0 * x).mul_add(y, cy); + x = temp; + iterations += 1; + + // Iteration 2 + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let temp = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = (-2.0 * x).mul_add(y, cy); + x = temp; + iterations += 1; + + // Iteration 3 + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let temp = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = (-2.0 * x).mul_add(y, cy); + x = temp; + iterations += 1; + + // Iteration 4 + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let temp = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = (-2.0 * x).mul_add(y, cy); + x = temp; + iterations += 1; + } + + while iterations < max_iteration { + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let temp = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = (-2.0 * x).mul_add(y, cy); + x = temp; + iterations += 1; + } + + iterations +} + +/// Optimized Tricorn iteration kernel for f64. +#[inline(always)] +pub fn tricorn_iterations_f64(cx: f64, cy: f64, max_iteration: u16) -> u16 { + let mut x = 0.0f64; + let mut y = 0.0f64; + let mut iterations = 0u16; + + while iterations + 4 <= max_iteration { + // Iteration 1 + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let temp = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = (-2.0 * x).mul_add(y, cy); + x = temp; + iterations += 1; + + // Iteration 2 + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let temp = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = (-2.0 * x).mul_add(y, cy); + x = temp; + iterations += 1; + + // Iteration 3 + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let temp = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = (-2.0 * x).mul_add(y, cy); + x = temp; + iterations += 1; + + // Iteration 4 + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let temp = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = (-2.0 * x).mul_add(y, cy); + x = temp; + iterations += 1; + } + + while iterations < max_iteration { + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > 4.0 { + break; + } + let temp = x2.mul_add(1.0, y2.mul_add(-1.0, cx)); + y = (-2.0 * x).mul_add(y, cy); + x = temp; + iterations += 1; + } + + iterations +} + +// ============================================================================ +// F128 (DECIMAL) KERNELS - Ultra High Precision +// ============================================================================ + +#[cfg(feature = "f128")] +/// Check if a point is in the main cardioid or period-2 bulb of the Mandelbrot set (f128 version). +#[inline(always)] +fn mandelbrot_early_out_f128(cx: Decimal, cy: Decimal) -> bool { + let quarter = dec!(0.25); + let one = Decimal::ONE; + let x_offset = cx - quarter; + let q = x_offset * x_offset + cy * cy; + if q * (q + x_offset) < quarter * cy * cy { + return true; + } + + let x_plus_one = cx + one; + if x_plus_one * x_plus_one + cy * cy < dec!(0.0625) { + return true; + } + + false +} + +#[cfg(feature = "f128")] +/// Mandelbrot iteration kernel for f128 (Decimal) precision. +/// Uses 128-bit decimal arithmetic for extreme zoom levels. +#[inline(always)] +pub fn mandelbrot_iterations_f128(cx: Decimal, cy: Decimal, max_iteration: u16) -> u16 { + if mandelbrot_early_out_f128(cx, cy) { + return max_iteration; + } + + let mut zr = Decimal::ZERO; + let mut zi = Decimal::ZERO; + let mut iterations = 0u16; + let four = dec!(4); + + while iterations < max_iteration { + let zr2 = zr * zr; + let zi2 = zi * zi; + if zr2 + zi2 > four { + break; + } + let new_zr = zr2 - zi2 + cx; + zi = dec!(2) * zr * zi + cy; + zr = new_zr; + iterations += 1; + } + + iterations +} + +#[cfg(feature = "f128")] +/// Julia set iteration kernel for f128 (Decimal) precision. +#[inline(always)] +pub fn julia_iterations_f128(zx: Decimal, zy: Decimal, max_iteration: u16, c: &Point) -> u16 { + let mut x = zx; + let mut y = zy; + let mut iterations = 0u16; + let cx = Decimal::from_f64_retain(c.x).unwrap_or(Decimal::ZERO); + let cy = Decimal::from_f64_retain(c.y).unwrap_or(Decimal::ZERO); + let four = dec!(4); + + while iterations < max_iteration { + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > four { + break; + } + let new_y = dec!(2) * x * y + cy; + x = x2 - y2 + cx; + y = new_y; + iterations += 1; + } + + iterations +} + +#[cfg(feature = "f128")] +/// Burning Ship iteration kernel for f128 (Decimal) precision. +#[inline(always)] +pub fn burning_ship_iterations_f128(cx: Decimal, cy: Decimal, max_iteration: u16) -> u16 { + let mut x = Decimal::ZERO; + let mut y = Decimal::ZERO; + let mut iterations = 0u16; + let four = dec!(4); + + while iterations < max_iteration { + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > four { + break; + } + let temp = x2 - y2 + cx; + y = dec!(2) * x.abs() * y.abs() + cy; + x = temp; + iterations += 1; + } + + iterations +} + +#[cfg(feature = "f128")] +/// Tricorn iteration kernel for f128 (Decimal) precision. +#[inline(always)] +pub fn tricorn_iterations_f128(cx: Decimal, cy: Decimal, max_iteration: u16) -> u16 { + let mut x = Decimal::ZERO; + let mut y = Decimal::ZERO; + let mut iterations = 0u16; + let four = dec!(4); + + while iterations < max_iteration { + let x2 = x * x; + let y2 = y * y; + if x2 + y2 > four { + break; + } + let temp = x2 - y2 + cx; + y = dec!(-2) * x * y + cy; + x = temp; + iterations += 1; + } + + iterations +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_mandelbrot_f32() { + let iterations = mandelbrot_iterations_f32(0.0, 0.0, 1000); + assert!(iterations > 0); + } + + #[test] + fn test_mandelbrot_f64() { + let iterations = mandelbrot_iterations_f64(0.0, 0.0, 1000); + assert!(iterations > 0); + } + + #[test] + fn test_mandelbrot_early_out() { + // Point in main cardioid should return max_iterations + let iterations = mandelbrot_iterations_f32(-0.5, 0.0, 100); + assert_eq!(iterations, 100); + } + + #[test] + fn test_julia_f32() { + let c = Point::new(0.355, 0.355); + let iterations = julia_iterations_f32(0.0, 0.0, 1000, &c); + assert!(iterations > 0); + } + + #[test] + fn test_burning_ship_f32() { + let iterations = burning_ship_iterations_f32(0.0, 0.0, 1000); + assert!(iterations > 0); + } + + #[test] + fn test_tricorn_f32() { + let iterations = tricorn_iterations_f32(0.0, 0.0, 1000); + assert!(iterations > 0); + } + + #[cfg(feature = "f128")] + #[test] + fn test_mandelbrot_f128() { + use rust_decimal::Decimal; + let iterations = mandelbrot_iterations_f128(Decimal::ZERO, Decimal::ZERO, 1000); + assert!(iterations > 0); + } + + #[cfg(feature = "f128")] + #[test] + fn test_julia_f128() { + use rust_decimal::Decimal; + let c = Point::new(0.355, 0.355); + let iterations = julia_iterations_f128(Decimal::ZERO, Decimal::ZERO, 1000, &c); + assert!(iterations > 0); + } + + #[cfg(feature = "f128")] + #[test] + fn test_burning_ship_f128() { + use rust_decimal::Decimal; + let iterations = burning_ship_iterations_f128(Decimal::ZERO, Decimal::ZERO, 1000); + assert!(iterations > 0); + } + + #[cfg(feature = "f128")] + #[test] + fn test_tricorn_f128() { + use rust_decimal::Decimal; + let iterations = tricorn_iterations_f128(Decimal::ZERO, Decimal::ZERO, 1000); + assert!(iterations > 0); + } +} diff --git a/src/fractals/fractal_simd.rs b/src/fractals/fractal_simd.rs new file mode 100644 index 0000000..8e63667 --- /dev/null +++ b/src/fractals/fractal_simd.rs @@ -0,0 +1,508 @@ +/// SIMD-accelerated fractal computation kernels. +/// Uses the `wide` crate for portable SIMD operations across platforms. +/// +/// Key optimizations: +/// - Process 4 pixels simultaneously with f32x4 (SSE/AVX) +/// - Process 2 pixels simultaneously with f64x2 +/// - Vectorized escape-time algorithm +/// - Early termination with active masks +use wide::{f32x4, f64x2}; + +// ============================================================================ +// MANDELBROT SIMD KERNELS +// ============================================================================ + +/// SIMD Mandelbrot kernel processing 4 f32 pixels simultaneously. +/// +/// # Arguments +/// * `cx` - Array of 4 x-coordinates +/// * `cy` - Array of 4 y-coordinates +/// * `max_iteration` - Maximum iteration count +/// +/// # Returns +/// Array of 4 iteration counts +#[inline(always)] +pub fn mandelbrot_simd_f32(cx: &[f32; 4], cy: &[f32; 4], max_iteration: u16) -> [u16; 4] { + let mut iterations = [0u16; 4]; + let mut active_mask = [true; 4]; + + // Early exit checks for each pixel + for i in 0..4 { + let x_offset = cx[i] - 0.25; + let q = x_offset * x_offset + cy[i] * cy[i]; + if q * (q + x_offset) < 0.25 * cy[i] * cy[i] { + iterations[i] = max_iteration; + active_mask[i] = false; + continue; + } + let x_plus = cx[i] + 1.0; + if x_plus * x_plus + cy[i] * cy[i] < 0.0625 { + iterations[i] = max_iteration; + active_mask[i] = false; + } + } + + if !active_mask.iter().any(|&b| b) { + return iterations; + } + + let cx_vec = f32x4::from(*cx); + let cy_vec = f32x4::from(*cy); + + let mut zr = f32x4::ZERO; + let mut zi = f32x4::ZERO; + let two = f32x4::splat(2.0); + + for iter in 0..max_iteration { + if !active_mask.iter().any(|&b| b) { + break; + } + + let zr2 = zr * zr; + let zi2 = zi * zi; + let magnitude_sq = zr2 + zi2; + + // Check escape condition for each pixel + let mag_arr = magnitude_sq.as_array(); + for i in 0..4 { + if active_mask[i] && mag_arr[i] > 4.0 { + iterations[i] = iter; + active_mask[i] = false; + } + } + + // z = zΒ² + c + let new_zr = zr2 - zi2 + cx_vec; + let new_zi = two * zr * zi + cy_vec; + + zr = new_zr; + zi = new_zi; + } + + // Set remaining active pixels to max_iteration + for i in 0..4 { + if active_mask[i] { + iterations[i] = max_iteration; + } + } + + iterations +} + +/// SIMD Mandelbrot kernel processing 2 f64 pixels simultaneously. +#[inline(always)] +pub fn mandelbrot_simd_f64(cx: &[f64; 2], cy: &[f64; 2], max_iteration: u16) -> [u16; 2] { + let mut iterations = [0u16; 2]; + let mut active_mask = [true; 2]; + + // Early exit checks + for i in 0..2 { + let x_offset = cx[i] - 0.25; + let q = x_offset * x_offset + cy[i] * cy[i]; + if q * (q + x_offset) < 0.25 * cy[i] * cy[i] { + iterations[i] = max_iteration; + active_mask[i] = false; + continue; + } + let x_plus = cx[i] + 1.0; + if x_plus * x_plus + cy[i] * cy[i] < 0.0625 { + iterations[i] = max_iteration; + active_mask[i] = false; + } + } + + if !active_mask.iter().any(|&b| b) { + return iterations; + } + + let cx_vec = f64x2::from(*cx); + let cy_vec = f64x2::from(*cy); + + let mut zr = f64x2::ZERO; + let mut zi = f64x2::ZERO; + let two = f64x2::splat(2.0); + + for iter in 0..max_iteration { + if !active_mask.iter().any(|&b| b) { + break; + } + + let zr2 = zr * zr; + let zi2 = zi * zi; + let magnitude_sq = zr2 + zi2; + + let mag_arr = magnitude_sq.as_array(); + for i in 0..2 { + if active_mask[i] && mag_arr[i] > 4.0 { + iterations[i] = iter; + active_mask[i] = false; + } + } + + let new_zr = zr2 - zi2 + cx_vec; + let new_zi = two * zr * zi + cy_vec; + + zr = new_zr; + zi = new_zi; + } + + for i in 0..2 { + if active_mask[i] { + iterations[i] = max_iteration; + } + } + + iterations +} + +// ============================================================================ +// JULIA SIMD KERNELS +// ============================================================================ + +/// SIMD Julia kernel processing 4 f32 pixels simultaneously. +#[inline(always)] +pub fn julia_simd_f32( + zx: &[f32; 4], + zy: &[f32; 4], + cx: f32, + cy: f32, + max_iteration: u16, +) -> [u16; 4] { + let mut x = f32x4::from(*zx); + let mut y = f32x4::from(*zy); + let cx_vec = f32x4::splat(cx); + let cy_vec = f32x4::splat(cy); + + let mut iterations = [0u16; 4]; + let mut active_mask = [true; 4]; + + let two = f32x4::splat(2.0); + + for iter in 0..max_iteration { + if !active_mask.iter().any(|&b| b) { + break; + } + + let x2 = x * x; + let y2 = y * y; + let magnitude_sq = x2 + y2; + + let mag_arr = magnitude_sq.as_array(); + for i in 0..4 { + if active_mask[i] && mag_arr[i] > 4.0 { + iterations[i] = iter; + active_mask[i] = false; + } + } + + // z = zΒ² + c + let new_y = two * x * y + cy_vec; + x = x2 - y2 + cx_vec; + y = new_y; + } + + for i in 0..4 { + if active_mask[i] { + iterations[i] = max_iteration; + } + } + + iterations +} + +/// SIMD Julia kernel processing 2 f64 pixels simultaneously. +#[inline(always)] +pub fn julia_simd_f64( + zx: &[f64; 2], + zy: &[f64; 2], + cx: f64, + cy: f64, + max_iteration: u16, +) -> [u16; 2] { + let mut x = f64x2::from(*zx); + let mut y = f64x2::from(*zy); + let cx_vec = f64x2::splat(cx); + let cy_vec = f64x2::splat(cy); + + let mut iterations = [0u16; 2]; + let mut active_mask = [true; 2]; + + let two = f64x2::splat(2.0); + + for iter in 0..max_iteration { + if !active_mask.iter().any(|&b| b) { + break; + } + + let x2 = x * x; + let y2 = y * y; + let magnitude_sq = x2 + y2; + + let mag_arr = magnitude_sq.as_array(); + for i in 0..2 { + if active_mask[i] && mag_arr[i] > 4.0 { + iterations[i] = iter; + active_mask[i] = false; + } + } + + let new_y = two * x * y + cy_vec; + x = x2 - y2 + cx_vec; + y = new_y; + } + + for i in 0..2 { + if active_mask[i] { + iterations[i] = max_iteration; + } + } + + iterations +} + +// ============================================================================ +// BURNING SHIP SIMD KERNELS +// ============================================================================ + +/// SIMD Burning Ship kernel processing 4 f32 pixels simultaneously. +#[inline(always)] +pub fn burning_ship_simd_f32(cx: &[f32; 4], cy: &[f32; 4], max_iteration: u16) -> [u16; 4] { + let cx_vec = f32x4::from(*cx); + let cy_vec = f32x4::from(*cy); + + let mut x = f32x4::ZERO; + let mut y = f32x4::ZERO; + let mut iterations = [0u16; 4]; + let mut active_mask = [true; 4]; + + let two = f32x4::splat(2.0); + + for iter in 0..max_iteration { + if !active_mask.iter().any(|&b| b) { + break; + } + + let x2 = x * x; + let y2 = y * y; + let magnitude_sq = x2 + y2; + + let mag_arr = magnitude_sq.as_array(); + for i in 0..4 { + if active_mask[i] && mag_arr[i] > 4.0 { + iterations[i] = iter; + active_mask[i] = false; + } + } + + // Burning Ship uses abs() values + let temp = x2 - y2 + cx_vec; + y = two * x.abs() * y.abs() + cy_vec; + x = temp; + } + + for i in 0..4 { + if active_mask[i] { + iterations[i] = max_iteration; + } + } + + iterations +} + +/// SIMD Burning Ship kernel processing 2 f64 pixels simultaneously. +#[inline(always)] +pub fn burning_ship_simd_f64(cx: &[f64; 2], cy: &[f64; 2], max_iteration: u16) -> [u16; 2] { + let cx_vec = f64x2::from(*cx); + let cy_vec = f64x2::from(*cy); + + let mut x = f64x2::ZERO; + let mut y = f64x2::ZERO; + let mut iterations = [0u16; 2]; + let mut active_mask = [true; 2]; + + let two = f64x2::splat(2.0); + + for iter in 0..max_iteration { + if !active_mask.iter().any(|&b| b) { + break; + } + + let x2 = x * x; + let y2 = y * y; + let magnitude_sq = x2 + y2; + + let mag_arr = magnitude_sq.as_array(); + for i in 0..2 { + if active_mask[i] && mag_arr[i] > 4.0 { + iterations[i] = iter; + active_mask[i] = false; + } + } + + let temp = x2 - y2 + cx_vec; + y = two * x.abs() * y.abs() + cy_vec; + x = temp; + } + + for i in 0..2 { + if active_mask[i] { + iterations[i] = max_iteration; + } + } + + iterations +} + +// ============================================================================ +// TRICORN SIMD KERNELS +// ============================================================================ + +/// SIMD Tricorn kernel processing 4 f32 pixels simultaneously. +#[inline(always)] +pub fn tricorn_simd_f32(cx: &[f32; 4], cy: &[f32; 4], max_iteration: u16) -> [u16; 4] { + let cx_vec = f32x4::from(*cx); + let cy_vec = f32x4::from(*cy); + + let mut x = f32x4::ZERO; + let mut y = f32x4::ZERO; + let mut iterations = [0u16; 4]; + let mut active_mask = [true; 4]; + + let neg_two = f32x4::splat(-2.0); + + for iter in 0..max_iteration { + if !active_mask.iter().any(|&b| b) { + break; + } + + let x2 = x * x; + let y2 = y * y; + let magnitude_sq = x2 + y2; + + let mag_arr = magnitude_sq.as_array(); + for i in 0..4 { + if active_mask[i] && mag_arr[i] > 4.0 { + iterations[i] = iter; + active_mask[i] = false; + } + } + + // Tricorn uses conjugate + let temp = x2 - y2 + cx_vec; + y = neg_two * x * y + cy_vec; + x = temp; + } + + for i in 0..4 { + if active_mask[i] { + iterations[i] = max_iteration; + } + } + + iterations +} + +/// SIMD Tricorn kernel processing 2 f64 pixels simultaneously. +#[inline(always)] +pub fn tricorn_simd_f64(cx: &[f64; 2], cy: &[f64; 2], max_iteration: u16) -> [u16; 2] { + let cx_vec = f64x2::from(*cx); + let cy_vec = f64x2::from(*cy); + + let mut x = f64x2::ZERO; + let mut y = f64x2::ZERO; + let mut iterations = [0u16; 2]; + let mut active_mask = [true; 2]; + + let neg_two = f64x2::splat(-2.0); + + for iter in 0..max_iteration { + if !active_mask.iter().any(|&b| b) { + break; + } + + let x2 = x * x; + let y2 = y * y; + let magnitude_sq = x2 + y2; + + let mag_arr = magnitude_sq.as_array(); + for i in 0..2 { + if active_mask[i] && mag_arr[i] > 4.0 { + iterations[i] = iter; + active_mask[i] = false; + } + } + + let temp = x2 - y2 + cx_vec; + y = neg_two * x * y + cy_vec; + x = temp; + } + + for i in 0..2 { + if active_mask[i] { + iterations[i] = max_iteration; + } + } + + iterations +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_mandelbrot_simd_f32() { + let cx = [0.0, -0.5, -1.0, 0.25]; + let cy = [0.0, 0.0, 0.0, 0.0]; + let iterations = mandelbrot_simd_f32(&cx, &cy, 100); + + // All should produce valid iteration counts + for &iter in &iterations { + assert!(iter <= 100); + } + } + + #[test] + fn test_mandelbrot_simd_f64() { + let cx = [0.0, -0.5]; + let cy = [0.0, 0.0]; + let iterations = mandelbrot_simd_f64(&cx, &cy, 100); + + for &iter in &iterations { + assert!(iter <= 100); + } + } + + #[test] + fn test_julia_simd_f32() { + let zx = [0.0, 0.1, 0.2, 0.3]; + let zy = [0.0, 0.1, 0.2, 0.3]; + let iterations = julia_simd_f32(&zx, &zy, 0.355, 0.355, 100); + + for &iter in &iterations { + assert!(iter <= 100); + } + } + + #[test] + fn test_burning_ship_simd_f32() { + let cx = [0.0, -0.5, -1.0, -1.5]; + let cy = [0.0, -0.5, -0.5, -0.5]; + let iterations = burning_ship_simd_f32(&cx, &cy, 100); + + for &iter in &iterations { + assert!(iter <= 100); + } + } + + #[test] + fn test_tricorn_simd_f32() { + let cx = [0.0, -0.5, -1.0, 0.25]; + let cy = [0.0, 0.0, 0.0, 0.0]; + let iterations = tricorn_simd_f32(&cx, &cy, 100); + + for &iter in &iterations { + assert!(iter <= 100); + } + } +} diff --git a/src/fractals/fractal_type.rs b/src/fractals/fractal_type.rs new file mode 100644 index 0000000..4c678f5 --- /dev/null +++ b/src/fractals/fractal_type.rs @@ -0,0 +1,179 @@ +use crate::utils::precision_mode::PrecisionMode; +use crate::utils::point::Point; +use crate::fractals::fractal_kernels; + +/// Represents the type of fractal to be generated. +#[derive(Clone, Copy, Debug, PartialEq)] +#[repr(u8)] +pub enum FractalType { + Mandelbrot, + Julia, + BurningShip, + Tricorn, +} + +impl FractalType { + /// Returns the number of iterations with specified precision mode. + /// Now using optimized direct kernel implementations for maximum performance. + #[inline] + pub fn iterations( + &self, + cx: f64, + cy: f64, + max_iteration: u16, + julia_c: &Point, + precision: PrecisionMode, + ) -> u16 { + match precision { + PrecisionMode::Fast => { + let cx_f32 = cx as f32; + let cy_f32 = cy as f32; + match self { + Self::Mandelbrot => { + fractal_kernels::mandelbrot_iterations_f32(cx_f32, cy_f32, max_iteration) + } + Self::Julia => { + fractal_kernels::julia_iterations_f32(cx_f32, cy_f32, max_iteration, julia_c) + } + Self::BurningShip => { + fractal_kernels::burning_ship_iterations_f32(cx_f32, cy_f32, max_iteration) + } + Self::Tricorn => { + fractal_kernels::tricorn_iterations_f32(cx_f32, cy_f32, max_iteration) + } + } + } + PrecisionMode::High => match self { + Self::Mandelbrot => { + fractal_kernels::mandelbrot_iterations_f64(cx, cy, max_iteration) + } + Self::Julia => { + fractal_kernels::julia_iterations_f64(cx, cy, max_iteration, julia_c) + } + Self::BurningShip => { + fractal_kernels::burning_ship_iterations_f64(cx, cy, max_iteration) + } + Self::Tricorn => { + fractal_kernels::tricorn_iterations_f64(cx, cy, max_iteration) + } + }, + #[cfg(feature = "f128")] + PrecisionMode::UltraHigh => { + use rust_decimal::Decimal; + let cx_dec = Decimal::from_f64_retain(cx).unwrap_or(Decimal::ZERO); + let cy_dec = Decimal::from_f64_retain(cy).unwrap_or(Decimal::ZERO); + match self { + Self::Mandelbrot => { + fractal_kernels::mandelbrot_iterations_f128(cx_dec, cy_dec, max_iteration) + } + Self::Julia => { + fractal_kernels::julia_iterations_f128(cx_dec, cy_dec, max_iteration, julia_c) + } + Self::BurningShip => { + fractal_kernels::burning_ship_iterations_f128(cx_dec, cy_dec, max_iteration) + } + Self::Tricorn => { + fractal_kernels::tricorn_iterations_f128(cx_dec, cy_dec, max_iteration) + } + } + } + } + } + + /// Returns the name of the fractal type + #[inline] + #[must_use] + pub const fn name(&self) -> &'static str { + match self { + Self::Mandelbrot => "Mandelbrot Set", + Self::Julia => "Julia Set", + Self::BurningShip => "Burning Ship", + Self::Tricorn => "Tricorn", + } + } + + /// Returns the default center point for the fractal type + #[inline] + pub const fn default_center(&self) -> Point { + match self { + Self::Mandelbrot => Point::new(-0.5, 0.0), + Self::Julia | Self::Tricorn => Point::new(0.0, 0.0), + Self::BurningShip => Point::new(-0.5, -0.5), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_mandelbrot_iterations() { + let iterations = FractalType::Mandelbrot.iterations( + 0.0, + 0.0, + 1000, + &Point::new(0.0, 0.0), + PrecisionMode::Fast, + ); + assert!(iterations > 0); + } + + #[test] + fn test_julia_iterations() { + let iterations = FractalType::Julia.iterations( + 0.0, + 0.0, + 1000, + &Point::new(0.355, 0.355), + PrecisionMode::Fast, + ); + assert!(iterations > 0); + } + + #[test] + fn test_burning_ship_iterations() { + let iterations = FractalType::BurningShip.iterations( + 0.0, + 0.0, + 1000, + &Point::new(0.0, 0.0), + PrecisionMode::Fast, + ); + assert!(iterations > 0); + } + + #[test] + fn test_tricorn_iterations() { + let iterations = FractalType::Tricorn.iterations( + 0.0, + 0.0, + 1000, + &Point::new(0.0, 0.0), + PrecisionMode::Fast, + ); + assert!(iterations > 0); + } + + #[test] + fn test_fractal_type_name() { + assert_eq!(FractalType::Mandelbrot.name(), "Mandelbrot Set"); + assert_eq!(FractalType::Julia.name(), "Julia Set"); + assert_eq!(FractalType::BurningShip.name(), "Burning Ship"); + assert_eq!(FractalType::Tricorn.name(), "Tricorn"); + } + + #[test] + fn test_fractal_type_default_center() { + assert_eq!( + FractalType::Mandelbrot.default_center(), + Point::new(-0.5, 0.0) + ); + assert_eq!(FractalType::Julia.default_center(), Point::new(0.0, 0.0)); + assert_eq!( + FractalType::BurningShip.default_center(), + Point::new(-0.5, -0.5) + ); + assert_eq!(FractalType::Tricorn.default_center(), Point::new(0.0, 0.0)); + } +} diff --git a/src/fractals/mod.rs b/src/fractals/mod.rs new file mode 100644 index 0000000..9c9a044 --- /dev/null +++ b/src/fractals/mod.rs @@ -0,0 +1,4 @@ +pub mod fractal_float; +pub mod fractal_type; +pub mod fractal_kernels; +pub mod fractal_simd; \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 3ebe19d..0aeda69 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,4 @@ pub mod constant; -pub mod enums; -pub mod traits; -pub mod structs; +pub mod utils; +pub mod fractals; pub mod ui; diff --git a/src/main.rs b/src/main.rs index a1868e6..e794c6d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,9 @@ -use eframe::{egui, NativeOptions}; +use eframe::{NativeOptions, egui}; use egui::IconData; use fractals_rs::constant::{HEIGHT, WIDTH}; -use fractals_rs::structs::fractal_app::FractalApp; +use fractals_rs::ui::fractal_app::FractalApp; -#[cfg(test)] -mod benches; +const APP_ICON: &[u8] = include_bytes!("../assets/fractale.png"); fn main() -> Result<(), eframe::Error> { let icon_data: Result = load_icon(); @@ -32,8 +31,7 @@ fn main() -> Result<(), eframe::Error> { fn load_icon() -> Result { let (icon_rgba, icon_width, icon_height) = { - let icon = include_bytes!("../assets/fractale.png"); - let image = image::load_from_memory(icon) + let image = image::load_from_memory(APP_ICON) .expect("Failed to open icon path") .into_rgba8(); let (width, height) = image.dimensions(); diff --git a/src/structs/color_scheme.rs b/src/structs/color_scheme.rs deleted file mode 100644 index a16f836..0000000 --- a/src/structs/color_scheme.rs +++ /dev/null @@ -1,400 +0,0 @@ -use eframe::epaint::Color32; -use std::f32::consts::PI; - -#[derive(Clone, Debug, Copy, PartialEq, Default)] -#[repr(u8)] -/// Enum representing different color schemes for fractal rendering. -pub enum ColorScheme { - #[default] - Classic, - Hot, - Cool, - Psychedelic, - Sunset, - Electric, - Forest, - Galaxy, - Grayscale, - UltraSmooth, - DeepOcean, - PrismaticFire, - AuroralDream, - CosmicNebula, - RainbowSmooth, - VelvetShadow, - GoldenHour, -} - -impl ColorScheme { - /// Returns the name of the color scheme. - #[inline] - pub const fn name(&self) -> &'static str { - match self { - Self::Classic => "Classic", - Self::Hot => "Hot", - Self::Cool => "Cool", - Self::Grayscale => "Grayscale", - Self::Psychedelic => "Psychedelic", - Self::Sunset => "Sunset", - Self::Electric => "Electric", - Self::Forest => "Forest", - Self::Galaxy => "Galaxy", - Self::UltraSmooth => "Ultra Smooth", - Self::DeepOcean => "Deep Ocean", - Self::PrismaticFire => "Prismatic Fire", - Self::AuroralDream => "Auroral Dream", - Self::CosmicNebula => "Cosmic Nebula", - Self::RainbowSmooth => "Rainbow Smooth", - Self::VelvetShadow => "Velvet Shadow", - Self::GoldenHour => "Golden Hour", - } - } - - /// Returns all available color schemes. - #[inline] - pub const fn all() -> [Self; 17] { - [ - Self::Classic, - Self::Hot, - Self::Cool, - Self::Grayscale, - Self::Psychedelic, - Self::Sunset, - Self::Electric, - Self::Forest, - Self::Galaxy, - Self::UltraSmooth, - Self::DeepOcean, - Self::PrismaticFire, - Self::AuroralDream, - Self::CosmicNebula, - Self::RainbowSmooth, - Self::VelvetShadow, - Self::GoldenHour, - ] - } - - /// Smooth step function for smooth interpolation between two edges. - #[inline] - fn smooth_step(edge0: f32, edge1: f32, x: f32) -> f32 { - let t = ((x - edge0) / (edge1 - edge0)).clamp(0.0, 1.0); - t * t * 2.0f32.mul_add(-t, 3.0) - } - - /// Performs linear interpolation between two values. - #[inline] - fn lerp(a: f32, b: f32, t: f32) -> f32 { - t.mul_add(b - a, a) - } - - /// Converts HSV color to RGB. - #[inline] - fn hsv_to_rgb(h: f32, s: f32, v: f32) -> Color32 { - let c = v * s; - let x = c * (1.0 - ((h / 60.0) % 2.0 - 1.0).abs()); - let m = v - c; - - let (r_prime, g_prime, b_prime) = match h as u32 { - 0..=59 => (c, x, 0.0), - 60..=119 => (x, c, 0.0), - 120..=179 => (0.0, c, x), - 180..=239 => (0.0, x, c), - 240..=299 => (x, 0.0, c), - _ => (c, 0.0, x), - }; - - let r = ((r_prime + m) * 255.0) as u8; - let g = ((g_prime + m) * 255.0) as u8; - let b = ((b_prime + m) * 255.0) as u8; - - Color32::from_rgb(r, g, b) - } -} - -impl ColorScheme { - /// Converts the number of iterations to a color based on the color scheme. - #[inline] - #[must_use] - pub fn to_color32(&self, iterations: u16, max_iterations: u16) -> Color32 { - if iterations >= max_iterations { - return Color32::BLACK; - } - - let t: f32 = f32::from(iterations) / f32::from(max_iterations); - let smoothed: f32 = t.sqrt(); - - match self { - Self::Classic => { - let r: u8 = (255.0 * (0.5 + 0.5 * (4.0 * smoothed).sin())) as u8; - let g: u8 = (255.0 * (0.5 + 0.5 * (2.0 * smoothed + 2.0).sin())) as u8; - let b: u8 = (255.0 * (1.0 - smoothed).powf(0.3)) as u8; - Color32::from_rgb(r, g, b) - } - Self::Hot => { - if smoothed < 0.25 { - let t: f32 = smoothed * 4.0; - Color32::from_rgb((80.0 + 175.0 * t) as u8, (20.0 * t) as u8, 0) - } else if smoothed < 0.5 { - let t: f32 = (smoothed - 0.25) * 4.0; - Color32::from_rgb(255, (20.0 + 235.0 * t) as u8, 0) - } else if smoothed < 0.75 { - let t: f32 = (smoothed - 0.5) * 4.0; - Color32::from_rgb(255, 255, (200.0 * t) as u8) - } else { - let t: f32 = (smoothed - 0.75) * 4.0; - Color32::from_rgb(255, 255, (200.0 + 55.0 * t) as u8) - } - } - Self::Cool => { - let ice_shimmer = (smoothed * 6.0 * PI).sin() * 0.3 + 0.7; - let frost_pattern = (smoothed * 4.0 * PI).cos().abs(); - - let r = (60.0 + 95.0 * (1.0 - smoothed).powf(1.5) * ice_shimmer) as u8; - let g = (120.0 + 135.0 * smoothed.powf(0.4) * frost_pattern) as u8; - let b = (180.0 + 75.0 * smoothed.powf(0.3)) as u8; - Color32::from_rgb(r, g, b) - } - Self::Psychedelic => { - let angle: f32 = smoothed * (2.0 * PI) * 3.0; - let r: u8 = (127.5 + 127.5 * angle.sin()) as u8; - let g: u8 = (127.5 + 127.5 * (angle + 2.094).sin()) as u8; - let b: u8 = (127.5 + 127.5 * (angle + 4.188).sin()) as u8; - Color32::from_rgb(r, g, b) - } - Self::Sunset => { - if smoothed < 0.3 { - let t = smoothed / 0.3; - let r = (30.0 + 225.0 * t) as u8; - let g = (0.0 + 50.0 * t) as u8; - let b = (80.0 * (1.0 - t)) as u8; - Color32::from_rgb(r, g, b) - } else if smoothed < 0.7 { - let t = (smoothed - 0.3) / 0.4; - let r = (255.0 - 55.0 * t) as u8; - let g = (50.0 + 155.0 * t) as u8; - let b = (20.0 + 80.0 * t) as u8; - Color32::from_rgb(r, g, b) - } else { - let t = (smoothed - 0.7) / 0.3; - let r = (200.0 + 55.0 * t) as u8; - let g = (205.0 + 50.0 * t) as u8; - let b = (100.0 + 155.0 * t) as u8; - Color32::from_rgb(r, g, b) - } - } - Self::Electric => { - let pulse = (smoothed * 10.0).sin().abs(); - let r = (255.0 * (smoothed * 2.0).min(1.0) * pulse) as u8; - let g = ((smoothed - 0.2) * 2.5).clamp(0.0, 1.0) as u8; - let b = (255.0 * ((1.0 - smoothed) * 1.5).min(1.0)) as u8; - Color32::from_rgb(r, g, b) - } - Self::Forest => { - let hue_wave = (smoothed * 4.0 * PI).sin() * 0.5 + 0.5; - let depth_wave = (smoothed * 6.0 * PI).cos().abs(); - - if smoothed < 0.3 { - // Forest depths - let t = smoothed / 0.3; - let r = (10.0 + 35.0 * t * hue_wave) as u8; - let g = (20.0 + 60.0 * t) as u8; - let b = (8.0 + 25.0 * t * depth_wave) as u8; - Color32::from_rgb(r, g, b) - } else if smoothed < 0.7 { - // Mid forest - let t = (smoothed - 0.3) / 0.4; - let r = (45.0 + 80.0 * t * hue_wave) as u8; - let g = (80.0 + 100.0 * t) as u8; - let b = (25.0 + 35.0 * t * (1.0 - hue_wave * 0.6)) as u8; - Color32::from_rgb(r, g, b) - } else { - // Sunlit canopy - let t = (smoothed - 0.7) / 0.3; - let golden_hour = (hue_wave * depth_wave).powf(0.5); - let r = (125.0 + 130.0 * t * golden_hour) as u8; - let g = (180.0 + 75.0 * t) as u8; - let b = (60.0 + 40.0 * t * (1.0 - golden_hour * 0.8)) as u8; - Color32::from_rgb(r, g, b) - } - } - Self::Galaxy => { - let cycle = (smoothed * 3.0 * PI).sin().abs(); - let spiral = (smoothed * 6.0 * PI).cos() * 0.5 + 0.5; - let r = (60.0 + 140.0 * (cycle * smoothed).powf(0.8)) as u8; - let g = (15.0 + 60.0 * (1.0 - smoothed).powf(0.6)) as u8; - let b = (120.0 + 135.0 * (smoothed * spiral).powf(0.5)) as u8; - Color32::from_rgb(r, g, b) - } - Self::Grayscale => { - let gray = (255.0 * smoothed.powf(0.8)) as u8; - Color32::from_rgb(gray, gray, gray) - } - - Self::UltraSmooth => { - let phase: f32 = smoothed * (2.0 * PI); - let r: u8 = 127.0f32.mul_add(phase.sin(), 128.0) as u8; - let g: u8 = 127.0f32.mul_add((phase + 2.094).sin(), 128.0) as u8; - let b: u8 = 127.0f32.mul_add((phase + 4.188).sin(), 128.0) as u8; - Color32::from_rgb(r, g, b) - } - - Self::DeepOcean => { - let depth: f32 = smoothed.powf(1.5); - let wave: f32 = (smoothed * 8.0 * PI).sin() * 0.1 + 1.0; - - let r: u8 = (10.0 + 45.0 * depth * wave) as u8; - let g: u8 = (20.0 + 150.0 * Self::smooth_step(0.0, 1.0, depth)) as u8; - let b: u8 = 205.0f32.mul_add(Self::smooth_step(0.2, 1.0, depth), 50.0) as u8; - Color32::from_rgb(r, g, b) - } - - Self::PrismaticFire => { - let heat = smoothed.powf(0.7); - let flicker = (smoothed * 12.0).sin() * 0.05 + 1.0; - - if heat < 0.2 { - let t: f32 = heat * 5.0; - let r: u8 = - (175.0 * Self::smooth_step(0.0, 1.0, t)).mul_add(flicker, 80.0) as u8; - let g: u8 = (30.0 * t).mul_add(t, 0.0) as u8; - let b: u8 = 15.0f32.mul_add(t, 0.0) as u8; - Color32::from_rgb(r, g, b) - } else if heat < 0.5 { - let t: f32 = (heat - 0.2) / 0.3; - let smooth_t: f32 = Self::smooth_step(0.0, 1.0, t); - let r: u8 = (255.0 * flicker) as u8; - let g: u8 = (195.0 * smooth_t).mul_add(flicker, 30.0) as u8; - let b: u8 = 35.0f32.mul_add(smooth_t, 15.0) as u8; - Color32::from_rgb(r, g, b) - } else if heat < 0.8 { - let t: f32 = (heat - 0.5) / 0.3; - let smooth_t: f32 = Self::smooth_step(0.0, 1.0, t); - let r: u8 = 255; - let g: u8 = 30.0f32.mul_add(smooth_t, 225.0) as u8; - let b: u8 = (150.0 * smooth_t).mul_add(flicker, 50.0) as u8; - Color32::from_rgb(r, g, b) - } else { - let t: f32 = (heat - 0.8) / 0.2; - let smooth_t: f32 = Self::smooth_step(0.0, 1.0, t); - let r: u8 = 255; - let g: u8 = 255; - let b: u8 = 55.0f32.mul_add(smooth_t, 200.0) as u8; - Color32::from_rgb(r, g, b) - } - } - - Self::AuroralDream => { - let wave1: f32 = (smoothed * 3.0 * PI).sin(); - let wave2: f32 = (smoothed * 5.0).mul_add(PI, 1.0).sin(); - let wave3: f32 = (smoothed * 7.0).mul_add(PI, 2.0).sin(); - - let r: u8 = (50.0 - + 100.0 - * 0.2f32 - .mul_add(wave3, 0.3f32.mul_add(wave1, 0.5)) - .clamp(0.0, 1.0)) as u8; - let g: u8 = - 155.0f32.mul_add(0.3f32.mul_add(wave2, 0.7).clamp(0.0, 1.0), 100.0) as u8; - let b: u8 = - 175.0f32.mul_add((0.4 * wave1).mul_add(wave2, 0.6).clamp(0.0, 1.0), 80.0) as u8; - Color32::from_rgb(r, g, b) - } - - Self::CosmicNebula => { - let cosmic_t: f32 = smoothed.powf(0.6); - let dust_pattern: f32 = (cosmic_t * 4.0 * PI).sin().abs(); - let gas_pattern: f32 = (cosmic_t * 6.0).mul_add(PI, 1.5).cos().abs(); - - let r: u8 = - 175.0f32.mul_add(Self::lerp(dust_pattern, gas_pattern, cosmic_t), 80.0) as u8; - let g: u8 = (150.0 * cosmic_t).mul_add(dust_pattern, 40.0) as u8; - let b: u8 = (135.0 * gas_pattern).mul_add(cosmic_t.sqrt(), 120.0) as u8; - Color32::from_rgb(r, g, b) - } - - Self::RainbowSmooth => { - let hue: f32 = smoothed * 360.0; - let saturation: f32 = 0.2f32.mul_add((smoothed * 2.0 * PI).sin().abs(), 0.8); - let value: f32 = 0.1f32.mul_add((smoothed * 3.0 * PI).cos().abs(), 0.9); - - Self::hsv_to_rgb(hue, saturation, value) - } - - Self::VelvetShadow => { - let depth: f32 = Self::smooth_step(0.0, 1.0, smoothed); - let texture: f32 = (smoothed * 10.0 * PI).sin().mul_add(0.08, 1.0); - - let r: u8 = (120.0 * depth.powi(2)).mul_add(texture, 20.0) as u8; - let g: u8 = 80.0f32.mul_add(depth.powf(1.5), 10.0) as u8; - let b: u8 = (180.0 * depth).mul_add(texture, 40.0) as u8; - Color32::from_rgb(r, g, b) - } - - Self::GoldenHour => { - let warmth: f32 = Self::smooth_step(0.0, 1.0, smoothed); - let glow: f32 = (smoothed * 4.0 * PI).sin().abs().mul_add(0.1, 0.9); - - if warmth < 0.4 { - let t: f32 = warmth / 0.4; - let smooth_t: f32 = Self::smooth_step(0.0, 1.0, t); - let r: u8 = (180.0 * smooth_t).mul_add(glow, 40.0) as u8; - let g: u8 = (100.0 * smooth_t).mul_add(glow, 20.0) as u8; - let b: u8 = (80.0 * (1.0 - smooth_t)) as u8; - Color32::from_rgb(r, g, b) - } else if warmth < 0.8 { - let t: f32 = (warmth - 0.4) / 0.4; - let smooth_t: f32 = Self::smooth_step(0.0, 1.0, t); - let r: u8 = (35.0 * smooth_t).mul_add(glow, 220.0) as u8; - let g: u8 = (100.0 * smooth_t).mul_add(glow, 120.0) as u8; - let b: u8 = 70.0f32.mul_add(smooth_t, 30.0) as u8; - Color32::from_rgb(r, g, b) - } else { - let t: f32 = (warmth - 0.8) / 0.2; - let smooth_t: f32 = Self::smooth_step(0.0, 1.0, t); - let r: u8 = 255; - let g: u8 = 35.0f32.mul_add(smooth_t, 220.0) as u8; - let b: u8 = (100.0 * smooth_t).mul_add(glow, 100.0) as u8; - Color32::from_rgb(r, g, b) - } - } - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_color_scheme_names() { - assert_eq!(ColorScheme::Classic.name(), "Classic"); - assert_eq!(ColorScheme::Hot.name(), "Hot"); - assert_eq!(ColorScheme::Cool.name(), "Cool"); - assert_eq!(ColorScheme::Grayscale.name(), "Grayscale"); - assert_eq!(ColorScheme::Psychedelic.name(), "Psychedelic"); - assert_eq!(ColorScheme::Sunset.name(), "Sunset"); - assert_eq!(ColorScheme::Electric.name(), "Electric"); - assert_eq!(ColorScheme::Forest.name(), "Forest"); - assert_eq!(ColorScheme::Galaxy.name(), "Galaxy"); - } - - #[test] - fn test_hsv_to_rgb() { - let color = ColorScheme::hsv_to_rgb(0.0, 1.0, 1.0); - assert_eq!(color, Color32::from_rgb(255, 0, 0)); // Red - - let color = ColorScheme::hsv_to_rgb(120.0, 1.0, 1.0); - assert_eq!(color, Color32::from_rgb(0, 255, 0)); // Green - - let color = ColorScheme::hsv_to_rgb(240.0, 1.0, 1.0); - assert_eq!(color, Color32::from_rgb(0, 0, 255)); // Blue - } - - #[test] - fn test_smooth_step() { - assert_eq!(ColorScheme::smooth_step(0.0, 1.0, 0.0), 0.0); - assert_eq!(ColorScheme::smooth_step(0.0, 1.0, 1.0), 1.0); - assert!((ColorScheme::smooth_step(0.0, 1.0, 0.5) - 0.5).abs() < 0.01); - assert!((ColorScheme::smooth_step(0.2, 0.8, 0.5) - 0.5).abs() < 0.01); - } -} diff --git a/src/structs/fractal_app.rs b/src/structs/fractal_app.rs deleted file mode 100644 index 2bc17ab..0000000 --- a/src/structs/fractal_app.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::enums::fractal_type::FractalType; -use crate::enums::precision_mode::PrecisionMode; -use crate::structs::color_scheme::ColorScheme; -use crate::structs::point::Point; - -/// The main application state for the fractal viewer. -pub struct FractalApp { - pub fractal_type: FractalType, - pub max_iterations: u16, - pub center: Point, - pub zoom: f64, - pub julia_c: Point, - pub needs_update: bool, - pub texture: Option, - pub image_size: (u32, u32), - pub is_dragging: bool, - pub show_settings: bool, - pub precision_mode: PrecisionMode, - pub color_scheme: ColorScheme, -} diff --git a/src/structs/mod.rs b/src/structs/mod.rs deleted file mode 100644 index bae8046..0000000 --- a/src/structs/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod point; -pub mod color_scheme; -pub mod fractal_app; -mod fractal_float; diff --git a/src/traits/fractal_float.rs b/src/traits/fractal_float.rs deleted file mode 100644 index a2538d2..0000000 --- a/src/traits/fractal_float.rs +++ /dev/null @@ -1,12 +0,0 @@ -/// A trait for representing floating-point numbers in a fractal context. -pub trait FractalFloat: Clone + PartialOrd { - fn zero() -> Self; // Represents the zero value. - fn two() -> Self; // Represents the two value. - fn four() -> Self; // Represents the four value. - fn abs(&self) -> Self; // Returns the absolute value. - fn from_f64(val: f64) -> Self; // Converts a f64 to the implementing type. - fn to_f64(&self) -> f64; // Converts the implementing type to f64. - fn add(&self, other: &Self) -> Self; // Adds two values. - fn sub(&self, other: &Self) -> Self; // Subtracts two values. - fn mul(&self, other: &Self) -> Self; // Multiplies two values. -} diff --git a/src/traits/mod.rs b/src/traits/mod.rs deleted file mode 100644 index c59cac9..0000000 --- a/src/traits/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ - -pub mod fractal_float; \ No newline at end of file diff --git a/src/ui/fractal_app.rs b/src/ui/fractal_app.rs index e32aac2..a3c7a0d 100644 --- a/src/ui/fractal_app.rs +++ b/src/ui/fractal_app.rs @@ -1,11 +1,27 @@ -use crate::enums::fractal_type::FractalType; -use crate::enums::precision_mode::PrecisionMode; -use crate::structs::color_scheme::ColorScheme; -use crate::structs::fractal_app::FractalApp; -use crate::structs::point::Point; +use crate::utils::precision_mode::PrecisionMode; +use crate::fractals::fractal_type::FractalType; +use crate::fractals::fractal_simd; +use crate::utils::color_scheme::ColorScheme; +use crate::utils::point::Point; use egui::{Color32, Vec2}; use rayon::prelude::*; +/// The main application state for the fractal viewer. +pub struct FractalApp { + pub fractal_type: FractalType, + pub max_iterations: u16, + pub center: Point, + pub zoom: f64, + pub julia_c: Point, + pub needs_update: bool, + pub texture: Option, + pub image_size: (u32, u32), + pub is_dragging: bool, + pub show_settings: bool, + pub precision_mode: PrecisionMode, + pub color_scheme: ColorScheme, +} + impl Default for FractalApp { /// Creates a default instance of `FractalApp` with predefined settings. #[inline] @@ -29,6 +45,11 @@ impl Default for FractalApp { impl FractalApp { /// Generates a fractal image based on the current settings. + /// Highly optimized with: + /// - Row-based parallelization + /// - SIMD vectorization (4x f32 or 2x f64 pixels per operation) + /// - Direct RGBA buffer generation + /// - FMA operations and loop unrolling #[inline] #[must_use] pub fn generate_fractal_image(&self) -> egui::ColorImage { @@ -40,39 +61,181 @@ impl FractalApp { } let (x_scale, y_scale, x_min, y_min) = self.compute_scale(); + let total_pixels = width * height; + + // Pre-allocate RGBA buffer for direct writing + let mut rgba_buffer = vec![0u8; total_pixels * 4]; + + // Row-based parallelization with SIMD optimization + rgba_buffer + .par_chunks_mut(width * 4) + .enumerate() + .for_each(|(y, row_chunk)| { + let cy = (y as f64).mul_add(y_scale, y_min); + + match self.precision_mode { + PrecisionMode::Fast => { + // SIMD processing for f32: process 4 pixels at a time + let cy_f32 = cy as f32; + let mut x = 0; + + // Process in chunks of 4 with SIMD + while x + 4 <= width { + let cx0 = (x as f64).mul_add(x_scale, x_min) as f32; + let cx1 = ((x + 1) as f64).mul_add(x_scale, x_min) as f32; + let cx2 = ((x + 2) as f64).mul_add(x_scale, x_min) as f32; + let cx3 = ((x + 3) as f64).mul_add(x_scale, x_min) as f32; + + let cx_arr = [cx0, cx1, cx2, cx3]; + let cy_arr = [cy_f32; 4]; + + let iterations = match self.fractal_type { + FractalType::Mandelbrot => { + fractal_simd::mandelbrot_simd_f32(&cx_arr, &cy_arr, self.max_iterations) + } + FractalType::Julia => { + fractal_simd::julia_simd_f32( + &cx_arr, + &cy_arr, + self.julia_c.x as f32, + self.julia_c.y as f32, + self.max_iterations, + ) + } + FractalType::BurningShip => { + fractal_simd::burning_ship_simd_f32(&cx_arr, &cy_arr, self.max_iterations) + } + FractalType::Tricorn => { + fractal_simd::tricorn_simd_f32(&cx_arr, &cy_arr, self.max_iterations) + } + }; + + // Write 4 pixels + for (i, &iter) in iterations.iter().enumerate() { + let color = self.color_scheme.to_color32(iter, self.max_iterations); + let pixel_idx = (x + i) * 4; + row_chunk[pixel_idx] = color.r(); + row_chunk[pixel_idx + 1] = color.g(); + row_chunk[pixel_idx + 2] = color.b(); + row_chunk[pixel_idx + 3] = color.a(); + } + + x += 4; + } - let pixels: Vec = (0..height) - .into_par_iter() - .flat_map(|y| { - (0..width).into_par_iter().map(move |x| { - let cx = (x as f64).mul_add(x_scale, x_min); - let cy = (y as f64).mul_add(y_scale, y_min); - - let iterations = self.fractal_type.iterations( - cx, - cy, - self.max_iterations, - &self.julia_c, - self.precision_mode, - ); - - self.color_scheme - .to_color32(iterations, self.max_iterations) - }) - }) - .collect(); - - egui::ColorImage::from_rgba_unmultiplied( - [width, height], - &pixels - .into_iter() - .flat_map(|c| [c.r(), c.g(), c.b(), c.a()]) - .collect::>(), - ) + // Handle remaining pixels (< 4) with scalar code + while x < width { + let cx = (x as f64).mul_add(x_scale, x_min); + let iterations = self.fractal_type.iterations( + cx, + cy, + self.max_iterations, + &self.julia_c, + self.precision_mode, + ); + let color = self.color_scheme.to_color32(iterations, self.max_iterations); + let pixel_idx = x * 4; + row_chunk[pixel_idx] = color.r(); + row_chunk[pixel_idx + 1] = color.g(); + row_chunk[pixel_idx + 2] = color.b(); + row_chunk[pixel_idx + 3] = color.a(); + x += 1; + } + } + PrecisionMode::High => { + // SIMD processing for f64: process 2 pixels at a time + let mut x = 0; + + // Process in chunks of 2 with SIMD + while x + 2 <= width { + let cx0 = (x as f64).mul_add(x_scale, x_min); + let cx1 = ((x + 1) as f64).mul_add(x_scale, x_min); + + let cx_arr = [cx0, cx1]; + let cy_arr = [cy; 2]; + + let iterations = match self.fractal_type { + FractalType::Mandelbrot => { + fractal_simd::mandelbrot_simd_f64(&cx_arr, &cy_arr, self.max_iterations) + } + FractalType::Julia => { + fractal_simd::julia_simd_f64( + &cx_arr, + &cy_arr, + self.julia_c.x, + self.julia_c.y, + self.max_iterations, + ) + } + FractalType::BurningShip => { + fractal_simd::burning_ship_simd_f64(&cx_arr, &cy_arr, self.max_iterations) + } + FractalType::Tricorn => { + fractal_simd::tricorn_simd_f64(&cx_arr, &cy_arr, self.max_iterations) + } + }; + + // Write 2 pixels + for (i, &iter) in iterations.iter().enumerate() { + let color = self.color_scheme.to_color32(iter, self.max_iterations); + let pixel_idx = (x + i) * 4; + row_chunk[pixel_idx] = color.r(); + row_chunk[pixel_idx + 1] = color.g(); + row_chunk[pixel_idx + 2] = color.b(); + row_chunk[pixel_idx + 3] = color.a(); + } + + x += 2; + } + + // Handle remaining pixel with scalar code + while x < width { + let cx = (x as f64).mul_add(x_scale, x_min); + let iterations = self.fractal_type.iterations( + cx, + cy, + self.max_iterations, + &self.julia_c, + self.precision_mode, + ); + let color = self.color_scheme.to_color32(iterations, self.max_iterations); + let pixel_idx = x * 4; + row_chunk[pixel_idx] = color.r(); + row_chunk[pixel_idx + 1] = color.g(); + row_chunk[pixel_idx + 2] = color.b(); + row_chunk[pixel_idx + 3] = color.a(); + x += 1; + } + } + #[cfg(feature = "f128")] + PrecisionMode::UltraHigh => { + // Ultra-high precision mode using Decimal (f128) + // No SIMD optimization, but extreme precision for deep zoom + for x in 0..width { + let cx = (x as f64).mul_add(x_scale, x_min); + let iterations = self.fractal_type.iterations( + cx, + cy, + self.max_iterations, + &self.julia_c, + self.precision_mode, + ); + let color = self.color_scheme.to_color32(iterations, self.max_iterations); + let pixel_idx = x * 4; + row_chunk[pixel_idx] = color.r(); + row_chunk[pixel_idx + 1] = color.g(); + row_chunk[pixel_idx + 2] = color.b(); + row_chunk[pixel_idx + 3] = color.a(); + } + } + } + }); + + egui::ColorImage::from_rgba_unmultiplied([width, height], &rgba_buffer) } /// Computes the scale factors and min/max coordinates for the fractal view. - #[inline] + #[inline(always)] fn compute_scale(&self) -> (f64, f64, f64, f64) { let width: u32 = self.image_size.0; let height: u32 = self.image_size.1; diff --git a/src/ui/frame_actions.rs b/src/ui/frame_actions.rs index 7608427..8c46103 100644 --- a/src/ui/frame_actions.rs +++ b/src/ui/frame_actions.rs @@ -1,8 +1,8 @@ -use crate::enums::fractal_type::FractalType; -use crate::enums::precision_mode::PrecisionMode; -use crate::structs::color_scheme::ColorScheme; -use crate::structs::fractal_app::FractalApp; -use crate::structs::point::Point; +use crate::utils::precision_mode::PrecisionMode; +use crate::fractals::fractal_type::FractalType; +use crate::utils::color_scheme::ColorScheme; +use crate::utils::point::Point; +use crate::ui::fractal_app::FractalApp; use eframe::emath::{Pos2, Rect, Vec2}; use eframe::epaint::Color32; use egui::{ColorImage, TextureOptions}; @@ -86,51 +86,59 @@ impl eframe::App for FractalApp { if self.show_settings { egui::SidePanel::left("settings_panel") .resizable(true) - .default_width(250.0) + .default_width(300.0) + .min_width(280.0) .show(ctx, |ui| { - ui.heading("πŸŽ›οΈ Controls"); + ui.add_space(8.0); + ui.vertical_centered(|ui| { + ui.heading(egui::RichText::new("🎨 Fractal Studio").size(20.0).strong()); + ui.label(egui::RichText::new("Professional Fractal Explorer").size(11.0).weak()); + }); + ui.add_space(8.0); ui.separator(); - ui.group(|ui| { - ui.label("Fractal Parameters"); + egui::Frame::new() + .fill(ui.visuals().extreme_bg_color) + .inner_margin(10.0) + .corner_radius(6.0) + .show(ui, |ui| { + ui.label(egui::RichText::new("βš™οΈ Render Settings").size(14.0).strong()); + ui.add_space(6.0); - ui.horizontal(|ui| { - ui.label("Iterations:"); - if ui - .add( - egui::Slider::new(&mut self.max_iterations, 10..=3000) - .step_by(1.0) - .suffix(" iters"), - ) - .changed() - { - self.needs_update = true; - } - }); + ui.label(egui::RichText::new("Quality").size(12.0)); + if ui + .add( + egui::Slider::new(&mut self.max_iterations, 10..=3000) + .text("Iterations") + .logarithmic(true), + ) + .changed() + { + self.needs_update = true; + } + ui.add_space(4.0); + ui.label(egui::RichText::new("Resolution").size(12.0)); ui.horizontal(|ui| { - ui.label("Width:"); + ui.label("W:"); if ui .add( egui::DragValue::new(&mut self.image_size.0) .range(100..=8192) .suffix(" px") - .speed(1.0), + .speed(10.0), ) .changed() { self.needs_update = true; } - }); - - ui.horizontal(|ui| { - ui.label("Height:"); + ui.label("H:"); if ui .add( egui::DragValue::new(&mut self.image_size.1) .range(100..=8192) .suffix(" px") - .speed(1.0), + .speed(10.0), ) .changed() { @@ -138,15 +146,16 @@ impl eframe::App for FractalApp { } }); - // Change precision mode + ui.add_space(6.0); + ui.label(egui::RichText::new("Precision Mode").size(12.0)); ui.horizontal(|ui| { - ui.label("Precision Mode:"); if ui .selectable_value( &mut self.precision_mode, PrecisionMode::Fast, - "Fast (float 32)", + "πŸš€ Fast", ) + .on_hover_text("32-bit float - fastest rendering") .clicked() { self.needs_update = true; @@ -155,20 +164,42 @@ impl eframe::App for FractalApp { .selectable_value( &mut self.precision_mode, PrecisionMode::High, - "High (float 64)", + "🎯 High", + ) + .on_hover_text("64-bit float - deeper zoom capability") + .clicked() + { + self.needs_update = true; + } + #[cfg(feature = "f128")] + if ui + .selectable_value( + &mut self.precision_mode, + PrecisionMode::UltraHigh, + "πŸ”¬ Ultra", ) + .on_hover_text("128-bit decimal - extreme zoom for deep exploration") .clicked() { self.needs_update = true; } }); - if self.fractal_type == FractalType::Julia { - ui.separator(); - ui.label("Julia Constant (c):"); + }); + if self.fractal_type == FractalType::Julia { + ui.add_space(8.0); + egui::Frame::NONE + .fill(ui.visuals().extreme_bg_color) + .inner_margin(10.0) + .corner_radius(6.0) + .show(ui, |ui| { + ui.label(egui::RichText::new("πŸŒ€ Julia Parameters").size(14.0).strong()); + ui.add_space(6.0); + + ui.label(egui::RichText::new("Constant (c)").size(12.0)); ui.horizontal(|ui| { - ui.label("Real:"); + ui.label("Re:"); if ui .add( egui::DragValue::new(&mut self.julia_c.x) @@ -182,7 +213,7 @@ impl eframe::App for FractalApp { }); ui.horizontal(|ui| { - ui.label("Imag:"); + ui.label("Im:"); if ui .add( egui::DragValue::new(&mut self.julia_c.y) @@ -195,58 +226,82 @@ impl eframe::App for FractalApp { } }); - ui.separator(); - ui.label("Presets:"); + ui.add_space(6.0); + ui.label(egui::RichText::new("Presets").size(12.0)); ui.horizontal_wrapped(|ui| { let presets = [ - ("Dragon", (-0.7269, 0.1889)), - ("Spiral", (-0.8, 0.156)), - ("Lightning", (-0.74529, 0.11307)), - ("Dendrite", (-0.235, 0.827)), + ("πŸ‰ Dragon", (-0.7269, 0.1889)), + ("πŸŒ€ Spiral", (-0.8, 0.156)), + ("⚑ Lightning", (-0.74529, 0.11307)), + ("🌿 Dendrite", (-0.235, 0.827)), + ("❄️ Snowflake", (-0.4, 0.6)), + ("πŸ”₯ Fire", (0.285, 0.01)), ]; for (name, c) in presets { - if ui.small_button(name).clicked() { + if ui.button(name).clicked() { self.julia_c = Point::new(c.0, c.1); self.needs_update = true; } } }); - } - }); + }); + } - ui.add_space(10.0); + ui.add_space(8.0); - ui.group(|ui| { - ui.label("Navigation"); + egui::Frame::new() + .fill(ui.visuals().extreme_bg_color) + .inner_margin(10.0) + .corner_radius(6.0) + .show(ui, |ui| { + ui.label(egui::RichText::new("πŸ—ΊοΈ Navigation").size(14.0).strong()); + ui.add_space(6.0); - if ui.button("🏠 Reset View").clicked() { + if ui.button(egui::RichText::new("🏠 Reset View").size(13.0)).clicked() { self.center = self.fractal_type.default_center(); self.zoom = 1.0; self.needs_update = true; } + ui.add_space(6.0); ui.separator(); - ui.label("Current Position:"); - ui.monospace(format!("X: {:.6}", self.center.x)); - ui.monospace(format!("Y: {:.6}", self.center.y)); - ui.monospace(format!("Zoom: {:.2e}", self.zoom)); - ui.monospace(format!("Fractal: {}", self.fractal_type.name())); - ui.monospace(format!( - "Resolution: {}", - format!("{}x{}", self.image_size.0, self.image_size.1) - )); + ui.label(egui::RichText::new("Current State").size(12.0).weak()); + egui::Grid::new("info_grid") + .num_columns(2) + .spacing([10.0, 4.0]) + .show(ui, |ui| { + ui.label("Position:"); + ui.monospace(format!("({:.6}, {:.6})", self.center.x, self.center.y)); + ui.end_row(); + + ui.label("Zoom:"); + ui.monospace(format!("{:.2e}Γ—", self.zoom)); + ui.end_row(); + + ui.label("Fractal:"); + ui.label(self.fractal_type.name()); + ui.end_row(); + + ui.label("Size:"); + ui.monospace(format!("{}Γ—{}", self.image_size.0, self.image_size.1)); + ui.end_row(); + }); }); - ui.add_space(10.0); - - ui.group(|ui| { - ui.label("Instructions"); - ui.separator(); - ui.small("β€’ Click and drag to pan"); - ui.small("β€’ Scroll to zoom in/out"); - ui.small("β€’ Right-click for context menu"); - ui.small("β€’ Use menu bar to switch fractals"); + ui.add_space(8.0); + + egui::Frame::new() + .fill(ui.visuals().faint_bg_color) + .inner_margin(8.0) + .corner_radius(4.0) + .show(ui, |ui| { + ui.label(egui::RichText::new("πŸ’‘ Quick Tips").size(12.0).strong()); + ui.add_space(4.0); + ui.label("πŸ–±οΈ Drag to pan view"); + ui.label("πŸ” Scroll to zoom in/out"); + ui.label("πŸ–±οΈ Double-click to zoom to point"); + ui.label("πŸ–±οΈ Right-click for context menu"); }); }); } diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 407be5f..edc0e53 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,2 +1,2 @@ +pub mod fractal_app; pub mod frame_actions; -pub mod fractal_app; \ No newline at end of file diff --git a/src/utils/color_scheme.rs b/src/utils/color_scheme.rs new file mode 100644 index 0000000..f32e919 --- /dev/null +++ b/src/utils/color_scheme.rs @@ -0,0 +1,829 @@ +use eframe::epaint::Color32; +use std::f32::consts::PI; + +#[derive(Clone, Debug, Copy, PartialEq, Default)] +#[repr(u8)] +/// Enum representing different color schemes for fractal rendering. +pub enum ColorScheme { + #[default] + Classic, + Hot, + Cool, + Psychedelic, + Sunset, + Electric, + Forest, + Galaxy, + Grayscale, + UltraSmooth, + DeepOcean, + PrismaticFire, + AuroralDream, + CosmicNebula, + RainbowSmooth, + VelvetShadow, + GoldenHour, + MoltenLava, + IcebergGlacier, + NorthernLights, + TropicalParadise, + VaporwaveNeon, + MidnightStars, + CherryBlossom, + QuantumPlasma, + OpalDreams, + DragonFire, + AmethystCavern, + SakuraRain, + ElectricStorm, +} + +impl ColorScheme { + /// Returns the name of the color scheme. + #[inline] + pub const fn name(&self) -> &'static str { + match self { + Self::Classic => "Classic", + Self::Hot => "Hot", + Self::Cool => "Cool", + Self::Grayscale => "Grayscale", + Self::Psychedelic => "Psychedelic", + Self::Sunset => "Sunset", + Self::Electric => "Electric", + Self::Forest => "Forest", + Self::Galaxy => "Galaxy", + Self::UltraSmooth => "Ultra Smooth", + Self::DeepOcean => "Deep Ocean", + Self::PrismaticFire => "Prismatic Fire", + Self::AuroralDream => "Auroral Dream", + Self::CosmicNebula => "Cosmic Nebula", + Self::RainbowSmooth => "Rainbow Smooth", + Self::VelvetShadow => "Velvet Shadow", + Self::GoldenHour => "Golden Hour", + Self::MoltenLava => "Molten Lava", + Self::IcebergGlacier => "Iceberg Glacier", + Self::NorthernLights => "Northern Lights", + Self::TropicalParadise => "Tropical Paradise", + Self::VaporwaveNeon => "Vaporwave Neon", + Self::MidnightStars => "Midnight Stars", + Self::CherryBlossom => "Cherry Blossom", + Self::QuantumPlasma => "Quantum Plasma", + Self::OpalDreams => "Opal Dreams", + Self::DragonFire => "Dragon Fire", + Self::AmethystCavern => "Amethyst Cavern", + Self::SakuraRain => "Sakura Rain", + Self::ElectricStorm => "Electric Storm", + } + } + + /// Returns all available color schemes. + #[inline] + pub const fn all() -> [Self; 30] { + [ + Self::Classic, + Self::Hot, + Self::Cool, + Self::Grayscale, + Self::Psychedelic, + Self::Sunset, + Self::Electric, + Self::Forest, + Self::Galaxy, + Self::UltraSmooth, + Self::DeepOcean, + Self::PrismaticFire, + Self::AuroralDream, + Self::CosmicNebula, + Self::RainbowSmooth, + Self::VelvetShadow, + Self::GoldenHour, + Self::MoltenLava, + Self::IcebergGlacier, + Self::NorthernLights, + Self::TropicalParadise, + Self::VaporwaveNeon, + Self::MidnightStars, + Self::CherryBlossom, + Self::QuantumPlasma, + Self::OpalDreams, + Self::DragonFire, + Self::AmethystCavern, + Self::SakuraRain, + Self::ElectricStorm, + ] + } + + /// Smooth step function for smooth interpolation between two edges. + #[inline(always)] + fn smooth_step(edge0: f32, edge1: f32, x: f32) -> f32 { + let t = ((x - edge0) / (edge1 - edge0)).clamp(0.0, 1.0); + t * t * 2.0f32.mul_add(-t, 3.0) + } + + /// Performs linear interpolation between two values. + #[inline(always)] + fn lerp(a: f32, b: f32, t: f32) -> f32 { + t.mul_add(b - a, a) + } + + /// Converts HSV color to RGB. + #[inline(always)] + fn hsv_to_rgb(h: f32, s: f32, v: f32) -> Color32 { + let c = v * s; + let x = c * (1.0 - ((h / 60.0) % 2.0 - 1.0).abs()); + let m = v - c; + + let (r_prime, g_prime, b_prime) = match h as u32 { + 0..=59 => (c, x, 0.0), + 60..=119 => (x, c, 0.0), + 120..=179 => (0.0, c, x), + 180..=239 => (0.0, x, c), + 240..=299 => (x, 0.0, c), + _ => (c, 0.0, x), + }; + + let r = ((r_prime + m) * 255.0) as u8; + let g = ((g_prime + m) * 255.0) as u8; + let b = ((b_prime + m) * 255.0) as u8; + + Color32::from_rgb(r, g, b) + } +} + +impl ColorScheme { + /// Enhanced smooth coloring function for ultra-high quality rendering + /// Uses multiple smoothing techniques for elimination of color banding + #[inline(always)] + fn ultra_smooth(t: f32) -> f32 { + // Triple smoothing for maximum quality + let smooth1 = t.sqrt(); + let smooth2 = smooth1.sqrt(); + let smooth3 = Self::smooth_step(0.0, 1.0, smooth1); + + // Blend different smoothing techniques using FMA + 0.3f32.mul_add(smooth2, 0.5f32.mul_add(smooth1, smooth3 * 0.2)) + } + + /// Converts the number of iterations to a color based on the color scheme. + #[inline(always)] + #[must_use] + pub fn to_color32(&self, iterations: u16, max_iterations: u16) -> Color32 { + if iterations >= max_iterations { + return Color32::BLACK; + } + + let t: f32 = f32::from(iterations) / f32::from(max_iterations); + + // Use ultra-smooth algorithm for better quality + let smoothed: f32 = Self::ultra_smooth(t); + + match self { + Self::Classic => { + // Refined classic palette with better color harmony + let wave1 = (smoothed * 6.0 * PI).sin(); + let wave2 = (smoothed * 4.0 * PI + 1.0).sin(); + let depth = smoothed.powf(0.7); + + let r: u8 = (128.0 + 127.0 * wave1 * depth) as u8; + let g: u8 = (100.0 + 155.0 * wave2 * (1.0 - depth * 0.5)) as u8; + let b: u8 = (180.0 + 75.0 * (1.0 - depth).powf(0.4)) as u8; + Color32::from_rgb(r, g, b) + } + Self::Hot => { + // Enhanced hot palette with realistic heat gradients + let heat = smoothed.powf(0.65); + let flicker = (smoothed * 12.0 * PI).sin() * 0.03 + 0.97; + + if heat < 0.2 { + // Deep ember + let t = heat * 5.0; + let r = (100.0 + 155.0 * t * flicker) as u8; + let g = (10.0 + 25.0 * t) as u8; + let b = 0; + Color32::from_rgb(r, g, b) + } else if heat < 0.45 { + // Red hot + let t = (heat - 0.2) / 0.25; + let smooth_t = Self::smooth_step(0.0, 1.0, t); + let r = 255; + let g = (35.0 + 80.0 * smooth_t) as u8; + let b = 0; + Color32::from_rgb(r, g, b) + } else if heat < 0.75 { + // Orange to yellow + let t = (heat - 0.45) / 0.3; + let smooth_t = Self::smooth_step(0.0, 1.0, t); + let r = 255; + let g = (115.0 + 140.0 * smooth_t * flicker) as u8; + let b = (50.0 * smooth_t) as u8; + Color32::from_rgb(r, g, b) + } else { + // White hot + let t = (heat - 0.75) / 0.25; + let smooth_t = Self::smooth_step(0.0, 1.0, t); + let r = 255; + let g = 255; + let b = (50.0 + 205.0 * smooth_t) as u8; + Color32::from_rgb(r, g, b) + } + } + Self::Cool => { + // Enhanced cool palette with icy brilliance + let ice = smoothed.powf(0.8); + let shimmer = (ice * 10.0 * PI).sin() * 0.15 + 0.85; + let crystalline = (ice * 7.0 * PI).cos().abs(); + let frost = Self::smooth_step(0.0, 1.0, ice); + + let r = (80.0 + 100.0 * (1.0 - ice).powf(1.2) * shimmer) as u8; + let g = (150.0 + 105.0 * frost * crystalline) as u8; + let b = (200.0 + 55.0 * ice * shimmer) as u8; + Color32::from_rgb(r, g, b) + } + Self::Psychedelic => { + // Enhanced psychedelic with multiple frequency layers + let phase = smoothed.powf(0.6); + let freq1 = (phase * 5.0 * PI).sin(); + let freq2 = (phase * 7.0 * PI + 2.094).sin(); + let freq3 = (phase * 11.0 * PI + 4.188).sin(); + let intensity = (phase * 3.0 * PI).sin().abs() * 0.3 + 0.7; + + let r: u8 = (128.0 + 127.0 * freq1 * intensity) as u8; + let g: u8 = (128.0 + 127.0 * freq2 * intensity) as u8; + let b: u8 = (128.0 + 127.0 * freq3 * intensity) as u8; + Color32::from_rgb(r, g, b) + } + Self::Sunset => { + // Majestic sunset with atmospheric scattering + let sun = smoothed.powf(0.65); + let atmosphere = (sun * 4.0 * PI).sin() * 0.5 + 0.5; + let glow = Self::smooth_step(0.0, 1.0, sun); + + if sun < 0.25 { + // Deep twilight blue + let t = sun / 0.25; + let smooth_t = Self::smooth_step(0.0, 1.0, t); + let r = (40.0 + 80.0 * smooth_t) as u8; + let g = (20.0 + 60.0 * smooth_t) as u8; + let b = (100.0 + 55.0 * smooth_t * atmosphere) as u8; + Color32::from_rgb(r, g, b) + } else if sun < 0.5 { + // Purple to magenta transition + let t = (sun - 0.25) / 0.25; + let smooth_t = Self::smooth_step(0.0, 1.0, t); + let r = (120.0 + 135.0 * smooth_t) as u8; + let g = (80.0 + 70.0 * smooth_t * atmosphere) as u8; + let b = (155.0 - 50.0 * smooth_t) as u8; + Color32::from_rgb(r, g, b) + } else if sun < 0.75 { + // Orange to golden + let t = (sun - 0.5) / 0.25; + let smooth_t = Self::smooth_step(0.0, 1.0, t); + let r = 255; + let g = (150.0 + 80.0 * smooth_t * glow) as u8; + let b = (105.0 - 50.0 * smooth_t) as u8; + Color32::from_rgb(r, g, b) + } else { + // Bright sky to white + let t = (sun - 0.75) / 0.25; + let smooth_t = Self::smooth_step(0.0, 1.0, t); + let r = 255; + let g = (230.0 + 25.0 * smooth_t) as u8; + let b = (55.0 + 180.0 * smooth_t * atmosphere) as u8; + Color32::from_rgb(r, g, b) + } + } + Self::Electric => { + // High voltage electric arcs with lightning effect + let voltage = smoothed.powf(0.55); + let arc = (voltage * 15.0 * PI).sin().abs(); + let spark = if (voltage * 25.0 * PI).sin() > 0.92 { 1.5 } else { 1.0 }; + let discharge = Self::smooth_step(0.0, 1.0, voltage); + + let r = (150.0 + 105.0 * discharge * arc * spark) as u8; + let g = (80.0 + 120.0 * (1.0 - voltage * 0.6) * spark) as u8; + let b = (220.0 + 35.0 * (1.0 - discharge).powf(0.5)) as u8; + Color32::from_rgb(r, g, b) + } + Self::Forest => { + let hue_wave = (smoothed * 4.0 * PI).sin() * 0.5 + 0.5; + let depth_wave = (smoothed * 6.0 * PI).cos().abs(); + + if smoothed < 0.3 { + // Forest depths + let t = smoothed / 0.3; + let r = (10.0 + 35.0 * t * hue_wave) as u8; + let g = (20.0 + 60.0 * t) as u8; + let b = (8.0 + 25.0 * t * depth_wave) as u8; + Color32::from_rgb(r, g, b) + } else if smoothed < 0.7 { + // Mid forest + let t = (smoothed - 0.3) / 0.4; + let r = (45.0 + 80.0 * t * hue_wave) as u8; + let g = (80.0 + 100.0 * t) as u8; + let b = (25.0 + 35.0 * t * (1.0 - hue_wave * 0.6)) as u8; + Color32::from_rgb(r, g, b) + } else { + // Sunlit canopy + let t = (smoothed - 0.7) / 0.3; + let golden_hour = (hue_wave * depth_wave).powf(0.5); + let r = (125.0 + 130.0 * t * golden_hour) as u8; + let g = (180.0 + 75.0 * t) as u8; + let b = (60.0 + 40.0 * t * (1.0 - golden_hour * 0.8)) as u8; + Color32::from_rgb(r, g, b) + } + } + Self::Galaxy => { + let cycle = (smoothed * 3.0 * PI).sin().abs(); + let spiral = (smoothed * 6.0 * PI).cos() * 0.5 + 0.5; + let r = (60.0 + 140.0 * (cycle * smoothed).powf(0.8)) as u8; + let g = (15.0 + 60.0 * (1.0 - smoothed).powf(0.6)) as u8; + let b = (120.0 + 135.0 * (smoothed * spiral).powf(0.5)) as u8; + Color32::from_rgb(r, g, b) + } + Self::Grayscale => { + // Enhanced grayscale with subtle gradient and contrast + let luminance = smoothed.powf(0.75); + let contrast = (luminance * 8.0 * PI).sin() * 0.05 + 1.0; + let gray = (255.0 * luminance * contrast).clamp(0.0, 255.0) as u8; + Color32::from_rgb(gray, gray, gray) + } + + Self::UltraSmooth => { + // Ultra smooth rainbow with perfect color transitions + let phase = smoothed.powf(0.85) * 2.0 * PI; + let secondary = (smoothed * 3.0 * PI).sin() * 0.15 + 0.85; + + let r: u8 = (128.0 + 127.0 * phase.sin() * secondary) as u8; + let g: u8 = (128.0 + 127.0 * (phase + 2.094).sin() * secondary) as u8; + let b: u8 = (128.0 + 127.0 * (phase + 4.188).sin() * secondary) as u8; + Color32::from_rgb(r, g, b) + } + + Self::DeepOcean => { + let depth: f32 = smoothed.powf(1.5); + let wave: f32 = (smoothed * 8.0 * PI).sin() * 0.1 + 1.0; + + let r: u8 = (10.0 + 45.0 * depth * wave) as u8; + let g: u8 = (20.0 + 150.0 * Self::smooth_step(0.0, 1.0, depth)) as u8; + let b: u8 = 205.0f32.mul_add(Self::smooth_step(0.2, 1.0, depth), 50.0) as u8; + Color32::from_rgb(r, g, b) + } + + Self::PrismaticFire => { + let heat = smoothed.powf(0.7); + let flicker = (smoothed * 12.0).sin() * 0.05 + 1.0; + + if heat < 0.2 { + let t: f32 = heat * 5.0; + let r: u8 = + (175.0 * Self::smooth_step(0.0, 1.0, t)).mul_add(flicker, 80.0) as u8; + let g: u8 = (30.0 * t).mul_add(t, 0.0) as u8; + let b: u8 = 15.0f32.mul_add(t, 0.0) as u8; + Color32::from_rgb(r, g, b) + } else if heat < 0.5 { + let t: f32 = (heat - 0.2) / 0.3; + let smooth_t: f32 = Self::smooth_step(0.0, 1.0, t); + let r: u8 = (255.0 * flicker) as u8; + let g: u8 = (195.0 * smooth_t).mul_add(flicker, 30.0) as u8; + let b: u8 = 35.0f32.mul_add(smooth_t, 15.0) as u8; + Color32::from_rgb(r, g, b) + } else if heat < 0.8 { + let t: f32 = (heat - 0.5) / 0.3; + let smooth_t: f32 = Self::smooth_step(0.0, 1.0, t); + let r: u8 = 255; + let g: u8 = 30.0f32.mul_add(smooth_t, 225.0) as u8; + let b: u8 = (150.0 * smooth_t).mul_add(flicker, 50.0) as u8; + Color32::from_rgb(r, g, b) + } else { + let t: f32 = (heat - 0.8) / 0.2; + let smooth_t: f32 = Self::smooth_step(0.0, 1.0, t); + let r: u8 = 255; + let g: u8 = 255; + let b: u8 = 55.0f32.mul_add(smooth_t, 200.0) as u8; + Color32::from_rgb(r, g, b) + } + } + + Self::AuroralDream => { + let wave1: f32 = (smoothed * 3.0 * PI).sin(); + let wave2: f32 = (smoothed * 5.0).mul_add(PI, 1.0).sin(); + let wave3: f32 = (smoothed * 7.0).mul_add(PI, 2.0).sin(); + + let r: u8 = (50.0 + + 100.0 + * 0.2f32 + .mul_add(wave3, 0.3f32.mul_add(wave1, 0.5)) + .clamp(0.0, 1.0)) as u8; + let g: u8 = + 155.0f32.mul_add(0.3f32.mul_add(wave2, 0.7).clamp(0.0, 1.0), 100.0) as u8; + let b: u8 = + 175.0f32.mul_add((0.4 * wave1).mul_add(wave2, 0.6).clamp(0.0, 1.0), 80.0) as u8; + Color32::from_rgb(r, g, b) + } + + Self::CosmicNebula => { + let cosmic_t: f32 = smoothed.powf(0.6); + let dust_pattern: f32 = (cosmic_t * 4.0 * PI).sin().abs(); + let gas_pattern: f32 = (cosmic_t * 6.0).mul_add(PI, 1.5).cos().abs(); + + let r: u8 = + 175.0f32.mul_add(Self::lerp(dust_pattern, gas_pattern, cosmic_t), 80.0) as u8; + let g: u8 = (150.0 * cosmic_t).mul_add(dust_pattern, 40.0) as u8; + let b: u8 = (135.0 * gas_pattern).mul_add(cosmic_t.sqrt(), 120.0) as u8; + Color32::from_rgb(r, g, b) + } + + Self::RainbowSmooth => { + let hue: f32 = smoothed * 360.0; + let saturation: f32 = 0.2f32.mul_add((smoothed * 2.0 * PI).sin().abs(), 0.8); + let value: f32 = 0.1f32.mul_add((smoothed * 3.0 * PI).cos().abs(), 0.9); + + Self::hsv_to_rgb(hue, saturation, value) + } + + Self::VelvetShadow => { + let depth: f32 = Self::smooth_step(0.0, 1.0, smoothed); + let texture: f32 = (smoothed * 10.0 * PI).sin().mul_add(0.08, 1.0); + + let r: u8 = (120.0 * depth.powi(2)).mul_add(texture, 20.0) as u8; + let g: u8 = 80.0f32.mul_add(depth.powf(1.5), 10.0) as u8; + let b: u8 = (180.0 * depth).mul_add(texture, 40.0) as u8; + Color32::from_rgb(r, g, b) + } + + Self::GoldenHour => { + let warmth: f32 = Self::smooth_step(0.0, 1.0, smoothed); + let glow: f32 = (smoothed * 4.0 * PI).sin().abs().mul_add(0.1, 0.9); + + if warmth < 0.4 { + let t: f32 = warmth / 0.4; + let smooth_t: f32 = Self::smooth_step(0.0, 1.0, t); + let r: u8 = (180.0 * smooth_t).mul_add(glow, 40.0) as u8; + let g: u8 = (100.0 * smooth_t).mul_add(glow, 20.0) as u8; + let b: u8 = (80.0 * (1.0 - smooth_t)) as u8; + Color32::from_rgb(r, g, b) + } else if warmth < 0.8 { + let t: f32 = (warmth - 0.4) / 0.4; + let smooth_t: f32 = Self::smooth_step(0.0, 1.0, t); + let r: u8 = (35.0 * smooth_t).mul_add(glow, 220.0) as u8; + let g: u8 = (100.0 * smooth_t).mul_add(glow, 120.0) as u8; + let b: u8 = 70.0f32.mul_add(smooth_t, 30.0) as u8; + Color32::from_rgb(r, g, b) + } else { + let t: f32 = (warmth - 0.8) / 0.2; + let smooth_t: f32 = Self::smooth_step(0.0, 1.0, t); + let r: u8 = 255; + let g: u8 = 35.0f32.mul_add(smooth_t, 220.0) as u8; + let b: u8 = (100.0 * smooth_t).mul_add(glow, 100.0) as u8; + Color32::from_rgb(r, g, b) + } + } + + Self::MoltenLava => { + // Ultra-realistic lava with heat distortion + let heat = smoothed.powf(0.6); + let turbulence = (smoothed * 15.0 * PI).sin() * 0.08 + 1.0; + let core_temp = (smoothed * 7.0 * PI).cos().abs() * 0.15 + 0.85; + + if heat < 0.15 { + // Deep volcanic rock - almost black with hint of red + let t = heat / 0.15; + let r = (90.0 * t * core_temp) as u8; + let g = (15.0 * t) as u8; + let b = (5.0 * t) as u8; + Color32::from_rgb(r, g, b) + } else if heat < 0.4 { + // Heating rock - dark red to orange + let t = (heat - 0.15) / 0.25; + let smooth_t = Self::smooth_step(0.0, 1.0, t); + let r = (165.0 * smooth_t * turbulence + 90.0) as u8; + let g = (50.0 * smooth_t + 15.0) as u8; + let b = (10.0 * smooth_t + 5.0) as u8; + Color32::from_rgb(r, g, b) + } else if heat < 0.7 { + // Molten lava - bright orange to yellow + let t = (heat - 0.4) / 0.3; + let smooth_t = Self::smooth_step(0.0, 1.0, t); + let r = (255.0 * turbulence).min(255.0) as u8; + let g = (140.0 * smooth_t * turbulence + 65.0) as u8; + let b = (25.0 * smooth_t + 15.0) as u8; + Color32::from_rgb(r, g, b) + } else { + // White-hot core - extreme heat + let t = (heat - 0.7) / 0.3; + let smooth_t = Self::smooth_step(0.0, 1.0, t); + let r = 255; + let g = (50.0 * smooth_t + 205.0) as u8; + let b = (180.0 * smooth_t * core_temp + 40.0) as u8; + Color32::from_rgb(r, g, b) + } + } + + Self::IcebergGlacier => { + // Crystalline ice with depth and refraction + let depth = smoothed.powf(1.2); + let crystal = (smoothed * 8.0 * PI).sin().abs(); + let refraction = (smoothed * 12.0 * PI).cos() * 0.5 + 0.5; + let shimmer = (smoothed * 20.0 * PI).sin() * 0.1 + 0.9; + + let base_cyan = 150.0 + 105.0 * depth * shimmer; + let ice_blue = 180.0 + 75.0 * (1.0 - depth).powf(0.5) * crystal; + let highlight = 200.0 + 55.0 * refraction * (1.0 - depth); + + let r = (base_cyan * 0.7 * refraction) as u8; + let g = ice_blue as u8; + let b = highlight as u8; + Color32::from_rgb(r, g, b) + } + + Self::NorthernLights => { + // Aurora Borealis - flowing ethereal lights + let flow = smoothed.powf(0.8); + let wave1 = (flow * 4.0 * PI).sin(); + let wave2 = (flow * 6.0 * PI + 1.5).sin(); + let wave3 = (flow * 3.0 * PI + 3.0).sin(); + let shimmer = (flow * 15.0 * PI).cos().abs() * 0.2 + 0.8; + + // Mix of green, blue, and magenta aurora + let green_aurora = (0.5 + 0.5 * wave1) * shimmer; + let blue_aurora = (0.5 + 0.5 * wave2) * shimmer; + let magenta_aurora = (0.5 + 0.5 * wave3).powf(2.0) * shimmer; + + let r = (80.0 + 120.0 * magenta_aurora) as u8; + let g = (100.0 + 155.0 * green_aurora) as u8; + let b = (120.0 + 135.0 * blue_aurora) as u8; + Color32::from_rgb(r, g, b) + } + + Self::TropicalParadise => { + // Vibrant tropical colors - ocean to sunset + let paradise = smoothed.powf(0.7); + let wave = (paradise * 5.0 * PI).sin() * 0.5 + 0.5; + let bloom = (paradise * 3.0 * PI).cos().abs(); + + if paradise < 0.3 { + // Deep ocean turquoise + let t = paradise / 0.3; + let r = (30.0 + 50.0 * t * wave) as u8; + let g = (120.0 + 80.0 * t) as u8; + let b = (150.0 + 70.0 * t * bloom) as u8; + Color32::from_rgb(r, g, b) + } else if paradise < 0.6 { + // Tropical cyan to mint + let t = (paradise - 0.3) / 0.3; + let r = (80.0 + 100.0 * t * bloom) as u8; + let g = (200.0 + 35.0 * t) as u8; + let b = (220.0 - 40.0 * t * wave) as u8; + Color32::from_rgb(r, g, b) + } else { + // Sunset coral and pink + let t = (paradise - 0.6) / 0.4; + let r = (180.0 + 75.0 * t) as u8; + let g = (235.0 - 50.0 * t * wave) as u8; + let b = (180.0 + 50.0 * t * bloom) as u8; + Color32::from_rgb(r, g, b) + } + } + + Self::VaporwaveNeon => { + // 80s/90s aesthetic with neon colors + let vibe = smoothed.powf(0.75); + let grid = ((vibe * 20.0).fract() * 2.0 - 1.0).abs(); + let glow = (vibe * 6.0 * PI).sin().abs(); + let pulse = (vibe * 10.0 * PI).sin() * 0.15 + 0.85; + + // Neon pink, cyan, and purple + let neon_pink = (0.7 + 0.3 * glow) * pulse; + let neon_cyan = (0.6 + 0.4 * (1.0 - glow)) * pulse; + let neon_purple = (0.5 + 0.5 * grid) * pulse; + + let r = (150.0 + 105.0 * neon_pink) as u8; + let g = (80.0 + 120.0 * neon_cyan) as u8; + let b = (180.0 + 75.0 * neon_purple) as u8; + Color32::from_rgb(r, g, b) + } + + Self::MidnightStars => { + // Deep space with stars and nebula + let space = smoothed.powf(1.5); + let stars = (space * 50.0 * PI).sin(); + let star_brightness = if stars > 0.95 { + (stars - 0.95) * 20.0 + } else { + 0.0 + }; + let nebula = (space * 3.0 * PI).sin().abs(); + let galaxy_dust = (space * 8.0 * PI).cos() * 0.5 + 0.5; + + let r = (10.0 + 30.0 * nebula + 245.0 * star_brightness) as u8; + let g = (5.0 + 20.0 * galaxy_dust + 245.0 * star_brightness) as u8; + let b = (30.0 + 80.0 * space.sqrt() + 245.0 * star_brightness) as u8; + Color32::from_rgb(r, g, b) + } + + Self::CherryBlossom => { + // Delicate pink and white spring blossoms + let bloom = smoothed.powf(0.6); + let petal = (bloom * 6.0 * PI).sin() * 0.5 + 0.5; + let breeze = (bloom * 4.0 * PI).cos().abs(); + let soft_light = Self::smooth_step(0.0, 1.0, bloom); + + let pink_intensity = petal * soft_light; + let white_highlight = (1.0 - bloom * 0.5) * breeze; + + let r = (200.0 + 55.0 * pink_intensity) as u8; + let g = (150.0 + 70.0 * white_highlight) as u8; + let b = (180.0 + 40.0 * pink_intensity - 50.0 * white_highlight) as u8; + Color32::from_rgb(r, g, b) + } + + Self::QuantumPlasma => { + // High-energy plasma with quantum fluctuations + let energy = smoothed.powf(0.5); + let quantum_flux = (energy * 12.0 * PI).sin(); + let plasma_wave = (energy * 8.0 * PI + 2.0).sin(); + let field_strength = (energy * 15.0 * PI).cos().abs(); + let instability = (energy * 25.0 * PI).sin() * 0.1 + 0.9; + + // Electric blue, violet, and white + let electric = (0.5 + 0.5 * quantum_flux) * instability; + let violet = (0.5 + 0.5 * plasma_wave) * field_strength; + let intensity = energy.sqrt(); + + let r = (100.0 + 155.0 * violet * intensity) as u8; + let g = (80.0 + 100.0 * electric * intensity) as u8; + let b = (200.0 + 55.0 * (electric + violet) * 0.5) as u8; + Color32::from_rgb(r, g, b) + } + + Self::OpalDreams => { + // Iridescent opal with rainbow shimmer and pearlescent quality + let iridescence = smoothed.powf(0.65); + let shimmer1 = (iridescence * 10.0 * PI).sin(); + let shimmer2 = (iridescence * 7.0 * PI + 1.5).sin(); + let shimmer3 = (iridescence * 13.0 * PI + 3.0).sin(); + let pearl = (iridescence * 20.0 * PI).cos().abs() * 0.3 + 0.7; + let depth = Self::smooth_step(0.0, 1.0, iridescence); + + // Opal shows multiple colors depending on angle + let cyan_fire = (0.5 + 0.5 * shimmer1) * pearl; + let pink_fire = (0.5 + 0.5 * shimmer2) * pearl; + let gold_fire = (0.5 + 0.5 * shimmer3) * pearl; + + let r = (180.0 + 75.0 * pink_fire * depth) as u8; + let g = (160.0 + 95.0 * (cyan_fire + gold_fire) * 0.5 * depth) as u8; + let b = (200.0 + 55.0 * cyan_fire * depth) as u8; + Color32::from_rgb(r, g, b) + } + + Self::DragonFire => { + // Mythical dragon breath - intense, magical fire + let flame = smoothed.powf(0.55); + let magic = (flame * 8.0 * PI).sin().abs(); + let intensity = (flame * 15.0 * PI).cos() * 0.5 + 0.5; + let dragon_energy = (flame * 20.0 * PI).sin() * 0.1 + 0.9; + let core = Self::smooth_step(0.2, 0.8, flame); + + if flame < 0.2 { + // Deep ember with dragon magic + let t = flame / 0.2; + let r = (60.0 + 140.0 * t * magic) as u8; + let g = (10.0 + 30.0 * t) as u8; + let b = (80.0 + 60.0 * t * magic) as u8; // Purple hint + Color32::from_rgb(r, g, b) + } else if flame < 0.5 { + // Red-violet dragon fire + let t = (flame - 0.2) / 0.3; + let smooth_t = Self::smooth_step(0.0, 1.0, t); + let r = (200.0 + 55.0 * smooth_t * dragon_energy) as u8; + let g = (40.0 + 60.0 * smooth_t * magic) as u8; + let b = (140.0 + 50.0 * smooth_t * intensity) as u8; + Color32::from_rgb(r, g, b) + } else if flame < 0.75 { + // Orange-gold magical flame + let t = (flame - 0.5) / 0.25; + let smooth_t = Self::smooth_step(0.0, 1.0, t); + let r = 255; + let g = (100.0 + 130.0 * smooth_t * dragon_energy) as u8; + let b = (190.0 - 100.0 * smooth_t + 50.0 * magic) as u8; + Color32::from_rgb(r, g, b) + } else { + // White-hot dragon core with spectral edge + let t = (flame - 0.75) / 0.25; + let smooth_t = Self::smooth_step(0.0, 1.0, t); + let r = 255; + let g = (230.0 + 25.0 * smooth_t) as u8; + let b = (140.0 + 115.0 * smooth_t * core) as u8; + Color32::from_rgb(r, g, b) + } + } + + Self::AmethystCavern => { + // Deep purple crystal cavern with luminous veins + let crystal_depth = smoothed.powf(1.3); + let facets = (crystal_depth * 9.0 * PI).sin().abs(); + let luminescence = (crystal_depth * 6.0 * PI).cos() * 0.5 + 0.5; + let veins = (crystal_depth * 25.0 * PI).sin(); + let glow = if veins > 0.85 { (veins - 0.85) * 6.0 } else { 0.0 }; + + let purple_depth = crystal_depth.sqrt(); + let violet_light = facets * luminescence; + + let r = (80.0 + 120.0 * purple_depth * violet_light + 150.0 * glow) as u8; + let g = (30.0 + 50.0 * luminescence + 140.0 * glow) as u8; + let b = (140.0 + 115.0 * purple_depth * facets + 100.0 * glow) as u8; + Color32::from_rgb(r, g, b) + } + + Self::SakuraRain => { + // Gentle cherry blossom petals falling through misty air + let fall = smoothed.powf(0.7); + let petals = (fall * 8.0 * PI).sin() * 0.5 + 0.5; + let mist = (fall * 4.0 * PI).cos().abs(); + let breeze = (fall * 12.0 * PI).sin() * 0.1 + 0.9; + let soft = Self::smooth_step(0.0, 1.0, fall); + + if fall < 0.3 { + // Misty dawn - soft blues and pinks + let t = fall / 0.3; + let r = (180.0 + 60.0 * t * petals) as u8; + let g = (190.0 + 50.0 * t * mist) as u8; + let b = (220.0 + 25.0 * t * breeze) as u8; + Color32::from_rgb(r, g, b) + } else if fall < 0.7 { + // Sakura bloom - delicate pink + let t = (fall - 0.3) / 0.4; + let smooth_t = Self::smooth_step(0.0, 1.0, t); + let r = (240.0 + 15.0 * smooth_t * petals) as u8; + let g = (180.0 + 40.0 * smooth_t * mist) as u8; + let b = (200.0 + 30.0 * smooth_t * soft) as u8; + Color32::from_rgb(r, g, b) + } else { + // Bright sky through petals + let t = (fall - 0.7) / 0.3; + let smooth_t = Self::smooth_step(0.0, 1.0, t); + let r = 255; + let g = (220.0 + 35.0 * smooth_t) as u8; + let b = (230.0 + 25.0 * smooth_t * breeze) as u8; + Color32::from_rgb(r, g, b) + } + } + + Self::ElectricStorm => { + // Violent lightning storm with thunder clouds + let storm = smoothed.powf(0.6); + let lightning = (storm * 30.0 * PI).sin(); + let bolt = if lightning > 0.96 { (lightning - 0.96) * 25.0 } else { 0.0 }; + let rain = (storm * 15.0 * PI).sin() * 0.5 + 0.5; + let charge = Self::smooth_step(0.0, 1.0, storm); + + // Dark storm clouds with brilliant lightning + let electric_blue = charge * rain; + let voltage = bolt; + + let r = (40.0 + 60.0 * electric_blue + 215.0 * voltage) as u8; + let g = (30.0 + 100.0 * charge * rain + 215.0 * voltage) as u8; + let b = (60.0 + 140.0 * electric_blue + 195.0 * voltage) as u8; + Color32::from_rgb(r, g, b) + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_color_scheme_names() { + assert_eq!(ColorScheme::Classic.name(), "Classic"); + assert_eq!(ColorScheme::Hot.name(), "Hot"); + assert_eq!(ColorScheme::Cool.name(), "Cool"); + assert_eq!(ColorScheme::Grayscale.name(), "Grayscale"); + assert_eq!(ColorScheme::Psychedelic.name(), "Psychedelic"); + assert_eq!(ColorScheme::Sunset.name(), "Sunset"); + assert_eq!(ColorScheme::Electric.name(), "Electric"); + assert_eq!(ColorScheme::Forest.name(), "Forest"); + assert_eq!(ColorScheme::Galaxy.name(), "Galaxy"); + } + + #[test] + fn test_hsv_to_rgb() { + let color = ColorScheme::hsv_to_rgb(0.0, 1.0, 1.0); + assert_eq!(color, Color32::from_rgb(255, 0, 0)); // Red + + let color = ColorScheme::hsv_to_rgb(120.0, 1.0, 1.0); + assert_eq!(color, Color32::from_rgb(0, 255, 0)); // Green + + let color = ColorScheme::hsv_to_rgb(240.0, 1.0, 1.0); + assert_eq!(color, Color32::from_rgb(0, 0, 255)); // Blue + } + + #[test] + fn test_smooth_step() { + assert_eq!(ColorScheme::smooth_step(0.0, 1.0, 0.0), 0.0); + assert_eq!(ColorScheme::smooth_step(0.0, 1.0, 1.0), 1.0); + assert!((ColorScheme::smooth_step(0.0, 1.0, 0.5) - 0.5).abs() < 0.01); + assert!((ColorScheme::smooth_step(0.2, 0.8, 0.5) - 0.5).abs() < 0.01); + } +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs new file mode 100644 index 0000000..a3bcdc0 --- /dev/null +++ b/src/utils/mod.rs @@ -0,0 +1,3 @@ +pub mod precision_mode; +pub mod color_scheme; +pub mod point; diff --git a/src/structs/point.rs b/src/utils/point.rs similarity index 100% rename from src/structs/point.rs rename to src/utils/point.rs diff --git a/src/enums/precision_mode.rs b/src/utils/precision_mode.rs similarity index 54% rename from src/enums/precision_mode.rs rename to src/utils/precision_mode.rs index 6db5415..33577f6 100644 --- a/src/enums/precision_mode.rs +++ b/src/utils/precision_mode.rs @@ -2,8 +2,10 @@ #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[repr(u8)] pub enum PrecisionMode { - Fast, // f32 - High, // f64 + Fast, // f32 - Standard precision, fastest + High, // f64 - Double precision + #[cfg(feature = "f128")] + UltraHigh, // f128 - Quadruple precision for extreme zooms (128-bit decimal) } #[cfg(test)] @@ -14,6 +16,8 @@ mod tests { fn test_precision_mode_debug() { assert_eq!(format!("{:?}", PrecisionMode::Fast), "Fast"); assert_eq!(format!("{:?}", PrecisionMode::High), "High"); + #[cfg(feature = "f128")] + assert_eq!(format!("{:?}", PrecisionMode::UltraHigh), "UltraHigh"); } #[test] @@ -22,5 +26,12 @@ mod tests { assert_ne!(PrecisionMode::Fast, PrecisionMode::High); assert_ne!(PrecisionMode::High, PrecisionMode::Fast); assert_eq!(PrecisionMode::High, PrecisionMode::High); + + #[cfg(feature = "f128")] + { + assert_ne!(PrecisionMode::Fast, PrecisionMode::UltraHigh); + assert_ne!(PrecisionMode::High, PrecisionMode::UltraHigh); + assert_eq!(PrecisionMode::UltraHigh, PrecisionMode::UltraHigh); + } } }