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 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
## π 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);
+ }
}
}