pax_global_header00006660000000000000000000000064152674431720014525gustar00rootroot0000000000000052 comment=888aca08d5bdf38e873ec23d6cac42d7f23a669c cglm-0.9.7/000077500000000000000000000000001526744317200124645ustar00rootroot00000000000000cglm-0.9.7/.gitattributes000066400000000000000000000000301526744317200153500ustar00rootroot00000000000000*.h linguist-language=C cglm-0.9.7/.github/000077500000000000000000000000001526744317200140245ustar00rootroot00000000000000cglm-0.9.7/.github/FUNDING.yml000066400000000000000000000004351526744317200156430ustar00rootroot00000000000000# These are supported funding model platforms github: [recp] patreon: recp open_collective: cglm ko_fi: # Replace with a single Ko-fi username tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel custom: # Replace with a single custom sponsorship URL cglm-0.9.7/.github/workflows/000077500000000000000000000000001526744317200160615ustar00rootroot00000000000000cglm-0.9.7/.github/workflows/ci.yml000066400000000000000000000524711526744317200172100ustar00rootroot00000000000000name: CI on: push: branches: [ "master" ] pull_request: branches: [ "master" ] jobs: build_autotools: name: Autotools / ${{ matrix.os }} / ${{ matrix.simd }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: include: # x86/x64 builds - { os: macos-13, simd: none } - { os: macos-13, simd: sse } - { os: macos-13, simd: sse2 } - { os: macos-13, simd: sse3 } - { os: macos-13, simd: sse4 } - { os: macos-13, simd: avx } - { os: macos-13, simd: avx2 } - { os: macos-14, simd: none } - { os: macos-14, simd: sse } - { os: macos-14, simd: sse2 } - { os: macos-14, simd: sse3 } - { os: macos-14, simd: sse4 } - { os: macos-14, simd: avx } - { os: macos-14, simd: avx2 } - { os: ubuntu-22.04, simd: none } - { os: ubuntu-22.04, simd: sse } - { os: ubuntu-22.04, simd: sse2 } - { os: ubuntu-22.04, simd: sse3 } - { os: ubuntu-22.04, simd: sse4 } - { os: ubuntu-22.04, simd: avx } - { os: ubuntu-22.04, simd: avx2 } - { os: ubuntu-24.04, simd: none } - { os: ubuntu-24.04, simd: sse } - { os: ubuntu-24.04, simd: sse2 } - { os: ubuntu-24.04, simd: sse3 } - { os: ubuntu-24.04, simd: sse4 } - { os: ubuntu-24.04, simd: avx } - { os: ubuntu-24.04, simd: avx2 } # ARM64 builds - { os: ubuntu-latest-arm64, simd: neon } steps: - uses: actions/checkout@v4 - name: Install Autotools on macOS if: runner.os == 'macOS' run: brew upgrade && brew install autoconf automake libtool - name: Install Autotools on Ubuntu if: matrix.os == 'ubuntu-22.04' || matrix.os == 'ubuntu-24.04' run: sudo apt-get install -y autoconf automake libtool - name: Set SIMD flags run: | if [ "${{ matrix.simd }}" == "none" ]; then export CFLAGS="" elif [ "${{ matrix.simd }}" == "sse" ]; then export CFLAGS="-msse" elif [ "${{ matrix.simd }}" == "sse2" ]; then export CFLAGS="-msse2" elif [ "${{ matrix.simd }}" == "sse3" ]; then export CFLAGS="-msse3" elif [ "${{ matrix.simd }}" == "sse4" ]; then export CFLAGS="-msse4" elif [ "${{ matrix.simd }}" == "avx" ]; then export CFLAGS="-mavx" elif [ "${{ matrix.simd }}" == "avx2" ]; then export CFLAGS="-mavx2" elif [ "${{ matrix.simd }}" == "neon" ]; then export CFLAGS="-mfpu=neon" fi - name: Generate Autotools run: ./autogen.sh - name: Configure Autotools run: ./configure CFLAGS="$CFLAGS" - name: Build run: make - name: Test run: make check build_cmake_ios: name: CMake / iOS runs-on: macos-14 steps: - uses: actions/checkout@v4 - name: Configure CMake run: | cmake \ -B build \ -GXcode \ -DCMAKE_SYSTEM_NAME=iOS \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=NO \ -DCGLM_STATIC=ON \ -DCGLM_USE_TEST=ON - name: Build run: cmake --build build build_cmake_ubuntu: name: CMake / ${{ matrix.target.os }} / ${{ matrix.target.cc }} / ${{ matrix.target.arch }} / ${{ matrix.target.simd }} runs-on: ${{ matrix.target.arch == 'arm64' && 'ubuntu-latest-arm64' || matrix.target.os }} strategy: fail-fast: false matrix: target: # GCC 11 builds - { os: ubuntu-20.04, cc: gcc-11, arch: x64, simd: none } - { os: ubuntu-20.04, cc: gcc-11, arch: x64, simd: sse } - { os: ubuntu-20.04, cc: gcc-11, arch: x64, simd: sse2 } - { os: ubuntu-20.04, cc: gcc-11, arch: x64, simd: sse3 } - { os: ubuntu-20.04, cc: gcc-11, arch: x64, simd: sse4 } - { os: ubuntu-20.04, cc: gcc-11, arch: x64, simd: avx } - { os: ubuntu-20.04, cc: gcc-11, arch: x64, simd: avx2 } # GCC 12 builds - { os: ubuntu-22.04, cc: gcc-12, arch: x64, simd: none } - { os: ubuntu-22.04, cc: gcc-12, arch: x64, simd: sse } - { os: ubuntu-22.04, cc: gcc-12, arch: x64, simd: sse2 } - { os: ubuntu-22.04, cc: gcc-12, arch: x64, simd: sse3 } - { os: ubuntu-22.04, cc: gcc-12, arch: x64, simd: sse4 } - { os: ubuntu-22.04, cc: gcc-12, arch: x64, simd: avx } - { os: ubuntu-22.04, cc: gcc-12, arch: x64, simd: avx2 } # GCC 13 builds - { os: ubuntu-24.04, cc: gcc-13, arch: x64, simd: none } - { os: ubuntu-24.04, cc: gcc-13, arch: x64, simd: sse } - { os: ubuntu-24.04, cc: gcc-13, arch: x64, simd: sse2 } - { os: ubuntu-24.04, cc: gcc-13, arch: x64, simd: sse3 } - { os: ubuntu-24.04, cc: gcc-13, arch: x64, simd: sse4 } - { os: ubuntu-24.04, cc: gcc-13, arch: x64, simd: avx } - { os: ubuntu-24.04, cc: gcc-13, arch: x64, simd: avx2 } # Clang 12 builds - { os: ubuntu-20.04, cc: clang-12, arch: x64, simd: none } - { os: ubuntu-20.04, cc: clang-12, arch: x64, simd: sse } - { os: ubuntu-20.04, cc: clang-12, arch: x64, simd: sse2 } - { os: ubuntu-20.04, cc: clang-12, arch: x64, simd: sse3 } - { os: ubuntu-20.04, cc: clang-12, arch: x64, simd: sse4 } - { os: ubuntu-20.04, cc: clang-12, arch: x64, simd: avx } - { os: ubuntu-20.04, cc: clang-12, arch: x64, simd: avx2 } # Clang 15 builds - { os: ubuntu-22.04, cc: clang-15, arch: x64, simd: none } - { os: ubuntu-22.04, cc: clang-15, arch: x64, simd: sse } - { os: ubuntu-22.04, cc: clang-15, arch: x64, simd: sse2 } - { os: ubuntu-22.04, cc: clang-15, arch: x64, simd: sse3 } - { os: ubuntu-22.04, cc: clang-15, arch: x64, simd: sse4 } - { os: ubuntu-22.04, cc: clang-15, arch: x64, simd: avx } - { os: ubuntu-22.04, cc: clang-15, arch: x64, simd: avx2 } # ARM64 builds - { os: ubuntu-latest, cc: gcc-12, arch: arm64, simd: neon } - { os: ubuntu-latest, cc: gcc-13, arch: arm64, simd: neon } # ARMv7 builds - { os: ubuntu-latest-arm64, cc: gcc-12, arch: armv7, simd: neon } - { os: ubuntu-latest-arm64, cc: gcc-12, arch: armv7, simd: none } steps: - uses: actions/checkout@v4 - name: Add Ubuntu Toolchain PPA if: matrix.target.os == 'ubuntu-20.04' run: | sudo apt-get update sudo apt-get install -y software-properties-common sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test sudo apt-get update - name: Install Compiler and Ninja run: | sudo apt-get install -y ${{ matrix.target.cc }} ninja-build - name: Set SIMD flags run: | if [ "${{ matrix.simd }}" == "none" ]; then export CFLAGS="" elif [ "${{ matrix.simd }}" == "sse" ]; then export CFLAGS="-msse" elif [ "${{ matrix.simd }}" == "sse2" ]; then export CFLAGS="-msse2" elif [ "${{ matrix.simd }}" == "sse3" ]; then export CFLAGS="-msse3" elif [ "${{ matrix.simd }}" == "sse4" ]; then export CFLAGS="-msse4" elif [ "${{ matrix.simd }}" == "avx" ]; then export CFLAGS="-mavx" elif [ "${{ matrix.simd }}" == "avx2" ]; then export CFLAGS="-mavx2" elif [ "${{ matrix.simd }}" == "neon" ]; then export CFLAGS="-mfpu=neon" fi - name: Configure CMake run: | if [ "${{ matrix.target.arch }}" == "armv7" ]; then # Build for ARMv7 neon_flags="" if [ "${{ matrix.simd }}" == "neon" ]; then neon_flags="-mfpu=neon -mfloat-abi=hard" fi cmake -B build -GNinja -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_COMPILER=${{ matrix.target.cc }} \ -DCMAKE_C_FLAGS="$CFLAGS -m32 -march=armv7-a ${neon_flags}" \ -DCGLM_STATIC=ON -DCGLM_USE_TEST=ON elif [ "${{ matrix.target.arch }}" == "arm64" ]; then # Build for ARM64 (AArch64) neon_flags="" if [ "${{ matrix.simd }}" == "neon" ]; then neon_flags="+simd" # Enable SIMD/NEON features on ARM64 else neon_flags="+nosimd" # Explicitly disable SIMD/NEON fi cmake -B build -GNinja -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_COMPILER=${{ matrix.target.cc }} \ -DCMAKE_C_FLAGS="$CFLAGS -march=armv8-a${neon_flags}" \ -DCGLM_STATIC=ON -DCGLM_USE_TEST=ON else # Normal build (x86/x64) cmake -B build -GNinja -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_COMPILER=${{ matrix.target.cc }} \ -DCMAKE_C_FLAGS="$CFLAGS" \ -DCGLM_STATIC=ON -DCGLM_USE_TEST=ON fi - name: Build run: cmake --build build - name: Test working-directory: build run: ./tests build_cmake_macos: name: CMake / ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [macos-13, macos-14] steps: - uses: actions/checkout@v4 - name: Install Ninja if: runner.os == 'macOS' run: brew upgrade && brew install ninja - name: Configure CMake run: | cmake \ -B build \ -GNinja \ -DCMAKE_BUILD_TYPE=Release \ -DCGLM_STATIC=ON \ -DCGLM_USE_TEST=ON - name: Build run: cmake --build build - name: Test working-directory: build run: ./tests build_cmake: name: CMake / ${{ matrix.os }} / ${{ matrix.simd }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: include: # x86/x64 builds - { os: macos-13, simd: none } - { os: macos-13, simd: sse } - { os: macos-13, simd: sse2 } - { os: macos-13, simd: sse3 } - { os: macos-13, simd: sse4 } - { os: macos-13, simd: avx } - { os: macos-13, simd: avx2 } - { os: macos-14, simd: none } - { os: macos-14, simd: sse } - { os: macos-14, simd: sse2 } - { os: macos-14, simd: sse3 } - { os: macos-14, simd: sse4 } - { os: macos-14, simd: avx } - { os: macos-14, simd: avx2 } - { os: windows-2022, simd: none } - { os: windows-2022, simd: sse } - { os: windows-2022, simd: sse2 } - { os: windows-2022, simd: sse3 } - { os: windows-2022, simd: sse4 } - { os: windows-2022, simd: avx } - { os: windows-2022, simd: avx2 } # ARM64 builds - { os: macos-14-arm64, simd: neon } steps: - uses: actions/checkout@v4 - name: Install Ninja on macOS if: runner.os == 'macOS' run: brew upgrade && brew install ninja - name: Set SIMD flags (Windows) if: runner.os == 'Windows' shell: pwsh run: | $simd = "${{ matrix.simd }}" if ($simd -eq "none") { $env:CFLAGS = "" } elseif ($simd -eq "sse") { $env:CFLAGS = "-arch:SSE" } elseif ($simd -eq "sse2") { $env:CFLAGS = "-arch:SSE2" } elseif ($simd -eq "sse3") { $env:CFLAGS = "-arch:SSE3" } elseif ($simd -eq "sse4") { $env:CFLAGS = "-arch:SSE4" } elseif ($simd -eq "avx") { $env:CFLAGS = "-arch:AVX" } elseif ($simd -eq "avx2") { $env:CFLAGS = "-arch:AVX2" } elseif ($simd -eq "neon") { $env:CFLAGS = "-arch:NEON" } - name: Set SIMD flags (Unix) if: runner.os != 'Windows' shell: bash run: | if [ "${{ matrix.simd }}" == "none" ]; then export CFLAGS="" elif [ "${{ matrix.simd }}" == "sse" ]; then export CFLAGS="-msse" elif [ "${{ matrix.simd }}" == "sse2" ]; then export CFLAGS="-msse2" elif [ "${{ matrix.simd }}" == "sse3" ]; then export CFLAGS="-msse3" elif [ "${{ matrix.simd }}" == "sse4" ]; then export CFLAGS="-msse4" elif [ "${{ matrix.simd }}" == "avx" ]; then export CFLAGS="-mavx" elif [ "${{ matrix.simd }}" == "avx2" ]; then export CFLAGS="-mavx2" elif [ "${{ matrix.simd }}" == "neon" ]; then export CFLAGS="-mfpu=neon" fi - name: Configure CMake (Windows) if: runner.os == 'Windows' shell: pwsh run: cmake -B build -G "Visual Studio 17 2022" -A x64 -T host=x64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="$env:CFLAGS" -DCGLM_STATIC=ON -DCGLM_USE_TEST=ON - name: Configure CMake (Unix) if: runner.os != 'Windows' shell: bash run: cmake -B build -GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="$CFLAGS" -DCGLM_STATIC=ON -DCGLM_USE_TEST=ON - name: Build run: cmake --build build - name: Test (Windows) if: runner.os == 'Windows' shell: pwsh working-directory: build run: .\Debug\tests.exe - name: Test (Unix) if: runner.os != 'Windows' shell: bash working-directory: build run: ./tests build_meson: name: Meson / ${{ matrix.os }} / ${{ matrix.simd }} runs-on: ${{ contains(matrix.os, 'arm64') && 'ubuntu-latest-arm64' || matrix.os }} strategy: fail-fast: false matrix: include: # x86/x64 builds - { os: macos-14, simd: none } - { os: macos-14, simd: sse } - { os: macos-14, simd: sse2 } - { os: macos-14, simd: sse3 } - { os: macos-14, simd: sse4 } - { os: macos-14, simd: avx } - { os: macos-14, simd: avx2 } - { os: ubuntu-22.04, simd: none } - { os: ubuntu-22.04, simd: sse } - { os: ubuntu-22.04, simd: sse2 } - { os: ubuntu-22.04, simd: sse3 } - { os: ubuntu-22.04, simd: sse4 } - { os: ubuntu-22.04, simd: avx } - { os: ubuntu-22.04, simd: avx2 } - { os: ubuntu-24.04, simd: none } - { os: ubuntu-24.04, simd: sse } - { os: ubuntu-24.04, simd: sse2 } - { os: ubuntu-24.04, simd: sse3 } - { os: ubuntu-24.04, simd: sse4 } - { os: ubuntu-24.04, simd: avx } - { os: ubuntu-24.04, simd: avx2 } - { os: windows-2022, simd: none } - { os: windows-2022, simd: sse } - { os: windows-2022, simd: sse2 } - { os: windows-2022, simd: sse3 } - { os: windows-2022, simd: sse4 } - { os: windows-2022, simd: avx } - { os: windows-2022, simd: avx2 } # ARM64 builds - { os: ubuntu-latest-arm64, simd: neon } steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: '3.12' cache: 'pip' - name: Install meson run: python3 -m pip install meson ninja - name: Set SIMD flags (Windows) if: runner.os == 'Windows' shell: pwsh run: | $simd = "${{ matrix.simd }}" if ($simd -eq "none") { $env:CFLAGS = "" } elseif ($simd -eq "sse") { $env:CFLAGS = "-arch:SSE" } elseif ($simd -eq "sse2") { $env:CFLAGS = "-arch:SSE2" } elseif ($simd -eq "sse3") { $env:CFLAGS = "-arch:SSE3" } elseif ($simd -eq "sse4") { $env:CFLAGS = "-arch:SSE4" } elseif ($simd -eq "avx") { $env:CFLAGS = "-arch:AVX" } elseif ($simd -eq "avx2") { $env:CFLAGS = "-arch:AVX2" } elseif ($simd -eq "neon") { $env:CFLAGS = "-arch:NEON" } - name: Set SIMD flags (Unix) if: runner.os != 'Windows' shell: bash run: | if [ "${{ matrix.simd }}" == "none" ]; then export CFLAGS="" elif [ "${{ matrix.simd }}" == "sse" ]; then export CFLAGS="-msse" elif [ "${{ matrix.simd }}" == "sse2" ]; then export CFLAGS="-msse2" elif [ "${{ matrix.simd }}" == "sse3" ]; then export CFLAGS="-msse3" elif [ "${{ matrix.simd }}" == "sse4" ]; then export CFLAGS="-msse4" elif [ "${{ matrix.simd }}" == "avx" ]; then export CFLAGS="-mavx" elif [ "${{ matrix.simd }}" == "avx2" ]; then export CFLAGS="-mavx2" elif [ "${{ matrix.simd }}" == "neon" ]; then export CFLAGS="-mfpu=neon" fi - name: Build with meson (Windows) if: runner.os == 'Windows' shell: pwsh run: | meson setup build -Dbuildtype=release --default-library=static -Dbuild_tests=true -Dc_args="$env:CFLAGS" meson test -C build - name: Build with meson (Unix) if: runner.os != 'Windows' shell: bash run: | meson setup build -Dbuildtype=release --default-library=static -Dbuild_tests=true -Dc_args="$CFLAGS" meson test -C build build_msbuild: name: MSBuild / Windows / ${{ matrix.simd }} runs-on: windows-2022 strategy: fail-fast: false matrix: simd: [none, sse, sse2, sse3, sse4, avx, avx2, neon] steps: - uses: actions/checkout@v4 - uses: microsoft/setup-msbuild@v2 - name: Retarget solution run: | vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath $vsInstallPath = vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath & "$vsInstallPath\Common7\IDE\devenv.com" cglm.sln /Upgrade - name: Set SIMD flags run: | if ($Env:SIMD -eq 'none') { $Env:CFLAGS="" } elseif ($Env:SIMD -eq 'sse') { $Env:CFLAGS="-arch:SSE" } elseif ($Env:SIMD -eq 'sse2') { $Env:CFLAGS="-arch:SSE2" } elseif ($Env:SIMD -eq 'sse3') { $Env:CFLAGS="-arch:SSE3" } elseif ($Env:SIMD -eq 'sse4') { $Env:CFLAGS="-arch:SSE4" } elseif ($Env:SIMD -eq 'avx') { $Env:CFLAGS="-arch:AVX" } elseif ($Env:SIMD -eq 'avx2') { $Env:CFLAGS="-arch:AVX2" } elseif ($Env:SIMD -eq 'neon') { $Env:CFLAGS="-arch:NEON" } - name: Build (x86) working-directory: win run: msbuild cglm.vcxproj /p:Configuration=Release /p:Platform=x86 /p:PlatformToolset=v143 /p:BuildInParallel=true /p:AdditionalOptions="$Env:CFLAGS" - name: Build (x64) working-directory: win run: msbuild cglm.vcxproj /p:Configuration=Release /p:Platform=x64 /p:PlatformToolset=v143 /p:BuildInParallel=true /p:AdditionalOptions="$Env:CFLAGS" build_documentation: name: Documentation runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: '3.12' - name: Install Dependencies working-directory: docs run: python3 -m pip install -r requirements.txt - name: Build working-directory: docs run: sphinx-build -W --keep-going source build build_swift: name: Swift ${{ matrix.swift }} / ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [macos-13, macos-14, ubuntu-22.04] # This has no test yet. steps: - uses: actions/checkout@v4 - name: Build run: swift build build_cmake_arm: name: CMake / ARM / ${{ matrix.os }} / ${{ matrix.arch }} / ${{ matrix.simd }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: include: # Linux ARM builds - os: ubuntu-latest-arm64 arch: arm64 simd: neon - os: ubuntu-latest-arm64 arch: armv7 simd: neon - os: ubuntu-latest-arm64 arch: armv7 simd: none # Windows ARM builds - os: windows-latest-arm64 arch: arm64 simd: neon - os: windows-latest-arm64 arch: arm simd: neon - os: windows-latest-arm64 arch: arm simd: none steps: - uses: actions/checkout@v4 - name: Configure CMake (Windows) if: runner.os == 'Windows' shell: pwsh run: | $flags = "" if ("${{ matrix.arch }}" -eq "arm") { $flags = "-m32 -march=armv7-a" if ("${{ matrix.simd }}" -eq "neon") { $flags += " -mfpu=neon" } } elseif ("${{ matrix.simd }}" -eq "neon") { $flags = "-march=armv8-a+simd" } cmake -B build -G "Visual Studio 17 2022" -A ${{ matrix.arch == 'arm64' && 'ARM64' || 'ARM' }} ` -DCMAKE_BUILD_TYPE=Release ` -DCMAKE_C_FLAGS="$flags" ` -DCGLM_STATIC=ON -DCGLM_USE_TEST=ON - name: Configure CMake (Unix) if: runner.os != 'Windows' shell: bash run: | flags="" if [ "${{ matrix.arch }}" = "armv7" ]; then flags="-m32 -march=armv7-a" if [ "${{ matrix.simd }}" = "neon" ]; then flags="$flags -mfpu=neon -mfloat-abi=hard" fi elif [ "${{ matrix.simd }}" = "neon" ]; then flags="-march=armv8-a+simd" fi cmake -B build -GNinja -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_FLAGS="$flags" \ -DCGLM_STATIC=ON -DCGLM_USE_TEST=ON - name: Build run: cmake --build build - name: Test working-directory: build run: ./tests cglm-0.9.7/.github/workflows/cmake-wasm.yml000066400000000000000000000123331526744317200206330ustar00rootroot00000000000000name: CMake WebAssembly on: push: branches: [ "master" ] pull_request: branches: [ "master" ] env: wasmtime_version: v7.0.0 wasmer_version: v3.1.1 jobs: build_wasi_sdk: strategy: matrix: BUILD_TYPE: [Release, Debug, RelWithDebInfo, MinSizeRel] C_FLAGS: ['', '-msimd128'] wasi_sdk_version: [19, 20] # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. # You can convert this to a matrix build if you need cross-platform coverage. # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Downloading wasi-sdk run: | cd ${{github.workspace}} wget --no-verbose https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${{matrix.wasi_sdk_version}}/wasi-sdk-${{matrix.wasi_sdk_version}}.0-linux.tar.gz tar xf wasi-sdk-${{matrix.wasi_sdk_version}}.0-linux.tar.gz # Building a wasm library without needing to define a main(): # https://github.com/WebAssembly/wasi-sdk/issues/332 - name: Modify CMakeLists.txt for WASI run: | echo 'if (CMAKE_SYSTEM_NAME STREQUAL "WASI")' >> CMakeLists.txt echo ' target_link_options(${PROJECT_NAME} PRIVATE -mexec-model=reactor)' >> CMakeLists.txt echo 'endif()' >> CMakeLists.txt - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type # Below suppress <<'clock' is deprecated: WASI lacks process-associated clocks; ...>> warns: # -D_WASI_EMULATED_PROCESS_CLOCKS" -DCMAKE_EXE_LINKER_FLAGS="-lwasi-emulated-process-clocks run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{matrix.BUILD_TYPE}} -DCMAKE_C_FLAGS="${{matrix.C_FLAGS}} -D_WASI_EMULATED_PROCESS_CLOCKS" -DCMAKE_EXE_LINKER_FLAGS="-lwasi-emulated-process-clocks" -DCMAKE_TOOLCHAIN_FILE=${{github.workspace}}/wasi-sdk-${{matrix.wasi_sdk_version}}.0/share/cmake/wasi-sdk.cmake -DWASI_SDK_PREFIX=${{github.workspace}}/wasi-sdk-${{matrix.wasi_sdk_version}}.0 -DCGLM_STATIC=ON -DCGLM_SHARED=OFF -DCGLM_USE_TEST=ON - name: Build # Build your program with the given configuration run: cmake --build ${{github.workspace}}/build --config ${{matrix.BUILD_TYPE}} - name: Test with wasmtime run: | cd ${{github.workspace}} ls -lh ${{github.workspace}}/build/ wget --no-verbose https://github.com/bytecodealliance/wasmtime/releases/download/${{env.wasmtime_version}}/wasmtime-${{env.wasmtime_version}}-x86_64-linux.tar.xz tar xf wasmtime-${{env.wasmtime_version}}-x86_64-linux.tar.xz ./wasmtime-${{env.wasmtime_version}}-x86_64-linux/wasmtime run --wasm-features simd ${{github.workspace}}/build/tests - name: Test with wasmer run: | cd ${{github.workspace}} mkdir wasmer cd wasmer wget --no-verbose https://github.com/wasmerio/wasmer/releases/download/${{env.wasmer_version}}/wasmer-linux-amd64.tar.gz tar xf wasmer-linux-amd64.tar.gz ./bin/wasmer run --enable-simd ${{github.workspace}}/build/tests build_emsdk: strategy: matrix: BUILD_TYPE: [Release, Debug, RelWithDebInfo, MinSizeRel] C_FLAGS: ['', '-msimd128', '-msse -msse2 -msimd128', '-msse -msse2 -msse3 -msse4 -msimd128'] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup emsdk uses: mymindstorm/setup-emsdk@v12 - name: Verify emsdk run: emcc -v - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: emcmake cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{matrix.BUILD_TYPE}} -DCMAKE_C_FLAGS="${{matrix.C_FLAGS}}" -DCMAKE_EXE_LINKER_FLAGS="-s STANDALONE_WASM" -DCGLM_STATIC=ON -DCGLM_USE_TEST=ON - name: Build # Build your program with the given configuration run: cmake --build ${{github.workspace}}/build --config ${{matrix.BUILD_TYPE}} - name: Test with wasmtime run: | cd ${{github.workspace}} ls -lh ${{github.workspace}}/build/ wget --no-verbose https://github.com/bytecodealliance/wasmtime/releases/download/${{env.wasmtime_version}}/wasmtime-${{env.wasmtime_version}}-x86_64-linux.tar.xz tar xf wasmtime-${{env.wasmtime_version}}-x86_64-linux.tar.xz ./wasmtime-${{env.wasmtime_version}}-x86_64-linux/wasmtime run --wasm-features simd ${{github.workspace}}/build/tests.wasm - name: Test with wasmer run: | cd ${{github.workspace}} mkdir wasmer cd wasmer wget --no-verbose https://github.com/wasmerio/wasmer/releases/download/${{env.wasmer_version}}/wasmer-linux-amd64.tar.gz tar xf wasmer-linux-amd64.tar.gz ./bin/wasmer run --enable-simd ${{github.workspace}}/build/tests.wasm cglm-0.9.7/.github/workflows/meson-wasm.yml000066400000000000000000000046071526744317200207010ustar00rootroot00000000000000name: Meson WebAssembly on: push: branches: [ "master" ] pull_request: branches: [ "master" ] env: wasmtime_version: v7.0.0 wasmer_version: v3.1.1 jobs: build_emsdk: strategy: matrix: BUILD_TYPE: [debug, debugoptimized, release, minsize] C_FLAGS: ['', '-msimd128', '-msse -msse2 -msimd128', '-msse -msse2 -msse3 -msse4 -msimd128'] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup emsdk uses: mymindstorm/setup-emsdk@v13 - name: Verify emsdk run: emcc -v - name: Creating cross file run: | cat << EOF > ${{github.workspace}}/meson_cross_emsdk.txt [binaries] c = '`which emcc`' cpp = '`which em++`' ar = '`which emar`' [built-in options] c_args = ['-Wno-unused-parameter'] c_link_args = ['-s', 'STANDALONE_WASM'] cpp_args = ['-Wno-unused-parameter'] cpp_link_args = ['-s', 'STANDALONE_WASM'] [host_machine] system = 'emscripten' cpu_family = 'wasm32' cpu = 'wasm32' endian = 'little' EOF cat ${{github.workspace}}/meson_cross_emsdk.txt - uses: actions/setup-python@v4 - name: Install meson run: | sudo python3 -m pip install meson ninja - name: Build with meson run: | meson setup build -Dbuildtype=${{matrix.BUILD_TYPE}} --cross-file ${{github.workspace}}/meson_cross_emsdk.txt --default-library=static -Dbuild_tests=true meson test -C build - name: Test with wasmtime run: | cd ${{github.workspace}} ls -lh ${{github.workspace}}/build/ wget --no-verbose https://github.com/bytecodealliance/wasmtime/releases/download/${{env.wasmtime_version}}/wasmtime-${{env.wasmtime_version}}-x86_64-linux.tar.xz tar xf wasmtime-${{env.wasmtime_version}}-x86_64-linux.tar.xz ./wasmtime-${{env.wasmtime_version}}-x86_64-linux/wasmtime run --wasm-features simd ${{github.workspace}}/build/tests.wasm - name: Test with wasmer run: | cd ${{github.workspace}} mkdir wasmer cd wasmer wget --no-verbose https://github.com/wasmerio/wasmer/releases/download/${{env.wasmer_version}}/wasmer-linux-amd64.tar.gz tar xf wasmer-linux-amd64.tar.gz ./bin/wasmer run --enable-simd ${{github.workspace}}/build/tests.wasm cglm-0.9.7/.gitignore000066400000000000000000000016461526744317200144630ustar00rootroot00000000000000*.xcodeproj *.xcworkspace *.sln *.vcxproj *.vcxproj.* *.suo *.sdf *.opensdf ipch/ Debug/ Release/ .DS_Store .vs *.nupkg *.opendb packages.config /aclocal.m4 /ar-lib /autom4te.cache/ /compile /config.guess /config.log /config.status /config.sub /configure /depcomp /install-sh /ltmain.sh /missing /libtool /.libs/ .deps/ *.[oa] *.l[oa] Makefile Makefile.in m4/*.m4 .buildstamp .dirstamp packages/ .anjuta/* *.anjuta* config.h.* /config.h stamp* COPYING .idea/* *.VC.db cscope.* *-git-ignored-file.* test/*.trs test/test_* *.log test/.libs/* test/tests cglm_arm/* cglm_test_ios/* cglm_test_iosTests/* docs/build/* win/cglm_test_* * copy.* *.o *.obj *codeanalysis.*.xml *codeanalysis.xml *.lib *.tlog win/x64 win/x85 win/Debug cglm-test-ios* /cglm.pc test-driver Default-568h@2x.png build/ conftest.dir/* confdefs.h *.xcuserdatad .idea cmake-build-debug *.o.tmp xcode/* .vscode .build *.swp .lastsession.vim .vimrc compile_commands.json cglm-0.9.7/.readthedocs.yaml000066400000000000000000000021161526744317200157130ustar00rootroot00000000000000# Read the Docs configuration file for Sphinx projects # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details # Required version: 2 # Set the OS, Python version and other tools you might need build: os: ubuntu-22.04 tools: python: "3.12" # You can also specify other tool versions: # nodejs: "20" # rust: "1.70" # golang: "1.20" # Build documentation in the "docs/" directory with Sphinx sphinx: configuration: docs/source/conf.py # You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs # builder: "dirhtml" # Fail on all warnings to avoid broken references # fail_on_warning: true # Optionally build your docs in additional formats such as PDF and ePub # formats: # - pdf # - epub # Optional but recommended, declare the Python requirements required # to build your documentation # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html # python: # install: # - requirements: docs/requirements.txt python: install: - requirements: docs/requirements.txtcglm-0.9.7/.travis.yml000066400000000000000000000020411526744317200145720ustar00rootroot00000000000000language: c os: - linux - osx arch: - amd64 - ppc64le - s390x - arm64 sudo: required dist: trusty compiler: - clang - gcc matrix: fast_finish: true exclude: # Skip GCC builds on macOS. - os: osx compiler: gcc include: # Additional GCC builds for code coverage. - os: linux compiler: gcc env: CODE_COVERAGE=ON cache: apt: true addons: apt: packages: - clang-3.6 - lcov branches: only: - master script: - sh ./autogen.sh - if [[ "$CC" == "gcc" && "$CODE_COVERAGE" == "ON" ]]; then ./configure CFLAGS="-ftest-coverage -fprofile-arcs -coverage"; else ./configure; fi - make - make check after_success: - if [[ "$CC" == "gcc" && "$CODE_COVERAGE" == "ON" ]]; then pip install --user cpp-coveralls && coveralls --build-root . --exclude lib --exclude test --gcov-options '\-lp' --verbose && bash <(curl -s https://codecov.io/bash); fi # after_failure: # - cat ./test-suite.log cglm-0.9.7/BUILDING.md000066400000000000000000000116261526744317200142110ustar00rootroot00000000000000# Building the library cglm can be built using one of the following build systems: ## CMake (All platforms) ```bash $ mkdir build $ cd build $ cmake .. # [Optional] -DCGLM_SHARED=ON $ make $ sudo make install # [Optional] ``` ### Options with defaults ```CMake option(CGLM_SHARED "Shared build" ON) option(CGLM_STATIC "Static build" OFF) option(CGLM_USE_C99 "" OFF) # C11 option(CGLM_USE_TEST "Enable Tests" OFF) # for make check - make test ``` ### Including in a CMake project #### Header only This requires no building or installation of cglm. * Example: ``` cmake cmake_minimum_required(VERSION 3.8.2) project() add_executable(${PROJECT_NAME} src/main.c) target_link_libraries(${LIBRARY_NAME} PRIVATE cglm_headers) add_subdirectory(external/cglm/ EXCLUDE_FROM_ALL) ``` #### Linked * Example: ```cmake cmake_minimum_required(VERSION 3.8.2) project() add_executable(${PROJECT_NAME} src/main.c) target_link_libraries(${LIBRARY_NAME} PRIVATE cglm) add_subdirectory(external/cglm/) # or you can use find_package to configure cglm ``` ### Using CMake to build for WebAssembly Since math functions like `sinf` are used, this can not be targeted at `wasm32-unknown-unknown`, one of [wasi-sdk](https://github.com/WebAssembly/wasi-sdk) or [emscripten](https://github.com/emscripten-core/emsdk) should be used. Should note that shared build is not yet supported for WebAssembly. For [simd128](https://github.com/WebAssembly/simd) support, add `-msimd128` to `CMAKE_C_FLAGS`, in command line `-DCMAKE_C_FLAGS="-msimd128"`. For tests, the cmake option `CGLM_USE_TEST` would still work, you'll need a wasi runtime for running tests, see our [ci config file](.github/workflows/cmake-wasm.yml) for a detailed example. #### WASI SDK ```bash $ cmake .. \ -DCMAKE_TOOLCHAIN_FILE=/path/to/wasi-sdk-19.0/share/cmake/wasi-sdk.cmake \ -DWASI_SDK_PREFIX=/path/to/wasi-sdk-19.0 ``` Where `/path/to/wasi-sdk-19.0/` is the path to extracted [wasi sdk](https://github.com/WebAssembly/wasi-sdk). In this case it would by default make a static build. #### Emscripten ```bash $ emcmake cmake .. \ -DCMAKE_EXE_LINKER_FLAGS="-s STANDALONE_WASM" \ -DCGLM_STATIC=ON ``` The `emcmake` here is the cmake wrapper for Emscripten from installed [emsdk](https://github.com/emscripten-core/emsdk). ## Meson (All platforms) ```bash $ meson build # [Optional] --default-library=static $ cd build $ ninja $ sudo ninja install # [Optional] ``` ### Options with Defaults: ```meson c_std=c11 buildtype=release default_library=shared build_tests=true # to run tests: ninja test ``` ### Including in a Meson project * Example: ```meson # Clone cglm or create a cglm.wrap under /subprojects project('name', 'c') cglm_dep = dependency('cglm', fallback : 'cglm', 'cglm_dep') executable('exe', 'src/main.c', dependencies : cglm_dep) ``` ## Swift (Swift Package Manager) Currently only default build options are supported. Add **cglm** dependency to your project: ```swift ... Package( ... dependencies: [ ... .package(url: "https://github.com/recp/cglm", .branch("master")), ] ... ) ``` Now add **cgml** as a dependency to your target. Product choices are: - **cglm** for inlined version of the library which can be linked only statically - **cglmc** for a compiled version of the library with no linking limitation ```swift ... .target( ... dependencies: [ ... .product(name: "cglm", package: "cglm"), ] ... ) ... ``` ## Unix (Autotools) ```bash $ sh autogen.sh $ ./configure $ make $ make check # [Optional] $ [sudo] make install # [Optional] ``` This will also install pkg-config files so you can use `pkg-config --cflags cglm` and `pkg-config --libs cglm` to retrieve compiler and linker flags. The files will be installed into the given prefix (usually `/usr/local` by default on Linux), but your pkg-config may not be configured to actually check there. You can figure out where it's looking by running `pkg-config --variable pc_path pkg-config` and change the path the files are installed to via `./configure --with-pkgconfigdir=/your/path`. Alternatively, you can add the prefix path to your `PKG_CONFIG_PATH` environment variable. ## Windows (MSBuild) Windows related build file and project files are located in `win` folder, make sure you are inside `cglm/win` folder. Code Analysis is enabled, so it may take awhile to build. ```Powershell $ cd win $ .\build.bat ``` if `msbuild` won't work (because of multi version VS) then try to build with `devenv`: ```Powershell $ devenv cglm.sln /Build Release ``` ### Running Tests on Windows You can see test project in same visual studio solution file. It is enough to run that project to run tests. # Building the documentation First you need install Sphinx: http://www.sphinx-doc.org/en/master/usage/installation.html then: ```bash $ cd docs $ sphinx-build source build ``` it will compile docs into build folder, you can run index.html inside that function.cglm-0.9.7/CMakeLists.txt000066400000000000000000000121451526744317200152270ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.13) project(cglm VERSION 0.9.7 HOMEPAGE_URL https://github.com/recp/cglm DESCRIPTION "OpenGL Mathematics (glm) for C" LANGUAGES C ) set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED YES) set(DEFAULT_BUILD_TYPE "Release") set(CGLM_BUILD) option(CGLM_SHARED "Shared build" ON) option(CGLM_STATIC "Static build" OFF) option(CGLM_USE_C99 "" OFF) option(CGLM_USE_TEST "Enable Tests" OFF) if(CMAKE_SYSTEM_NAME STREQUAL WASI) set(CGLM_STATIC ON CACHE BOOL "Static option" FORCE) set(CGLM_SHARED OFF CACHE BOOL "Shared option" FORCE) endif() if(NOT CGLM_STATIC AND CGLM_SHARED) set(CGLM_BUILD SHARED) else(CGLM_STATIC) set(CGLM_BUILD STATIC) endif() if(CGLM_USE_C99) set(CMAKE_C_STANDARD 99) endif() if(MSVC) add_definitions(-D_WINDOWS -D_USRDLL) if(NOT CMAKE_BUILD_TYPE MATCHES Debug) add_definitions(-DNDEBUG) add_compile_options(/W3 /Ox /Gy /Oi /TC) foreach(flag_var CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO) string(REGEX REPLACE "/RTC(su|[1su])" "" ${flag_var} "${${flag_var}}") endforeach(flag_var) endif() else() add_compile_options(-Wall -Wextra -Wpedantic -Wconversion) if(NOT CMAKE_BUILD_TYPE MATCHES Debug) add_compile_options(-O3) endif() endif() get_directory_property(hasParent PARENT_DIRECTORY) if(NOT hasParent AND NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified.") set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() include(GNUInstallDirs) set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) if(NOT CPack_CMake_INCLUDED) include(CPack) endif() # Target Start add_library(${PROJECT_NAME} ${CGLM_BUILD} src/euler.c src/affine.c src/io.c src/quat.c src/cam.c src/vec2.c src/ivec2.c src/vec3.c src/ivec3.c src/vec4.c src/ivec4.c src/mat2.c src/mat2x3.c src/mat2x4.c src/mat3.c src/mat3x2.c src/mat3x4.c src/mat4.c src/mat4x2.c src/mat4x3.c src/plane.c src/noise.c src/frustum.c src/box.c src/aabb2d.c src/project.c src/sphere.c src/ease.c src/curve.c src/bezier.c src/ray.c src/affine2d.c src/clipspace/ortho_lh_no.c src/clipspace/ortho_lh_zo.c src/clipspace/ortho_rh_no.c src/clipspace/ortho_rh_zo.c src/clipspace/persp_lh_no.c src/clipspace/persp_lh_zo.c src/clipspace/persp_rh_no.c src/clipspace/persp_rh_zo.c src/clipspace/view_lh_no.c src/clipspace/view_lh_zo.c src/clipspace/view_rh_no.c src/clipspace/view_rh_zo.c src/clipspace/project_no.c src/clipspace/project_zo.c ) if(CGLM_SHARED) add_definitions(-DCGLM_EXPORTS) else() target_compile_definitions(${PROJECT_NAME} PUBLIC -DCGLM_STATIC) endif() set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR}) if(WIN32) # Because SOVERSION has no effect to file naming on Windows set_target_properties(${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_NAME ${PROJECT_NAME}-${PROJECT_VERSION_MAJOR}) endif() target_include_directories(${PROJECT_NAME} PUBLIC $ $ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src ) # Target for header-only usage add_library(${PROJECT_NAME}_headers INTERFACE) target_include_directories(${PROJECT_NAME}_headers INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) # Test Configuration if(CGLM_USE_TEST) include(CTest) enable_testing() add_subdirectory(test) endif() # Install install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) install(DIRECTORY include/${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} PATTERN ".*" EXCLUDE) # Config export(TARGETS ${PROJECT_NAME} NAMESPACE ${PROJECT_NAME}:: FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" ) install(EXPORT ${PROJECT_NAME} FILE "${PROJECT_NAME}Config.cmake" NAMESPACE ${PROJECT_NAME}:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) set(PACKAGE_NAME ${PROJECT_NAME}) set(prefix ${CMAKE_INSTALL_PREFIX}) set(exec_prefix ${CMAKE_INSTALL_PREFIX}) if (IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}") set(includedir "${CMAKE_INSTALL_INCLUDEDIR}") else() set(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}") endif() if (IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}") set(libdir "${CMAKE_INSTALL_LIBDIR}") else() set(libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}") endif() set(PACKAGE_VERSION "${PROJECT_VERSION}") configure_file(cglm.pc.in cglm.pc @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cglm.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) cglm-0.9.7/CONTRIBUTING.md000066400000000000000000000030401526744317200147120ustar00rootroot00000000000000# CONTRIBUTING Any contributions (code, documentation, ...) are welcome. # New Features - This library may not accept all new features, it is better to create an issue and get approval before coding - You must add test for every new feature - The feature must be compiled on both UNIX/POSIX systems (e.g. macos, linux...) and Windows # Code Style This library is written with C99, don't try to add C++ files (yes it can compiled into lib), if you have enough reason to add C++ files than create an issue and get approval before coding, - All functions must have `glm` prefix - Lines should be wrapped at 80 characters. - Don't invent new style for existing ones - Use C89 style comments (`/* comments */`) not C++ style comments (`// comments`) - Don't use TABs instead use 2 spaces for TABs - All indents must be 2 spaces, not 1 nor 4 space - All functions in `include` folder must be exported by `CGLM_EXPORT` and wrapped by `extern "C" {` for C++ - Crate new line for return type, attribs: ```C CGLM_INLINE void glm_mul(mat4 m1, mat4 m2, mat4 dest) ``` not acceptable: ```C CGLM_INLINE void glm_mul(mat4 m1, mat4 m2, mat4 dest) ``` - Variables must be declared at the top of a scope before usage: ```C int x; int y; x = y = 0; ``` not acceptable: ```C int x; x = 0; int y = 0; ``` - All files must retain same LICENSE statement - Code with warnings will not be accepted, please suppress them (not by disabling them) - Run code anaylysis before submitting pull requests, if you use Xcode you can enable Sanitizer in scheme, you can use valgrind in linux cglm-0.9.7/CREDITS000066400000000000000000000063221526744317200135070ustar00rootroot00000000000000This library [initially] used some [piece of] implementations (may include codes) from these open source projects/resources: 1. Initial Affine Transforms The original glm repo (g-truc), url: https://github.com/g-truc/glm LICENSE[S]: The Happy Bunny License (Modified MIT License) The MIT License Copyright (c) 2005 - 2016 G-Truc Creation FULL LICENSE: https://github.com/g-truc/glm/blob/master/copying.txt 2. Initial Quaternions Anton's OpenGL 4 Tutorials book source code: LICENSE: OpenGL 4 Example Code. Accompanies written series "Anton's OpenGL 4 Tutorials" Email: anton at antongerdelan dot net First version 27 Jan 2014 Copyright Dr Anton Gerdelan, Trinity College Dublin, Ireland. 3. Euler Angles David Eberly Geometric Tools, LLC http://www.geometrictools.com/ Copyright (c) 1998-2016. All Rights Reserved. Computing Euler angles from a rotation matrix (euler.pdf) Gregory G. Slabaugh 4. Extracting Planes Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix Authors: Gil Gribb (ggribb@ravensoft.com) Klaus Hartmann (k_hartmann@osnabrueck.netsurf.de) 5. Transform AABB Transform Axis Aligned Bounding Boxes: http://dev.theomader.com/transform-bounding-boxes/ https://github.com/erich666/GraphicsGems/blob/master/gems/TransBox.c 6. Cull frustum http://www.txutxi.com/?p=584 http://old.cescg.org/CESCG-2002/DSykoraJJelinek/ 7. Quaternions Initial mat4_quat is borrowed from Apple's simd library 8. Vector Rotation using Quaternion https://gamedev.stackexchange.com/questions/28395/rotating-vector3-by-a-quaternion 9. Sphere AABB intersect https://github.com/erich666/GraphicsGems/blob/master/gems/BoxSphere.c 10. Horizontal add https://stackoverflow.com/questions/6996764/fastest-way-to-do-horizontal-float-vector-sum-on-x86 11. de casteljau implementation and comments https://forums.khronos.org/showthread.php/10264-Animations-in-1-4-1-release-notes-revision-A/page2?highlight=bezier https://forums.khronos.org/showthread.php/10644-Animation-Bezier-interpolation https://forums.khronos.org/showthread.php/10387-2D-Tangents-in-Bezier-Splines?p=34164&viewfull=1#post34164 https://forums.khronos.org/showthread.php/10651-Animation-TCB-Spline-Interpolation-in-COLLADA?highlight=bezier 12. vec2 cross product http://allenchou.net/2013/07/cross-product-of-2d-vectors/ 13. Ray triangle intersect Möller–Trumbore ray-triangle intersection algorithm, from "Fast, Minimum Storage Ray/Triangle Intersection" Authors: Thomas Möller (tompa@clarus.se) Ben Trumbore (wbt@graphics.cornell.edu) Link to paper: http://webserver2.tecgraf.puc-rio.br/~mgattass/cg/trbRR/Fast%20MinimumStorage%20RayTriangle%20Intersection.pdf 14. ARM NEON: Matrix Vector Multiplication https://stackoverflow.com/a/57793352/2676533 16. ARM NEON Div http://github.com/microsoft/DirectXMath 17. Pick Matrix glu project -> project.c 18. Ray sphere intersection RAY TRACING GEMS HIGH-QUALITY AND REAL-TIME RENDERING WITH DXR AND OTHER APIS CHAPTER 7 Precision Improvements for Ray/Sphere Intersection Eric Haines (1), Johannes Günther (2), and Tomas Akenine-Möller (1) (1) NVIDIA (2) Intel Wyman, C., and Haines, E. Getting Started with RTX Ray Tracing. https://github.com/NVIDIAGameWorks/GettingStartedWithRTXRayTracing cglm-0.9.7/LICENSE000066400000000000000000000021101526744317200134630ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2015 Recep Aslantas Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. cglm-0.9.7/Makefile.am000066400000000000000000000317121526744317200145240ustar00rootroot00000000000000#****************************************************************************** # Copyright (c), Recep Aslantas. * # * # MIT License (MIT), http://opensource.org/licenses/MIT * # Full license can be found in the LICENSE file * # * #****************************************************************************** ACLOCAL_AMFLAGS = -I m4 AM_CFLAGS = -Wall \ -std=gnu11 \ -O3 \ -Wstrict-aliasing=2 \ -fstrict-aliasing lib_LTLIBRARIES = libcglm.la libcglm_la_LDFLAGS = -no-undefined -version-info 0:1:0 checkLDFLAGS = -L./.libs \ -lm \ -lcglm checkCFLAGS = $(AM_CFLAGS) \ -std=gnu11 \ -O3 \ -DCGLM_DEFINE_PRINTS \ -I$(srcdir)/include check_PROGRAMS = test/tests TESTS = $(check_PROGRAMS) test_tests_LDFLAGS = $(checkLDFLAGS) test_tests_CFLAGS = $(checkCFLAGS) cglmdir=$(includedir)/cglm cglm_HEADERS = include/cglm/version.h \ include/cglm/common.h \ include/cglm/types.h \ include/cglm/types-struct.h \ include/cglm/cglm.h \ include/cglm/call.h \ include/cglm/struct.h \ include/cglm/cam.h \ include/cglm/io.h \ include/cglm/mat4.h \ include/cglm/mat4x2.h \ include/cglm/mat4x3.h \ include/cglm/mat3.h \ include/cglm/mat3x2.h \ include/cglm/mat3x4.h \ include/cglm/mat2.h \ include/cglm/mat2x3.h \ include/cglm/mat2x4.h \ include/cglm/affine-pre.h \ include/cglm/affine-post.h \ include/cglm/affine.h \ include/cglm/affine-mat.h \ include/cglm/vec2.h \ include/cglm/vec2-ext.h \ include/cglm/ivec2.h \ include/cglm/vec3.h \ include/cglm/vec3-ext.h \ include/cglm/ivec3.h \ include/cglm/vec4.h \ include/cglm/vec4-ext.h \ include/cglm/ivec4.h \ include/cglm/euler.h \ include/cglm/util.h \ include/cglm/quat.h \ include/cglm/plane.h \ include/cglm/noise.h \ include/cglm/frustum.h \ include/cglm/box.h \ include/cglm/aabb2d.h \ include/cglm/color.h \ include/cglm/project.h \ include/cglm/sphere.h \ include/cglm/ease.h \ include/cglm/curve.h \ include/cglm/bezier.h \ include/cglm/applesimd.h \ include/cglm/ray.h \ include/cglm/affine2d.h \ include/cglm/affine2d-post.h cglm_clipspacedir=$(includedir)/cglm/clipspace cglm_clipspace_HEADERS = include/cglm/clipspace/persp.h \ include/cglm/clipspace/persp_lh_no.h \ include/cglm/clipspace/persp_lh_zo.h \ include/cglm/clipspace/persp_rh_no.h \ include/cglm/clipspace/persp_rh_zo.h \ include/cglm/clipspace/ortho_lh_no.h \ include/cglm/clipspace/ortho_lh_zo.h \ include/cglm/clipspace/ortho_rh_no.h \ include/cglm/clipspace/ortho_rh_zo.h \ include/cglm/clipspace/view_lh.h \ include/cglm/clipspace/view_rh.h \ include/cglm/clipspace/view_lh_no.h \ include/cglm/clipspace/view_lh_zo.h \ include/cglm/clipspace/view_rh_no.h \ include/cglm/clipspace/view_rh_zo.h \ include/cglm/clipspace/project_no.h \ include/cglm/clipspace/project_zo.h cglm_calldir=$(includedir)/cglm/call cglm_call_HEADERS = include/cglm/call/mat4.h \ include/cglm/call/mat4x2.h \ include/cglm/call/mat4x3.h \ include/cglm/call/mat3.h \ include/cglm/call/mat3x2.h \ include/cglm/call/mat3x4.h \ include/cglm/call/mat2.h \ include/cglm/call/mat2x3.h \ include/cglm/call/mat2x4.h \ include/cglm/call/vec2.h \ include/cglm/call/vec3.h \ include/cglm/call/vec4.h \ include/cglm/call/ivec2.h \ include/cglm/call/ivec3.h \ include/cglm/call/ivec4.h \ include/cglm/call/io.h \ include/cglm/call/cam.h \ include/cglm/call/quat.h \ include/cglm/call/euler.h \ include/cglm/call/plane.h \ include/cglm/call/noise.h \ include/cglm/call/frustum.h \ include/cglm/call/box.h \ include/cglm/call/project.h \ include/cglm/call/sphere.h \ include/cglm/call/ease.h \ include/cglm/call/curve.h \ include/cglm/call/bezier.h \ include/cglm/call/ray.h \ include/cglm/call/affine.h \ include/cglm/call/affine2d.h \ include/cglm/call/aabb2d.h cglm_call_clipspacedir=$(includedir)/cglm/call/clipspace cglm_call_clipspace_HEADERS = include/cglm/call/clipspace/persp_lh_no.h \ include/cglm/call/clipspace/persp_lh_zo.h \ include/cglm/call/clipspace/persp_rh_no.h \ include/cglm/call/clipspace/persp_rh_zo.h \ include/cglm/call/clipspace/ortho_lh_no.h \ include/cglm/call/clipspace/ortho_lh_zo.h \ include/cglm/call/clipspace/ortho_rh_no.h \ include/cglm/call/clipspace/ortho_rh_zo.h \ include/cglm/call/clipspace/view_lh_no.h \ include/cglm/call/clipspace/view_lh_zo.h \ include/cglm/call/clipspace/view_rh_no.h \ include/cglm/call/clipspace/view_rh_zo.h \ include/cglm/call/clipspace/project_no.h \ include/cglm/call/clipspace/project_zo.h cglm_simddir=$(includedir)/cglm/simd cglm_simd_HEADERS = include/cglm/simd/intrin.h \ include/cglm/simd/x86.h \ include/cglm/simd/arm.h \ include/cglm/simd/wasm.h cglm_simd_sse2dir=$(includedir)/cglm/simd/sse2 cglm_simd_sse2_HEADERS = include/cglm/simd/sse2/affine.h \ include/cglm/simd/sse2/mat4.h \ include/cglm/simd/sse2/mat3.h \ include/cglm/simd/sse2/mat2.h \ include/cglm/simd/sse2/quat.h cglm_simd_avxdir=$(includedir)/cglm/simd/avx cglm_simd_avx_HEADERS = include/cglm/simd/avx/mat4.h \ include/cglm/simd/avx/affine.h cglm_simd_neondir=$(includedir)/cglm/simd/neon cglm_simd_neon_HEADERS = include/cglm/simd/neon/affine.h \ include/cglm/simd/neon/mat2.h \ include/cglm/simd/neon/mat4.h \ include/cglm/simd/neon/quat.h cglm_simd_wasmdir=$(includedir)/cglm/simd/wasm cglm_simd_wasm_HEADERS = include/cglm/simd/wasm/affine.h \ include/cglm/simd/wasm/mat2.h \ include/cglm/simd/wasm/mat3.h \ include/cglm/simd/wasm/mat4.h \ include/cglm/simd/wasm/quat.h cglm_handeddir=$(includedir)/cglm/handed cglm_handed_HEADERS = include/cglm/handed/euler_to_quat_lh.h \ include/cglm/handed/euler_to_quat_rh.h cglm_structdir=$(includedir)/cglm/struct cglm_struct_HEADERS = include/cglm/struct/mat4.h \ include/cglm/struct/mat4x2.h \ include/cglm/struct/mat4x3.h \ include/cglm/struct/mat3.h \ include/cglm/struct/mat3x2.h \ include/cglm/struct/mat3x4.h \ include/cglm/struct/mat2.h \ include/cglm/struct/mat2x3.h \ include/cglm/struct/mat2x4.h \ include/cglm/struct/affine-pre.h \ include/cglm/struct/affine-post.h \ include/cglm/struct/affine-mat.h \ include/cglm/struct/affine.h \ include/cglm/struct/affine2d.h \ include/cglm/struct/vec2.h \ include/cglm/struct/vec2-ext.h \ include/cglm/struct/ivec2.h \ include/cglm/struct/vec3.h \ include/cglm/struct/vec3-ext.h \ include/cglm/struct/ivec3.h \ include/cglm/struct/vec4.h \ include/cglm/struct/vec4-ext.h \ include/cglm/struct/ivec4.h \ include/cglm/struct/io.h \ include/cglm/struct/cam.h \ include/cglm/struct/quat.h \ include/cglm/struct/euler.h \ include/cglm/struct/plane.h \ include/cglm/struct/noise.h \ include/cglm/struct/frustum.h \ include/cglm/struct/box.h \ include/cglm/struct/aabb2d.h \ include/cglm/struct/project.h \ include/cglm/struct/sphere.h \ include/cglm/struct/color.h \ include/cglm/struct/curve.h \ include/cglm/struct/ray.h cglm_struct_clipspacedir=$(includedir)/cglm/struct/clipspace cglm_struct_clipspace_HEADERS = include/cglm/struct/clipspace/persp_lh_no.h \ include/cglm/struct/clipspace/persp_lh_zo.h \ include/cglm/struct/clipspace/persp_rh_no.h \ include/cglm/struct/clipspace/persp_rh_zo.h \ include/cglm/struct/clipspace/ortho_lh_no.h \ include/cglm/struct/clipspace/ortho_lh_zo.h \ include/cglm/struct/clipspace/ortho_rh_no.h \ include/cglm/struct/clipspace/ortho_rh_zo.h \ include/cglm/struct/clipspace/view_lh_no.h \ include/cglm/struct/clipspace/view_lh_zo.h \ include/cglm/struct/clipspace/view_rh_no.h \ include/cglm/struct/clipspace/view_rh_zo.h \ include/cglm/struct/clipspace/project_no.h \ include/cglm/struct/clipspace/project_zo.h cglm_struct_handeddir=$(includedir)/cglm/struct/handed cglm_struct_handed_HEADERS = include/cglm/struct/handed/euler_to_quat_lh.h \ include/cglm/struct/handed/euler_to_quat_rh.h libcglm_la_SOURCES=\ src/euler.c \ src/affine.c \ src/io.c \ src/quat.c \ src/cam.c \ src/vec2.c \ src/ivec2.c \ src/vec3.c \ src/ivec3.c \ src/vec4.c \ src/ivec4.c \ src/mat2.c \ src/mat2x3.c \ src/mat2x4.c \ src/mat3.c \ src/mat3x2.c \ src/mat3x4.c \ src/mat4.c \ src/mat4x2.c \ src/mat4x3.c \ src/plane.c \ src/noise.c \ src/frustum.c \ src/box.c \ src/project.c \ src/sphere.c \ src/ease.c \ src/curve.c \ src/bezier.c \ src/ray.c \ src/affine2d.c \ src/aabb2d.c \ src/clipspace/ortho_lh_no.c \ src/clipspace/ortho_lh_zo.c \ src/clipspace/ortho_rh_no.c \ src/clipspace/ortho_rh_zo.c \ src/clipspace/persp_lh_no.c \ src/clipspace/persp_lh_zo.c \ src/clipspace/persp_rh_no.c \ src/clipspace/persp_rh_zo.c \ src/clipspace/view_lh_no.c \ src/clipspace/view_lh_zo.c \ src/clipspace/view_rh_no.c \ src/clipspace/view_rh_zo.c \ src/clipspace/project_no.c \ src/clipspace/project_zo.c test_tests_SOURCES=\ test/runner.c \ test/src/test_common.c \ test/src/tests.c \ test/src/test_clamp.c \ test/src/test_euler.c \ test/src/test_bezier.c \ test/src/test_struct.c pkgconfig_DATA=cglm.pc # When running configure with --prefix, $VPATH references # the source directory that post-build.sh is in. When not # using a prefix, $VPATH will be unset, so we need to fall # back to using . to run the script. #export VPATH # all-local: # sh $${VPATH:-.}/post-build.sh cglm-0.9.7/Package.swift000066400000000000000000000020101526744317200150660ustar00rootroot00000000000000// swift-tools-version:5.2 import PackageDescription let package = Package( name: "cglm", products: [ .library(name: "cglm", type: .static, targets: ["cglmHeader"]), .library(name: "cglmc", targets: ["cglmCompiled"]), ], dependencies: [], targets: [ .target( name: "cglmCompiled", path: "./", exclude: [ "./docs", "./src/swift", "./include", "./test", "./win", ], sources: [ "./src", ], publicHeadersPath: "./include" ), .target( name: "cglmHeader", path: "./", exclude: [ "./docs", "./include", "./test", "./win", ], sources: [ "./src/swift", ], publicHeadersPath: "./include" ), ], cLanguageStandard: .c11 ) cglm-0.9.7/README.md000066400000000000000000000233601526744317200137470ustar00rootroot00000000000000# 🎥 OpenGL Mathematics (glm) for `C`


Build Status Documentation Status Codacy Badge Coverage Status Coverage Status

Sponsors on Open Collective Backers on Open Collective


A highly optimized 2D|3D math library. Also known as OpenGL Mathematics (glm) for C. cglm provides fast and ergonomic math functions to ease graphics programming. It is community friendly – feel free to report any bugs and issues you face.
If you're using C++, you might want to check out GLM

- Allocation-free - Header-only - SIMD-optimized - API-agnostic --- ### 📚 Documentation All functions and their parameters are documented above their declaration inside their corresponding headers.
Alternatively, you can read the complete documentation [here](http://cglm.readthedocs.io). ### 🔨 Building cglm can be used in it's entirety as a header-only library simply by including `cglm/cglm.h`. If you wish to link against it instead, it can be built using one of the supported build systems. Detailed information about building on individual platforms and build systems along with the instructions for building the documentation can be found in [BUILDING.md](./BUILDING.md). ### ✅ Usage #### Header-only Include the `cglm/cglm.h` header and use functions with the `glm_` prefix. ```c #include "cglm/cglm.h" // ... vec2 vector; glm_vec2_zero(vector); ``` #### Struct API Include `cglm/struct.h` and use `glms_`. ```c #include "cglm/struct.h" // ... vec2s vector = glms_vec2_zero(); ``` #### Linked Include `cglm/call.h` and use `glmc_`. ```c #include "cglm/call.h" // ... vec2 vector; glmc_vec2_zero(vector); ``` ### � Alignment While cglm by default aligns what's necessary, it is possible to disable this by defining `CGLM_ALL_UNALIGNED`. If you're targeting machines with any kind of SIMD support, make sure that all `vec4`, `mat4` and `mat2` arguments you pass to cglm functions are aligned to prevent unexpected crashes, alternatively use the unaligned versions if present. ### Struct API The struct API works as follows (note the `s` suffix on types, `glms_` prefix on functions and `GLMS_` on constants): ```C #include mat4s mat = GLMS_MAT4_IDENTITY_INIT; mat4s inv = glms_mat4_inv(mat); ``` Struct functions generally take parameters *by copy* and *return* the results rather than taking pointers and writing to out parameters. That means your variables can usually be `const`, if you're into that. The types used are actually unions that allow access to the same data in multiple ways. One of these involves anonymous structures available since C11. MSVC supports them in earlier versions out of the box and GCC/Clang as well if you enable `-fms-extensions`. To explicitly enable anonymous structures `#define CGLM_USE_ANONYMOUS_STRUCT 1`, or `0` to disable them. For backwards compatibility, you can also `#define CGLM_NO_ANONYMOUS_STRUCT` to disable them. If you don't specify explicitly, cglm will attempt a best guess based on your compiler and C version. ### 📌 Migration notes: - `_dup` (duplicate) functions were renamed to `_copy`. For instance: `glm_vec_dup` -> `glm_vec3_copy`. - OpenGL related functions were dropped to make cglm API independent. - **[bugfix]** Euler angles had been previously implemented in reverse order (extrinsic). This was fixed to be intrinsic. - **[major change]** Starting with **v0.4.0**, quaternions are stored as [x, y, z, w]. Previously it was [w, x, y, z]. - **[api rename]** Starting with **v0.4.5**, `glm_simd_` functions are renamed to `glmm_`. - **[new option]** Starting with **v0.4.5**, alignment requirements can be disabled. Read more in the documentation. - **[major change]** Starting with **v0.5.0**, vec3 functions occupy the **glm_vec3_** namespace. This used to be **glm_vec_** in earlier versions. - **[major change]** Starting with **v0.5.1**, `vec3` and `mat3` types are not aligned by default. - **[major change]** Starting with **v0.7.3**, inline print functions are disabled by default in release mode to eliminate printing costs (see the Options chapter of the docs).
Colored output can be disabled (see documentation). - **[major change]** Starting with **v0.8.3**, alternate clipspace configurations are supported. The `CGLM_FORCE_DEPTH_ZERO_TO_ONE` and `CGLM_FORCE_LEFT_HANDED` flags are provided to control clip depth and handedness. This makes it easier to incorporate cglm into projects using graphics APIs such as Vulkan or Metal. See https://cglm.readthedocs.io/en/latest/opt.html#clipspace-option-s ### 🚀 Features - scalar and simd (sse, avx, neon...) optimizations - general purpose matrix operations (mat4, mat3) - chain matrix multiplication (square only) - general purpose vector operations (cross, dot, rotate, proj, angle...) - affine transformations - matrix decomposition (extract rotation, scaling factor) - optimized affine transform matrices (mul, rigid-body inverse) - camera (lookat) - projections (ortho, perspective) - quaternions - euler angles / yaw-pitch-roll to matrix - extract euler angles - frustum (extract view frustum planes, corners...) - bounding box (AABB in Frustum (culling), crop, merge...) - bounding sphere - project, unproject - easing functions - curves - curve interpolation helpers (SMC, deCasteljau...) - comversion helpers from cglm types to Apple's simd library to pass cglm types to Metal GL without packing them on both sides - ray intersection helpers ---
Like other graphics libraries (especially OpenGL), cglm uses column-major layout to keep matrices in memory.
 
While we might support row-major matrices in the future, currently if you need your matrices to be in row-major layout you have to transpose them.
--- cglm contains general purpose mat4 product and inverse functions but also provides optimized versions for affine transformations. If you want to multiply two affine transformation matrices you can use glm_mul instead of glm_mat4_mul and glm_inv_tr (ROT + TR) instead glm_mat4_inv. ```C /* multiplication */ mat4 modelMat; glm_mul(T, R, modelMat); /* othonormal rot + tr matrix inverse (rigid-body) */ glm_inv_tr(modelMat); ``` ## Contributors This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)] ## Backers Thank you to all our backers! ðŸ™� [[Become a backer](https://opencollective.com/cglm#backer)] ## Sponsors Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/cglm#sponsor)] cglm-0.9.7/_config.yml000066400000000000000000000000331526744317200146070ustar00rootroot00000000000000theme: jekyll-theme-minimalcglm-0.9.7/autogen.sh000077500000000000000000000004671526744317200144740ustar00rootroot00000000000000#! /bin/sh # # Copyright (c), Recep Aslantas. # # MIT License (MIT), http://opensource.org/licenses/MIT # Full license can be found in the LICENSE file # cd $(dirname "$0") autoheader if [ "$(uname)" = "Darwin" ]; then glibtoolize else libtoolize fi aclocal -I m4 autoconf automake --add-missing --copy cglm-0.9.7/cglm.pc.in000066400000000000000000000004111526744317200143330ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: @PACKAGE_NAME@ Description: OpenGL Mathematics (glm) for C URL: https://github.com/recp/cglm Version: @PACKAGE_VERSION@ Cflags: -I${includedir} Libs: -L${libdir} -lcglm @LIBS@ cglm-0.9.7/cglm.png000066400000000000000000013650461526744317200141330ustar00rootroot00000000000000‰PNG  IHDR¨°Ö­ IDATxì½€^U™ÿÿ¼ý�^2-3“ÞI�:HY)*l ?q]Ü¿Še];»âŠ"‹®úS÷·X±‹±�Š H/!„’��@2é“dú;o»ÿïsî{Þyg23™òÖÉ÷$gî¹§ŸÏ½ï½ç>÷¹Ï¡#                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                ˜ ÏT ± � � � � �@n Ì=þ¬ºDyÓ2O r¶„Êæ:¡Š¹<äDúžw"½;Bû<¼}ûÝ‘Üö‚µ“ � � � �@n P@�[¾¬�H€H€H€H€&L mõ%íÞöã>"µ­WŠ×[©� ¯ûIÄhœ$“QÏöG.Ûsß�«»t$@$@$@$@$Pм¥Øiö™H€H€H€H€f"�@]ËÙžúöw�%œ6‚i¸<Þ ,8å7íí§—ÍD � � � �À±A€êcã8s”$@$@$@$@¥B %…N £Ñï¡ÏÖ}kŸsf© �ý$    �‘( I„û$@$@$@$@$P„2…ÒV8­Ýô–×,.Âî²K$@$@$@$@$0!PO3‘ � � � �@ad £Ó=@dZ`ÏIÇ3@$@$@$@$@%FÀ_býewI€H€H€H€H`†°"i×ȇù‹?™&?28âõeî3L$@$@$@$@¥D€Ô¥t´ØW    �™OÀʧíHGH¦G&ÛlÜ’ � � � �@) €º�ûL$@$@$@$0à Œ�Jc´®IW<í†yd¶Î…Ã#   ˜ihâc¦QއH€H€H€H d $LÏ�árçL•i¤u×Ê¥� :Y²ÃeÇI€H€H€H€H@¨AÍ“€H€H€H€H€І@2-|>¢K)©´cDÔG¤2‚H€H€H€H€J’Ô%yØØi    �™KÀêG�>B×¼G¦ZõèùK$@$@$@$@¥@€êR8Jì# � � � �À1A@M|¨��L#F�!³vÔ‚O!=Ô¥>&Î ’H€H€H€f6Ú žÙÇ—£#   (%‰„8F�’HCmÒ&”N3bkŒÌnKi�ì+ � � � �  €zˆC$p4~iXÖ$•³š¤¬¬Q‚å-âÖ‹/X)Þ@•øü5âõW@ŸÉ/¼nÅ/ŽÇg*ö8úÄs}¬Gb±.IÄK¬ünìî�Þ;dÏ–ÈŸ¡'u´n1�H€H€H`¦P j�Î wöb:àq2Щ„ƒå'‘#€p—H€H€H  xªÚ–×;¾ª V6H¸ÛPƒã Tzþjñ«<>µÇñ<^OrŸÞA¯×ƒi‘÷™J2.N¢?%Séò$#û�Xßng°w·§·ë…ƒö`ðñbÀ>�M€ê±Ù0…,�œö�7Hã¢Ûˆœnã±}²kÃGå‰_íÄrÚ+'  (:jÞCÓ®lÚ¾³¶‚êáK$ÚØ¢;D$@$@$@)•ËÎ?_–œóǤÇ㵯Û3g8#ãì¾ÏœëØ2™`ÓqȨáº5—%eßÖã;ïú|OGGgf^†‹—.Š÷ذgÅBà‚÷Þ•7á´ŽÙh’¹k¿)ç]s{± `?H€H€H€òG@M|+Ôº…O¦¶æ© ÝÀnꯆÜ=Å?$@$@$@$Pd*W¿ürYú’?C#ÚÈ Uàœ9{±a;«I¦Òm¼Ǧ٭Ʃ³ûf‹?º5í4/þ¨ÿ¤·mooo/Ó(ºâ'@ êâ?Fìa! Ô/®–òús ҅ʆ‹dáÚãåùGŸ,Hûl”H€rO“ÔùA©I–IEU•„*kÅ®�€¿[×t’/P#þp­x}e˜lÅëÕÏý‚âñŸÿ‰~þ—Œ÷H‚3)Ž3jÚ?Ö�®‡¥wߥçÀƒÒµïiÙùØóà9íjó|Lx È3p6G$@$0%'T±LKšyMÆÖÆ�7·mî3ZœÖe�mGëõT5_ˆÍ'm·ÅK€êâ=6ìY1—7´eµK Ú>' �‰ðIËâz©l^$UM'JeÓ™RÙx¡1Y4±òùË¥f”jZÞh|ºÕ׈tïþlÕ}[vmº_º^<”N*ÆÀ —¾EÚOú_h•—c÷LŸÖŽè™ã$¡ÑºCb‘d0²ÛIèÁ};¥ïð6‰îß-±®Ã²wïJ–š pÄ`§¿k¬ðG¬ìC–îè~1»•+Wda‹SÛ¼Ì)¯_#• çz*jÎMøüaH�ñ„kH{!|×-ö1 Ÿ §a�2à‹ÃÇ =át2&ƒ�DF’Ò§ÂéAW8Å™‘•“£¬f^”­“Æ%.Î_™”÷Ȟ§¿.[þþ"£ÅÌYx (êÃÃΑ � hhhëäÎÎgìVsd†u¬yÎhù4Nó�,32¯”ל¦uÓ? ¨‹ÿ±‡…$éÝYÈæÅ¨-hûlœH€F#ÐÐP%µÇ¯‘†¶ ¥¦í�,_4Z¶’Š«žý:Q¿ø,¨hBËúàÖ¯ÊΧ¾% { qÕů‘¹'wdtÑï«ÍÁ@Ù<ã�&VWþ‡”žý÷Èá=÷Kß.h¹oÑn²"›,zVè jPc•Dý3ôàeÕª3 eG<ˆe¤ç:8åËZ5ͧzê[_á©j|]Ÿ™·¸hŸš™„Wa4$ÓðXô[JkœBiÆèóBé^…ÓÞtî±644§£�D @8 Át/DŪ9��æl¬z~Öµ¿ÍøP´ê=ðÙõÔM²é®»Á°¸Î;^r}Z³~  �,8pàÀ@ê9gyO·û6ŸnÕéÖÆÙ<6^÷m>�3é™™LF��¤«Ðº"%@u‘v«HÄì/hOüþê‚¶ÏÆI€H`$�“ßøA™}Ü�ŒžQûªeÝ´ü“Æ/?ïnÙþ÷kdë#‹bŒm'ÜTýÈe'”UӥƷ®ji°gƒÚs›tíø£t=û´­û†gVÈÈ«#°ÉƒˆXÇjÆ›�±V6\ŒÅœ.–…gì“z»Œ0ôo•ý[¿"{Ÿû�t<±Õ@”9œƒÐç(u®ˆZCzÒ™XW½Z£Œ3ŠÖv'OÛöÓÞzާrÖ¦CF ­‚g5Ù‘òHP¥d]íÑ®��£AgUsÚëQ³NÃ<¹Âi,p*1øø`B"ƒŽô@sºG…Ó´jNêgÌ-<ó×2òâ#o—�ø5ò<ã5à˜¸äé‡ÌfH€H O<½î€Ù¯‹¬`Y›Õ°�ídîÛ<™å̰æµÎÖaËèÖÆÙ<©mfS#’¸[,0m¤#‡@ÌØ%'“H€Hà˜!P]ÛzÌŒuä@uq—%çýE.úðfi]Ú029Oûvþ�§æŠ¼5-ÓvüdÍe›ä×Eå´+?'-'Î/ò^O¨{Ö°‡nÓOTކ`&Ãx÷l¨²üN齕M'[Ò^”¤á}>˜D‡GØõ®æ´OMz@8­>|Lû}XGv¦þ(Ô¨$‹ÀÖô ô@]ú`_R 8rÂiXø(¬pz.:¨—§ÿB.ùøNiXVÈë ¯™Çe_2‡É0 � ”:�äžg¾lÇîlf¸pÚŽOódúÌxm;Z›OÓàÒÓ)w—‹‘@~g³ÅH€}"�£Øýì—Ž–…é$@$pLèëë:&Æ9Þ U ²æŠÝøüÿìñ²å,m°÷ÙœÕ]Ê«ºnãÂȺ×l“‹?²]V¿ür‘ö’ü "^WëX5��vò�˜:õ�•ñð�u¹|‰Ø.Dû2¼×£ÂiH£ÿ)Á´+”†¶´Ú˜öÇ$è”�/"¦½É˜ó”þtÒÁtWÔ‘>|¬‹!&0X;Þ¢95ýÁ9튲ì‚ó Ö'^FG?ƒ®£�±$@Ç<�y§ë·Ý¸ëOŸ|ùþõÕ{º½¯ë 2½¶0ÚÀl[Îæ-ïÈ´±òh>ºâ$@Åy\Ø«b"°ùîû¤ïàñ…j$T6Kêç], 󯯿²˜ºÉ¾� �@Î HèBut¯_–�ÿW©ký„<ø£OHæ¼9·|ú{“PåòÜ6RâµëbŒóNù¼Èî§?$�<úE¶ÀhDi8ˆ}aÒ‡“*õX–~Â:ÍÒQ&�ÞËÛ�ÁÞͪmÌw¤ÌzhãšL׌‡šóÀH`ÊÃë…)xìM{œ¸$ §ãN;Ò¡´z]QmM«`ZMz �6oÚXC*]zÎ]RÓt­<ô£Ï佫¼ý8•ø5àèd �cŽ@ÛêvY}ñc²ò‚ƒÒñä¿Éž~RJkq`¡ÄžòûÜš¨ª¨öúBužŠæ¤yñûE¿Pœ€³s‚±f<oóhu6ŸÙÚ� ´Ã,…%@ êÂògë¥A )vÊ‹?%Ïýõ¯òà÷>&¿ýTµlþëù¥Ñ}ö’H€²EB>'yÄB'Ùª½äêÑ…ÏïŸÑïüͧm¿µä8²Ãº ç+ÞÜ-'¾êíèFi(f¨© È@½R»‚`„†¼«Q­öž‡t«óûôå8Üáó¡wRûÔ„ú¢[ºáõA0íƒ`ÚsКöûԜǠø˜ôHDĉ Jl0*}ýª5�”.©ÕÞ´šôˆáéR dòô·íæå×Ë¹ïº yò Ÿ×€qˉ¥x 8bŒ 8æ 4/}�a &§æ®ù–œòÎ^9ûê[¤}ÍâRaÓà™ÝƒÛÙ4°åïô?ñ‹›îü¯å¾‡¾ÛìÁš"#o¤#ç6]ã­9nÍc½¦™0þè–®4äï�ª4x°—$0QŽlúó_äá_.ÇQE: 86Úñ�cc eEýy²îŠO0÷ô³íÚ|Ïô+9Æjðxƒ2gÍ×åe×î—¹ëVûè}¾ „½j>C…¿ÖŒ† c«ÂkxUä5‚lÝ"o>Ý–ÇzÀ'‰^mV½Bi„Ò~¥~5ç•Ly¨�iÓI¥£J÷Ã~GWORv;r¨ !B¯ÝjNëÚ�#Hó9¦)µUÕt)^~üÓ”ÊNµ¯“'Wb×€É�%H€f<�æå=bŒµmWÊI¯zÎsÑGŸ—ÅgžvDz Dôîݺ¯ÿŽ�“�ÃŽìnæœàhBfM·^ë±a»Y7÷‹“@~g³ÅÉ€½"�©س~»ØòÙ©WÀ’$@$Pbv<þåëqî»Û²ü3Ò~â’Ü7„=ß%´A;5Ô¾@­œðŠ�²ö�AúÌR”.ÍiLûS~Xvž}°0câLûjû9ÿÊáŽ÷ÐŽëý*”ÎXø0Ó~¦}¦‚ihLGSv¦{UcºÓýŽtGD°&¢ âO EmÒãhg‰¾üh\Ùr´lYKç5`ê(Kä0õ²$ �ÀŒ$ ‹óúMcŽ-^àYqáýÞ³®þòÇÌW¼ Qïæ»ß6^÷2…ÕšÏ žG›Ì¥ÓFK¯¦œ@i|êXpLì ŒC`û_”Æ%'“H€H`æxññgdÕ+ºñý~õÌTF²ê’¿ÈÎõóQSîM ÜyÓ ´3Þ´; —~²dl.g�þäªh=î©ûÀëäɦí7ú|h%õªçZ£6úÅ&j(Þœø£‹æÛùnü¾wvëg];Ój_:mé„ù°L-Åag:KHö¥#Q£a¿f§ÍˆjÊ# ¯æß‹$ÚÜ{ëÏ~ííéè‡}éž¾„t÷¹6¦»"ø|aÑ IDATYÂÈ ÖD”DÍ*¤V“*uUrºÿùÏË–{î‡pºY&*œ¶ÝˆÊÖG6ʽ߼Zîùú,9øÂWmBÞ·‹Ï\›÷6Ùàôá5`zbi �E uÙ«F� c­×ô#î­¾@}`íÚwŒV¶XãwôvŒì›Žq,—9~6[ü¹«ÆjP×ñ`oJ•@oçÎRí:ûM$@S"ðнŸ•W,ú8¤dSŸKl¾ûr´}ÄœzJý±…ÔìÒž-ï‘ÖU7ÉŠ—þDÊkO³IÙÞêä׺ô šW|\äöïÙø‚m±Ã¢ ‚åÊEû·JÿáûaŽe=ü30uµæXú`Ž!*ñ¾¨Db1ñ‡ãâ •KeY�xËgIYU L³´IYõr©k«x}å¹êÞ¤êÕ…‡Nø?’?}á ”›¬ptRMM$³/…ÉŽ$º8ÃÔÙó+u’Ù‡.7!uÀµi];´ñ¾Ëçž÷·„ÑðjÊC>´¦M¢Ùt֖㯑- ½_ȯ§_d×€‰wœ9I€f<�ÙCæ=Rw|3äÌðX œ–•Ÿù¹~ÙS"ÚÞ‰ØAÌ_ë§ÚaËÅjNëÖ†§Z'Ëå�ÀÔ*ó×G¶DÅO §³´ì;?Qö�H è `¹ó‰wÉœ“nžRWûÞ-ÛîhJe'Rhׯ²kã° �…laz#ËÎ~‚f'Â*;4òÃPÅ2§º½^TPVH—HÊ©€úŽ—bxæv ^Œ‚âÝ0ÉÒ&� _&MKÿUÀm”<ù‹*«=UN}ó'åÁü{þ½¥`YŸxÃxFs|FH­–<#¬ÆC–ZÃ>µž{æüÓÏÉp�Üæ{ï¾·æåë6Æ•«Œ`g…žæ÷0‘>íØðά/V¹õ¯÷Iß®V9éò�¢ÂÇ|¹ºÙoBSo…Ÿê!Ùë)¯“cYD×€Éuœ¹I€f,�–Å�XsaÎhãÓ{¬�ƒêvÔ{®×–úÅÕ©¯“F«¦øâú? Õ�/³cÓÚpæÖ†mºîŸ‘ ‚iý�j¥TÎ>_•FoÙK(VÝawñ®bíûE$@¹ °þW_—žý¿™RÕþtÅ”ÊM®�c-Ü÷ì'&WlìÜ:ïMY`}˯–3½¦ù�™Ú̹u£> M¢IG:6ì”õ¿úšÜù_Ëåïß«‘ý[oœDùìgmZz­,=÷¬ìW<¹+|ÝRè“ÊP�”‡z¥,Ô/aøP("ÁЀñ�à€ˆ`;eõ�É5’åÜ]÷ÞzÎ`<Þ SÔ“NÇ"òÄ/¾‘åî¸Õé×ë~JNê¯Òb1óÁkÀxGiô´"¹ŒÞ9Æ’ sf¯zeæ˜uâ5–ÏÌ—T5.ÊÜ/ö°g°ç™Ì>ê¼;ÓÛ9¸��ëV]f+˜NYI?¥ž.¤øËCU‰],[ ¯)S ˜ØG �™FÀ‘»¿ò‰ô¬ŸðÀœd\žàõ²ÿ©Ñ´j'\ͤ2>ø£ÿ”Þw­Ì°É-2�Ü·“bHû‘¨>�áu_ÍûZ†>ÇŒmH½Þ? á€ní>¶º�vA]׋‡�Ü~|æ:&|bÄcûä‰_�‰~Ã(HŽÜîg^�Q­æü¹¦%¯Ï_cã´ÄkÀ8pÆI*‚kÀ8½c �À±D IÍÆ�íF»ßÚ8»õTTÏ»†âKq{·Ú^aJmæâ#÷u>®sq;/×­É›*`Ôº¦‡Ð(9y芟€K: �éЯYéH€HàX$—?þìtÙûìµ’LŒ¾RøÀáåÅ'þEÖÿz±üæ“!yê÷?Ë;¨Í|óXmÚ °nub”éuœöÈ`Óf Õ ?| åƒØ1+ö‡+—£˜VW8ç$s- ÎÍØôÅÅ]_:_ž¹ót‰Gó÷ÃŽFíbŸzÅGìn!¶Ý Iô&Ä‹E}0êì�DÅ�Š? jV^‡“ƒ‚&#î¾ô¢«ÃÛܳ~»<ù‹ÅÒ½÷ÃR{úrªkÏOaÚç2yð–ùýõÍ¢ä\» ·ÿH"½O纙tý¡ª•ép!¼L�~\¦Öq–"˜QZ—6H0¼àhcRA´FÛ¼vߤ…+G5bóÝv gÇÈ1é„Zçæv›9O7a$` nLy˜<ø£ZÓLàƒN‡(|.<]Ñ  ê¢?Dì`ÉÐi] œŽH€Ž9°GýÐöOcØ7ȵ+%îO`½Ã"�=rà@?âs§!9QÖÏvJÛ³×zš—_o‹è$Öz�àÚ°4¬Nµ0†â=fìN†Ý°Í§¹ó °Ü¿xqP¶ltk)Àß\jO&zLsët¡¹þm‹äø·l�`ù¢Ü66¢ö¦åŸ”ª¶¯JOG爔¼ìîîÂKøN4�¶¦Í §g—û¦Zú^œozî¥ȺŠä=ù ¶É ^+ÍÍR±è8‰ö–xïañö÷É®]úÒÄ>7ç…eº‘{·,=ç®ô~.¡ÊU¹¬~Âuó0aTGd,ð5àˆþ0‚HàØ#аâe“tæÍuhnŠyB¨*¿s¨Étz”¼°N5æÚ^:.뵨 ã�Î…t'­9 Á´jM ˜VuYA¿‹ÓžÒM”Ô%Å|$p4‰Á}P ÓI€f8�¤<ÿè“E;ÆŽ§¾ãM ¨u.«Z#û˧Ò:ÑÕx"RÃf«e°Ÿ "^sjº[B%pŽTFËÊ_)œ€Ú�jm®\>ÔÚ÷]»úe×­«äÂ×?.!£•ž«YïšW]îùêeG&ä>f?Žœ¢\c.'–~¢ªç¥Š õ<ÓsÏ�Eíù«‘N±¨-ž½{asdïÃv·àÛM¾GŸÙ/ª›k·åº‰ ÕÏkÀ„0�™©€×€1ûÄ �c‡@˲�Mg°æ¥6*pü¡†éԓﲉd¤òåÔ¼Úm]Ç¢óuºM{Ì\H·(¤svŸ §U0 z°~‡ëyrBnºÍ?$€CHG$�ñèþ¬ÔÃJH€H€rC cC‡ÂUc;3 µÄ6„ÉlX=^Û—ÃW`R[ _…I­újõa¯TÁ붺 ¾\·ˆ×°nË=Rc=â*fUUçf¬5™Cu^M@;ÿÎ_ž(ƒ=&8òìd«nz�´,nÌNe“«%‚ï `áCºã®?9„WêÂwB€}¾Bìðû Ï®â`ºq $eÿó7�›#»‰…Wâ5`zG´€×€éuœ¥I€Jž@u{½„*–MuV›Úl½þŠ©ÖSˆrž˜ô«�R…ÐÖÙ°Ýj¼¾¸×ùÖ”GHçðД®,Ãü¯¢«+1‡¯ÂܼÊ'ÕU˜ÔÓ• ¨Kâ0±“%A ós”’è?;I$@3Ÿ€:ôÂÿƒŒÙ¤Ët2‹9k4+*˜І=˜ØbB«Âç ¯ÔVz¥¾Ò'õ˜Ü6Tû¤Q}�^·>iªUï•æ:õ>ãÝ8ŸÌ^P5« 8�1ì�g£S¹Ô̵0•rççÖÉ`ߦQ“s9÷´wåªêñêU{8ª-­>ާËXÊkØî"1?�Úê>ÝQÞù§£äÈ^rC‘ ìx ˜þ(Ð5`úg $@%M`ÞIO·ÿ*Ì5]¯7÷_M·³å}½¶ï™Û´¦4"5l…ÓjÂ# Á´Îå«1Ò:ˆãëS‚é*h›”C}:Vçf´Â`±(üÛýb%Ã~•2èÁ™5­t æÅaj«a}„³qfÑ%¢°·JG$@$P̪b�{‚‹Ì§€>ÌnÕF][¿†u‹Y¯Æëªß^|+èÓ}x�÷°G·ðFsö�4aýãàîb¼ùhlj)('½Û¹d2–£šÇ«6*�Ýv¾œþ¦Žñ2e5­iÑÇQß§á 1^3Yk¢ñ6Ín³:ö™XYßžgò7¬ÆJè·våJ^¦¸ | ˜þX �@IhY®ó�i;ðŠ×_5íŠòX�ןˆi¿‡yì�nS^5§U8mLy@8­f<ÊðÅcZ(>¬Žèƒ�¯/€9}æü¨A�ÇC8­¦( ž>.5sëdþ‰¯‘æeœ��J]I>y‹÷<'‡wýZÿùÿb,Ó{ÆKÄ{‹†;B$@$0*�j_d¯¯Üç ¨aã#ˆnÞ»û @(­Âj/¼¡³Ú›öi„ÓºuW¬K ¨}Pk&˺0bw‘¤J¨õvRßTóéA;N¦LÂÐDÜ�M»dÇãï�9'Ýœ—Ö=^¿¬ø‡ å™?ý6/íM²‘éMZ&ÙØLÈÞñìA9ÉIâ‹_mŽ�?-v¼Lÿù5`úd $@EG v~­„+�›N¿0-2‘áñ””tÖÛIØþ›-þ¨2ˆ ¦�9ÜÁ�pë4§Ã*˜Æ�åð¡�k¿x|AL×ueDl� $c*Þ¦+P—ÂQbÇ"à•¥çž!s×ü·”Õ¬+Ó¨ñ:á –/2¾²ŸÐxüòøÏ¾U¬꣡búð«ØŠ¹ß’#R²áô~NÈk@vŽ*¯ÙáÈZH€&F ý¸ '–qfæòù‚FÁB§Ùú6Y·F8 3¦îFkZ׎)K §CL‡±öK0è?´¦=^H¬��8IdpØúÄ)ü+ã™y°r0* ¨Ç‡ £“Ëša¸¦V‚Õ5x%Ó þp£+š%XÖ&�²vl`»O·ø”/å’ФM&áã}ÐÒ}Q¢½[d°|‡Dºž—Cû·Èþ§:‘» ŸŒÚnNcë•¶Õ­RÙ°Tá0h_Y3¾§˜-~0ñ‡çJ^™$ba3r³Dûž“Hÿv‰õ¼(‘�=ï—x§ô< ‡·OÎ4Fss…´žõ�ÒzÜ ã>�IMóKQ|zjI`©¢cÒá¶a^Òê=¾·Œ�X¾išé#Q¶¶–KYëB T·J¨ª ~ž+—H HÊæàÕh—Ä£�8çÈ@ï3Òß¹^ú:Ÿ“C{6Ë¡çó-(òJëª6©¨_ eU­¨œ/åUx!R¹×�Å’ˆÀµa'ü.‰ã÷Ðß³Iºw>$Û;·‹`A0: �œ¨©ô÷ø°‚ŠÂh:;x_ U ¤½Hc_ÐðI¨§Æ5œº¼©Ò%Jàʦ—<½è¹iСΰ…BªÖŠÙ´Ó8h2è�×IªBw–/Ä©Á8Na4¨Ý擲íá«dÉ™·çm¸ú$io/“�;�Õ{|^0ç­‘x¤#/ê½{ ÷ÇÂÄ5À³¾å5 ëHgX…yy6¸úê›Ë½ e ½Á`«ãñµù‚áyŽß·Äñ—á ô'ïJF£�ÉDü€íƉö®÷ö>çé‰lþÚ×>’×gƒë®»Î‹UµÅËj$<¾V'P6ßë .r�å^p±8‰’ˆïtbñ]ÉØà':¸É3pà¡ÎݽÛo¹åºcìÙÀñ\w�N¸îö>%MÞ•²Ï[±0ê«o÷×U?ëÛ·eƒgÓ¦b�<‰E£;ã�>*z­ËÙ”'ï¿ÍÙÇ}4m–*Ÿ¯[õ=ŒpÚhNCº`4§1]×…Ë ®‹!†aÎ#Iu‚iì|x¼ˆàBðHL"£‘„Îëqv$bYY¨ÃÓÖvJ½§¢i‘/lL„+Z k—@ù\'^hæX£Å‰¼èD£N,²[e_ž®½ îß¶ùàÁ-ÝÙ8®3½9º ~™³jžÔ/:GfÍ „Kçe¤M<¨‚Y¯@`�‡jéŽUO,²Cön¾Av<ý+9ðÌî‰7�ïœóÃ2·q‘Ìj?[êç]!åuçL¸¾@½”מfüX…±ÃrpÇ7!Dü¥t>³AŒa³¯iA³,9ïßчì/ZÔsྱº7áø¤Sj/¼xèÆU¼¼¾¯!kðr¡/° ÕB;­^|ØzCõÔáÊhÀ„¯ñHóÕãN0ú5ä±5Hdzúfê®na�Ô·¯”†9—HÝÜ«ð2¤müÊMé‡ÎªÆWˆ,Ê�î‘}[¾$ÏýýkçBh„kÇÚy2«í,©�ÿf©š¥/<Ævþ` LѬža�ÈñˆÑ¾v>ÿÙùèͲkó�áy¸G$0]Á²¦jOë—©–4nÖ hV$1�M"ì £!œÆ{çïdá)qOªŸ@îég)_¼/^ï�~E¬¡àw‰®•”{Wx}­dax ÈýT˜ŠúÙàê?Rãø“+½‰K¤Âs•×ïàÙÀ½Ãy`^Kÿ¹[ úM¯o‰7u'\ö �Ô»ï˜ñùêÿþýé=ô¥Ä¡Í_ûæ®Ëú³Òþ¾xý¸2 Ú“#uŽéFŸÃU'f«w:h�™–šS�é´prfµ5ÂÄVµ¦Õ”G„Ó˜òP;ÓØ™öx`Ʀ<ŒÖ4„ÓLcð&ÁÉ8n†Ñ¸466Nöð,Xpj“§zþºä¬öËœª¦+¯7¬•èïX¹jx躓:É‚áEžÌyFë* ­™�ÄâåÝ{¾ï}ññ›:ž¿ws©“|õwtáR¾Z/|;>i;a‘4.8Wf-¸BÔ3òÚ¥@xŽ´¯þãûÝ+þøzhVïÉkÆn,('\úF™½ê†£ Ç®dB)¾@­4.ü€ñòÐ î–Îí7ËÁço—ÈÎg$Ð2WæžößRÝø² Õ7•L={§ÿà™ŒR£l¢£ÈiW}NêÛþONì=ÉðD;4,_ëJë“Þ!õ Þ Axõ°´éì¨@¸õ¸Œ?´û‡rïþ) šÊAYþçIÛñÿ‘Õk‡öµyùõÆ/;p‡lèC²íÁ Ó>Ë’ ˆW´4ë dÒ[Õ˜V)n„]­i3¡ÕI-îÄeÍìÞÕ¾H ¨íÀœ­;QÅ£&òd ¨}}=ú@T0WéK&ÑYU1¶±ÑwYèR!M|¸ÝOÊžg>�¯¹¦ùåÓY4/¾R6ß=ýy›c¶HFr?ÏŽöoÅôÒPX§R¹\9^rE¶õõ³Áwÿø¥¹;ÏxGgË»ûº|Õ‰Áîeý¸ßFð#‹¹B"üÚ¬°ÈH¥2)âæ¬‹{R_?¥“|þ©i¼Á ÿöÏüì‡ñÍÿiºšÊJsÏ‹W6ýGo(|†™hÇÐwn�ަ¯ ®�ÚÌÌüsݦƢÅÒΫ}m¾>QÓtýû>ÿó;œÎúÒgÞW4Ï*„ö×­¬ó„+çy•K�Pøx'T~4KOw|¾péÃR�ìéä ¥ƒø:M��ŠêS1©­»¯&×|~zQP#ðÄ T—(&6ƒP SKÿ:¿ÑÚÔáK¸ * 9ðž&ˆ™¦x“‰~ï�¿êé|öÇý[xQ(] §_7ž|¹T4œ(¡Š%èŰC ¹Ë¼¬÷,Ty|è¼kþ õjcÊK}fÖ!¢Óñ™qo�-72ÝÛ±ñ¦Èæ¿üÙæ›ÎV5¦õ´ÐËU8†`Ú§ËÔÖ´ï:t-˜ñÀ‹ æ‹ÕŽ[Õ¡§Ö�›>¡ÄDánvê$2}xcZËxbe¦˜ ßÏOØACÕòKð{¼1/}«›ý&¹äÍÊã¿]'{ÖoŸp7ÝŒ™·f9èz?´ºÿy’e'Ÿ½²á"Yõ²‹¤ýøoÈß¾ñNTPìçØäÇÈ$�gýÞÆ3¿yFJâA)¡ÚðîäS'–xh4“Jü1P}€B'ÕãOÆ|Ó„Ís–Iz´Ò|ÞC;²®‘¥ÍLÔµT&b½˜Ð÷â mŸ7FÑqû §cH�c¢fæKærÆÌ†Æ ï}êGyP×´½=y|î~ã •IY$ƒù½\»ƒ;nÉuªßÉá¼”×€ ‚ÈT”Ï×�;?<ç•ë.©[uÖ�µ‹–ø{±nD 72H­œnÆ@©@ÓˆxS7á‘÷4½[§nÛÈ«_?‘ÂîPÓl§¼úM¾Õ§\øÖ÷ݰî–/~t;’&ã<ºö«Ë¡üóþ¾òªV!–iW+×ɤÎV¬e溇h#˜Ö,ð:ëSÆí™Û7ì¦cž®¼ÈÓ¾â¢~îÖotmþó;¿öµ¯åýÙàšk® õ¯�–Õ\â”×¼JOót : J�Þ„t-w½ŽÔqÕñ¥™;xS£ÃÖ©›îÖãJ)}X�ÚïOÂþp\â P'd`БÌoô%¼Ê¼G:�R¯7mhf—;M >¨>´âIötþQ^xøÚضûNeÃ&®mu»œtÙ ù�±X$z9�w9x¦Ô°u™a§e2ã3ÙylÝ6N·&ïÜk%‹jRÃr‡”Á¤t94¦Us:¬‹ B•Úç‡`Z˜¿‡ „V;Ó~xÀïÍ §“x™�»ÂéÔòÓÌ/›óÒVgþÒ+�Æ…×B2nôŸÍïƒÕsÑÌþõG›:y3¸©C1º¯Îü–M`8W“+ ÎâÓÓ:çøõž ?ÿ‡Žé~yn*�Ž15akNþi]yÓ˜¦ }\—œýì9!¹ºèÌëñÑ[ � ïí«Fíþý½Óo·ÈM|,~ÉÚ¼€dÐs4uJÐ{ò¥®íªé³Ÿd º¸Öº×l“mm¯•�¿ýÅQK×Ì­“EëÞ$-+þ3§šçcu¤vÎÛå’�½\ÖÿòtÙýÌ cec< �ÀÑ DÊšÞ“€´V?Ï3Ðf‹r: M?5ÙG,L*1!µŠW:éÔ‡�L—.¢ÓW3'E®d2òàƒ?(¨õ¢Oâ®Ä‡a¹²ß÷ôanÁó}ãDÐUbÊH*<4Å%ÑFyŠà~§“ù㺵�k§æ¬ZÏ’=[öçº)ÖŸcº^J®]çöÂ)šdŽÍñàŸ#Çk@ŽÀæ¹Ú"{6˜½dÍò¹Ç�üÁ}+Ú®j¨ J5O^XmðAsÖëÃé ³*ÙÕ5#ŒmYýŒßÜ•õž­7ñ!~As7²%$Û{¶Õ†Lß÷½¾ßüµÛÞ~í×_û�ëÿù¨ÏùÈ uÑÚùoòÖ4ü'ì_×kã¦nÓ�TëºqeU¦cºkÛ7}…°Vç©©ƒé¿†µ¯az8©ÚL>�“˜üuo¯=ñ5/ÿÀÇ—žþùOÿÛ ¦�<üùçÿøö[zk[¿7¶ÐTâœÑ¨í›‰B?õ8é`àUˆl~š¦+øs·©xw”øë–÷b­Ÿ §¡Að@àˆó!MHæ5Íë{ ½Ðev»ÆÙ8#¤FŒ6«\=ªe½êâ——ž³5ùüýo‹?÷׿!ÚfG0GnÙ¹·¸PrTFµ:Vë2ÃgðÛÄŒ­ÆÛ´ÑÊdd5A Ì–“²ÚSE5ÄwíšÖ"Á³P{B5§ñs§…Ó^hQë"ˆAÈ�S‚i#œ†Â‰jMëç”ÎÒUs:‰%ŒpZµ§q’¨éΕsý»N™{©Ì^qlH/³ãI_´ªM½gr•W´™TE&Þ„µÝÑœÆjn½:ÙR#ò…*OtNþÇ}­³|õ® ·Ý>"õ˜Ü=6Ôº¨Þ¼óß'MËþ3_…i�MKÏýÔK§UÇÄ {åÔ·~VðFqâEfXÎí}"+#r𚮘]}ëùyëžãkq �,»à\YxÚaãº%oý«¡§üIc ©ªdÙ+oȉÝó±ú4V¼~Y°ö ›åÞï4Ozaѱêd< cθð-M‘¸·^•ÿ\ó:a„7óFó'cSJ�ˆbÒ«[wö©�Ùu?UÔl4sÏÁ_šŒü3»Ñ¯„¦IUŸ#‡ûá!¨îÁÜj âi- oVQL�ÇŽÞvyä¾�7ÛBÛŸµ�Ù»å‹øªå;v7§ÛšÙK) Î)áüT(_�ó†zž{&çmL¤�\ÎKy ˜È(þôå“ãõíßuÔ¦7£ãQïö]ûæö4ý×tÖt8ýeš)£L9WH­˜(3ßÒÒ0ï¡ S£¼ƈªAíM L|¨F¬jPCÑ ‚9 Ì §ñ›J3þ¤šqµ¨ïž1C]+lù÷x�Ù‘|òwçKǹ´ Ãɳ.j=÷!÷8¸íhxä¾åc·™=Ò¸Ìü6Mãl~›n·š§<¼à¸~ÙõˆÍ?Õ­šô0ÂihM—a!Ä0ì|üˆ„• –D*œ6ZÓø­ C*˜6*$)át"®Bé!átLµ3RΦÏXtEÇì•ÿkµ¥Óƒ ˜ßš©;5hýÙÚd4[»cHm3£õ7;üê�‘'»³ð´_ÏŽGÎÙýôËH9&ƒúi&;Ÿœú–ÏÈ)ïì5ö\Ík¼n°| Ìä^@­Â·øÀCÇ´pz°o“ì|lKVÎ |)ž•zrV‰'/¤F±Ç=÷¤ãäÂn�¥çÜUÂiËyþÉ·Jýâj»ënñµÅº7]+§_Ó]ÂiÛ9µ­vÊëîÁîL¿vÛsKY%©[ñ�$ìÑégª]áÀ�Ü×/$` oÂ4*œÚ"ÂM7yTØíjkh}>?•ƒ» ®QÖrfùdN£Wæ7xd~�H{¥H#þ«¡•RŽ'µ fÏúÀf½^XÔë¤Úz�tÅ"œ:°õ/Gv.G1•m§ç¨fV›OÁŠÜί{6d竼,@Ñ•Öråx ÈÙ<×[<ÏI_°E_œê×>=Ps4¶bКµj,k £´^µY¬L•Aƒz¸mø)¯÷1M7ÿ°ãÞ×tÏu6·Ý×X£YÝÐzë5×\7ìÙà­o½.üþÏÞzmlþÉݧÓ5àg¦¿´´F¶Ö‘áUÈlÒM“1%¨rÅUnÜ¿ÚwtØbÇ](Ní7»ñFÞkFƒˆT§Õîr`ÉÚ{`ÿ:çÏNmË[tt�óïì8S˜Óã֞ظÌ^)/ë4l÷íVÓ2ë´¿@'áÊ6[~Ê[¨P—ƒV%ìMW–yöC›:$>/,o$Ëñ’¢L1Ø�Žû0OÇù†¹¸óp´ë�DéQ‰DcðqhÙ« ‹$&’òðüýUKÎxûU¯{E�Ó¶ê»89ËÍñÇlÑááºÐU ’ýrÁœç#¦šÔvüvk³˜kOjgèÊ3Ôž&iÛÆ->û®¶¶åª@~L»œ_È F·±±R.ü·Ç¤iñG Ö‡é4\ßzÜtеì‚SN�Sß¹Gʪ×5o±gˆàß©ºÍ÷]9Õ¢G”3R‰#b‹'"Ò“Ë·ÂÃÇÒ nZÐ,ç¾ûv9áÕOI¨rÕðŒE°§ŸnŸpÉOR=ñˉ¯¾Z^qe�´,ûTôîÈ.„ªVc¡Ë/™À �ñ¬]{iy²¶ùC*œ6‚dN«@[÷éÑ �݇'ûå>HišÆ»y‡ÒRñ™käIÞùÐx}ÉGZg²^•⫠K]£_Ú›¼² Q†ÕX�CÕXkƪ˜Uë[LëÝbW`}D"„"p»6îÄÁÌO_j›_^#f¦G ˆ¨æL¯Š£”~þÑ÷%ÇÌHæ5`fÇ"{6P!¢ ©�f,4d=F<,”~ pcÒõÔìÃ� 71H9Uæéš‘Èød¥”LÔ˜÷rM|¥ÄBÂT+\BËþØÜͳ¿þ÷|ú{W×�rvUü”Õ¶-­EEÍÚ¶ißÌ4RgFÔê le„UÚžI¥ò¦5º5:a…`º5@-£ñ¦ûÛTÐã¯î¯Z‘ógƒ¤?¸thþ££Vçþu…Ò¶CÚS×)w=8¶œºÆ�R;&FG ¯/"  6 $5´§aV?Šó"‡®,“C@R��³Ñnèù¥Ýê¾Û~Ævá9¿—µ—ÿ’rà¶k³qæ¤ZÖðHwdÈŒÓüºoÝÈ´Ìx'T5×îOuÛ€‚*œ®ÆBˆÁ�„üexISŽé^”J`{:á‡0çÎ+ަ¾¼ð8Q¤Å`ÖÃL«p:á´.¨©Âi]oÆò+;�¶•ßB©°ž—®×ó8õ/užfö;s¬úËU.O„Ó‰Íe’wÓÝ"æJ€â#Êy½þäê×ý9õGp̺™9øy«Ⱥé䔪 ×®ÈY××¼öݲêåëñZ²X í»BiÌ”3â�®O˜ðN<Ö½ñ¾[ŸŸpÇr”±s`V²3^-ÝÞ*‰••K :(µu~i­÷H{�GÚ †«´ÔAK¥ W<(©,‚@0\H­Óç#'‹PU)çHÏþ_ç¥+euç ÅAWª�œ[íéd¼W¶üåoEƒÇ5Λ£îð�#°ù­¶Èž ôV«Ú¹ƒ�"F êU{T1Õ¢„™‡˜±E¬j^ê·?*þuF*4²^º—jTeœ+~ÊH!AÛR§9­Æ¯Ùšúª¸è]7þâ–ƒ gòÕ·ÝŒ4¿ÊQ3�Vaê¶ ѕ։ÚMãSÂ(ì˜úQÆh§+ÒtúànMU¶°ö.]2!l|ºlF ²þ=j~$#&ëA'Òwÿ0A³ÛÙô¸´{Ƹ–ºå®Û4¨Ô¸\NCC FƒÇo#Tc^Ô~¼œP;äíØ8ìOÇuœ(™ÕÙ¦ÇÚÆHÔÉ Îª´6µæ×³È=“ГÖ7Éš×½Oã³ì0€ü9KZ·™Þ#»�H�2óf†G-ªh5~2‘ ³¤"쇉� }®pZ œv☰Æ]á´jM{U8­úX% íúÌ¿Dp~ ÀGTÓö_¬pZ_гöê93ÄCC)gƒ#¨¿Þ±]*Í”Êg«Êü±¥…ެi¡Še­+/9¦¿ØÓßâÌr+^ú2YýÚçq5öYNÉ 2Í�©5¯}WÞV½Ï5tÕšÚ|›û‰•.røäí?”?|v¾<ú“y²çÙ�áûޱ¨J&"òد³+45ªu¹ô4êïzúÉi”ž\ÑEç~NÖýÝ¢‚ÔRqµmWB=À—ˆ›sÖJ¤§ì& œÀIg\6Ï©›}í�ùLG˜Ý‡.íªN-Ý+ó¸ˆÙ¬‰1³Z} Ò²êu“ g”�Û®KU‚Má\çÁjgo•ì�TËþD•ôúñNº"$Uµižå•öY™S+2BêY)mê2h§©�Ú�92‚æ�M·:�>¥Ö�‰ëÚuG^z¢fâZ[a …®d Ô/¹4§}ßù”jÞ©ì£8\RßšåÊñ�+²y­·Ÿ ôÌ‚ò£ôaÝ„þ•LJØ7ˆÒ ) ­Z]$?\¯atÕÛ•žøfßlÍíÚܶ­æ´£/“Ó§pJpœÒÌÖK½ ’�+¯¾6¯Çy6Èü‰!œ±«5¸‚h+˜VQW*œê«nLôEû–0[Ä¥ªÒ4×ä@ª¬ Û;7Ÿ›ÉM™5;§ÏÎ@ïzípŠŽÙ¦±ÛHÓç!fneFiGâr1ðЄ·¼u„îK=®˜yhššòøÒK�»ß‹7x|�cµçX‚G•W+'ÿ] UZ@m/ÖæX¡Ž´�ºíø/HU[öM-Ä"ìjV²ÙñÚ­­4ãP¹Ç ™qšO÷ÇóšÇÖ«Û´‹õîJ‡§Pðáp6§ËÐhN'0õJ §½ÐœöbþîjNã$E8­f="°ýÅ Ço]Ͻ¦û«áá?²tOGrÐ{=°å--³¯_o �ëÝpº2@�©Jmݚ׺Ìp:®mõgløXÜÎ$µGN½â?dñY¿�2Þ¿;ëãXü’Ó!œþJÖëÕ ãÑ=Òø>‰F¶å¤þÑ*ÕÏ ÷îÅôe„ÛõÔ‹òð�n�ß}ªV¿m‰ìzæ#â©‚ë ¿X%‡žïQrz»ú}I1»zd ëá¼tQ…½¥bó=/@rÐHËÊÏ¢V{¯ËA¬’f O|á¿36¥SBicšÕÌ õ|ú '6W7lr`zÓÆ»TLì‘€�ϳí¹™�ÿ˜þnŸÓÓ–ÎC•²ûp­ì¨•Îd• „Ê%mê&ا^Øè‘Eø–rnÍ�6µÚ¦6BjtY?%Qµzûà† "+žû]ïžGLŸòñ'Ê©vZ>†p ·”æ¥×ålüñèyâßÊYýSªX-cæÈñ�#°y®¶Èž ô„ÕEï"¸Ã BÀµ@ LF  ŽH0ˆhÔ�4îL*¤Ö»“jRë_ýg¦Æ)³›Ooñº|š ¥]A• #§î«3¥PƘÁ6³.Íb½ÉlöR…2ÒRU %¤ú¢]qm1£^mC=þiÖ™úñG…fúA®+HϨÜfLmÓù͘ÜqéXÝ7<´¬Öá´±+®jhQãm¹?˜”P *ïNŽì�I?~î‡@mP«àq2N³«`Z½éoª° ÷lrÏ9ù²¤’²·éÞ{[ö*›ZMvü£aSêìÖÝú;2Þœ#ò{úz¶•˜bjŸÓ){ÓÉxBjüÆU0íÁË hÓ{a›ÞI¤‡Ú%Çbˆ®æt6§­}r÷…�Õ˜ÇYi:ãþæSaÄŒä`ÎCCg6®ÃNäbà¦iùá~H`m´† Ú³ÕèáIØ+¯;§½}eý°ŒÇÐNqÆ>ñá‘sßõK©jzÕÄ‹yÎþƒ;²ÚÃÆ•-²ü¼{³V§Þ v=ñéØü79¼}mïö2Y¾øTiYý1©šõÒ¬µ›Y‘×–åçž-ÏÞ}wftFØ1 î|ìFÄÝhLNø›ë¤cÃìgÿáºØM|(˜�þ]Ÿù›¢7a¡}¥Ÿ€?Ø óÖ,—{füŒL%�c›ÀêW~è?œ`Ùq.;EÅ^æ¬Tg‡î¬5­ue©¹SMd@~�«j@ÈF:SElàÙ�½wdZ!ö“X Ù�c‰Ç‚æ®—€=¿x( 5�€T†ð°ï”YÐL † ÷9RÖ‡õûEº¡¹†Nã+Z÷ÁR·Ø·}5rRˆ1�Úæþ]ÛdŨ)Ù� 7á±i[Qßìn†×¸æµWcîƒBŽÜÓw]ˆšóú wŽF2Ájy ˜ ¨âÏV$ÏzSQac Þ,”dîaÉÁ˜„  .Çýª,“>H/nêþ* ¶_W¼¨whWô8ò&¥wn�Íj÷f>ìØ!*„¥C·w“w;·œ&hÌ𻿹ó»eРV«¹LŸÒmÀÍ«ó­g¨!ì¥:;›Š°=Ä®Ö�ŽÕ}õšn¶hSw<Þ†÷]û…å_¼þý9y6øæþuë[oú]7wÕ¦9ŒÅŽÎt�²cq÷Í_ýcò)^Ji©«.“W¨‰*òÄ‹_ȧ¡9�”p@M¼D`�<‚ƒÒÓŸ�.¨{1OQ{åF‹Z«�„3Ü�ß ©õ%¼¶žé½0ÿ˜\vö™²éoŸDÕãgÝóì-2kÞ;ÇÏ”»T÷˜�_¿e02—Æ[gùÙmfü@çãwÛý©op•Þt0~ð©…½¬£^&‡�A8=S#”NâÅV2¥5­×}Ùƒ¤:i¹ö×§}ËÓP_‡~�v|vëæÑRnŒ[§æгy2Ûq[B™TƒÃs»‘ö%Žm+ÙºöͲó©/õëØ Í õ)W@:ƒ„Ózþõn6{§áü°œüêdz¢Ñª*hÏß™<}‡Ú|´¿¡Qººs@žÝy·«æöÒ³'¾>&β›³ö¿ÑÆš Õºw/½ÕçÈ%Ô˜i‘»gÿt‡<û§zé“öBÀù^©ŸçšI)ò®³{£˜µà ¨GáÂ(HX}þUç; ó®3»ö© sAói"Ó71 à!ÉlÒùÜI£›Ç¤Ø¹%òétÔM׺íDÔÛ±áº_ .©ßÀF£âÁäÞÁJç‘.ýq<ÔÃ~_ŸNƱ*z¥ß�µk¥ÂÇ-:-¥$ì|ÂÞ#ž¡à$}·é 'õ¨#vßî&±äL‘¸®³û5Ôxà —ÏFrZƒl¼¬L+"5së¤uUî;ôâ×å…û/¢»]Q#�9sXa¶X¯Ó;Eôl '¬P†€º êX\B0íP€�B‹q>Ÿ$U‚™€‡�S›®Ž´Þà‡îÝFÔdnâ©;¹+!5d{7¹Ý[¼+äMÝÑÝ® KïòH�Tˆ”ʪS†aÎÆkÞáζ”šsØŠm¦”ܔǛœY‹RFšf2ZÊ&àV¤åtúâ ×_€`NÔÚ„Þû OMË´Ú¦ýcùˆLO¡4ÍfÒ~é¾þUp0§bæPë?WÀ§ÇQ�'4§U@ íé`ó¼˜ðKD±^XÄÍ9ÑíúLF —t›7uOî�áåöÈtÏ"·Ÿn_žÆ·�M[:¹šÇÉýü}ëeåEãdÈ}’9fÍØ±fD�´åu;¬¬~­¾ùÞ׉š]�¶›K­XÊ^4¤¶¦=L{ =­Ыp:žPÓ°7�“@Óƒ¸pÄ2LzØópxWÌ!Ýo;»Õ¼Î<©Ì¾¨þAy¡™\7$œvÓm¼K'3óðtS%2§sèïBwl¬¹oÇÔC@K(´ø´5Ò¼üúœö¸¯óϲë雤{ÏÓ2Ðß ÓøÆÄhIø°P^í4VJyu�Ô5­•úùo’ʆ‹§ÕµOd„©Óªe¨ð¯¾ßÇ´ EL1¤Âé'½jÒ±-÷Ü/;æÉi—oÃpv?WWŸ$íKÛdçæŽ)Ž*{Årú �½n¦jJÈÎõÏÁ¿[œüeYqñ9y��õn³Âaª[Tc+7f{†5Ä(='�ôÒÖļ5e6i3r’™ž&b’èNS3Åô„Ñ ¤w‘kØt3Úÿì“w}çoÅBÊIôBÑZGN@¼I§&ï~�ýШ`B”þ²�TêCö=Ãø|:àK ©ñˆ�GE£É¦nFP­ƒ‡ƒ�ÌâP«T"v0ëó w¨Ãÿ–UÍÁ½ ”ÓÞü($¹QʉEvȽß|wQrp¬NVz§*lÅãx Èα(ø³�ÞbT@݃³ë 4dASv /!åN†ËqŸ a±Ä0t§X(mÚ·Pc=È;õtÔ;•ÖQ5nðz�×½aÎD£ !¦­`Õ-ê–×»»+vK«XKkWajºhºr;p箜ÉÎ#Ð òÙ½tĘXá4´ M×ýcÃfC555­qÇè–ÔH“¤‹¬åôÙÀÓ½ûµi-ÕI—µÛÕw�2DÈöK#5É�ÌÌg¬ˆØ—Ä•k·Ï‰î8Ñ]!én‘DÏòÁÈ`}woRº …éÕ—ç¨7³j­~*Në°oò4ìçTWƒåKâ��ódEèjz“�·/G+áQûê×Èò î5m:‘±�dÓ]¯ÒñM„Ypœ¶ìÑ…Ep'}‘Áî|¬{‚Õ�S»MjÀ<5 å ý½Áî¼W…Ó1ô=Žù'CTá4Ó*œvMzà|€pZ'¦ª5mÎ;­*0}>ÊÀm²-k÷ ±ÔŽ»J±½5Má�ec÷mŒýýíg– 단táªÕHÑÓÑžžCgx(7“µ|AkÆúóË.ÌÍà cw<úVyâñŸÁ.‚ ¤GsqQÛ]¢^vË‹F«æ{cõ¡¥³¥nÉÒ²âc®:q´ÂcÆíÞô©1Ó&›0ÿ¬SÕŽÍd‹�šó½MZ8m+:¸¥[ùÁqrÊ•»p…Ñ[ö\ËIo‚€ú¦ìU8Åš¼% A=Úж=²IzúŽ“Ó/ß5Zr^âtÑÊî}¿”®ŽÛ%6Ð-e5 $\³Bj[/Ï‹Ða²ƒŒô¬—ƒ;n•¾ý�a"Ø,Áš%RÝp~kgM¶ªiå¯È‘ùœiuŠ…I ðŽ?þ¬ºÄê—?…‡Ls¿ÉxìCç0¹´“M;ÏÔajfh´«Ý'LÌ33 f®vò¨)6lªÜúènåø[nÝÇ>=ª}Á´' mjØñ‹Å|Ò Kl0 Ц®  EÝ/åeRí�a�iØü„&uêØõ « ©u¬ÀËE亚¶rÀD†SV½h"Ù˜§Xà Âó_õ; †ä¤Gúb䡟®BÝú¬~l9׎BñŒ™×€ì‹>è½U¿Ôé‹&"‡÷ïûåoÇíå�@·ß³rAe…oE8T}y$ì«�G W©÷5˜ìv¶.kŸÝyÝukܵFt^Õ‡¯9iv÷þ—8Ë>sÂs´ÚtÛ#òOfWëÐéÍÐ1*í¯_½.¾ÿÏŠ™fH[c;/Ôc§N2ŲñÄ£ûbÛzb¢Å‹a~—ÔÅõ¨˜—OКNB8 …p:ããýКÀÛ¬ÓQ¼Ÿ²Âiû{Ò±šã ºµ,F2ïÄ#N_÷ÝÒÓy·ôu®OzUÞpÕb©¨YãT7½^kv¾�¨LÏù¡sh¨fó[@Y“6¢3Cùíù7$Înk;¥®£ã¡ÎÍÌøÝRP{dÕ€�",KŸe×ðnyä——I׋‡¦XsÒhôîÜüSyò·?5«À.Z÷Z™½ò“ÒdÞÿÀ÷¦ØîÈbYvæFFNi°w£lþÓŸ§TÖÚ»�»ž|/jÌîç �‹Þ�& / N¤%vÄ¥³=ð ^°<ö6™»æ[yítϾÛäñÛ¯ç·önYtòJ™sêg`ÆçÒ¼ömdcÉD?ÌɼT¶þõA$©ªÆ‘®na�Ì?á sŽçJ[+³UµÃÞÚZ.»v©¹X: X¹òÜJç¤KŸv¼>˜•r'ˆæ¯Î*SNCéIf::0¹Ò“F#¬Ö4Äà¿É•ÊšŠg û�§ïûáúTõűIB¿«›ëgÏó5¾jQãÒ!ušÔ15÷Mê˜Ú¨{%Æ6ˆõÒ¡M†¦J�7ŽÅŒ\sª1&*¤Æc£šûÀ¾3Ö›û‚ ¾ÿðãyP{ƒÙ7UV`Ç@£KÏ=K–œý{|'^™“Ñê‹õG´BnU­±"uÆgnú6ô �›ú'[+¯“%vôüx60·V<xñl°ÏáÑË¥{ú ‚ðøÝÿÞ#+cÒüÇï½Tgè´\_Æâ…Ç1m™»5nôgnÞ)‘Ùw¥Ò&Åýãæ2aíDÊÛ ›ª{Z3¶(¯s|<Û/»·½t÷æÚúÓ7Œúlðá¶&ZÕ~…·®åË(ÃGºô|$#I[³#æ5n†Œ`º„æ1`�'|õÕוík×åìÙÀÙ¹å-žùÇ?kàÑ™Ô?l\ØOc·eº}ê;×_6!óKŠ\äq(S=~3ýõðÚW½Íi]óõ4€il—TP­.}œš])›þü76çm7rÞPQ7‘¬w¡Z™W“XQ…Ó˜¿FÕ”‡ ¦ãLêp QšÓ뉇ÓEÿêqª&$ãý²íÑ×øú½gË–-˜éŽîÖÊÚÀÞã½Ô3oõWðÇ‚¡:Ývl)Ûæ‘-ãFgÌy•îÔP-g\ºÏ°ƒ¾õsêìj²Ú#“�íÚË?”mŃ/Þ,þÒyãÌ&?ºžŽNYÿ«¯Éï?=[ùñ|é|alí�m_Ìš°iéyçK°<;Ú>›ï;žù+š<-ñØÏoÆ“qvo˜þÐló`j=Ê^©Ò2ñq丟¸íûGFæ0fÛƒo”»¿úê£üÖÙúÈFä{%´÷¯ÌaoƯº÷Àòø7!œ¾G�€š =ß%�ÿòåžo´H´ÿ¹ñ+ÍRª·©-K5±(yk×®-—“^¾ÁñZtÊèþso^zK{Ì”“Xw›º‰×Œñ¶�æÔôT7Zµ© ³õÜýo(6x:±‡Èº0<“ƒXñr5'†í`\âø|z°Ç/==!9Ô[!�ƒ•Ò%X˜&’pe@êk¼ÒPí‘Y"5!‘2ÈB˜9úP[Q�w ;‹ëvŒ32Ÿ¿jœT&ž@@–¾äl9÷=wʲóþ–Cát¿<úë²wë¾Â¹@=(: j^rr&àÙ �ÚU IDATgƒ®q”Ä í|æ×müòÛç¾Ò×3x¥6‹Õ„•k¿Â)|8¥ZÒi�®R!×§C*15>“ž¦ºÎÜïñž'©7}»ðš1!é¿#²áï�ÿ÷ÓWß7–pZk¹ñÆ�t}áÚÿó¿‘§jIÆbϹæGt>14§p[sÛ5s �g¤ÒÓæJ̾ÎM�f}:�æwãuŒášºœ>|ÿÿ}x“ öþÎíwêoйá‰>˜>jŸR^#2À÷¾xø3Ãê˜øN2òèmßpøÉìlÊLŸÑÝê$Çì×Ì~3‚ù’™i“t €oýð‹}ã{½h<.P“îƒ4Zí�÷AÿbÉѾÄS¹þ6íùo7ºoà˜4‘¡k×wœõÿ3kÛ·Þ9žpZ«xT�í|ò'¿Ûñ›?-Mvï½Õ­vèp …ÆhV/5™}Ñ{íIo5Îõ•¬iX›YäX çëÇ–]ž N9AZW|6»•¢¶žÎ?Êß¿™Û•Uw?ó‚Ü÷­÷ÈCÿS)O¾O‹CŸªàöþ»?š¥qyeÑÙ8nß“-Ͱ˜ìnª7£±ÑÌ;ñ%c'æ)¥”5¨]D1Q�æ\»Dì°„ÕÉdÏtðT'"ød²Ï#}=A9Ø])�ýÕòÿ³÷%rÕÙ¯{νWÒ®V–Öº,ë°lɲ|bc ¶± csW$’(!!!ÜW þ1˜#!`޶ñ‰ñ}È–¬cu¯V»Úûž³ûÿ^UWOÏîì9]³3»S»=]ç«W¯ëxõúõ«þt5%é Q=„Ô�u5@µVa„ÂR=¥(Z)�HŽt3¤G· ÈÏ»J bÛ +¶®§�/}½ðÝß§kÿ)A^r?Õh4ÚMý`9µ?}xÞQt& b©Y1¹ò ëiõÞà??¶î{VÇÀ|°‹´X¿Y ¦qÈžTË0§Há�³~‹Þ+%A2…ªŽP�8YupáÇwy!¤fau_û‡¿ö××^=-å¯ýÝu½Ÿa'bO8ªU™çÎXÊŽd¯ˆá(!ˆ‘"^ ç<."‹ámrDûÞ tòÐ;QAF¦¹É>¯bÁ;Éw989x)‹�oµ»:ÞuÛmoÅQ˜y¸Î]íôÌÿ¬Ï’§äŽ‹ ;wæ¢lþ"¶ne§Äñ>ÙGÇíáv”š3 ˜¶ÒŽp&=†aoz׈О–&ç¤æ4:œ0̓:Ïû ÙïuN÷${÷½ºûs7>|x†}ðÞÔñ»?ûzûä¡“ßg0D UÕ+ëCÈS¹ªWÝ38��QRj³rÑÙ™| Ç]˜të/ÿ¹ïXóÉ£÷~åå€[˜1̇ vüäKôäO¾Fg¾ü•tê¶›éЃ¯#šé ™€g\uí´Ì‰LP<+z¤ïa¢‰?yÈÊ;�Àñ·û~°å¢¯DÕòÛ¯éà #�Q¢6¨½´è=úS˜Ò¸Îå»ß]—›{™�;ô§G©aõ'hÙFÿ_rä‡5§ŸÄ8��KÑc·_I/|[¸5}/ÑÚÙ¡W.U¦Àü¡Àú­/Y‘ÞúŠÝ0ûUË a†'Ìø¸µ‚™ô¦3_˜�E…ãTš‡w”^OÄhÿƒÏÿúKE{P©Ä”7¶¼äö±My±É‡(’Áì Ûî Ј]AØ©6¢ª ˜¬ŒS�™i¡¦¢L~„y{YD.9ÒSlÁú‚Ô³Ð*9ãªëð6deÎf›Áu°çº˜áEÄaÛ¡è ŠTŸ™3¿ÎȾãߥny;ª˜øK*�õìbûj°<èëE¾7øÆŽ³}ßgv}‚jƒŸæNˆr…ÕEK+ç,Y¼¶‹5_ü¨DGè+ÅMÙLAFà*`q±øðïnþä›fµ7رcGê=ïù·+#gœ‹—ªVTÉj(D¤�\ÆJ‘4×ʱžK¯+‹ã2œS]N2Ú¹CÚ÷ßþÚß´½é“ßÿ”YÛð÷,•–šëÀ¹ ‚+1—ˆª6éôñu•û¾ËmÈÛµî;NÕ\K§¿èwyÃÊ€éKÕõUS|ñ›£ä,£ÒÉNœ¿´ày ÖšN:6§ã00ƒ4šíM'q¥Ð¯ø¥Œê^b¬pXŒ¦»xjY€Ç‡ëŽízçáçùÖìÝñ?~ý“+^þO×Úá*‡Q#PÕ.k”¿9·2õGE¸ØŠÌ²§Ù¡HƒÊ³�î¥' ^sÁ-‡�xôÍxðü-A¡]ŠžûõÏp±ÐÝíŸy#Ñ|Ö?ç Cè:r›òúr?þh m{vÇ> íªùåÂ;Á Í1yV?б3O“ï;ö-jyøÉÉ3M‘úØ?CW~ôMøþüŒ)ræŸüìq BŽ?Q<ôЫhíÅ¿ÌÊäEƒaíLèä”S˘[ l¸à•[Ì /~ª;‚§™h!•ñÞT‡ Ìð‚™†¨8o.аJ¢TâÄÈC¿»±^ sì“oÅ€ï±< ѴظÊ-0o! 6( Y³Í§ËÀާ�+NAˆª¹6œ°K]4)TíiÚÖÈËö=ÍÊÌþsŽ›)«OŽö3Xžoý&tss¾øû_¿Áú ÏÆ.ùðo¢çîp>ëõziã·\ÅäÊs€¾§Q{ƒÆÑÛ?ÓUñço¢Pà ^ïxYf}hþÅ¢…0 m•sâYº7öWæc�«Jå²2Ç$º÷æµ7¸ùæ�÷~ø¾õ*{éj±7`425p=\±#”æ ½Î³ÕÂ9¬ÓJ('Úê`jŒ‚¬U?ø—þñÍŸúév£¢æeʤ ¿"ð�Ë‹=üÜ6LG_±ã–þÍ!{þp'­|ï ? ,àƒâïmäónCÀlñ%L~àTt>cÃä[³Åç”8ˆ¶ý#A‰Òàh §*)�óX!ª­5iI�Aõ5îN € š¤ªT*ÿ¹zðn’(›øp‰á“§áœ¢³ßžÕ²¾ãߧǾQ_šÂiq¼iVs| ›‰�òàÛ£¨öÐL¶ŒžØm¶Em³æ4.Ç5·G™ý�qœÆ ¼X EsyE“—#ì±XBy—,cĆ~öíÿø›¼×›:³õ×0�ó •E•rÑfŒÅ%~žW7†‘qóÊòŽ Ëjo`G�u½*�ý�b9˜ñ�Ø+º³tºËèý¬u¼å’Ô“;+xË»ý>7¦}¾^ÑÀ÷{´r±ï0'˜NõN”´Pâ»ñ}ÁÔ#0é1 ñ kNóaˆIŒS×ÔˆÁ/C„°w$‰_y—”b?;ÇoDì{?éDqR^®½ý�Nc°ógn4Vî`§ê–~Äñ8V"]¯Ìž3\Àqv0¼LùÒ½´4¨6,§ªÅ/öýzäFÀôö#ß«((Àu§�ík}ñ^ÿß÷ÜO•õúŠgÆêÚÛæ+Ì…¬mßé2Ço¥†¨õé_Hºï®ûhà }5!�»¿8aÚÌ,:Ùò¯´lçfVlš¹ÑÂ1MÓD©œ­L�PÀÜtÝǾnׯ¸I²¥¨«¸ØÇÁ+µ�® r�Ï,óì“[(ö ä0”�s Л߶,cÏg<÷È/ggªh\ º"+.‰‚�·l=·~XZøUõ‰MÇZТNbƒ?j‡%y Im‡ñÑpd”*«´v©‹ÊÙ±XaðÁ)“eç' Z¾å ~ô V"vˆž¿ëZ:úØ.ß`–é£@yÐGÛÙÄÛ¬ûB�,Ú�kñBìÀ°=dÉ` ä΂;/{òǹ#,VA^*—€•_øeÈ<éËÞ€êüô�þ•j>Åìó¢^Q?WȈ±“Ü #ÌÂiŽ•¸‹ŒœìÉ*9m lopË-ïæ/Я¾ñÆõfóÚ×àk¬JÄ�‰Vb´Ójmýþ÷?7Œ37ÝG¾Žæ¨98ß–%©ð¯z_¾€&,¿¯õ± Ófšpè©[µ ¨Ãá‚1¡3mv9™:(°eË–ªÄ¦×ÝcE«ÏS Ï*bó†;8Cµ™TÓ�wÒa¿ ‹Í #(„Ó2–5¥ä6ÐGsÇq°�ûï=빇n? b‹ù.Zår»‚õÍÞ˜s›ÓEF¹õ…Ü?  6m)¤ætÞTBO=ˆƒ««,7C# àÒ©�Ô²pª8uûZ|ÂZ\kX|h~ô]´ï¾ñ ÄZ8d-µ•ôoetf-Ï:©[{ƒ[n97ù¾ÿxþëTxŸ8_AH�x‘“—R *!,Ö>I2áÅH—ƒÝá à—¸,–¥9¯A‘�¸o{c¨íVªkøTf–‘üG®IG §K™î´�ž¶p>áL³àóêm·íèCÝ·JæäׯÞðk´dÍ_ù^{8zŠï0'h%˜Ž¾8î ,8õt_àêÒEÝÂÑ^ið¯¬%ÍÂiÖœfv–»<Çñ]�Zá?²¥2-ëúF‡wvuý1ï/ \xð´µüö™›_<‚ƒZ*ÕÎAl+€!c#0Â�JSa/ ŽcœÞ*Àáz¾-4Ç}¶4ŸÔ½xÕM¾#xÊ×}GpÆñím3àâŸëiõ˜i¸÷°ï0Õµ¾Ãœ Àù`âƒçÆTRØRšIÓ§•w°ý�ÓÊ7ÝL{0ݬ3ÎÇÚÞ~ Úõü ?O˜Îj�YPgÑ£˜×Øxþõë[ÞÚôN+–Îáì˜euOŽG²`öœ»Hãt÷ÏSžß/‚)ä4épg/ßDR`Ã|þž-»¸}·*Yôw‰¼ƒ¦Ó ñ.~±ùvâ Ž¶q`"±É˜ú°qrº•LR*ŽÏ*GqpâH˜†F+hæ>’0÷aVã`Åbrf°0óTY@íëc¯¨]í+¼|€�ôÜK»uýþ³› œ~ ÄÈÏd¹l)Pžt»döæH{ƒ /L}ÑLsi/ð,Æ�@ü&—0õ!"Æ�O-�‚ PiÖÐW¿úß¾¢ùÒ§?|€�-‰ƒªw%ˆB ÇwŽÚ ^¤Ë°j‡h‹dbd™b{ñçižVï‰ÝßÓ?PÀó~|P‹nbð�GC©9¶;͇!ò)ʬ‡àßy|pcÄÏøV��Va1ö»ÿo|‰¼c,³¿ýû.½yjHH ¡4Ï3üçÌ7⎰wìºãW¡Âà²o2n!ü–Ž€zÕ‹ß©å�t¶ü§¸s´qsÞà@¿ÉWçÿÆ/�öC Öùs&å÷Ò3)QœyÃþ˜áÛº‘ž}c£ò wÞŸWùÉ ÷Ü3Yò¬Ò†º~;«rS2ÍÈTYÊée Ì l¾âíalzñ^ ˜ÎËHÁª:›6Å‚ªM‡U:î97|R3Chb ;ça`²”ÒÐpàXV,½ëwëžýÓíÏ– --põö‚Yx !5Ç0m�Ͻ ¨f5lR[l—:AuÜ¢„Ô±¡„ÔU4”¬ ¤YÉ ‹Ç £Am§}Õ¼)Î&U‹×ÏQÍÙÕÆ‡÷Ò�Ç>LúôñÙ5–~’µ¢jDyÐû8Jdo`ÅÃûIœ— S°Gmà+ !¨ÂiI"TetYpIJ"yw‰èH†x•ë(òÄGîqÓýò$F~ËU)!µª‹íêJ¡ÛØ•<ŒÀñ2�lƒ·JÈÅíAž…¹78ô¨ßçfùõ¤§'™}bú%ÆåäòNÏ÷qJ "¾4©„Ô<Ы¥½i /Æóð//9.äøà8+'Ó0ŽFºWq~Þ�Áö»yÜeÆ ¬à‹9Eˆ¦åüâRs^�‰‹s'nˆ',½ í³wI8“–múw-˜öº[ ܹZ]Õ¤¡jÿÔö¨ÿö"�ÈÜjP˧5�¿À “±cZjìï;á+ÜÁã½¾Âóêbí)]ï‰ßRÍÒëüZ†V¦À‚ @`Ó«þö«þ”·A’ê4XÝ9(ý,XVŒž›ÍI•Ì)çä?éܼ"(ËŠTÖ¶‚—ÓÌtº/ðÔŸîî"·9í4,ë¦hÃL¯ÜÊŠ_-Ó$ØÏ‚jÖ΂�šscågRˆ”DPlô“fˆbTAfºÈÎ …üçS²èè, /×sÕ³Pâ*ë·ES#U謫ž¢³€ YÙuðêy1…é[EAˆF¢<è}x%²7hŒü¨·Ë|'Ö/ k]±šáÎ~^ÐxD �ÅX²Ä/m9+GòÂ'œä8$rÇF}ßàÐÅßѱ7�õ0Š g‰…@ÉÁG ÈÉŽS^p‹bNfÓ,DÕŸî J%º(nð ^ÁÁ˜V¼?óÌsW¯ž{îÔÒ�íî&ª`i´ãØÇü¸PËx•*îL0vN䘠Hà8c¸{góÛY½�O›«U­:O+ʉºÕœƒ€Jâ±.ò1ï�̬ì„ÿêÄ(¦³9tóÃÄŽÈõW�¬IO‹ßZó�ô=¬ÀûzéóWÛ›‘ë;ñ¨¯8ºÀ¼K Yö”)0/(°víöº�oøôÓÄÂi×y–$�—“%;Ç‘ÒÇÞ8<.P%d JÆ÷ÄðnóÉ_œú\ §mÓFØÀA–®"V‹±¸$°Ô¦©.è8¯´›­ä¨ÿ{ƒÑ‘G¡j)êZ•ª~Ü¥Vwæ.ÅVü+/ܤC^±â.¤]N܈…êOþ²”›¶ÒC4À{yµ¡ùÁrXõƒ©îL‹Rì üYœ¸Ð¹³M|€ku8>çÆMc€Ã¹.‘Ž„D¼[�ÓÄP+×!茊*ŒìüÉxùì8ŽÃâ×ë\Na™â‚ž…òÃ4*~×´æ\-HZéÀ-µCM''EE�¿Füù»_.‘ôŸîÉ‘N¨.8˜‰Q]Z‚þ÷¥�Ž_ky>©„ÿBˆ¾ã‡µàZZ¦À<¥À½r[äâ¿h7"•g2Ë)ù=‡¨bC=@3®òòˆ¦�8ONÇË0¤cŸL£0û­¡®_,oûÝÖ]»îõ>pêÔzã¹h7Ú#îª}Š>ê®ÄÕ|Qâi\i!¤†¹Ì}¤a“: P|¸B+ê3¾Ü’ÝcÆgXÀJêûrg†¨Ì‹ì‰‘EÝzDË7}–λá$]ñ×�Óú+®¾¥±wbÂÚFéàšoG(ÏùRpòò%´7’õk#;ÔRÛ†R,¤Ÿe– ×Ò·B! e„Óì7aQÌqRfdûÎ Œ&; !¸#¤–~Ôàzåa³ÄMàÈB,ÆW]ª=RHí臓%æœ Ï ¶ß[Ê�¥ÃêÕ ¿^{±àš'ö‰.•îv‘%†âL%WŠåŒÿ˜9W~Õû™×—Jsî †*M‡c²ølmýÓ(oa„\º³_�YåGª@sNñç”a“jØ \ÖìJ÷ùâw‹V¾J ’£ý�h�;—@ƒ;VohbnƒUa_ñd`ñáòÆÑ¢Ú)]66½ËŠ˜â™÷ë±—m%üÖö&ê?ê;c+ˆÈB¨…ëx +Öõ›_üûÿRf�<ë3®z÷Mö²M7‹æ:33š2¬¦uÏD+æŽcD*~øÎ[7î(ÒÏ÷‰»�ø¸ëЧüúËŸÄ#À0¼Rt’fªåÜ‚Œ?ãóÄ#’yIGîÂò->oH€õ²²FÌâêÛÉdaæÁøàA”ò�?é{–êWøK7”ŠÚí´á…wÒÚóŽSËýF-Ôó—îvø_—Ëlñ+ϳ¥ÜôÊ•ÐÞ I´¤q“�†€¦>àA-(*[xÙ ¯�VÉ¥] ‹˜G°…ÒqF(Äk¤t¾$Bù´íûÞ Ý³xÈ^#kQÂe^¦•àJa ¾êâpS‚€âgxÝΤiÚ¿+„Šù>б³˜Ñ›7ÛJqßSL û½Ž™/õœÇÞ9¯÷Rå,.Å»ž·Jcé2¶MŠ6L,å�Ç´¨EÝñÑç�Šêí∉¡xÞÍ �nDª=�šq¿.^5‰ À:«ÜØÎßpi¨ë–½NË#é{L ܹZQ½VCõ<¶ÔØö| â¿€zdH—`uzmNyfÍé•(Î\) j>qK‡ÑcŽ$�Õ€®ÿ_ H$çß1}r¯9+­½èKTQ ¾a,Þ5l¤ï!ºû‹O¿aåœÌ ×}ì›Výòw䤈£ÁŒœX”œ•I-PN²[TÄ{ ]HÖ]ýr6ɺå™i<ôðUïÿÑï] %êÁ†ÖY”¸u¼Œ³S-•áÌâîÄ»YY—Zæá(ñy% ±! #&(S;йÿI×f>6÷��G{ì´|óçJªE¡è ÚôÒ?Ñêó¡ýw¿¦/þ®1]ÿQk#Áÿf±<ÌŒ^3Í]B{ƒªª�)£š¬t€ì$ë¢b5“’i¶¦áp¼„© ^‚ÄŠ‡¾‹KDÈl6ÒÓ©¸ï{ƒ[nywêƒÿy�¨ŸÑQ¼�ÀÆÁ…ùÆT åøE>ö‹0B"Âj+š¶ ³&2^Åæõ˜q(P;”ÎzãÎR=LÕ7�Ç-û,Ò9̧{ó#èÆ³¿·ÉÛ^åWwÑ&o&o#Å(sòoMÍHªC×wâ‰á穲f»·zñ¼!3û½gãnxÜ:¸òK3~!%¥Øn/Øyï/Þͽ"}ýêz|çR©‚¾ÞG{žó^1 W¯Ó€ÆDÃ~öUAÿOî úÎ8̾�%\ÒÒ`c3�Ôc<¡É¬K‚tô%˜vMöP ´¸„{ÇÜ¢~ÎkÞG+¶|mn‘˜fí•õ/@NÞ%§YbÁgkn¾¨¢òâ—ÝC‘š ˜9“Ìœ‡,Ì¿‰ #œv’Tœ'§“Ë“a0fäE¤Ë Ú©ø‰Ðî»ÏÝûÔ�mca•bXh‚»ˆ{™\¹¤«I… £Ì>•}3áç8öñ'Òâ3éDq)PÃþˆÚ¿¹-ÖâI–öÆW MòzòP}æ&Z¹õù€™“²õЖפÆ�E�ÿø‹s‚C¹Ò Ês@†:|%´7¨¬îéŒÙ�`¹+ðr¢uX"„ÔrEã5޵ªÕJ'WA‡%È¢žHÁ›þ𦖽A*™ÂÞ �½7@�ŠGa„¦øá»¸Ø�K�¼#ÑiŠ+±æÂ Í]s«°–'½ÓI#Ž“%_ꙫ0ƒW�Ù{ç|J8­"Žc§òÉP‰ü2ÒÜ…¼jÌôUt†‹u2ˆUXƵ´4ƒ´z>¾Æ^\tÝj¥‡eÔÞñ¬šÀ© Žã<‚çJH­2/ {ñ ¨›NÕw€ÊPÿ�y÷¬Ói‹'›3òw76¢þÓ¾E�–îtå£WçƒKÅ}ÿ„ Ì¡žg32 Ç¬‹‘ò·¿«~ÚM•‹.QAîΫY€1”ÕQZ~ÖWŠÁñ¨­¼àt:úÈîñ 嘱ذíÊåtÆKŸ±¡%w̪^¦Žã²&Z‡»qY ÓÇéŽS^9S#¤"�Ž“½ï0žþŸ?ÛÛÒWùKýŽ µ4¹ÉL®pªÁ2,aÕÊLöqNÿrK/sâ}‹Rûα„?Ëßt’ù_\6•Æ€LöêyÙ:¦š|ægߤƒ�ü„–oØJU‹6A)%ó…�mD(mÀÕD¡È)Œ¬ PÅjäÑÀCÎ’ê§lþ½è}/¤û¾þ:@(®’ é 4ç€I{ÂB�JhoPS} 7n¯¢T*Á-LRÙ0õ�‘iañgÅÅEˆ5ޅׂ)ÀŠ(#<�_åä5Ñ °­Ç´U21ºÛWˆ½�ójÊ“¨QJµ$>b‚ò.ÆðM IDAT_È®8J|ÝÄ‚wÇÏ™E¹´—Ãñ4i!x;;‹ŒA™ÑñAvZñ!\’ý|±ÐÙ{G0ë!{Ë ;Ì Ç}™û8;nߨvIÓ7"Yü(péwJ¸]_¦”?>;>|TŒ=€u+dr½T•�çæ˜©ËM®ä£‹_@]»ê*mT¶‡Kú [NºÄž%j|YδÙF64D©«Ë_¦;T³l¶èä,7Ò{?â³ÇwÎŒåÈ))`[þ>ë)+Ì'C§»Îù 4YÙøð>ßÔøê~²*çMÚæõW‚ë.­¶.ÅúUPOÙ×_òÚKhí î3%gCîRLè‚«ËLíÂçŧ¬Êϵ8 Üd樖ó"�sËd8±ë-¿ÿÖ­™ˆùá}0^Ôv>‡É_ bÉ4I� ñ¤�c™Â¿’jìc½žRô¼säšfå"Õ¾}•%Û;±ž� RÊÑùP`ðx7í=þ€àkj×ÔTEͧRí²³©vù•T¿üÍsjò©véõtõßî§G~¼•zöOÝ€åXHgTø8LútêPB{ƒeæ�¡td%ÓaJÚQ¬Z&V-©à+°²0—�šë!ƒ!`«xæA8 Îê(Êèø±‰}v�ÔŒ…ÀÕHá”WHíÕeÜ÷rð•øqâ6ñ!�ÎÐñ¨ ÓN¥ø¹z�zÎÜ™ S}2×�ã¼ñcayá»_�Æ“yWî÷®s™¶²/“AùTº[N—'keТ^TÊõ*s6.*–ó*£›7/NF‘C ®JêBº8á¿€zÉ©7j#]"]ÒoØrÒe´oÎø|"+–-%òùs™JhÉøéNî/�Ïþýl³.XvºtÔ]]¥5†“CG|l¦á›æ ï¸ù 0Z³ÖOp�­?« õ”p%믺é/�¦�_UMP¬˜º3³Æ~æÓÜ8áwÆÄ#˜•�ÃÂ)80+•C Ô5³¼|~ùÓtð��ãz=Ѻ·Ð¹ç¼—ØôF¡]¸ò4zñûE÷|õT=Ñ”T8¬ød·…âÊs€Þ']B{ƒƒ{­úu�”ކÈH›NבeA“Ú B—ÔØ®Ù¬Fí¡ìÇ‚‰Tö!5ßå:(I›4�'c„Uµ•€\Ô& (ðr—eà wöŠ‹£çYÂKfo´��ÞÐTùô¡¥MûâMkO¦*W&Ñ:Ë ×‘ZD¡ðbÜS(´„á\�0 >ùùdÅ|ˆºìNÿ¦¬$�Ó9�=+MÅq?˜_NŽ>þUm”wBkU£Å^7EÅ3Aé£ÅáWB¼BÝ\}¶ÒG¦JÆ1 W7IÆòïBwE>y5óSú\²ØvX>4upÄÿÃ�j¶³?ø€]DuýÅ™@ž¾T¢‹Úöuå ¥\\QÀ.)µ»)ô‹ún'ý×ø6ˆu¸ê´¢~¶¹� U”Ô9èrÙe—Û^ôsØ›}…`3,¥ä.Å7µÌQra¹Adßdƒ]¦©2œ›Ø<ŽÂM2|"Ý2?yÝþÿë™gþþbc “)ºI"ZÈxI5E'I.I0%ÖâN1Hh–ñŽÙ’‚ꢡ^(X«—ÁÎßh¯£\�€ùÇ[¾H‹×ÝJ›_ò5ª_qƒ@§¢ºá*ºàÆÏÐ#·}lú…4å4ÙÌÏqå9@ïƒ.¡½ÁîÝ·Û/Xv)ÕÕ†(†™�Ê%Ò«#dâÐÄ€�úBè%îXã˜I`gÈuM¼Ùå°³DºÉ§ÁÁÄHŒÔ¼Ú*Qœn vˆS�,°ä¹Lã.Wh•&Òüì"ýºò›ßüf(½2º©¶²ûLí?¯¯‡^ò·íÁ-{ŽYt¸àÛ˜$Ô¤Ò;­Y`7ÓšP@=%æ͸=û žÃUÝ ‹Äƒ]7SÃK+/fŠZ’ùÇvØ!]öf‘b�I”›÷"PG«{Û¦Å?Ø~Ÿ¸e z(ÐÓ2@´¼™ÖœÿyÚ|Í£°Q�9|QO�¨K×|”6|‰ºöú¯4’©ejßBÒ .ÏS÷‡|r”ÐÞàw�}ǶQª õQm8B‰H�bé ÅYH�C ’{ÔÂ5Ö7y°¯ˆ°¬ ÅXߘÁ¢È‚b% ›h-͇¬\UŽò�Z‹³à9•J!´ p…•\ãO†ÀñòV<{ƒ�|ö™ªð²Ð ê—¥Þg× ]WctQ ž¤£ÛzFépgŠŽãt‡^|×Ô¹ ‡ãà†.d‹¹‡ ~ÔéÒËýÂ;U?á8åWù8£Èëò¦s¿]ÊJ¦¤]� †Ÿªm|ŒLQãŸCœ'3¾/Cè^\ É·€º&:ùçù>©Ñ’Ò�^k�§†È_ãDüÉ⢵u¾ü²nkdûçÚvýØ?`eHd””©=ë�­D4>÷ËÒ`V¨x˜PŸ©• .5r,;¢BòCÉi”ººQÜxþåKŒÓ¯~Ö„OÉ’<+¶rZ”’œ¦”™:\§qÞűT›a±sf»m÷‡Ü}ëW21"u^ÿ˜P ææç RŽvKf˜·¸‚1Vl2î.xðoØE¦B©Y“£QþF t>ã/À2´‚PàУÏÐÐð*:ïú]Àgâ…rg½ôVºg/›ú˜C'>¢ÐS¿4â«öl –ç€ÙPmúeJhoÀ\À÷:T¦ªú^ŠÃ4R¦QØ NÙ�K„&ušÅ€ˆŠáŠg@„ð:ÚÔê%9³é´¦ñ”¶ã\©1‹E–×\ÇÉu™cE&üò:,ý*�LEœræÜî ^ûÚ‡ëÎÙþšÊe -¶Î®­¥úê!ª1z(ë†òôuvÆèÈÉ4†ñ,>U`šÓIÉb¨V,Ìû,5¨ç±–È..º:ÿxws'JtyH8CÛ�‡�Ì?NV¦ü!;™´De¹`É×Gœâ¥nF‰™‹¨Ï™i0W‘Lžyè+nu¨¶Z+ÍÍ>½=U+òǧ�Vz„Ì€¿Âý¯‚€ÚApÓÆ'Â~ÆñÃ=÷Ðñgö͸\©P\IAñ¢ˆ‚Ö¸`*K•M|ÌúYÇGøë¿ÒrétBUZ¨û�í™/xÕi´ñ²�°‹\É»A6ÿ˜“4‚ Ë,Í^vMú3|šPÌdÍ Ì;IÇéd—½û΋>s÷ü]'TcÇÜÁ¸KeE‹1é4õÐP þe‚Ú´K½ät"œwÅe: R½>Góü�Šuò`ZÁ(й«�íXMÛßþ”Pº(DÅÕ WÓšs7СÇý?¼|ºø³º¨.gÌÁ~“µ¥<LFÒJkop¬Ã¢ÚÊ8U…¨¦ÚÓТ6ÂPà„Ô„¡‘†? u] ÇÎXßx­s_뢹bÉCœØŠyÖIˆ™"�JÇ„` ±’{ŽŠuD½¼.‹ º;ÁL‚WL'!ô�ý,ì³;vØf«µçuFSý·ƒUÁh¤.EÕ5 ZT3H ‘.ŠŒvÒèP/õž¥£íi:ÐiÓá~˜ö€ú[^–¼a6ÌJr¯,;9ä2šÄYA7Wé?ñðtƃY@ü $S†£A­àæ®”q啪Â\*«œ�#¶ãz×rŵÁKx;Z?6Ê×p²²¸ô³mlûž˜mÑ Ë­Ú~+Òò· ¾bãZ¼òÝÖ3Ó„}¿½a¦EÊù§ €Yb £miø*2‘f›œö_ƒÚ0ó—³mN!Ë¥FÛ Y�/uÅŸöN‰Ùöâ×m56¿dÌJÅ�©»ls`ÞËÓà1{b·œÊîÍ ?§»×PçÏ�Ǿռ…ÓL(8‚ÇcBMᢠ’bG.¶rg.Š«Mº"¹Èaj|M�nÎähí™9ãýŒlÛLJ$–]©R «k�žþÉ Šþ©çýSAë[™V!²9'°±MtÃå9À%…O‰í öv¥SÚ,ê?£à@?-N�¤eÑvZTÝCU5éJQ(ŠÅ/ÀZÕaG#”J…)� BS:]/>\‘…×М†ÔÔâ…0¢go€µ:.Vjñãyzsµ–¨ŸýX}q±—ãÅZ,âPa—÷�Ç0�Bï Œw|ò‰—´->z"°¢þ¿ÃÕF´²6Iµ õ¢Ê^ª œ¤H¼ƒâ½ýÔÙ£­NwØÔáô G8�f”]:¤a_[zdý; mî™âöwîûÙIn)/ŒLI7ÙWOjÐE !åÏQÓ(Ë2\P¼™‚Ù›XŒ¡,(WÜê¨fu4TèÉ»0�«}çm¾Wd«éü7ý]Þp×]ö�¼a(=G¾A­ûŽ«à¼¼kÝ\L@±ä‰ÐÙŠ&Ú²F|Ç% u .�ò_@MP Yn §¥äš9Ü¿àÔg¿äM/°N¿äiØx”߯BýV.æ(ù‰fXÆŒÏIšà��œˆð(M‹RƱgn8ðóuK ¾*Z¨$—4õRv<1=Õ]n|‘�=âùð¦X–“bÐÛ6‹‹ŒÖœ=¾e>Æ wß he­&I:' :œ¤ã;ÿ²`u×6½uÍÝXÑiƒº<¬EE%¶78Üc�쇴õDš†:G(<ØG�évZî ÅUÝRAH�Ä‘HdÔ¬s¦ù A( !5ÞñZBãšµ®q¥’j™ôõ‘ #.Mv0øLjæ…G­½b} κ ¼ÆïÚgnoð¶·ý¢æ�Ÿßÿ\pyÓÝ�ŠðÒ0T*kÒT[;Bõ•}Tè¢P¢“Fúú©šÓ‡N¤¨å$ž ¾1ì%ØÇK´Éa3|¥mI3Re^ƒº2�nœôyš=E '5@2C+ÛG_,–FOÎvaš+>WC‹Çãš1ÏÆ¹BsÇ4M§õ¡ X Ñè‚UóS°s|O7�ôÞï;åšNÿGÚvýM³†{Á?Eµ§üÙ¬Ë�-¸ïW5·á Ž ¤ðc4ä¼²›[bN¿vL˜.ÔÓoÕôsš¦•ŽécP˜œÉ#{ S‘�µ´>óU¡•¨³_zã•öº ÿÈ.É'òÝaÁÄl)ýü›‹1s'TY8«ý" ?,˜f?;á·Ó#ö³ÿ·¾åÞïý@Æ.à_C ÆÆÒVÐŽéåþ�— É“ÓÇ<%¥FYÛ¤bÒž ¿D×é:}['ø2ìRàÉŸÞLñ¡=©‘• Vl]W�ºrU¢SÉ!Pžr‘|ÞÆ•ØÞà8ìy´t8aщ¶ÅNSõ@—R7BH]_ÕÓ#TY�¢h¥I¡P˜$; –Ú‚°Ú C@íTCX ÍjÅnøþ˜]^F,ÐBÀÌBæL=XÈ•5¯Ìj]9�OæT嘂Ľî­ï¿¿1pÖÖƒ�ÊÊ3Ñ…«Lª¬MSMÝ(-ªê§Ú Ìz@{=1ØC£´Ïây¼88ÔGÔ#…H¯lÖ£ª«�Üééž¡ ›Âñc/O#‘?+Bj’'“¿^Ãq«ð¢+ðào$‚Yø¹¨ŒÉ„B©TóØH7÷|õ^ø5JF*šf’}Æyø¦g¾ºÃO~\KӚϾ™.|ë—‰VG§ ¿¡¡†^ø®ïÑÒõŸœv™©2¶>ýœ®04U¶rú,(`Š{^Û$30ý¾8¶ì|æÂh[Û¥â'Jæ‘�ôÜK­O–žÖ·O>óê·]o­:÷÷œË³ þLñiŽKÚ~ô²kB[Èa'Ý|ª ªX;ÂÉØ‘Ä3¿l>øô�û=± Ök@{ÒK2E±ÌÓ�¤[[dd—ØxHË‹óy™{ñtŠç ´¥kô|×sÄÿ—þ ¶gÎyÃ-jùã› †Å² ׬®qy%\ãóŒ("óbå9 Ïg9�â%¶7èI¢G±KÜ EÌ}R;ž¢˜–ô s¬I½¤¦‹j뇨²>¡ªI‘ÊCQªÁV ;Õ°UmE±†!°f« úļZ«Ë„ßÄ7g|ð±Rï¹TZfUç•[–áüü.JÜe,‡µï Þñ—�¬ ­[}4Xm�v‘jƒªêÒT_7B Õ}Ô:I©NJ€æí#´Ïàùv‹ôâPDNà ‚0W2�îWβð(�á:½Ü«—ƒ¼¨+è•|*â„0:“�ÙÚLH/U=òžù•_A/�íà¥Ê(Ì„EyÎç\‰Ä`iÉeTCò¸· æ`Ų<Ú6�¢Aí“÷4�ГåÀýã@ªKd [þÌÆÕ W¼å&êØ·ƒÚü”Ž?zUàì]סÊuaZ³d„Ò¯§¥ëü–÷ýôÔÏ¿áÖV,Z·�0¾ysQgá[9i�ü]_©8c�hPóóè=új<ýEÿhŽ=õnzúÿ_Ñã© Á³^ö®¿0Vœõ_ã¿;e6 S˜Gü»ë’Z£Ô=Z*MBà_Ç ­^¤Žö?HOÿ÷G²IEEš€�Q÷Rtâ4�+CG¥Ó®(œ Ä¥4ôm¾ª0ˆÕ4¾}¾0•�«Eß—f <Œ#÷|Ž(­½Á4sÙH€ !5¯ci¬]–•¦©Õ¤ ZToôEÄ·7&¤!CÁJƒ” (5¡t‡(²PÚaÉä-nŠ’‰ ž½êeÁ3ã™Y‘aa^¯ÙñËbüÈ€LAÿÉ,êéˆüc´jP¿ã#Ol ­ZöT(4ÙLJ¸Ê¢(L¦ÔT�P]¤—ª�n Ç»h¨o€:`båP{J¾(€æt 3Ž@8�ž,¸+»PÀ0Š[æ7Ž ¢c‹~ï¤ ”ýÎ8}žûºØP8…ƒœG8‘(|Ç!ÝNÕá­OÅ©º3X©‰›Â[Þ3¿éô•”)0Ï}ÅÝYÍ^]jtáÈüPóœrÏ'�å›?Çcwìɇ´†¦e?-®s^.!¥’'±ÂF)¬Íô¤e;ï o}÷¤yæ*1¨Øƒ¹BÀ§zm-¦J|B®P`ôiIøÞ¡êá;ÔâxèÎOSës·%r¶5JFO7µ¶B/¤ |PQ’aËeo¼Ð^á4ÜDo©XÃ�×%Î$–¦)Ö§L²Ô©È‚=xògþ÷3lëµ¼×aÂ;ΰœCÌ\âIkg0ýTH=)7››&SŽe ÙU<©E�ÛT›µÜ:n÷�DKe §@ŠúŽ—êW¼E{ÍáÊ Ú똨ÃÐ( .¢—Tå9`¢à_|‰í Xø9!µ�S(Rð'áO#2m%i%Ôv¬ékQ jÁ¼® E#èÒ£Á0ÅTÇ µœ ’�NAÆ‚ê$Â:?ÖQ+¬änXZ¾–��iÌ©Á4gá?Q|•ÈT%s¥MÆñá?T‘XsÊ#a§#°7Å�“U1ªª¦úHUÙ݈÷P¬"BUúà‰$íí°èŽî�ÍéÈû“àÖ¼<ǤÕJ�PF¬mŠû)¬|7i~-‰çR-øŽj˜zejcªË7h¥ñÉÓC¸‹swÑß�ܤB ã ±Ý<2>ë2¤Üëö÷fÛ•Yj… µqµ¨Gä`4qóF©rõõÃfG‡ -Œ{q ¨“±“ZC¤và?©µŽ¹þØ�¿d¼üï7BÑUò-/n@ˆ/.Zª¬ stà º÷k×#¬«nU³òx”ÕfU>g¡98ˆ*¨A{˜™Š’ršIÔAƒ|ƧíYÁìèƇ�ûgU¶\H;¶m»ryê4isš§éqÌ8/—ùR‰Ó˜Í%$}'¿(Žc¨ûŽ–²p:÷³5±¡òÐ+“ɉtŸ† ;‹+?$Å<ƒdøùð$Îêcg“õâUoÈ´Mƒ¯cß75@-ƒœk Û}s�Ôëæ¬©†ó’JŤA]žt<ál˜%¶7àõŠ…Ôð$!¤ŽA@Ç݆pڀЦ!¤NQU(Iµ•qª%¨'°˜úYÇ*TEæpˆÒ± Y \)ªY›ÚªuY˜lâä|wÝ•|’פ/Çð–Bj® šßøå“§¥yx�‰Óåaµ …1M.µrå7£Õáh"O¶á] ­éšŠª�ôP-At3ÜGC½Ct²=Aû[Ó´6§[`Ö£êSˆØ×öêØûMê;²ŸN²H;ë mo‹˜jnñ/¡ªÅ«©jÉYT½ä"ªn¸‚‚‘S¼™óö›8y£”�YD/§AGÛb5~¥g‚Bè÷B(-‰“G•Á]Ƚ„–æåýŒ®‘À•)ÝØFq8GAŽJ&+J»ïMIŒñŠ[@�å¯sô¹hýz}À‹rÚÚõ‡ËÛ^yH~2Ä˵êý¸Ëÿ¢@tJ$’£G讟^‚|ø(¨X�`/üEN§öËD˜ê°3g�®¹fì?Q«f¯ƒŸÓÏmðljeW¦ÀÜRࢋ.ª\ÍS�`¤X°éÁ‘c*oª°ß✞Œðr�3;Ñ*=;ë !ÛpÏ�-?ÿ·ëàåÅ­ìÆPT x7½œìÒQÐYü¸ÏÆMË‚ÃÏRÒ›Ÿ……çÆüä^õYÙæ. ÊE—j­~ïÝj…_>7è=º¯ Ë5š7˜s1OéÓ Ës@A:P‘TR‚{^Әπ\šú±{d9U&&XÃ8eY´6™¤Æä Õ4¤È¬HP$ÓØ6Ó Å±¸åÛVZ2žHs»7wlŒOŒðJ!4{3iJ"£„×cya†ä·3#ÎÉ/Yæ¬Fá,E»às*nˆSmH¥ð9ÇsÁ¢no߇èt•õ[u‚/ ؇>Lõ«þÜ^sÎ�ñú æsŒ ñ™hùRÉj€â$ø3ÌnybžØâó*îÂOÌl£ðQÙ4¨KÍöU‰}Êèg—+Ã*S`0Ö¾ò>_Ñð2ÂëŠ`´pgË`NÌå0=ÐEšd7=±nƒa§î2ä€é¸ågÿz âæBè£P)ê;4¨¤pŠiÏσ-ûåsâͰr¹§É ³ÈÏAd³ƒa½‡Xs=ÓqË7ó—púŸy1±—¾zË�õS ? K¨ss# Ö©äŒ”瀂uŸ"¨¨D÷¼¾±‰�®>\Ç0êE„½‰TšbP³nŠ[YlQ„®f(NÁª8 F“‹VS<¥Äp�£&%¢‘‰ɼãÄN½¶À<±†4;×nÂ2ŠåÚÍ �ÜË33!:ÂÒX0ï·Û±ãžàèúŠß°I�ªŠ8ÕD†©&ÔGQ«‡±^Š õS_÷0µu¤èp§E{lj$ê†pz”M¬§œhµ<ørzþÎßø‹¯úÒ°õ½ìóˉ!™X[/gU%aINÊ©\¬�ñ {‘àåÆsÎìÑßäp‘/z\`ú©J7gúéÝn†«ÞC+6ÝÌBj^É œù#ÕB`­Ú&†± *j.ï¶…oƒ¼šöÞ}Ï\¢1íºu˜øP†i#áCFí m‚vw.÷¡åê½¥'ª¸½j+n,ËØÍK l~ÍÇ¿M•ó¼¢N—GTÂigyá&«³" ±ØNd%‚\N9•GÐJŒþé×—ÃÏ{±²›€Øèªý­"cVN÷‘¸±2ÆU[qãÙ#…Ô"г™A?ŸŸÆV IDAT€gñ³lã+gQjúEŽîüòô3—s–Z ©ô07sd\ÚžI0\ž´·—ðÞ€—,þüvžnèÛ¦a,ŽM~ cŒY44œ¤æ‹*–¤©®æ>ªFi0£hRÁäÇH°*†É\ÎbEü{J°Æ%,HðÞ\BfÙУO¦zŽãK(°.ÃB`T;걕>ËßÔÆ•¯¬ZœXVUƒ9�Aª5û©"ÝCv¬V=©»k”·A8ÝeÑ1hª·�Π÷¤ÂéöýŸò_8=ËNZ,¤õÐÉI«ö#‘Ï+!g§«dgwz°èëÀ_Ýݦd†DfœÀçò±\€�›oÐõÉ õ¶H€•U‰ßqµ:ŠáGá)P•ºà ³T¤¦´_ލ†Ìà^ÜêäðÀ Ú2ó¬‘ê�3/Tš%¬G¿ý Úrc­ÝòC¡IÍ#ÁÄÊÇÊg,¬æåŒ‡ Xé”wNZ<Üs=û߯¤ÎNœ¿\"ÎÔ`Æb.4�uö8íȧÛèø”1|¦.ËKߜ٩Q,ç˜�ØrÁ5Í©úåïSÝO~žê´=’?¯sÏcº(³g™N+}ÞŽ,Ö$ÁUª\HÅ¿µïç·µ=QHíÇ’|t†cþGP� ëqŠ¢òáp‚ÌÀ¿â€%o~73'rÏÍ ‡6NÓÆ¿Bzœ•¢£�íÖ¼ µ(€ÓRZöæF˜&ÿÎM{qÚ›.WžtQ¶8á–øÞ€ ¿%�‡GdÖ7ƒ=ˆìISóÐ(56Â&uÌVÔA„FpÕbê .¢Áp ãIM/|‚XUY-V`ñü…À™×Z‰#Ídeás˜+n—¸ðÃÂi! Æ�Ô;vì0pÁç�«_‘úX%B¬ P õR4ÑKéÁAêí…Öt‡!¤ÇI‹Ú­éAœCœPsšÑ:zçgüÁN3”€©Í¦·fÌK¼0ñ�®ËÿèðjddíDÏövoGè‹»*ª ¢Âæ˜A»TÀÿ{66¾—gRØçî~ü¼mäR­œi¤ ÿ5½ª|Žîú?dÅ1ÅivË—WR[ÛÂØèî¼í¨ÿ¥�ÐY—?lƒKå0Æ‚ÈZÔ,¨šÕ6,œÆ%ßÊrX>ç¦÷�$b‡°!|?=×oPQAªô­A:´�u~ž9QÃuØÙÒ÷æÖ;‡OÔ¢™Ç—’ jÙ:=t˜9åÊ%R§]|7yÂÉšîwTÉv ù§*€á2,'ê9öÜ�‡ÿ¿½2¥ü;`›2¤ÈÏùÔ3ÊÜ•/ó\DL&Ú¯ž›LrµSX«cn4C³æõ+(^æ"é·§í¹�djø]QÞœQ k£@u­Öú£´ÂŸ 8æ€É’}H+Ï>±$@̃½OæÊÜ M¸ 8MXÀÔG´©W mê4-iLQMM gíÅ(†Vu= /Ô$ Ž€Ï É—ÃBÿY.<ŠRýƒ×a—rV&)è’¿œŸ�dá4'ïÚu†ZºˆYß?û»ïU5Tu_PaPE¢&=id`˜zºbt¼+M‡:Ótö¦�Aµ°BÈûÅ!• —œžü‰ÃÏs¦æi˜þÎ}�̯¡3*Ír?~aZôζpâ‰ÔR®ª—Ã+wkôp§ws_W}œß�|ëâq£w]Î[�’K\ݱìÁÙÅÁ1”Íesqœ#äo_v+.^Oq ¨“q|¢Ù…VmÀG(Oi®¥xÀùý!:òûå´å-n¯:óÛ¿äÏŠ”é!¬æ!â­Å�wÖˆƒGGkúŽŸ>ò/tü™ÂZ££ †M•9°;àÊ|vú4¨Õšä/Â:q1 �ŸÙÜ ŠÆbS/ ¬¿äú­vE›Ú� „ûªZ,o†€äÑD¾ñƒV%ª»çj_;à�øàc-÷~ç»N°|›‚#g}˜¡.³Íç<7NŸÈq~µEeÁm77_nmýÓèDe´Ç¯ºäãÚê`­×§žýŽ6øeÀÅA�på:íˆ �üµö:&¬ {˜0Ûlš›Ã8Ÿ¬<Ì–~¥Tnžì xýb �Pƒk†LZS‡9·iÚÔÃ킹˜ü×'¨¶*FáÈE"Çýß— E(e° µ÷–r¡E¼ðóú,.!ÌÑ"B¬Û`¼dº#¨æÂˆ[´¨×·½ÁêêÑ‹Ö 2c”¤�þõô$é8ÓGz‰ŽÀÀ7Û›î…p&½]­iÑ Ýq·žÖŸŒ‹ó+"àóËk#T_�åCŸ¦¦^”„€š*qH"œìîN/RjÆbp ™»¹C¾‹¸K¿‹HDÈ4•Û)¤é&ÐtªÊ©ÇW&ñD¼lŠBÜÍ(pF¦¤( ¨]ª…'©_³¹aåUtäO G@-Ÿkš:žú%-Zþ»né«E”aŠ7·üi/,WaBÀê‚KتF˜ÿòË,öûâÒÉ:ñÜǨíOÿ£í ª/ˆNˆ jšµŽƒPôµC­GÓ|HÓÌfiÒO³êÙe[&Tç;áÙaU.5¯)`k.ú‘ÛB±6Œ] øå&–g”òM­¼ÒŒ“JPÞL.p鱞ÿÃkÆD•ƒ“Plj ¦Ö;IJ¿‡ö™â>õ¼è±�”s9¢�0óÑJs#œjh¨¡Å«`ZF“kþc˜S±Õ.»yL“38ZÛØß~ŸVø“7¡–©Ó¥pŠLÌê¬bBØå9`BÒhI˜G{^öøâ`xRÙ�"åi‚µ j‡ð ð·æ>–7APݧÚE0m|F‹€š¨"FžˆwÛ ;¾ ù•سZ À ¹ga‡9/!n,¬Å ÔOõ ßcôñ�vî¡þîut[t4:ÚoÓ ¨v‚n} _tdºNË rZùf“)n˜M± ˘Áº ÓJ%Á¨©$êЯüé=*¡A�2)§£sŸ–£qØ\HVÔ“.Æ ÂœŒ1ŽD9‰çL¥RN�ÌÂÝ׈ZäX”qã«å‰ž°rL o&V´1XâöÏsÐiª¨âÖ nÛ×GÛ§jBžé «ßÿž'”R* ³ox;5Ÿ‰!„³Yé’‡.,jØÐŠK,�, Ws‚VKQ5²;cɹMÝ~†zî¦þã?§¾cÑС%e_zê¦w K[m:E¦Ì37&>ÆÏ¢S":EÉ=M‘iVÉþãÊh¾1u³jÕL 5 ©ƒÊ”™Ò­œÖØxÙ›^d‡+6x×å—wùëP:•/wåœÉA{�~éÀs÷Ë]¦›‹¶9æó~‡ð.ý]SÜÑÝ�Þ«lþ‹y#X¹õvæª[{ܺkÿE[̯<þèÍÚà—šš* ‚Hwû΂ԓ«ÝšWáEå9 ÝçcœŽC‹`oÀëäªdAªš† šM~ô"¢ u4ªW!bNú[Ú`ÑÒp§–½A P…-ydn¼c§-ÖX)bãÕoÒÄ’Ì• �¯Ïp¼³ãTq$²PÝ„š™%rR_dËyòÞØ;ȼ½Óºº³g�Nt§¨ Âéö[ˆ:{bò DaÒ´S|‚@lªŸÑQ¼ Ðâ ù;Zì#´ÉA™l¹[ƒ Ö²�}nx¶6Ƕ+`âƒû6z”è×÷/a‚ÖéûB †“–}/»ŠüHV±ºÔŒ ; a�»¦Ëñ+äxF×±WàèzdÇÙ„SZ˜+n5…ÚMÑê3´=—påéD«aøþ0¦ØyîÖ]ó":ýŸÀf#Þ*r—çù�G.ü¸ó@ZÒbàãTa‹$¾ClÍ*Š‹(ƒH'ûìT¼•’1\ñ”mÇu’ÒñnJŒöÐh¬‹’]-t|Or‹±‡ûüt–†CM³ð§›¥ô)É:î�þ;-Úðþ£éBŒWèÕ’r+*{Ê�°›Ö”}<©ó TN9Ég¦z/2!îb=á‚pn. @F:¿n‡‘>xìžOfe(¦¦€-Ô‚–L{”`¿ O`lº£”ÃR‹ò¼A°¢µ«c×Dp´ÅŸvî™Ô¸úÚàwìE_[<¡6–àšugiÇÔJǨýé#Ú뙨g˜(9ïøªºÕ€Qžò&d ˜§{µ&ò�…Ô0E-µ©¡¿5Œ«†ªOÛ´Ùñ˜ÿŠH¨7©" J’r‹Í\ÿA1 i¼'wø•€ZlÙË8sªøæÌÎS¤-aºÓ ÚêZ_ö·×6GZŽŒ�éc=8beLB�? ±Ö4Ûöf©ÂÌœ¶/åý‘ 7άmyäIè‘IUÖ.V-y`V°¢v8…g({x¦RÉ…Êþ�4xxO!äQ"/�”1ŽÓ=Q–Õ„˜VOŒ¯ØëˆŠùUf¡&vF¢bÑ"'ÍQy�R"O )ÌËt=¤˜ÔbPãµ\ë�(ºñŸfÕºéÚtÚ éùÃwN7{éåk® +ÞxUÔ^ qçnïíú<2øâ¹@ ©EØÂ×Óú»·õŽÔà‰ç)Ö7@�»ð�Xƒ@Ùy)05Œ§9P` ­d\Ì&„ÛnjxÙ “¦‘@X'ø2ì2¼ؼys8U½èe*N±Zbe‘œ¢L²Â+‹\m8Bp;‘–É #Ǭ,"Øâ»;wË åßéRÛÖ?iºK>õ Æ�9 ¤zžÞÈ\ùíª† ‘ç×Þ|Úý��Õ´þ껵ÕæÇûáç´Á/. ,;ëýÚ‘é>øÔ‘køh¯ZTà÷Aac±®m*Ïci2_Ãó|oÀƒ”¬|p" [¡äE¢P3Ï¢s„Y«šÕbKŸHû²7xàOÑê“§¦…`úÄÌ $¤`Z¥�ŒÀUÎØ%4)D-Z뿽è`dÅŒÛ7Ûñ¡¼µÞsV]³„í<˜3­È"Ó 3˜ÙàsãN-ïìcǼ-G a°èüÙÜ+çëÒé¤*>6É—pp'ÀX±7ƒ�'�i‘Š "Ú-ä´óRÈô¿?ûÒZ}@4Ô|F¶·íZªY@}ê9_¡çïÞä3æÅ®vóbºøÕÏáõì)„2C$;Žãy:Àà껓þð£k-Ø`œùÑ Ôå3þ vMbYh,¡Ób— 6Ì Yšòã@…ÿ}ÏoËðæ ’ gnUŒ£XMðÃwfÂDØi)óŽŠïòx�TÄ`©y21Ò—Q‰aûÈîO;YŠõfl:÷¥›SUu§ì¿ïöâyÙ§.¹4,2Èžý”²IÊÏI9åwØe÷Ùr˜ÓŒÚ¦Wãö÷*¿öûâuµtîŸï¡`ˆÍ èq»ïå/Ð +»yN�0-:å/´·±õ¹Û´×1YÍJµËËsÀdôŸOi `o Ö<( Añ<|ˆ"ÛV> �Ö£Çõì ¢KÓdóGüØÒX¨Ó†tÚ6ŒkCãÂiDƒi’x:+3’ V&‘†t‚Ÿ·ò† óœÁQ_ö϶ÖÖµCÔÝ Á4kM³Æ42)ñÈ£“W/YI]t"¹‹Ö6­Í��G¬(Ü~<šÐ$ ^v9(ðå<¨P°¢8 *(LyˆÕf¢\�ŒàE¥tZÄ Ós^ ³ú(È›®�›0‰©Í9èˆÁ¡Æ‡3RÝ:Õæ~ù$•Hd..#|žBF RP»Ô+ÏpÇní¨Dª7ÒʳÖÒÑgj¯«�¬'Jdñä¶óà8ÚñÂ'Yl‡W_x9µþ䄞+l~å#òü =UÀøg‚öþìíš ,/†,T)¸kذœºÒÝ%Ã7rZº^¿MûCÎ}*„’ÃÆ3.§=­å9 à¯À.À½¯{�É a1K c)={ƒ¥u{(M£.¨Y( ‰¸Åš•á4dâ¶"k“gxˆDÄ<Ï&=ÄÈ¢>ú @n‚ê$ ãÈn_ö½ví²IJ¾hMm×U5œÿwݰ_žúæWù* NSS„::ô ¨©…»�ÿ޵ÀùeïÁ~ÿ�û ½ZÚOW+J|ÀŒ§âS…ÔÙË�Â�Žv³x“QÔŠ†yähsJƒšåÌ Uq? +‰�p%®ædáœBœ¦¸n;öXApòÍó[ñ ¨ùõÜM5šßúÔ¯¸�Ö]üŸÔòLJçð™£[®†Ælž‡óœºý4Útyá´ÛýE½!ùžF¶Ü<òüÒ „«ù/ ž &éÎú¿N×êP‡¥07fÆJ¨²p§Kgj-û Öm»f ÔräáaÀ˜—røª1T‘±Š-S뎺�Éœá*UÂÀ‰ß)ï\ÞW¯^ 6Ÿ¥Ñ|æ)\qšj�à!]ÄÀjÖ5ß´æÌ vzî‘7zŽ<–aD™Îü ¡rìcÜÕ]Å‹ö8�ò¦eJ:�FVPš·}gíÚCë|Âÿ OSSUàôW|ÑZ´ò�j ]ÿï{îz6ž%i真‘÷9ùOœÉ â�ñ ^w*{Qê=þ:ñäèÀã»PBû#› « ÓЧhÓ+îš0ݯÖžnyøI¿ÀÍæ€Y—�nÁ5ç}‡:ZÖizðóÂ@˜¦‹Î¬ó•ð0ë6ϤàÞðd&&4M{ƒFzÚÏ�›á´C Bê¶ Ѓ†`Ú„mé€LãÒü µ º†I�´¥ùdG; y¦•$ÓNRØŽQ [©4ÅZ|ÙŒ˜¡j-3zuãKgÒ§•wéš&ªn¸jZygš)]�Aø=jnïò Wb®þÉL›^èüV؆µâm2ì„è †GŠvÙ»æ2†Rä›ÕWæHɹ¢!38¨±1./æÖ›á�+ަ¨ù„ïœM 2ܲˆ“iŽ;]®å¢]B˜Îý·hPóãÙxÅ}Ô}b©&kòÇ¢3¯~5oû*¥ít×çÏ�<ûd©ë"tæËRCš;;wò\nÜ[dù;vB¦ìfL�€{ÑJ4cdò(`j0U"ÑQspÈ�)jñ)¿œmèÒk@ £U îíªB–¡NE�`(ºˆx]áCz²W˜±a'yœ:ƒ,Źåwm’ãX/ö‡»;vr¶B»Ëè²`ûÖÀZ«aÕ•vÃÊ›(\u¦@ŽqÚ/[áÅLbZyÞé¹G>áM™¿¨âz™ºÊI¿—ÊNº'“òŠ\¨0Ã`¿Ph~„áºà5‡×-ª;·å‰?à<ù:~�hÚú†þ¦mߊۆž9Þ‹äñ�ïŸcå/6¥å¿äò¯á4c½hÅ[ŵáš:¹wµ>ùjoé,šÕ­\Dç¼iWö™,š°{ú·×h‚<3°fPÌ3+4ÃÜAÌýÅazöÏ¥cÏù2áÅÇÖ­o S·}Kû´ÜÜò0õC/ï °êÙ¤#³aq,\Óø&eY4,éRˆíNCŒ�D\ï�©Ûä •½e h£@ ª²Q|^*8'É>ñ¯ËH媙Õ²#8¯L¹±ÙÇÂéï�û¯™;¶R6¶l¹lEzÉêK­%+Þv¢rñå¶c ÎÑÉp©pTwœóMŸ½xÕßlß¾ýŸxâ =vÝ '÷@ûjbáÔ8ä'‡¥RÕcTa& >?®Ooº¦eíÚK³Ûžùëʾ–§víÚ5”É3µï oØÞ�¬Yñâ~Z÷¡“‰ºt�@«J`0¹éÒ}j(³ÈÑ×özò§_›EÉ9+â}üùòÆ 16•‘K³5¬¥S6A\¬IܾëŸèè®û¨ÿhoÁp[Ñšó·Ò¦«î'ÆM·kÝù^êÜÕ®»šiÁ7åKªiåÍ'S TOg¿¶…6¼ô1:úÄ_Sï³sFs-_ß@KN1̯|ˆ*ë_�:3*[‚sÀŒÚçWæòÞ/dõì ö<ÓO¡£ @< �t0`@ ëÓØ9ñ= [ÔlŸ:�5‘Šcá´³1ˤQØÞˆAHÍWÂé8 E�býêªðgo02ÒãW7gý%¿„€ºñÀ8OÇó¼<¼9O@¯jÜŒ”Â|3Ðñ Z²ê½`2ûèhÍÙÔ|Î:¼@n™=ý%-; jVZÉèG FÇá]9–ùN—9¤Ëem9q,sx8ŽTšÑÖ„ìJ…ÀZà t�$Ðb-ÎÆ!Ž€ú>ìQx;^©>‡ï É•†€šOT?¹ïŸ©iÃí'Z»�®þøAzú·—RûÓ‡5Ô¦Ó/½�–oùªm|YNøë_ðßPóÛÑ}sæÉÉ'Ü7®ýëL’Óë݈±a9ä�v3U4qÝO{bÊÞéP ôÅÖWŽª<ÓUŽT¿£šÕYž0}ï\U¡G»®ŸÅúùܪé:ÄO,˰æì`ÕrweR<· ³”»`±gür#Z/ò8'šØ\8(QW7�nmE}ûY ÝÈ¢‹ƒÑÆf«º~ƒQÓt5Õ4½o¥ùD"Q�:)Ü ¡9J7ÃAˤ3§¸9]{Ñwz’ ï5Õ,d·Æç‹‰j»çs”­=Ï\{éý1ãRZw¬hŽÜcÆú1SÉ#eõƒ¦0˜ è¢eFUíªP}嚊zs}ý¢Ô¦d`´’â1 ¤(Ô­1Ììüy§VÇÂÓ¾y£Ö:|î%…ò š>ߕߧê¦fí¥_˜2#o†W_øs\PûˆŸ “¿@íÏÿ’Ž?Ûcñ®kJùd¨_]O[_v«V¡…¿‘ž{驟~Ã5§~3àË!iÓnCEÝy´á%÷½�ÒJÑPï=4Úý¥“=ÐìÇ!ìHH@3pE«WQ¨z EªÖãÚ4ñ�îÓ®}æKh˜yã|.QÞ`‘Óc2ç‘çp¨á€5>ˆ ¥©"l@kë Y¼Éá9ßÀ¡‡ì��™3�‚Ö4î1HÀâ|Gx¯Ä‡ãð㇦u|¸ÎŸ½Ab«²&Ç/ /|˧éáï~$¯6]ñrZ÷Â;ò‚1UáÚ× Ë÷§ÊæKú@û}ZÔŒÜWÜ5¿¼`Öaön™�‡^vIçwƒ9ß_˜a�œ+ÌÍÀ—<ÿf„Ôì|¢>\—9’¥B�2}ÎÅÙS…ÄÔAn’Ü#¹TeK‚@X}¦¦`zËqœ {¿¼eçjÜ%¶ŒiÜ䵿&ŠØR IDATêÕ�…ªªV×'ëŸjTÔm0*ëφVÞ%Šœ›u¼çË,ìn•Òc¹Ü­\e¬ƒ››Wb¢´¬³£‘wqó È1ÇjÇV¸dÛ%Âð3®Üš©\v›œÜÞH  <'’¿ «¬¿Ò®\t%>Ã&$70E!ô‹™8ÿ& ÙIlÆcöyŠSclxcBvñ�¼õM…ðLÒGú¢»¿xŠäËßͤÖYåeÚªk,Ï#(€´×Sû²u�T³ô:OÌÔÞ`äZ¾é³âÚv½Eý'þ›:öÝF½'wAã˜M�øõ, ZyÁ&:õÌÐâ•ïž1Ÿr$b‡èî/³íS]½væˆÎ…™8…%Ï|~�î3„T}3½—Ð0Ó¦iÉ_Þ`QÒcñ‰c˜4xÝÃÅN)„æ4î8QÐEi¬�lsqðÃì4ÅÁíCQš,Ö®ÆOâ'†¸ÜÅa†HKÛ>í ÒÃz¿~aåºËÞ·žžüÅ�4Ð:Smí]ø¦Ôxú'´ô{/P)ùQLr½nH£y»HÕºð­_¢‡¿ó!4=efnûv ¥/ºîµÃ´íëÃË+ê—½Ú:¿ýgÿ÷ØÌ LžÛ2Caf|ÐÕ%¤ørÄ1Ẩ_á‘1Bð+bU“°C‘q—yì°sø¢(ïÿkL{�ÂDÅ åÎ#Ú#<‚וÅä¯àÒH”u;§v5t÷[œù~ÇTX"Ž'¬Á“¿˜1CœOóVlù*-?ëËÔ{ôj{îtèÑgNŒ•ÉÁÂvÚÊÆÓhIó iñª7På¢K'ÏŸ#uÕ¶ÏB@½-GÊÄQ k>˜I”�||8#�æ*—¼Ë4cQó;�ío?�zâÖÏdÊ—}SRÀÔªA=eõ¾e04™*IVú?ßXQ!Ãð­í P)šk¹ô=? ûo~š0v=T­*ßËÈ›6T@xÝÈêlž€XS8ì,2Š·TeÕ]ê?x Š™ðñ«7}øôôéâLËU›Á@�m†áØEv(¼’Î †Œ@¸Ñ0•Ìò¤`ÐÅ„¯aaÉ‘qTðŸ zRd$¸i ÃÜwÎæNg³Éªiâ—Ñoál¹!:V¢1+d&*úrÒX†\¶L¤¸� D'à'6 ~±ùÆ6/…•²Mh‹�Ÿ6ÛB@�¯�¦ …™ñ0\ˆyx;ï {¿ö*@пÉÌMU$£‚ïÊ�¥ÅذʧíÞ¼ýƼ`óK¢úåo—ÚCýí?‡àú>hßMÔÓMmmüÙ7?§Éš¢[š¨¦á ª[q5¬~?I…Õ¶Ò#ôðmžù¦®èQ¾ë£@‰Íú1Èå½ ¨+f@±ig=­gœoHA˜ùë!^÷xÒçI�×I¾«¯ŠØÏf>XÍ3<|ãu2…xXùÎ�ؤóÝ´·taÍÖkjµféµô¢wvÓ‰]EÇÃÐ×$óþ²³WÓÚ³ßO‹W¨ vê�Œ¨çÌWü=wÇ�8¨Õ�¶Ó ¿qõèÒ÷4Ñý¿½æ7cÓ¨Ë8åÌs6.9cëMÆé«þÒ¨0MæeøœN{ùEÿEôƒ»�/_ÐE2¼{.�ÙU þˆÇ ¢3<)"›H|‘`KÛÖ¹ úÇ:õáÆ¾ÌwŒž=ˆ›%“ê*üDâ.AS.¾«)uxsÇÎ…a‚×�‘?O77”#�ü �yíÌ46rCš~,3Ñ‹WÝ$®3_ÖñÁ]”ÚG±ÁC”J P¤r®5®^G‘ê³`ºaúL�3Z}6Rd¿ž KVtãæj U¬rEV¢3 Ô€qgb±)tŠaÅúT|`%µíúr<±÷µ¶Žf�,ÆS Z<>Ò—–·n#è9õ½ z~[“�„Xþä¿3B5þÕ ‘ßì¿ð&‹øÆQ“\Ù4WY¿)›¦Ó_˜rÓÇÛ9…?Jó!«'6žþ2N¾@Uù³òq@-bÂïþÀ#Jˆ»ôyX^D¸!áçrpŽ4],‹ ®'3dò0L ×Iq8Û/¼|ýö%mûžÐs¸�‹È„^7²\žÓ}ˆY…²À¹�±Yƃæò:!LK¨€¦oln¬4DÖØ‘[ µ ¬ÅÁP¸ó&JÕØP¨Òn•³÷°½Ù¾ù@ͥ똚Êyý*Nû½a­G!§Ú"Õiéº�‹K�d‘/;'GRbäT¡ħÚ#;ðÛ²†Ùÿ¦]ôÔ�ΘSÛ¹±7äζÀbçÉPð§VÞ€Ïг7†`šµ¢yÀ²ÀO­¡bnw&xeòŠƒâÂ�øJ »C'‹`]”_õÛŸ½�M?ÅWà¯UpµÝÕù\A|p' õS�ûÆ+n|­0£{¼å‡?x‚ººøÅ@€ššBlZ„—Èç­xYtÉŠŒÊ@%Õ!•;¨ãØk£§ŸòÒ—žsâ÷¿BÅç{·Œ@DꣷS»®l¿|:üøW^·~O„ ?Î�¸i<Œ‘¨RÁF@�gå ¬’å]ªêH¿‡¸á¶ƒÑUÑMo|¶‰è¬… ¤.-õ¡Ç÷Ró¹?¤úSXKpn\8 A4.b{þšÝâu5ÔÓ{mÓp¡(„£c:µ(&ãäð�pxàplVŠÇ‹£ŒÇ½¡ù½„«’ðÅâ¹€Ýk$†wÛÉ‘#f9)è4Þ½·í::ižL¢A��Uƒm^&ÚñEjÎçGÄ’Ó.¡@˜¿Bȸ˜=<ãÄššªÄ¢iZª[yn˜�¾ªúmø<ø´I!úvZý¤µÌ,‘çÆ—ÿÃõ4Üý;ê︛;§–û�œKâÌ€—s—) $b‡™Ìz;•\7\q¯Hã8o.'œøæÎ›¢V‡õFx3aQ‘BNÌ‹’þ?{o`ÇUŸùþ«îÚ»öÍ’-É ¶äÝx’8lÁ,&›0’!/�Ì{ɼLHò’ ˜73���L–°$„â a  ;`°�e¼H¶$kim­¥¥nõz»ïR5ßwNÕíÛ­–Ô’º[-ù;ÝuëÔÙÏïìÿ{î)¿Û atc0iPn’{rAŽ¥s,�IØ.¢†�D0í¼¹0Ì|xÔ�¹mк‹MMüÒr&ÔÁÊ•+‹ÅââÖ¸RÞUŽZñ%Sä§ø V'Ѧ©ÌžÄWêÊ=úàÇ…—ÆèK%uÍ0©Ç$œÀPŽîÎ-_L6vPÇn¥ =þ¹§ Ú]ðå&ûô–„‚ÛÙ©½O¼Ýžúâ§à™‰¹`ÔÄĦϼ§úYÍÌüµ8 ï’Y�¿ŽÀ�kÝ5«Ÿ&²Ji�=ö/×Oy®~šàÎÂÍbeÑ–[}#j!ßtá}ÑÞ�üÑ^ }ÀŒ°81P­ Nd2Þd†ÖXô:ÅþÜíŠÆ½±oçØ—4š§f´>¥šŽµAÏîÏΊ€º1#…¶ë�×ÂËMϯžcÑ-oÝkû6ý';ôì·-n°Žå‹Ëgqß¿lO~ño§=¿¾wïŒ ¨§šèÆÉ*$gÝ”õ`S¢×7/`åø›©·äÚ5K+ëò‹Ã…y·3ØT†4qŽ31,¶ƒÔ ç“~柶ظÉhòÌuAºƒ„óRç·¥/ú#wÁ7]z'>$g@³Á#ÿbO?}Æ¿ȗʵ(‘·¹å “ÄðøÁø`ÇøøìâezaÎãý/$hïÓC]¥&¼»]ãÍí/ x-Yk£û›Þf[¶|ºîø"Ñ\xj~CõýÏÜa?úKÏÛÏ;f«ðÛ]�¨¦& Îà'�®e%Õ8©ô®2#¶Mß½½öI|¸F4. ט}£umÛ=Ó� w¶2FrƒMš7gÄXzb'”{EÜÓ�÷—¦Á… o8ÍȽ"Átú®,Í2mk2™ö58_ô5®ÃsË_¿ä¥qÕJý_‰~)sl÷7¿ûåoîó Kâ?÷[8ÿ®·lªZñ’ ¾2¬@PÆÚš/£ °šg}Q`MŒÜ`)‹ô~îI˜bW_õJÛÚùo'u½xq«­í(®ýç†âO´®¸ãFÛñȧNлþuOŸ—·¼Ÿ,a«núU¨Ï쥵¡ã' nÆÌ—­¿꿜±ðð ‹@uð ŸYM–íñ#G¿3v²ÞÐ�~\š,,7Òœ`‘Ž0.D<¤Ïnbš<4Ææ·~RÈt{;|úÿñá×ͼ+gÙ0Yl0M‡1ç„ѦvõôÀ, ò­ÎÁ4\þò7ÿT|ÉMŸõC©Ï㟎ñe1–„4¥ÞÄeo¼QÒXžuô5F1Í- ¨•÷⬹ˆ së,ÝÔÈa…Ù9Ï2 ’9nî‹êÔï¼&æF§W‡Ÿ¯=öïƒCÆtA«Šé|妹cÉùŠzÎÄ{ðÙwÙãŸû Òs~ŠåÚ×ü”�Ì s8!Q0#”µ6˜^¬ëÚ€ï;~àïlÞ%¿0½À.‚ÐV\÷¨?ŽœLïxpôèÞ¿öel8zÃy¥Ä\á 0‹¢x‰ 9)£ „2 ¢æE¯œbÃê oÞ„#+ÜÝ Ú…}ÏÎ�wZŸ21n¦‹4¸y)�Íi™8¨»9aŸMè˜Zz¦†*ñкägW¯^]ìì<ͦ?ï©þEÇF]HN—ÄââMË¢î)‰2uá_æèm“`�̱ù<Ý�­› [¼ö·`ôézx‰fîªÎ(;Ég¿ñ²3ñrAº­ôžrºûzº¼Û´Šó)Ñ»=�ÛIí´·c»H/úðzÚ%~Ý}Ì-Ý8;·2f“ñ‹Ï4 ×h¯4£p:át6ÌXox(ä3ÖT­¥)°6\Í¡»æ·à}9­¡ÍoÍ$WÏ9ëhÍ[{sÁZ›š¬©ØdùB3N‰hÆyGMãW6µ°-[m^õÆêÒÛ?>ºîçöÜöî�ŒÜù+ø¾[7lXæ’zޝÙðÒ+,j½dÁ¼Œ-hÇÕÚÂÖÀ¶˜ÍǾßy8 £-gÆ×ÿñu}ydÚíúvy÷<Ï1 S÷¾ôª_=¥ãe·Ý=§„Óib½è­©ö¤÷«WÞ9§„ÓLè⵿�OVó©«RyºOá>}ÜK.Ÿþ³BO«\\¤¢ÑR·›Ð�&ãgŒÒÉV2Ðø`ÒIcâ!r¦Æ'kaiøtçvŒó�—"ÂÈ}bÚJÁ4/&‚—£R=Ÿ'Ø{WI½»º_Ú9ÿ‰õ)náHߎSXŸ½ÕÒu<ÎsCzˆal*;Ε{hpê1ÐÔ{»Ãȹûp~ùÑè?}¢™çãïÞ >Ç9n| ]rQlœóÁt»_Qa,ÍðBº8ImLÝ3ï§T}‡îµG?µ Âé�pwÁ §O™×Ù¶Ì4-ší(§+>Ö¥Æ:uÆáVGÚæ¯Üá4Û`c¥>ã ÎÉÃ%7ŒïÎ)°‹Ô³ú€©¬ÖSã4UWóÚ`ëÿ3U /(w¼ƒjÑ¢Ù�`{~ðs‚e2eã;A(çÈbBÏ‹Ï^œüÌŒ† ,zñ‹¯´D8Ý`|ÆZ¾þâ§W^¸Ë�Ù:›úsÝ¥7F>\Úaïç™cþ†—]™¾#õtÚ;Ú�Ù§³át‚И>á#»3TÄŸÆÌÇÔ‡»Ã½ÛyM7ý2ÝÅÖëW¯¾kfÞÆÄœ'u!î ö¨v}ïÖ¶ìWìÒ>|žØÍ|´w?7åHºG{}•fíe•æ�º´šcáÇ!ŒÇ¯©�sÚðáýºpØøÈãq(‚ �¸Rîñ½û„,§ÃIb™>6ºšÌÌÙsðHÇ'7æÀ¥»Óú$LÞ�² 7§Ü}ÌG+çF-ÞýCâ‰ÂÜΩ1“ÄîiÆËŸçÍ�>Òh×îæÒÖh}vpÿL)XŽmš©ñʧgldOÍS�é¥+Ÿ;¸šÄ�·oå�ú óÔK‡/7ÃåNjòîÆž½{oJ×îJäÔé³,†}¾þSÿ³GïÍùa8É£râçàѯٶÞyïd˜‚žOG gÜ)>e!YUÑcø2õ­ÃûvµÛ7_éÓ¦ÚØXÒÊO/�Mzt<\s:•XñÑ¥+|<°yÕ%ÕÔºŸëb÷4¶AårØ=��Æ…\„+† šêôg¼Î1= æÂg¼e5HÇHG8Ÿ‡ú@8�×0ÂŽW �$;K^lœ.»0GH.ÐB8ÜñÆxÝË�-mZüŠÃ¼ÿ—þ3üè^˜ «mX(ã]�ÙªexåqAP�‡ ºˆs>Ê£¸ °¦ z÷R"¨†±ñâ |¡€Kj?õÓ®²yîj"‚Ƀ %0U±ýôßRf‚¹™öa›uÙÔÔ]Ñ€�>·3QH䇯Q¤DàÜd‡ûûøÅ[c'ã:|p8h4S↾§Nlá‰þ]×å<óƒn�!¤& ÷ÔfÎe]J WÎÍ¡qÿ~lp³$TwsþǸM&Ì8�¥ib}¢+ï¥1¥V«߱㠾¼ë)�¤C̆<¥q×ñ0ˆÓ¤×Çi朖ãBñÎNõ™x©Ï�ëAxnusFRÞpCgï1qÁ…±>ùrš_`sŽ€\¹�Ôn‡Nâþ¤ÉèÝû1Ûóèl.¾¼ö¤‰¾@-ªÃSÿußÈ"kszq¹ˆjå6[ÐŒÝ ë!›:õ©[g�- ñþgþŸÑ'>ÿqXqßÁ\PìØ"d"YýÎ…$Í�4¨8»BÐÚàì¸�Ê׿6øî‡Ñ^ó;/µ\Óe§B0'ìF7[ç~ï.Zn«oûçMÓÈÐÐŒ…ÿÈß½Ë^ý[¯r/Œœ±HN0§Úq8Ÿ °È@°�7‰`<õï ‰üÛ©Cð¶HR¸†¨+ŽÁ 31àLÅçôrü€¥[4ØÕ—tœz¦[¨±GÌ;]øH Ó‰©[8`Uâì½?:Š›;®HŸÎä£Îx¡³�†¿åô+ž4Zâbt�f�zZÖ™¸tÑÖiê¾’™´3ε5ó=tÔ¼ é=¥º°ÔÌÚÞGŸÅµÒ^úöÙ‚Ë~唹½P,+#ìßÿæçÏ8¹}‡>cóVüB½»FÇPP©Y¯“ÚžVê´ªûx’ÊߨØ@½G׊\hÁ©¿ôîbÀÏ�ä7QÜ5͇;¢3¸rØ•Çv¨¾r+à ¨¹;Š?áå“Éâ9¥N(�^Ë tñ“_êwy±$¯Á1…½XCî ôL�¿x¤Óå¾Ãɬ\÷­/ÿ÷w=ð¾OÂêŒTo¼/³¨ BöW ‚꪿ ¨Îfª–çBw « ¸(¨nâÎj ª)´¦°—{¹"ÒÈ´S¨Žÿ™Ú‚Ã˸¾¿žáRßÖº~.iÂÌéUêß5—’\O ¾w©ë§¤�ÀjàØ7¬m᫦ä|Ú]�z±cÚBS@/\›7ëÈÕ·¼q�ý¤?)sýïIñжAáq’©[ƒhd¿éÕ˜Î÷¦ ¦h˱Á¹âA•ÜÆv)ø´ÐØéRwÎñø’óïýŒ·ÿ”&7èíúØx›i|*oµ|˺4O“†œäwR;ŸãqVn¬‡ŸÉrÈ Òkœ§Éè°Á;¨ós ˜Á �Q8ÍÁº† ¯R†?Ì0wà{(²˜àUã ixwj¤ÿ‡ÖõäïÙ–o=€güžIjVì~|·]{~�Ä<]>ë1'E¼Ò#c8Wåü“SU.¸]}šX¹`ÞþžöÿÑ™žCyº´M‹ýèÐV+¶®›–°.ä@Ôœ{éimpî '†pq¯ *öôç_l7¿…ï››r¤þ#ÿj;~·íòùzÑ´-ýk[xÙ®?O§¦Ví·Ã;�Ng�Šì±ù1{ÉÏï�|·}‚ÝÌ?r¬D,GywgQCÒÀ1Õ ¨£ÚÈ’½;?½o )©Vzö¹0à6�Ëq,®?œ"Œt¬æÔ‘*•1O:qõN¼;çÞ¯ \\ðÀ°ÒO”éL�>“å®ä3WÝÛ?¯¼éÓôèãÀ/ xb‘jévœJìSÿtÇ´6þ¢Ó¥ætƒ œø5÷Å¥X×.U±‡?ñ«öÜýwb³Ãìÿ„~: ù¢ýð<ÎàÌw;n¿ÿ]>)¬®� ÏÉbÝ­ÁùA' WÝœ† æÎý&ÆN“ÍÆÆ Äc:ø2Cî”ÎóÂÖè¢;kçM³Ö\ÌYs!oÅBÂé"ºÍØ�ÜŒuiŽžlÂŽè"ŽÆ(@¨›µR9c#£!.³~¬PÂqó#83co%¬T«V«VPÄ‹kÀ“\ÔÇ5¬M#Øáîô0  ÏàžÅ=»â²O¬|Åïý—F*SÑŠŽ em`(�«hýÃÍÖ?ÒbƒåV+E-VÉ´àüŸ&Ë´-×V°¦Žœµud¬£�çi‡¶ %°y8«º]G †qžS�îO;ú©¤cJn0@ÀÝäÂiPØ=¥pfÛÑÈàS§�r¤ïÀiÝœ•¾3éá¡gÿdV“ʉәC2«‰Sd �Øz÷ÿÕ¸a"ÍD2cJ'N4v“24&æ©…Ô©7ƒ§ú³ „^ù)fú4q¸Â¹ÓHXäÆ,Ž[ÉØÅ{2°¹tãÃÛ9�×#HÚQ97 ÷ºEÝÆ93ö�õÏ tüßwßÿW¿S7˜nÍHÿ“c©õ�§iwOãNy£ó4﩯žaÐèž›–# Û•wêyÂ�óÎ!<{¥á4¿œÆvPWYÜ\ƒc*@Lã¯Ç9Üûï¶÷ñ·Ù>½Ä¾ñ'7C8ý5„*áôÖ3üX¶c{þz†ã8ëàÓ¾ÃÏOyV&Þ‚waŽÊãæ²˜ˆåð>”|!ÀÜ4À5°l h «Gš�=÷ÛáÓŸîèyø3Âi’)  x�*õÓ[ðZL/O†v±¯ º¶µ§¿vÝ\wÎ Å_•t?ÿ?ì‰Ï.²‡þê§9óž IDATÇ §™Âï}â×�_hÍ„Úõè@°Ü77sêxçqûê§—ZÿÁ™¹HN2&`n\å�“1æõ|dö?ôªM›6MIn•è©–ŽÕîŽÞSU·k4L-™\É-5Mé�û¿ãVÞ?…Óî‚L î1Ep÷pd`ëXÀS×ÅvÞçW~®ËõSʤp~ìÍ0#<÷ìÍüs’£ÄÎ{¢ÇäJÃðÕ̓ê�=°º¨ÔÜüæëlïxøÛñð»æwÙ%×ÿ7kšwûÙ5ëþªå£ÖùÈ[í¹o}ã¬ã>¼ó³ù+Ù7[†ÄZíë»SÎ(yÀ�ÍÆñƒÆl¨Þ%œÎŸ¥}bA!Û‘îi´h÷2DÜù2Ä»¦³¼rYì†ÊBx�…=¶McKT »¢+ØJÌE*wEGQ³„ÏÐÜÏîN=ÓÃÆ�.jÝ£Kdbî’GS÷Ï&}´H Œ™dvTÁÒU¾üšŸþÂÁç>¿'õuºûîGÿâÈÚ«o©e³Å*z.ž‘Í�áåLÆF³È~¨’ÁÎê—á� [�}Gš`gu¡jEìªn¢€‚öQ,¡y ˆÛU ç<«šÒd×Ï3KPÉÍ?œéç@÷—Oé¥{ï36÷Nr6ë;üÕS¦›–£ûŸ?­›ÙvP«ôØáÃÃgíÖo~Ó–_óuk]ôgì÷l<ôìýðÙx“8�øðο�¬úMß_qühì¹Øã&ý®Óùñ¤ÑE}÷CâÎ9ã‡ë¬ýÍéi–zä–èý-µHŒiíÆ >óÁ›»ÔŒ9eˆãTjåSíý¤ft˜êS{ɸé ܧ3-o[°÷ë¯Ü=ƒ‹•¸wßç‚¶eoMÓÆÈÇå3Ml£ƒ†tR[·J5©Ú¥füÔ=ÁÞ�© è= ¢®ç¸MSÿŸ„†x¦?VSPí�÷â�rçt2Yq_6”‡Ÿ�ïþ›êá_³=Oðg SZMLºž§™Àί¼Ëæýò[-“›7Í!Ÿup¨>nÓ™N³ÞQϳÌs¨\Ü�ÏyªûŒ«PLI GÉdÊC[Þ­ïÏìßöµÝ›7_?“ííüÜ æXôvl÷ßX·úVëiWZL/ÒÊÚ€¿`<¶Ôn~ãÖ4…£§—òXh<»ëé?·]ß{†'ߤE»-Ÿ}™ÝðöÝN, àuû~øNÛzÿ”Ž·8ǘà½sÄúð»úÕ¯·+îü×YÝÁÎy!ç~ZàÎ16Œ«#¹�÷ßöô¿~ÿµà\“ayU—záq,^p 9Oêløà¦T{&÷[;¶bÍu¿/¹êý^væ}»u µLÓ­3KVO­]²øQ7uÚ &Þ¾:²gצM؈vq©‹K@í˦ℼô¶¯\`knÛ`+Ö½oZ;£é¬½>iûÿc,¼øM�«’çü毿Ë^öö_BHÚØøêìªzK™.44Xx;/„®§Nx„†{ñ!&úÜé9-„ÏÉ9ÓxàΔîœá‘Å=¤‚é§éÇX„ÖªxÙ!V¦U´>ס§cC„L�ž×àxMèiÀg4_Ü]#Æ£ÓáNEkŸPgá´N†‘Ø»0"ÝÎ-4™uw~ÞûüÕ0e;Û‘=/^õnþ´†Ž„çdFÈwù±È yì7Ž p…™ò át€sªsØÅ�#@ò9±qå!‘.àPêBrHúBÅúñH•&*‰çfë×~mÜóćÞ]}6:ðôù<Ãjb’ܹé{¿ñ�Ì'tu Û5DZæywL´:oÏ;~â>›âªÙ·ÿòµö²wü­Í¿ä?Íhúû»¿j�üÝïÎh üG`Û£á–+¯á45gÆ�”F݈L“çq &uã;èÄç8Î/-è$ Ü=qìÆ§§½ó W�AŒ{H}�¿7:OmR³ôNó4¹Î ÂMEÔ¶ZedOpà™ßZ0ºë‹SÝIâÂ9‹�`ÿ®‡ìÒÛàÓ‰LJàéSêÆÍÔ–F�™IÍScÚyo 6‰¶Á_Ý 3�<ø²õ©ý¸àðàÒŒ Ü" Ôé[É)ŒvµÚ`4tìkµò¶£ƒŸÈØ»ká·vê‡dIÍ9‡ÙS_ºÎ®ÃÍ¿ÿâ¼$1­o¼;™34JSÏ—oó˜˜ ²èª(œæ ¸Ü£R߃ÑÑVêþ¡ÞM›úÎKâÏ%Ò®í…kïפšé¹„|þüò°ƒÝ_³�î­ÿèÖ¿w—Ù} R0“¥¢µÁôÒ}!­ zvôÛ7ÿä6{ñÏý¦-»æýc²‡éEzBhƒG¿nŸy¿m}ð{°›ú/¨¸–üÔ5öÒ_ØvÎãÉñÜ7~þ¼¼�™ñ­÷7ÙÕw½Ì.¹éÎôÚ˜c åN4ƒ¯lª »ŸøÕðÙû¾°éÁ3îŸã §ó/lÑåïvÆjüŸ h– ‹S{>Oç8ŧYºÆàýTÓ~†åä^©xvÂi|r>Jã 4¸iÏÃ>§g¥ºîûøV¼ú­GmÅu�\äÇÒœlèqJWã£`ÚÓ¤%9«ç™ÞÜzwç»V9’{ó0ïp|@ø“Ct�ça*ÉlåÍ—ÛÒ5¯³¶å¯´Ö…¯Æ uöÏká.iþ4£ÿà×­ûà“vèI[0ý»�VÞ~¥ÝøÚg‘GHN}`AS×Xà©ÞÛ�·÷�îaé.øädßí–ÆÝéÁó¥ýŽiž3íΚvBj/œæ"ÀÉ/¸; -ªŠV°{òY¨ñU&…Ó8Ȉ¿ÊÁ¹èùðª$ì¤ÆöiXb5Õ\ÌRH�ôûNz>ÔŸMjàîü`kMs蟙C^ÑžgÞÜõÈß~.5=Ý}õuo¹:¸þϱ«…îÈ_Ì•.wÏbçϪƙÔ9 ©“+ãõO8~ÄpDI\©Z‚ê2¤Ò£Áó©ë;ª‘mÏÅ÷4I6Ož¼òðNã »²}}»yOÿ‚†k_û&[sû”ó~òÈÏÒ†…]ÚAùfë;ô {róßMùø‰õwÿ¬­½ãÞ³ŒùܽUˇðó°§løø¶ó±ÿeG·u�{ xqåšÛÖÙüU/³\ó%–oZaa®??˜�Ÿ!tà[œ‡q/ !âîú-nã8íõQmW¿U†÷ØÈг6täaëÞû�íw;§!™ BƸò§~ÿSÖ±ôRÓ‰½-»Ûzæ,ùä]±GO'`~b+ZûN®|ŸŸàŽìHÌh㜦–i$ÉÀ�Žé@ј®F}ê�f©Z—ÂÆç˜?a­¡mÅÑPU‚jå°•‡·£ƒ;ƒ‘ÁÎx¸gKùض}û÷ï/Ñÿl©5oz/Ρnšä71c¹ô,�›1#Ÿ<ÕóبoL|ƒƒT›ÞÓýÜžRMUƒ8îâê¾�îÃà= _ (xŠjA¹¼?[.w†åê¾Z%:‚/{!|jê﨎–6múèôÏ…ós¡é¯Ã[ì²ÿã%»{çì‘¿ÿ�3òsvË›þ‹-»ú}˜5Ÿ{pS�ƒ «v2 sGyø]ÒPc¶Æ ÜOPx$>þ€•Ž?–·‡†vwv>82õ˜æ¦ËÂkÞµ5η¼ˆ{;Ø6)@ k§þyV?ù²vÎE"ôú|ñ„;ž+ƒ˜×Øèð~+÷wb¸ÏFŽXy䘕†û­gûOõ³ZX ‘imÐã µZ¤Àr¶þî7Ú¥7}?!^žN˽<²ÛŽw~ÊïûºU;Ÿ¶s�o-^Üj×½õKÖ²àǧœ>öm}>ewþƒõmÞdÝÝsçHÙW-²EW¾Ò:–¿ÂZ—þä9 ß'@Á|wsqðèíƒ�_Zï|â™gööNprF�+n¹åêêµ÷ïþXF/Lµb?ËVXÇ’uÖ¶ô¥Ö¶äõÓö ᪣lèØƒè̾jÇö?aúöºŸfÌí·\j7ݳ ¾è¢‹wLXÍÇ´ðS±uêΙロƒ Ÿ‚iÞÝÐç°s8�‹ÂévJçp–_>Ç�Ã<ÎÂi¬øç^|ˆæÍoÜpÒÔN§BXÄÏŸl¸�TøÕ ^“„C÷yAbK!5®º€:édüNê¤Óq��ïZ|—8rù„ÃY!‚ºJôÌ^0uà_ÿ¿kêVÒˆ€ˆ€ˆÀ…E q€;Ó”ûÁóL}Éýì¸pÔ)“À–¬YbóV_km‹o´–…·[±íz+´Lò%Jêåìï¬üÜ%ÍŸ�b:j¹¸z<3zü;™Rïw‚áᑽGº¸cîâUê.Þ²UÎDàB%ØŠõ«lÞÊ›lÁÊ×Yûò gte(¥¾Ç¬wïgìèÞoÛÞî�3&?YpE»-Xu^u„‡Ë,(tX­Ô�/ÎcÃÏQ+•ŽY0ròœãø5ÏN¾@æNWlYërkmY†/ °é©8Ï2ÅùØA7ßrÅE¾bÕF±9p‚Ï’ÅÕ²U+øqääWǬ2pÜjƒøbq°×ººøåá’ï µÉ(Ý œËäfbXË37edlÅŠœ•ðv¿|P@£.Z¾ØŒ†ÝŒo=ZñíÞÊ74`CÜÔW²j¦d=hÜÖÉŸ¡Aº:Gò²+×¼þÓ�;ëödÂi[*¢öBkáA9./êùóHîJáQ^8�±¢JSHMuBlçÁ£<œhûß ”®á iÆ4ô|vEÑLÃ%¦€=ÒNHMlvQ‡PãŠwPCÚÌžÑ} Ÿ¸c„Î Zç€÷DãŽúpÏéGCUgƾûO‹xŒ?”�¹CàÂPŸŠE[�³ùaÁÏ©› øÕ+.ìÂv"Lþò¸ãE%8 .Âî†à ±Z±hdÈÊ£\@ã— ##x£vÙšËe,šÓù6f–c3ÀS%Bv" " çƒÀÊ&ëÀ.Ñ\S“Š­V,¶YXh± ~]1ÚÛkCÖŸÅ—‰�<®ƒ}º”ˆÀ ˜7H�'ÀŽ1Âä÷Âÿ©Ù¡Ýñ¡?M|Ùmk2k_ö78ÚĽ”-Õ¦bé±g ¥Ç„ÓJs÷t–Çx¸Ó+@ ]ÀË‹¸ç!¤æ9Ón_�LŸGjDXSPáƒjÏá~~H3 —q1^'õÐP˜LE³TŸˆ¤ë«:ñ…Ò‰`š�Q%7ÿ�|6„ë­SGŒþ/½æÕvà±ÏŽó£�é$€} �5ëµé9Vãøt&Ma‰€ˆ€Ì,�Ög܉{NGCÌlºˆÀ\!@É¢ÔÅN`Ïc»kÏ~ægÜ6õ¼RPë…Â�FN` «Fá´;[:¡t!‡/=óÖ„«PÈ[>›ÃŽj¿é…›]x2GµŠ³•qž¯ ª8ߣ†£;ÜyÓÜVí¶�Ô'RÓ©èÙ»�ßÄ³Ë l]˜°ôwçË–y7¥îu8?´ƒúüpŸíX³á oÿž{Á¥´N¢‹�D�KM*Äņi'œv/š9Þùÿ·ízìƒ6Ÿ;¢Û‚æyóðÞ£ Nhê°B>–G2ag~”JQ&‡ƒ§+q5‹S:r•¨�‹Ã(A!àh”0Óg3mQ�ë³Å¥q¶°"ÈçWʦk‚lá²°!=.y�,û�ÜiáÀ¹I°¥î“<¤yrBj¸c8u¿ipD�oº:ñ®›ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆÀy" õy?‹Ñ™»~ã_­Ðzý¸8a-e½ÔRŽËó¦y¤�ìÈ…µÁ•½�½oÓ®M3~ÔÉúõòAkv~ÐÚ¾6š·ô�6oÙo Ay—(J—Ý}ït]ÞœæÇgÅI£½ ÒŒ¥÷º¯äx‘b뵩ÝE@D@D@D@D@D@D@D@D@Î ¨Ï÷Y‹5óÒwü¥µ-|}º³ØEì%º^† =…ÓÜiì^„ˆwÓ`7´å÷?ù³›6ͼpšéÙ²å^¾ápr}ýúõhkâ×mñÚ?N­†Ô6;�—?»‡$/N_—J;×.Ëþ€�Ä#¥îóÅ5Þ�>E@D@D@D@D@D@D@D@D@Î�A}¾ÈÏB¼¹~î�Á‚Kÿo'“m�ÑRëiÁ4…ÓéÎé,^|˜‹†¸ï;ÿxÿ,$qÒ(¶lÙR~öËúAëÜô Kâ„Ê4ÇH§8§BæI}S�í3ëóéõÎiƒ¿ V94©wŠ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€Ì ¨g õ,G´xý2»ôú{™lrÆ4dµuq-,ÒsžCé‘ÍàÊZ>—³–Ý?ø¤¶ît–S^�nÛŸ|ÀŽíþ½qBé!sÝá$&>}�¢Óó¹ÑÝh©³ñQz�Ù' õì3Ÿ�ƒÜ�÷Ü7A$ëâM廩pÚ�7 uêb>k… z~Ûc_Þ=‰œJÍ�›?Ä]Þ<š#DÍ.#éó‰!¥ÂiÚŒL§N+ÃÛR­î" " " " " " " " " 燀Ôç‡ûŒÆš»ñgÞfÅ–ÓH’ƒ1Üñ˔뺗!òX¦³Nç ˜ÆÎéB>gÅ�C‘ú› ÷§Ÿ¾È¢rý8¦Ÿòê“*'³>Q$�§çXÛñC_?i²˜PÏ æYŒ¤}ý‚xÕ�Ÿš(¢M»N8â…ˆîX�T8�Åîi§!¤.÷~mS;¥¨‚á�ï1Ýé®on§v›ª‘)—/쑦~ì/5÷Á;á4´þNWP]�y[}Š€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€œ/Ùó±â�Ùu·¿§1ät³±èB° á´Û9�#=x¬GÇzyö4®\&cYênô?ôA¶°€"hþQÌìvPCÊì͘d˜;¥Ó¼Ot‚—(Fû7G{&šëYD@D@D@D@D@D@D@D@D`v H@=»¼g8¶õù`ñš_§à–ÂY/ Å'ÿq…N‡É±Nãh�"/ §Ã Žþ­zdki†yÆÁMm/áiæ#f^ å}ìaa5ÝÄdª§óÏ̬Nf%3�Ù# õ챞ñ˜2×­}íøHüžcšñx “‘ÍòX¼‚é&'œÎáj §½D·µ­ídbÝñAÏÒÓÚ[^ÙaA&Ä5î�v”P»÷%º$Ctí$ÖN~]OUr�Ç$»¬‹ömù_u‡Òˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€œ7:ƒú¼¡Ÿ�ˆW\ÿ§^ºìö{á,„¸N8Í�ÓNcç4wL§Âé<„Ó'œ6«E± ÙêE3�²³2¼ôŽßõ¢g§‘N^|½¨z,\ŸD‘‰»à&îùÖ¡­vžÄ©ŒE@D@D@D@D@D@D@D@D@f‘€Ô³{F£ZzùË׌Ûþìd¹<Ö;§ùRÄLÖ ©pšzž9�c=Üd§c\•bëÕ3šÎ3|õ­–ÙÂKßS(�§­—Y×…Ô§�N#¾FÛÚ®oþÇ3H‚œŠ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€Ì  ¨gî¬ݶbe}§0#Nºî¥ˆDó¥ˆ<ÚêB&g�;§)˜vmŽÚæ½tVÓ}’È®¸iÃâìµ/ß6&pwÒv·ƒšÇ‘4 ª�͘CötóÃÁ�î]ÿ­{Ë�$J‹€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€Ì2 ¨gøŒE×Ô~y=l/˵À §ýÑ9¾Âi ¨…ÓQ-ª §�ÿù«~ëúë_ÝRë}V!�¦Šré ²io^ê{äз>¼Ñ=èCD@D@D@D@D@D@D@D@D`NÐKçD1œ{"Ââüë(š…(×í.æ±aÆ푞;]€�:×pætÄÓÉÅ— Bkð4/¾ùµß¶§_r‡ÙÆèÜS6õx¤GöŠ[?·Ì{ }¥‚fî–viK¶M3�^H�üÒ.qÌ{zѨ®j•ãáã_{žg5?õø¥˜”€Ô“b¹ð ã–ŽÝ‹!±u/ä¹Óx1"…ÓLóªïœFö(˜¦Ð·æîOSáÿA¡åÖëß2ø‘Üö[þó¦M›*Îj†>¸[{dÙU¯Š—]þ+´ÜèÑâric¾¨I%Ò^Fí“Äã–ÙáÌ9e8Qµ'xúó/êêÚ4ÌG)�¹C@ê¹Sç”’ Vëa”ßR@��pÚ둜; 5Ö´wBiœ;í„Ôð'Ra'NSѾôÿªÜòŽ·]wéî?ŒŽîûòèÁž�;vÜ7šZŸÅ=\yç�…b´|aؾøzëXúò uñ›G²ùKÆâ…éK÷ƒ{•Ü‘øúîé˜fîÉ ‹wyóç}Ƶò¡â㟿¦³óÉã©�î" " " " " " " " " s‡€Ôs§,Î-%£ÏóÌéBèLÆ §ýîi¾1c'Ü�!œ†0—/EäÎiÄè…ÃÉ'n`×UämÉÚ÷‹×¼¿p�Ùú»î)ÛèÐSVÄUÚ‡0†Â¨:×âaÈ‹Cˆ…›ƒL®) ‚–8“oÁ›ç[¾y�š¯· Óš†ëcKâN`I9¹“;SOÇL#”¦ –=û—$Òùå îxG¬æüÁëp'>ýºÎ®.íœ&)˜ƒ$ žƒ…r6I †žãÎiž=íÔJóHwæ´Û9¸˜ã(Ânc €)¤fLü€t7ÑSŒ§ºr»«SwX[ou—÷å¼Ñšþ\¨Îmb‰›W�!¦fI”Écê�úðÆÜ9äͧ-½S>Ma5\S:M¸QXm‡·¿ëÐCŸø B`PR" " " " " " " " " s”€Ôs´`Î4YµÞíe‚;¼€šÇ{p5ÔîX­)©¥°9‚.Õ×ãð’j÷èÅÌNd]—ò¦O“�S+†Dý$N\$‰µÓÃMÝ[]“ºJÒ ìœèÂèÀm³fà>ê(£GKÛâ-Ýs`ë·¶7„ ­ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆÀ% õ-˜3NÖ�­ÇÂÚÈÎL¡õò,Ó¸x5wS¸KÁ4ÏœN_Žèv'‘PÀ›ˆ/úuÇ€P ¼Qy·�gì%ȉ¶~óòc<¦¾iS¡î,5qrgçîZBO4µ¼øéóÅ;Ÿ£ªxêç÷>øéÏáÁù¤©”ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆÀÜ& õÜ.Ÿ3J]Ðùƒÿ˜¹î•ßçËs<‹Ò[ÊoÝKá4Ô©øRä !´“öŽÙ§béôžúKÅÄõç1/N:\Du}ƒcˆ7pòehéŽzï>5õéjŒ�9J…ÓG#vpë­m¿ÿ“���#>D}Š€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€\($ ¾PJj é,=}ß#­—ßòùü‚e?Í£=ø2Aw¬¤¾nç4Ä¿”OSàìEÀ‰ ¸áV;‡Þý¤Q{I²('Z§ç6µ“7;ë �NþÌc;\ºh™$"õNO4öâvhjÕCñ�-ÿïªò¶ÿýàƒVi/%" " " �¿ “� ¨/²ÂîxæŸÞ¿äWËdÛ®§ —‚i·ƒ:É'…ÀT�Ÿþí‚Þ�“{)¶f;—Î1w.{7^Ä�êy§pyLM؈=ήAÌ<æ�âg±ûðzÚ6ÆÇe;zàµCÛ?ÑùÈ?uÒz'?¤D@D@D@Dàb"0:tðbÊŽò"" " " " §# õé]`ö;vì]_øä­ñ‹ßþݸÐz+eÍ©„˜Âi>¦ræDþ;–Cç8}L\Ãݧ~RÛq¹p¹¿Ù…8Îu"rvÞÒ0ÜþÙºtA˽Ýþeް¯Œî´ã]•9ºÿ«Ûþ‡çHT�_¸ ?|1fKy�“�€údd.`ó-[¶”mËoÞ~Í«Þyw´êºÏÄafÞ‰¢ã± 6Ú9}Ãj/>s{r]£ðÛ‰›§9Ÿ Š>!çbtð‡qÿÑÿöu»xtÏSO?}ÿÐ ÍnÚË IDATe " " " 3�ýG÷ÛMs•7O@êñ<.¦§ø¹o|ä«f]õʶæ_ú6k_ü–8ëeÞ(6ææg/VN4“� {º©+:õ�49q´?Q:1†»±ãA`VÝ”ú ‡û¯•úžÉöÞºùÑ›»Í6j‡t�¤4" " " /LûKvøù÷ÚÒ+ßóÂÌ¿r-" " " "ðB#0A¼øBËþ .¿Áå·¾qevÁ²õ–o»ÚšpNuSÛ�–o¾Ú“H^ž˜ì fåH+Hº :%FA5¯TÅq­ת‡ƒZ¥Ëª#ûltx{0ZÚÕJû3¥Òá ê=Víîéݶía :§»ˆ€ˆ€ˆ€œH ´ßøv[yÓGð-x¢5Lâ¨l½û>f]Ïý½íþþaR™Ô� E@D@D@D@D`ŽHå�s<™JÞÌØ�¹å–]á±cm™–Ëå,›Ï´e£¨dså(W*FCùÑ(7XŠ …–¨¥e êïï¯á8¾i^ç™/ Å " " "ðÂ#ÚÒ¥M–]:ße} gØÚ­dû÷SÍ9˜”ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€\ ‚iÉÄ;>’³=­Ôš­V ¬dGíÁ�#Ó¶¸( d§%W»z›­©²ÂBüeÂyÖ #\ ¨§®�Ù"cS7ÄÆMM�Ï VN{:û‰îÏìyÃ?glxg»Ý:Úg7F“z¾{c»Ù‚Q»ï×G'µŸºáéórׯ¢µçìK40i°Loÿ³Ö¾¥Ïº×çìªå5ûè;+“ºM 7n í#6TÀF¯jj|ö÷IÊpÆÐî½·6å0™¦NËÛ§Þ¦ãêÔƒ¨;¼kcÖ ÖOCÊ;½×½œ^ƒômè+˜uÔìÞ�ä{ª:ꃻû× VZXóŒÁhý`ò¦É˜øô¼òý6¤dÖž±¾Zh÷ÿöÐIÓåʰ€2+Cnä;r°ÅŽÛ âd<>�tÛµ„<6”)Ëã®�ÏÓ…ÿƒjZÆÒõáažk’ïù½¥/5‹¶ñ: Ý�Níø¹{Æþ; 6ÔÅHɽïAÇ2®ŒëÝû†I÷]�½aEÍ ÄC–µùËGmÅÁšmœÐèÆB˜D‡Š PIkpÏcz6bª´Ò{·4©·×pZw£bÞYžtÀté†� èÄç÷†õ†ËÎÕžE›v –Ši jL—{HãôÖüdØîîòì´ø »�EÁV£¡}¹ ñ@¹N»vcX¾Sð tl f¾³ˆ\}HÚHò_DþÝ =ý­*D®/a›`?³ ý ë.•+{rÅh–·¾ÁØÊ­£>Ïtà¢M Ö3¾jyàû¦$Œt‚�€d͸¯‹­ï±¢uìñŒõë1ÑC�wÁ®éê硪ьnY_íysfà¿“õxÇž ««ìÆMP`KVÝÇ�wÖ Nº¹c[Hg?qˆì–wdma{Þå“<¨6}ìQ¶tCÅ jªXïXïÓJż±¬ÛV Žm©¸|¸‰þPÖZP‡¹˜¢Ÿ´îpò8ÿ•¡«wmà<Ú¸ 7ë»[8¢ìYnyGaÒ,p“¥Öñ} û*–eï|”ݽ~Èø›ŽÅ¶êZ˜³m÷�câJÆÖw*Öù}£¡kSôÃzR=V³ÛúÉïƒHÕâu•¤¾ú«îgY/P30Që PW#ç�eÇEo~ña’š)TÍõŽ•O«óˆò˜¸ ò}/ë^àÊ©|0ãx±m“ѦMæ°í²LDûrõý!™²®�ÃGßÉÉ)Ò‰ºÛ×âÓÙ1TqúC5êCz;|ù ÝT ‹í†“gÖ!*.*ý¢Ù»q†I}#÷R�wçø>ÎW°ÙŽaâº))7Ö3–ë—7–ìî_Ë[Zn,÷ÁA]F?Â:_»4 Ž`Ì…,òoc7æú8|Ýeý^R-·2oq©†¾.råÅtuuUlÉŠ&LáG\Û^Š´ån<ê´ãÕWrb;0pýi¶'ãëÊq0©ÇY”OzW® j.¯‹Û±@ëu}hÒQù¾´Œ1‘îkA14êÛðÂØõ·ì+Yþi[f~“9úú´Om*X¡Äv…òÄÂĵ5Ôcª´o`ÙøvêÇÖ_Ö�ÕpÓ‰‹õsðê4úŠìBä‹­Õýe;¸"gÅvLÚÑžºj®l_‰õeF¿HÿHP;#ç£MÁ8ÆUÄ×Êt·×lp·¯­IÝ\ }ÓÈzÊ… Ýçšb+ =PµtÄ®Œm0NÊÛ÷Î>Ç_æÃõ©X„2T½[‘Ï5‘Ý÷ke—ïÆ4¹ùÊwاø4¥mߥ ¹Ö¾Šuƒ-Ë–ý#í�®=†`Žx]¹÷"�ƒeË:MŽN¡_ì[�±1 ­°fØ�/­kBëë ­£q®Ã<`?ÆbÔ?~bLB{.�5óÄq4í£_éFÛ„4°ý¸ò…²åxâÆ´!ÖÆ1ŠúZhÆxÑ5jK® ]8äoW¢$Ð&Ùþ¸§ZŒÙ¾ì°Yna›nª6ÒYf´j¬‡LË#ßé'�—õ&hʸºHVTL;ù³®Re�§\1¶‘‘Šc–-,7[k;ø¢ÌSÅ]Q½ŽÓ¦Ô„T^o™ò3À!„ÿB{¯+göñƒý¾NÐ-ù•[ÁB¡Ð®²\n·U*%ÇÖÅ¿mî}=A?!'ç#Ï\ýe=a[a½f¿ÌzHeÔ‹–‘œeæW]½d¬•[-ϰ‡Ác1òÁ#ë^ZçXÿ™ÖašU: à¹ÌJ¥ƒ¶ví°ë9gæê%C%W¦ÌUZ!ÅMêË)ëê}�GšÊM– ®±LüÊfЕçBL/ë8ÓTiö}Û6ÇÛµ-è· Œâ3ˇq°~²Ûдڣ˜ßu /«Lé ¤äYðbÍZá8Œ¶ì³ŽËFÜ|y1úÔá˜&«nœw}LcýIæÒœ£u´P «®Î´,(¢[aù »1 ?t«åsÛ,“¶ÊH€þ‡ý+Çþù.glw­í(ß2E(©ò�«£.Qø`}ë=œ·æ8BÞË.Ykq­€2ít\C”s-¼K¸ã–­uÛ(¸ÔUS»…Ñ�5Fܸèê@1°¡Ô%l �½!µ-(×O¡¿iFúX—sƒØ2šo²jp9ÚÁc.H7Ž]Z5ÎYÙ—V³-V®VœŸÚR5ÌZ_¬„Á‹,o²8·Â¢ sxyåº a£¬¬£Ù¢ýjn!êĨo¯,·°¿j•jÙµ·–ʪv�ÅU¶ÜíHiÚ„µ±?‰>ô0Û�·#E”§ï³K¥>kE¿¡®Çˆ§ƒ¯ãÖƒ/9Ž3Ey„Ù4�Vl9d•þ¥È÷�Q稆Z†Œó*ö-œÇ³¿ †ÐÃ"½åæ%ètç»81‚Z¶€G§å*7Z5~ý0ÆŽÑèCØ"›2óÑ6#œ�v’°ÑJÅr™…ÆK,“ÝŠrGûƒ½ë;kXoT[­);wË,ö[¦2 YüU­ î}Õn7²ýŽ˜§ ~�Ž¢/àËÌ•†—€Çh“e˱eòÇœpßeæ…óá ò\óûS— b_ㇰg‹å œö[¤s�s¢ y¿u¾{ãJ4‚øÛnŸÚ˜|û“é—¦ê1,í8îÒúº�è4Pub;„Á�&ÀÄ#ø�r‡l°y¤áÛx2›DNL¿Í㤘ßè0M[Ú vïo ~ ÂÜ7™ˆP‰ù­$¾CÐs"IÁ 'Ž\oÆÄ¤Ù*£ÏÚ×ÿÇÁ‰Q@ÔêÌFs-WæcA¾Õ=ÿô_nµÚ"tÊýöùßßS÷Çoš8�ãdìŸ!°�.àù ÷B@EáƒpïÇ·]øº+\0ä&áŸlý,vÞ™±K.y™eFž¶¸yž ;÷¢NëÛáÛ¶¥ä¾¢‹‹œFÚl:œ ˆ× +±8FWøõ�=vÏ0<–0±Ùè.´Àý¡žA·¨:c'8A*Í1�¼6¼�Ü» q‘aªø y*ü¡™[˜ö,´›QÆuÁg?ËêIt’¹u¨»É·èLÓ(ÔßÇ7³÷l\á&–é‚“i/³–ö[÷_c1†ÉÒà²Àöb³�ÁÝË-[Z‰­Ó¾ºñ0:Y³7Aˆ3�Ycy N…üAë.÷ºüßu¾L¹½ÅÖ7 øoØX2¥Â²+n±b“‘µøÞ¼��,Áw™uØÖ� O.êCÊ�"¦ªÐPHPÄ7üMÏ—m;aíå REûê÷uâu¯E§Üc_ÚØe°+`dä ¨�»…@®÷Gï°�bò“ 1HG*ª `Pv“c�h¦ò,¸HÀ„´Úç¾�"“°çÔ¿7ycù¶aòPC+Ì ‹~2>:rüVêˆe¢µö…?|ÀåÕæ>{Ç;²vÂ…êè:‹r‡-Êv'aÐF;,no³y£‡�ë;_ͪ¹ÍT®Fº÷`òׂA£ø1d¥þÛí`÷‘ºPصKËÚ~V~“端F&®Ä@·ÕÊ�¨¡˜zd –yj¿•®»Ö¥(Žj˜p6;ý‹«�ÛcÜâáa´)¶*|öucІp)ó z8ꨆv÷[6‹´¢¼ã<¦6-‡-šï8ö3­ë†\]ûj·òîŠ�Ì_‹ðo@º!<Ê~ߎëqñ•‡ªþË ô°ì®Xµ™&Ýö•ßíuýÌ&¦¡á¾Í-ö ùo–Q+8aÏ"M™Úwm½0®Zs‘=Ð,f =îµZSÉj¥Å„˜øÂ=iN>òµ•(—£ÈÏa«BpFÁ<ÙñfÖAØ„þgeßéÒù†�7»A>÷º:ÁÍ—ß³Í^÷Þ5˜dw»ÅÚp˜¶+ô­D�¼þ³¨ÚbùLÍ–,ÙkÝ.&ˆ#ó0ް€J&ñüz–caß‹‰}v¨¦ò�–ZŠ ó67A,#Θ}7òÇ�ZXYh}¹n´³{ÃÆE˜ð,F~°h‰°ˆÍ¬ZÀäbϽÖg»œ»{þçè{9f`rˆ„J5m®Ì�"�XìÄèkŠ�XùâÆñ*Û‡…X„0P'¸PÌg`!?è›2Hw ám3ò€:¢=ƒ;§òAîòÖŠ> åÜ Ú#ˆÿI´ù.L†1‚ û�~,R°”²V´ÓÌ•èûw̳ry9êêA¡\�fva|¹<Ñ'‚'óU6£Œ±€Ï•ùÕ.¸ÇB>º|žƒ]'Ò¢­_c8‡¹gÝâ&Š^÷˜ðS£]Eè/ÑvÜ$:‚| _…|;ƒñ¢PÄø•/cl Ù–ÃÚåãI€Åaõy8D´ÈO!.2¯€}„ƒ7=gùa,ôk× +×!N,*Z6a³ yàÕ�qd»+{rŽÐž‚Ì(úN¤·:ddz{¬ ª(^ áÊs(ÿ>ôëXX ïÅðUð¿å÷8êÉ>Œ�h“Õ6~‹h1¢Î¡½×j˜ñEÇѮ½äúd~Yað�•ò«çRÔ'Ì©À‘åFØ�†¼ðâ¼bs„½¡büÚnÃ-ìGú²j_ú§ù.Í͘›gÑ–¹° Ìã!,Ôž�àR,|Ð6 ¦ˆ,ù°Ð K;¬ÚÜžÈV‘ô�‚�Ý„¶¶ýƦê!j†0OžoåŒù™Ë‘ÖQ0‚P0>„<GjCq'Ê¡Ï{�'ÌgÐ/’Q€ºd¿€qñR°düÍ0o·àç&Äɾ ~0�¨a< ÐÆÃᠽЎ*ã‹ôAl ì…,êâc°?Žð𥒋 a=à·î.uiÌ„ßÃâc7é [6—E–Á¾÷�˜KàË’˜nQŸbÔï„oq/ò܉>u‹ã9Æòçø°ü*½V.æ-] ^¯ö<ê<*.T&ƒ´G˜wc~‚�îoBxClF~�#>øa¿lGÚ0Ž`  b>2è/âó|ØÔ Cþ¢õµ ÎmÅì1/‰jÈc@1ßNØõ»0ªÙ>ôÅ«ág ìЇ¡��¾jÜÍ;²žó�KÑ~"äo1â��<ÿ„0¨ d•¹õeÅöaXŽ1ê«S`sìBþÙŸ bä/>€2êA]iGôQ(û8ƒ2Á\"¨Aà‹:’É=�º‹qyfÏ»œ½wËr>´]Æ¡ úì�} ûí`ÀjÔ½Ü�"N„�ÞΕK8÷,“>TÕŠÅè«»‘ª(\�p7ÌÒá̃êÆ ðÊÃÇáÆYÖ=Ô5¬zgêÊ%ä¼ïX¡�E�Œ¢åÈÚ=Â1ܲˆv¸4„à£]Dø%q!v.�÷!­hG¨Ÿ.þ¸„´”`�±4`Ùd>”ë§PNáV¹ÏòÅ�!ê7惮^gúÊqeÑÿp,ìÏ-Äüÿ&W¶Q ÁRõYÌ‹P.1…µä†q å12ÂèÁ}»‹*æøÔFÀ ó Ö«Ìü¡œÀŠ_ƒWaÆzœs@ ÆyM€9uô4ò�Q;ĘŠùÈÈà7¬Ð´Þ™±¯rí2nƒÌQ\óêÚ~Œ~*Â\« –%ÄO¸Àý.:pjC;¹Œ0v¸1Žå !=Ò\@ÿ—£-w!^¦\\Û§¸zÂ8¬S˜#¡Œ9öûŧ�æùˆï88tÃŒ} Æ«˜eˆ¼²Ïà…cqæ(Ú-úWèG°hã×kü2Ñ„t�ƒÅó‘–m†mu#âØñ âA}A~Cä!‚`4ˆö;&1ú8‹ÙNзD›ÆE´i€GØTè›Ôa¤#D}²h/쑤;ÆXCfaæÛHÏÄÇq€5õ Ÿ!üDæ1ú‚Ì6Wï£àv„I¦ß@/Â…vĸPß)PŽÈ’õ¶†¹3Œh·aˆ~#^íÚHŒ1˜a3÷Að£ð·Ã§�íÒñ{ôñæÕQw�ª¤³¾ƒÂá\ã,ú|-ˆ8vB׉5ëÏ"=ý� Ø“o˜ÅX†þÁ·gÌÇÃÝг�^†°�>ìÓŽíÜÑöÁ7‘NÌiOnäEÅ>½šý.�WBwâA9ÀOoC~Зf0GÅXäúm0‰PBpŽ£—Á3Æ� ¸³ÎG¬»à?�|\�:‰¼‚™qœ‚Y€~›s㸒AÛŒ1_Á ²ÎÄá6×îëý8âÉ`nìêeåˆn3×Ã}ñFxÌã!ܯ†Ú0뤫+(g|Á‘ÉïÄzc‹¡½!ï!Â3ÎM0/­!�®~£¹ò"WôßäMaŒ¹½1ݳÃÇÐ ¢ÿ"%¦õ6¾騅´"LÔ öÁœ�Zæä õÝ�{Ï£|év Â/—7¬©ÑoË­sl5Âè…_Γ×Áí0ì0CÞjèO2ÌÒ"OH„WÜøŒ>Œ\YîâÐf˜ºåéúlô_1Ú¬±~²M£Žˆ+æ—Gn=€6Af²ÝuÂßÄÁº§èß åÕz¬9|ÊJÁ�¡žíD=Cۋ߀xУ¿dÅqÉ�­ì§9Î"×oãÙ8îDhè�ÐŽ|:'¨Ç¨Ë1ÌC”W€ú >Fè+´‘ˆm�mt¦‡ãz„¶æêæ XbŒygÓn+W^?»1¦¢íp=È>+†\$ƒ/>ã¨aã ;ô¹_Ýø$ì^P fyÜ-á•§ù‰Ã4D9.ˆ{ÞÕfQ뵨]7£01(cÐd‡£â&þn2‡Ž'ˆ/‡&ûœ8¡±„˜øÖÂ;àî9pºN–õ1„ÿc¨`˜èa’ê8ÃAC BLºñ½fc AÃ�Ñ!¹Fm»Î„‹Žˆ?@ec#â¤�{ë�¦š3gEä/ÐáD#¨”»‘/8yÇÄÛ5ZLb ·ÈEÅç„9H&ul]î&÷«Ñx9 cÐw i†‰O¡›\àÛiLø]§ç&–Ga�Å&ßAxébç„ e€´ $-ÞìÜr°Œ9I…½arç:d„ǽ2AÀŽl8™gÇ�ΙiŒð­b7ع‰ÒŽFÆáŽLðý¸K%÷zp�v:ÊÄ-È9IÀDÚM¤ ‰™g nA‹•ê<„ÁEÉep‹É¦-킃à‹r�ð 'òè ,À Œ°\‡ÈšÜ!¢aùÆàkè¸t4çdß¡ÂÌp°cGë: ç X–€ð5î(,Â| À8áÏd¡&<1"䯇Ý#ð‹Á<N\Á#ÀÄ‘�ž[ÌB sź‰Î8Â_ŽèàÜ„–nYWéž ! äœ,»‰ñÄáøÇ ü�œ9‰½ qE¸ Žz``a‡ÌºT‰þÞòÁÝx¾þÉ„u ƒ‚›Ð@€D¾XNûÉ ¸D(ç � “^WŸ9Ùã$�?&F \/²îgp“´ ØÁ“'`¨\lºE&L2ã$Œ"Ã@9b�1Ê “>Ø…˜Fø¦ÜMpÜ~X†h×@¸ËÕ?¸@¸ð ;ê '?A $-D]â ˆ…°[l¸‰1„Oh“�&ÃËõÜ ï@»àääÿ°÷&pvå�v�{oojµöݲ,KÂÆ cŒ3@@@Ë2d>†I>’0™If’I~ ¿$„%,Y'™l$“}õ|K ,"„-`;¼ d©mínI-©Õû½÷|Ïÿ=÷\]µ-[X-¹»õ?Òí³UÕ©zªê­·ÞªS‡9®ÜÇ ÊOŠ2­ü#ŽJ3y¬†$@˜)Þ긨1ÌÕÉ­#ÿéä‹!5ž‚¨<$~9qKMuöx.u[¦È”£Q5|Ôd@ :Ò(á©ùžGÃ.Å”¹tWù±Qòô~÷F¼ÔñÏÅ,Qå† Q”ã`Œò–mæ˜gëyÚÔ�†BŒ)é*t¦˜ÃÅ1<Õ¸Ç&æ¸e¦P(Q¯É•)�Rì+”2äE y@c«²�5ˆ{GÓû~ö/Ó+~þzÒð,üÐ0ãN ˜ÒÕ ”¢¨_**ÏäCŦBgJ�Ýœº(Qª=•c d%ÓB±“,§¼æ @ñ®T%¯(7(»™:­i�ð}Ï®æù(Ž’ù¸lÀ­R…7ƒ8b²XLªûI'm 2ÎeŠzs/c:$ÝÏÇ·”0:ñÔÅJeSÄCŠHy¨ŽuÔ먗¢Ïµ…‡ñlžªúTð¢ÔI? /:$’‰’%äm‘äˆò­èp‰ŽxlÔ¥è¸À½íi­<·È\½fý0˜“VMøæ„„áF’¡E`ä�ðè¬aDÑ@‘:ЊC´ t.šÈ†*Jp!sérÆ2Tý!�Urêi¦Î…Ñ h£¦õ„ƒ< å‹ú.e\†j˜«M–aN2ªˆËzܡҩ E�~¹A&‘ÄÓ¿§ÑF>Œëý\WWYÞiª0ƒCí´âÑ�B¨N‘ä%mž:Ò Ê�”ó�G ”JY �5b'EZµ±–n :⤻©ú¯tÒÉΫó<ꉌi*ojG©ç©ñ<üj8BõWí)ƒÈýJ~ þ¨kÙ‘H—d¦Œâ òA†Ž\J9³lÔ‘R߬ޅiK‘ß!—0˜©Ýäž =ʼÔ.©œ4¢ü)Ÿ9n¨�PÛÛªsrŸ>Iœ¨Q†1öR†›¾æVüS?)_ÒÔ¤�ŠºuøKÿÔE•Œÿ�ú6âFú‘i¡?ÇÔü"î1¦WÈé^¤«‚Á$ÏwQ÷G§;åø£zWÄE�{•Kê$íXFƒ0�’'ì ÆãŠrʵô ÷iC¥È-u¶àH^1á¢Ø�¤[íU“úS©¨Ž N/Ä-íB,᫨»<¿™½öä}åÙRA‡¨#ÃbÐRaÖÈÛ:åWõ' ’Ž}Á$«¼˜ô|WDÞË€YèyÈ ê&ïA7ÉiJ0ƽJÚ‹1{~®ä™ÈUâš«Ž3®Úü_”«ð ê§YÝC€dnÖ<CÊ>›: ã§dö�\ |‹1i,ôSdQÖá]ÙYèod0Ìd …‹A…8I§ Â/r„�xš ŠE|‘Ïr¢ú!ƒnä›d-†šD:räz![(;\o’Ç’1Ìáäú¤ôô É4žÖ Lf•Û¸§ç>é Y%å9õ,£ýQ›#§c¡0¨nÂ&⪸©ïC}D†©-Ï+„/£¢ô¿|3î�÷´a©IÜ «1ù—©Ö½?jWáN;Â+Äì•ò)£ P¯I»•h·*wq~ñ$©³UÉyù�t5¿¯q¼œ{”Kõ‹»|èB.`D#Õ¯�A6ÚZÒ¯²UÈÊýÄG2= IþÑžjÐ>kª_"yr/÷Ô>pN½ ™!¹Æä�h£hcÕ�n‹¶"k~�³ãø‘̤\«¿Gž¨ï:“·$eÔ)[išï%>bsϖˆ‰• ý�´fp˙̒5I‹ú9êw°e ù‰Œ“n¦|Q¼ C>ìÐa4—^oe7³»¸'=Jý.871ð‘Ò[),ü¿ôC L–äVF~f,›jÛÐáC× ËÈ-$ú{ÒÅéO©�®º—«ÿ'ãe#“�½¦Ð3®'NŸÅ-§Ô„Á™þ%s&ÉcÎUÖàTÈ?تÏ'ƒw´k”]äM“A •ñð«~[“¶{�ú*Y~=q¥ßVA>#¿2-•J2sò7Ï?Êõ#Î…½9„œ­ CNÑ’±¹™SwdSÈ`B¡¸æ¡CªNmÆ <Ä•2Q =SrT²‘<鮄« ,ª? yºå³É¥Ê{…¼–\ˆ2€lUzòæ ÷è“3¸z°d½ o±QÇdÀD×I�ðwqG¾©¿†þRöŸ‹¾íy\Øh�ÇÈR€[é—ò\Êz™êNž=‡8Òv ©_(Ù¥�'õ±Õ¿�ºz oùp¯’¶öNÜ®#�Ê+Ú³è;‘7rG=/úϪcêª œ Ý’Ô ò!ã£üeŸâyß@8”í(+”£ìnÂÞÌuee‰>gží�¼W³(ûÔIÅyÙ@&Ä@ e¡ÐÕ^ï!¬+i+vÒV cu~”èÈ¡ lÿ9<Š~eƒuJ”QlP*sadU™V0‘_èušq,# D!ÃUÖs&¾H¾}@òLu›¾vôƒUWC^Q§)#¤Šðh‹C‡•\˜w9u\u;ÏTÞ)S”Å,—k�”›ê®¡ç„þJßÙ¦6¢A�•>†]ò´°}ѾåWÏ‹¾§ú{0¥Ý pŽÁ2µÓ l…Nšýk„}·èËòlÒ‘çô‹Ò3ð¿šsŇåTv ÉóŒ‰{*Ñ ³”= n;#naÿ"Ï }B ¿ ?tRôõY+!/VpMúí>Âc¢BÈÍm¸íçÙ…^B¨ 1h O FT3ê2²7Ú4Ê Q&è,ÁNÒ“Ð £^F™?ÀDÔ÷îeµQñÀöïßF#Ñ|)QÅCÁ#«›*ìÊujU"2¿PHÔøp]Ê#¢9•^J}aô‘`BÁˆQ a„Ñ¡œ©£¨LçÎN¡ÈæX  ˆ”Ž¢£¬FáFâVc$…¤ •LµÄPŽ´uÜ¥ÐdTîmÕµP¢aŒQç[ÏçÙÉ“bŽ@•‘ â.…2:4ØTv �ØË�üµ:ÌEæôãŽ#gÎqšÅ"”t•ö8¦GÜU1U‰¥|âXJFU\°ã¹Jaª±Ëà+ÁˆÂ˜I!=Ì5ÅI‚†t¢¦ô9~p³†kRÖÔ˜J¸I1¡sÏVcC#¯Æ“gÒºáåD0¶,òCÊ†Ò íÃà¯|ª†Â|*î¤a|W^IȧðK9�€�މm:7b%¿ÊCâ‘¡ØäJ—^éâù¡ˆKKh DEG›$çºHcNÃy)E‰|’â&!ªøK QQ�”÷™ ¤äµ)„) üÊ15¸*»êŒJ¡ŽF“´Hˆ)ŸZ'#o£¼G�´¢¬T”�\‚“ú�e÷E£#/ÅGJSa¹ŽW)ýR`àJ¹.Ii�†GéW#¢Æð ˜ÜµÊÌ¢#�ûqŒp•V…�ò �$öUþCAP]"¯4ÛB ÊB±)ÿÉcóœNr†â«ødt|r:¶2À7›”AÕ”©ÒOÊ>N¼nåþ ÂUÃ%Žl*[1@C]§Óå„4ªîeDvÊ9 h$_ ¦Œ ʱ‰r‰¿`¢²HšʈŒ£R0É×BiR=¥á£A/ʬz€�?[yÖîâ™J(a GrïQçPŠÄ^Š[#u'”Ù éÑ€�8ª~‡!n”eâ²DÊl4È4üQ—TÇ‹rĎ˸´Âkd£ø…‚©´Ë=…@º@ñ vb„ÿ(·a¨§ãJ,\¤p„ÒA¤€2‹CPݯ�ŸÍ0Ø>�´ÞIñüÜb�º�GùØ|R½‘_¢¨wÔùl3a<ÌuÉd›â¤xÀZe²PœdàCé 7_¢*�…A5göJeZuÔ4£Q2^ˆè°ã#U0à`Äk6÷�Ü«8W9~C ¯†6^÷Usf ÉÜ„q¥ŽÂÛuî ùPÁ�:àêÌá�8I=J<•·0`¦LVYC>rYõ/dšÊ eùr�²Ï‚#8QžÐYCVÆ×U\¡ŽÅ}Õ¡Ìe•su@¢#ŒlÁ /‘¤öCmêäÊ—bv‰ÂVUr ãŠÂeSíÏLà³€i/i•1‘z(#šòUá2pª²2WeHuCƒGšÁDºŠÁ8]ܪ¨Þ©Ãí ʪÊ_Èf`(íU ˆC^Õþ¬ÀÍCÜSËx#YÍ%=Þ-å§3dõ^òZFÜ 3…B ŽU!9«2¿–ßWùII7É!äx“N†]Í‹Î~”«ÁÈ£bpñ)ÄCeíÂU»ó ƒ‚Ñ#Ó,))Ùj "}»¹¯4cü.ãm"õBƒPt2Ô‰SZ #qR}�‰ªMȵ1Ù a²Gõ¦ˆ?éD‰Íé�mŠê¯Úku~) ˆÎÇÊŒŒDÑ™¤\T²½¸›Àß6Ò¸ŽgSº¨çš•ÔhÐ)Â�dc´ Ô¹ˆŸf{…ÁS²Dòš|T;L:c FåRúLÔ5µW‰Ï2ÂÞ�»»H/�ò¢’à[ù(er~¹y´7ltžÊ2T ¾\ÁÅ�±Cî<•r^ JþQ7)2p”¬”'š%¨²¦v9:N [í_v=q¥ÌEþÁ‰¸7hWXP‡øÊ,M§Tºå�ÅxpGýοÀùZ®#ÔŽg|Ãð:…Ê,Ï#ž�0ºÑi�ú£ò®2ª6�cͪÊ$ßÈ3dAƒf<+Ï"|ä8ÜdpÌ™9.´¢v¤v?7:;”�è`ªŽ‘L©jà+û$YjÃ0,á_Ï�Ásò"�ö U/%�gÅàÊ0á#(ë1Û,äå–I2¤7¥SbXβçgÉÂ¥#å 6Úçé#Åà1L¨ÿ…>¸·_&>…«�Cu€õ*p¥58›²=ä¥ÊNÑVInTòoÄ�ÊÂ.®å¹’Q·‘ò½Ll£Ž…ÎM\HŸ¶ »’yª)‘¦ú¿b|{:÷éÐFzÄSƒ"×…û�kÌLÔs¢ŒPjÈÞ6Ëókxžä:GK¦iq�? €Ô Ú/ (k†j]ÈCé!ò"ê½êi"1ês¦¢žl$~G›W“>òM†ýЗ1ðÐä p“?È+b4QSú8ñÛ3t6å·d îKþH~“–(,ñ�Òµp‘nN�¤ �Q°hÿyÛ¿Õ�Ãj×ò|ÉKJ ºw®IEzㄼþÂÔÌ;¹©a�ÁàÔ ��ö›0*Ì^nÖi%KÅX|B~òlµ¿ä{èÄÊÊG•8Å@eJòMíT¡þÏÀ?ƒ21±'úW2¢ c8.fQâGe#t*ô)Þb«RG3É(ÉM¶’¨$Sîg ÃWLd¹2Â(Œ2ÄMÆ4ñA†k“ž+†*7*'!OH_QŽ%/Ä›ÊI¥§ñ®%÷TþHF— (Ǫ7šu�xÓ¤¢A5êI“üPå E› >-²$ÚRéuèöQ¨‡Òý¤÷gÊsµ1èYЖÞIÛ Xž�üŒ�¶†´G=A?É¥OT6ã�]ÎÐ�$›7ãÿñ ìˆ¹˜V©/šTÕ$Lm´;5žFfê@Þ¨Ÿ1ëVúƒ ûâ�Iï}a¨¬ ·4£_ò]6× êL“ð)ÔŸ+ñ¯ B”IØ {„ÂVz¤³ô‰dIƒ²Q¥«]ŽȆ�OÈp=›ò¥ú\¡�á=MÞŽ Þq]:˜âº2í¼dQè-°Ô[uU Ä(^„©xƒà’m°ÀàòJþ%WÈÿB6PWɧB÷fB†}d²êŠtXµ÷E�'}äC…úÑd€$ê ù‚t=òKý[mc0 �OMÕgõ7”¿êgéù´©É kF›�ÍAz^ƒúS¼ ‰þÏ@ïâŠÚ×âyòO„ó°Í0!ù^ K®\Kõæ‰êõ„·”òæ³qû9ÒsáÓæ…Þ#{‘ä›âK?L§ÄS3¨‹ö�pÑå8áÞϤ®Fû%û•ôÙb²Eô›”72hW‰cƒ>lÔeʉôÒ2ŠçHÿRÙc¨›Ø‘’½ÈCµ+’ùê?Ç€ŒÜ)Mš€ÞQÈh¦}¨2yGé%É?ÕoMh4¶òÙ'} Gwг5´üG ~Uä\È¡ܤ³Ø)�ÕùDój@®Nž:®481+VÊCj„•ŒuD4*¤†V3až” h(ð¥QVU¾˜AJá�!�S!4û\£:<ŒF„F)Ô F¸‰ #Î1{<ÊAîKÖu*.F…éD¸Ç«3øÍõ̦o ^óÐÌÌ”ËÏbÆLâ5úþꀡP+ŸÔ¨ ­fÌ¢ØÊp!ÅO³:çh„dÖ >Å#ÊᨱÑ+n…`DèKÎvóD){”Ò¤hx¤8 äòq/% VaØ»BAâ"×ÄL�(ò›NUN<Oub¶AÌÇC! !¤Æâ>î‰Ëö=^7*ž­Î°8“O”‡âµ")2~r‡RªøÓH§ŒÆ6§!ËQÎÄYe,”ÊÏ)Ž G3±P¾2f¶iöF4$šE¦òª‘RŠs —k´O�è&åYéT e‚Ƈ|VÌâ\ �œf5dŸåÚî¾Ê2å# þ1h«LüõS9‘IC«ò"e2ŽÀŒ€kv²òKÆÖÂ((%ŒE³…ˆc“ð£3¨2 YT±§¬ÄL,ƒÒPªÅài&Q18B¥Ü×l¢‚ñÑLˆh¤ðG*W)I4„‘oÈÍÆ¢œ¨ó¬W·÷LŠ—4)¿£¬žKÆU_T–£®±CyÕÛ):äwäÔ¬Ñøi45â!ùô5«Ñ§œ1k‚’xPV™E¯—E=Ò3ÈgÕ[ž"c) gÁ�F\p1à£2¥rGþȈÀ‘ê|Ì(ˆÑ` yÑÉ'Ϊk4ÔÅh-üe$`À%fÔ–Œfª_1Û?òŒ ÉÓÂx�’oè¾dœf" s¬'ÂX³vˆ‡êš^K¯èµFÜ3c׫x¥—,û¡ÙÕÚ¤èÅÈ5³ÇB¡U~Ë�ù¾ïRzPØe(%}¡Ö \Ê6Áh�kttQêY�6ʰŒÓz}½ÙËù4õ‡F>×ë³td4»I½ŽY"„¤Kµ�|’² e™×{›”g)Æ fÉp®¥aIJF]�bVÌ`£)Nz �zÓÄXå�ºx]W²Gí‚Þ˜P] ß$¯c�ò*FÄ5 @=’lDt4�Ç5ÊJ“<+iu>˜e.£ò²øØ°dÎAâWAIÂ8ŒÜR‡¤’ßÍÈ»”Zä6J�6•Ü*uªmíå ¹uy–¡Di0Mƒ82Ы¬Ùà©N|j<‡×ô3^õU'.:z2.ad«¦§qNˆkƒð*šmŠÌËõª¡Úµ�ä_´Òãõºlöå§J~ë^³J]@FgÌ8’ül±0þ¨ŒmÄí¿‘Ž«¸§v­‰‹M<—ò"%ùHžEÞ°._C¯YJþ5d4‰÷ð%Y¶¿÷Q_V’/´ŸÔ�&î5@ª6²I\Y•6øªó«ÎQUmˆ 2ò �W«tØ(CRê´Sµx�õAš*ñ7½:½Ÿåsˆ·Ü©˰w(¾”'¥»N½�ÙFtÐ5STÏ zFþèüÕ÷ Nˆ?²®�,ŽW0Éû&m€Ê\tÂhûsuäiçë„C†PŽÔbe_Ò�¡¦r/ü¹Vgv+¯÷k‰•‡ÐUXZBqÒ+›ÒE²ÐwrÒq×Éu˜Õ†ª|Žf±Êð¯çK®“žJF\)3Zí´˜%ÇsyEžO]ÔóHc…QØ&kŽg!“1Ø5ÖE9šæ�—®ê^–†a`ŠòÒÔà¼ÚÊl»^jô-U“Uv“Bê@èK‰7|‘Q*ÃUXk—<Ê¡t9ÖÉ„AwåËĹ+Ý�8Õ0X4È+½¥ÆXB÷ó:úËÈèíœ*K<ÉÐSENQøòü©sÄPK¨UBVÑÆ3 ·”uʇ–ØhPªÒ(É7âXø†´Ð.†$¡f*'-u1EYí^EÙ ­£.VЩõ¦EN_Eºm•ãxó‹Ù±ÓèSUÚ¾*ËNä”emÍî½ð¦� �wcÌb¢Œt7rµAÞ¥2E»M2–ˆIäMÞE[¤AÖDŽº%ãŠd¤ôSä¡Þ¤“QµA[Ü­z]Gnu#÷§�6µAÒ±‘éš­‹ž^ýt�J¾—²¤ÛjU†6³ß˲5´Ç,—!Óë”·R_ÁŒr•ƒŠ–”!üZùÍ[YÓ¡jù a“>òHy§·adª‘žKQǪ´c•i;(»0XŒA®éÍÁ¼K†X…{/Õ £ée”ò×Ä£7‡Š·—X—òÃBY¸éF¾“_¼YYEÏŸn O(‰�]µ{j šÈrdIÒ†áYEz»2��ª#i‚úØ=½žzÆëõª·¹Úù¾V:�Eä§æ¡7©'ZËXfµÅ’“5t7-u’àe£Fþ¨ÎȘ 3}0nÝé”EõS{x³…·ËbBÂÔ q&d–µëá¾–«é¿çË,'ÃÛpÌ$îb©½u·Â[uÊ@“2×UÛÏØ8D•_#Ô¹Þ©4Ê`DÏèb–„é'~ÔOÖËλÖâNoÁùÚ¬Jo&-5ÊÌ4ò„çå\+6É}~ÔÑhWY oÈ ­z¹>M5÷¢œÂåŠòä$my\¯1ß¶ùUQ‰2_¯â^0’>ÒœFöñ¶Zƒþ}Sœ�ƒ!w£ï­‰ P\¨ãZ~.ëRÛŒ, ¯jèXïýéýéåo?@9cI±:º©ê¦ü5Y¨ÎzÕZ°�|ÒúÊm#‰ÝÝ,Í3ºð”×3ì§ëH׮͸#l%ï%·éÝBÛs§–Í�A~Znm„ûkÉ[êN ž«§®¡ëÔÑû*UʲZmDá mãíEVà�{Y:1צè«KÎêMQéª5Üçuø£ßMc”S›Wë¡>Oâš¶?úu’ËP®"7ôÆ«ðRFЫøŽÆDßVä9ñ§-^ÔË2Aƒ¼ùÃYšLÀÒ#ñ¥Úqd�&ŒdÈTõƒÃ¨Ë P~jôIê´åµ1Öþ¼¯¹ƒ¨„]§>õt±0 dªú©Õh§µü—ä8ù�Þ¯<¯!ßµÄUÊw!«$�ÂÙ^¥¦Pg$cy ì“i¡RE}çLºP“mªÏjßšøÏ²AŠz�x£;U«ÇS÷È©4©vh}N:lMå—5ê'1¨fÀˆ61£ÍEîUˆ“Êr�eŒº�¡Ê-©õ˧XfPï"*ÿ´Œ›dCN;Z£ß¦6¦ 99ÅrVÙò²¯B|(³äG�2©r¦î¿¶Œ:GMKÝøSª³(¯Èë.êÅ(îº)Çp—>Ý`I-¾ ĹÚxÖ›žìJÿ®ûÓ¶48� Bi' Ƴ´ ÌðA7E¶7È¿§¬kÍ›yÓ]ä k +œ:ÃZx�ª±†3ià-×i®÷LÒ±´l›€Ú[¥O몓hÌ8´Ÿ=ÒU�³§ s”– iÆúбT¥ò}JÚÏQ¿¹JjÒrÞ$üúί`0M2]3å+È¡í8�¾åWŽ¥c,‘º|ù¢Ô×÷2®‘Þû¶ƒéåoû,>ÉSI«ÔÔÞ.zÍeDKœÉvÆ;Ï´½c”©¨ß¡ß°è\Mß6au1–ŒkL÷SOxc˜¶Vƒ{•ºòŸö‹²�QÖªÈþR¼÷ÍñuÙm…Yc¾'[_m®¤)|ß4Ö"šh8¢s¥×{$¸Qzõ ½:©QžPú4[†ÊLIÃ= …„•OÊŒf|¨Ã$%¤0>Räé°åÚø.*n¯ˆ*¥AÆ®Á¤"FJ 7]Ô¿ŒèÉàªgèyT �–©3 Îj|¢%H¯JðÊÈ£Î|“‘­x56FiX,Åè Æ ëèüÒ�Ð(³s_ð W'.¥Ò,©ÑE½N!CBFÅÕ,‰è�«c‡ VgYa3 ŒVé5âèŒi ŽšÉ ‘Od 7‚ e&F©$|õº®›Å #Šâqwt`b†Ò*â¯ôãù€b.c†Œ†Š¯f:Q3áM^03™`#ŠÁ•¸©ƒD\”–àH|h‘H’A³—B�Àh‚KÁC� c b—‘èxÝ1Û筤Œ(f*¢ª�¯Þ…Ÿç_åƒ_i¸ìh„âµ¼ £Q§’Ñ©ŠÁ9Fìà õìò˜ÑŒ{1Æ¿”üI ñ®æS¹~×>˶*£ñ0”Ò)ÖlHÅ?F:ÕáPYV8šñQ`ÊY1P‚b†Ÿ˜9"2"HhÓiË”KŽÕÐj]Ôš8£�i­ªˆ“Ä£ 1ä£ÜÕë4è5åõF( !1BSÊk”±O�g›[ñÂëŽ5«ˆxêƒ Ž4èHê•ÖrÆ¢:GŠC¤IG¯k€¢Îˆp±®Ÿòå…8¨.èù‘�(N‘–0}ÿ7q®†Ž¡ê[e"o¨¿4*g±„Š^»V#´Pdð§r,¿ÅL:_j¼Už¨g¡,¨þ1ë Œµ¤¿˜e«Žå›z›QV¤UhÔôZ7íyþL"¡.t°ðùH™LÈåõdï>–š\F‡jç’ËZyC§�õX¥ÎÔ›7ö~77Œ¯t.*R($#b„ZuŽ/(£R~Ǩu¾•xÆ/|cýK˜�GÅl,ÅYÊ×QNž«yÈ‚—\ “­™5I.f#;TŽ0úd<Á ›¢Î£¬«~`8ª`DPrŒŠŸ1ÓDÊp�gª~ɰëò¡ŠtcýÕf�ú‰²(ÅL¦‚>­YLš3­“)ƒëwÆdÔg½®+µ@Æ+)i'Ppd”î;ÆúÓ«¯ç>r�xÔ0Z'”}­]ÎçrÈæ‘tjÑ4ŠÈbÎ×áI÷&Fb½Þì¸f>€AǤ‡õAU¾¦PèGèl,¡~ñé¶4Z[Ê‚1J.!œ@¶]AšP$´Ýtøà‰¤ÓtÚFG5†NL��p4T¦à¯|Öw =“¯8ß9Å'£¡Üñµ9Í©&ëŒIч'ʈÖuî]2”¦N]Í“0{éÄÿ®”Xö#Â$ÎuŒ}½ÌþRœ*tnÒëßß½;>|3M¸ëZžDÇŠNK×ô*”Yêù®�¤h› g<Û\´¸‹µx§“>Ìx¹ªÎg7iï¢cQÃX«’,M[h‚1T�¯$È :cSÜëŠg-Mãý²¦/F]:Ü}¬¯=¶l%ñÞ—ö*>ˆ¨/�K×èíÚ„rM·�Nì ê «Ç³¾>§�aÚ0R×WŒ¤.¾wÆ)]¢,T0Ói¬ �¥úêEÈÞuÔ3tŒc¶>èØLÛwèãw¬¯ÍÇŽ˜ùY_½›�~­ æZºD™zÏÔpzé¤ôŠÙÚ™ÓE‡õÈ£/ŸÕë‡ÓðGùPß2ر£ø®EíĶ4Ò| i-vmJGW•u8é´×I„¶£u@Ëc�d)ÙêŒjiu8ÔaëåÃ3ÓÒ¢þÁø`Wƒ<Ð}­Q�† ÃS'1?®HÓ(ãï3² ߯ÙÑÏ0ÓD|ØTÏ�ï<쨤—RþÇI×Îjo‘¡?‡[jôXukZÝØ{æÃ†¸ëaÍé÷¼yOúÖ7.J]‹×òñ"ÚíééÝ;$3ŠM8ÝÂGú´Ìœ–žë¡ž.‚ImÉ>>X¨uèWßÅiÍúñ×—Rw²)Éÿ£©§†ñ�ô蛯|;˲Œ°®ùÊ©T}ˆzÏGÇš”1™<5èŠ�áCé[êzNñýŠ—þÔjÊèÖêFªoJ‹ß›¦Æ('|Œh ™¸™ô «,v ÙbÔëØN"c»'År€ŽçÃIßëЦ�Úí;ô:o{¨'K§÷â»!÷ö%}ün'ñÐGDõ±ÅÏ“ÆZåJŒjä ‘ï=üÑ÷)ÒF¾»ðÕMi™¡>�’WúæBùÝ1‘¼ÁŸ>¹TC_ü‡ŸlÄô[w,‡«ôiå=²qÅW‹�³î೿Ï�‡ÉŸ“|ãä�iŸ‹-£,fé-oAq­Sfua¨yßOj…ßHúÞ‡dÀ¢n̸t¾?°c~+üа^ùKtU‡y¾&&Ü‚[•smÊsʉakrZß \�cÛ¾CþÑEÿmÅSßш�2ãOÌ>ÔŸôÁw}XÜÀ‡Öô±Íø˜ãð–0,Væó¡«Ó|ÈðC;FÚé(ÃRÔÇ”c'hªùîÅúcQöÊh)ì)Ú—²²�¼àDZýyäØÍ=8™îø}ÊV«Ü(-Kh»¦Wk}p¼,÷áõœTÆT_Ëò{N‡3nt~ëHåXm[µïa;Îw?Æùhq?õzqúà[ŽDÅjºoªã[J3l�ªÌª­¨/Ûn_ùvŒÂÓ]m«tJ¶7ÆÈÅEã‘úžDmßrj}»gfÈñAq>0¯8I{S}z2¶(o|S¨Ÿ�AþÉê<¹}î�¶(¶Ò�ÎËãÖ­Ø�ëzáæo½:���J{r¼- ;ü·Ú¼Ô’_wâpû'ø6ÓçÒ­“'QFTvÇŸ¾]eˆ:4…ì[œú{ºâ»4e8z»|Š�½I}�óß$oãƒëgÉœó÷¾._OÙ=Å·HÞýŽÃxy4¾çõœo|éCyÒƒ¯>}˯`oaÐä£?y nUäœì<ç~þ·î`Às"OøÅáGDè;Ðå(×Ú�®Þ±•²ë=ob`pÆ&¾‘ÉÐ’É�·õí¬Åë—¤ÛߤA×sÇ©ÓÏÅ>V|wҦÍé};¾ØŠQ±S'³{z)#;ûùx•Œ-¤q†r{–Nf Æ—¿õ)| m¼­€Ìt¯s)-ݧ֤îkvTŒP$E�� Ù”†i¾JûÑŸ»øx$Þ]Æ.F»¯>ÔŽ¯üîù¦JºeðU¨’'wõ$†ž½î¥ÎÍCg•›Îpu,½oJ<LÔ¦rsúpúС9ŸÅm V�­r{ñ;V¦Fö>¸C�³¶3ÊÎwÑ€žæ+ÈïÙ�áþ16±ê¥ƒ¦ª¶{Z¬J//ûI I�'�Å;«iÇ ùò÷ÿÆ8³»_TWC®´Lß{%LGã¡“¾"{{KñWXR‚EêñÊWùÜóÝ«<ª3}›:ÄEõxä`ÖîLµÃÁÝ+ùt6Í(*ñèû3an¸ŽŽ,£Ó=“iúôâô‘·ïk;/žLue§¦¼ÞÞSß^ú Ô¯©+¸t¸#/Ú.Î:› ¾¸¼cÏŸì8cì©`ùÀ޽¸-êÃ+vl˜MGëgÿ;ˆÇŽ·Àþ瘭ÄVp<“ßqqÆŸ—ÿüÓ1�¤|\ñÏß(ãÑٛ䒾|Ý©½òMkS†ÕÛwh L†�O�ïÛQÀÎQN‹�·6f=o‹çû¯ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ž/¶¾ IDAT ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ Ì Ù܈†ca&`&`&` ‹Àƒùu•JZÜL©7oÖkYªeYV¯¤TKYªgyªå�”²jJ±/S_+Ø×ùužwÜšµÃ¼–ò¬N”:¶òZ¹¯â¦1ÃM‡ó¯ëð|Â’Z>sæùc=ð±Â¬{g…)è‚ßÚfúë§ þŒ²Ÿä‚®M“ïì"{)½øï§0(v±•A¶ŸÑº>ó¼uù‘;0#>mG­{VY•Ç�å§åù¼Ÿß~ØÙ�æ¿óZYîä«<î¼vhgÎJ·g®<2ùJžÜ©léX[éO¨ôÕ‡['Ž2¥¿s¹'c‹ò üJµÖÌëõ<«ÔêyczªRéyæUÙ½ñ`ÿ1000¥~e&`&`&`&`³H`ݲôÊÔlnMY¶SX_žç]YªÊöˆ1¸Ú6瘲²ö–­ÖyX¸ Ç+9i_ÃÌ�cùnÝȸQÞJYç½–“rwž÷0¦¥¬~ËóL¿:/7=¼LB‘ˆ¯â(wå¾ôPž·Òa—÷Ø·ýê¸ó9¸o�Ç#ãYg®“Ò½âávÜïxÄ~Ï(ýÈ]çqœË�ÎcS¼‚q¯óüI~£²R³ob™n*N8Ò¥œ@»ÑÈ—ð[ʯ›s JÛHÏ$œØ·Â�™F.ÇÖŠs°Ñ…N>e|‡N.íëòÐqO§Ê;=÷,7E°Y+OÛÏ’óp[î K[ù¬(Å¥ößÒýYÏ-ó[þËc…Ã/â!ß纮{3¶`к¦0´•‘.÷å5íK7z†žçz^+=rSní°9(ëp&õ=Ï2ŒÓØÂÙ×9ÏSuˆŠõþm .!zo&`&`&`°�ÚÅÀLÀLÀLÀ.��ÞærÌV«±@®ÃxÕÇqÆg™º°y…9K¶¯Òž53¥�¬m+üÅ_™£‹û¥«"œÒmiNÓ¾¼VîåC—}´¼Æ¥"RºÖqO÷K7å“fžëzçµò¸¤v±ézé¶Ü·n�µ›yOçåöha”×J7�þ;�u¿t«ë27j¯Ÿ¶ÒZîsàeœ´÷¸ ÿåuyÒ±öl¥ W~â\ŽÉï¬Nnu±—azœ)·š1�£#uÖ`�·’s±»+å1‹íµìºM2* AµãÌõ ÏÐcÊgwëÙåuEA[y®ãòZ¤¥u/®á¨Â�Žã\Ž[›Îylû^gx:.Ý—Çå}]/�Ç2 ãzy?ö8T™,Ó¢k�›ÎKÿe˜åý&ª-¿r§ûú•Ï”»2\—[é¶<—];ûú™º¦ëejK·q‰?:/7²S49‡ušçfu§¸xš\U<Ž•½7000(Ø@í’`&`&`&`�@wµÒ‡Em«Öæ«ÅìµpK}䨮 »#F«ÒˆV¿Z†.ÝåÞY[Ç5݉ÂV˜Ìd¼Ó÷ŠÃG=Ÿé¦p¯ù°…!®4¼•{¹ï4¾E Eì#ŽòuÆ`w 'üí {fü˜]ŠAR>‹ð˽Î"¼Žô¶¯� >|ÉO±=ÒˆXò)üâŠDD:ðtÆŸŽ5h03 :/¶‚C¾®•n;ãY†)wÅõ@3¤ÃêŠ1ºaYQ[Và0NOp›‘ ¬™˜.!Ô%C5?Í ®ðÓ<û"¸iÅ!¸ñÖ­°`ÏH“.kÓ`C%ÊQgœãN«À‹p‹ü/ò¨¼A´þpMQi=§·3Í¥3�Un–¶N~-·�º+Ÿ#_e<:÷òT„¨#¥_!yØ:n§Y.´�)Ûe˜Jgñ„p@ÚŠ²Xœµ®i×QFã”?¥¿ÒO›".EœÈm�/0ÀÀZ ¤ÎSXã'‘å‰]¼™€ ˜€ ˜€ ˜€ t°�º“†�MÀLÀLÀL`–tUR–¼ŒT=©ÙÓ]˜øº°aa¼Â¾…µJÆ�Èú%üoË ³t­Øµÿžõ ]í0§u†UÞÒÌÝö¦c¹gS8Úñ“Ñ®0t¶.膶–›öq<ªðWÄ«å¯ý Î[·Ë�c_†÷J7:)ã^î[Ï,ÝǃuMîã~+åõò4âðÒÚŸë9 VÌ:òë¬ø–þp³�•­š"_ã úÉ­g7Ù³ôGêG辶*±´q�ñ4fP³‹(é^Š�£ˆ¦þÄAûz¸åZ”Ÿâ¤íF¦W]�q‘ð!¿e¨GºZa†_Ýë¿óZ\ÖÅ…}Ëi;ì8/ýÊ i‹M7´ÉOë¸, 3ýijåWáè×á·<Ž{ÜåVaÈïW÷ä­øÓò¯kqñLxgÅ�{m¥ßÖsµk—NÊpÂÔˆ2VŠjxÒ8sãù¦†$X€žˆj½û_bëÍLÀLÀLÀ:XAê€áC000˜-•JE³X1Lgš[•µŠ Ì%“Viß*§ï©q·õl:Î[µ¸†-®Óc|‡íŒ?ŒkÅSJ\™–³Î;Nʰº‡ßJGXò;3üÖ5ìtE<:ïdzqÐ‘Ž¶mPþt"7�ÏèˆJ8‘›òšâa†1°`£xÆýÒQ1g¯2=E`Å3uáè´L_Žn¶6Áo[´ö�á–ÇÊy‹òù ÂÑ^K‡(îré–ÝŸÖ¶^ ·¬“õÈçZ‚­ø‡ŠrÜ;síÌQá‚¿íç·üœ‚®µÂ=«\�¹¾Êt餈žŠZ‘¶vžµž]–Åò9ºÜ‡8çZ8oùQ¸¥{…ÏåH[\?së¬pJ÷á¦#œ2ÏŽ2¥8”qíŒ�ü·ËŽŽ[å%Â-ÿ”á+bå5¹Å§ÊMçµÒA+á�0y´ª<§ÅÃt¨,­pZ% p2>¡¿ÞLÀLÀLÀLÀÎ"`õY8|b&`&`&`³C€™³Ëb­,––I®°µ�TqPXÏ\›q® ¯g·f^›y.ç³=ZäïÑÂë¼ö(Çáí\Ïìt.7�×[îÛa¶µ•á•ûN¿�Ç3Ãé¼WÏ »¼~®}g˜�ÏW8a¤ä@{&eêe™�l‚B1ÎÂÔ2PËäÞË|zŒÓ*$ÙçÓ°ÜG¬A-¯E18;Ïu}æÖùü™÷:ÏÏÛ�<µÊà£ù9Ÿk�Å3îáìÑÂîLCµ"„ο�×ËãÒhçúÓÚë3#t¾nKwEœÊ'EÞ•µ¹*ÃxS…Á› ˜€ ˜€ ˜€ ˜ÀYl > ‡OLÀLÀLÀL`v`w û$¡i�ƒòXSRe Âže;Õì�ž[¡DF—¹ÝÊx-><‰ñyãôi~“ü´\„J€¾¢7Á¹Ö€éÕOk®iD£,5åô]]òvþJ£ñùû¸p—šBMÕæo{S¶En*>®öm.>0000�6u˜¼™€ ˜€ ˜€ ˜€ Ì>¥˜#‹�±0J‡ÞU©ljœ}Üs#ÄÈÙÙ+ƒ³ŒÔš!³§¹h¢¬(jö´ ØrÃÿœY&§ÖŒ Ë»ÞÏ13 ÐÊ6ýÊ>Wy>Çbí蘀 ˜€ ˜€ ˜À“KÀ3¨Ÿ\þ~º ˜€ ˜€ ˜À%€½QV©0Na”Ö>l� 4¹NÖL世ñ( @a�æcˆi9Úw5cZË{tóÓ¹Žõ1E®Ù…¿ÒØÉ%oó�€²�±©XÃZâ@'Z§zþ¥Ä16000�‹LÀê‹ ØÁ›€ ˜€ ˜€ \ždd,7>´Æ* ¶L•<.‡}X'I¨–òкÒý§Wb°îáxyk¨BFêòÇÇÃ�Ü–Ë\œb[oLÈ2]&¯sÐyûbyÓ{000¸Ü Ø@}¹—§ßLÀLÀLࢰqú¢#žS�R6híe™”ºµì•ÚO1ŸV÷uO3¦5ƒZ3©µþ´Üêz¹qêm(�Ó­ü‹ìæš³s楣l&`&`&pñ Ø@}ñû &`&`&`—'�Ò¥}y|y’¸LSæHL“šÝ%Xže|VaÐÚÓåìj§5s:ŒÓìuߦL Ìã�YÔä¡2S¹[y cµ70000��4:.ûÐLÀLÀLÀL`È()­?; á9ˆyJ@™¯Ÿ#.?Ѝ�&ê<îQR¼´0ÈÖž,]˜££î#tVªHJ� 000¸pžA}á ‚ ˜€ ˜€ ˜€ œ“6©*Æ*­G+ãTªÎéØ7,M¤•yRË{œ®§4Î^³¦µißÃÞ–ËÀ±°þœÉTÉ×ÿ…•»N� ˜€ ˜€ ˜À,°�z–@:000˜A æN¶ìS6LÍ€s¹�6) ZÖC†é¨O5RZD©Ð¬i­KÝË=­Gå¥Uh.7F 2½’E~f V5Û3«db�(000xbl ~bܦ¯Í›{{‡‡×çšé5U¯T*“ccc‡I¬Të¯{»e``Õ##Çñ¨·W½™€ ˜€ ˜ÀåH@ßGŒvã¶)[/·B %J¿d Ã0-õ°fQc ÖúÓK(!9Fêö&.*móø€ú&'=ƒz礣n&`&`&pQ Ø@}QñίÀWœ:Õ=^­Ö'&�ï�•˜7­¿%�œ¼ÃêYÁé@LÀLÀæ͘ÔÌéŠ Ó6NÏ»ü»àËάŸ6í'1D�b Öìi©'(‹0L¯ä ŠÓ8¨ñÓ†mÓ�l¡üQÖ+K�­ %G�000�Y'`õ¬#�¿jf/™>By^¹qã=ÍæäÔTZyôèú=7v×&ú+Ë«=ý'�Üý‘ÑVŠ«[×n½.ŸÊOÕ*ÍE•©é¡©¼±b}øÞg/]ú,zëG§³E͉Z÷Ô=Cƒ‡7 lX•ue½SÕ®úÔTsòäɇ†ç/MÇÜLÀLÀdlÌš´¯B!cµ�Ô—I¡ˆWZ[ZÞ£ü0¢ Ô'1NŸfY Ô¨uMkSë¼í÷2aµ “y¶6}öÙ‚L°e&`&`&`F@³z¼™@‹ÀòTí© ô­ÜxÅâÅkפ´-¾×S›ž>qðàú“•J׊͛�õONžªödÓ“ÆéðßÌ«Õ=Ã{ÚulðkYÖûÍͬkésƒòÉîž•'hL5&SVß*ÇY#X~bÕ¡�áƒójs%—ªµZzê�ãöa¬®Ô'7êšÜz300�yJ@†)} Q{­ï1O“áh_œõ+ןÁ=ŒqZû£ìOa¬. Ôr£ñŒÒÏ…<×~ç��­7*,æTÖ82&`&`&`s�€gPÏ…\˜#qàÃâyo=;~ôØþCE”ŽhWi6kOYµêž+§›M}Ê'¥®‰)ºUg¶íi{¶oz_ûZ#KKòJe*ml¤úhZtxÙº§ueÍcôÎbP¤Â+Ï¥Ýù=,Éøt‚Ù–¶ÕÆê#+Vö­¼­žÕ§ëõÆé3¡ûÈLÀLÀæ%Ù18ÆâÓó2Žô'ÐidÖúÓÓÌ�>�¦¤ÙÓZâã8û>´"­E­ëÜ—›.†ç¥,e À¦Ì'žO¢ÏŽe§CÌÈIçꓘ7~´ ˜€ ˜€ ˜ÀÜ$`õÜÌ—'%V]]‹cÕ æòœÙ6oÞÜ͇ =|dÝÊ+oMÌ©®Tªùéžþ¶1ºp½“ë›û9®®]»¶7Mäð�ò®ÚþZ^_:¹ºïäâÏŒ¬©õÖÓÕrŸ7›½Å!fS7§v§ÝSë+«?v· {­Â¢›æÍLÀLÀæ--ëQ~QF)¦æmV>�ˆ·L“š-õZ�fKŸDË‘�z„ã),Ñc¬?-õ8÷5ƒZË�x²ýà=7½tÖyëµs3�.»X©]ºì훀 ˜Àü"ð ¼yù¦ùå �mÌf½ð`ÂB 000Vï™Ê&;Ó2888ÑhTW¬Y±á9y­ûÁññ®•}}§½£MºUg¶Õš –MM_½|ýs�vß²ëäž�5*SGúSs¬kz×èÀÉg×&›OɺӮV¯^œWóá�–�ºšW5[:?tòè¿-éë{Ö¢®EÏL鈔øóRž~iêkqË–¥;Š Gg"å#00x’ ´–÷ˆXä±xÓ!?þÒh™&±=kä=Ö˜–aº\ÒCk¥5£º4PëC‰R~: ÎãKy?i ”YXö»:�Ö³øe&`&`&`ó—€gPÏß¼›õ˜ïÞ½[Æé³ Ôzȱc‡îëxØÃCC:츔ÒíœmͦOíº³¼±ûÄAfCd�Å4ŵO•×[û{Ëó;Ž>ØZR$ÕO��¾¼~Þ{BŸènNŽmÛ¶á‡ð´r÷îƒ;<ûú¼ñÙ¡ ˜€ ˜ÀÅ%Àd5–ÉÊX#+ÓŒêN›õÅ}°CR È )ô¬“å j¢e¤Örš--ƒ´ ÕZ�Z?}HQî;gQÛš �ù½µ³Ð•~g¤co&`&`&pñ”#ùï ùr!и’¯>‰•õ;õ÷7O,]ªE³‡¾¶mÛâïÙºõÊïß°aÑ“?ÓLÀLÀ:È&%fȳ&Æv8ñáB$Ð~‰¾eˆ–QZê1~2NËh=Á±®kµ–ü( ×Z F†joóž€ê¾²RûXò‡½d�70000�žAÝÇF`'ý­ á‰ùžœœLßsOôã¾¼};]½4vÍÈÈøáZ­÷Û·n]“ººï¹ÿþã\w_ï‰!¶/00�'N@Ë}jÚ4Ÿ¾c µ~â$ç‰ÏNeCFj£ex–az”Ÿ–õ˜â'wúMr¬ëšA-7±Ì7TTdÕô6¯ (‹K#µ€'ÍëìtäMÀLÀLÀ.¨/Y‡[ác‰}G޽Ø(èËIùO»´ß¹3ÇôÓöíã«wïîzͶm«êØj½½'n¿çž˜týÇLÀLÀ.2�–U: Uتm¥¾È¼çJ𡜙Ò@-#´ Ð2Nk«b¶ÔRº_.óQÞ¯cƬq? MáÜç/�™ã 6RÏß¼tÌMÀLÀLÀ.¨/X›š2Nc¤îïëëkÔjµ¼µÆõl£Éê,éYª�5–ÇÚíÜ™±dötÚž†Vïß¿œYÕÙâþþÑ?¿ûî1œœå¾Ó¯�MÀLÀLà È0E#ÅÔ1V³b3>•Fê ÚÞç)š-ãô(†é Že˜îÁDYåX–Ê.Χ¹7Ž›rvµ–ÿ�[n<�óp+^œu¦�z¦ÆQ6000�‹KÀê‹Ë÷²½œA}Ë-·tmÞ¼¹·e¨žLkþÐ…!z }»ñ¾¾z:uª�>ØXnÜW×.¥�«ÆêíÛ1T³îã¡C}¯Þ¶íŠeÕêÉ‘›n»ýöÛéz300�Y%æEŒÓjóÂÞ8«¡;°9M@VIeº>|¨™Ñ2@Ë ½ˆÅ^º9б~2Xë<ÜòGm)%±†µM›�˜ŸƒQQÿ‰}¹Wn*˽™€ ˜€ ˜€ ˜€ Ì `õ >½8î¸ã¥õ˶mÛ6Àlj-ý!…]ý± ÚjtεfÇ#ŒÕ,ÂŒêìKðÐñêÐP¥z÷Ýk¿çæ›§¯ZºtxÇÎ�OÊ:ÚÀžMÀLÀæ*¤ÔÖi“a*Ì�šEímá�‚£%<4;ZFg¢—¡yw³WÐ*r£BÒ×2]Ê ­ÔÚ\T óño9ƒzÆäºçÄÏÇü\øqKÃûJƒ»$}¸çq·�µiæÍéºu‹×é¬;8ù`ºûkûÓÐɉó zÕÖg¦«×/OKzÎËùEv4’ß÷@zèà±4r>OZqUºfóÆtåòÞóqm7&0¿œ>˜víÙ—ö �>¯x/¿òºtÕ•Òʾ‰têÈþ´÷+¦£çã³eZ½qkºiãÀù¸þúÜLžHG ¦/í=v^þ-_›®Øvcڴ伜_vŽl ¾ì²üIO°–úhOwÆX½äæ›o½�Ì�£š¨‹§Î@*�Õ1«ºµV53ªÕ|X÷'�øþmÛVlèéÙ·ÃëT ‰700� ' �#ê§­Ý&§þ»Ð (ÃËL×Ìéµh$:—QZëXgšc͘Öqy³§:œË$}­) ?觬öfs�Àþt×»#ýÒOýUºcõiÃҮǎãS¿5½ú»¾?íxÅSÛÝŸ;øÑô‡¿ñwiç݇;ô©ãißà‘ôü·üczóë_œn]ÿØÎ/ÍÝ]éŸ~í§ÓoÿíißêÕiUÿã˜cnûÞôoøÎôºÛ6\šèù)&p) ø\zÏýEúËOì~ì§NŸL‡÷?œžö}ïL?þCoH/Ýz8}õã˜Þö=ïLÿ¼fSºrÙãÈ««Ÿ“¶¿ö‡Óoý?×?ösžÈÝá½é+ÿøûéGï3�í»1–NJ‹¯{YzÃ/ÿUúÑg?¶óËõîãHÄË‹Ó}©`¬á—mÙ²eé¦M›Fw>�Ì5>~xŽÔêj+÷gªuã5;wÆ= ÕÙÁ•+G®9ýÀôt÷÷lݺvrzúô_=ôP, "·ÞLÀLÀLàë$ 6¦óM¡h‡f̨ü:ƒ´ó¹N@™,t¹Éè¼ã´®kF´fGOR*äD³©e¨Ö¦]/&Ì.~åÌi¹iÝ–oó“@™…’2Rw”Žù™ ÇzáX~Ý Òë~ú÷Òo¾úй›È§_ú­¿ø¾Ç�ßÞw¥ï~É[æä¨Ðúçÿ¿éµoüÉô#/Xõøé° X¨®}uú‰ßä÷xéÛÿ·é'^ÿ¶´w†»ÅW==½âgÿ&ýÙë6͸s O×Ýœ¶ÿà糧ðqžyì3éößø_é�?õ8î.óÛ6P_æ`$_Jz¾gÏž“üª›Y§zzzºÿÀ�'¸~!³LMùï¼�…ö¬ê–¡z—€lß>™V¬84°kW÷k¯¹fUרXÏøþý‡q{!ñQÈÞLÀLÀ./¥aJF¬0“2νÄÇÂ/Êi­@,ãó"L’+˜Ü³­[çh'XPLKyèc‰ýü⣉ܓõ2ŒÔò¯ßÂGµ`SØQÏ¥*+¦ˆ+gë‚Íu'ÌLÀLÀLà‰°�ú‰’³¿‹A 188(#ðÄ 7ÜÐýðÃ÷1«z²µ~õl?¯4VG'¡4Tó�œYÕ±NõÈöíS¬ 6Õ·µ÷Š+–½¦««+õ÷Ÿ¾ýž{Îo‘¤ÙޱÃ30˜oJ£ÆÆÂ8=ßàø>qÊ|ÍžîÃ,Ya_Z)Os<Î\ÚOy n4sZjýºpÃÿ¶çõV*]J„ÒÕ¹uÞ+¯ÏtS^?Ÿýl‡w>Ï| 7e6–Ñ’‘úB’÷�ò-X8FîÿHzÏü|zã‡ó´éu¿’¾ð¦ç,œÄ9%&`&`�JÀêGÅâ‹O6�{Š5 §Ö¬YÓ½qãÆ¾f³™MÇŒêÂXMÈC;wf¬U=:222ÆÓºê÷ºê<÷•�©®Þµ_øÿw¸Ã1ü† ˜€ ,$2LÅÖZâ£<½¼öjYù…²udiàsË[VÄp#S^Ë ‘•[çáožüQ”ÃMšµ´‡’. eixÖ¹¶Ò�fPkC[9ß~&»H#«ù{Ε­J{¤¿L7ÛV[9,ï³/h=ïÖ­ÂËoDxjýQùÑsä¾üÉ]<—ëú£ùåòÅØô8meÒ‹3ÿ58'�‘‡¾š¾òtþµ IDAT¥Ï§»ŽO¦¾+úÓSo¾!­Äõ%¬·çŒ›o\<û?ýGéÿþí_§÷ß=–N íK÷ß{2e«nJ›¯£m,Ç‹÷x‡l&0Ø@=2ÁQ8/Í»ï¾{T.—,YÒíµ×VÖONN Ö—W]“eŸã¼{GegBÎbFµ4«zhgʶäiddº¹²vpj2ß\KõÑý7=ÿª=>}ø×÷v§�þåÕ› ˜€ ˜ÀeNà²^âƒV1oÍÍY{9,ˆ*˜ì2:�¹:ž2ßá&î—K]“¦Êý0TÏCëDD¹oíê- A»0Ƴצ¤ê~i”myÑ­y¹)}2,+½ÓO+oÙË`¯C*[•F]›–~r¯ûZÞD?Í>×%£È´îÉ/ÿa¨âvñ<öz¦~ò«ML#LŽUÔÊ�RêÞ%Ø]mªåÖ]xo&ðHõñÑtúô©4šV¥M«¾1½æÕOI}�tæ+ ŒÀÒ«nMÏ}Å¢´t33èÿñÏÒZ’V½à%é›�°Ð\`™íä˜À9Ø@}0¾”†²á‰-YµkzÝèH×=oyïh~tÅt÷÷÷nÛR¯Vþ?_ýªÖ©nu�ä› ˜€ ˜ÀeH ³P[Òy~yà ÅaˆÅèœOb¥Ó0.K¬3^×ÍzùõðÃB+ãtÎý\M6ÝOº/råO7æÙVf|™„²”Æè™É‘»ù¾)�2�‘Ï'ù��ÿú(¤ Ì‹±/!¿{8–az”û§ùɽî÷s_–ùÑ’(ìÂýb®Wø•3ÒÅIîdÜVXãüFy–ö:×=¹U¸ZBE¤¤HÅ5Ý»ÄO�±ˆV ¿ÄO÷ãL`ž=‘NŸ<Ê×e7¥•Ï~Qzé–þysGóB l¼)ÝÊïê5ŸNñ÷S÷¢åió³oLë/$Pû5˜Wl žWÙåÈvÀ`ܸeýú/l9v솩juõTJ‡:ïÏöñk˜C=´}(c‰�l颥k»GºîéÝ“ `´Ðã&ÓŠ>��*¾á¦›®èÍ~ç�öÍv<ž ˜€ ˜Àü!ÐZÚC¶0Ìe—éFÊó–�:ç]¨&_”й ÐÕ%ì¡£YÔaÀá>~Ș.U K"Çh«úÚD&‚O‚Uq6rmf�¥òѶyš¼G$Eƒšù,ãó̱ûùÉ-Cñzò}yªCÊ(ý0�ó›à¸—û«¸·\åÿ#ø)×ì^Æ5Í„®é[ÉJå‡â”&¹~‚…u’}a Î‹5À¹?€ÿÕ,ø]aϘH±ü ûK´•ÑåéÞLÀÎM`,�8Æt Ãõ´zÓSÓó^ùì´ñÜŽ}g¡˜<’î¹'}þÎÓ©ÑÓÒón¾j¡¥pA¤gâÄ�4øÅ÷¦‡¶þ`zñæbÐwA$̉xÒ Ø@ý¤g�#p!¶°´G¥VYÚÓsdèB:·ßèPt§W¥U«NöŸJý©¹eõ–œõ°Ã7K€$â�}yûvõ“÷��U_¿yó²f¥²d|jjèöýûér{30¸Œheµ#2©•ªË(ùIUêùiæ´fIk&u+aS³¤ùÉX­™ÓñÓ,k¹ÕÌêVA±u<_weZ´ŒÒ$4«WÛB+ J�~2ËÈ|˜¼=„á¸�´ŸBKÒÌùr‡c\ÓÌçåôLq.FS쇹¦YÔ2fkö´ŒÐU~\n/‹¢é9š­}šÇxÎq9à†fbOr<νeü2®iFu…è•ñ'©\©Ô{3xTcilt<�®\•¶=ãÅ點»éQ]ùâ%pr0=tß]é{—§�gCú¦›—/ЄÎãd�O‡ÿícé]¿óž´î­?˜^¨v™vÕ› ̨gƒ¢ÃxR T+•|woo>0ûË{„¨-�ÓJäŠæ«Oõö ÷¤¡úê�«óÛSaœÖ=i�êr™ŒÕ�Áíéô5#·ŒŽ/zÍæÍKkÝÝõ¿ÞµëNåÞLÀLÀ.2•]¾ª;)�õ£¥qbpÖ¬èœ_&c4†Äœ×ŸôS«Ç\ÓºÔ•Ö êXæCsNEpPì4ˆÊ¨ªM6ê�´HKùGiÒO3ž5+Z•@3¡GI3»´ˆô5°u_K‚hƵfDÇúÑ\çõ5ëZǺ®gh“[j¿5{‚5?4cZKzÈ=÷Ó!€WyX×b&v‡ÿäâÿQ´½™€ <&�É45Qáãˆ7§[¾í›Ò­¶O>&­…vsìè¡t࡯¥¡e«Ò3Ÿýüô¬U -…ó<=õ‘t|×?§ßþ¾ô7C/Kï¿ãôNw¶ØÎ˜‹Ë+OxßîDhY…²xxñÚCµ|x ghz†qš®Olí*ê¬0V§´+Ý‘Òvõ�¶�v?ÞóÚ«¯^Sè>ÑÛ{âö{îQ·Ü› ˜€ ˜À%ÀRlbí6e�&ó±“EêetÖ”Õl1FEŒˆaŒÖzÓZîƒ{¹4RY&iQµ¼GƱbmjË ¹JY(?Œ¨$ÉHªkJöBÜXM£m ÖÒåºÑZöC3ª5#Znø†f¹�Ë@­¥?Ħ—ò¡â¡ë§¸ C´>€(¿š!­õ§e”Ö,iͰÕ^®kÖõR~š¡}År#9ë_g®5»:‹ŽµÂ½„±‰ÕO.á#ý(˜GêÇÒ±‘%iýº-é¥Ïß:�"î¨^8�‰´oÏýéËwÜ›–®zaºõÏLk/¹zh¨RŸ˜XöŸ¯»®šuu�úó»ï¦‹~–ÿV0Þ™€ ˜€ Ìg—½qZ™W¶ªh�a|fu¥##�¢ Õ�“\×¢ãþ"öše-ã4ƶ…5�7aÐlaTµ„E9ƒºÄ3�“öˆ¨+�Z3œ, £³ ÏZCZçší¬´Á­%N”ŲÚjŸeLÖìiš5»º›½f#°=Ì�– ‘qZhñ<†'œEx+¹ÖÍo ìÜŒ-ù¡ûøÓr"+›Y<'碮_Â�…½ý>Ò�2�'ƒ@=�?šNœO�ž¥iéÒ¥i‰F›Ú›ÁH:rh8�7š©oùº´l /õœOõ­7¤�[®OÏóìÙ6­ó>hŒ§‘'Ó q”§ZwêX™®XF£ª�åŒ÷¤°îë’8šCÛôî´÷þ]é®/®H+ŸËúÓÏZ�š�Ñtü¡‡Ói¢I‰a[”–®Y––ô÷Ì;AÚNÇOŒ¤Ó4B­­ÚÕ“VmHË[ÙS^Ÿ;ûF¦�Œ¥#w½;ýå¾3ýêûL+·Þœ^´iyÚ;8Èhóštåò¾T›×ë|�ΓÇÒÉS£iª¶8 ,[‘–÷uÊ+r„ÙãC‡‡ÓØt#õ,]“–.éO}¶¦ÎzQ�cRiÖÓç/Õîæl–ãv?EK{hkœì[Þ=1}¢ç±�Ó3I« �vT³ºõÛɹŒè«wî̇VßÓ¾òÊãû×®š8}ºö]×^»ù{¯½v€'Î�„xôf&`&0/ 4›Í²ËQô«æe*f)Ò2ÒZË]Á-µfIkMêæ({¾Ò �$Ê ]§ÛÓfÛ-ó,Åe##ìBß”m28«Ïªe>´|Ç:òÿ ~2Hk­èœ�ÒW׌iÍŒ–áZ³ õ‘CmRðdÜ–‘ZÇR’4³Zþä_KzœÆB­ÙÓò³wš9½OúØâbŽµÌ‡ŒÙ Ô2¹fÍ=cšéìšÑÎÿK¹)éa7º”õ³LàÒÈS}’u¤Çö¤¼íµéÛoÝ’žûú·¦?üÌÑö@”*^sb8�Þÿûéõ7ߘnز%½þÿKú·ÃÔÆ·¥W¿êÛÓ|ûµ—.Ê âIÍ4=1žÆ÷}"ýùÏ|oú–Ÿ–žö4~/|uú÷ïülš˜®s4�}üçÒË~éƒé³{N̹T7Ø•îßuoúLeiê[teºbõñôð¾ÛÓOP>®ã·%~¯Oo¿ý‹i/FB Óy±5¦ÓÄøXzèÿ–ÞøŸ_�nP¾ð»ñFa^òêô ŸKS­6oî¥çáô/¿ó?Ò÷¼èÆôœÿøSé7>ø JZ% ï»?ýéHÇ3nIOû™�¥'ôñ�ù¸I^QoÆÓÇ~óÒë¾aKºí;,ýÚÇw”/äÕôDÛõ§é¾è¶ôtÊákáïÓ§÷]bía>â}q–®çÍ�!Äå&¤í{Úžii�±ÃÕ¥Õáñ‘ñ�ã��g¯9}¾IîÊ_ªe¬^½³0Tk½ê¡M›F÷­_¿ïP£1µöškžò†o\kCõ椽›€ ˜À P©Tdˆ’®Õn_æ@´ž¼(@¡4RË8]a¹�L³Oè˜Å:Ôº¯uªùÉ�½P–ö˜ \F[m2¼jÓyë°¸°€þ*]2*k9‹—RV’çëZ³ŽÆÐ¬Ÿ–î�‘¹\KZ3¨e°–ÿ~üi¦µŒÌ2>Ëà¬�jÙÞ¢ 7ZßZ÷ô‘ÅU•¾ÒJóÔñÁtço½*­½íÍ韆1šrýŸþõ®4xèÈ‚¤riõ…ôÇßýmé¹7¼1}¤ï?¤ß¼ïH:räHü௧·ünúŽß~Oz×ËÖ¦-¯ýÝ´õªkÒú•soqïvÝ•vÝ÷…”6¯O+žµ<-ýÓI[oøoéÏxÆüùOé�ÿímé·Þõ/é�KöŸòù_MÿáÅÏH7¾öó©÷e¿“>C¾DÞüë?¤_|Ñxú£ÿzkzÓNÚ¥9i¤^—^ôÆ?O÷}éßùéU›Áqå-é–7¿?ÒpäÀCéÈo|[Ú´¥n^nûÒ{üÅé×Þ”^óö÷¥Oâí®Ï~)}æï>’îl¥§1~2 ¾ëeé©Û2ÝþÀ‘tŠëŸúÒ=é¾Á}ó2Ås=Ò¨mÞL`~hLUèj`ô½°I0ê·°½&É8ÍŸ”ò6êé±±´9Õeœ.æAËÍžlÓî ÉH­ßNÂÒŒjªÇ7nl|eÆݕžžã‹·m[ñó›6ݲcû¼{{‰Ty30fP‡.Çæ­E@­-&º0DÓŸ‘¡:LøÚµ–öÐZÕ ù}"!�qZÆØËa“’¦¤j)}¸p µb#y,C³ Óš ­e;ôQDÍ,/gQk–³Œ÷Z›ZIÆfù_U+f@kÝi͈. Ùy¤µŒˆ~Kp«Y×ò§Üúé˜kR˰]<+H®]ÂMQð êKÜ�º”T¼¯LßþkMþüWÒ½Ÿú½ôãßvsZÛ¸+Ýùå�¥üäQ*ûiϧÿ"}ïÑN_¾çþôñ·oO[Öô¥-ëV§e‹i¼}ýüßô¦—ÿPúåû7¥—üæ;Ó/ÿôw¦ç_ÑŸúûûÓÊ-[ÓµÏý†´ìmÿ=ýì§GÓÐéëÒæ�ÜÓ+-sjûjÚu×ÞtßšéªìHê½ÿÎô_þxsúƒ¯Ü—víÙ“öðû»¹6]·¶‘¦'?™>þéIŸ¹cîÍŸ‰ô3ï¸5=ÿ ¿’ö]ÿßÓï}àwÓÛÞ°=Ý@¾ô÷ŸJCû¾˜>øg÷ÇÌw§i–æàÆ·º{Sï¢ñ41|:ÛÇàïâÅézf«|ů§Ë—ÍÁÈŸG”6¤—¼åöôžA^}ú�ÓÏý§ç¥��û™Éÿ�éÝfÀlôH:ñÏ¿ž^pïÒßâδóW_•n¾z mZ½2­ZÊ, o³N@ºš7˜×fa‰�v ½=ñAÄítZö7–7«Í -ë1KÆéNÆ�íO¬UÍŒé0RËÑ.ýÙž†»Fn91~ßdÏoé¿z¢Vþƒ]»Ðê¼™€ ˜€ Ì3Û<‹òÅ�ňƈ¨ÙÓñØëMkÖ´®ë\È06M”š~¬£7gÏ]ÊŽŒÒdilÊNÍ„ÖÌf�§˜)? ˆ‡[Ff]—Ñ^XJ48�e8Êe>d|Ö2!ËÙaeÖ:Öš݃C}tQl²å^ÆmÅ�KQ”t¬×MÎtü$nî=‰ðýè‹M Æ’´W¦0ÝløŽôÝÿéké¡¡éÝ»÷¤;¿ðÏé‹+{Ó§>º6½ýǾ9]}ÕÒ´áû~7½û[O¦lù–tÕúþ‹¹…~Ž<øÞô¦ï{GúëC7¥×ýøÒw¿â–´Eë·RšÕj©«·/U�¥cºvÝ7¥[·¤esmÂëðátäèñt�¥¾Ž¤éš›¾9ý‘¶\½1-m¥eÕ�ýtºë_ßšFŽ|-=pàp<|œ;ËZwçÖnzl8}ñ·¾-ýÈ»¾”Æ_ø‹éÍÿå;ÒKž¾>--×axÚ÷e ÔÓ+ÓâÛ¾7ýÇÛDUƒ7W·Á]é¾½¤;¦W¤u«®OÏ}憹Ó¯3^µÔ¿ê ~xÛ°âÿgïKã(®´_÷\šI£û–,Ù²%#ŸÈ áŽ�rßÙì.l6ÙÍ&v“Ýlø“ͽI6 KHH$á¾/�cÀØøÀ¶,Û²¬ûžûì™ÿ{¥éa4–lIÖ1’ëÙ=Õ]]Ç«¯[]U_¿~EïÿQêèÐNol~‘v¯Ì¥'þ”G?øÆåÔPå ¥øvºë‚ g•Se‰~gN±J™ü¸èÏ®ã&’'%錀nA=M1}•wD4äÑßZjõÎŒå´^Åx!Ï‘ *r‚Q²š‰êm|<ÚÔtØ<4dùPmm…569�i‡õ5Ïm¥H$‰@# àtûà4VtžT$!³‡ ç™0œS¸­Ül~Ä `NkŸ»Ê¸mgUl¤†º\ʃ¯˜Žp˜Bð«�–â$Ï«¿¦/þâUÚaý0}çÃWÓk’ÈiV:k­½úVº³ÁCVü ¬ÇŸ� ÒUŽî}“´¼E®œ*ZS�É�÷b“ƒ–¬…{¢µ+é¡W:éð“/Ñc•d¼æ tyMŽø¸O)¨¥&³¥Ì’ ž5heÁs…€É`˜î}œ˜—09ív»c0'O�ùÂÖ «�šÙ ;â¢Ï�ôã™ Ç”�…^‚¨æZšá§DugSS�µ£Ã�SSSðQ›Í3·s§w&‘eI$‰ÀŒ#À„T¢¿™ñÒ`�ìñDx=áÞOßâóL^4‘E>ÞqzÈq¾T/.5�~<ÞÕ/NO?ÅP/Š]Y,Vá¦1Í.;‚¸žLF3IÍmfëx¶¤æE yŽ;€kÏ>¤Ù%“ÓL2gà<ûŠæüø/þ€xòΖÒì„óòþ ¾§™¼ÖSÄnâÖ®Øg—!\ÜLv3‘ÍéæPXÕ9®r['«’Œƒ€¥|�V¿”ê3§ƒUÔm¸‚®?»‚¤3�qÀšBTÈ3L;ïù&ýÏ3;H¹ø?èCW4ÒiE¶„åt¢¨PˆÂCƒÔ#èÏjjº`ee¤꤃;wRkëQÊ]y-]zÕµta 9=Ú+Yñ™Œ1­¹Q�ôn¥?|û×´õѦ¯}†.Y]AyÖúÙ K亳èêºÄ•Jã�£´oû:°k„²ËϦN§eéf�?Cè™KVPíÊzZ“û:½1¸�Z"Ÿ£[/X"Ž˜!|'SÌt‰½É”-ÓHf�á@@É00…™²è¥±±QéïïWÌs™<š‹<žBx´n¦fžÇ̇ˆ¹X‚‡º Õš¿©I|¡•ÛÓãøôš5E¾‘‘‘ííÎÛF�„æC_Y§D@" �LŒ“RR’à^Ž{î6&¦¹GJ1XĶ9�Ã)‰Þk£lA€sfŽÓ·É–! öîF8^?7Ù²&HÇ*é.>x_Ô1AÚ…Íøó%¾žã!ÕL3IÍSuvÇQëù5˜èrÓ¼ˆ"“ÔìʃAäôZLä6vÍ$tf0ùHã†5ÿ�±E5—g�Ép¬ã~°åì{šÉiÎË9׃ÿs)Ü®RοæuY×ü"`­¢Š%ÅTU6L¯G¼ J«©Vºn=¹kq“çÈËt÷OŸ£·Ãë鳟¾šÎ¨Í£¬qž,a×õîÞŽ*ùäZ¿*—¬ü0�Ä}€víäôàà (nCƒÁb0özzß2�š:^ O&Xô<¼¯ÇñþlIr  IDµ2ÜÔäÆü-k`ÀÜ[W·ü#˰ÕdþßmÛxŠ/E" �HæýûÓägúük•‘÷Þ˜'«ö¸BL,sÜdÐJNߤ4³¢\Žð'/‹�9^ïÉ“ó"ZHüœð�­Ç�ðyx.ßO�ÕœF//uŸ��#l¹ËÂÄ)·Uãé$R-ÜŸxó¨×”4äKÐ� »â(Ä „‰æ\„쎃!Ä5ËÇ1§ã¥©Ù…“Ú>\Ø@œ¤Ö±¯M¥øaëk.#&ÑìƒZ�Î(Œëf î0ò†°3êb$†4ŠHËD6–uJÔ�äs%|7Ac)�SåQ~Q6ùöƒ >ÚMnZI’ó™þõ:»©åù_у»MTpöÇèº�T�9ÞcÅKCÝ{ióý[©ÛˆfýY´ºÀD©Æ¼Ó×dfrzn£�­tĶЮZ¹–VOP®~›{üäöUÒºú:ZR>½$LîžC´ý±§h·1ƒhí tA­…2ÓÚâûÄú·ÒáþêÉ\B–­¥ÆEý†ÉJŽÜ**Í¡à?uµu� /v²O “L1CŒ÷$›¡¢e1ã ÀƒR~Dñ¸™IDƒÏ—°_L,E°°ÅœåyÍdEO+ÈéÞÞ^c†Ñx‰ÛïÙä ú\‹¥><ƒm¨¡¡AÛ³g_+ÞXôP/C?=;{¿z= ¢šu¹¡¹YÔ«êÐÞ¦¦ƒì¢¤>.þòúõÙí¡Pë}{öð=¦çiå�D@" �Ì9Ü×ëýÆœWž– ^ÑPr£A£·R0�N�‡÷lØtw ¢§Êâ$§ §ù<¿À6&çå²ùªp=ñ²ÆÔ‡Ñš ªqžÃUÖ—Étð¤£ç¸ }ÓÓ#jL9|<Ž0qÊD* W¯ï‹ˆEòÃD¾�c«èÓ0O/Ãuawv`É–ÏÏ·‡”�4싚If&“9¾×®ä¶ y½m!¢a =j‰ÍF€Lh/AAìÓ:ä3çã4Œ+“ÓLŒó6ĦܶžÎËÍnBæÁÅ«&E"pj!è¡¡˜™"¦ *"÷�jñ]H�ÒÇÇ4ïƒ9ûZèù?>IíF½û¦+©!ÓFãy\ðµÒ®Í÷ÑŸŸí$ƒ=�ªß ­´˜I'¦©ÀŒgëÝ¿ƒ÷AÇÕï¦ëê©|‚|-oÓ·›´š&Z¿ú4Zžv¾Ë=ä:Lomé$Õ_Ùõ˨З$´gaDû©ý­íÔÒÖNÃÅçPáòåT·˜ÙÚà91^𙫩Ì3D�ýoÓï´I7¤XmAk¹°ÿ^ô………™##î÷cL­’õš3 ^òu��&;5áèûU“¹+àü=tµOM}ü?µ\³�:¤±ÂI‰>1ä´ÓéT Ã&·×Û‰DcV»õªQ­ ºƒ×kšf0™LÏVWW·Øíöhœ¨Ö+ÑñÒËãx=NO3ar ²Z·ªæ ;᧺FGY--æWU�·Õl~íîÖV×l(#Ë”H$�"Àã,9ÖJ† ='“—1 Âä/¿àG…Ï1[‰�ÓŒNO7†ˆfÄ¥„Ñ6/Ž8¯i™ðÖKA2sùú¨�_ãr=\.öYaÁ­ÇñiN U�) fõB_ŽcÝ9ëÊmHŽKÖ=yÉuIö?ÍÄí1íÕ.Ð�›Í~ž…Û `Sˆ0þ ™Iä l|žEÅy¶¦vK&�ÙjšÃÀ›}S÷a²˜‡NÞ‡ë$ÒàbuD&¹y�D®‡ËàËÀÂ/˜èfb›Ý{pÈä÷R ¹&·õ´£9æäÍ«qÊœ4RV"x� íÛL[ŽºÈm­¡Fí%Úßú:½Ùñyj\ñN*¹7´arõí¢­¯¨¤f8hEM1™Lx¨¥HÄÝG‡^yŠþëô+ÛÍôÁK×QFÚYó:éHK õ…¨~}5­ZVžÒýp˜v=ñ"½Ý§PÍ ÐÙg,§RýTÚ„ ú†¨÷ú)t8+ÊKÈÀÜòûÝOk~ IDATÉër‘µ¸˜ðŽ6M¥›öíl¥®öʪ/¤²%å4véÊ4U{Zj…Èyè5zã`ufÔÑ&åzéÀËð%~+m:mZÊLÓ@Cj)s€€Ñ=ì¾Ùè°ÿÖ?8Ø…úb §ç Úñ«PÍæJsvÁÏѽ/ŽŸâ„±‹ÑþÁˆ÷'HÉãΫ˜¢“² æy ÈiR˜œÖB¡ó‚¡P-æ>?ÎÌÎ_�Âóp�mˆàúô2q)E:öQÝŠ ŸÓ+3 T‚DÙ(\øªFúy�c™¤yPBV)˜ "®ÚüÔÒrªé«LôÊ¡gè ïAÚwoWH“Äi]Ÿ—ü]�t¤³¢¬¤ªr•Œ)O $iÛöǨ¹ù9Ú鮯³‡LÙWÒ…ñ|�V¥³˜É÷:½öj?µ÷ÖÒúâr*Í¿.O÷ƒtÏï·‘+r1½¯é Z�æn&bèð|N7ÖQˆ‰¾-µ» {‡èèþ½´¯ÍC믻”ÊÆoöüÇúÛ©í°“úmtÚÒe´±¡fþuš% "žÃôZó.ôÒÅ×”Ò®–陞´»ÅƒOÁ¤ãüY‚ý˜b%A} $3Q@V·90ˆ“ÓI5˜vû­š¢ØK–jµÙ“u ø•³(VZÌb²e¾­Ý«Q³¢æW7¿¶9?;ûŒ@$tmH‹Ù¬Û«.×ð= µy§u�˜ÎÖÂ5d/xÜîî³ùƒþO²q�j4ø|ÿ‡]­:+«¾ß¸F ö™² ëΫÎu½Ð뤕a¿ßj°äü©ÈºpØOtQ—¿ÁdúT0+ëÞX °¼?JW†µ˜Ãj.{ª0ؽ¡M‰æ[MÖï9Škÿ’ïêò›Ë#];ß,(XYêõ–\à÷?ÿG»¥è‹ŠÁçƒur¾jÏÈ y}#am¥jq¸{}xþ0¢÷ *�@ƒ º6‚„®¶ƒˆ:‘h4z$333š—Û�$¶éPŒnk$b¬uy\·vwwwTVV>7 ØbIVÕ˜" Ñëá=nôÌìü¦Ö!¬ª…Eu¼¾¶¶¶55¶vt®]¶¬pÖ: ¼¯£Sz)‰€D@"0»(FLM@�%w³[ã‚)]‡D“çÞ-¾‰ŽŽ i&‹ÙÊ™ÉcÞÀoh#ˆ™ÉÖÍìÇZÁ7Îl�ÍDh‚L(Ò¡A^¦ÖÇÇHÏy8T8dáP'¬“Ž9ž‰j&Æ£ø>Iƒ^\·Š¹‹2•uõð›7Ô/tÑëE~&W¹9àM…pU¢þÑÃEóËMæ¶ò%¢c€ƒ¤]±Ï®StáôŒ‰D²$a VKdbšã#‹­Î—Ádz96±è!ò3©ÍÂiXø8„´œ¿Ü¬Šyß'³GSÍ˯œÍ ì²ÒÙD Õ(ä$W ƒ²ò3Ɉ>ù{zÍÖ@k6^M—+ÏÐȺúåÃôÔæ­ºìBá÷2ä �)‡¬&#¬MgSÃER6VôÁp š£¢Sô¸|xygÁs�G ¸=Ô¹åtç«t0ãÝô‘µ¿¦öX(‹ÛÕÀ®Ì®Íh3áË•¤‡î»?âû®¢š2rùÿÔÓ±ëMUl5$Ê7FbE ‹/?%� ·¿Ï åüÀâ /ó)™O†B���üíÎ\ ÎõÞ—C~¥yD&§O³Z­÷ZËÊüìÂÃ94tiœœæyMtÛ6b:zèа/+«}WNvÎw±xâóÑpø]Èÿ±ááá3Š‹‹Í(O™ÍG¢|„º¤ëñ³Š9Ù}¨Aß 1O+lnŽù[[µáƒ‡žÏÉÙÉÌ´ýÍ«—ÞÐP]‚¤:>³©—,[" �œªø1ee)eÒpO†M�ÐLH³�j¸íà-Љµ6„­û8†‹G2b1%ÖIRá‘ bvÃ!Üq0Y­oˆWãç„55[TëÛ¸cŸ-¡9�Êy8-‡L|ó†}}ãs6XyÑÉrÈ–ÚÈêHÂè†Ï˜„ÞlÝÍúëÄ:Òñö±u8é5}šp“¾L“M¨†RÃÔücÎã@X]W¶væ7تÍá™0Ç>ŸO¯‚ŸöAÍ ê¾§“Ëa‚ºæØk°"X,§Ù÷4“ÓÉiSõ˜ƒc¾æj <Í‘UHF µÓc_,‡Eïéžö!Ú÷À—éoïÅ×Ké’u9”íÈ£BXÈRÏ y~‰6Ç�Û|[ýÛ{éV~—2 l™”YVEk±ŒT(¸•þýÖßЮAXꊬoÑ}_ú Ýðõ7ÈS÷^º­ÉHÛ^ÙOÖìLj¼lêgé[·=KÝÝèLÓDÞxåqêïë êu+é´å5”j@Íäôá_]IŸ¹ËIëþ¹™nûȹ°´Nå�Q£˜òKÖÓ»®Â‰0Þ¢¿þuºü¿ ÛàËXO;ô Ý{Û‡è+ÿ½�—ÞE¿A?‘žáöמ¦Þ®6¢3VRõúT±ÿ)ºë·Ð?~#=ž¤VZÈGÍÿR—2Ÿ§_nk§=O}‹¾ö§^Ê9“Þ·)Ÿì™ÙTRZI4â¦ð}Ïâ/GØHÐÖï7ÑwîÝL;z'Y‘L6e$A=eȦžaˆ†|Yš–�™WrróØYH‘ñÌ1^ ßùÃ~E�¡H, 4f0šø#R,'AÞXÌ.öC±œ8èµZb §ax£ôG"±.“‰îlm%M5(šÙ r×ÎÓÕæuÿƒÑbÑÈ``÷}˜N½ó$WMF¯AU¸\2š3&«i0ž�ŒÆ Á1aªGF'6�Á �£}Ôb1üÖñ×9Å9èÕ´bM´%¢ªÁ jà/S°$z°(šÁKA ¨Òßo�À;b!“ßjÇÆà‘S·„� '=) «*öÇk9ír¹Ö†Ãá3`ý§ÜÜ\[Aó«ôGÙr:IâSH&ª)ÚÑÑéëëkÏÉÏÿ#|S? ‹ëœh4ò ¼¸p``IAmm­¡±±‘ëÑÉj½(Q7t]ôøÙ zscˆj`¾tÛ¶èð¾}νöüö`ÄâýäŠ5ŸX¶¬ò³�� øèlA)Ë•H$'�@,¨%5Yã=˜páWLF³•2¾LP¤è~C (:1 Ëea='œÙÄEwÁ!Bôʯ5÷ΓÜ8½pÂ!o¸‚—u¼ዚ‰k�âLŽ  t2àõ<ëIé€þHÅ0Ú‚aN‚¨¦ÓÉ­XFMü;Z§ã»ã;ô¡3WÒ’øý^¼òú³ïúÜOÿ›>±VO”®a'|Oûa¥Ïüô Zgn£WövБ†¯Ñc7§9³~\HýxN5ãy¥á‹‚ûé_¯8ƒ.üÈ*>ûjúøû׆u ÎJ©ôô�t��sàçt®_¶_åÿœÞwѹ´îjí¸5É“SG@Nš¦ŽÙtrD”ìÌŸ›5ÿ¥ F/»lv•oV‡ûÚLJЊYÎ�’ñpÔ`sf¨šwX5aZ‰Z}ª"Èc2Y•p$bê'ÚV3ò×#�E5™ÞFÊÍYf-äV ú»ç¨!ªí‰„#›4“]S4/¦J½<b3©î[–°èÊ2E|Šu´>ÌŸí‰@`𶌌̀ŶshhÈ‹ëë\ÏÕh‰™•Þ…“ViR_jwº¾‘»tãf§ûð Æpçò ›ãkÃJhÐhºŸ+R(Ú o�b¦ÆÔ>c¿M¹­ÄXωHeÎ:%1hO9SeÌ܃-§aõ¼þ¤Ï…+�;òóó½Û¶mKè1'ê©õ4*LfÃbºî?ža�émƒ×¨±˜·¿¿ÿ¥ŠŠŠn‡Ã¡q:œKÎËú±Nz϶èu%Tä o`š› 7“ýM{!¬Àí^oùç×­£CÝÝýOõö╯‰€D@" ˜° Nô¿3PÞâ-"Þk&,§Aáñb‡:+¶ffkeáJƒIhî�™àÅ<ä¨è!%ïÇOO)Ðóë!ôõðˆƒ÷9`�quÙ-“ê‚ȆµuÂâÄ4ìÂB›-¼ù\|ÄÂ>µC‰‰2¦¤Ø©‘XÀŽž¨²™1ê ¹.œœ³¸"}ü„¾Ï–ÒÆx¾vz¼êåÌe¿¤F¬y"ç_s º¬k€Uoöôþ/¬¡ßþd7¹Š¯§ïÿÇgèº ¨ÜÂ…C%Õ®9—®úàƒôô= ˆ.§Ûš¿L—VÖRe¶tï1鋤ة¨î"úÌ/~CáÏŠ~²ÛC#l}!}þÇ_ ¯9�VäQ¦å(Önˆg"Ww+=ðÍ«Èöõ?Ò—ssÄW'“®o–š–\K_¹ãºþ™;éw�}�®ºëK„š ²åÑYÿù=¦•Š—US>¾†áþ �Eµ•Ó²K¾B¿iýîï>„ë㥑ÁøÔúÌOÒW?ýaúÜk©°(‹¬ißQa \`€%Ùvÿ÷è;¯¦ë>ôqúÊÕ5pï‘öÊç6±�Ñ´Ï«uôÇ¿I]Wп~ý³ôá+×Ó’ ¸¿áœj •/;�>ðÉåôðm4Òw}Ï««V¯£¥éÞã8àžô©…|g�tãç²�—ÜsüE¯sðè!}÷_°F9yÝ0³éî¦Q†¼.¤kèàQ¼ÑPëVLqèO¼ß38ø:Þ(„ydË®Á}øûü³ßí{ÁƒйçÄ)Úµ¯cQ‡ˆxê�£»ãUˆãƒý®VìÜξÀ¨�Gß ÿ¯8Ä AOH‹Ëu‚{Xé4.w‰ÐçÄ'F£ú;¾_é'»Â=?Ó÷á'û}&B�ôñéÞ¸¥q7¦ŽŒŒTû|¾+°â¯á—Ù��ç8¼‰näõÙØ?�CpÌ(÷A@a5ýr x.Cj††.Ç8 Vð�׿å²”–âD5g`IÔ7z˜ˆK:œ•Ý1ó¹ûâUÜ ·qÏ­-~C€¬ÎþŽÕzÆn£ñÍå­­žÛÄÔ{Vt’…J$�SŒ³˜’LóÕ|_ î¥@Ø rÃ^��­�µ>Dƒäî5ì@³VA39Í$5êo³Ý†äKßþªyÂúsœ_G›yê*ï³5Fp|Êíˆf!t7"}Æo ‹êäžÑRF/-ã àŽcž Sò%IÅK?—xy‘š`~�åük~ñ—µÏ82g/¡3nþ =v¥‹4{5­n¨ |»Y¼G­Î Ëßóè†Û~O§}:„¯xKiÕê唋“üø”2Y°(bF>-9ýZºù7Kp‹c‰ ©fíR*/ÈŒ¼%Twá§é?ž¹˜¾ˆ¢ F3•¬*§Bô?i…·ÉA%5Ê»þ³T°árºaH|ˆ-À0Y3©t媅e]¯ÂuV9­<óJúÛ_=C—á 0 c!yKhEuUæâãö!&Z}ã÷é‡ç Ñ0{ŸULeUÕT‚JãÊÛ÷Ð7~þ0mÙÛKu—|’nøÀMÔTÔA-/ý•¾ÿרÝÇè'ÿñ*Eæù½á+Ü”O«?û?tïE#°TP}]çXÅKñѶ)«¢‘.ûç»è™›¸ñ%´jÓr*0ã%ɸ�—‘3…Àw×L/Ë‘Ì+Çá�ýRÿ6®)çÑÏÅ£Çú|G?ƒ¶ˆQ}Äô¯¼^¯ dõ#ÑèÕùÏ.|ºöTAAA8NTëeëù¹|=N¯k¶CÑ^®D'ªy_'«û÷ìq=Iô[U«+jÎùûŒ¬Ãù;wv݆±§“"�H$SE A£N5ãâOÏ=6¶&†±” ¦™�ÖÑéÀàˆ­¦c<¹Á>ûˆ†²Ìl¨ê=süÔœIu'܈°Ü®x›„«Ó*[SÃT�Ý”„Ñ– · u”ÛÍÖ×<ãáòxÖ–T.ޤ$!°Ð¡�õôBoBÒÕ�»�wPŒÊ\²�š–¼—ºg°åQIÝYØRÏÈã©!’Ú’KK6¼›&†;ƒ²‹ki-¶… f�·u¼-eO¨#Pc6UâúTž0mz'È®ZO§WMRÇ¢5tñÕ6ÊŠþ�^|ãiz²0�Œ5.zù�÷ñ›ÈZTO<ŒK‹Nƒ3kÅz:§bâ¶©Y”_»‘Þ½0þ„&nÈ;# êvÁ¤ºcF"X°8¢±ËŠQñüë(.®„åôDZ âíã�ÓœE<#sŽOa…Éߤ”‘zÈSN]ôg+ÇéD5ï{áNäÏ X¶rµ«¿ï; ­{«««ïAÞ…xá&„óÄ7Ç<§“ëáó3-©å'\€$ÕÑç`’¿~µ[W®,þ^ °ê‘ÇŸoÂL«#Ë“H$�S�x/Èä4µŽ%\z°Û c ºY·Q�ÓHj&vy�B*‡ 0&r©›Àé#‚x(,«yŸÉfŒ´´#ÆVkøL– xëÆc^D‘]€0ŸÍibl…­“Ôz¹8·˜E”ˆ�Ðnnú"l¾pu']|,æûY¶M" �œ’œFç]|5Þ¦#ÿó(=xÏ}ºì":§ébºøüZâȤHN„€$¨O„�<ŸÖdåå©XÈ1LMM”DRó‚ˆj¿Û]öx> rú§ §1C �iWPÃÌxTôpÌùqôtúüI?æE9.‚|{~EÅ.ÌEòáäF,ÐËÍÊz³¬¬ìÕÒÒRžŽ+I~°õü\•ÈÏ;s$\·h‡nU­ÕÃðÓÝOÔokll.Tû7²³WìS”¶û¶oG´‰€D@" 8!èÞq’|ÂÔ§Fîu°‰ÅaAL¡˜°’fÓLâóÑ%a„*È[&¥áÿ .´(|û8• ¦Aì&,�q*m„{TÖ“ÛÉdsœ¨fÂ�}&[ 7¯|d×hsÖâ±lŒ �ÌÙšZ'ª±;ÚCóÎâ†ˆÛ hHãö#d¸Œ!ö“€œæw|×K‘H$‰À¢C ¿átZYð miƒuAq#]$ÉéEw�g³A’ žMteÙ³Ž@HÓ.Ù,ýó&§ýÃÃ%ž@à#wtuué‹2ò¼'U8N)+)»³µµu¼ó©éS�“óèó(Ž‹mãyUGѽÐéG98±Ýßî:zt›Ùj}ñƒÐ‘-°õrõòô²8^�ÓÓÌF˜\G²E5<šQŒ‰jTêÙÜDÛ³»ë¬Ÿ\½z©Éë5”:tð¶QïÙÐI–)�H:V�Ó̵%?cz›NNF›°œŽÄÄ‚‚Ú jøh6–+¤æ`YI¶�æt ò„Õ4zDá—š{Ô6ÄÁEƒÊ–Æ1œKX#.­DïÉ¡'ï ]ãú2oÁR*Èê(æpá£XA;Çlb„ö‰…ÑHÑ6n”^ï/—?l"K�÷„[‚xqÃL¬„ÅDõbiö¨á4ZƒOzEÜÕ‹ä*Êf,¼ä%V‚ÇâtCü©Ç"�¾#4 QkøG—VJƒF¹°¢S€úÝAò¹Ø~JŠD`‘!P\FùT›m'GQ¾pëqÒ-좑€�z0^ò²Khò㟋ú‚ÙúEÄIW1븇ð7?H½Á2Â3IÊøðØOŠD`A# ákI¶ ÆóJ¸õÀ‚‡ÅÎ`ð£ÙfóoANã£`1ÍÅ”'!Éû"rxxðS‰³ÓßI-—�Å«ê(¬¸‡s ž†OêÛŒªÚ …>åu¹> }ë+**LðcÍó0}KÖb¼¸äó3½¯ë-üT߇Òyc)l¦˜kÿ~ÿ¡üüöÞh´ÿÍšð×R$‰€D`tC~ŽK‰÷.ÂršYIÎZ/\{` nZÂä4ZXL³Ë &©Å‚ˆlAÍ])ÌkcAÙ°:íÇáˆ]ž“  áÚËNW‰÷âL6 ç|W`óàXµƒ˜†Dc.c�æt ]h#[�³ë±p$ÛÜò¶ˆ„/W”ol>ì¸Ñ¾0ÔO»5‹Ë-,«K“aK�–â?UH êÅrYY;ü Mý4 ÂÇëâ%{�t´ÒÑpˆzàÿ?Ä/8ÓBø5@ˆF|a z Îi�«T"]pu8ñ™�FÌìÞÛŠçÊ HO;õø=Ô�qŸ_¼× â¯ÈGCá(yGÈ‹ç� ÷R;þì]x&IIP��‹Œ]@Âa9T JgII,”?á°Zÿ”ßÓÓ‰f`6 6½E||ŒX ¦®c"§¡×§‡\оe—°Ôö•—ïÈËË»]5™ž g„B�îïîÞ¢:;NTóßf*1­s8¢ëÍa‚¬f‹j>î·X4øÿf#6)‰€D@"0>òS~—x�2º â¨åt¤‹]{ÄÈXr+ç¨Vto n…Í9÷.Là2A�p4Bÿ(IÍî>‘Ëó{ œö$5ãïÅU´ÇÀíã d¼‹(àâÃ\‹$°ž·£Ih&bl9žh“Ô¢F¸€…›ÀätVÓnì âåCK J�¹4 à˜Ý Àø`·p"Õçjø6Qý2^"p< (ßMÖ9,TRí8^Â…s.oÿ &ª.'r¤�ÜR*‡MéòâLÊ-M¥Î5•š¦7Þ^Ú»¹“Âù…T».›BGÚé ÓO#ørà$$»– V*CP€úD9ä ªÏ4QÙrq…ÏQV+¬0°P,?‹ø™$e|0D–"X¸„±H¢Ôðñ¬€¤¶{½î/eeeÝ}¨££mÛè4.y†“¼?¦Ñ�Hä¹13w�Z'³KöUÍÍÍ=œ�›ûû£ùÇxÓX ýoêÿ@QQQ»*AÚøtV„ÉZÍõ,'µÄb6M¶d�ä¾D@" �‹ÓŠR€“È1Xɲep¤–Ó®,§±Ú=ëŠÝšNNcW¸¶àc¶¨æqÌY «b˜ãDa× "3¶6^}E›þP³¯e¾)Xm&ã£hŸh;Új,Á¬q°® ·!Äça‚¤f kêczdä_ ªsûa Oà£i>=vø£ô�S£ÃÁ(-1�NM˜¤¶Æ ¤]'R“]|ÄÓįö‰rÈó‰€D@" XD<}ÔyôÞr/íÏ«¢Òw‚.Ï·“m÷KôØSoRóþJ{FS¤–óŒ€$¨çùÈêOXO«Q;�™ƒƒ߯ª*ý]QÑÑv”Ês ÞtIÞ×ã!¬®ÿ1q0ó;º.É:ˆ8�¨néê)íêýK~~á¿ æƒÁ`ðÓ]]ÿVUUUÉî? OlôM×P?Ö'=zül„IuÜ Ê÷…j¦Q55QO¶¤H$‰À±À6vQ¹Ò=¶…“‰A�§[N³KŽHÈi¶œ®9 _Ì œ :ùµ,Ê%\á—YÅZ“\—ÅÓ`wÙÍGøÐ(™+ˆk^iOô®œ0}î•…•°Þ«Ðnù ·&l1ήNLU£ía2m„KØ…nMÍ—†Éi?¬¤�Øarúuøóx`Dƒ{�(1.E¸Øµaôj§ïEœ¢f£ž=p c1öjÂã:)‰€D@" XtÝÿ%ºáÒ3iõO]Ë®¤¦µËhYC!eöü†~õƒïÐÞwÝLg/Š–ÊFÌ6’XšÑæ¸ IDATm„eù³Š€�*&UÍér�üÃÒʪŸazÓŠõS§§||\Y]_ÿ—×wì8nš:©ë‚é—ý˜`ñMÔÚÊÓë7±õ”—g»�Î/B!G]ݲG‚A­9??_©Íyõ|zxLy\Ü ˆ^.Ý€,ýMýl­®¬°åd4ªç¿×ÝøÂ¯¡<è)‰€D@"�‚¯4Å´«þ¬N9} ¢å:9Í$²6ÖÓæÚ¸åtœœ>†ÆçÞȱ/j•¿6×Ék†Œ{J“¶ømfWæå£Iăì:#Ñ{qÊô6‚�-ª…kns¼­lMÍä|¤M†_jSŽ™ÐgL1‚鸽QXzþð/€È.<†qý˜ ~þ¦ŸÇÆn>¬hs½Q%öòbÆfĶš5e°AT+‹Ê¹ö”�$‰€D`±!PyãoèÙë5ŠªF²˜FßÁ®ºú«ô“Ë¿„!›�Lpg&E"0x,E"°`À\7cOWçÇÊJËÿ`¶Ûw²Û 4†çAº$ïëqÇ„þ,<§Âzé›^±~Yëììt;�·ÙíöV¢ª­¯¿ÿ§GŽüíÊ%K ØýGc£˜»ñü-y§'ÇéåO%ÔËy˜œfbš·ìîlë…¶\�aÏËUÛ|ïÃÛ¶Myéܺ Ÿ3Ž2'«³(r™5¯2wi#lÏÆà’Zݘö%�TÎ/¬¸<é˜w•Õ+ëSâä¡D@" ˜ lÀ#õy¾M¦Â´J£÷j ™œŽ:£p[…u0|N;`5ÍÈ0BqBöÝÏi ðO-ÒP xz£§û–‚̬Í™™¯L§!‰¹^ÊþqÑràÀÍÇM0»'YçT½õ¸ØÀÀ@`ß�Ûm¶0[­ÏôºÝßìëéù¦ßµüôÚÚZpˆOk¡®­¯O&“‡‰é¦¦&ALÓHNæºðe,kÛÐoñwP0·c›LÑï¤Q•öÎué¢TU­ÎÙ�™¹j}NÎZ«Ùüþêêj|è,D1Ì× †ëqtÌWœÎ€ôK×®ÀyC8ê¿64à9w4kâWÍ6X®0,WSm­nS2 ì|6Çj½Öj^r]I~ÍÆFj4(R²Ül¾>Ól}N+µÙÙgv÷¹2»¢!/QšÜ‘H$“C€)ØS—ŒBO9ÍߨÄ1�Ó‹2ä«£,˜HÝZx\8¹—ÀHuÔ ÊÁ±’š-�B3âàúƒMŠ#}ذè¢@›QÞp˜n¢w|ìÆÂ•ôíû\Â!óÜF¶’†Õ‘ŠåØå‡±Í;:JTcùúQ’š±MÓ¶r{ø09íÃ}O•ǟG"ô,§»AT³%uÄ5[M×à'@q¡…j.`Q‰¸ÈúK«EÕ2Ù‰€D@" �H$'‹€$¨OA™¾0¶å䵺 ¯¥ØnßÎJ°Õq’2ÉûIщÝ1ç‹‹Š~�83;¬“¾éZð±˜zö÷÷Ž=º?//ï[fæ¯ý¡Ðê‘ááï,)¹¾ª³âD5çÓ§¹z|¬oz\j8æ<ÓºÕ4¹³r–†×¯3ù3l;LO<Êê/,ŒFLÁh@õŽÁ1µÐ‰Ž£šÊmJÅ–—ïÈŒFk‡M9½å¡ªUŸé NpnQÞu!mù£š¦Ý_\|Ç%·Ïà´–_¨…B÷úåõË,&ÛÓ–¢œ‡‘.¡[™µá.-ø¤¦Éìq;T·ša/*Ì|WQöÊýKõ‡j2hê%½½ÆPØ”[ =¸¤(ÿ¹Ú5g–·º\[Ë —<çêØo§R$‰À”ê”s-ô x󢆂œ†©pøH„;ÈÇ xæO=…#f„ÉOôä6#ž}P ·âµ&“Óĵ-Fª=F|Ûb^ â–_bD+\a ! ˆPQwryi¸o‰�ÂE;Sõc\p^´?NT°6±¯bÙz:Ø‚ÁÜ~°Å¸À8ÍHj¾ôìoš.{AN{°ñ"ˆ¿ Ók^�ú"Qr#AJEw]ƾ $2$Âø áâF…EG�ä¯D@" �H$‰À8Öˆ‰À@@Åb‚·ÚíÖWƒÑèΘÑhÍÊÊâѾ>â×ÃI7% U!qߤ3Ì~BnOOuÑÛkmmåýŽÆÆÆßšÂa\pžíñxn£ªò7–(Æ—Ž9Ò¡gЇz^>ä2S�E2&¤Y„+ê'ÍiÍ]YSÕìë;”µ}í'*Ü_(òrŸ×Ë_'ë(òOæG! ö`cÅ âJLUÉN#­ý­¡sc5ê!ÌSßtÚ϶›ÚZÊ=ªŒ¼^E &Ú³¶ccè<{$Óñæ0Ú´§««suuþ»¢ìÏ£AJf“­tè¥]˜_˜¥Õÿ�F£m°ºâ<çy²$—%"ÖÒ8²ô[²kŠN_Ùmm;bÜùVán&¥ é>üc4v3H€ÆFÅ’ZDNñ'Ê_𦈪ª1•4È`Q¦ªDA?P¬À`  zßâäp3º ät"§Ï—¡ÜBÞºÁàõ«Z¦¢h#6³{GúýG [aaa¦E _MåyÕ`ŒÚ©ßÄ+˜±€,á�Åy­-]bF“™u�"�H¦‹€îÞã˜çît \(ùb %c "™˜Žôh UANg‚zd׺ÿ†É ‚4Lvª°¾V, ¨ñÄgÖì‡9Ô‚:° ‚!¨°Ï �·ÆâÑôL榫Œ§Ú„úÆ'\¡BÞg—ì£:ÜŽö{Ñn,¨Èep?– ÿÇ«h–Aáú™lgÃîQ·1z˯Ñݰœîc=‚û‚JäÎÍ 3î^,r�Í@™Øg‚zB,�>턬Ëxx§œ9ͯSô炞S†‰€D@" �HNyŽ!‰NyD$éŒü×|7ªD™œ~œ5ûýQ,ŽHŽÑ9ÙTt3�ðù|·O%ó<¤Õ§8ÉzëqÔÖÖÆsÁ×aUý:Èö¢®žžÏG#‘ŠºººûƒÁà‹Xhч$9½ž'¦[L3ã "[1º�öuù—žwÐñÊÖ}±-[ WƬ÷½CLëmfšYbC §m°zÖã§‚î0û�îèèà‰ë‰D@HÇ¥ âTEåùk´¤Ìû󈿶¢³³u°4gÅeÝ#-r<6êêêò;\®+@<ßm=ÚwnŸ¥h³=¬™Ý™cˆå¼ìúKÉØ·Å´}VêÌV�Q-꯬<ðÃ݃K+íjHë÷ÐÅ9¥PSýQ ÍB¿ˆA-D Ï¥E½ñÓ2�H$'B€¿9µžx‚39-Z�'qø`Xøœ~§ù ›sÏ1…ÞCøaæUð6ÀZ˜­© ›±/K‡a-�÷eÍå£\|‹3å:�c΄›Î1«KÒ®56Œ'`ò9†Ñ;“¸ì“š-ªCûøEHëeðÝ ÒZœ×ß¶ž°à±ÕœÌ‘è¼QwÀA�Ðl9ý&Èé?‚œî‚¿i/þBxÛÀçù¥ƒm1bPk1Pî vyb@ÃæPåé5—ÊC&ÁÇÉÊ'�ðx¿‚(XP þ>)£Ü•H$‰€D@" �µ¼ Êò¥u7û‚¾‘ÎΣЕ¶¨*êðTô¤$??ÿ[ƒƒƒÿrR…ÌMæ¤éÎ1Ó Ýªºªü,ŠÕP pS__ßYYÕÕÕ?ƒuò°ÃáˆÂ% œxô�jü6e4•~èºÍ†Ç}#ôèãd†½tsaL·˜Nj×�<õ¢È4 ê½»_{4©\±»{÷‹Gw%Ú#ŽŸï=üïlmíìø9}¿¾cN�ç—äñpkðÒB´ÊC]ÛÆ$rí{’#†Øñ‡«ãUáþc¤�sŠÂE•æŸóHkëË¡V¢¿Ä3G[¶<ÒÉû;÷ly"'‰€D@"0U@žBÂ=6áÚ£3L1øŸ6ÖcÙ;¶pfb•{ì1=Éq°átñ´LĪ © … 0ÑOqÏo*W(°3Š7™Xx‘ã�vJå§êÙ<űð"‰LÔNZâx09-O`À Hšáæ#|8&ˆjs-ðaÀ›YÇ0~4«ïLB³¥ôËð5ý�3LÃØç·4ÜÌ›ÃîîZøv`RZ¡e`¦­h ;ÓâÛ#ý…opüçÆò(TÆYønÁ_Xý_0´×,†]@‘¸2zNJ$‰€D@" 8åЇ®§<€ôF`Ù²eŸñøüJw÷ÑÿLÕÔ�âÎ!õüdŽG\#Â×ðdÒ¦Q}VÄS"]ô8xÂØʼnwû+*þ”i6×ö ýVÕA‡Ýþ X.¿âˆ:2.(¿éªíöÇoŽÜý¶F;1­—Ÿ5¸„y� Ú2pu•ñ§Óó_ªbèV,‡oGãø%*w$‰Àô8µ>åÇ>v… m,4ê{Ú´ÔŒE ™ -ÇD]r�5 \9 3—LN3égÈg‚:^ìQÙz:Ü%u�J ÔÃéõmåÏWnB€©JÖ5.Éûzܸ!ò$ñ†làs¬–aIÍ„½eÌäî Á'§·¼ŠÔ;P¸›¦gܽä�ïqDfáÚ¯¶*ô¬;ŒÅ¡+â™�fÒz9j3oÂÆàú 7› §Ãšc°×ÎŒ@ᬌí¤cX’O&#½Â!›‡«*»%ÈKŠD@" �H$‰@2’ NFCî§%•ÕÕt:�™?HUпÅa�ípNNêWÔßB÷ä ™¿Ü<]b9ØÇ:5Ð~“Éôa›=ëö=û÷ß^S^Û^U±ôg�Þq/ÜcDG‰i.â>þÑE/W?>&œ®‹�c š§ˆ]íN6žþ\Ã]ÈðpUŠD m€ŸâkáS¹äô¡$¦ÇÊ4-¨“ËŠ�œüÖ±%/Še¸lØ8<0|}(ú?Ÿ;X“cÏùB[çÁâƒ�ûwÃñsÒ§çS#§ ^BÓóA=CÈkkk“ô'ª!̉�ÆËF7Ëee+ V›—®F} bÎ;C¸Èb$�ôA€OLÐ{¥�’3¥ È7AÔE�XR $iœ8ðHSg§ù$e€ð4ס ¸ë ŽcÒ›]0éŽÂj5Žur?S�›Ártõœ¬/„aqSŇÓcøàUˆ‚ÕMµ ¦aUÜ�k0/ Ä‚•àPÇE±3#ºú5 œÏË4ÐZXM3!Íþ¥ÙÍGkP£�景’—2ñgÚŒTˆëx’·ÈÌ4` ¥(°–Î8«”̵9 «aIŠb!Pìs¸ æºÏL�ç™CÆùsñqþŠÓ6µ¶¶ßQˆØ§t/H÷'°=¹¶¸ ««%kdWèÐÞòú� /¤H$�9F@°U¨Sa�Á‹\¸­l= Ò5|4L*»�Èíò£Óo©#éŠ÷ Mç¾ÔL6›±Ã~¥ÙzšÝy<8¢u6-ÏP© ‘¬6Ÿ?/ˈ[Dî>&m=>]¬f"+ΛÀÃúÛ¼2_�ÏŒmhV¸€Û�¨/BÁ]"�e}!Ü{à+^Yð·À¹ùË )‰€D@" �H$I`´$E"�~ÔÔÖ\âöºÎìÿ´ãß'Ü|Œ±ý�0å„'b¨àé Ï¦ï žä$ +LL—””¬xH‹(×–ä•ý´w¨ûo;z:¶ã|Ìl6ãÓ¨Âä4Üš]®]Ûk·ëêêR}"¦–Ÿ\ñºLžHd^>SÅ�æ­N86�@Êr+e,ßKÔÌöi0÷Z„ÇmÏEÉh‰€D@"0}À"3¨ºEþøa–•ýSpÄÑáü g€”C„è™â!'˜Žp¦æææö#u55eMMMÉåòéÔcŽ›9ÔU’]èß=ž"XÒäWª®>Øœ8¿¬«ÙÜH�Òçþx€É8‰€D`6€ƒÚS@@Nó›^vsÜæ~§…SaÝzz6z.›°¬ÆÓÝÿÔ¼0cÔ SV¼š|¹èåÒ]-?[z£k怷“†IǃIj÷&�Ô«�ðK¡ÐA�÷lÊ ÿТ2] Va†…±‡Ó 1è8·O»Âô¸ö°a$ž b·¤tî�Z¸Ḡè½ð&$ ¨™¨†ö-m^ÁÎÑaE ËéоaÊh,&5^È˜ÈætÌM+qÕgrYœD@" �H$��ÀÂNòÚ’Ì|c™ñÛÈ.Æÿ×®75€ÐKµ�féïd[«ª·àˆmX¤L�¥K—.ïèêú;·Óù/È÷Îxü‚ìÇ?=ÑYqè'êîÔ÷Ó8£3ôäc¥ººÚ¸béÒó†ŸùÚéu§¿¨ÿ3Û[¶¿o OCõ�Z9Ó;/RSÔ‡žx¢þ¾•\{í²x>=H­W�ŸLÈ L ›+ë*ËjVÕ³õód2/MئÚ"VÂϱijÌS^wÍ¡œÈñs"pD£áÁêAùw™ ŠÜ—Hæ°V±Åý9¿Þ»€•ŒEHsE°p¡Y¸šö¢'Óƒœè qÙ¼�T*©y …;â﵎�OTÈÜž×UfËb¸.ÂÇ':äÑèéýÆ+ÖÔLÜ—àî$u;Ü}t‚6A=Û>©¹xWAn4òwC!j„k�z‹.=@Ôâ\®×ø§æÍ†8a=�|nÁ+Ëmáͼº€ÔL³xIc1mi��øŽÅb¼Çc¢ÅýLH4\îH$‰€D@" ˜<Jêáì ñBV—«_2 ¿¯¨hþo¯1ªßº"3ófÄý9iq7ŒË O¨ó�ÉeÇ‹8¥‚åË—¯ìèîü~Àçû~BËiÇ` šáHyŒâI‚6fhŠÐAä7Érf;O�ôM¯K?VêëßÝÙÑù|ÛÑ®ÿª­^~Kµ¿ú}[vmy ÙB‡Û“Ú&qœ©¼mÛ¶hïðð¡ÆÆÆ1‹â¼^§ž”Ì–˜’uëõ‚Ê‚bƒÑ°E5ª¯vì¾#SɼnEB‰B¦¹cðj~5+[Ÿýq[y£†j{I—ËÞC)u šL0¯žÔ �iª$³I$�ñ€$…]!MôØ/Ï‚‹¾�ñw…°`!†ãð¸×ù8¬£0Någ®6�Ö’Ü e¸W`ÔÓyx·ÂÖÆ K<=8™_.ˆ¡gòõŠ d9ÍD¡C!XS‡I-|oÌ0>\¿ˆðË ìo…kHê÷8ÌÂ Þ u˜¤f×&§cqÄ5V#ÁˆZ´›U^°Â›ÂDº½isb$ˈ# �‰€D@" �H$�0’:5Äó*ƒþ`ïÆÐöZ¬°^M‹ë)E¦ÜÇ4íò ³çfkÖ{o¿Ø¶âkƒíæÚŠO˜cŽË¡°â.ŽhNöc›X*Ê€ãˆ1gw(y_¥o_9—‹jN?ÂM%ç»MUÿÒ´�e»Gnå20eËnñx~¹\ÓnRÃÖ 9î]EKn‰Å´Ë£ZèÖì÷}�ãNE)**ZÖÝÛûÍ�?È�;¢—XØlô{<‰k2^šÉĽ¹o:bŸ:_ãc±­^±âÊL[æ}­Û¾VZPú©²ò’s÷¶îݹ‡ö0“Á/?Ž‹^G"»üQüð�7^ˆ)lé3�œÐ›�jÖÌçVVT>¢*ª>®ÿu×®]wOPØ”¢÷F:]m– R3ù½Á�ùC{ß«ªÆÛI5þ­ûàÙœ¦mÉhg³$¨S“ljÀ ,¨õgíÔ7ÇUpïB’-s#íA²¬³Ã½âæªÅ\O|Sì*r^ïAÑÂbur=âCÆÕ1wiQñÝ™Ô�qÑ1I­à»%cHêz3÷)Ò�î °%õL’øÜ víO+t&ÔϺ#ô™‹pëÁÜ­�þ¦®9��¶žf~—Õ]PÂ�~€chÏ �•™p¥¢àkíX´S ‹TÆq†›ÎÁs/þ ‘"�œ�Ðà!Úqÿwé¾ú úÊ_öQ(rÒS¾Ô(OK$‰À|"pòi>Õšùºj¦èÑ^ܱïÕìÒ›þ=»ÿ®Җݽ�g«ªÉdÀØÝzfuw™ýã¦Ëß ØÖc$©„Ùj¬(ŽpžèÚÝäöj à2cFš1d]㈽ÑÓÙùÑâ‚5®H¤'a� ÷ Â’j“A5°¯ÜW�žsQwãs¿É{ÿø,à�ë)ÕûÖC¡¯y\®�¡í“²œF:!‘`0±`5 “”‚¼‚¿ïíí=ÉRf,{j{ôc¥¦ªê²á‘‘O·9j·gÙ¿P’“sþ£uÌxâ“,ÉÇzúy̤ŽNŸHüãŸ+Ü´Éìp8T¶¬NM=�ïoÎ;óÌ3×lݺuOWWןV­ZÕ”_–,§§–qÇ‘M•íí/ �-áPä»c<Ã츇øk…ëƦ”G‰€D`N€*|³µX½† �ÑC„øÉ�oÄ¢pư5é\²Žèy„�_SŒLK�ä߀«|*—k ŸÓ»ÍÿÅ`’–-‡À�9t¸‹†þ³ W¼LÆ&fˆÁõŠ‘¬gdPàÍÅÂ2×Â%þ Kk®þ$t`ˆ™‡e×.ìÜ1¤ Ït?Óη ‡œž+䨓¨V”2ç?¬<¿”ᇣ9â¤ð¾!Ê8¿œ  E�.ŠŽx(ôVYϯ–p#U܉£ú¤]�Íy›e…�¹F ØO;ž¤;¿ÿCúÑv�lï]E·\YK¥ðaÏ“e)ÓC`dǽô§ÍGhн„6]s.�~Z)9¦W”Ì5#D(èé¤í¹›^èï4Qê :÷†óhíò"Êž‘:d!�…ƒÀ)CPÛ ëiF&Ù¢«³ŸúùPÌøìïkkk ¯(]õP‹o÷ýQœ¢ðÍGWÜŽô½?/Ïbòø•÷ñåÄ�’-¯Çˆ �Îl¶‚dF ]oï?ªTOØv• IDATñŒwû×½ÿØ5çžÉ•Xß¼ ‰¡g oƒF ¶‚-{†̱.¢_�ž>u~á|i$ý†Éhü;´zÊ®:3V§™‰D"›PÌ£ØFçL3Pæ4ŠoŽ&âJKKÏö{½·Ž ¹ÍÖ ó×G\®þ Ÿ¸šT�S�SUáoou êÔ´|,ê¼�smÙºøœsŠ/½´Éöä“͇9Jwa9*®�H[__ž¿o_çpNNNÕÈÈÈ�Ó;9-ËîÝ»_Fpì qvú?/ìÜÉåòõ?.ùnÉ¡VtùR$‰Àœ#À.�f|½‹9oÅDÆ-”Ùz:¸ßKë²ðTF·À=ƒè&Ê8Ãñz} ùX´~—ÇÃdÈá."Ñ­Íp¥Ó/Ž£Lä²f,܉ÍÚ€œ±›#Hj˜jËMd Ãâw�T+,˜ËL ñ“HjVhŠÂíà�]{ hzÓ¡Ž�F7Ù…õ4[Ië·…^ô\Þz�3ŠÆÆÉiàu‡(ðz7Y6a¡NÜÿa�Ìõyäoî£Ð›‡ÈX�C¦êÌ>ÄEP㘔H‘Hއ@xð íyõqúËË=dÈ,¢"›U,NÄ‚R¦€@ÄK®î·éù'ß"|åM›B?|põf˜¾»v­A-ežðQßÁ­ô—æ­´oë^òYЇxÐægž í}ùãÑYŰs�"8…8e^@ú`<6ðZïD/ïèêkñ­3L›, &G¤ì'—IO¿ür/.Ï‘sÎ9'A²ô75)a“I�ffnd åX,“I˜(Èé6„còãxÆÉi”É"þ~Gw'þ=B’œžyF" ˜}fäEêì«9Å𤾧Fºñ~Ö¤†B¼³Gï%¬™çš�äz㦹¦jiƒðE=ê—Ù_î•R{¦)6wÆ’CÏÄà:Í L\‰Ž*7U™É\g¡ÀN?•Œ»Ca?#Ü«NCZÎÎPwÁ¢øWú4\{8ÀJs[SÉéiT‘FY@NscADG]Aò=uˆLK2É´ <õ&i.LB0ìç?˜hlq>Òè IUþá~êj;@d!«}]zÝF*1Ädzq´pŽZ¡ùÉ×û6m~ø!zøá{èž'÷‘Ó¢â¦3¨¾ª$a±4GÚÈjt@N÷ì|’îþåé»÷î§ìD?ûå¯èGÿx9­)9H/¿ú6h›=¢× C‰À‚D`Ö 6Ò �ÖO?õü…_ ÙÔþæ>b_GÇ®x4‚}´%nװχNFz^às�ö$PÔÓÂPD�ÄL��x½>òîgÒ�ŒDÿ‰Ã·ú}Û \µx¬¸è5Žûs4ú7²l9´ýY÷vwAÀyCû÷qx")<»ðŠ¼Æ¼�vÄüÆAóî.ºïø¤'*o>ÎgggçBá;ŒªòA�š#ÓÕ� êÜéfNÊW»¬ö¸ HŠ™“]L�„¯ÁãñÔ Ý E»JsËîØß¾ÿ�A§à”y˜*ãÅ¥¦I>ŽÁ=G"&šŠ£»øhhh~öã¿nÛ®]dúýïr˜L¡Þ@à ¸31uë÷d…ä¾D@" X¤°&�y®.Šör«@LG:°Ìµ�šî�ãæ£µ\'c�‘­šCU¬È>ˆEs­ˆL/jB_?[à,f,g�µŒ_&ñcì e‰Ö¿wø„[¶<fÜüaT‚A?1nÜ6¤gëé ÚóûÁ­µhA„�¶ð1¯úÄ…¥{ n, Høð¡lCðç=H¦eYð»Ѐ­ÿ-ZŸ“ÔÜwûü¤u¹(ðÂv2ŸVE¦†¥XÉ“ÂKûhYòW" -¦p0›ò)»òúÄ%Òyû¸H� ÒR@%>Fß{à&ÌÖÞ¢ï^v ý÷V#�³v%Uå� ³<=+D<4¼ïyúóÿýŠþóU+}ôÛÿMßÂýÍ2Øí¢ŒåõtÞÆ•TS¸(lgBYèâEà”!¨gãÂx¢§+7¡®Ù(}â2C¡£=·6v4ªëÎZw¡ý;½üÒËÍ´mÖ,U'Vf:gª)#Ð~ÒZh¾d¤}úä4WŠâ›ÉÜ15σô)ĤµèûfÒN.áxs5°êv»—9ÒþG³ÉܽªfÕ�ÞÜÿæï†\ìå|Ü6M¹�qµñ1o,s‚&Œ«[^^ž-yä©§–Ö××—9�Î7=ªšoñz'"¹'(^FK$�S �ب)Ð} î˜œì ’ý’|a*;+¾”' �VX'�€–Õä{ÎCæfRá‹z&ü,OV�ã¦^Üy³‹� Ö7ž˜Õžõ%^S¤1,ÐhiÀbLjóoñ�õœLáC\a¦œÔ‹ë7Q Ú‚ üYàpí1€E̾Rb£,�µ&Ü |?L²¨‰ªHŸxnƒOÀ¨.RrÌ”±ŸÇó25|NolÇøðÒrÖr¼À Ò::£—ب[40úÒuú\U©IZ"%·s€z:ÛÉX¸†Š¯?Ÿ„¿Ì´Ôu�(…gQ¸å)zfWˆÜѵ´¤<›ÍH“ªš‘�7éé¿ÞI?}`˜ê>ô%úÒ•èGâRzåÒ]WêGéF#Aò»ú(`­¤<¼�]4ý|úB~Êh& ꓸÔ->ßë4÷V· �·-ÅÂu}ô,¨iýåëó\ÿéúœö”öÓ¶æ¶i[$' Ÿ­�ÓJ‡asAQîù]í]ìåäexÌJyñGúçǯ¥KšÐ½Ir:m.ÍbP„IRf�íÛ·÷ïÙ¹gKm}í&G~þ»y¹™¬B�¨q“Œ”RÁvlé½ÑõÆ£Þ'¼¯Ô]UWSñåŠÏÖ�S7ïŒÊÊÊlÃNçŸ JKß×ÞÞ>Æä9¥S:4Æb©.>¦”_O ŸØ�êû3Ž;å\³råGŽãÞ×wîüMA~Á竪*—´´ÚÎü•lêth¢)ÒTT£tëõD<îSãÊ+>�B·Çó7θ>\OªN¤†Ã!÷Ñ£-SQB¦•H$§3Úÿ§ vÜ# ÷ˆy4Òºýd(B3¹7a«Ûcz‹yКuÁfÈ7 Ô¡^*�Ê¥�~l]lÁ|0 ‡[Њ‰Þ9—8F"°€¤^ +óPTXR³_q!L Gk8ÉIwù#ô \^|¹ØFvÜf¸|+pÙ ND›ñî<Q¯3ñܘ8nâ�7r”xF<78iS™Àf×2¸ÐLd«êèk�ÅìògÁ]l©pú"0BÎ…²´³èS×o_œ¤¯® A3/…¯ÐwG®¡¦MË©~øq&e. ­ÜC=ü ª®¤ÂóéŒ…ÆÆyZè�'ï¤úé+¤^ÑDM §%?=—÷Ðâ¯k¡ýI,¤+âoÝ׺Å98ø\OOÏÒU«V­¸l&€XR}×ñpúùÿì]`GÖþ$[²,É–{ïc L &!R åÒ/½\réÉÝåOïý’K.É¥“��BB =tƒƒ î½7Y²dµÿ�°ŒlY¶e3“,»Ú�yïÍ·ëÝ™oÞ¼!¢º¸¸X—»*·´üõòÿiäù¤;'Í»<&‘2 ú·ˆyN«Ôêe>^^U–ž0´ÿGÔå<¹î6Š  üÖÆ¢Ýc[6ËuóïÈÈÈTŠç¼,¯¨äc¹LþjB|ü¸²²²ì~Y2ZíYÝìQ¿“î9=¬“ÄIDrX˜=—2ooï8ö;;/�ÅâîIg×yzÄØ´^AmM�yIÑ… ɳÅlæ‰#Àà80ì{mv�u`m2�fxB_O_aÚ;ûY5KNúâØ$Ú.…ÌÞÁÔÊ•Œw…¾Tc+s¡zã,°ÔR"8Ùï!#s;•3Ÿ^ÚC6Ûújšþ�¥ÍB>ÞZèúòŸ¸-ìkH8!Û@1§ß©mí>R„Ò_º„ñ´Ãªƒa©�…”¦½‰êE+J›+jÒŒ¬¶N ;¶õ”,×Ç“Ù}š™ «?˜Î«|Çàœ@@IµÌÎé pYÔÈç=QÙA8R+¡Ù»_+�)‘á2Ȥ]ï¦A0€«`4îü߯þ¿ª„©Çb8=ÝÊìßðù Ç�O~…<£3æž? Ž· 5Ö†;lN&O‹€©­­-;++ ¾¾¾±DTßL¿×!YGj»÷„>‹=½%¨ÝIOíBt}uJÖ•Ô– ¤–<©¥ñ7$N5éÑ¡.lÉ"oë“B7œ$Í~?D-Jår…â¹’’’lû‰=.‰és®¤åiú+—ÈÖŸû+£³|îV¿M���c)\Æ?êjê“ÝÝÜ Œ\K¡3 Ý©=õ^v—§7çNµÅ\†èÖ]R‡„ˆ´B¡?yIçÓ…¼†††Sevg;g–Ë«ˆÉ#ˆZµjÕv~Ú´inþù'5xâp8zAvÐ SFHt½;‡=*æ·>«Ånè ïi1Ròíö‹3Dµe¶t".Ti茎£H&K�‡bp€»a^$ÑÉ‘øx¨Œ¡ÂϬ—…¨ P¤B¸Nw‡ê÷&eBˆã;»žVx±C‹C±–>¬kƒœØèt7±Ùsz¨ªaÓ“Æ*Ã’Ù·™Hi¶gMZäÐØÖC�ºÜjŠeî ñ¸°3òÑf9½û‡q÷<uï°â¹†;M{ðÃGßcõŸ¹�¥-Ä¢«oÁœÈS+UƒÍo>…o÷TÂgÞƒX2ÿ<ŒñŒÄø>Ÿäo>œs*`=ÿ¶ÂÛÜ«s�ƨó–àîE^ÈÛô-]EiÖtŒó–C1FÛв÷K\ÿú¦“ê4미ö’٘ɚWŽžaùßþ ¢cPU›‹£ÇJÐL�qýÑ-Xþäm(7W=q7f›]DZ.�ØÿÍðýº½8PT†’‚9ÕaçG¯aÅÖˆ¦Ü‚K/YˆÉÃ.ˆøÉ5r´_œ Ä;RWWwŒm¤ÒIáåõW‰H´²¦¦†5RbQÃÎVö‰ æþ™«ÆŸØ…ôtÁèpSòÔ±S=³fe¶îl5¯~w"§ÝŽœdrù:oOÏlj�ϰ›T+AR£QDÄê)n-Vzyx¬ à7Ê:¹3»¥ËÒËÒælÝõÉ„��Þ1*µþ�––¶Ñ^nŠ'W1bº²†hõÓ“-zO—ÒÙtêui&LH+()9ˆº:…ð`Ä>{OM¶ÚaÒétâøøx·ÜÜ\NRŸŠ*ÿÍàœsЇÁb«»oÄðѱÑô¿®PIšçñÅá­†ÌDf'‘âQ.PoTBë¡7‘éÌÍw#xY*Ów§e‹$²)²Cf•Y1‘ÔDX8‰!MW@³³Nþ"ŠMM]ºnöH·2PGdnŽF‡�J >�ô†‚ÂX0Op‡ç<ÌØÓ?�÷ÀÄnm,¦4ÈkÚPÝ Í®"èÉ�ĤÖ@<&ⱡ,DÇq"»?#1l<â8†œr3ÿð �&4¡…ÊË[É4ÛY—†?ßÇ{ä»Â"ÜyG‹j!.v‚)p2&F&Á㤊—àÀÏëñÛÎè’‰èôPøzÀÿ¤|6ü(+¤á -Êke› å¤H-j Dq½-µl"*-¨Úß^ü [²J¡ ŒAìì…˜*¥±¶–ZTû�½!�de¹YË”ù3ê.wìi-ÅÈþó¼±2NÒ@¤-\_²^€|lxãklÈ~�Ò«æc\¿’~ƒ>ˆO¿¦F%r¶W£†>üež£1jú<\5?!Þ‘¥{å¸I¿øI˜f’CøÇohÈ9xG!8ýJ<2/Š>úÔz‰ €t WI¬*£/T¨©'Oô†V+ýÕ¡@­ƒ¢Ø|Âf›ö~�O~Í@NÁ1dï?„CÙd+Ñæ>fÄŽ‡×I’+�µî¬]��Æâ¸‡ŒFbptWcÿ¤¬§þhbÆ×B© Gyõ©ùo œ ¶ 1¸{CKcã‡�J¢ðÈÈ÷JŠŠî'axÖD ±ô¶aÛÙü6‹<ѭؼÙt8ÄΦ^�*¯y¼îénɲ¼�yUtªßd¯Y}Cär·oƒƒƒž#²rwç9»ï(`³]úBã“’É8xÐûNàz¢´ 220¸¡Aµ¾¹Y£ ô þ©°4ï"µZi,¯9Þ8èÌÊî+o}ŸNHéÛQwv ""BäÝÑ!<ÚÔôT]TÔ3GöíÛ•Hýàºã:­õZ÷J³Ð`8íý±gÏó€ýôéÓ=·oßÎ^ú,·WÊy&ŽG€#0< ?ówŠ\LFPbž¦:#ŒÔ1p"/[öb줣¥Î/¬“/Å¢&7_mN;\§Éi@b ‡,®Æq�$Ôz!‡eJ„e'éÉ>˜C†¢E1íÅQêuh[UùŸÎE0ÉR2�Ù¨§ƒz {ñ|e ®õ’"PäÕÁ"‚ÕÊá3œYoÞÓŽ…ïè^bÀPÑ5m¨m×Á¿‘FÏú‘œÝüª†³»Í´©FSC-ò Ë‘—qU7�JPû!6)ò#8RRŽªºhjŸüˆ™6èÑD=’vö5vˆÔ‚ªa�R uk?�2Òdì‚5xíû•Xó}=Â&LÁüË.Çyãc(!n¾1{~ûO½ö Žæ³fH Ì ‡»Üq›$M;°ç×�ðÝöRì§ãú âÆ¥)æA Êàu`Ž}»»öeâ¼ófAíÐì.a„q—]‰qD¨nkù »¶í�»_2¦-¾ ·_—4 VÌ•"dü\Úâ!§çéÀO€«o0ÆÌ½·Ü2zðþ¢š‰bÐjÐBM*5SÛNÿµ¢Vk€€{ú“œå¾ ‰€ÖE'U#š«é]TQƒ¼™(ÿÛ©µ7"ãCá±3‡<É«Q^UCvô’ V‘ÿ^…Û¡?ûã${¬¹eO#˜FnU¶f:"§ï&"QRS[»")1ñÞ½{÷ÒQÏI(èa‘Äž‹°+�Mrs¦®>DƆŒ6lÀëìlÊßRê\ŒŠ#¯úŠ~ö‡¨¸¸J3cFÅ?ž¹oßF³FÿG(—ôÑÄ. ­Ê |ËÊË~/-¯—GE¿›W’ó6‘ÓÖØ[²[ÎYö–óvÙSÜo1ó�Ž LÛ´sçŸ$ôqòܶ–ÍæD±:جß$ôøŒ9Ý´xñâè•+WX+åÇŽGàD€º‰#,Ñ—CW¢¢0DܱÿúIÜ :ì+ÇÌ£�ët9Ú~m¦˜ÔR3Ymþú± C”˜÷ñ%�À>ÆChN äaö(–Œ•CO‘àÚw6C6Ÿ<üˆ”67è^3nÿc ÑJç® ‚ZB'yíöwUÄúÀl8� � f'ˆ\g‹j×@»³úšf˜¨ã -õ�z(ž€V±”-�LÞôç˼¬™u?“>½u4é§F^œ#ÐäD »!@j€Â‡û‘c.Ã_Ç0­È‹6QZ�ü½MPUW¡Š¦¹µðL»ñ¯¸E(Æû%Ap•¸ÀnMß@š"‚·' ÚM¨µí¶{Ùê … dý0Jß]Ñ|ôÎëxéó&$þõ\{ïŘåÝ…ŸØ+áñã1oág}Ô˜ãŠÈä�ISu;~ùü°õ±Ńwß…k'ÐÍëJNf‡]�€”зGby¹wep܃¶cÈ/hB59Ñú�DLtÄ0 §­àl,EIir›¤ð‰ Áø„ «‹ƒpèE>ô.xºrsd)¤P ÐÅ™ó ›�pK˜�kh#öE«Ý n*Å‘-J´W—¡œ8å1–¹�f ¡˜xåu¸‰â´µç„@"u%;z™ä šW© g—æMX?Ö½,~®dëkë\Aj€ëI!04íjõb"§Ë“R’æ8‰DÛI¥U[ö„F“±Ó•Ã|Ζ73+cÙºg¾“ù+‘Ó_'^˜èúbØû©é©¶Ì9"Ïi�Ãc““Þ!rzM—ð: 5Ñûû ›qØ—‘ñk/Md÷ä´û’ššêç*•îÊÎÍ9ìü–A§‹#rú-Ê{êý9 ÷^êµÎfmƒõ1fMž<™BlPä#;o"rš=GÝé´~“Ÿj£µ®�gÁž‘Óç�w^$ àa=¢È/p8#�Ϧõ&Æð‰©+RBè)ê —aÓgdpªÈL#RÕÉË¢-ÕFÔ�ª‡Àlöq¶DQw>¬!3ÄÝÇaƱDx ÈÅ[v‘ g\³³‰HÚã� æ=}”<,×·ªñbˆ§9´‡‘Î1^Ûa’å¾2BšÂvXØsu(uy�Po(BÓkÛÐömt•0¶A­l…ICφNMÞõ:ȯ;�ÂÁÈÍD¶oŽ%¥‡ærC†Fœz"B.†wÐIŒL?¬qGÜø 5*šÈïzšÚ^ r:<-yN¸×Í£˜¯s’âcïi¦%8‰äg!µNS='|i¥z9ÂhpÏ�—µ)4DžÀÚ^ÁƒÿÍFàÄkqßó1ÑŠœ>.W=½ÓÚè.‹à3*FÑÞ!#·#cÝøßʽÈ÷ZŒî:•œV¡x×7X¿½åNã1nlÆ„ZwgmBrð UÅá¢z”¶ú Ð?¡'�Ò ž6jjÍ=„ìü£(�À?|<¦%zØ(ÉÆbþrÈU_Š·ÁHjAONáq"¤Îð 3Ÿ°Q°u19"“R�46�¤7£½½ÄÉŸ–ØÜž�Ås“Ðû�f¼äôgÏÞI*ê/*�f}nQ®eê¦u^vl�déÜ0Yæc"Ç…Ê––%Ré¿�•—ï'Ïi‹~‹¾“t·GE¹ú)•¿×ÖÕ�tÞ’¹·{�¹�%mݺµ(&&Æ…Öa¤h,¿ àÂè°°ËÔ7ææç3"ÂRÞ"ûL²ºÆS™HLLtb‹-Κ1czmcãμüüר¤E—eª0óyzž„µÚºub±ùÔügümìèÔI$?´ó9Íp^}õÕs¿ù曵=fä8ŽÀÈCÀâA}Ö½aQuö!ÕØB¯u"©�ýhž"cU»¾N\ "*�|E‘õÁ6ÈÎïôþdÛ-Ü6³÷tgȉã°:xÌP"yE!HÓ< ÚMÄ~  Þת¡4qƒ�›ù¶³ÛüX8’õd»�bèê ›¡§M{ˆ–Xa´�èŽö㤴žža31M5»Æ¢–1r:} $ó&RÜijaÚµbæÍÜ#¨¸µ#=/Ü–�EÀÙÎ4ØÃH=ÅLîÐÑ߬c w y+ÅÖ¥àZà/f‘Ž \Òõ­¨ÎÛŽÿ½µ ¹¢@Ìì1\ï¯ÓÞ*h+KP¸k'¶ É[[‘†‹gÃÅúT úéöblúc322+7c f_0>-4-58VÁÂÝxýê7�)wCüu/áñ¿ÌÆäˆá4ö¯Ãáý;QWS qÄLø…û›}tœmU¨ÏAÞáJäŠà?# ã&&/ûûRozW9Ñ û3¡éèè8õ}¥C뮯ñ‹2SÆ%#Ñ^ÎÛ}±q„çåõ0¸Á*•ªzÿþý?))� ¿¼¹ yBdRdVQÍ9žÌ­^:´4|íY+SùÎrF0æ!ùòQ!iwM�˜[t¬®ù·ºE>>O �QVZ\üüÍoTÛN×ÌE:y{vGضdmÁ+>ç¹g,PŽÔy390Fõ[êÁý›PYžo–³ö£ÛÀ66ˆ‘|¾¯ù³û­aˆTìÂŽÌFTPx›8/Š£l _2ÄvõR}]Ö>d•¢<( S“S�âßË‚#0[Å/â�ð+peJ*’¸÷ô€Üa63�§a†@»ª­¡²¨tMÆŸ{¾”;ÉÛE..oEDD ô„ÖŸêêÆUfdh+?,ÿG„Wê � ¸Äï¨gªçi¡¯Za±ôºlë£Ns¹Ö––o»+òGumýƒÎ”ãQSSù^ee%ó*·$[u[ÊŸ¶gq¥é¤pÆÔ´Kýýý%�É ¤$rš¹°ÄtZ6ó‰^üð²àŲ[ì¶ì{!¢+‹-eÌ…‰œÞCFò·× ,]FñŽG€#à`Œ,"Š}Aˆ‰44j!ЦÎô©²þª8øÝšCä¥K²ÚƒJjiü`ˆìgÞÇ&b¥mþ˜v[9ûŸ´Œ?|¥Q£H!À·ñ>%bE•·fi1ig;&ïjÇe:ThLæ‘gV†Áª³ªœÕ¡ý�Ì윣¦Š=>©o§Q�8Ï]„ó(HØ£Q"ÔhMÈV‘ÝfD¦ÒˆoªháAªÄh¹Ý�0ÕSˆDò°fÞâƒ^=‹K:k¬m†jù&è+ká~Ï"è‹*б?óx˜è!»v1D£cÌdvת�Žz3¸]�a‡€BŠ$t¢?16Ài`s,tШJðÃc‡1�í™#¿sbq›ªÊpD/…Ô9££Åݼ²Žaãgëpps)üü±óH3üäs1s*݇L•¨ÌW¡…. ¥5ܽáçç׳¥µYÈÕøÃÍÓAÃÄÕiÿεhh¬�1||¼á㨷¢[Ô«P‘ߊÆj#FMÃÄÄ8sû¥Û¬#â${_±�ÚgÔ Ñ›ßWlÑ� |ÿÜL¹ãzLN �Â:®Ùˆ¨·ãT‚µ�yXú8ƒR›I“§>]VZzeltÌtlÞÌZÈý3WUøTáƒDN—͸oÆÜñONø�Ð>‰P«•9Os4»úxÌ”¾$†›©]¥šÅ ‘'ºØÛËëPiYY£ÌEžiÔëÕuU7±<ìzg²g�Ìr§ŽJ1Æ]iÄXsèÐ!MQIÉS�º¬õZô;ÂÞÔßÑ-òocäô=÷ÜÞž8ŽÀHFÀžß�!ljyP;wÎņ5c*›ë�ŽÜ6Z4ÏÜ„L™µ¹4$Ú{§´ƒl¼"¿ 3ܤHw?1ÿžÝöfy9á®0>LtÁÖ4 >JÃ�B~¼]¢ÃâýZŒÛÑŽ7¨™VEdv;Amݨ±>î�5}ÈÅܸÉöŽÇÐôð»ä1­†ç ·A<.ú£4ç�yOëÕp�;®‹ç÷œæYæY9½EÀ O7(XÐ]U;´Õu(©/ÅÞOîGFú]˜ o±Ó'½z‹ÕYò 0è‰Ü‡cjˆÔeŸ‘éÖ¿þ6䡘1£¥ÍÐøùŸžŽ™ò¹ëÈ~.pedsn ª�¢ k7¼„¿Ý÷¾Úš�FÆ‹T�¢¼z¨ÚtI!ïéˆ` «9°§ªúDÄFŒÁØ„þú¸9úMs‡Ü]/f»�[®¨A™º{Þ¼ ûS.ÃÄøh¸Šøûjo#'¨Ü(ÚÜ ;qü5‡g^Fa'ºû<˜¶½½mýþÕ¦WbfÄøD?ýLüœø‰"/ÒéØäIŸæ^à~Zwš;<&—Ë×1­ ôóû*$8XZPRpG²ûª¯[“ˆ�v‰DIJëêj;cK3Ùv‘ß­R;ž¤•m»»÷}Öðî»ï>?eÊ”á´VDŸëÈ p8�‘‚€Ig„‰âSDû éä#†ˆ¼µÔ™ÛOÖX7B¾¬oó ¾?àÄgÚúºu9’œÅ¤~)NŒS]ñÃ8„ƒ²Ý#„ÑãcàB‘B[cûò÷ñú«ßco×üZZ'™XvÇ-øû“™0¥ÌÂÔ‰‘°Œ‘w/Ó�ÎÖíÁîÃj4)ÉA<<¾Þ踬ö¬}Á¾Í(¬*A[\"’Ѽüôžüå˜=Õ8�,ˆ � ãáÉ{ÚØX‰¦¬ïñ±r)æÍ# .Ãêþ9°½6¥¿N�½VÄ3Ú�!»m¦„1‰K ŽåßÛ9}¢¢D^Ór ؆§Ã’ÃÜSoN›U�ßêOªWP¦žú7'ÊÜQ—8¯ªªª7ÚTªÈ1 ‰ïjô‹³rrÈ­Æþý&KuhÁE—@Ÿ+÷ff~IçfSR¹ŽG€#À°7†: „®ôúÓ]Ƹ¡õÛ HR´HcO7±ÆHWƒdpUŸQ›¥¡ 4ñVu#>Ž B”ˉ°É–ëg‘ñîBóvCðñz®®3àÝ=¾¯>¾ŒÇ Áθ9ÄټȢÌÏóšf!êšÐúÆW0µ©àþÐõp£ØÒ�ÉØÔCK#œ|¡xöA݇dŽ8[<•'ŽÀ9ƒ€Lî ¹……R•£øÀ|>“.¿ÏìSQ·0'LÂÜä¯ññÑfäüü"þiZ/ZB¨ÌC½ÓL^°sfº¡rE9в�ðˆõA¤_=~ùªnó&а½yƒÛÇÜÞI‘"bÖ¥¸`×Qä—í@nÞfüð~=Js·ãx˜_F¿—aÛ!¦/¹W^sƆzâÄ|žÞi²\%‡‘QÛŽf]"âcBä?œèé&䣹± ‘“G!ÑŸfCegcw³/’h-�‘š\¥ ¸)È…ZS‹º¬µø÷OçQxôÛ11Ì®CFÃ�T´O¯‡øtLø™ˆw!…õ¸3*,r>…¡`a5z›L¥‡K[hÛÂBh. L•úKCµYÚ-å;ËY íAO´@_@}}ý?ò o��"<,lòï›6íµ2Ä®}Æ1cÆP�K¨(I’B¡8@äôVºóЮõ²§á¿ÿþ{y•‹QYÉÞKl¸œ'ŽG€#Àp0 5íHé5íp�ܾå&5Ç¢Öf6C:wð—ý1‡øè»ÙƒR¢�ˆÞë *‘&wÅEÿ©F‰\ìë„´©�8D1«×Õé1c§‘®¤{;ãê È›%Rß÷GŒÊ´¯ÞõO@’ž ée@ —šåYþ1ÐTe�Ðù×9ÍL9Áö[ ã{ŽÀFÀÓ;Þ¾4™¶½F�®£g`q’û®ñUMì�à±sqÕm7 úýÏñëÑMXöÞ&Š·4—-� ¯¼NH@¸¢ •4`'¤×©’â€ZŸ Ũñ¸*ÅÃ!½?e‘3°ð/÷P¼_àëßwà@Ñn¬þßnÑ.Ò1X|ÿl̹÷ÜtU¢¼¤Y‡žîxñþm¨P·As’cC6¬{là—’¡,Û·I¡›€ñSÒ1oÔ� îö³]Ï+<|àhsaTRýÎÇ•ô·3øn v­Ö°Æ êas«NJ7Í.¡NH<û‘Ó³*+kž ›IätûÙKtŸƒÚc?]Ý3?)rü~SË jsëÖ—“³õÀ;‘Çt º­í‘cwúûú>�0*Þ�Bk4ç5�þΟº·½¯gY�ŠŠŠ©ÍÍÍÛé çyèP.Ó±—ôõUÔ9“Ÿ°éˆ‰‰qIHHˆYµjUÎ9Sq^QŽG€#0L0Ôª!pÉ7L >ƒ™,µ|A Z¿)…ë,ßA[rrìÐ3:—~nVb¯J‹ £Bí:¥Œuu£¤Bó¶Øßï©üaiÞ-Òà½ÂvŒW8á‘ í�áI1Cz;blhAÛ‡+ +,…Û½WQ¬éÑÝ¢f¨©ƒüºË Nßíu~’#À°?R™R™?|‚pÑ5Å�KR†W^ûCb³Dy@¦\õ$$."ìév1îøk:’‚�$šBÇž‡…w*áSãA1¾qþõíÛѵ¹ÝtCôÌ«q�»þ±k°µÀ’GF±©§á¶ç—`�^Ä}Ü DæžýP«¥}ÅT$G³çÞ13á2}òê¨:2¼#Ç÷HN×ü»rjQ«tGXò8$��E …ÊЫêQ•—�-uáX4wµ}œö¦L‰”f|øAA3ë.¸êv<àÐ;`?M^çý¬ì).”%ª´ Zuâ'TUT¼åvÞ‘ÃDÉN)ÿ·¬"Uä?fŒkÌÝ’kÝêÝ)3”9ùùùÇç~ÚI‰DFFú¸ˆDÏæܬps{;6:Ú;77WEá=ÌZFEG_›}Ì.±”„©©©7WñìâòªÍDNoe ˆœ¶‹p³±ýüÇÓÕÕžžYUÕÕý”40ÅÙý§�‘Ó,„ûºÝ VSE.•#Àà [ uj=È�¤·Ì¡ƒ×ÔÉÇ…¼¨)õïU�-TkMô‰sD’º™â.¾VÕ„·Ãý0J2°Î¾,²Ç�ábÜ*ÆáV=6×ëpß!Z¼’\¨çø‰pg”+ÜÎÐ]!;vBÛ׫àê�§î†SPÏÞð¢Ñqpš5mPï3WÆ8·Т±¾ �Dbîu³pëÝs{nÒïÚK}¢0íÖ�hëI” ¡ãf¶õ”ÅÏû�»×±Ímë³I&š ¬>ŒÃÙzh\&àúYãÇâl³9çA<<§wF7æoöõ{ðÇúfÏ¿·>J„t¤†¶*mû ÿ÷Ýx$A�HâÎðUï�²ËÕ�–æ6Z'#éW.Æ=�.D€éâ‚»C`ø¿tW-~Î^Œ;6¦¼¸x¥"8xféáÊ×�Gvþ{ùË|{ Ë{’wRê?&þ�ƒk–S€]?CǹÜŽÀˆ@@]Ÿ…½Ë Š™�{¸|Yôq[y%΂€IßMö:ü‘ÝQÊ\Œ�õƒ¯ëY óË£.¯~ü.YAå1d°É》yô�ICr“ ÌÓñä/¹9‹Ãü£iÌáÃùhõœŒûÿu+Ò)5Oƒ‹ÀÈêa .v#^yû;zä`P`à¨r ƒ16íþz÷�Œç÷¾+ š"^Šú$i~R´�z�ÂBCWæ6547·ø˜ F‰¶½ý òÌÕu'¯¸´˜…ék0bš ⢢ÆQx C^~þ3ý �ÒWlÍoŸ®Ù‰N¶­vœ­Ü×_½•òÒÒÒ†UÄ®³Õ‹_çp8Ã“Γš<¨el‚ËÈI¢¹Ù‹Z{¨©ß•:R®Â¢7²p´B¹¾­yÕj\�è�—åãÙ•%]:(ºc×±£üÞ¢ÂÆV5 ò‚hˆˆ\м‚+C$Ø4Ó œçEq©)võ–:LÛP�ç)¡ÖÓBˆ%•hyöh·ï‚ûc·CzÕBrÉYÏ¥£<ÜŽ€­h[k�ùËÇȸ!|Þ•œœ¶H^n˜!@ß(� y¿¯Áa±‚ÂÚ,ÀX<µ‹÷�Ã#áŸ94Î-¨j8N™œh¦Zh$Æüå|L!ûu™È޶zYÿ56¶Âoñ-œœ¢g�ÔC¼£«�HLôÛŸy ,48$�H]š—5¸‰OÔ?Vx«©ÔT–vsÚô�GÞì­Þžž+NÂ6g''ULT´¼®¡aÞÙʇœ-�õõi&\Hä´˜¼¥Ùß�iãÖ­»ØÞ:?¶¦Ý»w³WÇëÉÛ­Š\G€#Àp|LLƒz„ÔæXÔ‹B =Úy<÷'}¼¹ 5äAýð‚P8Q”?óZp×ì ¤Fºá¡!ø|k%”V^ÔŽôik¥Ð/W5à©`o$»²ñ÷¡MR"ø'z‰ñòXJb~€/¨Ç#ï¬EÕ£/¢N*…âÅGÁÂvp¯è¡½W\û¹Ž W¤‡V¥‚ª]ƒÉ]{;|q'¾­Œ‚ßÄk± æ\Lj×d"`„¡C ÍèÑhõÇãRš´Ð¶åbݪƒ\úhÏ‘YûÓkÅVdgÙ;�mF¨+Ûд«ç?1õôìCvÆ€5yt·w@o¤÷•¦Yß?�Ù&RïÁ•<®Ç�ÝNPôŽ«8bTDXMqÑa"§})LEëZj"¯dýîOvï0í6|Bvôè!–J¥Ÿ1­ñòöT’í…ÅÅéÉcúÔ:iÔêçO=wêïôôtarBÂC©AA’’êêÍåååÚšš›Œÿ}F(�LK—.½ðŒ¹øEŽG€#À0LZš„¤QA(uÜè�¶VÞÉWg"@Uë«la.·!«çÅ+ ob«¨Ãêæz¯9I^hï0aóÑãžÚCä Ümý Ô‘|°´žÔÒºÖÛñ&-yˆ…x9VŒ­Ù¿àñ=«ðö´‹0-j:ª†’B©ðÄà %­h,]ŽûC|Ñ{ØQ³¯^4 /¾³ÞŒ¥ã†_ìÝ¡D“ëNdcÍ ·a�ÿL\zÇW`S²;«pôÓgðÏ=×ãõÌAh l8U¨Ÿ¶úÃ/Ð žÆF´ÖÔ£NU€òê�XE¾Ó3ú)Ù~ÅÛ‰œ^ƒ'"Â=çüš»ï]žÛŽQóþŽÛ¦xÛO—ÔgF^£ÏðÖEG7U7lñõ›XœS< 1§­õõöX«ÓvÛû(&žžžÏ–”•=ñ©SGGDn~a �î“7s}SÓMTæ!ÚNJŒŒF` ÎC"™Þ¼Y¹ý0²_§ }’}’Àõ£Çñ‚«åwß}·Ž„›½ÖiÏïÀ!Ís8�Ó0h:`Ô¶Aàê¨4O·¹/g\R¼ \Q ×40ÂÚ–TÙÔ�‹Æv¿°` ';/@yc‡Y4s2r”©A›ZUØÐÒ‚¯cÂà*t0ÿ£º#yP¾û ¼Üep{õx.(1J¼šÕ„OòZñ¯±^X)G¨ŒwmlynyŽ@h-ËdžWþŽeÊf´í|W¦‰¾àYüãÖE[P¯m IDAT8?ÁÎ#dQÝþ`ÄËŽPjQS_ƒÒ_ŒK�ØªÃØþÙ¿pÇG"<úÇËXàç¹#�FømÀÇ?ä1®5µ¢ ß åûĸôú�ž= ܦ“hšê°å…[ðEsö½ŽÛçˆ>÷Üÿ×+±hœ�9<ÛÉ%ø¯ÁD€·âmפlhøÓ/Øg^þ‘üRG6—<¦%Jµúæ- oH$ïD{{G’·t¥­6'ŽíOÞÚæâ{Û©°°p.-Ô¸¥¦¥etyFÆ>º°ÅVÙŽXn˜3»Fòf�hllTS¼ïZGÄ—ÛÄàpF›uø|_=îok…×%¨ÅÑnäEí mV ¤³l#¨YXƒÑê+ku¨£ØÉŒ‘–º þG¶0â?ÊÊñP€7&ËËÓˤ×CýÕh_½ÒËÀuá…bFjîèÞ玥?|ku;þN Q>›Y�‡“½ðH²'Dœ;Ó-ç×8vE@æê†Q±ã ÄÄJQ8žG_µs¦bB˜¤4û�'ŽÀˆEÀ}1%%�bVïojjú�6&–‘Ó<9›7o.f&�3FF$µÊÁÌãæp8��ãY³[uxïX¾-Uã�Î:åˆõ Å<–/†ò{ò¢žìCõì;‘á#Á‘r¶l‚%�`¨÷+Íž9Ó‰Xe‰xa¥Ñ’qHö:2â‰ÒRÈ„F\çëí0Ý CYÚ>ùÆòr¸?pÄ“'žkړȯKÂd¸ ÈÿÉnÆ»G›ñù±<—ꃅar¸Ò=å‰#ÀXœ!ˆ½üEüÅ|…<?u""¼$à\ÏÀâÎ¥;"……¸�ÇÌÆÕ�d�D÷ˆdLŒórã†Æ…½âr¨´4@±Ób½Ðý¼²¡±Oèê ÿùÏbÅ·CopGô„qˆôwƒ´ïM¾¡©À×Ê ê~ƒ{S=ßD_i]EÃNo?Ï«‹òò3{Sf°óˆáæ6z\ÀÕG3�¼*rqù:Ðß_QYY©îð�Oë�-‰‰‰Î*•JØÜÜ,§c§½™™l±Cžzƒ€¼Ä‰œn¿æškR¿þúëŒÞ˜Ìóp8Ž@ïÐ;ýσDøå*1ÑÇ[gû!¢° šßÚ!�Ì '?8y‹¡ÞX-jØ×téo¼úk r+Uˆ"odÆBS2žÏ®,ÁŒx7Dù»vŠZrš‘¡RâóÚrüŸw'ø°w"£Ý¹mo}@ ÆCñòSzŸy…)™³Ðì=}sœ_kÅõ›«N[_¥b¢�áZ:Má;ŽGàlˆ¤�†¦bmìöFtxÉ�G²¸­XuÌ7 `iQ^‘Ãy ÇÄĈbb¯ÜY”S˜W´�:zÎ:�æZFN›¡fKçõ= BBB\ˆ�ö0 ÒB�ÁÁÁ±û.ê\.ap„Ê9}ÑEÅ‘1ü}æw„ÛÀà k´V”¨�øs9V•©ðÁ$/l¼À‰ DzŠ�,¤…Gr¢Ð.)Ь‡¡NÓçšÞL„èü1xxY.Ön€²]‡½-xâÛ|L:<{Ed——r'wÝgö*Ðf0àÅ9¸Óß3Ü=ì%¶_rL-­h{ïc(_{Ò«Ãý©GÏJN[+ô¦ð)÷'yâðåáë킹¿•á‘=u(TŽðçÖ~Ìàp8�¡@@™ƒ-ENp��‡ë/šŒx¾ÞàPÜ…a­“{PëÛ×?ã)Ö²ðÀÁÌF£ÁàªP¸%�´ƒ´u»aÿ4ÙV:4*ü�ü¢ÂÛ<½¯-ÿzB/x½ÿ&„~>6«Šuã›YAØ_¯ÁâßËñÁQZLqf ®ˆt³Y&/Èàp8Ž€&"ʶã³L7L+DùÁ,löÇø‰‘H°ýn¥€žkp�ÃavÇ™G±K‡[›ÌL ¾é^ê9ùED¨ÚZ“Eqµo ÿ‡D\eÐ$¡_@À¿�Ä¢f�V;)(: ¨©®1E¥UµØZçD__©««Ë÷T^PTTQt¨¦†¹D±vW·pÂØ±ÏÙ*ߺ[`qÉŒ¿Œš�4Û—Ž²ä$ûQüî'�‰`*õÚ\È.K²Y¨Aßs˜ƒ�êoauoú½yÛðß,òî{œíî%Úx–ž©Ö§_DGF&/>qêx #ÓÃóg£ FT?Nõ� ¸œêäEø˜¼©o&Oyž8ŽLÔ-jÊÇŽ#Uhï°5â£+¼B /GZŽß^ŽÀ€" €Rä‡)�Y8œ?÷ß7 Ó’Á¼ØxâØ‚Àè=[Äñ2ÃÁsÿ–¶ùÈýýýõÕU]&×9¢®Ö“ço|cccBKsëžÞ^‹Ä.Ïùzy­¤ÍÖËÒw•ëÏ‹m€áºÒò²W=<=7„�/,,, ™¶tÙãÆ�óW*• ”& †=DN3Ï鳦Ị̀̃¸×Q’.ó×Ѧ±‹VQS£Óë„_d¼·‡ÊÛbóYmãú†=§,t‹àª«®š²|ùò}+Íss8�s Åšþ<¯OgÔcZ€¿Ì F¬â̽jæ)C�”Ï €œ„�L „òÛ H¦‡Ót³3�É6µiÍÒbç“4ê{¯¦v Ôƒ‹§�ô½P²5Ú&<z 8Ø— îËáݶmï~ç¸x/ûyMûõ¥xŸò²ZzR|êßæ‡âÃìfüsO-~/kó}ÏúÜ÷IÏÌà ?Œ4ðšóž}òT4¨l´?“—ÞŒ›ïZ‚ÉC9ÙFëy1Ž€-œÅ\ô*¾YdKi^†#p:œ >“}†‘Ó»”{0Ob"¨OîEuÖ<##ƒ¹GeÑvMRR’oCkÃÍE……1ï ]„Ÿ),ï/HlqF8á’ò²ŠOÜn«ýƒC¦•­µA0 «QWW7¦´´ô É¤‘åçç×�˜?›ššz--*,ô²‚’’ó“W®T®• £ÓSTâêúŸýïh�™ùG@Àd!§É;ß…ž‰n=çÁPnG€#ÀltF–þ^�UÅJ,Ÿ‚%Qn½tZ%2Õh«wÙ`ײÿúÄc‚á´&ƒB}Pè“ycz¨Öêpõ‹+ñ¿.B°÷ÉDö/ÿº""»»Kzâc� êÂöf¼R´�ž‡`ywf ø9“^Õ¿ßGû¯k!¿ï.¸^<Ÿ¼¦»ÇÈÞÆ¸�;õ½´ˆâÒh7ÌùµÔìM½ñâ0L pµ·*.�#À.8‰€©�ã·M�‹¹�ŽG`D"À êy[»¯Ô’y÷§-[¨üÈ‘^“uYYYäT�—‰ }½ÝÐ~y}UÓw>þB©Øå&±XL¼_~Ÿ‚32�i‰‡|FAvÞj¹›luXtLJavvAc]c÷FŸù¬°ÌÕm¾¸¦f¿›Bq˜²33³™÷uŸ“Q(<Õ!ß‚0Óè�¨^é'Žß׸iï×G^ßÞgá¼À�"@¡^bé9Í!#ÎVeHçÊ9GF`C¹ ÷l«F Ì–D"ÅGÒksÍ!�™õ¹’¨Â²+&BùÉzH¦ÅBèv:‰y¤¸×¼ð * ×_x2§zT[g0è— î /Á;sÖàß,õO°6eÐŽõÙ¹P}ø ŒwÚã•ç ŸÒïXÓ¶ïïêŒ=—EâåÌ\¸º÷iý¯TH�‡(·Åf^†#Ààp8ŽÀHF€Ô#ùîZÕmé¢û§ÌÝ{(7×¶06�õH¿e[JZZôÑC¿ÐëtãÇMwcMyÍÏ•••Œôîqž*‹1-�8Ï9v4÷gI£doâ„Ñ!Y»³ê”ÍÙVVöêÐÜsˆˆŠx²¸°ø™P¥ò·ÕLwyÿœºËJË6�vÿxŸi2y¸F³Èõþ'v´õáOû¿Ìí´ª²WÖñL‡ÀêÕ«ÙlL™2ÅkçÎ�§D8œ½Ü ŽG€#0°ô²c-¸Ž<§ïJöÂÛ3àlCts˜��0ÐAe:‡ûÁÉÍ í?n�ì†y'YYVÛ„÷¾‰¦%@Ä&…ü:éúÙ~°ÆAô ~£dö6ãÀ”;‡$°‡vÃ&´¾ð $ç§ÃýÕç!pÚnˆ„¼©ÿ�Hé¥Q²«KUظ0 >’n'žívòëŽG€#Ààp8ý@€» ô¼¡*zæ‘§[uÝ¥¥Tl;�›û§­AµNš¹{wAG»fšQo�)•ªé•ÕU-Áá!?§¤¤¸SÆS»»‚¸ÄQ·ähÊ Kþ—:m|ˆFÝ>•‘Ó' =ó�¨]Ds¯ œ’>%ŽöF"§Ÿb{ïþö"äîñ`Ä—ži1iòÜú?U,ÄÉÿm¿îÙuëjHLjKç�ïÛI÷Ž‘ÓsæÌ‰=é$ÿÁàpÎÚÉS÷¶ÍU¸“¶ekú½ól#§Á\¨)<ù”bgHf��fû^ªºª¾53“nyM•4@®mTMxÿÇ�X¾a~Ùž‰Yù¨¨k:#mÄ…í�x¥x ^‰�ƒH×Á �j¬©…ò…W¡úøS¸=òÜ{pÈÉé®I žbì&oêhwfþ\Œueªž=.¬ òcŽG€#Ààp8»!À j»AyVA‚1sÇ Üê/=¨_xá GK7í"Òµçeä{(Û‹ÓÆüì¼{F˼ü}ŸÏ9–[ ‘IMž>ù<*+ˆŽ�}ÈI,ª©(«ø¿¸1±Œ˜ÎØ–ÑÒW�˜’xý˜1c$:°@‰Æ�›w²P ýNןwÇØ¹SçúŒ‹˜ô‡¯»ç¤eÚ‡ÝvçïVŸGÞá$üT’½ßúIÀÐú+ -ëׯ?vùå—O +ø»oho×Îà 5íz$//Ħò6”Þ‹kb¶k¦¯£à\ ñщ”Ë”1äE-BÇ®LsÌèm™9˜yó¨.Ì'rºõøÖÑŠ7>üW?ð.ùûó˜vã™s¼i»ýÅÿbnÚµ'ÖÇI´ývô¶$óÒ¾óèJÌP„âöÐIƒ×È!½†‚B4Ýù7èsóàñî›�Ì›CÞæŽ×‰£B¿›Œ™A2,\SjŽÏN¡ÚyâœCÔ¡µ8Ú¬AUaóȨw-¤Õ ¨ h¦Wµc¤ ”£¹Õmh¬¤Ù7Ôx˜�âŽ2¹ÅÅ•©‰‰Á *U­··· û¼åp2”Ãþ×?ü°�•ÕÔÔØeFÁ°„W€#À±dÖkpý† ${¹àM éá)vêW]B'˜´½^Æ¢_º­°ì¦ÅP¾ý)~†7½ü ì\ˆ™y•›ƒs·Xä鎯ž»‰‘¡äAÝ€ceUØ“•K¤õÓDN17mn\t¦§$Â`øÔŒc}¿l'65äaÿÔû Vöœ´µí+WÁõòKàºôr¤ÒAÓo‹"‘P€OÀ8ŠË~ó¦*Ü•¤Áã}ÀB�ðÄùÈ % ?I;ܼz¿6�CãâE¾a4 æéH\Î`)[ü7ë+Ü÷þVÔµØêÓ勤 aѳ‘Äæ÷˜Ü¡€¾nbHÝÏdT�øŽÀ¹‡€§7 –@AëPË]Yõ]é¯È~Ô®•ú8vÛ¢ëfɘñîæw‘½“xêNPw�K_ΊF½´-çáÊiTÈ0ã>׿ﭜ°_³bÛk!%ç—þØ,nJ¤s¬wh°¾6ÇóÒ‡U6TµäçïnùÝÉL1¸ÉRb–Ì(®;üf�ñØ’ SƧ‡‡FM>´ï@õÙ<¸)Fµ\­PëÃÜÂ&íÚ¼k[ÎÁ£o‘Ž.ßg§¾¯Z“—îåÖwy™Ëžj�Ö¨c…ÊBá†Úo?è$Ô»«ˆ´l§­œ. ]…ÂPZ(‘:�Aff&#ª»ìé¶0?9l`ä4=s.£F�ÿ믿î6†sC9Ž@/Ø\¡Â¿”àæ|03Ľõ?‰œaR©û/gJpŽ�@»»+ê׬ÇgOÝ w™ r™+í¥p#âÕͼ§“ˉ@l‰Ñá˜;¸{És�w<‚¿½ôo¤ÿe&Ž Óœ̤õ@ÂQMÞÏä¯Ã31s‘$HU]²�Õ5h}êyêê xùY8�NèºæèŒ‹¾•þf˜Gõ|Z<±MgÄ i~œ¤vôÇí³R"¨¥ƒÝr�BP{úPÏÛÄ �‘ fƒŒ‘—ÚŽU‡�X*éÅYÙ7¸Á^21$òß •òb�swbtEbjkR3A-!‚Z"¨�¼Í')3^ÖLdï$žºGଯÐî‹ñ³Vèt«š–Ÿ™ñAì²ìv„E_hx{Û›V×�Dˆ;ÉiD,Œ‹-^•—sÒõ>üÐøj„®F×3z#§O^¦iê3)†ò¤I³=cýÓ&5Ö×T¶î±o#""X¼hlTo¬À7®`Çó.ž—FD¯°±¶q���ÏèòòróꈴO÷ŽñÞ­kÑEWfTfV¢r+ËoK"2Ù)ÉÑ—ÆhqSÈÙºß/t‘ÕýF²ª;²Ì4“ˆÉÞŠ6fÒ\ 5.Îkê„ ïØ·o5‘šNùùù}[©·)ŸÑÉI, mu$+^ ÝG-m{è¹Ñʰ¾§�×Àà ØHê7y-xtg ^˜ì‡{’½íCN“\-a¢éÒ ØÉž[‘’ |Èóùê>ƒÇØÑp ðïó#1ul"v}ùöÍÁ¿¬Å^eÞùê{D_6F�ê³¼³ ÿlÜ}ô{Œq ÀC‘égËÞÿëz4ë~‡š<§Ec’áöäãp ì¿Ü!�03HŠÍ—„c)-*ZÞ¦ÇÿÒá&>·žù!€�«ä ò ›‰o™94ú¹VŽG€#À0#À j;<[ÛËfNÚ[·åï†:ܱ›†FNN1£cRóaæ:¡šÛ¼ «�zrŽÞÿòi÷qi×µ÷H.N™rq °ÃÅicÆ·¥½—jSNZ\pŠbâ¨Ù“ëj–­záw’båaÌ\µØG~3mÀÚ_×î6Ð?ÉÓ“K#ã¢oÖ›:ÖFÆÆ6gefjKŠK2-×û²—]Ýf¤ÎðOñ›:áHÓî`¥¦x­R«ü=#ûFL³T~|gû¿yy,ÒÑ*&Á¤Ó-;vìggçZ"5ÜÞv«{.)0éýDNN©É FQQÿ„ }i»�K®¾zÊŠo¾ážÔC?¸Ž@?`áo�µà~v²?Hñ¶o¼aózÅô-Ôh>\C?`챨Kút¨¿ýÛwÁõŠKzÌw¦ ÎÎN˜<&Ѽ½ÿI.2wç`â¥ÿÆkO<„[)†»ü´fä™Äõx�= _UìÅOÕ°gêÃp ,¹j"²]õéЬY Ù_o¤°‹‡ý Æ$?Wìº<3~*!¢ºËç†@ÁIêŸ9~�#Ààp8Ž@àuг*[°\ó,þ~Ã"àóÓHËêóë¾³d­×�'c ÅUî‘d¶äíë>-m¶¯‹ÉYDäô@²†‚øøiÒôñ—\\Ór,û³ž[Gv²~ÐI‰ÑÓÖ'ÉóX¤×ë]kê^;¼ýðm‡qøÃÎf"ý/7ýe‰T$ÿч=ÁEœýÅîøWÌ< ñ20ÍSGÚø Íû;D‰ ðxÿ�EN[nb”»;.‹@­Z�+Ö–£¥ƒû$X°á{ŽÀ@!`hoBmáAìÊ8ˆe­¥†Ëåp8B€ÔvºååhǃŸ'Ÿ*Î#Õ{.ã-}uû“’ÿãl©ë¦Õ|uj¾þüf®Lèë¶qÇ�ýgÑ�LþC—~÷bLÈD¿·WÜúƪ߿Éë.Ÿå\GG‡ÐD¼uCCƒ“‹‹‹éðáíY²þk¹~–½éç?ç|óé7ÛB}c}bB'? ‘ÉnŸ’–.K-¿é�?®bïÞ[i¡ÃA[üñ,öË++/Û½{wõ”ñã#S’’¥üüïê, 9êåíÛ·—Ò@ŠöÆo¼ÆQmävq8�SXNa=îßZ…÷ÓƒpëhÏ-eq˜NN0µ´œjÂ9ó[@‹!J)|…fãi@{%ÚcåÞ‡Ïü×>ø(zñU¶H³Mâª9ˆ�J¶à• ³1@ÉPQ‰ÖÇÿe&¨ÝŸ²{ïö!=Îóšþq^(Š[;p3…ÐÑú98q&eüGà\GÀ¨ECÖZ|þÄå˜2ÿJ\öï=0/&t®ãr®Ôß E{s E’,AIi#‘,gðˆ;W0áõäœ#p";7ú´Öª¤Nš�Û�BEŽû›š íNý2×ÿ¸Œ¶——&…Ãp óO ݸóWSø4ýý©Ù(¾ï¢eO{Kcü_kú϶¯`x�:¢¢¢Ü¤n²Ot:�ù¹òöö6‘ÌÚ=–±¶�áÌ|rÂ¥Lœ2婲ºcõ;2~y)cÏžÿl-Ù´ö•—^ cù¯ºêªq×ÞpÃë²plܹ¡Îdz�Ù2aܸ+Ç�àvqúŽ€é³Ï>[NÅx¤¾cÇKp8ƒŒÀÖ îÝ\…{Çz›ÃzÆYÖ\+�+­”Nµñ&¨.³Óáä¡€vëŽþÝmò ¶¾]ò¦¾eéåØòõçXþËj,ºõ.445÷I.X@ IDATGu쟢ÐwGÌÂL¯Ø>•íMfZ‹º™hyàa€<¨=ÞxâÉiæ4{S~8ç‰$Oê?/�ÄÁ-ÜQ µž{RçûÉmw\LM™Ø¹n%þ÷m-L¥•(#s{Õ¡tÜjqËΈ€ F}´jTÅ»±ñ��Š”)/c•³}NÑ•ò‹Ž€ƒ!À ˜¾!Ù?Êb*òÇû²SÕWuGêÚê`£× ë§ø—D± e1AcGý¸ö?�²í²c$q²âš«òj·nz{Í_ž&¡gl�ÇÇÇË¾Š™{¶ïa Þìá¦0‡HÈpË8k;"==]¨hš|¯Ö·ro«²2¶­½ö;‘´ôîŒ�=/@¸|ùò¤‡mQPØøøÿgï:¢8Úè»wGGz©ÒQ°`Ä^bìQcЦ7“˜˜Þ{bÚo¢‰IŒcŒÆšØ5¬ˆŠ Ò{ï®WþoAQ@:ìè²»³S¾y»·åÍ7o$5WíÌÌŒ††º`¼»ïZ/¥é’pƒ�Çå«WwøØÛëûûûój$’±&±±!!wÁ±K j²Pš©íóÊj²¸¾É\óÊ9 ÎHJŠ¡‰Ù÷¢¾yžÙV±ôjbK«ñÈÙxm¨)^ñ3!)‡®mãA ʲþëA­F˜$3t{•+¿#-êñ¤EmЩÀ�â‹s;ÿÂË^ƽ�>‰ý~…éãVÕñ&I{èpµð�çÜV¥oS"¥â5kë&B|ú gL‡úšhS!½;±©�‡í4Yâ˜=©0Òæá“@óF� ½»u¬õ,š�@yZ"bc¯!‘ÌÑ%I¥¡ƒàHÛ]üˆÓŒÆ÷[+ŠpqÓgøá»ß°7M ‘Õ0²…öý0�0a¾^ÙÀ"À"Ð÷` ê^zމøÔw0õrîLrzäÈ‘FΆS‚ŠJ³Ò~;úÒz‚¦9¢—ã1ÄÃN—§›—”4–ÏçŸ&rú`k dÛÒ Ù1U{Jü,æ#2e?G©¿oSÖ±h†zo«+’JYV/¦EBĺ)cÃC‹�.‹eûöíëTâ¾5í»%�òzFF922@žáÒùöJ™³¶¶^&M§)ò$·˜Ën6…Àž¿ÿŽ k–DWÕÞÔìè¦@bãXXz�± fbŒµŽÚ{šßÕì4µ’ñ f&ÂëÏõ'[ËÇ \cH·n‡îÓ�8m§N8ͼeq¨,WGì]¿³Ÿx“\‚}…�eË³ŽÆàÇä#88êU‰¤îÌ OLBå—_“›F«ÿ¾‡{gß«Êj&ÄÑ™Ž˜s(ÃÌE˜å¤Ïg½ê ²Æj:*ê S*ä!eKóû°t‘=ûÓô“ÖaûÀoÁ{X5ù%¼�xGÿŸœÒÆœ‰cXrºÃز°ôX‚º÷œ«KØXÙó¼,þ>D‚\�lM\̃|y––”þyøÃTd“ŸLŒ‡D.ñPU«øZ|Eø¥pÆËôDtsC}CêÊ!‚OXXS#°Ú=/Uæ¯Î×9«ÉSö_úNÖZóBý&¿´¸*Uý¡Št ÕnénÛvŽ)—™ ‘ê~œ´°O–––¦‘Χ4b:ÔdûZkK[Ó‘Wµz6©à`Ä—zyŽ12™Ì"999»­e±é»Æ{ÚÃÃÄ&PÔ a¤tØÀ"À"À"У(é)ö|HlôøXl¿þQØÅf‘¼×аßK|0(sôô ³è~ˆÝÑýsˆ¬6i3øÌYkéÌY[Xàà¦õxdù Lyp)BvlmÑ“úí¸=xfàDL2Ôf[šÍ@2$²Ýÿ@¼ñµ´‰ÎÒGÀ5n�7w³eö�£-Eø|„î?œ‰#÷9`¼­nhÛÍ@ ¢¬¥Eô™dé £qA¦gú:<ôM`®/€8U‚ü¤2càéBÒb}*¤!tÓfüñóA\3×q�bå›aÕ§ÚÈ6†E ý°wûöc×#9Eú<‘@_ßîï�«wtÐŽXÌ£1©ž¾¾…õŸ{¿ü�Ê»ƒ¸e<ž™zT|ÕÂBf;Òo±spï÷À²ôs*PVR„Â-(« ‘—~¸r(¹hüDoky=“^œ�ˆýß"jè¯xt0@ó³�E S`/¥N�±Û á q;!7;®#žÓÆ£yÙ‚ÕOzºH_˜ŠØ´sר·’ÓÆû˜ñ˜®�U½Ï´îJØ•¿rÂsdäMÚ¤x1C[XXˆüý§X˜s‡_¢Ò8{Ä„?¾ûÂÕ?f…†VwJMTÄØ½yëÖ†´ÞÿßÉB¡°j¤­­àÕåË¿žlMY8Á4ÿ|Y»$ŠÈñ¼Ë—/'1-Cmí+õx3vtI…l¡�…€üá¥w�°gg™Ç–Ã"À"Ð×˓⇈blœdGš´­»ßÁž$>*H¥ŸDÕÏ£E½ä!ˆ×ÿUaÒÆ ~àßúöÕL~k sÞ²‰æ$¬Á‚gž'•�Æý¤gJñ^Ìv|æ>»ÓÈéÚKá({êy(ó `¼î'ï�ÚŒuý7šG'põ=–°Ôáã¾`:�ØÀ"À"ÐQjPS]‹j#8�™Š…>ìˆ�Ž"Ú›òKòR‘}IZ&p �A:½ÉúÖØj·qâÅUë°îÛ÷ðî) OËëL¶äYmhhÈ#/ëꀡC?¶922²M˜·Ç–Ó¡¡Ñ”/š©ßÖÒò™ —/¯¦ýFçª=åÞžG&—[iq¹¡·Ç·u_%êŸõ œätžDYYY Ñßþv[AgÓ³°ô[j*¼|&FžõÐc80µ’HL(šPÕcvõTÅ}è<¼XíE-º¸·Éo´hW m/7WœÚõ7†M½Ãûb Õ÷uÊdIKq0à¥{O+ËÊQñÆÛPfeÁà‹ÏÀ§‰ YbºÅ3¨>8ÄTˆý÷Úcþ‘,,v3„©�í¿¾;jl �f�¡Xes7?ÌjÙL"6ºO" ËAzb"¢”0¤‰x{²â.štž«ócú/þܺ®Jàõö8i’�¬-}– îÖÓØ®î%Î S˜Ã�Óm5•¼�uÆÚ®x.&ïöÿUýúÂÓDDóUJ•–¾¾>O!W¬ŽŒ‹lÖ#ÖÏu|P¹"{މ‰ÕÊØ¤KñFF†Ïoûwµúë´%wšÖÉ”]sƒ˜¿ˆ�ßëef¦÷ÆÈ‘“ä••Êo£¢N�1ª�HÇjZÔm*//ߨ§§'",kǽxîâÅM]­]}£þ˜vŒ5*°¬¢Â2"*êß;Afcz:OêN‹ Œ¦Ñ—h©éI{غYXú6Ç2«–'ÁÒºÕïA­[žãAÍÔ·^m‚‰ ÝAZÔ'OA8gæ­‡ZÜnÏËŠ»ó@¬%¯æ‡—-G�¨o)ÿæ¡OAÄkîM©Eê*”�üw UkÖB4܆+?Ǩ»”µÂN NÂL’xŸ£¦ïÏÀ±™0èÁߨÃÄšÖÏ�f_Õ˜TdÝmà¦=�÷�“…Dr˜ùÀˆ#¼Y~² WŒÙדš‡FpkëÃÀÆÁ#¡ñÎè%ÈHMÅuéØ9ºÃÝøÖæç#êP’ËÈÃpñ÷‚‡›E/ó°–¡ þââS‘ͳ‚�›/îqí9‡ƒ[Ñm~[ŠÜë—“œ�Ôè38v`7þ͇¡µ ¼³/aëßWÇQ˜9Ä ºä@Ñ›ƒ,/Q±‰H¤wí–ƒ Œq¯j³†÷Ö(p˜ì¸Û]³¥r;ñXï~uüа°Ù¥¥%ÇD::Å´üªkd´%3)©ÛGtR{ØbXX4�R™�Í£,àa,èQ 9úzôV¡"‰E«å)zÔàdD‹¡ê‹•LŽ~ë%·î¥ªq#˜=¯âõ÷ÞÇô—a±M`ãmØS‰%d÷W( ½€—Hãú·gŸfÉé6àWŸ”yíý$ÀŽ›±5©O{6bVꓱk�~„@52NüН¾Ý†½-ÉßÀaðsøÀÕ A­?c‚úL�ÐÔÒäóˆÏ¡Î±ÄñäJˆuL¡ž¢¢º%µ(4Ÿ†/ßœ€Fþè¦Îðv²‚…AϾSÜÚ|I~²©e6< îtP¥”CF—’OaÃóßàCÀÃ3Þ~ ¯.Ÿ…±fš¯à¬&>S Q.)Däîuؾó("­gaÁН{A-FÖ•£8pà4ÎF§S ZÒ´Ž"#T�_�õaÚÀ$kŒó0ëåu5rB·`Í7¿bÓù¢[/ËÛ¶õa빯®²€%KP߆Mçì²uçàØ%¥, z5`ë©/Z-Å0dH°�·õ¨áÅU%E¿~—!µÕß=Œötzvú(KwË+U¥Õöä9}�Ž]qpph`oëêjØr¢›“—í™*9žžCéεµqD~3 Ôírok]·¦jÃÓÓ¯RÜÕû--=ï ´MÉÍMÚ•‘‘Nqíù¼µøúmUhhD.í0 JÅâ\ŸAƒ†A}aÚ¤i£3r2®�\VŸ¸“Ö4ÚVíÕ½'˜ò{FŽôJÎÈàfggGQù�Õ®N2µÿcbb(–Jÿ•ŠÅ+ŒŒ çe¥gÑ3ÖõQH¥ÏÒ�èWœß(•Jw”ååe*�.ÕÒ�f[Ê"п�ÓÄk†ÀN_ s]è£@×Äʼ\pI™ uhõg€‰Ú“ZçÑ%]*�Áãñàõä8X»àÏáO�ÏiÇ”24ÉemD$Ä¿ü•gõý·(|û=Κ‹µ+?ÇÄ{Ætÿ‹\/¿˜è7ú×$[¼± œ `Ü˽Ézùé`ÍïijÓq52rž)<}lo›¸E¥BŠ’´dÔ˜NÁó«žÃ4o;˜ô´Í½¬~ÍA Î�Åþ¯àƒDLë�Àâw?Åã ÆÖyŸFáüŽopÿÛ_ࡉ_4j�pÎ×øã�‡q¿¿E£øžÛ‘!).ñÑñ°³†1~P)j ÎŽÆéŸ^Â+«ÀÕ5ƒ©=M YxûCNÁ—FüŒ�íÖs&·²æ²ð?ñýÏ!ˆHÎEQ^!ŠJEðpÄ=C][YBO&3Åð%ŸÒ’‡ ë¿Ä7}�øžð{î{eXOÖ¹u˳“ƒÊj# ò±RO6u³†n©Q߯d†cñègÏ`ÖhwòãgCW ÀÔ]�j'”yà ÿmg¿a¼gï8���ºvãFˆK$Uüü¦Ä…?xAÆA£Ï;{– 9�–Ä”Å�Óê “É™£k`0ÃXè U©›¾ïðâyÁ,½:ìÈ£1´º¸|æà°$FKë�™ÜÙžÎgΜ)& Î3`úïÐf<ÐÝÑqÐ/¿ÿ~p´»»Î¹øxÆã¹3ˆdUSiU;::Rw%àçååC$y8zäiÞE!º2ÏGoÅÁ‹`¬Õ>ï1ÙîPµú'É[÷Ù§À 1iì|øÁǘ<{>¾ûò3,òqêoívƒ.B­{Š�ï¬�u1%xátþœdÓ=•²µ°h ʬ«ˆæLÁ¢/¾À}“=p³;“!§Å(Í:�ߟ|ù/ü„‡†™ÂR¨��Ðd“ˆœVTàÐX±M‚ ,Æk߯’i^°®·ÛÌ–àƒ©[ðôßÌ燦zШ7˜uÝsªÞ„V¯å±ˆ�HCL¤% fºÀÁBi~Îox�l4Æ;‡b‰·!Äÿ>�g¿Ø†Ã\.¸ÔŽÞ,ïý›ï%o¥¬}øî­•ø~[5ììáïÙ¬¿a£¼…9ÅÈÉäÂØ×^Ž WY/jDó¦*s¢‘ À„×_¯ †ÜÒYF#UÕ�–E¨ïW™ó¿ÂÃcÁ±}¯^ÍÀi@ . yÙ�6#Ð:Žò‘ŸLÜöíÝHbޝ¯¯è©ùŸÎµ7æµiç—ÇwžøáMˆÈ÷ðð0Ö5ÐÛL4³’ÈéÓdf½÷&gà@}fÒÄãŽþicãi8*`Tzzêóa×�®­©‘º0RmnVóZ×àæówøÉ|T¼“ž¾aKRRÌc<Þâ×GŽçka!¢‚»ì‰’BäôªCeçííòÒ²eë˜ú† BÜfçà{ƒ�V]�ŽVw8z{›¹›šj¼´X‡OhÏÀuqsû ¦¬ô¼•�Ýâ²’’¥jrºÎ¦ûn3M•^^Vþd�¬ÆTOGog¥¸rƒ@$ÊñðôüE߯†qaï¿·�Æî²°4F€œ§ñBHæ¹ÀÏŒytiFàÙØ 6&V3ŒÑ +-jŽž>ª��lµUíyù(a/Æ›ºã ‡1­®§>¡"+ï¼Éö�Ðÿà]è½ü¢šœfŽO¬WOR¯¼õžxå5d媌Õgg×wA@‹“W‡˜bÉ|\,�Þ%5{˜E ï"�s‘Fþ?3Á�Èi¦½2òD<­&{^ÎÇ{SLa¥Aã¢p--—,ÂÒw† ‘ü߯X|y.äïÇ‹C 1€Ü³r³âQUQ{sØšjº~sã«©0ê2¢2R�åã ë‘>ðm|X³÷cp=9¡0ƒ¥Ù`Œ ¸ýJÓlóïf]~0bÞ=˜ÒˆœfrÕªÉéu3F zÑY,»w\Y¯»ÁÙ¡ã¬u‡àkKæÖqµÏŒ[³àç“Ëv´T2O[WôÒü_–gT†ûuç»»(-ó}Ã%}i=¡�pÜ¥s—þ¡ý‡o”¡þöùhrDÄÁ¼7§†EÊaâ¿MšüÐ�ãé´ž`;ÒVP™[ö[vnîng7×mŠšÚgˆ|c´—[gø�Â4yõv|üFƾ¹~~¯¿ò£\þØbŠê²6nÛµ‹nwx‚©÷ÚµkÌš<¬í¬­í7ýõW½|J‡êgÈê4 ÐßߊŠ$cüýÍÏ„‡PUM–˲¢ÌYh[ ßÖȨ˜˜¹\þº¬Jìq=¼qÿ‘¹¹y:i»7[(M¬É\“™‡œ¡¾¾kbRb8‡Ï5·³±;¡#-‰‹‹+n63{€E€E ß"p2« GÒ+qjþ@�€kc�šsõ�0�2­g�!�.ÑÂy¨üì†õ]¼¨ÛCNo˾ˆ£…ÑH�°B®V›Ú[{)寽 -_oÿ±‘ˆéÆ> £†Óp]ÅUÓ„f¤û¶aÝo9'þƒž®mju÷'žî ‡I¶zXS†sÍéXê~$Øû3Ö³gÂϿMÚƒä/áØú÷qî¾CØ4ÐkÛm¬?CÚ¨íRIBŽþ…BNñs0r˜,L%QïH%•ÈJ‹¢m扇ô 9jwvõX\u�øST�‹²Ò"X ô‚¯‡Obõé¡8ºe!œÈÂ:]Ò0\ü¯¹i€Åx˜ èMLa®_ŽDFJ>¼1ÂÛC#po­ 1—‘’@ƒ„͆Àlp ú? ‹É“aJrg·ó$U¹I8ù¿ÅøwÖü1јíLkíÓ�t·ŸƒÅfm�&©ÂÆ9–�ÛøØ rº¹ÔWë)+t„†Ößï|úû=G6D�?†¾&’|à]¿~½â9M$è4kÆÃúÙ…_ÌeŽpt°o=9Íìß²BIã8-óOcSÃ=陕ZíØ‘#GºÝž¶uûÍ5¡u¹oO%ÐtÚ—Ñî«WÓ‰‹{©*)Iöƒ¿ÿòn¯¯+÷ÉÃ:3*>>”©ã¹'ž˜óúŠ‚;Á›6<<¼„)3³¸¸tRp°Ï omö7΀ÒÎ@¿!]=}ýÈòÊÊ·T …^ZJÊ÷MEätdSñMÅ………%R�£J®Ôåêé=Q)oäkkÓ¨‡£Ã‡·k*Ç"À"Ðÿ¨%÷éµ×KpŸ“†˜jÖØg.}*22¡"O[64F@‹H^î€�î"_šL²3C¢8ÏDnÆ;®3`¤ÕzâSUVñšµ¨ü|%tŸ~¤1};9ÍØÉÈyx{{Ý0™±]…”èhXxÆŽ}ûoij«Ö °*È{S+‘\ÎþFZƒ›¦ï!@Rwк�ð‘¤]@øé}8íü-¾{ÐúD’Òm‡ mF òÚl$ÅÊ@Ó žn°3A÷ޝ¾B”äG"ô0‘Ø|{È ·Õ†ŽÆu "îz4Ò“9p²·‡‰RŒè32Ìúp6¼ E7;9®œÅñ‚b¤)áîâ§;Üf$»-CÁ5„“&{jž/\ÃwPoò�Glx®ÕÂÄÎÞÇÀ¶Aßšs¬¾_ÝÖ¡ÆLn}d-¶ÛþŒu�ùÁÊ€�^¢*Óš&klšÞôËÐX[mX ß)ϯ]´ê䣩¬¦Rq^ÜñJXÑ_›ÓKÎ¯Ñæ©´\¹,3Ô1ü19.™éU1^´îî£u§º>ýÒ®âµßfdT¦¤DJ###ëÖMðÇtÃî#o\�ÜÒ\«„äÄ=z†úZV––ÿÓæko¹q¼µåitºhR»1<ü[2’ÿXP��w~NðO*îÏ�­SÝ*"“LüO¿ýÆLfÉx¼«üüüL$‰L (mMMMž8‘ɤicP_ t=D2R.#ýýѧQryy¹¢ÚÕFS5:9ÇhÀ€Uñ‰ñKôuõ=3ÒÒrZ´–Ç›A. ûZLsçAUZttEϤ…glhdVYUù®Ž®î,¹¢ö´‡›Çôûe~ßl``臔V+qö`cœ µ0œåVœËÇžév­<[�Ë`÷XúUI§pðø8$�בÑk`C;àC[`�ÁÃ�w>ž¼“ QV]KÓ¸5ÅñáÙ¶ËÉaZŸæxêQxá+hÝã£qa]¹W�ÈÈ $fC×"’¤¥$à�x3ìŒ9zG�;„ìâ|ÔøÝ w'¸4Ô•v¸ì¢ë¡ˆ ‰­\÷±˜íë�A�ójÐa»ZU@i6r J‘+5…Ø \ IDAT­­'†ûÙ@ãú8ZÕ�Ö'’f…ãôÑ�X—7 ï- ‚³){¿j=zKÉÔïSr3"þòìv*¬9í­Á#™‘�6üa÷¯"ҘˑsÉjj÷&Å&­qq ÔoûæW�Ù8@>ÒãŒURLüþG>¿aTuGŒ»A fQÃíÜí,*Õ#©é)–ÖÖÌMM×qVÔ‘ò5,¯|ÃÙ³ŒCäTKK‡G<=ƒ.q8§÷EG3íÖ'ˆz™î€áëé|óÚÛOÐÖÑñ"y�Õmí`é$€xx`�““]P@€M¨ËÕÖv¢(µwkÇ݆†† �Q;…�1G%Ð6‘yOrŸimPëlÍQè4ܵõ³œ=¡ÐR�Ī6ÎÍü«ôõƒ­©GSÒØæÅe%�>_–T²¼ZZÝèwÙ¤� ʼn&ã[©(,,Ì£eeY. m$2ÉÓDV?*¶êëëÿ™žž~•ŽÝÝ–Ö×ɦd`Ð`Þ<—‡94ᚉ¨n`«&™ÊÔ--(ÒÒX‚º‰#˜4Ò�»Qsä³f4‘¢íQ»sñ?ÿNŽz£�œ®‹QHtaq1ò i#ZÏž6&Æ4ìY¡3¢xó‚ï�ÎÒGÔžÝw«Ù�<¨7yaéä„*ûÓ7ß /5Ç»ec�߆өô´§1ÉD\i5÷"&å¶¶°»,F ÷2Nœ ÃÑ<ÌX4žìŒˆ„” -=3x?øÆýøNVǺŸ‡Áþµyïnf|MaôaìÛð Öü› ‰™¦>ÿ=Þ�mºišókYìeD¦e «ºZVðàéÑö·L¬ÉÀ…s‡ÓQœ_ ¯I>ph�¢Ø}Ù‹}!9…páïA.Ðë¾Ê;\SyM ˜›‰Üì1CíûøóŒdÔ.�9…¿â-1ûá‰lÓúk›-,AÝÃÁ¬À§=iBD†U“”Œ9D †[.^QQ\Zöó…Ø”Ø<##£!D_±`bŒ5ÏØÖkf°Í–½«B“ÆLÀG!: Ô�Ú!3>“ñòüÊÝÝýÇòªª)Y9Ù'm�ì¯òù‚oÒÏÛ»¢þn,Su8//�YÆXZš½êç7¾¸°°2ÒÂâJ½ÇsgÚB´°¶¶¶¡›†Ö2Š`êP(‘ðjÄ5^׊¯2ØçUVU�ž>eÊ‹²êêS‘QÉö¶Î%…jEuzžwP]N:J¥®´ºÚ¥~¿¢¢Â9.5Õ©©4Û1î-wÖvM6v<}ÁÖ…êÊú­ºuY"­oâETe’ÊjNyY} 1¿¸T¦-WëŠ ‹*$%&§#ÂÃõo!N?;_Ÿ¥ [¿A:ÒJŽj}�¼&CG òLMJ­jµÑÆt/í¼¶Êe2YzRBÒÛTÿ{DP»Óð½Å�è„¥¥ù2ÙŽÒüü:¦öÂoµ�lB�^ƒ@ze-þˆ)ž™i3#ñÁÑׇ<=½‘w“FÛF1ZÔsf¡rå7Ð7ý¬¸åñÙLªlY)ž ù†!ùX¾aRÒÉÓ,% ‚º.Ô•@“>¾øò–®Då+Qsñ2 Þ} ÚÁc›)ùÎh†Œ`c‹sûÿÅðÉÓñû¶¿ñé[oÜ™��¹+Óõ`©ÃÇñL1KPß-6AŸE ÷ö½€3Å–7e,¦¸3󄳡£pµta쵯c�>À–ãëð]ÅEì·6CVd^CJn9 §~„o‚œá9q†[u´Ö®ÉŸGÂsŠó 1vBÀˆ)¸oüDÜq™$„àHR ¤^˜ïãgûNSÿìšF5*5 ‰ù(-0€“­¬[z'h”QvÊ‘tõ’S³!6G8öe¾¶à:N…œÅ¾}M‡YÞfpú— ,A݃ç{²ïÃNÑÅÇ“ÉFVCML:ÎõSÕp´/çí-HH¸žD¸¼¼¼´;NåÆÇFÐ$ˆ&iqqG¯ŸÝQÞݦÇÇÇ3_BjI k›aÅEùï™ ðÒÕ=#7”_Ì�Ìï­Ó•3$qQLzÞÚ©ryUjaá93]]ã¥%{Œ<<~N­ªŠ—)•\’áhð&¶05u¤¼ £\´ø|oŽJ¥î˜&öP$–H†Ðqu(+-w+¯ª°¯ßOŠLs´8’º}ôD:Y®JÂBŸšr§6F¡RÐh-%ªkjKOž>}†‘D’ÀÕÒÄNΫTêŒé莔”J^–Ê«ò™²”<¥B(PäT*•êóa"“I뽯Ät¹P§D±`Þ¼IÅÅñ‡CB2˜|͆¼nÂ_>h̘”kigÊ�ÖlÎÞr@ÛÁÉéÅÒÒ’E:BÑ’¼œ¼è6^ æëo›óÝ=ƒ¢¤¤$†–w)é{\¡Ð‡'•>*‰±¶±ù�:PÖ‘|K:SßCî^›‚E€E 7 °3±Dl�¶ÖÐ0 Õòe& 4bt–YÑ;.+íQ#ÕÄ´lï~ˆzàŽãm‰ø*éœé£ö�… °â­÷‘ÅôQÖŸ ä±ûÅ;o¡öBªÖü®¹Œ~ù|gçºã­ü;Ô×�À@üúíWxëÓ/ðѯ�G¤{kBi“Ç&$ÂÚʃ½<[“¥Ï¦aÞç¾i�Ï˰Ìw@Ÿm'Û0�f¨JDè¿g𣠗©c0k„C¯òm¶]q€& ÔrÆØçž‡½Y®¿µ±‰–012�«™º£á<Þƒƒgc†—�FXÜ´ÙHŒÌBaŽVÞA˜qß,Lóº“L Ù�˜ÊrT¹Ì‚�«ì5¹I·74ó:®fW _ä� [Ø5¸ˆÝžP÷si.Š,äg‰a` ggGhè›iÇÁ“¤áêѳ8] ˉ°p¬ zSWBÇÐŒX‚º‡ÎÃô€'ÝJN¦“ Iqøk=>ó¾ b©¤(<瀯�Âr—D¢'¹wè®"ž‰ñÎK+ÏÁΘêáã£u“í!롌�Œ¼H•Ï÷>Üž™ŒñfÑÓÑñÎW*?é茳²²ú¯¢¼üí¢¢¢:ÆzV·[6‹€Æ @’Z8’^‰eƒM` ÝðHÔûê Ñö÷ƒìðQµ”hb64F€cd½eÏAòç_-ºŸf»¸#æA}·R‡_ÓOáê=ÂCß ÷ž Æ¢§ŸÅ®]{èâæKD`@†ÅÄ¡ŒêÓ}øAè<ùøÝŠnò¸ ËõaÞŒ{Õõ‰Óg1‰dBîvÿÎç_âþY÷a×¾ê‡_ˆä¦‘@wËÚg�ßc­ƒ—ÎÔâb�æ}Ùí¬ÏžB¶aíE@œ‚‹ûN"$A÷‰£1i”S#rZ%¯Ee|²­áDšíBÍ}ܵ�.ϧR*Pr¬á:f!†-Æ‚ilÝ‹î5Yˆ´ê�dÿHo|�Ô}ÎfãÔÁ˨ª�ÂnÚ0¸Û[¡7q¼y¡ÇQ\¹ç½ðps‚mïÑ&!­˜DÄf– »Ò‚$CÝ1Ìˢ˯ë©@’�ˆ£§p2¢þ£1}‚n社 C®™7l u¡{ç+]�˜Ý+e¡í¦³ª£ÔƒE­R‘ˆ{ƒ˜—r%+)'©öÅé?=QP›{5ãà„{« ÍmüròÅbƬ¬¬ÐØn2¯ÝÕD_ºÄøÖ.#Y’—ZÂç’sR²t tÄCýýÉÕ—ãªÅ×bÜgÔD±B�в²_8*”UúäæfûÕWÎ9ÃSÄrÔ¤*}´)IŽ¢šhVõ~þß…ZÍ {™{kéÅS¸R˜‡J×Ù6|8[݆]+(:†CçjQ.¶ÆšÒ‚›‡ø”R�¬á ñ“má‰0”)à1Ù îNôK(HDbQ9jxk¼{Yø9\ËËFö?Lvó…»A>Òr�ÁuÄ—ÞÔMpÛuÕh·igãÀ�2Œ›€é‹üawëqÑ(’tœÜ¾’9ö0Ôc ê[áéìíæß4;»¦þ]÷óŒŸ0¬|¶/þîáã'÷ q˜ý®—Ï””ˆœÿÒÙ ã^¹vñµ+Å�ˆÝ9 ׆q‡–"{ #m3ú ª»4Tx�婸j× $ÒK¼øV«<®ýY¿/ã—æŸ˜þ`YU¡Çõ´ÐEB}íµö–©Ri Ã:+|q’‘ŽáõéE"qnNvƒ×®JÁø�Ý„àæôDpÐÙßBBêóÞ¾Î+M³Ô‡¸ìú­Î_‡çäH–¯RÉœ�‚‚æ? T¿zþüÚ§fö|`&GüêÛo™ó¤æ –.\8œ¶£|=<¦……%†feÝAÁŸ9sF-2sêTׯٮߴédÏ·¤K,à t¸&+3û!7WW·¨¨(u»;Z‘ÓÞTFJGËioþ+¡$GŒ`òÛ�;ufvövêà®§¯Kí\tùòåøö–ÝÞ|ó}LÜy½hË�ü<›¾VÙ%4†¯…àiàSÎŒÎh‘X÷åÎY©Üó,S”¯Ó0÷ÈÔîo_ Í`±t�m eð5ÂHÀ ÒÜÀ%O[ÆR ­­¹†ö¤e$‹!$/äÊoþí±cÀ14llM‹w:¨=§•t;ülÐ<ð97Ý uD"<|ÿ| ÷òÂK³æb%é�ëx¸#uÑœ$IŽ�“¦â‡Ï>ÁÜ{§AO·clÅ "»?ýì \º�‘ÃüÛËÞ†-Û Mgº¹8«ciBmL&¯ë•߯ÁDP÷×N -’^¹×QŸ\*D‘LS"¬ÙÀ"з�¡0áüô‘9Ó i.4V¬%©†ôãXëƒ_Mù E+6´¹ò¬X³1åR'ä&Fâši%dŽami#µ{X[ íîôÕˆ%ò¶.“a�‹Ý^«ªÚTŸ;�´®Ò�AÅîÆ‰2g¸›¢ùuõE\<+Ai±=†´‚ž2×Oþ�s™2G8j8A]ƒ¨kQ˜Ÿ ý¡ áâfAÜì>‰H³ûûA]�â”Cظr/r܃1ʬÙt¿jD%)‰:Éù?Fyáƒ%ÌûywÿNúW}ìã ëÏ7÷Û—7] *yP]Ó,ã§7ZºŽ\±=îóÙ×BC2)RqêÚ�ÖtÃDuµ>×SßÇ¡Þ4m®Ï¢Êo(³Ÿ¦se¤E¡¯Î4 FòB9Ñ*mYEý¾Ø03V®¬÷Éå(UyÒL’T–«?ƒjÉ�6??¿a:71Wª,+ËiÈ›šZR¦­]Üà¹mbbr¼¾\f^þÒ­û`î ŒþÄ×L´^|7ǃ{¦�g/�!OïL~÷.�\´4/¨>8{v™Å™àíd¾¨J±|ƒ®þ×$•¡>ç¿ÿý7Cø1!††ÚäšÏ}á…¶ægg¯Ú¾{whÝ¡º¿{N Nž3}º‹\¡ÐÚwäHõpkºÞ¸M�1Ssòr7�œËË5ÕÕˈœ¾ 5ЦVîmSê.LLzæRñcháêëéWUU}¤­­ýIÞ\òôô|÷êÕ«—»°zuÑNº°á�:ÉÈr�´µEee¥+T£[ª×ÌP4?µ¼v¥ÐB:’m眸Î5ÜŒ‘h'! £"ZÈÏbÐx~¼V‚Å·™j5o MÄw"1ÙÐ4š$QüÓ/�:BR šNÔDlHQV§Ç?/ÐÐw­;R¨¨cÀfÏ¿øËÞü‡b¿B޵3ïÃu:»ÄŠ÷?Âú-á·ÿ}×�ïÈßÚ?_Øé|ôÄÉf êšš\»‘ o™rˆ·76oþ …° Mìþî#‚úå3yH.¯!‚º ½ï¯'Œmw;PÑ”5¨Ì¿ˆ?^~Û“s‘½ò8~YÙTqh“dÑØoÏÃF[Ä+›2QÓ㘹ø"è 9àÊâ±ííÅØF6<úž]²céí<„º†03ѽáz¦a�’§"=E†Êjw r‡«ý�Š¿J…Y4H•YÃQâ‹›pÄi.&MÄtÏÛE4¬}Œ99ÙÈ"r]J㵫ŠSºm?Z1hþ»˜ã®�ö62©%…5�ÑrWs˜ˆãq.©ÒÁËðÛóF){çŽUW°ã½Ï°íJ NÀo?7Õ¦‹]c¿9+}]°ütSu^KPw–�J"2VPVùÜsâªaËÛ_kï09ö w”$¾Ê²ÛÛOt~‹ã²ÅWÓò㘌’¬ F=Bx\¨øgê÷ ü�Õ×™}__ÿ˜líÐäðüp0¾:Å´¾°Æë´´´ÆmÜcä"ha¼;¹v.vŽ®^®¼CÿR·¹�EirrÕñ¨Ô|bòßbddô®ŸßŒ²ššâ5ÑÑ¡šdô é5‰·zõê…ŒmŒþô`�11W®œWèéqBCCËCBBò/ÉÇÇÇ�‘ýÐÕÕÕ¿xñbC§†&µ©5¶P,srsWªTæ¦fÎ ÒÖäkK‘H@ÚàõmÉÚ•i•ÙÙÙŒ\Ð2Z˜Ž%“êêêçutu÷Ñdž¤Pc¶>==éÅw&QOÅîƒG§^Ù»›Ù&�}}//3WiéM†S¨­wØÁJÿñô\&W³AÛÆÁaZz&Ô§¨ªÖ=§gW3ª*§ëãØ5‹@oE £²×I…ÊßܲW4�ï⊚SgX‚º…³ÅxMë½²’­Ctÿ<" nzÐ6çU\Z+Æó×ÿÄLË!i\ç‘ÜP�5“GÇ òý�Á16‚ñ–M¸×ÒþD3�ñ®~hþ<µȃÏ<¿q“±}ý/˜6a<ÍeÙ\� ¥ß±ÁxE¿¿âü¾ío|ð:3xìÎ «®FIi)´´ø ‰œX[Z¨5Êã“’ú5AmCb•¾&D•ÈhÁÔ »¡aÁLÿH’Je{^ �W'aÛóðý)Êh*µæpè@Ïh$fOp€ +à¨ý›T$÷H/»íiR—œ!²‡p¦ï²©�F©”PÐ×ZµùL¡�«a|”ªÇÇ*±ù]<¾ñ­ºa½&C¸àulúfìh@´ŽöÍçO—4­­…æ\ÂåÄZTÙ�‡�§#›ê›§çWKú~�,ýO©^‡•ô\ïª×ÖÚz&=—ž‹::dŽüï7Þx/>;#ZrÇéK›¨ÕÖNF0µÐÅ™¿ÅŠÔyXòÂëø±rZY+C�\¡¾>oȇ˃¶P@£ÁnƶiëÆo™ùÉÔýl˜»Í4Fûæ¦ÕæÀäÉÄžW–â‡ã$a"oé~Å8 Åô±a ×�–ÚxúáRÕézÙf »&KPw2®ŽŽÓ-¥µ³–¥¤û­P*¸B»+Ÿ•ýõãϱÂ×�¬�/„Eüw`±µù#Á¹§¾z1ëä‘ËÖf_þÅç¯:›‘ÑàŬ6©¨iÃj¤b‰J®E]ˆ½.(O>™ÈXí7ÆÏÄËÕ÷ž«a—÷µVï˜Ü&u{C‹¯•••]»zu/ÓAñ¤³ób-þS*��,ˆLígô§i9ÄØæïï¯?yòäaG�½<ç¾93¤µÒÔÇGM˜0Á„þñãÇë¾~5±!MÛÄ£I+_KÏÈX&24—‘ž®¾þšNÚ±X�ž^-3y¥æžQó­?644´Wñ½ìí142ÚZ-•n/))¹DÇ:Å Ù ·j(•¥&¨™z Êwû"W¡°° Vn”¼ÅPM�foTC"úmIýÝ�ø·ðú¤ÓÈ„¢â›>·çí/ûsàD¦�ê+š�ýåÌõ§væ Y/’Á'†ùµmcãùУ;Óð½uÞ�2¢—9Jhuå£#ê2ÉPIK®REŒ«�u›Ô%ÉSH°W3Êá™JJ—Ám]"+ˆÇ¥uË0ë{Þ"¿¯K®Bè«Y�«ØúüGX³é"ÛK"qé·G1tŸ3Ìþ©ŸwI‹Ú]¨Ýøæø<¬] äIß1ÅÂñɈ[ªP“\-´ùF´·€ýÃXs~!¾'&U.øÔéKÿ{MúôNìyüáLd;cK!bã#øèçƒ8vÓÕ’’ÀÒõ^¼óÏ:<êÐRîŽ%Då¥HβçL’ÍB:.•WÃ<‚‰hkÁ SîˆÖ_Å<"¸ïÞWD»ˆöŽÜ¯rÈø¬4•9!&™ªA î@ ©ûÀ‰Øˆ»"ÀÑ7™çn ·ä»´ ëiBQu‘ŽÞÑ—�tlÊJeX+nZ†ËwÇNÎbJŠÖ’Wçú‹Š–Œ++ûb¸LöÞuW×oÿ‹W†ää4CMßÕ†^“àꙫŴìa ~àÑÆD‡GÇÒ„o}ªÝ$eB>8Ï´ñ1só‘F�Ö‹),ŒÙŸ��GQw{gc²u{ iˆJª”!)±gßF¦EMZ;ØØ8GŸ?nѼyÃ+¤RÅÁƒ¯Ò!�lc3Ž……E I[ìVr8oVUVÚÒRw¤‹þ–^뢢»¢XEyyy*-ŸP៚›™¹Ó„£ …Âý$_½‡úX¾§I$ã©ó¨¦�•s*iÓvæmO6y„ë´'#›‡E@Óˆ*ªÆ@#mXõ’éÁy¶¶PUUA‘• ž½�¦Á©9ö0ZÔÓ§¢jÕjhßÔ@*7e`xy:>Šÿû–c€vÁË|9)òò Y³µ1qÐ}å%ÆÞCO»–]‘tÉkë™%�ÐǼ^yïC˜ €‡ÞßTµ-ÆÑ(!xº¹bÛîðèâEw¤e<•äΗ˜–Œ‘Sîm8^RÂ0B*T±ÞßÃD;]ü]¢~yjù¬õw¤Øö÷ �VçÙÛ>jÆr.‘κh™ÂêÆ*ÿ jã´¨1_.äõ©¶‰Ðn³§z2/ïÃïo¯Ä޼ øþÒk¸×zŒ´ÈËX}cŽEßlÆ´A @œzGÿ+¶$ `ó2¼39 o“àž®¦œ y‹îFGÝð Ö›Ûzù¶ª�m-´ûÒ3ÞëÂVc¹fÏaÅ7ïáNzdd%RI õЮ`éç˜oÓ»iÔó#¾9B}·ª‰ÐæßQ½ð:MvŒÔ§èÔõ�60÷"ÖƒºydïvGh>'{„A€ooÿL`aÉû*K\Uq˜�ýŽÙ™i¤².¦o6潜‚···;éÝÆÖíÕýeÈŸ·�u´·~¥™Ù²Q¹9o|#¿šâä°ùÅ¥ËC+*ú…»ÉÖ�[Ï Ü€€cŽG–s+N}a{CAA( 0"ØÍÍôS�‡"TªÓ1|~vk½Ç{†´¦åcƒ‰›[)‘Õ‹¨s%’<“íÉËïÆ—sOZظnò 6¦áÅÿ�7W:m»äЄ–�StÙÞ}TòÞ.+½ë V‘Grÿ³�œË âââg)n–��Ãe™LòFaa!u÷ªßs[k…J¤'b¾º+ð eâ>wßè.ðØz4 �ø²jšPÍ@³ŒjÁ5)M^³òÄD– n'æ�`òDˆþÕÇOBDÉL`ø„[ÉÊ ¹Ë"7c¦ÅÜcrsDIõ鳯ú|wwýô=¸VVêü­ùÃÈz<öà0"©‘gV¼¦–Ú˜<.¸5Y¥ ê‡_7mn’’Ð…� IDAT æR<Ò§c´®ÏÞš¤W�wiaϽ á×nTVÜ1òQY£D¾DKvF¸þx ô‚6›Ã –ð2·µKñôwó¡›o œcCM9v°ƒ1YëÃÔ¶mÏ{qJ8Îí^‡M)µp^º3-Õ“ Þ|Ž gjIK][VD^ë2÷ß÷ðÖ?y¸Ÿ…Ú@ë.v[לY;º7Œ ¦y’ò‰ª�pübcòaùدX8Î솗;­r¤w"ý³°§× õõ=€~E6ðÑÏ‚ÀãÆß΢»-›9ýö,m`Lº .tObCÓÔ½A6}Œ�m¾×àÕ/ƒ^›‘óx8åIC|¿s+/™2‚Èé)[£>Z"Ì ›/ Jb€~S%¶9á<ð9‹¼üñ«++ŠXšŸ²·oò퀼Tn>‡Z(¸× �’Ñ8–WÊRž3#©±—PÆÕ…ÇPo0œ{“/Ê7ÎOh+'/ vQwš 0¦uK94ï²õ&ô`l¬£&§ãoÂñs)P>�9÷ ‚­~ÛA“0ƒ"ˆû©ÁP`&WB�D­…z½ä~¥Í/½2©ïID¤Ïfo úl ÛÙ°ÀÀÅ®·get…õ�O§‚{¹6:jÔ7vö»]ГVNºví¯ÄÛÓ3ûÆÆÆöä�ZÜÔ±Ûã^OJY;V*³Ý5Äo–YAá¨U™™%gtu³'ZÔ§åp9ªaÎ&Ó‚‡«IÜúè>±&œ˜·vÕ¥�K \èGÛÌ´/>E•¯ÅÄü²êԩБVVŽ›‡ø~;ÒÖ–™U¨×´õÀ±cieûIJÃÐÜÜdsÞfÍšåóþûTÓvÛÞ¶(CGBppp—Ç•¦Ð$€N4 "ãÜ­�äDbºµÂn¨Œ~�ÉÔ®y2©ÔÚÎÎnFiiéf"9j¨ ‰&×ôlÉÃüÈp.�ZŸ†æÇª–Hbs™ýëå(7á+²ê�ݺÎ) ?Kûê¾|‘åžúí[Ó0qJåþ7êãâ³gHsÂ3ê÷Ù5‹@oF ³ª#­:FP×ÒPG¦œî ‚©S¡Hê}t]™öÄñt#É †¤¾-\¯ÈŠèmøÞg1L´õ HNAiGWŸ¿ÃᅢÎC‹ÕDËmÙZ½ËhCôækp$)–Õë6´:_}BOºíGÞò·¡@c#CÔÖÖBV}“€Í!Y&x¸¸Üž¥ßíë�på"¨#Hß— ,,,íA€OúËB‘>$U¸vŒ\#¯¸; •‘lo&""s!p�ƒù#t! 96°tåˆ=´{Ϥ Òq &�ñ'麮«�-¹ï!ÀÔMœS#“mŠÅ: “z ò}t(_p,&)e›¬²\ÇÑØñ¥Pøkg¦Í™Çh 7QDC”©¥©;í´üìhH]·ñM² Tiý0hÐP‘Db½òÒÅÜãAÜ’Áƒ½b÷ÄFEFçýüÚÕÄ™óÜŸº-kŸÙý{Ëßá4i÷¡Ç—Lµ©&oûLÛnmÈÖÐи‡¯E.ÏåóUk=<Þ}ÐÏÏãÖãš¾M,æoÞü×6Ò,Ö¡!½Ü�?þˆ!ÚåtîLüq† äŒ9²á·Ô™í155Õ×ÖÖŠ»}ý'U y5rmg–߯²‰�>.]º”WPPD³�k‘ H`ZJÚ 8Ý\ƒÃ�Z„ý~¨™ãÊüK»Rš9Ör-­¼a§…�Òë[má0{ˆE GH¯¨ÁOÅêåGZÿr½׉ b¶ë—ŒÊ›dr ‘ËF‚¶½š•×(È+SŠ?ãʰä¿,ÌÝŸAëu_³ãÇAžšª&^»¯ÖÞY‡ÜfS&£jí¯P’'rýi’*jðJÔV’õpÇTC7Èö@ùòÐäA’$íAúÏŒ`GƒiIýÑûøå÷?�š‘Ѧâ\:�'!1ùÎÎm’ðêë±DŒ²ròš¾®D^‡—ßÐ\õQ»>W’ˆH^%øìçx+f²e7tú:Éb!yy™�·$#ãÃ�ö  oç‡abœU.oÿ°gòä¨VÞYZiòyYÿ>XûrÆãƒ×žÅ8;ràìø£äÎÊØ5å`<§÷�MC­ÓDŒ  w�¶!ЭžŽm3­GRsLÌ~_]\ìò £SÄ_B½'�9œE¿ÄFº u¤Y¶öküÒ� ¿Hs´.ð¥•RÆ#°=AõGLÌÕ?è“ä~S3çåâªÐ"#¢Æxz|q¨Xò›¶\¡÷ÚÁ”ïªHˆqÈ 6ÿ.íÚµ›_í©QÃò�§‚†ä⌚4rö¼Ù‚výó�†™Ù)æ�æ¯ìYà#/zoxvèл¢"Ÿ]ff¿3tJ]\#§±gÏžh¦Ò¨Ö&»‹h9Ìì§§§sˆ°ÖÉÏÏWMš0á“‹—/¿Ý� ø˜"y¤�ýiuµl‘©©Ù=Tw&ÙÃáh×ß-Õ8Ð5??o›‰‰i–\,¿[ÇC›:æšh@kó·6]U°Q,]‹@-½-ìO©Ä¡´ºÇóD{}Xè`[|9Îf‹1ÙQÓ�êÆ=ËÐ%ßÖÆKúX†›‰”>“#F)åQ=ÐH€“óœ`Ý�3 qÍÍÀáó ÌÏ×Ò²5æ÷ë4ÂÓ!ùm=jNŸ!êëíÍ»Šë•Y¸>ìMÔ¾÷)jcã ÿÎÐ  1I�ûª>ØÛ n.ÎøöÇŸ±fåç­> =šìINKk2ÏSKÁ÷¿®Cjz:ìmmˆ¨.Ç�#G±aÍM¦×´Èã�äܮšäÃøÃÿiX :×å‹éŒ°Óã#ª„%¨5íܳö°ôf®2õq¼¦ª…ý…"\ßø²kÊhNÒ·½>TK É{º <êô1m^ž2°·4“µ³—"�{ùo: ™ã L›<Ãíu .-EYq1 h$UÝÛn/mkv·!йo½Ýfv—TÄ1±øý‡âBïç™Ò££&mäöµWQié5m�UÓÊó÷¥¥%¶Ízð`ÿ1á';h­jGaaÒÀlž‰‰G~Unþ™à¦L‘L.úhwÄŸ¯›™9GZ%<XV\VšP˜p¤ëÜÁz5)»*¿,7ôÔ®S YÍ�?þô�;w í>GLÃ[}åÊjÛÅû%×™..aÁ££´y5éÄÜf‹œÙW(úî£G×ÄŸ;WÉì3ä5-Ì&6nÚô*³ž8q¢=yà:oß¾½M¿’_YY¹Q$½J“÷½SQQ©×¹¾¾¾.ÙÕgÇíîºtÚ¾“ɤzzúS )éTÓm‰ ,,-!àb¤�}³1ãŸ4N«„D®TÏ8žM³] °uº=„7Ü�³(ÎPÀ»£8æAW$%i"¶®‘÷õ‰Ì*œÌ£\Ú¸ÿÒÏB„îs€½~÷kññÝÜP}ð0D�-½Ã~6¢1}=è­xÒ»€‘¯ ¾*+£7à[™ø/¾ •©©ÚkšçèÐ8c'퉄B,˜u6þµ ••0Ðoý'ㄱ÷ 6>¾IKÜéãóço¿ÆW«× šÒ=q/\€ä1Þ‚‡]>3 ¤i)3ñcgs5RÈ©ƒ‰ ,,,íA@ßÚÁ�ÿ�sqÜêSlOGDú�%y܃ñ¾†ùƒ5fvÈ;�dcú ┳Øùó*üS9 ùH:÷/-4¬Z¡M“vÚã—>ÓT¶!]ŒKP×Ì3±Ø²®¸ÐýÑz¼kk ËMõs3ç/ª�kãšWYYz¥�yZL¾«¸8î1»a~…™+êŠjª­Våç•<§47¹xéâfÒ:Ç Ç áR=ÈceW’Â’ªêÓö‘µ’ÈéýL[H{Ø…<�³ïã>Ò¶[›¡ÜQTÏ,3lmmÞ:tRVYYN¶½}lHHˆF�²·{ëv\\\1³`BžÎVˆºõ8³}ìØ± Z1 CVO‘ËåÉÔ®___ÓÈÈÈ;Èxº®-‰ÞJÞMñ$1á•‘‘¡Q×5Ù6šš²—iO <"§—VUU~¦««7'''7”iŸR©¤YgØÀ"À"ÐþùóÑË“ 4W‚ »Sál¨�õ“lÈi¦œ<±ÌDjõ�ñ’þ'¹¿Ç”âR¾”ˆ-%ª‰ànªkv ±ûg9t«çt½�Ìšïå éÖm,A}+(-lk�†tÛv(¥R|Ï�ÏÂôðÂ…÷ƒÃÌÔ…áÞÉ“ðåªÕ(b¼šÚ@P�ŽCÇŽ5kÙc.ÆìéÓ •É0wƽ0¡I4µ´º¿Ã¤Y{ø€1I|0¿ëj– îá3ÁVÏ"ÐÛÐ‚ÈØ3>þ 3z{SXûûU‰Ç%u†Vq®¡åF«¬}ÇaÖSóÀ*}ô‰ÓÜ-�èï5×Í-ȧ¼|Å'ù…ö÷Ýüê«óšÈÍ\ci¯ôÊËØÒæ ÐÝÜ\Sh¶¶Î<‹KF÷Z›´¾V[»\«¦¦¡;”'— *,,zÒÂÂ,2-MŒ4òŸ¦0p®ÛðÑËÆšfE¤]K?“^HQMl26·%¡™DÒ†DP׸»»ëÆÇÇ«=vÛRFoH»?++›Y˜I:HI™ëîç—r¶¦&Žd2$šlÿÅ‹¢šY8ÞÞÞæQQQùMÙKdõ‘úx" 1V­1cÆÕÔÔHã:kÔ¨Q‡^Ýhog¿¯ººø½¼¼*q}z Z3ýêà8FiU.RÜЧ7ô�q¹ÒKŒèèšú4½`Í177÷‘H$e2Ù*±XbE ëòÕ Nk¢f"0ØL„—üLðahÊIŽcéHcõ„iõÖ2|U¶¸ä)ýù¥B„dUáL¶2F#ä.ÁL—�¯ƒ,Õ7Crw8Ô½Q1õõ?ýúý;kàš;Á&7 Ò5æÙÛß™€�i„G €vð=@I-Þ$ÍðçfÐýú9h1’Ý\HOºº¦•â¶=NýHg:;'·Y i* ˜š°Ÿ¡ÍÄŒ–PÐOšYØÀ"À"À"À"À"ÐW°˜ò~™ÒWZö£'è·õàÁ~ÏDD\ýµ²òÁù…â23³óï•§êeĪTR¾ž’U©'S䄇·‹LKH`¼z;õtÓ¹KÑ›€Á7.N°——®�@`ç*‘ø ()rYQ^ºz ð$W�ûMÙ�p) pí®o÷ºÝqWÇTgÒÄŽ7gdêÉ«¯ u×ðMzl’αz"5’‹`\tø¤Ìí ¾q¬êޤ̄œŸÛAÀ >>c™ïÍÉ9ž’Âx×3ÝkTëjS9]ÌèPÓùbÄ�K¿¥Œëׯ—2»gΜa:TÔaذaï ‚±ÅÅÅ‚¤¤ü-41â077÷oÉ‹zmEEE%êÔßÙ�jÛ´²±±qÎÎÎVwH¥]CçGQ‰êyÚ’ƒdÍCAûñÆYÆÃºWú-ðÿÏÞu€EumÝ5†Þ;HS°""Ø»&–ÄhLLL1½ç½—ú祽ô®éÅ�ÆÄh4{‰Ø(¥÷Þ¤ Lý÷Ä t˜<çû.sçÜSöYw¸e�}Ö‹w©TŠ,77·€¶ÁšÄ ¸‘# $n׉–÷‹hGMlô¦ÔËx(Ô,pKÆáÇ WjñJQ~‡¬-"RûŽ™WédVY{Í·¦7ˆª¹á³¾NÓnßXïëJ^©Ìò-R$‘$‚Š´“9AÝG]ŽJUâE(Žƒ"ö4í_½G`Hp(lÿuyM›·PQÿÙÒµ¦{)hõR‡·¶²B y}[ªTÕ¢Xñ��‚“ÔÖâðTk5È’—\}PÐÿ‡›¹-i¶Ö{w—+«a'aJVצ ¥¶’¶Â-\[§µoúÿ×�Òºæ‰#Ààp8ŽGàZnX‚šÈéoyy�½Â>‹È·“múHÌÓ•H� }´ÕJÚèøxFL&\ÙZ,zñ0yÆ;¬@È!w ¿u¸…öoí*" ±×+ž’�=ZÊÆGä´èé§Ÿ~îóÏ?ÿ˜}ï­é‹sçö³±EÚ¬î×ïóU"ÑÛ;ŒÙK^E¿7Õ¨Q£¬ûöí;jÅŠ;Ú{nÈ‹úòÊ*!é�Dªó7«GÈCHëz©}½¼¼Ñ‹ö"Z°PÜÞ6õ].???€ÚlX1¡º'öܼÝÿºëÎ:ç?ï)úµêf}÷×Mí ¼¼¼VåååNóõõ–’’’UZÊøÿ–R¯¸t´48žÏÐ+L¢ãÍc…ˆt·@\‘Ѥ#½2¡ � tÐõóR¸3|Iöã­ã…¸%À§©ÌéÂZòЦùä6þÕ<­$ør¼ú’Þu�¤Æ¬öÕgŽ�*þÌLDsøªézÞÑ””BMq4´©3³ ÎÈ„*5ÚŠË8:@äéaH–ôUႃ ß Çc3=Í ù‡OÕ³EM›S1]W§€XÔ±×MB˜“üHqi)œê»M[ïùœ2¢ñuê¤TQ¼ "£�dŽ86öuXºèŒ9^–‚Gâ–ã|E&„B1Bm¼ðYè]˜è¬;>hß+ø+âߨ"¢›¥2e òk+ðÔÙŸ±#ê0}j}$&ï!$r¼;ô­õaoƒ#Ààp8Ž€!èØ“©!-5¡¾mî sW£Éñ_ÅÿÆìòó·õøÈs•ïî>ÙuÄ`Ä^7`¤n §Ÿ|òÉíÛ·ï"­�J¯XŸc>žœ|ù8ðµ)|gèлå"QùÛ11[ôÙ‡>Û:L�iÛA’,ÖBzâ;ÓþÉ“'ã¨Þ0ÚDN;’Þåj‘Xeia?`À€GˆÔ>Û™v;[‡ÈrÀójZ¹»Ì?]{ÞáâÄ—·«5–÷jCîDDDÌ‹‰‰ù™d=nÏÎξ›ÈiCšÃûæô*X@´ûweë$=vßæ‡çäá˸<¶7£<,êXÏL:P€DW 1Þ‰r…šHiæiK$õ—gJ°!¥µ¤AÝ\Ê©Tâ±}¹8½0nTßPIIÚÉÕß/3T÷ëWK2Ê“'¡8|Šã' )"O]ò�˜I!2Ò#`ñàb== bHS‘�Ï�EÊ”§ðÒá*ܲ=gøÃ¶‘ys*'â4§¶ÁÖîDs6;SÐ\µ&y—èoFöYY6õnR¸qÔ¶66È âݘêgý§a¦ë ßÿ*ë.SPѼ’°¿„=‘@ˆH‡¾8=ámxìxš°óÀžQ/éò†ÆÊL=ú¡Q3Œ>ð?ݼPÕë Î í7|ÊIÛƒ­¦ý#5ßpˆr8ŽG€#À¸á0Ü›Lo…>,L{ℎ6æ!¦Æ¦V ³sCr¤Q�EͨB•HrB²�¼\[”_0æñ4gÛ—_~ùËŸ}ÛìAR�Ô¶³dhsmažæ•Ó§&»„s<çTUýçG;»W_¼Ø1�ÉÓ §í0ënÈ�!vqqq�%qµW<§§³±ÓfG²�I¥Òý˜éW\B»(¿ D*Ñ…DÝ£årù¡ÆMÌ(ÔÝ“Ó8ÏØöóó 6f»‰d·9uêTÖ{wž16¸=�îB`[z%¾ 2:¡´‹CìuA}m¤‘C¦šî¶ïÉÁƒqW�Ü,%¨ºBB³ÀŠ"úé.£Í ÕJ"«å8NžØ,Øb }fT(®š�_¥ÄŒ?Ó±þf]Æ«zpG>š·ß…†<……¶6=Øst¥TBÍ4¶³³¡Îb^Ñ´±Ïì,�Ç®ÈÃS'm"»ývˆúøè6¡‘È$£q}Ê$òtæ±Oñjÿ9p#2ô½‘˜ðg>¥ßÉ›#œ¯/~Í÷´š" ª˜MÞáaD¾KbÉb"™™ìiéŠyÖåœÀmá˜ï1B‡‰øŠ4+Ó°ß`Ú”Ov»õ³Œôç¥ômÆXjž8ŽG€#Ààp®A€Ô×ÀÑõ/äÒ>§€ä®·ÔC-ÄCq$þ ð&ö¿)È?ø©�áªsÒ�—¢cu’=dE›Ýteqåæ?63oZ]óæÍODõ~úÞ­„e›ê¾šM$Ͱ xv|M�ÓkÇOÍ“ËSÈ�üœ¾Ç¬Ðh:¥ÏÞhè:w@¥R©ºõÖ[C7nÜx¾Ñ±«»¤‘i%‰˜vu[ICDk)mLÎæ]"©�¨íé$"wttü‹òÖZZZn¡ šõkxÛj­Ç-,,”DPw †a‹2ö¢¢¢/***=E"Ḅ„£ú7,:¼wŽ€þH$bšyCOò±B‘È5*-âŠå˜èm}õ&Ää?Aím%Fy]ósÄ–!ÆzZê¶ë.PÛß�+ÅÏ$ÂêÅ�ù{ Î,ì w œØã‰Xwq` ê¶n…lá�=Þ½^:lЦOuAAÉ<£Ïœ…¶†®ñÄ+ IÚB óÙ7C é2·7±�÷.m¡s¯ÅSþ“uÕÜÉëý�é^ú{*fúZ!Ü¥eÍã¡¶};þ ÔiTˆ.JÀo¹Çñò…u¨QÒB1²Ù—¼ƒxEàv"eÛø€Ir0Ú¶q¢À·X·i3¦Œ«#›kkŸµG+•PXl¼ ï&8 €X(ŠԽ¸ýø$Mý �DZCbAPm¥ô jc8ÜŽG€#ÀàpŒ ¼Áú6§®=<š¾;ÕK{ªÔm±‡tt=Ç{zE<2jRiAaQÒŸIŒ4l~]±^ºí±FtoýW¼¨…C‡u=}ú4Sož è1³º¯£èÊÊâ蘘?¹ºZ>AºÏ¡F|¼ºîèÑìl£ú‘2 ÚΓþ±Œ)ß´iÓ!Båê½L{›››ÿý¨}�i«ªªŠÈ»z_EÞÔŒ¬žXYyùÉXT*Š/¬¬¬�œ…^ˆY àxâz³6¾¯y¨^"þú#ºÉCýîD„óýEEÅÏRàÉûòòòŒÚû r<ƒ#`bü{˜ØÖ8­šæÝøëÕ}{sØí¿Ý;˜aé8w|0Ú JjCõ‰|9þs0ïF¹Áצ©÷îÕκiGеžXà9Ò &×Òê‰R’øM�Ryâp8ŽG€#ÀhŠÀ GPÇ#žDãW’߬@î¼ó…å¯6…¥s9%%EL·'jÍPWeðp«›#Þ�ßúûò�âM²ÞŸxu¤írldh.9|äpÏìSÙòæ3×£!6çäc IDAT™}�IDN'²z!!!~$‘KúÛŒ€×#Þ«ºµŽö‹ììý ̓y½7dÈ¢UU{ mm ŒM{œÈéœððp7 †X¨oD’)°$µùI�0­x‘½½ý-ô¹Ü\føß¬¬¬µ”(¯Ý.Ý ÔUi=9ÜåðP¼OüËTªÇj[[[{s™l·¼¦&•¼§½hüFåAß:bü(GàÆBÀËZ‚ù՘égÝ¥�ÛQÀEC$qP�NòByá:JPkŠŠQûç&ÔíÚUz:dso�x@P§†¡! ur*µ“5yF«só Éσ–ä-„îî¤iæóY3!rwƒ�¼¢E®ndwvв÷’þ‚½ÄOøMn¶¦ˆÈß_§zbÆ–L w–áξ6Í–ko&ó²B2 IIäôËo¾… ºW=ñÀ ÙM>+Uµ°›7ÉoÈ É-ÔÑoìi’s0žë7_ü‹b¿E€… ™Ü^Ú_ÿ£«¦Õ%DPvj[ý÷Ê[äp8ŽG€#`:Üpué™.úeÍiû•w#žÖ]ONNNÖÅÅÅÿézKík჌šm»$GŽDôÝõšÛH?ÜÐn2­}=\[*ymò1–ãæaáñ¦çž'<>Öäk²Œ�ؼÖêö}Ûºuk+É‚õ�7æ�/–~A.[½;m?{6{;°‚F)ú<(èÙá#Fì?T]}–¤6:$¯[1R9�OÞÎf$û1•ìz¥›z£ÕÝPÛl�”HTuuõ^’ñëׯ߯äUýJff& àØê„ ‘ÓíÑ�ÅÆ/j… cæÙ­ÿ³Ô¾ÈÏÏï³üÂü)}\úÜtöìÙ´ö�èT�'ŽGÀ@øQÅ=YU]&¨ d>]DÍ ›u3T§ã"€ÛLäݬ©¬$Ýêm¨ùöh®xæ ííañØ£tk…hg^Ñ %´JzŒ«ª‚2î ÇŽCI}kÊÊ)@¡ ÄC`6~$áaº@†mÚÔ X`įI9fü›ѶņyùH°=ž;R€H7iJëGBC8ÿµc'¾^¾{ÿÜO÷fm`7:Ÿ]σ‚-Îv íað·p†L(óJfzÖbFP×éåѹYô•)"Ïø�BîÀþâDœ,IÄë7Ò�œFh ŽºR¡Fq­ªU�q}��·Ãàp8ŽGÀ¸! êñCÆÛíP¸ÊpaMª¾Nš[@€ÔÕÉíJ÷Úè@¼=#ÃfÅΤ y]i¨#uscsk‹Çs‘ƒQÏŽšvS¸?¶i–ö¢:..®œ69ýü‹/~ô÷ž=ÿGãRv,«~:1Q7æ‡Èeùù��…÷ÅÇ?Gãh•�í©q2o_ÒJÞ%°ˆî½÷ÞI+W®ÜÛ�}kcbbSûÃXäYퟟŸ@(9;;Çúôñ™O¤yV ýÏ¢üV%>d£ežµ¨…F �yz̬ƒŸ¤X–Ý“hUÀ .ü,“Én“WËŸ&rº{:â­r8zE Ÿ½V\(ÃgcÝ Å£uy'Ü“|0¹Ä`Fé¡cÒ?Ö‘ˆDúe“§¬9y§ ²³³k©i½ðz0SïMÐåK³³Pâ®®f„„U«÷íML4(ùÉÎmŒœßu×]ã~ùå—½z|Ë ’\jeÉÙø³_S‘o$3gZ>=1//o­««kBmmõ/nnž»è·r�Ü�²¿rüõM††‡Ž;~÷õùü.rqqy¨¬¬ì¿ÖÖÖ7‘$I‹$yÛåÅ9 àe%¡ j2’x�cj+X@ÊYÙ¨úä3’ذÓy+7è@3Im-ÅX%¾Ù–4Œ[$¨‰�–DF@NÕ™Yº6ê¶ï$�éeÐÖQý6’ÈÁ²ûï…xÐ@�ŽtÅ�öp¼ùا˜á2‘�²SH?l‡}9Uxú`>6Îð& èz¢¿­†h²R§7ýàÓÿÂð¡Cä \œ�Ûª†â’R8�gº°Y±@?Ò¤fÛx§ 6Ûl®Ó�¾Þ˹¹rÉ;\r ?eÀe¥‡K/á�Ä xÔoÒU½of÷As1‘ô¨ ‘rhEÄùÒZ„:˜¢{Þ'G€#Ààp8“@àF$¨õzb(˜Ú ÊÜÜÓzmÔôSm+Š+BQœëÔ>~ÃVœYœ™)÷¿„èh�©�$)Í’hæÌ™á[¶l9AûìHÅ2{qR¯-(8Ún ôø¿1c†_ÌÉIk•†ðjo ³ª�œ;vlß0ïöžœ4ÐÐúsà7ÚÖÛPªªÒN///ÿƒÈj{Šßõ–T*:Bž×%‘ê-êH§\§d�…FPäZ4´4ªô%ª×i‚šúˆP*•+èô>-ãö¡Ídÿ·ž8�+<=Äk“HbxÛ¤bw�Æ‚ Z¿ù:Ä‚ ‹u²Ïþò|fÞÑ’‘#[íZ2t(ff¨|û]hò󡦭½WgÅšgûu-,݉÷ôhµc>¸Œä0rkËðZÿ[:MȾáŠQÒðÁ©b¼J¿F\·–Önü|þÊ+.“Þôǘ=cl¬Û7ÑqǃaýŠå°ëF¹”:ò¶^|z|-œ0Ö1#ía+麂[�Fo G¼>àÖ«ð¨4ê«ûlgêk†?N¶â5µôóeSZ%œÌÅè„'¼~,à­p8ŽG€#À0~8AÝÅsäåå•›––ÖÅVzoõ‚]iÈH 4óœœt§›WX|íéÚKä+§Q÷$™¨O�ÕWÈiÌ�;7ª¨¨(áàA½zåëÓV½¶õgrV ÛÂHR¢<§à²^ïBcŒœ&ýe—ãÇ�3¹žkßJ»Ðn{«YìCç©T~Muuõ&¹¡RÕÍ­“«–ÛºØÖ®Ó¾¦ÎS_¼ôá¥R¡\˜¥yVãS±¾b•goÊú? OiGòpÛER'§ÌÍ͇çääT·×N^Ž#À0~îèg‡WŽ ¢N[3Ô­‡Ò"ò¸e:ÐBÇz54åÖmÐääB`m «ÿþ2ó–�"éåÁCDPK¡*bVDÿ‚Òãè©�V·Õ€^ÑÛ2Iw|Æ LQQQ.�A�a?/ÿ™äVzŠÍÍe‘­šF·ê†¡—––qpphëÿLKätMÉ&Ož55lîº>1¯ëŠ?OA'Âêÿ^$R¼ëž¶ mwçgµº·ÿc�úé‚ vµ¯Ûmp¼ ‹vçàÈräH!m:rúñ§žºïë/¾XEv¯+’Q!`Æ0Ýì+ä´ø±Ç{ä›o¾ùª',SÕÕµ&Õ¡!2ù/²ƒm$¿)�ŠËÄ5B­£··×™Lvobbb«:íC† ™æÌ™Õöööó/\¸ðµ×Ãâ}p8@@Dï´>Öx?¦Ïq‚�´g§hR)Dþ~º‘kkkQEž¹šË•‘G®ÅCÙܶ¨ÐÞKKˆûö…òì9Èî^Ø.$µD¼2ÒZËlFX“G0#³k~Z ‹{î†Àª}rí꬛ ýš} ‰U¹ø9ìaòîú¹cËlþM²/›I&báW`~f'¢‚9y•Нi2aÆäI À½íõ…‡«+ÆOžŠE÷ÝÛ,Aýøs/ÀÒ¿|ÿ-$ô{Ðw2Jà#sÔmáv~¸ãŠgs~]…-Oľâì):�ÕÙ‡ñgij³õÕ· =Ö^tN <,%sÖÉßc†óŽ8D *i¶oú «ªáÙoÿè6„ÐÞ5G€#Ààô œ î<΢CòCû;_�×ÔyU¿„ûÓÉGg؃#&T¸•E¦¼�ô!Ó¦Gµ1£Gäô ²OÀ¼yÉëH£§1Ü;mS]!§…äÝîÄ&ºs˜b±x2Ïl×d•Z¥* Õrö±°°p#©Žï$ñ$‰D?xðàÇŽ=z®ÁÖ���@ ¸x ¤¤ä­Vk~øðamHÈ43³±7•—{„¥¦Þÿ¯†²ü“#Àè=Ìïkƒåã`n5nöµ6ØÀ”'b „‘³³Äí˜0hÜ#²Ç�ŠÒyG7ο~ß�&F„ #ç÷®“ì×·ÝÒw73[Üá¡Û˜Óå™jR“ÛÅÿ+Àh‚�'ŽG  ÊOaóª­8p6…EIH8w1¾æq3^m£*?ÌHÁ¾/×âï3iÈ×â‰~#&aÞCcP?ål*(• ýD46ÿ°õ/Dlò5}:ƒ¬ÍašS}IØýɯؗ˜E hYòFÈè)¸õÞHôªµ5)ÛñåZŠ¿á4³¦ŽG¤¯…n´&ù§" ‡7ãË¿ Ñö³xzlûŸMr¼Fd4'¨;y2|üünÍŒM[ßÉê¼ÚµhO-;ñ7eíóóp”Þdþ”cœý�±Åf_[̤¾i™7/Ó"fVÑhE^¯L΄§žE@CätÉ�wÞ9î×_í¶ %;;»²ââ⎎L›���G•æÑ&’É,l«ª.?+•JÒ¶O«õ1ËÈìàðdji©s[[Û¸ÊJ»àøx Y&QËUÊÇ úÖÞs”EGaåå9¦�€·•÷‡Øã÷K#¨µh¯zéÐ’v´É@0²¹£ÉlâxÈW®ÒéIKêhu“*_£VàîØofç‹.ƒõn{¤› ¯=õ(V_¬ÀûÁ¾pµèê#<óÍ6ÞdF²žæö60¡2r:T×Õ܆TJ 7Î-é•(”«IÚªÃãà8=�@.£™Õ Hò ðÊ"²„½›'|*ë /O„‚îAvîÎ<~Ü; FÑ�4Ù•O�èÕ5�mDßõJPL*ÙerT–èǨòØ5Xýw4¶D×ÂÛË~}lP›W€´ýËðaåLœ¸ó‡Øé{ zo¯&óü kþNE^¾-ÆŽò‚V©BÙÉ?°äíó›¸wŒô‡§mûV éÝÀN4Xvòg¬Ø»Û¢• ð„Ÿ§5ä9y¸¸÷{|T~“&Îí úJ׉Q5TQB­H¶w×â�'EöQ¬Ûs š±6©_‚º¦PÕ¡¸ ¨¨dýWÑQ)2å*Xgë2ŒêÂg.ìÚ‡ƒûÏ!“ž%ÒÏŸ…˜ÐÿýÔut]­«D5)¨±kOÍ#ÐÕ§Ûæ[½r3ÓÒvÞÃìé!jscs‹‹×+Âìm‡?8|l…ªB"=)í6b±»xE‹˜VD‹´L§šÈR6qj²R&Ý�Wóíw.õrZ¸`Á‚ik×®eÁ õ*¿Bätló¶7Íõ¨óŒÉ%-öë’úòåË¥çÎÅ¿Fù¯…ÜV^ÞwjeåûÂBçQו…µÕãîee±J„Yä‚ ÅjÃñü®´��w–Äqâúòü;G€#`z¼>ÂÃ~MAV•Œ°îÑD�«¿ùªôt¦›‹§o—ôõ62½jÉàÁPR¿ÞNPo-ˆÃÞ¢xœ›øÌEÝs¾žì€_’*ðÊñB|7ÞLF_©IKM2ôÕS÷¶óaÒüžs6bs¸›Ûaªë@Üì:öþ=ªe­ ÍöeÊ0“V@ôµÓ¿LJ÷¢È[¿1¨D%QÔ¹ÕJ8ê‡8íŽÖý1f>mò‹ØùM¢OAnç…ðÏ5sMájRÐ#‚ºˆ>)d©”hµä•“„VYm×LÒÒëLÖ!,ÿv >Ý/Bÿ;žÅÝ÷MÃ8;"Aãð÷ÚÏðÙÚ÷q>E ·—žÄï®u×­µKqxËÏøxõA$9LÁ£Ï?…Æ÷�FYƒÒ#ßã_/¿ŠãËa.|ó¢üájÙ­Öt½qš(eçæ»/?Ág‡-1ä¾çqï=“0ÒÇ5™'±ó—OðÅo"1C ×?Œ(S[8¦®Fu^,6ýú3¾o%Ž)T¨»‚ ̤÷TSNoï ”Rø¥Ëºù3êeÈ©UÁUjÕiˆ9°«?[‰Í»O#íÊ,Üûéo( ?E$5 ñQH×$žšG€;Á5�K«¹W¼b�æ6ת±&z°,¶¬"fYLtÒŠ¤}ÁCêªUmÉ3ꑞ={¶Z'3&ž7oÞx2–ÿïõüÓ9½�ºÕP Åzî~v;Ú£×ývùrie2é%;»Ä8Kˇ&ÚÙ•^%¿­Æßÿ½~DNÓíÈE,½AlMõò*/;í®¸ÄÉévœ^„#`"0Ùq^–ø×�<(‰ìêɤJ¼ˆº={éN%„ÅâÅ]ížiC×mÝ­Ju5¯Å"Pe‹¢n7µ¥T¶XÌÔ�vòÿ]X‡/)`�U§}ýÚ„ÁÞL„�Ó½±-£ “¶q×Scºñ~×[6T ËI^%aòX:hÆ8õGLy8ý¼v>ƒÈoâ?ç×`mÎq+KF^m9ÔÚîQ•K©Pàd¡ïEº@Ø; 5Ô)åýÞ`Ôå&àbâ%\¨rƒ­{(ú{Ü`´{¸j"o³»ìC|²î<Á ðøm0‚Èi–džC5u>nV nÝ|¶â4زÍî¹âéºìŸR¤G¯ÃšÕ[q¼ÒÓnY„‡ˆœfI(±€Ó¸gñâ¼`(cVàÇå;p8¹Ti¾ vsU”ò4œüö]|¸>fCáéyc1„Èi–,|Â1vú\Ìñ¯DÌÚ/ðÅ/gu²,=û¤×E(رârO×Àó¶ù˜;)Ž6¦)À¢CBY†ÜK%P9aä쉈àÚE€xõÎ"ÀI²N gçèx3UkÇ›Y'çU®G@•½.ûÄÅoèͯ7¤ØXåúõë£i(šùóç/=z´Oo–‰�A»gÏžÄéÓ§‡“Ýz¹R Ã¸v`Ðn_7¥ÒÁ)#ã±ç�W^�É~\ÄÚ¦ÊOÏ­‹RSÿHº®/¡cá›{ÔyïϺ.¿[¿çn·™7ÎèQÄÄj=1ÈÛÒ«pº¨‹^V´¼zÉçД•Cìã óys¯©Íˆkùo¿·›põ§+­uÑû¯i§·|Q‘ÛƒqËáJZÉ‹¼›,xÑû0:šá…aN¸e[2*»@ú“v5EímÑ>¡@/·ÇÛï®l˜`¼�´¬—\„m#ŸÃ±±oàä¸7ñBß™¨PÊñ‘Ôc¾��½/aMö‘n1å šXºÍß¾ÖÝãMß-FóF9F€@Ij"R2.¡ÌÕ^C‡c ƒe„&hUÕ¨Hûï}²å6˜<{,Bú¸@ÖÈV{wŸ‹¢BìYú1þÌ’£®‡'¼™Óân]ñql\¿‡Ž–¢_È`L˜0× <…N¸}¬ìpá·UØz0)•ÆKÅh”(IÞ„7?ØKÒ2˜NAŽ×èg;zùcÀ°Ñ�æfc÷WKðW¶ª–oÉ-bg°;ØÏÇÿÖ¬Á/´­yçN õ²‡ÉÞñì†aö3ÿ×l,_¿ŽÏ ƒ±;éìÜwsǦùôÙÍ ´Ö¼¯¯¯ù…sçÖ·V†ã´�uëÖ­=tèPf`` ÙŒ3‚©÷±i¸n�E»cÇŽ“¬»G}tqW±—Ëå9ÍšÞL¦CµC}Ì�fŽ1; zjÌ™3ÿÛ^]=ØU$*ÏÉË[{‰up8ÿuvök®¯êòÆÂDÿè—�hã}R»Þhþ�#Àhc=-1ÓÏ ßœ%í½žH$íQ»n=±´pƒfÅÌçRpC330=jMQ1ÔéPì‹(�yW·' ,-!ùš_¡­kXÚžš¦Qf{Á9*¹„OBï„…¨g¤î²#ª_¡ÛÂöŒJ&«»“V.GíÖõO9DV×ü° ¥·ÌEé­·¡ìö;P~ÿPžŠƒÀœ–q¶“ fD·Ù¬›¡JK‡:-­»‡Ð£í×Ñ×GÏü„wÌ#�ãæÞ¨»Ç[©Ûgú`ov56¥uNí‹÷ßÅÅädÜÿÔ3È+(€–ÎwZf&îEhÈÃƒ˜¼¬{cb^Ö¾Î:/ë¾Vnz"“ãùôL °ÇP'^î¬WTxc¦�€�"E`«wDb=ã©Î#þT.žwƒ·GÂv‘ž–˜AL÷ ͵µ÷–ÕýçJL( éúJxwgm-ä•—ð÷޳P©‰�~ð´2‡Eã�aïŠShé7M<ÆmÙ�$¹ cb24Ùˆ;y9Y%€§l|œáÒd,#S,á@3NŸÃ…ÔL”ãrN­Uå—°×ùúQ €—Ììïéúnpr¦À�Db“(ñ™#©NÍ—è׃Óô¯DJq7„K¢á¹þz%1äõª©•­çЄ¹H$†„îŽóñªõñ·ó¨é»F´s z*&>sæÌ—zj‹7Ãh‚ÀÁƒó˜G5#­›äÝŠÀòåËwQ‚ñãÇ‹££;ì�¼­ÆÑ-µéaXX˜$3ó­=)).c$RU…�Ï3>ö6š¨êÚjrQ¬OEE·ÌlØoüy¾ðx0»=ú×�«ñ}ŽGÀ„ð°ca;<º/Ñ·ùÁѼûžjäýbqÏÝз^\èíA¼kÅ���Åá£×èY›Ðihbª‚o=~ægx˜ÛãN¯È&Ç»;ƒéQ¿;ÒwìÊÆ‰yþÒA2tܨ(œ;|[wíÆK?GAaV¬Y‹YÓ§bùKà`Ͻ›;‡¯&¬Ç¾â µõÅ`[oô#Íñþ´¹šÕ»Ç­M¾ŒœjþºÙ‡kO7 Ï3b<àO wÊ�k°“aì<‡˜¬tœ†¦Y“÷oWe`‡OG¨ì(Ô4èd4—4?ÀC}láê{½Ës;a§¸5)‡°•;é–Oô�»¬9‚ºQ{Jzµ<¹ R ˜õÌ‚ŸF´°›{ÇÏ!³ˆŽû:ÀÖÅ©m¯ù”X\º�Šä²0¸8¶Ð®¡²kKq9ùv4ˆ?öíO»±ôJÓꪡ>¹ûÒC¿ $&«“Ñddú˃¾ûIzŽæ1t×gºJøb¸m&DCºz¡ÐŸ™­¶ä3€þçbDØjÉú '¨;pú�áæÄ ÝrûTãE9B �œöó·M�M­¦Ê7´tC�¼Æ9/>¯§Vqi‰œV/X°`T<ÕÞçäää\\\Ìb�´š=-«“]-çáñÅKgΆ¿¬ÕˆdÁÁk&ÅÇMmÚaÆi±Qc�÷eëv[;v}Yþ�#À01Däýõf„ VÒrÖß“*ðXw r’K‡tâønAÈâÁŸüò+tñ>�|H·tÒƒ�Æ”§ceÖ!ó*ì)ˆ“!óÒ]u‘4+Ä6ò¨îh ôóÃ3�<¬«¶eçn¼ùÒóptà‚¯­áøýæ Ò¡/~Ë>†â×¢¬®rÍ °tÁ4çáøêH,ïk‰�g"+=��‘¡l ö£ u¤%�™â§uAùyÃÊüª_Ë5Ë,làåJyÌ£÷$é{« ¡]c!¨s2‘T]ÆO{99À§Æ™�ÃÜ"ƒJ¦ °¤Å¥´klµ¼òìô«¿í!4y ka6À‚4µ=‰´iÓ)$¥©¡dÄ%'¨ žnTøÓSûϼ@­Pôiq^’#Ð5ˆœ® TäQm³pá ]kÍtkWTTø‘õ=EP3 ´ äô}÷Ý7Ÿ¾·é®Hät8«ØZ:t¨ËK¹ïA¤U÷éóô™ljnnä{în'>P«ï³"rzÕçdsk òc�kZÓøËto¼S„ó%¦¹ÀFäç �­-j7l4ù³X®¬ÁgWâ¿ýgc„½¿ÁÆ#›nòFÊe>#Y‰®Ý@¨1žÚD@&’à&×Áø9ìÍø IS?ÁúOc¡WV&§#ÊÍ ·Ö{S·Ù/À¸¡ÈÅùíKðdø-Xôv&®Ü Z®ÛVÏJÃÏ_?‡—?>€3U ô%ÝÞàžtÍÿ@µµÈÉLAC˜\ É1‘cK³…Y>“¨OJ$edSœ�†šÍVéÑÌ‚œ TÕTéˆv!Mö±­¥$¤qÔ�S�‚â•–·TÔ`ùµòjäe¥ýsnhâŸÉJ5—$YÁÆÄ^ÿ4.¥eCIšâ]T‹Y[3ðA¤+'§ {*xïÆˆ@ÖA¬]ùÞù*Ufa¸ó•{1=òrš™lîæâ£EäwZ×/¾¡l—WcD”fjå•Wm³ ýiQ žÇBò®67¿2@5Rò ¡P�u­¼ ju½=ŒÈ•J[Ö·07· oðú…­…å—Q|Ùøüµ4Dœ_{nd-z…³±˜]97Œ˜NÊÍ'jã#ݯþÐøG ¸! êqýDãÛxÚÎ#?ŸIu[:[€êâkëu«‡<ûëho".ÝH°Ý†î�ÛðŽ;ÒcccÓ£F�bS¯Í§½!£šöÈ‘#„§ð>J×ãzùòe¯ëóÿèç7ÞÿK¹äãÉŲ¤„'7ÏI^éøqzzÞ ±XþaHÈÃ#¬­™‚Ú y=nŒßçpZGÀÓJ‚US½ðI}ìͪn½°:;Ãüæé¨Ý´Ù­kÛ$µVƒNÿˆÅ>c1Õ…ù9GbQì—Oð =d5^>VÐ)©�ð¡C é@àKã¹á­`ŽˆÏÉG¤›% 5š(l††[À`\>�=¿¯Æ²Ÿ�£Â! [„[üÐt�GJó” Ç`8úyÁ§�Zö£åÐv¥¢e¥ÅW«X™›SWÓ|å(+-‚‚ÆÃ’9E43ñ{–¢®åe çF@:âæ-Jµ\=�|‡#ÐË0Í«SOŠ–IÑu�66E' àòf² ™ !Ø…^ï1uˆC]!v[ú�¾&>įH-¬ÖÓôÝn™˜."MXÏù¬¬Í„GŸf¦�íïê‘`¯•Óà Ôsb2VÜ Á€-³Âl‡5xP rŸËêZOxâyVwº�ç¤P�§$�aMï߬O�zt ‡Îóòòb¿g¶~È(ØÜ^|‚Ô$û±‚�ïÉ'Ÿ|”>t×ÐÚÚÚý,¯µôÎ�/=ÿþÙ‡BþµûœjµlÅðá£ó$’#£’“ßùº²²8†t¶×®ïáád«ÕZÕû´Ö"?Æà܈ v2ÇËÃ�±xo.•+Ló›o†"æÔéé&e;#§_KÜ€Ju-ž˜j”¶åŠ�O•`g¦ñy•%`]4JAìôãûóP¡Ð`ËÍÞü¬‹xòê½ �J$EÿŽ5ë·ã¢Æ,Àí3BàÚÜ0³ÎátÎeÈзOø{óÉžæ`jÈ‹¥°µwkøÚê§Š¼¥«*ÿÑjvµ·�øŠr«{è ��3yM³×ضSe%I{\ñþ¶±”ÁÚ¢}õÚnY%$3:7ÍþÊ›t¢T*PuEÞ„Iˆ»;ØÑ¹¹!é¹&ØðŒ�ò?€.äï€ZÚØzmr2꺖éÄ�îmq³mAlÜÉ »x §:Å»M–õ+jªæÓZ”)%–#Ãû…ÇZ¹ýÉÊ:¤íøÞ3h„ãåt×Ç ÖN©*>³¯á§µéö`À}¡M˜YS]¡{s`æÕ÷”Èa «ëSøÕÒ€AQ."a�ø|®û·Jeî„KŸ‰ õù'G ´ÙÙÙr:®ºõÖ[ƒZ)g¢‡Ø¿«ñ¥/¿üò[²J0~üxví˜Ó <˜×Pî˘˜ÃsäòI£êêœ_ w/òp?ì›’¼ðãÜÜ¢�NŸ^ÿYFÆW‹FŽÐP¾ñçêAƒ—6þÎ÷9�&õñj¸³NoøžÝÙ¨Uç5²¥3"ôö‚ØÏ5+VÑ˜éØžR]ˆoÒöâó�‹àinœäÉ +¼æ„—ŽÑnû]´ô{1æüŸÊñ]|)>'éSÓ„7f\¹m½�ÂXlúcö_PÂsìTL�9ý¬š[%’wîFlA!JlƒÔý½¸�VsH5䉉µwdºÒõ©¢²ªÝzÌvBdD$(#Ú¥fõç[^[¹œQ4m' ò6–ÑflIBd»�ƒûU³**+¡Ö´·‡´#™­Ö‚D^m”ïpz17$AÝÜù¬ˆ?4i~äß‚E5Îññ•ª–yW‹+í Ïfß „j’ç ¯ªÞ‹Åb-Sï‹«;û}ˆ¢† k•`Ö@#$Q(]ÛæD‡Sž8]B`ãÆ� ¬�Y³fùqÚªìD—:â•PGGG«ûôé£ 4£ÌN]S·�<™?#7ot¸âÅ®®VÇ==ÿ²­ªòzæØ± GÅ’ËÛÍe'_6lµ¯ó�÷HO›´ÇÂ2>ÒËëQ¹‹ø'G€#pC ðù8w ¹xOª•m¿ü (Z–+[t'OB�›k,fµjG-éc>pzxE`¶ÛÐVËúà4yÁÈÒöåêôÊ mOoíy©¿}²ÌðîB`ÊÞŠG ¹û6`Ç© ¤JÂ6,Í³Ó¨ÉØ‡ŸÿˆFV~9¬‚†"¨¿|,9‚­! ’Haåä6UÊ^ ŠJ P6¯+­&MdrŽ£RìÅ�¾.Pñ*}Ay†Mæΰ53{‰º\U�r"Û[Jr‡Z¥¢ÃVpqt‚³ƒñýP„R3X9:ÃîÊ òŠŠ¡T2››&5yƒ³ ŠìÜèççBR[| mS¤xÎ�„@§È“HM1ÄâÏhŠê#¸�x’�çb1*}‹Í<øÝÞhòD óN§ãïÁ{ØÝ×�—$>ÞŠÅŸäxh��.L<\Uz kKæ:11ñD‰¹¹ä>V÷\�Evãºóë~=aà{ÖÖ–ºi‹u¹—BªËf³ºÊq·MO9{¤°qy¾Ïè,ýõW§Ù!Œ“$“v¶^¯uøúúšeddlONNVØRb5ˆ¬fdrgžþ´g ªtuýê‘��»î¬wõÈZ$òºõÔéÍ'…"æV �ªÕvvòšà�ŠK2ñôl�'b]óÄàÜ ¸Yˆ±y¦öfWcÉ™¨˜®‰$éȈɓZ±¯Mu$ƒ�HKþŸ¦ìÀ¥ª|¼x³ÁíiË3‘ï�tÁoÉ—±)íŸ ZmÕãÇÛ�@L‘œ‚"fá¡{ÜêÏâ®óÄà\ƒ@]2¶nÚ‡¬ÌBØŒEß`Ý’äkÊ�ljóqü·o±áT1 HÚ7´?½=Àõ^ƒT“/k[x…�Æ:ÂÈœ*òðwq€“™gó‹‘™KUpGS=Y)äqLü´¤ï0ôòƒ¿1>:�\‰ÌÃíÍp€ÎMÂ…d”׆†ÂŸ]ëZ‰šªd³¹ªcqF{‹a~C²sÆòcäv×þŸƒE²ÁÙÙÙ¬ôÒ†åmuºDó•12º¬-«ùqŽðË/¿ì-))Ñ„……Y„‡‡»™ &Z£"[ØcƒP«ÕÒ£^«IÃÈiVB­VÿÆÈi‹àààˆVk]9HA Å5kÜbËÊ*¾-,<üïôô=�/A­V8*'ûƒ�ŽGè�ö´ÏËp8½�1ôoÿÓd ŽWŒõ)—)†iŒM-:©]GsüFªE]§Qáá¸1É9wxŽ4 `¯Xùà;ÚHqÇî“Ó)7V Ó.+1zC:;™áýHÈÄü5ÊXÏ·ËÀd§ãb]-*àG\;IëR4(ËÛ‰WfìÅèážÈ¶6C¥h2†„øÂ×ËÀ¶›D÷6°±‹þ;2‰‚¿öáda9Н¿ÿk+Q]‘‹Ô ˆ‰yË$ø›QmTc†é £æᙋȊ¹€óšf T§Ñ8êPS)Bàð�ð¾*£ÑLifÙÃÁu,î}1¬~)íÆ=8^Z‰Ò&çæ2*Kó�~Q3 +DÌ? ^Éùiž:ÞµQ ÀŸ¬®œ†¢¢"F5w9¼æDÅ"åš þ…#`B¤§§×2j ÀÀ¼¨LÄØÍ§@uÆ`chhh€»»;sÑ�‡t‡mÊÍÍ­¹páÂq6''§;Fþ±Ý ü‡‹Ó%’=qvvKãlm—îžÛ£Õþg�ÿ9ª¨û.R*AÍ·»=f OŽ€é#0Ó×ßOôÀ£ûòðõ¹RZNjücP &ÙmsQ·{/4ååFg0ƒð»ô}8Rš„WûÏ1:ûÚ2ˆI}|:ÊGókð[Óå©+äÕ¨0oGéMËðÕXwHLd¥BWÆÌërºŽ@ò‹‹PzÍ%¾ y ëñFä‹Àš­g[DŠÂôX=eB|Ý›J�t݈^Ù‚˜d>ï )®ƒ6âhL НjAòNŸÀ¢r-dwàßùB&»ÖÇúºùê:m¦…b N##ë$âÎ7cÆÁ½ø«º y˜‚›&ŽÀÐP›f G–”$Kú-z÷�9æX‡CÇËQ¢[cÛȾÜldŸ�Åv8ÁÖúv\èô¶£—û0Ÿ3 òµ¿Cyì8ÌfL7ªóVP[�ÏH{ú£�;dåaT¶µ×˜Zþ½|‚ž>”�I^Vð¶â�ýíÅ®q¹ÔË LÛœ‰þöR,ŸäKî9ݾÏhŠ€—/úSà»òý:¾÷E†c„ÿ 8T§âÜ®åxçƒ}ðøä^Ÿ^€m÷œBue &F …Ÿô"¶íIƒÄ>SÃìš¶ËsþA@ ƒÔb2~) ›?‰ÁŽ£§ðÀ¤@ rfjÎ,]Fêœرa¬¼úàö�^à  k\ÞÓõ– Dƒ1qv^:‡_22qèLP�„K€lüöÃZ—aÂócfÔPøó$¡À –¶“ñø«aøóÓ3Ørè$›à‰þ ¢Ù¸tþvoކ]@0nÿ%L$rÚø¦®œþÁèA¸u‚Í»â̘ÈiñúÌ3Ïã jKW;ŸãgM^¿X°+—l6“§Ž �T¡ÀÌ-Yá*ÊIžœœîx¼ì�‹€÷-˜;Å ¾$(X›ô–ÿß]˜‰È sñÌqðzô�.ÒVÖTàèû·à½½9°�ûžºs†{™¹†"™ B_‰ÏŽ„ãñ�ðÑo‡p"³> TÎÑõX¿b ¶Õ†`Âcâù©öºsÓ:¦�Ÿ{ •4-ä$¤ 9=×,œ0…A\±±*/ )—΃yïÕV×àü�“4EÒ©£1›Ê])ŒùìpÛ8=‡€véÒ¥Ÿ±î|ðÁ›H«:gãÆ�gz®{ãêiĈ~¤!�Ç$QzÐ2-y¶ë¢¥’Æ5{~d›�ôÂ}Ož<Éî‘þ>³%,?gÂßEpxì« Œ»6 T€I},íŠðõiøùb9žèОj¼ !p¢@Ž¹Û³0–tÞ¿ŸàÎÉiþ«à´3gŒyd žU?‡Ï×�Àé”䕆 |Ú<<üè4 8}lUÔš܉ÌË)Äž¯Áá¡…˜ÕÖœ¢hÔt2w€ñ‹ßÇý7`ùšUxë�Ÿ`n#A�Zg¿ûðÆ×“Ò/ŒðnW‹+$±õ@ðäð‚‹7úoÙ‡Í/Ü�ýîæ4Ñ.D‘b8/}!Ç`¸Ÿ#¬LÀ…G ¤€‡n!˜ôÐÇøiÀX¶ú;¼ý-Ìh%SµÚý›�°s3ÞÆ«VÒÊïA‰šÒDì|ï¿X�Dþú'q.¯ì¿Z•¼kÞKƉÕvè:7Ý÷æôm¥)£8T†3ü€?¶FLj.½9³«ºy»ßÅ}s~¡¤À¨G?Ç]£ûÀËÚ(Œî•Fð«¯<­|P�Î#°lÙ²m¬vÿþý­I'yöÊ•+é|k¦UÓßß¿Ÿ­­Y݉'Ò i¹D$Q(•J¦s­!r:“>Eýúõs³°°ðˆ‹‹;ÙØ¶Ç=¬£4ÒQÒoÓwD³ü¯Íñî§^�ovF'»q»|Ÿ#À0]˜×¬�Ô›p f>ø6Ü¢2�Í\)-Üá4£‡yéˆz´¥L?Ìxm)\skQ£òÁà ƒèak”2Æ|Ž,¼‡cÜ,Àô‚u IDATò�¶‰CRni=±ÖocA½mR‡>Šš k§~ JBËJçá˜3µ?ÍÄ0µ)c‹>˜èèHçæ4R * ó|²ô„ð`ŒìqåÁøÏMS …›;!`Ì,Ì èž…M ÁÆ=&¡ÖcçÀሜâŸV3ý(æ‹)L�4s*L&‹Ô&sª¸¡�žEàâÅ‹•´­a½ÎŸ?Jjjj4XTö¬L�¹EIf½™ÂÈxk �‘y*³É_ƒ' è�¬>éì¹"RȲhâ "''G�••óunåÑÍžÖ óï‚c/ì’ [“œ|¤ÃA¯ôÅ?8�^‚À8O œZ€[¶ebúætü0Ñ}¬¯^WŒj”f3o†|ý(£÷ÃlÎlƒÙ¦Ô¨ñðÙð·tÁ“þS fGwt<޼€o¦«ûþÎAô_8˜sµËæpVP„ÑU+ðòÑÝêƒW†;ñ€ˆÍÅó8í@À)x ¦·T�­–±AÐÔ»AüO]EÀÒ#n¢­«íº¾Ôž¡ãpm½&Y"rm½f@l "Ò@wÇ ÙbP¯yµž¨ÛzÅpLx¦6 eÂPsÓ9&‰€Ž^·nÝn²ž¹µ BBBz“0œ , ’ÚÚZ6&…Ã(ÈéVÜtÇŽ;Nät,Ù+ŒŒŒû­ƒÏ›Ë.híÛ¬Í:Ò\ìk*ÊG€#p£!Ð×NŠ�³}uÁ§lJGJE�Ï1¶r’õ�Ý»Õ_}MIIûêtC©�y1X•qo ¸­Z7l“Rr¡_2Êr•_œ+5¬1FÚ{�Jƒ'öçáÅ#ºU¯†;srÚHÏ7‹#Ààp8�Þ‡'¨{ß9å#ât ä=]L k����èSDDµ (€µ …ŸŸŸ«§§çÄØX(322òZ.i´GØä�æèÑ£û/œKLª²·Íœ|ü Êšú¹1ZĹaDÀ‹ôÝæ�I^–Y“„_.U@Ûý S:Œ”4|8..�¯¦…;M‡ëwµ‚œ¤=Þ¥`^ÿ š‹HûÀ®6g”õíÌDø‰ä^>=SŠ¿sZYÃj”ÖwŸQìßáR¹wîÊÁÑ|9þ¼É³ÉÛœä»yâp8ŽG€#Àè!8AÝC@ón8½�èèèt ó6¶š3gÎS—‡‡‡óOKK+ ™Œ½Æh?IªäæÖ¾$X)¶;ò´›hðq©äùÅA“"4�c``àxªÎ^¯YLž8�¦?½dŒ;~�æ�§äáž=9¤÷ÙÞKLÏ'°&]¿çþ…Ú]»¡©¨è™Nõòè™°[àõþsåö¾ÝH7î²Åcä)œ_c‹† �ò‘¼Lø3�þ'4Ø5»F»óÛ¦¡Ï ïŸ#Ààp8�NPßxçœ�˜# âããK7mÚt�?óÌ3_Ч±û1ûDVVVd{•^@è¦FÊÊ*ªªªÚµûc?<ôÓ i�Ó˜OÖ)—LÌŒ~Ø,ïÿÙ»Àªªûàß·ßËNÈ&B$Ì(Ľ«¸q¶Ö­Ú¿µBÔºk[W]µ®ªÕ:Ñ¢.5²G Œ„�½wòÖÿwnò’<’IÈøÞöqï=÷œsÏýÜÈøåäw,õ²HâJž;&&Æ=a„àÉ“'«%*¸î@½3vK��.`‘é  FùãÝSã°¡´g~˜ƒŒâú~Èòð2¦É“až< uO?#¿{õ_}yáz¼œ½wŽ=FÝÐÎÍl�t*÷͈€šMýÀO¥�”ËÃv«±»pÏ�%8Eþ[øåø ||F¢}ùÇä°ý‚àƒS€ (pD >¢ü¼9†„€ãÑGý•<‰û·¿ýíâÙ³gG÷æSét:5[û°¶ôôô8 О �8e±A•ªd€oÿãíÿ·ϾøÓßyèÒ:ç/ÖU¬Së¥k[nnnýÆ�Ë×­ÓÊ´ŽçÌ™s±šIî©Ã=(0|Ôâ‰_�“€„æ¾-‹'n.Po½à<4üo6ôÛ¸îØú6n“àô±¡ãúížGòF>Fžš…3+ðשׁ#9”#vï]UM˜)_ÿÏÊ×ÿ—g'`‰ä›6¨5àF P€ (pD >"ì¼)†¦Àßþö·{¿ýöÛ‚„„ëyç�7¿žR§?¬uºé¨™3§Iþì Ъ…‡û¦¨¿ùæ›×òòòÔ{�åiiiÆÏO�á$h6à™c£ð˜)ï“å.ø_.¶”5SZ,3g îõ7dÙÚ¾MAát»ð‡-rÙîw>äÏ›aЃ˜jÅï&…`ÑwEØ[3@Ïìˆj™5ýŒ¥ç¿—� #,øF¾Y35Ì*ù¦‡Ï»ïVvI P€ [€êÃ&d À~®={ö4¼õÖ[ßH¹á¸ã޹ßõþ8UÿÒÔ…„ì¶ý¸zõ÷ýqÃAxí=ɸOÛ´iS¡J2zôè«•Û |™è¡€Qr*­ÁšóQÖàÄÔ7wáù­ý™Y£ó ðûãbØ×®‡cûŽÎëôRé×¥™xpûXš²`X§Ÿš,¼(=ãCÌøí·…½$:°»Q)=Nù 7~U€GçDàåã£ïo؃æè(@ P€ À0`€z˜¼h>&Ž€€šúæüüóÏógÍš5ºåþ=NîÙÓô˜©H5Oœ81Uîç.++ž?»|/[¥Ù¹sçsÊ->>>qêÔ©Ir¬‚Õüsâ<Ù„ƒA@ýa3b¹äÞ}dvîý± >Ú‹5…õG47±Î×>—,DÕï„«¢5cQ¯’:döô’mïâÚÄpzÄä^í{°t¦f ?<3ŸçÖâÉMå�¾ó}µŽ•§üPlkeñÃ*ÁÈ—¶#AÒÛ/I’|ì02¥Ç¡p² (@ P€èú„•�R€í\«V­Ú©ÎO<ñÄ)©©©f9ìõYº!!!Ó§O¿››6lذ©ÝýyØC�ìììÝ?ýôS–j1Mrx›”oRR’¥‡]±:(0̲€â�BðÓ£$HéÆŒ·v㮊�èÈ­g� we%Þ}¯OÆqOæ{(j¬Âß&\2ìfO·M ±à¡Yá¸ãûbÔuL©¢òT«¯‰ÁºýTÜ€˜wࡵ¥øßñxå„‘%ù×¹Q€ (@ ,.U=°ÞGC�!-°bÅŠÕªÕQQQ¡o¿ýöšî¸Ûkßh hZ³fÍ–îûc�¸ ¿“�jâ� µšf¸Îf³Å×ÖÖ2XÝHV¥À`²ðîiqxwW�§ïÉþ–)¡¸0)V b÷ç¦ „ÿ]KPó×Ga;÷èzíökÊwâ^Iíñ¯ôë`Õ3XyÕ¸`¬ÜW‡Ë>ÏçÆÀÇØ6eyv ¦…ÛpbŒo¯ù÷GG›Jñ× ”ΩÁÕ’ÊæWCëÇwÝö¼Çà¨ÞýÖþõF\üV7kiÇÏÀ±§-ÀÕscûÿ�w,ß_ù?eu³îyMVçW`Jÿ�°Û;–¬ý/^¹g7¾¦›¿N§ž‰ËÏ>§¤†uÛ'+P`Ð d�—ßúgì=ðÐër°nÓ^ĦyW«Ïß�µOþ ÿ·›¿£DOÄÔ“/Äÿ�˜èÝAoœIº¸Œ/ÞÅ#ït³¸wc1r2·¡.tnoÜuÈöÁõ�}µ|0 \�–ÕjVµñºë®ûÍÓO?ýW9Öðëá¨u)))—oÛ¶íE•÷º‡mY½g¬µÒĨ×o4�ûzÖœµ)@�Á  âÐç�Ð>YWŠ_~¶•Ù§ËΈÕ|ý¦6Ï™ Ó—£ú�‡pß=½Â§¾åyç¶wpnÔQ¸häô^és°w¢Þ韦‡c’ä!h]–ÚúcN[+šp»,¤xây}ð�º>€kpº%�G)–®)ÄÄ0›,‚˜¨¥õèƒ[±K 1�0Œ9æürÉ8t*j~îð1ÖM»¯„ü¢16u L#ºËä7Ó�g'#®÷¾Çy˜O‹£/ºÆ´lLO±qˆ è&ˆ}0ý°¢€O8âÇNÄtct7£“ÿ–�=#§ÌĸPU5qégâç÷Dá˜nZj—Câ1*¢› öÁôÓY‹?‚cR0}º­³«^eÓç�� ˜±˜ïUÌ“výùïŒv·å!(@o�+¯¼òg’¯ú“ýÍ:“ÉXi·;öÿk¥QR…,Ù¼yóÞ½ �³ÈèÈ?;íΧ‹‹‹µ4å©Ò&M:gˆ�¯§¦¤ž¾qëÆOʸ8 T·lul3.5ømå�xJò¿šY‰3üpÓÄ8:Üz0Í{¥Ž}ã&T^szæ¹³«Oõ<ÉúOíù ßÍ»¡fÿÃêo¨5~gW5®ÿ:ŸŸ•ú£°Þ‰ÈlÓsÛec06Heè˜[Y£/È"Ÿê(? ðk™1}®–gz`ŽW'ÛÀG5ûŸMÃáñ)@�a/p¿üUaÑpShû¾áöä|^ P`@ üóŸÿ\&Ái-æìÙ³»ü6ª,€.w Õàô€z)-ƒ™6mګͶÓÑØ8ËåvÙœˆo‰c¢@ï ¨Ú¸` ›‰� G#WÌ›öæN\ºbJœ�ɪ}¾™&¤ÁvÉŨ{éeù9›CùA›¶!nªÚ‹;¶½…ÛÆœÎàtKëÑ9£üqÑè@œ¶|/ên|±¯V–Í•ËòY±·¦µÞ@:P3¦ß–T4)¯íÄ"™éý›I#ðÕ‚--M»L%iÈ (@ P€ @' Pw‚Â" Pàˆ hꆆ†b DûÊ¢|^ÓµF�. Ù•»ú�¦²ª:²¦¦¦¾nÕÝ-ŒþA/nÚ²e“Íj�*©TþO^„¨»;ò:(0 ¢}�X~F>=;v™žüê\·2›Ëû|¼>×]£§ëþùâ!ßKÅYUj�Ó"&áŠØ9‡ÜÏPiè�Š¦Ž¿�ÿßä8äâY$óãvAéÿí•`õÚªí.<¹± sÞÙ�?®)Æ¢ôPd_>FË7ÝÏéÒ� ‡B P€ ¯¼lð¾;ŽœC^@Òx˜].W�ÅbY²nݺå�;þkz(*èð‘ÌX»\íHãuѱ±gUVU>èëwq^^Þ·C‘™ÏD�¾Ê?F½¥¬ W‘‡Õ…u¸49ÌŒ@¨ÕsE›V~‰ÊÛnGð‹ÏÃ8n\�^�[~CýgöWX¼õ-l8ö^„[öÏÕ£î†Lå׳*qëê"fÅq²â±#}.ïpkyNù0G{—U2k^mV)¯ºj,Lú#÷OõM†JIåñ¡,ÜxëªBÔH�Z¦o‘YÓ–>úºÓ¾~aŠ�>@e—-0”ÿl:hV¤(0°†eŠ.’8°¿(9: kIãÑäïïLHHð/||l…#F„>V__ÿfIII–À8‡.Ž ¨Š÷ÿ” sèÿåt:?Lˆ‰£ÞAÿ�‚w¤ºÀø3>=+ßI€úÉO=FfT'ΫÆãÔx?˜{9�iš= –“NBÝ‹/#àÁû{ij£¦·mywŽ]€PY̆[³À¤@Äúšpñgyxo{% i‘mˆŽó3Á!³äjÛþ˜m�”.Ïn©À�iÁG„oo��ËŒé÷wWÁ×hÀ’£Ãp†|�ÅÈX¹Q€ (@ ~�#7 bðÛñ (@�þÐ'ÆÄUYWw±¤YýJQQÑÓUUUÙ2 {ÿ¥�ï¦ÓÉ jw¿Î NHH°ºuº{**Ë'ù^‘���ßÇOÉî)0ä†Ó,µ"YPïæo °lw5’͸{zfFú`„<{í/›vÊο¾7\ˉ'hÕ\h½jÝ?�U[„/ç,’±ôÚhº»õ ¹^!³’Oø ùuò½QõÍÑý�š¿a`F¾¤Ñ0öò7º‚ªs¸�+�é¿®/Åó²øa¢¿wM Åy£úm ]�ípË9ƒúpÙþp†ÓŸM‡ãĶ Ž À°œA½ÿß@� ?oM !ƒÜ·mš”÷ Tžú¤Õˆ±¹=É�ÜÚ‚üñ Áûö]ŸMš4)yË–-KÌfóÌÀàÀ½f£ùZYdq§´üÁêþ PëÆ�77;'çßñqqWmݺuy×ê¼B ôD`¸T^ãÌŠ&,Ï®Æs[ÊÑ$ Ø/©#nœ‚ɡ֞ÐuY·aÙ¨}ôq>ýwÇ$uYÏsáå½ßàö-oâóÙ·c¬_”§˜ûýŠå ‹ÖáÊäJ?Á#3¬W]0 3#ä�ú>Ü*%7ö«2£ûõ•ØXÚˆ³ýpÙØ Ì�ûú™†Æò9 P÷Ủ(@ P`P �¿å JzšG^ =Ù?cgGt6’9zý¯m3ŽîìZeVƒîØ]]\ë¬X7]¿A.hß(­ I:èÄ ëׯßn·Û/©­­u®ÌªþƒÑdÌõ È™rô”yž~;»ñÀ/ë"8ÐË�‹‹ 6Û,åEE·ÔÕÖF38ÝËÀìŽÃL@M¬lÆï&�À–…IøóìHüTÜ€Y²�݉˲ñ‘äίs@âÖ‡¼YÏ8Æ´4Ô¿ô²¶pâ�:Ê©/Õ‚Ó×$‡d§D…0›ÏÍ�Â=ê¯]�å½}±¯oKTù¤Õ‚›w|_,éb²ð§ŒbL ³!ëÒ$¼tüHœ ßè*Áé¾^¤(@ P€ÃT€êaúâùØP¹Ó¯Cæ·R9øû˜?¬�4éýƒU7*lÌÈ9ÛmЕL›ù€1`Ôä'Ëc¯÷ÔÏÈË«3$Îþµç¼'ûŒŒŒ’‚‚‚Ÿ;쎈Èðð1.féôú&ƒÁP4mÚ´+¤/þ^ç ªûFEUå÷cF%Å”—–ží}™g O@«Ïå�Õç&⛉Ú"|7}��iÿÙ……ŸäâãœØÕ”ëžnz=ü—üެ�hxçݶ¾oû2™5�[“Në�´â€ ‡ñÅßO�÷O�…ŸOg¹�ÝÚ…½É£fnßýc æ¾»óÞË–ñܱQÈ8þ6§yáÍÞ¼û¢(@ P€˜ Ú Ì÷ÂQQ _"ǘKäF"ÕuMgTW¯-8ØAlÝU¼cߊç?“ÉÐúê¬�•€£j׺d�#¯øB·¼«~þú°oÍÊÊj\¿vín—Ë, ýÅÚ]ör«ÍZìãë›}[jjª_gc.e#GŽü¹Éb)4��TUT&Ë"ˆ5ÃåÙùœ @ÿ ˜ :™ kÅíSC±ã’1xò˜(T49qÙ§û�úúNÜ›Q¢Í².—<Èõˆ<‚ü¸ l /Díߟ�s§Êì佩~>,\‡×sWãñ‰—ÂÇ`ö®À³.Ôâ–?KðÇÇgÄ!:ÈÒ¡Þê¼:È,øCÝÔ7%vWÛ±\¾AqÖG{ûÊ-•Ç©ñþØxÑ(¼ur Î’ûGùùM…CEf; P€ (0+4Ÿ—C¦Úô}m§Gþ(®±fßÖ„#öì9ôý¶=†ŠQ4®ýqí2Ù�ˆˆˆð5šõG•ÿ70$ÈfojZ6*aÔs›6m*lk2t�&L˜0*g_î«f›ù{ccôîÝ»®î¡ûºød’jVµ ~žï‡l Rªô/eVàÁŸJ0Ò׈yѾ¸:5S%_µª{ ÍrÚ©°ÿ��Ú§ŸEÀÃzU-h¨À-_Ã�‰'"EfPsë¹ÀìH¾;'¿ø"Ÿí®jëÀéÂýkKð¨¤oéÉVÞ迳*ñªä•Î,oB€Y�Ÿ§Ꭳ´E5ƒäœ(@ P€ Àð`€zø¾{>9\&½É_1Dûû‡æUW'FDLÜRX¸á LY­ñ áHM]�Í›½fBwF›� ‹ îÁ¿ˆÑÙ5…;‹:«ScÔûÃ×·‹2vÖKçe………ê¹¾”Ï1ÑÑÑ>åöÆ)5µ5Ì•…Ÿ°š­ËrssÕT¼ƒ�Ä×ù�XiRR’¥º¶zIQIÉ1Á� vgí>è™ñìQ8 P`ˆd±½QfísÞè¨4*pù `žöA6|%²*?MÙª^¬Ÿ©CÀZg2ÁïÖß¡âªkPÿ¯×`»ø"™Z­—ßÀÝx|× ø-X’²Ÿ‡úe£ÜÿsÒH\¹R�÷vJ�ÚÑüÇó?¶Tàî£ÃØEPYý!Z)3âÕLéå›oïªÂ7ùõˆ–YÑ3$ð}ï´pÌ�òéðNuœlG P€ (0ø üï�O@�C(‚Ÿ¶@¢§Uª� NwÕ—!I~(Ëj�F%Áél©œ-ÁéNÛøEF†Õ{.JpºAŽ�à´§¨Ã~CرÁؼ¢ÏgöæI¾k¹ù·{ª÷|›žžnÚµwï´FGÓo}ýýÎŽˆ6/7ïYtq¯Ôé�™Üž³û‰ÞÀ}¸�r]xTÔIûòóžµY¬×”••-êþ¾¬A P ÿÔ}¿�‚ëeöt~­Û+%íCΖ²ú®¤>WÖçŒ �ã¶ÜȺùžæõ×¢úO÷Á4iŒRñqÑF<µç3|8ãw°èù×ÜÃ}›ÁÞœ{Æh2­tøúž�ŠŠ OYOöaaa‘.·k¹Ñdü¸0¿ðiëìI{Ö¥zGÀ-[ïô4<{q ß'{kefuÖ—6`O•*˜}rœŸü(Œ/Æš1ÒÏË߇c[&÷/Áüõ�aîˆd<>árΞîå/›Ë{¸á«”רqóQ¡øõ„ìQ©ZJêñ¿œZ|'Aë @�•÷¢Þ‘J碾¡Àlt|:Ù:–²„ (@ _þåhø¾{>94�Ùic�úvSæ�ÝpeqA½,¨×m*O?éãÆEelÝÚ<ÝÊSx€ý ú±·~êÊ|øUúýÒ¤I“FîØ¹óQ—Ó1Í/À¿02,ârÉY½]Ò§ßÃPë#¢"Þ*++9+''§¼ßÑxC P U€êVŠÃ>¨±»P¦ÒFH�úIñî®j”68$Í„)f;–¾ù>žc‡éX=÷N-ÅÇaß”x 4ʇ­-Å�ßB'é=TŠ�:‡³$mÇÅc1OÒv¨u°”»K"îÕóð;a€zø½s>1(@ P€`€úÀ>¼J P@ˆ‰‰±ùúû>’™¹ý:½^ß8kÎÜ3¿Y¹òÓ¾à9”õ¬Y³Î]õÝê7�š–~ü�ßý¸²/ÆÅ>)@�ž 0@Ý3¯žÔ–X)¶”7bUAVI~〬­Èw¬Â×Á³1#x ÒìH ±"FÒJDË'Ê×$3ª{r‡á[·V¾�+©VöÊLi•Gz­ä‘V³£3+š4Ï™­ò†Ÿ;Ú7¥…t™‹zø vÿä PwoÄ (@ /þU}x½o>-(pøê÷MãQÓ¦]¹~ýº‡ä™¹ñ ‰�™ †z2Ãü@Ã0ZL+ýl¾gK†�nS|ÄÇÇGå|•ÿÉöÌí¿’~ûd‘É�—×(@�ΠîÜ¥·KU•zYÀ¯®É‰‚zVÊ2+öÖàëü:TÛ�ð1êf5b¦Ìô�áƒ6L•6'ù6¿‰’'VKZy}+ˆ®Ï™=>Ä‚S%]ÇÉ’o:%È YÀR-bÙ ù¦UÐúÄï<Ô½ýn‡j PÕ7Ëç¢(@ PàP >T9¶£( ""|“üýg—•—ÿÅårU8]Že#£F>¿mÛ¶ÒCRj‡¨”ƒZ-î¸gÏžÇ$03ÕépœRYYÉt‡ Îvè#¨ûö »•*repFq½6 8«ª y5mvp©¤ —tã$;:ÀŒDù„K~ëp›QÛ‡É>Ø¢‡iG±Uà¾Z4TèâzŠe_$û53ºÒå¡R¦¸å6“Ì47 Þߌ #,˜ .SB­ð“`4·Þ`€º÷MÙ#(@ P€ƒ[€êÁýþ8z P` Èâ„~‡c²`à­µ55‘M��o„‡‡ÿgçÎ�j‘Ń޺KñuNC]ÝŸý/ËËÉY%«87 P`€ 0@=°^ˆJ b—_š$rÝ$ûñ~fIb0Ák•›;WïY•MØ.³Ÿ·U6b{y“€VjõÌjÁIõ'Eœ §„Jð9̆™2“|¢£­òœfù¨`¼ÊÍôý×-Ô}oÌ;P€ (0¸øwÐÁõ¾8Z P`�$$$XK*J¦ø]Q]]u|``Ð_ª+?¨,¬Ì–G8`Ž®ÔÑÑÑqÆŠK˜ IDATÕ55ÿ³Xͯ••< ýØ ‡I�a)Àõàzí*†[*³Œ³Õ c™]œ/ì‚:ФL•—©�ƒ«$•ˆZ´QýF®ºA²P£šm­ö>F|dÖ±J+ÒüÑÁ&eªž^B¿R ƒv¬öò‡�ÜS}TÙ)ªYßv9¶Ë�J[¢Rm¨…ëä~µR¡ÎîF¥Ü¿´Ñ¥ÚRWº—ÔY P�‹#ä*3À#|Œˆ”YáÑ’;ÖÏ$³£�²x$gD„¯J¨Â[à(@ P€H P¤·Á±P€CUÀ ë£+«*ÑØØxv|\üs’žã™úúúyàAfƒÉ´Òéë•âÃ2z̘{$‹Ç”°a—oݺ5¨Bñ¹(0” oSbÆPÁk—ü¢‚Éê¼yï†Ä�µô{%˜]TçD¹�Ë(opiÁì hWH™Ä—µ™Ì�jö¶|Ô¬fu¬2h¨€µEÍbÖëµ¶MŽmH–@³ 8©½Ÿƒ%"iIÔ¬np¶JdZ…›%Ø©Íz–n´¼Ú*.E}¶­•Ùæ›J[û÷5ëq´ÌÈ^¹¯V+S>*=ˆJ­s¨;wa)(@ P€ÃWÀ8|�ON P ßœ�þNî¦>×šÍæT½^ÿ ÕÇ6'<<â;·ÓyûÞ½{÷È5§|ÚoºQ£’�ÏÙ—ýªÎí¾ZfMÿ^>í¯ó˜ úX@ÅzUÀWß!êÛ0›1ZR€ —m�¨oû®Å2Ë<17ŠêáòÁç¤(@ P€½ ÀŸóëDvA P 'ëׯß\[[{qC]}œ�Õz½S§»Ko4•­ÖÒsçNÕ ¶´„„É6_¿‚†¦ú‹��YYYËzrÖ¥(@ ô…À/R‚póÄÒuóLï'æFbn” ÷NWEøÍ„X˜Ð·fŸ (@ P€CT€ê!úbùX Ààضm[©,tx©ËatÄÄDK0úx{“ý¨Â‚‚?ûÚ¬Iy¹{¯OÂQR€ ÀpX8FÐ’Š¤@fQ¿¿»Z{ìW·Wjû+Æ>'(@ P€ @/ 4ÿlb/uÆn(@ P WÔïÍ*�'7 P` 0õ ~yz·®Ø‡7·U`ÚH_¬Z�€àç31%ÌŠ/ÏŠï¶íp¯ÀÔÃý+€ÏO P€ ÀþœA½¿Ï)@ y§�ü;à(@ Pà˜"i>d¡ÆMe�xfK9ªëZ>ê4á% P€ (@ t*Àu§,,¤(@ P€ º# CN µ¢NÓw~_ «Ó­]Ug9(@ P€ º`€ºK^ (@ P€ :ð5éqZœŸv©´ÆŽX#’Ì�Ue(@ P€ (Àõyx‘ (@ P€Ø_@-–pyrв¢Í9‰þPAkn (@ P€è©ÿÙS1Ö§(@ P€ 0.ØŒy±2‹Z¯Ã5ãƒ)B P€ (@�C`€ú�ØØˆ (@ P€ÃOÀár£ÞÙ¼–o­Ý…�²HâÉ ~Hð7 ? >1(@ P€ @¯0@Ý+Œì„ (@ P€C_à³¼:,ý¡v T/’ÅËœ¸)-dè?8Ÿ� (@ P ÏŒ}Ö3;¦(@ P€ †”@I½ýXŒ¿l(…ÃîÆYI81ÆwH=#† (@ P  î_oÞ� (@ P€ƒV`F„ ×L A�Ã�ãGúâ¼Qþ°ZVJ´OÅ�S€ (@ I¨�¤>ïM P€ À�ø÷Ûoßr°çj©Øœ{­}6ÏOOžkmåmGž:í÷žúíËtÜuozx÷ÕuÍõß÷×¼Gé}¿�:fïQü³c=:Ú1SW«¾/˜j8/⤛æê}ôS¥´5xÚON ½ F‹Æ×؉g?Ùþš§Nwûó¦ÙÎ�8åÆc»«×ÙõéÓ“b`µ6ÀdsûO˜ŸÒY�C,ÓI¿5ÒVa{©óý±ŸCj6ßlûƒâ1sbbbl0YÝ‘SN óttöÛ¹AÓÏù­:Ÿ4&ôZ˜4gʤ³ž�¢Öw£®§§GL‡Ñä†ÙÖ:v¶¿�¿Ï›ˆ�­®q£(@ P€ (@ P€ †‘€'@�€±[<�ÝßjÏ}uß!@�,êô Ζþ “''$èmAU¾ái‡ÚOÚͳù½Ÿ9{‘”dQ÷—OoÎ8ÖÁ棨{2&OÝôtù¦@ÊÅ�zÎ{¸7X’Ï[®Úhj³Í�À±{Ô¹ÚT€: %@=A¨§\ô3)6LœŸ¨³V!bb¸ª—fµ~kŽ˜÷/9T3À=�kÝHÛ‰ëÔun (@ P€ (@ =Πzï”OD�ÞˆŸüåDß}wøD�ú‡§cOäP�'……] ½þ±øQ³OSçóF#62nÊø‘á—#~nԌȰ ¬ªF͸^ªÂõ¿÷‰×: {FbÒÏôFÓ£ˆ›ö+¹Þüû’®9v{âXÓQ#fž›’š 3 ¦ÇZ?–Ù§ªû5Ê|®*‹NM�Sçj‹‹ Öê¥sµ :¯Å`µ²Œ~jVµsݺ={ŽešW6éy­¡Œc¬WÁ?ð¡�¤éªÌ7Ðö{™×«¥ÌHH1i ÆÍOó9ÊæBmöó¤ñã§Àâó˜%jæÉ-}`JŠí\Uœ>§uLaaa~_Ù‚SP÷M²²¥®S>nÕF‚º!ª>|C’)Ä­é9Ä-A+‰½Cª5³ûM^:iZJ2Æ�pysÛië÷ROÏæg ó» bê� LN�›­úQ3’U›ä¸äQþVßwtzº�é¶ìª…«/�-à ÄÌ´©z£|ß G&ÏRçã“’RU?–дߩsÏvîÿ3­æÊ;=çˆûä�òktÑcßUeêAÛ6y½V›æ¿aCöîãÍÇ tÂó³ýÇn�H+h*üêR©k—�§™»ÉoõW=K b·õÃ# P€ (@ P€ †‚ÔCá-ò(Зµºð ù5ïŽ)Øw¼iêùéío•ay4Ë71Fãߣk¿»ÊwâÅ—‡ ¢ ^÷NE“s²óË‚-¥'T™Ãåz\¿/ã¶Ä1GÝUÔ`z?È•3©hAÝïvïÝêrèŸH1®7™'�qWû{„èÆZ‚¢ã6o– ¥SÿxÈë¿¡‹¾ÖÇ¿lÝ1Áþ‹vûLñ�Qÿxivæûˆ›œ�”Sœ›å)ìZý�Ä^8K¹ÌjÚŽU³åžºä€€— -£öÁåx¥,wK¡”é“ü u¶dÿé긬*òlz73Ì_—l �Œ;>2ä¼m �wÁlx²±&çG5î¹a#í¶É˜`|¼zç¦÷$آʭµµлóåP J«2µ%Gû‡æ:ý¿“”Où›ÿ‹Íej´aæè°¤=ºˆ7¤ï¿‡[ê6!8m³”ë Ïº~k©y*J þ’ëˆú^Rf<…ìïVyÕlÂÙ°Œ4ùëë} Ï|d]vmY@˜ÿ«%Ùåª�íÕnÃóVCÅʼ½å?H™;$ØçŸ”g7ºCîꦔ��gs­cK¡s<¿'óÇbÈÎÎÅWþgcuå{Ò¦ukÜá:§²¸0§µ Þ0býî¢OÓJó'búÂ9*´î‰6·Öi9(2êÅ¿zŽ»R?Ábp®ßÿº:o”:03@ÝË(@ P€ (@ P€ƒ\€êAþ9| ô“€+/4`‚}Ý»ßU…[ev«6™W_^4þìùþohjÚ–mˆ¸´~“áa½Á¤‰‹~¶¶¢VÒ2h3…¦r=ï˜äÖýX«·½‰ÆÆL£Ùòš\¾R®KNXƒ{{q¶{I¬ íŸI6ÍØmÜYßõ�ª+Ùš_XÝt}i溗áÂöÆFûdsµO¬¹Ú�ަ CMÍV×V éªÙ¸]n!%õó1>ðS© «lpœZ—»g9î pë,’ŠÃTk�|ÎÝxwʨàÔ*cп¤ž6 [uøYƒëÆF»þ:TWg¢z_©*+¬i¼¾bÛ†—¡wmw4Ú§ É£Ê fs¦Ñê¸ýærúÌB}òý¨)ÝZQPðeš®t7ÂRm¥åÎKPm»QúÞV”_ú*«´ÓC§GÓÎ�·P´©Ðè´LCcÊ_T[yÞ-rM£r·_SÒfþI]¯Ê-\£7ï­“>t£Ã|Î�W¸½¡Úýt-Wu�-h FçÉý$ WyƒóìÆœ¬eòM ŒëŒy•F£oDÃ5!–‡}FF«o,´þ]2&¯­ù{®úØðñØðÁŠšð_™A¯Uqš'‚{êGV8�ÅøàN v×ÕYOð”{íµ&f¯"žP€ (@ P€ (04ö‹* �‡âSP€½)Ї,..®9.Ç,_]ÿbKï® ð-ï!qæ�²8ߨwáKæ4ç¢Fg[·¹^k³“A ž·ï ;&ýè°hÃó*쩦{2}´k¤³øù.¯w¿Em¦ ~~áqÁþoE$O8 ]¢ú4•¯Ùhpê²t–�×! þ–d‰£¶¦ÌP}9Up½"ûhsbÂØ¨SVÔ?�œï~)—\!¾¡ßøEÇ�+zC‚JÅ‘%ŸÈ¦/2wÕ„¼¡{¼Ýx0ÙÏøªÑ¢��£ª®Åù¿:&í,¸�‰p›QôõFU¾§¢¢"Å\ý¤÷¹Vß” m|à¯[ ß]·!0|´ÿÈ‘37éCQ¼¹>(\ÿ:‚ì�#0bTh|äé»|‚›¤ÉXÒö۶ۥτuû ª-BC“eµQÝËå5i¼Íߥ‚Ät/.ðÿ3BFL ó½HÔª **�¨Ý­õ…ù†0ÿÐ/üb�ƒ[/ÏaHDÖšš¢ÂšŒ²’Òk- {® K�¯¾¹ m¦q¶Wýãb“<çž™ÜÊnæHã¬/~¨z¾õš:(ß+þ�‰ñÉ1§~Rôwä~÷Ë5ù•?Å×o)Ò§ÌyVÞM‚öiIwRhÒ¥Âälþ²ðêˆ' (@ P€ (@ v�¶HÇ`ŽŸèu�ÆÆb;uïx:þ<Û±JgÒß×X[¬fÙbsa㯓êw;e¦òâì¨ciØðÚó5 öbgmÕ&O›òF|[é*¯WçÕ:ÝçŽêòruÜätìFSŸ=:>ë7°»›‚’žE]å—ÁÁy8j>TõJ ;U%ûRSSM��Î}hÜ5I¢ÌwH€óœOŠKn¶87EHØöŽ#Ï�êú­ÙÉ#ëOGCÓíÑãO —É¿ÿ�òÖ´uv×vì^=nËâFŒ�â]q(˪R÷ÚZžs޹’ÎÃtGô¨ø9ªLmV«þÁ&¿È§*7~£�½¸Ö°«©¦lߺܒDúm}Tæh/†iì›ÏpdÔ×7 P€ (@ P€ (@ P`˜ D%àJ· K=³¥µ½üÒzî9ÖAß`ÅœaÎÅÇï%¨{ ’ÝP€ (@ P€ (@ P`0 è�X³PZ=Ok€ºÝ±ÓKÕ5n8\5SŸ(@ P€ (@ P€ (@D¿î~Qrz$ê]ا³b¡–æC\<é=Ô¹:V³^me^÷ ]Ù(p8 PŽÛR€ (@ P€ (@ P`ˆ DÿÓ=ËŒoµÔEÔ‚Óò¬žµ¾Wm½D÷ü}|>V? 0ÅG?Aó6 (@ P€ (@ P€LyWêV¡ ïzÒ~¨±{޵½/þ4˜ž‡c˜ PÌ÷ÂQQ€ (@ P€ (@ Pàˆ Ø q­ F¥Ð­CdÒ3îÑû_ã9z"ÀuO´X— (@ P€ (@ P€ÃH à׺b4â õÈ*(­í›wÚ¹17´œrG�C`€ú�ØØˆ (@ P€ (@ P€ÃCÀY‹%žYÔj¯>.ÏÞ‚ßÎ_ê6 >e_ð‹§/TÙ'(@ P€ (@ P€ »€ž£b1YoÅÏ=�i-:­VK”M Zë Ï‹ÇL9ýZ+ä/è¡Ô=cu P€ (@ P€ (@ e�˜¸CVÜü^Å¢%×´¶©YÓZ:™–²Ös?,‘’´Jü…=hùòêa+V§(@ P€ (@ P€ †”@ÂR·µ6OÊ+TÐP}T@Z;–_%Ö¡(@ P€ (@ P€ À@x°ØKK ³¡{:<Éýg—4jÍÙÑÒ�½?uÕ×Þk±KÔEZ@Z¥¥¢ PkAjÀ8ª3»jËr t&Ðã/ÜÎ:a(@ P€ (@ P€ (ÐO¿ùh,î_ÿžÚW‰SÆøVS\N¿—ÝÿNxÁm=¨QüÅ"³§£<é9T€Ù³Y,0{Ž;îunÔ`±'(­fS{©pOÇ6,¡@× PwmÃ+ (@ P€ (@ P€8§ßŒÅŸ|‰¨Ðm°¯ƒÛG“Dˆ�p¨�Å}a… xÆmênÐF Rœ-ÁeµWù¿öirÁv öÆZ¼í©«íÛµu1?á¯î µç5 ´`€º½�)@ P€ (@ P€ (0ο÷DL˜P£avY‘P}$8í”�Ú»]°Ëê†v=Æ�°áOÝ=‚Á€ Ozm/ <©>t~˜s ö97èÊݬj_§}ÀÚ†ËÚ_ã1$Àõ�tx� (@ P€ (@ P€GZ`ÁmgaäèOàrèátHPº%8­Ó*P­‚ÔRæt;%Hí†Ý†ßG>æ;аe¦s€N*8ÕG¢ËÚG޵ µn9P[íZ î貎î;”œØ]öÇ CZ€ê!ýzùp (@ P€ (@ P€ƒB a¾SN ÄӃ½Æ{æïÏFtê{Í�i NkéýƒÔ*@Ý<‹Ú!Aj‡œí�ø�W?û�èœ(Sj5óÙ¤VÁi-Ÿ´“#vûî×Äë´ÐޝÛ¨~<èà—�ií¯ó˜] ¨¯Cn (@ P€ (@ P€ $´:åÄ(˜CâPS—‡Íäô-Ê|#Ž{6"ÆÜ«ïDu{èäSWþöfÜ¿˜t$Lxz™cª>I-m–5Í’"ºuïXZ>fÙ›¬0é�°êõ®êrXq­N¦XwÜ,O¸“ÝáÈ”P·Ìšvà ÷5Ê­ r®öº œPy•-ÛJ¢^u?¥³á:©®mjèjS;�ksÎ×MÕ ø  àùú9@^¢(@ P€ (@ P€ ÀP�@ñqc/Cô¸§¡Ó›[Ÿ´¢àøà¾«[Ï{ó`Ε'`Ô”÷¡7øh]-8-7PQ^-Ò+{½:n N»]Ø»þ 4l•ZvL9úDÄŽ}6ߨÀ´¤–IÏêXÙ6 RÛjprÙ/uŸt6ìàÜ�õ£Q¡f[« µ åc�-PíÀšÊ‹t3:kë)‹yÎ=Ñ5ëÕ¹j¯¶öAjW1Æî»F·½ù ¥@瞯�ί²” (@ P€ (@ P€CY )É‚ôk¶ÊŒäÄNsó—“ðÓÛ:½v(…ó%2ÿuø‡�ç˜Öú’P�'@Ý~¯fOïX‰Ï^/ôºå¿E mzž§õ°HpZ©U€ZfWõ¤vé3ª/Öåզ݉ϛîr‡A*Hí™E­¨¥ŽÚ �Pq“.»]ïÃ¥n}ÔD4JUÛî¤Ö;°.g3Ò±T§2‡p£@§òÕÍ� (@ P€ (@ P€ÃT í’w`¶$vùôÁ‘s»¼ÖÓ éé>ˆ ç.}ÓÎ.AxâRèfˆ{ IDATe…BÏæx<Οü,~SZ£µ•¯`í²üøw 2^AiîcmjÏýÕT'ò‹IR�L•ÒCKï¡HË=�ò‹Aíµãö-Z‚ÒR.ÿ‡„žkŒÅ]x½®(â9÷ à¯:²ÝåXTxƒn—wKžQÀ[@} q£(@ P€ (@ P€ U༻?…-èX™%Ü}:Ý-+Rðã²ÌNo5û’3kuÛ,ê–°'P½ñÝ@¬ù¨Ó ³Öß�ŸåÃê©©=3¨ÕÞdƒ¾Fÿ+×µæ':½ïR·Ñ'Å ÒfR«Jn—ö8*8m�SµW�DõQ[ëÞ%¡ïbL(¾QWÐ|…¿R gÝÿGÓ³þX› (@ P€ (@ P€ƒ_ u¾޹|νëS\üH)æýüœ.ê­;OÄ+¿6`Õ¿QW¾¢Ëzê‚OÈè.¯ûêØ²Û®«tmgMYÐî¬ãaqîpª\Ô*u»½Ë—¯ûA¼éV±æŽÛR�ÃPŒ*P¨&nkC9pËÿTÀÚ3³Z Å“kZÛ;°Æ/q Nw$eÉÁ 0@}ðV¬I P€ (@ P€ (0´tH?g*,ýST#6ýø/©?B;é ¤¦š»xüæ0rÖš*¬zÿl™}¬â·�o#â.íü‚VêFþ¶›Uh-2ÝÜ«–Z+ uÿÚù»ßÒÓj‘Äý?pù ¤ñ”®ÚWß Ë4TàX,ÔÕjŽ´ŒÃ³`¢W�Ú‰½(Åܪ‹t3ro‘,ÓÜ(p P›R€ (@ P€ (@ æ\v¦Ì”.øc2àÜÈõ‰õ#‚�>¹Û§Í˨CÁŽ[º¬çz¡\ë:&—“»\k빯¬néÍh‰Â¬ »ž�ýÞÒ ÔV~Ó<‹º%HíôìeFu€,lø`m4s[°ÔÝa 5WëV÷Ɉ xM.:´éÔrµp¢6“ZfL»Ëpf툯¾V÷M—ÏÈ è�@‡/Ä´eU P€ (@ P€ (@ ~�Ÿ-~ G/ƒÞtÀ‡‰JþÓ¯{.nÍx¶ùÐeö\�½ÊS=í¢©íJ¼³>jDeá Í…žö²W�jõ‰÷kïû�åíºNGsŠ�ö³¨U ÎÄ÷™ÃÝ £ñð~-µÓÚßê ›.×]â¼fäé"Q¦ŸŠ¬šPçšêfÔ]£ûPžÁ3°Îº`z$Àu�¸X™ (@ P€ (@ P`È øŸtÀgò„c­~1ñ¤ðÖUsW×£,÷Éæ¥=�ÛµŠIYÔî¬ãá¾ÌG%­ý_»ØÚ…EÞ„ôtSÇF-%™™ß´æŸÖrQ·Ì v46§ýp9awËÇŒ["vûvÙ$-Áj\¯[‹E¥Xªë:mI×�ð º`€º["V (@ P€ (@ P€èT m^,æýâZŒ›ÕéõÁR¸û§Ëµh°ËQÑí�#“/é¶Žª�¿å¡¶z­ææ"¿ �îÓv}¿£ïߨ(y¬Õ”gÙZÚj3¨µ=BÒ�ÕŽ:û%ãY;Ê žl^(±]pÚ®Ž%H- &ºåcw:+ k!Ü(pd >²þ¼;(@ P€ (@ P€|IIœtËÓH;+ÑiO#õÔ yˆ�gÒcêÉI8ᆛqÖï`áŸËqáÛqÂM�±Ê €í¶ï^ûkßõÇk¿ ƪ‚ÐP½¶ÝUïÃÐÑK¥À»½w�泌rÐT¿S«º_|Z«�<å´Îšµ”¹PšÛàÖÚHyðm%8¾íÏ­³¨[Ó|H,Z©› PÞp¹c{f„ÌŠ–\ Ü(pdºÿ�éÈŽ�w§(@ P€ (@ P€h “ƒ0ã²r¯amûl Ö-_çUv$NÒŽ�@̤ß#däMÐÌ�!wÓ•øò/tzMŽ=1GŸ±Ï뺮]mÛ—iøáíÍ^×;;9æÊˆŸòŽ–;Z».}xº±7ìÀë·&wÖL+›vf"ÆŸºËÓ¬¹^K{5–Ÿ–�ÄÚeyH:Õ‚˜zV®lðêë¦WÞAPø˜,€ÑÜ€&×_ÐhxÌÜãU�'8Âí;[G˜ƒ·§(@ P€ (@ P€èV`Ϻ ÔU~åU/*õV¯óþ>=+güáeL:£#bo�N/Ái5óxÿ�…Ä,<àð2W䡦äï:-³˜UadÊOuq¶sëÇÍWïüÙ^Û�ägþq_mWÒœ1D%Óˆ'ÏŠ–^5¼O,ß*�¯k7QT�Uu"e>%Ð�ñ?ïFr¦¢L8ºm1D­‰§�ª-ǵ•+P¸ã.|ñüj)ðþf�ªÂ�ƒ@€êAð’8D P€ (@ P€ (0 ön~\ò9·¨%àjöICâôì^SاãUi=&œ»c@Û}äþu_`óÊ °}eïÌ&®øá} P·ÝÂs¤âÄV¿t$Ïíö^+W:ð³Ï"0ú:­¹ŠK·ßF¦<$§ÔñÇŸ-3ÃÑoiähØ‹‚¬ÅÈÙû2—U·ïŠÇŒí¾s3‡Ï1S€ (@ P€ (@ 1�­+²à´·ƒUÔV¶øÉ‘º¹ê!ÿš:ó>è ­).Ôlb—Ó�wWžÔmÀ¸'7ݰ¡VrHw=#<~ü%Õ]áÖÇ¡“ÈôþÁiÕØì;§Þ²=¼GŸ›ÚÚ_ÕÞ/[�Ýòl¥Ù÷aݧ xåæ8¬xò§[ux0È ä/�ç(@ P€ (@ P€GPÀ�Âíôºøè;ä¼³P¬WµC?‘œÍ#bÛÚ¾%.‡}/ ³•{{Û·éÞ]zž.¾¶æý­@¯kIë!M<´ô>êO°ØR0vö§­÷úayrÖ�ƒ«f⥯¬øàÁÅXûNvëuP`ˆtÿÐyP>(@ P€ (@ P€ @ìÚöŸ¶^%Z¬f6O8-­­¬—�RCã;ô¨‚Ôfk¢–r£ÃÅÃ,øá� Y ²©Ó^ôF?}Nz§×¼ Ý(ɾ߻¨“3�ÁOJÛâuŸ?÷.¾}õ;à?ÎNj³ˆCB í ~H<‚ (@ P€ (@ P _rW—¡®J‚¨íf�kŸ�Áh¶tÚ· RO9m#fž æÉ™A>jPí&g=ß\(Éùs—Íb'ÝÓå5u!]f|Ï»úEý¼Ëz. €ïYŠ¯ß “:\ì°K(^ЇûèP4á3Q€ (@ P€ (@ ôDàèsOÀèY+¼šüø”YY�^e½q’:?“ÎÊïØ•„¹Z#]*ZÝ~“ n—NG \Ž28sPš÷”ç­ÄÆÿî–šû7hßH;u4&Ÿ’åUØz/9ØøN0Ö­¬ðºÞ|¢ÇÅ�äÂhŽêäPSö. ¶Ü�UodÈu¦;EbáPà ê¡þ†ù| (@ P€ (@ P ¯ê¶}Õá!SNèPÖ›WJ�¹¦cWícÌ­Ñã¶j:½QÅ‘²(áxø„œ‚ØÔç1ñÄ�8ÿÞMHš«f.w½múh—·Ëº¬:þÒÖkS¼ú’Aé½g|Ûv gýùØü¢/ÞYrާ�¶ N·ò`¸ ¨uàF P€ (@ P€ (@�C(.v":- ¶€£Z;±ŽÃ¶•Ï´ž÷æ�ψ ‰¹¸C—ºNÓZ¥öåžã–½Á†IIâr¼€â]•úôDŽi‚߈S<§^ÝúÏ‘ñìÄŒ ßFÔäáë÷r·ìÓêXƒ¾Àˆ˜ËP²k)v}sV<}öü´ùùv¯¾xB�a*àù/r˜>>› (@ P€ (@ P W&œ”‚Ô“·zõõã{áÈúºØ«¬wNt8{ÉWð šãÕ]—êöµº‡5V¯Å[T ¶ŸŠÝÖP¥™²À;µHkW­ÍõëÖáÍ?Lik¬-|ÈYÒí@xH�S|x$¸§(@ P€ (@ P€8t��ŸdvHƒ�Üq–ó¡ß¡}K7Þ»kŠvßÕ¾°ûãýÉžªØê?Ó/œî)ê°ß¼²M�»;”kûÅ´«‹>دƒÓû�ð”¦øðHpO P€ (@ P€ (px#âëvZs'´õ ž�-Ÿ>tx� õ®5+Q^õš*–ËÄçR8íE²o„Á�ÞÔuËýÕm§5ÈZõ¿íbfÚ0ù¤s~ôßÖëmíä¶®&”äü ;W^Šo^[ÖZ‡ ÀÚÿgtÀмH P€ (@ P€ (@� $§‡bêÅíRzH�zãG©ØüÙ–¶ë»‹Í±¯ôt#j¬VøÅ#zò�ð;hó6ÔlÀ[‹'y gòc�zü x½ÊÕ‰jWSú.r7Ý�ÞÉ�3ΔV.Ü(Ð�Žÿaõ 1«R€ (@ P€ (@ •Ú컽…ÙQ¸¡¶ßG¶=£ã–«ŸÊåܼÅNºYÔW{Nûyßœ{##C-H¨>›€ÿ^ˆKüev·,xØ™Vµ´C·³Ãø|üc;§í ;�·mvnX޼ŒºmX@ ´sP4+R€ (@ P€ (@�,–t’f}ŽqǬÆüËkpúíÉhû?½ë¾MlS’¨oPôUHM5·•ñ#7ò¶¶¤Q‘éæ¶¶¯.|¯ÃèV½¾ö†Ýp;P´ó�ØüáH¼q[2¾~á-§;h±€=à ꓱ(@ P€ (@ P€€ަj¯Qù�8ÇÞx7¾xr±Wy_Ÿ”¯ý˜Ñî.¤ö7ØüI»Â#{è¾ßbˆ¤VqêüÌW:˜ _¿™&Áè¹Æ�±ˆ‡#ÀÔ‡£Ç¶ (@ P€ (@ P` ¸ìÞj5®ðÄEHH°v>ÄùF¤/˜ƒ3Š”ã“;¯s¥YY�¨ÌÁ«eTÚÝ^çGîD�c~y"’îï0„ʰá“ÝÊUAs§;Åa!O€3¨Ï�­)@ P€ (@ P€ ÀÀp:;¨ÕÈ¢�Yˆ={ÚÆiÇ�FTêõ‰»:]óäÅñó?Ä¶ÏÆJm5�øð·¼�� 0ê­Yý§#eÚlû¾´µ¬¿’¦ `äx„Œ<¡±¿‚ÁÞáÖÕůãÃû¯êPÎ P Ï îsbÞ€ (@ P€ (@ ôƒ€ÛÑù¢ˆQ) 9ý„§þ ‘)÷J€6²Ãh̶1•€]•®JÁúÿmAò±U0˜Z›GL¼@ÔOµž÷öÁÉ¿yK8 F?è þòñƒÅo" †¶1h÷T1xI;âÙÊsÿŽå¾IN{'8ïé—{ Pà  >(&V¢(@ P€ (@ P€\ÀÙE€Úh ÇÔ…Å]†_].ò6]+Áéª^|B7Šv-ETò_ZƒÁáI*ÍÇÓòéƒ@pº #në0þvqhïk2—,z˜¿õ:¬|þ%ïk<£úS€êþÔæ½(@ P€ (@ P€ @_ 8œuºn õ{ÂõeÿCîæ»±îý5ÒÎÙ¡íáänzµ9@­n(77˜B1é´1X¿|ûávÝ¡}z‡’® ´Àô¶›P½öeddØ»®È+ @0@Ýʼ(@ P€ (@ P€èK�¸9Á�»¨Û[ز‘·}ÊÖ|€ÌÌÎsVwÛÉAVعªOÚ ¥ÙÐ&MK�:bìo€å7d_MšȽ|'vÙ¨©aò·/Aý†·˜îR‰(Ðïžï�õû�yC P€ (@ P€ (@�^8þ†»6ê­'Ïìhu²Ô'û-øòÙ¿ö¾‹œ‰„i˚ȀÜnÞxÝ ôÁÌå„ÉA˜qi¾äž–þ[¶Æê ïú J3?ÆæÕežbî)@��#ÀÔç]p$ (@ P€ (@ P çA#¯:¨F�agJ½þ P|¿BÔmÃÓéô˜7ßg|ÞVØKG{ÖU`Ï:¤L A�Ù…œoÔ‚�®^ê�ÝP€}$`è£~Ù-(@ P€ (@ P€ @¯Ì7bl\4(@ P€ (@ P€ègœž·p –ÈŽw–(uc}&ª ÞGMÅZ`‚Îè½É•¹_w¬ß®$oã­HšÝy�q·HÍEòq¶kÑ·‡›W ù¸m°ø¦´Þ(zÂMØôùÍ­ç< †¥”bX¾v>4(@ P€ (@ P€G\ )É‚‰WdÂh�ï0–¢·ce†äŠÎ°w¸vpzœÿ`-ôk§Õ3¿ž�uï¯êôZ_μhâ�~§µ{·Û…7>´+­e< †�S| »WΦ(@ P€ (@ P`@$œþÿì�|TUöÇ™LM裸„–@¨¢+E»¨ ²ê®®««®»ØbïYÝÅ¿eu×vì ÒA$ˆ„zéÓgþçÎÌ›yoæ½I€9÷ó™y÷žsÛûÎÌ›÷Î;ïÜgU�Ó¿}Ñó^~üŒÓb÷<عþ^ÍýÌë[®©k/Å–MŸ+ºŽ‰Ñᘴc2.0&Ðé°�ºÓ}ä¼ÃL€ 0&À˜`L€ 0&À˜À!'Ðíø®HË¿6b ;Þï_ÿ!ßÁ†U¯i6KH=½ghêÛCQµÈІ]ï+ºÎî}Ÿ¢Ì&À:6Pwº�œw˜ 0&À˜`L€ 0&À˜hC1è1ª;Ž6zŒÈou¿ÝÞªZw{…õh£Tµ¨͵ó5{Ëzƒ¦®½[V?¦è:>m4º NVȸÀ˜@§"ÀêNõqóÎ2&À˜`L€ 0&À˜`mB oH:F\}Æ?ÞŒ£N[�îC>Áà3¶ ×ñÝZÑ RóþÖŠz^eû*í0™Åw£¬ÌxàƒìC+g®€ÇmS´È);WQæ`�Ѝ;ÕÇÍ;˘`L€ 0&À˜`L€ �.ýãqê­ÿÅqã«‘Õã!Ä„-BØ}Ø-ö_<4 1zõÅ =º¶µÕü´e¼à�œ–ˆ�uâý‘Š€dôu�¢lD¶¦~ÿTW>¢hšS¢,+”\`LàH'ж½#�ï`L€ 0&À˜`L€ 0&Ðy tí—Š/®FJÖ%~ƒo˜ÑW»\€Ì²„¨�L Ú!-³Em»ÏÊeNÔT½èo&&öÊê6ýNî§ìv°cn~Åw¡ô”Ÿ*·eªZñº¢;½9¥#Š2.0&Ði°�ºÓ|Ô¼£L€ 0&À˜`L€ 0&À˜À(èv„Ç´dðv_)õtž”UÝš ÚꌢUÛˆpËŠç¢6ï3f%Nºò6 :s8†_vÆO¨EJî¾6zSÊ,9QÛï«rÝ¢­pXÿP4+è�¢Ì&À: }§ÙSÞQ&À˜8øn}3:s>Ì–^0š@o(†Ó¾ +ë^ÄŒ Žƒ?!‘ 0&À˜`L€ D!PTdFB÷^ðxÜX=÷7ªI¡1diËÊO‘ÓÏ�NÅž",Ô1ô¢mNÉ£”ySÖR™u‹�É_ FdçÊ&�û.^û}%JG­„9¾¿fãì’'‘]P‹ý$�«MU»¤b›m·­™Œ¢AïûK+¸™ò“éåÊ8Ø@§  r@íûÍ;ɘ`íAàªid矎ø„‹aŽGçç* ®Ä}=5˜�7Úc Ü'`L€ 0&À˜ØG1pæ1Èí{?ÓN¶Í.}ßþëÎ`Yd6ÿºÆWÒár9Ðí´rdÝá7JKµnÔÂë¸tXÖ,Þ(i[GÓvE9¼�×}(¨¿ Pyã’¿�‘úç}êÃåÜ…µ_‹�•‹îS'•+W~Fê�Rý�9g(~üdaHÈ9&À:ñÑ>eÞG&À˜ÀÁ"н×KÈÈú–ø CÆi™ç…|–Ä?É‹œgL€ 0&À˜`­&ÐïÔR >{$úŸ6ÌçiÜê†c0tü8ÿÑj”œ¸‰é!ã´¨šQ|„GuxZ¿¾Þg°ýö_wÁÖ´2\,çú{0žiòì )Êý£‡äPTneá—9ËQ¿+ä±­™ÇíÂŽu7・ò°ê[e(ŽhíöE'<Äö|âk"]6äô½w_ºàºL€ Ø@}d|޼L€ 0�ŽAÀáx‚Èð‰³Í°—É8²cL˜gÁ˜`L€ 0&pØÈìvºŸð-y/ÂI—6âŒ;çÐ>ÄîÓ~”•qîý+QxÌ ÄêÓümåç°�Þ²†ž¥_/¶üLFh•v¢Qzá-ô®>¯ªEV¸Õš}›ú£ßˆRMýþ*æ<õ'4×-Ölî´U¢rÉY˜1Ç‚ï^tÙ%� IDATFr—fݶPT-»;Ø�½q9ª~{ Xæ `�†¨;ÍGÍ;ʘ8êk^jy:��‰ÑCħæÄ˜`L€ 0&Àö•€ËÕ hŸ>#¯yP!k©�2ørãû¶T ¹eOD­³|ÖˆÍj)†BV :sˆšÊ'«Ùë~8 Û~»µÛ_Á® �bÝwÇbÅ+IøðÞnXúþ,`^û¦¥ùýòEV}5ß¾‘€ï? ?¨m<—Úð– 0�#ލ�¸�”wˆ 0&p <5a~¨ÔcÕÏFÔÕܪœ‰ð,‘y—ÄÄå*õ\bL€ 0&À˜`­ àq6Гªgv£÷TÂqøõz 8ëxœy××(=¾—OT»}‰Ô4êÖh.F÷ ¢Ôñ`×åšúÜ>÷iêªÿø@S'ñicP6ºOÔ:’2¿, C®þÉ9qôß–“X<¨•¼Xþé÷øáµ©øâÙ¿aî¿îÆòY‹°v­Òð¯Õº­å«>_Ù¦ B¶õü¸?&ÀÚ�¨Û1À˜èdfLpãå«�¸÷Ôgáq×ø÷^f˜–p˜Ì½¥,o™`L€ 0&À˜@« ¸ >¿Å)&r�¿XÑG�QÝ1úº§1þI;Řþq©£Ñûò&ãmÅW+ðû÷Ç¢bvOÔlRz*‹~¥—è° Ï_ÅF3m[þ¦¦.>c,2ËTõ«¾^«é}-5è}òÍöR dØ%› 7çùDƸô?k¨¤æ-`L £`uGÿ„x~L€ 0�×€õõ�)¼¦åûb1+/rž 0&À˜`L€ ´Š€ÓÕ¤Z/»ôqôœ�áºç?¼G�¶éE·Px¹�íÃ`é‰nƒ“|í…×pżõøúÅI¨Ýúª} CufÑ]ôê#¼âúå»ao\.–{ô׊cíÁöÕ7ë©etú ?JJ#Ô$;eÒkè}Æoõä)Æë‘9ϘèÈ´°yÖ<7&À˜8<ÔÕÏМ¨%nŒ¦ŽL€ 0&À˜`L@‹€Û©n Ö³0ð¢Ý(ø*bMÙÍ=¶üòWlXV¡ûùs± ¡zŠÑ1pì`ue@ZµêM}ví8Ö[xËßNXÂ5’9q0\Yï3F3n,Nüë­8ý¶�1ê¯õH͹<¢Usí<ü2ë§9 ˜`”¨;èÃÓbL€ 6»«4÷Co¯7Zl<ͦ¬`L€ 0&À˜èÌ\Í‘{/N+5N-›j¾ÀºyÇáý;ÍXôÖkT1Ò\Mñ—kª^RÑøkçô^ÔÚ©nåךJƒ©€BŒ«ê7n´aëÊ+ý:)®Hø6Ð25÷r;Ù¥O!!óÕþšk¾Á¬ÏO%{P«b!`‘¨;â§ÂsbL€ )DÅo˶ï_'‡¸Uj~ †4ÉP+nò¤.bQÂ}7P‹æÛ+î@áàé�žd+¯Ï#$Ð6PÿöeÊFÚ ‹5ˆ²Å£þŠª7ÿÈr"ÄÈŠ�KQvÚW0'#ÓȲÒþ’¨~× ì\ó–ÏZB%ç!£ÄY&À?aGñÃoxÆL€ 0&p \?=…yŸ‘§´ÆIt sknœ†;Gþ½…Z¬fL€ 0&À˜Ø_=z˜P|Ƥæ]íëÂeߎïͧ|G1jêP6¢2ºŸ…¸´—2’ÂUìÆž-¯áûWÄâ‚!«ìQœ‰CfúöÃëq@,^Lró5ùé½Z ±.¨nmF„ñ8îBå"Œ¾®ÓX9§ÂÓZ+�¼æQd«Ç«öz=X6³æoÖjî“8ëxd]‚¤ì‹CÆn±¯Í{ç¢q÷W¨Û¾+«å0Q ²’ 0�ÃŒ€ü~˜M�§Ë˜8ˆÊËõØÛ+}ìŽ=˜zIäÊßq:b¨;¦wEnÑoˆ‰ÑŽÅ×ÒDÝî-˜4L„ùàĘ`L€ 0&Њ¦`ÈĽЮ+¾„НV(d»P<´ º ¹iùÿPšCöhT­¼ ÿ÷ºbjÇ]v5v®ý ë];qÁøfèt‘O†‹.6SÛ%amE)Œ½e»\à³�‡[Mj¶ý¾žr•f벱ǠlÔRM½PxÜÍØ³y æþkrÔz¬dL€ tá‡ÚN²Û¼›L€ 0�V¸mz62²§Âb¡TY²ZgÀúíE(/ï(ž'²É©dÇO�E‘¡úØ|ÄÆÄÓE@mÈo¦ õ;¿Àó—ï[è[¦÷A×¢_È8­rAàuÁnŸKgÞ�ôxcŒ¦a*3 ‰~¨ÔC,¦È‰ 0&À˜`L }œ5ù;XRN v^·ým|ñÜŸ‚僙é~lz }ɹ—††•¥CB qïW˜ýØ©r‘"?âªû‘Ù£\!“ ÂSü£{s¥â>mûœ<e§üln9Yü¿4lþUiô—*[ˆ£ÏÝ -ÉÕ¶o˜8n´–1&ÐÙD:Þ_&À˜€�;>€¼uÏ‹e<š¿CM?ÒjÞ!ä“?ˆÔŒÇ`2�õÏG:»–]ddOÏŸ�=»nÇcç-jqÞѸìÞu!bü� ÷®`?Â8~LÎ,˜¥95þL6Ò(³;LÊE&À˜`L€ 0�¶"°eõýèu,9RrÎDý7Ú$Q»oó‡[P6lZÈ0-;ÕÜh.ÒRùä›~ù·¦�ZoÊAɉÅXû}eÔ>Ô”«¿þ½G‘wvlØ“‚�séÞ£§��ú2µ¦Èéu¶ª<\èhZEÆig¸˜ËL€ 0�ÎH@×wš÷™ 0&Ð2o ²sçD­Ÿ<1ªþP*ï|§Ï,ü ÙùËCÆé(2šŽGNÁBÜõÉqQj� Ï:ää}­Z§¦új)…¯ jõrIF^ÙˆK-©ÉöìÁ–_/G—^å0š‹}r±ØáÆåãÇ÷ÄS˜2¡VœcL€ tFl îŒŸ:ï3`-H^M'ÇþóHÍÊõµÏhê•"šqÚëm¦ó`Å�NÒœ^ tèZ(âíeÓ+ò¤95ý!Õ¶N皨q¤+ÑEµ%`²Œ Í¿5´,îè„W=è{CAÇ›˜ì�)Ï� 0&À˜@{غrªß@èÜßb¡Bá…Ü^I„õvv%…Ê óOÙ©eÓÞ¹øýË X·¬ú€‡þeæBônCŒÞÑW - 8ðŒ¡XñÙÂ]KÁ¥Ï¨¹ˆK©Y55÷Jˆ—”¤]ôºmøuNŸ@x‘ÿaÐÙÇÃekBÃºŠƒVEšo™`œ€¸ äĘ`áD 冺ÇÂÅÁrõ޳ñع«ƒå¶ÎLšnÁ¤ºaò'gà¡/ïÀÃ_݉ßÖ2ñúG¿}z‰ªç´ðôÞºe n’@¯dÔTšÐÔð”æ”cuY¸qzA„~|¹Cß¹x½»Tå’0uÝ)±5›Ïˆ�± ãßÇ'¾{ig¸éåômŸ^ðî™}.M> ±ãïÏ� 0&À˜@§!ðÛ÷ëár( Â}e ¶‰Ò£õ§e}{=.|¶èÔ61Nû»õ`û÷ÊFPfsû—+ûPª\Lç-$a”–^¢ª`¼‚žH žö`ù§ßã×/—±qº–¬fL Óà ÈNûÑóŽ3&Ð 1(Ÿu!’¯¢º¸\ëQ_ÿ¬öÅÃÚŠö-WFßü>™´€`Ä™�†Ùr2=8ŠÌ{ƈÆn×ï˜4¼W„Ü/ˆÁ³‹þ€^éö½µ²?ž˜ðkD»§øœÆR�=XWsî3UÑæ¶w»£ ûz…L*ê[Ží-U·Ï-Þ†ØXõ°)?¯²à?—¼EzT'ÈÂV¸î�tôê]EÞø‘žJ¢kÓ Ü1bB«ûãŠL€ 0&À˜ÀÁ!pÜ%W#¯èÉ5·«LN¡Á%ßß6œÇ`&\èˆèÐa«ÄÇ÷u‹�ˆ ¿, Ãÿ¬í±à½LlÛOoí±·Ì@b— Z5={ñû§¢zmC«ês%&À˜ðàüE`L€ hð¢üÌwI-^–ÆO�EWW* ¦b˜ã‘!ú$z�NñœÅ�,I÷ U®tºH¯f©åÝŸœ jœözmªÆiÑnë®kQÜõ© ¿Ók`Ü„¤;H®4P É¡ºR.0_½¾«$ÑÜZ›g!!ñoªú³)²QUÇÂŽG 7ÿzMã´˜­%~<„ûÅ(Šo¯xFL€ 0&ÀŽ|›–ÏP¨cõIèwr_üúu¤3Ã�Ò(K,ôw!?¯¥sG�¹×àŒ6ô ª*j`­�KÊñªÓîyÌ d ¾OU×’pÍ—bÐá7çiVuZÇ .öyIkVb`L€ hàZdXΘ8`ÞÜ7çb<»ðœPìBaÏÝÈíºiÓ?1Ò8-'ðò“xÙ$¬ÍoÈJÊljšz8»ý+eEYéÙó*)4‡Ì«E6n¬>7½®4žÇãd­CYa£ŽÑÅaDyô›ž6«úâ5¢§KŸP‡œëðL¦[œ£Þßb®À˜`L€ \Â�ÛL^¾ò”Ûï6y±ÍòÞ�kÊNmé¤Q:Õí{î¯tÖI((Î7céå;£< ±«Vk‡ùÈ*¾(‹|B±5nÜhÃü÷JÑTýyDuGÓjlX8ß_ÂÆé:,`L€ ´š@tcB«»áŠL€ t:ådŒÜÛ+}ìŽ=˜zI}ç`@Fçk_ŠG|fšv7â¥ë5÷û–J�Qø¶¦~_µ5¯ª6¹jš��œ»Pu�-±"l…J¢t�{¬ÍÃjûö†U°7mAfád$&ª{°x=�0ÿºL¥3 9«k¤«x2JO~käáL(NöÉ'ü©¹W %ç2lôÐ >õ£™È ½êFlÍ6¬`L€ 0�–°�º%B¬gL DàŽw ¯xEH ˉ˜³Mƒß!ÉG2éá›á- K—"Vß3êN$¤ü•ôêê]»–"+_Ù¼©ñߨ«}��Û¨TPé¹EÂH«žj÷Þ£iü�ñdF6 Üôz)tF ®šž„ C1,q#—x †ÒÈv2IݮͲ-|çÔ¸ÔJLC¹Ÿmä….¿×öòXòâ?ÝHFMYÈycÎw(/_ÝLßÇ>hp4’N…ÞPBŽI±pØ+°kçôDEU‡š¯4§KùÄCàg"©)®¶ž~"'W\˜^”GË”—ë0:Œ ¯ñ#í]´ýf`L€ ¾**ÈÝ: ©yWw"¯ì!,û°m Ôâ6ðÆe¡Û°YÁq$c"cõ ‹wÁ_ˆ ó•ç©R¿[V>§n TèwÊJdv½µ»æÓB轑[6:z"T$cº›% Þw  Þ0&À˜@Û`uÛ3å™ÀJ€žËË^2'êÎÅ'‹çó:–�ú/¯›‘›6É)—"V—]l*ŽÕ¨Ù;•Îeš^žiùW¶hœ0„'9 ŒÔ‘Iñþò~$¥>§s¶m?Ïœ¿)²"I®�ž@ãªê„°¹þ?š:£1IS§Óeà騇Ñhåõº°cÇÉxùj¥÷ˆd`Ž’.'í#š5„ñîùÓvPìm™g¹pa‰,…=ôE”Y'Jœ~cìRš©x©¾~. ~¤ÅJ�QNX|eÖj·§å�EW>ßÙݦÀ!FÓƒ#zMþð{Tïx/_û‰²Cåh\bL€ 0&pÈ lúåy…�Úœ8=ej{'ï猗}89¥Ú‹îs·ôÝwÄÇd LMeÞ�ŽÖ~_‰’+aJ §åI:ç$Yvé“ô’+ýy�³žª]‘ –0&À˜@{е÷Ü?`G�I3ÌQÃAˆÝô¶Â¨s°pLþh žøîÕ׊ìÜY>¯H£y$yzô-P˜Ÿ¿ÃòWA°Õ’«ù5q„L§KÂõ/˜"ä’àîS®­gà–áý5�Ó¢nšy„Ô$bk³~‚'&D1ǨïƒÔ‘j|jIØŠ˜ÁVë;صë4lY“‚ÇÎþ.¬ðÒø&º Ðá«ï®ÉSêÌn,”(.d Bo‰%Uã-hÏ_¼·7ջÂ]†�æq®“(‹×ý3=nDBÒ…äuM_åÀË"r‹?­GlÀ%&À˜`ŒÀºykávÖ(L¼Ù¢ÿ?îß.x1ëѱ{Ãû×\Þ*`�6‘1½ÿiCåE~ý�Q”[Sp9vá—ÏB,ˆÈ‰ 0&À:ö >èÈy@&p˜H^MÞ´ÅQ&OšºÚg¢T8p•0&gÑ#}K&Ù6ãÐdÝ€äÕ�Õ cqn¿iˆOøs‹Š½»¿Fõ"OÆuË¿Aµî<2Ç6!=ãŸQ½©-y"ĆzH±akÿKI»Cs¾»ªïÑÔ …ù#ª>\ér¯…­iš›ÀÑT�ê¦*¼öWú Ò EÑ–öÅñýL˜,ç(ÄòBAÖÙTœ.)òn-ºHßE ›˜|'‰ÿ­Pq¡c¡o ñfØÝÐ'4ÒïÏ®øýu¬ÙjÏF·„ Èg¼í¯þ}$©Ýþ»vcÒ¤^O7ìÌ>¯iŸqšî÷ëè{,n߈E â“ÇcÜ]éøè±ÐâPQ;d%`L€ 0�ƒNÀ‹kïG^ß©Á‘»ô,§ü ôjáœ0Ø¢µ/æý»ùùO cÀ ¤œSbO-Åt^ß‹žpŒkmGÁzÝ.¤üâ`YžY=g9 ú¼‡¤.¢Nôäu»°sÝíøáuÁÁ½2k™`L ½¨\•µ×PÜ/`‡=�G¾~‰Éw©îGõ޳ñàY3Uu"ñ]íG�@Fâg`4ˆGù”Éáø›*O¦˜·õ¸ó£Áä-ý5…�HQVj¡ô{e¦NÐŽ¯|Õ4ÊVSŒ]õP;¶�£çÌmamõí¯&"¿¿zH�gnšK�µ/îü¨¹ù•š8 Q³ãzXÝÉ X{@Åû>»YojŽåñÔ vN¦æÏ.\½q ²½l×ví�‡Ïz_©çR‡ pßgÓg0êÊfä¡''¶ï`·ÍEc×xâ‚ ™¶ãf§,m"ÏçÀ±8’}·Vö§§~Õœü£ß| £i$¼ÔF„öyIV±¤3Ê7köÁ &À˜`‡š@¯Áx¡ò¸â‹2T|³úL-`›¬GF£™/D×þ÷!)k¼.²ÿiáì`o\‰O¤•5S,μ›B‹$S­á°UbËÊðsõç-|ȉ 0&À)ö >¤øyp&p˜¸ûä»Q>g%h�=Šç—k=êë߃վÏM°î÷Þ\5-é]Š`Z±Ž ›¡ÄÉŸŒ¤Õ´?ôœå'¥²‘ŒÆcУçN<1o&ÄB�û“2’Äâ„/j6±˜øü>¤¦?¯ZÇbBò¹ªºÖãr/Ö¬V»û6Òiì| USS�f{¡ÐÅæàÑóŽZ§µÊæ=_ÐèÚµuº4è†]KþQéžOÏô…XñíŽt4lײ²g`ÊÒf¬_œ†©7Ø#ú`Á¡#�”,>×È$ÂܘãÎò½’Ó€{fŽ£› GV HÄM§m9±ÈÝîÖ¼‘¡Ù¸Mäö,¥°ï¡Û¶SÒ¨n�ŽÅô$ÁHŸËt u#¾Îâa )Ô‡/NÅVÕ¶,dL€ 0&ÐQ¬[V�ÒÓ—ÁœDN �ÿÂÜ~“È@ý·C0ÅÀ–9Q z­]…ß¾¼§ßžˆøŒ±þùHç�¢äu·0G7f=r,�},iŸÔŸÖ¡Ù…šªYØþû*ê¿¡…ö¬fL€ 0�ƒH€ Ô6Å�ûæ\L�Ÿè±ü…x|Âú˜‡å§½KíÅkÿ’0N5—dØx4ââΤxÐ’ÚÉÕ›:]ƒ+È£¸Oé,òP<Ñ?H˜ñ(|ä�9Â8ÝØðœŽ 0{’Aýºð&ŠrbÒ•TÖ6P‹Ê��³5 Ô&Ëhªñ„¨¶ï‰â¤ü¨Ý¶®ùƒûÞãS–4’‡w‚j]}l1®{#/þùÀà <}Ù.<³p Dx­”’>�ƒí[ŸE“‡B¤» +÷Xç@ óD)üã^­‰ÅÇ“æ›@eÞtûOô›ŸKô¤×i?¦[^®GòØ H‹-ðuòÂÂû¸.Šùì¦Ð3Nûì©}›nxÈq*úüüÚ2&›5+Ú3¢Ä|§V[7?Œ}Σ0%¾Ð¾/±ÌÞ½£ò4̘ÑÒ…³æð¬`L€ 0&pÐl_uŠ��ã¿ÛJ'e©¹W¢¬ì:TT8Ú´òbëš'Ñëø±þùÉ*ÖíоªæÅòO¿§¢xqbL€ 0�L€ ÔøÃá©1�6#�”ô2,ëó|}zÁbìÜ:OMØÑfý·¶£G¿}ñd,&[Õ&s/Üþn òº/%ãQÀØn½Tmz=�ز¶;„!UJ·|ð ò&C8¹wª$±p¢0œÉ½·Ã«m\µ …áRÙD�úïošüá 躦¨6onz½ÕžéÍMo[uWÑyvöeôþœê8jB/ÎøüBl¤“ÿÿ\nSTÙ»ódåÏUÈ IÉ“!^ZÉë­'¯Sº1!c›ís¾ÓjÊòCD`òèItóè>”ôø?ߢ£ZÓp‘ÁY+Õ–ä�ÓR]lŒô†Ñ�&Ðb�ó(2P‹',2²z‘÷}OºáÔ ±ô;öz›)¤ÈJª»O�'og_¬w©Ç–·#Êcý•$O¬°ïàÔÓ£_”¿|u3/ú ®çÑHH9} ÚcÑL1Ýk¶½�Wn¨jy\#*�’ãr‘?ð:ÄšÒálÚ„M?½„ Ë¢ß8ˆÚ!+™`L@•ÀÞ_ç’�:  œ—™{Ž XU_ªÖ?ØÂä¬tîòw IDAT¡ªCîXû_U9 ™`Là°$ ]™–“çI3&ÐJS~t’Á7tCJx,ÖÎîB ”z ‰ ™×¾�øÌ4ínÄK׉Åö"Óµ/& tHôGéÜží䑘£lf8R*#K5»ÿŒòÓߌPÜýáñèRðC„\lX“‹ç/Ý.U·Ï-ª¢ÅóTu«~އ0Zíkzváb2¼©Ÿxoü£Ï^´®U]ÞõÉqÈÉ�µî†õÅxþâ�QëåMï¡ hŽÏKÚíü“†õŒ0>½`)Dx•}M^¯ »·�ýŠÏ7j&……8Ýß}Î"~uMõxðŒOI¶�ü¾N„ëï7�–~Ë›*Ëð̄ժý_óV*z÷ Iv*²eKZÄs7ÒÓ/Brjyä1!¬gñ�Ú³k"�S&½FžÓ—wÔV¿Ÿ>¤»9X©Ý3: ½èOè:(p^/;_¨Ýþ:¾zîŠvŸÀ˜`�€ºãAžbL Ý \?Û¤0N‹u1°öï·_cOz% ÷|4�|u?ž]ø ^øÉã3<o÷mïþXrÁPv/ ×.z„?ZŠÕ)�Óu{há’UüP©Çïk“a³~­¹OW_7WµÎ#ã�T}!BÑ >‰Œ°-$«UûQÂøÔÜZGªo{¿§¦qÚíÞÒjã´èÙ´|…W¿9 �\X4“>è&[zåöé%^îÝzV’G(…ð ÃP¬¾;îø �¢®(lØ:ŠxµùCTVdâásgûnŽ4{jv_ІºPµy¸oqÅÏŸ1§#€w �ÖM¨à]¡§‚²@æ_Ú‹ «R!¾ Z)7û ô,­CZæ´�Ó¢qó-£Ët<ù�¸±!»zÕ€ä6C²_«òU³Û—DiɪƒEÀœÔÛ?”øHé£3¬¡y&À˜@%‹þ§ £qà) 6œåÖÕÏ„N¿è¿Ñ”8yCÒÛp„ÖuÕ£G’oOüÛ=÷ðö�qZ4üg×ï|‡ŒÓW¶®C®Å˜`‡ ��Gåá2cž'`ûFÀ[G'—Ò¢v2cL\Üêè—VwvÓë)(,]JËè†Ü„”¿RŸ Uû­\2R“�AJæcÐSìÖh©®ö!Ü;fª¬Š0.Ÿ‹'¿ÿfË92¹2«‡FÜW ÐôõãHL~TÙ P2›„7ð÷ª:IhkþN3žu¢ESBa ¤6Ѷ™YÏkª÷Vߢ©SSoøò¡· -cššÚ'ÞßÅ]ÿÀÓóçÒâ–ÓèF…�ŒÌòbî�ø„k‘c¤Ð TUö= ½Î½¾öò·—&4âÒ7{ $ïN$%Ý#W)ò^¯M /aïîâ©‹þPèüüÿSȸp8ˆnެ׾$öîùËkqý Ñsx tŒø¾ÉºŒ5tAò°ïcH©Ì‰…ïšÞ�ixoËkÇ›2åEEÞa×>.Šã !Þ gôhDòj{Û<‰¢˜�øä� Öºße.0&À: �ÒaEÈtÒ o£puz¤?‰¹/ÝѦ»¿ú‹Õè}R=tzÿº0¢óÂÞ°ué¿Út©³Q×<ŽXct† Ý•Hã&À”Ð_1~Äÿ?�ÔT½„o^øuÓÊ“i@Þ2&À˜@G'ÀêŽþ ñü˜À�H4Ðbd*çpñ Q×S"ºŸ4ÝBŽ9°è{Ãa_�§'Túê¤å_Ù¢qZT´X. wa¤ŽLS/©"aÆOÿǬõyçFÔ Ìµ©áµ•lÛt º•j¨#<#·©¶­¯™¥m Ž?…Ú�÷H”dk^©©5Y†“n¦¦>\qû;¹dh„·WRyóîÖ÷l¾ä8O½žBsô ŠÔ2FŠ™�‘9R¡òÙU¾'Ûxâ¢íxòbEu_á¿—5Ñö^üåõGÐ5k<Œ†b24zèëæ…Ç]‹ÆÚÏñä…ÈÃU¥ãÈîXr˜?]ûé+úä1c‚£Å=™zƒÏ-ÚDǀ¨užGs㺡Gá>îS?fÈzHÉ7K&Ê$êYƒžŽ‹Éá\§ª‹Ífd¼­Ðy‹(²ûØzØ­ß¡¹y.= ð%ž›X¡¨Ã…ý#`NÇÔPj®WÞà i8ǘ8òOâÌ!ç"»ôQÌÊðr™E·ÓßI¯¶<¿òb×åÈ.y6³KÏ)ÿï6‡ºl #;Ø¥éûNBƒÃú3’. öºm¨ªø;¿õFXE.2&À˜ÀB€ ÔGÈÉ»Á4 ˜ã)TƒJ2š†áÎwŠ_ˆ8ãÑäE{2ŒæQdL4úkÓÉ¢Ã6—ò£|eW3yª¯å§è]§K"ïH„J+͘àFÉgÿ@VÖ­*°;wªêDœèg­¦‘a'DƒExFþ¦ÚvgÓïPžâ‡ªM£C�\ãî­Ù`Õ’Ù2–Ä“ÕTª²ô¼§UåBhµ¾±0¡Ze–CG\ä'õ9 ……¿k.©Ö��…]øªÕT_�òÓþ·ªjC=ùQüoH Ë=%îƒp:¢¤î¥P ¿—S=ö´�·)ô�rø�Ž?›6á™ó7Éš¾‰?ÿRÒåOVÈÔ”5›£Ü¼’U5ÉK›ÆPûj;ò1C�’T!�¡>Ä1Oxo›-g!5¸ëýqxìõp@â7»-'¹ÛÝŠßnhÎù ÄDdluÛ`Làˆ' Âj ýâRµÏKªg· ‡m¿½¥0Pë�(Ýk¾Q¿q{À“Pû;†é­¿ý‹V¿ ,sð�Ü`L€ tXÚ^PvÊ<1&Àö‰€Ñ4D³~n�JääÌCrúÓ0‘�5hœ´0šGâªi_I·üTï8»vŒ�Ûý»fŸBaÉÓ~|^j¸mÇ)«±%On�ÔXû‚†0šiê„!U,Ä'' UqlÅâoÑ’ˆ½+éU½Î$bÄnVÕÙ¶�ñ;_¦’�o2‰XÒÚI,tè3P«T±Ä &itµÍ>Ïo VioŽëERuã”Týúé™´ ᥪŸ�¨#<Ÿç•ûo €>ûëÞLCfæªñwct hî'X/–ºWlŸ½H<’y�ïU>݈F›ÍæÄÙ¼HØ`�0l+s� h0›ä?>ª$ûý9Ýk5Z)Åâiƒh?qÐT½EÙ@V²;*e%eÖëÑ-$¯©×÷“ƒy:|ÑMí>Ä1ñÚéW¢´Xi ö§©±@álR¿9ç°ÕѤ€'ÀËçu-F¦²WˆÝ�[qÚõIÈévRsËÉ€�ã[¸TZ¼Ô·¥zÞ\ —Ö™-9Á…më&â½ûg�ôÈIÆÔlÁE$·»^¼ûòüƘ8 ”•áÎ.‚§¶ë–iŸ+þ6o"Ž:{œ¶õ0Æõ�ØU±&C{¦Ý˾"uh„˜ŽÊ=?/û6$lƒÜƵظ"yCÒkõ`ó¯âæ°úSŠm0wÁ˜`Ÿ¨;þgÄ3쌄ñÆ>° IAÂO7"¦Ø¨ˆùúì⵨Ùþwèù^ÕÈè°®n6‡ý{Tþq2+÷ªö­“ÆÆÙ~uÀجKeSœðb~"(ÒÊX¿Ð4PÇ™�¢fêa@| ¬-ÙE«~gEtcƤg-xîfu#¾Ãæá)æ°‚˜ã„gò›}ÊŽæŸrWK&˱$^¨¦ Êr3 ŽÊ21Ðãáo‚…¼¤ ?ô‘)U²ºVmÊ} ×µ.ü�Ê0,bA&ßT ÿí“ÈiÕ6,; ÌÆB#ÒäYÞíÞBOnhÇ™ôz›eµ•Y·+ä}¬Ô„J"l‘飖\®JKfQµÀKñ‚Š›ïP"Þšv©6|û®½øKy*r¼J^ÓçùˆšÔƇ’†íÚÿ ÄŠøØ”ÆhÉ -õíÛŠ&bŠ¢@û‘W2WO›‰iWŸC¡8üS­� O¶:àò œgL€ tH: å,œsKo|òLënNº nFüÅL,HH)€›¼å{.½¥eþÏ. ½Að­õã cp×ÁQô XYdͧ^R�)K]>£±LÌfYS(¿^ÔVZp0!ñ:_aCǧæ’|}pµŒ0¤?§ª#yݬ¹hŸÃþ«Z—>™%ެ*P¿8‹=>sê ~½ ‹b 7�±?å~”"7)›È0X±|öÅÐ}ž“e¶í¼S&„ :qñ§ëEˈÛW°‘|³íg¸jþ@�cOÔ°ÑúchKzCÀx(YR¥Î©,Âï´& 5«Ùlk4uB¡�²¸¢Ë®~cJÞ¡É$»ÃvܲەO£ÈÛIùÔ½& X*)·.WËrÑ‹&_|d“¬ó7qù³ÿ@FÁÔ ×´d˜k‘âRDˆ�Ö¥S¯-@÷‚¯ÈÐQüÛ�Pˆî|ù@Æ’x"Ì%'"»PÐû¼c¿hçcq‰Ã;ÒÔð‡¢Ì&À˜@G%�–+ž¦k9Å’0rH9æ.»[£²¶¦50ÇûÏW}ÿT3Ö"žlïäÁî ¢KÏǃu)yˆò¯ÒKú·ª8Ø`L -Dój‹þ¹&ÀRsoò§ÃIøNïè-)yr„qÚëõ ®ö!ò0¾M ÿoQ£»>FYõä ¯[­_¬¥jQ.ÔJ‰–ÞZ*…ÜnýÚW¶ñ’§Œxí“ð:ëFyUEÞÝPã°ÊxHçÙ�ÁSÓÉø%Ý¿O�f�´¬·�’þ/ò’¿Ù™w)깜JãõD‹"~�úÚ{±kÇlÚ\„ŸWYpã�xÜv⹸wÌT©HLʧ•¤É#VW‹™–…íî=ÕQ`ŠÅ ­}òaŠDqŸ‹)6pO:QtÃíÞI±JW¡©nž™XuºVë—HLV*¥aç©>±µùüöÇ Ïá;?zÙ¹‹ ÓeKM#¶é�’L=„„µyyôªmããP»Ÿ"úk�ÀÖ¼R³šÉ2œt35õ’ÂnŸ�¸xõÇÒÍq"Öm¥TU±ÍˆÕæ.¼££….±[ª/ÎHV³ùL<½p1y0/Á]#o"£‘ÿSºgæ©HKSHŸƒb*š}¬ÒÀîYü6÷ù½u®m´ØZµUûhvÉ &ph ä§iŽït¶Cjl´#e#¶�Î�2¹Àh …�ËEÞåiùi½‰Œã’Å5¬§sG˜$²è¥XÍZÉáÐ>&ÊÛÄ’¸ôËS zCS¾nÛ{òª²¼µ;þ‰¬nd4 Æ¢�Ï{Zê6Y]õì¸;G!¿ìS¿2Ø.P—Êb�]-kI ½©§²PÌÓ×NúËf(½œ••÷¿T4‚<ÔÃ’s�öMÁ°ª�²Ø¥<úžt?ý_™)ÌÍv87ÁÚ° ¶ú­Ø[³;W6—ð¼S¢â�fûE tH:Œ)9tþï«f§ßÕúå»Uûúí‡íЙÁÕ¼ ¦äôš´Ú^m渱Ôtr´æ>�£‰BuÐy»Ú¥sœe$Õ SÂz*§8¯S–ÐBc:s˜Æ_Ìu #’º¡«¹¹BnÅ7¸t±@[#…[¯»>øõ±œ^1ÈÊþ‚¶-'žÃNá9¬M¡¶aº¢�/¢epWTäè âÌš3s;µ= oä‹×. ”ÍNíð¢ŠÁ¨~!/t®â¦Oôd4È «a¢�-z6›´�ÎV„7>u±:Ѓ2ðÐñÆç9-nzQY€¶i{¢Ûm•‘†iѵózìQw|ÄU(ìO çªÔòz\ØøËHÌ|f~P;úo½Ðûx:>댾´8Dжb¾f2`�º,ß¾©ýìh3ñHñï£htòÆ}ì¥sUïuôÈ(¼Í¿ÓòXð£äu»ÐPýÖ|#*—¨ÿ/úkò;`~:ô?m2»]€Ôü¿A§�|r¦÷éó±ìó1ضLÜR¦Š¯VÛ`ÛÛÇU)+ø¦~Q\Ê0=îüôÑWÊ:T²Õ®��L…²ö쨘ŒÂc> vŸ^p0‚Ž5‡`ñÜà$8Ø`G*6P©Ÿìþì׈¿ŽE·cæ ÑÒãÆ1tá,å…�:5ûïÔýû3D‡osãÛ]PP8Fã1þ ãVÌXÔ-È_�ÉŸŒÂ£çÌ�h! œ�WHþ îûl.¾_‹¨# l¶�ðâŸÕ=Ÿ™°Ï,XNÆ™ARõˆmB¢ð8^!oölˆ�I³åt)»ÏÛ—&4bÊ�²!ëŠ2‰y CŒß(«ÔÉKÍ®JyQ‘·Ä�£ò$…L^°Û¿…Öü}!F¼»pÇŒ$ìÝÛ¬‘á¬Ú Ë{ ËŒ":CJ@Aq­³c‰ðNÇ|ò6¤XÑôX¿Õ±{êwFÜ\뙋Là°&`4¨„…ì‘î~“.|‡Åq!6ìéy�MfmO`ŸqWi(�ÚO½žÂ\Ðõs´d0í·´ªTzn¼öØRu“¾§”�Ø:�ÚÆe©òÆB#úÐ1&hœ¦¼ø�ÆX·k ^~Ù)U�غ�duÆ ŸaZÔ"™Ó¾>¢¾\P2ø]_Qj.×íÚtƒÂ8-tßüß:zÒätø]°ª˜§XDQôѥϭô®}|6ÚÇŒ1¡‹¯…4O�[ÜûØKçªîvË ø8�@|O(ÅèôHʺ%'8É@}©_({÷y`Ÿ@رì�-ÃÂÙNH wpŠË.ENïgÉ(I ð› KÊñ6n=>D¡æB‡¢Þ:ZP<¥ë V:-�”І|ˆŸ6“·FØ‚‰Mua†mj 7fHÍÚ}»mÑçd  #ö�. ÅK®ß·ûØ<`L€ t:‘F¥N‡€w8H@„ð� Ñbë󘦭/( cµÁ˜�ñãÉ£êK÷}r ºõÜæ7NË÷M\ìµ"eç~‹[§G­©ûñ º¸wiÖ±Û–iê„bomt�ä8ËÕöÂ�ìõø /bw令ӥáªiÕv­:íòE-щlC/:Ùn!¹´CuÄê Q>WûFšÝ¦}‚œ™÷^øÉƒ¼âZ߬˜Ås7[á Ð"ZÉíÜ„ÚÚÛ`\þC°Êž× zÇy¨ª,ÅšÊDÜxŒ·wî9åa<|Ö—xæüMlœÒâÌ‘JÀ`¬¹kNÏ&M�\Ñ\//*ò^¯⦞VÚÕGÅ`¨ìöбDXl£$q¬ ˪%·{{‹íE»Xƒ¸¨žšëw©+dÒDo¢â¿Vþ¿ë ðCÑ’Þàÿïm|IÚRÁn•<ö:ÙæœIý—8Z&¡,µõ5§ÿ¤U+_Uê¥úe�ùÈÆñ�Må´ì›TÛ¨0.…Œ=�ñÄÆÖ°ô@»<âÛ×lš ký�¡ý”}^!!=aଗƒyá��^tÒ ®G—�¢`à[èuÂ| 8£#.mÄø'8í¶wQ<Ôó Ø�3Là!Pr\.N¾áQòúý;Ò8-þZTþ^ô¦Œ9á¥`; IDAT),}ov¤YO§OÀÈaD蛚ÕÈÐUZDÝöTUYѰó}×�ãJn¿ûÚc(î“ 0&À˜ÀÁùsc·�]¿~yÑL_a¨öyQKy:A±—¼»÷ƒžˆ/œ‘û%]Ë~�“Q¯§™ŒÊ‘�ï©Í+¿p…/̆šNÈ„7qs“ð¦VO:]tCqã®Åê Ò¸ø35õ6ûÌ�NœdN4…И”ÒícÎfŸ§ÙÂ×KS')¦žn§s~òzÔHu»Õ/ˆoŸ^…MÑJ11!CVRʃÕVý~ ªw_„†º'P³ûϨÚ2›WwÁªeFL^„ûNyš>¯ÐÍ„'&lƃg}„''¬¥ØÑÂ[MåJ%b0�ÛÀUÓâðÜâm˜²Ôާç/¢xñŽÜ¡ÀñDľmMršµ�7N…”ˆ’•Áy5ÝÎUвZÁ`Öö¾v:Zg5›%w2•Õ €òš±ÃZn”–çm#³èCoLòµ•÷'«­Í«åbE>«ûm¾c¾tØ—¶¢RsÝLTÌP?Ï�qÓM_’5òeee…¶y·$+½ôm ?·MÇGp/kæmħÁæC{)>Ÿ°ÏÈÞ¸>¤—åÜñŸ¦Lò¦º öÓÊJ\b‡9�’‘%8óî¹pîVß ÕÝiát/9ïJäoÙ!ã·áq~kòX`ÐÌ¢»Ðíø®Š)¤45(ÊR¡G�è× R½¶Øn[õX¨šw\úhtœ’qŽ 0&À˜@ÛP÷"j›¾¹—Ã�ÀŠyµ0å Ö‹‚²ë�‘›ÿ":` ÖÑI‰¸ëä$ñˆó¶ƒ³‹´ Ôõo%’gs>â-ý`Ž;Žæ�Š;GF>¦º?ºþùªñ……ÑtÇ–xtÜbÚo/©cpÿìK(DÇ›šÃèèÑó‚®B®f�¦Ú÷Ÿ ¤„%bk0ö*‹Ï_^‹ç—TÓþg(�’>ŠgŸµñsX,ã•fUS¤¤„Þô¾Ÿ§ƒÔ‚†ÍÇ,õðÀi$§m.Œæ1ªÚŒôIxðóõhªŸ a$é–·3�_¼Fµ¾šÐÚôz„ø?— �r±™xqbL@�@zö `8£iXd•À1D(²²ßÅcß~ Š+·½®ùD�%¡0²Ÿ€ÄÕÂ"ƒzs®f['…Çh)%ÄgkVq8£Ç¥†zÃ@)±�zCô8Т�™ö_n”–ò˜è°F?®-Á1E;nC$ñ1¸›ÕC9�v½ ‰—úëJŸ—dp¡r}Í,_Úoº��SSô#õ¡Ýp¿4æ¤ßÀÖÚŠýêç€ÑÑEîx˜’R¡÷¸a�±ÂÓìÀ†Ä¦{uÑÿÞ£�,okîwU]M…+þæ¤cBŸµJM-l•ª,bš@×~©(û*³D(9õä;yèb©‡'¦Œ<ã2дgÖÍW¿=�ù,y«*Ðü\ýgÓÊÍ%A£´8?“¼©ãã�¦zßÈPšmEŒÑæ>£—pyë�…q)]0 {8%qA.¥ß¾S&øb?ÅÝdžÅRç´ÝµíÆeUV’•œÎ5´HálòT_«}öl¦øÓ­ó€—uÃY&Àˆ€Ã¾7:qXÇeÚ ¥¾—àQß0—ÞCÆÖ?¿‰©�ÀíÜ@×ú)¤SONŠå-b»iª=.éÿK³ L¦^šJ‡m�¦NRLzÖ"e#¶nwËrÑÈh.ó?•DÌ$ã´ÏØLöMýÊFK�àÿ`} ÓØ´U^5˜7žd |Lþ�‹ Rüêú=?ë†g†�·ÐxÊsEÉ0.ÿ?ow å¸Ä¡ÒWÊ÷ݲ֫{ýÈjm»›…¼’qÈìq/ ¦zÖ7xfáŸ!Fµ �–!ô>_Uýâe5˜B±‘áDDM:A�‰ÍÖ40K�56}©i uöô¦‘�™×5nBÐwPœ ËxZþD‚[éµïɺw ¼–vb4�HûE©Ä…½æ­Ttëú¦þ4ñ‰Á&š£ù¤ îéËšðè·/Òw2Žâ®~kÓJØ)þmòêZâýâ Ø g˜h‘@âê5Ø‚:ÞeSx‰BßqÏh@O{ ƒ>¶Øß^vq-u¨ [Ô.9}šï˜kÒº=ço™�x=yawõyaï®ùÿ¼˜Ž/²¤7÷–•ö=kŒžiêÉéÞ¬®�KóÓä%EÞéüEQÖ*X(Dˆøõ…ÎÇ}‘¼¼Ö�ZÍ|r /D]_¢¶¾Ã+„'µÓµ' Pn“Å eJ²v~�ÿ½dÈ/(zu ÍËaoZWó¸{º=�Œ»=áú8køÿOL ÙêÆiš¸uï\Ì|ìʹƒ»±~½ë׿ �ÃA ÎÊå™�}O? «fkßð“êµàœwþyÐëÕÿ»~ [6ÌöÇE+…9 7P[,âÄy‡Ôe»ow¬z]a ÖÓM¼ÒEtckc»�Í0&À˜@§!ÀêŽøQŸxÕÓÈ(ºÅ-)]PÒDeY_>£H„‘h/5:7ÏEW²HÎò­%þä¨èF�owòöNLî‹ø¤a6O^cC¨/=jª¯Áãã¦QÇêW@±ú®¾�õí/½I[i@�·µ5·!uC•$ÚïmZ潪mÝnñ¬úüDƒêW §`¡j[!LJú½«¨Å~;ç£i„¨‘ööJ'™öE¤»9ä•Ñ8Š ³’ jÏ RÆ/}3ÿ%Ãᆭ”Md ï«Ýª|öÅÐ}ž“e¶í¼Sa:2SÆR é1Ú ÿÛÚü1öT—+êN%sbL = øoøˆ‹`ñZA¯OdÃÅà/¯›�lJ¦c|6­ a¤ã·Ë¹O] Ž¡¡äqý�X}Ï�@ÊÉÿØè�«Ï£V×BxaÇxÅMÈ祚¾­A¯q#m\üe¸~öqíµ’Yã¸+ê»mb£§8s(ݦ4š»Óù[ôÆ­‰nÜÿOuþ¿B©ìÔE÷ˆ3Æü)64®ø§íu.õãw|ÚŸÞWOÔ§ºâïW¾5YJéx\ŠDÉþ.ô²½‘B‰ÈDhÚ;]^l“|шÀ�giŽÔkc�ºá½-ì=ªýƬ¢ÑBÝÉwœ¤aÅP½@®tÄ2PÇRIys´ÿéC)´J)b¨o�ÎLj…pÙMÞ™{`³ÖÂå ÿN[#Ÿ¬Ø¸‚òaí#j• †ntÓXáI|OiGbvEÿ~‰9x\ä�­� õ  å�ªÌ9&pè ”Žî…Þ'Íò¦¥Ù¤÷8X𲯸ò‹Ÿ‘Û’²ÆKêà¶v»xZ/dœ*(#¼š“ þ‡”ìKäâ`¾ l2¨Ï –53ËœX“4 }O[¥ZE»û�x… Ô}z{=YfËŽ‰—³T{i[áºE[Ñ{,=í(<¹Ç„œÒkÈ@}GÛĽ1&À˜@g&ÀêŽøé[’#ã‹‹O_m"Co‰]„�úNŸ¸=Þæýg'�!O_ró’B{ø<¾hl�<�ŸdÁŒç”¡þRnöyXÎ ÎSÌÍ7g±¥LzÖ¿pÛû{ðÔ½j÷Ü�LŠejäß;©�àñ‹7ú…òNWçæÏWíÁÙÂb[¦•Kà-Pñ‚ôf‰»ås/AùHu3«u¶¦�:!¡˜zÑ6P7«yÉIp¨¥‰âeª%ahzöÔ5ä1^êW‹LY»îiãHð?µ¦Qe÷ßï¥ÔjÈÈM– Ù…¬Ô(-ë-)‹ìL.à_ÙfSz¨{éÂØiŸOî_Áf[ +=ê¿§~§fÛ`§œaLàð~Ÿ6_³~ÑœÇúuÃií‚‚H/l½8ÞQR9vPä¿Nö«K–•”YaÜî‘ÙŒ{>�‡ÇÍó)ÿñN.zv'ÃqŒ™Ž/ä…fO·¨'»«V]!“ %²’2ë²ÿ¡¨”D«XCŽÏãY2JûþW©®0Û– –êI´uÒ:’±Xòžµ…lÎÔÐ#ìòÌ GùŠâp/7JË�Ô¢‚БSÞ§ J¾sCþ‰Ôíø¯_Ù†ï ±É¾¿%ß8�ùlLilÃB]‰Çüû�YCÆØ0ƒ®œUw;«iÿ�TϿ؂PË“˜kQ‘"¾¬”úŸÚ½G-–Šê[Ì¡ôSSí<Ôm›ŽšÍß¡âúÎ*h«w)†rí´~½úwDÙ‚îšÈ“l‡[òÀ–7ã<8øb0òï ³û½C§æ ñß@-”ë?ºý.¨0b{œ5¨ú-ú�·Šù7ḠÈ@-ý.d¿ãÄÌqÈô|Ž˜„L°zn²KŸ ØïwȤþ¬è2©ËÅ0æyüòÅRØ›7FÔ1ŽGŠvl«˜Œ¢ÁïGH+¼™ò“é¥~ݬÈ&À˜`­#ÀêÖq:¸µ¶þú(z�xJðäG:³�ç�šLÅôRzíˆzm“¼ô¸ï—HHë3P‹E¥—¸XMìšCÃlP •œ?–ø�q:8_ÊóÔ"³ËKôþ>½dgv�ž +f`Y·Yèßm!-Œf¬§NjêwjØæúˆ)Vÿ ÄÆªxúɆÆÞ'G~F 6ž%“*³{·k{B77-Frв¾¯D8Œ¦A”Õ¾°µ64(ÊÁ’Æž¡n�šßARê¡ö }Jæ �ñvDˆŒIÓÓ�–zî=¥<ÔŽr÷Ì<iéOPˆŽ�¾ï‡ÊGéï[öëcÅwÆŸž<¿ “?9.ûz4b+^š ¼ÿd•¥Š¼eLà°'ð⟅¬x­ ×'²ý‰ôÂ6‘§µÛÛ€m›#o˜56¼‰4ËèPû°C†o`ŠëGúy¾:iI£É¸H†E:Ω.òê …Å_â±yó阴 �uoÓ¢¬u2­?k0 Ž�I'…j)5Ä#5P)h ¦¹‰ÿVoŒ3fh_èW ½¨žH¾ í»o÷©àqU“4 †¯&y¥ò|f¡•ŒÒ¾ª¢ÅZݰ|L ]}kNXâP~(yÃÓ éÅ8’AÜWŒik\ˆ�ÿ"0BÛmŒñ]ƒúûôºÉè;Oû?mG1iûœó›bÑ/y_vëZ¬ûâTTÌ…})A¡×ºŽA6Å^5P˜)9W+ŒÓBîv„ŒÕR½–¶ñ)# ^¹}€ž'¬Æï‹&¢â‹_Zj¦Ðwéð@WHý‡-ú“aþZô 7ØËújÙ[V™³Là` µzN?åC$¤“§´JŠO¥ë*Ya;LïõEÁØ—É|)vü>M??‹JònŽ–¶.݃=Ç<ƒtzÒÕ—|ÉP‹‚n§“�Z\ß´œ¾ý×Ý8÷Á‰t<)ðÓ©‰ü(ÞýÄ/àªêB¡ì"�VbMj-�y 56¯ùŒ Ô¡tûïC±ê3í'JCµ9ǘ`L EêÆ¹›q…v%°êóïÉ�X“Þˆ¢¡ÿB|êñ¾ñÄ9�”|yzËžB«F×Hâ6ß6ÕÍBRúX¬Lñ(²xѸâe G‚à ÔÕÍ+�㛜ÿS:ãò‰dò˜Ø Üôf)ž¿Lx )“ÿ‘ò&<5ß®TÚ¿|•¸Z©ÚŸ’™šÍôºBl!57¾Õ@­×§S‘'•¢ÛZð$dªUd¶ü?{×Eµ½¿l²-ÙÝôBHH¡wDEÄ.Xž˳ySßǽ_®†Ñ2FÃDÁ#Ú?æn½m¥J§£Ôócä©f¢¢†Ð&ôPÔDúÚ™÷®{=ý‡Ò÷c"ÚZÉ['ùm¿ƒ=ŒB[Ë>Õ¶ÅŠ6ƒûw‡ý†2â—½�Ä’“òmö î‚ÚÞ� üö²ïl©÷4+·©®–X¬~¦Ã†K!yóv,|Ž‘ lûÚ]éј2KGÞñˆ2¦Òâ’Ép’zt4?Ù@ÞÚìá´ØšÄì³Ñq=<½»[onøó[T6OŸð("#éÁ…Bjk.Å‚R�üaÁ¦üý${�¶0öòÈò͉t(^}C@+-Må²öô10èôµHï÷–¼xcئqfõ7 šê|ÿê ’6ûXÙ¢�ÂóÀV0ä"Ž@g!@Dôèž“�1äyúß» –ã£pÎÉ+¡7oW/láÄM›f’ ÛB§ÜáÉHz)âÒ¯ñ)û} ¦šH8ô)*åؼx<†ž½CñÛ4R‡ŒÉïSÈÅ�Œ#é÷àP§²õ�¨ŸôLÉ縻¦sÏðÔSõPxŽG€#pt"À ê#ósubç²mÂЪ«'ã¤KÜ÷ žvc+¦K6JpðêæÚU)-õœfƒacˆ‰=�†±HŠpüè+fÏ»žlŒˆMø'-¨•å®g6¢¦'ŸòO’\'JŽ ‹BJIbk·ï¢²ßlЭÕî}$»iWIŒðÈ£8Úyyêž[ÍVòHQi€Äz#£ 7+*´Z+|€ø�ŽA?YÑF&ô‚IR‰}“í3™š¡¶²îûy•§ �îddõ¦±)$“…yŸˆµ‹Bq,‚Á8Õ«ÉCtx¡àŽGà "0ç|FƲíA¡—éótèa·Ù‹ÖÖ6¼xÅnoïQ«ó±§9Ä"�^m_Æép““‰iÉÈdßåA<°Ù÷1}‡¦PhªÇúIXàq×ÞwÃMYÂï'#§E’šÙÃ_Gëz¡µ]Œ6Ý7 {!$‡GÙÞºGÍŒmÔ�›¤~O=¶ì§TC¤³rr ÝBUŒheÛ¡IÆØ¾îŽ<˜65¬îôŽsŽOEbÖlÕv‹×\FurrZ®ìÄo|ŠÜÜH1 «¿úU^M¥Â•V =«Q†,y�ˉ†Ê¯„\CáL¢Éc:XJ …‡Nyë¾]LÍ[eRðn«c!‚§`ØmMáx`oŸ×r:Š@¿Ñ‰Hq3’zÞOß—îû×nýó€“pæØ…rrš¾Û„$™+ïߦþ?ïÑV9D`ÈÔÑè1ü9DÇŽõéˆ}ø$BŽ-Ș{|}”øÕ(·-Û‰Ô>³)ÜÇSŠ –Ô‹ceëõÌ æÐ§Ý÷aÀd"¨=çßl ý½rèGÉ{äp8�.ŠÀ±LPG!eP"ŒDRÖÛªP]h="?Cö´ºaÒ×0'Ÿ%ŒÏKN³Z’˜Ò†Ò¾óoàD0jv¯ 7ЬOÏÆêMæI´w¢>;>5ÃãmfÞëèêz…–Biˆ Ìžåig¶üÓónÆü¼V±VvŒˆ X”^CwUkË ™Î�´Zºa’ê2˜w•:ù_m-Ez{8Õnü) Þõmxae%*I-DhL˜õ’soaä@`ªÁoBarÜÐ8/Ð@"aý>öÃXbï•HÃË6Úä7áUûo$~$Õ›ÑPA!:nj¤†^ó\‹#Ààt�ù3ØoH¥g“7ÑþE{Âé(Çö–¥BC­-5òƒ”´ߟmìѪµþgÚo´ùîZ˜ãþ ‡}'+ž×²Ùo}]Š¿qìh·‹³€�ÑÔÓóê9H¾nímêdH‹m=ô1ô@ÙÓ';Š¡>"„µbE@—‡\mê& «Õ«¼#Ì~­ª•�¼àÿüüÕzi PX(õ:—Ö%k¯CΘï}Bú¼v®¾«>ùŸOFÞ cû_†Ìao+ÿ|½O^Lu ÙH>p_ ²\L\¦¬,-Øj·I‹Šy¯6ëŠ]’d Ë[bÀ³�N@ Ïé=Ñû¸ç`J"RÔ/Å$LÀ´{#:~‚·Æå°£d݈N:‰=n‡ËÑŠ�ž…‚Ï{uÂËD`Äy§ 1—£t�sõ`md¿‘êû‚©Èê~}ûYœóÐLèèÍ ÅÄž`ú¥-»G9ô‰ÅÎ6§\kÅ6üõ#§ƒ=Ì;ôãã=r8Ž@—FàØ#¨“¦aà)saI»PöÉÕ•ÍÇ/¯\L2§L~$ön}}=µ8á¾�v±I'‘èQpdq£³3àÐéé]j*vcË�Uzj‚ïck1Šún¢Ù‘Yžm:Ãñ¬D›òMÓ»y͸sÀåHMÿÖ­æÑ¦ƒ÷¾'gÈ)TZÂD)225@ÖÖÂâ—vN²;ê‚6dHLõ¿¨ê0²÷Å?$ %2(XòÀ�zwYeßÔô-bb.W¬Õ&³›Qe�¸ãoRc—³[•±”ê­«~cÍ×"RÃú�öbTV\Œ'Ï—{I<9c7³�'ŽG€#Ð^ļy }«x`‹ <*œºFrÓ›ø:ýæÑ∑¾ï\ÿ_Nö›j‰�…‡ö@³m#*ʾÂÛ³öÊZÖû{;e!>H+�¾ð™67üÔì§ÉÛ/e„—‘(ÆÈÙ³ûàÿž NŽûZ;¸9ƒe´0Haœ4`›µ°“;Ô�¦úÚÚ}Ržñìy%b-m'’ƒÁP8[m¨¯ÙŠõ_ÿ.o•âÝþVðNÒ™(öôKŠ]Gj“È[[Gd¸òCkiƒS/iQ–o²ËÊJ…õÀVj“Ë8á"ÀîYXØ 1�œ~&rG/‹ŠG)9ÍÖ}•�m+(´>AŸ‘�ÃŒ:„ˆ+íß0óÖî;å'ŠÇOóm–ü¾\ÎVÔ•ÏC\{Û"0%eß ŒÌÂî׉õß�†ã.ØؘŠD©î£bÒi╟}Úimñ†8ŽG€# AàØ"¨sFÅàiÊglÚt šö 6.\ ÁçÈÈ6ì-p„ݱ±$)“|¦ ’í(ÛqÉ#�Ñ÷6ah‘P�Ç�¹»ÖÍÀò÷6ÉÌ ´`Ûçk)Öò0¡[¡ RÛú[žå©{ŸÇl^ W·jòÂ|~½7žB_t �PV™T�ˆ¼>Ûì¡=€ÏCAØ*,*¥Pᙢ¶¿¨+P�½m yÌ){<8œÌ£X=µ6ý¢JPL}È0� ¾ãã$Z`’…TYy æÏíÉÀ¼ “_é…Œþ#Æ|3}®:Yk,TGKó"Øê ¦á¼(Ñ2^àp8Çí÷ÀîA¿ ¥xúÂí^|œöˆ¤…ýû ¤#ý!J×�<­ÿ�rŒs9õ$yAf"Ä¿öè2ÂDâÔx¦ÌzØ–Cf†Ú²�—z—[Èì™-+±N)“’ueÂ�sÌLNŠjÎ�:`ø´ÚJ:µ«�gô¤·ºTÞž",êöÿÔ©ý­ýê7j�mÁÓžÕ¸ jµúh6 ƒ ¶ Tn�ÎÍVšüŠ1gúìÙE®Oj­ï¼ù—Ø&?rØE6òüñÈþ:­mÓöݱuù^§½Á»Åä¹.½ ¸zä5%¯yÈi·`[{³¦}iÄY' ×¸_½aDDk{ë>”l¸EK±ke9‰]˜t;¼$µtx,fÓñ=ÏÁÊ0Kd}ìZY†äž—"kØÇb—²ÿ?ŸÐ�‹P Ïä¯ÉËŽG€#Àè2€]fèíhúOT&öXSl®“”u)í�<‚zgAF\ØŠˆH�o²BfcŽÒ’G½"ê~J¯Ái7Þ„n}_ ÐáæNzsAê‚‘Á4ÇmDdK,ý4�ô$»¦†oaŒ!‚šõÉ6rÕó¦´ ÒÜ,Ñ–gÙÍý]ƒnDJº;623“xÔNÀ�Åã?“¿F�—§ìfo-–wp¥òª–¢MWRõì`*´hÖZA-›��m»ƒ¯®ew IDATÚ65¯E¼ŠFbâËÈûöa4ÖýAÁ¬É;ÎeBlÜ5Ve–¢E]íýxôÌyŠuJÂWob“þ;(Æö�¨ÊM‡AgGC[  -¡\ë”,¹Œ#ÀàpÜ„öÀfz…ÛÆ Ö’It–DgJ‹-ž€¨È¡ö{È~>¼¿¯TˆÐøý P½6ŠÂ^1]¶£ä9ÆZ"·‡žfCbú|xO¾P/îFn‚ÕQIÜIB?Âo05Ïz`mX’nÀÏãý=!š–cî�€�0.ÏøÚªÃã+œA[‡+«±N)ÕTltgñ¾hm-Ž»ˆ>£¨$Åžõ.šÿ!øCofh4§hÏ„®²às¦à�íÁ…](õ5ÅL…'Ž@§!ÐoB ¿P ¦…FézKÎ�FõBqÍ‚_нÿ�«ýTö¥èëW¼.}!×PCsæHC& BîÉ�¡K6]�ßÞ{“Z–w\¶ýu� –KÝÈö:VÎÿ’ á¿™»ê“O��qÌ’p&,ì�½¥Ë(Ù™EFee^àp8ŽÀQ€À±CPgdÐêóún�ŸMºéOHN‡º'p açJrsõh0[`¨©GQQs@ã ÕßÀ’|ž Ç+| 9Žñ :ã;Š ÜW¸Á`º"™Ìævl±Cñ&¸×¸/ˆ ¦×iC¤¦†ß‘æ¶c}zÛ£|tÌ ²V'¨YÓ5U �ÜÍN}ÓõÆì™PعÛJ�»€o1©/ P¾6m e>�̽:£A54kš½Ž=ëC æ^¦~]8�rb]’ËeÇÜéÁ=7ê­E¢zÀ‘Å1MH¢‰ªò½ªL¿¦ê6<4ùE™,Ü‚Û;°D®~½¼ÈKŽG€#Ðq^¹’‘¬lcop}%i(3ßÑ#VK!—Òè÷›ìÈÞ´Èb=jj>”è¹³ uï#Ñ4ÁË‘x½½¿§MƒI9_f˾ç/x`zY-üô d û-¦Œ*„ŽI™�ãú×F¢jÏó(µ­ÁŠç›dm œ®CNfÄu;—HžŒ×¯KõJ´ŒÌ¬]3Èuœ;1„IbTðPY‚A;v±i„_�[ßysŒ Ý(Vµ %#¨=Ÿ«¢²ŠPÃ>åTT†vü�y`+÷Ì¥"pê?FJÏ|ž¯“¸ôóIæ&¨YåÂ9l�n-8$—ftí®,\i…Í~.N¼¨Þý½ç³öæbS¹}¯·ÜžÌ˜~ÓÉI;0®s;ŪÍo¸N§7\5ì ‡À”œ›‡s½†¾_�XðUï°bR ‹¯>äG´{ŸFúúpÚ•d|<Çàp8�.‡ÝØÖ¤EZn2²ÇCÿÓOG�Á=âhì¨Øñ¸·}‘…¿�M+.÷uü¨ÅÉ7¼ˆAçí Å§SÞ2Ëí>L¤éû½Ë¥õíÍ7Ö'×- O`ÖKzÕfµ:Éë´’“*/yHÕF¬`ñ¢›´½Éé¬FmÕ?±c{'§Û ×çp8]�ÿÞº/\þ ž¼` …uŠÄ–?ôØQ�ŒÂU¹Ø¾& ß¿JõìÞý×k(ùk<œ´ ®˜¼s ö»îÒDQ)B,�Žq^òEZo2÷µ;í¨7÷ð‚�«¹�æ=�œߤc}°“NP”uZß :­†Ÿ2†P|ÛaS‡aà”v®7rÇg y ‰zÒ”ºt9‰4c±µ­ÔŽÊðmÖß•š�¨v@ƒ\pì"@DôhZäðüG·aäYãÜ8Ð9眹RNN³ï—Kp¸öذoóíªJºè¾HIÔ:�2®p[±ÿ!ÉfI¤µï÷£š’VOá� YÞ}ŒšJrm€Ž½µsv:àŽG€#Ààz”=-Ö8’¦!9ãxÄgNFlê¹�‘âFø%�e —‡7‘ö3 Y\ñÞ}röz$÷ºN'šm…¨Øù·þŽ’ùë¬! ª EÏ㳡�Ë¢ÅÓ¡3§ÃÙR‡6Û>8]d÷�{J` 4A«)ž('I]¥‡È”Lâò™Ê¢Èi/GÑŸçÁºáO .´%ÆcÐÄ…0RÜ2¯®„¤f²ø4æmð¡bŸ¢p>½ê;d y�³‘¦(moŠc¬¡-xŒµ7®¯Ã¿ø1¦ËÜæâ¸=íÅ'ÿ‹ä÷6íˆ`7lòĈÙPýÈ-B—žœ±/¬²Rø÷«ÅþtÓØmyÖ»fÐò;¿¼EWÐÄ4ð¨¹e žý[±SŠå¦¦Eªq¥¥Ng%ßAmõ›´øV!UÉÇ"ÕåyŽG€#À86˜Ÿ×J'ZéÙBŸó'þ‚ñyñÈ4]Mó±'éyœÏˆý.ÓO‹ðëâùm*IÀ~ûÅ™Bù.õ5=| ¶/g°¸T‹}µ4´¯��Ú´6‡GG8G?}—£3€G`ÔŒiÂà*˜’ÎóëIRTˆ¤šaÝܰF*QÍǤ%©ÖÙjשÖy+¤Ø~ã ×ÛÛϳô�ˆô7#)ç~ï¹Ûà<àëI˜6f! æáî/ñŸÑ©ýÛfûIäÅ¢­o }à r¡¤”’9{ ò%’ð²Æ¸“ãº_ Œ¿“"'у"¿4zú¹~•"yPו†ñ?¨b�Ð? ¦­µ"@ÆŽG€#Àèâ’kë„Æ^ù ’zÞán^œ”øM€YeR¯sAÍfDëÿïSê…m��´ä3ƒ¡É—{AAYtÎâi‹™úŠ`q¯M‰gR|ì$8Z˱ºôG™™XØe¬ÂhO�ݼyÛb2¡àÄú…½°)ßçE·�X¿ø\ö|…ó�,rÈì=›)þ,±‹ Ç–æÅozš¬c¡[ÚU$Å“mUP{VYQñ€› f}3�°czµØt-y*ߌ¹·¸c$ê)&§jmëì›UÖƒ‹þÉClÂsþÝyË&óMxjyTÍ»5´°¢žÂ�¤Ä_G‹>&ŸdÓõìtYQ´Ž‘þá¥Ö–ßqáC¿ÿæ%½sßkÈ.nítb>¼Ñq-ŽG€#À8ÚÈÏcDË´½‰snÏ 7¹¦q]�æ©B8á§™~�¼?ILÀ tl¶~�Òí÷"ÿÝZtn2Z†¸çž¾šê6tnãé ½'I¦‚„uérÙÄêh¦Ý»X8ŠÈ¸vìÙpL Ç!!óv!¤ÏŽ?ÎBÁçê!5˜mÉŠ&T�z‰™7‰MÉŽÝûß�µÿË—ÉÂ)ØÛÊ ó,\+Õ×D™0aàü˜‰Å“ŠÄøëóÈáé~©ªbž-rø×7cÁÂ�t4™âO0­¯Z ãŽG€#ÀàtqAmˆ£–ĉ¯øï–z÷±iìiôÝÞò‘Ÿ‰Àðó.Gæ°wÈSÀsó#ž£8x¿²XÜñÛ]عr»G‹-vÁ@QñD¦'÷öIû¡½Î©‘¨fíÕ•}äGN{š¥öv¯»ýÆ­ôÙErZX4‘<€'ý+‹Ÿi �Í ´Š¶išðñ1{ïçȲ–Ú‡&¨_¸¤O/]�ž¼'X”„ƒ'oÉ™D’¯¹6‚‘ÞòÔÖzp&c÷OzÏ.;“âyª/ždÐOD÷œb(ÞþI®åÝ;GáÕ›¤ äçà_jªßDOeü¥îr”.ï^Õ™]Êýp)G€#Àà‹¸ðÕs{èÄYÍ6`Ê,=šê�К¢aÒ™`×jÑÖÒg³ ­ÍV"¦ÞoR´ùxaN .ÜØR/Î�„¡øŽy@žMÍH~³ÅFÙ4$’5… Pò”õB#qÖ}ß"0Ž®Š%ëXaÆ��«(DÐ;ÍÓó¦bì›)Þf/­àb‡cöí:Ï]²7¸¢_mK##”“1ú<ª¸U¹’K9ŽG€#ÐÉ|;—½ÅĶÚNn9tszÓò¢$=b…1ÔÜPÚ¨�ö¶rDQ|mÅD�öѤbiÖ±4æâ³UÉi[ÍÏØ¾d:¶¬ª¦Æ#ˆD3¡•‹øôS�ØãjZìšÍ¥S³5<¢Þ;0ÐØ#©µíW­+Ô[l‡�=Úìí¹wªK^ó�Ón¬¶°0Eá§�Ëvcè¤Ð•çìÝûL£0Áטñï­r×Çt�å#¨ErZ|€¤§Ð$ÝúúlDûVZ€ô×÷‡¡ºÐŠ�Ø�?Ä!7W¶Øá�§Œ˜òB@35„_ÑÚCÿ0.àp8Ž@ç"à{ݱsÛ lmKþR|Ù›¾ [Ͳ@‰$##NRêܬ%#ýN�.{gÌ^‡subì-õ{ñ>áØï49Ù¬Þ»oÿ)€œn±mÁÎߦ`Í‚t¬ý<‡&a¯Ë› Y:š“¦aÀ©ê7rC ±ê7±K¶¬é¥KöW—”]¨+ÓkÀHiæì-xRÓ1Î÷¨¯úú,"§ÙÛfŒúr�fÃÆïÖã×·çb×Ê«•퇦ºðscì Êm�ÔNë „J^l�¢— £r8Ø¡ÚçõG/kü‚ÆêéSxÎE 50¥îTuzê>à‰v·¿æÿ–ÑÿÉ~á¿Szí»ov<ÍùÝ·4[WbÓûýrÚסë€Éé^cSpÂß®ÄÙmFl:}7Ȭý~¶¯;žãp8ŽÀ󱓇,9Qºnvü¹>™´WCFvÐúŽTÆeÇaÊÝÛ0þº*ô9ùg¤ôɃÞ4$ ©”>×È”ÃÏ»Œ¼dÆÉªZ›¶â»ÅC°~Ñw(.ØGO·‹°ôµP±í!·Mlüæ6Hr¯¬�`…†ŠõBBl'Ù Fæ­žj÷}éõž=§Ý!>È:á$uCOMMÝTIúÇÀŽÑ¦©!íE¶ÈaMÕ-�@x’Ü7wZOf»­ó½©Äq±ã WÕbyq j«þN±¤‰D—œ¯T�É[›¿GEùE(\�û'>�ù3Ze*ávÇVUõ˜xO/U ^Áàp8�®…€�^‰—’Ólô†ÊúN?‰ÊŸm³[ÿWi=‘AuÔ*ûÒ«øzZ”Z)µ6nDÙúF¥*A�ØOµ®¹%<¢Þ`>Î×#´$¤VɊСY”<°Å&j+B{`û:ç¹c�…s&bÞìHÌ�¥·:—È®?<¢Í¹þ¢v—÷®øÎm#^¤’t†ôèè"QQÈ:±cÕt9‰ÄûO­‹^õ(Yw ¾~lì“Ñ=GÆbàCBzÒíà‚9uqn2‡¾KoUH¾è<Ù€Í?CåÖÎÿnT>q.åp8ŽÀ!EàPÔ¾++k„µÌÊÁ'õåbR‡ú �”ë}µÐF÷Ùš%õÂ�:,I÷!/ÊõhòR¶ù1@!~Úò÷æÐbˆòXhl®ÃRl·Ki)äCí*kv s$¶¼ŸÉ@œ3b%7& ÕWlñÔŒ˜ÉivŒ c¡DæaìrR˜OŸÂXžšÈ8ZàP¯Ð«²¨f‡äµ;Ö $E›®Ç?æ™ ÓÆ[Óh»I“4×îìü<8ù-Ü6:ÅÛ’Qº{ÊJOAù¾ (-„=»ºá×�Qø×I“ñè™ó¼‹:¶»#‰AKÓÏ’’<¸r·\ƒ—8ŽG€#еˆ3ÐÃXšxç6.{ØñhÛsæk®Gs}pïÍ�§þ�¯¸ýF'4�=,#Ï?“n{ c/½XVÓo˜¬,-47l’ò  ç/«ðÌ�šw…>a¤–ÞŒ‹’™ "µØ"mAÙB�•¿¶8=cüŸ=*´¶§~8 `×þ�Iƒ„‡5' @îIÉaœ»R€Â•V¬ùþ\ZtTݛڜþbâj—”4ÁZùeàÿ mYƒoP3U•¯ûzʶ߭ZÏ*ª÷¼‚ßæ™±â£·©¤~ŽAñTfg0ò¢Z ˜°V ¤cÓ.âW+Ù:Z÷cÕGIØôý:¥j.ãp8ŽÀÑ€€Âdö�Ö¾-/Ð çg)öfIe½ï(Ö¹…:ôœ�­Z½MDÜ–na¯Mª§†jåt6�'áÌ:’¼x�Kdk�Øa&œHz’0$즊lëÊײ&’µ¥ÿEBÖ,…:ÐSþî`ñÔB¥’äÕ;ÃÝ—0f¶ólF M ìŒÓŠù5Ip 7¤&=êô9Ÿ…ü<{ ¡DÒb[Œh³›ÀºõôÍÎè4ÚK´Õ³soiÁc?Ì�%޼dž›�ö!-9< �•›Õ½�”;Að쥌?ø¤x“mbLÊi½žyéÿ 9†¶h žåp8Ž@WB@kÉôÍÅèg®Ù¶æ ß… ?ž‰‘ÓvdRìC-�E™ä+1øsÊ™ Qè3fº ½�¼Ž/ ¨Ô°åÏÀî?”½TþZü#"5çS8…FäŒ|ÙçMÍ&3~“°îÑä9‹’€>DA÷aOذºH­QT 8V’×p¢HPKúcY£1�ö¡ jö¤¾•b\ ¯|‘!³õnTzàølÊWó´q¡Å¶’fòLf¶Ò�ÚI %|�¿&Û/ˆ±\(ØÊ0£¶L–Ad_L[xi_és°ÄA­� Æs¤.—-$�`ÔEmM›UGj2ÍÄ£ß7Òg>zÝ©¨*¿�L›¯ªÏ+8ŽG€#ÐÕˆ6÷æ"¿ÔÌf>H©ð× ´ºz`Ôä? ó[d�¦3²¥Kó=çшÒw£³pW8ì-2[iÁ`‰Á“úaÃâ-R±�Ýl:wz�MLþƒ@èE´5ñÌI@95Y7(WH¥jؤ®¶´9žï¤�ŒFÎ�Ë‘Þ÷¹€0Âe-¹£ãÆaÌù…(BVXo7ìÜü†› V€‚ýǤdŽ&²;_¡6|Ѻ…è3ÎNo…ÞÏ2ÙðØñX#sò¯íÍß®Áæo/ö(ûþÇó_«PS‹@w #H!�öl¼«¿ø†;0/íðGÃ59ŽG€#pØ�LˆñXjvÖ‘WвWH”–‘¥ââpŒ¼pÎÊkA¿É+}ä4›/H&Nlõ÷aÓ6"}P¦Ê™8i1šزd1¾}b «WÏäà¡@´FwâÄaèbR½múglû}«°‹ú¢Ž6*F̆<²§ø^{¿Ä%wjßX³8�œ¦6YmNÔ–U¶ØÖ{u„1xl™Ðh:Ù[Næ•+«Ðdû,UA§¥uyغ]Iqú¼HDêÔ?ÿȨ,Ä&<ƒ~"}NQˆO|¾+�+G€#ÀàpB"`0‘ÍOš}ó��ÆPؽ¬_Üߛ֑8�Ø=áµÀ&>’­±ú;øf�µ{|ó<¥Lú ']u#RlÜÜñä±:o{©}WRo—ÌßGU¿¹n›j�XÔ»><l±-~<òè{b:&ÝòNº¤^ $§UN�=”I:åU•Z¹¸dE-ÿŠûF^%”º÷¿[AÚ^‘Õ»ŸS5ê1ôio]ö¨4œ|íÝ`1ŸÛ—|ÿãí³ C›ÂB–oHPt¶5`ßÖ»±òƒ|õð`"§Y(LNN‡�"Wáp8�£�À'·òÜê‰lµ¤œ§ØeòÀDòH6`è¤ïÈ{´¯¢Ž’pà¤/°wãh¥*‰¬ û7?ˆîƒéÕ3–ŇÀºR\èTfÿ³P¥´Óh"}$±D!&®•J$¾¬­BÁ³ÙÓ_Kc¹O1DÎZó³ïHeÁ šô=ÍÀ˜<�Jê î5ZG*)³EÅ…Å£)Ვ†’ˆÝ^,ô+Þ ±þYbÇhó”»K(‡»+¯¼ Y=(îb©¥é—0´ºŽJ^ž†ñ :æÒ°ítÖ¢¥i 懥ϕ8ŽG€#ÐU0šF»ç4`ÍÉZ‚“½�s^.üñù�´õ@Ÿ‘IHp:â»��èÄ)ˆ’†qóëÌå´SÚ—°>ŸÂHRÑÚZô�ðâº]%‘ú²lÊÔ}à«´¹eâÔÓ§¡œ8P‡M›”:D Sü1ëžJoj ý†ž¿¶ÄÍáx`ûzç¹#�!§öEÖ‰¯!:n|x£”^‹Øn×"cÌ]ö¥:d{ÿ| 7\“Ì�…Ï`Ü,È�¤Òõÿ¥û¢ÙŠMèMÈ”¾ñÝ/ó.8hN>; NUÔ?Â_Þ|„B‘Ìiw(’Ã1VÞ'G€#Ààp2‡— nØÿ“*A=bêèM,l„Jb“&6Ûg›deŒ…´Üdì/¬P1t‹Ë¶/òÔž&"<í˜S&�äÉ öʸ%d_K6Ï(Ú••¾úɆÎRumðÐn-÷¾¹j³´èÅ@ð‚N<…ê¾”×KJ�µž…ÉqÞ»H" ‚Ùšb/'Í$Ú�YkM¥Ð·8v‘¤ŽÒöÂì/) �1ãQ]ý<ž¹pe`#ɳãé_¿‡Þp†DªœmiþC¹¢‹Jm™1HP §]®V´µüŠ&"£Ù9·6nAôÖrä…ˆÞEaàÃæp8ŽtÑîùž0µ£ FS}˜^Í�„ݶ‚Jl+`ñ¤Ý1¥) ‹ -úhu&¸4:8ZëPßTOÄ\é9{Þ�3FŸ9Ë(y½8iòÌ3=¹ŽJ)í´9°Ç=Œ­ËëU4ˆìK1-I¶ÚÐ1s™¶Ú˜ÂñÀV¯8"è1.ƒÇý¦$e§ q�laCY¸±Âs¯‘Ü¡³èÿàa¿ÚÀâ&Z_§Ï;B鈚=úL#‚zžXìÐq˲í4µA5¦|ZŸÇÜí²ÁÓÿELüxʰÅé•ÿ‡©âЧüàkúñ9ŽG€#pXP&ZÕP*V«v”œVµrW¤8ƒêƒj•¬-ƈó}*â\žI¢ãNõU(ä\NÙÌŒÄÙeÙ¢F°•¥ýS|Ï‘Pnª¥£×7*Ö) köî1iF IDATeF ä0ƒg3'³‰ç­Jf‚¬±’l9í±•£tY˜™gÀ»yͪöFK«ûžGìS¢ÉDÝÒ=!D(¯ÕæÒþ8‰†r¶hçß�˜t6XæÖÖ¨¯·aЈ@<š›…7•ò†ô©kêñäÒÏaoÝŽ¦æßÉ[lš-%˜;5ðAÆÁ蟷Éàp8�#��ÓuÐÐ:ÌsZp  E[#=?ŒÉí±ÌR=‹äœ{©îQÚB‡ Ø¿éNô8Nî<ÃîXJð팠fÿY»æ µ7y!û'ñŸŽuÈþšwaÛÏlAÒ#ˆœö3/s8ŽGàØEàðÔÕÕ;BBßÖVŽmKÏÃŽ¥’® ©½È àÜ…ˆfÞ)lâá™tyOkñ™ŒyNPÓ4öæRh �q›54‰KO§×Îö*¿vVµûM¤õÉ ¼Û ±dŽ¿%>í‰ï�ÙoŒPHeŸ;¿QR �ÝYP�gúôÄÓgG­.#i¡›Ši¦”VÌo‰ӉdŽÐ¹ÉmRInvÔ% %I ×óŸ\ˆÄÔû Ó ðÏÁÿÈ> 6–"£qu×È÷,5ðŽW8k^²7/Í8ÚHªßòw�<½+ “�‘#Ààp8 �4£Y˜‹5M"ØÑ±ÛzÐú;ø ;ñólø´:$6{‘ƒz8ÛéA|­�Ò §­ýÊæ5"ƒFÎÉ—"kø§ŠÃki,–ɳ&Ð<Ë"È¢ãN�Õù†LYŒ^',C‹u#J×Lá êüU(ÜÂø™(Ç[ÔåÇ#}Bš29MCµÕüŒ¯çL¤œ�°-,lAaáÇp:Z‘=r¾â EЃ¦ŽÀÆEìÞ,xÚSüzŒTСÿu½1=)&ûNò´îP¢{žQ½ÎC|Æ5�æž-¶ÞQEñã(Yó W–êq G€#Ààp8G ‡— .ßHädŽŽ½jöçë½P!‰ß\¶£eÏž€IwÀ@±Å¼$µRs2{::YËÿ‡Ä¬›|оûhÒÒ�½…¾:I®rÇçn‚Z"³iýŸÂ Z~ãwù‘ƒ§œ„Ü%‹R #r«÷ÌÅ_ù=záœämL¯ËE÷’°i‹Ê¢… Ô'`-�?!&n²p3(%§™yzÏ÷ð÷—φ͹Ýâ¾9d^Õ©ó½D¶¼S¿’ˆæŠ“\¿¥eŸøU†W´è¨t:+ñüŒ@¯ôðZäZŽG€#Àౘ…¡ sš‡E¸ìªÚ�ØsP ‚‚àë{ˆ¦¿ô†Eä z)Ío“×t2šéíªÚÒ/°âã/D5áØÜT*+«OCÌac:ÍÖíDPÿ€p<°Ù¼�¥p<°Ýš|$"°þëÕ´â|˜“ýn¸èڨݿ€†ì#§¥ã_ùéçDü~Hëò\&ˆ%·HB9sð½DP3‡ à‰-–XÒ—Ô¿‚.5š3ô"¨™Gv{“çŸ[ ¶pc@¢vë+`÷ÆÇ±é»ªíéÐp8ŽG€#p¨8¼5`§ûiž¦xâµ{?’‘Ó>%' —]ADðz·ÈoÖÄ^cKM�AYY£ÏD!W·ï9AÍfãž¶bSû£ÊuáòÍD8¯§ƒCZzŸü3z޵Âe¯£sK%ÏŠeÈ’8Û§léú°â“×q{w¶ZŠÏMµèÁÌÚeM³rl·þ”S'¨›ê€)ÞGP‹vÌV«ë‹œ[É{ÉF1�Í´9…�sNÙ�6G&ÓwÑD¯­•¼q— ¹uÚl[QÕZ†w¯R"‡±3Yþ ÕÔð^€Œ 8ŽG€#Àèúhšhiš\ó Úµ6mèú'ÕÁ3X¿ˆ½Åø&›s«䣺¤â’Ó 7gAO‹t›,Caˆ=�Þ Ì‘©‹Sd†¯Óå&#l-y`Se4Ù¨&2 Ç[ÕžWlûâr ¹r´FŸˆ£­%›‚‡×ذô6Œ›~™xk$;3ųw‘ÃÒÍO¢ï)r‚Z\÷'¡Ç�´H -8Úî8Ì.áÍé Ú(àÞ�÷bÏÎE¼ø¢´]žçp8ŽGà� p¸ jÀZ¾ˆVxöÅÕ“žv]™º×ÉÎ)^Ÿ‘‘îW¥v„;3(Û*ûÊ<·•-),$Ç× 5LäÂÖ%gcèùEî;*�›ü‹‰½záyýR”±£ÓaæÇR 4Š5ØÁÔXó;âÓo¬±,nÊ[’O"ùÕ–m+‘ªñÙ¶L› ÞsM4Jºg‘`«AÙîsiRÛ‹ïÛŒ6k)^½‰ÿâ-� Ò)»éó"m¦óòŒCì¢Ñº°SÚç�p8ŽG€#pd!°äí½(k3!-&‡ü÷¤Pû�¬‘£q¢è†ÛÖÒö•d”ÈÎÖ#"5–ÖTI£øÔY0š{ÂÞRŽ‚/— z^l6ßR›Îyæby`ÓÆ’è�-ø®Ë ÀÂvè?„ÌÉoÀ’z9öo¿�«ŸÃ.•�€â‰•®ªBå¨g‘˜}‡(’3{O%"øs™L©°naúŒ³»C�x®+ñ²cNEÃÇc Ôïù”ÚdîŽ_'#÷”¥(ßñÊþz‡â´‡¿è¼r›\Êàp8ŽÀaDàH ¨Q%¨µúä Ø¸P³çM$åФIœåH´ÍɃ©‚ .¦W$U&ç–äÉd¯þÊÙ®5Å´y(†œY ÛÍ3ÿòŽ¨Ùº’øòg±oå7ª±­½Ê!2MÕ›½"9-,~HÄslÊ LºéòªŽèøQx÷ÖkI×�½fƒ—Ðmbž�.+êJ}¯�¾x%#òÕÉ|ï`0Ó?æ  �„_ªÓ¯ð“ð"G€#Ààp8G ë?h¤Y yÖÞ°gG �y.ÑmlCm�‚v y`Gû<°£É;ÚBØX2m” LôÀ– y¡K ÀþÜ´i&�•m¡Sîðd¤�¸qÝâ;{ÌÓ°… CÔ,ŒHõîç�˜3;°cºEé1èi¬ùb¸P—=* =†Î¤˜ÑÿQŒ—.m`íw`íw1$â!<¤¸ðéÙµr=lEqÈšpº|Žt)yÆâd«³W|�Šo¢rõŠ&¥Ý�»÷-¶2¡,%—uÑ}Ñçøßiew}$0í®—°ðIßÍÉü'ëps¿<$¤<è>ookK½Rû#ZšV¢¡e 2J‹1ŸÂ{Êtß×ã�”ò¶»KŸŽ†ú¹˜;µåP…÷Åàp8ŽGà(F€<°óÛá�KØM>죘cüÔ"0dêhôñ­W3VX°4 : ’;>…ù%ÁÔ„ºÒ­ÿU&¨é>DOk �¿î>Ħ_F! û ú–ä3ˆ >5d»ÁîÓÂ0æ*ŽÀQ†{#;©Íƒ6:áÒé gT$4v}¯ÙÑF›3¢Ž&½]T�úˆúN Uz”AyԜά3`ŽI‚KCT�‘d'…ãm…‹®ƒ¶Úýxú*6'ê¼të¼0j¡�öö錠ë­pRh;›m/æ^]Ñy=-~‚ºz÷nU8câŽS­c U[”ëi²cIc %Þª\/‘6ÕþFžÆã$Ê’=Ké}°w[¥» ²/+kB_S/o­­v)¶ÿx9Mªö�L´z5:žÕ…Hí{Ÿ{qH##¦ÙX¥5 ó!”AMùhS úËW=Œñyÿ†1!ßÞÒÚéãô?ü< "Ç�§;�ÉåÁ$‚¾´Q½(VâDE ¥1^‹ûvmW~­Ð¿^æp8ŽG€#À8PB{`hÜþHC #Î;ÙÇ}Fkç$ ƒs…q ÃT2ûßHõ}!OhË�Û1èôh¢LŠº)½sË=ýFÇ�§2‘*‹8º•ùž#À8æpEàž½cžAk1ÜDNzi‚dø*¬s±¶úAÌŸÁøžŽîúr(2z¬õ±rJ¿mäûÈ÷wâÁ3žé”S¾ÿëIHIû>d[.º�Lý,¤Þ1¦H j¬%µª]éé½ÀÀú.)™nɦŒ�I|{Eìüì>¡B®¾*?� öèY2ú„ ¨#pú­_Ô2ÕmA„pñï79­Nº+ !,Qöxy4Ì÷‘Ñd%%¦¥yÐ"‡ÍÖ%¨)û/\Vl??�áEÛ EzÂSí²d 5nÛy<Þ¸¾­]v\™#Ààp8ŽG€#À�@¿Ñ‰è;å'òbvÇ÷·p9[é�Ðy»ú2w»¹§û1%gß�‘#óP"ž5sQ©(šƒÔ\$xjmÞEkõ0G#÷¢žÁµy-G€#p¬"ð¯/¡ûï_"2Ó·lG±ˆˆˆ†9ö.œhþ;0¯'©; äfg±LUaå5DŸB‚Î!¨Mæ‹å�«”ôúQTà j?x?AÍ^ÍjnØB^ÁîWº¤d¡7’“cÀBq('šêVÂ{¼bufßìÙ|ÁŒ†ªÕ4YR4‡9�ä¿)W’tô¥·Á”ì!§=ZvÏ éªF#µèÕ}JwÄ$ô¦ÅkzBgLE¤.ŽÖr4×nÂþ¢ïPø«Üå¿(¿'œ¹ z"ÞE2ÚEصÔ/ƒ­~ á°ŠÚJ‹0–!ÿ]wðÈIQ~+ʇ™­ñmlÙuÕ&P¼ž#Ààp8ŽG€#ÐFœuz�û5`-{Ë>”l¸•奨µ²œZvaòíôvj7"©%ä´Ð%ÅŒêyl±Dº÷Õç<$‰g͈ðŠ]�£dË[a… éÀérŽGà(Bàþ¯Ï%/Õ�~FMúÐÞÀï�Þ6oðÐ#`kúæ¸`.¯î1i"H©“RCý"DÇ\²5�ÆýÆRHÅcKáH ¨)TGù7Š5û,LY݉ V_ìÐZ¶˜H^?‚Ú3y2e uƒÔÖ mÇwcOïÕž¤h‘ÞŸêü&j&�Dzc,š›i5úXÄX2�ПÈè`J:‘Ú8· Ù‰D³pd'ËdtȤð×iÙ3°ìƒùLêM»~?—Úé…–Úͨ­(ŦüFªc® GvrØåd»ÒhŽ­°ÖÎ…Íú5žœÑùèJ}rG€#Ààp8ŽGàXC`ȤAÈ=9pò’�×ã·÷Þ$8ä÷û¶¿î&¨€Êþ:VÎÿ’j”Ö¯ÑàüóŠ¥ï¦` Ô—/À¾ �Ób‡*öŠf\ÈàÃܹ WPrºµùg4µ,C[Û_ôµ½®'9ù�‡N?>,Ô"",aéq¥#�O[ŽYóS�{!â_U°Óš¯R5ö«ˆ*ø{tƒ%þÄÆ=æWË‹!82jkåoHê©k8&u �C0‚úw¤ú¿ÕÁæTÄôÆv;…2?ÅÀZ&!°Å¹c‰)ãN¦=+ˆLêN™#{PLe ªì—"u)2­Ð-%SOS^-¡¬ ÷*zêzŒ˜‡1ŽÉXñ±/~ÍÊ/Ø‚’lëZ©°õ7Ä7ƒa²wàNW-š?E}Í+¨¤‡<”‡žáp8ŽG€#ÀàÈ£¹ïi´]Wú‘ÓoÈ™ ~ïE9j´ ÃÈí*ùß3¹èvI/³mkÚŽ½›ïÅží‹°·À&«ãŽG€# �ÔäwUˆCq:ª±w×8pÄ„uÞôå1¬Õñ4„°ØC¹hqÈöÙ)µ…0>sf7ë%=4Iq¨o²áíkÔ£&(öá2,çO§ëæÇm1ªÿ/)ÔìóÙÛÍ€èèX8ôvlØ\ƒ|!Žy°ÑÊë4šƒëlÊÆØÐÓˆ6zÀlˆÒÃÖZ‹ýºF¸CØÈÇÒEJGAÝXþ;3oPÄÍÒ�½Š¶D±Ž ëËWªÖ‰ •‘5$ Åëw ¢-ËoDB·‘DDoFCq)**IÞ±Ö\,�Óâ"ˆEÏ´«­¨ènôE!Ž”Ž,O[Yáìvµ#i�g9ŽG€#Ààp8Ž€ �Ê]#^‰ öÜ‹ÌÑÖo¸ÛFrÒÚ¼ ÃΕVìÄnü¹ ¹¹:vŒh’ Š8Ç9ǧ"5w2’z\Žè„ rÀƒû×;�vÍãWbOÁ?Pðõê0ŠÀÉW�AJÎß—v5´Qh"�Hq;8îÕhkÊGSãO¨)óó$áRUz¹íãÓk¹€Xe#R›ŽHM*µ› MñI+€ª/¯ÁœóßöZ_÷º–d�“y&¢MÓ¡Ñк`ž‘ ¼¸ h´¾„’­÷áÕ›ÔCs0‚36ç,"î»B¢V�²Ñhbñè÷³Ä.Úut áb›ÑÖV…Ææ-x~Fa»ì™ò?æ™Ð-þFô'Bk8…p‰ hãÅ?ìhÊŸ‡ë'ˆŠJ@\â‹„K ^tpÚÝk¨ÝûŘâo@tÌY¤›üIÍž ¼D›“ök°> ûò§ˆ|fN˜òt÷‚‘ˆ‹ÿ Æó½ýÌ%û—ˆomýå»ÏÅS—¨/Z{ÿÿ�†úÌ#£²¥I'¾‹>sM2]¯ô™S;Õ‹®AÞTßgÎÈÒ¦aN¸˜ú­v´[×3¬™ïñîUîób"¦_?8Fm/huƒiëM×U õ×�~v§|w²× Ö'QNúí±Û7¢µeê­`ÅÚí"Œ†@Œãe¨-s.÷»CÒÈáËJf‡oBÏ=ǎ 3è›J!µ4nÅÎß®„%u8bGaé×’–ï›)¾g,NšY«`é9ìV|óH2 Bû¬ÂÉiqÎ#Vú'¢'Ÿõ’uǪÏÞ Ç©Cbpò%…ˆÒ§ ?NŒ¨f›½¥ŸÎîIm¨ÿ#…ÕWâp8ŽG€#Ààp8\ðX)"uDvH“x##•yòÍÖ•ØüÉ)œŒVÀ†‹8á"Ð÷ÄtzkúE˜S.tóžÿ9™£š§1©Œ©møª6.Ý´«qWŒCÏ‘ŸBgìN)ñ¹ÄåÊÈiFR·)‘GhPVt^»ñ'Õ¶Iœ9¼Ù;faØ’±³leÔç¼�?ŠGzò£0YnÚ“žkÀcæm‹)íÛ5�ÏØ,èûïùî"rÿã‹Æ>È_ÝWfºáèù,¼¹}ûÇâñ³ˆu#1’Õ9êJ$¦¼EçDÀ²t}3s—«·ŒŠÆ]óû #g Måû&à±³åŸß=ÿ@ ?n jçrÙqëhåµÞf-Ò£wЇLVÁ±š>sFPÿsž‰ñ·ÂûñX¾þ�ïÚMä“ f$ë‰Ù•ŠD¾¿�Z™�ßj}œþ©¨ Rb<óF r÷/ ŸWks>ä#ˆ„'�w1iÒåjEUùÙxdš' ‚hãwüç[ Ȫ¼ccÃ{¸çÔ™~Á‹÷ÿo*’º}@ÿÛu\ÙSÛÒôv^�¹WW„¥˜•<ÿD‡y¬ûæ:õPz ÓÑâïè>ä?ˆË¸9£‡ÈF\³³û·åÑ?³Ó+o² rÇSô”ÿ¬û¼'‘ÓñT×Ùä40äì)2rš @gÊòŽ#Xfø´¡7cƒ@N zž/ݶ–=XóÕ`ùÎ'X;¼Ž#Ààp8ŽG€#Àà„FÀ‰Â•´Ð˜R¸g÷V{6\ƒÿ{t,'§ýñâeŽ@;5c†œS*�ӡ̤¤®@Ð.¶Ç˜ f8÷¾gÑg̯ä½Ë¼N‰s#š‡mI-‰ –’ÖnòÚ„î½Ä czžÛ[Õ¿£—fµ*ËêBP7è#oÑ#èÓ«Z §…1H„2ÓdccrI]rÆ—Ä/JB‹âÎÏUá{JÔôÕšò*Ïè59Á<µ³?¡0HgìDRÊÛt:ãÕjªnÃþÝ#aküØÛgEùE„‘ ö”!ŒEíþ©Íz<Ì:/�žX(¤—¦„æÍ´†~äµþOdç4À÷xPršuñü Ÿ÷t| …þPð2WŠªˆ�?6ö<öÃcª:Ò sªÊÅCb�~<�ŸÈi¦"nRc¿<óìNJýs~zɯF^tEvŸÇ„<žÿ_¤tÿ¦]ä4�Þ8½—ƒ‘å] )_�‡ràC¦\ˆ´A÷Á`Rxï?ƒ…yBËÓª&Á¿�\úæ-dÿP* Üì€KFKyô=’œó/òŒ~eëåuôÅ•{|:²Ç }à£ÐG÷uA“–ø¥m³æã�o§¢d…ÂÓ¿Öx‘#Ààp8ŽG€#Àà´�u_/£øÒw#­÷�fìŠîgªö¼‚¿–ÏÆÞ¾ÈS H\Â�ñ×?Šä^÷Ë <ÿf^™Óa#oçh/7À*z’vìØÒPÄD )>2ædòXcÖ IDATÊfºžMJL“+ µM¡>D¢šŽ�-êÒÑ=}†>Iíÿ3 F–ÞõÙE+ù_Dä�êÉD˜x4ÇÞæ( BAÍ{‚ºDî®u}qÏÿ‘×2–KÅB¾‘ÞÞˆK¤¬Š­hÀ¼i›)ôB°Ä¼{™—lddf05ÂÆ´žUŽ'b·[ΟÔ…‘$6Žª²Ka­YFNÆÄ‡Ô´Ï©MeÏâ¶¶bO†¿áº×gÂhNÀ‹—º7w;·#¶j¢-3¡ÓŽ”ô"É.ÐKîl±ý/Xªþ Sì-N$' ^lR!ÖÙgþÀ7!.î_„™û3mÄ£Ù|§˜õÙç¤@õ¶È*Þ¸Þ†ç~ߊ¨È¾>Ûæ,±÷âÁ¯òñÈ9ê!�…¦ iŸ^'ìsdÿ$¡<˜Ì³0û‹�ñÔ¿+6lkUCQS]袇7Ï.û:éªJÌë>˜÷:3ìÖ÷-ÚŸ¯ÚÆRq˜ êl²O˜ìK»‘R,ßþ_üõÃÏ*6t!Òv“ÑÜKþÅK}GÐÀ˜ w£æÄwÑÚ¸›¾hzÑ6ÑñãÜ_ØÂ‰ü{ÖéhÆžÕ`ùÇ‹áèyWŽG€#Ààp8ŽÀ±†ÀÒ7ŸÄÐ)‹‘6à.˜Ï ¢Å‚†ŠoP³ïsìÛºEì?Ö áçËèt†Ÿ;!€œfKN Aº-ÿTX·nFQó.�@ö°XÄgdQø".ýJA�‘ {vnrçýö“n¾æ$wÈF {C{ ]Uz'Š×¼‚ó›0~¦™ŽG�~?Q­‘“ÕÌŽô- ·Iú<Þ¸~·_/À“Í#Ù|<òýûˆ1]&'2˜¶ç¤Ø\ôxCíý°5-£ 3,±3ˆ¨õœ ÓUHF=‹{HP?Io›ÃEƒ£tÝQ4BÙ³×é܇»N¹XÐ µûç=‘ÓcG(µ õÇ=@N3ƒý{‡âñs¥áJ¾Á­g£WoåïӄćÉêB_o\ÏÔóE` ÝÍǢ>ï œ˜UJŸQ’ 'Û1þSèùî¶}wò?¤çî’™H i žN*ôä=Óý™?‘ÿ¾“YAE&r:÷“'ø¤{ �Uî­[[=G¦Ë õ5�#>éÝy]íè®ùÍÜ � XÖ¹HK}QZu‡Ö˜Ø¿S;Á êýi.ôèM.h¨{ËòðòÅû„Å(ëõAf�t>qnE†·_Jíö&IûIÝE}Œ‚�¢¦ºðß?ÜGê§**ÔTÎÄÆúOhQÄVúßÕ"#ëzz 37P—>fƒñ<Ü5o0„ÿ©@�#Er˜ jú"n¡7ô†/ ìU2[í2XË— ¾bê*·b_ ý£ _Ú^µ#&ãtúV«–þ{Gj�”u»—¼ê< R½¦ºß°«àz¬ÿ†ýèø|ÄÃÂàp8ŽG€#À౬ûv Ö}+’:ì…ß‹±X—C 7ׂžÇ'·ÈØ[÷aý×ý(ÜŽURïBÑÚZaÙHùä%ò™¼oßÌNMCzŠ}L�zÃyxÂxÔì}ŸÞûŒ·íüwþ ®|þdäô_&Ò‚5q¿B$ ÏÀ2{~Nz£½vòŒ ÷ Æ|™ÈG Õâ9‰ätá–¼re•Ätò¾YŒ„”�$2y6J×O.�–È›—¥ô<ï"­noþù vRh†¹´€ã¬öš ú÷|Ù‡â-ß`kwìò#§Ý*Ì#ú‰üIÞ(í\7/ǫ hO0òqØ’—aŽËEaŸ¸¤ˆ¤´Ó5¢ÌûÕ›ÅOO­Iª«îQ»Ô¢ŽH<0‘‘Ð.ܽà¤gìª].¬uOãÑ3à1©Ó\ùœSž‘ï{)ËÁó²EWIŽïö yŸá׊»h0*ËeÊì¹AŽL"+´µmAëÒð2ëûZÄQø=Ü‚;¾†¬¬"™®´ Õ¢‡©^Ïwi��gwð§õöOû9ýh@“LÀÂÃ<4å=o�ûÇËxlI\  ëŸÆŸBo:à¯Í˜Q¾På@·ýt.bâ{¡±r3ŠKéK¯‘ºïà'x(îékߺWˆˆv/ ëž.v-²ÄŽŽ¶Z4Ö|�†ª|Ôî[�:ë6ÆC@‡ï8ŽG€#Ààp8�Ë@×¹ÿ:¼8ñÞ9á!Ðý´ùæã[Dn€Y—n¾Ý�œl“…×Ù[ð~`…G’;â79M 3h�¤öä÷n}UÑî½.ǽ –P؈‰n6(Ú„íô†Q¸é­,¼rm±¢ýþÂräôtÛ0f'Ú³¬µæ^?ršI‰ì;“ ü:ÃD¡ì¿Óé”=Pýõ:«ÜjË'çn AÍN$̯@“åjÅa45|ª(g†šÿª’¼f ¢NP3û¦æuä‹Þ±ätÓ☽:fLV»åÈbÝÚR@äô¿½OœWDñŽ¡‰ÖàÙKªèú p!ÞZ_&/ÏŽ›rú!½û]p‘Ýf[Žýû—ã 9íÖgá9ónU]4’-n˜7O‡<"óÕR|·àðþ½gãi…¾Ÿ½ Oüò1}~—º/x…fb-Ì»ûû€®�-åv\_ÒFºuIZ”å++ß‘•ÅÂÞm/À2Z�Ô¦¡hucEµ#õèûÂ<\#ܵr=uͶ®™¶ÿþâ³þŽŒ¡äÚOžËiGSÝÏ‚xCÅŸD¼o§¨#ä^À^Ùà‰#Ààp8ŽG€#Ààp8�£�Ü\=’{Þ§zz;×-T­ §bȤ$¤ÿ] ™…ØÒÄCˆ$µÓY‰üw•CJ°¶ëk_£ØÄÝä6•w&ì(Ãòcí‹™4 ÍÏkÅrVlX­ÇFÔZ¿°Vësªuy¡ÊÔfWÀ‡�”‡O 6Cô™�Õdk'ï_µÔÔV®V½¾;ÕmQ­g."‰;šŽŠ"¨™÷I¨÷ÞP÷\@åó×V»eÄéKnOûÙÁT¼uOÍØŠV–S<õÅÏ©ÞN‹¢Ò«ßÞL‘³XÕ¤Áúž› f ׉Îp2UÔ æ0.(•^™W¶^Åc¼­m#æ^&}ûÂ×È«75¨zÍkµìM…ð™îÜá'¨7�ÑÿªÏÞªÏÞö4E¯ðÄàp8ŽG€#Ààp8ŽÀ1‡€©ß"€É­Y!µ5oGŦ…šðE ™'yÉio¨ꎑÔÍ Ëƒ6ÔPÿ«�af\m,<‡�èh0 ìR�@á@Þ®ä+ª»íY‰l5öZ·Èf¥�¦Ä-*¥P ¼)ÙˆÌîdoí·?ååi(&²™N´@G«öj"â`ŽËCv¯­´x‚ÿþáÌú0ã`vÍÛæp8ŽG€#Àà3äæjeç*ðE"iD5'Åp>€”]Á¼%‰Œö�ÓŒ”6&£|”Ö²u‡“HrϘD¢Y§#høÔ´M4úC}„ê4ï!ÆŒQÇjñºCµÙáúÈŽ‘¶o\߇ÊbˆlA»ë^�UR|ü¿åW)Ê„¯ |ºAàtú…D‘ôѪë–¬ FLß¿ð|¼D÷¥™…ˆMx Fã…>rZÒ�pÑy®Y©øPå�vúŸQINzР”¢›Õ?4§K�‹µuJÍ…'c]ªt[Qή7•Êÿgï<à£*¶?þÛšMï=!”P¤) EDE쨨Q¬ÏþÞSAy¨QQAžâÓ?>+ø»"RD¤h HIBBz/[ÿ3»{wïݽ÷¦š°g>ŸÍ�9gæÌÌ÷îÞìž;÷L묟ìZÊPNvÏdŸ"@þ!FÿÇÊ4Ú0„G>‹ž½ó±pÓ!ö…JúeúÏõBˆ D€"@Nò:ù´|œj† ”ãšll|�ÓAÍWL{VO»�Õ¼l0©ÄÃu÷ì`›öñaù:§¹Úªàls7u­!uÏIh/èT�>Të¶Bé+êÉV9ŽE¤ÕUÓdMra¯~_JœÔst˜ýõãÐé{øµi¬{Ï^¹ÆO.'Щ¬øÖ8ØA%Ù5íw {̪ØOl¿ÃsÞúåHHü€= æéª£få�m¶BÙa7Ô¶ïMo3³kÈ JVëA4Ö¯DáÁ�˜}åÊdõ¤™ùs¥8iÓ ÃD€" H`nÖ<òÑ™HI“že±î_@‰"@ˆ D€�ö 9 }üS¼’Þ~㬥©ÙîuL‹�Ô‡i!é ÉNǹsx¢1ò¬µy·zkÍ ^ÔÂý›¢1¨wþ×k÷Ô~ˆ‘1%l{‚ß`ŒA#Ðp^ÜRÌVÊW8Ã+Ê-Xµ±Mìû§_{%�N¯âÖ´¼b^Én«å*«}k�µïäÍþæ‡\';„榯P[µMæ"è A2¤3–ÝYý+`0ÈoâiÖ«�£ÒÇZ¶C¾Ûh I«•_Ï›Y-ò]6™”ǤÑ*ëš#̮τÂi¯«]óú)-ŒÈÎ>7'Zìå„V õ ÅIƈ ”Às×lÃü�Û`4 ñ¡^�g¿[À³rÿdwÉ-Íyhn\‡òÒƒä¼ö#F"@ˆ D€"àOÀjt-Ïõu?9Ëì�!¸›£6H~ü¤ƒ³\«§y˜ÖC¼šZojy…¶NŸäY=-t-Œ¯¡îA${Ôh”WwÖ†;­È¶S:‚ð¶ 9¦ÙÓWƒsDFxM¡7µ1‰šx²|c9¥¤iÁ¿"ËŒn AjúAÆPÞŸ¦Ñ&AÏ^rÓ©­}eeOœ°ßW:m¨ÒT\re¤ˆª›`�cZªÐ&ýÌ#"jŽl›Š²{�}Ùk²ºG?ùÉÉëduZ«º“9©˜Íµ›lSvžÔÛòV*S)ÕÕ¯•U…)óÕð­B*…}¸Ž7—9Æ Ó1³ó9Ÿf+ŸØ7šÄ4ˆ D C°³;ùrIo8aì%Iá®R2[ä±àÇí¨¯}½Ë6VP~¼IÒž D€"@ˆ D Àe1šÕRpÿέàyRkèÑÙa·†!$Ãå˜f~.!5÷y‡È¯0šggk�Ó¼NUÕ¯BUù£ÜŠ]·ÎhnÙÑ'o”ùá˜#N-dH¿½¬“nÒÖ‚ïNƒ¶­"2©øÁäæ'íó®-À?ÿ�î§c�òæˆâf�õ+PrôŸXpC™Xܪ|3[P«”´z(>µš`‰·¨kjÝùÒh|œ©îóÍ-µÞÉíí78bœ·à“ÛSû¦�Ä[Ôé”çä;Fo3gNŸ¤ö RåŸm»z FD€"@ˆ Dà °Í»Mº¢ø›³V†ÓÆt9®‰ò§§´ß j}&Í�S´_"Ñ9Çæ Ýz˜­ìUw ª­VŽÏTÒM‹…óŸôq‚ú´8š¬b[#�“OS¿¢ÝΔ(˜Óh•Wˆ‹ Ťœ CÐ0�Èî¨AS稫ý/ª«¦£¬xŽäÀþ_ðÃÁ Ì�Õ.ç4ï@«U¾éa R¿!¡Ñ*¯üµÚZ®ÅÇ™*Ü`c«¯Té!㟠½Ö_È$¶'_¡®” ºJ*XŒÊdÞ¨YeÕ¼¢Q·¢¤¯òûËf+açµ\ÖDˆQ…�ŠC]£qÀÜ´VÖ&j`Äôå-?)¡h ã*|Þhw 42"@ˆ8Ó>삌.ÇwSRöE‰Š]ÄB…LÂáÏÇ`ÑØãØaä8æBM‰ D€"@ˆ@G%P[ò1¢’op=ž/ã£Jì9¿}7¿ÝÃonÜÊVOßê ïÁC}ð ù dþJLä«z?–µš0Òéœõ Käl¬(½_¶�XÈ�c~‰Û`›UÂøµñ ¦Ã:X}¤ÞbŠ8†°0x÷Ø•Bmx[Ks�Û1ËíˆæÏkiTVÊr=ßX¾G¯Wv'/:wJÏsËûsë�÷ A£¢ ƒ¡/[á«g/yvz�3X„l{C¨ºS×ÓHe¶>ºm¿/ùÆ‘C�iq†ÿÖä«••b'ƒdÚ¹ß :G˜Ø”_ÞZÉn€tó;ß·ŽB|„i•V—=ÀŒÊŸw‹ÊçAÓÂJý†ºeluþù2v‰b’ç²ÌÍŠúNªhÛ›©“N’†MˆxÑ“œÿ€•@˜›7#w2»Ã¯Ç‘ßÂPpä,ð•rÉh‰ŒˆuÎ/rz’"@ˆ D€�@%P‘Ÿã?uæHsûÒ�˜9ý.Éô¯ã#9kb0.Ÿ2žI…–® UGÿÇ6éóÆžæ{¼ñ—ÓIÍŽqÉ/ãoÙòÎǨ˜éRknÓö½?è×Ï}Fà_T[a¬³°ÎÕïKxùÔkΗ¯PíP=Ÿ¤«½{È‚ªÍGƒBìhnHå0ü)Ò>~–8§y›Ò²y쯼“’ë�75™¥+ò}홇œç+r–§¯<“½/”¥:d6z”3¤•‹sͧË^Nǯ\#YR˜òxx“º¾²-ï}+!¡·{u>ï#S°úŠâÐhåújïiÞa\â³Þ~E9‡ÃŠò?>I¤Y½Ay®Z•XîÜJu…ü &¡‡�Лðø§W EÕ㔥QxúˇðÈÊAªõ:€²… H! �"@Ž“û2ù¨¢›õV{ž¿­˜=VeÃü[êYlµÍ(ø=…Ńcwã}¾pC|—jÍðÛm’‚"@ˆ D€"�Æß¾`ß¡íÎïÐ~ÎT&Ð2§á€‹rqæø³‘™) )Ñu´ gÝ8Ÿ~.i@—Ó?ÀU3.–`ütA*Kg‚‡Î^Âêi^6RÑcäZüã•hO;ç*Û/^†)ø×w{�Æ•9zd´â*\qUïYèK,çyMhËþ%6Ç´·GŒ„N¯w®„bKócCÕ»Xú€ôqþÑ,¬Ã¹g–BoŒrÖç«§Åa>xܾÃ^ÆbbÀ`<Ã=—œwÏWÀòj5O ûЧœ"¹?7¿ŠS4z-ÒÓ¶3G¡ÏÊPn„¥Òc×ÁÖ¼×™7îúÝÇá­ÁK[]N{gá�ÛÛì°×¡¼ôv)ýT´)»Ó?H…^Ãæhè‚„äÏ„V~¿M …^Ûîú´XkðbÖo]–ã¼÷é­ÑˆÈˆ,DF>&Ñ sóz—Üë,j›+0oÒQA…g×,DXÄOYœ©«} 憭0;Š qÔÃjea9ìVXíl‚Z¶±%ËÙèš›-°iê›×àÃGlÍ?Ï�¦õ³vv®mÖ|v®9Ïkkù<†rþ¡sðÂõû$�NcçÜÁι]‹D¹sî®]Zâ:ç‚Ëù°õ7ç‚'‰1ŸÂ¼ _Ã$ïôªÚlEl.¹,Î÷¹l.>7>Üï7¡®óÈ&[QzJêrðJV�DÅ ÜÉÝ­[�ŸÜWÀ¢?ÃÒ¼‘…ÏéÉ>‹©¾jO¹¾ö<:Æõ>ñY†‡(á«À�úPGtÜëbµ'o³¢°èROyþ5l£E{ZœøçnHï#ìs#+æ� ËX˜µ›,…30×糡hðÏWø\XþüP�D€"p’ DÇ=¢Øƒ¹i�¢sš7ªªýQÌA-“ø?¿ú¾üw±Ÿöáœ$$&¿‰Æ†ÏPV½ÊïK¢_"@ˆ D€�S„ÀK^ÆØG.Fx쮹�jbç´àgÓ%Á`Jò8˜…PÎÕÑÜñ¬—®²æ×±˜ÃÝŒF·?±vFæ”bþ-Ñ‹{(¹}�.Ž9Û|6MtûÁ¸¾²t2ž¾êenR6ñ—gve?·=¿J܈;Å'þOÈ¢ÀqËoö”¹G™o‚Ç��¼‰Çç.h´a,” �âÇ´Ÿ:ÛÍúô*$$¹C(ˆúñ6öšOËØê)ØU,ï]=ÎcǬb«ÇÇzê(eŒÌ!Ú%ýW§Új=ÈŽÝ=UåÕ²aá,~w¸§jË™ÞÀ¿/+C}ýRÔU½Ž9ã¥b_O"¥µVÇðqN¾RȾּe�.‘Ñ0�·~λtówòz[ysñ Þsî”>�vy+ÈäŠ îC×¹2¯H§KfïÛd¯@œÞ<Â{Â]މz}«ù”¸¶3olå&‰<ƺ1h´_{± ¦f6f]ð¸XäÉëFe£‹ÂÍO%–áÎoá}ÆåSÞMÁ¿Q$®‚wØSÍ‘Ë ³û¯­rR»n)ûx¹»²RÚ‡¤Ã¿¾às'â¯�€"@N �©9Á,^×MŠK�= ¨ã ] ÿÌuZù/‘1“a ¾„=Nôzt;Œ…[Žá©/ï“<²¥Ú1)‰ D€"@ˆ@§%àÀçÏ�Cño÷»†lÎUÍ|>̱æô­ñ?î¼Ç¹Ì\4<Ï�Ó<®´ÃÑ€ü=ñV~iÉC;±kwê–Jl;mŠl{ Ž=&°Ù#Ÿ­:VsNóv¡õ®ÐÜœ3¹í:' ¹]áå®Â<°>©¹ñKg=^UhêS:¶RZHFƒÈ±.» W:jÙŠkæ@œtz¯]±\-¯×ws®ˆêÔT¼'dOÈ‘;”ÃÃFrz.žùŽÇ±VNÏ]³ õuÿ§\A¤N_ˆTtxö离Â6Šêˆ³Õ•kÄEÏ9—[YîÓbM¾Z»®Z}¾¾FÌÍp,ÿäî�ƒÍ^âR U¶ :‘ŒgmMM>’¶ù õââ ™s𝾗C˜Ã¿=É–.Ûìe¶‚ÿÇÃÉ­>÷²F˜�?¡Pzìr¼v�E©JG�“ƒº#œ Dàd½ZÑ´ÍVˆ¹ØãD*)8ø4-Û6Y½É4Æ+gß@ulލØEèrÚ1,ظ³V³ _XL1JD€"@ˆ DàÔ$àÀ÷KaíÛaÈÿåz˜ëwHɧ4sÍ8Ãt°¯ÇÜ1ÝÔ°Ey‡$§Þ IDAT7b÷’H|ýJ¾"ž6bö¸Ûq4ošØÊc¶Ù¡Ó.k!÷M»¡nsô�ÁôQݰpÒÏŠvÅ›·51g¶rÿ~~:æ·kjú5•¢pncù;Æ£ºj¬–½ÌÉXÆœf ÎxÄ|e5_õÜÔü ŽxKèš9å6yò­Íp»5U�ù9âêß—¢`Øn/fÕÝÏÔ,,‰;ïÝ û OìD…G<ŒìÏoQ5ýèùÿÀÑÃYè‹ÃŠõøï»êÊi8øG,¦�s!æLØ‚E7 ¨p„óf‡ÐÐܼµÕ3�_ßð-žsÁˆÏ‘߀¨+úÖG*_œyá  R�‹Ù¼UåS�cœ6ê<3~þsk9ÈB¦”I ó=•ÊJnÁã—,–È…Âü[JÀí ‰Çw.+¹š½WÙM“’¹y-JŽ]…ª/ñì•Rg¾oÓºÚÕ¾"Õ2ï76®DI•òªóYfðs¿û—P”Ëb׆�Øg§e‡»ƒ½‡jÿ‹²âqøè‹h̾òkÕ±t¥Ü%« ‹†@ˆ '€€ 7Ê?Å.ÿ¥“�}û²¦’æ®_�àà Š5éŠ×úIúÇ{Ñìq¤�l“Ñ]tÑ�f‹e79@Ñ.)ˆ D€"@ˆÀ©G@‹~gEAÍ6_ †Î]ûbÞ\ »¦vvüé£J6m¯c´­ ø†ˆG“£’ #ÛXÎl­`æj{¤\âpm«]ªïŠ1l8û1„Ge?wœÃV‡†·&Nˆ†=•}x<4¶D4ZŽÁ¬+CÂ^×Zý}s÷â,¾»‘ÝÄý0;þ™—>¦ Ð„'£ÙV ]SæßÒÀlª�qê ìó§EXz3²Ï·¶j ®•õvƒÛw%Ÿ¼WßP„Ù"XÌë&$Mæ*Ø«ÑÐPæw³Ch÷Wù“ÒM AìÉš-˜›àn†µ²¹ÃŽ[…›Ï'B¥&©ˆ D s˜þþiHë¡p—Ÿ]þ®ÁB¶êB)ñøcçtSÿgÿÃÁ ¶†°-†ÔÒ£«ÎFrê©Ðý=£ìØ¥xꊯ¤:*"@ˆ D€"@:0�©ïuG·^<#´3ç ?aг êØ¦‚6"Ña7À 5Ac`ŽdM» ‘Áý\Áâ�pµSpÅÙÆœ³õÛ”!D@9€vA ©"@NI1I³çÕX÷ºªsš7졨؞+¬¶ƒŠÎi®·7+?|‹µv ºLè =Øc}lňµœíx}€=Šô*«·;áâv("@:7þ+T}Pçž�ž"@ˆ@`˜üy2b·H&[Qš…ù”C4x+?ƒ­:‰©ß{E>¹fS“�ƒÚ ƒ9¨ã<Ó,‰47¿Ê6G¼AqÚÅ%su‚":áQ!+{¬©˜-+„A!2ñ«Ý~šð™Í^Œ®–aS�� ¼¸¥ � oáðÑGñê�üQGJD€�ÎF@ƒq�¯GpØ™(üõnlxg›€|ìþÎ63/ D€�@#�ö!‹.Ú¼‘Ð6¬m5†g®ZÏB0泌éÒ6îÕ,òµTN%"8h“ÄÀ9×4S"@‰@f¼rÜh¾òyaVž*Ó*8x¢j�ÒÒUªúЈ[Uõ-)5챸�°{�ž˜ÝRUÒ"@:$�~£Ò9 � ig¼�‰sK0,ë6V÷/Ñ9j D€"àKà‘å]a +óðÙ á%= Û3ÒSòd؃VæÆ¯TŸNõÔ¥ 85 �ƒúÔ<¯4+"@š€CƒÈ˜yŠjʦ)êEdØ$!+{47¯S ÁÁ7 Q·Á Û¬ûÙ.ÌŲ}ÂòªW…,‰ �Š€)š­²rx7,ÒécÐ}ø—?{?�;³SÍ…Kˆ D � „D_è7}­6‚mLØz¿Ú¬�΃Vág‡ Ž•Ý++'!­ÿ š& D Ó˜±¢?´ºÅy”ÿñ™¢Ž+ø—¬¨Ø…ªuŠŽª�ŠOêmÏV8ï GV´X~GîÞ8L=«¦ OFQá¹Þú¢\cýr,˜ð»HBY"@ˆ@ç!°íÓ_°~y8ª‹–Jm î�Þçmeá?6¡ÿ˜ˆ D€�ŽG $ünùA ¿S^.’NΉÇ3ß>Š„´µ"©7[Qr#ž¿Æ»ñ¢WC9"0(uÀœjš( C .9[q® õK°èþfE=W؇_Çb«ÉÜÙwÇ�¶Zv`AÖ^UQ±�)î æpX‘ûë¼v�7ÆZžy ’},ÚíU(=r—�T¾ÈWl§Ù˜sÝ»RQ¾fû¥Üq_×=V¶wCM!¿¥ýƨ% Càè¶ôU!;ß�Èèy2†}„ß×ÿ6–ÈÖ#! D€"ð×°ÛJe·ÿÞ2 la�Ã^Èž­d‹…¢Ø+:} L¦‹¡QX5Í•_ƒÙãVËÚ&! ÿ.€N6M•� 0ùÝôìãvüòË>Éáh@Þ¡®X”%ÿkÛ\1½OûeòiÉŠnuqþ<;~·¿Þ-qŽ¡·×ùì[±¢ôVd�}ÛWŒ),®[LôÐ{1� …ù�*†y`Y"bc&"kªì‹fËêHHˆ¸dÊĤ?è!sßPè‡ÿÅ¡ð§r‰Œ D€"@ˆ@Ç ðܺ÷zC»ÓÔü j— ºvÛ´¾±Ýv¨!8 �ƒú<©4%"@”A}Y5Û:¬UÌæ�¨«|fËnMÃ5“­FÎPlk³—à·iê¡-Ø�ÿþ©Œ=Ò#âCiõ´b§"Å¿V�‹„ä5ÌQÜöðTÜQ�·÷:6ö‘ÅÖe_uâR¾ö¬ —kUx¸?æNØ#§" L Ë¨hœ=Þ½"šy§[rPÓ ê~³ÐÔ‰ D S¸÷­X$$L`‹zBgèž°Ìtýö±WÃÆB‚-ȱÙ*Øo¬½,ÜÇïlï�C°ÔAHnñI GØ)àÑ ‰€2�¶ÿÈW¶E"@ˆø+ 4 †˜V:§ù8�Æ‘ˆI鲊焯|.8ÐOÝ9Í,Íüp´]ä�Ó¼£CÇÚ÷XܬO/FBÒWÞ±ŠrîÈ#"‰Ödºý•bÆÊamw$³r-¥ àa¬ 9¨[âDz"hú�˜hS¦ù"@ˆ8¥ üçVþ¤ÓâSzŽ49"ðÐþ}R—D€"p2$$);Bx¼d«í z· Õ8ìu(Èí‰7”©·gÚè„gëÔU¿„7okRÔ+)f~t†¢sZhÓX¿”9Ðû¢¨°ªÊÿáZíì3¢#5c7^ÙShÖªcsÃ×p8̪K-�ê›F¶ª#ªDˆÀ)E ÿðDD¥¸7zU¹(ž´¶®•Å�(Oˆ D€"@:7rPwîóG£'D€¸ðM�Æsq•Ü�š/3QRx{Ô쀤ž�W¢«¯}yåql³Á‰\®05'A¦KäTNYIéBE�’bòKAHHY«¤vÊ+ʧ`ÆèÛ1ïúß0çê½xüÒÿCÁþT8lÅ.GµOë´ô]àv[›æ²ÍÍèíÇMho1oÇœkŠt$D€8 tÍöàþæ6øœµ:õÊÝ¿—N{ýÇx7‡%ÜD€"@ˆ D “ �üÒð‰ N‰ ® ¸äpð•Ó ®=ìV}ËŽ™˜‘Ó!× "êaw:UҌǚ®­œÃâSç`Þ¤£�Z!.æÅ8ÍÜ)þïI‡ÔšËêR.�V«b£±q9ž¸ôE¿¶|Ü�>qñïûé4Z’N{„ÉŸôÓ) œcwôÄô‡#*ê„†ß {R_·;*²Ù¼Õ�JJvINˆÀ©I Ï¥]ÎâSŠSk®jê^g¥"¦‹ëZ9ö&t9óCänøllù¢x”'D€"@ˆ Œ€Úº¹6T D€ˆðë·ËÝÁW÷ž˜’Òk0{ìÇ­°ä­2ýƒ4¤uÉ÷ dr…£ÀW8Ë¥)K£Ð½¥œŠ‘³£ò3mT"K‡„D€/�«[‹�èÑÂeÚcÎn·z¯“©7óÓ²(ü±MþšvÖ Ñe°Ïµœ]k+óaûš™(ÝSç5D9"@ˆ D€"ÐyÐ êÎs®h¤D€îP¿x'ôº®¨®|”í­¼Â˜·8V°Z]v¶�éTë´¤´Ö�…&\ô?Åë?w®ª®Îû¢%~úØøüdb?¢äœæõ4¡Íâê’¼ZÔHg²Ã9/Ìüô¶3÷»hnúµµ¯£ tC»bgû& A`ð¥]Îi>[ñµ��å>ÌžàPwd5+‡ßÛ´lšjÎ@סïÃÚÇÃ2:}2Æüm2Šs§£lӋس‡Å̧Dˆ D€"@:‘3¡ó šFJˆh•½âcèïd»H•EcÃÿðÚ=Çç|–ë`zNo¤uû|óÅ’’Yˆ�c±V}w̰ÔP·‹îWv»jIÿ>´,Á!½BŸÙ\QVü„W/“³[#d¤^‘É�Ì R5wþÇ$ñ0(`ý_‡àÐë��œöý[(/šëŒsíTÒ"@ˆ€, º�\îZ9í¾ Õšj·¢4ï}Uµ=̧‘ÐØ}ܾz'ì¶Ðç‚_|4@RïyHÈ| ‘¿Þ…�ï±1 íOÃø% D€"@ˆ8ù”Wiœü¾©"@ˆh�o8†ý¥&T»6›zŒŠ¢9íé¢Å6±ñÓœuŒ¦ XŽMÐéØjd'2¯TZ² E{¾"c&xE2v›WaÁ eÞ:29ƒ)^Fêiâ-¸s‡2Œ®÷ñ—»ïà�[‘Öc/nÊìOƸkÓ�" %0|üh¶º¹¯K(\»Ü>çß~¸ »AÚÀ§¢²‚Z¨Úuø…¬ßQ«3!ýŒw0aN1ú_xšŸžD€"@ˆ D  u<)4$"@ˆ@‹�mFöïbêˆ.(*ì‡Æú²m´ÁaL®¾"O¶a B�a�| Á!ãÖÚíUX0ñ7ùº*Òð¨™.ç°�=¡IeEËNïð�K„ê²G«Í?Îë›·5an$Ì�k<Îiqc�¾’×àéoŸ‹)Oˆ`´è2ÌgcV÷5¬®üSü¾f¡áª¤ì!ê×ë~—œSØe¼9{é q`žråz¤!D€"@ˆ ‡9¨;ι ‘"@ÚG`ÎÕ{1ct AeÙ�ìñïb�¡ä” X¸¹ÙŸßÂ6ÀŒœ~z9�&$üzE½¹y+e•*êIAˆ@`è7: I™®§*œîeæh6X-É{y[¼OdM® ¢*XAùUÏC'Œ�1¸‡Ç®¸Ñù 9%Ƕ¸&å‰ D€"@ˆ@‡$@êyZhPD€�NNàµ,¾áØ*åWÑÐ0ÂÃÏG]õ—À°–�(Öæ*ÕÙ77+‡æà O3]�V9îµÍzÏ^³S±�»zƒ¢¾¼üaE�’‚Çÿ®ŽBd�…1‘w@)µ%9 ›@ú�¹þdh‡ÍŠ_Ì“è &õF �rOvh‘qæ2‰g�]Në«ÖaçÛýu$!D€"@ˆ �‡9¨;Ϲ¢‘"@:W�ŸÙÀù«u©®ú jÅP•ÖÜ•øºjûÒ²;˜^ÙQž�r¾b{ÌÈkÚ ¨+¦,ïŠØ¸1�­"�BŒ[ùâåvXš× ¦r*«¿ß”‘ �“@¿ÑIˆIc›ªÊ\RŽþ~Ÿ3܆xfZ�뉱Lœ7†ØÄEg~Ä�lóE[yÍúðtãÎüþV¿ú$ D€"@ˆ �Œ9¨;Ù £á"@Ny¯ÝcÁ¼>‚Ét�ì\�‰Ã™ü[Y�}ÈU̬¼9¢ÍZˆg®øŽ…"QNÑ1Ï)*kªžÂŠ,’¸Áäœxd¤äÀ4Z,öä5Ð2ÝEˆKâ/`î÷¢¤àA,¸ñ°§eˆè2ÏY*;P»¥ë¼á¯s¨_?j¥z¾ùb—Ó—ˆ<Ó̤Û9]]üöl8âßG$iiÁˆÌL…ÎhB³Å[³ºòäæÖ¶Á U%D€"@ˆ ÇE€ÔÇ…�"@ˆÀI!P˜ÿôè)ï ŽŠ~sÖú9ŠgätaßUÇs´ð|hX¬l¥ôpN ÆAJj”俦¨ãŠÇ?¿q ï{Hª•ÝÊà�ñÈè5Ï~÷_l/»�ÍK=wklR"@N>�!c 4æRIGBlé‚�leó:ÿp>v‘ƒZ¨+6`•†ø=ãŸÐêBœ×ß+×Þ¯§Š›¶:Ÿy»‰6ðaD¥Þ�!Ê¿먿¥ ÕÇÞAÉþeØõÅVÇ·wÿf$!D€"@ˆ í$ mg;jFˆ Dàäxñ†c¨,û»lÆ ‘‘¾ “ßMcñœÙÿ1‡3?:ÉêqXk«gâù ûem ¨è{„¬ßÑÜ´‹nWÞñÉ/îq9§}[r/”øå«w—ÃÂïÂÈŒ|LY*ã0RhCb"@þ*t;{…lç6s1~\ö±¬Î¡‘®�ö­d*õ:¨S†„ ù´|«8Ë%ŸÆ‘_+euJÂnÃ1vú<®±]–:§ù5JH,¯3²°Dé“ÑgÌ&Œ¦gMš„~ýŒB :"@ˆ D€�I€Ô'’&Ù"D€�Gà‰Ë£ºj–¿A¶�Ï`苞½ós¹ /n5#)m; í!DyöoÒØ¸3/PÝÁ[ŒÎÖ#,R¦?·¹ÊÒþ†Ý’™Ÿ^€è¸ÿs-2”YhÈ}?µUsPøGò 2�ï:m2úæâoKMŠ}‘‚�?Ÿ@ï³ÃÑû¢OÇ£&]� �Þž²8shÛ�¬èu4‹u«E\ôËçåyõ}Ge³'>øM8éúe‡ÝŠƒŸ«*ò3‹3¯‹¡Š?Þ_É%üº%vR‹jé�qH´ }o®Å°‰üÉ…Š¢6”%D€"@ˆ m @!>Ú‹ª"@ˆÀŸLోžÁ¿>^‹„ä5ÐhEN[‘X£Qÿ_ÖPÿ.9ïÌP íÁ§5jð¹Ì$oËaoÂ>ë&ÙÙO~7‰‰ŸËêayé$d_ö¾Pdǘ¾üS¤õ,”zž˜†;©{eÌc¹ûEõ)KˆÀ_G@‹!ã�²PaèÎþå~¤�)þ<{GfnÜ�ŸV¬õ |sîÔ¢K˜§†ÃÎÃû¸Û}†Å"®ËÃ�8S(³ù¢X/Ík0æÞ9ˆëª|ƒM¨ït;»}ÏñÝy�Öˆ®C?DRŸmØõå8´µXhJG"@ˆ D€"p<hõñУ¶D€"pò ‚úÊo\¦Å�»;3…ÁЉE8}Üùn ˆ D€"@ˆÀq�_)v\&©1 D€�LàÍÛš˜Å˜üÒˈî>š9pï‡)x¬l/v[1jªžDÁá·ñÚ= ²u|…÷-O�Þp†¯ØS>V)ïšúAw˜‚.rÖ»“Å>�òÂ'¶üï‘D9{ÆÕ£‘Ò¯eÇqUÑ|ýÂ�Ì�èâã6{lW=ŽízœÅ¯ÞŒîÃ?“í,¥ÿ" »¾?½¿LVOB"@ZC@¸Åíÿ9”´Î B‚) vKÊrk%ªÖø÷þ4Z }©Æ+[ÿt›ªYR"@ˆ@  u Ÿ}š; D 3xí¾™X‰ûÕþ™pGwX¤r|ÖòŠGd�ßûV,L¦K=:ÙŸzn#Kî�ÿ!5ÑÓÞ7c r…ð•S™�¿†À/ŸìÂ/ŸôLjëÏCÆ åìÆX’d =†cø]ذä=&·ItBÁn®²~GkÝô»ât„F�vé|.*l½žÉ}„~V€ø~aèuÖ�TTW¾ZÑ9-®ùóŸ£®ª7^’+{òƒßC}éìY³×#£  Rý.ÃâÊ_ cHWèMü©­Dè ñl ×ïñü_îÀÏ,5Ò¢ûYý�|Úõ��àˆažº¼ÒŽ×ƒqèºLHZt”Ž�ø‰€à°žÐ™`4&³þR¡JeíY82÷%Äf­AsÝnöÚƒÒýï`ï¾Ï†ò 4ô3b̘å�»:]ˆÐ©óÈMZ£pçTì\ý‘D'-0àÒ‹ÝÃ+|ۢȣû·¼�Ê?”¯•ÞÆ”#D€�Sˆ9¨O¡“IS!D€�vHH»€…}ý2Ùp°ÕŽyMDo66n¬· �‹ˆš…3ØkÞ÷Ÿ¢¬ô)´o÷IJþÛRB‚oThÉÜ[‡\«)•*L}!¡=‡#,üfèõ}¡Óg°žv˜-ëÑÜðêê6 $v²ÏWùÁ©dœäD€(p`óûëØ+gß:é—BëŽG­ÑÑ¥ÿ[|õüòñ6ÙöV‹òVk=z“n¾(¸£›ëv`Ǫ�²6}…C.cN.­ü5M¨k³–àØ7ãYQèAÐÈ_³]NQI<ƶêuþ÷ÌA�È‚·É¿Iˆ@ Èd+Ÿ{�jù¦çL›:€ IDAT“–ŒÔ1 ±ÇlcV“"2«UX½Ì«èpevûå__\M¤Õé#5ÒùŠN¿ =G[Qr`6½ù«å]ÈŒé�ðvÍ`öü´L`0e ëðÙw�‹ðÛWߊzòfO¸égüŸW Î F™ýæ†æ þŸXKy"@ˆ8õ ¨y=õçO3$D€�@'­¼9bMõ3‡²/§¨ØùŠ˦�+‘–±£º™1gÝÛÈ^}úe~Ì6W”¿Ql³îÇÂeíñßÏ|û,º�Ó€„$7ôvƒF°MÉìÇi*‚ƒ'!*v¡³¿˜0 æ®_†G>Âl)üJ•íE*äÎô6îÄ”¥2?~¥U©D„€?¾•ƒýË¢PüûýΛC|âv“¨f÷nEÖæ*E]R¯'Xø�>²ú¼ 7ÈÊ}…g\:”ů–>™Á?ù¾¯}kÏömü)”Ö§ÃÛg;+ ~$qK½1ƒ'´|ÓN܆òD Päå™Õ§Ê>TÁÑ}0솩8óïuHî5GÕ9Í�xWO§¤É;§yE¹,— ‰_Xþ}$1ó1Œü›ës.¨…c]Q¾+Ëíù¾„Jì˜Ô뢒4ÑS*à%Á–H£Š•(Kˆ B€Ôr¢išD€" CàÁåé0úÊh\¢šJù•>sŒÐëz+¶ã+¯k«g²ÍÞ�¼2_©z3bßA�éÅöuÕ‹eu3VöCß3Êù¨¬^NÈÖ)i?cᦃ˜õéÅÌ�Ö6Guv¶ý{®e�#D×¾ûñÏ ="Ç™d�I€;y¿[¼ëÞ g1¨oÆïß@^^³" ›Yä öqÌèÙ DOâ:wª+ÿ»¿ýM(ªuèqîj?½È”SWvh~ýúw¿z- r׿ÂfSÞx¶ëéÿmÉé‰@€pà�­×¡±f«ÿüÝÐØn³¸ñ/°/ -ÿ>o¬åOhx?ÙG�6°UÇò!xœz«*ö/(â{ÌDÿ‹]›? 2~,Î+Cþο£ºH}esxÜ8q3I¾´P>–½¸R}ÅZïZ!Qž"@ƒ@ËÿƒÍ’"@‘@\âÅi[ÌÛñ|V±¬¾+bdå‚°©iþuál8†¢ÂsÁ7ZlKªªóÿ7ý£aHÍØÍžÜ�h‹)O]$!é+æ¨Þ?»µÉ4úuç m^_«�CF|˯µÖ6Õ#§ �£ÛðÃÒw±ý õ8ÌMM•þSæÎ#±É�Dû×ÝéßFF2bÒµ,¦m‚ŒÆkÞa7ãÀg³dë´JèsÓMÜF”Ê€ þv~œƒ/çgÞw¥JvÏXî¾±Õ\ŒŠ#ÿ�M&,PñoÏJm°RIî?”ä=‰Ÿ?뉵‹cðó²Xìýn8škwøÕu^†Ü�øžwùéùUä—•‹±î•ëQQ |3ŠÇÔŽÉ”ÿž’ûÕZ¬šåŽƒ-\àD=­ûo ¾}a /I)Kˆ B€Ôr¢išD€"àC`b¶‘Åo~ÐGê-–W<ì-øäZæRYˆ\_ëZa´"ˆ9Wÿ€i£ÎÂ�ýI¨©|‚­`V� m¶lÁ‚ ÒÕ�­ìÃâRn‘ŽB¦ÿÆÆ¨(½ õKa·WHë»K|%t¯ÓŽ‚‡íh)=õåBä6Iµà°[q÷âH‰Œ D€´Ž€Ú&‰âGÝßMÕÑ%Ø·©°ƵHðªj=nóÈŽ›}6VSmâ§ÔêÔŸ °'ñ8Ô”ˆ�'à@îÖ–Ÿ€*Î�…ÕO¥`ýk÷á×Uѱóa0’4u8Ì(,¸V"ã1§ÓÓpÉÄNiÑ�I«eò F`a–·šm’Æ–deyëç¿X×�iÑ£˜Mù�Œxg³>ãŒeíêXúWm“ ÚXâ<‚mU€jÅßm4IÕ‰@§ PÛTë'ÿ<‹>Ç^…7—ûÝCÞ‚JnÐÕçCkP²Ãf©Âæå+U¬¨«âû…±èFÙ!kÜsу~[¨S$m (¬+‘ ð½4ÖlÃæwžñÔ9´ãs<ÇÂnÑâè>¾²Ø·…PÕŠíÿ냮#gÀam@Mñ�¨Øý#SÊm\jÃ� `àÕìf¸Œ9¾�"ú±•Î{äcgççÅÖ:hõò7¬ÂâNgýî&9†§ôö–yßîkGQî\¯œrD€"ˆèKd žuš3 D à 0çmÌOÊ¡*jkæ!;[y¥³N[#û£Nàêp0¬BZÇì®ÃwL;Ó߇1á,„_‹µeG߯¢ÛK%-»÷^Ì6KŠ“ÈÄ?(m¶Bç´»ªÆ�l¼ÏbF¯F÷ÔÏ`4ž+±Ñh-�”g¯yAÆ¡¨. v[1’×HôBÁf-Ä+YuB±MG¾jû´ï°�'8Ûuc‡®ÿeÅS0/K%~f›z¡ÊD ãˆolýg§ô�'qh‡(fµÊ´2†È?rÏ}?½5Uqðç\ô["ˆ�#Å�£­Èö±Z~d1â»Ëß@‹L<ŸÕ^æÓÂUŒL–~.*e¹Ê7Ìe ‘�"@N5âãT;£4"@ˆ`˜Z-Îò£ŸžËâ)ËÇjåüjJÿ£Šñù‰Ç؈Êަ �úJFÁø¼;j1ûʯ1óÂxâÒ~Îé©9© »M¨î:úü¢->2R´rZZ•—¸3yKá45}ãQ67}) #25'³œ7&0gvR¾“|ª©zZ^Ñ i¿Ì�<Îi¡º)øR¤uûs¾{›‰wš ¥#8µðM-M‡½“’yËó�¸ÃnÅŸ?ç­§’Ë£©›_ ±i»µ›ÿ·Ê¯N[I§Ý×bõ†cõ-Ö9Þ g^s®}¦çÜþ0º¡pCÇË“Úÿùøf£>ÿÊ=7½ë ýãCŸ¬Ö•­m·éŠÃ*¶ M§¨‹I¿ÑOgiΧ¸Ó~TH@ˆ8ä ¸SN&D€œâ&æè0oÃWèÝ· �v³ßl¹>11Çå {pÜ5Íæ�˜7é¨_;‰€­N®©ž-‰ ÑqóYQƸ¸R+òIIÏ»~´:=V¬�Ï/Ú¦ÆU˜›u¤EK<vÚK™“z5ÌM±'ïIƒ¶»¤¬6ô’’•Òº­,q'xsF+¥Ðð›ÙùºIIMr"pÊزú4Ô–(;wøD�î¹·Õ±¢cO»@í#ë¼lýÆWU¶?4O É‘â=åc.KVs „0C\s2’éC–9Ù$õ™‡!YH;«u7OÆhÈ&hks‘·™ðÿÝ-±Öµnµ´×@ûs • 7£[ñõ¥üØ.ÅŽ F¾À £7ÀÚßO^º�ŸŒD€"pÈAp§œ&Lˆ8Å Œ|&ÓEÎYÆ%¼�y?|�éËS<³÷ ™áZ=íü æóC¬$ÿNO]µŒmãØl¢™¢ÊF*ãñϳD’¶gZÇVORmX\8YU/VfgÛ™“ú*Ô­9oÞ&�¡m±ïAeùתpbp4±p$r?:%µd A†—\Å~Xøõ²mIHN%›ñÙÜkñÛ·ƒai<è75ks!6¼õ†Ÿ\I�˜9Å©´Äy®,Üõ?¥æ­’§œ}…j=îc+;ø‚j�¡>iôÆ8¯)�úÆö‡-ñ¢øó8¬,½�cZè½Îz²žBàW{±ÿá<¾4{Ù,•B·m>–Õ\¬Ø.u ÿ†©]†¦ËÖ/Í=¾§;d�’�"@:}g0�—"@ˆ€2Ú#òçy=wV§ebá¦ýlóÃFè %zg�ÿnc?�«§¯ÿÍ_/#á1ªì=Ý÷±�ÃL~5ââßÇ³ß CÑî™Xt³Ÿ¾%AdŒº³–¯†~aR~Kf$zK®Í_Ä£~�ätùXÐN‡—Æ„ônE˜ÿãVT–Mþæ[½ÉáK>™C_§K–‚Sf¶ü¢¨#8Õìüb;v~Ñî»]N�9^]Ÿ�ý?\À¦ÚÚÕ·÷ ñuLsEcåÚVDzö’d´HðŠDâ)p'O¬ãò»ò'éo?æPK �µ]_ºê8çv’Kf‰€ »]ù;�±¶µŸ}•Ø2}Hw$dŽEdܹ‰ÃbMŸø' *ó— ¾ÇLÙ�D'öE!Û YœbSÏ�y‡ÝÌ>Çýä$ D€�€#@+¨î”Ó„‰ §2z£±^>…NßÓ뜜*Œ…àÐq8¬(:|U›èpqÁánlåq�l»°ðÑsDžüâLYÞ<¼HkSDô¿T«V–>«ªo�24òfÅfâÅ^|…xbÊ÷Õµ³¿y|µwK‰‡9òkXÌ»½ÐE�ló¶Ââ“¿SÔ%e‰@ àÀOÿ[�•3S±cu7ü¼*»¾”¿I$7Ø~ýZ~¢áØ�Wåš¶Z6düeÒUËBKÑuÔj.ÞuÍI9Æ ½ôfàÞu?)}‘Q"pR Ø-Šæ�FùÉŠ $ N7W>QƒÁWç!­ÿKOšpRœÓ¼ÛŠƒ«%½‹ á)£ÅEg>º‹ÿ�÷òüÅL'º˜øµ" D€rPȉ¦i"@†ÀŒÑñÇîhTWÍbŽã&Õy‹ž�7”©Ö—S>ŸUŒí{ÑX÷–œ`««£ã_G÷žqNw+æoX‹çÖ½ƒ¹ë—áùõ+ðäWÿðk7yI<ÛÄ1ÉO.YbGŠ+µ!Ï�çáÓ•[°ð¾I£1""j2z–²UÕßcZN7ß*’òÂ;+ðÐÈ�8vô,4Ô/a+Ú­N½Å²E=ðê�íÜXÒˆ@§#àÀïë!ï‡Ò6�¼ÑÜbýò¢Í-ÖQ® EÆà%òj~wÏý:º“_ÇÄWTù&í•Æ÷ �9-N¯àÐÖb±ˆòD Sà7d•Ò!}û?G£ï[Ž®C?€V¦dþ„ÊËŠÙ g…™<ÞG£ExüXPšû®ŸŒD€"�(ÄG@žvš4 Dà'ðïÛªØ ŸaÐgñØÇç!*á�#¥³æ¿™s…Ç‘>Zxæ�o]h©WÉÓùo˜ñáB$&½ÉVjŸá­æó[Ó4Æ ¯Út)+HW8†Eez+Èäxx�ì,³Œ¦ý¢n†!àggò3—<” »Õ€ø¸{õ«+ýa4ž “ñ4^ÓiBù�ÏŒã3örÜéªÆV¾S"D íìåÞPüSÄýÅâä”-‹Ú”6ñ*èø†gÂGÔ·fÍak–'7¼ÇÀÑÏø�ûðç�úÉH@:T‰Ye>d­˜ÔðAdâu²5ë˾Bñ�Åhª+bßO‚šŽ�ðîK¼!‘CeÛØí-�£,·–Å¡.“}Â"(´7³Ë¿'¸nD§ôî"îp_ÑNq‘òD€"¸¤?.—Íœ"@NE§ãs›ÚÙ˜þF8BSoAxäCÐiãÑÔôjkÞDnã­Ž£Ü£¹ãù­Axhe$&,€)ص�¿�:?‘)d°ŸL,¨©ä�ÄžØ+G’÷ÒÜô%fU¸;| £³ŸÅ¨Áç":v> ÆA.¯s`Õ›½?4gó4sdÏDsÃ*ÔT¾Žjã,ëu¦9�‘cÚÍ”D }jÂPk }á¿bRð)GF*¯ÖTë533]-ó:§yeÁ¨Ð�ù°ŠöNe%—JŸÈcæ xÄdÜ/1Y²&òòäC+I*R�t@­Ìop÷g«+ï¡6Ž9óœÁH>mŽëãéóÍßq~ùà5Y‹}.ú½Ï]'«³›Tœè¢•,uwù§¯Ò{' ?÷¨³v\7ÿøÓ •ë�<Ÿï"Û”%D€�€" óÏ1 æO“%D€�@!0ïŽZ6Õÿ¸_'wÖ &üÎ:¸w/A\Òùˆ‰�ÅVM��í´¼ø?¹VëïlW²Û ÄÅãÎO{;A!,þ¶Ï[ÁpyÙ,!ë<®cD®Ãw,?÷-OABôXØY�…Y…Ný”¥Q,ô‡«�)äð[ƒ‰9,´IMÅlÌ¿ÏY�þ"püªK–#*å.yCì3]‹H¦k{ø¢ô Ÿ‚Fg’·ë–Ú,UøqïªuŽW™yÁÿIL8lf®¥xõ(TèT4�Ù�‚/XfŸWk;VP'ô眿ӄێä—ßß²~G�V9DP�AfŒ~€ª#«Ô‘]ú{Ô±]nôk]œû²ŸŒD€"°ÈA°§ž&Nˆ '�Àk÷4°>>s¾&f‘Ú;§C§O�År æ†=˜—•ë7‡½ÞO&46œØ•ƒ!1l¥·‚sÚî¨Âœ«Ásâˆò/Oâ«£^IØ‚êÐPIY(„†Þ þZ¸y?JJoÅœ+7 *:"ÐN‡6?‰3ÆßåÞC0—xúMØ·íßB±UǾç÷C_©p]ŒØ|%°MyÃ7¡^{�™#{ c<ÛšÐÎv¢?‘É׊J,ëvR;ìé‰=f©NT Šì!*¹²Âp|7$õ«èÜ…ž£åµáé2Å×ìÅâO'°k…O*ß¿ÖGBE"@ˆ`ä à“OS'D€�?‘ÀŠlþ#ñ�û¥Þq]ýψŠU¯s"µÑqþñ]û5�²xÓÂOVAª~ä+©§,�Fz¯ï\!@|ªët=‘œ´³¿}³.ü—�–ŠD€´…À¾M…È<çC„Å�—uR'f>É̽È^­û÷ëgD¯ Ö¹† 8Ñ\%Éߺ²ÕØùé‰ìDúŒ~×eÒ=t»¥[–¿}¢»!{DàO% Õ±•Ë>G¡h±´.´†wÀ:Sº¿§èöM;Ë ·Å_òa~B#Y;wÇBÿ®†`¡ÐÔŸärÖc*ÿ¨†�}.u†Aä9ƤÜÌòÓ‘>¤›§á"e5ãè¾¶?Ùá1N"@ˆ8Õ´õà©6š D€�ŽG ±p»ê â“&«êÛ¢œÎBtp‡±R*-c1hÛ‘øF•åe©¶ÔéÓUõ¤$D uv-»É¹Y™_mæ­Òê#0ú®ÖÞÒ¢ûÕß°Kq~¦$¶2󷯹óéä¥Ap �$òœÞÎû´�¼NÉ2ø3hež2r¿Ï­á­ ­áf¦tÁ™çãâ¾¹”1,ÃSUœIí‹èÔÛ�/O^ÁÝ.$*E\]5_Q°T¢çöì�Θ„ÄÄP$dº÷ãpÛæ•K,�´¡ D€<rPü[€"@ˆ@‡#°èþf”•øÇ¦1ÿx/Z(×12þ>ÅöM�«°è¦ã'b¯T´ÍuUÒØ²ª•IIˆ€"�‚‚FìøbˆÇÙ$q8±V =ŸÆ%Sßc9ç×h=.�¶Á‘ç:ûù’üúÍûñ|ÚQå'?q zœ½ÜeŽ„½ÌÍñó_œ¸.Èø‹hu^µà̆¬ò*‰�,Ü�Ãî ãáû¹çŸ›Ó.ø‰ù.BÒ íôTœ>~»{e„Σ†ÕwÜÝåj‰N­Pvx•¢:~èÅHÌ|ÔO_œû‘ŸŒD€"Фw\Mž"@ˆ@"ðÔåïbî÷—#8ä:ÙQõéYŒYŸ^‰ÙWòøŽíKw/6 ,r†bãò£O(êZ£0�V¬æ°7aŸy‹¢žD€´�ÀŽ (¸ú]°Z]ˆ_ãÈäpÕã}qàç»°ûsæœò,MÖ`À…ýÑãÜU0šºùµóìþ;¶²ÞW|BËC®¾†`铇~¼žõáç‚;¡ý’1"p²ð•Äá]3àÐiÙç3ÂûNöyKÇv¿A‘{=Ã8°ñ7–Wj ®ê{„Å\äiãÉ0ÛA!}0bâ1XÆÁ\Ÿ‹�èsYØ.¶H�éx×Ü!-—b»ÜƒA×ü„‚ 9(-­“«â‘Uìðä�ÑœºûÐÕ‡¨#îPÏßö‡´ •ˆ D Ð ˆþS: š‡&01G‡®†®ÐÙcœ;Êë´vן¹²‚ïæniªD�6¯d©�êГ¤Á"@ühðìšÀWL+%sÓFÔ×½†êêMp°ë`Á^¢“H)r ;›ÿ¨ýRô12ë³K‘� ¿"Ñn/ÔalÕUãO‹»X¸©€m™*yò5U�bÖEJ[/zªQ†�6è2 gfm‡Þ”ám)\„#û ÐT³v[#Lág²0 Êñf…&ÜXå‘Eøöåû½vOJN‡kfC/ 3ÂÇúélîƒè”t¸z6ûÍâ;v?�o`×êÓqpË.…HÒ}X/ ç³árK¶}õ2n^åØïO`Ë{O‰z“ÏŽý×QLÉ®9úØvšÙ/=ø6.y@ÞI‰ D P 0%"Ð  Š[ˆô´<¤tù É©ë‘�¼ ‰ß !i-SDZ�½èÓ­3rºt‚ÙЉ ­%àÀÌ ¦¢àÈY°Û+dM#÷&ºöÈE·n 8çòfôlFÌåÌúè<Ù6‚0:úy!ëw¬®Ì>.çôäwÓ�Ó¼³ÊÒ×ýúl�€¯úÎΦï/­aEu“À‘_+ñác=p,o¦?‘“È1œ­¦­êœ8–û0sNŸ|§ÒðI“$Îi>†¼õ<ö4%"ÐI t5x·ÜyëãÀU›UDB5µS÷ÇOûPz`ž«^+ìó*õUðÛwçàçeq°XJû°6)ëÄ�ʲ�X[Ñ7oS²ÿ-qSÊ"@ˆà(Ľ:�°Ð»Z5Pƒ)“Õ;ÒªºT‰"ÐYÌ»v3î^œ„´Œ;½­©uC×+ot6ííP ýíTT¬TÔµF‘�t·b5³y=ÜP¦¨+X–ˆØ˜‰�œÂÞ=<ª_V…æÆoQ_ýª7bþ-õeˆ°áûÅsÐuèR ¸˜Ç•åE"rR{…Ê9‡ÝŠ}ߟƒ]_lV®t‚4ýú‘~úkµ¥«ðÛúýˆ@§"p¨ –Æ|¶Â8]:lþYTqVו}‰ò?¾•¶Q(m\:=G.GÏѳð8²µª·¢2Šv¾ƒÂßË=u, ÄÐkvCoð~g07ÀÑßžÄÎ�ßõÔSËå®DRù§¢œSdxŒkÛ`5ï‡�j¦HGˆ �I �ßPͺ˜».Á¡[IYñxТ)T]�Çvýu¡rœÿ¬ß‰ØùÕ#~²!è9tœËŒÈ­3Ġǰ/‘>ðl¹»?ÿùDtE6ˆ@@Hx›ß¼í¶Ù¢|ãܯ ˆ D ��ƒ:�Îö©0×Ec›1wýgn9ÜÇ©0_š D µ\NßÊÖV‡Õ² ƠѲõ­MGeå­N{;�9ɇKSÙóA IDAT«2Ç´�Ž–¼)dýŽ3?:CÞ9-r"5Ô/EEñóЙ46�‹¨ØWýì𛘩»ñðÊ^x~Å®õD"à&�—ÇåÿëS�� ˆí2Y2�’ý3OZh‘Ø®·+.’6šzà´ó¶¢ë›ñûæ›�÷Ýɸ¨@ˆ@ ºš�Ôã ¿JE¿óN¢è~5H@ˆ L@Às§©wVÍÍ?uÖ¡Ó¸‰ †€Ù¼Kq,Ó@E]KŠèä(Vijú¯Þ(ïDŸüRS×*¶åŠÊò)xdôí˜wýo˜sõ^<~éÿ¡ /»||Ú´ô]àv)"б ô¼Xz£‰‡)\ûÂI´ÎÛ¢íàÈtI.�ö!¸� ­#0bÔ ¶™3['º9Í[Þñfë P-"@ˆDä ijÞÙçlnÞ×Ù§@ã'D€üå*ËæÀá�ß)&á%üã½è6�ñîÅ„EÎ’¶ý@­8ö/©NTJ=} ûA%’H³��ËñÄ¥/J…¬4oÒQ”3ǵ\ÒhÙ*®ÓNNˆ¹þHFˆ@Û dŽì�ðéþ"¿Þ�“¹º»$wjËV±›[fï€ùµJxy¥�¿ƒo<†1÷¾Äbx‡‰4”%�E u`À©¥>çŽDB¯lWÑbéê¢wOÚjã! D€t¢_��fÌ4Ð@'0ë“1ìp;Ñ?•�ÇSWòÍÃ("@ˆ@Kù`(RºÈ?•†õ¯£±þc4™«¡³iðìµ?±=D¿8}:˜µzWùH]E‡£•ŸGËÆŸžþAÒ2òeÛ9…¬ËƒQ˜›U-[gÊÒ(tï/¿2Û;*?3ÈöûpNûò&š>CYõ*¼˜uDÖ> ‰8y®˜¹ ÁQ#<Ø-øà_|ŲÍ#;™™L¶a¢±kD¥Ž@lú­0E°EÊ—9í{•›bÏ‘sûd�l�@ ÷ùg£÷ùœ#±YkPWþj‹¿‡¹©vöÁl©G\úåHèés“Ú=öõK¢Á7Q¤Dˆ D@�Å VsÊ‹'æè�Ñd‚Ö ›ÑM}#jLͨD#Vdµó ·ƒÝðpÞó�ÿVÏûL­‡1" [9f5¶‹³ÍÚ¾vÙ9FÔ#Z6Ç?PÇæyâ~øðÍÉêºâƒI„sŠ�õ'´´ÀW€ÉgׯE¡¶±Kî¨Ä­:þ)óhÕH¨ �ç®ÝŠÉï¦#½ë˜‚.rué¾w­�¡aÿt¾gÍ“OêXùk‘‰�/�P%shÓDrN«ð! D€8 ¸…�SžÀäσí�ˆ¨©0Ng+àŒŠs¶Y Ùª¹wq¸b^óY­65'11�Âh샾 ³“­>ZfÏÁœ•ewâ‰ËÞpÚžúB0ÂûŒChȵ0šÎƒN'�ßÇWµYÌ›™ã!»k^nµ3÷ѕÑœ±YvüâÔ“sâqÛPñ±ß4KœlÖ(*¼ó&´o—vîpïÍì†GÞ©¸i£Ý^³yªJž`+w/›ç«ÃCî…Nßz} {Ü=Zm¼+ŽkQQr²Ç.ñ´å対ýs=LÁ£Ù¹Ææé½ñôËî`¼y[“§¾\Æ3�p6�PùÍ'Û:¹~HFˆ@Ç&0må@$%¿Î®ïCeʯÙ åjùôPN_dtßãã]öÖ=¼? n(ó ܹ‡–Å!£g©«äûµÄí©Vj+{`Y"zô”�CÍë+: ÏŒóÿ¿1Ã&¶Q¤Ô9&Ø´Xö¢²â1̾œ=•£²j\¨OG"@ÚJ@ƒ«ŸÜ۔ЙØçßÜt«çeÉmª¶>!õ»ò�Þκ)ýþ �A>ü�Õ\†#ÛnĶ�¿éc>!'#D@†Àå�³'©˜cZ5‰?¶îÿçû×�‡ß¾[¯ÚŒ”D€"@¯#‹pœšî}+)i�"<â¡VOP§OeN×èÏ^¯ì…ç'ì÷´�‹™ÂtÞ;èûB¿‡h4áxðý^HHš��ÐÛ=j¹ _Õf4Ž„1v$FFNEFÎù˜ŸuP®ª¿Œw&þ䮡ÕEcƇ§#6áyïj@ÿÖN‰N߃=R¾Ï­{—mºu³B-yñ¬�Ç".ùæ<Ž‘¯à–jY§k/gR)ZRio=^Ø„Cjë<äiÍCnÃy&À:7á„Nm²¢,¦&ä-—(<½l%=dŠûw°Ù^Arêûš“-Ûs6+V†§Y?í¤7lrÂ~ÉÞݧâñ‹~ÐÔ Å£_NBBŠø]TO{Š�ë;Žîùø$du[ªZ±lß¹xdôWª:2&p t¸tZ)…šó?è§KGí ,|Lý�†驽êvë‡á7ï¢ÕÔ¾1®®ºN+ÿëÞ¿ ÅÅm G×^cåv˜@ûˆÂÀQç 9ïRÄZèMÚØ @g„£f-¶õh¨ÚJoà¡Ñ¶Û÷Òâ&zÀÉ 0&À˜@+ð êVÀêT¦“ßJ§˜¢":§=n…ŽÐ^}+&ìq)WûV•~ƒi…¡˜@mk‡ …åñ46oOø©™ÿ¥¥šqJCÛm¯rFæ[ÔÔˆˆÍ òÓ?~K¯ƒ�Ô´k Ó¬þ¯PýKÂÚ�=ðÙ_ÈùxÓ»‰ˆ!ç´Hã($Ó'R*)Y¬ªžü–9¢sZTŠm\¡ZW.ŒOºÛW”? ”ÔU”YwÃ.¥@V2Å]HoÙü…~“�A´®'<î:ú µQxª5p8~¤›òŸ`Ûó;æÜª[Ög™ð8áŠ+‚Îi!£ÿ»[—´îm¶?怓ûሳÿG!’½!í´ú¶¤œ�A—ÏGñSçi™°œ tR¬ÿîK»øpbL€ 0&ÐîÄêJN]‘@vÿõä¥YÄÔ,ÜÙ?êqÛ &TÆ¢°0%{΀£~aŠÚšÏ²Ùã«hEõ­ôÊã@…\«PYv ¶lJÀmÃb±e¹¥û.Õ2õÊ££SázAD¯Rò»JΈ�ûçÔ×Xï�êª)p¹#ovå‹AªÑ˜¿íißÞ§éœóü�X ¦ë~5 ª|¢bDb¸Ò��Æ‹1uî`…^*éo pI&?ÊÛr�»¶šàv…¯È®ª˜.¯È{ç¡áœöÎã3íyøâ¸PS„*Ò<�q† 0�.I@£§ß�ÒˆŽiâuu/âå MRQqŒŠÏ –ÅOpÈϰ£~ šÙ¸wʇÙn)UYWÖŽˆ��²³<ØOH.6îˆI°hŽ¿™ÂU�‡>fõ‘HΩî”ïï�ן”2Û»BßLÿþ9\EÎvNL€ 4O`à@rŽ냩vÿÇØ°$R.¨9Ô9=N¿±ƒÇl‚Þ�¸–‹4ª†ºÍ‘Ô¬cL€ 0&À˜'À+¨Ã™t~‰ˆê½YW™JYé?0ëÒí�ïÆ7•Åg‘÷»gÊ´ât¸œûðÄ¥+¶ò̬ü­˜ùÃwÞ•sr¹å[x›–Lèp3|îô=ùÓ@H�– Ðãvb×òЫ¯–Ôd&À˜`L€ ÖxuWüúÍÉGiNËÖ¸QS'o_]GŽÍ¹¸cDؾ;-¢­Ý¡—S¬Xk\2Uµ¾ˆçétm ×ù ѺTLxÙ®•g„øÈ’Çmúê—e_vΕ5س'òÊlw‚%¬ž$Èêþœ”õe}—•½®ÔùK{6ÏV• ¡Ø2R*¤•‰‘R…ïxà¬idâðÄÅEÞØÖ;¶¤á¶ã-¤+Puð‡ÍCÖ‰æ<*gS[2CY6¦™yÈL9˘@—#àÁôKÖá®SÇá÷5Vzsä¸Ý²·9ü¿æø`ÈÑ5˜ñÇôðQùcÒÕ‘ŠÍ¾#¢^ÄȶZQ·ñwU[õ’ºž¤7¾“érM½P46.CeÙ?èmœ;ÑÔ´NÓVlü›”ú ¾¼BÓ†Làp'�6ЂÌ~O*0T¿ˆÂg#µƒ“pîäO0`ä² sš.·|W\Š¡+ NÇüòalým¿BÎ&À˜`L€ 0�f °ƒºYD�ÐÀhó§Áyú7Œ±ç‡=8s6TíTr Ú¡9„ùæÑ´Söp1äçÏåÜ�é¯ViÙ'JË8^S'âM É'�L«¢_¢³0éÄÁ(+‹ì€NNy×{ÞˆØ0+™ÀaJàè‘ááÇVuw¡¡ÇIã'ã„++Ÿ6&8¦�ß• "˜+Ùt?>*胫ö…œcL€ 0&À˜@»ˆ‚X˜#>YðÓ.ÍwŒF8ÄGÇøÚw ö š &$>†ißšQòÇÚá,4+‡(œnmÇBCÃÏ!ÖÊbm,•�,“…øjÍf—´HfвlSÓ6M‘NÌZ¾ƒbˆæªÛĨ?°IJ¥nOÒ¦Æß5uBátnFLÌ‘ª6×¼‹7Æ;TuB(Bu¨Åº†¦Èý ›Ðt óp¹6C¯oÛÅœA›ÖN”LÃŽqñ½HÖqV„† �Làè}b:’z(ÿß”n¹e›ÂÃÿüÙÃ;vÌèy‡´qc"]){—.QÅ1D…úÊEØôÅ_±mM©²—˜`L€ 0&ÐF"l¯%õt û:±±§ÐæôÇZ:ù7ê¿›…Òò0+ß�w� ;¨»À—6…*ûH—¤ÒUµ(û¯ªãî�eø$<úÍ#¨Þû˜yuÛ.ª�MÚ7nWäUovWÈ�»›4VÊûœÈ?I³hñ±‘VËEJ�M+aÒpPG¹ÕÔq–¿j6étiêÄ„ôú~šzs´ØPKÛAívî¥WK{«Öw6Ê^£Wµæ!ã,Y57�®íó�úà#`‡�ùÕ4az[Æó"&¾�9 ?gˆ˜ýOþoŒq«Â1dœ@òoUuî¡cµ÷ óˆËµÓFOsõ4ñ+½s®º’¤å¥´RZã�”ªÒEtPÇè{R Ë5Ûf8 ô=ñ_Ši{Ü�ؽ(ü�0…ÑA. Þ}Θ c‚ÿm ÿµ²¼ÛÀ%*]?‰K(Qv5–bËOcÝgË䦜gL€ 0&À˜@›Üõz&ÌçÚ<z]Í6DXA³u2u¹d3NÓ®*ØAÝ ¿´f‡üüå{0cñ+0Y®÷ÚJÓòŠQQˆÕÔâ3sÙ T–LFÌše7’’×yŠ2* ”ݰòj™¨:•°²›‚XƒX}Ö†äÔvøŠÖ\�´A¤I½ÝXƒš< ±qÚ±«££2p÷û=áŠÒÁbô1ä0±"ÆØññãiÕ öÿ±:w�Z‡™ÇîÌ‘”Qµ‘ëJvÁ£’s:¨ðæôb h ²yÄÒ��®¸È˜ÀáF€œ¼s@¿ùWªO|÷î›h[uubÒÃô*Û¢°ÐMSçö@jæ|õýÒ=Å#5\vb ±NKÍ‘‹.ç6L»Pû!i”^ý�¦Ô‚Ûù!­dÇG&p¸èsFoħ_¢˜nñÚ±ukƒBögRûÇcÈ9³‘ÔýZiýF`!‡êd×O»×ýËßþ7™¹TM["ÌÎ6!6§; ±F¸›šà¢�pUå¥b5yKÆÏ6L€ 0&À˜@û7×€¡éÿ¢ÕÒ×¶ªA“ù²VÙwcmçY'<1�â5ÿDÞqÇAoÁʧ2Äœ€ŒœàénÃ#ÃïAå¯bÖ�Í¿*#â·1éuMkº#¼Ö±b3J—GÅ1î¯ãrÊî>ü²_ÒÓjmG„%þZEwC3½†«ÅfŽoŒoæ¦Ì£­¯r¶î¦(0 _Mœõzß? ›ðYн\Kæ¡V‘eL€ 0?�g¯Ø‡‡¿øm0(>þäÿ9ÊÏYƒÌwÎAÊÖ=(xȃ{?:éݾ“,U�µÕ÷â©Ë¶¨ê„PlÖøìÏ34õ•“4uBcʉ¨/µ¯ˆ¨g%8Ü ñŽbÊî¦ üô®R¦08X…Óõ8¹Ç-È8ÛÛCà’'�Ñä=ü²ð&TlÕ¾–Ô® ô9& 9ÃïBb·è ¹DUSWSªJÞFɦ÷°á[ñ;Ò‚�©¶ÄB&À˜`L £˜üÁQÈÎùNû­ÐÐÚï,B•Ž®Òv¼uô‘óø"˜skj¾ŠÚjß x¸ë5¼¾Øh*1ezž\†ûæŸn"iŒv‡HZ^,sEv°º=´ÙßAHn—Ê kG|TB|ØMªËªÛ>2_ûKÇS‘o:ÜÐvâ7ZÇÞÚÜ<ÄP¤O+f×’y´¢96eLà0% 6!¬®º?8{ÙïQ Å¿ïÛ’/páÙ•�ÈÌþ�.â’ƒ¶!9»ý}Ü;ꉩ²8õ£ã#¶±¡î e…�’É B�¨'—s7^ö†7Q׳” n�â†+¦½ó—¿Q9òµ ¢Â¢pìØspñYå^ç´ì'¦¹Ë14ÖoÄš/àëYk“s:ï„ œsLJò—R¤äÞ¥éœS1°“s&âÈ3—cì#¥8.ÿr``;_‹0Kn€ 0&À˜8P~q9zä®VuN{< W¸…ö<û � ‹ÑظŒØ(ˆÖÙ^<Ð!t´ú¼‚º£}#í9ž‚áļSÞ)Y�Ñ+ã›q‰úzó‰ÕÓ¿}÷ž9UsH†pPÇ׊[íÔäªÔV�FùŸZÞ”Þ@;¢†¤ÔÆØIÛ‹bÃ-Wã*”•<‚ùk[Ð�¶:>#2¿ÐÆ]í<�&šGE‹ç:.3&À -j(úõr¬úðcÿÈÕí"I‡Œ=}F|¦m"AQéAoHEî±ï¡ÇÑ�(ZõWü:ÿ#+í¦YØ`LàP¸ñ¥ħvCltêU˜õ×t ßÌI÷P ´ }èQô±HLø †ciï´Þä`ÎB}ýû°U¿‚˜ß–¶(lîí&65õ½°¸Ý%(Þ}f^¼žî5™ÝñŒ †ì4èb{£¶a]XýN.`u'ÿ[4ü')&5p-nýN¤åÜKBý@„¬Æÿ·OvS0åƒyxò²_ZÔOkŒô™‘Wï7ºÄ˜5R´v]wT¨Ç@£ 5±J¼èk'µa«�ƒÆ%·«µ¦�ù(DÍ<Úó¬Ý׺yÒy4?S¶`L€ x L»h®y= ½³n�5åɈ!–¼ü?…O#mj˜�G.ޤÈé¶÷2è‚òTM£êòYš:¡¸ëÃ>ˆÊµhÚÔ–½«©c8Ü ½è,LÊ Ÿ·,§UÁ-Z2q`´z•Ž~ç¾ sÊh_C*׺Z=”Î@ñw@Œì(œ>áq¤æi/ôð>äò�Iuh~aT´yÇÏGfÿUøãÛÑ(ZY¢5l–3&À˜8dn=™y/ÐÂHÚh\–žY¾‘®ï�¡§*o³Ëì:röš×�èM!º¬‰O"9:|!�Ù|ħ1e1 0ªY'u·œ—U§[²ë|̼LÛñì Å»“êŠO—Kì îr_i„ Í_EÚÇié'ÑÇx2=±y1†Aïºåˆ.)ZUQ‘Ã@Ûµê³w6ƨT Š+¶ ¡¹hí·ª«ëBëk”Ýîð1í§� hØ ±!öhÜë]©Á¨­*‡y[›:¤óhë ¹`‡%ßÅëÓ˜øÜóHêu:,Ö[a4�¯ÊÂã*AuåÃ(Þñ^žP¯j*LK¿5T(‹WéfäG¾àKH¼&`ÈøINçø 4œa‡1zÿ¾wþ’ÖQ³ë¿\yP™ˆ û]ø(…ÓÆ’—úo®c{Õ¬ûæ¯Ø±jos¦õ#ÿù«]‚Ü\‘±uf�¯VÈä…HNh�§ù y[ò¼Nî ž;® sV‘•ÿ&Bn/ò1eLÅPý•£ÂCŽHí%™·8’Xóè�G„…ð11qš£b`L@›€ØKI¿‚xUÐjJ‚..�6ÿ�§×ËH^�YùÚ ¨hÄ.ÙÖ„»U4>Qåþ«ɤ  ñÖ;}Æ*ç…ªR ýÁ‰ 0/�®¸‚b*'+.¡¶.¹ê ÒÑ㤫®§Ó/Л‚Ê¥ò·dÿuérJ\Q¹hÓÆÂ—à·…âúøÀÒˆ«n sNK-о¥+8;9ë7}1[Û/©é8G™ÑoØT¤÷~À'W ˜6[<é{Šé=Ëß{^V�³L€ 0&À�ìžïª:§½#¢ŸÅr e;–ƒÚë�¶ƒxË%´úù¿Õ;\ñ–€^ﻹÔjWíêrïæ»±ôÕ§©ŠY༠IDATö>%Zí…ʇŒ>ÝFv‹1Tíy ß=w=åÂG´oMö­yCÆþ„ÞÃ)~µÊ%_·Ás0t\VÍ{/t\fL€ 0&ð' µÅFu‰w tªs»Åâ’Ž‘¦~0™Ý?£øÑ¹ª2Ñ››·½7 ={ýF 9³Tm" Å‚Ê>úad²\ÝÌ ᨧ„ÄÇðØ·qØW1sòå°Õí»˜Tû&­‹M”§�€X¥V[©ý”¦¶L„ißg¹Põ‚[ôRZòDÄÎÜÑ~'´¸`¹h×Qœ¾6%qàIT­Zo£‹ÿ�~†T/9kF Ø®™(“fszgëÿïzç¡ÙâAœG„>YŘ8˜¦Ìí�çV҃ƾŔ‡#)M{Ãúºwš��—’ú¤æpk«g `ä�;¸4;`èD¦I+‘”×d›–ÜtPf0ò–gÑwÄ×ÐÇDvN‡v^Wñ –˜JÎiqwàÿwÓZh3ÆïB» +ÛÊ?ÕtNË�ÿøs¬ÿ¬¿\¤È÷<ö]ô9åH…Œ L€ 0&Àþ|r@—D춬쎈ú¶+£hµ²Úļ¥)%íqMç´hCl|Ø«O±Â9-ö»©­} 5UÀ^?¿Ù®,‰kÚ¤¤Ujꄚp/úæ•böŠýxbñk(øüjoäƒk_��X¯ ([ïäê“>,¦0ýû§ñàgcqó –Í×åVÊáqÛ(®§v¸�5btÕ[fÚ€ñ.µE#p9·á™¿n©R �Í,û-й ©^ô:¦}âCZ¸ž$Õ©Ê%aœùJˆ¸D-Ibã€G¿œ„»?8¦Yóèh³¦�S¯þC«Ò¡š‡ÖxXΘ8ØRÒ|!7 ÆQÈî±\3œ•GYEä‡�ç¦Ñ+~'j¹|¿v¬9ÍJ¬`]”Àú¯V£xõuð¸|ŽßŠ]/P�}í>Û~#º#5÷ÖVµëqÚ°íÇÓñÅ“gc÷Ïå­ªÉxÈٯт†h•5ÑÁZ®ÆR|õý%$ Í§�K7£ªäMÃ�gþ�t|?§ ˆL€ 0&ð§¨(½Y³ŸŠ}—âñ ÅùêÀÓÍs-¸÷ã‘ä¸}³~ÚL QÜ8%ω9¿¸ñìÏu˜þý˸ïãSé4+s…t[SóVˆ$¼(+[gû7*?7á¾3¦àþ³ÃÔÓ.ÅÞ]Ú÷¢5³ùºðFý± ÅVûœ¦^RDG§Ò†“㑜ö&z䮯�£jðìÊÌøß‡¸ÿÓKÈ1¯\ ÕëÄGí/­Oê°ú½‹Ì«–¢ªìqT7®¤í«Q�ßЉxšÕƒ{"7g¢£ÂWÛm¯`êÈöòÌ=óû!+g“\È»œ;P^r 65ý ˆ½sçû9ÈÉ[¡x¨D™�…½éå:)ÿÂË�ž9O¹ªÙ�_]>œû´dv|øËÛ�”2;L.Žú…˜r­ìVI3–¼“érMPd·½‰}% Â±?° OÄM��I„))©É÷Ãçsd{<õXZdU° ¶äËÍ^Q\-®NÁ¬ë+ÔTeÍ΃~ìu4�=í7�ˆb%`Là ˜¹ìb†6ÛƒÛ]…Û‡Ñï­Ñ<4c®jó/—™`‡†@&ψ´Ô‡è!ãešCrK7��'¯Sw ‰WOΫ÷î; õ›üès5Ûg`‹@Î�üâÓ/ v rÝ$þßþ<¿Ìÿ$h×n9.zdmà*öl OÒpÊ‹žÆâûÞê·Š,¹ø±:Dëâ”Fþ†›KðIA–RÇ%&À˜`]€ÀϘÐýø…ãzT«gãñ8°kc.f^]ªY÷þ…ÑâÇšz±ÒùÞ3nSÕÐ æä<íÞÅێēݠZWï˜Û=ó6Q4ÙhM›–(ãÓoÏÂâ‚WÖ’þ¢Í��8ˆã¦"ñ@¯?*²sšbìlÙÞ_Ó9ÝšáEGgzP"9k+Ë®×tN‹¾t' GÞvôÈYësNk Àdçµv¹Ý?³jrV…Éäñ-=ë{¹È›Ÿyu¶nL±•Z¶jY< ‹4_áÀ®¬Ü«èG8@zaCVözdõXësN+,‚…´ôÿæ™)æ=0¨Œ�{»µó ¹w!Žk© µyH:>2&À=Š?}É:L=u~_cEUù ª¿ã†Ø“‘M¯Í‰WæÄƒÂÐÔßt ]<Òã@ÉÓb°¯˜W/† á"ø“xðåÌK±á«£ÑPç{p¯Ö±ÓY{µòºKÍ®-²ã/½TÓ9-Úó^B¹QôåýmiÞ[Çãv(ëÒo‘ôs›‰>}b•z.1&À˜èäþù~7ô8©¨MÎi1u±È.»ÿzˆ° Zé±ÑÓÂM›–.—¶s[D&¨¯{=X7ÄggÕ^ **ÍÊߊ¢B …”½Ó·À1ØR«r†ØÓqö©êQZÕС7fõ¡ÿÚååïP£Ž†oPTÔ Ï_¾'b;.gÈÿÀˆÖ!JQ•>âÕ‹’âcðÐy¯†(‹11ê«R”VÊRLÌp¥€J�öua²PA´ŽbQ«Ä,<~Ü‘ƒ(bj‹øÜ¿ïŠíݤhÆ\çßü‘¤ÒM‡Â BÁdA«TµxÊj¾;,ÙÜ´æZ�ËL€ 0�Ž@à5Zý๯P(�TïyÇáw*›â.�Ýc nbÊÌ0™$hp|E¿çõR‘�L€ ë¾[ƒO„-KFÂE+нIvÍ"6P<’BpŒ¾ï I?v¹ôƒ•@rúà�ý#BŸ¢ª‚^áÐÓjôHèb’ƒõÅu©¸>•]Úºšªðë‡mZ™Kh¡ëÌàM§Ú¥¯ÞÄ÷t­ÄÊæL€ 0&ÐÎ éa¯sÜHïõµØFv†DFãoäK9¶ù^i±`¯¿¡Ð!¡­¨fYÉ%xdL0$‡p<N~–„)šíêt}a?j0éW«ÚTÙæÃšô°ªÎ`ˆ<Þ½•«‘!¹odç~ј1Ö·ÿ˜jÃ!Âyù.’ló^§ëˆ(Üþݧ$ö„Ñt:ÌÖ Í:Ë�Fáû �ÒUG.ª]âtäñòØZMÀÿÆDt±Ðǘhå…ø8Ñ„RÔ–‰�õa«y[ÒϤ¹G"7o½ªimõ ””]?ùvg�üCÛ(t•ytÖÕ,§ªÊ½o—�/«>Ω®g)`‡–Àª&,[5݆¾ŠþÇ?„”žá««¢tF¤õ~Àûx¡¶²¨Øõ!jÊ~‡«ªŽý6«_ßõ9& 1Í8§Eìë_?øø€8d üg³õ£÷Õ5kÃL€ 0&À�‰sÓZäœ}Gg‹‡º‘Ãr¤füKu˜µÕo¨Ê…pïŽ[ÑkÀešú8óxz ~‚êÂÁ9·6àée5W(—™Bíî×l»¾î¿ôfý ªz‹ñ’k¹CÿƒÁçlÄ�¿”bø?ë‘qTøÆ©¢‘ÄÞ£¼mi­¹ò=…S\¼¶Û¶”�mBBÖU+;öj:Ñ#Vd%`L€ 0�v PBoÉ‹7ô[’Ìæ¡Íî˜Ûz]U7…ÕJ³¯Ú »ý}-µw]IJÖ‰šz»M»®5V8™µ“£^;f´9a¤vÅ6hþõ·JÍZ k4u�DÁêNòEuÈa6FrPG7üë�ƒçA1&À˜h�™ù…ØZfEEÙºø®÷Õð¿V/q–+é²¼G Zb&À%�ÝËñõ³êOz¢®jq‹‡bªQw0gô»=ІÂI-+”®ûoÀ¦-™Œã›ß`©´ð™¶4Íu˜`L€ è1eÁ0LÿþiÌ\º³~Ú‰gnÂã‹ßÂ}Ÿª½É µ ö·*)>Õº¦zz MµŒ9þ<5q@fŠȇfêmÚa8„mU鳡UåÚ?L+Ùmá!E$[cÜ)RVõhoúUU.„&óß4umQÜö^†fµ=Ë5u�DÁ!>:ÉÕ!‡©×i;¡=žñ?:älxPL€ 0&ÀÔ Ì9¿�/ÓÅù+h8fÒÒž†Þp‚7Z­X]í,Ù¥^‘¥L€ t8…Ëv pÙH y4z�òÄÆ УÛiCQ‘øÿš¢`²ú~$�ðK{Ÿ]ù`ÕU,BÑïb/ÙC^ô6/óyûúR?¥›?òÚð&À˜`­%pÍëFôîv¬‰O"9:¨ÚLeÅÍT7²_µbDzƒºc}�k4n·¶ƒZÇ!>:×—É£eL€ 0�f øbUÿHvÃqË›)HI>‘^'\ »Ž`�‹ÀúE«±~Ñ‘2ú4äÿ>t±™aØ_øÉ”7ŠÂhà@õk`¹åþíê14Ã:Ñ ¹ð<Úx;U¥÷`gc¶-ßpŽ 0&À˜@�‰ïXa‰ˆ&Ú'L¼(¥ŽAJÆˆŠŠ°¸Ðï(6ÄžŽ¨¨jóç¶ò-oj:¨£¢â0ù-3f^­¾w‚>¦—4<߃XÙ‰ÕhìKºŸ‚ú�ÜËê1kùèôÂ.<éÈY¬•â7S\gõjˆ1ƒqsu´R\ý�*á>zEtÑ©ªÍÛôýH¾NUwãKqÈÍ[ïÕåÐßcWR`°¦Mp¹+¡�éI›/ú®M’Ukû„bȇÎiþ{‰ÐDGQqˆ�ŽòMtÆqè"¬ F¤¹Î8Y3`L€ 0�þ^ŽGÆ,„ذ„`�•€¿º êŽm?œ…&ÇŽÀD\MUØöûÌ@Yž±MǶj‡öM´¼-õ|4ÅÂ~Í»HZø¤�°•Ý«c÷ê›B$‚`L€ ΄CúžON£pÏR˜Žjôí_�¬œeä4¾Ã‹E¬šžùãÿ�šùIdç´°–�t“žó:j›c+n4:išÅs5uÑÙ÷AœýÉd™­ú5$Gªã�'ùª: Äá“ËÆ-LÂÿ4Y*ªëk—!Am¹±üªZ°×‚˜õUÖ¿kÔlu_Ó¾4b…yx²&NÅÝï¿ã¦â0Ÿ˜Sl¤,9áUæÞšOb¯Ÿ�u;®ÆÛ+ѵêup9;¨;øÔá†5ü&ä¤<ßì¸ ±§¢[ö/»=8Žò«eÎ0&À˜`L€ 0�ŽEÀƒ]¿íÁ.ì‰8¬¢"Ž¥øÔQz‹¦ÝÖ·¦.’¢OŸXäû^Ðbì½�¥?{7ˆ•p¼ø#™`]’€110n,¬)�B¯?20G�¾7N§ ÓbÀ”ŒÇ•Î逕/#l{õ)¦UÓA? ØKÅf{W�7”…)Îçì©(Z/¦|ó꺦åP󋆌qb£Ä7E6,¹œ[Hvb˜\bbàŽ¹&ÌÊWx,ln'²ä&}e’ö¹ÙaÿÖÑJxŠ‹MÂOÂ~Iƒm5�¡®!Tºõ)úw ꇧ.sô%˺upeï¥ï­ù ä”®¬zö†Ÿ"2�Úî„Çà?ÌN8xò!  ×[ÛÔ«!–þ7²ƒºMì¸`L€ 0&À˜@Ç"PUò>’³o¬h]7$�›»,TÜl¹ûÈG­£�ª"¬¤áG~Úøj³m±`L€ tÞXÑ +Ú®Œ}ß'Ñšñ1Å8¦7kTRÏ\á×s¢¦ê-Mc"ž?äÎé:Û¿Ñð¿[hUoÐi{ÏüÞp *ÝxEfóutœ¢¥ÈÍMÚˆ{ǰTf ¿Ádù»R(+ÅêQ‰5k&Š%šüçSÜG:8×P3{£/t¨\”ãÌ¡¿7ª©¼2Gi1Ð[SP$%ÿ“ò·Ê‚ý¤~G!%óA˜ão¡ïÎ�§ÎÆÕ´qãbúü §}3**wàå M�z]4Ãê.úÅ´iUW}³ÕÿƒáÂY>€û7¨Ù÷•\Äy&À˜`L€ 0&Ði ¯zØë  ³Ô.‰ó_‰=«f·j~GŽˆÔ^ÍßøoYFˆU]þFµUìØ˜ 0&ÐÙxÒÖco¹„ÂC\C1‡i1 �Plµsh*·’ãXÓoQhŽË#N-Ú-â*; _õJ‡Ž#gêXâïŒXÇí®Á=#o&åìñK–ã‘/o@bÊÿ©Ö�ŽNnv³¨X�߈Y?í¢P"bë?eŠ´QbSÓ¥qHÉ’pI´Ô³Æ9ðÜ/!•üÅFÇ7”SÎWnÙ¸›ö•é!—ó⻑6wnÞÛè]µ.Yˆ¸ÛO/Ûè]å-ÉGÿ*5 ±(<}…x˜}«ÿ#$‡mbõaûÕ·qâO^&þ·'µ±6WcL€ 0&À˜`�ŸÀæå»‘7|>â3.Q ™Öçašä³ôѾVPh@ßÓ7k^[ö)Ö¹TQ• L€ 0&ÐyxcEw‰-†ï?])œÄMï>kïåÐëú7;±½|!/|{~}@öàþ…? =s�fÝúº7H§~~r×¼¤úÔ*&1îžT7²#™ P_ÿÄÇß%²aIדdá+–íµ¿™aæ�%þ´Âø~ S¢20²*x˜<ÁÌ{]ä}„“yöŠ zP œ$«÷"<»âDE[�S9‹ñ´¢ýÊò{˜‹UÛM KPgûu5_âÉüMŠ:\PˆV”¸À˜`L€ 0&À˜`ÍX?ïJz W¬|ò%ÿ)oAGañN¾î>IÕÌ1ç]ð ô1©í<76Ï¿*¢ +™`L cHI‹+Z¯ËÀ¾%aÎiÃ&V_÷ F†ïGðØè�áqÛÂì%�Ë¥½‘¯Xý\o{]2 ;ÆYÅ&‡Í'»ý{M£XÓ0U�XMÜÔ´N©'Wÿ'Z—Œ>1¬ÕSQ®A]AÒò m‡½¨tÇ3&:§oÔ¬c8ÞëœÖ¤éav��ù» ³P¶ï\ìÝ=Û×%á¶ãô˜|òH¶€¯ n$6aL€ 0&À˜`L€ „ؾt'~ý¬Ü®ú0�$d]� îûýÏ:ŽJþ;e¯eœ:cÜ kº¸Q�œv­ýÖ~½$²k™`‡!“y$¬‰�#«û$ÅUâÁ…‘�¿mE4qnûæn$�W‡ì˽qžMæq0ħÍm3)ì„ñÖIÈîý‡×fÒ‡¹ª]ycE—Œ#gö3ªúPáî�Ãðtþt ñà¡ó^EaaîÞMÛ9ío Ê6?´©@9Æpl ¯–Ù[º:(–ŸºHi“Ã`%râÖ©;„…M¬ñ|z°Ò°¿²­Â¿™ºšBp¤Â8òmoŒnywÌ5!+ïK¹È÷ð˜ìûKoPÊe¥8ëÅÍ:§›W¢¶ú^ì+9…ÛS0唿ÏÛ².8Û2ßxË*³`L€ 0&À˜`Là°'Ðcp޹ô7è�* º9–’½fÜN;LÖã­·øÄ2½d'?V옃E/‰ ”81&À˜@(�§–|„XÓX…¸xkw‹¾#šöŸéTW!Kfÿ\�è(«TT·lJÀœ+k2µÂ¬ŸöÐF‰YA•̹csšƒÀ ZÊÍX2�6‡¼ÌW”Õ©èlÚFNã'àl*'‡÷Q°$>HºðE¸e—£à¼ÿHM‡ï~¿'ºõ) È›VÁ^·ŽúPÓ°)”Gä¨È™%À!>” ×gL€ 0&À˜`Làð&°sm%v®í�S®›‚ô¾þØ”*ŽgSü Á»kd¢Štó-Ô{6Ý…åo*7bR©Æ"&À˜Àa•¶” IDATK &–~WC’5U„Vz"DÚúâ�/Å ¾ûOˆ1ÓêÊb3½Ü¿c\A?Ì+�-±¢ŸýÙˆmډ˹+TÔâ²Øôïée¡ΣüÈjk¿f{õ¶ÿÒ*qõ•ÇãTo…f]IÑ`ÿ„B…Lðå'7’ÄšÓßE’©âhw]Ž˜¦~´7ÃQÁZþúÒ©U§ï�ÄÿfŽŠÚÁBuÕý�ÓÂò‰Ë‹pßG'¡¡f+,ÛËØÄ÷gçŸ.üÙ#àþ˜`L€ 0&À˜`�Ÿ€ ?¼ú8V}˜…úÊ¥ÊéеGº«Vj¼%I%Ý¿»ÝNlù~9§g’^ÒªTd`Là0&à¡0ÑÑ™aÌ–„ÉZ+((УßÀ%ªÎi±‘_MåC¨­yš~ÛÃ7)”úÒésqÄqÊÕÝ’Î{±¢«ŸRˆä…(]œ¼Øê¼Ýö¾fk¬p2k'Gý7šJsÂHM�\Qïø_°(NeÒ‡²–øsƒº�œØøq×OÃárîjä§By>hÈyàFYéÙxà¬iY¤Ì´‹–aæÕ¥ìœŽéàëØA}ðsL€ 0&À˜`L€ .ŠV–à‹§`õG9¨,~%à˜ö:Ÿ%´Ã“-—n}?¼�Œ5ßþ$Yñ‘ 0&ÀTÜ9Ï蓊QÙ©p ‹˜Ä�DŽì›ÞM”Ãh£ÁÛ0sé÷˜¹ì—€:4#6B´œù�7¾t¨®dϘtâ`Üö#¸oÔdlýɂƆU¡f�rBòƒ�¼Z¦>B¬h�®¯Z•Ëì¶ï5m�q§hê„ÂÞô«¦Þdþ›¦N®hj�Ų–+èÜgŠ ¶qãKáŽøYwÚ±yû`rRï�׌øÌV8¦kªîAÑÆo&§¸Æ"lW{Ü\9t]ªãzc¼G¯(ƒ.:UUoÓ÷#ù:U�$´ÇF^k4^,™">õFÊO ” ƒ2Ý{þüŽBpDÃÖË�QO­…ñõšãÔçLg!ÀêÎòMñ8™`L€ 0&À:7�þýã‘pÔñHν £CÑÞ…@©=6’ƒ:r,ÈÎ=s½œÀÖ­ ò"ç™`L U¢pÿgçÀj½�Vߞݪš’±Ë¹ÕU3·úWI8ÖÙÉNYgýî€]h¦¦æÿ4ÔÆ¸sÈ\ÝA-Ú±¢c’mÒ[Ö™…‡¹mê‚7ž>{m”8Hµí<]É•z¹aCý‡ÁMå Ê'Xó鯺ƒúá/®£3)>xbH-�"=`hª_£¡ ŠÅ|~¨$Ò¥rì îR_'O† 0&À˜`L ˆÆ 3ò�Òû|¤äÞƒ©wpl²Õ^ó ƒU«Úö o°QÎ1&À˜èÚ&¾–Šôô/Zã ï*é°‘ÉœÓÛoصz2~eçt&0&À˜@×#ࡘÂÿ“…8c6mBØ ±1yÐÅdÃ騛} êj¶á…¿—kOÜÖrGæ®uYxj|‰v[*SÜX©Oä‰N§Œ²=o؉Aƒ�šñ¦f=—s—¦N(µ´’PC“e‰ ·¸ì°ýk‚º¹Å"B�|¢®$iƒ�69ÌPWGÁ€nÙ…@6p× ~xê²-^Cᬞ9j Æ‘�Š�M«`¯[G=9£6 å�rrj‹ÕМ˜@€;¨(8Ø`L€ 0&À„Àézô>¿ Ñ:«v+~ç´8¬û´/Ö/ÞªmË&À˜`]€€Ø¬/Ö|9J¯Às+óѯ�Ì埠HôŸ#güï¿°»¯T]é,b6Oûþ)ÄÅýöúy0›oDT4UVIQ¦$’*Ê*f ‘>&GQ–âbs)nóFdë²o:fË¥0š.E2´WV‹úUUOË› ËGŒMá9"ÅŠk,D`w­‘ø‹ÄÝ÷*ˆØÏêÉQJ««Õ‹ïÌÿ]‰šIÉÿ¤¿·‰¬7íÞ{ŒÆ>hªÚËö2vFK`ø‰€ìG!’ë˜`L€ 0&À˜ðРDZ؃¨ó Ú”dÎia› b?²ƒZk˜`L 3Õ¼èc�˜| 9�ÿ®é@öÎMæè”æj"Ç©Î!6ç;‹>á÷�!6Óóm¨7ýûxXâo�ª*Žq–¡TÞ �5WˆŠNmõ”šù N‘T’c]><’|·$w¹6awq>f^¶Fª¥z«‰gžµÃñªú<—XÆÜ¶8Ô�»ÉAßC¥Y_t”“ß2cæÕu¸ñ¥8lÞۈŲp7p L”âG7(ç7+_ÄêNL Å"?åiq3lȘ`L€ 0&Àº,�h ÝgÞ|Æ=^„Þ-hµtxra÷ÚávÕ£¼ø9”Íšøo`å÷±)¹õœcL€ 0&ÐÉ ÜñŒ �~S€“{:��»’Ç·DvNG˜¯Á8 ÷Í?)‚…OUoÓQa´œ×lý6ˆºü¤NE—s7jkg£¬ä\lÙ”€;†hÖ9-õï XÑZÉ`=JKÕ¬\8™Ýî M»ÌÞ‹ðìŠZ :¶£†WAK*«î‘²�£ÇãF£c1*ËoGqáÔŸRµOÛÜ `L€ 0&À˜èØú_kÚ�AŠ[îÀm·ØH$ˆÕÔQÑüðú;-vN‹ª¥Û–ˆƒfJéy�¦ŽL€ 0&ÀÚ�€' Ÿ‹EA�ºèÆ—ЧÿŽ€sZœ£¤ó QQFÜñN¦æ�^žÐ„ýûÆ„éß©8§}f�]ô99IÃCfI�X-䬿Ñnû¯¦Îl%¶<Õ6üÑ8Þ2Y“a¤Š×¼nŒ¤¦UÞMpÑ*u­$��ÝûôÉž¬eê•Û+•¿›šV¡ºê~ìÛs¶¦£â3&�4 ÷�ù8¦]²”�Ói²òO  þÃô'tÌ]0&À˜`L€ 0�CN b×\ŸCZ8¡Åh¼Åø¢£â0`XŠBÖ\aûªj4Ú·©›Q_ñ©âF^§®g)`L€ 0�67×€©ó�Æ#ßLÆÌe¿à¹_Üè;Â�¤óªqï‚!a­šâ�ŠPòs¢ÜØŒ¼–lÌר_úz+É�ƆÅ(-‰I'«¯n–*—–†oÄ'éŒæðÕÜ’N:ÖÕ.•²aGs|ë6Jœ“¿ŸÆn kGDEáÚòØÖâ�À£ß܇cÙ1åƒã¤fÂŽ"”‰«ic˜\ˆXÑ"d‰”â­Á=.$™üøÄåEØ·û$ìÜ�ásFŸx8k¦�]1G±òœè@8ÄGú2x(L€ 0&À˜`2�E¯þSò=¨Þõ-öU¯E¯~7#£÷3¾Qø�ÕÞ‚?oí5øYûUdµáïßþ4º |QMå• :³Ö}»ASÏ &À˜`bõ³>3渞€Ûˆ:Z•<+?<6³pt¦ ™‹u¢êÓVáäLN›E@G* >{Å>LûvbŒÇÂës(ËOƒ’qœõ\Êj¯xv�^0—þŠ�/=&e4Ž–uëàéá¤Ûá>ªX㵂b{I�,ËsFãXy±EùÚê§`MzXÓ6=sn»f_µWÓF(&ÏÍCBÎ7Ðé{{íºç,"Çp‚Â9ì�݃bEë4& Òƒpþ——ݬ¢QЦ]´L)àè¸xuÇýnxdL€ 0&À˜`-%pá”ø–š†Ù}þÔøñ?¿`ë (ßþ¡RrwžÖóïJ} J[TÚþvÅ!µgëož[Ð-›0&À˜@"�sÌÈËÛ‚ôŒo�žµ={Öà–7ÃßêéqâŸsZÌ=J€!ötŒ›þöÎ}gÞ�)'Ÿ�êÊ»Õ+’Ô§½� f¥fb5¯£þ�p+¿ˆg=åÕÈçø9·6@l¨–¢¢ãh£Ä5•¦l÷þ9š:I‘Ûïw<¸pLÇ›çZPðé%xzÙZôÈÛpN‹zâáÀγԄ÷è�ÝŒsº‘bE×Vß‹}»NÁ–µé¨üÂŒG.x[ј@''þtª“Oˆ‡Ï˜`L€ 0&p¯ÌnÖõ†5u4Å�¾ º˜\ÄôƇÛhö«î€3êé&2NŠö¡hÏšv)•Å"�–¿»~é. ¼°ÑÃZј¿�ÜóVÊ=¡¦b`L€ Î(ntÁÃQØ“e¤MG+HˆÕÆ“ì…ÜwŽ’‰„“ÚÿPT&E62©¸[. ä·í~Ç&©Ÿ—tº,Pø�‚üÆ€}«34¯Éo§Á�p<,ñçÀd¾ ºè,e32çzTR/Ò­VêCJvûˆ�¿+DJEš{ZæÑ”Y®Ó�üëo•xbñkˆ3_«aAÁ¹¢Ó‘šù N¦ÕÌ×A§KE4})„»ÛS…×®«U˜ˆXÑI)³²FŠm¯[@ûPÓ°)”+V\ 9úvPw­ï“gØ`L€ 0�®K`ÜÔÄgœkúµhŒ‡¼¨hïæ…bÆbìÜ)w�(@ò ¢øy¤äL ÜÐ+î/©ÏAgäaÝ÷q¥U{ö rÏÿ!9ûŸÖß Ô®Þ�…ƒ“°sm¥jm2&À˜ÀáAÀCŽÛû>:ÖÄ Öt>t¿äá"Ycúfë$Ò(Ôûö�…Õz­t>—œ¦¾ÐjÕÍæÁ$VwP¿1Þ�AK‚!–ÂZ©$‡«I‹T4‘DQ¸g~_Ä'ÞóÊ›uù£dNhoMéÄ( ²|œIŒ£9õ÷êjªi¶G~ËÔdŒí›þ�#‡œ�èháÈ—¥‡¿ˆI=@f žm¢UÐÛvŸ¦±¢ïûè$4Ôl…e{;£Ã±à0!ÀêÃ䋿i2&À˜`L Ó7N‡è�½‘”5Ii½«¤¥Ixï[ÅÙ�¢ÓQ$©èX¾ý=ŸƒZ£•ä^óû4´êb[åÏAµŠIjÚÈhí§*1&À˜@W'0ñµ4¤v»Ïý\€ÌìàFxÍÍ;&f€7Äļ|WÀô‰±¿QþŸÖ"G½–BLôèä“I8K¿”‹ùºÚ74Ô«X‘\¤°�T¸ï“áHMŸKsr¸Ë“t—ËTòq–‹Hú’Š&(jt¬ BræøkéAö�.Ä{õ¢U/¾<¡ wÍ=Ýsד“Zöˆ R*óq9·¡²b¢W.Ä‹r¬hõ‡vPV_7O– 0&À˜`�€Àw'¡ß çaI¼Â;ÚÀ½` œ„³qö ºô;ÌŸy³¢`­È9×Î?|2ç·¼FZωTlÆA}ºG ¥÷%Hɽ…éÁ&üíš§LfÞõ¤guç˜`]Ÿ@A�æ3>…Áx9OÛ6ßžH£Š%a•…ƒõÞ�oBf·ïÃtBà‹%Mo i¤ÚºåH ‰X!™MbÅ�¥¢æQ8Éûù!…'#_­°÷¸�p¹6£©éÄÆžJÎ`ÙùÒoi0žM+ª PsÜZbÐCÑt eÅŸžFåÅ™<3ñóXÌ9¿A.òæŸÊ/Ás³‘•57,ÄJ˜±$ k—sêë^"Çô03¿PÒð‘ 0mì ÖfÃ&À˜`L€ 09�óž‹ÅÀôk��rl•ïaFþ#ru»å{ (8§µõ:wé�£n ^¿ý-³6ÉW­jBÎèOaN­¸¡–üãS¤ ´`ÿz›¢ýÃR�Ôû¤öš@ui•µ”hœÞºR’\v´¤�¥’¸6wʤœeL€ 0�®J@8oã,!ç´z�–Î;&ö2 wP‹ú{*–“ƒZ½%=mÌ'Æ Ùj©Þ½]Mì•Å™Å~ ÿÔÔ …Ø„q@öˆUÞ¡É^?ûËBÍþMŠþýz*Dìkq’ÉÞŒ¢½DÌê™(õÉUþ81ó¬e0NTÑ)©¯`âs!6T”ÒsMÈÌx�"÷"Ñ0I¬8ÎÊ·SyŒwCÊôôÑzå4r¤Óêó(�¯‰Vfï‡Ãñ#öUôY‹½õðöÕuŠ6¸À˜@³ØAÝ,"6`L€ 0&À˜ÀÍ/X(Nr5ÝŒE{oÓÆ�ÏÁ{÷´ÜäšÊ¹HLú’×­áܵ$þ�Œ®£�†�¿�Öö¾„^ä Kþnr�8û�?bpƤõ¤UÒ=þI!HüKÍdCñfeå@{ÞIJÞÌÀQý°þ»?”B.1&À˜@—#à[Y¼œœ©C}§/É!K3u»«P[õ š‹àvÙa0�Ùüwrôòq�Ù �Ùr*ý]äÓ…ü±¤/[¬¢·XE|å]!R_ñÅ|žýÙA+»�az—y"=´–;{C�†¤>=9§CO�µÕ3pß™w‡š{Ë "< %Q)džÆDá@Žü¦Q]ÍË0¤ª;¨uúÞè5lî_x;1.‡5árÚñÑ›7Ý»`¦_ü»T ;¾ð÷r’½éÿ„©YÀ˜À�  NL€ 0&À˜`L /ÞbƒÇí[1,Ýl¦e�ÒL­¶©ß¼ãG”ï»Eë�ǘÐÔ°NÑ�è_CT”ãîÊPèÛ£°{û�Áf¨3oR§¤é=ì üõŠF µé½ ‚ÎiQËS-3'v�¨«øJÑf°àË¥ô›8qbL€ 0�®L@¬,î{äψÎi‘èœ!ùb««îGÕ)xàœ9xdÌB� ûƒ:ùI”¤Ö¤ƒ:�Üî�ih|b�¾;Ò³æyÞÈ�ÓBëtñΈðXÉ.vP\¾Ü:`L€ 0&Àº�ÚJŠ»,»a´¦Wµ÷,_¼î ¼=õ,~Ã�²’é�æeÝd–n'òí•Ù¹´MŽÝÁæB:ŽÒ…¯( ûr�uë°gý X÷Q.æN1âÓéçÁãjT0”×Ií\5.—sž 0&Àº�~Æ|ZÑ<$lB� KñÀ™ÓQ ²‘^eep�…ŸšÎMzj« @Û·S_»$¬/Io)eU�öºÏUåBh‰;FS—n ŸŸdl¢ÈZÉI«Çµ’ˆc}ãKqZj¯üå Õ°ÕþŸ¶�8—‡œÏ…qƒã+ºý«·µk³† 0�ƒG@ûGìàõÉ-3&À˜`L€ tFµåó|Ãößܙ̣q:mðt°Syñ×Þ.<Ò�¥üHšÄ4â£ýSÅ®g[Õ¨X%]Yüolýñd,yߌ Ư¿‚õKwR;¾AWîy-¼M?O½!Ý)Ž5'&À˜èšÄêé”Ô—ƒ+¡¥Ñt¬®žCrÿ !dú"N´ËµË»€Z:Ê­åGjŸ;ìµ›BZ �q— *¹ZÛ/*RŸÈd>OSkÔØ­�jèõ}5ëÅ[Ï×Ô Eß#çcÊûÝP°HûÚcﺉ´º0b;’²±q%öí9 uß��yù.IÌG&Àþ|ì þó™s�L€ 0&À˜èœJŠ×‡ ¼r¿0Y{ <^gãnµ7›½]™âÏ=(ŽòÒmŸ¨®´’»lkh•ôõXùqü÷.#¾šu~™ÿ#ö¬ªWÅP±ýÝ€\ÞŽ$ì–wš”å#`L€ t1=û#*Ú¢:+WãfU¹$tØæÊ}Ò’Ø{´êû+ÊòÂìñÕ´‘Ÿú¼:}®w£D¹½<_êØ!/*ò±fmç¶ÇíVØÊ É)T”<óAÍÄw¬HLy.(PÉÅÏAvŸÝÐ9ïWÑúD".öò�PVz›VìÜî*¯Buå£(Þ9ŽÇ䓆aÚØ%ª«Ö9ØÀŸA@û©ÓŸÑ;÷Á˜ˆD €VåÕ è·½‰;jøÂ!,Ö1&Àþó 1è‹¥0ƒ!5²ÆRÏc¿ÊýO!­ûlU‡±˜z†S¬ÈÚ ²í–Ö|¹ƒÎV6'w*7Ñ�û‚‡ŽV4S*Þñú��¼�À’8’gôº™þÎo¦V3&À˜@g$`²ŽÐ¶½¾FS'µ¶E0'LòÙ(N"€ÑrÉ—úta=h°cܘ0�$¤‹ÕÎÛTuo_]‡ãVÐF‰Ñáa­¢£!œÊs® ·«A}ãEщ!öTLÿ~ví}.› :‹ÝÒn„5ñ1:¶le¬q¨êx%á¼| §…÷½±j}^¾p˜‡@“ŒùȘ@G вÿüa¤<&À?–Q_¢gïMè5¨É¸ð̲õ˜þí ÜÿÑù¸mn�ˆOû?Zȉ6޲Uj;‹õ1ÝqæÔ„vDq±ìÆ\å;µgËWqIƒ«(üÒ— mÏ_Né{¥dÊG&À˜èJ¢La³‘ÞÒ†éäïF‰M;Ô#UÐùãÎyÚ‹÷×m—7ÌS½˜Øã}÷LA©"çrÖ*Êò‚Ét9îýðXˆ0¡iOÉäPQÄr}Ýëøm} ¦�]äµ›u}&�8[öñC¡žœÖgâ±ÑŸðf†)²’ tZì î´_œ ÄEHeÙ5š3u{ñàgcñä ½!@úö¯FNöVäæn@Ï>;‘Ûw?äÕ⹕õ˜öítL~Ë¿bA³EV0&À˜@ó<¨«ú·÷Ù»ð‹þ$¦\ß|µv°¨Üÿ޲¿CWf% —²ívܹ´’6hô¯Z£¹†t‰øŒ+¨¯Ö]S¯_\¨>>/P ©Û�¤íI½ K™8øº ì�ÜÇ ÿ)'¡ÿ¨‘èwæ™Þ£(ç ;™}Òþ ¸‡.A º@h*É1-MÌ7ZÊjëísÕutþ0F‹½ÔÓk×ÕzW'{O-âô"}üæÖëÔ+’ÔbUyh*;EeöX…Sòœ˜<7OÑÆ¬ü­Ø»Û¿g…ÿü¦0 ‚ãQSù ³q÷é×â�ñáa=æœßÀNéPp\f]�@ë.¦»ÞüyFL€ ttžok1)e6RÓÿŸ½ó€o£ÈþøOŲº{Mu:!„N½BK¨ÇQ¸ûs¡w5ôP8zwèå¡Ä”ÀGIBz/Ž{‘eYVù¿Yi¥]iW.±'yóùH;óÞ̼ٯ¤ÕîÛÙ7ïÃjmçdÎ`…+ãFôße39´Ï×í�L€ 0&Ð1õµê d›s¢æì©ŽõÖñZuKIY9«°gåµë(î¶ÎŵÁ`Ä.G¦~,;yÐ"¶õGº}MV 9lP´™ ÷ÈLî‚%L€ l#;ʰ×ä5†ÑÇübvÄw†aã¾2 ?øsЖÕßaÔñ¿bì_*1jÂé[eYqxΨFïv«�ÄÎ>zÆ‹Gü‹utÄ_,ÿD·öŒÓ0i’ 3g›nQ¹rõûÈt§Ô‡lRÙaÁ ‰´ç(Eíæ«V¿gî ñz Ûçq ã�+ÿ4„^¬6‘“z~[¼>ç˜Ø*r‡œÑ!;Μ±Tï­ÕåJ;/_Ë|Ø]Ñ�‘ÑŸt+tõ-þ…º:›S\4=ª«onš ‡+!f´â¿§ß€¥ôÔé=hmû ÓnpgÝF}iLjT´‘�…BS ÝxÕH‘xÑÿ&�xqbL€ h`µ&2&Ðk”Îiÿ8åký 5ÓèQ5?23o@º-ùî½r‡² Ƶe§S¼µ]à°�ƒÍq Í  ”Dj ‡¸X £¹éÔU=ŽégèŸ$*ûå<`L`[¸à9ŠóÆÂá<�.~ÏFvô¢Òá^LÃÚ¥[‡6kF+ö9æ{XlÄúÍÈÇÞžuP c •3�×ï٘ݤÌð!$Z’$ÞÁïKè¦î„gä ¸Š´�tP¯ü%{é�Ê™}LlÒ¶ÑlÇž}Áÿæ¡ß€5L€ ô�ºuÿ gõ9_ž&!lh¸çDßܱÏ�îXü­‹Rî�3S<ªïdöúÔk@(;KO?œŠâ«ªùÅßwP<Ô¨&ž:u);�æƒÁM¨Þ89…3èºiU _˧¨®ºÓO]¯’s� 0&Ð wÃ:Ñš«2&Àzš@C•;nBœD%œHy›_Åu…»&~ƒ»Nü/®w*+ŽŽ·ÑÈY,ãпdŠŠ¿‚+³4âœN¨g0Ø)ÞÚè7x9ú~qÊ…Cšr‘ 0&°UˆYÒ×¾9w~6ÿ°{ŒnD~Ñ—4;ê/ty?ÇKKÑî#Ã]pCíãªfÊ=U¨«ž�øW3%âyfäŸ+w[†f.{k¿ÔîŽl¦YŠÐwÿlm½Ž4ÝÿŒtªÄÄáP� «ceÎ0&°õ,œõ.þ[VÞ¼xªÆ™èÖ[Ú1´øSßÈue\™rG[ü-ºzñß}™âÚ)¡æÌÉ~45N�\O%\S%TUîÆŸöÇ]§|‡ÆÙcÑÔpÄ‚† µ—áÏ¥Ù¸nܱ¸Ÿ�Ó*f\`L ÓÚŸ™Øé.¹`L  ØLu{�’­\rA’~Ú ³ñÀwßÀ’>.I×�9m8†X…+^ŠGίïJ܆ 0&Ð-.~: ¹Åãàv�GOœ›%­×y›ÿ¨«¹Ï\Òý¡!ê7ÍA~ºÎ�NÖ2Yúà¬{²ðú�uzÃéùÌÛÖá¦4I,~+y�¢Ûî¼ËÉ]€wsª^÷,úe‹ÙiÉI˜î[2ëx7Y™ qø0ìrÈl¤Y$hâEiÔ¬ÕËËðÇŠYºÐ¯À9&À¶"�ªVÐën~ù1°g´m³©�@Îò�À`NPû&¥Ù<W¿6ž½Fs×›©ÿÏ ÆAÔîšm…°bÁ-pì{ ŒF}G¶Ü8XE‹�é§-“E ‘þqO¬Ì&À˜@7Ð>(vSçÜ `L`‹ Xì{ëöáó<¯ëtiñ|¨ÛN(¤‹ ãÑÔpŸô+H§J&c.rû&ÄlKÕ`é„óêú²Ý¶‘u6˘@O_jÆÈ=ªQXøìŽsT³¤µì®Z5W8ÓNüJK½Å²¯ÛŒPÈ£ê'#/òC¥è΂!Œ¦ºb=Šã¹2™Òúàød)EÝ’¯_ûµv?ÂAO)�pŒ·Ÿìv-Òl4+zë¿Ãšùgâçw ñöM.Ìyòzü1{>;§5i±� lmal^ª~rdk�€ímÿÄZ7>ïûº;"žÊï£2j˜e_ݶBasì“R?ã²V¬ù£â¶V …êifôuX¶¤®Ú�Ê9­UŸeL€ 0�n"ŸyÒMr7L€ 0�n%`wž¬Û_]ý¿tu¡°Úi’X1Ðö#~X fNJª‹Ÿ¾‡>§ë²Äª±²CÒÝ+ken|wŠýzj¤Uª+ l€ß¿ u5ºÎt­~º*ë7øddÜ‚i³oÃÔ#iA/räpbL`û" n4iÍxΆÁ`éðÎX)ì°¼Ãõ;_1 OãS*éÚXÓì¼ )ÿI¬ÜS™ÆÍ¯Â•}‘n÷ÎâI÷±®¾+Š…å›1ê8 &«fs[æ8 98VŠC›K‹&®�ÿVÎoHª»þÏÇ‘ÑçoR˜Ð`[#êÖ=…ê•e®_€…Þ†7 7Ãá>�&Òèߘ•÷6Ý–z-¹žØFB~ªqž 0&°­pˆ�mEží2&Ð>�)/äê>®ŒãZu;I·ŽÕÕ57¿‚ÎmNÒ Ç³×ób’\ˆ˜×zÎiQ'«.Á .7Œn�&Äfÿ+²óžCqߟ±Çî�xpî<ÜúÉÄnY„1@4ö©¸t¢”‘9�Â}ô�ø� 0�^Eàâ§30õ££pß×o"ëø6ô°ÙÁD±'ÅM²ƒöо9wÇq¯âò}œ¸é°Ë±l]iÊ}²;i–n§µ~Š�¬Lttlª”ôH~öÍø)&fôx'ŒÇ´<éËñã»6£`´CwÌ5kgjë4ÿîü3´ë’ô癲sZ—+˜@/&àóŠÁ)Ž<½x¬<´^K@„ù¨©:O{|Šo—Ýq>­;1}ævÈ9-:OZ]ðœK»o–2&Àz/vP÷ÞφGƘ@Vþ]-M/éê„"Ý6!®Op4V?×%ä‚¡äDZå*Á¶ß嬿¶xÍÈVœTjVR i\iécéQ½÷1¢¤ w}~-<ÒµãòÔ÷�ƒ%-“Ná¤1›ÙA­DÎy&°­ˆYÅW½9 w~z5þa5F�©G~ágtÓêtÍq!C‹öP¥°=‘ƒÚ‹çûà÷}©]�¤FƒW¿ž««ïÅ,Šeéoù¯ª«ì쉪rOªgH]K‡¼ÉI-ÕâeÝ}d'M0î pøyŒ�tˆªmñ^vì7ùír³J@‚´¹®‹æ¤ŽšÐ„‹L`'!`DA�ù%(Þµ?²‡ˆ…ÚL[°ïâÄKœ;uæL6×ùvmMmrãÚv7ŸÄa N`5$]úŒrsÙÑ™H°»ÊÓNx�ÀâÔÝé|T� wÃÛüªnÛìŒ]+˜`½”@×f–ôÒ�áa1&°ƒp8OÓÝ#oËgººRZHÌdê›I—Xѳñ×D‘¢œ<³ZV¶ú‘³š[1â¡£~„Y^¼$ê0Ѭœ(¤PWf)Çüÿ~?scb Ýò”ÇÒ‘W¬=«¯Í_£ÛŽL€ ô<�¼–…}§E Ïj×X(\�úÊ)¨kü�žÕ±Ð�õ�"·ðpݾ’î]}w(êkfЂNÃR8†©Cwö¥ô~_wt�²�ÚŠYÈa¶£ÇZÉ1­h‘×WÌ`N}cQ®¾÷ñ£0pÿW`qì!õ7dÿrTýdÃêÕ>ŒØ'{L¦Ð�ˆQÛÁ@=Å’~5«f¢mÍ"Ž%-ƒå-�˜0âÈÃQ0äoÈ(œ¤É$ØV�Z$tíÏ·aùõÏ·†ì7…»ýîüè|«PÕW°­•˦㧷î'yH¥…Áûîe,ýጂS`LS‡skiü)¼äã“°nIêó¯´tí0oIÆ:%�øó‡ü-œÀGvO†CtŒi®û.¼¾>ÂìðÃCÎÀS‘n³µ˜8À”–G‡°ÈµÿZ =ôÛ‡Ï+FhÄ ýwEþÐ3àÈO!ˆö‰Õ•>zÁб�S÷0Ð çk^ÞEC—ÃdŒ—å]²ý�‘-·µ-ÀÆMðà©k0õ“c¤“c÷uÝN±`qÇþÿä¾yË˜ØÆØA½�?6Ϙ@ Vû9êIŠ¯ÆÆEº-ë†å [G ¬€X½Z/™ÓvÓS¡Õ;WW'+jk§Ò¬ÈÏ#Eq†Icnh¸5ë‚Ù‘‹mr²§#Ͳg¤ŽØ'Å™¨ÙT‚Á%41<€äŠŽÔ޽_õF?„M!¬GŠrï§Çùì1�*Ó¼^Uä`[—@¿¢Rmç´ü»WüÌE,ÊÒ ¯vj€¿!µ~§SÄ@îYuKÍ„‹ãc0™ûá¤ÒL¼_Zö@nW¬„8š „1Œ”‘Õä›ÊÈŸBš›•ZÊ+“{N܃ö~Vב! ußC&“ƒúe„‚:Æã6¢u¼µsPµê)T­+Çòo«-9˘€L`—#�àý^¡ðEzgf‘š&r;ó&`ä±Ðoì§øsÖ¹¨X®þ]•ì=œôó宓¶¦´l�¼‡´ó°ä«¯TúþûŽ4Œ<îçØ¡B¥¤‚Í=Ö°ûkÂënOKT©ÊMÝ.Tõ:Z >†’½Ž%¹Ñœ WÞÃ.‚Ï>Ÿ†ÿ¤ôùH6iæó°CôŸ¬Q�«¯ c¾œÓ·Œ‘Å_5ÇÐ7` óMN=A@„¼øéþ((<Ù3`4©oœ›á°�$~ µ/àþIKc×MÍ‹�¯TôºCˆì´È"ð/¥–óL€ 0�ÞN€Ô½ýâñ1��•À¥/å�CÀª¹ûâDmÆ9�š:!teD�¿5š›^Ö�ÆE6Û±ñBBÎëißA=m¸á�}`wH³!2hQÄ•¸ãøW¢= gÍ*z�¡¸ÓAn~t, —&S?LýàpLà #ˆ¯,‚�%ˤB‰f�ˆ0öãþ =)jl;Õ�ï —ëšéîDkÛø<_ÀòÛïâ$yÆÓ¶%[f[N ©©ŒâF^Ö¡ŽÄ�&qì{â¯òá™K(dÈ š7Xá¥�›³ÚOèñE Ÿ¹²wÎöÒŒ;ºQ=ž÷Ý�ñi| =�Ç‹Ë^yvZ˜Qئåðb ƒ‡�[Œ¯^Þ ²Þw†�> C$nEÇttÜÊŠ®Üý©ø2–ίÆàñÏÙ êÖ>Žš5oøiæÏoSVç<`*FŒ»èYdö½@%íHÁ•{ öùK%ÊŸÍAãúÚX“0-žÝ‘du*î˜E¤5ž€Hè,2ÃX\ëÏ’6šCG‹„Ž:T4ºèÙp–š�Ü·¼£rYÕ£+çñ 'ò‘*-÷«êj¬Ù#°÷ä+Q8òéæÕÑ´#·]¿Þ'gyÛÄBíÀ«tü:|»í“!�ElEØ@‹(`ým­æùñÆE4©E{@ëáÔÆ¨ÙN»K™`Ûœ;¨·ùGÀ`L@“@NæM¹¶xßÕÕ …Ó¡ýø¨Ðµøf‹�fºøé4Zœ,WS'„-«uuJާþDEñÒOÂi}ÿ7gÀj;N³RfÞÝ$×vP;œ£4Û$ �¥˜òª+¥3?±MÏ— ¸ÿëw`µ“C)šèÁQ€&Œ„‹}¸~ô~¸ï”ßdo™ÀvOàž‰s1íóÑØðZ6þ�üáÿ'-†(¹d„b/32…c÷…¤ý¬§ñAdä<©[±Ä<Œtêê·\†§þ_pe_ë*#KÌÜîYµ0ÖPù"lä –Ó’£š\-r9£ïITë Œ>Ê�¼’ƒ‘Óÿ Ø2ŽŽé%G¶èH#U¬ŒßМõàETCì'&ÀÚ'`Àá—Gö¡ºUƒAݤ֞ˆ 73ñß(⹈Õó—!wàd <�f<ï“'fŒÆôDVüüg8kà•†œ¡—,VÉ«§ã”MíÈ65›‰£¹xuð.»‡]öEØ‘£â£ì8 úäYÍIû"* c{Ÿ¯|"ôëé(q ëÆ&µ‚ü’k5åZB_£˜±®šV-–u�È$�Ô×J;3Ký8à˜Mô;¢XWâ ‘�ê†å‘ds‚”‹L€ 0�^K õp¯6Œ 0�ž€Ý}jdÅ9±üŠîµ·ùãûo€Ív–¶žNÞª6é;i2ÝâDN;‚«R†Ñn•ZêizS·B($f[k'#.¼ÄI©Æ‰iZÚ( Þ€Gæ5àÞ9ÿÂÔ�ŽÃå¯�cF£²¶©n—^÷ξ*ç´Ò€ÁhEŸ~¿’SÝ­sž l÷¦y/î?ígéâix'¾?×üY�ë;˜ó4|©©óÓv»z~цš·b£»es�†I“L1YOej7~÷��a ©ØŠ ½r”âÜG~Æ>§z0`�Y°g- Eª§5(Rx¾ÇŸÁÿÞûAQ£ƒ~'E Î2��•ÀسnÖuN¯�>¼-ŸÜa£­Ÿ¢‹É�2ÅFÞM¡âçwÇç€@[µB®ÎMµ@*QÛ· ÿ6ë°èÑAU%~H¢s �V×qP«:k¯ ñÉ9T‡¼•š­#>Eø„?ºÍÞðûY/oE=é—Ì'byÁÊðÅCû¢~ã«bgRïUø+P»æ ˆÞ‰iÓb1a‚So%Ðê�^)¿ÑÁºìÊßNoÝ`L F€Ô1œaL W°9þ¢;ž¦fýÙW¿N¡AÈÑ©•Â!/ÄãðzÉêÒ?‘kö¼ª×¬Ër¿_?Žv0X¡Ûïǽ…• ²P]q¢n¥ÂhpÃîºùEŸ`ðÐ <ös÷ûJ?Õqä+wsÞí>¢Ý].ýYQí6æ L  \ü´×—õ‡I#ÂòÜ>ëBz]‚[?>W¿3 K7{î›´ŽÚyuGiµ�*=–«[ACéSÿ±n‡û2�VÝ+òmþ=ê&oˆ¸P¦dÛop$Óƒï=X ql—ÒÂ)-òòËhÎ¥…ÂöŠ”Å8„NÞŠŒT 'd¾ÁÚ_&cÞ[xÿö±`Ö Q‹`�$0h÷a(~§f« ¿_�_?|‰tòñªMr8oZr‹f}!ì;ê �Õ+×�·/ªøu53¤ò zˆ (ÞrO¦>ħP‡ÏF >¿�C¾"ÎG N¯4ÌbM>BÆÊnŒ¸§)Œ¾TYãmÓ⩘uW1æ>ÿOüòqüü+ôbó²Û±à“÷4Z±¨·ð¶|«;›û(]+˜`½�‡øè… ‰ ì”Ĭ٬̣ák[3]¸è.úGtëtÙ\ú¡A|-3uÛ …ÍIßÄSøèe€¯qvʶ]QŠsz)ÒwP‹6�œ_�kË¢Žz1ÆÄq'v¬¸œ1ÀH¡E&À’.B ¼.Õ,-5£qÄ „Z*‘¹¦±ÇbÖƒu‰#K.‡:P'¹K˜ÀÇ!§sw¸Ü(®ñ‘�?ŠßŽÒ€ôȼjz2á"L;á}¥*už¼·Í_<gÆušõÄï³yD é:á }~õ,ź¾T³O“±ÿx- O�Ýs¿­K}ä¸ÿiéûÆÆ��/n¢=+÷T¦©öe8³ÿ.ymdÇ´(ˆ�N*‹­"/ Á`#êÖ=…ÊÕeð-Y€… e‡YO�’ûe;�’q�éîèªß^ÐÔ­þü]§¶-óÍ6-u]nó­�ÅÞµhÆzq4ézÖE>äÔ–ÏôÄ66{¶61 ¿WbÌi±±ªÚ i …ïøù�»b„óþëê8íFl\ZCò˜™XÎô.­­tsX'9h²Ïí³–ÐõÍñ†ëÜqßlÐAÅb&ÀzvP÷ŽÏ�GÁ˜@ß¾ÿ†-Eìh™P0¸!e¨�ȪÕrmõ¶¹ñµ ¡d·Ÿ“ ¡bôt¾¾I?4Hb#±(ICßLXÜN4¡ù‹¼š_“¹ObÓX¹Õ7?–×ˤÙv�«®!üm?¢jýdš9¸/®SÉ!}*9ýÕÇüP`}¬½óðO‘M ªH‰B\?xô"´¶| oó×hjY€–ºM4û|Ëkª|î¬[iÉü˜m)½ì k¥ÅÕJ.1�ž! ~«Í£Ã�1�Ó—Ó‚y:eÈD1ëó ßÃ=åÏã†CþF¿±„¢No �¯ë:¨Egæ1ôþ„Nkm±ß7�VˆÕvP‹9®é=ú(°v[,­¯zy}ãjw¶˜¹ÝsêñçYÑw—ƒauŒ•Æ.;§ÅV,c&¶Â¿"Ë[¿GõŠؼr|Éq9·øç˜@�üQpäFÂè$¨ÐêY€Úå�‰b©\Uå‘f5G)TWIwŽ A’o•ÎO*Õ;Q ø«ºì Ö8ÎGÏ`Ú@~I�Á™{´82%¥vøĬoM>vm>©o¼m^úPÒ8Ä¢”ÚŸRRUôž&:—OþyH#3š ‘•÷o)o±B†t3½ƒç)½`×xL€ ì|ÔΊ�oÿy�™è-L–þJ(T‰kÊJà\´FÓéëpž­ÛO³ÿ]ÝuϹèÄß­©Óš7Oœ[ üUS- Ï{ÁŠaî#GðD˜Í�­¬ZB3-�­@kë·ôš�ç öOši8,RKyi½liløQÙƒfÞn¯)Âæ¦—pßäµ”¯™ô2àÒ—²‘•µ;Žã`² CMUü‘Z±Ú·2¥™G"Í=N÷u®ä@Û"zW8Ä••;‘àÜfœ÷ .þ\™Si†*‘Šî0° KWì‹§J9Ök'�rÕN¸øé äïK³¤/ xè“�mˆ‡;Ó¼ÆÓª�:`ÚìÅ$œ®Vè”êªQ¼u%‰]™Sè=µƒºt=kR7‚fzŸBÎîKé·”pÓ'¡ûŒÌ¿‘¤gÔžÊ/ÉA7l6÷ä{30óýÐJñÚ�ËCFï[Aþg BtÈ/Ù-oƒmÔnz ›W½…ŠÊX>«µsF¸6`�"PP¢>—P6ö6þª,&åýÞ¥HwŽL’8ð IDATK‚�ôÄÙjŸJgð«Ë*e{…pjÇm{Í¥‰ÅÊs·vD*Œ’øhþ«´¤ænó.5Xâ|Ô}hð‘‡$BuMv¹¨j×P™ú3‘ñ¶wø¿2' ÄäÇñ°ZO�nÄ&�0úý!°|-Áç�ÅÎé$H,`L —`u/û@x8L`§%ÐX{Î ÉÁ{²æ LšeOô´›,ãHô­,¦­SžÏMÄ•½AQ_�5e$_Égñm­_¦<©»úíè×ïreª;U”ŒÆBZ¼q’ôÊÕd'NôR¶%Ï‚øu ͈h'ÙÅŒóXCue_Ë×j]M=ñWñ¸æWÑ—Zí÷} •“::.¹V³çE9+m/~: v‹Cš%Þìi�¥Æ‹õ}ý˜99¨ª§Uxñ|qQù°ôŽý\“µm-xþÂ&­ê,c[D`R™ ýBƒ)„Ð äÈ�Ý@Š¥„ïyôþPLÝ™LFöývçLŸ\Ñn3ñ4Âýß~L–4ëšMÃñO8ñ䥕þÒ—r�•}022/Aºõšj­R§,¤Óͳñʧ¼4�²Þ–(Ÿ¿~îøÌ«:çdìG]~¶%Ýj¶5¶™èøg¡Y—qÇ´py›þ‹šµ3P»ì+”ϳ¤·äSÕ4ÍB&Àtäô?CG´yVëêÄɌŽi¯Q«�Õ� P;¤ƒá-8–‰Ç–¤øG<×~†T|ü©ùÒ’ùÛÒÎÕæ 'öÔ|äá}› FÇ`ù@(o%u‹‡&_pÚî °‰®•’OÂa|¾�h’Ê,z r‚ÞÕC81&À¶ì ÞN>(&Øá Ü1A80Ä˱ÐaºkwŠ�'âÀž‰+§ÖtJn4ÆÃMÜüîA(è÷-�¥ë_p‚KPz¨þÅŒ=ãˆÈi¾âR#j ^χ²õ¤íÍ¢’äD�(¯ž£='’ˆm6×5³©n¥®NKqÍÁGPœº¿"+÷E-5ÂÁ&ÜôÁ¡ãödš�}¾æ‰q µ<è§�?…›¥ xŒ0â¬Ö¾¨Ò ™@ \_–�¬üÇawœÓÁ)ªÅÜ)ê�*#[Ì|¾9u¥¨¶±îiX‹´Ô¢JvñÞ¸øé¹ôÔà ‹s îª�…²¢®´×Èa(‡x¢§R˜â\>gÖ’q\ËȽ�Þ»ßA-G°ëK°Ò,²úÍO£vý[hùíwÌâYÒ=õár¿L ¸òŽOª#Ÿß˜­¸Ç@&„L&z’+�œÒnú ÷GA‰8¯Ð¿.ÝàKv²Cú7ÄõÏ#à o“W1>2«4âSH|ÒùØû#oðùaâ£8C¥¦Šÿ¥¦´d>rçÁPS8MÓ"�öôÛÉíyÛû´Ñ5MšaWrFŒÏ,zý„¦ªUI7µ{ßÈyDL€ 0�”ôOR6c%`L Ç„ñàYÕÔ;ÍZ–^Wâš—0»FÐ ëÃ`#§5BmXêû)6WöR^,.¦—ÚZ¥� FͰ ¢�Óõ×HSù$>z Š­þŸ#:�÷œü5¤‘ßÿ j«Ki¸õ4S²6×Ù4þStëË×ÍM¯éÖ‘5C #aDäñÊ Úkqü*„Ȇ|8þÅxMEß™9OÅå)râ3 µ•–_�RDn\ÿö®H£Y«¡`Z‚«ñð$Z¨­ÎëfXÅÚ%àιRºÁ•Ò!Ç£¿÷€ÿGTW݈:ϯz<(Þ„wx!œ¹“‘™)fý§N. ‰SZz‹îqFÙº¦i.ò‹”u>¯xòûZÕÂ¥0=²îo�C3«µã¿ gFfÖÉÔCO:¨�úª7cj1\›óTLšdÂÌ™úΤ»•RµyÖ…ÔïùTGþ SVg%`=JÀLOODÎô~‘Yý/B6½:›Bz’dukr3£–• ¶tu|4bÑ�³$¤úæ0yáã-r‚ÏØÔ|”¶b­Ãz|ä¡»$`–¦î?.ËfyÛs~\¿o‡žXì¹pÏL€ 0�!ÀêÁÊ�2&Э"�§Í§>ÅK+Æ+Å&l'Ùì§Ãvüéxàˆr¬Y=3ÎiŒµ(-³Àd+Kù4ž.;Zëµg#ßX6âQ|­ ¬€çóCqw,žòÿ¨Ú»˜òX:2H3•EZÚ(USÙ¤§¡\%×*ddQ[¹ABOóË ’ŽKi¬�É“ŸtúîHO--oÄf«_Y6},P5{Œüýþï>‡§ñUšõQN±²×‘~ ªzçˆhn|ŸâLßÃùÈ7 ãð¥¯_CýTÜrä]±úñÌFÊ>‚›?ü/9”ç’'BßÁ "­)b}ªCsÄûŠçž:»ÿ°�BŽô‰ 9ݱŠ:QwHпM��¢¦q6™´N?úí'…¾ÐJ.÷e$ÖÚG­Ú]“ù«OêŒFØöL¡ð—v­Ã­zÂé�«˜HA  @û¸#šÈÜÍuUk>ŸtÉçÆ@{ó¤u»Ü"…1Ù1®œþÿC*>�°b�@È8%»z|ä>CÁ6Åødid»Ñ²mªGÁ¥ÎèH8½ÎöÉõ™`½€€þŸh/� 0&Ð!¾ò¿`ݪ"Tlœ@«º?K1Iõ�C–ôñH3e¨úm T•U:­¯Æ�ÙJ]V¡–³ñŸqY+¦�øZ}?Ä»J¸tðcy\§“³ÙÓÑ>ϧººT ±èZG’x¤°¹ùZ”¬Z³zUõÝ1¹ƒcÔJ–ô#‘�÷ú”¬Á#ójqÃ;cµª±Œ t™ÀÝ'ÿІšk°~ÍX,ûÁŠõëF§ì+ݺ_Jý]'þõÕ¤¬#”&¿~,úÄÆr.w&‰YÒÍžaÓ†ƒ°`¾W°n=æßx”D5ˆ§èåm~^·K£)ŸKÍÑÕw‡âÅRÍä7ã)#ç„x�sL€ ì�ZÒ’' OªìM•vZUÐÇà÷­Bãæ·±àÓÑø}ÖÛš¥cž¦FØ4éhdqòù™¬io up':JàÓùNâ-ÂÄ'ÜTñ6¦à5O )ö•&usbL€ 0&ÐKtÌÑKËÃ`L€ hˆ8‚+H÷Iôu1ÅnÍ@NñHŠc}4lŽsi¦s‰Ô6L‹êÔúªTý8Ú³ åJy®~”]&cÛtÛ1±|b¦±é§DQ¬ðØOgÇÊÊL(X‰‡'·(Ešy»ý M¹ü uu© Und»¨†ÎõJ0°+×퉓#ü¦¾7žBÌQué÷ÿ„N‰Ûo­ûþœ9´ã¡ªzòu–0e4d"·à>Êé;ÝU�¹À:Hà–cŒÕ ‡—Óïί;»X,X(TL53©zÙ›ÈÌ}žœú7ø-wÌf{™¦†)nõý)«Ú~GSÃc4Ã{6:c½ä„NÕÀS÷…Cú{r•èï:+çÒ½›¬ïFICåcÈë÷R¬ÇÌÜ)”�1g˜Øa¤·úcû"ÿÇ+5«g`îó‘øô1¹f&…CUQß�<“9¦5¤é<-«ÑõŒ8‡ÓM}�’O´½\Y::׬š�ï_ì>>ñ1êÿ_! !^›sL€ 0&À¶�XÛhDl– 0&О¹¤÷œðn>¼Wí7¿,°aõòþXúgaR|æP8ê¹Ñ1Ü·ßï¸õãI*­ˆg�ÊIe2µ©ê+ 7ÍÜ…œd" €"‰!ÐËëy]!ÔΞ÷‚•B’§yr ‡½2£!YщÍ40RKçzeý†#bÎiQqÚI_Ó-ïA¬ n Ã?ÀÊ_#Mœçôó+pÍÁ‡¡¶Rí��׈˜lõý7’Ñx¿â•"ÜøþÁ¸®l8®xAÌNÕ F[1™€˜m×ìyZ.jnûšhÊe¡x¢©á^¹¨¹ a•¦\K¸ª�§%D<ù«Ø·û:“BáˆYÒí¤µNH?efüŸ¾²›4ÍÕ_¨z2¥ À¤ëÕO®¨*p� 0�íž@UUÜA­Ú™è_¶=sw çs{/Uë.LFGGÚ w²ô¢Êb”ÒHû¶ã´ eJ^èX}•!ƒþÌmÉŽªl=ŇBOqbL€ 0&°`õvð!ñ™èbÑ@áàyâ¯5I½M;ñ45MO’Ë Öæ8^.ƶá�M:]cõ3™yW&ŠbeŸ÷«X^/Sà¢x®:É×ܾƒ[§),ö½ãª„Ë'1‹óÁÓÇõ"Gβë>—ïcÕûõŵãNÒ_A¼9ù]¥«­Å§½ßÿx- ƒFlDQŸoзd1�ªÃ£óü¸ÿëQúŸs¥™òêAq‰ 訯}Y_IšLçÑ)õBéo.×­ÓÖ¶¸CO@ȈÙÚâ&�^2Ñâ¢ÿWæÔSkÊ_9·�àM�Z¬‡ÓLq‹®¾;Ï_¿‰BùT]e—ì£*s� 0��€Æ�yŹ„Õ�:ŒRgi´ÆÖþKn™î,I*$F£MQRgÛÚR_‡S„øëè' >ŠÊ¶Œîå#wmHá4oÏ/÷Á[&À˜`[�@ê?à­06Á˜è¸ù°ë°ê[;Ö¯Ý wB„³P¦ÖµU„ñzžQVQå³rÿ…[?:™âPÇ�³â±Ði_Þ ›óoªºÊBSÂsØ�ã•MTùæõÌE•²�‚Ãyr¼†Ò{LÒÚÚÛãº.äâA?´7xÓTØLyIrqhµŸ Ű5¦w}y[R0-«B¿k‰c2§ûŸ±¼^¦•Âð襺š[ôTºòúÚçtuB‘mí¼c×Sÿ¸nŸâ�‘Á!1“±'ÍV¯Ve #ç|U™ L€ ìhèw_;G{§è¸#oí7¼X[ß©9¬vø’‰Øó[V÷Ø”=Ó¤µÄáPz)+·ÚҔŤ|jµþ j1º(1Ô¤d0Z�Û�|d:NséÖAWãiË}ó– 0&À˜@7ˆ;Nº±SîŠ 0&°]xøªÜêqË·âÊýûbÁ/¬^1×ï�Òã^NÚ§Úú’dJAná»È:®~ÿ úá7Z °n÷Te•¤|*ç—\Ùá=­‚$Rlõ}†i'¼­©K%¬ó|ŸJ §»óŽÝºÆO5û”£9³ÏÑÔw§°®6þ4‡ð„Ø�§«nØu§-î‹ 0�ÞA f]üw/�HœO(Î)�ëMtOò#ëu$˜�:·ºFÒV6³Å>"q±Q¦9RǯvXS8¡é‰»T©6ÎGvÌ®h·K7ò‘ÇaØ‚Ùâr¼eL€ 0&°°ƒz+@fL€ l§ž¹ÄK‹’-Ž'Ï×܃é'¯Àúõûjêd¡Á`EZÚž0›GÃd̗źÛ@]ŠgV£­Ò,ûë¶÷×éêR)®~#‡œÝÚÿ ¡PE—ãZË63œäl²SÝ÷>ÉT×h±º3ÎiÄ5Q ëê3c²¤ y¿²rõ`»ù݃¤Ùì×¾9˜œ�©gF%õÍ‚Ž@}ƒþìb±³9…{¦Üç¬Ü½4ÿ,’±ß—-:%e;=åSg×Q8Œ =5…:«ÓŽÝõíÄÁ¶».&§‘bt­w]Ѱ,á©:¾,wêz‡Ü’ 0�^O rýŸ§HÅç`×£NHQ#®Ê˜‰½&_�!ûk“ƒ­^qæ dò+Þ˜rÃ=DU– ƒÜ›Nw4�×Ò‰ˆÓ™ú\­Ílõä—Ü­´5ÓUåÄB{|2»Àg€ٶѬ�;àJál—;à-`L€ 0�­C@óÏyë˜f+=NàìÒ¾HËÈ…Õꀑ3¥™`2‡èŒÊCп·‚âÅê_wv€S^í —#aZ˜Ä Œa:é1’½€Ÿ®ƒ=h«¯€X0�Ø‘Üò<\ñJ1ò‹¯ƒÃ}}÷µ�¼ÝçŒ,rCÿw2©ÌD�ÉZã݉K$…Ÿ)‘7®ëDÎáØSêFža©lÚÔ¤~T_©ëhÞê8@]Uº ŒˆZšßQë4J¥Ç¾‰éßžG³¼bG÷Ýdî‡+²AÌ‚W¦kÊJPÐïÛ˜H,-ùÐ÷¿ÃÓü ¼ _"à]Š(f/§�‡@Kã7@�þþº]g‘rnR®Ç2îúÿÍÑ÷/X‡•k÷‚¸¡ÕÕäi|îÌ;5›‹cJó¨Á¤[¦©×ŠØÖc¿þH …“¤§ßž‘Ž!×¾5Ó±‚âQ›Ð§Ù…GίOªº%‚™·`øøÿ!Íu.«¬¬ Ôå#[Ò-·eL ظ´ ›Þ@F‘þMåÁ~ˆœ�/aù÷·`£§ X-Ç«OCá�L¸‹JPг8„Ÿlâ³B‡�-¯ÆL…+ʧ�ø¬Ñà#Û7šôÔA?]«qbL€ 0&Ð;(ÿ{LjxÝCàô;vǰ1¿ÂHçFò—™h+&Gé#e9ßP{-î<ñ�-6zý»»£O¿_Ûí§žìÝzô–Ûk×W`Û€@é3¼5{Àb)¤YÓ9ô[˧C…àóÿŠïrxÛ6ÁJº’mgS�7Û¸úxL?c…æ\÷œ }G7jê„°öͶ éêõwõ8\®K%µÂw,•7­;÷œòƒ^ÓÉøn,éã5ë®\^‚GÎ\­©S ¯ywú÷û#.Jø [³z—¤…§~p Ý<˜o£‘ó6¿ŠÆÿECâ•ÀÃ?VÑ ¹š»ûqùXº ¤˜Õ/fßô}‘¾ÃÅÛÐ÷¯µåSÌÛ4"tÈ–¤¤ïvBgõõôßydçþ;K?>ÙŠ›?ôÿm9èªÏû)ÍÜöÀj;�¶bx&9ÙÕ1]†Ñéâ?Ÿ=yýŸ—Ú Ûÿ* ƒ2¨Óýp&À¶ì}ñZ:ÿÉŽ :ñ¤"aW¡—tÍ¢¸ùžPçç²ظpm‚†ñ—~sÔ’RÓRÀ_�€o¬ní™ØªNEtlø+ñûÇcÃoK£j#Œ³Åwß}ÑwÏ«šÉ…6ß,ûü¹ˆ?‹8ÔÃ|öº(Æ'áLFjªjÐ>óøé -hÄ.ÇÿOoÆ89âOGK¥ìÀ�÷O€úF@lg8Ø`L g ð êžå»ízÏ.<.r:=Ťҵ6� ‘œO·B¥Î]ôjí•Û}œ–8Ifí&{I³€ ô¥‡h?w`$u¸·üuØéÑýÄd2‡#s_k;¨ƒ¶Ô��–K3¸;ï v8ô´- â‚¥ëIšyªãœ½þºd}‡:à”…xøÇÊH¨”è%�ØDsÈp çábU_-­k¥/Mæ>*¹²`4d(‹œß xé†Lf©æžŠ…¼®™9Á²8l‡!;÷~ ÑS’T7jDåæËP6©MùCR½Ž«–ý5£ßoIB_p—ë*ÊvÙû=¢î!éG"~'ÒR†bi[�‰”In0ØávB¹/èÕ}©®ösrPGíR·æ´œ]êÆk¥ú7ÙºÏ:÷ĘÀ¶ °ys3~/Û £'ÿAOœÄŽBºCá6 )âE‡È�½qá&­öáu¿Ýny¤4ÓZÙ4“Ù’KŽeí’š Hh¶ä#Èá1õ¾ç”"è-zÕcò4kŒRŠTùϪ!§’N(rj4fœª~G ?�A³kÜ’£7ñ /òmñ£ÿÍ#óu‡á÷ÿ„òRáØïH £¡æFiv“\[ŒWöåÙ]ÉNö'/Bkë×ruÍmcÝ¿4å,Üq Ô5)fkìfÿ’•ô”C ò gj:§E£Á�~–ⱟ¸ý³Г ]¿é/f.û}_FF"¡åqQÙd*•eí;zä&bÛB3ç¤D?éw-ÞD>úŠ(£erpx[VË¢nÛ¾výš�-?¾éÖž½O·õÏ1&Ð; ¬[²ŸÜY„šu]ÿ‡¬PÀC¡@ާœöÓ+¾›®í¤�æš/±øóýðË;ýè,áüCqü­\=&“usºþyLªOÀ•ÙOS]½dcø?ÓŠ ѱ+¬jV×J|¾Mà30Mô×¥>9#tm±‚ 0&À˜@èúÅTŒ»ßBoÜ0“ņo§¡ ÿ“± Rƒ8]‘/P) Tm¡¥Hó»&ÌÅ”™ùÈÍ8 YÙOêö v�=]¬`Û �È£ô�ÐhéE‹••–›°q©…±o!™¸,ÓKa4{žƒÓ5E³B~á'´ àY¨Øøê²ZQXa†¹0ëQ¥† §`´f_Bèm™©«ë¨"-}/ݪ-žWtuZŠ9óŸS©dZ–ôqR<]WNw|~�æLõ``Ö¯; !4àáÉåê¼ÝI$ÍXÞ‚ý1¢Åÿ^èØ»qÃð=q»Ô[#ÅzϵžÜ6úϰ�'Ý»ÉúÉUoC¿�³É©= A£.†h-ЦÆ'QWU†M«ÿÀÌÒ- S¢î].…ÑTûÜ9—F´/ùçS¾{gjËÖx˘@o"àÇÜÿÅÅW#gôñÈt&¹ÇÒ±I#”GôúDŒ>à¯@cÅG¨[÷Ξ%$)wŠl„ìÿ v9ä=¤Ù´�{"ôFÕŠ‡±ìûи¾6ÖŸÕ¶Fý …±K2oýÉö‡XüÍ3hÚP«W³îcd÷¿$Vn/‡ÐTñ.VmJ5ÙŠò çìy¼!{à™pæNêDØ ø*ÐT™‚Åônk]GñÿûtN'£ÿ*±½ôá©þ4¼öw>6Ǩp† 0&À¶6éÿhke{[™À5o–ѣ̓bñ¨E jéE¿×ó,n;îânÑ}ß”Áf›¤Ù§‡.Ào:¬{íib!Ø� \YfCß>s‘fQÄSŒÎÅ&våËÖŒÂ}§‰XˆÉéî/†3㊸BÑ®²bÅŒ};®ëBîÞ9ÿ‚ÝIv9kWïŽNKu—lð�ツÅz¨J!ï÷¦õ»âž“Iº©N@~QòltŸ÷=,_|z·ÇÛU ˆ ½žÀôo?M^t³F]½ñ(Ü1ñóN÷tmY!ú R? .uý=úýßàši·ßûÊŸ…Íù·ø�€ÚK]Л¯å;4Ô>�æš9xô¢ÍíöÕ.x|ô]”ŒÆ"Ç�q^Z—båwÇx¸&À¶-�¾}mh2Zaq¥Ã‘f¥ÅŠÛh�uü5­¨ªj¥ÁiÏ–nÔØa(ʃËY€&Ïf7TSŸ^jš:ôYq±7¶7A ýtG %ñ1wŸî÷Á˜`L Çð êCÛ‹:®«xœœO“"±&¥«TmiÒ&Í ŽÏ"è®!7Ö=®ë ‡ºß^w�›ûaÛ �‡'·ÐL᱓ÿ Ž TÖâq/5©é·nLÒáº@òKmcDºõµÌWõß•‚Í~¶n³`h™®NOQWSŠ‚>jµ¶pR;]“é½7~x-ލpNG÷«±þFL=ò>ª“°£$á´shnx¦]uk˨®¾ ž¦õh øé)¡á(,~•b)×…•[<S?žˆi>Ô­£¥˜>y3�ç£p;4»Pãëi±ŒÃ”²<ØB¹4#y"Ö®|Šn²4$uU[û8ú8ÈAMIÄÉnnz õ ep t sL2ÖAÓŠ_�!T‘öIì–�Vi^e/¡ÜŠ´æ*L€ ìhÖ¯Ž`ñ=ÛÕ�) ßôªÀêNu¼q£pb÷ޤäÓ;FÄ£`L€ 0&°U°ƒz«`ÞÆFš[ÖÆB|ȱ'…sZ8sBáøãkÝ5Ì w­nW=aO×+˜ÀL@„±˜‰ qåCÿ„ƒòÉÊ-¥ÕÑP Î-GÚc™£1åU7²2�†¯m -Kä�ÅŸŽUPdÖ`ƒ¢Ôùì•ÿΦþ�‘†’w*Þ‡ˆ·-œí�Miîï阒]‰m�®Ëqó_‘±\R)Qtufk¢ .ïš¿Av¡b_”_{›_Å ãÿ¢¨ ²bÔ]pçç·!#ó¶]¼˜_ð¦~t4=}0;.l7FKóK‘§ tê-©Œüy“~Ðð¡ô~aRÍûNùMr�75þˆGÏÚ:³¤“¡Ì|¸ý÷yžžäŠÜL êÑæOýȾ¢9g™`L€ 0&À˜Øñ °ƒzÇÿŒA „y“Ô´ãÂY$ϾÚR&�6ýYÁ°·¥ãåöL`{&ððUÂÁû±ô*�cFuE>ÜöáH·ô'® �PÖoúž¿P<6I}ûþ6‡" O‚cN® ®Ó�[-×iok+P„!I¨ìk~3AÒ±bé¡ÜýÕS4[šâÚŠ;mÑ$vÃH ¿öùZ5UZá~õÜ7ù¹*o™êÓõ˜ IDAT<«�Ì«¥ïŒöâƒ6ÍÆŸKß±ÄH·YJßÁÜÈwP‡e~ág˜úáá˜vâW:5’Å�ž™)ÔÊ6ûTLvP‹:��½­ì·'òó—\ŠÁ¹/Áç«ÆkžÅô�CêÇí{b Ü'`L€ 0&À˜`½–;¨{íGÓ�kjiMvPÓõ¶âÃßýêF²§—Báî·§g‹åL`g# ·€XðO¼ôSš¹¿¾R¡ «qMY œ‹ÖQ¼Ø®Íxt9OSô¨Î¶´t>N¯èáʲlZøðÔHg²ï0ꨖ‹²¥0-·fåHG®Á˜€’@}ýmp8/„Õ~2ͲÖÿ‹0ö/Y ”ù?l^w6î?ãOeWíæíŽsÕu‡N_Sçg4_^Ö,Œ‡ ‘{—û�:ª…8Ü„µŒÂÃãØ÷2&Þª x<ïÂí&µNÊvKš§u´a¬Þt †¬¡ß‘E§PTTŽÒÿü¥Ç½Buä/j¼ú¥/å`ØÈJzÀ&äBázxŸ„·i&–µ-Úâ'ºç"`L€ 0&À˜`L`[ÐwLlËQmÛFíÙî¬Ápæì«k(ÌéùHK/‚ÙÖ‡b»ö!‡Hü4lD«gZ›¢ré+Xúõ4l}ǬzŸŒ(9 \9ƒáÈÚ öŒ¡d'b+ÍÚ‡ìö�Ñd¡ ^z²˜^!²ÕÖB¶¼ Q·îÌ]O¶Ê;j Ȇh¡¤H_bÖ´‡šÊ!ÑwØC.}y(rsþA‹)ž³9QÛÂþ��À‰Go€¯ù¬_r3ž¼”Ú¤HA+u®“¡ˆ½ß WÖ?È ~=^� åÖCK€‰d¯¥…ìýÙ¾=S,fL@‡À>#�xpõë9Hwí§}…ˆüµš gµÕ1‚TwP Ç›Á`×êN’­2u.>îõïîŽâ~¿¤täIþ?:n‰´vÍ8vNGPð»këBMDìÎ3šõÔÀ““=˜úþñÈï“úi€ì¼—ðÐ÷WÂÓüšÔ±ÁàÆ-GÜ*å­iÍï´¿uëŸB�·3&wïRb‘½ãw&À˜`L€ 0&À˜@¯ ½ŠïcÙ–ƒ0áø[ªaJËŒ "y‚“öàøDŒÓÊ•÷àÇ—o£º©:0aâíÕ0[ȵ—œÐ¢w‘é-ž�•ib•Èé%lÕn¸ŸÜßž-Ñ10þ<+ö?©&š�-^Fñ¢þÄ«Í_Žôô10™ÝRYÙ�·òE?BûQSy"".!MNç½`ŘQÚ Ÿù[ËißÇÐ~¸#;)š§ÀÕ{É#` `]%p͢]#h†õapÒìgSÚ¨XWÖŒÂ}§¥vè•~|µÉC“w.œ¶1ÈÌy*Ö^™ ´ýŠ«ØS)J™¿õƒ#‘[¬^p.LO³x=¯ÐXÿšÜ–ŽWuUÇmÇê;“±dg$ðÀܹ°XÐÝõ_wS ÷&]½PÜ÷õ›°ÙOOY'Q¹bYalÃ{ÊŸƒÍv <žÇÑÔð6}wá™KÚ›p™ 0&À˜`L€ 0&°#àÔâS-.N�;§»ø1Œf ¹û�kÂ_¾Y·Ù–ðÉÆÖ]"GŠœbrá Ž %u´ éÉVnÿ[pÂõ&|tŸ¾-¹O›+¬âC̤¶¤�§™á[¢,’pD‹$ÙŠdcïâ1æÜ‚Oiq¨¸é°ËbreÆUíH)Œæ…=))ö9ªÒÜtÄžfC2&Ð%œÛLíæG_ÓqñÓiÈÊ*B&<0yUÊ>/½Ù"Œ=¹¡|,B£U‹·LCª-ºõ“ó‘›ÿ|’rÓú}ÐØ¶#´ÔtÊÈžFmž¡—þ1)©Sìt)chʲIe<¨U.Æ·Ñ þ¶¶Åhš�lïêw`@ÿÕñúÊ\ô«ºbiFK‘‰Aª*l§¶ç©ž§ßiÒSÙKÙ’•L€ ô6RX!ñ8G4U¯™Ûn ká¤6#ù ç©{Mî&i+d¼öí¡Ir0�‹Ÿ¶ãÖ�N@Iÿ—;ÃßZŽªÊÓѰŽßì0®Ä˜`L€ 0&À˜hŸÏ nŸ‘~ oí|d�®_¡5Í óáÎ�ØîšÐœèûMiMç‘´ éÏòf®ñ#¢]“aÙ•$Ï¢6 ´íÊ´áp;ö’½ɨg/EV1&°}xòRñû+úÒ�aí©O^¨¶ºúö×ßÏü‚ÇHy¬~Öìt.})ÃFVÒÿ©þÍúP¨ž6|Þ¦™XöÛ¢”7tw:€¼ÃL€ 0&À˜`L€ 0�î!ÀêŽs.aqK¯]Ež6l«“¶Ýÿµµ—»ú¢¶|uqç°lPv7Éým’cZ8›élKí0.½-ˆˆöKC‘F#Û¥‚ÉT¤oTC¶co|�ý¬Ñ0*2™;gO¿'Ö0&л $ǰžòŸt`94<|æ’6Ü÷Í´¸â™š»•n=÷}ûª«¯Ãô“WhÖaáÎEÀšfÐtNû}sÐØðê¼å˜1¹jç‚Â{˘`L€ 0&À˜ØúØA­ÍÜ€~{ B~Éqpå�ƒ#ç0˜ÌÙÚU·XjÀ�!—l¹ó¢¶Ò²¥8Ïb–²4S9Ñ1L6%±ä-:àŸŽ…é�Õ¢ÉA¨O½ôø}xn(v¯´+žÌ…[R·OÐi6ZÊ$ìý·—X·³öÛs™ 0�í—ÀŒãZS~Áê‹°ç°10›†kÖ³YOAqñþ¤+ÖÔ³pç" ñ¼§üyº©q <žÇÑÔð6êªAÜìàĘ`L€ 0&À˜`[�;¨Õ¨ uüÉ8æ%ÍΈJ8�%¯¬ºæ–— ØýD²µ×Käü&[²:êt–úNdÊH¢¨\J,l«²¾Þ æS?b-CÑ_´OÙQ-bQ·—‚më`° �ªIæ¢mÄ"‹¡àºöšwZ ¬#&{‰�…Ž`L@‹À+ç6ÃW¶+†÷†+{2-ðzŒÆLUÕ`ÛbU™ ;7�Öò‹pcé…;7Þ{&À˜`L€ 0&À˜À¶%Àj%ÿqÿx™… 1¥Ûsà&ê;â0&£‡þ“lEãW G¯h&º’› ²ì´Ž™ Œ¬ISR}½´Õ¥ÅCÔF8¶cy±`bP¯Q\û¢Æ"21^‘Ä&Ø åÛ}‹¶i·UÈžNê°=�ö,fL`Ç&0s²8¨ý}]�)¯ºá°†Å6ŠœÕ6x7¾±cà½ëi¡ÎNµàÊL€ 0&À˜`L€ 0&ÐÍØA-{æ ÉÎ騲¹ú3l^ö4|M›`¶¤#ÝÕVÇ ¸‹&À–1Vî"²crƆ„7X'í{ö È Gx´ªª–§æ3T­|�ÆM0ÙÒaqöƒÝ9®Â °“-¥?Z¶à°É9UW±‚¯Î  ñ"Ç´"Íá‹CÉ Év£ñ·-•«Å¶uY ãQ ú‹QÉÉž”D;åSQË^¤2¿3&À’ Ì8§‘„ÿ‹¾’õ,aL€ 0&À˜`L€ 0&À¶)vP üCöc(Úå ~œüa¬ýß%øõýg’$qè×6¾\S²j;b‡<…#îÑl³î÷KðÓ›Ú¶ö<™lX™A­'9qÛüÚ¶d#­ž¨ƒZžEMmbNêPê¶R†LÉÁ-ò²¯YžEímš#›‰m +¨VI¬¨Î„Û·g {zÉÛ’lO¯.Ë™`L€ 0&À˜`L€ 0&À˜èÕØA->žì!'Æ|Ó²VþØ~}ÿE9›´5Ñã⚉Èém&MUnɉq¹p4 ƒ´ߟþx1®KÈ™A¶D}‘¨®œ™4£¶­He ÏiÔžA-B|Èžf¹r¶´ÔH³­­1ƒ²]™SMÕ„€¹0Á -E�rˤf’ fO”dcŠª~O²=…š³L€ 0&À˜`L€ 0&À˜`L€ l?‰ÛÏÀ»u¤™E§ÆfO+}¢a¬~][陃uu 9u5RVñ©*©l/,¦4/La˱%êKmä m:¶dC�U¦˜ƒZ˜ñ­ÅV,�(í¢\Qc[™g�µ�-°C0X‰g.©IjÕJöºš*GÚu› {ž•lO·+˜`L€ 0&À˜`L€ 0&À˜èÍØA ˜�î¥ú�„ïW$ƒ/YŸ‘-KÝ.Ò*òn²;•ÅhÞ‹#ÒFZQH…“˜6íÙ²fŒŠO(ŽPlÄ+ͤe‹Ñd5ÇÔ²sZÞ†Ú ñ4�ˆ8²©/ɽIc§mÍæË£RÙRd {IIj,ÚêómœÆIMeACµ¶=YÏ[&À˜`L€ 0&À˜`L€ 0&À¶+©�…ÛÕ®tu°CR‡90z€fÏ}Fä »Ïš:!´;‹“u ¶„ÏVN"?`[ûä ³ˆl‰Jô’6Ѽ(¤;4lÉÓÖbŠ8¨¥Ó¢=½¤™Ôb5Ò5“³ùÅwK³¬ÅLkék@Óú÷’�Ä‘Ejª§• †Ôör ïÖjFc f¥¶=Í,dL€ 0&À˜`L€ 0&À˜`L ·`5–·’ãU?´Æð£ÿƒ‚ÁùŠÒ€¾Ãú`ôÉóa0Z"r�°ÊYOR´‰fm g¯PE�¹»A¶F«m ۿƱ%ªÉ³—åfB–ÕGÖ¨M¡ô´˜C:æhކøHK�‹žzã¯P/Lx^©×–½‹íȈC› Û²“ºbñ˜qY«lBµ Òä]RÉEÁœ6÷”?‡+^H°÷‚÷–¿kú‘Im„ ªRßžf2&À˜`L€ 0&À˜`L€ 0&ÐÛ hxV{û�{`|‡]6޵c4‘L[ë&ø›—Àž5.Ž£ý�¬™!6þP†ª*O¬òáWDl)û7ÈÚŠl°MmKÒGur]±U¾Ö/¼5+ʰ°yÂzé~„üÑKL¢L“�…Œ&YÃhð£Íÿ=ÒÓ‡ÂbíÓ ;±v”on|wžx©Ü}ÒöÊ—ú`à.ë¥�¡êº)ŽØ3™†Âdî£[¯¹éIÜx˜¾=݆¬`L€ 0&À˜`L€ 0&À˜`L 7 Ï$',ùúŸíRHK/‚#{|‡�Ó¢Ã{=‡AG\¥ê{Õ÷dKÌDVH¥YÑŠ²ÉRDŽðñäà�|>RÝhe]!’_}G=‡¾»©mÉ]úm‘�Ò hj oåEår¤ÛÆÃ˜Ö'¶€¢u";©¥˜Ôвä�¦²\?ÐV��«ŽÀ=§ÞBÝjY—­­>_¬ Úw%…BÕ¨¨8Soß^Wúç6L€ 0&À˜`L€ 0&À˜`L€ lsíxa·ùø¶î°Fò>Ò¬âá)VoãO¨_ÿ:6ýö 6,®‰ .¿¤{Ÿ½€â+çÆd~ï lZt;~ûèU’):‰ÖJ¶†Œ�ØR†í�Ôô±øÈVÙZ;_m«dßìq¤YÈÕmÛ|+P¹üv|÷¢¶-ÑçYÓçÁæ+MÊn®{ o!oàßáÌ<&Þƒ&=Ka>äp´a=ü-sÐTý *?Fi)M¡î`šþÝïhn~ .÷ß‘n=&eþÖ9¨¯æŸ;g/e§¬dL€ 0&À˜`L€ 0&À˜`L 7`µÖ§R\l‡!7éÎ"ø}uhÛ° ›7{©j²£YÙ¾o_ͦ6R]±x`@©ÒÍ˶YEð6uÒV6ÙÊ&[å³µ×^i@qæ$ö%’Æ�7Üç€1ÏMq§³ápÛh­GØÐ€5ÕÕ˜ÿL›\µÓÛ‹Ÿ&{HÃ3—(앚±ïHÚ‚n¤¥gÃl¶Áç¯G°¥^o5Õíº½N�0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L€ 0&À˜`L`ç"`عv—÷– 0&À˜`L€ 0&À˜`L€ $˜TfB!²a åf,éN„@ ­ þ@3ZQ�''{Zq‘ 0�n Àên€È]0&À˜`L€ 0&À˜`L€ lg¦ü'Yác�™U sÚêÑ+]fáˆ*ªFeÅy¸{â'êº\bL`K(m[Ò·eL€ 0&À˜`L€ 0&À˜`Û�©Ÿˆ¼‚™0,‘G�бÑG]fb#©úÍ›öÇ]'þ7V•3L€ lãµæÆL€ 0&À˜`L€ 0&À˜`L`{"pçìëQPøŒ²sZkðQ‡tÌ/­˜ãiµ®Õ‚eL€ t�€¹k͸`L€ 0&À˜`L€ 0&À˜ØÎ\÷Þ>È̾72+Z{Ô í÷ÿ„æ¦×5!Ý>6Ûñ0š²›EÍ´úçË-yÛESžÏCɈ٨­¾æ_ÊQZêbOÜl ÀêàCä]`L€ 0&À˜`L€ 0&À˜è�‚—ŽM‹Ž7ð6¿ŠÆŸûÿì]€UÒ®ž¸;›3`wÉAQ@D1a@OQÔ»3ûë%îÔ3žkÄœð<õ<õÔÓ;8Ãþæ„bÂ"+,°,°,›ã¤þ«^wÏtÏt÷Ì\=˜éëÕûÞëÙîïUWc†Vø¨(¼ìoà+9²rn§«ÛvBËïDr¬Oä'ü~¿�#¾„K†N‡;Îìè“,n4àÐ=Ÿ0àÇÂ`F€`F€`F€`F€`̘ÿL ¾Þ´pÃÆ ¸sÎÓ2-ó÷Ï É™wÎ]¥eñ±�ÜýQ5þÃ"­é”ó§bZÛ ˆqdÏG€-¨÷ü9æ2Œ#À0Œ#À0Œ#À0Œ#ÀdgL³áóo7[–iw�¾I‹ò±üöïyršD9ù0ÿÉApÏ[ú!™›Pø%‰tâXmF€`F€`F€`F€`�^ àË:ɲöÒª eì\òò�1˜š‘cšÏ™{<LPïñSÌdF€`F€`F€`F€>�ã`@ï·r¸=.›3vY9Wš f˜çs»øØÓg˜ÇÇ0Œ#À0Œ#À0Œ#À0Œ#àvV=«¯f ËM; ™ö~”çÝçG~6´uu£çµY÷�òª®ÃOɳ—+¤ªÊ×^+ƒ$õ®]¬-}Êb'”w§€Ã�!�¤Ž.hMé�&è‚%sýZµ„Ç_ÿ#ÜžÑæÃqy¶·¬°»`•Ä ,µç‚×E‹¥#é—CÊ({ÁãYàrz §¹]Ôc Ç+PÏĦ5«Ë0Œ#À0Œ#À0Œ#À0Œ#ÀØ!@DpVålðzŠÑÉq de|žl IDATß­®Rbt‡;¡µéòh™.ÖÙó ,<þÝHÎÕÿ™ iésЇr¸\% 9ŠÐrÁŠhãöó ê˜G#õ‰(î;2rOƒ”Ôàvï¯ÔUûÿâÛTxüœnQÿÊg'BzίÀ—6eŠÈ H8Üí­·CðƒÛ�°Ê(qùó“ +ç7�šz¶Í6”ûýŸBýÆŸÁm§×òíó^öBŽtde.—gäÝ­ÉãPp3tv<­� áÖ¹-qbõóàI=R}'›Ô]ÝÏ�¿si\{-#öõG?$’;+b%!Vê\Ð@±Ú–«Þ®�eèH1¯ÞÔcpí”jCÇP¨šv\×û¤!ŸW<7Ò3ÏFÌŽVžÐtÅ2YCKó¡vݽðð…�¸¶(C7ª¤5«Ê0Œ#À0Œ#À0Œ#À0Œ#ÀØ!pý«¿‚켿XWÑh1½‘1æQ¶È¯Ph-,8`¤�AD㈅L¶ªÔ §B^ÎÅ�‘u-Ò)VÕaýzÜ=· .[< Ê*¿³¬§Ôo9 n<þm-)ŽW, Å•+ y± YÂÅû»c³ãÒôò²+ -óqeÉdlÚ0n?y­¡ª˜‡|uôXj%—Xñ…²s†î\¬´u@* ~vXõf –¥ƒBzÆÿ$5¸æ àO³îÁþ%¸ú§B^á_�”ol£«PYî„•_– I¿9`l¼Û¦Øõn;5¬#À0Œ#À0Œ#À0Œ#À0Œ@?HðâC"KMS}–Ó9ë(¬à}G'veáN 7¼±**Û!3g¡-9M»{®Bx‡zæ1fÈT¤~\Ž’˜B´úu%æ÷È»ªÊÞÕïÅ‹‡ÀÈ1[ûLN“b9¹Çé ÎƒX“ZÉded ‹;¬tBvVɬ�wo¸ñÍ›`ÔØ†¤ÉiR;;ïn¸åíážå[¡¨ôƒxrZ76}T’|0tÔÝú¬�O¼€ÚˆX_F€`F€`F€`F€`F £uyïAÐHk<Êà‡––�V˜Uòç¼½þT —V!#ãRt%ròÉȹ% dý�ÏQŒRicx-4ï˜JžNz o-9½ºB%º!¸Û.€`h}\™>cåXkð’' ahÅꈫ};-.‡í­Ç‰D—åíZõÈQÌC,"•m"ÝÝoÀ�§ïK¬´¶*™ß'¬T¼­°ÒÖ¹± é™ó!3ËâE�V�Ô|_Æ…àtš×ŠY úJ¾´s`Þâ}Ö@ŠÛŒl ƒueF€`F€`F€`F€`bP­Ÿ/xØ{M4·€&Ê Û2BL›À-KŸ@ŸÂ¿Œ/ŠÉ ‡·¢æg±îéè:×PÚ¸mT÷œ!ï”Å8¨|3ÖÍW¬¦ ¥€¾Š×eî¶äòg* d¸5I½v{ ,:ÆüÅz÷,ß®ôÓ_0¸ 6Õ͆ÚÐ|bªP¿(€TïHÈÎ^)¾ÙJ •b¬Û°?Ü2Ç„¼Uçaá;÷CZÆobzQ’ uGÂõÇ¿iZ&,ÈcVZ+Õi‹ÕóˆUb¥«¯‰ ãÚzk¬”zRRk@–q“£ñbhïø 2Ò'£?é? êr}W–ñ޶ µíiôu^ YYçƒ'奮Ù_[;n;ñKy»q�õÎÉn¬4«Æ0Œ#À0Œ#À0Œ#À0Œ#À$F€¬ŸñS²%d]W—ªõ GË24î¸Â²T+hi¾æO)�+gþ¶ÖMÒ²ÑʸÚš¯ƒk�}>’§E–ÌõCGëýJ’ˆH 2R«¯?Þrz�ðŸ¬ÏÓÇÛ¶™³±óˇ q“°}Û¯àî9ë9MÅU¨ßÝs7ÃÍ'¼—r<|º:]X•‡?€¿çCsršªø†ÂÍ”2 -´Íæ�òL€0`¥IÔª&Àí–û†•Ö é“h ȆïÖB¿ÒÂms>†kŽZë>¡àQ1±úm'À3 Oøn8v1\2íH|Iæ}f0D$øÜe‘ø‹0A=À&ŒÕeF€`F€`F€`F€ø‰Xª·Õ€\u\sÄMXGaJ‰]ÿulX[ON‡«Ž¨Bwæ,jW÷×FÙæÕŒuÔT-�{Òrc^ħÐî·qã“gvuÁÔáÐþÆ!º–æQ"çwfˆÃªÂû‚•^¼íÀ½€Ö¦+á/¿hÒ7�EõÀæMª%´¡$š7À�ǽÍPcþ÷€n�Ë×2œîaZt ™ h3Æú2Œ#À0Œ#À0Œ#À0Œ#Àü´�õ®]hoº+®øîóáΟ7(VÂq¥Ñ ÙŒüN’¤…â}@G%›ÇRRö‰/ cküæ\_f‘SU¥¾ Ñ¢\d‡w.AmŠ•]ÿº2K¬’ÄÚt ¨¸Q7�ÍÏêz‹F-ÝMÖ�Ú¶£ýA¬¯DUUÚÛEÅÄÜ&¨c á$#À0Œ#À0Œ#À0Œ#À0Œ#°›#@¤`ƒ�5púîk�C/#Œç,ã»�LˆÏøZ†œžÀj#ªbB‡¬œá¦7o†y÷Å¿œÑ $É„,w%Y3¹j–X%Ó\�a«}’i«Ö1¬�˜µäZ»3ééyݲ?ZP[…žîw㋨_ññÄ— Œ¶ óÄZ2Œ#À0Œ#À0Œ#À0Œ#ÀìN„C[,Õ B£eY¢¿œ„%²•ýi÷24·­2¶P‰p�ÏȺ†Ð 7¼q\òD¡±n/Sá�lA½S°ÒÚ˱PõÈ ‚8&„]19Ѥß³�¡kZ¯«žîÚ¨ŠéÚIÒ€åy¬âÆÉà#À0Œ#À0Œ#À0Œ#À0Œ#Ð[úANÊr›eoR›59iÙH-p‚Í 56q ‘¨Éý§×AWû#Æj„‹öÁ¨$y +ûF2fÜñáÇpÕsÓ ªª÷¼bˆ^„¸Ã��U¬ê‘5 a¥;·Zoý›Œ¢tíBÐc,Ó¥ä€êÓZXLë 0*ËNcÆÀIõ~! œ±±¦Œ#À0Œ#°§!0ïѸëÃ/áêÿÌìÓñž†�‡`F€`Fà§DÀšHlö�d†‰­ìcèƒ5õTûíï ˆ±êµPÁãžEƒ—AÎÑ-pý«¿ƒw¥ZԌϖw2A-°ÒYÇ÷h“#YÈ6­ Ea2ÙP1&ëÍ ÄTÖ%»œ6…lA­CŠ£Œ#À0Œ#Àì"rŠŽ—{_(,~ 2Žø 1LÛE=±XF€`F€`�=�¾™@„ÃÖd¡ßÓòÓÑ�¶º&Ê^tQ´¾> ÚZnMT5R.9Ò!;oTLk€«^œÉ·�ìd‚«X>ßĺØT§�³Í0íSÍt„¬77ë… ¨î_tך¥»$Y·³Óe7(c êÝ`XF€`F€H�œÜ«"5Ýž P6ªÓöB,2Ž0Œ#À0Œ#À D¬ÎŒ¶XÖ4ùñ9m,¨¥Dnúa\U†«¿j«K¡³ã±¤–$ Z7¿™˜ÜvôË}I¼J¦X©ämRXõ}šâ•éENXî[Ç^¿M;iç¼È²ÃØYU™ ÞYH²F€`F€صüöïyàt 3tâpäÃü'ò8Á0Œ#À0Œ#Àü8Xójm}7¢pºlHHgŠýÐlšÚ7Œ–Þ†>©/Ÿq.¬[‘ƒÕW¢oc´Ð&–žu\öïýljØ!\n)ÁØLš÷+ë퓎,³Ü–%v²Ã¦]Øz]ÙÉ”äÞãg'ïG,ëÛ€D¹+F€`F€`yùǘ"‘êÍ1ÍçLF€`F€`F@C`åXd@-È[©Ï–§.Mü�vtBw6¼xNšM¡Éî9§-ªÂû5>زe„+Lj³J¿fÌH”"•TµÂެDµ{Už+iÉbåpX[-ÛmR8Ází„m\|ب ‡Ï®xw.c‚zwžÖ�`F€`¢då\MècŽ }ŠãŒ#À0Œ#À0Œ@ãVÙ�³}°ÜHθ~´Œd N­¾þØcc°ìpU꫚ĭ_Xèìî¸dnÿ.,8poظa…6™ô«d9¹¶/MT=(+¤´~JpóÀåÌ´”kUЬЬd°¶Zöømð–¬ jdš­†k›ïpX�ǶáO_hÆO¯kÀ0Œ#ÀìYÈT]§\…]{­ ’daÂñ#ŒºªÊíCS!àJ‡—:ýͰÕÓtñ¹+õWWœî”Tp¥¦áŧÁžn�zz {C;TUE.UM»ÿõ?rÀímZ.�y~¿r%X°8ü]>HG}ýÐ_®j…¥ ôì}—ÚU¹ýZ8zž²eCGK'üç6›7~÷^nÁ0Œ#À0ŒÀuÅäZŒT‚¾YžJ6V°MÚužE§6Ù‡õË=ÞÉ6-‘÷ud+åZ÷ºËÌ`ÈÆ­„­Ôhá'óî•û¯ÆkúÊh�.æ(/ÄÔ]N4*…º¢ Šéôsº‹�eI¤v V±ý vÉbeg}Ÿ™ªMBl8O’õ\8Ázã#^’šƒ]IR¾eñn^Àõn>A¬#À0ŒÀF`ÁâT(*|RRgá&8^†ƒ9VÐ"ŒßûI_>òô¼û[$h­= U½ã‚`û‘àõý/ë¡iÙö/¸ãÌz}V\ü”ÅN•zdd�©©§@.]/é.G`ò åÍà÷¿Íõ×ÂÍs¾ˆ“Ñ›Œ‹Ÿ.‚ÜœY�–~xR³¼!€½î8r94nù�¡Ïy÷y!«r6Ž»<©[v��3nxm_ËòpØ×ý�e¹V ãÂÕÿ;Ò3¾ôsñÏh QQp¬Fèé\ íoÚ®¿"¡ocÞ¢ þÝ£3!3k8Üx_‚k¡$g^A*×aõµçÁ¢sÕÔÀµà€šÌq�Sp¤¦Ï@ìö�Ô¥J­¾T$Ê»#õ9Â0Œ#À0Œ#��’Y¨‹Òõ°dgÍj'ÚÆbÕ•Ó7+XêN‚W§ƒÛ=¯]ø17ðp¹Ð¨CŸîZŸD¸ÓŒ×·:±½Š.º¨®{å&ÈÉÄ´][C³i>eúåmJYŒn”éKû9~ߤ”'ùÝo¬ÌúAÝ’ÅJkc™‡5ÑlGPk÷ fªÙå9œ½'øíäýˆeLPÿˆ`sWŒ#À0ÿed 1­\d™œ.„ÓÒ0½+\b^‰r»Î„Ââ¿ÈäØÊa™.€ï�ÍŽ¤¯~áÈ/~R!ʵ\“‹BZ\¤¤ƒ†·/{6n9ÍÝ®µHêxÙ3%�Wz/’à''UŸ*yÜS°ÏÏá÷Ï �»NW,ydçý%¡ŒTßI@»pÁC�ÂÃZ[¢\õÜ4¸çãBQi©©í%Û’” ^ìË“zL ÝåOŸwüümÓ6”I${qÅ[øbLàG@®©‚È À)w¥BIþÅ \ 1ä¸RCù.hÑî8ô¹gF€`F€°C ¦Ão0¡»³kkUæ�¬ýA›¬ÉI+yZ~·¿S‹šý“Áü·âÊè…‚l·—ì Ëæ­qí(ãæ·ï„î®÷ ¡æ-xà·í¦uô™¡°¹��nÇëî}UC¼½³Ñ�Ö'ˆ|?û±xüœä�1úŒÕÿªXéÐÅí°ÒU°ñAí ØmRXs²á°µuµ¡o}ç\’èIºW°Xúú»WܨÝKSÖ†`F€htt­I¬2^?ø2ça=kÒÑížðÃáÊ3틬qoYú7(,}ÉHN›Ö6fzSfÁˆÊzXðˆÕÃ�Æú”ºæ¥¹P6|s¯Èi½”´Ì©º¤¹Uˆ®BÒÑŒ ‹® Õ4]Œ ^N—99­u¢‘Ì‚h¦k>)І¼7¾þ:œRen9±hž�…5Ê 1ÞÔѰà‰0nl;ä.Œ³ÜÖúGl°äîä/Ø m9Á0Œ#À0ŒÀ1ŸÐtFŸ~Ɇ Nsö� ^ô {—nEE¯Â‹ÇF´§'.¯ø÷(-_É3‹äåšÅ\ùìDHÏø=ä¾£÷oƒ;Þ_dà2oqT-6^çÒýÅ‚g‡BnÁ]f]@wç?MóµÌ†µdœcFWþ5®ð²gË êå3ãò)#)¬^0ÁªÄ«‚|s¬b•pØø –Ò¬yWÉiMB»FÌcû´¹u„_ÿCuñ×h·Î°¾Þ­ÕfåF€`�€À¹ñ"ñðùŽCrV¼ÆÚŸa¼8Þ¼>n�knipõ‹3 pÐ;ñíÕ¿ÿCذþTXôËZCrYqço�Ç{¨!_Ÿ�eômc­Ku»»Ÿ‡Ë¦Û[(S½߸2³¯¦¨e�åNugß¼Jmí¸íÄODáï ¥•ߘWìEnwÏpÙAG!¡{"Á­ï-¶%Óå0’Á*>DP[}Zšî�›Ž_`ªÕE�Ï…ìÂKÀãA�$ƒj©ª˜ÅÕ"SY=]ŸÃÂ÷3-ãLF€`F€`�X$¸ìÙRKø” cˆ0Úˆ­¡¥k7L—#jpóI+´"Ãñ’'ÒÀ�YRØEe_âµ­¹%ìöúS¡«gU¤í†àê^½ïå¶wÿ)¾Ù‘öf‘P¸ÂÁMàöL0+6Í …êaSÍt¸ë´ï#å7¼QYÙ×Fұ ®9܃}á5­E ëéï¿«€?ŸµÃ¢†’M¸Ç;-¾ŽzFÛÛ—«¼Þ#Ñ�¤\Ô]¶Þkêb/¬Âˆ½Ü1‚•ÝE·ªY8\×±¢"m p Nb ÜqÒJl¥vˆ÷h/ %E·áS §ª=ím†ÆæEæ†o¾‡%UQ£—ù�eÃн›”&cVASý¥àúêUtcnånìm·H™ŸD»…j¬#À0Œ#0ÀP\JüGñܶ /0Ñu†!è/(\Xôµ¡XKÜ8{)œ²Ø Ó+{´¬È±aëIpýìç#i}ä¦7¯‚Ì$§õý¨šΆmψ <"ÒËÊ/Dw‹ôÍ#ñ””�Èâ[ç~É‹�\ùâa–ät8Ü õµ‡B]ë*ñ¸ç ÏoV9äæ-€Ô´³":†ÛèâM ¢?áº`á»÷CZÚo´"ñ¡îH¸þø7 y‘„¸È5+\÷ʹ–ätsã¥ÐÔòg¸{n—x̰8k ” +ÔÇŒ¤ÎÈšÜ{7<|ñÆH×Zä¾³ct \þÜ�–ñK-Û0-z á­ÐÞú,¤g�gõÞ¸íæH{Ž0Œ#À0Œ#ÀØ#põ‹' ¡‡ùµrl˲òO Y—<‘Žïxé0äÑ;]† m�æé/⢹"VPø/cΆ}0�¼ñEcãuP’€ v:òÁéÉ7ö“ åtBVÎaX+JP'h‚»$‹Ç+}ZŒYÆ×Н]7*!9M}5l:J†¯7v«’Ó”é@3³¯ŒÜ#h‡¹K0Z£%#Çd°r V§Š•Å"Õˆ]¢Äb%Ö@¥n Ä6Ò¥µ5pÉE‘÷U½räVþ]W+>šžñ[´hÿ­(Hq‹Ç—#•:ýQ²Ú`I­Ž‰Ü¤ÐÓ³ur%¶©‰´ÛÍ#LPïæÄê1Œ#ÀìÈPW;†�!¨ucKóMÆ”9AMÕJ‚9ºÚѨ£ë¥hBûý?GâEÝ J]ìé.švÌÇ—F/Š"ý~´€Î޶ÑÉ¢hvá|ü>/&WIÎ{*è1C³ m�uգѺ»5R, Kfzq }Ά ú ” >YX*ÇÞhVÏ¡7±nÌ84�´×êiy‰Ž—.dùR—–¦àOGÝ¡øÀ{.}ö`Tü¾‚%á©Ã”*—Žú7~ïOQ“ CCí�6 jl§oª�7Õ_ ÷œI$´ g/¼*&¬²ÂáNhÝq;hìÊ(ÀVF‚:­CqË`qYjÛK*ºuë A}ˉøäÜ;*בּ•-ôw¿;¶]íÝ›aøÈõ–ÖÝ-MFÿÕM;ž¶µ Žö€1“ÁÓ‹[êÎ�ûO¯3TµJÜrz ºÉ»�i®Sª�ÌØ ¿HƲ°Ü )_ǃP³¤±ÒÉì+VÚˆU×4­båò‘+ÁzQ…È÷ÞoYÇG ê‡/ì‚{?mǹM·¦õ[c_g÷)e‚z÷™ Ö„`F`OF༻ûãÍàtšû9NI=‡ÿˆ%dqa �m…ª¹ºt]qIé}º”1ÚÐð˜1CMÕ}dÚ15<žcr¢ÉBt_aõhcKÓï ät´U4öð…�˜x"ša#× "˜\›TO˜•“½e�Ö͘–Ý>ç¸é­7À›r„ ˜éúV³¦¦ �w2œw9üíwLÛ·4âE)Ö£v‘ KøÑ}Ç=gÞ)züŠôm�.´Xy¦Š“ÄÊgDŠ9Â0ŒÀNE`ôÌ#aä!¯%”¹îÓÓ`ÅÿÅX&lµ‡Tî…±ÃfAéÞU�’±¯6(=­¢ûUú fùÙ°úMóÍdMF`×!ÐÑþ>%Ø;ù²ì‡ÎÎÁ�Mq ÉpaŸå›ðš~°R–äµiw÷«Ð¾Å≿¸^¢Wúk¸üß㋼Ÿ�¸¹ˆ–*±Pp3´¶Ü Í­�áÓÑ^þüP\ú^§ã¦#ÏÇÐÓý¨Ûüpœ•3¹û˜ÿL%”•= ž”iŠ`«oõ—N–ƒØol­{0NžUS}þÕG^�ﺹ †V‰žGÞcø%¥=ÒO¡«í_ðMë"tuÖ‹0ēŪ±jìVb |¬[-Œ 9ÄO> u«"í�ïAvn$iñ÷¼íMOÆÔ‘á»ï‡@yÉBt#9$Gîx°r¼èn†\™ø{Þ‚”o?�i·['õKwkEY9F€`F`À#pÝ+çYZíÒÞÅûÓ…EÌ™:ê›ß¾óšgÀ`ÃúqpçÜèÅŽVxñÓE0lÄV-i8+àîmÈÓ'îý$€9º l�:Mv`U]¦æÝç…áSѯ4’¨fá»õðÀÜþ[�ÝðÆ|¼N}‹Qزù`Xø³efÝ›æ‘ϸ!cÌu"?~ ¦�µ�y¸lÉIPPü¬�˜$5V§ãæ�?Ÿÿžyc̽þu�òÕ¥`û¦_Àýç?mÙ– F€Ø•L¿àQÈ)='a ëî„ÿ~IÂz{Z…q³Ž—*§,Á¿‘ýOwRÃ\ýúT¨þàã¤êr%F€`Ì�Ðï±Ȫ[ AW`ø� P¸ª3¡Ÿá òÁCt!Q�äϺã›�îø %¤äM·lèþÀ²Œ ¶oYùƒ0BŠàG#§5¦9%�°³&¨ÉU‡Cµb1Ü"`¢£Ù~nP0F€`v-›^NŠ vy-þ�í2Í~rÁŽI§ýQ.sKŸÉ‚—™ î3~Ü�`Yõ‡Ý�ñÊH:ÐÓŠ_˜tuAß#\ñ™ß—ôBRïª"�þ8 ë>ñQ›öFïHo?"V‘>9ÒOÌ­�ú)”›3Œ#À0Œ€ ‹ænÇ·_o6)Q²RsÌ-›<’‹[Fc­-7ZZøÒO³ì#ª±,#æ×é-70¨iŽ´h™óe—§eüßiÑ~Ãh¥aP‡Hê>_êq–-Á-–eT°¾±)JL£BDP ¢š 1îM™L1ËBùjCÊko�>’i(ä#À0?ß¼ò|´¸¶~wõ�ÐÛ®ébÐð8â’/aÔÌ™ØÁι׭œº¿FNky´#tµ| uß̇�ŸŸÍ›Ÿ„PÀüw¼£~@=f½k&‡¥2Œ#À0Ö°µ56\Â0Œ#Àì|Ú[o…¬\sÿЙ?Ãã]U¤í§HcóSqyJ†^½éÙ<8¤"¸üù õ8!Np»Üàðf‚Û923Ήº÷ Æ4&t„ÉbÃ|g3t){2\W1‰h(DÖý6ž2|i§‹£ÙW8lîE«»´*G#GÄÕ oê!ZUÓ£,·ó±�ÚzRãñ5Væ#À0»�0l_‰/ö[y3>ørt>H5JVûÁÚ•jôCvѸã–ˆÔ IDAT„o葇¼C&| ß<5¶më×o«4bÚß5� £o®{ –=DµìGE½üü (=ð({#¸SË!ê„•ÞÑdð‘`F€`â`‚:ÎaF€`ví-ÿkIPûÒÎÅŽÿ×yz†ñÍxd…}÷\sKì rYºÜ Áéÿ#>ÂMF\OJñÚí¶V…\Š<~N�–Ǫ*8ƒ yúDÈäÅ2úòÞÄeY!¨I/3ý’•uÊb'êlýV’p¸>�(èe'ôa=MµU°(íp$x OX‡!ÖW›Š>å®�8ò#À0?-2l­¾†NÖÔú«ŸV9ÛÞ�¾*Rž’9&ž_¯ÜTˆy}À }+À›>:"S©þ„,Íãå64´AÞ‚¯ñS²×`ôÝšP­ûí× á8#À0Œ#À;ç±'Æ’`F€`’CàÖ¹›�ØìTXÖ˜&G6ú¡Î6äÊø²�Tßi†¼Öæk i}"3•^´hˆÙÕ>U´lª¦ÛëÏÁ¤ñF|G®[_%nLaçÎ DP«Ýµè]i1:Ç5O‰Ë‰Í7E²4’Z;5‘2³H8P²q†q`¢ ¬ßJn&‹óF€ØUt6ý°«Dï2¹£óÀãf�ïòäCþë�TCe“DÑIS¾åKó�b}µº›`ã—ñ/3Ö×á8#À0Œ#À0AÍk€`F€ø‘�¡½õ^ó>‘NÏß×Pvù’ÁøÆmãOõõ/êè!¿WŸŒÒ±Œ³±–!Ed+‘§ÁÐzèêú7l^?nœýoC‘È�é‹2uý8]%ñmú˜F‡$"�bÚ§²<±ø¨2„Hü"(‰B8ج¼‘aÐÈi:Y�KHBc=Ñ”¾´FSwˆ\É�`�Ÿ�@ëOÛz:âÓV¾ÌÓüd2³Ÿ¤ýJ›ü@“ÁuF€`F 1ÆÞÄõ¹#À0Œ#Àô�ŽÖ§!#ë £$v‰ÛMK?¿—FÊR3fEâ VÀŸÏÚaÈÓ'z2ýѤŽ,Ö2Û[�ÿ½ùZÒòXU•Øš7(9�íéö]×§Ó1ØX¾‹Rn)±Õ³ÖuÐ?.=Áì´qY¢Ép¸ŠU†sTÊB“ÑÓµB«f~”ZC9‰éÊÓ�g(å#À0?.=Ý;ñ ˜Iõ¢ÑWšöä } )é†MãI-Ûû(‘›1Œ#À0Œ€ LP›€ÂYŒ#À0ŒÀ.E`mp5˜=pLw¾¾´³ñû7øQîƒ3²æa<Ú¯�&LbÛÁ£)ß‚ëôx÷�+“ ŸMDÇe…ÚM|jFnßܞʸ6»"#ìÈJZì�Mø²¬ñJu�T*ã—H;[}‰­o‰£ŒÎÖ7ìu‰±†×Áö-¹ô¿””¤€”™ Þ´4ô�.AG |xþÕÔIÖ+NíB¿Mî…Ê”lh tBÚ˜|šT7fIPV–rºOèíïn‡Ú•d•Û}�’ÍSN(*JOIöàÆÓu�1jJíX©Û¸3oœD®*?åûP~+Ê—Qþ:”�¿»?nH4NȮȀ´Ìt�w@m-騻hSÝõ®Y/kÓ&'m&X‡IHÍ’cé+Úã´q}•@¶Çgþw,lJв/ÅÊ9Ó‚çL†3 Ú[Ú¡µvWœ3‰Ö�ª;žÿ…¡l·áù�~µ“ ÉÈvÂ á¹øwë¶wôâ%–®ë,ðâ|n“ZدwrµF€(0A=PfŠõdF€ØsX27û½÷ ¤¦ž”z.¡5ðïž)†ûO¯ƒKžH·{¯hŒµ7¾fHÇ&Ÿ€EŸÅæFÓnÏÑD¿cö†ÛM–gt³ÚòÁNU—3Ó®ØPF–áwµœÎr‘¯'—)îqO6Ô�MЋ!µÑˆ£šÐòšÚ¾�mbLÇZ�k¥( £E»±×2ùøßŠ@á^EP1vä >Òò‹À ­3‘�‰ én]5þV/û"R�"㎜ y•sÐ'o¸SJÀå*‡»$‡rý_ûåyðÙ³�êÚ8`èÁã xøièjh¤dì©K•¾úk*âè Þ6H0zæT(ñ È.9NÝÓ ¨ï~Ø6l„ÎÆ¥Ðºímølå_ûN#y6a¯“ pøðf샺êHȘŸ�@÷fhÞü¬~o!ÊHl%Pþø1'AÑȈEŒü˜ö$¿¥®—òcdÄ&ËÊR¡tÆØ÷hœÃ!àò ÂOqdœ›¾<¾|áo¢ÕÍÞ÷xÈ<|y‡àß�Bƒ¸ r:[>†æ�‹áógïÇ2Õe’¡–1áöög#ÁÅCfÎ0GzÞÞ8†àôÊno1¸RKqó²$i ¶BOÛ ¹§u%ÔW? ß¿û*“Dÿ8GãFÌOZ1dæl€.U¤,¡u¥H‘‡ýðõs)y4ï(Ó�2%ýú5´pºó`ÂÉÆ dííN-;¾�êwÞ�ia•”`ØÁSEÃ!甉sÆpšS«P :ðœiÃsæ‹gñœIbCdÔL<ÿ+æ€×W!¹èü÷¡Îžÿ$_Þøùyøǘóê8Gá°Óä´‚�ši8ÿåKPÏ![¼© “­¸#Ãs/N6ÍÓÐ#ñ÷l6¤ƒ¿G¥4¬È¼` ^®ûúøúÅ')ßJ÷é(u¶œ9èhˆ±fG‚;,mùî�áÏÿy/¶±¿1å#À0ŒÀîˆԻ㬰NŒ#À0{>ÍÍ jÝ�s3�ÂÔcàÉ1’Éþž7àŽ3ÑØ&H’ w¼ÿxR�ÖÒÝîJà�Ëž)�Û�ïoxøÂÜûI'Þ”úLEIŽtøÃ³CàÎ9LË{“)¡5¤Upº‹­ŠLó{º—â‹'Ïeü¢#}$).x(¾°Á´íÊLPëSj#FBþ ðÌ%æí´j’L×^HÉNC[*ïΊܯkÕùø_†Àà %0rú½�9èäÈÈÅ‹,´Hv$’’9FÏúZº‡@ݧ›”|$„Fò–ˆGV•N†.ŠVÎH„μІ_k$”#=(‘`0")¦DIŽ;|TðO�|2­C””Ë� ™E'‰Oɘ[à‡Ò`åëo›×7É-ÅáUx’ï0)5Ï"B¬`ØÅçÛÿ ë–¯5¯ˆ¹$¿|ê�ßKùùCÿÓñóÅs#¡ö+kù–Ç”2Éñkt?2Æ No”î3*§ürKÏ5Ƥ�•„´ìŧpÄXõò¡°á›õ1µŒÉ¶vý*1–Ù§œÒ±×4 šMb…hiI”¨KÊéÊ_ö�~ gÈÿÀÈAiû ÃËŸºÖDD´÷ ûœ#•�ÿ‹&3ZÓÖ[L¶!ùõsDÖ@•Ie¶rN”í}Ÿ^FäÉï\+W¿3R_f9c �úO ×§m_NÝ9S<ö¨þàXó¶Í9ƒçÿÈCÞŠè£ë<®<ÿÅ],Žç\¹Ö¶ ÏÿZJ(²µlÛ#½´rŸƒŠ9µ«èrJCö{Bvûòà³݃Ui/ ›òÜ|/[Í®k¹dÌíÒ ?]'øTIò›OvÊp#À0ŒÀO…€¶ÏûSõÏý2Œ#À0ÿ�twb9ð¬œKDYvö|C� 7ÒV‰Îö§•[kºÕ4¹ÝÌ-¾Õªi¯ó»:_Pì èVØäv8+ó”^Ë4kàïÞf–-ò|i?·,3+èêüTd ëićŽh`(ŽaŒggO3k&ò¥�TƒV³ÂÞ¶ù"ËvZ�,¡š 9M²RøåÕLÿ•lj?› û�¼‰Û(9-€ÐZT J§FkT'v9‘š3öÿùØïWíP2j¡99M}«ŸÚZ+ëi ¦�w'Œ˜±,!9UP‰9\é0bú[pØü×Ñä[g[QM—L“Nßš˜œ&�M~�HLÉÞ«Òâšü$§-~ÒâÅä”ïg-?¦ªm²³uƒmyÉØ»aÒœ5�‹V·e“PÚ�ZûÌYdk&þúíêke%%^p¸RÍV­>O‰ã·$\|`kÝ|‘•oáˆkà€_Þ¨‰5=ÊrVÖ¦-ã3KF*®¢ú!32>�ov P\wxö�0êÐçL\;|‘/ž3H>ÃÌ‹ðœÁ gÓ�ÄùïË ûÍ] M8¿]46îü§±hÑEäüOFvîÞ8w7ÁŒÓìÈé^ê¤b\Ó�÷ tôÕ[¥±‡@ä´R$Ù[üÓfÁ¸ÃïVÅð�`F`€"Àõ�8V›`F`€#p÷\ô_Úó±é(Üî±põ Ç@JÊq‘rºi®öIÛEZ‘4¶ ¾´_Ÿ^œmS#Z4ÿ±l¸áÕ?Àåÿ&gñ¡³cq43övK²²‚Åãu,b §BÕÿ�¤ø¤4©ÓjŒä*¦w‘$>Î>Î~,%š‘ ÖÑò/AFS5AN£Þz’:»à~8»Ê\^Náeâ¶]#¥ÅQA(Ô «ë^NÐ3’ ú¶ªÕå´*áü=�içÜå“ÿ¥ŒÒÀkE‰™p¨Ó…®Ö]¹ ë?=Ý(›1T@ëN|T3¯òR(w>5€÷‘B­’rÔÈî¶ÏÕ<‚3ç-Fkc£«}•PÈŠØVjQ×éyGÀASì7ΊÆ¤٫ nGôý�õkXß Ž ˜ìÞ›+ÒEÃtò s­n�ÍVðSÓ! ùúêÉÄ7}û2ì¨Y„›g6› &c´­¯ëxØ�´Þ¬ïÑ8UW[�®I}®¯«ëg�–´¥i©’l®ƒè¼`Ä•0æ°#"²b#­[–S–ÅlQ‰~ V. ºÑ}ÆP÷ý!^ÈT$ZË5M¿Ðë„_®_K›Éú¾õu%8äW‹q“å÷Zf\Ee�éõ�«‚®Ž€©g[�3xþ/?Uîj‰žÿªB$HËv)�½CÆJÓƒŽ‘r%wn1¯«Uþ Ù#[©®~çW·‚—cÊ~­�l]CÏr!>e¡sQ#4ctÓµÄhNé9è׺À˜É)F€`��„@_þî¤ñ±®Œ#À0ŒÀî‹ÀÕ/ž …ƒ–$¥`kËÍpõáW%U—*ÝúÞÓ–.D4!]�‡mu×@#*�Ÿ£�H<ä¯;Rs*!?÷jHñÍÕe¹Þ¯ÉòŸ­§,öÀ´Ê.d 7¹ú*x†­uC»û3XtLO¤ŒH墜�“}9¾òç"¿aÛ,¸þ¸×"u´õ3½2ÚVË׎�OÁå3ÎÐ’âxÙ³eàK� UÇhß4&ùæ]»ôPhëZ µ‘› *ð%ažÊr(»ý<ŸŽyŠå‡÷¥›¼lL‚¿{²‹±Zî‹{ù¯.À +´Öÿ²ýœ.u�*-`ý'sÐ_ísj*zØï”ó lŸG¢ºØ–U—¦5@ÝçH¬W¤ÀèS`ÔÁo+„¸ZO;‡´fŸþ³êVnÔ’†ã±ÚŽÄU¾!�=«`Õ[³aã§0…¿Oh‰]š^ˆçê(ydþLiC§6ôÀw¯N‡ï?4w¢üØkP¾G‘O>$üG'§�ÿvTþptqÐ�–iù#¡xô´xÇßHí$Æ&ß½º¿©|E‰Þ—MO°q¢ÎçÆ/φ�ß>�Õ­Â Ã^£Ž…¡û?kÛá�îU^4­“;<¦�ayóß὇Ï6mG™û–4xÒã¢\UOLõ¶µ×Aݪ§ ­a¤ûÐíHÉ0©|ÒCè£z_QW)XehÙºÞûË\µÜì ôpà¹÷Kyåô‚áHÐfªß;V¿e~Ž)µ#UÕÆŠÌáÃ=0æ ó ò;þêÂÁ‘΢‘XYÑŠMøž3”s&²ÎÔ*u«/…-k£çÌðJtßs�3TA÷7–ºP�ý|±õ9C•¦_ø„”]òKs¥trÄù¿åYÈÂßr)¢tþ¯x)öü²ñ7è—ª&‘³@mJä6¾³7X6¯¸Ú¶~œѕÐ€¬ø’)ïØøìX÷4Ö/E_óç#)?³#¹j¿´´”èŠW§Àú�¬ŸNKÐ'3Œ#Àü´hO~Z-¸wF€`Fà¿�_ÿ#ÆŒLŽ�ü¾ºT¼81YœÎÀ,Nµ1J†Š{Gýß}åæQ“Gڲ܅õ3´¬¸ãæõåpëÜxòè†×æAVî�XßmhCþ°e${õ!ÞŠ/Iû_F¸ÞSúôE"nF4k•îxx¼Ó°ùãÐݬ«¡:hoÇ�‡Öç³�dSn‚߯ñ"±n´B¬BÂ9í0´¤DŸÓ Ýââ!Ò@&ù˜ 5@(¸­´Çcž[©£TSz•ÐÔpÜõó›”´É÷‘—¤AqIZwJP9îK$\Ô÷)؈~‘X«¯ý%¾(qEäýWÝ_­†%KŒ&â9k#0tRŒÿY¾Œ�Îe%(Ñ Ô½Þz´B8ZŒ±¤Ä¥ÓN¦>øtÉæµJÇ—Áä¹›¢e´ì¨+~òfQPq@ì{ÜzQ?u·Ã‡�_§6Ùâ«bò Ø÷„-Ñ ]l[õ ðÑãÒå(Ñq³¦ÁˆiË0�ýšœÃÝhñùÚS°\�ºÝ©È†CΣÍ":4‚JÄê¥Ã÷o‘LóP4> Ê�…Á{Ý ÁžmðÆ]ÅUòÏ݆€x°gõÜD|dìoí²™°úõ÷âÚhEE(Ò±è�å6›wÍÔŠvÚqæEo¢•ùa–ò6Ü>ï“{ôáG¡OóW-Û ðò�EXNŒÁ@PgŒ¿WÄÓïV"‚=�ì+ñwÓ[è^�„.=MÓ×)NéÐA/AzÁáØ‡˜[ÃäÓ&ÍË7dEäXDœy“\0ìʘb…¼\ó6®‘w­×HL#]Ò³¯3ÿ toÂñ ÑÕM-7˜kvÎàïÿÚ›aùSñç̨éÁÈÃßW…+k^I(q²d~ó®ý-;/™q=VéÁ¿Y!ØŽçÿ'OÅŸÿ$[¤‰s6éÅúAsrXöh>´lT6zEEÜà9jÎJ|ñç0};å”ÇsN ë>Bßô¯þGKŠãÔsï†üòùWÆn(ÄqÐS#ñDº¡'F€`v_\»¯j¬#À0Œ#°‡#ð—_4Á]®A«ÀQ†‘’ ²ßÓ‚¿gi¯Èij÷$¾L1뙽aÄÐÏñ ÞA˜CòˆЈݨ|̤©CÆ!ì›Hµ.º¯@ö ɤ 45™ÝX\sÔýpÛ²# .I”HLÒ) <$¤¨‹ÇCúPÐô¡2¼áÄ~$ð*E&ß ÛÏ€’²5XW±�V¡›U¤Ùœ%�™ùGŒÓ ƒJ1•†ˆ$©QÒêwUUæ ›eådm…ò°IQ¾Pi5ípäƒÃ�ƒÉèK IU­êŽ-¿‡{Ϻ_É0ù>e±Æf´ã¸zPŽ�Úªí�Õ�PXú È¥J9UùöXò�±§ö(J&,PÉiVädcÜôíïmÉiªDîê?%ê[}mÕÃþèþBÖ6�"ëg�pìj[Žättƒ¥æãJyö;ÐúyŠ�40tQ>ézLãÆžÂÂS·µåÓ uµÄÊW߇Ac߀ô\s· )Y“ñˆC`ý‡´&âX’ÓäŒ^¸<ÑMEÓºÕ6ÒAX­o{åãÇJ¾­€$ Ûê_µò—A§¶%ðÃGéw/>|÷ækP>q xÓFEÈe}-²HÏšaúr9‡“æ]Å\�[±©Fþ€æ¤mTv¾}n< 9à�¸Á× mõ@ËŠ°˜~ócÂ’�¼~ê|iïYè¾Ë£.?¨ 73ñH¿ùþ˜†Æd8Љ¸ Bñh!þíêÐþVõOÒ¨èœQƒ2<5á„u_šŸ3k–}¥Þ.=´¦‘#Î}*ž3ÅcÊaËê ‘l}¤îÓm°ßl<ÿqƒÕ,t£ûžOž¹)R´õ«x·!OX¸+nOÌÏj°ù›z˜8'Ò4&‚-ß]e$§©F5>ÅðÊ0ý BdY‡ ÐU‹ät¼eÿG¸ sÜ5烄~¸ãnü¦¤Ç�Þq•8ƒ`F`7F@»IÝ�UdÕF€`�=�Ö–u£SnÞ‰„Ђ,·ÁŽú µd¯Ž÷Ÿ^ïo(‡ŽöQ¢_QÚM»F1@Ä4"ÔkANï€Û��‡/$²Â,Èpé´ã¡¹‘Ü_h$YHÒ'Êײ|ŽŠk×!xÄ2YÞÛ¶Ä[jMn9±Z›´é.Ì&=I�e™ HD!Œ!´ØÎ^³1’«�,:ãkøaut´>„}Ó g�3ø·$&„ðœÙ¾rkLn4Yÿž3q�TPjöàò¸Òh† §qIè¬ê/N[1†íÕñçk-žÿß[ŸÿQÙô÷¾]IJÚ_GJ*'QÓú甲˜ï ßÔàŸSœ/íïŸ¡Ü Û×Óxu'a¤< ÛÑ/{ †Ú˜ÀËu)Ž0Œ#0À‹Œ#À0Œ#ð“!мõÿt}k—•XYn@rútXxÒ÷º:½‹’k‹+ý5¬ü"eýººþ‰L+ Q‰¹[¨ôMþ¢éæ�\q±]_?š:ÁõǾaÛ1¹óøÓQÀšõyиãT$Ð2Y›W$gÅ�&õ#d•¤ 3‰Ûc´Ñ ¼‹n2ÎÂ~†À]§o²íçê#¯‡õ_ç¡n û ¼¡—�˜¤ ’çH¦aEÁßó.´4-€ÖMåPU¥'µDqäëá ;Ñçõ¯ ®z"tu¼‚„vâC7ݤÝ )¯X•ÓãþmK`Ë:ôk}t%<:ﳈ«ÈÒªnÞèËÍB.ÉVäþ=øAý)�ˆ2Ú(èl{6×¼I¹öPö>Gæ„4N¾:J¤qÝÑKæÖ´í´‘Ó ‰üÓ“ÔJÜ�í½·Ò/*›®êFÄ(žÈâ\¡¬t5}€Gm<”g ÛV-C+å˜Í.ñ[@mÜàËkl€©ÎæÕØG*ÆèwJ“M�Âè›ö˜zÖÍP1ÃüŦX)aòŹŽUÕ±ÝF\é Q7 ù€ ?Uð÷+”§kMGÄ»³Éþw¨­îcT›6Ä4Ü´QÐoMÒÓi†£Ô­i+8HüûNޤ6´OH;–a ú›YL˜¦ßnõo•}ûp8€� þžE§6´±AË´�›X¥Š:—bÖpùE“蜡6„�¦¢ò·©«ù=ÛÖ ˆþÉÉ VŒê¡ÆR3ÇØ´Ç¿êèªGÖýÍU*+}·µôþü×u&‡CAÜý iR‹èÆ�þf]U}T†Ž&üûF:Q0´âÓ5"Ûì«}û»ø74{rHN²´çÀ0Œ#0@ØyÛÉV›`F€øI¸çœfX°8<Žbpàc«§ý>�†©·\ã;¹¯Ê‹þ"ÔÀù -']~z!ÅïÅ>ƒàôô@ tA!’U}ì÷�¹dME�º/FbØ-c³Ñ±E.Ž-‚r:ö�m�6ð‘NmƒŒÏm dî>¿ó.²Ò>çq/d¸=�—„•]AXr Þ¼ê9Ž8 ñ÷�¿3�ôBÄâôlÈL/§Ã=�&¡sË QŸÐ½0j¿é„!ñrÎ=¹eG!ÓÔ�ÄY×kœ�ÐÓþÝNÅ'ˆ¿%žTô·® Š+$‘v��Þ…ì!Gc…„-#ú;!гÅVØÖê&…�Ò†l §zЕÁdlÿ AF¨ j"/iÊÀÑá‚$õ¥�?ôWP\q¬[ö(lû¡ÞÐ>Q¢½fÀAD„†)­¹XÒŽÃ.…Ù•¿‚ún‡ú/…õ+¬-ÄõÕ§òž6\+仞˜VÚÔШê ºO›ÐÞ‚ºâï!ù×6𨺠�QNZ.ý>‰m r.M�B¨Š—àÒo*ºi¢M*so¬ßÏT¸§í3÷éÜõ IDATÜ 8U•%Àé½á4m±Øô"“E.–‹ß~¬/ôÅ1SÓþÝò¢\ëädžÖaI„ì&‹�jT”Qz$ªGë‹Æ¦³B9ti�þæíBn°Ûâø M«F£ÂÑÒ!„çÌ$-ßôBÙÎ´áØ€ú¥6Z@ëv²”î{ —+zœøî ½X8^Çl#�ÍCgã·�ž¢NÂG�VÏ…n‡póÙ"´í¨ç¼R,&£Ô9¹ÓpµhÌÙŒ#À0»3ýûk½;�ŒucF€` wÏ%•>?^PkëG®w†&Šåò®Ynƒ°š–s;CmXZE$Ý´÷ïÆ}§(ÃBöX²JÏV #ýq=#‘èZ§Ïìw\Ò“ ø¨¿ S×ÖbM"YuœUHD"� ÒllÃhý¸Y)²ü&b W9I>$–ñ‡YÄ1a*jcãï?Ú ƒöy ÝŠœ«í›H‡”Ãn€Âa×CWË'PóÙåðýÒ�°õg6­©ƒ¡µ�@öà³P,ˆÔ†ŽB)q”éP4âzüÜ Ã�ü6|�ò Pþ�ð"S=y�s(ÅZ“ŽôDŒu𸱨õ Íâ(kê¾T‚áÃ�576ºZ°b'•ÆDsK�îU鉖ÄAv£†.RR B_Z'‰ç_kbròèKÓˆÖ(‰î­uÖ ³° Οa½£T| È߉/ìµ Ÿ„ÙÇÓÜÓ†Ad  8>©Ÿ:˜QÏLL8LOc uüG+€ÚUã0Üêéßu€¢ ˜°¦@ª`7 <#qƒ NdÆ}º7¢S�þx#à’ñ<éèrXÏy˜¬²qÓ¨�¡OŸ¦B\oœÁ0Œ#0`‚zL«È0Œ#À0Œ#°!0c† \"«ˆŒ‹ hAÝ]›Ù¯´,ùGd˜rP!rûà·¯wéîô�ßb‘(È@ÚØ AOg"‹lr9@/L%uˆ0Ã@„º� ¸_JjêÞ¼|s&¢ŸÙ}±˜ˆ:b£¨!ÊÀ¶´Y%,(QHjÖ0fæë0ê�غözؼæïèSÛžˆ{÷íßÁQ'îÞŒ½P.Ý#鯧aB_Ü@ ù£g¾ #ñi�m§^ [>xjki`×§‹æH ¥ëÉ? Ê&�.;&Ú k_�–Œ’‹B<"‹èø@.>”w H8ã-¨‰0–{ãâã' «­ÄÍ…Y�^0 |¹SqŽ)JöÈ8—¸)@–ðè*B™LÑ� q$åÓè݇ ‚ßOã HâœRàªÂW_oyO!1D–êúG�Ñ]‚ãK ‘®˜Îz±‰¡iÔŽ¢ŠŸ`²¶V¤à0B’ä$ jM‰QÞ™àt£l› ‡[°ÍµU�+d•ÝÛó_k¯Ã!eâIˆY40+ÚL©ÑjŃ~zÚJE‚0U½ Â."î=°_b¤ESñ…»4FŒ#À0þ Çj3Œ#À0Œ#À Pª{�¼!R7–ŒAò“\(„ƒödjo‡­ølEâN¸yÐZÓ#ñp§©“–�àXSC®&”—ŠŠª·$Èv¸S"ž–’‚~tÁ!‘ow­q´j°Çœ¬«®î�ŒuS¡aÃ-8Ž¥-5WÇDäѰd•-²Ñ:ÔáÌ…âÑ÷Á¤ã6øçE;1‹¡ü×n?7ÞFBñ?>•AÄ·*�qAó’,a8W*�½ö=·&±|³>“Ì HD­Þ…�J¢ŠZÌ\˜·…¬žÍ|óªë/dñ¤H!±‡J;"æ ÂBXP'eªê€}ö38vÔ&3ë+(Þë6È(š7 X*¹)86"•ÕMm8g"`1ßž5¢׳XXÄM£¾èŠ#hÏyš§åŠwè×4�/œ~Ò7¹P�猸V•õ¤¶k}‹£«­D!à¯Ã _ÏbX44ŒÓ'(ºÍÏMf8„òñ‘÷OŠvÊü¦¶önƒJ“©eÀß*U‰�Íi,Ö&S«=JŽnœãιN!Ët»ùr¥ ¾âI½lŠ£›2˘£}qŒ`F`@ Àõ€˜&V’`F€`F`�AÀã'‚Ë‹ ù&vG DºÀ›V e씣¬Z¾%%„å*~»¶èûO¢»ìU¶jPI)’.¹TëX­Ìä6 ͦ'ÆTI('Ð]mÒBÉZ‚î4>xäO°ò¥1ÐR÷8ö�–¡H`*Så�›•0'RWr¦Â°ƒß†ϹÁR¶R†÷©‚Uoƒæ-Ç9êBGÚ‹Mc¬˜I>Yý".9ÓaØôdä'èޢ؋¸(/·E¦•âôOk" j×pª‹>ÿÑÚÖòÝßnþ"»Ü Q©~±b¨?a=ŽßÂ6½œÖ6H0ã×�Âà}CB:k"V¸®•ÍZ%d5�s%6hÎèžëNY]£˜CùɺÒp8•õ$pQ×£òbÞ~XP£Š¹;R7W’Õ‹Fê9Cn6IÄAÁÕ“š§äÙ|Ë‘�„èý»"Ë Á®õ6-ÑîÝAn`¢çZ^ãtÒ‘ß–D¶W¦Má#æ³\^‘ˆ«JêºÅéŠê²uÒoÄ7•œ(“ü�+ÇA}(ó#¹¢ØhøÈ0Œ#0`àñ3U¬(#À0Œ#À0ŒÀ�€ÇI–ƒè:€¸�°ŠŒ,.wE$µ3"Šå-‘„È"©äåImgåhÖw{JªTGÚQE$ÉO²Ç[dÖÌ�çò($¶bMª�X䆂ÈÅî¶µ†ºf‰êåµðî_þ¾xe8l«¾»&·­8´ÀÄ­rT¬©‰9#K`ò+/ƒQGìg&Ò�W½´Þ{ðWðõ’Á°½úZlJ„,‘ªt$}�©‘Ød ¸¸Ù�WñÛ¤äS»Þ"x±•ÚµDƱø&BÓˆ6 D ¢k8¸Å¬éÚ}¢:Ï8?Ê|Qu­Ì´)LùåÐZúT•|²Ô÷âÜRëNèÚñ*lüâPýñaPûÕ1òæoÏ–w¬«’»[?ƺŠUµ�*ÆIký$ìû£úäÆCÌ?‘•¢/ÌÄMráp*›*Bn/¾fl'›cZ;HÔÓºît$ïâÃå%�ÈUˆ:ytP£DÜ;=dUnœî¡jÒ£t‹µŽÏ\´¯´m,Ë4ÄB“ ¬Ó•DØOÂúȲŸÈîH xÄX‘üî±– »ñtǧÔ tS­Ò�äÿÇ"¸º´ß¬C�p†èŸÀ²,Zq6#À0ŒÀ@Àâ‚ehÎ*2Œ#À0Œ#À0§¯ù²ÔÈý(ÂhA�¯ÏèÜ�ä*Yü¡%¬©‰¤¾ý�›á€Ú^ôÐpz‡ ëd²"%YÄAEH"t’’ØÔåÁ$bCÅ=‘K¤Y¥ÊÐÞüNÒÚÔ~ÔµÝ3fÜ-AáØ›ÁãÛ Û#!GÄê¥*(Žèq†ðX󯍤úØømlüö6”ìH=JÆßŽòG¡žñJ™Fúž>åß(¿")ù½«DD`ü½›“,JmBWmL(Ϥ-áNGdÖÿvhn_gÝšÜk×"´y ¶Ãy²áaìá `øB×èÆ˜]аö2øø5íoüqÉåû½€j¥b¹Š)®Q"@åšÇÄAqAãU·}�œ&‚ÛãÍHÜØ¢†bEÅ�Ð&—$’+‘yT`õòvs µÔ¹¢˜òüè�¾,ZÙ"æòúԹà B < b8�ÍïZ´R²%5À Î35Š[(�¶J«øo‡7g‰Oe( Ï1¸^ìÈo—‡æIÁUÕÛÒ¼áœ9­u “›r±&é|#jÀÝ(‡Ë¥eó‘`F`À @ü90Œ#À0Œ#À0ŒÀ�…@‡ Ñg®j)'­s$võa®ˆ·RS¸²@å¡/ôfec•\VšªÐ�7Zž×~dîâ#Uˆ4<ýý¢2¯²�êì²#©¬Ì¯Ö–æ!j×=¥×À—Cäö†6mèŸ0&w‚Û©#"µ¢˜#¹ V^°G›/Ú´(úJî¾Ômm¢=Š‹ö�9=º•±Á F5Lâ9Ó½‰Z*š‘X!Zñkž’N›*"�ñ�ÎÚdˆœs¤„ZM·A[ýªøFºYÆó_¬lˆç*Yƒã¹&:ÌϵîW'Â:*Îe=ñ®È£¹ÌÁÍ/«ÒZPÓÆj¥ø‘G_Òëv%X×ZË+áx,BàO¦qüÅ0Œ#0ð°þñxca�F€`F€`�Ý�š¥ø"ÄY`ª×â:‚—´—œ™°÷±•;m ´ T5´:Th"¨P>ZPöáÿΦ÷±=Þ$O£Êˆ`BÚîl>ÝÚ|íö ¬Ec'‹i ¢=¹Aw#]«à‡·Snƒ ß¿ó5Ô;ü]ß+| J_ íȵA¸23»T0W@†•o|›?Û ÇP>‘ê8~ú/,Óѯ/öÑwùæ½*¹HèÅô .tˆÉ6$=iƒc$Õ‰G»VŒÓÜ´5ü ¿•¸ÈÐ}µDâ4WÔuC„¢�uFÁ,�‡¡mbÈdíué ”G¿=Yå¨ >Y p$ʆùøV\…DëšÅè/\t,H`U]$‘ÉŠ;5±Û3™-…êù)PªX¨8å8ÙdAíè�Û�Îæ÷±Ž%âw›zTÖŽÓ�•S¬×$�3 ÉNn:h"Hl‹sìْ蜑r³BëçšÖ,�$²�ïgp,ÉI'<#Ðr�d÷tYs ÞTšꥮ/�á`tC@—-¢mu¤½?$›úSIñw®eð‘`F`€!`ýGc€ „ÕeF€`F€`2´íøêJ¤½¬LTò({Ð ºÌþE%´,DOµ(„ˆBúOCD"!QÔÛÐÕþ J v Ñ%H/5N¼YnñA–"…STkn´¥±ª„"éÓ°î:lg@ÃRŽ]Áç/vBcÍýX…È/£<I±n0·¶“©/ûæõØQs/Š&W-ŠÅ.…ËÌë¯|}_‘x¸ G‚îÔÙ#â•<$;Ôõ©ÉÈ? õ$‚R›gšýJ ¦oþS;šLqaêCk'Ö }¡µ¬x9d´®›1Ã…Öÿ{á¼êÖª›3fX�iYè:E�¿Ê|)ã$ c´Œ•Ò´.,��ÝÛ6ä œÚ*�ŽaÈ,:Ѳ�]A°‹ÆO$nt�‹úÂ�Eï¬ð;¿@N¹!%“wM?”/,ˆ��U6ÕRGÞlCä²2ÿtÎ�{”[Ö\�í4yæ"¨ eí༈¹ &´^=¶$²¹4c.ùèV6«P&áâÉx¿Ûz¾ÉbÞp]еL–âø´ƒEðá¦�Ò_´‚ÒmŸŽÈ‰frŒ`F` ! ]¨ 4½Y_F€`F€`F`à"жåE$ZÐß*‘NDÒ rŽÆC–Ž.È-¿&ž8&áÇÍH‡‰s‘„ÔˆD“’_†$¥‰$S?^ð6[“A&¢DV{3ê&[$ïaIäñSD€9 p䟀ôŠ H¨æþªŠ„#‘˜‚$# ÚТ|#4¶¼×DÉ�`Úù×¾sŽ�I‡'÷"4§pG«·%²:Œýl…𥤻>�ü«„ü¡IÊ Ý !JóˆÄo¨ÑD¾¾¯ÞÇ=.×�'¢#Å׌䴾ŸuPä ¹@Y[¢5¤ r9±Ý•¬µTÆá&â‘0Ó Åh’ñ[§‹^@[ùþF$b­‘†Z@Ý‘°ÜêªeŽÃ,”2ŠNCá©Ô�Òõ…�tõ¦—ê›%<Ý�HŒ“E¹ö2BjO3OjŒ?21É+×ßFd(­iµ„ð&kpAÀÓæ’VÛ2>Ý´éyÌ$ŸØô¡M Ô£Å#o0?gðœ!xÎHµ3¬,|OãZl„Žî7â;‹Éq8}¨)ö£’ÓŠõ5Ycã YKâ-ócšÛ'ÁNUP=ÂF²¢îÚä° ’ ¯É5m(P o"àÝàòE׺(Ò}µwâ«z"Ø1Dút¡e?Îq•õù 4àoF€`�ÝþßM'†ÕbF€`F€؃Ø^ÿ„í8BòÊD ±TH¶ý"!É'9Rað„¥0ùôCbÈ5 Æ�’ŽÛfÎû+ Ÿ¹ �{Éì–h9äVC%}ˆß"zŒÈ*²¬-è=Aµâ?Û qÓ­¨röI$µJaJBÒÛé©„ÁSž… GˆRlÆÙ)pèïî€ÔìéX3h¼HH‘/g²äÞøÅYPý YyLJ±‡ï 9eçÂà½ÿ%Ó×ÁQ—,† ' cŽ*†I³É’U#Æ&]àÄ~î�+….Š4r!‚Ä úëíÜþfQßÑ@ò³K΂!㟀qÓ¾�#.y."¿l*½´O'’F6 ‡]…ùHòá8Ä?"~¥0´mó�ò£=õ=&£5á%Ö®"J%ì?wðoaüq‡ášÐY¤bÙÞ‡…a3>EÕ rbMc ršðn‡ÚOÎÀ´µžŽ0® ™,ï£sKã¤ys¸2±m|øüÅ.ÜØ‚ë7ÚFÔݤAù^OÂÈ™¥Ñ†è[yô¬ iä!¯�ÝÚD`Ƶ©hæ@úÒ 9¥è6$AèöÑË;ñ|$,µ¦a„n$�¸Ìq_ y)Á^G†‰'Ÿd)¹x(b †¢Ze‹óS�ä2HC”òléÛΞޟÿzÙ‡ñ¥¨´>i�Ðo‹Û†hV^4ª¬YÒDщ6Ðq�£ÖéÚZ¡.qdü‡Öî…ôzsœ`F`·CÀzwr·S•bF€`F€`öj–vCÉÐ…PXyR2D1-h(u„©H\IP:î‘ïi…òZñå|5àõ�„›B:: ,#q‰wVÉÉØîí:dÁöT€/݃õ}‚�&:�ˆ :b}Czæá°Ïñ«  ¢¬¬L_° ó¡ñ£�Ô½«'òSo�M®!R!%ý@(?ð;(›¼BÁôL/~$¹*YФ¶Lä<’¥�µwÂ7/~aÙ£xñR•2úR–ðãÍ< �?Û’¼0ï×�Î ˜î—4N©”ð$k^‰u°¹j‡ZaÓŠÛ)ÓrÊ~¿É§4Y›§dÎ@ù3°ö‰úM8JBŸÖÕŠü´‰xTåéO“FV±ôâ6´žnZw“AöNI dŠa:*3HîQˆ v¥”Ã�I‹ÑÕ‡ÊGÖ ?€÷O@š–�ªáËñhLØFôhÕ*Im°­úJXñöñªU9`ï÷+pƒ!Ró§`93é¬`žäg-’gOD Þ t÷„ ú�ÕX�WœÑ–o!5'ûÔ°ÁFôõpûFÃȃ¿…aSêÄ‹&½SPŠs¥mrˆÍêSt†è¢ã4˜4÷ hÙð�”¬°)ö-t§ŠJ<³à$8:0 ÚÎÆáðäȾ¬Áå„`6CëW/Auµ¶9"Á°Ée�’‹c�+p=¤£n¸!ô$ì1ˆsÇ/®<ÆÕ†äzº‡·ì_VØþÙ}r^ÙyxΓœ·:~$©q®R3÷ƒ1SVÀˆ‰Íè~›äM‹|4ù­&,ø§D˜t!2aØ�D«_³>g Æ¥C~i¸½´,ÎÇ68—¢= €¥�žs8Œ=z¥˜K'�ÿ¹‰Ïúmqø*Á•J 3ek›#‚žÆ<ú�î^|3`ôá+á»7éŧ´>0T9`¯å•àË™ æ–¬¹´XDä;Í—/o:þ&ýþÖj×êæ¯|Ø�PÎìÛ`+üOãñ@ñ>/€”Y_Ko%õ;F*q`F€Ø- ?Ø� ´ø9|0^Óçá£v>Üw“W9ü‡7øfùî`t5lÅ}Ô[(¤´OÍÊËq¼Ñ à—›nVèÆ©D«€m°ü™mí9{ç# ÁU/”áMZ+¸}è#/´éF-gä@g¶ Bá­pó ?ÍœT½ƒ¿q�ùø†û<|³w*Ꙇ7§¸^íE'ty¶Á­GÄ>æ»óQb‰Œ#À0Œ€ùÑ<ÒrÈŠ“,‘½‚´‰’kDüàß-)ICü¸cÿÎ ¢ ¤eÈbY�VºËúIhå[6ósÌÏÅ*D)/t#}àb>AÐú°häýAËZa Ýò‡§Â* BÉ>¬\‰–¸•§Áðý£JèûUÆÇëÓD¤&©ˆ–«DyãõÚ`q} "‹ú&²Š^˜'ACõuðᓟMp�Ïd"Z "/i°È‚QWx )áßwOZà’E8V‚ ¤8¹S ñ¢«ŠP7Ô,Ÿ Õ˶cÚ$ ¦dµNAB9Dú ÷+€cC«c�oÊGYH©*Œ¸“ «ä°fÊ_ju+D÷éËߡΗ0)ˆZ½ZÛãQøjvgÖp¥‚Тk2áV‰M)Û¾¿>yúIS=X1äø+¼^ÊÆv´fˆ@¥¾ñ£ÈÔ[J) ™H–èä¹M�€ ˶™µß\#YŠñNüž4_¤0i­¢[ o9Z Wb®â [¬?±&ØnBˆõJsNãôBñè›�lÍB‚ú>”adØúÝ bÿ·±]'jI}Ó¡¾ .7žC¥RvÙE4e¤Cê3¶Uvæ5_³¯2ü3P'Æ“þØb6ÛšÛ¾‚Âç f-êdêãYaµ9ž}|HwrîÂÛ^¶žžÓí]Çùêw»óãÿx<�€G`#PˆìÚ9_°w.½Í¦îxo!‘j�°¨„×v ÷“#ƒtUÄ+^! +••öòƒßv¿ÝìÊj!±Àu²? �ªwœ#2õ¾Ö7”È9�/äˆ0ˆŸ æfâwt‚Zé<øÛûà w·iÓ¿ ¡4‡$DÞB;'bÖH$ÉÄ!„˜#ÙtªËÊÅ—Xàí‹vÏÿ»«ê¿ñnÅâ«lÒÌ/âA}§¼Ûˆö"i�ÉÞõΉè'-³q/×ë_q½½ôÐIöÀ5ÏUý¬¹[öÜolâvÇ៰&¼ô½P%»ÁF&W$†Hê¢Ðá&FLã õ®ºÎ?xäôókFüER»DM™Ó'2uZ˜ÙÜ¡) ëÔíÓ%\×ø ÑÔJ÷a¬�ÎiG ßÚ¡™ßè„w�––\ ‰RIS ù@ä£R¬¡ëªsZ6ÇtXÛ°µÚÖ¿ýñëì<—4'ÑVô±J» ¤j¡£®Á üÄ�:éêL¨Ã©Á޼µµ_b߸ú£öÍÃïäšw�€GÀ#àx ÀœÆ-v©½ãð+Ì&ŒMá/ ÖÝ™÷Ä•TœRí2à+çTH§ð…xè¹ÙV-šgK–^iOüIï»ÄÝ}UŸÍxÛã¨Tw"P¢RŒ!Á‚ÂV&ð&õª ðž”RTßa}Ý7YÿÊÛ«±Œm÷àüèìl÷9ÿigž`ù¶·cR@b½‡¥BQ(2â‰s=Ë®´eÏ_aon„œNHöÑRzø·�[4x06¢Ï±¦¶=‰-:Dê‰:”ì»H(‡{ïó}Y鱕/üÀV,¾Üd3{$÷Èu�Y6u€Mû» ˆÓD&ÒPéh±·„�†�VrAf3 ~£[ñ×ÿ´®çÿÛ¸näøGJ{,×Rya)Ò4qޏ$SRÁ:›ÒÎ>5™®*ºyŠô«XߪëmÙS?µûþþz³+U�]ßÒ?a¶å#xXÜ�ŠVŠfÚN,•–øÇË϶³òÖÒÜiÙpš»gŠ˜Æ°R�M+.yÕ÷ÌxåÑÇãðx<� ˆ€WPo@p}Ôk!ðv­•ï€ÐÜúãÖ¹å©ô¤HÀ¹�lš"õ_*‘uÝVåkíÙ{°æ©· [^*XgBB·ÚPÌDõï£?ójˆ½ÞV^y€e;>ÌGõiTž:Ú’úLì>ªs˜(¿^mz�ÂÿÛÕ{bÒãTšjz)Ã9-ÅX¿•KwB�ÿÞ":óéôž–Ëï�º[69¥QÔôÍUV|¬Qô›ÄùÓçM±)[^`}}—Z9}›f¯V mô…ðx<› ñ¼„iÛøÜ¢öï¦ï/÷Ì'Äâ2âÕ¶Äé#.î ÿ+Ȳ³µëÌ1ð�‹êU_Y2Çâì.²~ýä+ˆõ5B^E¨ ±‚Ù³«üÓêÃúG±ÝÍ0En}Oc:›´ŵ:¾gÆòµõ¤ESÍ^ªn«Ó~xõ¡?òx<�À¦Œ€'¨7åÚ}Ý• ¥ÂýØx³ÂùvH÷¾LÝBEIJûÐf*›l�š’XÇ%˜Ï[�ðwõìmÙ¶Ù„ƒ�vf%\ |´'Ê‘:Áý© €@ÁÙœ[d…øû–½i?¯9”:Pý©¥>”¦)nØçL¡Z[Ç7ISé°1hh1SO‹Åù¶Í¢ãlî\)¹å.s ˜Y}°µ´‡2M6êV¡R¹Å]ÛTÿ´LšÅ‚;Z++ÄG•GìÛ×~ÖNó DnªÕíËåðx<›Ôó‰Ó¬0×õS[$Ó^˜QÇï<�€GÀ#àØxð4oÝmÄ9G™ÒµøçËýlU»„'YPb±>?=TàáW¼tèØÝ‹’ðDD8ì¨UF <‹?ODT÷÷ÿ}%ìÐ9[—N ï’œ=ÄñLm͸Êoß»}oâ¤ì2@!Á6«Ôka¤�¾ ‡‘Ó«Ã[n_?è—ö•½ö³Å/fKÆ ïí[íaS;b  ¥åXJ•B=ÎÛÔÛ-×z  þ°©Uµ/�GÀ#àðlzD,b—˜$«Õ”Ñ}ï°�߆�¤¶é�éKäðx<�Àë� «l|=–Øçéõ�À`ñ¯dD$¦¾®ENkÁ-Ô¡ãÑIæ�®g §!S¨H䬄¸˜dgoôðΫÿ3® –ž¦*°�éÌl5uê*T‡AMÁ<®IºÈòZ€‘E¤Ü"I®jE$¹ÚQGùÙT»3{nD?›ÂÅÂï§Y8e&8‰À×Â�Z™[îWoAñžßŠèËàðx<�M�LNëfˆœf`¹ÊQËT™˜‹µ¶†w�€GÀ#àðx6n¼zn㮿�7÷©°‚Y«43UÑ‘„µ²¤ÆD/§>Öjõú8ç…¨–It6¨ÇC-=¿/ReÙjá+bZûׯår³IO½5™÷Т™²©}wøßpa ×¦øcJ%Ó<+éØbŸ›¥ÎÁFƒ“«Ä2oâ�GÀ#àðx<¯gâ´šd��ÕŠ õ­¥g©öÎ#àðx<�ÀÆ�€'¨7îúÛxs_,˜ £”])ª¼¦H³` fb™’p«Â;:4‰G¤èkÇ‹n¼ào œ·äe‘ΓêÀ©§5`°á+$�ÞE0é:'vZ‹i¸b Úy«^ÚŒwMù�Súvð`I� ÔK¥Û6cT|Ñ=�€GÀ#°q :yw'ùÕ»»ûªWh£u眹¡Íß²®ÐØü„ÒÎW&Y‹LçšúíÞ·u�è¿–ïY…´ußÝi„me`•ÝÿGò¹†*¹æó•ïµÝüÓ¶ r²Xá+�K!ƒ~0%�îXô™íþ@pŽ…Ò *%xH6ò#ç»”º„õbþ&N=¸KÚv}(b!GÈÚqvZÁ}îü�øcâ¯_Hå!¿O›•Z­/Ù„ Ëzoíoèÿ•d±° mùr‹ 6Ñ7jµTX%¬Ø`ÐiY©xjSP‰ÜQÔм‡0¹ø®�©xãÕi¯œ‹!_#­n¿œ³Û<Ÿ{aNÅænÀ²æñ<˜ÐÍÞa©RÆ*ieŠÉ³h}ìeŸõ‡–N½ÍÝnRW+Z˜4k© u ä£ôx<�€GàÕ"0gNÊ+ï`¹ô$kî|Ñ%ƒÌÕ¯f>·øzfà9×öV{ÇÇöµ¨X´þrÑâ'±Ô÷‚w�€GÀ#àðx6-¸ÑävCdtŸ÷µY<ák�zd�mÚ�™rš&׊ù‰š« Ñ%¥/�åÁ­ÕUöò‹?³G~%skºÝ>°·µm±¿e2;Z&ßÁLú)(¥ZLC–uÙâÇ/¶;/Ÿ7h×9­Ö–ÝÏš&íÍ‚eï Ò™v>4sZøªµlQy¹-áb»ýÿû_ §mûûìd­Óް¦Ž·“Ößq�QMß×"*Ñ2[ùÂÏ,êú™Ý:Rk7kVÚ–·mmMmÛZ*¿#f�·µt¶“rtZ*3™m UÙ·Ãþ[¹¼Ä*ŧ¬8ð”õ-¹Æ–¯ºÃž¸Zæ6Æîvûè¶ÕN7P^ÅÝW-R“ÑJë[ñs»î{'�Ùîÿ0özÓ�`;…ð (ä$‹ñÅñJë]q¹]sÁ‰#†_ß‹H¯šiímÛP§o°|ó–àÒa™ìVà?…}'З-Le˜jIìA¯E•g©÷Çl çëOßi—}v`LÉ~íʽˆÿ`ˤ¶dñ¿©�‹(£Ú�l+÷¬úž}ãÐÿŠ«pU³ešÞaÙüûÈÇ> Ñ–(ˆ¥’ufPŠ60ðÿly×�ìÛïY1n}Žû}Φª­æ¦m@¹GXpO‹ÊÖsAxʴγº¼ˆP¹ØDˆ–X©ôk;i_-Ò÷êÝ óš¬³c–år[‘ÖDkn=‰úo&b©‹?fE{/b[n½½ç‘Wpƒ¬–�óÚµJô ýó¡w¯“‘ïÖ;Ó‚ô6î>NggR¯ÜËáTö ã'F¬ôJ”›zŽžâžxÊz¯±Îè;þˆõ»j™(,hµ\|(ƒSGÒŽv"žE"Þx’\C¡ž´¥Y¼ÖV,ý™�ýÁuŸEÂh2Å”#Ÿ£mäÞºOdâƒhYœ”‚Ǭ\º•u-µ¨$ÃE©ê€¾-à™Rî¶3úu-‹~ïðx<�Àk„À;þáC6y»ÓIM߀l¡”ÒRLk¬¾›ù2Ðû<งOœ.ö½öì]GÛ¸ÿ5Ê¥OÆ#àðx<�À¸ °ù*¨ßü¾i6q‹Ï[Û”�ð�—ã[¯ºÈ¤^ŒÓÙusd¤�S#G–δYÛä/Zëä´æô‘ö󟪅ÝßÛlÓßüM~O%>Z�tŽÀ“QK­–nNÔŠo�³eØ1娏uò³Í$ ´ñ Hå(t '¦.ÒmÊ̳l¿/L±üï&’´ÿ©½¬}ê A¶ù-Î?Än ZuJdòžÄÓa¶üŠEÓ?loÿÀGíŽ:dºr%·ûQkšòkÛZ ¦A‚Ê6m BÌ‘›Äªo`b…ébñÇq*�¢3½�eš÷·Ö ±)ÑR›1ór›¾ü‡cVW—úªêVñîNþ̇öp^ÉŽàÒ•„„ >ÌΑnì×#Ž¢_ã’0Úºsž¥§ìH2Ôæ$D„¦DF‡"‚QmWt/a:Aƒ,§„ md¶ãÜ;­©ù#6ÁVÙWþû2{!ûï6nce¯ˆÅöŽo@nM\­ÄÍ e±êã�­¡2pRÆfò_°lÓGñ‹CÁ,U¬*-i{€¡:ƒ¸Ïå�¶éùXá÷Ÿ¶ÂÉ÷˜œÔÂé?¿ÛÚZ¾îÚ‡ò$R:vi¨sÄ?µ×a)­öÃ^™®©ø4O7±ãPk#‘Ĥ1ó Ø´„½Ú�� =ò@Ô·´~�¼hàB5Â…Ÿñ à|€£O³­vG]’±ÎæyÜŽÛàGd·pV½–9VY5H“¤áˆpîYWÏá "ÄæŸÀúKöí…—ÛÀ?°Ø�Å�ñ›i,í$°ÉQû’­Iů=äº1¢{ÐæBò–ËomÓ·šk…?|Ò ‡­~ÉϤIï±––¯â™ £ i ÁÝà  f¡gSÜ „eÒûq"¹·Õ~u=ffBÀ KôØ óþhÎ} Kézçðx<�Àø �Éjà_ßPú¶Ò{X_áZ šï'Ñ÷¤¾;õçýÍ÷VÀÀv®ƒozó5 xçðx<�Àƃ@Bxl<ùŸœîù¡ímêÎÿ Ñ3…/:7T‰C|±–Ûƒ’MÛ¨f«Uéòõ‡º:Ž ©â¥ÕïãÜw†2´}¾ˆü:p*ì> EØÉ‰¨Ê¡ŒÜÍøÒYAëÄò…)¥¶Ì!p4Á©.ªäG°RÄÓDz9kŸñ5{×—w¶Ìà^ÖºíDâ‘���±ˆpÈ,÷Û‘‚ ¬x!OùݲÅñüþ�¬ëò/å-œÞÁ5‘¡“ISDÎ¥SEÞE�¹r§ˆ-}»ô0oC®‡„í˜öE{Yå·‹˜mdBèÅQ?<âj¿¢…Ôê3�ãH¥É…T#ò,έÈa>6^°qäk]É—!+í­�UQèꪺ(£ˆcu ” hˆ¼åºjÊ21¹ÔfÍm_±­zTÏ�1Úù“ô4R©á¥”Q›#Œ¢V[‰ieÁnöíë¿iÙì‡QÚjp#!gÕŽ�jj{ D4ª'¸"¸;: 6oÞÇlî$¹ ÄŸïÜÒdÑÍçX¶íP~ué�7ÆDˆYåcf�ëé¸VkIšÕ¤WWL-ÒñØ»¢i`@÷®Úœ6ݫÒsù"O.[Ô†ÚuD¾�ö©I&ò}8‰¼Åu/¡V�ÛˆNÄ7aœ\¥ƒ¤v¥T:ú­Ä4�Cf”ŒÚ�:‹Ü‹ù¦£,¾^õ|!ÛÈîì?mÏÌ…_ND2Ï )ŧ$QÌx’*hz¹6¨çMDzGòûü5JKýì¾xVðŒp³+\û¬Ö�R'µá)³9Äí:¸Ü› ˜Å¶Ò¦L× „'¨×Øÿðx<�ÀF ëåÿ£ðXò>ÖŒA}Ïñí+3fr�f©¹¾c->ž¶�®?Û`Ï�Éyÿ×#àðx<�Àƃ€H”ÍË¡^¶)oúüÝ–�1€"„`¢¸‡=H Äi2­^|"¿PjŠˆr-Óú!Ä¢Òš„�ì2ïõ‰ó¬mÆÇQBî )XUuÎM�‡ðn�ô¨-™âÀªN ÊŠt‚6’êA&Dr‰|VZì´'\ˆš³iÂ' #IÔŠP®J+šÔ‘eJOÊ^GR‹àÙU²¦ÎCl·�^b÷\±H®ãn¾²ÛÙùé ›Û‚4EiK™Aì\R�Æ1 Í)_RqF"§Q‡»´Ôv äÈ’^²ž¶6Hê=>zŸÝuÅÂuÒYûDG§Ò 1ËŽˆãP8}€�æú”KB8|]î·Â…éWfb¡Qš7ÿg·Í<÷)ËäöSÙ¸©�é †;st@/FUíH¾€6ãˆDVWw¦WòVA¥škù‚ûãûìû_XX79Çgüê"ÌV|’ô_ˆQT´ÉÀiƘ�È–te’�6QOä3dc(¥°ÈZ7h ¶K^Pã»U߉Aêç0õf{bâÛIûÖºé×N^„I�rð_˜ ù{â¤Î5è!GººOÜ"•±¦’R‡´ ‘é2!¡öëÚ„#?]÷g,uºÚ÷ÈG•þG˜íº dî2ÙÝ/j›ÑjKjS˜[Ñ}6¦»ò‡sºïÔÆºl ïWk�ÓJ±0»Ç¾sërÔÐÛOµuA`s¿j*­ö1ªda"¥µ{VÈ¿”ܘ7©ÝÜtŒ}óÚ{ì/TÔuÝ™×miM­?!î\owátŸÉôFb²‡éº„Ñý ­¨™ìC »´À\χóºí½§ï1ÌÄi- ø©6EÇ·T¼Ãîyi¹;çÿx<�€GÀ#ðÚ!pÿï°û÷Ñ×.AŸ’GÀ#àðx<�¿"7#WƒÅKá�¦@S¡ D¡ K Ôkåâ#Öõüñ–ËAÍë~ùJ›4sOâ$A±õ"Ïû¬gÙ%6¸ò·ØÞ^bÙThåìö6aÚ)˜öØ¿äG&I ãÌ™C êÞŽé‡p°�md×ÓcÖ!³ k›Aˆ ^+Ä9Š QP‹ MÈÃÕže{xC,’ؽteÛ•ZÑtK†(BÒ¡¼½«.µRÏ•ÔÎ2Ëv¾í­sòW1½±~¤LFÒS«.ej¡~ïãüÂÕ™^ëè[¸•ó5öpÛ…¨îç�&Jfˆfýs¸kC¸±E¤[ìû/+G÷X*nÆÖðAØ¢>2i§Ž­™®p(o� ÆË¼‘F&¨ZN¶\j7üaóPijâ� rwpð×Vì?ËÞ°|©=Ä‚�Z”1 v�ýŠ¥Ó³ð«¶G»UqÊ_‘éYÎ��+¼÷›3ëhj¶ á}ÄO9I3äЀJ‘vðŒ5¥ö¶»Òu—%ìçè¿çäÜÚ9*/·Tӛȸˆgü9s�õ÷_bÅâoXbé<í3ÚŽA„Ó©cêÙÝß2 ¢{Wµ$û܃(›ßMô ×NÂýÖb–­­ÿNXÊœ=oÈv‘Æ`\®§"CøõñÒÓü[k)}ŒRvÓvX„?ª<§¾ýê[kbô™Â]mñ#lCFž †1±¢bU}Hõ›Ê@ð�‚‘”Ô§Í»¢ûÈP™Q_‡5AU^©ðƒ•Ö½ê=Ø”~~XQ~‹ù�;¬)ÞÕØ”Ò“ù™mP�äþíÚÝ Æçâ•0Jp§P–�Cð,ηm^qb0yÇ_Åa˜‡C!)5&œ¶¦ý£ ®”ž¶ÜÌ«’Õ¿…BD~þÍš;!Ä¥ÖM‰€’’4qŠ!“ßb�0kÿXxÙ@üwør”‰ÅÕÖÊ ÌH,µïpËï‰m¶ØKv¦0V' vïLö¬>5¦£Âì+üñó–Ï}ˆ<3k ú ³+î]‹œN¢’ßs\hé¬L¦ÈxM¡,Å<¸Q_çý±ÙN>tÝ{¡<¸4‹CmC÷O§¬°‡Á£#æõôý’gQ_iÿ:¿V?�ƒÄae*DmH÷IµvX`45s:�cöW<�€GÀ#àðx<�ÀëÍdÿ×?mMÏlV é³eñÁ_„ï”0_™ê±Ré%úÕ/Ó_RÖ;�€Gào„ÀæEP‡™ía3!#MÈB‘BZäMÖ*šÚ?Lœ7†zˆ×R¯äà™½v—³ (6?® IDAT©çh:v�CqE6‚y®úóº�83sðѸ¯‚MØ ƒ,5‘=©2ådÚ£ßú–ÿÆn¸$QEºÓÕ?R9O9ö TÔ_&9È@‘’”IÖ­Egr#+¨Íý¿ZÌßïëpTwè´ÛŸ²Tš…1“’,<§’Š„Ì[‹#(×%å†GÜ&ÓÁÎQʦ ê¤ÐÉÙ±ýé–�¯Žœ/¹ÄnøØbX_7þTJÔï�)ÈK÷Û ¥EÔÄdxÎf57g¨%¢NºÀÈuóûz-ºŽ6I-SŠÃ¡ ©D}Vì½®A^Ð̳Lë¾à *ó¤+ˆ5��JmÛ œÙ™ÜŽLHÈœ ¶¯û/u2v—£ev÷Ššê¿NýÔKÒ>�šY^T§°ÖÑÖ\[Oî–ä¯^)^8T÷Â�Æ”å;—üÅöiz‘Ûlþ¹hƒ¢Æµˆ¡Õƒq;ÇëÞ ÙÔ6œOr*ßÀýÓ™TJêõsurD— ¬;@²v Èd?[‹<®étnƒØÃY3ÿË#àðx<�€GÀ#àðüMøæu{YGëit·¦Ó¢oFØ-:«®¢Ä:Ì*�ƒevÖuç3+õÚ¿I}¢�€C !ô60žƒ/ÓTw‘5PAb¦e/7lµÖ‰ÿd|é ÛçsCÌé+†EªfÙB–©‰DGª´HÊMáïcṕuã–y�bÿ½Ž�L¦ããÍ�â)<ÓñKa \±‡p,ôè?SÊ–ØÿÕ1¦FÆÑ©|ƒ=�PF‘‘"ÄI¢J¯Å2½æú‘îz½?ÉêãUUç0cV@;B[yHPv˜�ûëÁ £bï#Ø–‰€©\Æ¢q…�YÌ}�æ jDåå„g¬jq) c™°Àþu*+%m} >†Ÿ.ê¥[ó£4•yíÌÚûL~7¼ËnzÕ\…<8’¹H¾1™ÖÙ©½©N‡%‹úZæE6ˆÛU±Š Nˆñ¡44ð¤YØ �rùRá™RS‰;˜¥„F�©ÿŒ­T^ ϽäQ•“TP‚{vÄ?oçÞtš~/rûÕ» ÌbžnqÇjCÐóA%ë¢öêó1x<�€GÀ#àðx<�× Ùô~ˆê&Ó÷™ïÓA7h Û &³…[pM³‹§±–Òί“ûlx6[ê“'›*qå)Š&Ò®b"Ó‘¿ÂåcØI�™‹²YÇkû~j&çG'ñT×Eå•„fÊHíªcìP¾B¦uaË·‘+‡6ŠÈŒ¤#šñéÌ`£¶´´Q0+E˜ƒ)îÚ*áåH(ˆ¨p4R±a´ /Tâ§)K•ðò–clR2ñ!RÑÙ� #šc±!�ÊTË8”¶~WÑÆtÁëÁûŸ��NY…ìT¨‘ÔÚ*•Œu—†ZƈY­”—BZä´#©i-I;.6V`Çé„éac°DêýÆnP¦q%¥Â½yaccÛÊIc7² É^~fļæ3òŸ`?TjÉô{ݯæ¢~¤\®¹²ÎJíäÝ?­Jq) Á à Q4Lµ?IžUÚÀ ÿ�L}ÈŽ5P¹ìQÖ9éûöÂãìÌë·ÆO­T £lx!µ)³*ÜýZÍ!é%‹26 æ/x<�€GÀ#àðx<���ÊàÝ®¯%µ´›íÊ]fZg©…�áA;¢Vº¬“7êrúÌ{66¼ÂðõÒÝóŸµ�û�å'Ì� ‚ЊÚ!ƒd+V ”a 'ĆrË”ãÉöçÃCO¹3êYþ3koº[Ã�ɦzeŒ°5]SG:ë"‡áÜg¹6˜Æ®<€y)_�Ýiy’b*B²’i<�?Ÿ^ÅÃ5‰Tdd²Xœ~‹è~uõ<«�¶¦e­+Ó¶ŠÅÜ2í¨aźJ!*¥6銬†¥ˆØtÊŽN¦5cf{Èé�<‹2³¨H\�ñ ガe¶€à+'Œ¶eðaQ&4Z±i5FÔa¥"ìAGuB“ ÇV´¡b”*´6¡‹£¦U'¢\ãÈ2 G~´8^±Ø!i'ð�#+‡’:(XŠ1·—«Ëš ô¡P¼Ðãxù�ß ÄGŠ"Ä©ÏpœI\7ý*A�2¹¬ß=»nœëž),HÛÄþ”-o‚ðm ­=J£,W¢ZUªäÕN¦\¹ÂÁÏÚy7]ÍlŠƒ‘ìÔK-Mœ„‘-ùdAˬ55Ü?mÞò •b}Sn·Â®�ŸõÒ XÐSí`xÞÜt6FKç°^LþœGÀ#àðx<�€GÀ#àØx(e®·•Ý·|æÃ–oú'ºlš].’šþºãgÔQ¦W”,lµñÌçÔ#°é!°ùÑQå»VØ‘…÷àA„âòΜ9Ô‹�Ó1dQ`ÍÌÖˆ3M‡[°Zeq¼ß~n}Á¯ìîKW�­Há AˆUÄ9rˆ û5ÏWqÄ6D—#öj!EøÅ¢¯º"e‘�êTŠ4õ ­ÑQ"‘‡©KFP½°ûQÌOì`Ùüž–iz‹ešß ©J;™�cFL„EåvâKC8N d>Q¦JOÄräÌJŒ–Š™Ô­R‹Š¹uÙ¹M c|1Ôn¾Æ¼¹L�=¯ÔÇQ`ôXvknÞÓrÍ;Ñ–ÞbaºÍŠŒÆNnWaX ±³Ã�ÄÆq hÚï=—=W7eøýZ¦GÎETf`"„dÖ?‚$4l¢R¶ÚQŽ„2ælâˆqb f9%/3!uÝzQc£�rC£ò)ÿlÎ<Ž~×w¥j•¶¢Á¥©6¡bbúbäÖ[?¾±œ�øWÈûÉ TÔTóJÏÆR%¿:³"—Ü•±Å]Û[6Ø‹…w¦Žw˼E-9›Às"¦Rƒ°�O�¾C2+=UÐ0x3¿�ë-]lí©7±h¥â‚L�;ÁMwyBRËvx¬Y žظÎ5íaÙîÅvÎÂÿäÑu¥�vðØžE‘L¬ÔU±yuø4(–?íðx<�€GÀ#àðx^f«ïü¬\d™ÊîôßfÑK¥ï6œw@`†Õ>öë"×>�Í�Í� ^øÃÛuÎQ6uú1ÖÔñIžK2˜ é ‘†sδ,”ÕRE†RFBµÏ8ÕZ*±ýþñL»ñ?náÚ0ªnÛÑNvp«$�ó£Q:L‹`þ¨‘ Pš&v²e2 IÑ…�Ý¥ž™y.:bZv †ñN²:R´QŠÉyÓ­ñAÖ<ù80™èH±„,SdäEŠn§Ä9 ¡æH9i 㥴ïÙ˜�['R…×Ö8ÔE‘°Šo,öŠ‚»¥ÈSfŸôµkã·Fr‡ØÒiGÛ¤p*é¨Í@²ÃÂ&jyBõ�Md”ä1S‡âE9$¥DÅn°òTf^RéÑÚO’ïJDý¡ÂvصèwA¬2ŽÀO[n*vÂQrSoNÙ®ô‘ ¯¶µ®kbEãЭxT"ÂÔ…ÐOå¥-�ä«*¨Ú9 ÿ¨ž�Ýòmb›Ø§çù«µsíUФi®w2"¦—ul}•c¬­…z†v× –P0ˆpW<î•Vªç € ¦¾];–Z\#͇�~X˜Ýc…yGYóô£-—û8q÷O§k7£ú"ÀE|kV‚i0(f*iåò'aVþSvæµÿj_?èfÎ�Ü–ôLIüªmpç]-É;�€GÀ#àðx<�€GÀ#°é# ¢úÜ�8è�è©õ©ƒíúñI¯Uýwï<�¿)›A-¸œ?hÚE¶ÿ篲Lë?X®õ0ȬNÈÍðhZ$Q޳<®DTCÆBò(&S©¬µÎ8Ï8ör»þû�Rs"×$�vḑþéè/=-á>“xÒ#¨1+ò“,èHqq[Ž,å¹;Š à9s0YÐ|¦GÞOª°çR”ËtŒiÑÎV­ì`;û¢;1!ÛMš ã¦Ã(-þ‹ÐdŸëHòœmèš� flPƒ‘ó­÷ƒû%s#0ñkÄXóWM¯JLÆR|�³F}¿F‡SvLÃÂ@Ä1*e0Ëæ0¦04¨0à¡AaÊlƒHjÕåu¶‰Ç¸�dTJY» )½@…‘6WܲM¡Œ/v3„�îG‘Žÿ*Q«f¤cU“û³±Y‰òI�keã¤V\ ‰2^­38£8©ë•Ñj�¸<“*ûa£&£Ä±Þ—uBžMÕ ¥^;1æý¼y){nà4Ôñ‡‚ó„“}2¨{K³"TR;³×BŒ®ÍQ¿nÐF9HÒNV†fP)¹Ÿ9_ßæÊüÆÅvÞõ¿eüçs,Îq Q¨f[ˆ©…2U§Ÿ‰$g0ÄbÚjÚZÛϲóoú¥�d?¬yõlYƒVÂf]ÙNœò9þ÷I-v¿÷x<�€GÀ#àðx<¯'âòs�}ô¥Ôw¤Ï:Ô7¢¯WY½žòëóâØÌؼ Š~ò4õýMÛó3?¶ÖÖ÷Y¾óãPQœIÛÊ ¢ÑÖ€$r¤êaLZ4w~Ðöýü-vÓO0¸ßÐ¥a€B¸Àä©§¿ 9 ©:‚ô5HÕˆb²V®®‚*œ²9nÔ‘Ìš²�fàA¢w5a¢6¡¶(“:*¸-i›µÄ(‘ãœò$â˜íäŠS¥C´§LPŒàhòШ8¥1,nÝ;ÌNØn¢ì�+ß"‹•r-iµ ­L¹žî™éŸµlæ"ÚÒճ⠴¨ª-#ºÛ¬R¼Ú*ñ«pO¥âi(á·aÛßÒá`ÝI=%pƒ5:,×èÈ9ù€§ñð ;ëOß·lö}˜ùÏš-9'De†H*m™^aÐ<…±ª)�ý˜�¹àûúì»8ר •¤V+®-0bQÑ œw�€GÀ#àðx<�€G`G ì¨×:EɹÞ#ý+úȵNÒ&^~_<�Àë�Í› ®UÎ�—½Äá¥6ë3?³r~/kéøäë.<² ªc©e5µ^X¡h„ mºµM=ɬð 6G$×¢ªíà œ.ËçžvUÚŠ_‹M™Æ¤UާZ<É^¿aãÔΣ’rO×!všìŠ – ´¾Ûûw³Ö Ÿ‚½š !6‘ÜBP¢�leÜ×u±-¸èÒº÷ÿ§‡­5{1v©nEàã�´A=ûÊ•*¡.<TN¾F2Çj3[į3?âB“¼ö*cx«>×o7ë‹oÃ̧Éà$°I›Ø¶¨ÛúV]lWŸóãºqòƒÖž½ˆ0M—Ô+U U—¥�±e2Šr⢓b©h²i®ÔSª4rvÉåDdЏÒ‰ù“Ší¢Ì¬åJ9ù¯¾ i¾ò‘üåõíTõ¼iìÜUʦzt âU骼Ã1ǰþW–?؄Ҭæ×Å cn�õµ{}Ö‚·Y6÷Iâ’ršÒ¨]Ë~³õÙàÀÅvòþõëùœë¶T~güC"3XC á¨݆é‘ëÈyöçk½Ì¯Ûwnùoë+½ÃòéÏSç;«J‡`K[¢î�²Û�[´Öü V(|’ Üë¸0¥% óäLØ�7F&� )Ô æOy<�€GÀ#àðx<�M­ÙE'ˆ¾5½!õSqbä™5õÎ#àø["à êáè/¼Œ)ü¶¢ç»æ…Ý­}ruä®b9�ùŒ;‡Î6¬ë‰6ë™v|¯Åбˆ[GPUŸ|zì994¤j1Õ˜´RÎ|ÆPL(H¾Tªú~­z\AI;«/Š‚‚ŽÃtM•½úZí¨©y/¢G\3ÛÁ…Ø›]–øeÍÛ:ûd¹3âÈÈä¡î J“×lÓÈŠmE–A+‚yˆKçdíx“$.<~DöÇ`9a0†àŠbÌ.�ßÞqùk%‹Ô«sZxn•åŠóÆ:ŒÊ˜Ža„VÅu0q 7Ó¸N†GXA�Ë`G¢Å‡tö¬�â@Y=’“€8É/`¥�gGMbzdÅÝ »æK¸)£Å“)O®–aò+ŒYø1µýHÉY9›Å0<‰¹:ÑWfXTsƒ¸6ÒÂN·0Mî“j*Jr¨®Æ–r&Í‚¨2Ÿ�ù–X÷¯#ºUÏ=–®4®gÝ×1šxVV%Œ‚�²F0‘“z…¦MN|§>žxÅ7XîúݱQýÏ<ÞL… TˆpHêÄüjþÔ–ßG¦‰hêe GõÀà†Svs¨{Í šˆT÷Î#àðx<�€GÀ#àðü�(è›ÚƒKb›?wÍ>j-Kß¹¥ÉÊÅ«¤%¾[a;¼Øesø­…Y{Ÿ‰dÉ<§D_êœkÇ?u•ÆÃÍ£ï÷ÐÂŒÍh«ØÑ{$b±ñˆ·G '›YAýÍ:N&+ŸßªÃ{[­Œ¹ÉtØew¯èiˆk�(F=Ux!×âvË—›­„)Ü�4J©UV˜->Í;�À+FÀÔõ K”ˆwÚÞÿøIë˜úKHê·ðã&”Ýeh¢ÄäAÆcÙŠ­KPãlõÐÓóÎ=ñô‡/DZn‚:±Õ«‡�ÄšñU%”j§ÖÚ§¿T’µé*ütd¥šê?½ð’iÝ ,Ć­í$MyÕK¡dûnÑm⨞‹ƒÉDïôÀJÆ9GÀóP®¤…ÓÈN„zB*®ö'5µÃJv­GqTÚ²ïìÔºÃýЉu Óá'_Ýq¾y7Òa)Œd›[øˆõ+ÙÛ:»ì×�¢G•CžºrÉ�ʧŠÈ#Ê豸(Î[¥,õ<͈`z¹hÜ7 A]ŽXÄzéºw0É;ˆ±WÞ;(Œ×|ivæPí*l:«n•]9aJ½JY\øÃD+VßFM4ˆ ŠŒõÊhÔ©áˆpø¹“îfH.ŽÇßn*œ‚Z÷e2îb 4xi7J6�f°F³$dJƒzvuŒ}ëâwÕ¬®FÁ8Ò½ 2 §¤Žk î03¶znyòáq'ŠêO[_A=ò,rÄ»jUD8õH{ŠózÕ'¨cÙÌV]C ;=õ“,ÀÈ CZá¼óx<�€GÀ#àðx<�‚VzÕGbs&Ëôf4‹Á }•(ê²=¦ÿ?›_í]_¸ ÓŠÁ~˜?Ü ?o…ª˜hYQ,üSÇø…mVÒGzÊÊ¥[­/ú͘ÈÑ2ýF­!äúºtKŽZýÓ†tÉ —Ü•±å+·¦¿»ݾmèýmA¾´.³¬Smünµïj²‰,ÛTdM¬ïݱÊ*ѳ•_²ÁÁ-Ÿÿ?KDHCQ6<8뺿·\v/b¤ '‘ÀôS{Ølð¦ŸöCá…ksjwú¥³l¢+å%ß¡u¥Ô—MÛ¾íËí7_‹Öéçä¡~_~(²…yk ö¶Tv–¥{÷D¿©uËr–Wÿ7è#Í”}ïö¥˜(}Ü*ýÿc'xOÒ÷lŸ?í¨ƒ€H*ï!pë,·w}ù,ÕþFn:)4¡ÀDò8ЇXSw£ p’P�1sëÅWiSgª#kýÑêY'·(£Â!.BIÓP†ìS¯›¬#|×"fr0Œõà¬çf}&Ï‹AØ„xM2ª¿zd¶ðÍõGÁÒ™máädWöT@ýI—ãA<º*3ξ¯Þ <6‡…"÷Gq ¯ôÜ‚�kø[‘vãäFÙí¨¾ é·{“_‘Ì�¶ QÔ7Â(Ìlƒw[á"Œ¤´¥ÙhG–0S#Tâv¨^íA³#¨y)Gý#´#BÄeIÔ Å"·VÿÔ†È÷˽ʷTº«�FyÏ»éQlMóÂeÑÇ Â¤k,rÚÙ*æÅ׌) »yu aG6™cu-°©ÁŽ„¤•Ç9+ÌËX²(à°@¯ö°Ÿüµ0Š.`“fèʪ|¯)®n˜šNnÈ»k?à­E:S_ŸÐ¬½ëºÀ¶ç¤J¬f€_±k+i¬±46¯³nL�ÏèCâüÿ‡5[ß@ù¢™Z%@‰\ò¡7|q?ñ¢¬AØ+ŒkCÔiÌ¢‹™ôÞ\øAã„ý�€GÀ#àðx<�€GÀ#0dí Ö²úý‘mè›h½/õ71Ÿ)U3¢štxŸ�³`/KeÞ Œ¹Cf·Ò�Å ȳ����~³JCõ­ÓÛ#þÛ×Òñ{ìœ?Ÿi§øèˆ¹ÌôÐꤕtŽ�_õ‘Õ«Éæe­·tžåÛ¶£�;•<ÁBã“£êê}2ÇǨ?)6¥d©ðÍºÌÆÍIšËì¼›ÿ¡ØA¦KìVß�÷ÇË´C·#ŒÒª™xä0dÆ3fF-’IJ³ ®ß >féÔáºH>43<%h’hŒ>y¨|S-Ã:YQ|°}ûϧÛi>èÂ�åO�xr ´¦¦cˆŽzÃädHß>)+ɺ²‹AÅ:N©Ô®–jÝϾsë�ö�ë~`'¾ë…±$ãýx„€íæäÛÿ‹±}>7Ûf…M×±8ŠÜæî!æFÖ¤ž…ø‹{í�éKÆÄM +¸†‘ƒ²"+²«¾‹�R;!øVûÐc²‹Áú8…)³³ ë’¶MmRŠ*/jµÇ²ÐR¼ò2èÜ©nr‡»]�m9�“È7-)ÇνnŸ/ìbMmGXûôÓ­iÊÏí�“~`{¸íìvvÐQ6gŽÈÜÄí}B“Í>~w˶ÆÝpzˆHÙlQ/Ï®.ìý¹á¢dŠ!†Ô’ª²6 bSD¬”¸åŒHÏú.“ù§›]#`<8Ù\�Óigýp:›,G¯X 甯�–^‘Œ² }õ¤~®À?D—#ßEz)œˆðVFɾiûýŽwøq9›uìNAØþ=<ÓÙ0 £<¹ªp”—¾\“T™#»°|ª&S\’ò®òò ÂdDr¤¢�¶#‰"2 NÜhÞønïF¥Äư”« ¸ºo´Pâkéü¦|òš½û”�­©õ»äE$´ˆxŒ=yuêé,/ßwrrtW)· HOC0c:E$µÈæ²~·ÒF°¨” SÆ*wE›ÈmÕ¶ë/ïX7ñrñF<ö ‘Ô‰}eA/ÛN^Ì{ñRýš}ë^L8­gýiš=·Å Ô‡QfêÏ 2P”;!ôÉg€½° ædÆÙõ÷‰X†×`‡œîSΈ,ŽiÇ3î^}O'êÿíß§—°+C;.ª4͸ÝÒÙoÚ¹·­®ç‹~Ÿ³snÝ™©ZºôÑ0¬.tÏj„Ÿ1ÿTº~=ŸsÛ-“�µ´�Âö ¦§]lçßt¸�yÝ6vÑmí&¿æ W5Û97íA›ùÌP:n–S©Ì–Y©|‹F0gRªÐ~Ôò‘à"µ…�t}àM°båë¦)k5§:=Ÿ||ûúúy¯ùó{�€GÀ#àðx<�€GÀ#0VŠÅûL]C?i}’bÂuh¦2„µTÉ¡Hΰ“c‡w<&-l1Û3ø™ýJ®Ñ¢«æHeú["°“þضÄŽ7õÓ¹RMC¸-ò„>`ª±ªù´ƒe®c1i©O,ŽÂ\B@Ç£�ÇÊúù/pîE®-æ¼ò-ŽEb'õU!ÙáDj§2sìÜ›÷m”E»ôè’õ÷Ì#¾×Ç&²Zij¦28Ñ7Íd>ÂLØOñ[D=&*é Fˆ–dšÒb™¦T¿�$hÃ|¥DdÂW&UÎM¶çFvê¾Ðõo˜Xyg"Ô@D| �Ôr6ÕÇÓ\£ìpJ3ïÝ,b¥ÅÁ,£ž IDATú]ƒdv˜ýyWä�G`TÔÐ7—ÊìÎ ÉèUP%W›ÙÉ¿xÈqS÷Në²Ã¿¶”›­â”…�éá(²ÒX&>¢^‹Q²>eÝóÖn÷9Ö>q[f«ð�dË‘VºE¼²ÅŽ�m·l¸�íý™Ûª÷!›?Ÿxq³f±xâ¶;2dWn~ÝÔªÒ_ÚaKœjÚË8ú¯Ö×Õe-¹'-YÔчÃ#ªnG°A²¹€"ØÜÈVk˜ÎŸÍ:æëŽn¶»/ÕÃWˆlð¤§,Û ñæKƒw*h¼<èÃÌ›­mÚ<;üŒg1ñƒdÛZ3£e†É–8�T™¤æ:zS¾æCPªßoÑÊkì¦_@€W�T܃OoÃuTážÎoB†×X ñ¦fÚìã°J_—õû¬õyʺ°l»•±leT©“ ßî^^2A!“¤Tæe¦¶²¿¼?ƒÝ6Ð×kÛô?9„s-/cÝËùágü…—#³Œ@JÉ.ª“˜öbŸ¼¥ír{áÚÅK¼p¶æº^¨Œì*?Ά1/_åÒ‘–ªWÈåü!vÄ÷[_ß5¶ð»¼h‡¹9§v°�æ6–k�`•"¸LY(1f*“þ¹b¤EfÙG¿5…b—u-~Ê®¾X/¢Õ® +­#Ã01 ‘,°¨¼·0Òú/vâÚ@¸Ð~8W‰«ü¤•ÜF9fá�—`¬EE^2µŠbÄhuÈ(m“ ©ú¤}÷¶Vki�´ ׆T‡j_¼°)¯^F®Ý3’œM‹j¸ÛN�}[’Ø+ü«iFé?oí¦)Á¤‹Í/§šOÚA‚‘êv[Õ;ÛÎ_¸ÂŠå"¤{¿}ãà'È÷ÊZNïwn~Œr¿�p"~ÁIum|P„á[,_nÞö¿±%lk9êÙ-œ‰=ñ Ô}0èb­�$8§Ò‡Ø¹×Ó~¢?Ú ³W×s*x+ù˜IVf°‘½ˆ€»ŒlѶûîÏS6ÝcÛ÷TòEzú–XÀ,Ž8^B™ž°¨ïç.ÝFþeV¯]xëÝÔ›žeú0QÔÆÇ �éÌ¡Ö_ÙÙοe!iåH÷ 6k|¹®º× ïÞy<�€GÀ#àðx<�WŽ@²–ÑÅvöõ7YSþ?\_ [ôIà;j}Gz;(¦¸¶œ™¿ß·r|�õïó’µßÚ I|}À“¹.Á Jaq «>|Mog-pýšº™Læ'D´bp½ÇyêˆçºÁÜÉRéZ’ƒ«q$±l;+�+¬4ø úe×ZŠ¾Ù fHSôãÓÙcví†aG «o*q|{:Pol˜Øéïú3¢­gð[Äw$iRNâÂHùvãSrüT%šWõÇÍô[1y’9â£èËÓ„À¯ø ­QÕ_²#çFêû´årÊçL¶êLh‘àÓ•ò)ëoìô}WÚ…÷v`zô#(¦ÿIYÉ )Î�` ù?À¾}ÓßÙivŸ.zç ‘›� RRBŠüeô'„x±`o×-¸§}8i$¢S:ÝÌ"ç°Ã òÀc”¨òLܽòT»éÒ×Nêbk=ƒ¸v$~%7C7¥âNcÙVš¹Îã±+ô°½´èTâHâÜþ@d<‰‡E�á™#F^Š‚‡mgƒ|ë»ã(¿‡åÚŸ¶®—¾OØÛ‡òPŽ‹˜ü� î°ß”Œ˜éÉN<Œ¦A­é7†¹ÎÏFƒÏ>Íé¿…(þÌÒ9-< »N<´°KK’£Xä$X¤2­pZoâ�Ǩ˜8sV¿ ‚UpÒRfê1Ï A&7¸&õlˆº©ýcäDÄÖUCiE/£^ŸñøÕ”¦zˆ{ú Èü7¿•5w|×¢–­‰}wôÏ\û+©iM“?Ès™ð©-‰CоâQ¯ÔMmþeâyžzálü¬Y_ 5V×»òrëœúvÈ@¡ EºÔdBÂÒ~ÔFÒ�ŒÛë]ÉoÙ§îx€GŒž؆´ÛÄñ‚âå‘kú„UE*ÿ¦zÞLí(œt†µ;ß6œñ+ó "@iB 2U£ ™¦!º_âÚS¥¾Ë¹‡†â)ÌªØ —ó QCkÑa#[]´%·° |f³Ÿ²¨K7¯GÜ…«¾~�§Ü'º7Ô–u„²eÍË1€¤NfL¥°º/„»L‚ ¿Ê£zaª‹4¡Hj�új�¥Ó²MG3¥èìn­&ŇãAîzMáúùÙÁå6•�jº¿“W?¼�s¹ó!“—ó9ÀHrô²]tûWíx×qÑàѶÞJ¼äŸ;Iåˆùpƒ6Ü Â-¤½Ç1õì>H¨W^FÈcƼðµx…{nèöÓDeù\Æiÿ¿l‰‹¸WÒRj§ôœÑH4ù‡àwÏ bp ÆÛ‚i8ux–—¥eQ´©ˆû"ŽŸ³�Ò×íôCP Œà4³â‚J‘ÞB|š‚†ãÃJˆ‰†–Š:Ãl°×ô¼â™b´›2ùüd®?Ëæ�GÀ#àðx<�€GÀ#àxõœ~À=vÁ-w@âB2«ï%’YÂ&×Q¡�dÝVªü��´ÏeÃ[Îñ<;÷Æ>ú±¨#®Fœ–f7'}©lî£�» Lë+­íJÌ,ÎT)0õ«å’EäÕ�¤ß5‚ëo¾Æ2¥#è[ª¿ÛI¸úáYoù{k-Ðø é߉­é éÏ¿ ¿Ê#}J×7TŸš¾_jÒ£7F?­‘SþÏ¿á§ôËG•Œ§¬NøHÞÕg“ªÜJŸ²“ö{jX4¿Axô1ˤÄ5) ú¤àëÖТ?ëàΤʰ k~ë†]L8&3ÂáÞ™–\i•ÒØW÷½l(Ä RµÛ%Ìn¦ß{~ÅyàßÕ©xf#‡‡rÎÔC ùƒFˆ„Ù|Ü`ß�–énÚ…¦$hê…ˆ5= ±ñAÐB:{?ÜÌRRƆ¢šéQü°•þh½KN±›~4ü�à×�éÙ S"åx¸…ØW2ñKP%S‰Ôv¢è·Ö_ú¤ ¿CYŸ!jƒjó‹ÙØGËðó”Mì_÷caÍŒòK÷™³Õ.2Z›Ú‘Òy ãß1CàD;}��‘á)¬yüÕý£þ/'ìÃÄý eá~Õ3Éá¦òP§üK~Ê ®©Z[È�w�€GÀ#àðx<�€G`üˆË÷}zúûZGŠƒjK¦é{F?¨›Xß¾¿§ú}ÄrêŸ9’—ŸHT Œ°k½tåš\ÉPDêz;òjb81i)þ†mWØ£Ïú{¿aƒ¥+qÿ×-8}-r:‰àhü–ƒKÈ#}o«Ír§ƒO_O&)¢/º]"°‘]¹(žDb¨Z?Tý5Yýµ.¤wB�þàI{“Gú©IX çHÿé»Ù»3GL8Ÿú~á0ñ™ØšVOQýaTíÈÃ#‰J—“B½Äl¦TÛ " ŒJÛÃ}ûc�@]ªÃGu¯mz'oý�'ìÀ£Î°TÇçÝÙ•Š´B•ÈâqRG�ŒR¿:΂ө#!§{¢€¼Önøás AYøÃ̃<Ù„™ R©]µpšAÆ&ŽÑ. ±³»Ä*÷X)üëP|e{„ãÇñßKú�mÈ©û†Âê`a¡lû}¶`¹‰@ýV¦RðP†Ì ŒQ�ÇñʸT¼Çš¶yl�púñ§ïþÔö?æÔÆGó¼F«)šBâä 1W.?—î‚G»ÁþDÊä¡~à—Ž±lÇ)¬¢»%çÄ—x`?kƒ]¿³i+pnµ«&ê¿ÇOÇâ_êTþIe®‘O£{/è�¢K-ø?F)Á•ïÁ÷Τ"Œy¤þd² ÁJq@~£ŽQûZ´Ôûﱎòjœ]D¯àÏ5þØ:îN˵�Â{&éhÄVE�¦^4ØQîRÿÝ´•ëmáÅ«1:ì´ãQ¢ž¶� Ä¨Í+¥çhWWZÛs Í�›_è±9ß~½7cHK72ìÈM@B]—lo‰û-?¥�{±)½Z=]‹,êû©õg_dÔ;‰om"ïˆÝˆÁ‹Dˆµþ¾;jÞר‹¤.Ìû²•ÛÞï{ eê&Ð ŠÙ�ÓÎÞ9ƒ0"oËåk ½ÕNÛ÷YÇE�?`¥Å,Þ¼‘{Jí—ÁŸøqÈñ_YÓ´ìøw®9p±FÂcùÉC°ªh&D Å6¿œ9êß9ª_Œ´ðS÷5 •…Ö?Udycwâ¾?µoßp�å3ÿ¹Í‹ó!Š&1[ÂKVÄmüdý]�Ù7`®du=Ÿóqà{"åÞŠ|1ØÅ=¬Á¢ÒÀïl‡Y ÖHô”·³o<ƒt>AÖ1÷!Ó9¨â5X¦²8…6Ï"%­¡2­j]!írå÷Œ…\Kº�Y?wÒ¾?· oø³E™÷ãy7º­ôJÕÈ´¨æã´Ï»¬/ú�ö¢­xçðx<�€GÀ#àðxÆ�J¸-ý4øÑŸâ™³ô{*Û©ûŠ€^×É4ãy7_‡ùÈ¿ã"}•>€N²dI"Í�—°MbÁµœlPgàFÀt‰J̤°£»¯¤8:ºG|ô ÜÏŒg„inaCõIÅ]¨?IßX{fg[ƒ™½\pnû=¶¨ñ�ë«Á‘¸Î!}Dá0[;º¡æuÍ=åªÜü[¬„îêÏÁ%¨ŒNü¢\—éÈúîìÛB³ìÎEü@.;[ÛK�[ÑÝ©ûÂÃÔq}³[îNTåø5 ¨üW™s¤·µ[˜±0»Æ�Õ‰ÀŸò¸V³™Â {ÆÍŒ ¥S�±�h¶0éˆB9æf¯¤WYj°ÛfMíq1ÄM >-Ùµö�‹²)<,`v‰¥&­px£² ¡-\Ùn©æ@šìšóûðª§ç¦ç†c”’2»äYT¨ýcÀè^0ê‡XŽSÅ� #HÓÂÕmP¿S,]�¨NõX&ÄÞViö‰¥¾]·® ¬ø›]¼=vÌS¨È—Xá�dÐeciZ¤ð‰‰ò|Üd´2GƒÔó *ò‘^¬™YˆvµÌTìäC¸ôá3‚+ÌËZÇôI6b {Öe¶ ñ27©ÒJ˦»ˆ¯Û–ÌâYäÌ»ŒÙz\ÒÂËû1Çâ­}=¤•´Îü@Ýépë­÷êðx<�€GÀ#àðxFDàœÞ…�êL>; ð‘�Kä­ÔÆÏÃÍüÄNÜû†áÏ[¸7äïw ißÈ&¢WÂKÍðÕLá§Œ�l§ìó:á/ºaŠE¹+³ ›ÒÔÌUõgŸ±òà嘮8{�0¯æÄ7ŸÃÚOG’&ˆÚD˜ÇìÜÊÖ]üœ}ý€çF�þ»·ÿŠðoc“�P qH^gîñIÄfŸ¶Óg?S7ŽóoÙ‰>å¥lo"]ö"‹¥XÉþ;þíïoîH8²SHo{6D�ôo�e�˜Ù¿Ñ/턽O«N'¿{ÛÔç;Io*ad¶Ejjf ÇXÜ÷‰5Ödj‰¿°9#°y)¨‡×t²Pà‹œÒÖØ-l|i“»’,ظœri»+¤x^9ö±ÏÍ#Ö‚Ýí¢æžSívÕH­flœnî\�rczÃmc/CB ¯ß½P˜+¬F�=có™Øe[16ÏÞ—GÀ#àðx<�€GÀ#à'*˜ÊÌ—3±!A3T&v+ÙEåê«§kIG|…›]\U_»x‰gfüV¦Ô¼®±—…�–ÚŒÛÚ©¯!aƒ”ËDíì¸ìezÒ9'2rÉ7é±Ö“4ÍcqAPí¯Ió4$|".Ì‹fdv²�+"(kav{²fRU0åfë*ñ7õ]Ê‘á�þ˜!9�(¡…Ú< ¸yÔuoE-"úT µÜ` ë› g´VÑýϱ#°ùÔcÇÈûôx<�€GÀ#àðx<�€GÀ#àœ‰NLG†¬¯%nÚ9XPÙ/Ž*ðŒà²Ø�¬UÊ—c"¨Æ@Û†fý6p1& ÖºoWX�¶ö\ÆJ‘Ì[¦­…­äì]‹°…èʼn¶uy&Òm�ÅÉ\«Ëï0RY¿YæÈÒ�Ë‘.3“7#S±à[ÃÇñÆ(©eò³ŽS‚`'®°®šTéÎ?DTKniçß¼'æfYC -7ƒ©T+U±¥½Ðu(uÉÀ€ˆmÊ+Ó¹RŒ³€ÇËf4ËÞ;�Àˆx‚zDxüE�€GÀ#àðx<�€GÀ#àðx<�qC VK=Œd…H�#È�¾Ê@ªÁšÑ:òWc·“C·&ÕÚ*i.ÕœÖTrë9ÕN°™êÖ/vn¤C©…Ÿ]¶#kSazÃ0QnK$"ÅS�´Ƙ� Z x9`RÖiÅe'[Ž¿ä!=FÅvá_ëkN|±Ö‚’Ó‰ùrrìN¬õ'ƒmo­c$|«A¨dÛÎkàçLˆ”C­Ó–�̤Ʊò­u·šÉóa¤»§¥š5c¸Lù´˜8EÖ… !ª]YÓnaÇnÒ^º/ÚªÔÞðÎ# Á*³"`�ù g)œ!Û8Í(‡EúbĶ5žb;`AÁ(®¯ÖÕ²ô‘â'œã^•„8nqª H[y©9­Ô¼å,{¡û–ÊN'f+P DZÌa$‹ÎÇŽc“ñ’<ג뉩Œ IF‘Eý–.*ÑÑ]€Ýè)=<Ï:ËŒv·UGÅ^ì)5³ü⯶OM\7`?yΨj$¶„Ót‹P¢�e˜â]„w 6ëk ?-P)•´l€'d¼ð…�»©Ö,*]1â:NëæÄŸÙLðõfZñ¾Ø�€GÀ#àðx<�€GÀ#àðx^s²2íÁ;2”Cå FR�’›"Êá [L|9æ•ð"aQ_+¾(¨o›¹ˆj9§*ÂUNA夞Ä`Nάûwæ,ž»ý‹–'‚„‘ÒXN ð.~kñByD-’:°NÎa#lâœÔÏ5BZdqÎʹZê.’†"ˆø” @+xµ¬Î¼ eè©Å¹nðý¤Cºá05ºKQæM éc°fÃ]%“•V:95,j™]1ìY±”Ó,zjáCð�Àž¶2Aú‡:†¬�ÀÁâ—,*¿Àþvâ>ÙW‡'ä�=õðu}\üY�€GÀ#àðx<�€GÀ#àðx<�ñF RFÛ‹9 §`f/–¿l�ÖÑ0vT§×rý•”5‹Ì†l!-ߢ}�9 +BèJÉ»®쇠Nã; �ìEÒ¢žŽFIóÙÛ>j©àÝ„™IÄ!f•i¤U‰n·J¼ÀÂò 2«T¦r}¦¥ÃwBÖîN6e2UµÒÅI}œ®’äÉ™Æ%b^{QC‘˲†ÐÑ8˜»@�«X.�!\‚s`sçëì0ó*ü er…Í#QU(‘ëÑ1JîJt�UšO³Tod]ÅØ&nå*ÍV< ÂVîX²Â0büD�ôÎ#0:ž #ïÃ#àðx<�€GÀ#àðx<�€G`¼H,$¶„çtÑŠ@�µa2MY-<˜¸@~!R“EùŠ�¨=�²ÏÕ.¯±ÏÈîs,ûÈU{Î\uIC;Ây ß«\pã[QB¿Ÿ[B.³ „skÂå�é—ØWßù“Õž‡�wã,“ÙÒ·�üIY�# ‘ßòm<,D�C½Í ç6yqäoÑVG�#±¯] +²ÙER´/N l¾âær©°gQFìƒ'#ì\¦ÉFUBÌ{œøVÔÑÞy6 ž Þ0¸úX=�€GÀ#àðx!°ûQÛ¾%m=åÈ®¾¸:M·ŽçCNšJGn{¦‰†–Î,·ÁeÏØÂËÔ)Ù~\»E™í¬5Ó¯[d“Ú^´ù…ú«Ö�Sý«ï-4Û@/ÕÁ‰è�´’¦½>k×}o1{×›«p=ÎÎ*¤­Í²V^V££.ÉØ�maQ‘Nsy©-ü÷gÖ#³wŸ6ÁJ3,(O$çM,‚´ØŠØŒ\xÁ2⟲¬W†¼g�€GÀ#àØô�™fÙ-F±+'ÕîXß8„oJ6žù cÌ«*QO›ÈU–ãëÌ/qq®ýGµItœ¶ߪ x׎èÒ»ïtÒšHZØavN&A–×ÿV¯» eN[Ì"{U6‘én�ú9N�N.'1ÂÙÉÖ³\ØhqÂÖìXãp¡ù“:B1þ—~°[k1Éém¶¨uÄ÷RˆùŽ¡ô’ÁT+v¸:º³ß{ÆOP�ˆ> �€GÀ#àðx<�:ñµ÷3…wVºG=¶áƒoOlªŸ3P^eV|˜s…<ô´!HßcAzüO¢O׆W:¡¨�ÔÉ˶¬´#¾~�õ¥/¶……¤S«Às Yëx·e²ûàoñwÐéÍX:Âf"J£þJ·½ûO :ºÔ~{6_�;èÔˤ>„�Å·£|ê´lË-åR–!'lÂ~åûþ¥‡üb›±òiûû#»ùû‹†ü×;8üô)à2¬ÞLšS-—ÁFf2 ˜N3êÖ ÏÞóÏtªã—­RºÃúó¿\ïzqús�€GÀ#àXôª“)jgªCoRGàÊnrB¤6Š«Ïpï+§Jvæ.¤øàý«wðÝvôõíI†�åð8%5AÄT;'ÿ�ÉÞTð&®k0Zö¤±/�½é›Ì"ro}žo™F.Ô*†úV©š!qdºÌ TÁ>ÇB‹Z ’¼Ë%9Nl>£Ôú²�=Ì܆âÙ\ÜR\ ÈóÕnöÝÛ ¾ Pš[ < ÈllKë{¬õÖ7òû‘Õ�ü‘G`üðõøaécòx<�€GÀ#à¨!pÄɬpì ‘º º15Ê%¤º‰z)µÂÂlÒÕ:ô´ƒ° y$þñ—‚ô+t²!ðƒ`'‚—³( F(—âr�‰jýÊCO}+~?Ƶ˜j¬Îy3áX¤)Ìb>³™½”ë½Ö’—­ËúÎù¥Ïƒál¢¸¦<ÂJÇ¡:¡*§UG”Ŭèw²æÒAvø)—ØÕçÞV?bÖ#àðx<냯Š‹šÒ6¡^ Ìû4Àhr…�ß‘\*µ;~Û Çû�¿ØqÔM�e˜ø¸¶aÐ<ƒ°NËÊ%Ê{O Ðb<ºn¸ÂU|‹Ø4¼ñ-ÂVS_Gú0!¾]›r˜Êè«6 ¶æ<ïiÞ­n1ÈjIcÊ™.+ÞÑ�Â%oæÄ¯²í¾oˆ£XRFp"Áõ�‚êÙ%-Ôîƒ*�i}+¬k®£R¹[Û³(ï$ü¶ò¢4´éÛj2¶³?Ìñ™lÞyÆOP�;¤>B�€GÀ#àðx<+³xP"7¦s0× bWÓhÕD¥«sÿ{geWU§ûÿ9·† d` bhˆ¶íôÓ'¨Ø $`¯§ «_¯¥.×ê'.}6Ò"¦®×L2hìa¹Ô^4úºe)QÛf4Ò‚ØL2(O ØHÈHæ¤RU÷œó~ß>UI*©[IU’&�o“S÷ÞsÏž~÷^öÙßùÎ78=ã¯~¼ gRš-r|Æ„‘96ݾKRZm¾Òqû²�—wFÞI)6£êÐ{Lø$NSO–·ó¨©\ÁäG5á>$ÁFçÇùs3xl² IDATÛ€sJ;‡NÓÏÅå‘�9–£ÏUGš¨1ÉKʱR\I&¶š¼¦~Ð>ÄôœvVù~ñ¦)/ürÜsí‹ÛTÒÓ»6Æ�g™¸h¹£É”7pû0®'„úœÛ€Ï¸ì_xOýƵ-q\Œ¨™Ý§2µàRž¯E[¬îYœömýGÎë ÍËp¨¿6‡ðö€�/wºÄhÑÚ“Ê×”¸/Êm îªãÜ8å‚füäºÇ¶.Ú¯MÀLÀL`D ¯¸tSØ �H<•¬‹¯ßZ¤¯>8•ƒOa\šÌ±:à-狸Ùêé8ìeÝ™5t*¸ +÷r†¸«`:C 0þ5hK=žn�sÒ>ì×ùDŠßÌ¡)¯ÆGÄn.O:àídybëlñÕ{�d StžÀNè4Þ&$ÃEâH9í­’{Z­eÓÅ÷ôØ��<´¨¾©Ø>e [çYœ3Uôµj“p¾bÓ¡OÚªGá¹”Ïc ýÖ¹ùé³ânG†#<ÿ£˜ýàS±úî[1 ¨?­ÓìûŽ¢í�QöÍ� >ôlëýŽ Ôt"íd&`&`&`&`»–ÀÝ7¬�3.þ%óBW$a¹žLÊ�“1I’‹'Ë�d‚¥‹p?UÝ4×0Žž²”À+1VbµDSM™X¥É»jæh¥|�Ó¸Âé[ɹ¬ÛUåÔÎkÇ’ÜUYÊÃ$ ‡p¥[]ó•¸�ß»]7ðYç��î±WãJ~7õJ{t«.í®ÖP×êY…ëjT…ø˜H{—ó}y.áX“kDs&¡U£=:ªsyýE¶Á龯¯‹Óf=FÙ“0M+Äu$¡[‚w-ç„ý¨p~Ë!–øˆ�nƒæöâä.×]Ï Ë‘å«â¡Ùâ88)&wÕN_²£™‡O£,ØÊGV➢Uµ’×,ŽÄ… ëY…žK0‡µóüË"ÚÚþÒ'¶;)\»_™€ ˜€ ˜À` �c8™t‡ø—ÄS�grFÏŒë~þû~ž(ñ9âÎ^zè(ƯK8f*Y4ÎkìcÌ#UU¾H¾ˆ³ÏV¸�¡SÕ�LLè0�‡¤;¬ÈΞŠ;¢ÊjhÁøÁekㄱŒùZ8Pc­„Úþ?nº÷«ñ©rÄÉZ°@Ýš�ß1000Ø·_ý‰ý£è.o¢Å¡æÜ3— ™I’Bdh²¦ûeå~*W0A|’Ççyûp¶c8þ`Ža’”&’mqòp+î€ïI±«jªçÉû+ÞÆí+6ãXnÉMùÎwå<ž�ت¡‰ÙÃÃvmý¸s£Ñ8šr¡œýi#ÿ*â[–K¨ëÑhö|3zÆþ&Ú6¼5ÚÛÏäØuûŒ5!M"<j è�Æïîã´˜{å]ÛÔy×5߉“º~ã›7’G±³å£Íô5ÍG²DŽ©Ô×Wï%*#(k±&¹ª“ûZü^bÿSÛ”¯ÙäY„9Š'S©ƒ fºÍw%ýyvPÏ7ãø¶çâ±æ[xëãÖ"¾u)×Ô$Ž?&ô„OɇÅ#=åõT¬“ ˜€ ˜€ 칊\¹ÓIá2Òb…ºãаWY\Ê{ç –.gZ ê‹S¸ �%NsP. „ï!?½M[ºnéˆqq‘·â"póW׸`�Æ×$øR¿.Î6�Ù�Lˆ�Õ,̼*6p.ÒõáfÌAð>ᑌûGsæÂ…àä$VÎ)z«x7w&}=¾öÈ"ÆÏe±Š�fmén(½'2wŒ¥XÏr!“�±½Ò�`Åã+žÅ{ÿùþÁNæÙ÷2NwLã|Ea6{Ó]eê/›\Ñ }Æ]imùIqý½+££ûùø‹º�½9q†Eöq’Οôš5¶·!2ßð�±nÍÑ5cÍæL<«:oNvÎi™Ö Ñx.ƧÐ"©o¬YÇ(OŠf¾6MÛ“§'»àül,w±•äSÈ2œ×%ŸOkcÅx]ØVT±_ìíôÅv20000�ÝC`N×:Ü»™‰ “K‰Ôý ‰ÔZI^1+8eyEÜqå=›1³ë\Å×s˜&°}õ(ÑT‡h¢¦8ÉË™ Ý·_ÉD–WJr>÷Lú¯Þ“ŽO«òQoFHŒJ.Ū&�>ëCÌåi‰)Wtè[-¾TI þ1î™ÏÇœ9.-MˆŸŽ™—p«rþg<×"JrH)Ì"|1 gòTÚò1„èûXlp[Ñ}0šq ŒÊC©÷·!SåÐnMq‰UÄÖ¬ªÇ#߸ŏõºµ1ã¢�!„÷äÇA^ý&ºW}Ÿ×ƒÓi³>éw‚L}Ѥž²µpR‰sºxæç§ ·§¿Ïò÷ܘyé·˜ÄKdçØ4ÉÔD×uãnƒ~?û,P'\þc&`&0*E“K±i½ ¦õÙ9…ÄÐÅk�;\Ö]Viü–“Wccl}uQûUö=ϱß�uï¿mÈvLxÓ(ãôïwpÇkUè¢o[õ¨;·8¿¨*¹�/fœ|…ÐZÏĤâFÞ[”ÊÌ«;ÇßÍ1É£óµCçʯõ#tç–ǯuG"rºË Ñš1·Â‰œÆötg.h.´§õÊéâ\pŽÍç>]8°Ë1Ÿ`ÜþÎŽä8Ê&4HÅ]Nõe:×QþNN�>ÉÅä…Ñl&º«›Ùÿ[¶:}ú¸f|íѵ¹š¼khc}Ž´é®´Šv7>c'.#ÃcÙÒãùÇ/�Ù�ÎFÐ?�óŒ ´ŸµA$ÆÓo…OS8³tw•.x§¤pgí9ÏRÛE ’ ¯ó.>Á•ƒEøþŒ~0�- ÔWq¶Üãç&`&`&`&`&°+ ˆº)$ ïÕŽi^&ÇT‚ï:ÜJO §U÷]OñÞw8^“'DlŸb/âÿÑd­ª…í¬ç˼_O¼”o!.*…ÓÀr<Ë9¤$·6S'W3)“PÛ:5Ú>ŠcI‹"É5„0« “è˜?ØBœÞ\ÆW} Á÷ê[Íqª“É™\N„É™¸æùÔèÜxâæ [=ËŠ_S×*öŠ}Õœ]b>Ï+æU±0-þ\§•uî—H[®‹¾�×áæþ|ÜyõWB!C'n+ÎgÒ&¢É¹®øÖ í!AÁ;ûîàÃû_Í ÞWÙäÆÒ„Sø4!G´æ¶_'00Ø)蜹%>kœCmæ‘ ³¥Æw‰�ˆÆIHFàĵ,1¸"\D}±ö…(ŠgÉù@ôe7Ä_žð¯Ñ5°¢ðV�Ê„#–r®ÒrgŒÑ±„Gβ…lË©w£<ã]º¸¬E;¢7�™uañ¾y´k.Û³´a>m]ÊKy¾‚�òÒE_¹“%3ŽW/rìOiß_óøIŽANBúžS_àú–x«•Sx³ºýÛ® Ü9gÐEbJq‰Sn¦vÆb¶—x1ýAtFà×íÑ>o‹9„”„èò ê™W´§ZÀ#ý®$º3¾ãjÎ8�ڼHçýáüØØ~)œçPÆ/ùxæqì|Êѹb³ÎÁ8Ï©R\í:c-Øëlmª§¢­Uõkž/¾t*w9™Àðì ž�ß5000ØYÝm/3Ý’xÊD‹«äœfÎ"!Wuqÿ�Uä�[Ù�+¹’ãYVåÕ”Vâ/e•ó7 ¶[p[×r|ž ±£5ù{“ó ¡š‰_«tú,…Âp�£Våׄ�š…º;îm••96aFòi´ ×5NíÔæäÞFf‚ÜÐ{-Òú1¯Ä„J·+7ýÃ�•ÄiMšaT!ò?þ­~±½¿Œ»ö7-J«wŸ>ëƒ8Æä c‘Câuæ)¤Šú;&äs¯øÅ�ù'Œy’Û›×ÑŽ^Žc*qš˜Š½Y•É¥® N&`&`&09ê¬�ñ\§Æf’\·ã`}A8�7Èá,g²ŽcLÒë§pö±nâÃÑu´öµN ÿ‘·/¬Ç3Bp(ÔX¥»²(=-rœ.K\ÖØK8Ör¨JîHê“°»9}á}7Ç×~šaùO8‡˜Fs¸CJ¡SÓ§ÓEsêán¦fù0áF^ä=�¯DÌþyW”íÎ13kl×…è—©ç§±¡x$3ðG1·ÿæá(§xŽ­8ÓõÐâÑ^­yž'9nm¹£³y¬oüÜ@›{›s¢£]Îå÷�ƒ‹ËŠ%�DÎ%ê+òµ÷! ·H/1ÿ›qõý?B8?ž)'{+yé»ÚWÒ&… #ŽxVrÞ’7ù”øühSÏQ篣XóˆÅé|½{¨·Aâ&`&`&`&`»”€ÂZ|䯹=UÌ4$F!4ÅfÔd¦HŽžm«¼­kCœÙ%§�òJ”ÖÝrQ)¼³Rîê¡SQüŽÛ‡�çp«ÛOëÿt«ižDã¡ó5Ú>Èp?&a¸‘˜4gé6Þn™Ps¨›Kz�6ý“´ާ¯ZRÊô(çö›7ºÕ³šLt[lšŒkÂÌ4¿IÜéªÉ„|„)'LI¤°ZìP"{ƒ(U"rGד筋�ÓÕgü•\Üõû5?œZð—“m]›ú±ídxërüÚLÀLÀ†"P¦Ås�èiLÒØ¬q©Ò½Å�Èò=Ü»í骜ÂU¾žc¹Ð=yi|é];îÆý➤,m;—êÐO°X㓱ô“£·Ø—‹ë“¢Ñ¶!úŠWcbçÊ8çøÁ‘j<ïóã–[.‹çž:¸#«»'>{îåþ1và¸�Çsß÷OOwê±^`òÇ”¡môéâê\ëδÝrK#~wØäS.­èŒ¢‰ƒ»³=eoŒ!Þuosæ…-G_£sî¥,P良»m&`&`&`ÿ¥²\ŽM@©VŽ) ÔcKÂ|¤0-š£ÉªœÖŠm˜œ?8œäØ‘[G‹¶HYAìÇ6n&oZ°0 ÆÕ´¡êwk •5K1/RN#6¹ªtÛ±êOΠ¡rÕûˆÈEc¸bFK—ëX®/þéÖa-¶8Lʳ²_Ø®£^ê¯`ÔJĦ8òNÕã©[nn…è�h.ï•bg¶žœ|!‹H±R¯Z)žr1ižxÌJ½çd&`&`£# Ô�Ž4¸h€¬Ï7öK‹é]ôaÂbì�éìtYεíx:›Å#6Ÿ³|ndzîQGÖýYß÷¨¸1{2�Ö'¦{r«Ý60000�×�Ú=M›5¹KsR¹y%<ÑžÜÔ-ú£øËÙºõ¶¶qR%!W·#r·He“Å“:$øJÈV=ºE–[{Y±™ë¬³±1c¡#\ÂJr KT¯o;¦^Å¡&­·&ö!¾³âQÖêzò­›q+{TœÈáR '‚ˆœ%µ„mÚ-ǹBm#[`èÌ.“èªêÔ9?¾ÚÁ-ÉU°S95N›uN}8Ñø rźÌqƒ5~�Ø—ïf‹I%��>¤'·é?.©ÈFÖ2:™€ ˜€ ˜À&)äÔÀ«4Îi|ªÇ]”u2ØëX Þë>rwØLÀLÀLÀ^òo©%6§ ­“ǾF¿‹jˆv•LTsâ¢JóOb)sX•VÇ£"»Jâ]7ä²&)Ÿ²%7²rêÅiõaûGGIø‘n.ÄÜ´ ’ªT…ˆÅÛ›4ß×µ>Îü?pU¸þh²½… ŽH=\’S;5´.€‹Z-°g¸ÁG’Ö¯Þ7Æî3†Úu!@I7R×�Šm©E£ú ">q(%ˆ‹ ±9³ Q;- I|Iµ=-¢$ဘ’Éé¾<ÖZ¨ÉÉLÀLÀFG ‘B|hO&cÏÀ˜©qPc§“ ˜À^FÀõ^ö�»»&`&`&`&ðÚØ&£®^¢o ±ÝÖH<ÕÄU¢ö@Rlè-_ìßüXâ®– ›B|èIš+LGë‰oÖ6‘ Å¡“˜¬Lµ¬›&ÑÄ“>©G´7S›êÑsàØ“;løRuý“s9ž5gWè�fŸÜà;žòvú¢œÔ—Ôwò¦Û¨ëÇ,ï`·y—B’¨äJ‹7¥$1\±»qW§îòÔÂQ yýX<äû9ùÁLÀL`4_º¡qVµbL3ÞUýãz½^ÂhJu0�×1 Ô¯ãÏM7000�×�Z”–H,ÝSb/"n­ÿ¶ìGrËYLJ &GpíÇn™‰7Ú[‘¥Mbö@%¾Ô[¦º·Í�Ç„Ô.U—ë�B[ð_‰ûÜ6×à=É­�ê“@­­µ“Ky˜�$*¥¤N™Êê|¶•j¡;Æe^7ø¯bO§•! cr“+FöZö-罕<×"�Ñë,::W¶´ƒús\ḧ«êÁèîÔBIN&`&`&0zEÕ ]DÕ™ÂiñT�ZÌ7>ÖèkuN0�=˜€ê=øÃqÓLÀLÀLÀLà�C ¹w‹åBNBm¿€‹ZG|º«“)/ŠiokáV‚k}KðÐùä7–È,!q÷×LÀLÀLÀ^[ˆµÂ/“Q‰§Rƒ{‹�8ÉÛ¶,cqCY«^CÂ-y’³Y*ò€ »m¾ÍŽã:ÄʳtçTcýgÛ."�O7êèîÝë,Ö›eºü¶¸êžS¢j®æ®¢5ÑûÊ‚èúÔÈÖaØ]}p¹&`»�ÀÀ ÷n«À›€ ˜€ ˜€ ˜€ ˜“ÐZv­C{bBNc¶L¡3˜”¶NŠÃ¬Ù«bNð¨rRY%:pësÙ²¨ë«cNËE�{z Îù~ÜµŠºº©KŽaÅ`¦ª$è*¯Ú8!NÿÛÖ~ï5MŠR‹," Ë ¦pµƒzm”Åê(ú~C玄þ ˆ÷u_€£u_‡*±sÂJ´õú ·Jý‘&â¨>á?îÓ1§‡*ÁûLÀLÀL`ט|ÀqÄ�þcÓg(ô6�—ºK‰õÒšŒUê²ß�¼qAäíÎxV4¦þ;�LÀÞàFv¢û‡á ˜€ ˜€ ˜€ ì.I•ÀL né•PZ ìF VÌh©È$ú*Õº3�ˆÎykçu:4ÅP¦JÄÙ �:‰ÕR�U‹Te«É@8Ž$ê#•!Ç·\]£±ô¿·ÈÑwyukr'}à –¬ÔÞe–+bmï/[æÕ‰G²’õ·U;“È­0'#;o¿³k u®£ß(D–îÔqåPë€ê¸8hÊ©¼v200�ÝO *¸À«±›19«Vá¢^Âð´˜ñö%F¨hÀ†ªe¼¿ž¨Z\`ÍÛÙÏÛJ ;™€ ¼Á ´>9ƒwÜÝ3000�QÈbÆ%Ç1iz ‘&&3™Zecall8îëR8‰�IY̼èX”Î#Ðq÷§ ÕLà({ì®+»Œ#™îí‹d)!vW•½}N±™™›29•X\ ÕŠ Ý�r'¯„^ ÙÉe…H,°^ã2Ϊaò‘£êwZKÞ–ÐÍž”·,:Z6¸*Ã=UàäB¤NnhþV8½‚Ï»,?DÞû†ÎŸ}˜¼¨å ïÿ.Tˆô±‚Ïñ‰xh6bõ0)µ1õUõÑ^u»T»Ûp_·ns«"g:Ê·aTg¢/�=‰Üý}É&ÓÇ�‘õöVÙ_£ýYL×o 8’Û¿áÝàïæK±q®ù Lÿâ±GDQí‡è�ˆŸïªßí¦ìÈ�ä{Çÿ(»*Fs—´û5ú(\­ ˜€ ìBU¼ÍâÅèht3&.fìgÑbÂxå«KÆé\S5vk‘ã^Æ­¼z6ÊŽçÒ~ÿ1xC°@ý†þxÝ9000�]J`úùS¢}ìç�¥Ü£ÚÐIû�#WE£8%μôÛqÛ•Ï�ªÎÓgÈ-­Ÿ!Þ"‚b6‰‰®Ýèc[ã‹Ó®oŒ;¾<Te«Ýc>‹hvx4æ":úØå1¾yí¾qÔíÞÑU„¾ÈàÅŒ“IaÉ ‘¹d¡¤–‰xÕ£“¸*Á6%ÆŠ)� “�ãòΗµbV'Á¸Á#åáž~ýø¸ûKº­xp*Êû.ÿ[ð³\‹5é|Yõ#”ç“øÈß3/>&î¸ú©AÏì‡ ù^ŽœÄ±µ³»ÂVUËÙQæ�?Ô 1¢ÕäOž1žã£¬Ôׯ¸¡² »¯,ÆíÔÇÒ®Ó÷)q¤üäJOß±#cæ%—Çâe×ÄãßR�ÖéÔ ßÅç€[ý.þíúŸ·>p'ÞÑo «>G3§¡ÉïO;Y”!5¶Bü>�‘×mÿ“×W±� Öc£–-!3’{9‰¶¸§SÛ•OŽ`œª-’I,Âs-˜Äiå¡^ŽFDn¬~/9ºMî;¯z8f^:�Ïx_Þ#T3 úª—vfù›ayE̼üoc\þ@Ìéê�™]GP×eÑhÂÑûp¬nIÆA‹K½*–°ðâ]q×Õ/oS×Ö;ÒçN¿r8Õá>j‡¹õ,ù-Îw]óP̸øPÍ�˜Ó&ðÝ’p.rxK =˜¾œB¨�·Äé³þ%òâ·QvÏ�îý‹³ñÌê|ÏÛä¸?Žcu¡±¸œŠ˜ûb.1®wuÊ?E?ßA}Sá�Я‹¸Øól~[mÑ–�þ÷•å§GSþTÊÕÝ ú.ðk¬A¤O¿þŒ}W²�<µu|’²�á«ùfÚº/í×……iYÏ÷"çÕèÛ=òÖ8‡ ˜€ ˜€ ˜€ ¼îp‚êd&`&`&`&°]g�766æ�ùĨ‰ˆN„r@´“)¡+«ÖRÆþqò…“âžk Ÿ1‚¤²{òƒ’ÙDp s„tÈ�ˆ›Å:„®Ñ—½±!Áo ›j ¨Èsè‘�‹4¨{4íÞ^O»h®pEj§^Dá’7³ªX´/Ç)^4N‹S¿41zÆßA˜”�©Øéç��¶Î“im'¼†YTØ IÎiá?úˆ™3f�Cø bXÆC¸k—¦¼ú“K Ìzx†“•:•·Ž}Ý€%áâÓqêEGD¾þ–¸óïõ°Ejô~#ŠÎ©|ršËÅ<�¼Š+­Ï{.Yú… ½¡\g\NJ ÈûÒ‰“,ÞXuÓÇUl¯ |>Ž8ýý-JüTŒ"ÞmmßäO"rúÜõÍR»åÜžŒ8ûÇqÚù‡Rö«Ü"½"z:�®ÓwnøÔ¬þ1ÚJ.JÞ£Œ7Q¾¾·rjëûÅw!;„}ô­q(ýâ{ÛÖãúø€|q�ë=ŬÖñUµ¡x}ôõÁëLJ¯x„ïê7°!?˜O!>—€ÌE êV˜•ŒvæŠ ¾¿¯õ™úN¹|׳t±„ ¸œé$aDô=ýïKeë3ÊtñGÂ:®ï\¿-Üú¹\ôôgwü¾FˆØ‡›€ ˜€ ˜€ ˜ÀžJÀõžúɸ]&`&`&`{�e“*¤3ÄHmIØ• Y¡#$N#b¦EüÊhŽ•Ëwdi vf µûXê�†®¿±ú…hôé{ö33lºûšgbƅߦTÄU/ý>�DZ”?žG] PÛü‡¶<¹IDAT |„a¹U%ÖßE-®ºP‚è.Á?m õÆ.MúžŽoâz— �ã=K"ºÒS‰Ó}é××\;òß—ÊG(”Ÿîæô= —úN '.¼�:hd©.[Ä´É5­ г® "�ùÿÂ(Ú=²–øh000xÝÐäÀÉLÀLÀLÀL`{äì-K9b_eÃIZl@e¡ŸâUö³^¹ˆKqK Yú6e+o™Ê^B™+£(T6u6Y„±©:–Œªlµ»jf‚ņJ¿e±Š Gvs-¯Ù×\Éû‹FUöp½×ƒðи܆h—#Öå+8| :Þ|ŸG+|‰ç¯°­D#…ÇD üö'‰Áµ*žrFÃ7žãq!ÂßbÞc±‰3[ÒÂJYZœ°?3“YX/²—yöç‹ýùxž-b¿Ú�á;W¨‹!Ò�×ü8ŠÞëaô¢ð<ÊxŽç ùìWðYu³á0N¡!ƱUŸU±ˆç/°Ÿßœ˜{ÅµÃÆv×.‡2á6±90±Ì#SßèkõRb”Ñï<1"^2ŒÐå‰+�Ú@ÜÞÁ4÷Úû9òJ„Ó_ðYÏ£? hëÚ¹˜ï°\Ñún#��|ÆÐvÕº–Á„§9^åìJx�rªï`¶{Xúžê7T.c[O»øžö"#}_%øÃGú}_ùï+•Íï«h.£oKè¿'~W…Êæ±â÷ôíî«G˜~_©�ü¾ ~WͦÚMŠe<êÿüvGÑî6Ň›€ ˜€ ˜€ ˜Àë•€N&`&`&`&`;B ¯ùÏxq'²„29�qØJ@Íþ3:«›v¤˜!�é-¾�椴¢}UÊ©ªðr­"¦Æo©éÆ!óíÈΞÞïF{c""µü�BëE3‰¼”ÝS}gGŠÑ1·^½$>r¹hÅoF„Æ+÷±B*(%ç9ÎÜ W¯DÐ<öכꨪgÉ'G¯hBR;:Ïir§’%ÇíZHÔ&„B¶Œ÷~µ)¯žÌ™Ý� úfʘɱ¸†q cPOæíJu±‡/Gφ‡uø�é®ë~K½Äé—ýqäÍÉOx— }9™ç¶ϺnC–#r",gù/£Ñûƒ¸}Âo̽~qœq™Är…‘-FâCBr$ß5®s Å™Üï��ˆÕëA—·û©!ÛÜjçÜ«^à­Kbú¬·“÷ÜÝo£û#žã›%)¤Œê$\Ô÷F¾–6þ$c¡ÇøOãÛv‹8=Ðæ"þ™¨úÌõ=Ñ÷¡<Û›¥4ëé(ÚGÿ=-»¿‹aZ¿]…xÁ�¯;äÌçbGÆo·Ù¸i #~l–ÿ„3›00°«äªçת‹+Yh�Ìgh÷·G\¦3˜€ ˜€ ˜€ ˜À^D@7ž9™€ ˜€ ˜€ ˜€ ì8�,N>÷»£Ñ×� Qò'³Ûñ"ZY—ùQ8:§ ¤I<{2þýom™cÇߨÜîª:m)ä®j÷Ž·âu}dWÓ×Ížcµ˜"uù_Â)û(.YÜϯ£túç;£»x-¦ê÷:.t9ÁåLϸ¦óEqÿß/ GI*ÿ/êY'}öêâ÷•ˆÃ�; øžÞ÷÷»æ÷¥²3~_eyuèóúUüìë»æ÷5Ðî žIøÞeí¦8'000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000�½‰Àÿîã>�ܾƒIEND®B`‚cglm-0.9.7/cglm.podspec000066400000000000000000000024101526744317200147620ustar00rootroot00000000000000Pod::Spec.new do |s| # Description s.name = "cglm" s.version = "0.9.7" s.summary = "📽 Highly Optimized Graphics Math (glm) for C" s.description = <<-DESC cglm is math library for graphics programming for C. See the documentation or README for all features. DESC s.documentation_url = "http://cglm.readthedocs.io" # Home s.homepage = "https://github.com/recp/cglm" s.license = { :type => "MIT", :file => "LICENSE" } s.author = { "Recep Aslantas" => "recp@acm.org" } # Sources s.source = { :git => "https://github.com/recp/cglm.git", :tag => "v#{s.version}" } s.source_files = "src", "include/cglm/**/*.h" s.public_header_files = "include", "include/cglm/**/*.h" s.exclude_files = "src/win/*", "src/dllmain.c", "src/**/*.h" s.preserve_paths = "include", "src" s.header_mappings_dir = "include" # Linking s.library = "m" # Configuration s.pod_target_xcconfig = { 'CLANG_ENABLE_MODULES' => 'NO', 'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES', 'CLANG_WARN_DOCUMENTATION_COMMENTS' => 'NO', 'GCC_C_LANGUAGE_STANDARD' => 'gnu11', 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) GLM_TESTS_NO_COLORFUL_OUTPUT' } end cglm-0.9.7/configure.ac000066400000000000000000000040531526744317200147540ustar00rootroot00000000000000#***************************************************************************** # Copyright (c), Recep Aslantas. * # * # MIT License (MIT), http://opensource.org/licenses/MIT * # Full license can be found in the LICENSE file * # * #***************************************************************************** AC_PREREQ([2.69]) AC_INIT([cglm], [0.9.7], [info@recp.me]) AM_INIT_AUTOMAKE([-Wall foreign subdir-objects serial-tests]) # Don't use the default cflags (-O2 -g), we set ours manually in Makefile.am. : ${CFLAGS=""} AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([src/]) AC_CONFIG_HEADERS([config.h]) # Dependencies for pkg-config. PKG_PROG_PKG_CONFIG # Ancient versions of pkg-config (such as the one used in Travis CI) # don't have this macro, so we need to do it manually. m4_ifdef([PKG_INSTALLDIR], [ PKG_INSTALLDIR ], [ AC_ARG_WITH([pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir], [pkg-config installation directory ['${libdir}/pkgconfig']])],, [with_pkgconfigdir=]'${libdir}/pkgconfig') AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) ]) # Checks for programs. AC_PROG_CC AM_PROG_CC_C_O AC_PROG_INSTALL AM_PROG_AR AC_ENABLE_SHARED AC_ENABLE_STATIC LT_INIT # Checks for libraries. AC_CHECK_LIB([m], [floor]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) AC_SYS_LARGEFILE # Checks for header files. AC_CHECK_HEADERS([limits.h \ stddef.h \ stdint.h \ stdlib.h \ string.h ]) # Checks for typedefs, structures, and compiler characteristics. AC_CHECK_HEADER_STDBOOL AC_C_INLINE AC_TYPE_INT32_T AC_TYPE_INT64_T AC_TYPE_SIZE_T AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_TYPE_UINT8_T # Checks for library functions. AC_FUNC_ERROR_AT_LINE AC_CONFIG_FILES([Makefile cglm.pc]) AC_OUTPUT cglm-0.9.7/docs/000077500000000000000000000000001526744317200134145ustar00rootroot00000000000000cglm-0.9.7/docs/make.bat000077500000000000000000000014461526744317200150310ustar00rootroot00000000000000@ECHO OFF pushd %~dp0 REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=python -msphinx ) set SOURCEDIR=source set BUILDDIR=build set SPHINXPROJ=cglm if "%1" == "" goto help %SPHINXBUILD% >NUL 2>NUL if errorlevel 9009 ( echo. echo.The Sphinx module was not found. Make sure you have Sphinx installed, echo.then set the SPHINXBUILD environment variable to point to the full echo.path of the 'sphinx-build' executable. Alternatively you may add the echo.Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% goto end :help %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% :end popd cglm-0.9.7/docs/requirements.txt000066400000000000000000000002061526744317200166760ustar00rootroot00000000000000# Defining the exact version will make sure things don't break sphinx==7.2.6 sphinx_rtd_theme==2.0.0 readthedocs-sphinx-search==0.3.2 cglm-0.9.7/docs/source/000077500000000000000000000000001526744317200147145ustar00rootroot00000000000000cglm-0.9.7/docs/source/aabb2d.rst000066400000000000000000000124521526744317200165650ustar00rootroot00000000000000.. default-domain:: C 2d axis aligned bounding box (AABB) ================================================================================ Header: cglm/aabb2d.h Some convenient functions provided for AABB. **Definition of aabb:** cglm defines an aabb as a two dimensional array of vec2's. The first element is the **min** point and the second one is the **max** point. If you have another type e.g. struct or even another representation then you must convert it before and after calling a cglm aabb2d function. Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Macros: 1. :c:func:`glm_aabb2d_size` Functions: 1. :c:func:`glm_aabb2d_copy` #. :c:func:`glm_aabb2d_zero` #. :c:func:`glm_aabb2d_transform` #. :c:func:`glm_aabb2d_merge` #. :c:func:`glm_aabb2d_crop` #. :c:func:`glm_aabb2d_crop_until` #. :c:func:`glm_aabb2d_invalidate` #. :c:func:`glm_aabb2d_isvalid` #. :c:func:`glm_aabb2d_diag` #. :c:func:`glm_aabb2d_sizev` #. :c:func:`glm_aabb2d_radius` #. :c:func:`glm_aabb2d_center` #. :c:func:`glm_aabb2d_aabb` #. :c:func:`glm_aabb2d_circle` #. :c:func:`glm_aabb2d_point` #. :c:func:`glm_aabb2d_contains` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_aabb2d_copy(vec2 aabb[2], vec2 dest[2]) | copy all members of [aabb] to [dest] Parameters: | *[in]* **aabb** bounding box | *[out]* **dest** destination .. c:function:: void glm_aabb2d_zero(vec2 aabb[2]) | makes all members of [aabb] 0.0f (zero) Parameters: | *[in, out]* **aabb** bounding box .. c:function:: void glm_aabb2d_transform(vec2 aabb[2], mat3 m, vec2 dest[2]) | apply transform to Axis-Aligned Bounding Box Parameters: | *[in]* **aabb** bounding box | *[in]* **m** transform matrix | *[out]* **dest** transformed bounding box .. c:function:: void glm_aabb2d_merge(vec2 aabb1[2], vec2 aabb2[2], vec2 dest[2]) | merges two AABB bounding box and creates new one two aabb must be in the same space Parameters: | *[in]* **aabb1** bounding box 1 | *[in]* **aabb2** bounding box 2 | *[out]* **dest** merged bounding box .. c:function:: void glm_aabb2d_crop(vec2 aabb[2], vec2 cropAabb[2], vec2 dest[2]) | crops a bounding box with another one. this could be useful for getting a bbox which fits with view frustum and object bounding boxes. In this case you crop view frustum box with objects box Parameters: | *[in]* **aabb** bounding box 1 | *[in]* **cropAabb** crop box | *[out]* **dest** cropped bounding box .. c:function:: void glm_aabb2d_crop_until(vec2 aabb[2], vec2 cropAabb[2], vec2 clampAabb[2], vec2 dest[2]) | crops a bounding box with another one. this could be useful for getting a bbox which fits with view frustum and object bounding boxes. In this case you crop view frustum box with objects box Parameters: | *[in]* **aabb** bounding box | *[in]* **cropAabb** crop box | *[in]* **clampAabb** minimum box | *[out]* **dest** cropped bounding box .. c:function:: void glm_aabb2d_invalidate(vec2 aabb[2]) | invalidate AABB min and max values | It fills *max* values with -FLT_MAX and *min* values with +FLT_MAX Parameters: | *[in, out]* **aabb** bounding box .. c:function:: bool glm_aabb2d_isvalid(vec2 aabb[2]) | check if AABB is valid or not Parameters: | *[in]* **aabb** bounding box Returns: returns true if aabb is valid otherwise false .. c:function:: float glm_aabb2d_diag(vec2 aabb[2]) | distance between min and max Parameters: | *[in]* **aabb** bounding box Returns: distance between min - max .. c:function:: void glm_aabb2d_sizev(vec2 aabb[2], vec2 dest) | size vector of aabb Parameters: | *[in]* **aabb** bounding box | *[out]* **dest** size vector Returns: size vector of aabb max - min .. c:function:: float glm_aabb2d_radius(vec2 aabb[2]) | radius of sphere which surrounds AABB Parameters: | *[in]* **aabb** bounding box .. c:function:: void glm_aabb2d_center(vec2 aabb[2], vec2 dest) | computes center point of AABB Parameters: | *[in]* **aabb** bounding box | *[out]* **dest** center of bounding box .. c:function:: bool glm_aabb2d_aabb(vec2 aabb[2], vec2 other[2]) | check if two AABB intersects Parameters: | *[in]* **aabb** bounding box | *[out]* **other** other bounding box .. c:function:: bool glm_aabb2d_circle(vec2 aabb[2], vec3 c) | check if AABB intersects with sphere | https://github.com/erich666/GraphicsGems/blob/master/gems/BoxSphere.c | Solid Box - Solid Sphere test. Parameters: | *[in]* **aabb** solid bounding box | *[out]* **c** solid circle .. c:function:: bool glm_aabb2d_point(vec2 aabb[2], vec2 point) | check if point is inside of AABB Parameters: | *[in]* **aabb** bounding box | *[out]* **point** point .. c:function:: bool glm_aabb2d_contains(vec2 aabb[2], vec2 other[2]) | check if AABB contains other AABB Parameters: | *[in]* **aabb** bounding box | *[out]* **other** other bounding box cglm-0.9.7/docs/source/affine-common.rst000066400000000000000000000072371526744317200201750ustar00rootroot00000000000000.. default-domain:: C 3D Affine Transforms (common) ================================================================================ Common transform functions. Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions: 1. :c:func:`glm_translate_make` #. :c:func:`glm_scale_to` #. :c:func:`glm_scale_make` #. :c:func:`glm_scale` #. :c:func:`glm_scale_uni` #. :c:func:`glm_rotate_make` #. :c:func:`glm_rotate_atm` #. :c:func:`glm_decompose_scalev` #. :c:func:`glm_uniscaled` #. :c:func:`glm_decompose_rs` #. :c:func:`glm_decompose` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_translate_make(mat4 m, vec3 v) creates NEW translate transform matrix by *v* vector. Parameters: | *[in, out]* **m** affine transform | *[in]* **v** translate vector [x, y, z] .. c:function:: void glm_scale_to(mat4 m, vec3 v, mat4 dest) scale existing transform matrix by *v* vector and store result in dest Parameters: | *[in]* **m** affine transform | *[in]* **v** scale vector [x, y, z] | *[out]* **dest** scaled matrix .. c:function:: void glm_scale_make(mat4 m, vec3 v) creates NEW scale matrix by v vector Parameters: | *[out]* **m** affine transform | *[in]* **v** scale vector [x, y, z] .. c:function:: void glm_scale(mat4 m, vec3 v) scales existing transform matrix by v vector and stores result in same matrix Parameters: | *[in, out]* **m** affine transform | *[in]* **v** scale vector [x, y, z] .. c:function:: void glm_scale_uni(mat4 m, float s) applies uniform scale to existing transform matrix v = [s, s, s] and stores result in same matrix Parameters: | *[in, out]* **m** affine transform | *[in]* **v** scale factor .. c:function:: void glm_rotate_make(mat4 m, float angle, vec3 axis) creates NEW rotation matrix by angle and axis, axis will be normalized so you don't need to normalize it Parameters: | *[out]* **m** affine transform | *[in]* **axis** angle (radians) | *[in]* **axis** axis .. c:function:: void glm_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis) | creates NEW rotation matrix by angle and axis at given point | this creates rotation matrix, it assumes you don't have a matrix | this should work faster than glm_rotate_at because it reduces one glm_translate. Parameters: | *[in, out]* **m** affine transform | *[in]* **pivot** pivot, anchor point, rotation center | *[in]* **angle** angle (radians) | *[in]* **axis** axis .. c:function:: void glm_decompose_scalev(mat4 m, vec3 s) decompose scale vector Parameters: | *[in]* **m** affine transform | *[out]* **s** scale vector (Sx, Sy, Sz) .. c:function:: bool glm_uniscaled(mat4 m) returns true if matrix is uniform scaled. This is helpful for creating normal matrix. Parameters: | *[in]* **m** matrix .. c:function:: void glm_decompose_rs(mat4 m, mat4 r, vec3 s) decompose rotation matrix (mat4) and scale vector [Sx, Sy, Sz] DON'T pass projected matrix here Parameters: | *[in]* **m** affine transform | *[out]* **r** rotation matrix | *[out]* **s** scale matrix .. c:function:: void glm_decompose(mat4 m, vec4 t, mat4 r, vec3 s) decompose affine transform, TODO: extract shear factors. DON'T pass projected matrix here Parameters: | *[in]* **m** affine transform | *[out]* **t** translation vector | *[out]* **r** rotation matrix (mat4) | *[out]* **s** scaling vector [X, Y, Z] cglm-0.9.7/docs/source/affine-mat.rst000066400000000000000000000053661526744317200174670ustar00rootroot00000000000000.. default-domain:: C 3D Affine Transform Matrix (specialized functions) ================================================================================ Header: cglm/affine-mat.h We mostly use glm_mat4_* for 4x4 general and transform matrices. **cglm** provides optimized version of some functions. Because affine transform matrix is a known format, for instance all last item of first three columns is zero. You should be careful when using these functions. For instance :c:func:`glm_mul` assumes matrix will be this format: .. code-block:: text R R R X R R R Y R R R Z 0 0 0 W if you override zero values here then use :c:func:`glm_mat4_mul` version. You cannot use :c:func:`glm_mul` anymore. Same is also true for :c:func:`glm_inv_tr` if you only have rotation and translation then it will work as expected, otherwise you cannot use that. In the future it may accept scale factors too but currently it does not. Table of contents (click func go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions: 1. :c:func:`glm_mul` #. :c:func:`glm_mul_rot` #. :c:func:`glm_inv_tr` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_mul(mat4 m1, mat4 m2, mat4 dest) | this is similar to glm_mat4_mul but specialized to affine transform Matrix format should be: .. code-block:: text R R R X R R R Y R R R Z 0 0 0 W this reduces some multiplications. It should be faster than mat4_mul. if you are not sure about matrix format then DON'T use this! use mat4_mul Parameters: | *[in]* **m1** affine matrix 1 | *[in]* **m2** affine matrix 2 | *[out]* **dest** result matrix .. c:function:: void glm_mul_rot(mat4 m1, mat4 m2, mat4 dest) | this is similar to glm_mat4_mul but specialized to rotation matrix Right Matrix format should be (left is free): .. code-block:: text R R R 0 R R R 0 R R R 0 0 0 0 1 this reduces some multiplications. It should be faster than mat4_mul. if you are not sure about matrix format then DON'T use this! use mat4_mul Parameters: | *[in]* **m1** affine matrix 1 | *[in]* **m2** affine matrix 2 | *[out]* **dest** result matrix .. c:function:: void glm_inv_tr(mat4 mat) | inverse orthonormal rotation + translation matrix (ridig-body) .. code-block:: text X = | R T | X' = | R' -R'T | | 0 1 | | 0 1 | use this if you only have rotation + translation, this should work faster than :c:func:`glm_mat4_inv` Don't use this if your matrix includes other things e.g. scale, shear... Parameters: | *[in,out]* **mat** affine matrix cglm-0.9.7/docs/source/affine-post.rst000066400000000000000000000075161526744317200176720ustar00rootroot00000000000000.. default-domain:: C 3D Affine Transforms (post) ================================================================================ Post transform functions are similar to pre transform functions except order of application is reversed. Post transform functions are applied after the object is transformed with given (model matrix) transform. Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions: 1. :c:func:`glm_translated_to` #. :c:func:`glm_translated` #. :c:func:`glm_translated_x` #. :c:func:`glm_translated_y` #. :c:func:`glm_translated_z` #. :c:func:`glm_rotated_x` #. :c:func:`glm_rotated_y` #. :c:func:`glm_rotated_z` #. :c:func:`glm_rotated` #. :c:func:`glm_rotated_at` #. :c:func:`glm_spinned` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_translated_to(mat4 m, vec3 v, mat4 dest) translate existing transform matrix by *v* vector and store result in dest Parameters: | *[in]* **m** affine transform | *[in]* **v** translate vector [x, y, z] | *[out]* **dest** translated matrix .. c:function:: void glm_translated(mat4 m, vec3 v) translate existing transform matrix by *v* vector and stores result in same matrix Parameters: | *[in, out]* **m** affine transform | *[in]* **v** translate vector [x, y, z] .. c:function:: void glm_translated_x(mat4 m, float x) translate existing transform matrix by x factor Parameters: | *[in, out]* **m** affine transform | *[in]* **v** x factor .. c:function:: void glm_translated_y(mat4 m, float y) translate existing transform matrix by *y* factor Parameters: | *[in, out]* **m** affine transform | *[in]* **v** y factor .. c:function:: void glm_translated_z(mat4 m, float z) translate existing transform matrix by *z* factor Parameters: | *[in, out]* **m** affine transform | *[in]* **v** z factor .. c:function:: void glm_rotated_x(mat4 m, float angle, mat4 dest) rotate existing transform matrix around X axis by angle and store result in dest Parameters: | *[in]* **m** affine transform | *[in]* **angle** angle (radians) | *[out]* **dest** rotated matrix .. c:function:: void glm_rotated_y(mat4 m, float angle, mat4 dest) rotate existing transform matrix around Y axis by angle and store result in dest Parameters: | *[in]* **m** affine transform | *[in]* **angle** angle (radians) | *[out]* **dest** rotated matrix .. c:function:: void glm_rotated_z(mat4 m, float angle, mat4 dest) rotate existing transform matrix around Z axis by angle and store result in dest Parameters: | *[in]* **m** affine transform | *[in]* **angle** angle (radians) | *[out]* **dest** rotated matrix .. c:function:: void glm_rotated(mat4 m, float angle, vec3 axis) rotate existing transform matrix around Z axis by angle and axis Parameters: | *[in, out]* **m** affine transform | *[in]* **angle** angle (radians) | *[in]* **axis** axis .. c:function:: void glm_rotated_at(mat4 m, vec3 pivot, float angle, vec3 axis) rotate existing transform around given axis by angle at given pivot point (rotation center) Parameters: | *[in, out]* **m** affine transform | *[in]* **pivot** pivot, anchor point, rotation center | *[in]* **angle** angle (radians) | *[in]* **axis** axis .. c:function:: void glm_spinned(mat4 m, float angle, vec3 axis) | rotate existing transform matrix around given axis by angle around self (doesn't affected by position) Parameters: | *[in, out]* **m** affine transform | *[in]* **angle** angle (radians) | *[in]* **axis** axis cglm-0.9.7/docs/source/affine-pre.rst000066400000000000000000000115131526744317200174630ustar00rootroot00000000000000.. default-domain:: C 3D Affine Transforms (pre) ================================================================================ Pre transform functions which are regular transform functions. Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions: 1. :c:func:`glm_translate_to` #. :c:func:`glm_translate` #. :c:func:`glm_translate_x` #. :c:func:`glm_translate_y` #. :c:func:`glm_translate_z` #. :c:func:`glm_translate_make` #. :c:func:`glm_scale_to` #. :c:func:`glm_scale_make` #. :c:func:`glm_scale` #. :c:func:`glm_scale_uni` #. :c:func:`glm_rotate_x` #. :c:func:`glm_rotate_y` #. :c:func:`glm_rotate_z` #. :c:func:`glm_rotate_make` #. :c:func:`glm_rotate` #. :c:func:`glm_rotate_at` #. :c:func:`glm_rotate_atm` #. :c:func:`glm_decompose_scalev` #. :c:func:`glm_uniscaled` #. :c:func:`glm_decompose_rs` #. :c:func:`glm_decompose` #. :c:func:`glm_spin` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_translate_to(mat4 m, vec3 v, mat4 dest) translate existing transform matrix by *v* vector and store result in dest Parameters: | *[in]* **m** affine transform | *[in]* **v** translate vector [x, y, z] | *[out]* **dest** translated matrix .. c:function:: void glm_translate(mat4 m, vec3 v) translate existing transform matrix by *v* vector and stores result in same matrix Parameters: | *[in, out]* **m** affine transform | *[in]* **v** translate vector [x, y, z] .. c:function:: void glm_translate_x(mat4 m, float x) translate existing transform matrix by x factor Parameters: | *[in, out]* **m** affine transform | *[in]* **v** x factor .. c:function:: void glm_translate_y(mat4 m, float y) translate existing transform matrix by *y* factor Parameters: | *[in, out]* **m** affine transform | *[in]* **v** y factor .. c:function:: void glm_translate_z(mat4 m, float z) translate existing transform matrix by *z* factor Parameters: | *[in, out]* **m** affine transform | *[in]* **v** z factor .. c:function:: void glm_rotate_x(mat4 m, float angle, mat4 dest) rotate existing transform matrix around X axis by angle and store result in dest Parameters: | *[in]* **m** affine transform | *[in]* **angle** angle (radians) | *[out]* **dest** rotated matrix .. c:function:: void glm_rotate_y(mat4 m, float angle, mat4 dest) rotate existing transform matrix around Y axis by angle and store result in dest Parameters: | *[in]* **m** affine transform | *[in]* **angle** angle (radians) | *[out]* **dest** rotated matrix .. c:function:: void glm_rotate_z(mat4 m, float angle, mat4 dest) rotate existing transform matrix around Z axis by angle and store result in dest Parameters: | *[in]* **m** affine transform | *[in]* **angle** angle (radians) | *[out]* **dest** rotated matrix .. c:function:: void glm_rotate(mat4 m, float angle, vec3 axis) rotate existing transform matrix around given axis by angle at ORIGIN (0,0,0) **â�—ï¸�IMPORTANT â�—ï¸�** If you need to rotate object around itself e.g. center of object or at some point [of object] then `glm_rotate_at()` would be better choice to do so. Even if object's model transform is identity, rotation may not be around center of object if object does not lay out at ORIGIN perfectly. Using `glm_rotate_at()` with center of bounding shape ( AABB, Sphere ... ) would be an easy option to rotate around object if object is not at origin. One another option to rotate around itself at any point is `glm_spin()` which is perfect if only rotating around model position is desired e.g. not specific point on model for instance center of geometry or center of mass, again if geometry is not perfectly centered at origin at identity transform, rotation may not be around geometry. Parameters: | *[in, out]* **m** affine transform | *[in]* **angle** angle (radians) | *[in]* **axis** axis .. c:function:: void glm_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis) rotate existing transform around given axis by angle at given pivot point (rotation center) Parameters: | *[in, out]* **m** affine transform | *[in]* **pivot** pivot, anchor point, rotation center | *[in]* **angle** angle (radians) | *[in]* **axis** axis .. c:function:: void glm_spin(mat4 m, float angle, vec3 axis) | rotate existing transform matrix around given axis by angle around self (doesn't affected by position) Parameters: | *[in, out]* **m** affine transform | *[in]* **angle** angle (radians) | *[in]* **axis** axis cglm-0.9.7/docs/source/affine.rst000066400000000000000000000161471526744317200167070ustar00rootroot00000000000000.. default-domain:: C 3D Affine Transforms ================================================================================ Header: cglm/affine.h Before starting, **cglm** provides two kind of transform functions; pre and post. Pre functions (`T' = Tnew * T`) are like `glm_translate`, `glm_rotate` which means it will translate the vector first and then apply the model transformation. Post functions (`T' = T * Tnew`) are like `glm_translated`, `glm_rotated` which means it will apply the model transformation first and then translate the vector. `glm_translate`, `glm_rotate` are pre functions and are similar to C++ **glm** which you are familiar with. In new versions of **cglm** we added `glm_translated`, `glm_rotated`... which are post functions, they are useful in some cases, e.g. append transform to existing transform (apply/append transform as last transform T' = T * Tnew). Post functions are named after pre functions with `ed` suffix, e.g. `glm_translate` -> `glm_translated`. So don't mix them up. Initialize Transform Matrices ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions with **_make** prefix expect you don't have a matrix and they create a matrix for you. You don't need to pass identity matrix. But other functions expect you have a matrix and you want to transform them. If you didn't have any existing matrix you have to initialize matrix to identity before sending to transform functions. There are also functions to decompose transform matrix. These functions can't decompose matrix after projected. Rotation Center ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Rotating functions uses origin as rotation center (pivot/anchor point), since scale factors are stored in rotation matrix, same may also true for scalling. cglm provides some functions for rotating around at given point e.g. **glm_rotate_at**, **glm_quat_rotate_at**. Use them or follow next section for algorithm ("Rotate or Scale around specific Point (Pivot Point / Anchor Point)"). Also **cglm** provides :c:func:`glm_spin` and :c:func:`glm_spinned` functions to rotate around itself. No need to give pivot. These functions are useful for rotating around center of object. Rotate or Scale around specific Point (Anchor Point) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If you want to rotate model around arbitrary point follow these steps: 1. Move model from pivot point to origin: **translate(-pivot.x, -pivot.y, -pivot.z)** 2. Apply rotation (or scaling maybe) 3. Move model back from origin to pivot (reverse of step-1): **translate(pivot.x, pivot.y, pivot.z)** **glm_rotate_at**, **glm_quat_rotate_at** and their helper functions works that way. So if you use them you don't need to do these steps manually which are done by **cglm**. The implementation would be: .. code-block:: c :linenos: glm_translate(m, pivot); glm_rotate(m, angle, axis); glm_translate(m, pivotInv); /* pivotInv = -pivot */ or just: .. code-block:: c :linenos: glm_rotate_at(m, pivot, angle, axis); .. _TransformsOrder: Transforms Order ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It is important to understand this part especially if you call transform functions multiple times `glm_translate`, `glm_rotate`, `glm_scale` and `glm_quat_rotate` and their helpers functions works like this (cglm provides reverse order as `ed` suffix e.g `glm_translated`, `glm_rotated` see post transforms): .. code-block:: c :linenos: TransformMatrix = TransformMatrix * TranslateMatrix; // glm_translate() TransformMatrix = TransformMatrix * RotateMatrix; // glm_rotate(), glm_quat_rotate() TransformMatrix = TransformMatrix * ScaleMatrix; // glm_scale() As you can see it is multiplied as right matrix. For instance what will happen if you call `glm_translate` twice? .. code-block:: c :linenos: glm_translate(transform, translate1); /* transform = transform * translate1 */ glm_translate(transform, translate2); /* transform = transform * translate2 */ glm_rotate(transform, angle, axis) /* transform = transform * rotation */ Now lets try to understand this: 1. You call translate using `translate1` and you expect it will be first transform because you call it first, do you? Result will be **`transform = transform * translate1`** 2. Then you call translate using `translate2` and you expect it will be second transform? Result will be **`transform = transform * translate2`**. Now lets expand transform, it was `transform * translate1` before second call. Now it is **`transform = transform * translate1 * translate2`**, now do you understand what I say? 3. After last call transform will be: **`transform = transform * translate1 * translate2 * rotation`** The order will be; **rotation will be applied first**, then **translate2** then **translate1** It is all about matrix multiplication order. It is similar to MVP matrix: `MVP = Projection * View * Model`, model will be applied first, then view then projection. **Confused?** In the end the last function call applied first in shaders. As alternative way, you can create transform matrices individually then combine manually, but don't forget that `glm_translate`, `glm_rotate`, `glm_scale`... are optimized and should be faster (an smaller assembly output) than manual multiplication .. code-block:: c :linenos: mat4 transform1, transform2, transform3, finalTransform; glm_translate_make(transform1, translate1); glm_translate_make(transform2, translate2); glm_rotate_make(transform3, angle, axis); /* first apply transform1, then transform2, thentransform3 */ glm_mat4_mulN((mat4 *[]){&transform3, &transform2, &transform1}, 3, finalTransform); /* if you don't want to use mulN, same as above */ glm_mat4_mul(transform3, transform2, finalTransform); glm_mat4_mul(finalTransform, transform1, finalTransform); Now transform1 will be applied first, then transform2 then transform3 Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions: 1. :c:func:`glm_translate_to` #. :c:func:`glm_translate` #. :c:func:`glm_translate_x` #. :c:func:`glm_translate_y` #. :c:func:`glm_translate_z` #. :c:func:`glm_translate_make` #. :c:func:`glm_scale_to` #. :c:func:`glm_scale_make` #. :c:func:`glm_scale` #. :c:func:`glm_scale_uni` #. :c:func:`glm_rotate_x` #. :c:func:`glm_rotate_y` #. :c:func:`glm_rotate_z` #. :c:func:`glm_rotate_make` #. :c:func:`glm_rotate` #. :c:func:`glm_rotate_at` #. :c:func:`glm_rotate_atm` #. :c:func:`glm_decompose_scalev` #. :c:func:`glm_uniscaled` #. :c:func:`glm_decompose_rs` #. :c:func:`glm_decompose` Post functions (**NEW**): 1. :c:func:`glm_translated_to` #. :c:func:`glm_translated` #. :c:func:`glm_translated_x` #. :c:func:`glm_translated_y` #. :c:func:`glm_translated_z` #. :c:func:`glm_rotated_x` #. :c:func:`glm_rotated_y` #. :c:func:`glm_rotated_z` #. :c:func:`glm_rotated` #. :c:func:`glm_rotated_at` #. :c:func:`glm_spinned` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. toctree:: :maxdepth: 1 :caption: Affine categories: affine-common affine-pre affine-post cglm-0.9.7/docs/source/affine2d.rst000066400000000000000000000104521526744317200171260ustar00rootroot00000000000000.. default-domain:: C 2D Affine Transforms ================================================================================ Header: cglm/affine2d.h 2D Transforms uses `2d` suffix for naming. If there is no 2D suffix it is 3D function. Initialize Transform Matrices ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions with **_make** prefix expect you don't have a matrix and they create a matrix for you. You don't need to pass identity matrix. But other functions expect you have a matrix and you want to transform them. If you didn't have any existing matrix you have to initialize matrix to identity before sending to transform functions. Transforms Order ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ See :ref:`TransformsOrder` to read similar section. Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions: 1. :c:func:`glm_translate2d` #. :c:func:`glm_translate2d_to` #. :c:func:`glm_translate2d_x` #. :c:func:`glm_translate2d_y` #. :c:func:`glm_translate2d_make` #. :c:func:`glm_scale2d_to` #. :c:func:`glm_scale2d_make` #. :c:func:`glm_scale2d` #. :c:func:`glm_scale2d_uni` #. :c:func:`glm_rotate2d_make` #. :c:func:`glm_rotate2d` #. :c:func:`glm_rotate2d_to` .. c:function:: void glm_translate2d(mat3 m, vec2 v) translate existing 2d transform matrix by *v* vector and stores result in same matrix Parameters: | *[in, out]* **m** 2d affine transform | *[in]* **v** translate vector [x, y] .. c:function:: void glm_translate2d_to(mat3 m, vec2 v, mat3 dest) translate existing 2d transform matrix by *v* vector and store result in dest Parameters: | *[in]* **m** 2d affine transform | *[in]* **v** translate vector [x, y] | *[out]* **dest** translated matrix .. c:function:: void glm_translate2d_x(mat3 m, float x) translate existing 2d transform matrix by x factor Parameters: | *[in, out]* **m** 2d affine transform | *[in]* **x** x factor .. c:function:: void glm_translate2d_y(mat3 m, float y) translate existing 2d transform matrix by y factor Parameters: | *[in, out]* **m** 2d affine transform | *[in]* **y** y factor .. c:function:: void glm_translate2d_make(mat3 m, vec2 v) creates NEW translate 2d transform matrix by *v* vector Parameters: | *[in, out]* **m** affine transform | *[in]* **v** translate vector [x, y] .. c:function:: void glm_scale2d_to(mat3 m, vec2 v, mat3 dest) scale existing 2d transform matrix by *v* vector and store result in dest Parameters: | *[in]* **m** affine transform | *[in]* **v** scale vector [x, y] | *[out]* **dest** scaled matrix .. c:function:: void glm_scale2d_make(mat3 m, vec2 v) creates NEW 2d scale matrix by *v* vector Parameters: | *[in, out]* **m** affine transform | *[in]* **v** scale vector [x, y] .. c:function:: void glm_scale2d(mat3 m, vec2 v) scales existing 2d transform matrix by *v* vector and stores result in same matrix Parameters: | *[in, out]* **m** affine transform | *[in]* **v** translate vector [x, y] .. c:function:: void glm_scale2d_uni(mat3 m, float s) applies uniform scale to existing 2d transform matrix v = [s, s] and stores result in same matrix Parameters: | *[in, out]* **m** affine transform | *[in]* **s** scale factor .. c:function:: void glm_rotate2d_make(mat3 m, float angle) creates NEW rotation matrix by angle around *Z* axis Parameters: | *[in, out]* **m** affine transform | *[in]* **angle** angle (radians) .. c:function:: void glm_rotate2d(mat3 m, float angle) rotate existing 2d transform matrix around *Z* axis by angle and store result in same matrix Parameters: | *[in, out]* **m** affine transform | *[in]* **angle** angle (radians) .. c:function:: void glm_rotate2d_to(mat3 m, float angle, mat3 dest) rotate existing 2d transform matrix around *Z* axis by angle and store result in dest Parameters: | *[in]* **m** affine transform | *[in]* **angle** angle (radians) | *[out]* **dest** rotated matrixcglm-0.9.7/docs/source/api.rst000066400000000000000000000025571526744317200162300ustar00rootroot00000000000000📚 API documentation ================================ **cglm** provides a few APIs for similar functions. * 📦 **Inline API**: All functions are inline. You can include **cglm/cglm.h** header to use this API. This is the default API. `glm_` is namespace/prefix for this API. * 📦 **Call API**: All functions are not inline. You need to build *cglm* and link it to your project. You can include **cglm/call.h** header to use this API. `glmc_` is namespace/prefix for this API. And also there are also sub categories: * 📦 **Array API**: Types are raw arrays and functions takes array as argument. You can include **cglm/cglm.h** header to use this API. This is the default API. `glm_` is namespace/prefix for this API. * 📦 **Struct API**: Types are union/struct and functions takes struct as argument and return structs if needed. You can include **cglm/struct.h** header to use this API. This also includes **cglm/cglm.h** header.`glms_` is namespace/prefix for this API but your can omit or change it, see struct api docs. * 📦 **SIMD API**: SIMD functions and helpers. `glmm_` is namespace/prefix for this API. 📌 Since struct api and call api are built top of inline array api, follow inline array api docs for individual functions. .. toctree:: :maxdepth: 1 :caption: API documentations: api_inline_array api_struct api_call api_simd cglm-0.9.7/docs/source/api_call.rst000066400000000000000000000010031526744317200172040ustar00rootroot00000000000000Call API ================================ Call API is pre-built API for making calls from library. It is built on top of the array api. **glmc_** is the namespace for the call api. **c** stands for call. You need to built cglm to use call api. See build instructions (:doc:`build`) for more details. The functions except namespace **glmc_** are same as inline api. See ( :doc:`api_inline_array` ) for more details. 📌 In the future we can define option to forward inline functions or struct api to call api.cglm-0.9.7/docs/source/api_inline_array.rst000066400000000000000000000042211526744317200207520ustar00rootroot00000000000000Array API - Inline (Default) ======================================== This is the default API of *cglm*. All functions are forced to be inlined and struct api, call api uses this inline api to share implementation. 📌 Call api is also array api but it is not inlined. In the future there may be option to forward struct api to call api instead of inline api to reduce binary size if needed. 📌 **USE this API docs for similar functions in struct and call api** 📌 In struct api you can omit namespace e.g :code:`glms_vec3_dot` can be called as :code:`vec3_dot` in struct api, see :doc:`api_struct` to configure struct api for more details. 📌 In struct api functions can return struct/union 📌 In struct api you can access items like **.x**, **.y**, **.z**, **.w**, **.r**, **.g**, **.b**, **.a**, **.m00**, **m01**... Some functions may exist twice, once for their namespace and once for global namespace to make easier to write very common functions For instance, in general we use :code:`glm_vec3_dot` to get dot product of two **vec3**. Now we can also do this with :code:`glm_dot`, same for *_cross* and so on... The original function stays where it is, the function in global namespace of same name is just an alias, so there is no call version of those functions. e.g there is no func like :code:`glmc_dot` because *glm_dot* is just alias for :code:`glm_vec3_dot` By including **cglm/cglm.h** header you will include all inline version of functions. Since functions in this header[s] are inline you don't need to build or link *cglm* against your project. But by including **cglm/call.h** header you will include all *non-inline* version of functions. You need to build *cglm* and link it. Follow the :doc:`build` documentation for this .. toctree:: :maxdepth: 1 :caption: API categories: affine affine-mat affine2d cam frustum box aabb2d quat euler mat2 mat2x3 mat2x4 mat3 mat3x2 mat3x4 mat4 mat4x2 mat4x3 vec2 vec2-ext vec3 vec3-ext vec4 vec4-ext ivec2 ivec3 ivec4 color plane noise project util io call sphere curve bezier version ray cglm-0.9.7/docs/source/api_simd.rst000066400000000000000000000005521526744317200172350ustar00rootroot00000000000000SIMD API ================================ SIMD api is special api for SIMD operations. **glmm_** prefix is used for SIMD operations in cglm. It is used in many places in cglm. You can use it for your own SIMD operations too. In the future the api may be extended by time. Supported SIMD architectures ( may vary by time ) * SSE / SSE2 * AVX * NEON * WASM 128 cglm-0.9.7/docs/source/api_struct.rst000066400000000000000000000103371526744317200176270ustar00rootroot00000000000000Struct API ================================ Struct API is alternative API to array api to use **cglm** with improved type safety and easy to use. Since struct api is built top of array api, every struct API is not documented here. See array api documentation for more information for individual functions. By default struct api adds `s` suffix to every type name e.g. vec3s, mat4s, versors etc. Also struct api `s` suffix to namespace e.g. `glms_vec3_add`, `glms_mat4_mul` etc. By starting v0.9.0, struct api namespace is configurable. We can omit **glms_** namespace or even change it with custom name to move existing api integrations to **cglm** more easily... We can also add **s** to function names if we want e.g. `glms_vec3_add()` -> `vec3_add()` or `vec3s_add()`. By including **cglm/struct.h** header you will include all struct api. It will also include **cglm/cglm.h** too. Since struct apis are inline you don't need to build or link *cglm* against your project unless if you want to use pre-built call-api too. Struct API is built top of array api. So you can mix them. Use **.raw** union member to access raw array data to use it with array api. Unlike array api ([0], [1], [0][0] ...), it is also possible to use struct api with **.x**, **.y**, **.z**, **.w**, **.r**, **.g**, **.b**, **.a**, **.m00**, **m01**... accessors to access individual elements/properties of vectors and matrices. Struct API usage: ----------------- .. code-block:: c #include mat4s m1 = glms_mat4_identity(); /* init... */ mat4s m2 = glms_mat4_identity(); /* init... */ mat4s m3 = glms_mat4_mul(glms_mat4_mul(m1, m2), glms_mat4_mul(m3, m4)); vec3s v1 = { 1.0f, 0.0f, 0.0f }; vec3s v2 = { 0.0f, 1.0f, 0.0f }; vec4s v4 = { 0.0f, 1.0f, 0.0f, 0.0f }; vec4 v5a = { 0.0f, 1.0f, 0.0f, 0.0f }; mat4s m4 = glms_rotate(m3, M_PI_2, glms_vec3_cross(glms_vec3_add(v1, v6) glms_vec3_add(v1, v7))); v1.x = 1.0f; v1.y = 0.0f; v1.z = 0.0f; // or v1.raw[0] = 1.0f; v1.raw[1] = 0.0f; v1.raw[2] = 0.0f; /* use struct api with array api (mix them). */ /* use .raw to access array and use it with array api */ glm_vec4_add(m4.col[0].raw, v5a, m4.col[0].raw); glm_mat4_mulv(m4.raw, v4.raw, v5a); or omit `glms_` namespace completely (see options below): .. code-block:: c #define CGLM_OMIT_NS_FROM_STRUCT_API #include mat4s m1 = mat4_identity(); /* init... */ mat4s m2 = mat4_identity(); /* init... */ mat4s m3 = mat4_mul(mat4_mul(m1, m2), mat4_mul(m3, m4)); vec3s v1 = { 1.0f, 0.0f, 0.0f }; vec3s v2 = { 0.0f, 1.0f, 0.0f }; vec4s v4 = { 0.0f, 1.0f, 0.0f, 0.0f }; vec4 v5a = { 0.0f, 1.0f, 0.0f, 0.0f }; mat4s m4 = glms_rotate(m3, M_PI_2, vec3_cross(vec3_add(v1, v6) vec3_add(v1, v7))); v1.x = 1.0f; v1.y = 0.0f; v1.z = 0.0f; // or v1.raw[0] = 1.0f; v1.raw[1] = 0.0f; v1.raw[2] = 0.0f; /* use struct api with array api (mix them) */ glm_vec4_add(m4.col[0].raw, v5a, m4.col[0].raw); glm_mat4_mulv(m4.raw, v4.raw, v5a); Configuring the Struct API: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To configure the Struct API namespace, you can define the following macros before including the cglm/struct.h header: - **CGLM_OMIT_NS_FROM_STRUCT_API**: omits CGLM_STRUCT_API_NS (`glms_`) namespace completely if there is sub namespace e.g `mat4_`, `vec4_` ... DEFAULT is not defined - **CGLM_STRUCT_API_NS**: define name space for struct api, DEFAULT is **glms** - **CGLM_STRUCT_API_NAME_SUFFIX**: define name suffix, DEFAULT is **empty** e.g defining it as #define CGLM_STRUCT_API_NAME_SUFFIX s will add s suffix to mat4_mul -> mat4s_mul â�—ï¸� IMPORTANT â�—ï¸� It's a good idea to set up your config macros in build settings like CMake, Xcode, or Visual Studio. This is especially important if you're using features like Modules in Xcode, where adding macros directly before the **cglm** headers might not work. Detailed documentation for Struct API: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Since struct api if built top of array api, see array api functions for more information about individual functions. cglm-0.9.7/docs/source/bezier.rst000066400000000000000000000042251526744317200167310ustar00rootroot00000000000000.. default-domain:: C Bezier ================================================================================ Header: cglm/bezier.h Common helpers for cubic bezier and similar curves. Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions: 1. :c:func:`glm_bezier` 2. :c:func:`glm_hermite` 3. :c:func:`glm_decasteljau` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: float glm_bezier(float s, float p0, float c0, float c1, float p1) | cubic bezier interpolation | formula: .. code-block:: text B(s) = P0*(1-s)^3 + 3*C0*s*(1-s)^2 + 3*C1*s^2*(1-s) + P1*s^3 | similar result using matrix: .. code-block:: text B(s) = glm_smc(t, GLM_BEZIER_MAT, (vec4){p0, c0, c1, p1}) | glm_eq(glm_smc(...), glm_bezier(...)) should return TRUE Parameters: | *[in]* **s** parameter between 0 and 1 | *[in]* **p0** begin point | *[in]* **c0** control point 1 | *[in]* **c1** control point 2 | *[in]* **p1** end point Returns: B(s) .. c:function:: float glm_hermite(float s, float p0, float t0, float t1, float p1) | cubic hermite interpolation | formula: .. code-block:: text H(s) = P0*(2*s^3 - 3*s^2 + 1) + T0*(s^3 - 2*s^2 + s) + P1*(-2*s^3 + 3*s^2) + T1*(s^3 - s^2) | similar result using matrix: .. code-block:: text H(s) = glm_smc(t, GLM_HERMITE_MAT, (vec4){p0, p1, c0, c1}) | glm_eq(glm_smc(...), glm_hermite(...)) should return TRUE Parameters: | *[in]* **s** parameter between 0 and 1 | *[in]* **p0** begin point | *[in]* **t0** tangent 1 | *[in]* **t1** tangent 2 | *[in]* **p1** end point Returns: B(s) .. c:function:: float glm_decasteljau(float prm, float p0, float c0, float c1, float p1) | iterative way to solve cubic equation Parameters: | *[in]* **prm** parameter between 0 and 1 | *[in]* **p0** begin point | *[in]* **c0** control point 1 | *[in]* **c1** control point 2 | *[in]* **p1** end point Returns: parameter to use in cubic equation cglm-0.9.7/docs/source/box.rst000066400000000000000000000122371526744317200162430ustar00rootroot00000000000000.. default-domain:: C axis aligned bounding box (AABB) ================================================================================ Header: cglm/box.h Some convenient functions provided for AABB. **Definition of box:** cglm defines box as two dimensional array of vec3. The first element is **min** point and the second one is **max** point. If you have another type e.g. struct or even another representation then you must convert it before and after call cglm box function. Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions: 1. :c:func:`glm_aabb_transform` #. :c:func:`glm_aabb_merge` #. :c:func:`glm_aabb_crop` #. :c:func:`glm_aabb_crop_until` #. :c:func:`glm_aabb_frustum` #. :c:func:`glm_aabb_invalidate` #. :c:func:`glm_aabb_isvalid` #. :c:func:`glm_aabb_size` #. :c:func:`glm_aabb_radius` #. :c:func:`glm_aabb_center` #. :c:func:`glm_aabb_aabb` #. :c:func:`glm_aabb_sphere` #. :c:func:`glm_aabb_point` #. :c:func:`glm_aabb_contains` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_aabb_transform(vec3 box[2], mat4 m, vec3 dest[2]) | apply transform to Axis-Aligned Bounding Box Parameters: | *[in]* **box** bounding box | *[in]* **m** transform matrix | *[out]* **dest** transformed bounding box .. c:function:: void glm_aabb_merge(vec3 box1[2], vec3 box2[2], vec3 dest[2]) | merges two AABB bounding box and creates new one two box must be in same space, if one of box is in different space then you should consider to convert it's space by glm_box_space Parameters: | *[in]* **box1** bounding box 1 | *[in]* **box2** bounding box 2 | *[out]* **dest** merged bounding box .. c:function:: void glm_aabb_crop(vec3 box[2], vec3 cropBox[2], vec3 dest[2]) | crops a bounding box with another one. this could be useful for getting a bbox which fits with view frustum and object bounding boxes. In this case you crop view frustum box with objects box Parameters: | *[in]* **box** bounding box 1 | *[in]* **cropBox** crop box | *[out]* **dest** cropped bounding box .. c:function:: void glm_aabb_crop_until(vec3 box[2], vec3 cropBox[2], vec3 clampBox[2], vec3 dest[2]) | crops a bounding box with another one. this could be useful for getting a bbox which fits with view frustum and object bounding boxes. In this case you crop view frustum box with objects box Parameters: | *[in]* **box** bounding box | *[in]* **cropBox** crop box | *[in]* **clampBox** minimum box | *[out]* **dest** cropped bounding box .. c:function:: bool glm_aabb_frustum(vec3 box[2], vec4 planes[6]) | check if AABB intersects with frustum planes this could be useful for frustum culling using AABB. OPTIMIZATION HINT: if planes order is similar to LEFT, RIGHT, BOTTOM, TOP, NEAR, FAR then this method should run even faster because it would only use two planes if object is not inside the two planes fortunately cglm extracts planes as this order! just pass what you got! Parameters: | *[in]* **box** bounding box | *[out]* **planes** frustum planes .. c:function:: void glm_aabb_invalidate(vec3 box[2]) | invalidate AABB min and max values | It fills *max* values with -FLT_MAX and *min* values with +FLT_MAX Parameters: | *[in, out]* **box** bounding box .. c:function:: bool glm_aabb_isvalid(vec3 box[2]) | check if AABB is valid or not Parameters: | *[in]* **box** bounding box Returns: returns true if aabb is valid otherwise false .. c:function:: float glm_aabb_size(vec3 box[2]) | distance between of min and max Parameters: | *[in]* **box** bounding box Returns: distance between min - max .. c:function:: float glm_aabb_radius(vec3 box[2]) | radius of sphere which surrounds AABB Parameters: | *[in]* **box** bounding box .. c:function:: void glm_aabb_center(vec3 box[2], vec3 dest) | computes center point of AABB Parameters: | *[in]* **box** bounding box | *[out]* **dest** center of bounding box .. c:function:: bool glm_aabb_aabb(vec3 box[2], vec3 other[2]) | check if two AABB intersects Parameters: | *[in]* **box** bounding box | *[out]* **other** other bounding box .. c:function:: bool glm_aabb_sphere(vec3 box[2], vec4 s) | check if AABB intersects with sphere | https://github.com/erich666/GraphicsGems/blob/master/gems/BoxSphere.c | Solid Box - Solid Sphere test. Parameters: | *[in]* **box** solid bounding box | *[out]* **s** solid sphere .. c:function:: bool glm_aabb_point(vec3 box[2], vec3 point) | check if point is inside of AABB Parameters: | *[in]* **box** bounding box | *[out]* **point** point .. c:function:: bool glm_aabb_contains(vec3 box[2], vec3 other[2]) | check if AABB contains other AABB Parameters: | *[in]* **box** bounding box | *[out]* **other** other bounding box cglm-0.9.7/docs/source/build.rst000066400000000000000000000073241526744317200165530ustar00rootroot00000000000000Build cglm ================================ | **cglm** does not have any external dependencies. .. note:: If you only need to inline versions, you don't need to build **cglm**, you don't need to link it to your program. Just import cglm to your project as dependency / external lib by copy-paste then use it as usual CMake (All platforms): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: bash :linenos: $ mkdir build $ cd build $ cmake .. # [Optional] -DCGLM_SHARED=ON $ make $ sudo make install # [Optional] **make** will build cglm to **build** folder. If you don't want to install **cglm** to your system's folder you can get static and dynamic libs in this folder. **CMake Options:** .. code-block:: CMake :linenos: option(CGLM_SHARED "Shared build" ON) option(CGLM_STATIC "Static build" OFF) option(CGLM_USE_C99 "" OFF) # C11 option(CGLM_USE_TEST "Enable Tests" OFF) # for make check - make test **Use as header-only library with your CMake project example** This requires no building or installation of cglm. .. code-block:: CMake :linenos: cmake_minimum_required(VERSION 3.8.2) project() add_executable(${PROJECT_NAME} src/main.c) target_link_libraries(${LIBRARY_NAME} PRIVATE cglm_headers) add_subdirectory(external/cglm/ EXCLUDE_FROM_ALL) **Use with your CMake project example** .. code-block:: CMake :linenos: cmake_minimum_required(VERSION 3.8.2) project() add_executable(${PROJECT_NAME} src/main.c) target_link_libraries(${LIBRARY_NAME} PRIVATE cglm) add_subdirectory(external/cglm/) Meson (All platforms): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: :linenos: $ meson build # [Optional] --default-library=static $ cd build $ ninja $ sudo ninja install # [Optional] **Meson Options:** .. code-block:: :linenos: c_std=c11 buildtype=release default_library=shared enable_tests=false # to run tests: ninja test **Use with your Meson project** .. code-block:: :linenos: # Clone cglm or create a cglm.wrap under /subprojects project('name', 'c') cglm_dep = dependency('cglm', fallback : 'cglm', 'cglm_dep') executable('exe', 'src/main.c', dependencies : cglm_dep) Unix (Autotools): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: bash :linenos: $ sh autogen.sh $ ./configure $ make $ make check # run tests (optional) $ [sudo] make install # install to system (optional) **make** will build cglm to **.libs** sub folder in project folder. If you don't want to install **cglm** to your system's folder you can get static and dynamic libs in this folder. Windows (MSBuild): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Windows related build files, project files are located in `win` folder, make sure you are inside in cglm/win folder. Code Analysis are enabled, it may take awhile to build. .. code-block:: bash :linenos: $ cd win $ .\build.bat if *msbuild* is not worked (because of multi versions of Visual Studio) then try to build with *devenv*: .. code-block:: bash :linenos: $ devenv cglm.sln /Build Release Currently tests are not available on Windows. Documentation (Sphinx): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **cglm** uses sphinx framework for documentation, it allows lot of formats for documentation. To see all options see sphinx build page: https://www.sphinx-doc.org/en/master/man/sphinx-build.html Example build: .. code-block:: bash :linenos: $ cd cglm/docs $ sphinx-build source build cglm-0.9.7/docs/source/call.rst000066400000000000000000000015051526744317200163620ustar00rootroot00000000000000.. default-domain:: C precompiled functions (call) ================================================================================ All functions in **glm_** namespace are forced to **inline**. Most functions also have pre-compiled version. Precompiled versions are in **glmc_** namespace. *c* in the namespace stands for "call". Since precompiled functions are just wrapper for inline versions, these functions are not documented individually. It would be duplicate documentation also it would be hard to sync documentation between inline and call version for me. By including **clgm/cglm.h** you include all inline versions. To get precompiled versions you need to include **cglm/call.h** header. When using the precompiled versions, explicitly including **cglm/cglm.h** is still necessary for the inline versions to be included. cglm-0.9.7/docs/source/cam.rst000066400000000000000000000266711526744317200162220ustar00rootroot00000000000000.. default-domain:: C camera ====== Header: cglm/cam.h There are many convenient functions for camera. For instance :c:func:`glm_look` is just wrapper for :c:func:`glm_lookat`. Sometimes you only have direction instead of target, so that makes easy to build view matrix using direction. There is also :c:func:`glm_look_anyup` function which can help build view matrix without providing UP axis. It uses :c:func:`glm_vec3_ortho` to get a UP axis and builds view matrix. You can also *_default* versions of ortho and perspective to build projection fast if you don't care specific projection values. *_decomp* means decompose; these function can help to decompose projection matrices. .. note:: Be careful when working with high range (very small near, very large far) projection matrices. You may not get exact value you gave. **float** type cannot store very high precision so you will lose precision. Also your projection matrix will be inaccurate due to losing precision Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions: 1. :c:func:`glm_frustum` #. :c:func:`glm_ortho` #. :c:func:`glm_ortho_aabb` #. :c:func:`glm_ortho_aabb_p` #. :c:func:`glm_ortho_aabb_pz` #. :c:func:`glm_ortho_default` #. :c:func:`glm_ortho_default_s` #. :c:func:`glm_perspective` #. :c:func:`glm_perspective_infinite` #. :c:func:`glm_persp_move_far` #. :c:func:`glm_perspective_default` #. :c:func:`glm_perspective_default_infinite` #. :c:func:`glm_perspective_resize` #. :c:func:`glm_lookat` #. :c:func:`glm_look` #. :c:func:`glm_look_anyup` #. :c:func:`glm_persp_decomp` #. :c:func:`glm_persp_decompv` #. :c:func:`glm_persp_decomp_x` #. :c:func:`glm_persp_decomp_y` #. :c:func:`glm_persp_decomp_z` #. :c:func:`glm_persp_decomp_far` #. :c:func:`glm_persp_decomp_near` #. :c:func:`glm_persp_fovy` #. :c:func:`glm_persp_aspect` #. :c:func:`glm_persp_sizes` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_frustum(float left, float right, float bottom, float top, float nearVal, float farVal, mat4 dest) | set up perspective peprojection matrix Parameters: | *[in]* **left** viewport.left | *[in]* **right** viewport.right | *[in]* **bottom** viewport.bottom | *[in]* **top** viewport.top | *[in]* **nearVal** near clipping plane | *[in]* **farVal** far clipping plane | *[out]* **dest** result matrix .. c:function:: void glm_ortho(float left, float right, float bottom, float top, float nearVal, float farVal, mat4 dest) | set up orthographic projection matrix Parameters: | *[in]* **left** viewport.left | *[in]* **right** viewport.right | *[in]* **bottom** viewport.bottom | *[in]* **top** viewport.top | *[in]* **nearVal** near clipping plane | *[in]* **farVal** far clipping plane | *[out]* **dest** result matrix .. c:function:: void glm_ortho_aabb(vec3 box[2], mat4 dest) | set up orthographic projection matrix using bounding box | bounding box (AABB) must be in view space Parameters: | *[in]* **box** AABB | *[in]* **dest** result matrix .. c:function:: void glm_ortho_aabb_p(vec3 box[2], float padding, mat4 dest) | set up orthographic projection matrix using bounding box | bounding box (AABB) must be in view space this version adds padding to box Parameters: | *[in]* **box** AABB | *[in]* **padding** padding | *[out]* **dest** result matrix .. c:function:: void glm_ortho_aabb_pz(vec3 box[2], float padding, mat4 dest) | set up orthographic projection matrix using bounding box | bounding box (AABB) must be in view space this version adds Z padding to box Parameters: | *[in]* **box** AABB | *[in]* **padding** padding for near and far | *[out]* **dest** result matrix Returns: square of norm / magnitude .. c:function:: void glm_ortho_default(float aspect, mat4 dest) | set up unit orthographic projection matrix Parameters: | *[in]* **aspect** aspect ration ( width / height ) | *[out]* **dest** result matrix .. c:function:: void glm_ortho_default_s(float aspect, float size, mat4 dest) | set up orthographic projection matrix with given CUBE size Parameters: | *[in]* **aspect** aspect ration ( width / height ) | *[in]* **size** cube size | *[out]* **dest** result matrix .. c:function:: void glm_perspective(float fovy, float aspect, float nearVal, float farVal, mat4 dest) | set up perspective projection matrix Parameters: | *[in]* **fovy** field of view angle (in radians) | *[in]* **aspect** aspect ratio ( width / height ) | *[in]* **nearVal** near clipping plane | *[in]* **farVal** far clipping planes | *[out]* **dest** result matrix .. c:function:: void glm_perspective_infinite(float fovy, float aspect, float nearZ, mat4 dest) | set up perspective projection matrix with infinite far plane The far clipping plane is pushed to infinity. This can improve depth precision for distant objects and is required by some rendering techniques such as shadow volumes. Dispatches to the appropriate clipspace variant based on compile-time configuration (LH/RH, NO/ZO). Parameters: | *[in]* **fovy** field of view angle (in radians) | *[in]* **aspect** aspect ratio ( width / height ) | *[in]* **nearZ** near clipping plane | *[out]* **dest** result matrix .. c:function:: void glm_persp_move_far(mat4 proj, float deltaFar) | extend perspective projection matrix's far distance | this function does not guarantee far >= near, be aware of that! Parameters: | *[in, out]* **proj** projection matrix to extend | *[in]* **deltaFar** distance from existing far (negative to shink) .. c:function:: void glm_perspective_default(float aspect, mat4 dest) | set up perspective projection matrix with default near/far and angle values Parameters: | *[in]* **aspect** aspect aspect ratio ( width / height ) | *[out]* **dest** result matrix .. c:function:: void glm_perspective_default_infinite(float aspect, mat4 dest) | set up infinite perspective projection matrix with default near and angle values Equivalent to calling :c:func:`glm_perspective_infinite` with ``fovy = GLM_PI_4`` (45°) and ``nearZ = 0.01``. Useful as a quick drop-in when you need an infinite projection without tuning the individual parameters. Parameters: | *[in]* **aspect** aspect ratio ( width / height ) | *[out]* **dest** result matrix .. c:function:: void glm_perspective_resize(float aspect, mat4 proj) | resize perspective matrix by aspect ratio ( width / height ) this makes very easy to resize proj matrix when window / viewport reized Parameters: | *[in]* **aspect** aspect ratio ( width / height ) | *[in, out]* **proj** perspective projection matrix .. c:function:: void glm_lookat(vec3 eye, vec3 center, vec3 up, mat4 dest) | set up view matrix .. note:: The UP vector must not be parallel to the line of sight from the eye point to the reference point. Parameters: | *[in]* **eye** eye vector | *[in]* **center** center vector | *[in]* **up** up vector | *[out]* **dest** result matrix .. c:function:: void glm_look(vec3 eye, vec3 dir, vec3 up, mat4 dest) | set up view matrix convenient wrapper for :c:func:`glm_lookat`: if you only have direction not target self then this might be useful. Because you need to get target from direction. .. note:: The UP vector must not be parallel to the line of sight from the eye point to the reference point. Parameters: | *[in]* **eye** eye vector | *[in]* **dir** direction vector | *[in]* **up** up vector | *[out]* **dest** result matrix .. c:function:: void glm_look_anyup(vec3 eye, vec3 dir, mat4 dest) | set up view matrix convenient wrapper for :c:func:`glm_look` if you only have direction and if you don't care what UP vector is then this might be useful to create view matrix Parameters: | *[in]* **eye** eye vector | *[in]* **dir** direction vector | *[out]* **dest** result matrix .. c:function:: void glm_persp_decomp(mat4 proj, float *nearVal, float *farVal, float *top, float *bottom, float *left, float *right) | decomposes frustum values of perspective projection. Parameters: | *[in]* **eye** perspective projection matrix | *[out]* **nearVal** near | *[out]* **farVal** far | *[out]* **top** top | *[out]* **bottom** bottom | *[out]* **left** left | *[out]* **right** right .. c:function:: void glm_persp_decompv(mat4 proj, float dest[6]) | decomposes frustum values of perspective projection. | this makes easy to get all values at once Parameters: | *[in]* **proj** perspective projection matrix | *[out]* **dest** array .. c:function:: void glm_persp_decomp_x(mat4 proj, float *left, float *right) | decomposes left and right values of perspective projection. | x stands for x axis (left / right axis) Parameters: | *[in]* **proj** perspective projection matrix | *[out]* **left** left | *[out]* **right** right .. c:function:: void glm_persp_decomp_y(mat4 proj, float *top, float *bottom) | decomposes top and bottom values of perspective projection. | y stands for y axis (top / bottom axis) Parameters: | *[in]* **proj** perspective projection matrix | *[out]* **top** top | *[out]* **bottom** bottom .. c:function:: void glm_persp_decomp_z(mat4 proj, float *nearVal, float *farVal) | decomposes near and far values of perspective projection. | z stands for z axis (near / far axis) Parameters: | *[in]* **proj** perspective projection matrix | *[out]* **nearVal** near | *[out]* **farVal** far .. c:function:: void glm_persp_decomp_far(mat4 proj, float * __restrict farVal) | decomposes far value of perspective projection. Parameters: | *[in]* **proj** perspective projection matrix | *[out]* **farVal** far .. c:function:: void glm_persp_decomp_near(mat4 proj, float * __restrict nearVal) | decomposes near value of perspective projection. Parameters: | *[in]* **proj** perspective projection matrix | *[out]* **nearVal** near .. c:function:: float glm_persp_fovy(mat4 proj) | returns field of view angle along the Y-axis (in radians) if you need to degrees, use glm_deg to convert it or use this: fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) Parameters: | *[in]* **proj** perspective projection matrix Returns: | fovy in radians .. c:function:: float glm_persp_aspect(mat4 proj) | returns aspect ratio of perspective projection Parameters: | *[in]* **proj** perspective projection matrix .. c:function:: void glm_persp_sizes(mat4 proj, float fovy, vec4 dest) | returns sizes of near and far planes of perspective projection Parameters: | *[in]* **proj** perspective projection matrix | *[in]* **fovy** fovy (see brief) | *[out]* **dest** sizes order: [Wnear, Hnear, Wfar, Hfar] cglm-0.9.7/docs/source/cglm-intro.png000066400000000000000000002205051526744317200175010ustar00rootroot00000000000000‰PNG  IHDRØR8vm{sRGB®ÎéYiTXtXML:com.adobe.xmp 1 LÂ'Y@IDATxì½”]Õ™¦]·rI¥œs) ˆ,@‘s6‘llãizzfzºçoãž5kzz¼ši°ÁdÁ 4ƒ‘…A ! ¥RV©$•J•ãÿ¼Çu¯o¥[¹TWzÏZ»ö¹;~ûÙûœÚßN'!Á— ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ta¡.,[ ÚUW]•:|øð¤^½z•ß{ï½±ä½óÎ;Sºwïž\XXXñÈ#�(lu¬ðök-©£æäØÙõØÞò7§Œc&`&`&`&`&pøHêêEš5kÖQeee3rss+úö훿yóæªÆdž6mÚøâââã*++«�?þø+V¬h4lciNîRgÏž�vì±Ç&À¢ÃZRGÍáÛÙõØÞò7§Œc&`&`&`&`&pøHìêE …BÇUUU]“œœ<9+++Yòj†ó–[né}ýõ×÷dV;p“{uuõTÂ_‹™ÆÏ¹ÁW¨G�“œ8“‡Qpê°Á”†ê¨-Ü;»Û[þ¶”ÝqMÀLÀLÀLÀLÀâ—@<(Ø}Q€F%&&öLMM ä­¨¨ò;RRR®Ùºuë0fjå‘p½pÏBAë³ÿþ._¶Žl6÷ÜsO:΀Ʌ(ØÃ÷îÝÛ‘ v½:jKÙ:»ɯ]åoKÙ×LÀLÀLÀLÀL ~ Ä¥Šâ8¥èx°Ïdv»_Ÿ>}â²Ùl`§Y˜ fÿ÷õëׯ²#ósÚ&`&`&`&`&`&p¤ˆ,¯Ž'ÌÈ®Gi|%»°¼¼|Û¨Q£¬á5gΜd¢F¸Ê¡C‡V®Zµ*�¥ç©|ò«šƒÂJ^zé¥rJµXÃNÁ=™=à‰Ì Wqºyéý÷ß_†2[KŽÆÒTƒc¾òàÁƒÕ�É£0’TGå ɬ0 \!fø§#Ëf®?Á¬?ꨣ*�¿� õ�`™ÛTf¾SX~Ÿ$n”¿6e0 ñ´1j�< J“=à)È•‚âŸ$¦¤Sç2üb~z­¥õ¨)?•¡[·nɪ{¹‘w9ûõK/^3?…mêR í%ÃUm¢JyÑRÕ¸T¯¥áöÒPZÍmCanJƒ%þå;vìH¢ §Òfô)ºjµ;¹®*vß¾}i° ©}Áº4V=…9©® ŸHø*â–…Ó¬+{8|ݲª}I…§½…~ñ‹_¤ê^é¨Íp«vœJ; ‰íª\í)Ga£¯p>-­¿0WÒ 8Œõ¼+?…óÔo…;vl)ùkµG­gYþ¾LÀLÀLÀLÀL )vðUS7×úôé§v" ã :çkøÜT9�à>¸Íd»oNNÎÁo¿ýV³Ø 3f̘)w:ùß>ÿI( sù}�úcp.¥ñ¤“N*=ztùêÕ«#�h”ᑤ?SJ RÊÒ‰Ä=Åãhî �ã&ÿ£HãĤ¤¤“Éëdüõ±ôE‹fff–Jñ—,ºKyŽBIQ~¤�ðYª¼¯¿þº–âG'_JÛ4d˜NRe—\rI>Êa$í ƒþèduÒ½ ¯�Ø‹˜Í^õ/ÿò/R›¼¤Ð—––ƒÓ±bF„ÙØSI§ eе‘›�u�¿@æ†ê(œ™Ò,((D:Óàt ö)°;{(i& œ•Lš4©"º.ÚP�!N—OgÆ~ùÏ„ßI*òÎÂÖ»wïŠN8¡�6T‹u,ùÃ制§N�:%w:ò'¢ÐfPžcat&a”ßDÚ]ÊÌ™3 Æ�W].X$ñù¸^ÍmC(¡½hk3Qü†ˆåÈR»ÃmùM§mdàwPmYŒù=÷9°UÛM> ’㫯¾ªWÿuëš8'�îê¿Ê{õ[‚ì‘öF{LÞ¸qã`ò?‘<Πœ'gm"ýÀ�EãÇ�/UY‰Û�ß3¨ë¡°©„Å@œDÚ:pOç&LÀî�¼•Rf‰½u¡Uõ'®gžyfS¦�ÏÉ”{6Fu2 “&Ož\L‹<ïRà‡ Ö9&æ✊ ÞÈ• ðW\qE9Ï[äý€Ü¾LÀLÀLÀLÀL Iq©`ó]ç,:Ä×ÓyH 7Mœ8QÊ^uX1£ã¼O�ü.ÆÌâ÷pìÑ)ß3P>˜ë¶—ïKÙ ”âJaÐ'¾�ö±Øc¦ãÖûâ–Ó¿ûÜNÄ…™ˆ™�™Eœ¸(…’7)ü�¦‰wŒ”¡(-Ù(cÂñåC ÒÍøKéßLúÛ—.]­Œ(X½‹2I!¿ ™7 ü¿ÍDntºõ"Ô8H1E:–Ÿ7�×EØG“Æ0ìñÈ ¥ZŠ·× ù�ÀLç°+æwBc ª JJJŽ�Ûµ¤©º8£º`Óo/’)î„ ŠÂr¶¶¥¢ˆjïù Èzf2F§Êk�à8îG#Ǿ¹sçî^²dIDÉnL~ÒiðB¾³HójLdנΙ¤=37ýÇJòÜqùå—‡5”ÝÁÔÉ%ø5« Q—C¨ûë¯ÏÏ©½ÍAþiä1žßªçcñ×*ˆ$~Ÿ‡ûù¸MÀ¨í‹ÃQ¸åŸ|òÉ;—-[Q²ï¾ûî4ÂKÆkñW›ž„ŽÛ$ŒÚ²äÌ£œûÃ?cÆŒOyn ü%„‹É"ŽVJè™*%üv–¼øâ‹j×�Ì„W›9—ßó°UçÊc ¿õ\dQ÷E °ì �µ¦þH'ôÖ[o C¡¸’¶¾F‘�žw±šNU÷ìÙs×…^¨ºH ,C�÷Bü¯ÁhPDíZqô¼OÅ/Ä Ûž‹/¾8Rwøû20000�& Ëg› ÕÅ TdЖ‘Hç9-Z<:È©øÍÃ-�ûÕØ‹ø�Ã}ˆû,:ýs±¯Wt¤_¦S¿ƒNQ•I¸1øI)ÛMøïûövfB×2 דûј„ù¿mÜk€Bq.åþâí>|ø"~Šg¬4 Ó3£™âå(¬Û°Ã ´–yK•²ð=r6ëpÍJ’ç È‘I¼o™ÑÛÅRåÈ,$n ^”?1;;{ž7SŽ©Ø_‘Æç˜ÒKÆÖ@‚N$×lð8Ü6¢Ð$ó[³ª�¦¹iÓ&)¶Jóh}�Yƽö…«Ýi&S ã|êPKˆ_Ço/nÁà÷-®G–Pk òHÒÖ ‡e¤õ=éhÿy?ÌéÜŸ€�‡¾Vaæ�só/ÒÑL¾ÚÉdlµ±/¸ÿw±–’¦öp9 äÖ/¾øâ3ÜJ1 `t§¼ÍnC¤¡ö5”´µ¢`+÷K`õgÚF!÷RX¯ÀïŒÎ¤Ü¹_‚Ù€Á«úDŒ”Ûói[©ãï1ZÊ�ÈRy)ž7b¤„~Iø¯¸?€Ý ûxìS0Zæýá׋+yÌÃï<ܾÆïÏÜ‹«Îâ÷Ñäÿ%˜uW< ¢hP¦ÿØ‹1ë¸/ÆhæXõ � $ðI¹/î»ï¾âÖÔßOúÓÞ¤s)\/ÇÎ%ý7I{¦’ßRœÏÀíXzV“þ~–…w£íj°çdÞƒý:q7s_E¸‘­xÑ€PÅ–-[ÞÅ_å Ú$¶/0000ˆI 1¦ozÒ©N£ƒ¬ï�ø�³dõO>ùä;O=õÔ":ÑÏáö0þ{±/¢£},�ît¿ â$ұ”¢'Pzÿ@¼ÅÏ>ûìN–ÎîÄý(»¿eöû÷O<ñÄ"N/3==ý¾�H܉¤Ù�û@댕& ûŸÉï+ÂEašÂ}�p<”†îÜk†RJÿJ”›f�Î,ÝHÂKQÞFšß#¿ý&•ˆ—f@5«ù1r?ÂRÙ—)ã»”ÿM~?�ßË„‘‚Ô »Évƒ×›xRÈŽÃþŒx�±Ÿúå§Ÿ~:HEqé<�¿fV/¢ŒSÃ{wù-ŽÅõ¨½ó(µKIûwÊoäÈ‘¯Q÷o+_ÒS=mÅÖ¬îÈÁƒ·zp‰44û�"ó!é-$¯·•íã)Ü>ÁŒ¡=ŒcÛ@°XeBÉÓ@O³Ûih@J»c~ \/�1âMêä]Êù<þ‹IOʬV|…ÿK’ãñÇ›¼ŸÂM[%´ z4[‚ò²Ì»mCõ¢Yp)ÊO�ÖkJ“:ƒ4Á]JôɘY(™ÈÝ“ô&Vƒ-KhWïꙢ ëyú7ÌøïaK„d _Ã¸Ñ€É ,,@®7”ÏãkÈó i½‡™ˆ,g³¤?ø–ýÃ?\ÑÒúã¹<޼/$Ÿ}ä÷,÷Ï£ä/R] ¼¿@÷“ß«ÔËNVª,Óê”ó0» û æ…¥­¿£ð”ÿyÒQ���_ äðe&`&`&`&`Í"Ф¢Ô¬TºP :Ô‰tž—Ò©~` ³”%“NôAü?Ãÿ=DîMZÊh/Íêá®,Í€®Äýânæ„ò`æQÅ{î¹çòéˆC'|#{Loºé¦¾6lèÏXÍ oÇÄôE�èAz�‚+MŸÊGŽÄÙ‡}öf×%ˆÇqü–Ò½³š}ÔM΢© (+Z¯e¹ß¡(lª9àŠ¤b_ Œ#®”ë͘7Q jqCaÛ‡’*fxØOúM*í„Sfa¶Âsû„¨áÄUš(GÆ_ŸÓÒí£ù và–€[‹ëQñ(óV|Cýå¯[·®ÇüùóPG½ñÚƒÜZ™ Á„¾»víjuÛ¯)¿¦‰ÕV>G¡Ë… \>öØc»ÉK³ÚšAíƒÂQ°[Ú†t ‹àRšËÉkù”q¯rjÆyFmc=æKÚî¾9´Zƒ šÉÕ¬´”ê@Q¤]ŒÃ]ËØ·þsüò†¶×‹U™økåÇ7„ÑLôDî{ÓT6= =ø=�öŸ¥öÏïrÚÅRó/8Ùo˜î Ñ`Â;Ü~øÐCí ûiÕuŸ�û+„ÙDm�§~W·¤þtHñ5ã>€ô>Á|†a >ø`–¡Ü¦za9ºžKÍž÷Ç|IY×ÑNªüã÷Tùá�㕤§çN+Æ„&ïËLÀLÀLÀLÀš$(tM†Š£tŠ5#ú-�ç� )˜Ì¢•°ßø{ÂìÇhö¸û2÷ Jñ“وٮÙPìÈÅì\òÏþó^(�SÑ™´�TЬ–�k¦UËxc2¸O©99YJF¬4«ñÿ’ðRÆ´|ŠàZ‘J–kk_·–«¾‹ôƒNcæwÌ‹8ýHO˸ ˆ³ ¥(Ÿ�23"žÄÓþSÉÿq74”Êqþ­·ÞºŽà9˜ZlJEEòÁï=f7aWÔ '…óæ›o^K¾RÞ†2SªÁŽƒÌšJ¦×#iìaéwÚ¶mÛ²¨×c˜9C:ýQœ´ª@3Î31ZÚž‚2 ‚Ô•©¹¿IG ôffDw«ÎêÄÓEø§"ƒž1åUÝÒ6D†“Õ2ë�ü”ë°#yÀà· Þ¹š¡ ûI‘…­qä$e9¸?’Õuˆ8§ñœèL‚ºí$‹pZ=1»7íRK©—a´ßúlÚˆö`¯c`æ{Ê¿%{+Ü‹¢—Ünf-~’¡nú (¾Y ²�´&np^^ž8•’NF ê¯q†bò•¶¹jå%™083Ò³u«ž×áÜjµÈdÚˆÖê>[¦4búÆ3Ø€ðe&`&`&`&Ð<‡�‚M‡¹”N{>Jƒ”¶Z�í0:üê�bk¯r7Ø ¡(Þ¸³ì[Ÿê©—CÈF hïæ©Ä“r¢™gÍ"jP�ríMÖÌk Ñ‰Õüi,M”›Ä‘’­™gÍX‚rQÊo)Üeüþ%&2;�f�{å9£ÓÖ¿&Íu )ÉuâDÿ”ª�‚"Ââºe”?÷%ص؄ý£m‚ôD– Ü ¯±4 £�í)îŽ"ž¡Á ”2qlq=j93J¨NÐÖA\£HSiï¥=hV¶ “…»f^Û|‘V ‰ìg°%²B"œ(yH.'ŒöÒGÚCkÛéi0è ³îµ¸S® Ò—r_Œ¥ÌÐV‡•IÉ"¬*â‡h»a9´Zõ2{2mE\õüÃál›€ ˜€ ˜€ ˜€ ˜@]‡�‚M¥ôDáÐÒí—VË?u´µô¶ˆÙêjf€¹ ƒj:Õµ:ê(ú®òl¼/Çl¢óý&öúæyRlP¤ kVO³šµâ.˜É®›¦Ü™a/g6}9·g#ÓQ(˜cIKKeµ4w Ê}ÊHac],oÍ`€@K_5ÛöJDdIn¬xa?ò“*E¸/³•½˜EÌÓÌ_Ø_¶À¨7a4³©åÑÑÞ ÝKy*¦ ß�øy˜º‘¤ô a )±”DÍ`sµ¸ÉKŸa»”ü&`/F¡ú ·]¤]„ –JM «Û|‘‡”Í –G×-SPßuõ6ñkCÒ ö̺×Ê‹¶¢¼T²«¯(6RÈ ^ðSûz {/œj)‘”K[%4ȱ�žm¿üå/Õ®ws6À"Ê»?ÍðŽÀè ³“ ×·ý”ï#Ü—ömg²ô;¬Ø‡Ý›6–J\µ F£XkEÇ(Òivý‘¾V è\€nØÝšZöÏ3XHúÌÉ#¼¶&h¿~½ç wµï*Ú‹^ ’Ï— ˜€ ˜€ ˜€ ˜€ 4‹Àáª`�Â9–±ƒÑû¨EDŸ£ÂÒl±öm~J{/v-ƒßµ.)ä:t,™úû(‚:I³£ÕRœPµw3ƒ4kÍXÖJ¤‘¤·†ÎüJÌ…¤q4IèlͲ¾M¶�~-E·¡dˆ7÷©¤±‰û”G§C lÅM§}Oc_j.vd¹­ÊÈáXC`¥=ëC0ÍY6«P)·:íZ{Y•¦f}#ßì–r­ÙP} m'Ê\>yU³]a¤`·¨á¥ý¸Ç`t úËì½]OzšÅM¸í¶ÛÄTƒ.Ú·Û Ò§puudj¡ÌA½G#»˜9þªÎ3‚¦–¶sáWƧçBÄÙ³g�Úâ_Öé9¢=|¢Q X_@šLý-£íâÀX{½'£�MÔÚŸ­öÄŒ¸“ÆnÏÀ.ÒRÚZ�Ñìúcp+�’PXµOy³½}±?@á\ƒRª%Õ§ñü‡€Ýxã�{¸¯`ßtmEƒ(RhS9Œ/Òö ¯ƒÄÎÂd£L/¡�æ3›]¥[³¹Or߬ÃÍ�c(JêLâíAQY�››«%°-Rj”ü·àÑŸ|OÃü¾g6rJ¶f|¥Iñ×’z¸¥åÑÜ6~qRô~”Ÿ7 7’P§c÷Æ^NìÀNG�›‚­ïjëÛݯÀà»:ûÆ[\� l!­lòšEÚ{a£üÊqM>š�×êímOÄîÔ«5mˆÁˆv—Qõ‚R¹F:ÈìLXh[À2ì=dÖ[ ©V¬£=hÐ%�Á�LÚÁ±Üê�¸ïPªWGûÏGÂVÊm.å˦ýE/·ÞJ:Z5p#ÏÄdöG¯¢.Ô6û’Þ,âIÉÝ€yåz‡¶$°Ê ÅõG¾ËÈ÷m亘4oÁL@îïyæ«xöÇH>üvòû…;v|GÞ_2ˆðù^†™O| º|O8�« ¶ªïÈÄÖÊ–ð|Ýú20000�& ty›NºöYî£]¢}š*n:„H‡‹åÓ™–Ë�²f@wá·SŒ™‰Û$lä„’ò*EâyìwùœÓ.Í^+.þ¥¸í#|! A­%ãÌ”ßqÇoã>ˆpR4nÆh·fŠ¥p~L¼j:ë:8-‘Ó¢8™‚û% é$oʦåÔ:mý;â¾Î3·‰%Ô|’+Ÿ:Òlî`̉„™É³ 2jµâ½B>K9ż4jP@ÊórÌœJZLw ¨èœ�eÄ{ƒAœ¯t²?îZÒâúcÀ`Šù«Ès�4ça´bb®ÒãÒl¸ž÷Õ˜}>(Ïë¼7ôüžƒ çbæp¯ÅÓ(w>÷o‘Î'Ô­îëÕ/n¾LÀLÀLÀLÀL A]^Á¦#üòUt~7R)º´�ôQlÍïF¡ ”:ÖŸã®=™[ˆ'%è3Œö‚öǨ¿‡ðši[?f̘ýaåZ ÒÑ׉Ý÷N³¶ug�«Y»ºwïÞ¿#®føFEyªóþòiVV³ÐÕ¤£obò4‘&Áþr!G³½ún°¾1­¥ÕßK� ûDzQt·öUÊ»e®Ö^×Xñêúi·�(©RÈtøÓ@ÊÚ [ŠÔ^˜l!¯Ó�-‘ßå°Š(©„i¨Ž¤8±4ø+”»dKºÃÉC³¤*›–èo$îÆ‡~8Ÿûˆ"ÓÚz$¿<–4/B¶lÒ�Ñrg)^ÛIs5²§¢(~@ž[øFv¸-%4&?ñ¼ÂòÁ#›Yózõ¤ú#ϧÌ9Ì¢kõCP¶–¶!dÝKÏP)ØÙu?‡kQƒÉevX'Ú×’—xŸâ¶ ÿÍÑ奮uRü— êäà§ÓïU/½0a¡o…¯Gßrß}÷•ÀT²Ò.>Ç=‡ô´oznR^u6i¬Bi×sXI8œƒ«ˆ´>GÆ7ù¥ÇG6{?áwᾎûí <ˆ_À§µõ§ïjßu×]¯0«¾’´F‘Ï ÒV;ÕV‹�ä÷ƒX:d/x.ùVövÚÉë,Wÿÿ,䌭�–\Xlã9úa/WÍ3!/_&`&`&`&`&Ð,µ{äÍŠW�B÷ÜsO:{±õ}êr½’bQ [SÆTféôY!í'-Ö>ÐÖ¤G+¡þ ·kQ ^@±z†tµD5¢tF‡�¾W\–¿f¿…@ƒMƉ޾W:º¯™å ‘°ŸlíõFYœÏíí˜gÉo�¾c-¿æ^5ŸaÊ`v¾‚eôÅ-P`ZT�Ôq↠2PâRÙw[ÂÞ`}v­^™š+w{‡ëˆ6ÔC(Åi ¥i|S¬Ä6''G{ÝSà[ªYëèz$­,d¹—v¬“È‹òª�']¬ID .~òÉ'5hÓh;mKý©�òlv£,¡šçSÏ{£yéÛäÆ ëÆròjLJÚãyJë?&`&`&`&`G$�Ã]ÁŽ‹JeÉꔑÿŽÒ¢ÃŸ@9ø°ÎÉÎZ)%ä9¥'�ü7³t^3á‘�ˆåz(BüF'°?ÈŒå"+-åöe )ØVZ#x|c&`&`&`&p˜èòKÄWþšÍÕ)Ç(ÖéÌœ�ÅÒԱܿÇýš:‡}u8f¦û’ÿÙd¤½µŸ²tx1'Eïf†²œå²úô˜ö]Ÿ'”륄ýžè6ÏÜwxÁœ� ˜€ ˜€ ˜€ ˜€ ˜€ t"+Ø�;:+–uOe)ø,ÖÑ(¬:µYŸJúˆ¥×9�½œ%Z+w×2ƒ.ytºòI(úÛ‘g?²éÛÑÚ£›…YÃï×YN¼…CÜ´gÛ— ˜€ ˜€ ˜€ ˜€ ˜€ ˜@ �Nÿ\‘Éÿ…³ÂÁ‰ä(¬:ê+f¯ p£ý©�ÍèÁ,`ûd¸y‘¿yËB®cQºÇbK¦7¸„ýÓËYò«¥á�îkÅÏ— ˜€ ˜€ ˜€ ˜€ ˜€ q<ƒ}ˆª\Ê4Êìíjì],ÍÞÅiÈE=ôÐ!Q\Ùó�ÏAg_pZø:íþ`é�b�†|%Ìd@ÞÜ Œ{iø!j3ñ�-m¦’�~§óÜVâ¡Ò,£ ˜€ ˜€ ˜€ ˜@»ð!gí†Ò ™€ üÝßý]wÎ8%[{÷×Öýž ™€ ˜€ ˜€ ˜€ ˜ÀáLÀ öá\».› t>�§Î[O8e^ŸF;$+2:¿ØÎÑLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀº6�{ï½7±ºº:)C][RKg&`&`&`&`&`&p8ˆ{¥táÂ…’’’ÒòóósçÏŸ_JeUÎæ²™€ ˜€ ˜€ ˜€ ˜€ ˜€ tMšù�ÛK³×zeeåéééƒQ¶ãºšYìt~ÇýÞò¨:ò­ ˜€ ˜€ ˜€ ˜€ ˜€ ˜@ˆK;zöš™ëîpÆ �À>׳ØqÐê,¢ ˜€ ˜€ ˜€ ˜€ ˜€ †âRÁ®;{®Ïb‡IØ600000èlq§`74{†æYì0 Û&`&`&`&`&`&`�M îìÆf¯Ãà<‹&aÛLÀLÀLÀLÀLÀL 3 Ä•‚kö: ͳØa¶MÀLÀLÀLÀLÀLÀ:“@\)ØMÍ^‡Áy;L¶ ˜€ ˜€ ˜€ ˜€ ˜€ ˜@gˆ»9³×ahžÅ“°m&`&`&`&`&`&ÐYâFÁnîìuœg±Ã$l›€ ˜€ ˜€ ˜€ ˜€ ˜€ t�¸P°[2{†æYì0 Û&`&`&`&`&`&`�A .ìñãÇ÷Ƙ~˜rLi�©Â_Ñî�uuõ¼¤¤¤ iá@¶MÀLÀLÀLÀLÀLÀL #$wD¢í�&Jò`f¤KP˜¿$í¤šôCØ30}0ºÿ³­t'§qÓ°‹±«ñ÷e&`&`&`&`&`&`íN .ìÄÄÄ\”ãß`RøO®¬¬ü-¿¥d«Onv&rîÀž={¤\GÜ|c&`&`&`&`&`&`íM nµÎåË—§lܸñ-çÙÌN§æ‚ÌÌÌÎ?ÿ|-÷e&`&`&`&`&`&`�J .ö`7DdÅŠrÎC¹ÎÅÞƒ)+((ðpQñe&`&`&`&`&`&Ðéâb‰xCTúôéSÅ’ð·Y&¾ÿ$f²·¯^½ºÖþë†âÙÍLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀº<�¤./¡ìŠB÷Þ{¯N Oܼy³?�vkˆÏÔ…vîÜ™2f̘§èGê¢1÷C(jgdºêª«’fÏž�|ÑE%,^¼8£32oC¡9sæ$ßrË-‰q$sŠë¨‡�@ܶ5þç$N˜0!ÞžíÖVuÜÖSk ìx&`&p8N…qY:‡JL&×H>‘V‘žž¾é‘G)»~.Rðœ¼k׮З^z©²£%¾þúë{¦¤¤Œâ“u…#GŽÜB'´By6æÞÑòÊôaŸš‘‘1=“’’¶>üðÃù|¾¯Ë+Ù(Öé ˆ Cæd®�~že+jSÞàIá’ÉÅÅÅ!Ú¢Ú^9õ©g²¡v¨ð‰Ê±…ïŠèxú4eCi+ÙzWÛZ�/åKÜ¿»zèС•¼sšú<¦d“V­Z•XPP1bDU3ãÕ’Ù{ã0‚g$çÀ�¹-dN«Õì4h9wîܤT“ws¸åÞ±cGj¸=ÀMÿôÿ2f�µ±žÂem/;RÍ‘½½2u:&`&Ï<ƒÏµ× ²Ka<çœsÒ�;¥K—)îG Ð]‡ò2¥àÛ+V”v‚(]> ±¢S=¬¢¢bjZZZé¸q㊢g•;¢³fÍK=Ü„éC§sÍW_}U¦|sïÚ’fCí«µé�tÒI½h—gVUU̓ÇVXìeFXmV�êÔ£Ž:J¦º£ë¤¥ò}ôÑxŽ.Dæé´�•_ýuIitéò4!{{zw)wÞyg7žû£x<•ºœ‚B6’ÂVñ,æñŽ Þ�áÂk6vذa=?ŒwFæ%—\RXÓVÃA³C7Þxc7½g0½hÏe+W® Õ‹íÞŠ¶D×szâ‰'vg@uÏ×ìÑååå}Q“™U.Cy®üÕ¯~�•NcÇŽí�ŸŸ?:55u¬f‰ß›wUÒøñã˯¾úêªf®Ú͘1c \o ÝBѶñœ4»Ü5‚µš�ÊÿÆo0¦ÐgeïÁŠ“’%K–Ä@¥=¤äææŽ¢œ†ÜÇðlO¢¾»�zê©9ü/�·µõTSÎvµî¾ûî´œœœ,ÚÛhäÊ£½y@½] ;10�Ñ@0z¯[¸pa&³Æx° ý+R³0ƒéD�sðàÁãUOSÌ ô¤“4‹ŽÃ1t²RÛ?ÛøLQ½/¼óárf<¥èŒ6Ù›¼N¤>ÔùL‰"ט{T�C~Û`ûj­T¥¥¥ipGüã±ûiÆLiÑ9îNÇ~F÷îÝçõìÙs¸:Ë­Í£#â¡\w#Ý£¨Çé<[Á3+Ÿ®^žX²·§_Wã€Õ›vwõøÿñ,Þ†}!niwÚN¹Ôþ¶mÛ6…s. �_‘——— ãe‡h©j+7“×9¼Ÿ{¢¬7{%ZKÛšDÑö^mÃÈó|ò¼ûç˜{�ý˜›{ôèqÊOúS½ojÉ¡ÿÙÙÙT>âýTqHîo±ïƾ.³7nÜØGƒ Ê'ÖEœ˜öÇ>�´†“f‹Ÿá6° ñþè »³‘ágäÿ#þ¦cÊ­Á⌦\—ïVÌ?!ÿÕEEEÝc•U~­©§¦Òl­?ƒ!™Ôó˜ßŽ\㩯Zí¹µé:ž ˜€ ÎbþƒèÊ×?eþaÍAÆ+yù_Í‹Šv‹ÿévå26G6qà}ªFË _«ƒ£øMùÇʃŽX“&Ò)øÏ°¾Ó#VøŽökKY:Z6ÕAYYÙÑ䣙ÈL³Kµf­:Z†xK¿³ÚJH_Úð¥ðù9 Ï4:öÑñ†-!Vyºò3ÒÞ cqh:“Šoˆv–ŠÉãù�wç£Ìv.C™V•( ½§5ȃ’v1áþó3œ/Ø·o_“JaC,5Š¢s%q.çwîK©ó˜Ë�•o®PVVVž›K$/霅éÎ}f0÷—S–_ ×ìÿøÇá|�)cø}+æos¶øìý÷—cߣ¹ÌŽj€©C/òm5;  ÿ ÔàÂõØÁ} ÆS›ºŒ¾É·„ù æÌL2ƒÒõþOãÞe/ÊPIù5À1!ÏàÜ•f uÙY00èMýƒèZ—Å…^˜Ä?»¿#ö#¼üÇLe”ùˆYeW:šÓKJJŽFÉ«§84åß úyüƒ]뵘Cº4¬ÊÒŒâ¶.J[_: §{æ}f86ÐÉléÆÖeß±:¼}¡ø”R70+˜!Þ[XX×±ÊÓ•Ÿ‘ön¦±8´w^-I�vv�wåJÞ›+~÷»ßmﮄ‹ßµ˜ דÏ}³Úãm·Ý–‰bw"²œŽù–x¯mذ!ŸûS°‘9%xyM'ŸlÌ¿#óÃþ[Êw/÷/s?ûJ”ðÁàáwÂÖ­[{gæüv`îçÙû{êLJú?`^ Æÿj&G�O‡Ž·–�ÊCù‡cÎ@Þ^”c;v³þªÞ{ì±ÝO>ùäÔÛJâ`:¬®�«C®§žzJFŸ’øfìS`1Z(’™50�Ä@Ü*؇ ÿ6ƒÎÉþáÝHgçJfFê�,7åKöÆU°×M¹îß¿ÿct4È®¶”¥#…®é„�$�é€lÂ,澸#ó<Òî¬öE'7‡vü<æß8O` ßÈŒbºŽßw5é-Äof„ÊÕ‘«JÚÂŽÙZ œŒÑ²üÅÈ»®9õE¸Ãê¢Ì[1ïÃ`u7‡�¼&W\V\0h!�ð?ÃFsð$>åT§Q‡˜ Õ̸U†gB”·”:þÉ%1s­“ÇðÏ/�~éZ‚È ­Õttªµ„­1⇬h™®Ò££V©Ù �€­<é¼Uêô[Â(=ò¨7úά…² d¡s¤%¯ffêÆÑçGÂ'±6tÐKPþ={ö„$“â‡Óo¢,‘|àâÀ�¤½{÷&5ÆOeŽºBpKæšÄf†�Šš� %Žä9 GÍ^È^à�Ñu¥À ÉDuÀOPF… _ ËrËdf� ,' ×a"å ‡ï;rj,ßDöXV÷ë×OrVQ Ͷu*9kGx5(wcíK3ZtîUvåYÝ–ú‘\ì‡,Õ�P¤-¸œÁ©ÀjÿMŠ.3y׫¥WsEžÕpê¾U'$‡l®]·<üŒœ¨ÛHý"g„S�óƒ°ágOí¶5'F“~³žÉºOïÞjt®Þ� Ôk‡×%Šd*ïPmmú˜û—QXõLhÉuSWˆûg.uÖÂ"Ì<;>ˆ'=/ÛjL=9Q¶Šøÿ“Ã;k2÷}ž‰>ˆŒ‹qÿ ¹—sÐY-Y +ÿM„×Ìx_„ãÕË£�­f§ÿ¥ü›LÎÄhàôÏÈ2£rQƒ)Y*¿’BïÅœ —7y_Ôý?wDAqaMÀL +Ø1àt¶—:ÉRÖP$ò}Šj:a)ݺu+¤³�hRÜJB¹îË^®‘øk�t/dMÄÖ¡cûu/b6;ŸNLÿ†ü7mÚTÀ¡4Ùü“¬¢c£=}!>ë´›¥æýP0GÑ‘HCQØFc�]báÒ+¢ãº�NvdÆ„pºRt`y�ྟ˜!oë=·ÞzëNÒ+Šþ'¬pÙ—8 e¼’ô·ÐI¬µÜNûÝÈsJ]*{ÿ²aPNYû4VÖpY|ðÁBå ›$”ÓÞ”me׌Q*[ °sÈ{§:z„‰(Y0ÕÉß: gyõ§ Iä-v;9gç< ÙΕCå§‹OÏèœc¸U§q ÊVtg2P�©iе–…¦¦ˆ|rø~õ>¯UX#“:ù)pÓRÄ¡T½vCö*ÊŸ{ÓM7e³×1/š§òoÏ‹:Nž¬÷tßÀ¥Ü ží¾øUP¶|þçEÞÉ „oµSØ…�k̵4¼7Ì_ÀìD摳ÕìĈü_VùWÀäl²�Äÿ°lì ¾;Q ge&`qAÀ v©&þiiÖR#ù:%õÄ�›–ÙéÏî¿Ex›à f‡¤OÄï:ÜG6 £Oeé¤ÒÌVܵ ïT܆c²0”Á�tŠž‘’‹ûÅ„×çe–þdîgàVMžof a†á¦|6M™2e! vþá+�º“‘E³·Š§Nuá ‰»�ô–¢¼.£¸(æ(FƒPu0�Òys}I©RG²�°Ç±÷Ç*k¸,pÙÌ?|)û£ ŠÊ�ÝŸøjãȲ…¼?£S»YöbªÔAD>)âó�÷xÂJe-$þj:±"Ì*ʦ¥ÞÄMœ\ÒÚŒ"”7�`�ŽÚwyFŒúa§b— ÓVìÏè܆<¹((©”gþ³1Ç�–ÒíN¸tì°þ�e¦ï‘f½rüÛ|¡°¦¡0�D‘>‰¼�E)�Ê»Œ2ìE¶ï`üÊÉÚ°r¢L9Y§ûÆlG«5�¢xºPd‡“G­öE[Ì >N Í(ó2Ê߃û鄊\Z-PHZ‰û"dþ%[m»Ñ ¹3éÀÏ&­)Ä Ök0ä­Ù¨k1R¾ÂžAÚš±÷f'yü™6óáƒ6ƒ[÷Z±Ñ—ö4“Ÿ'f ¶~*Çäâþy~Šlëš’Méµôª[Ê´‰úiô}@øày§Ý´ø‘lâŸkÉ£˜²©>Äi^R¬¤p¨.Þb–uîzÍÂMûrµŒ4�ºüû]¸mÂDž Üê]ÈØìg².Ò^C½ô¦mH8–üõœ2IÙÖoÍ ¯bðäÂïäw0XÙuY30&ÅS&aþüù²b^ȘÈIÛú_p>r"𧔥‚AŽ,ÊšÇ ÃÍâwä [´€ª0tÒ} íau«wÕHd[Éïõ4ZÎ}t”z÷¤¡wâ<ôLK)ßÀjžßõ"·À¡-ì4¬ÿ Èw"æsÌp×ÿ‡#öâe©ßÃâê|ÏÙÀÐ •/00�:á¯Æ?;�ßM¤Ó1sæãø'VŒý¶ö·i‰ñ%üƒ¿�Ù»Ñ(@Iêd¶÷b¨Ó*S„{¡Ü0¥˜à¾®?aŠ1Uê GŠÔ¥ü¼ûd~ïÅ–²±e«‚¸šÕ;�ßÇ�o¤ÃŠ»fÌG*~—`´ÄïÌrÌ~ü¦!ÿÏÈã ”ÞÈá7ÄÓ¬ìÉøÏât$=Ü‚K2FŠèÉ(EÁ©åäÑhYñ Ê¢¥íÄC§èfâÞ€ûòØÈýrluh§ãv'ö¼~øAå¡,j…À<îïÀ Æ5aUv•í<ù1ã„Å­Ñ ÅMûô”ßvLƒY%:¿)(ÄãIW§ÏÎÇè° lä\A˜Ý˜£07ÿhMR(»”G)(—ak–p þ+¯ÃeÆá~7å;7Íœ¶ë¥™kê{4ùÜD>·‘xöÚØrÜ6ñ{öõ˜ùt²¦¢g uSôʨÆâ¶Ô½µì4ˆÀ ßXò;‹ò@Æ·FŒ‘ßÒü·ð,¤ÞvÂC‡Fޤ vJ›;Ü8º<&`G�vïüØÚ¿”ŒüWÝqÇ:QùRÏÖ̯–=óÏ^JÚT:Rwá>ƒlšÚ¬“Iùç¿”¥­šMúgÜ÷óï¿q�L÷çê—cù³¬sá* ?ˆÎ¨fs¥õþ€ö£hfªÑYÒVÛɨ3û,Jâ,¥Ý­xȜɲQ͆ߊÿ5ÈžËÒ÷W¹/À´èb™xi6YVf"ƒfyæ�Á{È÷ûÑ£G¯%n~Ýñ›�ßíø]Eçé:¤ßf ²©ÃÍmõ#ø¿¯ü¶oß>eAiíÅ/æEú‰,‰Õ €”¸\"3ttBûá®ïâÎSژ̔}«¥²’‰úÒ@Šf΃evÈUF'u=mà9äý”™©Íj,ÑíÍàÆE„û/¤u.íáî 11;³ø7û‚•úó‰ S—`? ‹¯(Ÿø'£�C.)¡gÓVÊ™ÕT]oÅTᦶ³5[R'U”¿Œt¥œiEÄtÂ_TûB‰Òq=ÿÿãa87 V4µÊ€ µ¯¹å¨ZÆô[”Õ¥êHÒ>ôi" ÔÜŽ™‡ù”p%z©££¹ÿḞˆ÷'í€Eˆ¶0‚°t:—4÷¬[·NÏÕ~L‡]Ìþ•1ƒÙ!ψڪ8a$ÿ`ʤ2ÿ;õó-í³Š(­`ùϸŸ‡{æ„ý={6sñ‹_¤²lþTxüwüOÇü FZÚ¼[[ïâùhÓ3I=hý©pœÅ’¢…ÚGÛwö²ÞIjK¼ïºT]†å– §Ä-[¶Œ†Ÿ>ý§ÙÓýØã±R bœ†ŸY_å]ó2msk'Ìdk …–´ÒF&Ùüþ<7q¼Ç°¼�OÛu4Px qç`–RoðŒè]Ö®WØß¼¦<ú¿0ó{Ø®#½ þ—¶«Œñ˜u¦5 6èÿER<–Á2›€ ˜@gfr:##ç›�”jNÅÝÄÞµ§Ù“û1ŠC9�ü –ê •ítD–“B2�“ÑØêä&(î‘ÃÇèèJQO8è 7åOg6Ï?Êä·¥ø­ßþö·‘¥°Ê#Æ¥¶£�W餾HG|'�� ãL'¯€Ž÷‡¤»£N×ùtR¨Ó#½˜^M”%D‡_§ØjÆaÄu)¡@IDATæE”ÕMt¬“˜iMëÝ»·NC׬±o}ƒö˜¦c’ù��¡‰iäÑC3•0ϦL1kñ\Í^€g#* -…Ë”߀n!ÒT]�…û&îŸ5jÔJ),Jç™gž)D�ý·ÿÇ`ÉGRêP)àþCêÿY”—­Keÿq7âKÉY‹ÉÆMJg_:«­fIüºWˆ¶3š|¤$m'Ÿ'áõ%õ(­ê\¢¸¬ÁoF³’'ÁpªX)¡6¶#%QëB™®&}1WþßÒ6_ Þж´\}-îbR¹£g„û_ÔIø9É!òkä»"¼¤›zÊE†Oa¢Y¹‘´/Í€ªó­Yï1ZÚþ'Òx¥¼X3ú´7-›Ý�ûÛ0RüS‘­ÉvÒj—‹|c½ZõŒH°Nb¥%ódfþ{µc)s5mòclÝë}ð&mz¯dK¸­#žVáôÄoˆ”Z¥ÙØÕϤòÕ ÊõQÈ}yvÇýUdù”ö\Ò•ëR|P®õ^ÑJ -¥ÞŒÜ xþ'nÿ€ù%æQܵzB«�Φvø÷¤Ékæ%Ì“äÿ ö>å�\g³t\JW÷z—”kÞ�cñ¸–º¸�p«ˆû ÿs~èˆÙëÖ²Ó È&Þs1ß#ëûuh«W¸#È6å´G ªgPçíù?è¢è¢š€  bvvŽ]©ŒR@ه݃ÙJ}wSˉ{ck¦BJÜ8dMç^ËSÛeä˜|èkvj7‰¥ªÕ’ýTR$7#ß»œ"\oB�ëÛn»mé®&ÜxòAçz;Šw“È Û`'­±ˆtÞRà2”xð·nuÍ@F¢(M.)ÓRXÇa¤”åaVâ6 95ë8³�ùvânƒ�Fê¥XÈ4xQ¦$:ꩤ!妌ÙÄ œf︊é‡×f=7KQ�N„ßb(%2|…¤¨Ñ9ìGšYÄÓ x&quúð@¥!g*¦'}YunbÎ…mÊ?d?íñ\Ä`Èz�z{"Q·3s½˜0Ó «õ>⾤�íˆ$¾È#Ÿr¯¡�åÕ° ÒQGÇ+ЄöÓêð¸V?Ä'›ê\ÒúN{Y£%áÙ(àYÛ‰p0vmº/aŽÖ=FŒfÐ^‚AÅ…£Üµôµ{ñ‡ÓF6á]Ï Ú©Wž‘@NÊ¢g`åÓÒïHYX¦­õþ8€»Ê¹/º®h#Ú²›èI°èÅÀUÌN9aÛüL"CpQæ$¶ŒBæËHWuöGÚðë "0îÊ.]—0Õ`ÚLŒx/ä9x„AX­†ÞG Àjß³=þž²œƒyöá Öþ€zîÁ„xú�÷ä{+¿oä�¹•÷ÞÇÜ×zŽ�SƒÄ:C«>´4| æqÚÂ’ð€îízµ†í¥ˆg^Ïì9´•î´›÷1ù<¿iøéÙN£ÚŠÄm¢ãL£l 6é½ÔI»¢ &×*Ê^ŸtAè‚"Z$0è¬`w‰jøËr@fÕ1×RæSkF³fRø,oÔ2ä)ŸÄmò"¿RþojŸrDQh*qÔ©ÐRÅÜÆ–%â§å‹Ú³¥$)ˆEHåગ �¹'É¿žg#Ì<ê”Ýþxkg"ñ¯&~-eVQqÓ^aÉøÑAÚC~R\Ü´\[K5óø~ËèL-Eá]«ÈÞï*,u€¥©¥²¼^Y% tª®”néî¦c_Ož `Ô­X@™žŒÓâL#®f°‚YbdR[…û^îC(ƒÍæ•Eƒ·â‡‡—¸«1Y<(¦S¬¬$ÌÂÕzàÖâvÔ @5ޤ§�›í0©ÅNŸ…B-U”’TK†š¨Í¶`¬WÈ,|.ƒ µ,¨å«ý»:)9YË�aŸ�›žSµ7-—䨓¡o¤¼iÿfZSJe�¸ò³µÏHXÊ!6(Ìû£ŸwÝ£héF)Uxžj½CèƒWÂ(¸#�dFb¶Ûöx&kdÖ jÓZ•qò-Ǽ¸zõê\䔡®^—(Ô™ð�üzæÞ©ÙQäPìŠ`ÿþßR¶  bnáwd„ûŽºªµº‡÷ã;¼ÿ¤hßMþ§1࢕V[Ê5îZæþ#Ê m.R®£n>Žõ^m«Ð­a‡LÛ�3‹¼OÇhЭ7²žÎ`'·ŒfòÅ ~kà»/áŽç¯ó6QÆ´¢#t˜ÿ‘RMù5ÈPNÙk=ë‡yÑ]<0h�6uN[”“Ç$ Ïsñ¿ëþgý„€ê”~Æïï0»ø­ÃËtÓݘH‹ûv¹ø‡©%¹Á÷†[˜ F°¥L¨Ó\O.dþ+}n+éÀDÂð; ¥¥^g›Ž‘fi{“^³GÇY.ù¥hd=‡þß`›�WQ·�O‰:EÌL¬diå¿÷8ÌÑÄÓ‰ß s÷ïÒaü ³B[¢gå¹ø>t¹¦SUDÂ÷`Æ,�›²iɸ4•1‰ÎX½²FùË�–iÅÜL¼“púó1rdó{?¼´üR{Ç*¸VcÊn�+Ì�|téûÆ ÊªYsäÓ2hå]©xÑù#[kÛQt2‘{’+§ž È·VGŽïYW³×Y'éG¶áFmF§’×Râ•yEâO$y5ÜVÊÿZŒ–�ÿ5@$d üç¡0ndy{½´£‚uÊm¸ŽÉ¬EÏH”p*CõÊ¢qíÿZ,Pì« ©å•f½Û–<“ëׯ¯¿ÆA+AzðìžÊïK1;¨³ß³y}ôrä8¨K½[5(XFýíûå/YÉ{ˆŸ½(ƒ”Y Žj•SOžÝf¿7ÿšJÌ»à3ƒЫ9!¼V]Þÿýo¿ýö�zq�ÿ0ê;Ò§�rÍj˜,Þ]×à}1þk©‡Ç¨‡O:R¹®)M‹Ù!W²V _ÁZÑs;vô»G¸#1ì¼öÛ°µÿ|+ö¡`ÃD«©4xœ‡Ý./`Øù20�ÃŽ@äŸa<–Œ¼–a#»:}qý²§38€ÎÇé”C‡_ý“7™QS'>A”‰áÜjæPN ^ )¬Ñ›ò�ÛŒ{ÍLh9ÝXö­iö¯–BKG0‘y}‡{áôê-ì-®àDqͪ®´T[3§*PÐi«‰£ƒˆÔ‰Ñ’ÓF¯è²lܸ±xôèÑÚ;¬å“Ù˜ß3»¢™óèÎ`°ü…'Êž~úiɪYj½‡ŽýÉÿufiû0#s*qç“Þ©ÈýåÐ G­òñ;¸ˆSÅá7…„Õ¡\ý󺔵˜x’AáÆP§úÔÔÁh™øš;wnÒ|PÉÖ€dÊ4ž°'ãþ ùþö²nVú¸…`¬eíÑ�=¥Û.W?¥?–ñ‚^ä[P“w8��Ï>(PpЬü&ÌÑ© �­:ÄlâV'Ðkä–ÍÖjpKæJꨗӮônŠn‡ü윫�ž‘Îö¯¹´ä™ük¬¨;í£å}:�öy%u¥í¯ðœ/ùõ¯™YUð®^—Rž)ƒÞiØš1�wÄv9)µZ墥äzÿˆÞ®€[›/}�ƒDz íúë¯×A€R¬"홯_¤0ëUz¯—6ð«ùŸ¥7ZMt1þk¹—rýi'(× ­aã þ?láÚK´™¿L[G¤â¬mZ=±WbÖc6ÓÖôŒw‰‹wO"«B¬,Ñ» ¥ÑûÍju¤ÎHL'Q�¤Rª×ë`.þÑ難‰Ì® ÆïüÔ™ª5C�›Ê¬}ÔLr¤¥*ŽäÕéÓÄÁ¹q:AZö¦à­½tГ¾‰¹›|³ù§]Î?wýSOB¹ìKÝ�_a¾`fc;ÿÐ+9´«w͸Œ¦Ì£‘!W{_‰béo_ܦò\Ëð )O-¹b”¥’Nõ6ÒÝ@-G?–oÌ~LÚ…¤->ú¶nlj¤ß�½æ:Àk¿V 0�1†ð!”ä�„+Æ-�|¿ £5 ¹¯ÆO{85RK‰âwôu�šÉF]©c¦SØ+(«dÊÆ}ùÎ@¦Â°LªWòì�••Õ÷]„Ó!QZz¬¶¼…üµ÷/4‡Ïg±44 ÿQÈ"å6™´Úu‰¸fõPæ·‘÷¤¯rÏâY’¬ÅOuþpu¢�A†ÙØZ²ú­N¯æþˆºhGû¨ã¯¨£™˜³à±…¶·…ö^A]%ècÜë ÕU6 ×jV¶³ !ScïƒV=#�tÂ;¬8RèZðLÖ“CÏ —öû^‹£xn^áÝó.+Hô>Õ G°úƒU• ‚t麤�í§,ßQ}úl¿w23ŸCYª4£ŒÒ«%äSñ›H˜m˜­<«(Wõ¸´Ö¥Sƒ¤WÐÎG3xøïª�Î;ï¼bÞIUÔ“–x Ã� ú³yËô?¿aäy5æJÌÒx¹—KÊPëÅÎ* ÍÌ·«’Úv Òê‹ :c@¦ÞÅûZœõ�yeóËÎ|¶ë TÇAܳ³³û²Š¡÷]wÝ•;hÐ }Ù@ïƒàâ>‘çKç ô'\á÷Eo÷ �þª2ˆ÷}ás0‘z¡ÞôU€Á„Ó¹0Ù°è´÷Ú_Jà¿&`&?âVÁf¶rÁ‚ÿÖ¿ÿ$§{_ q‹ü3ˆŸ*ø‹¤tÈ‹ù‡•ïatfN¥c“@ê �’^øIéÔf)aµlܤøiVAŸšŠÐ�üU7ÜpCaÞÆþÈÆüQ$Ÿ'R¬‹´õ�[³Øê\å³Ìz Ÿ·ÚÉÀ}›r)×úîô…øé{¹¯Q†àpž{q§a.#l2ïD)I#œ”–sq—ÖÏm½Ï€4Z: ÛHë5âÜI:ד¿FÙ×è„gl-9Ÿ„}&Ò:Ù(¯yøi_øå˜˜·‘a²èäc}z nù˜íMÍP�_io"¬Nü…RµS/î·`^%­ÛsF2­…Q2ôÂOƒ&c°ßBþ•ä£Yû ÂMÁá6âŽwâpÂÍÁO{õÝïvn©—-¤û ùü˜<®ÅîÏïÉÿ �-ÍZŒÆý<Ì üþÇ•tÎŽ8›zÍçszŸÂFƒG§P7Úgýé¸qãrh?Ú›¨}š'ÃKíûÔ£ÚEgvDÛõAöμBÌ€6û™¬;'A'MšÔæçS7z÷ìÄi=+/²Hwm9( uSÄÒ6¾ç~€g¬ËÖ%' ïCIú˜rœˆà`—ñŽø;ŸYc�;1ž{•5™vø pð™Ä �íô‡<¤8ë}s,ùhNoÎ�ÈÆ¹€wFoìq;  nj`²„Áºtd?�ß7à§UWkdóéäÇù¯~*ÓÞ™›ÛSYí ìþZÊι£¿ Ï -Ì ÍÊÿ¸÷ÈY+ü‚‹÷¸µ¥¹˜•ô™þ»\R éKM¥®.ÁaóÆ�bk0<˜ §žúP_“ñ/£î×ñ? 3ßk�Œþc&`ñB Ý;ê�Ypf5Û{X\ts耼Ka4ãû#þyMæå>îõOSûžÖã§%ÕUtî#Š1ÿìöa¾Ä]3f·ÐÁÙDܽ(Šop(“–ô5êÏÒjÒÕ²Ébfy"#ÝüŽ\Ä—»N.%Lð�¶ÆM=¥•¸ë€}¶I'Kk™¶–5á·f·5`ðtü"§Åò|ŠíbÜÕa; { åÔìi¿Õ¹ÎèB¾dÍâò;¸ðo´,ÌHý€‚ó!aúõ\ò¿óâ6·!ÜKa~‹ûÝÌôT3НBþšµÍâ~²è÷H~kfæx~EØÒX³BÔÝ~êN,ÂßµÖòÁ,›ÏûÉO~òg:ü�enwP¦õ¤+9`‹Ñü2é¼”‘Æjêv ~'à~'÷뱫©O XHÖOˆ£Nu �Ü€ ¿ëÕá4:Ñ »üº8UY{)?B¾~ÄÕ Ç­ä£N³Vˆhè(lͤÿûf2"=eä¦Á^ÐFÛQCyÊ�´êÉ©v³rò×`‚¶Ô‹ŽŸaŠ0%ŸºR{ÖRÙb˜É?¸sWÞ5yDÚv8Žlùctp[‰ÊXãWM½l�ƒ>Aw3nbu Ùi INZÛ³„xßð‰ŸZË’kÒ¨eÑY%ZµöFk‰jðŒÕ PçGcåQ0Òh·g„6”™4cr¢¬b­�¬2ÚE-ù™ÑO >Õvå¯ÃéjùKæè‹0Í~&yÞëÕ7’Œ:›4µ_V{EÏG¾Z¯Ô‹Þ7¯àÿu{×etYšº7ä+Á.k¨Þßzë­Òë®»îÔÖ~„Ü7�æéÕqâé¥í¯ÿuVæèyˆyµ´­ñîÞIÛ~‰¼¥\ŸL»ÿìm¼'ô)6ô§%½§"Ã7R’™åÖ@ êAu öÚö¢âzá4¨øq5¢º�u©=ê½y¶ Üì` üõÿMÿ+ùŸ³-7&[sÜ[ZOJ™zaipïLîõ¬}Ì�»ì)Ð}PÂ߯Ž(Ø<;z^&ávñ¿c9ÿ[Ì`k5––“'2(¥ÿëÚz±‡pëyÖ›ª/’òe&`G&�º³¡G&….Pêçž{.ŸªF”ßa–a4; ÎºþA.ÂïqìWùý%³‘N;³{éü¿…ß›Ž6‚0©((•(§Õ±üé,é3HŸñÏò:š‘´¤¹#%ùÂ,G9”î5ªý>æEŒä}’t¶à®%Σ°Õy û×äÿ²¾ïL˜àÒ’4:S«ñ{óF°,l}BëÌ¿óûÌ»”9_Šp‘?±Ê¢²¢Ðî"ÎòV*—”öÜë”ãp¿ûU:�ÁÒ9}r†ÎëSø‹íZŒfº³0š•|NÌ9Hi+�‹@ÑÀ½Á‹º“²ù5ië“9Ça†j¹žÿîw¿ÛNyƒãý¤¹”0Z9£Îõ{˜ßÐQy_{ØñßD]>„ßKí×Ö²p)׫ùý¿b/R�Ð dj¨~£OÊÔ«7¹Çº{ì±Ýtªž%Ì}äõ1²i. £ýòß``0áadÍV=â\ÈÜd; ‡­k7$'CÍ�¬%ÿ·1Ù,§¯¥ qØ“”ܤõ&þ«È?h—(rRÈ5¸ñ.î»XÂ0jÌ�0RTÔ.>Eaˆ¹Zß;n(ŽÜšS)¸5Kæ4›˜Ç¡g±ä�{*3b}I>�Ùÿu÷¯5&KØ�™¦>ÔÕ5äq5nÏ£h,Ô IØ_¶dbKCO”ÔL:)QÀ¤´ÕëX²\R3éÓ7éÔe{ë8�l‡Ü«²Gµ²ö¢Mh9­;T ¢ÖtiÔ½êK߈Ýלç5:%ÚE«:´j"Îëà D‡ié}G<#-•¡­áÛúL¶"ÿ6Õ%«U†¡ìþŒg[+Pþ™çfJ‹V¿4© 6GV½?|êA[ëÉû²˜Á”ଇæÄ ‡iK[Ó;Aÿ›tØ!eÔb^cï°p~íi³ÝIŸÇÒ ¯] pín ×ö`ך²Ô¼Gµ'ýDâÿ3feø%ÛÛöÆJ¯µõÎ�w�öêýÿmÊŸz ±òMu«¯Šÿ›‡Ùë)Èý·øk Û¿h z{¼§b1°Ÿ ˜€ Ä3+Øñ\{–½+ÑÔ¾ó¿§RΠÁÿby¬”¥vé\w¥‚Z0�úز4Œ–Ÿ¢Îåð$ï‚oXb½%;Çï�ú¼w)õÔ?Ztx©¶Pé,ŽåÌßÛ”‚Ý•Øpð™¶]†ü?Á^Œ¹�•&¹ØõxÜ|™€ ˜€ @ÀKÄÝ L }¨³‘M[ûÚJè\÷ÖIáí“´S1èêxö5˜¬ZA‘šÇ ÛeÌ\ͬ³¾Bàë# zGÁ‡bú#Š>�6Ámu~SËá»&Úq&ÿÏ!×Ìk èœ+×]­¢,� ˜@—"` KU‡…‰gìaÞO'êÌó˜µ?üpsö߯s‘-» ˜@ líí^ÊO ¶’{�p�åÿVFjIgkè@Rš©vð-æÚÄ'¸ÕÚÝÕ™°<%û}þ§=Ã9,+[º¦«—Ïò™€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ tQq½{áÂ…©Œ³ð|r©,|(Gem±LÀLÀLÀLÀLÀLÀcÁ§„â±|:Ù’oÏâDÕ)˜±C† Ù?yòäâÅ‹{9^„õÒœÙë°xžÅ“°m&`&`&`&`&`]“€ìCX/Í�½‹èYì0 Û&`&`&`&`&`&ÐõXÁ>DuÒ’Ùë°ˆžÅ“°m&`&`&`&`&`]�€ìCT'ãÇ�ïEÖ`úaÊ1¥5¦ ;|E»þœ–>�Ï“MÈÈÈH ²m&`&`&`&`&`&pè $zŽL P’3#]‚Âü%Âßïq?Ó£ûï0û1ÑJwqú7 »»_&`&`&`&`&`&`‡˜€ìCT‰‰‰¹(Ç¿Á¤†Eà>¹²²ò·ü–’­ºy‚p˰Ë0‘‹pöìÙ#å:âæ000000�CKÀ ö!âõÕWï!k™Èµ|ùò”�7Ä!˜•F�ÞЭ[·¯Ï?ÿ|-÷e&`&`&`&`&`&Ð… Ä»‚] Û ºh¨Ö2ê.ÌÜ¢™€ ˜€ ˜€ ˜€ ˜€ ˜€ †âVÁ>xð fy·`Ö`’ù„UaAAÁá°Ùƒ‡áƒæ"™€ ˜€ ˜€ ˜€ ˜€ þâVÁþðëøŽô‹ôµ˜}ʉ؛¨.)§q{ƃq['ÜLÀLÀLÀLÀLÀšKÀ§d5—T'„Ó·±48“Á‚A5ƒ&Û]ì׎ë�ƒN@ç,LÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀL ½xv{‘t:NàÎ;ïL)++ëÞ£G�âx ìÆoì––––‰[rjjjÅ� .\XÈ'Ûê�&ϾöÐm·Ý–Y\\œFü”’’’Ĥ¤¤2Nž?ðÒK/•E η’'Ÿ|²ôg?ûYw ëFº)QqÊñ¯‡eÏ|7N²×§âJ²²²òÙOßèg㮺êªÔ”””îÄIç;ç •••¥Ø…*“ÒÄÔº”òöLNNNÃT+|~~~r2(ðœ9s’É7“Û’§žzªôî»ïN---íA¼´ôôô*ì2Ê^DœÂÔËCiœwÞyiƒ ÊP>bŠ|•˜Â‘#GÆ(Oè§?ýi÷ŠŠŠtLjMœ’ýû÷K¾†ÎÂ#KåH¥^ÊÁV2~üø‚yH<_&`&`&`&`&Ðå XÁîòUdÃîºë®‰(Š× è¾�"·íLüNå÷@”´½ØãöÊÛöhå…6£oß¾ÃQ8Ï%üxÌPL&á³1/á¾ô¹çž;ˆ[ xFåó1nÙ<7 “Eøm˜QZ?C¹¯DÑ=ŽòÈ#ú]ëºîºëú÷Xä= �I˜Dânâ÷Ç(Ý_ >|O´¢‰ì™={öœ‰ÿ¥„ƒ©BŽõÄY„BûÅ3Ï9n!ßOø½žûé„;�pYü–R�ÍýÜ>5jÔNòÐ÷ニûÄ;vô%½ãð?3’°C° ð)î„Ѧh¦ŠˆŸë¡øŸÇÏ)ĉ-Žß#Ç[ÄY–· ,ôêÕk²©¦a†g7e[KÙß,//ß ÁÜÀÝ— ˜€ ˜€ ˜€ ˜€ tiI]Z: gQ¦OŸ>eìãT‰=[ d>vöì¡ÜîÞ½ûç+V¬�r\ÇüI„�ç`úaò?7)Å71c»…0k‰(Ä3fÌ8%ð_P05{%f÷ÅØ©˜ã1? ä$Üÿ¿Çböcc¤lž…ùhܸq{W¯^Q™ ïGøÿ„ß?‘ÿdì|lÍtKŽk‘§³ð«.½ôÒ‚Å‹+^è„N¸ž8¿å~f'¦æ4â]†»ì¸ãŽÛ†ÜU°™@¸_“F ¶”ñ»0R`s±õ9> hpb³ñ?\rÉ%¹ä̲�1¢~ÿˆù{ÂIé¯$œÊ®û a: øÓË.»ì@�\ÁŒyffæ\ò»Ÿ0¾/ñ•—ÌÁýrâ¬�={vöÒ¥K+Q®“¨—Ù„ù˜‹Óƒ8{0Cù}6áÏ¥<[§M›–ýõ×_G”Âù20000�¸!�7’6 ¨fÞXœ$C'ݳñ 0:œœPj¥äRÕÕR®“QÈ®c6öj–q_Š¢v6nïc®d&ôX-‘æ>¸§Yß (Šw°<üfI¯D9œÍï› °¿dIôÀšà ÌÈjÆW î­ø%î–_ÿˆx硌߂[æ^Ìÿ!Ì#,ï>¿« 3—°RÌG 0^‡BÙ#œ¦fo™í½¿Ûq{ûlÂ_Œì—“ßiÄ»Ÿ2HÉžÏlrOK¯ ÷_1{‰s9e½†ðgV2lÆmÎ_í¥!–ÄY@˜+QœÏ`öx™Ò ç£(Žç:tõÌö*=â<‹u9æÚßß��fnƒ ¥8³¨¨h Qsh—×?û쳚uN ÍiÈðæ#âümtù«Þ7oÞü·'#ûyC† Yƒ<‘4ÞAýåóî lÅ?hìËî…\Ãr…eÆ¿yßÎÞòÿ ,�¨uÍŸ?ÿ"Ã/Hó°TýÉ|°@bð9Žô^�ûÇÄùO(Å{–üžÄ¾¿»°_C±Ö Dä‡�ÕÈ"ßßáy>iܲú�‘­Ö¾wÒ›M/�ÞÒûWÒË‹$æ0000ˆZ:—tRu ŠÇh:íIÌ”=ÊòÕõ&n——¢XhÐ`0å  Þxã��¸Åý A4°/Is«”áè´Qξ†W)ööj×jÛ¿úÕ¯Bìî�"Ý “†2—„�LûÙDœ2Ùa Ò|MzÑi® \NX‰�Êk-÷e´»wˆYŠ.)¬(àR„‡£œGd �³0=‘í�¤™N˜Á ¾P®ð[A˜ÿŸ½7�³£ªóöÓÝYIÈB�@HeWPÜ!€kdp\ˆ Ê¢(.ÃÌ0ïüß™wÞñç�í3¾Î83ŠŒ ¢¢ãÆE  £„M[6ÙȾv÷ÿù¶]íMçvÒ�¾·»ïíç|>ß[U§ÎúœSUçW§ªî™M?�íÅâ+É#í,–oå£n?£o¬gÆ|óUW]•ÇË÷ºù‚ß<ÂÜVθN^Ìd_Å €÷’æ[XÞ€W›��´®¼òÊQkÖ¬9˜|Gá?Œ<᳓°éƒS`ÔVŸ|ô ¿×æQüŽÑ½‡q�‡,ã¸0Џgça6Ÿ…Ù!Ô?»:M±ˆzo"Ì«Ûó×Àî ãŠ$  H@�@­è0j¥ÀE9g̘Ѹxñâ<ŠúZ4Œ�ùÏxw ë5k`×ãMƒ¢½*¹Äî[€��aíáxÔzÆeÞΗ³;žÎˆá¸|ùòc™~òw>6ã1ý&�=ç}àr¯K<�ºÇLk2$ìâ‘LË3Ì¢ïÕß²Ÿ`Ç�~GØž‰fÞ߃ÿy¬³º§#ÍÉøäqö#1¢‡b¬oÀýa¯Äïo0Bÿ„ý÷ÒÏïà‹è·P¯eŸùÌgbÜ–Ú÷Ãg/ƒ·È‰4W1›ü,ÛÇRþ¶ÇèI»á¢‹.šÄãæ¯ƒß9øÇþ#XŽd_¸L¢ ÏR¦¶d`r Ûy4ý1˜ïÕm�J~Hã6c´çÑù¿ î^L1À#iVòñÐI@�€$  H –”3*j©üuUÖÜ4 B¹iðÇèOb˜`Lù>j§VÆH{z/Ãvüøññ+56Ûbòè÷›0j¿Ï÷ⱎå5yWbˆ^Âv> –¥íå·º\>䟰Ég;�iï•iïåGØX§yN=7b`Æ0ÝCø/E߯È}*_(gÿ•þ2‹‹Ñ¿QžEè%èÿR†oñ¨õ1Àc”–:lþ-åò/Â4?_Å {›•ñÅ‚ñþø}åÃfwPŽ¿F—Ãèýl/$NÇ#òä=ŠíôÕ­¤±¯¼§ÕwíÊGÔH®�KÙº,OÜB~·�æ^�¶·%ä�$  H@�€8�š�Áà\-Þ!��‹aþ1Æ[þwúBŒ×_•þ}êLŠÚö®;F`5Kýéÿeøe¸³´ %™ÆàÝ«<‚�G⣼Ë=ƒú\Àê•,ÿÃø^֟ξ8üNæ1ðÌ—½iÀãÚcyûhʲˆr´Í$cоžyýpú{òË;åmåàñø¡K–, ¼~ë¸é°˜42K>“tÚ>bVì+·¤8 ™õŽÑ¼ý97 V• ‡_ÙúwVo H@�€$  8Î`¸&±@•$Àû¾3Hï Ä;1(÷øoêßìËÿ1�ÀPü�YÉü.­Âx¤ú,E{ä—/gó_ÖÓ1ø�Èz¢Å¸Åïð<â^„ç«Û‹1Pÿ‘ú܃ßKHïPÂuÇð¯Ãÿxü:¾¢Îv›Ã¸ÆlòÛ‰›wÁïÁHn›)Æ(?“#áóM>޶Žõ#Ÿ/šOšãñëx’"h#þ“0{ ûŽkçØ–GñC=Æ·û7\}õÕë ÿ0:½°\ø /¼p,q^À{æ£Ic6Eš.%  H@�€$0Ð 8ƒ=Ð[Èòõ–@µÞ…9ƒr2ÆÝö &´`Hæ=íc$ž™YXf‚1V{›W—ñÉïgüEØm”cFîoxçùG乞õ–Ì83ƒ<}ƒõþ±cÇþ ­ã½ñ# ÿ·< þ#Âÿœr¶}ø Cø`ÖsìnF[0¦[™ÙnË;u¡Ÿà#iŸä]ë¼#�ÇÁóÞøHê2«W²¾šåWù›°b–;ÿ��GÇ_“¥ô›x¬~(q3ÛýÂDœ¶; _6ÿ•ðŸ£ÌΣùŸà�ð̈oçñô¡Tg,þ—ðWh·Áû^¾-�¥åoþ„>ÁM�¿$ü ÏvÞK?ˆ|ÞCšÂäO¸pW3üÕI@�€$  H`àÐÀ¸mcÉ*@#rÆæ/I*û;Œ×aÔnáKÕÇa¼¾ÿ[Ñ ÀÑøuÌW ë=’ÈÏ1*ÿŽ2F^ŸÄ¸œÅò—”[1._Bà³Øön ê¶™eŒÔüåÖ‘,?MøŸdÊ ƒ7÷t–ߣ{Ì8Ç�8'±ü"ú)�?IJ‘p'àÿ6âmcý/yd{ †yÛ{Õõ?Âÿ øçCj/zþùçCœ‰øÏ"NŒã'ØÆ—ú;ø\{íµ7cÀ_Ͼ÷ax_K¸³\À»ã‡RÞsIëüÆ�ÿ£ÄÝùÕ¯~õNf¨¿Àú‡ñ¿–x?Lx–Sñ;½”õÛ©çRÞkOu�€$  H@¨9æš+¹t0Ì2ã¹­ËÌog'NÌ£ÍKÐ* µ6#-F$†âŸ£¯ã,Æß_`Èý5ëç²üþײþþCø \Û íþòaÿzâ,$î¶Gy¤ãqjüÚéæïÕ–0Üöiì£tá¸qã.$þUì?ýúK¶gæ1ô Üï±Å£à°ï2ôS½œýÉò¯Ð‰ä}=éÿÿ�»Ô=B Î-„‹¡ûÐÿfû lç?¸çsÌ1ß/òHDÊu+‹0YL˜w£|ðìchÿ'ËÛð[‹ñÜÁœôZ)_nüû–‘ÇAÙ>„ýÇWÇÿö?þã?ªÍþŸYÉŒøã„{kÂöèPês3ßWP–§ Ãÿ·±ü•€$  H@�@íh3(j§¸¿+é½÷Þ;Œ¿éºŸ×¢a ègóèém³gÏΗ™kÒÕc�RC|ìc;‚Ùâ#1@W­]»vUf•û«|<:Ý„±����æ‘õ%Ÿþô§ó(÷^ÆzQ>›ÎcÔÇbж¢åÌòn*5DyDü¥¬ß#üg1V?ϻڛx¬|"a§¡m<ž¾´Ì_zÉ·-Ioä²e˦‘ÎðC=tñþÊT™ò�cFz:l×S¶•¤µÏçížúä?ìŸÛ´iÓ³ýÙ¥õp]�€$  H@½!à#⽡gÜš"�ÿ€¦ÀQ¿»vƒ2³íÝr¼“<�nwÛ1»½–ÀQ·Fqžx¼[�;¢|ùïï;yw¹Ùþ�.¸C�€$  H@5HÀGÄk°Ñ,²$  H@�€$  <µn`ç‘Ú¼Ú£¶]>^;ð°[" H@�€$  H@¨75k`ÏŸ??m‘(=×®�üR=ÙÞ4HËê$  H@�€$  Ô�š};ÿe ë›™¸~Œ%5òè§{챎¯×X;´77 ¨WqÓ ÿ\/7 j±9,³$  H@�€$ �¨Y{Μ9ùôµ=ªí\�7 8òº)_Ñߎ– ²aV7µ"�€$  H@Àjöoº0S‹&�>'ÀÀW®\9’Œwñ…îüEV=¼.ÑçÍP�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$ � ðkèjr�€$  H@�€$Ð35m˜þð‡?ÈfÀg±¿Ùë¢Îb$\J@�€$  H@ýM`¯Çnû»@æ/�}½{Ý™Žïbw&â¶$  H@�€$Ð_4°û‹¼ùvI töš@ûí£~Q¼K”î�€$  H@�€ú�À~�—>,‹YI`HOf¯ \Îb$\J@�€$  H@ýIÀw°û“¾yïE`æÌ™ãð| šˆv¡Ýh¿Ž/¯¿®©©é#GŽ|†Àù¢¸N�€$  H@�@ŸÐÀîSÜf¶?ÉG0#½ƒù>–ýrxWigqG°ÜƲµ«púK@�€$  H@¨�š6°çÎ�;|Ë–-m�¹_rÉ%;1ªZªÉ4ûŽ·µ†vüÞÓ\‰³aõêÕ1®{Õð�€$  H@�€zM f-‘¼«{â‰'¾‡0cÙ8tèÐ{zè¡5ø×´‘íMƒò}Z.å¹è+ H@�€$  =zwà{È�÷¼ç=CG�õ×dÆò-,9iÒ¤7ÜpCó@*gOÊ’›‡vØÇ?qذa/xâ‰'ÖüñÛæÍ›7¨w–KOz‘a%  H@�€$ �þ"P³�ˆŸ~úéC/^|8àŽÆ¸†‘=j̘15;#Ÿ0yòäÜðøêsõÚÜÜ| Yu~;³°:¹ Ö–·Þ�€$  H@¨-þM×j¯Ü4À¸.nL£h5Ó xåR Ц! H@�€$  T›€vµ ›¾$  H@�€$  ؃¢™­¤$  H@�€$  T›@;ƒ]m0¦/ H »øßЧžzêC¼âq.5wí—¿ü固×p�€$  H@õCÀìúiKk" ô�çž{n$Y¿ˆ�žÅrZ¾|ßOE1[ H@�€$ �~$à v?Â7k H v\|ñÅgRÚ×2C}ûu×]—¯ûw8þ^oëŠ+®âËÿ7 :tvKÇNW$  H@�€ gYMS[Q H 70¬�Cç‘ÆÌÎéÄ ~þùç}ôÑ÷L™2åÙÎûÝ–€$  H@œÁíl-% �^ÈÓ·´´ÄrX¹¤n¸á†fTn—~�€$  H@ƒ„€ö ih«)�J¸ä’KÆóô‹16O'Í£Ð&>îõ(ºû+_ùÊSl·–æuÙe—OØá·`Ó¦MKÆŽ›¸³0T§gzbذawe8FjiÜbýÒK/�Dø—ï¥Ì"�'Î3lß³cÇŽ‡¾ñ�ol,ÂeyÁäÿãψ!L¸Ñ‘¬¿ŽåtvßÕÔÔtóµ×^»ŽzÁöiì;�}G±ÌcÝ¢Ûx|9ËŽ´X�IÞ¯!Ì!¬¿†òdwÜo’õÞNz/&íé„yðšk®YòÛÝ¿ûýЇ>ti¼O˜,—±ü5ú EÛô»�C†|ü㟸uëÖÔwÛˆ#d9…ÇÏ_O˜™„ßÂö|ÖN¾«Jã¹. H@�€$пjÝÀÞ¾ˆñf‹ï<öo_2÷ú'ÐðÁ~ðejÇØ;Ã2Æð: ¾Ñ¬�c¹„ý_ÄÈüÁ¿øÅ ŽÝ»w¿œõ‹ÑÍtÐâ^@Ø‘¤³¿á¬Oصk׳Å_ÁpýÆíê".é6à÷¶ÿ€ð¯ ìfübŒÌòòáÇÿÃöj ÍÇŠ8ð£ûv4�ðOã6a�e¹›²-ß¹sçPÒ<¿�²ÿü·°ÜÊö¡¬_Èú=¤ùiÒüù„ FS¶w²ï]hûF²|;áf£!ûŸ§N YݎΡnñÿWÔa`ÃäüßM: ñסœ»a9¿›s5Fÿ#øµÝœØ¶mÛ¡ìKYv/Fô9hÚ�ÿ$–±ï§”ó_(çlë$  H@�€�š}›™°V˜¿�á/Ñ/X_¿|ùòz0²‹›;0ê¡>•êær©ÉL碋.z†âÿ"úËÐ5—ï`9‡nz>ëÂúvöƒú�W\qŶÛÇf Ã),?J¸Ùè?‰“¸ïd&ü­Œ—³¾œåÿ ÌEþð‡ÇµEä§Ý¸þ3öMÇ8þGôNâ¿‹]àw :“õË14§³ls„iÆ?yž…ÞNš�ç}èlŒÕkÆ�¿¿cØŽaý ”2$Üø}�õ“X'å8z=ŽÙõ¿§^g±ïŸIoû>•íˆô>ÏÄŸOÆøÄ"F}GÝ)Wn$\†êc? ÞÆò�l§.ÿÅþ×£?ûÀ>c¿Í±�c?éýå9ý„z]Løw/º ¿7°|3¬Çþ6–¿�€$  H@ýM fg°gÍšÕü­o}ëKà³�Ù¯'y4t÷å—g¬^›®¸iÀÀ9Êà¹^nôªAäÒ+|‰œYXl¾ H,FàçÆ�w†êÆâkÙ{+>øàÌ<ÿáÞ·yóæÌêÞ�Ú}9Fg˯ðÈó×׬Y³±xüÍo~óÊÃ?|%ûþ}ÿý®Oö‡¸‡bÀ¾“õÃñÿ7â}÷óŸÿü¶Ùlm¸òÊ+Wnذa Û1Bï£,ËRŒöff©[Ho û¾‚>CZH~;Y�ËLü70Xÿ‹õ ̶ocÙJ–S‡ÌÊ¿ˆôNâFÁÑÄYÆö3Æþ*üw�îªë¯¿þQüºã^Oœwç>–ÿDú÷ö³ŸÍS7CRÞÅ‹?E9v²ï½èQ ò§˜‘~žsZnD÷+ÔçÚéÓ§¯Lý(çÓ¤óMöÍ$™“a�Çô$M�$  H@�@ÿ¨Ùl�­ï~÷»Ÿ@÷Í™3gþìÙ³7Ưqö.÷Ü4À} å/HéϸiðFÆîÞ¥Zû±åÒÿmHŸ<ƒî%èJó“ù—y>Æ^Q2 Ñm£G�¾‹ý·â7�Œ!ØTìǿ݄áxãÕW_½¾0®³ÿ¦›nÚ�ñøpö£§eV£ò$vŸŠî"Þ­×›Yo;Æs¬§ øßCœÈ'`¬N`9C¼™ý)Û öݹdÉ’'JŒëiÍ;ØÖÏ ­ÙŽgÊtÈ!‡Äp^„ò®uÔázz~�O# T!@IDATq^ŽòèùO¶lÙr_a\'ÑðûÚ×¾¶–Õï äû êó–¥îiØÏŸ9sf›q�íìP·§ØœDœ¶z—Fr]�€$  H Ôì vÿàªn®íøÌÞéJÈ¥F?­bÌM;Lf9oÔ¨Q™ÕÝËÅxä¿¢Ÿ$ÜvNåýå~yÏ:�OgöøÑ£Ž:ªíãañ+u›»™!~‚ôŸÃÿè�7æ£fSYχȰ1[®`f—÷pãGâqxÊÆr"ŠÁšüHªu%Æç3óæÍ+{“ŠG²gæôJ¢¼€8‡¬]»v뇱þ,yöêü¸hÑ¢C™�ÎÖžEK;ù)f›ƒç|Ðl9a^AYRßR·Œ4:ŒëbO¬_·nÝ&¶§gxáïR�€$  H  ôjÙ¿E7w H ¯`ü�Ã�…Áºé°ÃˬoY‡1¸Ã4"‡ñ;š@m6˼ïœGÊË»IŒ´7g3áÆ²>&i$O¶e;_úN°=þMä·Ïå¼+Ý1£Þ(�^çÝý=O… cvü÷ˆ÷qÒÎ�ƒ| í–Ï~+ËÙ,�Þ#Òl𶱆ô6=�¶—uáùÔSOåKìcu8⮥œ¹a±‡c6|7ûv§�‘N�€$  H`ÐÀ�`$0Ð `ÈÅPÎŒéxfycÆh,çòXu>ºµc¹Ã0$þX ÂñØC»2²1$ó�°ÄÍlîólyþ„õ/ònußËadÁ`Þ†�ݹL­ìÛË*篽ŽÃÿ]”)_ÿ¿ä5�í-Û·oßÍÌp _ðžA&½6°Ig-Fvþ†lé¥^eÝÊ•+óEô|…}=åhû`Zÿ–¨Ø.–S¦Li]ºti±éR�€$  H`€ÐÀ a1$0� `ü-ÃÐ{�ÊãÛù¸Vþ‡y—/f³ÿdÂNd¹‚÷ªK ÞÌ4¿”÷¡_H¤GöˆÈFw#³¸§ïâßÌLøj·åÉî£ÙÁK?Ù9^ñžwû{É�w—ÝÆˆ=…|Ndç÷y<»í�ð" ³Ûù‚yn 'Lá}@ËãŽ;nuÊ{ào"�ò^ù¼Òw°‹D¹‘÷ÌÃ4�Ï?[ø»”€$  H@¨=5û‘³ÚCm‰%P»˜Î-߉±x2êùùÈG+­M ]ŒÒü·t¯¾›ðwa4wžy}#qç\vÙe‡—Æe½�¿ØËUŸO�cLÿ2_öNž„ÿ9û_Šú¶÷¼ç=ùXX‡Ã>ˆ~ý3ÆýË:vìg…<ò÷W#I{¯�<Ò}ž/£,{íÄàßIÜaìË_€í÷±ìöúÿ„ð�¢w2£}fqC È˜¿>;’º½‹íi¤}+ÿá�ÇÕu�€$  H@5JÀìm8‹-�¾$�¯móQ°üõ±‹äqêã0jÌúb Ã<ÞÃt6Êû×ß|þùç;ÿmTÞ­Î#ß¿‡{,»‰í“þÕ™çe¿OcøþŠõÖä‰1þ-ÂÏÄÿÃ|ü…ÄûûW°áõ:–¯dßSö1ø"=—�€$  H@›@MØ·ß~ûP¬ ü=O v—™1Øô-�jˆÇÙ¢c�=öšù‹¨ (ú™,3KÝÈ2/ûÊÿ\ÏÿêW¿Züç4^m.äúOf§WaT^‚Ï_±�?´Î_Yµ`\Þ�ßuèí�Åê�!|uüÉeË–}‚Õ ›<Ï&~ÞKÎŒùó,ÿ“å7x?{qÂwÇ'ÿI}5aÿ�åGˆ)ëùBù ’þ2Ë|ÁüìËLu‡#�»Ù+þáù–ùÐØ×xdþ*¶c�ïåòH8õ ÄË{å`y �>Àzž?§Ú�ñÿ;ÞÕþﶯÚ+=$  H@�€jŠÀ~s¨µapÛÀ{—Ç3`͇xœôÑ|0_)΀¿f�7 Ê7�\Êsék_ޝÆ|”‹Ç�á˜;‚ão2†ç&fgW0Ó¼†™íç;ÿ³Îåx�!ûYÂ|“߉Ì>Ãq›¿ýÊWÇŸ¦«¹Y¶¾Ü;ÊÉ“zå8?„°G¢|U| Æú3ù�im,};ç†}èC‡Q¦áãÇ�_SnV8�—S–#(Ó1„OšÏ‘ffÆóî7I7�CÏcì—~¨­áòË/ŸHº' Ã–8O}ôÑÏQÆÝ<î=&ùúùº/ùË™éîp¼=‚™ì ¤y(û§’Ç´’ðy¯}ÿË�þŽ—¾)ß0Ê7 ¶­<>¿.ÿÞ‘ØoWÞÿþ÷çFÀHÜšÒ›�¹) H@�€$ЇjÖÀŽÁõÜsÏýÜ e°ú‰ 6<Àx¯¿åéCž½ÊŠzÔåMƒ^A!²\zK°:ñó>ñèÑ£‡1ûÚŒ�—ì±4ÇÂÀæXý7 Ïk³/äúõëóMóܹsw•—¥q;¯cÈÅØÊÔòÄJ—ùÕ9^Û ”c(_ oêIz){âì¯ÞåòL_ž3gΰ#Ž8¢aÕªU»Ko ” ¯Ÿ$  H@�@m¨ÙGÄóhøêÕ«_Ê€õµ ÆÌпN�:u¯ÕRsÌ›7¯‰ú\L]Únð~è'&Ožœ�KÕô¬|oÛ@.½%X�øíÆa­î±Ã Ï�°¶›a×ÝŽßnT÷Ö°.òË{Þå(<÷·<�8Eší7:?>_ìv) H@�€$PãjÚ ­qö{?7 p¹iðv¾1�“ÖúMƒ½*yr9hF‘€$  H@�€úœ€vŸ#7C H@�€$  H@¨GØõتÖI�€$  H@�€úœ€vŸ#7C H@�€$  H@¨G5û‘³zl ë$�z$À_QÝ@½ng¹ºëg�$  H@�€$Pp» áR¨ ¾º½vÊ”)O\uÕU몒�‰J@�€$  H`€p{€4„Å�@håïµÊþGv×ÙªI@�€$  BÎ`ÂF·Ê�€$  H@�€$PyØ•gjŠ�€$  H@�€$0 Ôú#âÍ´ÙnÔ€k„íg•%  H@�€$  H`€¨Y{Ó¦M­ÕK[[[�åPÖ7ãêá=Oo”?8äRž‹¾�€$  H@�À!P³öwÜÑrâ‰'~ ûö¡C‡6ìܹsÉ»ßýîÌf׬«ã›½j¹ô Ÿ‘%  H@�€$ �>"ÐÐGù˜M7ð¥åFnœÝÒÒrXûMƒyÜ4X5Ø—K7:�A$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H _ äÝx>2ØH!ü–C¿¶„™K@�€$  ŒJKX Ô�¹sçNjjj±qãÆ5—^zéŠ_“Wc­`q%  H@�€�Ì>é$  ôˆ@f¯‰pVssó;FŽyƶç’4°$  H@�@=¨ÙÿÁNcäñÔn¸¡mþ‚ .há﬜A«Ç^j��N8a"…z:…Yì%ãÆ�[ÍúVä1�$  H@�Àà$P³³N× דi¶c¢o¼qTüj½sÓ€ÙÀ¦¨êS©ö�K¥Hö>�böš”NCÇscëÍëׯw»÷hMA�€$  H Æ Ôì 6Æu#î÷1¼Ž¥ švíÚõïóæÍ{’õݵÚ&1¨ÛoŒJ¸i°¿mƒ}f^.«G³×´ËúfcKKË[˜Å¾yìØ±«(©³Ø«¹,�$  H@�@¨Ùì3fd`ÿvù€þ�wA§oÛ¶­©ÙU<«â¦FËÇÐÜ4˜ÆMƒš®S% É¥+“Féì5}t4©²h˜ÊòMÎbW†±©H@�€$  Ô.�š5°ky×%¯Ç›]×¶û{äÒ}VÕY:{M^ç�öYì“x{$þ5ÿªFµ9š¾$  H@�@}è ×gõ¬•$P)åf¯‹´�Å.H¸”€$  H@Ì4°së[w ô€@W³×EÎb$\J@�€$  V؃µå­·z@`_³×E2Îb$\J@�€$  V؃µå­·z@`³×ERÎb$\J@�€$  F؃±Õ­³z@ ;³×ErÎb$\J@�€$  F؃±Õ­³z@ »³×E’Îb$\J@�€$  6؃­Å­¯z@ '³×E²Îb$j{ÙÚÚÚpÙe—s饗^yñÅŸ_Ûµ±ô�€$  H oh`÷ gs‘@M˜9sæ8 þ4íB;ÚÕ²p¥þmû1Î^×ÔÔtܨQ£F�\Ö�¿þë¿nÚ½{÷ iË?å¦É;çÎ�ÛT[5°´�€$  H ï íû,+šc+©e ß 0ë: H ‚0’�À¸ÚÎáuÉVë/APÖFëQ©Ñ=„8ˆ;‚å6–Ÿhîƒüà!ÍÍͯ }¶\wÝuw”–ï‘Gi3fÌ2ÚïÚÆÆÆÇ,X0 Ûp_u(­�ë�€$  H /Ô¬�=þü!&LXÇÀpÀa;6oÞ< €=lÈÔÁ›{C“ËÞLªîƒaµ†cìshx‘ëCyÏú³w1²‡æZ–÷¢�E˜, ·aõêÕ1®K½]@vîÜyøÐ¡C/¦H«Ðö 7ÜÐÌ+O¬]»öÓ›6mÚÉú7PJ5öU‡�RFË! H@�Àà!P³6Æu ÷›hª,ì?Í Ë€v·;ÕñMƒî"(N.e±ô‰çœ9sV“QÔá¾ð…/ ãø[ÆqwDnn±\À,èý„ÝÃÀîˆàÊ€%0lذá´áQ]£z7û6vµ øï¯¡Œ–A�€$ �ÁC f lóÍ4ÓuõÔTõxÓ í#—JP¬\õØþð‡‡1+8š™%´˜˜o|-½æšk–²�'(:ÜÇ>ö±1;vì˜ÉÍ…íGuÔã‹/žÀLð)«G&ËgIç©mÛ¶-ÊLpGÄ’• .¸`øÁ|a“硤µ�õ§FŒ±ð‹_ü→ C0tŸ~úéIìŸFØ%•;¹©q*ëGnë¿øÚ×¾¶öŠ+®±uëÖ©„›ŽòÞüHÒ}.7A®½öÚ§’f‘ïWÏæ±„Çþ—\rɬìg}ãøñãýÌg>³í /K^/>|ø:Ê´(ûKÝŸþ韎f†û…Ä9 �#­ ,—tÐA‹>ûÙÏîa˜‡1<�ܾ}û$Ò{‚üsCô$Ê>ƒ8�<…´’ø�~ùË_^YšG¹õîÔaäÈ‘KàŸ¶�–~å+_É,ýŽ6EYgÐv£wíÚµˆGâiÖÞµ+4P×±´Íñ¤y$õ‰ß³Ôs eXL]÷èK{È H@�€jž€ÏnÖ|Z H 70,Çc`�ƒô ¼i1ö’ëyJ&3õ7c,ýãèù"Þû}áÿ˜} ÷üßÅú),cLåCo‰¿¿[1°~Œ‘þlü ×þÞð›ØžM˜É„meƒs+º�ü¾ýÕ¯~õ‘"| gÓ>“íKw#Á�aù:¶Ec¸þ/üv/¤;Mb~³È7* Ì·0^o§¾1ºÏÂïn š‰¶£GQ ìÇ0òÿæßÿýßWðñðú3ü~EÜ«²?.Æ2Æcâ½ ½%�”?ynf9Ÿü¾Gœ‡Xo3(‰3fç£×³ï»1@I÷åì…ÆoÛóáõ xÍǯK×�:�ο’Çiè]äw#eùbçI'uHýv§ÎÔiToÚµý¦ÉñÔå�¤{:JÈ –füž!Ÿñá¿›?ÿùχ‘N�€$ �:$P|´¨«f•$  ì›À{ßûÞÌ<¿ #ìã?‡ú6 ¡»X�õ�,3Ëû:– /~ñ‹|à�òÈô�SO=õh¼>œU–™�}ë?'î�¬ßÇr Ûǰþ&ÖG÷!âÆˆãšü.`߇P#úÞw³|5~Ëi§�vÚ£÷ß>7„ÿ"Ï£øyçýãh"ë§î! Çylß3zôèG0§³~9ûângÿ¯ØŽÑ< ½M=ùä“ç3³›Ùñ<ž¬ë ;�åZô]´�4…É#÷Þ{ïvÊ},û?FØõ”ÿ'ìo›_³fÍ‹ðÿ3üÏÅëIÖoC¿b{ Û£ÑëYŸþÒ—¾tù}÷Ý÷ ÛCHk4Æë™øç&Af–§³¼›å�äù8Ëé¹É1æŒ3Îø¯†´Ý¨Ào/Çþ”}Ÿu í‡É/7 .Oš¯|å+oN�ŠÄrÓ‚÷·_Åvn”ÄWÚ‹¢¸”€$  H ŽÔì#âuÔVEè™…ÅÀŠ¡ƒ*³§ËãпàQèÌ"ÉcàábÐ>ÈÍŒƸξ”8引8cY所î¸}Ö�÷©óXö�I3ßH>Å5¯ƒ2~g³)ûo/2c½ÇíJÜês4ËÙèŒíÿH{iÂd;ûÍö÷Ñ òžUìs) H@�@}p»¾ÚÓÚH@Ý$c—ÔhÖ9R¶™=ˆ8y|ûxÒŸÂrîpvMGÃHs,Ëv7�D—¼ÿýï?¿“ð;œòÜD=2ƒß–Û=nW¸<ÊßD†Kžhx€›çÒ¶mé?Ô/«ÓIùžXø»”€$  H ¾h`×W{Z H ›˜EEÐÌbná«Ù³��£c„oÃ`\�ÿÉ­G°l3°1’vc¤­eÆx]ç8Åvâ²ãîe„M^yŒ;Ëqlçý콌zöÅÀ<ˆp+ÐA¬w8¶w¢¶÷²;‚øÇ±¼€í½þi‡ô¥¶§ö  ‡$  H@5O Ö ìÒÁbÇ©æ[Å H@U'€1ƒn+FOì¹Û;ÊeÊ£ÍM1Æ1œb –κ6â7"ï9·¿¼WtŒË¶´mÅÀk3" ¸Ž´~Ȳ4½ŽøìBÜ<>½°Ã“ÒÈy®x,¼cNÃìo¾„þA<ÿë,<_>ߎAûÒ;ÿ^�'y¬~wŒ`ÒJZ{ÿ…ùíJ>ÞÖÆŒ¼÷¨#þ»QÛ£á¥qN<ñÄÖ§žzªWå+M¯XÇø]K™ï`{:‡¿ûÖêÕ«§R†3Ð}´Iž0(u=n×.;Hóatsi‚¥ë´Cš±í&M©¿ë�€$  Ô�š6°çÎ�›Yš&– Ì@m>ûì³ÛÞ;¬ñ¦ñ¦Aù”Ky.ýå[óí�á¼ cçIŒ�Wnܸ1�ŠßÞfÞÙÅè; ƒéxö­ Nf —óç‘ê'³¼¯ð,Y6ðú!<*ýâoÄÒ^„±™GÓçÂ=Σɿ* _¬6ð®wcÞg.<º±œ„qý¦„#¯š6mÚ=™½Í6Ë¡Ôá…¬æì^9}ÞÎÇÛ–Sþ¡§äã]y¿¸s¢ä—ú½„0™Á¢óþ¾ÜΣú”óIòL�¸nݺWÓyD;�Îÿ¬xœõÂõ¸]y<¼� ä}ûm\“~ÐÅM—iÛ¢\.%  H@¨Å_j ¨{1_|Îa0ùn¸ïaFb wE+Ü3§¾ÝÊM4ö»ßýî¸Ûo¿½¦o€T’œ\*I³÷iÕC{ð˜ðZŒ¡;¡1£÷]ayü»Ô5ðÎnÞc>Ÿp£1Ê~Úù½aü§¡K˜ÅÎcß{8ü&2;£7ïæþ|Æ Ï%OÒ¹“4G‘ç…¼§;©4R>¢ö¡}h&_⾜/`¿²tß¾ÖIk4iæ#[›cÈÆuâðòá,ò8tÞÁ.½12„ò3â1¾÷ØÇö^.F?y=ÅŽü½Öèõô…=λ1ºÉ'_P ûŸà¦Ä],«æºS˜¯‚ÏMh"忈œMù–ã[¹‚±oêv»† åXFœ|Øî5ÜT9·ýÕ‘ü…^86o;vìÅ|Y=7 t�€$  Ô!�š5àÎ;ï¼&ŽĀ浴Kþ#v6ƒÒTÖå{á�Ê1„²m&�¥øŸÉòý]tÑOãÇöªòꔑõ¼»�÷»KÝvöåKèÓaqù.C#ˆó4³ë_E/��Y|Êø5üþ’¸róÍ7Oæcnóñ{ž2‚ò×_oG£Hës“'O^T¿ ëû­uÙÌ ‹¨×3äŸ6Í£óßáïÌ–—)Ï�´ëžVxÃúzÒþiþ¼ƒ~$m›¬mÁ*ËÓñ#í³ý L¾zI@�€$PjÖÀ®ö{U¡oìUÉð�Ë@«b”zj�‹?WcülÆøš…qx:3‘k0’ZXÏÌofcob9—Ùëe¥XÙŸ_ X~‡å[I#†öZ¶wb@å±ò1øgFó[×\sÍ#| ­-úÚµkWò˜õÕläÝäsÉ73Ákˆ›G–“çVòœK9~Íz·ûsõs |4ºœõü¿sÞ•Î{Òù�WfoßÊò`ÔáÈc5³êùk¬ÿ�ç_±|†²¯¦.Ÿe»¬��Y| ÇŸSî%Í·ç£ÄÉÇÛþ`¶e=> ß¹!“›UsݬCþÎ+�¶ß‚þ7e{Ží›Ê•�}Ô®í\î„Ë¿‘Ç;Pþóz9l¶‘fžTÈ;éy\þëhCÕ€˜°$  H@ýJ@»_ñ›¹$П0Švad=²råÊÏ`àÆ~Ò$–M`óY_ÄÌòÝÈO—)g¯~£éë„å�ã²ui†²ž›`„.dßSlgV»ÃwÜqxè¤ÝˆçLâd–ýÊЖ7 –‘ç?±\Ò‰•|9ýÊ+¯ü6�½?ÆæË‰—/‹�c}!˧Ù~ˆ'Šæö³Ÿíøp†üvÿ‚}[óxizY§Z™ ‚üþŽýåÞMï¥m{u("�5êyþbì¡ä�ß#”§Ü{ó ~@횈á«7pÓ&õË�“¼v�-¿�éSÔë~ÞY˜íä¡“€$  H  ì÷�»�Zç{ï½wÛ)ßkQñˆøm³gÏîÐ Ô²wU®z¬SWu퉿\zB«úaë¹=òEpŽÃjÂx\ßþX÷^PyœúÅKWa¬-Ç`zwð_È#Ö¯_ÈA4k}¹�í•P{¼çŸ~é5Ϙ1c}¹YÕrñÊùQž†Ë/¿|ù�¥»º›^ÊÎ,ø!¤¹‹:¤Þ™Åí–£¼�<=~ ì–o|ã™Éîsru ÍÆÃøRý!åû{ÚçK�+XÉv žV³iÓ¦ƒÀ²¦Û:çç¶$  H@õGÀìúkSk$  �Ìh5ï$÷صÏÖæß¹öxÏõ(R�1 cØæÑó¨Ûî@Ëž ÚoĨ.ûHy· ÑË€û«l¦`\¿�l–q3àgÝÍnév•N;—�ì�t�€$  y,P' H@¨[ù‚7ök¨à±,o=ꨣò%t�$  H@¨8g°+ŽÔ%  H ¿ ðžûðñãÇÏäýóWR–|M=_Š_Œ¾Õ>»ÜßE4 H@�€ê�€3ØuبVI�À`'À—ÚG`\ŸÂcá„Å,”�]͇Èò%o�$  H@¨ g°«‚ÕD%  H ? ðó�|`ìa ì/2k½Ž/¡?†_¾ìÞç`ëOæ- H@�@ßÐÀî[Þæ& Ô>’õ � ãÍX Ðölÿ8Ùo(^Ô-g»v “�$  H@ØßwI@(G€ÿÅ~îè£�þúôéÓPn¿~µIÀv­Ív³Ô�€$ ��D ¦g°yÔo³HÛXîjóÂ… [Ë" Ô/�V>”•󎮾Ø®õÕžÖF�€$ÐçjÖÀ^¼xq ´~‰q�ÿ¬mÂ={òÉ'7÷9Á gèMƒò@åRžKùÚýEÞ|%  H@�€2�š5°ç̙Ӊ!±qãÆ5—^zévµ–ìvU�€$  H@Ý&Ðöîn‡6 $ �:"�ÙkªsVssó;FŽyƶçÄ:j_«" H@�€úš@ÍþMW_ƒ2? H þœp ©ÕÛÐ)Ìb/7nÜjÖ·"g±� “€$  H@è�šž­É_]wÝu#£öw({V{CK@ƒ–@1{ €ÓÐñ o^¿~½³Øƒ¶GXq H@�€$Ð{5;ƒÝþa¢—�=z"ã†o~ó›÷à·µôKÿ¥�›[¶li»ñqÉ%—ì¤j5]ŸJ‘”K¥HV&�zh�böš›sS8Î[ZZÞÂ,öÍcÇŽ]%g±+ÓULE�€$  *5;ƒ=yòdÆÂMWÐZÿŠ>Ç:ãåjö†Az]ÉMƒ7Œ3æ�Ü4˜¿ìÌN.«õë¡=Ú�«³ {Æõh–,¦²|“³Ø«¿Y H@�€$PKjÖx;ýôÓ‡0ã4 ØG2uTccãHŒÒšþ*z=Þ4¨ÄÁ —JP¬\õÐ¥³×�é8¶ÏbŸÄ»Ø#ñ¯éóIåZÜ”$  H@�€ºK c`Ù݆«�z¼iP Zr©ÅÊ¥QëíQnöº ã,vAÂ¥$  H@�À�ÐÀ>jÆ‘€j–@W³×E…œÅ.H¸”€$  H@è) ìž3¼$P³ö5{]TÊYì‚„K H@�€$ �žÐÀî)1ÃK@5K`³×EÅœÅ.H¸”€$  H@è  ìžÐ2¬$P³º3{]TÎYì‚„K H@�€$ �žÐÀî -ÃJ@5K »³×E�Å.H¸”€$  H@è. ìî’2œ$P³z2{]TÒYì‚„K H@�€$ �îÐÀî.)ÃI@5K`æÌ™ã(ü[ÐD´ íhW Ë•ú·íomm}]SSÓq£F�Qr) H@�€$ �® íj‡þ�€ê…FòÌHoÇ`¾�:5µ×«�åKДõ‡ÑzTjt!ÎâŽ`¹�e+ûu�€$  H@(K Ö ìbƉ×%[ö—­­ž�À $ÐØØ¸ãøshx€õ¡ÍÍÍW±#;çÂ/î×,w¢G¸ «W¯ŽqÝáçŠ$  H@�€Ê¨Y{Ó¦M™IzŰŠ[·|ùòz0²½iP®§þî±^o¦”çÓ×¾5ÕOçÌ™³@Q‡»÷Þ{‡-^¼xÛÑ0f¨Ÿ<è ƒ˜={v×I@�€$  H ÇjÖÀž5kVó÷¾÷½/05šY§]üáx÷å—_Þc%Bß4èb¹ô _Å#×K{ÔK=*ÞÀ&( H@�€$pÀ|æñ€ÑU>"3h Ü4˜QzÓàüóÏßÌ£©ƒú½O¹T¾¯õ&Åzi�z©GoÚÒ¸�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€ê›@MÿM×í·ß>tõêÕ�i¢ ìþä'?ÙRßÍeí$  H@�€$  H` ¨Y;ÿaûíoû„–––±¬7îÞ½{Á“O>¹¡Ö�lo”?TäRžKùÖK{ÔK=ú«˜¯$  H@�Àžšöܬ�­Y³f ݺuëŸRâ9 ç >üþ¦¦¦çn¼ñÆš�ÅÎMƒùóçÏòtÔ„ 6�rÊ);çÍ›×Z;-Sù’Ê¥òL{“b½´G½Ô£7mi\ H@�€$ �ÊZÙäú.µƒ>¸�ÇÃO#Ç×¢aÌdÿóÔ©SÛï»RT6' é&ý—�êÉÜ4h9rä_Lž<ù¶kö¦A%É¥+—F½´G½Ô£r-kJ�€$  H@½%PÓio+?Ðâç¦vnœƒ^ÇMƒCký¦A%Ë¥+—F½´G½Ô£r-kJ�€$  H@½% �Ý[‚Æ—€$  H@�€$  @@Ûn  H@�€$  H@¨ ì @4 H@�€$  H@�€¶}@�€$  H@�€$PØ€h�€$  H@�€$  lû€$  H@�€$  H 4°+Ñ$$  H@�€$  H@Øö H@�€$  H@�@ ­@ý™D3™ïNZú³ æ- H@�€$  H@ƒ›@ÍØ›6mj¥é–  h(öf\üjÝyÓ | Ê¥<—þò­—ö¨—zôW?0_ H@�€$ �5k`ßqÇ-ÇüR—[1®X.¾à‚ Úf³KêWS«u|Ó Wí —^á«xäzi�z©GÅØ%  H@�€˜@ÍØŸüä'óHøí\ó±oT³\*A±riÔK{ÔK=*ײ¦$ H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H Þäÿ£kÖµ¶¶6Þpà muà?°[ø;ìÖš­Œ—€$  H@�€$ �š&P³ÿƒ�qÝð�ï|gJccã(ÔpýõׯÀok­ÙÞ4(<É¥<—þò­—ö¨—zôW?0_ H@�€$ �= Ô¬�ÍÌ5vuãÛ ÛÜÜÜ4vìØÏÏ›7ï ª·{Ï*ÖÎu©Ë›½m¹ô–`eã×K{ÔK=*Ûº¦& H@�€$Ð5k`Ϙ1£qñâÅo¥ò¯EÃvíÚõ£mÛ¶-b½f ìz¼iЛÎYÄ•KAb`,ë¥=ꥣWX H@�€$ �hÃÀ!�›---oefí£èãÜ4˜ÆMƒ¦�SÂþ)‰\ú‡{W¹ÖK{ÔK=ºj'ý%  H@�€úž€vß37G H@�€$  H@¨CØuبVI�€$  H@�€úž€vß37G H@�€$  H@¨CØuبVI�€$  H@�€úž€vß37G H@�€$  H@¨CØuبVI�€$  H@�€úž€vß37G H@�€$  H@¨CØuبVI�€$  H@�€úž@­Ø­ k‰Zq}�Ï%  H@�€$  H@¿%P³öüùó‡`S¯¥Ï444¬d}ÇæÍ›ëÁÈö¦Aù£S.å¹ô—o½´G½Ô£¿ú�ùJ@�€$  ”Z²^S«&LhÁ°þQKKËÃ,Ñò d6»f]nŒ?~-uÉMƒ¡Ô­^nôªMäÒ+|�\/íQ/õ¨x› $  H@�À¨Y{Μ9ÍÔúk\ó±oT³\*A±riÔK{ÔK=*ײ¦$ H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H Þ4Ôx…Z[[ÛªÀÿFÿv¥Æ+dñ%  H@�€$  H 6 Ô´�ýýïÿদ¦¶ÿò^±bÅæË/¿|Wm6Ã¥ö¦Á8:6äÒ�b@¬ÔK{ÔK=D§°�€$  H`°¨Yû“ŸüdãI'�t>3ØS˜½nD?lnn~zΜ9͵ܨuzÓ ×M"—^#¬hõÒõR�Š6®‰I@�€$  0�š5°ï½÷Þa‹/¾™š¿ ÃÀž=zôèÛfÏž½ã€iôsÄz½iÐ[¬ré-ÁÊÆ¯—ö¨—zT¶uMM�€$  H 7Ú¯îMÆ­�óÎ;¯‰›W�âk™™ÏMƒEcÆŒYÅvMÏÊ÷–�\zK°²ñë¥=꥕m]S“€$  H@è �ÆÞD6®$  H@�€$  H@¿% �mO�€$  H@�€$  T€€v š„$  H@�€$  H@Û>  H@�€$  H@¨ ì @4 H@�€$  H@�€¶}@�€$  H@�€$PØ€h�€$  H@�€$  lû€$  H@�€$  H †V �þLbGkkë¶ÆÆÆ]¢yáÂ…ýYó–€$  H@�€$ �AL f ìÅ‹·444ü=×ÒÒ2CûÙ“O>¹¹ÚÒ›åQ.å¹ô—o½´G½Ô£¿ú�ùJ@�€$  ”¨Y{Μ9ÍsçÎýÔ¤I“RŸY³f5cl·–Ô­æVëø¦A¯ÚB.½ÂWñÈõÒõR�Š7° J@�€$  0�6ãô€c±â¸iÐTO7 *H.•"Y™tê¥=꥕iUS‘€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@¨_ •¬Zë¬!C‡l2|Èæ!MCš‡ô,í¦!­meéi¼ÞT 7yn²{È«‡ìh¸�šöÐíÅ©s9ö·Ý‹¼»*ê^eê*`Oü;×£'q» [+iV¡�ºBRêÀíX ®¥+]?мzÀ´K=É»«°=(Giµ]—€$  H@¨=3‚÷ãõCŽÂ¬>uHã�Ã1—÷¼Öw¯à6ÂCò,[zR™ p:༻*gÊÔUÒƒÕ¿âmÔ�uÞŽÝfZeÝ.GwÚÌ0�€$  H@õC`hE«Ò4d4†õ4ÌÍiÚ•M»¢­Hb�Cv ybÈÔô†¦×{NžwWEí}™ºJy°úW¾�ºC²¾Û±ûL«Ë¡ûåèN›F�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@�€$  H@U'ÐPõú.ƒÔex»š:eÛÊöN´e]'�JHÿ‹Ò¿ìcN×ãøÀÙ ¦˜oƒ©µë³®öáúl×ÁR«Zê¿)ëP4¢}Ù¹�vãû K�*B ®\žIè%èEè`Ôˆ ãútÚ„4€€ «�ÜÐ9†v ­hÚÒ¾mD7œÇq7 dˆÇ›� Ö ؇k½wùk­ÿŽ¥¹NjWl…Rû …íèh ÒÈ‚®÷êÅÀŠ· ?C1rJ6Û ê;Y.G# Ô¹‹±6�CÃPŒÞÜ\Ù…*mðN!ÍKÑ{Qò}=„~ˆîB¹3ªÛ?�z=ŽódM.ð9/¥Öã“4o4¬NÝ$à5£›  6 ÔRÿÍu÷èÿ¢(ãÁÎn)/^�6£zpÕº&çæÊhtʸ:IÍH׉@½Ø¼æÀ9Å *çâŸÇCÒétõO ÿ™èRt$ºåä¹ÅÈ®”ËIùeè�èX”“ùtôB”“Ï}HÝpõxçBtJÿÈù'}ð×h'ª'çñVO­i]ªIÀkF5éšvµ ÔZÿ�£Ð44•³â?eüV/®Z×äŒÓÞŠÞŒþý=…*9®&¹Úwõb`o )žDyÌ#�œze0›A¹ƒ o]�8Œú½�ƒrs%'Ï…hªÔ‰ }ëè<4ÇSf,cXEõt¦:Uuõvç7 ý:=ˆÒ7êÑy¼Õc«Z§JðšQi¢¦×—j±ÿæu½åh1Jù3ƒÝ„bxgÌ¿¸bùÛ­Úÿ­æ59¯á¾½ ebé*¬Rck’ª}Wµ^“<¢pz�GÐf3‘nðˆA=ÅÈI?Ÿ„¦·¯³¨ˆË�¼W£sQúYN.¥'l6u= POÇqúCÎ?ˆrÊS 1°Eõxòx£auدûäîM ûo DïAŠòvÆ‚G¢³ÐLTî‘q¼kÞUëšœ‰�ûÑã(ãß·£0¾ eËWp�W/vÞ©]ƒî@w£CQÏ}9ÒÀ t¹C™gqW2Û•4~“^NÖyT&w סµèXT¯³”T­ª®^Žãô³—¢�£×yšæ^ôC´¥žõæ<Þê­E­O¥ xͨ4QÓëKµÜ7*¯få&wêq š‚f Z3°3¦í΢Z×äÓ PÆ3' Lh¾å¿ÿŠV „ô®¿ ìtèÌ,fàc$!/É—~�¹SU”7û’ÒÏñ•¾•})gÂ&ÏÎa‹s@êº?—¸3P.8¯ByMà4=„’ogWÍv+—WêèñÖ™LÏ·û²Ýz^º¾�‘¾ß—Ç\q>*wíÌu"׌œ›ºsܬåո&ÄkF*Ý×íÖz€­ô5ûou;@ÎÏ9–s½Ëõ=ç�\sNÈø<çˆbÌÂj·]¥Û­èw±!r.Kú)oÊ–±Jq.cµí’²?:±?ö5–bwÕÜó¤üKtš�rn{3Zˆþe–û@Ø­~\ª/]:|žÝÏ]�3Ññè”GÒaÒ8i´_ âb4�õ¸4ØoУ X{zÑ$Ê>]:yòL¹NBéìX'χыћб(Fï�è{(ô³Ñ,4 å`HøQÂt5c•(,^„2?…Å(ó9ôJ�£SÑãúëè6”D¥]_qH>9ñ‰R·ª'¢É(\2À Ëô‹Uè~t zåà.wb Ó‘(éŽk_&Ÿ¸,“æ!¨.¬Ó†a™üºsRHú§¡óQòYŒnBI'êWív ×ôÑW¢cP$Ï5èô+”ã%~éïFiϱ(¼Ã6ÇÒ�PÚ´;œ vÀ.†íÉè tÊ…¶p1òsLå\²å<˜ºå8,­[ʘ‹XŽçÔo9Úßy'ýaJßÈy-ýô1”¾[î¢^}qÞI>i³#Ñ©Èã ½p}Õn½(bŸGí«c.çùäu,z9š‰¦¡\;rœg|ðÊq{7ZŠrÍ.wÍÀ»Ã%Ýj]“sì ´kFQñ¾j·"¿�ºì+ößêö€\ÏsÎ8d:š�bG¬G‹Ð“(Çyé8�Íýºj´[Êš1iÆ*ç¢QÎc)Æ’ë.G÷f‰ÒÁ‹ƒ/äb”‹ãa(áÒ¸ÅM‚f/FL§.Ù—ƒ%Jçø6JÇ(u#Ø8…ÅèX”ƒ"ñÓ±âRßW¢·¡µ(ù†ßŽöítàä]i×W æå('�°Š_êöQXNG9Ñœ…b´\ß®0ÉþÂ%Þ4”6œ‰f´/ žék¯@ŠJ¹%íUè×h>ÚŠJÓes—¾˜¶›�’OúiŒ¯[Púo¹j·[ئ­Òi«pˆË 7£2˜Mß çsÐ'P Ç´c†é/Ñãè>”“d5Ý Iü ô‡ƒPQ^VÛÎ5)÷\ôhú0ú}TZ76ÛÂ>Íò:ôE”|W.u=%�É(ÛÏ¢«©wúZgWív+ò˱åñVÐèý²¯Ú­÷%í»úâ˜K?>½ ÍAÉs$ʵs(Š;åü’sùoÐ7ÑOÑ3¨Ü1ˆwÛµ'çõj\“sîIÚíšA‘Ú\öõ¹²=ëµè #¨±ý·:Ížã,ã�´ã»PŽå‰(çêŒ3¦Þ†A1XE¹FwÇU£ÝR¦ ‹QÆùG œËâ_”«…õ— œïâR¿Œ¥£Ø›Páoʘ§šcà"¿-¬„åCè0”²¿½=†V£”µ§.õˆ­“qÔùè(´ý} eü˜v𮸠U» é,éHAï@iŒ\ãÒéD982ÎÉçp¿t¦¢£±ÚöÎD`§*í’WÅlçîQáNb%lX¥ŒÉ;Ë„{Jù‹º°Ú¶?aOFo@w t†Ô'.a_Š®@³PN¥í�pI3'…(7Â#.yç@OÞÕ`@²mÌû‚CòÈÁFa¦©{Xe`”�Pê˜ú§mrð†éh1ú *5”“FNRGÓð+؆[Úò8TêÂ:yýý-ºíËøKy^�Rîôל\nD+QÑÆ¬ö¹«vÿ=˜MCa›¶(\ê&i¿¸0™‚rñ*=ŽØìxÅ¢¿j¹ä} *úBç|Â+'ñ,Ç¢º–ëW@IDATruûÍÉoÂ}é·¾{ÿ&�Û¹—þ–¾µ݉6µo³ØÃU»ÝŠ>éñ¶ö^oôU»õº }˜@µ�¹\;OG€ÎFű�ó÷ŽvåÜ’ó~ÎC9/½ÍD§ Ï¢�ͨÔUûšI¦šÇ\Î!¹v¾e,‘kgŽÏµèI”qAÖs^:�‚r>OŸÏuá|”sØ—ÐjT J‹t/Ä/ךJ_““þ@½fP´6WÍv+ò¨…e59ýÌþ[�ž�ëÛèŠöåA,‹kxÆf¹æç˜Ïù :uÇU«Ý’÷Lô”ñIÆô»QÆ_EóÑ&4 ��Þ€¦£Œsãrî+Îamüd_Îu‡¢rõ �Œm¢r.㺜3S–]å”ñ[ƒßƒèY”qOâ¦^)ó}¨°Úm7•�¯E‡£¢¬I7韌^‚2® ¯íúÂÀN2X:l:FŒÉ›ÐWÑã(Fæ‹ÐûQ:Ý!("nú!úz倩´Kc݉þ]ŽR†ˆq� O¡E(õøJcÇ¥ßF×¢ ÿ‰ND©w ätötޏÔ)Êï¡Щ_3Z‰nDsÑ>‰w::½�C ßù Â«¢®/8¤À©sÚt$JÝîG·£0ÞŒRŽp �ìÏà'aÃôHþëPúM\ÖF ŸV ªœds€†[Âå$»µ}�E‡‹ñóZˆöubI›ÌB¯BI÷^ô´õ·«v»­ ‚W¡GQúÿËQtvayÊ ÷bô~”6ëk÷$þ=º ¥¯Féé1¬s<ÿå"–›[ÿŽžFŒ^ˆrü®B7´+ç€ô�®\úêÑèT”|âÖ h#jEå\µÛ­Ès%+o�Þ/ûªÝz_Ò¾K¡šÇÜDªñFT\;s<-E×£\s¬æZšs}Îû§£¢³QÎ?SÑ[ÑèFTŒ!ª}MÈ× 0´¹j¶[‘G-,«ÉÁþ[½�c~ú}[#Çü2Y‚î@¹æçü�ýç¢i¨Üøï=\µÚ-ã…I(åÈX#.cØyèû¨8Ÿ¥Oþ7ú1z/Êù,6Ô"”sX΃…ë‹1p‘W±Ìup) ߌÂ>缓ۗ±Ý2æê‰IàŒùèԥM³o,Êú€wEÃV³ Hü4”»E‡Î]�yèŸPìÙNGye0°9XF£¸ l¢AÙ_-·™„Ó¡£](vʧP:y:ý‹P:v9.~w¡ ¤'å<…mÚ —"î…(ùÃPá—ø_C_BÏ ¤ƒ&7RçÔÿ (�.z;êi§%J·]µ9¤ 1jæ¡_£° çÔ-ý Ü¢Ô1†ZŒ›³ÐH”ë`”ß2TpØÄú¡èÇ¢PXçfÇ0”6ûº%ïÂ%ÏäÖ+QÊQÎ¥Œ§¢¤™>�8·¡ä—ùpÔß®šíVpJ[<�NG]Õ9åH¿Í16ýár¥œ7¡ô•“Ð$”ã®(wúAúO”þ“:ŽG9ÿdý7è?ÐC(ç¨}¹ÄË9.ËâØÎÅ%eHZûrÕl·"ßÔuòx+ˆô~ÙíÖûRö] Õ<ærí<×Îܼúú*ʵ²ô¼�ãîg(ÇuŽù—¢\^€^…nE¹Ä%ݜӋtãW©kòPÒè׌Էší–ôkÅU“ƒý·z½ ãÂŒGÞŒ ã+Çþ£è*”óDÎ q7¢\ÿel˜ct_®Zí–|G¡œ— cq4ëÇ¡”+cˆŒûÓ's®º-DßA‡ ûQÆ,¥.ÛÕ—æUºžsñ(e�Ëøé”ómÆèû;d·ž­%(mZŒÕ çøÕ(öØþÆTé·¿ÎU‰Ž#‘£Q‚Âú-hбX¸ Æ3˜½Å *îDÅè ܾ€š|¢Â¥Ó>�²Lùr ¦Ã§L90žGé Ù—b-*âçà)ê�Nw8š�â—ú<€n@+Ú·Y´¹¤±ý÷o7Û:í«YÏ †œ8ŠÎܾ»â‹jq( ~©C4ƒŽBèÄH ¯ `Ã7ÛÅIˆÕ¶¾T„)úDN¨i›Ñ#h%zz ï´OŒèï¢À¥.iDI£+—>œøñí`Yœ¸S—r.'Éœ4S—œdRŸ}åÁî^»j¶[êNEÿÞWa&a»b³¯¸•ÚÖ9ç£èU('ì´å+ÑÏQÎ?)ãT”ã+ç«ôµUèh!êÎâPÂÍD¥„¿¹øt—Wi¸J�wȾͥŽoí0*¸H›U³Ý*XÔ>IªÇ\Ο¹.”^;3ÐZ„r¼Ž@å\Ží„9å�°ÓQnÐæ�ós5¯É9ÏÔÂ5ƒb¶]—úê\™üª³ÿþ®ej¥ÿfü˜q^ ÏÓqëЭ(u®åÅ8$côŸ¢i(õKÜ®\µÎ;)KÆ£9ÞRΉ(yÅVx=ÊùjI»–·/Ÿ`ù,Êø6uÈX2×óR—¾»%L5ÆÀ¥y•®—ç㡌¡º3~*Mo)?@Oe¼�ó{ê–v¼ýõ4M¢ô½ë {,Õ:•æ•N• _9H¹(Æ8Jg:•Æc³Ï]„tæ4pŒRe ž:¤ƒe!VÛ\öGqcP8wü2ˆ~=�bŒ”sÉÿ^ôÿЯP ìÛQòìKW)E™cˆ‹2‰r �D9Ñä$náÙŒ28Š¡Z¸ìO¸r.£ô£Ä-\ÚmÊÉ)ê‰Kþ'¡7¢ôçôÍœÀ’ÏQ(.õ™„Š|–¼½¥n9éÍEéû)K_¹J·[_•»Rù¤-Dw SP.ÂÑi(ý/¤¸Ü©~5…ÒoG·¡ûÝqéŸiÿÒóUúYw ìÎyTºÝ<Þ:®Îv¥Û­:¥¬nª•>æÊ];sìþ”ëoWçÓ\#7Çt\ÎÉ1²sœ®@9f«uM®ÅkF¥Û ¼5é*ÍÁþÛõ1Z‰’c:ã°s…Ëñ}ÊMéù!ëÏ {Ñs(㹮ƒÕj·ŒSާÐ/QìœÔ!cÞœ«¦¡)èå(cÖhŠ�à&”IƒÕ¨tŒËf›KúQ%ÇÀ¿M¹üoÊ––¥e)ÆC]±-ŸÒo}SgÑ,tÚˆÒfá•z—¶)›Ó•«U ì;�§pé0|æDVÎe�²¯ýåâTË/ ¹¿Æìª¥eÊÁz*e^ Às0ìË¥߇ ”%pqRQW))TœŒ>†f£<99æ “âÄ�>“°•ö6ûÔLn3Ñá('Œ Ð.E ¢íS¾´qN”qYOÝÎE¹q0 ýåD‘þßW®’íÖ“2÷g{u.gNԹ؞�rAMŸ:½=†ò4Ä«Q.jiß\ÈîFO îg#›´ÓW ·…•Ü¥.½ðûö·¬d»y¼í�våöW²Ý*Wª¾O©’Ç\¹kgútŽ·âü»¯f<—ónŽÇœƒÓNåÒ­Ô5¹V¯•l7׬«$‡rýÌþ[¹®‘cí¦…ËäU®ã宽ñ‹á½Í@¹æ—sÕj·"¯…¬|eüûJ4Å^ÊØ)˨p9_MFÇ£7¢ï£«ÑRT®Žx÷™Ëy5çÔŒÛSΔ¿Üxïn¹¤‘±Ó|›'íšó|Òß× Uv,WÚ!«U²â‚UÚ Òqc¬$ÿÎÆF¨1RŠÇ&X­ —‹|:M:OáÊÝ|(öu^†SgV�ÃÔÊöT ú.ô{(�’ä€L?yÍC£Ü‹Ñ= �‰67jzãÔèK9Bʼn8Û)wÔÙy¤§ŸG99D©c–µîJûpê.E½‹º¥þáÔÙ¿Øß—Ëœ{b,߉ŽE˜OA¹¨ýMCg¡´qÚ'aoC¹H—Ö•Í.]ê: õM¼\6£þns�7¡Î\qÜå8+ísékݽ)TM$•<æÊ];3@~ ­CÝ9¾Âä9”ãz%JùÊ¥[©kr­^3*Ùn Þ§È}¸’Êõ3ûï>»F�v¦åG^Õ ÓŸr:}6ÇXq쥿¦Ÿ/D=黯ŠKY~‰z{Ì•»væ|üMt#Ê l_.¼rýÌ1˜sq¾\º97äxéí5¹–¯•j70véj¡WŠC¹~fÿí²kôxG1[�kpÆ`q¹‰~ÊqßyÌ¿CÐ$´¯ñIµÚ�lÛÜ0~sžÉùè»èÛ(çóãÐ 4 åŸeüS§”7çûœ£^†rL9Ë�/âW©10Iuér,gœû¤¸¥-r,W.¼÷ëjáü°ßJ¤£UÛe&2üéL—Îòô8ºÆe:ÐëÐÛQÖëÉå ��MD9Pbðåf¹èû(w5;wÈ´Q.ú9à^…Ò‘oE Ð@DQŒ¹€iÿ£QÑÿþÿöÎ>®âÜÛ’,÷nlãÞÁ`:vh¡Ø 8ôÆz -npIr¿\bÒï½ :¡˜f¦…S SMsÁÛ²\p·qo’¾ç¿ìÙ¬V»Òjµ+í®þóû½:çÌ™úL}gf�´`0ù‘‚Í@�PR[#?jäAXêxokduØ^uQáKAT‡ÛQ9ÍGT'ƒÎIØKÈ×H°(Àm%£¼ˆœŽ¨ž+Oï"*×EÈ4Da溑ÍFõQì4á_…ˆ™ê¶€½½Ï£ÎþKä=¤¢zÐ9‘QSÚUÕ¾TæAÝá¶F£ðå'¨3ò Gõe ¢ºØÆí­!¨g6NõeG!¿Bº#êÇdTÿÆ#A4–4´IW›SŸ;vvÃNcçDýy¼ö¥º¯6¨~`øþ ®êÃ4>Ä 7]c²Ê"WÇŒt•š\¨Ãé⯞¹þ&¬µ~¡ùÈB$z>¬ùÇaÈ$¤ Æeõ ý�Cõ zNd2UnA|ê“.E†!š—Ü�h^?ѼTsJõGÊËÉÈH/DiÖ»Žˆò�h~¡>Nýb0�Q›“ûTæÀxKh”VÍÿ4�Æ"µ�ØùVI›\èjÌŒ )Óf|€LDND¤|h¾'òKä Dƒž*¾È÷M|UhÉMà¦R…+£I­*_tãQEíŽ(l5DU:]•¾`ÇTaÉŸÂ *ŠÂÔ³ìå.Ö¨"HaV¥�ŽOîÄWO鑵y郴CÇ.Ȉó$D jŠWaËíHä8d ¢4(ÌH¦&Q™ä |�GÀXe×QG² ‘å_eÖ9$|Ï%d”>1‡UˆxÅ•­Â :Å9ù>ò¢òP¼ý�Ñ#ñ]Ѝ£‡¨,dÊ‘EÈr$ºŒ•F¥E嬲Rx§ 2ªÏ �×�eˆÊMv™4™,7ñRúÅt 0•‘ø©S•»�‘㑃•a`ÄH¼ê~tz¯´§«+¼x¦K•ý÷ Rª÷BdT†ß Ÿ Ÿ"ªƒµ1ÊwlžT:!Ñu&^˜™,7··xÄÓc—Ér Ú[¼”vÅr2iv ~n ¢±Tí0[L ©k›SÞJ‘è±S}ÅHDý¿újå]u]}uÐ/wáþD}‘x‰‹ÜÞ‚¨­Ç ·û]� …—ꘜ+cYŒkJ°­k¹Å 8l™+u8âÕ3×ßêjGíÞiÜýQ_ ¹…Æ[ñ�ÌCžFôNå ùÇ‰È ˆÆÿÀ¨Ï�_Í+ÕO¨ígªÜ:4÷×|óX¤ÒiŠüY€hî©øeV šŸìލÝhN¥wJ£Æ‰À·•L:çÀ•ŽyÐ\JÜÄ00Á|Hý`*&Wú‡jó¦BË´`­ÈŒG!{!šxª2©‚I±:‘Ñ\•'º dŸÈ¨!Ii:ù"%Xvò/¥6º)Þ¼Œ‘*òóÈ“ÈDøräˆ*�ŒÂQƒTe‹Ä2Û»k�å3Ú¨’œŽ¨<€” ŠkWD A~ä¾¢‰ý—ˆ: 5v ôû"ÝåEÌ 1Ò5Fáfšƒ&7ê44RYIöG®EÞF–"*Ë=�ï"ª7­‘ÀˆËUˆòG‘EHlCV¥I—ÊMFù‚ŒA¾B6!Š¿"Ö*o•­: Õ¥§……¿%xàª2PüJ£ÂÐó~ˆÊTFe¥rþ!2™‚,FŔ۴šú(·…¤XíDù¿öˆâU>ÕTVz? ±ÔûÀ¨^]‡ @TnËqMg;^Gx‰ÌF^LE>A:#*3•“ŒÚ¨êÅëˆêg¢A‹Wq�Úl Ô79R�ÕïD¦>ÊMùY�¸½%*…ÚÛ×G¹©½Åë/vÆ^ýNÐ×(õjwêcÞC4¶e‹IW››G†bÇΞØ]Œ‚(ß%ˆòÞј¡1¥¢þ]¬ÄHc©úùÀÄ WýB:Æäl3ñ®é*·xaË.Wêpº8Ä«g®¿‰jGíì7ãü#ä%älDsvÍ)ú#W"š—LCÔ—j¾~Ò‰—58 i‹<‚¨/•›©rkFØ�õUºW¿¤´÷Cþ�(þMˆúõGš»jþÌW4ýY…Ä#°Í_—p æ$³ê2V˜ñŒæÎ±óœxó¡x~ÙåJÿ�(ý!ûè�¦Z‡u|©Êðr#r2 Q#Püš„JdT™ÔXä^¢ìU)U¼¡Èh¤Ý`ä/ÚoKžû"�ÑZVnÞC!Rf�A¤0©�Ê(�½‘£5RUúh£Áûpd²‰ŽS g 2ùYŠ|ˆ<ˆ¨Bê�ò ¼öC¯âQƒQüò/Q¾”^qQÞEÄ)Fœ2ÍAƒ:•G[DÌÔÁ�| ò/.å]�„XÈ­ô>ˆì¾D–#bmTêtˆ¨©›"½Õ…)®…)³QÚ¾BÔ¹Vgvãå5ÈpDéQJŸîeT®"{#k‘Ç‘ÿEV#™0õQnª¿ªÿ3�Ï ʧò½+¢òTg™ ˆÊ/(7•ƒÚ«ØNEÄBb…!ût´cMˆ 8*óyÈ[ÈAˆÒ”½Òª<©ÎÄÖ%¬j4èf"ë‘öˆÂU×�Díµ>ÊMuÚí i4õQnjo±uYã‚ú/µ7µ+Õë9ÈDõPm0[LºÚœúŒ‘‘���ˆú MPÕ–5fi“©9po[nÄ9èk5þˆ¡ææâW[“KýCµy €Të(M/¥d¼€ÌFNBTéU(ÈT•Fn4Ê�*Ù‘ˆ&22jDñL`¯Šªp½*³ÜÈ_ô³ìj2ò£tj°ŽgT±¤¤i’›Ø8¾ÁîyD ã,äDŠŠ¸& ’h£0¥ÔÈŸ˽ÈÛÈV¤¡L]9h¢óÒÑÄH Te§²Ž.ou€ê$ä^̇!�ò"®ò£'–1V!>ªK�#g ½±•Ÿ`bÊm¨¬ÄRŒç#O"ò#…«:£4«CV§¨pcÓ gÕm•«$¨ë²�®<Ö›©k¹)¡ C�»Úò¤?L85Xé½Êísdr² "�I´ ˜È^e”ÈÄú•¿Ø°ù•ýD‹]Ó¥Me¤6¦:ö"¥?H ·I›m¸,Ef!]…Û Qýn‡¬GR o!uéwÜÞD±þ�Ê».å/ŪKjw3‚v¢º¥:ý>’h!‡W fÒÕæª;ÕÇñWß®±v&ò0¢~+–Quáªo—D›TÇä\3ÒUnÑìtŸku8]ª«g®¿±µ¤vÏ;p®ùñMÈ:ä0Ds3é8ÑmXý±ô -Öi¬?i�D›Øq:å¦>Ds¥GFÏ’`Þ 9Äîa;åA¢tižZ‚ŒG^BôœÈ¨ï›‚dj¬x5÷Ò[¥InUÞñêÖ³€»ç•Q/DaÆ3*«™ˆÒºÉårSý•Yƒ<…(og# Ê›ÊVõõQd9"Æ2*3±RQÙᩨŸAB:!EH2f+ŽJ� ×TnJ�âþ¢xvFTÞ@ÞA”–T�ê„êÑ~ˆ1„¨Þ©¾*­±Fñ¹½¹½©.ªýÄŽ±õ¥+»#ª[2ò£ÉŒú�+™ê_:e“®6§¼%;vªúvõëõíW‚>‰Û�©M¸êÃR“³mÌg?á%]åA®Õátq¨M=sý�­55?«½¿‰”"'!šW÷@ÔWj>¡y¢ú�בÇÍÛô^×Bd2™ˆDÏ2QnêG4?š‡¨~iΩø5´B4ŸTš•.Õ¹—›�‘gÍ34§PÚª3™œ+^¥Us‰Ò¬ôÌGÞET©˜\ëæQ…×�¦ ‘«P‚J¤Š¤ú.òÛðUÕYÈ_‘ÇMà£�Ò¶ˆ&ðA…Œ~Ÿè^ñh‚¯J ѳÂÒêI·!£t©Á)nÅ!7j´J·ü©á* M Uᤄ+oz§Æ³ ‘_5’h#7�ûöÜ÷DÔà¥h«±­D¾FÔ�¾¥%Ó¦>8ˆ�âéˆ(Ï}�Έ.F– RäÄMùV=‰æ.×ê˜(•§êˆ+.Å£rQøb¬NW|UÆ*#•[MFe× :CÅÏ(Õ3åCá'6ÎR2õQnAÂÔTO» ½‘nˆÊ®Y†¨þª\Ä]î‚¶";±–D—›Òž®vLPÕ¥½2鋨LGTïbÛ(VIÕ‰#�ß"ßAÔw)Ì»‘[MÌã™ú(7··xäëfWå›ÂC±ø¢…(Õ/MºE~�h¬ÈdÿBð)›t·¹Dc§úcõµZ¨P?´4ü¬¾WýpM&Q¸êÃê:&gã˜Q�t—›âËÅ:œn‰ê™ëoM5²æ÷A;Ó¯y‰ÆxÍ!¥ˆÆ{-´iN©9¡®5Ñ\SsÍéãõ¥é,7)ÓC‘.È\Dý·Ò£¹°ì4R|š7HМXó õCškÅKÖUŒò–‰9°"Ú¹ù¢ù°Òö8ò;DiÕü·¶&û‡Úæ1£îUàê°b�*“”ŸŸ j *U"­Úœˆ¨’ä«M˜ÔÁª¢j@×s@NAR�r¹ Û•� µ>�âÓ.¤”h TÚ�T¡H‰VÅ׊ÎáÈ™ˆVpd§‰„Vœ¾F¢w¼xÌ+LÆ5!oLFe¯r­�²U\ÚÅHf'g6IÈU¦™J·Vš_AöEŽF´X¶'r²ÑŽcC··†¤_·¸wÂû®ˆ&]U—¤`K´ó’í&Sm.Scg¦ÂÍörŠM_:Ë-—ëp:9D3ÎT=ËT¸ÑiÏæ{•W øe"�uå+ÿÚ‰Ž6™ž §«kü鋌@º#Z,XŒL@ÞER�r¹ Û•M}+ؽˆþ<ä$DÊ´*—Žs骕ˆp�Ò¦£^Ÿ#¥ˆ‹� ˜€ d+ �S‘‡�žÈP¤òD�ú2÷c@°©5-LF´8­ÉÙ,ä_ˆ 5q²1�l'à:œí%äô™@Í´C­¹Í‘Hp4üuîCV!©ŽGyÕ?J,<êÅô#–c‘!ˆ& *MtÕŠˆVAt•‘�~ ¡IéˆíT ¯ygĪUXtŸN£^-|h7ÝÌÓIöÛ:îrK/Ól M«·ê·Æ"Z4„ì�¨ï+AÜ—Á¦Ö4f6E4.ê·nï!#Z ¶1�\ à:œ ¥ä4š@bÒÑvEN@z &!šïÌGê²��WýC}+ØšxjuCGÃõ[ƒ@¸ )Û*˜Üé<¿v‚¦!>Ö „(£�!ŒDŽA¤°¥ÓÌ#°'í¶™{:É~û —[z™fchÚU|Q{)29™€H9r»‚M­ÌÁõ]H ¢zõ4âÅ Øä ×áœ)*'ÔâÐŽõþÈ!ˆ6áÞAnCұ؛WýC}+ØR”oB#ú�¢ÎÛiÐÑJ)ÞR¬g!¯"Z¡_�Há¶©L@G굊¤ßyJÙN§ù„ÀÔh´²=�;¬ÐO!\nù_tòC}×xd%r"»NˆÛljM@§Št2âSD»ÚÉvÿ ›œ!à:œ3E儚@\R°¥s,D¦ �!úY\:þKN^õ�r ›z1š¼�H�S!µ _uÄy=ììhUDʶv¼5)µ‰O@l2ñQ„àØ~üXm[W.·ºÌ ÿjGÚa|™Œèx¯”m/Á¦ÖÔohl”ؘ@.pÎÅRsšMàß4‡yyY‹z·u6yÕ?Ô·‚-xš\J4ñ ~wÍmè·Øš�Ú$G@«EZ5zIõ“ø‰bZÀ‹%ˆ”w›ôp¹¥—g¶‡¦>Oe®ö$£g000È5Ò ¤dë´±u¶jJO ®MnЮ¿Ž‰KÒ]Žú¼”?´B„4—[a:(0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000�T ¦êÑþLÀLÀL 1¨Ø­ _AyÁ作üW„íR_«ó;¿ ¨à­Â™%qâ´• TK bhAÓ‚5Ý©C�«u˜ø¥êfíëtqÁvÚÊ×…³ V&ÚoLÀL ¿çWvœ0000�JÖ´/(.8yT%ûäRS°+P¬+ î&š§“�Ê.M 95,v&H|WÕ-vÆ÷Ñp¶™J«uëP¦µ_�¬Cdöj&`&`&`&`&`u%`;DÐ v]+’ý›€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ d”€?r–Q¼ÜLÀL ±?~|“¢¢¢ +**‹EaaáØQ£FÍà|œ¦±#rþ³”u·I¢äQ‡·»ÞfiA9Y&`YEÀÿ¦+«ŠÃ‰10È7kÖ¬)êÔ©Ó‰äë(å E{â 7Üð¥nõlcYJ °yóæ·nÝú¥�z»zâĉp»#KÓëd™@Ö Ý>ñÄ»’°”¸&MšÌ™:uê‡cÆŒ)ϺÄ:Ai#P”¶�� ˜€ ˜€ ˜@C‡•rÒi�½U(Ù"ÛPW ÊËË[’®c%<ÅŠ®»ÙVPNO¶à°Rá0ä¿$´©c�8â·£l/µ:¦Ï;Øuhï&`&`&`&`&`&K€Ýký·#²›Þ¡dwÓÕ&¿ x%¿Ë×¹300000¨'V°ë ´£100000ÈoV°ó»|�;000000�z"`»ž@;000000�ü&`;¿Ë×¹300000¨'V°ë ´£100000ÈoV°ó»|�;000000�z"`»ž@;00�ÆI`èС;ŠŠŠ®+++!)..~w̘1å�“†s�KÊËË+Hï–°lÍ¥´;­&`&ÐP¬`7yÇk&`&Ð(VŒ5jZ“&MÞ‘œ|òÉ«EÆ�Éœ& zÛ¬Y³�db\XžîÒ¥‹†rºT�øú&0zôè ÚÒJâý\RQQ±høðáZ¸²ÉcÅyœ7gÍLÀLÀ²‚,+&YQNDmœp R .ª�»5¨D ‚L“8½tµl¹_ÂÅãA%D~00000000000000000000000000000000000000000000000000000È…9�F'ÑLÀLÀr–@EEE“§žzJÿu/e‚ÿ‰}ó)§œò)׊œÍ”n&`&`&—@q\[[š€ ˜€ ˜€ ¤…À”)SŠÊˡØQ Åzü 7Üð·V°Ä&k <ÿüó­6oÞü%�z»eúôéÆŒSžµ vÂL L˜0¡õ7ß|ÓAIkÚ´éÆ“O>ym&ÓIJ#�¢4†å LÀLÀLÀâh‚uS ;Ú{ã3²m žnذ¡+Iz\Âó]C† ñÆL•‘“’ýX�*B¹NJï�”••�5~üx�6yLÀe®³f&`&`&`©hÑ¢EÁöíÛµ0$\¿}ò_0� °(¥ŸãöGN”cª–uéÒÅ?ÑŒ<6^EÏãÂuÖLÀLÀLÀLÀLÀLÀê�€ìúcí˜LÀLÀLÀLÀLÀLÀò˜€ì<.\gÍLÀLÀLÀLÀLÀL þXÁ®?ÖŽÉLÀLÀLÀLÀLÀL � XÁÎãÂuÖLÀLÀLÀLÀLÀLÀê�€ìúcí˜LÀLÀLÀLÀLÀLÀò˜€ÿMW®³f&`&P¿øÿ¦} kË æùóçëžvžy¿ÿž{î¹ã‰'ž¨ìtåß·,ç2ë´ÓNÛmï{000�Ü!`;wÊÊ)50È~íQ”Ç�Ìa1Im<óþHYð\‹ŠŠ®///Ÿ<ûjõEàî»ïnÚ±cǽYüiÄÉb‘þWo7ì«fÜÌÂÐöÀBWÞoëׯßçÆ «díÆ÷&`&ИXÁnL¥í¼š€ ˜€ dšÀ "˜‚ì�tLYDÙŽz?£¬¬ìv¯×DÙùÖê…@ëÖ­[¢(ŸÇÂÏÁA„aÅZJu`ÚqóWÜDŸ¼ÐBÑô3füW+Ø)_�±cǶhÙ²å‘,”Ž¢íD~‚KsÑ ÕàÏÃW®\9–…ªòÀŽë*W_:ýôÓ_‹²óm°‚�Å礛€ ˜€ dä²gžyæÑíÛ·NÊbw±&– Ùc¼œÍ5ZyIèÞ/L �¨¯Ûš5kö õï€È.vLMym‡ûõ‹Â³‚�E…ᤘ€ ˜€ ä�jv±½{�_E�7¹©aÛ»×ySÒÎH¦$±‹íÝëLÁÏ’p­`gIA8&`&`ùG Ñ.¶w¯ó¯¬ó(G w±½{�G¥ì¬d”@ »ØÞ½Î(ý†Ü v×�S`&`&�Çâìb{÷:�Ë;²–`Û»×ùP¸ÎC½¨fÛ»×õR ‰ì†åïØMÀLÀòœ@ì.¶w¯ó¼Àó#{Uv±½{�ë\Ô�»ØÞ½®¿"h°˜¬`7zGl&`&ÐXDíb¿[^^þæèÑ£W6–¼;Ÿ¹I fÛ»×¹YŒNuˆ³‹íÝë,�úŒÚ v}Òv\&`&`�’@Ô.öïÙ œ�T4JÎt.ˆìb“è5ÔÙqÔãŹ”§Õš@Ì.¶w¯º@ê)~+ØõÚј€ ˜€ 4nÚÅf²õšw¯w=È¥Ük{ÇŽ/“æg+**Ë¥´;­&� ‚]lÒòä­²²²Ï³!]NCf f6x‡n&`&`&`&�«Æ�ßÓ}Ô¨Q‹r5N· 4$�7ß|³xíÚµ}9Òü¤“NšÑ�iqÜ&`&`&`&`&`&`&�ÓÆŒSÄ)ŸÎéRtâMÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀLÀR!ை§BÍ~LÀL �ð¯xºð¯CúaÂÙZÚ¯_¿R>ÊRž®lþøÇ?T^^¾y �;-[¶œuç�w®%|ÿ?ètAv8&`&`&` N ¸ÁSà˜€ ˜€ 4(ôê£Q|ÿ¿YEB¶pÿøôéÓoBÁÞ±xñâ½·nÝZ¾yóæéO<ñDYª E¹¾¿G"í‰gç-[¶œ=|øðMœ8qGªaÚŸ d’À…^x0máZâØ'ÏÛ´•ï»ï¾iZ(ÂÔyqèüóÏW»¸�°º…ãø;ÿwú�‡~xyøÙÈZ—\rIçíÛ·E 'r× cÇŽý ›M[À4ŠvÖGé¢ýÎåù‰‡zhq6¥ÓiÉV°ó§,�0H•@S<¶còñ7ˆéÈì&1�Ÿÿüç-Ù5Ýí'?ùIG\Õ©LÇ’o˜�RÿÅèc®òü?kXѼys)Þ‘ý±ïªÿo›jŽ×­[÷òá)åëù¦À¯ØÍþ}³fÍi1*Õì„vQF;ÛNu>ržj:»¿Ÿþô§ÝPÂΣm¬âTÁó,.kìLj“ªî&ÚÉ|ÚÈüÚøK·ÛsÏ=·'e¨SR+8þ9YB;ÛL\¥œ:QÓ.»MHT> �”ŒGéÕ›Œ#v&`&�»xà�¥·ß~»~›íÉîc$åL<Û"úmq÷%K–x;B¦V7(`¥Ý»wŸé…§ZqËZÇ(×mIÜá´‹¡(Š­³6¡NXµXéÅ.úY,~Y­C¿l�©|¼ƒÝ UÌ‘š€ ˜@n¸è¢‹væ`9Ç»W’â�’­cÆ«V­êÄoØÖ°£·™UéNLj:±sÐÙÂu5Šù7�ûºätôèÑÍÚ¶m«é|ÇŸ6±ÓÔšÉpgâi…”ïFv×ÞqÇÅwÎ9ç´æx`ûmÛ¶µb€oŽ¿mJ#;«cýœyæ™Û´iÓâî»ï^ÊnGsÞwS\L¼7_Vבà ìDÜ­`ÓRÇ$IÃ&vú—¢pm�Í/ñw%Þ"˜,ƒ] ±Ã};ÒPÎDp C  wáÂ…8ºØ‘WÍð³wËy¿)6Ìà™ß·âƒq §�ìð»!\.•ü(_¸Q>ºàLŠuxô¤|wpÝË"Ùpg2Ìä.Ÿ uBmÁ‹NyR¨ô…ô1š7Q{Γl5ºlÐ'7§ïÜYÒè2ŸnLåc;*¤“h&` E€ÉæEĽ E÷vŽÙmS:Ö¯_¿ Êß�™�>ÎÇž6¢´‹õ¾H'î×¢|LÆþÙ>}ú”Ôåø¬âjß¾}OÒð3ͧQä—¢\Šõ÷ˆ§+×M¼[‚ÝÇÙ}»wïÞŠ/rä™47A9ï‹»Cq?S~º’¾M¤ÿ}ègúöí;3:�ü¾ö8òµ×Å_|#“ù;é…Ÿ)%%%ÿ…âÙ|Ñ¢E»ó|4q÷æÚ™pÛ2¡+ݸqãÓ¼ …xñD”/&ïçF;”ÙÛø½íáÄ} ~wÇMâw9üüÎ#ü!Ä9ÙÑ¿4[Íû—QÐ_eqA_ç�„É}!áõ$­‡Þ!¸UZ*ð·»÷x÷Î=÷ܳXv¸-€ßñÜ@:{à¶÷#‘Þ¤£?Ó`uo¸|k®Â®‰N¶È]>Êì0¸u‡å{,>-TÞt̘£÷ª3Ë(ƒÏá²+÷j» ú—t“(Ï7Óñ…𫮺ªßK8‚0×S¿¦�–Ž|íÿÄ÷ʕǢy¼{�ò�ÂÂŽâ®bhO}¨»Q'öäeümÅß„ñ/ŽúVRPp»7n÷ÂÍÈzÜGØßÅŸÂ&ЦR÷›’¿ ovƒ}k1þžåÃmŸÆ.>Ñfu”W¿eŸÄ¢Ð&Š´ƒ¬fµQ:ëy}å™öYÌÂÓ^„{nC,IÃî? �qºBÿÓƒôJ8à®=R‚Ÿ·ˆç3ã6ð2Ênö'.¥C_˜nƒ»óèV’ŽåÄùŽÒð­k>÷žd¸rŸ ³ Ü|¾^yå•Íé£{ÃsùÔ×òÕ'-BfQ~óÃÏ\¾5Ô �#ƒ)¿u>ø`•ßsS:…³ eSØ¿ÿÏùO,~jçzwìö"”HÜ£éW²h:í¦›nÒ1ñZ™è´�‡™ÔãnÔç¡Ò)#>Õ�9ôßsÂ?÷¨>u·ˆñ¢ ýÁž¤Cyï@¾¶�Ö/;tèðitšø¯ÅÊîz²è9Gáî;\úQ'Uß .®ªM˜ôS-HoâìˆÌ¢þR×÷%¬þ„YÇØBŸ´Qn"†Zˆ]�ßiœÖ™É}háZÉh±}õêÕÄžð:žÚÖú¤™ŒƒZd/ò%7É”aRv�q¿7îÕ&›qª/¤e.ñTJ éî³]ɇÊwcÝ.ðF8Z ÿŒ¾é}®õnŠë=FGh&`&�3¤N'±k:vìx7×�‚Íugì/bÐÛÁ¸?^Kž¿àªNJÅï¸ßoÙ²e?“_$eCøÝ²Eƒ¨h–â8—@›a¿7ד\'1‘ù&Ÿ"¡ßÄ¢ M¤)óÓp%îvÅ�ò°éN=‹ë$”Ãë™ÌÈ}ÈÐöÀý%ÈsXìÇõ(®êÞÇ+�v§î«M‡�>zµ˜{):]¨‹òÛÿ?ïCÔሲÏûï¿ÚC&¤´ì…�&å]±?…8G°Ðõ'ž”¿Ë°W½Ý„-l¨ÝÞAÞîŠ^ �òÁé’cñÿŸäqoÜ-ǯ¼ŽÂî?P’‡ÿßà¯þC Ì!\~†»~\u‡ÛŠý‘rî?ã½ú)ùµ ?Rìªe&7ùn(ónô›'ÀSõB œÁh1v¥”ßó,Déã�‘q‚rêÇ»Kà/Ånz,#ìÕÎÎäZ8wîÜ™,¬p«Ÿ½¨þµÅ}/¤÷¿•_êå¤áÜj|ª• ÒB=X„r=™ëY„;H�pÝF¼êC—¢ÀO ¯ÏR¿#*<묳ڱ0taŒÂŸ4fsß¿ËhÃ/2V<ÀX¡öW°ß~û5eÑL‹ 'Ñç¿ÎuOÜÊ+-(L¢ïx·¶aÒµ¡ýIï+°Ø“{�¡ú€igî×î3—]vÙS¸;9;-Œ5EšÓ”’¯ÇPüÿŒ«ØËâ§é=…p�æ¹#ᩯS¢KÚöcÉcú—†”�N�%U>RØYþáœIþ5–Élç^‹Ky÷O2_ˆ^$Ã^‹ðç‘õ{Z˜»?RÌW ¡>Šk½U 00HšƒXh¢ÂõÎW™Hþ’ÝRíU0aêÁõ>Þ�ÎŽÚXvFß&öIGÇ!ƒ¨Í% ¢7pÿ$»†!e“Á¶ “ó+±»’�µ}ii©&Þ_#Lz¶³º¾�´ÜÈDã¡`g™IM&¿"�?f`>�ç{£â­„Õ¹Œ÷� øÞ}Ûm·…ÂS²ØÙÒÿòüwv£§(oÚ¡a§]äÇ�ë ûYœF î7cß‘ë%ø»¯ÊŸÒ΄ÿVÞi²8€÷s™X]JZ4IKÙ=NúÆ$èî5Ù¯Ð$„‰ÍuØŸŒ¿{ðs+~Vé�ŽÃãörî«LŽþOŠ9�?a÷'&=Ú±|•w7‘·{wÚi§í¿ùÍo4ñK)\”©–Ù·Nòî¯& -(»&AθßÇ&\Gc·”û›�giøù€Šþrì?¢lKí¾áUw¥Ìu¤YõTu@“Ú×÷r”ü™Ô{-µ¡žGY«Ýüåàz®!…ùàƒ.ûàƒúò<¯¿&¬)ÜkÛÑbÖiø?%{q°{‹½b´�v‰üQ�¥l¿Íýúyóæm4hÐ>´¿–„wmj<;eÚÅטvÔÍõ ®³p? ìTï¤i¡è!¿�ô—¢pµáùâ<ƒ0{ãF“ä¿çK¸ÙB¾´Û®~@Ê€Ôž &ÿ(ãRä~-?¼WûžD8[¨ë­IÏ9²ãÝ&ê·°¶·ÀæqâÝ•û?ñ~qÜB*!žôZx(H!Ü‚š˜)Ü|6gŸ}vwòw6N‡ù×°}ˆûe°U¶ð¬–ŸÓw¦Ÿº[ý”^À¿ ö»sW!¦LUÏ!…¸kBÑn¦�i�÷NühÁh4a—"+<žuŠ"îI½¯Î(-ħ…ɹFX;wÏꋵ�Û‹çá\Štå¿3Ü,¨ÎQ÷á½”½‘¹Ü—†>4y$Ïñ^ ÷!Œ!ÊO'Þ�;ý4�–ZµjIDAT©ë—�yÜ—ðn5Av¬M˜âCX]‘‘„£ò(%¬`¯x{#Züø1üvÁ^?½ú»O-ïÅ;õ/ç±P0›çiHÈÐ7ôÀÏù<üÑnû“¸ÓÔÑ¢÷ÄёŬ¿ÒžK“)Úp1‹cZ”ú%aµáú ÌgV¨oR˜”ÅO¨/ê÷ÂMhQœ~¡%q B´Ó¯…Œo¸Þ†_•‘úœ1¡ZÞ 1;R00�\%PFÂã*62qù%Õ$4Øi7 %ô.Þ�„»w¹¯“!,­ü_ËNÜ›Ñ {x%ûO(,š”]‹;)Ì÷KafÀÖ$[»x¡´ à])ŠæXkíFÈDz,ïB;θݎ] ®“¸þ å:4é ü¢ØOÆþ½è0ÃG_'’ïwxw )SäCñr¯IUS¸ åú� ýJ;鸓tH!Û wçôèÑc÷Ëy„ùÏ¿åÝ`+¾–_ ö'¼³±¿eê�ÑGouÔ�|ÿ…‰Ê!¼¿ŒÉ‡ò¦ÿP˜(p* Î&=å¸•à„­úÂÅ›”¤j™…oàP[Mº5ɼ‡2{Œú¢Ù o@I{„{•³Ž%ïÌ}J“~üE…s;r mc^P·x^‡Òr#×2âS=8‘çRí°]zé¥Ûi#m×®]!õg+i í*r]ÏÕc¸J^´{Ö ÿš¤Jé‘b¡:¼†û›ï5Ú‘ü…ê×χ r F; °�°Ä¡€ë+Ẩɾ<7C¤0Ë(mš‡NâÝ#ìtÍà�ü­§Þ�ãº?¢¼ë©¯ÏÁr5÷b9–Ïàg0σ¹oÇu-yꎭv¡p‹rÙS–¡Å ò4öS9†R®•G•+JÅtŠr¼¤·•}Ì4Â|¾ÿþscêN…&íã|„úx(é9œ:ú"ñ©½ BtüòÏ~ÛRìwÇ�×À„ÕHû¿˜ ¦ÉtðBW~»Ùm¾×QkM¿&�;³Û­|‡&ÍØ…ê-ï?DæE¥¿‚69—tÈÝ"d*;é!åZaÊŠ”¯AvƯÂ\K>µ[®�è'Ø•þ˜�Äè4Vè÷®”ÁdÒq$nv›={öD®‘£ÉÜÇ5u·Zfq#ËKÚ‚>Ž9œòQŸ5ŽÅ‘�)›H?…·žºöe¬]ÓÿÆÝ±ôS¯$êߓĢS¡6HËK$¾$ý'rF K{, ɪ«‘pÕŽH÷GŒsÚyÖOަ?~AÊt¸�}hØïê¡Ú­N�t¡=uÆÍ¢¥K—V°!{3öS¨wÏÃI?oˆ˜Ú†I;Òym-‚*œ�y)× P‹±´£™Ä·ˆ÷ú™Ók”SH¹Öû^½z­`,ùŒ[)Øýe'Ü~Âq8·:±CV�ò2á6ü5ããì´ËCÈ×C\—#Õ•O!õE§&®—YÄxÖ‘þ„z±™��Hÿk¼¿Šø"¼ˆ‚�?¸ŸÖ±t® n¬`7x8&`&�›˜pLå·»¡™LtºvíºjåʕԥF¿Jùžp>ÁsDa� ˆA~)›å¸Ì„E“:MÄ‹˜ äöXÒª�»;W­äkU^J¨Ž¢FŽøÊO`pW ^%oRÖùÝö¾LNÃmoÜéØ]3žN{âÐï8CñaéŠÝ&&L Â�È+¾V¾ŽIŽ -f÷£J|„Ú ÇóÀ÷ƒ±çRxñ»�ÁëàÚ�÷šTEóàE¢k]ÃMÄ,Q|ùjÇy°ÐU¥ÊÏûÖ°ƒºûNÔ—´Ì¿ˆëKê‚~#\¥îˆ/J¦N”h­�ó�dvm÷`| ÏRÀã¦#“qÕßÖØÍæZ¥ãnnâ*¥ÚÍ#_#i[#ñ¿/n{²{ÝŠg�ÑÂÖ?Q¼*…‰�vÁr²C‹n[CmZõ¸Kø®#®-øWjÃÜ÷E:âvm­[¸]EÂÔ n{pÑox{1‰oÏ}ܼÈm`ê.q%dÄ‘oW˜Ii‚èôÌd¤Rù)¿R9j<‹²”R7€ö!?:Á“m¦œ2œ‡¼/ŒÛ¨ksI´Ž#÷Kè'BúÀ?ŸèM]•B8€¶ �piV[„̧=µâZÀjîÄI;Ý_Ž7®’r-72µ ó[¡z¯“'³a½è¤ö �ø\ÛÒ6¿ Üëª>…#ÞëI¯Üh¬ ÜvAT¶ÚÉÞ�¼ë$I%C¿Ò‹Ö —#Ýb";¡¡ïh‰Ÿ> G]ð3šp«¸‡›âmG¼bmÄm)þ+-hD;¨ïû´tðõ�hÇg&`&Ððì–3‘­2±çØi™ìt¦�uk áò~+“�ÐdEnÙ-ëΤá/Üî�|„<˳~϶–‰ŒÓÇ‘¸éd ®4Á]Èà÷T&×ó  ÃÈSØ-A4 9&×r­bo _�­&þ´Ã.÷:ªZÅ�oMº*ÙV3ùÃr5×�•^þûAÕÏx_²fÍš*eôogÿ¾«k¸‰˜ý;†Fs§ÔU)—ÝvÛmÇûï¿*Lê‰êk:Ìê´”ö¸Fõ„‰ê:ʦ%$:n©}w>ÇQ¯àQ NQÏå~)×�Ô·s¹êëør^Éàv»H•+$.¤¬£(ü‚Û ó‘‘Çq¯ôé÷‘?⹊!]R"ÖÇî\†ÓÍëÐÇ «´ÂÓÎx¨í’΀¥Nª¨mèwÝý«Dö­…ü©¤©” ªä#�Ÿ:…Kzâ2KW^XÃ_‹4]Èûlþ›„›âÊa/ôAI-zH¹R¿U­¡nê’U’êת ,¹—:é´J»î‰œ‡Û�Ò>�ÛÁ±‚:˜Ñ:ð#ªHôQîàUèªzÀ)ýkºuHh—˜ã¬ûОôá)W¿šE²iÛøIDyxí{„Ù%va§RÀ1ä÷ Â�¿›ûa>r¶F¿)Õ±WÜ´£}ïy]KÂöB8:ùÓ¿õž6± lí„nÄn÷ã7Â$oÛi¿qû’H€á›L…O>=ÃWl¥°5ã¿IHَ˶ZÑîhàžÛ�ÑǹÔßW1ØkgTuºŠÂXÅq,ˆGãD+úÿ¦±;ÀQÁëä‡ò¡…à�¢Ê‰¤ÁŒA—“ÖV¼{&3x^ͳc5ViÁ« v±�BÏqR “¶RF²ƒÞ�gý|¢R}Ã.­†E‚¹ôúÿÕûÀåEò5+6ڬ潡�ûžKôœ©pÅ—öÔ1ý>~>2˜ã¾û�§‰±ùÒQgÊ©nñî#>LRšxÖ‰íª¶U_S¯õOÞõ?�ûá&®’…}Z éQ:ûÑ.TÇõS¥XÃëÂîXê½þ{À‚ðÿ‡ÖW¸ÕΤ�=ÝÎè›ÛÓ¥�'m2fÒ‘G9Œ*[õ+Køy–N‡U2ä»�ï�ÅžL©ä(ê�ÅîM,Äé7Ô;àWF›‹þ@aÄemÃ�xl€›¤' �6Gi&`&`! ¬:nv“œÃØ­î¥ßBó/Q:2¹ïÃÀ|Ž®@¾@fP)Ž~ËVÄÝA|¡´;“MØ:3á‚ý¥¼×Ñ·Ðï7C‘Ôð‡I�VÙ7áoJÍ ¥�ðÚKÁà�vèöQ|¼K:Ì¢ŒûšÉÈëÄó2/ÏàcN§“ŽA䯓xpß%ã&o÷áæþx%E‰4êcQÚÙMæÑÿUž ë.þm€e¬“?¥]ÂBS¥zG;Ù™ÉðEª¯¸{¦S§N3”DêFsìôeä–ì2G6Zx.D: '{#:º*ç5âPX:Ú†{yŠ(×´¹Ä5é[c@ut@[x�x&‘Žï“ÇÕ&¢ƒTûç7ácX|º‹{)}ƒ?ívK©Óï²[D^pS—p£Ãid÷K(‡·É³xžÊ¿$Ô"KÄð®�ª—'c)î¯_}¦>oÄ^ %ÝY´Ü#â‰úÚÞôµGâ^?(¤NG¿Ö½Žî•T:3fl^’|^B²ßFôáÐ3øøX×hðhÊ;Œqù®‡D¿ã>nùHÇÌæýØ ‡ç‘,†UÒQãÛ™ü¼åâØ¶GV<&×{fER�00�FLà &*û’ÿ[ˆ5q›…âÜŒ ýnÜ…”òþ×ìL¯à>4ÁçY¿�Áó´÷â~.Šˆ>Ðr÷‹¸~ɵJER&„s™ OÀß±¤áÏÄýáíà:�ð‡ÏãȵH[¾^Ȥ�ÛôMF˜Äh±A»‚ÿEüGpýš¨î«´p]�ýDŽè»ùABôPµÓx×”¨õä¥åìNÂÝV‡pƒð}­_:N¹åÿwL^`Bû&ë;›˜ îJ¹þˆwR$Çb÷о¢­¤qÿ1ud!·Wlذ¡Šøë<7ï—= +ôa=ì’š#Ò.Ñ.fáï|üü’pÆQ÷ôçþØ�‰¨=.À®9õ-©0•ÎÚ)h(@÷âoò âFZž'OÚéÔ‡µ§E°Ga³†ûˆá_ -%²ŸG»ømá8�pKS 7A#»a·Vÿ‚ðMÊ`?²>’>¶åèeŠ_¿Ÿ-„çÊåXÊBÿrðez´`2ü¼` Üõ/¢ô¿Ó¯äC[�²£)…]?[8;}�\J^!§š*Õ'Þë÷Í«x¿ ñI|‹«˜¾rA¢�†…£­î¢C¨/{åúÒó §¢4–è4Ð.\Õnã~2uç)Ãüi3 –Ú‘ÕÑñc¨‡ ðûÒšª>’wZì,â¾Ò"(vq ŠeÚÃŒQ –*[ØN$ÝCqzƒIÍm ´îÁ„y(W)�ú½Û“È-ü‹‘¤7’žß`bs=ï.ÄþHÜ�ä^ÊÃûL þˆBz-“þA�;wŽNc n&3YØÆµ’aâ¤ctª„u“€ q �/Mö®'¬¥¼;�wÚéŽ6ú¯[õ›ÔhËàžwïs?;ÞÙá¬ßÎêo/ãß EòÆŽÈÜ«®ºê<þM—~ã§ çhÂh‚ÛµÈ[<ßÌÿ®ôqŧã–L†ÆàF“˜3±ÚŠÛ÷PÎB»)†[B8q™ao“Y3)Ë"#U�‹i#ŠQue.r ò´§…�˜z–1ãIúÏþ½T�{+ô=�ÇI“¾rnô‘3ýàY}ºO)àZìmõF“‰0kŒ4¾ƒ Æõ(üw’7-J}90\Fúoí-àÝ“ϸFLuåƒâ>ïŒ3Îxƒ²’n: ¹”~d¼Ä¿=ÏêØ4¯·óÎ;‹V+ØY]4àÚà&©cq žJ'ÀLÀL cP¶.d€º�ê|ÅQÒÖòÿs¥¼E±ºF®�'qœO_SÕ¿²úƒâsçÎ}aâĉZ•Nh8Jx0î_ÅÁuLÆïÑlBÇ~ai$@»ø>íâ�Lì^Dnçã])OÒkJ ÅAÄ!¥ð]&‘ /ä$ôÆ¿ÅÚ%âVèèéÿ°H3—ûB>úö›o¾©éÛ/“ä&+V¬�¿Z}ø+QÂHKáˆ#šðÅÿ &áRvkLC¢°Òa�‚WDST‹ü…Ö”þÂMGv². ŽK¤Îê8¾>yi¸ÆM'‹:MqÚ­Õ$ «íûˆü°PÑF»š,xl¤]TYl‰™þKþÚág 8¤´Ë'šz“Ϋ¹ŠRy%Êýçñüvô‡“·ÿåù”ÅŸr-$ìf ›¾¡œ£ïúsÕ*u䳘/ù·aü*&ëkZ â®îš‰0«‹¯†w!&Œï­YÄÞÁ‚ØÒ§¶ŸÐ$*Ÿhê›XDkÅœ¤ÿ#}C:¸E‡Ÿé{ï`gš°Ã70�,'À„C}Xf4 ÃXÉ~‹ò¤Æ P²Yc"rn÷%Ž\·19 Mx’õow&ÐP˜ˆJÜMP‚§q}‡KÓ•�ô{Ìh{0‘ïUÇp+‚+ÂL*¨@ñÀ_RîkrVêÓÖoÔ_MïÃýòZä/°º°S·ºàòá�þÝÔQÔçþÔåY(£:"\É„Gu¤8i“ŠVÆ";ã(Ê�h_ú‡N' L:UVĆ]ÕIe›ð8ªë´™L„Y‡ÄL‚“a5• Ãpß”õGÁe6ô›«D/mo&`&�ÿÐuK˜xD˜Ö�6lÎ¥ $Gåº�…Ýbý˨ä|Ø• ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜€ ˜@: ü¦ÆmÒžÆmIEND®B`‚cglm-0.9.7/docs/source/color.rst000066400000000000000000000015041526744317200165640ustar00rootroot00000000000000.. default-domain:: C color ================================================================================ Header: cglm/color.h Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions: 1. :c:func:`glm_luminance` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: float glm_luminance(vec3 rgb) | averages the color channels into one value This function uses formula in COLLADA 1.5 spec which is .. code-block:: text luminance = (color.r * 0.212671) + (color.g * 0.715160) + (color.b * 0.072169) It is based on the ISO/CIE color standards (see ITU-R Recommendation BT.709-4), that averages the color channels into one value Parameters: | *[in]* **rgb** RGB color cglm-0.9.7/docs/source/conf.py000066400000000000000000000136631526744317200162240ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # cglm documentation build configuration file, created by # sphinx-quickstart on Tue Jun 6 20:31:05 2017. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # # import os # import sys # sys.path.insert(0, os.path.abspath('.')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '3.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.doctest', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.mathjax', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode', 'sphinx.ext.githubpages' ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] source_suffix = '.rst' # The master toctree document. master_doc = 'index' # General information about the project. project = u'cglm' copyright = u'2017, Recep Aslantas' author = u'Recep Aslantas' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = u'0.9.7' # The full version, including alpha/beta/rc tags. release = u'0.9.7' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = 'en' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path exclude_patterns = [] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = 'sphinx_rtd_theme' pygments_style = 'monokai' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # # html_theme_options = {} html_theme_options = { # 'github_banner': 'true', # 'github_button': 'true', # 'github_user': 'recp', # 'github_repo': 'cglm', # 'travis_button': 'true', # 'show_related': 'true', # 'fixed_sidebar': 'true' } # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['sphinx-static'] # Add customm CSS and JS files html_css_files = ['theme_overrides.css'] html_js_files = [] # -- Options for HTMLHelp output ------------------------------------------ # Output file base name for HTML help builder. htmlhelp_basename = 'cglmdoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # # 'preamble': '', # Latex figure (float) alignment # # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'cglm.tex', u'cglm Documentation', u'Recep Aslantas', 'manual'), ] # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'cglm', u'cglm Documentation', [author], 1) ] # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'cglm', u'cglm Documentation', author, 'cglm', 'One line description of project.', 'Miscellaneous'), ] # -- Options for Epub output ------------------------------------------------- # Bibliographic Dublin Core info. epub_title = project epub_author = author epub_publisher = author epub_copyright = copyright # The unique identifier of the text. This can be a ISBN number # or the project homepage. # # epub_identifier = '' # A unique identification for the text. # # epub_uid = '' # A list of files that should not be packed into the epub file. epub_exclude_files = ['search.html'] # -- Extension configuration ------------------------------------------------- # -- Options for todo extension ---------------------------------------------- # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = True # -- Options for the C domain ------------------------------------------------ c_id_attributes = ['__restrict'] cglm-0.9.7/docs/source/curve.rst000066400000000000000000000020521526744317200165710ustar00rootroot00000000000000.. default-domain:: C Curve ================================================================================ Header: cglm/curve.h Common helpers for common curves. For specific curve see its header/doc e.g bezier Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions: 1. :c:func:`glm_smc` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: float glm_smc(float s, mat4 m, vec4 c) | helper function to calculate **S** * **M** * **C** multiplication for curves | this function does not encourage you to use SMC, instead it is a helper if you use SMC. | if you want to specify S as vector then use more generic glm_mat4_rmc() func. | Example usage: .. code-block:: c Bs = glm_smc(s, GLM_BEZIER_MAT, (vec4){p0, c0, c1, p1}) Parameters: | *[in]* **s** parameter between 0 and 1 (this will be [s3, s2, s, 1]) | *[in]* **m** basis matrix | *[out]* **c** position/control vector Returns: scalar value e.g. Bs cglm-0.9.7/docs/source/euler.rst000066400000000000000000000126421526744317200165670ustar00rootroot00000000000000.. default-domain:: C euler angles ============ Header: cglm/euler.h You may wonder what **glm_euler_sq** type ( **_sq** stands for sequence ) and :c:func:`glm_euler_by_order` do. I used them to convert euler angles in one coordinate system to another. For instance if you have **Z_UP** euler angles and if you want to convert it to **Y_UP** axis then :c:func:`glm_euler_by_order` is your friend. For more information check :c:func:`glm_euler_order` documentation You must pass arrays as array, if you use C compiler then you can use something like this: .. code-block:: c float pitch, yaw, roll; mat4 rot; /* pitch = ...; yaw = ...; roll = ... */ glm_euler((vec3){pitch, yaw, roll}, rot); Rotation Conveniention ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Current *cglm*'s euler functions uses these convention: * Tait–Bryan angles (x-y-z convention) * Intrinsic rotations (pitch, yaw and roll). This is reserve order of extrinsic (elevation, heading and bank) rotation * Right hand rule (actually all rotations in *cglm* use **RH**) * All angles used in *cglm* are **RADIANS** not degrees **NOTE**: The default :c:func:`glm_euler` function is the short name of :c:func:`glm_euler_xyz` this is why you can't see :c:func:`glm_euler_xyz`. When you see an euler function which doesn't have any X, Y, Z suffix then assume that uses **_xyz** (or instead it accept order as parameter). If rotation doesn't work properly, your options: 1. If you use (or paste) degrees convert it to radians before calling an euler function .. code-block:: c float pitch, yaw, roll; mat4 rot; /* pitch = degrees; yaw = degrees; roll = degrees */ glm_euler((vec3){glm_rad(pitch), glm_rad(yaw), glm_rad(roll)}, rot); 2. Convention mismatch. You may have extrinsic angles, if you do (if you must) then consider to use reverse order e.g if you have **xyz** extrinsic then use **zyx** 3. *cglm* may implemented it wrong, consider to create an issue to report it or pull request to fix it Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Types: 1. glm_euler_sq Functions: 1. :c:func:`glm_euler_order` #. :c:func:`glm_euler_angles` #. :c:func:`glm_euler` #. :c:func:`glm_euler_xyz` #. :c:func:`glm_euler_zyx` #. :c:func:`glm_euler_zxy` #. :c:func:`glm_euler_xzy` #. :c:func:`glm_euler_yzx` #. :c:func:`glm_euler_yxz` #. :c:func:`glm_euler_by_order` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: glm_euler_sq glm_euler_order(int ord[3]) | packs euler angles order to glm_euler_sq enum. To use :c:func:`glm_euler_by_order` function you need *glm_euler_sq*. You can get it with this function. You can build param like this: | X = 0, Y = 1, Z = 2 if you have ZYX order then you pass this: [2, 1, 0] = ZYX. if you have YXZ order then you pass this: [1, 0, 2] = YXZ As you can see first item specifies which axis will be first then the second one specifies which one will be next an so on. Parameters: | *[in]* **ord** euler angles order [Angle1, Angle2, Angle2] Returns: packed euler order .. c:function:: void glm_euler_angles(mat4 m, vec3 dest) | extract euler angles (in radians) using xyz order Parameters: | *[in]* **m** affine transform | *[out]* **dest** angles vector [x, y, z] .. c:function:: void glm_euler(vec3 angles, mat4 dest) | build rotation matrix from euler angles this is alias of glm_euler_xyz function Parameters: | *[in]* **angles** angles as vector [Xangle, Yangle, Zangle] | *[in]* **dest** rotation matrix .. c:function:: void glm_euler_xyz(vec3 angles, mat4 dest) | build rotation matrix from euler angles Parameters: | *[in]* **angles** angles as vector [Xangle, Yangle, Zangle] | *[in]* **dest** rotation matrix .. c:function:: void glm_euler_zyx(vec3 angles, mat4 dest) | build rotation matrix from euler angles Parameters: | *[in]* **angles** angles as vector [Xangle, Yangle, Zangle] | *[in]* **dest** rotation matrix .. c:function:: void glm_euler_zxy(vec3 angles, mat4 dest) | build rotation matrix from euler angles Parameters: | *[in]* **angles** angles as vector [Xangle, Yangle, Zangle] | *[in]* **dest** rotation matrix .. c:function:: void glm_euler_xzy(vec3 angles, mat4 dest) | build rotation matrix from euler angles Parameters: | *[in]* **angles** angles as vector [Xangle, Yangle, Zangle] | *[in]* **dest** rotation matrix .. c:function:: void glm_euler_yzx(vec3 angles, mat4 dest) build rotation matrix from euler angles Parameters: | *[in]* **angles** angles as vector [Xangle, Yangle, Zangle] | *[in]* **dest** rotation matrix .. c:function:: void glm_euler_yxz(vec3 angles, mat4 dest) | build rotation matrix from euler angles Parameters: | *[in]* **angles** angles as vector [Xangle, Yangle, Zangle] | *[in]* **dest** rotation matrix .. c:function:: void glm_euler_by_order(vec3 angles, glm_euler_sq ord, mat4 dest) | build rotation matrix from euler angles with given euler order. Use :c:func:`glm_euler_order` function to build *ord* parameter Parameters: | *[in]* **angles** angles as vector [Xangle, Yangle, Zangle] | *[in]* **ord** euler order | *[in]* **dest** rotation matrix cglm-0.9.7/docs/source/features.rst000066400000000000000000000023411526744317200172640ustar00rootroot00000000000000Features ================================================================================ * **scalar** and **simd** (sse, avx, neon, wasm...) optimizations * option to use different clipspaces e.g. Left Handed, Zero-to-One... (currently right handed negative-one is default) * array api and struct api, you can use arrays or structs. * general purpose matrix operations (mat4, mat3) * chain matrix multiplication (square only) * general purpose vector operations (cross, dot, rotate, proj, angle...) * affine transformations * matrix decomposition (extract rotation, scaling factor) * optimized affine transform matrices (mul, rigid-body inverse) * camera (lookat) * projections (ortho, perspective) * quaternions * euler angles / yaw-pitch-roll to matrix * extract euler angles * inline or pre-compiled function call * frustum (extract view frustum planes, corners...) * bounding box (AABB in Frustum (culling), crop, merge...) * 2d bounding box (crop, merge...) * bounding sphere * project, unproject * easing functions * curves * curve interpolation helpers (SMC, deCasteljau...) * helpers to convert cglm types to Apple's simd library to pass cglm types to Metal GL without packing them on both sides * ray intersection helpers * and others... cglm-0.9.7/docs/source/frustum.rst000066400000000000000000000114461526744317200171610ustar00rootroot00000000000000.. default-domain:: C frustum ============= Header: cglm/frustum.h cglm provides convenient functions to extract frustum planes, corners... All extracted corners are **vec4** so you must create array of **vec4** not **vec3**. If you want to store them to save space you msut convert them yourself. **vec4** is used to speed up functions need to corners. This is why frustum functions use *vec4* instead of *vec3* Currently related-functions use [-1, 1] clip space configuration to extract corners but you can override it by prodiving **GLM_CUSTOM_CLIPSPACE** macro. If you provide it then you have to all bottom macros as *vec4* Current configuration: .. code-block:: c /* near */ GLM_CSCOORD_LBN {-1.0f, -1.0f, -1.0f, 1.0f} GLM_CSCOORD_LTN {-1.0f, 1.0f, -1.0f, 1.0f} GLM_CSCOORD_RTN { 1.0f, 1.0f, -1.0f, 1.0f} GLM_CSCOORD_RBN { 1.0f, -1.0f, -1.0f, 1.0f} /* far */ GLM_CSCOORD_LBF {-1.0f, -1.0f, 1.0f, 1.0f} GLM_CSCOORD_LTF {-1.0f, 1.0f, 1.0f, 1.0f} GLM_CSCOORD_RTF { 1.0f, 1.0f, 1.0f, 1.0f} GLM_CSCOORD_RBF { 1.0f, -1.0f, 1.0f, 1.0f} Explain of short names: * **LBN**: left bottom near * **LTN**: left top near * **RTN**: right top near * **RBN**: right bottom near * **LBF**: left bottom far * **LTF**: left top far * **RTF**: right top far * **RBF**: right bottom far Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Macros: .. code-block:: c GLM_LBN 0 /* left bottom near */ GLM_LTN 1 /* left top near */ GLM_RTN 2 /* right top near */ GLM_RBN 3 /* right bottom near */ GLM_LBF 4 /* left bottom far */ GLM_LTF 5 /* left top far */ GLM_RTF 6 /* right top far */ GLM_RBF 7 /* right bottom far */ GLM_LEFT 0 GLM_RIGHT 1 GLM_BOTTOM 2 GLM_TOP 3 GLM_NEAR 4 GLM_FAR 5 Functions: 1. :c:func:`glm_frustum_planes` #. :c:func:`glm_frustum_corners` #. :c:func:`glm_frustum_center` #. :c:func:`glm_frustum_box` #. :c:func:`glm_frustum_corners_at` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_frustum_planes(mat4 m, vec4 dest[6]) | extracts view frustum planes planes' space: - if m = proj: View Space - if m = viewProj: World Space - if m = MVP: Object Space You probably want to extract planes in world space so use viewProj as m Computing viewProj: .. code-block:: c glm_mat4_mul(proj, view, viewProj); Exracted planes order: [left, right, bottom, top, near, far] Parameters: | *[in]* **m** matrix | *[out]* **dest** exracted view frustum planes .. c:function:: void glm_frustum_corners(mat4 invMat, vec4 dest[8]) | extracts view frustum corners using clip-space coordinates corners' space: - if m = invViewProj: World Space - if m = invMVP: Object Space You probably want to extract corners in world space so use **invViewProj** Computing invViewProj: .. code-block:: c glm_mat4_mul(proj, view, viewProj); ... glm_mat4_inv(viewProj, invViewProj); if you have a near coord at **i** index, you can get it's far coord by i + 4; follow example below to understand that For instance to find center coordinates between a near and its far coord: .. code-block:: c for (j = 0; j < 4; j++) { glm_vec3_center(corners[i], corners[i + 4], centerCorners[i]); } corners[i + 4] is far of corners[i] point. Parameters: | *[in]* **invMat** matrix | *[out]* **dest** exracted view frustum corners .. c:function:: void glm_frustum_center(vec4 corners[8], vec4 dest) | finds center of view frustum Parameters: | *[in]* **corners** view frustum corners | *[out]* **dest** view frustum center .. c:function:: void glm_frustum_box(vec4 corners[8], mat4 m, vec3 box[2]) | finds bounding box of frustum relative to given matrix e.g. view mat Parameters: | *[in]* **corners** view frustum corners | *[in]* **m** matrix to convert existing conners | *[out]* **box** bounding box as array [min, max] .. c:function:: void glm_frustum_corners_at(vec4 corners[8], float splitDist, float farDist, vec4 planeCorners[4]) | finds planes corners which is between near and far planes (parallel) this will be helpful if you want to split a frustum e.g. CSM/PSSM. This will find planes' corners but you will need to one more plane. Actually you have it, it is near, far or created previously with this func ;) Parameters: | *[in]* **corners** frustum corners | *[in]* **splitDist** split distance | *[in]* **farDist** far distance (zFar) | *[out]* **planeCorners** plane corners [LB, LT, RT, RB] cglm-0.9.7/docs/source/getting_started.rst000066400000000000000000000105221526744317200206350ustar00rootroot00000000000000Getting Started ================================ Types: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **cglm** uses **glm** prefix for all functions e.g. glm_lookat. You can see supported types in common header file: .. code-block:: c :linenos: typedef float vec2[2]; typedef float vec3[3]; typedef int ivec3[3]; typedef CGLM_ALIGN_IF(16) float vec4[4]; typedef vec4 versor; typedef vec3 mat3[3]; #ifdef __AVX__ typedef CGLM_ALIGN_IF(32) vec4 mat4[4]; #else typedef CGLM_ALIGN_IF(16) vec4 mat4[4]; #endif As you can see types don't store extra information in favor of space. You can send these values e.g. matrix to OpenGL directly without casting or calling a function like *value_ptr* Alignment Is Required: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **vec4** and **mat4** requires 16 (32 for **mat4** if AVX is enabled) byte alignment because **vec4** and **mat4** operations are vectorized by SIMD instructions (SSE/AVX/NEON). **UPDATE:** By starting v0.4.5 cglm provides an option to disable alignment requirement, it is enabled as default | Check :doc:`opt` page for more details Also alignment is disabled for older msvc versions as default. Now alignment is only required in Visual Studio 2017 version 15.6+ if CGLM_ALL_UNALIGNED macro is not defined. Allocations: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *cglm* doesn't alloc any memory on heap. So it doesn't provide any allocator. You must allocate memory yourself. You should alloc memory for out parameters too if you pass pointer of memory location. When allocating memory, don't forget that **vec4** and **mat4** require alignment. .. note:: Unaligned **vec4** and unaligned **mat4** operations will be supported in the future. Check todo list. Because you may want to multiply a CGLM matrix with external matrix. There is no guarantee that non-CGLM matrix is aligned. Unaligned types will have *u* prefix e.g. **umat4** Array vs Struct: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *cglm* uses arrays for vector and matrix types. So you can't access individual elements like vec.x, vec.y, vec.z... You must use subscript to access vector elements e.g. vec[0], vec[1], vec[2]. Also I think it is more meaningful to access matrix elements with subscript e.g **matrix[2][3]** instead of **matrix._23**. Since matrix is array of vectors, vectors are also defined as array. This makes types homogeneous. **Return arrays?** Since C doesn't support return arrays, cglm also doesn't support this feature. Function design: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. image:: cglm-intro.png :width: 492px  :height: 297px :align: center cglm provides a few way to call a function to do same operation. * Inline - *glm_, glm_u* * Pre-compiled - *glmc_, glmc_u* For instance **glm_mat4_mul** is inline (all *glm_* functions are inline), to make it non-inline (pre-compiled), call it as **glmc_mat4_mul** from library, to use unaligned version use **glm_umat4_mul** (todo). Most functions have **dest** parameter for output. For instance mat4_mul func looks like this: .. code-block:: c CGLM_INLINE void glm_mat4_mul(mat4 m1, mat4 m2, mat4 dest) The dest parameter is out parameter. Result will be stored in **dest**. Also in this case matrix multiplication order is dest = m1 * m2. * Changing parameter order will change the multiplication order. * You can pass all parameter same (this is similar to m1 `*=` m1), you can pass **dest** as m1 or m2 (this is similar to m1 `*=` m2) **v** postfix in function names ------------------------------- You may see **v** postfix in some function names, v stands for vector. For instance consider a function that accepts three parameters x, y, z. This function may be overloaded by **v** postfix to accept vector (vec3) instead of separate parameters. In some places the v means that it will be apply to a vector. **_to** postfix in function names --------------------------------- *_to* version of function will store the result in specified parameter instead of in-out parameter. Some functions don't have _to prefix but they still behave like this e.g. glm_mat4_mul. cglm-0.9.7/docs/source/index.rst000066400000000000000000000017531526744317200165630ustar00rootroot00000000000000.. cglm documentation master file, created by sphinx-quickstart on Tue Jun 6 20:31:05 2017. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. cglm Documentation ================================ **cglm** is an optimized 3D math library written in C99 (compatible with C89). It is similar to the original **glm** library, except **cglm** is mainly for **C**. **cglm** stores matrices as column-major order but in the future row-major is considered to be supported as optional. .. toctree:: :maxdepth: 2 :caption: Getting Started: features build getting_started .. toctree:: :maxdepth: 2 :caption: How To: opengl .. toctree:: :maxdepth: 3 :caption: API: api .. toctree:: :maxdepth: 2 :caption: Options: opt .. toctree:: :maxdepth: 2 :caption: Troubleshooting: troubleshooting Indices and Tables: =================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` cglm-0.9.7/docs/source/io.rst000066400000000000000000000100611526744317200160530ustar00rootroot00000000000000.. default-domain:: C io (input / output e.g. print) ================================================================================ Header: cglm/io.h There are some built-in print functions which may save your time, especially for debugging. All functions accept **FILE** parameter which makes very flexible. You can even print it to file on disk. In general you will want to print them to console to see results. You can use **stdout** and **stderr** to write results to console. Some programs may occupy **stdout** but you can still use **stderr**. Using **stderr** is suggested. Example to print mat4 matrix: .. code-block:: c mat4 transform; /* ... */ glm_mat4_print(transform, stderr); .. note:: print functions use **%0.4f** precision if you need more (you probably will in some cases), you can change it temporary. cglm may provide precision parameter in the future. Changes since **v0.7.3**: * Now mis-alignment of columns are fixed: larger numbers are printed via %g and others are printed via %f. Column widths are calculated before print. * Now values are colorful ;) * Some print improvements * New options with default values: .. code-block:: c #define CGLM_PRINT_PRECISION 5 #define CGLM_PRINT_MAX_TO_SHORT 1e5 #define CGLM_PRINT_COLOR "\033[36m" #define CGLM_PRINT_COLOR_RESET "\033[0m" * Inline prints are only enabled in DEBUG mode and if **CGLM_DEFINE_PRINTS** is defined. Check options page. Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions: 1. :c:func:`glm_mat4_print` #. :c:func:`glm_mat3_print` #. :c:func:`glm_vec4_print` #. :c:func:`glm_ivec4_print` #. :c:func:`glm_vec3_print` #. :c:func:`glm_ivec3_print` #. :c:func:`glm_vec2_print` #. :c:func:`glm_ivec2_print` #. :c:func:`glm_versor_print` #. :c:func:`glm_aabb_print` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_mat4_print(mat4 matrix, FILE * __restrict ostream) | print matrix to given stream Parameters: | *[in]* **matrix** matrix | *[in]* **ostream** FILE to write .. c:function:: void glm_mat3_print(mat3 matrix, FILE * __restrict ostream) | print matrix to given stream Parameters: | *[in]* **matrix** matrix | *[in]* **ostream** FILE to write .. c:function:: void glm_vec4_print(vec4 vec, FILE * __restrict ostream) | print vector to given stream Parameters: | *[in]* **vec** vector | *[in]* **ostream** FILE to write .. c:function:: void glm_ivec4_print(ivec4 vec, FILE * __restrict ostream) | print vector to given stream Parameters: | *[in]* **vec** vector | *[in]* **ostream** FILE to write .. c:function:: void glm_vec3_print(vec3 vec, FILE * __restrict ostream) | print vector to given stream Parameters: | *[in]* **vec** vector | *[in]* **ostream** FILE to write .. c:function:: void glm_ivec3_print(ivec3 vec, FILE * __restrict ostream) | print vector to given stream Parameters: | *[in]* **vec** vector | *[in]* **ostream** FILE to write .. c:function:: void glm_vec2_print(vec2 vec, FILE * __restrict ostream) | print vector to given stream Parameters: | *[in]* **vec** vector | *[in]* **ostream** FILE to write .. c:function:: void glm_ivec2_print(ivec2 vec, FILE * __restrict ostream) | print vector to given stream Parameters: | *[in]* **vec** vector | *[in]* **ostream** FILE to write .. c:function:: void glm_versor_print(versor vec, FILE * __restrict ostream) | print quaternion to given stream Parameters: | *[in]* **vec** quaternion | *[in]* **ostream** FILE to write .. c:function:: void glm_aabb_print(versor vec, const char * __restrict tag, FILE * __restrict ostream) | print aabb to given stream Parameters: | *[in]* **vec** aabb (axis-aligned bounding box) | *[in]* **tag** tag to find it more easily in logs | *[in]* **ostream** FILE to write cglm-0.9.7/docs/source/ivec2.rst000066400000000000000000000144051526744317200164620ustar00rootroot00000000000000.. default-domain:: C ivec2 ===== Header: cglm/ivec2.h Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Macros: 1. GLM_IVEC2_ONE_INIT #. GLM_IVEC2_ZERO_INIT #. GLM_IVEC2_ONE #. GLM_IVEC2_ZERO Functions: 1. :c:func:`glm_ivec2` #. :c:func:`glm_ivec2_copy` #. :c:func:`glm_ivec2_zero` #. :c:func:`glm_ivec2_one` #. :c:func:`glm_ivec2_dot` #. :c:func:`glm_ivec2_cross` #. :c:func:`glm_ivec2_add` #. :c:func:`glm_ivec2_adds` #. :c:func:`glm_ivec2_sub` #. :c:func:`glm_ivec2_subs` #. :c:func:`glm_ivec2_mul` #. :c:func:`glm_ivec2_scale` #. :c:func:`glm_ivec2_div` #. :c:func:`glm_ivec2_divs` #. :c:func:`glm_ivec2_mod` #. :c:func:`glm_ivec2_distance2` #. :c:func:`glm_ivec2_distance` #. :c:func:`glm_ivec2_maxv` #. :c:func:`glm_ivec2_minv` #. :c:func:`glm_ivec2_clamp` #. :c:func:`glm_ivec2_abs` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_ivec2(int * v, ivec2 dest) init ivec2 using vec3 or vec4 Parameters: | *[in]* **v** vector | *[out]* **dest** destination .. c:function:: void glm_ivec2_copy(ivec2 a, ivec2 dest) copy all members of [a] to [dest] Parameters: | *[in]* **a** source vector | *[out]* **dest** destination .. c:function:: void glm_ivec2_zero(ivec2 v) set all members of [v] to zero Parameters: | *[out]* **v** vector .. c:function:: void glm_ivec2_one(ivec2 v) set all members of [v] to one Parameters: | *[out]* **v** vector .. c:function:: int glm_ivec2_dot(ivec2 a, ivec2 b) dot product of ivec2 Parameters: | *[in]* **a** vector1 | *[in]* **b** vector2 Returns: dot product .. c:function:: int glm_ivec2_cross(ivec2 a, ivec2 b) cross product of two vector (RH) | ref: http://allenchou.net/2013/07/cross-product-of-2d-vectors/ Parameters: | *[in]* **a** vector 1 | *[in]* **b** vector 2 Returns: Z component of cross product .. c:function:: void glm_ivec2_add(ivec2 a, ivec2 b, ivec2 dest) add vector [a] to vector [b] and store result in [dest] Parameters: | *[in]* **a** first vector | *[in]* **b** second vector | *[out]* **dest** destination .. c:function:: void glm_ivec2_adds(ivec2 v, int s, ivec2 dest) add scalar s to vector [v] and store result in [dest] Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** destination .. c:function:: void glm_ivec2_sub(ivec2 a, ivec2 b, ivec2 dest) subtract vector [b] from vector [a] and store result in [dest] Parameters: | *[in]* **a** first vector | *[in]* **b** second vector | *[out]* **dest** destination .. c:function:: void glm_ivec2_subs(ivec2 v, int s, ivec2 dest) subtract scalar s from vector [v] and store result in [dest] Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** destination .. c:function:: void glm_ivec2_mul(ivec2 a, ivec2 b, ivec2 dest) multiply vector [a] with vector [b] and store result in [dest] Parameters: | *[in]* **a** first vector | *[in]* **b** second vector | *[out]* **dest** destination .. c:function:: void glm_ivec2_scale(ivec2 v, int s, ivec2 dest) multiply vector [a] with scalar s and store result in [dest] Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** destination .. c:function:: void glm_ivec2_div(ivec2 a, ivec2 b, ivec2 dest) div vector with another component-wise division: d = a / b Parameters: | *[in]* **a** vector 1 | *[in]* **b** vector 2 | *[out]* **dest** result = (a[0] / b[0], a[1] / b[1], a[2] / b[2]) .. c:function:: void glm_ivec2_divs(ivec2 v, int s, ivec2 dest) div vector with scalar: d = v / s Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** result = (a[0] / s, a[1] / s, a[2] / s) .. c:function:: void glm_ivec2_mod(ivec2 a, ivec2 b, ivec2 dest) mod vector with another component-wise modulo: d = a % b Parameters: | *[in]* **a** vector | *[in]* **b** scalar | *[out]* **dest** result = (a[0] % b[0], a[1] % b[1]) .. c:function:: int glm_ivec2_distance2(ivec2 a, ivec2 b) squared distance between two vectors Parameters: | *[in]* **a** first vector | *[in]* **b** second vector Returns: squared distance (distance * distance) .. c:function:: float glm_ivec2_distance(ivec2 a, ivec2 b) distance between two vectors Parameters: | *[in]* **a** first vector | *[in]* **b** second vector Returns: distance .. c:function:: void glm_ivec2_fill(ivec2 v, int val) fill a vector with specified value Parameters: | *[out]* **v** vector | *[in]* **val** value .. c:function:: bool glm_ivec2_eq(ivec2 v, int val) check if vector is equal to value Parameters: | *[in]* **v** vector | *[in]* **val** value .. c:function:: bool glm_ivec2_eqv(ivec2 v1, ivec2 v2) check if vector is equal to another vector Parameters: | *[in]* **vec** vector 1 | *[in]* **vec** vector 2 .. c:function:: void glm_ivec2_maxv(ivec2 a, ivec2 b, ivec2 dest) set each member of dest to greater of vector a and b Parameters: | *[in]* **a** first vector | *[in]* **b** second vector | *[out]* **dest** destination .. c:function:: void glm_ivec2_minv(ivec2 a, ivec2 b, ivec2 dest) set each member of dest to lesser of vector a and b Parameters: | *[in]* **a** first vector | *[in]* **b** second vector | *[out]* **dest** destination .. c:function:: void glm_ivec2_clamp(ivec2 v, int minVal, int maxVal) clamp each member of [v] between minVal and maxVal (inclusive) Parameters: | *[in, out]* **v** vector | *[in]* **minVal** minimum value | *[in]* **maxVal** maximum value .. c:function:: void glm_ivec2_abs(ivec2 v, ivec2 dest) absolute value of each vector item Parameters: | *[in]* **v** vector | *[out]* **dest** destination vector cglm-0.9.7/docs/source/ivec3.rst000066400000000000000000000152531526744317200164650ustar00rootroot00000000000000.. default-domain:: C ivec3 ===== Header: cglm/ivec3.h Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Macros: 1. GLM_IVEC3_ONE_INIT #. GLM_IVEC3_ZERO_INIT #. GLM_IVEC3_ONE #. GLM_IVEC3_ZERO Functions: 1. :c:func:`glm_ivec3` #. :c:func:`glm_ivec3_copy` #. :c:func:`glm_ivec3_zero` #. :c:func:`glm_ivec3_one` #. :c:func:`glm_ivec3_dot` #. :c:func:`glm_ivec3_norm2` #. :c:func:`glm_ivec3_norm` #. :c:func:`glm_ivec3_add` #. :c:func:`glm_ivec3_adds` #. :c:func:`glm_ivec3_sub` #. :c:func:`glm_ivec3_subs` #. :c:func:`glm_ivec3_mul` #. :c:func:`glm_ivec3_scale` #. :c:func:`glm_ivec3_div` #. :c:func:`glm_ivec3_divs` #. :c:func:`glm_ivec3_mod` #. :c:func:`glm_ivec3_distance2` #. :c:func:`glm_ivec3_distance` #. :c:func:`glm_ivec3_fill` #. :c:func:`glm_ivec3_eq` #. :c:func:`glm_ivec3_eqv` #. :c:func:`glm_ivec3_maxv` #. :c:func:`glm_ivec3_minv` #. :c:func:`glm_ivec3_clamp` #. :c:func:`glm_ivec2_abs` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_ivec3(ivec4 v4, ivec3 dest) init ivec3 using ivec4 Parameters: | *[in]* **v** vector | *[out]* **dest** destination .. c:function:: void glm_ivec3_copy(ivec3 a, ivec3 dest) copy all members of [a] to [dest] Parameters: | *[in]* **a** source vector | *[out]* **dest** destination .. c:function:: void glm_ivec3_zero(ivec3 v) set all members of [v] to zero Parameters: | *[out]* **v** vector .. c:function:: void glm_ivec3_one(ivec3 v) set all members of [v] to one Parameters: | *[out]* **v** vector .. c:function:: int glm_ivec3_dot(ivec3 a, ivec3 b) dot product of ivec3 Parameters: | *[in]* **a** vector1 | *[in]* **b** vector2 Returns: dot product .. c:function:: int glm_ivec3_norm2(ivec3 v) norm * norm (magnitude) of vector we can use this func instead of calling norm * norm, because it would call sqrtf function twice but with this func we can avoid func call, maybe this is not good name for this func Parameters: | *[in]* **v** vector Returns: square of norm / magnitude, cast to an integer .. c:function:: int glm_ivec3_norm(ivec3 vec) | euclidean norm (magnitude), also called L2 norm | this will give magnitude of vector in euclidean space Parameters: | *[in]* **vec** vector .. c:function:: void glm_ivec3_add(ivec3 a, ivec3 b, ivec3 dest) add vector [a] to vector [b] and store result in [dest] Parameters: | *[in]* **a** first vector | *[in]* **b** second vector | *[out]* **dest** destination .. c:function:: void glm_ivec3_adds(ivec3 v, int s, ivec3 dest) add scalar s to vector [v] and store result in [dest] Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** destination .. c:function:: void glm_ivec3_sub(ivec3 a, ivec3 b, ivec3 dest) subtract vector [b] from vector [a] and store result in [dest] Parameters: | *[in]* **a** first vector | *[in]* **b** second vector | *[out]* **dest** destination .. c:function:: void glm_ivec3_subs(ivec3 v, int s, ivec3 dest) subtract scalar s from vector [v] and store result in [dest] Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** destination .. c:function:: void glm_ivec3_mul(ivec3 a, ivec3 b, ivec3 dest) multiply vector [a] with vector [b] and store result in [dest] Parameters: | *[in]* **a** first vector | *[in]* **b** second vector | *[out]* **dest** destination .. c:function:: void glm_ivec3_scale(ivec3 v, int s, ivec3 dest) multiply vector [a] with scalar s and store result in [dest] Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** destination .. c:function:: void glm_ivec3_div(ivec3 a, ivec3 b, ivec3 dest) div vector with another component-wise division: d = a / b Parameters: | *[in]* **a** vector 1 | *[in]* **b** vector 2 | *[out]* **dest** result = (a[0] / b[0], a[1] / b[1], a[2] / b[2]) .. c:function:: void glm_ivec3_divs(ivec3 v, int s, ivec3 dest) div vector with scalar: d = v / s Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** result = (a[0] / s, a[1] / s, a[2] / s) .. c:function:: void glm_ivec3_mod(ivec3 a, ivec3 b, ivec3 dest) mod vector with another component-wise modulo: d = a % b Parameters: | *[in]* **a** vector | *[in]* **b** scalar | *[out]* **dest** result = (a[0] % b[0], a[1] % b[1], a[2] % b[2]) .. c:function:: int glm_ivec3_distance2(ivec3 a, ivec3 b) squared distance between two vectors Parameters: | *[in]* **a** first vector | *[in]* **b** second vector Returns: squared distance (distance * distance) .. c:function:: float glm_ivec3_distance(ivec3 a, ivec3 b) distance between two vectors Parameters: | *[in]* **a** first vector | *[in]* **b** second vector Returns: distance .. c:function:: void glm_ivec3_fill(ivec3 v, int val) fill a vector with specified value Parameters: | *[out]* **v** vector | *[in]* **val** value .. c:function:: bool glm_ivec3_eq(ivec3 v, int val) check if vector is equal to value Parameters: | *[in]* **v** vector | *[in]* **val** value .. c:function:: bool glm_ivec3_eqv(ivec3 v1, ivec3 v2) check if vector is equal to another vector Parameters: | *[in]* **vec** vector 1 | *[in]* **vec** vector 2 .. c:function:: void glm_ivec3_maxv(ivec3 a, ivec3 b, ivec3 dest) set each member of dest to greater of vector a and b Parameters: | *[in]* **a** first vector | *[in]* **b** second vector | *[out]* **dest** destination .. c:function:: void glm_ivec3_minv(ivec3 a, ivec3 b, ivec3 dest) set each member of dest to lesser of vector a and b Parameters: | *[in]* **a** first vector | *[in]* **b** second vector | *[out]* **dest** destination .. c:function:: void glm_ivec3_clamp(ivec3 v, int minVal, int maxVal) clamp each member of [v] between minVal and maxVal (inclusive) Parameters: | *[in, out]* **v** vector | *[in]* **minVal** minimum value | *[in]* **maxVal** maximum value .. c:function:: void glm_ivec3_abs(ivec3 v, ivec3 dest) absolute value of each vector item Parameters: | *[in]* **v** vector | *[out]* **dest** destination vector cglm-0.9.7/docs/source/ivec4.rst000066400000000000000000000105041526744317200164600ustar00rootroot00000000000000.. default-domain:: C ivec4 ===== Header: cglm/ivec4.h Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Macros: 1. GLM_IVEC4_ONE_INIT #. GLM_IVEC4_ZERO_INIT #. GLM_IVEC4_ONE #. GLM_IVEC4_ZERO Functions: 1. :c:func:`glm_ivec4` #. :c:func:`glm_ivec4_copy` #. :c:func:`glm_ivec4_zero` #. :c:func:`glm_ivec4_one` #. :c:func:`glm_ivec4_add` #. :c:func:`glm_ivec4_adds` #. :c:func:`glm_ivec4_sub` #. :c:func:`glm_ivec4_subs` #. :c:func:`glm_ivec4_mul` #. :c:func:`glm_ivec4_scale` #. :c:func:`glm_ivec4_distance2` #. :c:func:`glm_ivec4_distance` #. :c:func:`glm_ivec4_maxv` #. :c:func:`glm_ivec4_minv` #. :c:func:`glm_ivec4_clamp` #. :c:func:`glm_ivec4_abs` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_ivec4(ivec3 v3, int last, ivec4 dest) init ivec4 using ivec3 Parameters: | *[in]* **v** vector | *[out]* **dest** destination .. c:function:: void glm_ivec4_copy(ivec4 a, ivec4 dest) copy all members of [a] to [dest] Parameters: | *[in]* **a** source vector | *[out]* **dest** destination .. c:function:: void glm_ivec4_zero(ivec4 v) set all members of [v] to zero Parameters: | *[out]* **v** vector .. c:function:: void glm_ivec4_one(ivec4 v) set all members of [v] to one Parameters: | *[out]* **v** vector .. c:function:: void glm_ivec4_add(ivec4 a, ivec4 b, ivec4 dest) add vector [a] to vector [b] and store result in [dest] Parameters: | *[in]* **a** first vector | *[in]* **b** second vector | *[out]* **dest** destination .. c:function:: void glm_ivec4_adds(ivec4 v, int s, ivec4 dest) add scalar s to vector [v] and store result in [dest] Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** destination .. c:function:: void glm_ivec4_sub(ivec4 a, ivec4 b, ivec4 dest) subtract vector [b] from vector [a] and store result in [dest] Parameters: | *[in]* **a** first vector | *[in]* **b** second vector | *[out]* **dest** destination .. c:function:: void glm_ivec4_subs(ivec4 v, int s, ivec4 dest) subtract scalar s from vector [v] and store result in [dest] Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** destination .. c:function:: void glm_ivec4_mul(ivec4 a, ivec4 b, ivec4 dest) multiply vector [a] with vector [b] and store result in [dest] Parameters: | *[in]* **a** first vector | *[in]* **b** second vector | *[out]* **dest** destination .. c:function:: void glm_ivec4_scale(ivec4 v, int s, ivec4 dest) multiply vector [a] with scalar s and store result in [dest] Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** destination .. c:function:: int glm_ivec4_distance2(ivec4 a, ivec4 b) squared distance between two vectors Parameters: | *[in]* **a** first vector | *[in]* **b** second vector Returns: squared distance (distance * distance) .. c:function:: float glm_ivec4_distance(ivec4 a, ivec4 b) distance between two vectors Parameters: | *[in]* **a** first vector | *[in]* **b** second vector Returns: distance .. c:function:: void glm_ivec4_maxv(ivec4 a, ivec4 b, ivec4 dest) set each member of dest to greater of vector a and b Parameters: | *[in]* **a** first vector | *[in]* **b** second vector | *[out]* **dest** destination .. c:function:: void glm_ivec4_minv(ivec4 a, ivec4 b, ivec4 dest) set each member of dest to lesser of vector a and b Parameters: | *[in]* **a** first vector | *[in]* **b** second vector | *[out]* **dest** destination .. c:function:: void glm_ivec4_clamp(ivec4 v, int minVal, int maxVal) clamp each member of [v] between minVal and maxVal (inclusive) Parameters: | *[in, out]* **v** vector | *[in]* **minVal** minimum value | *[in]* **maxVal** maximum value .. c:function:: void glm_ivec4_abs(ivec4 v, ivec4 dest) absolute value of each vector item Parameters: | *[in]* **v** vector | *[out]* **dest** destination vector cglm-0.9.7/docs/source/mat2.rst000066400000000000000000000510411526744317200163120ustar00rootroot00000000000000.. default-domain:: C mat2 ==== Header: cglm/mat2.h Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Macros: 1. GLM_MAT2_IDENTITY_INIT #. GLM_MAT2_ZERO_INIT #. GLM_MAT2_IDENTITY #. GLM_MAT2_ZERO Functions: 1. :c:func:`glm_mat2_make` #. :c:func:`glm_mat2_copy` #. :c:func:`glm_mat2_identity` #. :c:func:`glm_mat2_identity_array` #. :c:func:`glm_mat2_zero` #. :c:func:`glm_mat2_mul` #. :c:func:`glm_mat2_mulv` #. :c:func:`glm_mat2_transpose_to` #. :c:func:`glm_mat2_transpose` #. :c:func:`glm_mat2_scale` #. :c:func:`glm_mat2_inv` #. :c:func:`glm_mat2_swap_col` #. :c:func:`glm_mat2_swap_row` #. :c:func:`glm_mat2_det` #. :c:func:`glm_mat2_trace` #. :c:func:`glm_mat2_rmc` Represented ~~~~~~~~~~~ .. csv-table:: mat2x2 :header: "", "column 1", "column 2" "row 1", "m00", "m10" "row 2", "m01", "m11" Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_mat2_make(const float * __restrict src, mat2 dest) Create mat2 (dest) from pointer (src). .. note:: **@src** must contain at least 4 elements. Parameters: | *[in]* **src** pointer to an array of floats (left) | *[out]* **dest** destination (result, mat2) .. note:: Mathematical explanation .. csv-table:: float array (1x4) **(src)** :header: "", "column 1" "row 1", "v0" "row 2", "v1" "row 3", "v2" "row 4", "v3" .. csv-table:: mat2 **(dest)** :header: "", "column 1", "column 2" "row 1", "v0", "v2" "row 2", "v1", "v3" .. note:: Example .. code-block:: c mat2 dest = GLM_MAT2_ZERO_INIT; float src[4] = { 1.00, 5.00, 8.00, 11.00 }; glm_mat2_make(src, dest); .. csv-table:: float array (1x4) **(src)** :header: "", "column 1" "row 1", "1.00" "row 2", "5.00" "row 3", "8.00" "row 4", "11.00" .. csv-table:: mat2 **(dest)** Before :header: "", "column 1", "column 2" "row 1", "0.00", "0.00" "row 2", "0.00", "0.00" .. csv-table:: mat2 **(dest)** After :header: "", "column 1", "column 2" "row 1", "1.00", "8.00" "row 2", "5.00", "11.00" .. c:function:: void glm_mat2_copy(mat2 mat, mat2 dest) Copy mat2 (mat) to mat2 (dest). Parameters: | *[in]* **mat** mat2 (left,src) | *[out]* **dest** destination (result, mat2) .. note:: Mathematical explanation .. csv-table:: mat2 **(mat)** :header: "", "column 1", "column 2" "row 1", "m00", "m10" "row 2", "m01", "m11" .. csv-table:: mat2 **(dest)** :header: "", "column 1", "column 2" "row 1", "m00", "m10" "row 2", "m01", "m11" .. note:: Example .. code-block:: c mat2 mat = {{3.00,4.00},{7.00,8.00}}; mat2 dest = GLM_MAT2_ZERO_INIT; glm_mat2_copy(mat, dest); .. csv-table:: mat2 **(mat)** :header: "", "column 1", "column 2" "row 1", "3.00", "7.00" "row 2", "4.00", "8.00" .. csv-table:: mat2 **(dest)** Before :header: "", "column 1", "column 2" "row 1", "0.00", "0.00" "row 2", "0.00", "0.00" .. csv-table:: mat2 **(dest)** After :header: "", "column 1", "column 2" "row 1", "3.00", "7.00" "row 2", "4.00", "8.00" .. c:function:: void glm_mat2_identity(mat2 m) | Copy a mat2 identity to mat2 **(m)**, or makes mat2 **(m)** an identity. | | The same thing may be achieved with either of bellow methods, | but it is more easy to do that with this func especially for members | e.g. ``glm_mat2_identity(aStruct->aMatrix);``. .. code-block:: c glm_mat2_copy(GLM_MAT2_IDENTITY, m); // or mat2 mat = GLM_MAT2_IDENTITY_INIT; Parameters: | *[in, out]* **m** mat2 (src, dest) .. note:: Mathematical explanation .. csv-table:: mat2 **(m)** :header: "", "column 1", "column 2" "row 1", "m00", "m10" "row 2", "m01", "m11" .. csv-table:: mat2 **(m)** :header: "", "column 1", "column 2" "row 1", "1.00", "0.00" "row 2", "0.00", "1.00" .. note:: Example .. code-block:: c mat2 m = {{3.00,4.00},{7.00,8.00}}; glm_mat2_identity(m); .. csv-table:: mat2 **(m)** :header: "", "column 1", "column 2" "row 1", "3.00", "7.00" "row 2", "4.00", "8.00" .. csv-table:: mat2 **(m)** :header: "", "column 1", "column 2" "row 1", "1.00", "0.00" "row 2", "0.00", "1.00" .. c:function:: void glm_mat2_identity_array(mat2 * __restrict mats, size_t count) Given an array of mat2's **(mats)** make each matrix an identity matrix. Parameters: | *[in, out]* **mats** Array of mat2's (must be aligned (16/32) if alignment is not disabled) | *[in]* **count** Array size of ``mats`` or number of matrices .. note:: Mathematical explanation .. csv-table:: mat2 **(mats[index])** :header: "", "column 1", "column 2" "row 1", "m00", "m10" "row 2", "m01", "m11" .. csv-table:: mat2 **(mats[index])** :header: "", "column 1", "column 2" "row 1", "1.00", "0.00" "row 2", "0.00", "1.00" .. note:: Example .. code-block:: c size_t count = 3; mat2 matrices[count] = { {{1.00,2.00},{5.00,6.00}}, {{3.00,4.00},{7.00,8.00}}, {{5.00,6.00},{9.00,10.00}}, }; glm_mat2_identity_array(matrices, count); .. csv-table:: mat2 **(mats[0])** Before :header: "", "column 1", "column 2" "row 1", "1.00", "5.00" "row 2", "2.00", "6.00" .. csv-table:: mat2 **(mats[0])** After :header: "", "column 1", "column 2" "row 1", "1.00", "0.00" "row 2", "0.00", "1.00" .. csv-table:: mat2 **(mats[1])** Before :header: "", "column 1", "column 2" "row 1", "3.00", "7.00" "row 2", "4.00", "8.00" .. csv-table:: mat2 **(mats[1])** After :header: "", "column 1", "column 2" "row 1", "1.00", "0.00" "row 2", "0.00", "1.00" .. csv-table:: mat2 **(mats[2])** Before :header: "", "column 1", "column 2" "row 1", "5.00", "9.00" "row 2", "6.00", "10.00" .. csv-table:: mat2 **(mats[2])** After :header: "", "column 1", "column 2" "row 1", "1.00", "0.00" "row 2", "0.00", "1.00" .. c:function:: void glm_mat2_zero(mat2 m) Zero out the mat2 (m). Parameters: | *[in, out]* **m** mat2 (src, dest) .. note:: Mathematical explanation .. csv-table:: mat2 **(m)** :header: "", "column 1", "column 2" "row 1", "m00", "m10" "row 2", "m01", "m11" .. csv-table:: mat2 **(m)** :header: "", "column 1", "column 2" "row 1", "0.00", "0.00" "row 2", "0.00", "0.00" .. note:: Example .. code-block:: c mat2 m = {{19.00,5.00},{2.00,4.00}}; glm_mat2_zero(m); .. csv-table:: mat2 **(m)** Before :header: "", "column 1", "column 2" "row 1", "19.00", "2.00" "row 2", "5.00", "4.00" .. csv-table:: mat2 **(m)** After :header: "", "column 1", "column 2" "row 1", "0.00", "0.00" "row 2", "0.00", "0.00" .. c:function:: void glm_mat2_mul(mat2 m1, mat2 m2, mat2 dest) | Multiply mat2 (m1) by mat2 (m2) and store in mat2 (dest). | | m1, m2 and dest matrices can be same matrix, it is possible to write this: .. code-block:: c mat2 m = GLM_MAT2_IDENTITY_INIT; glm_mat2_mul(m, m, m); Parameters: | *[in]* **m1** mat2 (left) | *[in]* **m2** mat2 (right) | *[out]* **dest** destination (result, mat2) .. note:: Mathematical explanation .. csv-table:: mat2 **(m1)** :header: "", "column 1", "column 2" "row 1", "a00", "a10" "row 2", "a01", "a11" .. csv-table:: mat2 **(m2)** :header: "", "column 1", "column 2" "row 1", "b00", "b10" "row 2", "b01", "b11" .. csv-table:: mat2 **(dest)** :header: "", "column 1", "column 2" "row 1", "a00 * b00 + a10 * b01", "a00 * b10 + a10 * b11" "row 2", "a01 * b00 + a11 * b01", "a01 * b10 + a11 * b11" .. note:: Example .. code-block:: c mat2 m = {{19.00,5.00},{2.00,4.00}}; glm_mat2_mul(m, m, m); .. csv-table:: mat2 **(m1)** :header: "", "column 1", "column 2" "row 1", "19.00", "2.00" "row 2", "5.00", "4.00" .. csv-table:: mat2 **(m2)** :header: "", "column 1", "column 2" "row 1", "19.00", "2.00" "row 2", "5.00", "4.00" .. csv-table:: mat2 **(dest)** :header: "", "column 1", "column 2" "row 1", "**371.00** = 19.00 * 19.00 + 2.00 * 5.00", "**46.00** = 19.00 * 2.00 + 2.00 * 4.00" "row 2", "**115.00** = 5.00 * 19.00 + 4.00 * 5.00", "**18.00** = 5.00 * 2.00 + 4.00 * 4.00" .. c:function:: void glm_mat2_mulv(mat2 m, vec2 v, vec2 dest) Multiply mat2 (m) by vec2 (v) and store in vec2 (dest). Parameters: | *[in]* **m** mat2 (left) | *[in]* **v** vec2 (right, column vector) | *[out]* **dest** destination (result, column vector) .. note:: Mathematical explanation .. csv-table:: mat2 **(m)** :header: "", "column 1", "column 2" "row 1", "m00", "m10" "row 2", "m01", "m11" .. csv-table:: column vec2 (1x2) **(v)** :header: "", "column 1" "row 1", "v0" "row 2", "v1" .. csv-table:: column vec2 (1x2) **(dest)** :header: "", "column 1" "row 1", "m00 * v0 + m10 * v1" "row 2", "m01 * v0 + m11 * v1" .. note:: Example .. code-block:: c vec2 dest; vec2 v = {33.00,55.00}; mat2 m = {{1.00,2.00},{3.00,4.00}}; glm_mat2_mulv(m, v, dest); .. csv-table:: mat2 **(m)** :header: "", "column 1", "column 2" "row 1", "1.00", "3.00" "row 2", "2.00", "4.00" .. csv-table:: column vec2 **(v)** :header: "", "column 1" "row 1", "33.00" "row 2", "55.00" .. csv-table:: vec2 **(dest)** Result :header: "", "column 1" "row 1", "**198.00** = 1.00 * 33.00 + 3.00 * 55.00" "row 2", "**286.00** = 2.00 * 33.00 + 4.00 * 55.00" .. c:function:: void glm_mat2_transpose_to(mat2 mat, mat2 dest) Transpose mat2 (mat) and store in mat2 (dest). Parameters: | *[in]* **mat** mat2 (left,src) | *[out]* **dest** destination (result, mat2) .. note:: Mathematical explanation .. csv-table:: mat2 **(mat)** :header: "", "column 1", "column 2" "row 1", "m00", "m10" "row 2", "m01", "m11" .. csv-table:: mat2 **(dest)** :header: "", "column 1", "column 2" "row 1", "m00", "m01" "row 2", "m10", "m11" .. note:: Example .. code-block:: c mat2 mat = {{1.00,2.00},{3.00,4.00}}; mat2 dest = GLM_MAT2_ZERO_INIT; glm_mat2_transpose_to(mat, dest); .. csv-table:: mat2 **(mat)** :header: "", "column 1", "column 2" "row 1", "1.00", "3.00" "row 2", "2.00", "4.00" .. csv-table:: mat2 **(dest)** Before :header: "", "column 1", "column 2" "row 1", "0.00", "0.00" "row 2", "0.00", "0.00" .. csv-table:: mat2 **(dest)** After :header: "", "column 1", "column 2" "row 1", "1.00", "2.00" "row 2", "3.00", "4.00" .. c:function:: void glm_mat2_transpose(mat2 m) Transpose mat2 (m) and store result in the same matrix. Parameters: | *[in, out]* **m** mat2 (src, dest) .. note:: Mathematical explanation .. csv-table:: mat2 **(m)** src :header: "", "column 1", "column 2" "row 1", "m00", "m10" "row 2", "m01", "m11" .. csv-table:: mat2 **(m)** dest :header: "", "column 1", "column 2" "row 1", "m00", "m01" "row 2", "m10", "m11" .. note:: Example .. code-block:: c mat2 m = {{1.00,2.00},{3.00,4.00}}; glm_mat2_transpose(m); .. csv-table:: mat2 **(m)** Before :header: "", "column 1", "column 2" "row 1", "1.00", "3.00" "row 2", "2.00", "4.00" .. csv-table:: mat2 **(m)** After :header: "", "column 1", "column 2" "row 1", "1.00", "2.00" "row 2", "3.00", "4.00" .. c:function:: void glm_mat2_scale(mat2 m, float s) Multiply mat2 (m) by scalar constant (s). Parameters: | *[in, out]* **m** mat2 (src, dest) | *[in]* **s** float (scalar) .. note:: Mathematical explanation .. csv-table:: mat2 **(m)** :header: "", "column 1", "column 2" "row 1", "m00 * s", "m10 * s" "row 2", "m01 * s", "m11 * s" .. note:: Example .. code-block:: c float s = 3.00f; mat2 m = {{1.00,2.00},{3.00,4.00}}; glm_mat2_scale(m, s); .. csv-table:: mat2 **(m)** Before :header: "", "column 1", "column 2" "row 1", "1.00", "3.00" "row 2", "2.00", "4.00" .. csv-table:: mat2 **(m)** After :header: "", "column 1", "column 2" "row 1", "**3.00** = 1.00 * 3.00", "**9.00** = 3.00 * 3.00" "row 2", "**6.00** = 2.00 * 3.00", "**12.00** = 4.00 * 3.00" .. c:function:: void glm_mat2_inv(mat2 mat, mat2 dest) Inverse mat2 (mat) and store in mat2 (dest). Parameters: | *[in]* **mat** mat2 (left,src) | *[out]* **dest** destination (result, inverse mat2) .. note:: Mathematical explanation .. csv-table:: mat2 **(mat)** :header: "", "column 1", "column 2" "row 1", "m00", "m10" "row 2", "m01", "m11" .. list-table:: mat2 **(dest)** :header-rows: 1 * - - column 1 - column 2 * - row 1 - m11 * (1.0f / (m00 * m11 - m01 * m10)) - -m10 * (1.0f / (m00 * m11 - m01 * m10)) * - row 2 - -m01 * (1.0f / (m00 * m11 - m01 * m10)) - m00 * (1.0f / (m00 * m11 - m01 * m10)) .. note:: Example .. code-block:: c mat2 dest = GLM_MAT2_ZERO_INIT; mat2 mat = {{1.00,2.00},{3.00,4.00}}; glm_mat2_inv(mat, dest); .. csv-table:: mat2 **(mat)** Before :header: "", "column 1", "column 2" "row 1", "1.00", "3.00" "row 2", "2.00", "4.00" .. list-table:: mat2 **(dest)** After :header-rows: 1 * - - column 1 - column 2 * - row 1 - **-2.00** = 4.00 * (1.00 / (1.00 * 4.00 - 2.00 * 3.00)) - **1.50** = -3.00 * (1.00 / (1.00 * 4.00 - 2.00 * 3.00)) * - row 2 - **1.00** = -2.00 * (1.00 / (1.00 * 4.00 - 2.00 * 3.00)) - **-0.50** = 1.00 * (1.00 / (1.00 * 4.00 - 2.00 * 3.00)) .. c:function:: void glm_mat2_swap_col(mat2 mat, int col1, int col2) Swap two columns in mat2 (mat) and store in same matrix. Parameters: | *[in, out]* **mat** mat2 (src, dest) | *[in]* **col1** Column 1 array index | *[in]* **col2** Column 2 array index .. note:: Mathematical explanation .. csv-table:: mat2 **(mat)** Before :header: "", "column 1", "column 2" "row 1", "m00", "m10" "row 2", "m01", "m11" .. code-block:: c glm_mat2_swap_col(mat, 0, 1); .. csv-table:: mat2 **(mat)** After :header: "", "column 1", "column 2" "row 1", "m10", "m00" "row 2", "m11", "m01" .. note:: Example .. code-block:: c mat2 mat = {{76.00,5.00},{3.00,6.00}}; glm_mat2_swap_col(mat, 0, 1); .. csv-table:: mat2 **(mat)** Before :header: "", "column 1", "column 2" "row 1", "76.00", "3.00" "row 2", "5.00", "6.00" .. csv-table:: mat2 **(mat)** After :header: "", "column 1", "column 2" "row 1", "3.00", "76.00" "row 2", "6.00", "5.00" .. c:function:: void glm_mat2_swap_row(mat2 mat, int row1, int row2) Swap two rows in mat2 (mat) and store in same matrix. Parameters: | *[in, out]* **mat** mat2 (src, dest) | *[in]* **row1** Row 1 array index | *[in]* **row2** Row 2 array index .. note:: Mathematical explanation .. csv-table:: mat2 **(mat)** Before :header: "", "column 1", "column 2" "row 1", "m00", "m10" "row 2", "m01", "m11" .. code-block:: c glm_mat2_swap_row(mat, 0, 1); .. csv-table:: mat2 **(mat)** After :header: "", "column 1", "column 2" "row 1", "m01", "m11" "row 2", "m00", "m10" .. note:: Example .. code-block:: c mat2 mat = {{76.00,5.00},{3.00,6.00}}; glm_mat2_swap_row(mat, 0, 1); .. csv-table:: mat2 **(mat)** Before :header: "", "column 1", "column 2" "row 1", "76.00", "3.00" "row 2", "5.00", "6.00" .. csv-table:: mat2 **(mat)** After :header: "", "column 1", "column 2" "row 1", "5.00", "6.00" "row 2", "76.00", "3.00" .. c:function:: float glm_mat2_det(mat2 m) Returns mat2 determinant. Parameters: | *[in]* **m** mat2 (src) Returns: | mat2 determinant (float) .. note:: Mathematical explanation .. csv-table:: mat2 **(m)** :header: "", "column 1", "column 2" "row 1", "m00", "m10" "row 2", "m01", "m11" .. code-block:: c m00 * m11 - m10 * m01; .. note:: Example .. code-block:: c mat2 m = {{76.00,5.00},{3.00,6.00}}; glm_mat2_det(m); .. csv-table:: mat2 **(m)** :header: "", "column 1", "column 2" "row 1", "76.00", "3.00" "row 2", "5.00", "6.00" .. code-block:: c 441.00 = 76.00 * 6.00 - 3.00 * 5.00; .. c:function:: void glm_mat2_trace(mat2 m) | Returns trace of matrix. Which is: | | The sum of the elements on the main diagonal from | upper left corner to the bottom right corner. Parameters: | *[in]* **m** mat2 (src) Returns: | mat2 trace (float) .. note:: Mathematical explanation .. csv-table:: mat2 **(m)** :header: "", "column 1", "column 2" "row 1", "m00", "m10" "row 2", "m01", "m11" .. code-block:: c m00 + m11; .. note:: Example .. code-block:: c mat2 m = {{76.00,5.00},{3.00,6.00}}; glm_mat2_trace(m); .. csv-table:: mat2 **(m)** :header: "", "column 1", "column 2" "row 1", "76.00", "3.00" "row 2", "5.00", "6.00" .. code-block:: c 82.00 = 76.00 + 6.00; .. c:function:: float glm_mat2_rmc(vec2 r, mat2 m, vec2 c) | Helper for R (row vector) * M (matrix) * C (column vector) | **rmc** stands for **Row** * **Matrix** * **Column** | the result is scalar because M * C = ResC (1x2, column vector), | then if you take the dot_product(R (2x1), ResC (1x2)) = scalar value. Parameters: | *[in]* **r** vec2 (2x1, row vector) | *[in]* **m** mat2 (2x2, matrix) | *[in]* **c** vec2 (1x2, column vector) Returns: | Scalar value (float, 1x1) .. note:: Mathematical explanation .. csv-table:: row vec2 (2x1) **(r)** :header: "", "column 1", "column 2" "row 1", "a00", "a10" .. csv-table:: mat2 **(m)** :header: "", "column 1", "column 2" "row 1", "b00", "b10" "row 2", "b01", "b11" .. csv-table:: column vec2 (1x2) **(c)** :header: "", "column 1" "row 1", "c00" "row 2", "c01" .. code-block:: c M * C = C (column vector) dot_product(R, C) .. csv-table:: column vec2 (1x2) **(C)** :header: "", "column 1" "row 1", "b00 * c00 + b10 * c01" "row 2", "b01 * c00 + b11 * c01" .. csv-table:: float **(scalar)** :header: "", "column 1" "row 1", "a00 * (b00 * c00 + b10 * c01) + a10 * (b01 * c00 + b11 * c01)" .. note:: Example .. code-block:: c vec2 r = {8.00,4.00}; vec2 c = {7.00,2.00}; mat2 m = {{5.00,9.00},{3.00,6.00}}; glm_mat2_rmc(r, m, c); .. csv-table:: row vec2 (2x1) **(r)** :header: "", "column 1", "column 2" "row 1", "8.00", "4.00" .. csv-table:: mat2 **(m)** :header: "", "column 1", "column 2" "row 1", "5.00", "3.00" "row 2", "9.00", "6.00" .. csv-table:: column vec2 (1x2) **(c)** :header: "", "column 1" "row 1", "7.00" "row 2", "2.00" .. csv-table:: column vec2 (1x2) **(C)** :header: "", "column 1" "row 1", "**41.00** = 5.00 * 7.00 + 3.00 * 2.00" "row 2", "**75.00** = 9.00 * 7.00 + 6.00 * 2.00" .. csv-table:: float (1x1) **(scalar)** :header: "", "column 1" "row 1", "**628.00** = 8.00 * 41.00 + 4.00 * 75.00" cglm-0.9.7/docs/source/mat2x3.rst000066400000000000000000000123461526744317200165720ustar00rootroot00000000000000.. default-domain:: C mat2x3 ====== Header: cglm/mat2x3.h Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Macros: 1. GLM_MAT2X3_ZERO_INIT #. GLM_MAT2X3_ZERO Functions: 1. :c:func:`glm_mat2x3_copy` #. :c:func:`glm_mat2x3_zero` #. :c:func:`glm_mat2x3_make` #. :c:func:`glm_mat2x3_mul` #. :c:func:`glm_mat2x3_mulv` #. :c:func:`glm_mat2x3_transpose` #. :c:func:`glm_mat2x3_scale` Represented ~~~~~~~~~~~ .. csv-table:: mat2x3 :header: "", "column 1", "column 2" "row 1", "m00", "m10" "row 2", "m01", "m11" "row 3", "m02", "m12" Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_mat2x3_copy(mat2x3 src, mat2x3 dest) Copy mat2x3 (src) to mat2x3 (dest). Parameters: | *[in]* **src** mat2x3 (left) | *[out]* **dest** destination (result, mat2x3) .. csv-table:: mat2x3 **(src)** :header: "", "column 1", "column 2" "row 1", "a00", "a10" "row 2", "a01", "a11" "row 3", "a02", "a12" .. csv-table:: mat2x3 **(dest)** :header: "", "column 1", "column 2" "row 1", "b00 = a00", "b10 = a10" "row 2", "b01 = a01", "b11 = a11" "row 3", "b02 = a02", "b12 = a12" .. c:function:: void glm_mat2x3_zero(mat2x3 m) Zero out the mat2x3 (m). Parameters: | *[in, out]* **m** mat2x3 (src, dest) .. csv-table:: mat2x3 **(m)** :header: "", "column 1", "column 2" "row 1", "0.00", "2.00" "row 2", "5.00", "4.00" "row 3", "7.00", "6.00" .. csv-table:: mat2x3 **(m)** :header: "", "column 1", "column 2" "row 1", "0.00", "0.00" "row 2", "0.00", "0.00" "row 3", "0.00", "0.00" .. c:function:: void glm_mat2x3_make(const float * __restrict src, mat2x3 dest) Create mat2x3 (dest) from pointer (src). .. note:: **@src** must contain at least 6 elements. Parameters: | *[in]* **src** pointer to an array of floats (left) | *[out]* **dest** destination (result, mat2x3) .. csv-table:: float array (1x6) **(src)** :header: "", "column 1" "row 1", "v0" "row 2", "v1" "row 3", "v2" "row 4", "v3" "row 5", "v4" "row 6", "v5" .. csv-table:: mat2x3 **(dest)** :header: "", "column 1", "column 2" "row 1", "v0", "v3" "row 2", "v1", "v4" "row 3", "v2", "v5" .. c:function:: void glm_mat2x3_mul(mat2x3 m1, mat3x2 m2, mat3 dest) Multiply mat2x3 (m1) by mat3x2 (m2) and store in mat3 (dest). .. code-block:: c glm_mat2x3_mul(mat2x3, mat3x2, mat3); Parameters: | *[in]* **m1** mat2x3 (left) | *[in]* **m2** mat3x2 (right) | *[out]* **dest** destination (result, mat3) .. csv-table:: mat2x3 **(m1)** :header: "", "column 1", "column 2" "row 1", "a00", "a10" "row 2", "a01", "a11" "row 3", "a02", "a12" .. csv-table:: mat3x2 **(m2)** :header: "", "column 1", "column 2", "column 3" "row 1", "b00", "b10", "b20" "row 2", "b01", "b11", "b21" .. csv-table:: mat3 **(dest)** :header: "", "column 1", "column 2", "column 3" "row 1", "a00 * b00 + a10 * b01", "a00 * b10 + a10 * b11", "a00 * b20 + a10 * b21" "row 2", "a01 * b00 + a11 * b01", "a01 * b10 + a11 * b11", "a01 * b20 + a11 * b21" "row 3", "a02 * b00 + a12 * b01", "a02 * b10 + a12 * b11", "a02 * b20 + a12 * b21" .. c:function:: void glm_mat2x3_mulv(mat2x3 m, vec2 v, vec3 dest) Multiply mat2x3 (m) by vec2 (v) and store in vec3 (dest). Parameters: | *[in]* **m** mat2x3 (left) | *[in]* **v** vec2 (right, column vector) | *[out]* **dest** destination (result, column vector) .. csv-table:: mat2x3 **(m)** :header: "", "column 1", "column 2" "row 1", "m00", "m10" "row 2", "m01", "m11" "row 3", "m02", "m12" .. csv-table:: column vec2 (1x2) **(v)** :header: "", "column 1" "row 1", "v0" "row 2", "v1" .. csv-table:: column vec3 (1x3) **(dest)** :header: "", "column 1" "row 1", "m00 * v0 + m10 * v1" "row 2", "m01 * v0 + m11 * v1" "row 3", "m02 * v0 + m12 * v1" .. c:function:: void glm_mat2x3_transpose(mat2x3 src, mat3x2 dest) Transpose mat2x3 (src) and store in mat3x2 (dest). Parameters: | *[in]* **src** mat2x3 (left) | *[out]* **dest** destination (result, mat3x2) .. csv-table:: mat2x3 **(src)** :header: "", "column 1", "column 2" "row 1", "a00", "a10" "row 2", "a01", "a11" "row 3", "a02", "a12" .. csv-table:: mat3x2 **(dest)** :header: "", "column 1", "column 2", "column 3" "row 1", "b00 = a00", "b10 = a01", "b20 = a02" "row 2", "b01 = a10", "b11 = a11", "b21 = a12" .. c:function:: void glm_mat2x3_scale(mat2x3 m, float s) Multiply mat2x3 (m) by scalar constant (s). Parameters: | *[in, out]* **m** mat2x3 (src, dest) | *[in]* **s** float (scalar) .. csv-table:: mat2x3 **(m)** :header: "", "column 1", "column 2" "row 1", "m00 = m00 * s", "m10 = m10 * s" "row 2", "m01 = m01 * s", "m11 = m11 * s" "row 3", "m02 = m02 * s", "m12 = m12 * s" cglm-0.9.7/docs/source/mat2x4.rst000066400000000000000000000136161526744317200165740ustar00rootroot00000000000000.. default-domain:: C mat2x4 ====== Header: cglm/mat2x4.h Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Macros: 1. GLM_MAT2X4_ZERO_INIT #. GLM_MAT2X4_ZERO Functions: 1. :c:func:`glm_mat2x4_copy` #. :c:func:`glm_mat2x4_zero` #. :c:func:`glm_mat2x4_make` #. :c:func:`glm_mat2x4_mul` #. :c:func:`glm_mat2x4_mulv` #. :c:func:`glm_mat2x4_transpose` #. :c:func:`glm_mat2x4_scale` Represented ~~~~~~~~~~~ .. csv-table:: mat2x4 :header: "", "column 1", "column 2" "row 1", "m00", "m10" "row 2", "m01", "m11" "row 3", "m02", "m12" "row 4", "m03", "m13" Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_mat2x4_copy(mat2x4 src, mat2x4 dest) Copy mat2x4 (src) to mat2x4 (dest). Parameters: | *[in]* **src** mat2x4 (left) | *[out]* **dest** destination (result, mat2x4) .. csv-table:: mat2x4 **(src)** :header: "", "column 1", "column 2" "row 1", "a00", "a10" "row 2", "a01", "a11" "row 3", "a02", "a12" "row 4", "a03", "a13" .. csv-table:: mat2x4 **(dest)** :header: "", "column 1", "column 2" "row 1", "b00 = a00", "b10 = a10" "row 2", "b01 = a01", "b11 = a11" "row 3", "b02 = a02", "b12 = a12" "row 4", "b03 = a03", "b13 = a13" .. c:function:: void glm_mat2x4_zero(mat2x4 m) Zero out the mat2x4 (m). Parameters: | *[in, out]* **m** mat2x4 (src, dest) .. csv-table:: mat2x4 **(m)** :header: "", "column 1", "column 2" "row 1", "0.00", "2.00" "row 2", "5.00", "4.00" "row 3", "7.00", "6.00" "row 4", "23.00", "1.00" .. csv-table:: mat2x4 **(m)** :header: "", "column 1", "column 2" "row 1", "0.00", "0.00" "row 2", "0.00", "0.00" "row 3", "0.00", "0.00" "row 4", "0.00", "0.00" .. c:function:: void glm_mat2x4_make(const float * __restrict src, mat2x4 dest) Create mat2x4 (dest) from pointer (src). .. note:: **@src** must contain at least 8 elements. Parameters: | *[in]* **src** pointer to an array of floats (left) | *[out]* **dest** destination (result, mat2x4) .. csv-table:: float array (1x8) **(src)** :header: "", "column 1" "row 1", "v0" "row 2", "v1" "row 3", "v2" "row 4", "v3" "row 5", "v4" "row 6", "v5" "row 7", "v6" "row 8", "v7" .. csv-table:: mat2x4 **(dest)** :header: "", "column 1", "column 2" "row 1", "v0", "v4" "row 2", "v1", "v5" "row 3", "v2", "v6" "row 4", "v3", "v7" .. c:function:: void glm_mat2x4_mul(mat2x4 m1, mat4x2 m2, mat4 dest) Multiply mat2x4 (m1) by mat4x2 (m2) and store in mat4 (dest). .. code-block:: c glm_mat2x4_mul(mat2x4, mat4x2, mat4); Parameters: | *[in]* **m1** mat2x4 (left) | *[in]* **m2** mat4x2 (right) | *[out]* **dest** destination (result, mat4) .. csv-table:: mat2x4 **(m1)** :header: "", "column 1", "column 2" "row 1", "a00", "a10" "row 2", "a01", "a11" "row 3", "a02", "a12" "row 4", "a03", "a13" .. csv-table:: mat4x2 **(m2)** :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "b00", "b10", "b20", "b30" "row 2", "b01", "b11", "b21", "b31" .. csv-table:: mat4x4 **(dest)** :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "a00 * b00 + a10 * b01", "a00 * b10 + a10 * b11", "a00 * b20 + a10 * b21", "a00 * b30 + a10 * b31" "row 2", "a01 * b00 + a11 * b01", "a01 * b10 + a11 * b11", "a01 * b20 + a11 * b21", "a01 * b30 + a11 * b31" "row 3", "a02 * b00 + a12 * b01", "a02 * b10 + a12 * b11", "a02 * b20 + a12 * b21", "a02 * b30 + a12 * b31" "row 4", "a03 * b00 + a13 * b01", "a03 * b10 + a13 * b11", "a03 * b20 + a13 * b21", "a03 * b30 + a13 * b31" .. c:function:: void glm_mat2x4_mulv(mat2x4 m, vec2 v, vec4 dest) Multiply mat2x4 (m) by vec2 (v) and store in vec4 (dest). Parameters: | *[in]* **m** mat2x4 (left) | *[in]* **v** vec2 (right, column vector) | *[out]* **dest** destination (result, column vector) .. csv-table:: mat2x4 **(m)** :header: "", "column 1", "column 2" "row 1", "m00", "m10" "row 2", "m01", "m11" "row 3", "m02", "m12" "row 4", "m03", "m13" .. csv-table:: column vec2 (1x2) **(v)** :header: "", "column 1" "row 1", "v0" "row 2", "v1" .. csv-table:: column vec4 (1x4) **(dest)** :header: "", "column 1" "row 1", "m00 * v0 + m10 * v1" "row 2", "m01 * v0 + m11 * v1" "row 3", "m02 * v0 + m12 * v1" "row 4", "m03 * v0 + m13 * v1" .. c:function:: void glm_mat2x4_transpose(mat2x4 src, mat4x2 dest) Transpose mat2x4 (src) and store in mat4x2 (dest). Parameters: | *[in]* **src** mat2x4 (left) | *[out]* **dest** destination (result, mat4x2) .. csv-table:: mat2x4 **(src)** :header: "", "column 1", "column 2" "row 1", "a00", "a10" "row 2", "a01", "a11" "row 3", "a02", "a12" "row 4", "a03", "a13" .. csv-table:: mat4x2 **(dest)** :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "b00 = a00", "b10 = a01", "b20 = a02", "b30 = a03" "row 2", "b01 = a10", "b11 = a11", "b21 = a12", "b31 = a13" .. c:function:: void glm_mat2x4_scale(mat2x4 m, float s) Multiply mat2x4 (m) by scalar constant (s). Parameters: | *[in, out]* **m** mat2x4 (src, dest) | *[in]* **s** float (scalar) .. csv-table:: mat2x4 **(m)** :header: "", "column 1", "column 2" "row 1", "m00 = m00 * s", "m10 = m10 * s" "row 2", "m01 = m01 * s", "m11 = m11 * s" "row 3", "m02 = m02 * s", "m12 = m12 * s" "row 4", "m03 = m03 * s", "m13 = m13 * s" cglm-0.9.7/docs/source/mat3.rst000066400000000000000000001034211526744317200163130ustar00rootroot00000000000000.. default-domain:: C mat3 ==== Header: cglm/mat3.h Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Macros: 1. GLM_MAT3_IDENTITY_INIT #. GLM_MAT3_ZERO_INIT #. GLM_MAT3_IDENTITY #. GLM_MAT3_ZERO #. glm_mat3_dup(mat, dest) Functions: 1. :c:func:`glm_mat3_make` #. :c:func:`glm_mat3_copy` #. :c:func:`glm_mat3_identity` #. :c:func:`glm_mat3_identity_array` #. :c:func:`glm_mat3_zero` #. :c:func:`glm_mat3_mul` #. :c:func:`glm_mat3_mulv` #. :c:func:`glm_mat3_transpose_to` #. :c:func:`glm_mat3_transpose` #. :c:func:`glm_mat3_scale` #. :c:func:`glm_mat3_inv` #. :c:func:`glm_mat3_swap_col` #. :c:func:`glm_mat3_swap_row` #. :c:func:`glm_mat3_quat` #. :c:func:`glm_mat3_textrans` #. :c:func:`glm_mat3_det` #. :c:func:`glm_mat3_trace` #. :c:func:`glm_mat3_rmc` Represented ~~~~~~~~~~~ .. csv-table:: mat3x3 :header: "", "column 1", "column 2", "column 3" "row 1", "m00", "m10", "m20" "row 2", "m01", "m11", "m21" "row 3", "m02", "m12", "m22" Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_mat3_make(const float * __restrict src, mat3 dest) Create mat3 (dest) from pointer (src). .. note:: **@src** must contain at least 9 elements. Parameters: | *[in]* **src** pointer to an array of floats (left) | *[out]* **dest** destination (result, mat3) .. note:: Mathematical explanation .. csv-table:: float array (1x9) **(src)** :header: "", "column 1" "row 1", "v0" "row 2", "v1" "row 3", "v2" "row 4", "v3" "row 5", "v4" "row 6", "v5" "row 7", "v6" "row 8", "v7" "row 9", "v8" .. csv-table:: mat3 **(dest)** :header: "", "column 1", "column 2", "column 3" "row 1", "v0", "v3", "v6" "row 2", "v1", "v4", "v7" "row 3", "v2", "v5", "v8" .. note:: Example .. code-block:: c float src[9] = { 1.00, 5.00, 8.00, 11.00, 42.00, 33.00, 95.00, 59.00, 88.00, }; mat3 dest = GLM_MAT3_ZERO_INIT; glm_mat3_make(src, dest); .. csv-table:: float array (1x9) **(src)** :header: "", "column 1" "row 1", "1.00" "row 2", "5.00" "row 3", "8.00" "row 4", "11.00" "row 5", "42.00" "row 6", "33.00" "row 7", "95.00" "row 8", "59.00" "row 9", "88.00" .. csv-table:: mat3 **(dest)** Before :header: "", "column 1", "column 2", "column 3" "row 1", "0.00", "0.00", "0.00" "row 2", "0.00", "0.00", "0.00" "row 3", "0.00", "0.00", "0.00" .. csv-table:: mat3 **(dest)** After :header: "", "column 1", "column 2", "column 3" "row 1", "1.00", "11.00", "95.00" "row 2", "5.00", "42.00", "59.00" "row 3", "8.00", "33.00", "88.00" .. c:function:: void glm_mat3_copy(mat3 mat, mat3 dest) Copy mat3 (mat) to mat3 (dest). Parameters: | *[in]* **mat** mat3 (left, src) | *[out]* **dest** destination (result, mat3) .. note:: Mathematical explanation .. csv-table:: mat3 **(mat)** :header: "", "column 1", "column 2", "column 3" "row 1", "m00", "m10", "m20" "row 2", "m01", "m11", "m21" "row 3", "m02", "m12", "m22" .. csv-table:: mat3 **(dest)** :header: "", "column 1", "column 2", "column 3" "row 1", "m00", "m10", "m20" "row 2", "m01", "m11", "m21" "row 3", "m02", "m12", "m22" .. note:: Example .. code-block:: c mat3 mat = { {3.00,4.00,5.00}, {7.00,8.00,9.00}, {17.00,18.00,19.00}, }; mat3 dest = GLM_MAT2_ZERO_INIT; glm_mat3_copy(mat, dest); .. csv-table:: mat3 **(mat)** :header: "", "column 1", "column 2", "column 3" "row 1", "3.00", "4.00", "5.00" "row 2", "7.00", "8.00", "9.00" "row 3", "17.00", "18.00", "19.00" .. csv-table:: mat3 **(dest)** Before :header: "", "column 1", "column 2", "column 3" "row 1", "0.00", "0.00", "0.00" "row 2", "0.00", "0.00", "0.00" "row 3", "0.00", "0.00", "0.00" .. csv-table:: mat3 **(dest)** After :header: "", "column 1", "column 2", "column 3" "row 1", "3.00", "4.00", "5.00" "row 2", "7.00", "8.00", "9.00" "row 3", "17.00", "18.00", "19.00" .. c:function:: void glm_mat3_identity(mat3 m) | Copy a mat3 identity to mat3 **(m)**, or makes mat3 **(m)** an identity. | | The same thing may be achieved with either of bellow methods, | but it is more easy to do that with this func especially for members | e.g. ``glm_mat3_identity(aStruct->aMatrix);``. .. code-block:: c glm_mat3_copy(GLM_MAT3_IDENTITY, m); // or mat3 mat = GLM_MAT3_IDENTITY_INIT; Parameters: | *[in, out]* **m** mat3 (src, dest) .. note:: Mathematical explanation .. csv-table:: mat3 **(m)** :header: "", "column 1", "column 2", "column 3" "row 1", "m00", "m10", "m20" "row 2", "m01", "m11", "m21" "row 3", "m02", "m12", "m22" .. csv-table:: mat3 **(m)** :header: "", "column 1", "column 2", "column 3" "row 1", "1.00", "0.00", "0.00" "row 2", "0.00", "1.00", "0.00" "row 3", "0.00", "0.00", "1.00" .. note:: Example .. code-block:: c mat3 m = { {3.00,4.00,5.00}, {7.00,8.00,9.00}, {17.00,18.00,19.00}, }; glm_mat3_identity(m); .. csv-table:: mat3 **(m)** :header: "", "column 1", "column 2", "column 3" "row 1", "3.00", "4.00", "5.00" "row 2", "7.00", "8.00", "9.00" "row 3", "17.00", "18.00", "19.00" .. csv-table:: mat3 **(m)** :header: "", "column 1", "column 2", "column 3" "row 1", "1.00", "0.00", "0.00" "row 2", "0.00", "1.00", "0.00" "row 3", "0.00", "0.00", "1.00" .. c:function:: void glm_mat3_identity_array(mat3 * __restrict mats, size_t count) Given an array of mat3's **(mats)** make each matrix an identity matrix. Parameters: | *[in, out]* **mats** Array of mat3's (must be aligned (16/32) if alignment is not disabled) | *[in]* **count** Array size of ``mats`` or number of matrices .. note:: Mathematical explanation .. csv-table:: mat3 **(mats[index])** :header: "", "column 1", "column 2", "column 3" "row 1", "m00", "m10", "m20" "row 2", "m01", "m11", "m21" "row 3", "m02", "m12", "m22" .. csv-table:: mat3 **(mats[index])** :header: "", "column 1", "column 2", "column 3" "row 1", "1.00", "0.00", "0.00" "row 2", "0.00", "1.00", "0.00" "row 3", "0.00", "0.00", "1.00" .. note:: Example .. code-block:: c size_t count = 3; mat3 matrices[count] = { {{1.00,2.00,3.00},{10.00,11.00,12.00},{19.00,20.00,21.00}}, {{4.00,5.00,6.00},{13.00,14.00,15.00},{22.00,23.00,24.00}}, {{7.00,8.00,9.00},{16.00,17.00,18.00},{25.00,26.00,27.00}}, }; glm_mat3_identity_array(matrices, count); .. csv-table:: mat3 **(mats[0])** Before :header: "", "column 1", "column 2", "column 3" "row 1", "1.00", "10.00", "19.00" "row 2", "2.00", "11.00", "20.00" "row 3", "3.00", "12.00", "21.00" .. csv-table:: mat3 **(mats[0])** After :header: "", "column 1", "column 2", "column 3" "row 1", "1.00", "0.00", "0.00" "row 2", "0.00", "1.00", "0.00" "row 3", "0.00", "0.00", "1.00" .. csv-table:: mat3 **(mats[1])** Before :header: "", "column 1", "column 2", "column 3" "row 1", "4.00", "13.00", "22.00" "row 2", "5.00", "14.00", "23.00" "row 3", "6.00", "15.00", "24.00" .. csv-table:: mat3 **(mats[1])** After :header: "", "column 1", "column 2", "column 3" "row 1", "1.00", "0.00", "0.00" "row 2", "0.00", "1.00", "0.00" "row 3", "0.00", "0.00", "1.00" .. csv-table:: mat3 **(mats[2])** Before :header: "", "column 1", "column 2", "column 3" "row 1", "7.00", "16.00", "25.00" "row 2", "8.00", "17.00", "26.00" "row 3", "9.00", "18.00", "27.00" .. csv-table:: mat3 **(mats[2])** After :header: "", "column 1", "column 2", "column 3" "row 1", "1.00", "0.00", "0.00" "row 2", "0.00", "1.00", "0.00" "row 3", "0.00", "0.00", "1.00" .. c:function:: void glm_mat3_zero(mat3 m) Zero out the mat3 (m). Parameters: | *[in, out]* **m** mat3 (src, dest) .. note:: Mathematical explanation .. csv-table:: mat3 **(m)** :header: "", "column 1", "column 2", "column 3" "row 1", "m00", "m10", "m20" "row 2", "m01", "m11", "m21" "row 3", "m02", "m12", "m22" .. csv-table:: mat3 **(m)** :header: "", "column 1", "column 2", "column 3" "row 1", "0.00", "0.00", "0.00" "row 2", "0.00", "0.00", "0.00" "row 3", "0.00", "0.00", "0.00" .. note:: Example .. code-block:: c mat3 m = { {19.00,5.00,7.00}, {2.00,4.00,6.00}, {12.00,24.00,54.00}, }; glm_mat3_zero(m); .. csv-table:: mat3 **(m)** Before :header: "", "column 1", "column 2", "column 3" "row 1", "19.00", "2.00", "12.00" "row 2", "5.00", "4.00", "24.00" "row 3", "7.00", "6.00", "54.00" .. csv-table:: mat3 **(m)** After :header: "", "column 1", "column 2", "column 3" "row 1", "0.00", "0.00", "0.00" "row 2", "0.00", "0.00", "0.00" "row 3", "0.00", "0.00", "0.00" .. c:function:: void glm_mat3_mul(mat3 m1, mat3 m2, mat3 dest) Multiply mat3 (m1) by mat3 (m2) and store in mat3 (dest). m1, m2 and dest matrices can be same matrix, it is possible to write this: .. code-block:: c mat3 m = GLM_MAT3_IDENTITY_INIT; glm_mat3_mul(m, m, m); Parameters: | *[in]* **m1** mat3 (left) | *[in]* **m2** mat3 (right) | *[out]* **dest** destination (result, mat3) .. note:: Mathematical explanation .. csv-table:: mat3 **(m1)** :header: "", "column 1", "column 2", "column 3" "row 1", "a00", "a10", "a20" "row 2", "a01", "a11", "a21" "row 3", "a02", "a12", "a22" .. csv-table:: mat3 **(m2)** :header: "", "column 1", "column 2", "column 3" "row 1", "b00", "b10", "b20" "row 2", "b01", "b11", "b21" "row 3", "b02", "b12", "b22" .. list-table:: mat3 **(dest)** :header-rows: 1 * - - column 1 - column 2 - column 3 * - row 1 - a00 * b00 + a10 * b01 + a20 * b02 - a00 * b10 + a10 * b11 + a20 * b12 - a00 * b20 + a10 * b21 + a20 * b22 * - row 2 - a01 * b00 + a11 * b01 + a21 * b02 - a01 * b10 + a11 * b11 + a21 * b12 - a01 * b20 + a11 * b21 + a21 * b22 * - row 3 - a02 * b00 + a12 * b01 + a22 * b02 - a02 * b10 + a12 * b11 + a22 * b12 - a02 * b20 + a12 * b21 + a22 * b22 .. note:: Example .. code-block:: c mat3 m = { {19.00,5.00,6.00}, {2.00,4.00,8.00}, {1.00,3.00,7.00}, }; glm_mat3_mul(m, m, m); .. csv-table:: mat3 **(m1)** :header: "", "column 1", "column 2", "column 3" "row 1", "19.00", "2.00", "1.00" "row 2", "5.00", "4.00", "3.00" "row 3", "6.00", "8.00", "7.00" .. csv-table:: mat3 **(m2)** :header: "", "column 1", "column 2", "column 3" "row 1", "19.00", "2.00", "1.00" "row 2", "5.00", "4.00", "3.00" "row 3", "6.00", "8.00", "7.00" .. list-table:: mat3 **(dest)** :header-rows: 1 * - - column 1 - column 2 - column 3 * - row 1 - **377.00** = 19.00 * 19.00 + 2.00 * 5.00 + 1.00 * 6.00 - **54.00** = 19.00 * 2.00 + 2.00 * 4.00 + 1.00 * 8.00 - **32.00** = 19.00 * 1.00 + 2.00 * 3.00 + 1.00 * 7.00 * - row 2 - **133.00** = 5.00 * 19.00 + 4.00 * 5.00 + 3.00 * 6.00 - **50.00** = 5.00 * 2.00 + 4.00 * 4.00 + 3.00 * 8.00 - **38.00** = 5.00 * 1.00 + 4.00 * 3.00 + 3.00 * 7.00 * - row 3 - **196.00** = 6.00 * 19.00 + 8.00 * 5.00 + 7.00 * 6.00 - **100.00** = 6.00 * 2.00 + 8.00 * 4.00 + 7.00 * 8.00 - **79.00** = 6.00 * 1.00 + 8.00 * 3.00 + 7.00 * 7.00 .. c:function:: void glm_mat3_mulv(mat3 m, vec3 v, vec3 dest) Multiply mat3 (m) by vec3 (v) and store in vec3 (dest). Parameters: | *[in]* **m** mat3 (left) | *[in]* **v** vec3 (right, column vector) | *[out]* **dest** destination (result, column vector) .. note:: Mathematical explanation .. csv-table:: mat3 **(m)** :header: "", "column 1", "column 2", "column 3" "row 1", "m00", "m10", "m20" "row 2", "m01", "m11", "m21" "row 3", "m02", "m12", "m22" .. csv-table:: column vec3 (1x3) **(v)** :header: "", "column 1" "row 1", "v0" "row 2", "v1" "row 3", "v2" .. csv-table:: column vec3 (1x3) **(dest)** :header: "", "column 1" "row 1", "m00 * v0 + m10 * v1 + m20 * v2" "row 2", "m01 * v0 + m11 * v1 + m21 * v2" "row 3", "m02 * v0 + m12 * v1 + m22 * v2" .. note:: Example .. code-block:: c vec3 dest; vec3 v = {33.00,55.00,77.00}; mat3 m = { {1.00,2.00,3.00}, {4.00,5.00,6.00}, {7.00,8.00,9.00}, }; glm_mat3_mulv(m, v, dest); .. csv-table:: mat3 **(m)** :header: "", "column 1", "column 2", "column 3" "row 1", "1.00", "4.00", "7.00" "row 2", "2.00", "5.00", "8.00" "row 3", "3.00", "6.00", "9.00" .. csv-table:: column vec3 **(v)** :header: "", "column 1" "row 1", "33.00" "row 2", "55.00" "row 3", "77.00" .. csv-table:: vec2 **(dest)** Result :header: "", "column 1" "row 1", "**792.00** = 1.00 * 33.00 + 4.00 * 55.00 + 7.00 * 77.00" "row 2", "**957.00** = 2.00 * 33.00 + 5.00 * 55.00 + 8.00 * 77.00" "row 3", "**1122.00** = 3.00 * 33.00 + 6.00 * 55.00 + 9.00 * 77.00" .. c:function:: void glm_mat3_transpose_to(mat3 mat, mat3 dest) Transpose mat3 (mat) and store in mat3 (dest). Parameters: | *[in]* **mat** mat3 (left,src) | *[out]* **dest** destination (result, mat3) .. note:: Mathematical explanation .. csv-table:: mat3 **(mat)** :header: "", "column 1", "column 2", "column 3" "row 1", "m00", "m10", "m20" "row 2", "m01", "m11", "m21" "row 3", "m02", "m12", "m22" .. csv-table:: mat3 **(dest)** :header: "", "column 1", "column 2", "column 3" "row 1", "m00", "m01", "m02" "row 2", "m10", "m11", "m12" "row 3", "m20", "m21", "m22" .. note:: Example .. code-block:: c mat3 mat = { {1.00,2.00,3.00}, {4.00,5.00,6.00}, {7.00,8.00,9.00}, }; mat3 dest = GLM_MAT3_ZERO_INIT; glm_mat3_transpose_to(mat, dest); .. csv-table:: mat3 **(mat)** :header: "", "column 1", "column 2", "column 3" "row 1", "1.00", "4.00", "7.00" "row 2", "2.00", "5.00", "8.00" "row 3", "3.00", "6.00", "9.00" .. csv-table:: mat3 **(dest)** Before :header: "", "column 1", "column 2", "column 3" "row 1", "0.00", "0.00", "0.00" "row 2", "0.00", "0.00", "0.00" "row 3", "0.00", "0.00", "0.00" .. csv-table:: mat3 **(dest)** After :header: "", "column 1", "column 2", "column 3" "row 1", "1.00", "2.00", "3.00" "row 2", "4.00", "5.00", "6.00" "row 2", "7.00", "8.00", "9.00" .. c:function:: void glm_mat3_transpose(mat3 m) Transpose mat3 (m) and store result in the same matrix. Parameters: | *[in, out]* **m** mat3 (src, dest) .. note:: Mathematical explanation .. csv-table:: mat3 **(m)** src :header: "", "column 1", "column 2", "column 3" "row 1", "m00", "m10", "m20" "row 2", "m01", "m11", "m21" "row 2", "m02", "m12", "m22" .. csv-table:: mat3 **(m)** dest :header: "", "column 1", "column 2", "column 3" "row 1", "m00", "m01", "m02" "row 2", "m10", "m11", "m12" "row 3", "m20", "m21", "m22" .. note:: Example .. code-block:: c mat3 mat = { {1.00,2.00,3.00}, {4.00,5.00,6.00}, {7.00,8.00,9.00}, }; glm_mat3_transpose(m); .. csv-table:: mat3 **(m)** Before :header: "", "column 1", "column 2", "column 3" "row 1", "1.00", "4.00", "7.00" "row 2", "2.00", "5.00", "8.00" "row 3", "3.00", "6.00", "9.00" .. csv-table:: mat3 **(m)** After :header: "", "column 1", "column 2", "column 3" "row 1", "1.00", "2.00", "3.00" "row 2", "4.00", "5.00", "6.00" "row 2", "7.00", "8.00", "9.00" .. c:function:: void glm_mat3_scale(mat3 m, float s) Multiply mat3 (m) by scalar constant (s). Parameters: | *[in, out]* **m** mat3 (src, dest) | *[in]* **s** float (scalar) .. note:: Mathematical explanation .. csv-table:: mat3 **(m)** :header: "", "column 1", "column 2", "column 3" "row 1", "m00 * s", "m10 * s", "m20 * s" "row 2", "m01 * s", "m11 * s", "m21 * s" "row 3", "m02 * s", "m12 * s", "m22 * s" .. note:: Example .. code-block:: c mat3 m = { {1.00,2.00,3.00}, {4.00,5.00,6.00}, {7.00,8.00,9.00}, }; float s = 3.00f; glm_mat3_scale(m, s); .. csv-table:: mat3 **(m)** Before :header: "", "column 1", "column 2", "column 3" "row 1", "1.00", "4.00", "7.00" "row 2", "2.00", "5.00", "8.00" "row 3", "3.00", "6.00", "9.00" .. list-table:: mat3 **(m)** After :header-rows: 1 * - - column 1 - column 2 - column 3 * - row 1 - **3.00** = 1.00 * 3.00 - **12.00** = 4.00 * 3.00 - **21.00** = 7.00 * 3.00 * - row 2 - **6.00** = 2.00 * 3.00 - **15.00** = 5.00 * 3.00 - **24.00** = 8.00 * 3.00 * - row 3 - **9.00** = 3.00 * 3.00 - **18.00** = 6.00 * 3.00 - **27.00** = 9.00 * 3.00 .. c:function:: void glm_mat3_inv(mat3 mat, mat3 dest) Inverse mat3 (mat) and store in mat3 (dest). Parameters: | *[in]* **mat** mat3 (left, src) | *[out]* **dest** destination (result, inverse mat3) .. note:: Mathematical explanation .. csv-table:: mat3 **(mat)** :header: "", "column 1", "column 2", "column 3", "", "" "row 1", "m00", "m10", "m20", "**m00**", "**m10**" "row 2", "m01", "m11", "m21", "**m01**", "**m11**" "row 3", "m02", "m12", "m22", "**m02**", "**m12**" " ", "**m00**", "**m10**", "**m20**", "**m00**", "**m10**" " ", "**m01**", "**m11**", "**m21**", "**m01**", "**m11**" | For more information see `How to find the inverse of a 3 by 3 matrix (the fast way)[youtube]`_. | Remember we are in column major not row major. So, the way the table is populated is slightly different. | In terms of multiplication priority goes from m00,m01,m02,m11,...,m22. | May utilize the distributive law to acquire bellow equations .. math:: (m00 * m11 * m22) - (m00 * m21 * m12) = m00 * (m11 * m22 - m21 * m12) .. list-table:: mat3 **(dest)** :header-rows: 1 * - - column 1 - column 2 - column 3 * - row 1 - | 1.0f / ( | m00 * (m11 * m22 - m12 * m21) - | m01 * (m10 * m22 - m20 * m12) + | m02 * (m10 * m21 - m20 * m11) | ) * (m11 * m22 - m12 * m21) - | -( 1.0f / ( | m00 * (m11 * m22 - m12 * m21) - | m01 * (m10 * m22 - m20 * m12) + | m02 * (m10 * m21 - m20 * m11) | ) ) * (m10 * m22 - m20 * m12) - | 1.0f / ( | m00 * (m11 * m22 - m12 * m21) - | m01 * (m10 * m22 - m20 * m12) + | m02 * (m10 * m21 - m20 * m11) | ) * (m10 * m21 - m11 * m20) * - row 2 - | -( 1.0f / ( | m00 * (m11 * m22 - m12 * m21) - | m01 * (m10 * m22 - m20 * m12) + | m02 * (m10 * m21 - m20 * m11) | ) ) * (m01 * m22 - m21 * m02) - | 1.0f / ( | m00 * (m11 * m22 - m12 * m21) - | m01 * (m10 * m22 - m20 * m12) + | m02 * (m10 * m21 - m20 * m11) | ) * (m00 * m22 - m20 * m02) - | -( 1.0f / ( | m00 * (m11 * m22 - m12 * m21) - | m01 * (m10 * m22 - m20 * m12) + | m02 * (m10 * m21 - m20 * m11) | ) ) * (m00 * m21 - m20 * m01) * - row 3 - | 1.0f / ( | m00 * (m11 * m22 - m12 * m21) - | m01 * (m10 * m22 - m20 * m12) + | m02 * (m10 * m21 - m20 * m11) | ) * (m01 * m12 - m11 * m02) - | -( 1.0f / ( | m00 * (m11 * m22 - m12 * m21) - | m01 * (m10 * m22 - m20 * m12) + | m02 * (m10 * m21 - m20 * m11) | ) ) * (m00 * m12 - m10 * m02) - | 1.0f / ( | m00 * (m11 * m22 - m12 * m21) - | m01 * (m10 * m22 - m20 * m12) + | m02 * (m10 * m21 - m20 * m11) | ) * (m00 * m11 - m10 * m01) .. note:: Example .. code-block:: c mat3 mat = { {8.00,6.00,5.00}, {16.00,31.00,25.00}, {13.00,18.00,7.00}, }; mat3 dest = GLM_MAT3_ZERO_INIT; glm_mat3_inv(mat, dest); .. csv-table:: mat3 **(mat)** Before :header: "", "column 1", "column 2", "column 3", "", "" "row 1", "8.00", "16.00", "13.00", "**8.00**", "**16.00**" "row 2", "6.00", "31.00", "18.00", "**6.00**", "**31.00**" "row 3", "5.00", "25.00", "7.00", "**5.00**", "**25.00**" " ", "**8.00**", "**16.00**", "**13.00**", "**8.00**", "**16.00**" " ", "**6.00**", "**31.00**", "**18.00**", "**6.00**", "**31.00**" .. list-table:: mat3 **(dest)** After :header-rows: 1 * - - column 1 - column 2 - column 3 * - row 1 - | **0.200** = 1.0 / ( | 8.00 * (31.00 * 7.00 - 25.00 * 18.00) - | 6.00 * (16.00 * 7.00 - 13.00 * 25.00) + | 5.00 * (16.00 * 18.00 - 13.00 * 31.00) | ) * (31.00 * 7.00 - 25.00 * 18.00) - | **-0.184** = -( 1.0 / ( | 8.00 * (31.00 * 7.00 - 25.00 * 18.00) - | 6.00 * (16.00 * 7.00 - 13.00 * 25.00) + | 5.00 * (16.00 * 18.00 - 13.00 * 31.00) | ) ) * (16.00 * 7.00 - 13.00 * 25.00) - | **0.099** = 1.0 / ( | 8.00 * (31.00 * 7.00 - 25.00 * 18.00) - | 6.00 * (16.00 * 7.00 - 13.00 * 25.00) + | 5.00 * (16.00 * 18.00 - 13.00 * 31.00) | ) * (16.00 * 18.00 - 31.00 * 13.00) * - row 2 - | **-0.041** = -( 1.0 / ( | 8.00 * (31.00 * 7.00 - 25.00 * 18.00) - | 6.00 * (16.00 * 7.00 - 13.00 * 25.00) + | 5.00 * (16.00 * 18.00 - 13.00 * 31.00) | ) ) * (6.00 * 7.00 - 18.00 * 5.00) - | **0.007** = 1.0 / ( | 8.00 * (31.00 * 7.00 - 25.00 * 18.00) - | 6.00 * (16.00 * 7.00 - 13.00 * 25.00) + | 5.00 * (16.00 * 18.00 - 13.00 * 31.00) | ) * (8.00 * 7.00 - 13.00 * 5.00) - | **-0.056** = -( 1.0 / ( | 8.00 * (31.00 * 7.00 - 25.00 * 18.00) - | 6.00 * (16.00 * 7.00 - 13.00 * 25.00) + | 5.00 * (16.00 * 18.00 - 13.00 * 31.00) | ) ) * (8.00 * 18.00 - 13.00 * 6.00) * - row 3 - | **0.004** = 1.0 / ( | 8.00 * (31.00 * 7.00 - 25.00 * 18.00) - | 6.00 * (16.00 * 7.00 - 13.00 * 25.00) + | 5.00 * (16.00 * 18.00 - 13.00 * 31.00) | ) * (6.00 * 25.00 - 31.00 * 5.00) - | **0.103** = -( 1.0 / ( | 8.00 * (31.00 * 7.00 - 25.00 * 18.00) - | 6.00 * (16.00 * 7.00 - 13.00 * 25.00) + | 5.00 * (16.00 * 18.00 - 13.00 * 31.00) | ) ) * (8.00 * 25.00 - 16.00 * 5.00) - | **-0.130** = 1.0 / ( | 8.00 * (31.00 * 7.00 - 25.00 * 18.00) - | 6.00 * (16.00 * 7.00 - 13.00 * 25.00) + | 5.00 * (16.00 * 18.00 - 13.00 * 31.00) | ) * (8.00 * 31.00 - 16.00 * 6.00) .. c:function:: void glm_mat3_swap_col(mat3 mat, int col1, int col2) Swap two columns in mat3 (mat) and store in same matrix. Parameters: | *[in, out]* **mat** mat3 (src, dest) | *[in]* **col1** Column 1 array index | *[in]* **col2** Column 2 array index .. note:: Mathematical explanation .. csv-table:: mat3 **(mat)** Before :header: "", "column 1", "column 2", "column 3" "row 1", "m00", "m10", "m20" "row 2", "m01", "m11", "m21" "row 3", "m02", "m12", "m22" .. code-block:: c glm_mat3_swap_col(mat, 0, 1); .. csv-table:: mat3 **(mat)** After :header: "", "column 1", "column 2", "column 3" "row 1", "m10", "m00", "m20" "row 2", "m11", "m01", "m21" "row 3", "m12", "m02", "m22" .. note:: Example .. code-block:: c mat3 mat = { {8.00,6.00,5.00}, {16.00,31.00,25.00}, {13.00,18.00,7.00}, }; glm_mat3_swap_col(mat, 0, 1); .. csv-table:: mat3 **(mat)** Before :header: "", "column 1", "column 2", "column 3" "row 1", "8.00", "16.00", "13.00" "row 2", "6.00", "31.00", "18.00" "row 3", "5.00", "25.00", "7.00" .. csv-table:: mat3 **(mat)** After :header: "", "column 1", "column 2", "column 3" "row 1", "16.00", "8.00", "13.00" "row 2", "31.00", "6.00", "18.00" "row 3", "25.00", "5.00", "7.00" .. c:function:: void glm_mat3_swap_row(mat3 mat, int row1, int row2) Swap two rows in mat3 (mat) and store in same matrix. Parameters: | *[in, out]* **mat** mat3 (src, dest) | *[in]* **row1** Row 1 array index | *[in]* **row2** Row 2 array index .. note:: Mathematical explanation .. csv-table:: mat3 **(mat)** Before :header: "", "column 1", "column 2", "column 3" "row 1", "m00", "m10", "m20" "row 2", "m01", "m11", "m21" "row 3", "m02", "m12", "m22" .. code-block:: c glm_mat3_swap_row(mat, 0, 1); .. csv-table:: mat3 **(mat)** After :header: "", "column 1", "column 2", "column 3" "row 1", "m01", "m11", "m21" "row 2", "m00", "m10", "m20" "row 3", "m02", "m12", "m22" .. note:: Example .. code-block:: c mat3 mat = { {8.00,6.00,5.00}, {16.00,31.00,25.00}, {13.00,18.00,7.00}, }; glm_mat3_swap_col(mat, 0, 1); .. csv-table:: mat3 **(mat)** Before :header: "", "column 1", "column 2", "column 3" "row 1", "8.00", "16.00", "13.00" "row 2", "6.00", "31.00", "18.00" "row 3", "5.00", "25.00", "7.00" .. csv-table:: mat3 **(mat)** After :header: "", "column 1", "column 2", "column 3" "row 1", "6.00", "31.00", "18.00" "row 2", "8.00", "16.00", "13.00" "row 3", "5.00", "25.00", "7.00" .. c:function:: void glm_mat3_quat(mat3 m, versor dest) convert mat3 to quaternion Parameters: | *[in]* **m** rotation matrix | *[out]* **dest** destination quaternion .. c:function:: void glm_mat3_textrans(float sx, float sy, float rot, float tx, float ty, mat3 dest) Create texture transformation matrix, rotation is in radians CCW/RH Parameters: | *[in]* **sx** scale x | *[in]* **sy** scale y | *[in]* **rot** rotation in radians CCW/RH | *[in]* **tx** translation x | *[in]* **ty** translation y | *[out]* **dest** destination matrix3x3 .. c:function:: float glm_mat3_det(mat3 m) Returns mat3 determinant. Parameters: | *[in]* **m** mat3 (src) Returns: | mat3 determinant (float) .. note:: Mathematical explanation .. csv-table:: mat3 **(mat)** :header: "", "column 1", "column 2", "column 3", "", "" "row 1", "m00", "m10", "m20", "**m00**", "**m10**" "row 2", "m01", "m11", "m21", "**m01**", "**m11**" "row 3", "m02", "m12", "m22", "**m02**", "**m12**" " ", "**m00**", "**m10**", "**m20**", "**m00**", "**m10**" " ", "**m01**", "**m11**", "**m21**", "**m01**", "**m11**" | For more information see first portion of | `How to find the inverse of a 3 by 3 matrix (the fast way)[youtube]`_. .. code-block:: c m00 * (m11 * m22 - m12 * m21) - m01 * (m10 * m22 - m20 * m12) + m02 * (m10 * m21 - m20 * m11) .. note:: Example .. code-block:: c mat3 m = { {8.00,6.00,5.00}, {16.00,31.00,25.00}, {13.00,18.00,7.00}, }; glm_mat3_det(m); .. csv-table:: mat3 **(m)** :header: "", "column 1", "column 2", "column 3", "", "" "row 1", "8.00", "16.00", "13.00", "**8.00**", "**16.00**" "row 2", "6.00", "31.00", "18.00", "**6.00**", "**31.00**" "row 3", "5.00", "25.00", "7.00", "**5.00**", "**25.00**" .. code-block:: c -1161.00 = 8.00 * (31.00 * 7.00 - 25.00 * 18.00) - 6.00 * (16.00 * 7.00 - 13.00 * 25.00) + 5.00 * (16.00 * 18.00 - 13.00 * 31.00) .. c:function:: void glm_mat3_trace(mat3 m) | Returns trace of matrix. Which is: | | The sum of the elements on the main diagonal from | upper left corner to the bottom right corner. Parameters: | *[in]* **m** mat3 (src) Returns: | mat3 trace (float) .. note:: Mathematical explanation .. csv-table:: mat3 **(m)** :header: "", "column 1", "column 2", "column 3" "row 1", "m00", "m10", "m20" "row 2", "m01", "m11", "m21" "row 3", "m02", "m12", "m22" .. code-block:: c m00 + m11 + m22 .. note:: Example .. code-block:: c mat3 m = { {8.00,6.00,5.00}, {16.00,31.00,25.00}, {13.00,18.00,7.00}, }; glm_mat3_trace(m); .. csv-table:: mat3 **(m)** :header: "", "column 1", "column 2", "column 3" "row 1", "8.00", "16.00", "13.00" "row 2", "6.00", "31.00", "18.00" "row 3", "5.00", "25.00", "7.00" .. code-block:: c 82.00 = 8.00 + 31.00 + 7.00 .. c:function:: float glm_mat3_rmc(vec3 r, mat3 m, vec3 c) | Helper for R (row vector) * M (matrix) * C (column vector) | | **rmc** stands for **Row** * **Matrix** * **Column** | | the result is scalar because M * C = ResC (1x2, column vector), | then if you take the dot_product(R (3x1), ResC (1x3)) = scalar value. Parameters: | *[in]* **r** vec3 (3x1, row vector) | *[in]* **m** mat3 (2x2, matrix) | *[in]* **c** vec3 (1x3, column vector) Returns: | Scalar value (float, 1x1) .. note:: Mathematical explanation .. csv-table:: row vec3 (3x1) **(r)** :header: "", "column 1", "column 2", "column 3" "row 1", "a00", "a10", "a20" .. csv-table:: mat3 **(m)** :header: "", "column 1", "column 2", "column 3" "row 1", "b00", "b10", "b20" "row 2", "b01", "b11", "b21" "row 3", "b02", "b12", "b22" .. csv-table:: column vec3 (1x3) **(c)** :header: "", "column 1" "row 1", "c00" "row 2", "c01" "row 3", "c02" .. code-block:: c M * C = C (column vector) dot_product(R, C) .. csv-table:: column vec3 (1x3) **(C)** :header: "", "column 1" "row 1", "b00 * c00 + b10 * c01 + b20 * c02" "row 2", "b01 * c00 + b11 * c01 + b21 * c02" "row 3", "b02 * c00 + b11 * c01 + b22 * c02" .. list-table:: float **(scalar)** :header-rows: 1 * - - column 1 * - row 1 - | a00 * (b00 * c00 + b10 * c01 + b20 * c02) + | a10 * (b01 * c00 + b11 * c01 + b21 * c02) + | a20 * (b02 * c00 + b11 * c01 + b22 * c02) .. note:: Example .. code-block:: c vec3 r = {8.00,4.00,13.00}; vec3 c = {7.00,2.00,9.00}; mat3 m = { {8.00,6.00,5.00}, {16.00,31.00,25.00}, {13.00,18.00,7.00}, }; glm_mat3_rmc(r, m, c); .. csv-table:: row vec3 (3x1) **(r)** :header: "", "column 1", "column 2", "column 3" "row 1", "8.00", "4.00", "13.00" .. csv-table:: mat3 **(m)** :header: "", "column 1", "column 2", "column 3" "row 1", "8.00", "16.00", "13.00" "row 2", "6.00", "31.00", "18.00" "row 3", "5.00", "25.00", "7.00" .. csv-table:: column vec3 (1x3) **(c)** :header: "", "column 1" "row 1", "7.00" "row 2", "2.00" "row 3", "9.00" .. csv-table:: column vec3 (1x3) **(C)** :header: "", "column 1" "row 1", "**205.00** = 8.00 * 7.00 + 16.00 * 2.00 + 13.00 * 9.00" "row 2", "**266.00** = 6.00 * 7.00 + 31.00 * 2.00 + 18.00 * 9.00" "row 3", "**148.00** = 5.00 * 7.00 + 25.00 * 2.00 + 7.00 * 9.00" .. csv-table:: float (1x1) **(scalar)** :header: "", "column 1" "row 1", "**4628.00** = 8.00 * 205.00 + 4.00 * 266.00 + 13.00 * 148.00" .. _How to find the inverse of a 3 by 3 matrix (the fast way)[youtube]: https://www.youtube.com/watch?v=p8VnTCfJHAo cglm-0.9.7/docs/source/mat3x2.rst000066400000000000000000000121521526744317200165650ustar00rootroot00000000000000.. default-domain:: C mat3x2 ====== Header: cglm/mat3x2.h Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Macros: 1. GLM_MAT3X2_ZERO_INIT #. GLM_MAT3X2_ZERO Functions: 1. :c:func:`glm_mat3x2_copy` #. :c:func:`glm_mat3x2_zero` #. :c:func:`glm_mat3x2_make` #. :c:func:`glm_mat3x2_mul` #. :c:func:`glm_mat3x2_mulv` #. :c:func:`glm_mat3x2_transpose` #. :c:func:`glm_mat3x2_scale` Represented ~~~~~~~~~~~ .. csv-table:: mat3x2 :header: "", "column 1", "column 2", "column 3" "row 1", "m00", "m10", "m20" "row 2", "m01", "m11", "m21" Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_mat3x2_copy(mat3x2 src, mat3x2 dest) Copy mat3x2 (src) to mat3x2 (dest). Parameters: | *[in]* **src** mat3x2 (left) | *[out]* **dest** destination (result, mat3x2) .. csv-table:: mat3x2 **(src)** :header: "", "column 1", "column 2", "column 3" "row 1", "a00", "a10", "a20" "row 2", "a01", "a11", "a21" .. csv-table:: mat3x2 **(dest)** :header: "", "column 1", "column 2", "column 3" "row 1", "b00 = a00", "b10 = a10", "b20 = a20" "row 2", "b01 = a01", "b11 = a11", "b21 = a21" .. c:function:: void glm_mat3x2_zero(mat3x2 m) Zero out the mat3x2 (m). Parameters: | *[in, out]* **m** mat3x2 (src, dest) .. csv-table:: mat3x2 **(m)** :header: "", "column 1", "column 2", "column 3" "row 1", "0.00", "2.00", "15.00" "row 2", "5.00", "4.00", "6.00" .. csv-table:: mat3x2 **(m)** :header: "", "column 1", "column 2", "column 3" "row 1", "0.00", "0.00", "0.00" "row 2", "0.00", "0.00", "0.00" .. c:function:: void glm_mat3x2_make(const float * __restrict src, mat3x2 dest) Create mat3x2 (dest) from pointer (src). .. note:: **@src** must contain at least 6 elements. Parameters: | *[in]* **src** pointer to an array of floats (left) | *[out]* **dest** destination (result, mat3x2) .. csv-table:: float array (1x6) **(src)** :header: "", "column 1" "row 1", "v0" "row 2", "v1" "row 3", "v2" "row 4", "v3" "row 5", "v4" "row 6", "v5" .. csv-table:: mat3x2 **(dest)** :header: "", "column 1", "column 2", "column 3" "row 1", "v0", "v2", "v4" "row 2", "v1", "v3", "v5" .. c:function:: void glm_mat3x2_mul(mat3x2 m1, mat2x3 m2, mat2 dest) Multiply mat3x2 (m1) by mat2x3 (m2) and store in mat2 (dest). .. code-block:: c glm_mat3x2_mul(mat3x2, mat2x3, mat2); Parameters: | *[in]* **m1** mat3x2 (left) | *[in]* **m2** mat2x3 (right) | *[out]* **dest** destination (result, mat2) .. csv-table:: mat3x2 **(m1)** :header: "", "column 1", "column 2", "column 3" "row 1", "a00", "a10", "a20" "row 2", "a01", "a11", "a21" .. csv-table:: mat2x3 **(m2)** :header: "", "column 1", "column 2" "row 1", "b00", "b10" "row 2", "b01", "b11" "row 3", "b02", "b12" .. csv-table:: mat2x2 **(dest)** :header: "", "column 1", "column 2" "row 1", "a00 * b00 + a10 * b01 + a20 * b02", "a00 * b10 + a10 * b11 + a20 * b12" "row 2", "a01 * b00 + a11 * b01 + a21 * b02", "a01 * b10 + a11 * b11 + a21 * b12" .. c:function:: void glm_mat3x2_mulv(mat3x2 m, vec3 v, vec2 dest) Multiply mat3x2 (m) by vec3 (v) and store in vec2 (dest). Parameters: | *[in]* **m** mat3x2 (left) | *[in]* **v** vec3 (right, column vector) | *[out]* **dest** destination (result, column vector) .. csv-table:: mat3x2 **(m)** :header: "", "column 1", "column 2", "column 3" "row 1", "m00", "m10", "m20" "row 2", "m01", "m11", "m21" .. csv-table:: column vec3 (1x3) **(v)** :header: "", "column 1" "row 1", "v0" "row 2", "v1" "row 3", "v2" .. csv-table:: column vec2 (1x2) **(dest)** :header: "", "column 1" "row 1", "m00 * v0 + m10 * v1 + m20 * v2" "row 2", "m01 * v0 + m11 * v1 + m21 * v2" .. c:function:: void glm_mat3x2_transpose(mat3x2 src, mat2x3 dest) Transpose mat3x2 (src) and store in mat2x3 (dest). Parameters: | *[in]* **src** mat3x2 (left) | *[out]* **dest** destination (result, mat2x3) .. csv-table:: mat3x2 **(src)** :header: "", "column 1", "column 2", "column 3" "row 1", "a00", "a10", "a20" "row 2", "a01", "a11", "a21" .. csv-table:: mat2x3 **(dest)** :header: "", "column 1", "column 2" "row 1", "b00 = a00", "b10 = a01" "row 2", "b01 = a10", "b11 = a11" "row 3", "b02 = a20", "b12 = a21" .. c:function:: void glm_mat3x2_scale(mat3x2 m, float s) Multiply mat3x2 (m) by scalar constant (s). Parameters: | *[in, out]* **m** mat3x2 (src, dest) | *[in]* **s** float (scalar) .. csv-table:: mat3x2 **(m)** :header: "", "column 1", "column 2", "column 3" "row 1", "m00 = m00 * s", "m10 = m10 * s", "m20 = m20 * s" "row 2", "m01 = m01 * s", "m11 = m11 * s", "m21 = m21 * s" cglm-0.9.7/docs/source/mat3x4.rst000066400000000000000000000154671526744317200166030ustar00rootroot00000000000000.. default-domain:: C mat3x4 ====== Header: cglm/mat3x4.h Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Macros: 1. GLM_MAT3X4_ZERO_INIT #. GLM_MAT3X4_ZERO Functions: 1. :c:func:`glm_mat3x4_copy` #. :c:func:`glm_mat3x4_zero` #. :c:func:`glm_mat3x4_make` #. :c:func:`glm_mat3x4_mul` #. :c:func:`glm_mat3x4_mulv` #. :c:func:`glm_mat3x4_transpose` #. :c:func:`glm_mat3x4_scale` Represented ~~~~~~~~~~~ .. csv-table:: mat3x4 :header: "", "column 1", "column 2", "column 3" "row 1", "m00", "m10", "m20" "row 2", "m01", "m11", "m21" "row 3", "m02", "m12", "m22" "row 4", "m03", "m13", "m23" Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_mat3x4_copy(mat3x4 src, mat3x4 dest) Copy mat3x4 (src) to mat3x4 (dest). Parameters: | *[in]* **src** mat3x4 (left) | *[out]* **dest** destination (result, mat3x4) .. csv-table:: mat3x4 **(src)** :header: "", "column 1", "column 2", "column 3" "row 1", "a00", "a10", "a20" "row 2", "a01", "a11", "a21" "row 3", "a02", "a12", "a22" "row 4", "a03", "a13", "a23" .. csv-table:: mat3x4 **(dest)** :header: "", "column 1", "column 2", "column 3" "row 1", "b00 = a00", "b10 = a10", "b20 = a20" "row 2", "b01 = a01", "b11 = a11", "b21 = a21" "row 3", "b02 = a02", "b12 = a12", "b22 = a22" "row 4", "b03 = a03", "b13 = a13", "b23 = a23" .. c:function:: void glm_mat3x4_zero(mat3x4 m) Zero out the mat3x4 (m). Parameters: | *[in, out]* **m** mat3x4 (src, dest) .. csv-table:: mat3x4 **(m)** :header: "", "column 1", "column 2", "column 3" "row 1", "0.00", "2.00", "78.00" "row 2", "5.00", "4.00", "12.00" "row 3", "7.00", "6.00", "32.00" "row 4", "23.00", "1.00", "9.00" .. csv-table:: mat3x4 **(m)** :header: "", "column 1", "column 2", "column 3" "row 1", "0.00", "0.00", "0.00" "row 2", "0.00", "0.00", "0.00" "row 3", "0.00", "0.00", "0.00" "row 4", "0.00", "0.00", "0.00" .. c:function:: void glm_mat3x4_make(const float * __restrict src, mat3x4 dest) Create mat3x4 (dest) from pointer (src). .. note:: **@src** must contain at least 12 elements. Parameters: | *[in]* **src** pointer to an array of floats (left) | *[out]* **dest** destination (result, mat3x4) .. csv-table:: float array (1x12) **(src)** :header: "", "column 1" "row 1", "v0" "row 2", "v1" "row 3", "v2" "row 4", "v3" "row 5", "v4" "row 6", "v5" "row 7", "v6" "row 8", "v7" "row 9", "v8" "row 10", "v9" "row 11", "v10" "row 12", "v11" .. csv-table:: mat3x4 **(dest)** :header: "", "column 1", "column 2", "column 3" "row 1", "v0", "v4", "v8" "row 2", "v1", "v5", "v9" "row 3", "v2", "v6", "v10" "row 4", "v3", "v7", "v11" .. c:function:: void glm_mat3x4_mul(mat3x4 m1, mat4x3 m2, mat4 dest) Multiply mat3x4 (m1) by mat4x3 (m2) and store in mat4 (dest). .. code-block:: c glm_mat3x4_mul(mat3x4, mat4x3, mat4); Parameters: | *[in]* **m1** mat2x4 (left) | *[in]* **m2** mat4x2 (right) | *[out]* **dest** destination (result, mat4) .. csv-table:: mat3x4 **(m1)** :header: "", "column 1", "column 2", "column 3" "row 1", "a00", "a10", "a20" "row 2", "a01", "a11", "a21" "row 3", "a02", "a12", "a22" "row 4", "a03", "a13", "a23" .. csv-table:: mat4x3 **(m2)** :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "b00", "b10", "b20", "b30" "row 2", "b01", "b11", "b21", "b31" "row 3", "b02", "b12", "b22", "b32" .. csv-table:: mat4x4 **(dest)** :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "a00 * b00 + a10 * b01 + a20 * b02", "a00 * b10 + a10 * b11 + a20 * b12", "a00 * b20 + a10 * b21 + a20 * b22", "a00 * b30 + a10 * b31 + a20 * b32" "row 2", "a01 * b00 + a11 * b01 + a21 * b02", "a01 * b10 + a11 * b11 + a21 * b12", "a01 * b20 + a11 * b21 + a21 * b22", "a01 * b30 + a11 * b31 + a21 * b32" "row 3", "a02 * b00 + a12 * b01 + a22 * b02", "a02 * b10 + a12 * b11 + a22 * b12", "a02 * b20 + a12 * b21 + a22 * b22", "a02 * b30 + a12 * b31 + a22 * b32" "row 4", "a03 * b00 + a13 * b01 + a23 * b02", "a03 * b10 + a13 * b11 + a23 * b12", "a03 * b20 + a13 * b21 + a23 * b22", "a03 * b30 + a13 * b31 + a23 * b32" .. c:function:: void glm_mat3x4_mulv(mat3x4 m, vec3 v, vec4 dest) Multiply ma3x4 (m) by vec3 (v) and store in vec4 (dest). Parameters: | *[in]* **m** mat3x4 (left) | *[in]* **v** vec3 (right, column vector) | *[out]* **dest** destination (result, column vector) .. csv-table:: mat3x4 **(m)** :header: "", "column 1", "column 2", "column 3" "row 1", "m00", "m10", "m20" "row 2", "m01", "m11", "m21" "row 3", "m02", "m12", "m22" "row 4", "m03", "m13", "m23" .. csv-table:: column vec3 (1x3) **(v)** :header: "", "column 1" "row 1", "v0" "row 2", "v1" "row 3", "v2" .. csv-table:: column vec4 (1x4) **(dest)** :header: "", "column 1" "row 1", "m00 * v0 + m10 * v1 + m20 * v2" "row 2", "m01 * v0 + m11 * v1 + m21 * v2" "row 3", "m02 * v0 + m12 * v1 + m22 * v2" "row 4", "m03 * v0 + m13 * v1 + m23 * v2" .. c:function:: void glm_mat3x4_transpose(mat3x4 src, mat4x3 dest) Transpose mat3x4 (src) and store in mat4x3 (dest). Parameters: | *[in]* **src** mat3x4 (left) | *[out]* **dest** destination (result, mat4x3) .. csv-table:: mat3x4 **(src)** :header: "", "column 1", "column 2", "column 3" "row 1", "a00", "a10", "a20" "row 2", "a01", "a11", "a21" "row 3", "a02", "a12", "a22" "row 4", "a03", "a13", "a23" .. csv-table:: mat4x3 **(dest)** :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "b00 = a00", "b10 = a01", "b20 = a02", "b30 = a03" "row 2", "b01 = a10", "b11 = a11", "b21 = a12", "b31 = a13" "row 3", "b02 = a20", "b12 = a21", "b22 = a22", "b32 = a23" .. c:function:: void glm_mat3x4_scale(mat3x4 m, float s) Multiply mat3x4 (m) by scalar constant (s). Parameters: | *[in, out]* **m** mat3x4 (src, dest) | *[in]* **s** float (scalar) .. csv-table:: mat3x4 **(m)** :header: "", "column 1", "column 2", "column 3" "row 1", "m00 = m00 * s", "m10 = m10 * s", "m20 = m20 * s" "row 2", "m01 = m01 * s", "m11 = m11 * s", "m21 = m21 * s" "row 3", "m02 = m02 * s", "m12 = m12 * s", "m22 = m22 * s" "row 4", "m03 = m03 * s", "m13 = m13 * s", "m23 = m23 * s" cglm-0.9.7/docs/source/mat4.rst000066400000000000000000000214161526744317200163170ustar00rootroot00000000000000.. default-domain:: C mat4 ==== Header: cglm/mat4.h Important: :c:func:`glm_mat4_scale` multiplies mat4 with scalar, if you need to apply scale transform use :c:func:`glm_scale` functions. Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Macros: 1. GLM_MAT4_IDENTITY_INIT #. GLM_MAT4_ZERO_INIT #. GLM_MAT4_IDENTITY #. GLM_MAT4_ZERO #. glm_mat4_udup(mat, dest) #. glm_mat4_dup(mat, dest) Functions: 1. :c:func:`glm_mat4_ucopy` #. :c:func:`glm_mat4_copy` #. :c:func:`glm_mat4_identity` #. :c:func:`glm_mat4_identity_array` #. :c:func:`glm_mat4_zero` #. :c:func:`glm_mat4_pick3` #. :c:func:`glm_mat4_pick3t` #. :c:func:`glm_mat4_ins3` #. :c:func:`glm_mat4_mul` #. :c:func:`glm_mat4_mulN` #. :c:func:`glm_mat4_mulv` #. :c:func:`glm_mat4_mulv3` #. :c:func:`glm_mat4_trace` #. :c:func:`glm_mat4_trace3` #. :c:func:`glm_mat4_quat` #. :c:func:`glm_mat4_transpose_to` #. :c:func:`glm_mat4_transpose` #. :c:func:`glm_mat4_scale_p` #. :c:func:`glm_mat4_scale` #. :c:func:`glm_mat4_det` #. :c:func:`glm_mat4_inv` #. :c:func:`glm_mat4_inv_fast` #. :c:func:`glm_mat4_swap_col` #. :c:func:`glm_mat4_swap_row` #. :c:func:`glm_mat4_rmc` #. :c:func:`glm_mat4_make` #. :c:func:`glm_mat4_textrans` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_mat4_ucopy(mat4 mat, mat4 dest) copy mat4 to another one (dest). u means align is not required for dest Parameters: | *[in]* **mat** source | *[out]* **dest** destination .. c:function:: void glm_mat4_copy(mat4 mat, mat4 dest) copy mat4 to another one (dest). Parameters: | *[in]* **mat** source | *[out]* **dest** destination .. c:function:: void glm_mat4_identity(mat4 mat) copy identity mat4 to mat, or makes mat to identity Parameters: | *[out]* **mat** matrix .. c:function:: void glm_mat4_identity_array(mat4 * __restrict mat, size_t count) make given matrix array's each element identity matrix Parameters: | *[in,out]* **mat** matrix array (must be aligned (16/32) if alignment is not disabled) | *[in]* **count** count of matrices .. c:function:: void glm_mat4_zero(mat4 mat) make given matrix zero Parameters: | *[in,out]* **mat** matrix to .. c:function:: void glm_mat4_pick3(mat4 mat, mat3 dest) copy upper-left of mat4 to mat3 Parameters: | *[in]* **mat** source | *[out]* **dest** destination .. c:function:: void glm_mat4_pick3t(mat4 mat, mat4 dest) copy upper-left of mat4 to mat3 (transposed) the postfix t stands for transpose Parameters: | *[in]* **mat** source | *[out]* **dest** destination .. c:function:: void glm_mat4_ins3(mat3 mat, mat4 dest) copy mat3 to mat4's upper-left. this function does not fill mat4's other elements. To do that use glm_mat4. Parameters: | *[in]* **mat** source | *[out]* **dest** destination .. c:function:: void glm_mat4_mul(mat4 m1, mat4 m2, mat4 dest) multiply m1 and m2 to dest m1, m2 and dest matrices can be same matrix, it is possible to write this: .. code-block:: c mat4 m = GLM_MAT4_IDENTITY_INIT; glm_mat4_mul(m, m, m); Parameters: | *[in]* **m1** left matrix | *[in]* **m2** right matrix | *[out]* **dest** destination matrix .. c:function:: void glm_mat4_mulN(mat4 * __restrict matrices[], int len, mat4 dest) mupliply N mat4 matrices and store result in dest | this function lets you multiply multiple (more than two or more...) | matrices | multiplication will be done in loop, this may reduce instructions | size but if **len** is too small then compiler may unroll whole loop .. code-block:: c mat4 m1, m2, m3, m4, res; glm_mat4_mulN((mat4 *[]){&m1, &m2, &m3, &m4}, 4, res); Parameters: | *[in]* **matrices** array of mat4 | *[in]* **len** matrices count | *[out]* **dest** destination matrix .. c:function:: void glm_mat4_mulv(mat4 m, vec4 v, vec4 dest) multiply mat4 with vec4 (column vector) and store in dest vector Parameters: | *[in]* **m** mat4 (left) | *[in]* **v** vec4 (right, column vector) | *[out]* **dest** vec4 (result, column vector) .. c:function:: void glm_mat4_mulv3(mat4 m, vec3 v, float last, vec3 dest) | multiply **vec3** with **mat4** and get **vec3** as result | | actually the result is **vec4**, after multiplication, the last component is trimmed, if you need the result's last component then don't use this function and consider to use **glm_mat4_mulv()** Parameters: | *[in]* **m** mat4(affine transform) | *[in]* **v** vec3 | *[in]* **last** 4th item to make it vec4 | *[out]* **dest** result vector (vec3) .. c:function:: void glm_mat4_trace(mat4 m) | sum of the elements on the main diagonal from upper left to the lower right Parameters: | *[in]* **m** matrix Returns: trace of matrix .. c:function:: void glm_mat4_trace3(mat4 m) | trace of matrix (rotation part) | sum of the elements on the main diagonal from upper left to the lower right Parameters: | *[in]* **m** matrix Returns: trace of matrix .. c:function:: void glm_mat4_quat(mat4 m, versor dest) convert mat4's rotation part to quaternion Parameters: | *[in]* **m** affine matrix | *[out]* **dest** destination quaternion .. c:function:: void glm_mat4_transpose_to(mat4 m, mat4 dest) transpose mat4 and store in dest source matrix will not be transposed unless dest is m Parameters: | *[in]* **m** matrix | *[out]* **dest** destination matrix .. c:function:: void glm_mat4_transpose(mat4 m) transpose mat4 and store result in same matrix Parameters: | *[in]* **m** source | *[out]* **dest** destination matrix .. c:function:: void glm_mat4_scale_p(mat4 m, float s) scale (multiply with scalar) matrix without simd optimization Parameters: | *[in, out]* **m** matrix | *[in]* **s** scalar .. c:function:: void glm_mat4_scale(mat4 m, float s) scale (multiply with scalar) matrix THIS IS NOT SCALE TRANSFORM, use glm_scale for that. Parameters: | *[in, out]* **m** matrix | *[in]* **s** scalar .. c:function:: float glm_mat4_det(mat4 mat) mat4 determinant Parameters: | *[in]* **mat** matrix Return: | determinant .. c:function:: void glm_mat4_inv(mat4 mat, mat4 dest) inverse mat4 and store in dest Parameters: | *[in]* **mat** source | *[out]* **dest** destination matrix (inverse matrix) .. c:function:: void glm_mat4_inv_fast(mat4 mat, mat4 dest) inverse mat4 and store in dest | this func uses reciprocal approximation without extra corrections | e.g Newton-Raphson. this should work faster than normal, | to get more precise use glm_mat4_inv version. .. note:: You will lose precision, glm_mat4_inv is more accurate Parameters: | *[in]* **mat** source | *[out]* **dest** destination .. c:function:: void glm_mat4_swap_col(mat4 mat, int col1, int col2) swap two matrix columns Parameters: | *[in, out]* **mat** matrix | *[in]* **col1** col1 | *[in]* **col2** col2 .. c:function:: void glm_mat4_swap_row(mat4 mat, int row1, int row2) swap two matrix rows Parameters: | *[in, out]* **mat** matrix | *[in]* **row1** row1 | *[in]* **row2** row2 .. c:function:: float glm_mat4_rmc(vec4 r, mat4 m, vec4 c) | **rmc** stands for **Row** * **Matrix** * **Column** | helper for R (row vector) * M (matrix) * C (column vector) | the result is scalar because R * M = Matrix1x4 (row vector), | then Matrix1x4 * Vec4 (column vector) = Matrix1x1 (Scalar) Parameters: | *[in]* **r** row vector or matrix1x4 | *[in]* **m** matrix4x4 | *[in]* **c** column vector or matrix4x1 Returns: scalar value e.g. Matrix1x1 .. c:function:: void glm_mat4_make(const float * __restrict src, mat4 dest) Create mat4 matrix from pointer .. note:: **@src** must contain at least 16 elements. Parameters: | *[in]* **src** pointer to an array of floats | *[out]* **dest** destination matrix4x4 .. c:function:: void glm_mat4_textrans(float sx, float sy, float rot, float tx, float ty, mat4 dest) Create texture transformation matrix, rotation is in radians CCW/RH Parameters: | *[in]* **sx** scale x | *[in]* **sy** scale y | *[in]* **rot** rotation in radians CCW/RH | *[in]* **tx** translation x | *[in]* **ty** translation y | *[out]* **dest** destination matrix3x3 cglm-0.9.7/docs/source/mat4x2.rst000066400000000000000000000131361526744317200165710ustar00rootroot00000000000000.. default-domain:: C mat4x2 ====== Header: cglm/mat4x2.h Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Macros: 1. GLM_MAT4X2_ZERO_INIT #. GLM_MAT4X2_ZERO Functions: 1. :c:func:`glm_mat4x2_copy` #. :c:func:`glm_mat4x2_zero` #. :c:func:`glm_mat4x2_make` #. :c:func:`glm_mat4x2_mul` #. :c:func:`glm_mat4x2_mulv` #. :c:func:`glm_mat4x2_transpose` #. :c:func:`glm_mat4x2_scale` Represented ~~~~~~~~~~~ .. csv-table:: mat4x2 :header: "", "column 1", "column 2", "column 3", "column4" "row 1", "m00", "m10", "m20", "m30" "row 2", "m01", "m11", "m21", "m31" Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_mat4x2_copy(mat4x2 src, mat4x2 dest) Copy mat4x2 (src) to mat4x2 (dest). Parameters: | *[in]* **src** mat4x2 (left) | *[out]* **dest** destination (result, mat4x2) .. csv-table:: mat4x2 **(src)** :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "a00", "a10", "a20", "a30" "row 2", "a01", "a11", "a21", "a31" .. csv-table:: ma4x2 **(dest)** :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "b00 = a00", "b10 = a10", "b20 = a20", "b30 = a30" "row 2", "b01 = a01", "b11 = a11", "b21 = a21", "b31 = a31" .. c:function:: void glm_mat4x2_zero(mat4x2 m) Zero out the mat4x2 (m). Parameters: | *[in, out]* **m** mat4x2 (src, dest) .. csv-table:: mat4x2 **(m)** :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "0.00", "2.00", "15.00", "44.00" "row 2", "5.00", "4.00", "6.00", "12.00" .. csv-table:: mat4x2 **(m)** :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "0.00", "0.00", "0.00", "0.00" "row 2", "0.00", "0.00", "0.00", "0.00" .. c:function:: void glm_mat4x2_make(const float * __restrict src, mat4x2 dest) Create mat4x2 (dest) from pointer (src). .. note:: **@src** must contain at least 8 elements. Parameters: | *[in]* **src** pointer to an array of floats (left) | *[out]* **dest** destination (result, mat4x2) .. csv-table:: float array (1x8) **(src)** :header: "", "column 1" "row 1", "v0" "row 2", "v1" "row 3", "v2" "row 4", "v3" "row 5", "v4" "row 6", "v5" "row 7", "v6" "row 8", "v7" .. csv-table:: mat4x2 **(dest)** :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "v0", "v2", "v4", "v6" "row 2", "v1", "v3", "v5", "v7" .. c:function:: void glm_mat4x2_mul(mat4x2 m1, mat2x4 m2, mat2 dest) Multiply mat4x2 (m1) by mat2x4 (m2) and store in mat2 (dest). .. code-block:: c glm_mat4x2_mul(mat4x2, mat2x4, mat2); Parameters: | *[in]* **m1** mat4x2 (left) | *[in]* **m2** mat2x4 (right) | *[out]* **dest** destination (result, mat2) .. csv-table:: mat4x2 **(m1)** :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "a00", "a10", "a20", "a30" "row 2", "a01", "a11", "a21", "a31" .. csv-table:: mat2x4 **(m2)** :header: "", "column 1", "column 2" "row 1", "b00", "b10" "row 2", "b01", "b11" "row 3", "b02", "b12" "row 4", "b03", "b13" .. csv-table:: mat2x2 **(dest)** :header: "", "column 1", "column 2" "row 1", "a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03", "a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13" "row 2", "a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03", "a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13" .. c:function:: void glm_mat4x2_mulv(mat4x2 m, vec4 v, vec2 dest) Multiply mat4x2 (m) by vec4 (v) and store in vec2 (dest). Parameters: | *[in]* **m** mat4x2 (left) | *[in]* **v** vec4 (right, column vector) | *[out]* **dest** destination (result, column vector) .. csv-table:: mat4x2 **(m)** :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "m00", "m10", "m20", "m30" "row 2", "m01", "m11", "m21", "m31" .. csv-table:: column vec4 (1x4) **(v)** :header: "", "column 1" "row 1", "v0" "row 2", "v1" "row 3", "v2" "row 4", "v3" .. csv-table:: column vec2 (1x2) **(dest)** :header: "", "column 1" "row 1", "m00 * v0 + m10 * v1 + m20 * v2 + m30 * v3" "row 2", "m01 * v0 + m11 * v1 + m21 * v2 + m31 * v3" .. c:function:: void glm_mat4x2_transpose(mat4x2 src, mat2x4 dest) Transpose mat4x2 (src) and store in mat2x4 (dest). Parameters: | *[in]* **src** mat4x2 (left) | *[out]* **dest** destination (result, mat2x4) .. csv-table:: mat4x2 **(src)** :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "a00", "a10", "a20", "a30" "row 2", "a01", "a11", "a21", "a31" .. csv-table:: mat2x4 **(dest)** :header: "", "column 1", "column 2" "row 1", "b00 = a00", "b10 = a01" "row 2", "b01 = a10", "b11 = a11" "row 3", "b02 = a20", "b12 = a21" "row 4", "b03 = a30", "b13 = a31" .. c:function:: void glm_mat4x2_scale(mat4x2 m, float s) Multiply mat4x2 (m) by scalar constant (s). Parameters: | *[in, out]* **m** mat4x2 (src, dest) | *[in]* **s** float (scalar) .. csv-table:: mat4x2 **(m)** :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "m00 = m00 * s", "m10 = m10 * s", "m20 = m20 * s", "m30 = m30 * s" "row 2", "m01 = m01 * s", "m11 = m11 * s", "m21 = m21 * s", "m31 = m31 * s" cglm-0.9.7/docs/source/mat4x3.rst000066400000000000000000000151561526744317200165760ustar00rootroot00000000000000.. default-domain:: C mat4x3 ====== Header: cglm/mat4x3.h Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Macros: 1. GLM_MAT4X3_ZERO_INIT #. GLM_MAT4X3_ZERO Functions: 1. :c:func:`glm_mat4x3_copy` #. :c:func:`glm_mat4x3_zero` #. :c:func:`glm_mat4x3_make` #. :c:func:`glm_mat4x3_mul` #. :c:func:`glm_mat4x3_mulv` #. :c:func:`glm_mat4x3_transpose` #. :c:func:`glm_mat4x3_scale` Represented ~~~~~~~~~~~ .. csv-table:: mat4x3 :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "m00", "m10", "m20", "m30" "row 2", "m01", "m11", "m21", "m31" "row 3", "m02", "m12", "m22", "m32" Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_mat4x3_copy(mat4x3 src, mat4x3 dest) Copy mat4x3 (src) to mat4x3 (dest). Parameters: | *[in]* **src** mat4x3 (left) | *[out]* **dest** destination (result, mat4x3) .. csv-table:: mat4x3 **(src)** :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "a00", "a10", "a20", "a30" "row 2", "a01", "a11", "a21", "a31" "row 3", "a02", "a12", "a22", "a32" .. csv-table:: mat4x3 **(dest)** :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "b00 = a00", "b10 = a10", "b20 = a20", "b30 = a30" "row 2", "b01 = a01", "b11 = a11", "b21 = a21", "b31 = a31" "row 3", "b02 = a02", "b12 = a12", "b22 = a22", "b32 = a32" .. c:function:: void glm_mat4x3_zero(mat4x3 m) Zero out the mat4x3 (m). Parameters: | *[in, out]* **m** mat4x3 (src, dest) .. csv-table:: mat4x3 **(m)** :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "0.00", "2.00", "15.00", "44.00" "row 2", "5.00", "4.00", "6.00", "12.00" "row 3", "88.00", "8.00", "4.30", "15.00" .. csv-table:: mat4x3 **(m)** :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "0.00", "0.00", "0.00", "0.00" "row 2", "0.00", "0.00", "0.00", "0.00" "row3", "0.00", "0.00", "0.00", "0.00" .. c:function:: void glm_mat4x3_make(const float * __restrict src, mat4x3 dest) Create mat4x3 (dest) from pointer (src). .. note:: **@src** must contain at least 12 elements. Parameters: | *[in]* **src** pointer to an array of floats (left) | *[out]* **dest** destination (result, mat4x3) .. csv-table:: float array (1x12) **(src)** :header: "", "column 1" "row 1", "v0" "row 2", "v1" "row 3", "v2" "row 4", "v3" "row 5", "v4" "row 6", "v5" "row 7", "v6" "row 8", "v7" "row 9", "v8" "row 10", "v9" "row 11", "v10" "row 12", "v11" .. csv-table:: mat4x3 **(dest)** :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "v0", "v3", "v6", "v9" "row 2", "v1", "v4", "v7", "v10" "row 3", "v2", "v5", "v8", "v11" .. c:function:: void glm_mat4x3_mul(mat4x3 m1, mat3x4 m2, mat3 dest) Multiply mat4x3 (m1) by mat3x4 (m2) and store in mat3 (dest). .. code-block:: c glm_mat4x3_mul(mat4x3, mat3x4, mat3); Parameters: | *[in]* **m1** mat4x3 (left) | *[in]* **m2** mat3x4 (right) | *[out]* **dest** destination (result, mat3) .. csv-table:: mat4x3 **(m1)** :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "a00", "a10", "a20", "a30" "row 2", "a01", "a11", "a21", "a31" "row 3", "a02", "a12", "a22", "a32" .. csv-table:: mat3x4 **(m2)** :header: "", "column 1", "column 2", "column 3" "row 1", "b00", "b10", "b20" "row 2", "b01", "b11", "b21" "row 3", "b02", "b12", "b22" "row 4", "b03", "b13", "b23" .. csv-table:: mat3x3 **(dest)** :header: "", "column 1", "column 2", "column 3" "row 1", "a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03", "a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13", "a00 * b20 + a10 * b21 + a20 * b22 + a30 * b23" "row 2", "a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03", "a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13", "a01 * b20 + a11 * b21 + a21 * b22 + a31 * b23" "row 3", "a02 * b00 + a12 * b01 + a22 * b02 + a32 * b03", "a02 * b10 + a12 * b11 + a22 * b12 + a32 * b13", "a02 * b20 + a12 * b21 + a22 * b22 + a32 * b23" .. c:function:: void glm_mat4x3_mulv(mat4x3 m, vec4 v, vec3 dest) Multiply mat4x3 (m) by vec4 (v) and store in vec3 (dest). Parameters: | *[in]* **m** mat4x3 (left) | *[in]* **v** vec4 (right, column vector) | *[out]* **dest** destination (result, column vector) .. csv-table:: mat4x3 **(m)** :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "m00", "m10", "m20", "m30" "row 2", "m01", "m11", "m21", "m31" "row 3", "m02", "m12", "m22", "m32" .. csv-table:: column vec4 (1x4) **(v)** :header: "", "column 1" "row 1", "v0" "row 2", "v1" "row 3", "v2" "row 4", "v3" .. csv-table:: column vec3 (1x3) **(dest)** :header: "", "column 1" "row 1", "m00 * v0 + m10 * v1 + m20 * v2 + m30 * v3" "row 2", "m01 * v0 + m11 * v1 + m21 * v2 + m31 * v3" "row 3", "m02 * v0 + m12 * v1 + m22 * v2 + m32 * v3" .. c:function:: void glm_mat4x3_transpose(mat4x3 src, mat3x4 dest) Transpose mat4x3 (src) and store in mat3x4 (dest). Parameters: | *[in]* **src** mat4x3 (left) | *[out]* **dest** destination (result, mat3x4) .. csv-table:: mat4x3 **(src)** :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "a00", "a10", "a20", "a30" "row 2", "a01", "a11", "a21", "a31" "row 3", "a02", "a12", "a22", "a32" .. csv-table:: mat3x4 **(dest)** :header: "", "column 1", "column 2", "column 3" "row 1", "b00 = a00", "b10 = a01", "b20 = a02" "row 2", "b01 = a10", "b11 = a11", "b21 = a12" "row 3", "b02 = a20", "b12 = a21", "b22 = a22" "row 4", "b03 = a30", "b13 = a31", "b23 = a32" .. c:function:: void glm_mat4x3_scale(mat4x3 m, float s) Multiply mat4x3 (m) by scalar constant (s). Parameters: | *[in, out]* **m** mat4x3 (src, dest) | *[in]* **s** float (scalar) .. csv-table:: mat4x3 **(m)** :header: "", "column 1", "column 2", "column 3", "column 4" "row 1", "m00 = m00 * s", "m10 = m10 * s", "m20 = m20 * s", "m30 = m30 * s" "row 2", "m01 = m01 * s", "m11 = m11 * s", "m21 = m21 * s", "m31 = m31 * s" "row 3", "m02 = m02 * s", "m12 = m12 * s", "m22 = m22 * s", "m32 = m32 * s" cglm-0.9.7/docs/source/noise.rst000066400000000000000000000023761526744317200165730ustar00rootroot00000000000000.. default-domain:: C perlin ================================================================================ Header: cglm/noise.h Classic Perlin noise implementation. Based on the work of Stefan Gustavson and Ashima Arts on "webgl-noise": https://github.com/stegu/webgl-noise Following Stefan Gustavson's paper "Simplex noise demystified": http://www.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf Implementation based on glm::perlin function: https://github.com/g-truc/glm/blob/master/glm/gtc/noise.inl Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions: 1. :c:func:`glm_perlin_vec4` #. :c:func:`glm_perlin_vec3` #. :c:func:`glm_perlin_vec2` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: float glm_perlin_vec4(vec4 point) | Classic Perlin noise Parameters: | *[in]* **point** 4D point Returns: | noise value .. c:function:: float glm_perlin_vec3(vec3 point) | Classic Perlin noise Parameters: | *[in]* **point** 3D point Returns: | noise value .. c:function:: float glm_perlin_vec2(vec2 point) | Classic Perlin noise Parameters: | *[in]* **point** 2D point Returns: | noise value cglm-0.9.7/docs/source/opengl.rst000066400000000000000000000034771526744317200167450ustar00rootroot00000000000000How to send vector or matrix to OpenGL like API ================================================== *cglm*'s vector and matrix types are arrays. So you can send them directly to a function which accepts pointer. But you may got warnings for matrix because it is two dimensional array. Passing / Uniforming Matrix to OpenGL: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **glUniformMatrix4fv** accepts float pointer, you can pass matrix to that parameter and it should work but with warnings. "You can pass" doesn't mean that you must pass like that. **Correct options:** Correct doesn't mean correct way to use OpenGL it is just shows correct way to pass cglm type to it. 1. Pass first column --------------------- The goal is that pass address of matrix, first element of matrix is also address of matrix, because it is array of vectors and vector is array of floats. .. code-block:: c mat4 matrix; /* ... */ glUniformMatrix4fv(location, 1, GL_FALSE, matrix[0]); array of matrices: .. code-block:: c mat4 matrix; /* ... */ glUniformMatrix4fv(location, count, GL_FALSE, matrix[0][0]); 2. Cast matrix to pointer -------------------------- .. code-block:: c mat4 matrix; /* ... */ glUniformMatrix4fv(location, count, GL_FALSE, (float *)matrix); in this way, passing array of matrices is same Passing / Uniforming Vectors to OpenGL: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You don't need to do extra thing when passing cglm vectors to OpengL or other APIs. Because a function like **glUniform4fv** accepts vector as pointer. cglm's vectors are array of floats. So you can pass it directly to those functions: .. code-block:: c vec4 vec; /* ... */ glUniform4fv(location, 1, vec); this show how to pass **vec4** others are same. cglm-0.9.7/docs/source/opt.rst000066400000000000000000000153741526744317200162620ustar00rootroot00000000000000.. default-domain:: C 🛠ï¸� Options =============================================================================== A few options are provided via macros. â�—ï¸� IMPORTANT â�—ï¸� It's a good idea to set up your config macros in build settings like CMake, Xcode, or Visual Studio. This is especially important if you're using features like Modules in Xcode, where adding macros directly before the **cglm** headers might not work. Alignment Option ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ By default, **cglm** requires types to be aligned with specific byte requirements: - vec3: 8 bytes - vec4: 16 bytes - mat4: 16 bytes (32 on AVX) - versor: 16 bytes Starting with **v0.4.5**, **cglm** offers an option to relax these alignment requirements. To use this option, define the **CGLM_ALL_UNALIGNED** macro before including any headers. This definition can be made within Xcode, Visual Studio, other IDEs, or directly in your build system. If using pre-compiled versions of **cglm**, you'll need to compile them with the **CGLM_ALL_UNALIGNED** macro. **â�—ï¸�NOTE:â�—ï¸�** If you're using **cglm** across multiple interdependent projects: - Always or never use the **CGLM_ALL_UNALIGNED** macro in all linked projects to avoid configuration conflicts. A **cglm** header from one project could require alignment, while a header from another might not, leading to **cglm** functions accessing invalid memory locations. - **Key Point:** Maintain the same **cglm** configuration across all your projects. For example, if you activate **CGLM_ALL_UNALIGNED** in one project, ensure it's set in the others too. **â�—ï¸�NOTE:â�—ï¸�** While **CGLM_ALL_UNALIGNED** allows for flexibility in alignment, it doesn't override C's fundamental alignment rules. For example, an array like *vec4* decays to a pointer (float*) in functions, which must adhere to the alignment requirements of a float pointer (4 bytes). This adherence is crucial because **cglm** directly dereferences these pointers instead of copying data, and failing to meet alignment requirements can lead to unpredictable errors, such as crashes. You can use `CGLM_ALIGN` and `CGLM_ALIGN_MAT` macros for aligning local variables or struct members. However, when dealing with dynamic memory allocation or custom memory locations, you'll need to ensure alignment requirements are met appropriately for those cases Clipspace Option[s] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ By starting **v0.8.3** cglm provides options to switch between clipspace configurations. Clipspace related files are located at `include/cglm/[struct]/clipspace.h` but these are included in related files like `cam.h`. If you don't want to change your existing clipspace configuration and want to use different clipspace function like `glm_lookat_zo` or `glm_lookat_lh_zo`... then you can include individual headers or just define `CGLM_CLIPSPACE_INCLUDE_ALL` which will include all headers for you. 1. **CGLM_CLIPSPACE_INCLUDE_ALL** 2. **CGLM_FORCE_DEPTH_ZERO_TO_ONE** 3. **CGLM_FORCE_LEFT_HANDED** 1. **CGLM_CLIPSPACE_INCLUDE_ALL**: By defining this macro, **cglm** will include all clipspace functions for you by just using `#include cglm/cglm.h` or `#include cglm/struct.h` or `#include cglm/call.h` Otherwise you need to include header you want manually e.g. `#include cglm/clipspace/view_rh_zo.h` 2. **CGLM_FORCE_DEPTH_ZERO_TO_ONE** This is similar to **GLM**'s **GLM_FORCE_DEPTH_ZERO_TO_ONE** option. This will set clip space between 0 to 1 which makes **cglm** Vulkan, Metal friendly. You can use functions like `glm_lookat_lh_zo()` individually. By setting **CGLM_FORCE_DEPTH_ZERO_TO_ONE** functions in cam.h for instance will use `_zo` versions. 3. **CGLM_FORCE_LEFT_HANDED** Force **cglm** to use the left handed coordinate system by default, currently **cglm** uses right handed coordinate system as default, you can change this behavior with this option. **VERY VERY IMPORTANT:** Be careful if you include **cglm** in multiple projects. SSE and SSE2 Shuffle Option ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **_mm_shuffle_ps** generates **shufps** instruction even if registers are same. You can force it to generate **pshufd** instruction by defining **CGLM_NO_INT_DOMAIN** macro. As default it is not defined. SSE3 and SSE4 Dot Product Options ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You have to extra options for dot product: **CGLM_SSE4_DOT** and **CGLM_SSE3_DOT**. - If **SSE4** is enabled then you can define **CGLM_SSE4_DOT** to force cglm to use **_mm_dp_ps** instruction. - If **SSE3** is enabled then you can define **CGLM_SSE3_DOT** to force cglm to use **_mm_hadd_ps** instructions. otherwise cglm will use custom cglm's hadd functions which are optimized too. Struct API Options ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To configure the Struct API namespace, you can define the following macros before including the cglm/struct.h header: - **CGLM_OMIT_NS_FROM_STRUCT_API**: omits CGLM_STRUCT_API_NS (`glms_`) namespace completely if there is sub namespace e.g `mat4_`, `vec4_` ... DEFAULT is not defined - **CGLM_STRUCT_API_NS**: define name space for struct api, DEFAULT is **glms** - **CGLM_STRUCT_API_NAME_SUFFIX**: define name suffix, DEFAULT is **empty** e.g defining it as #define CGLM_STRUCT_API_NAME_SUFFIX s will add s suffix to mat4_mul -> mat4s_mul Print Options ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1. **CGLM_DEFINE_PRINTS** 2. **CGLM_NO_PRINTS_NOOP** (use CGLM_DEFINE_PRINTS) Inline prints are only enabled in **DEBUG** mode or if **CGLM_DEFINE_PRINTS** is defined. **glmc_** versions will always print too. Because **cglm** tried to enable print functions in debug mode and disable them in release/production mode to eliminate printing costs when we do not need them. **cglm** checks **DEBUG** or **_DEBUG** macros to test debug mode, if these are not working for you then you can use **CGLM_DEFINE_PRINTS** to force enable, or create a PR to introduce new macro to test against debugging mode. If DEBUG mode is not enabled then print functions will be emptied to eliminate print function calls. You can disable this feature too by defining **CGLM_DEFINE_PRINTS** macro top of cglm header or in project/build settings... 3. **CGLM_PRINT_PRECISION** 5 precision. 4. **CGLM_PRINT_MAX_TO_SHORT** 1e5 if a number is greater than this value then %g will be used, since this is shorten print you won't be able to see high precision. 5. **CGLM_PRINT_COLOR** "\033[36m" 6. **CGLM_PRINT_COLOR_RESET** "\033[0m" You can disable colorful print output by defining **CGLM_PRINT_COLOR** and **CGLM_PRINT_COLOR_RESET** as empty macro. Because some terminals may not support colors. cglm-0.9.7/docs/source/plane.rst000066400000000000000000000013361526744317200165500ustar00rootroot00000000000000.. default-domain:: C plane ================================================================================ Header: cglm/plane.h Plane extract functions are in frustum header and documented in :doc:`frustum` page. **Definition of plane:** Plane equation: **Ax + By + Cz + D = 0** Plan is stored in **vec4** as **[A, B, C, D]**. (A, B, C) is normal and D is distance Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions: 1. :c:func:`glm_plane_normalize` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_plane_normalize(vec4 plane) | normalizes a plane Parameters: | *[in, out]* **plane** pnale to normalize cglm-0.9.7/docs/source/project.rst000066400000000000000000000067741526744317200171320ustar00rootroot00000000000000.. default-domain:: C Project / UnProject ================================================================================ Header: cglm/project.h Viewport is required as *vec4* **[X, Y, Width, Height]** but this doesn't mean that you should store it as **vec4**. You can convert your data representation to vec4 before passing it to related functions. Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions: 1. :c:func:`glm_unprojecti` #. :c:func:`glm_unproject` #. :c:func:`glm_project` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_unprojecti(vec3 pos, mat4 invMat, vec4 vp, vec3 dest) | maps the specified viewport coordinates into specified space [1] the matrix should contain projection matrix. if you don't have ( and don't want to have ) an inverse matrix then use :c:func:`glm_unproject` version. You may use existing inverse of matrix in somewhere else, this is why **glm_unprojecti** exists to save inversion cost [1] space: - if m = invProj: View Space - if m = invViewProj: World Space - if m = invMVP: Object Space You probably want to map the coordinates into object space so use invMVP as m Computing viewProj: .. code-block:: c glm_mat4_mul(proj, view, viewProj); glm_mat4_mul(viewProj, model, MVP); glm_mat4_inv(viewProj, invMVP); Parameters: | *[in]* **pos** point/position in viewport coordinates | *[in]* **invMat** matrix (see brief) | *[in]* **vp** viewport as [x, y, width, height] | *[out]* **dest** unprojected coordinates .. c:function:: void glm_unproject(vec3 pos, mat4 m, vec4 vp, vec3 dest) | maps the specified viewport coordinates into specified space [1] the matrix should contain projection matrix. this is same as :c:func:`glm_unprojecti` except this function get inverse matrix for you. [1] space: - if m = proj: View Space - if m = viewProj: World Space - if m = MVP: Object Space You probably want to map the coordinates into object space so use MVP as m Computing viewProj and MVP: .. code-block:: c glm_mat4_mul(proj, view, viewProj); glm_mat4_mul(viewProj, model, MVP); Parameters: | *[in]* **pos** point/position in viewport coordinates | *[in]* **m** matrix (see brief) | *[in]* **vp** viewport as [x, y, width, height] | *[out]* **dest** unprojected coordinates .. c:function:: void glm_project(vec3 pos, mat4 m, vec4 vp, vec3 dest) | map object coordinates to window coordinates Computing MVP: .. code-block:: c glm_mat4_mul(proj, view, viewProj); glm_mat4_mul(viewProj, model, MVP); Parameters: | *[in]* **pos** object coordinates | *[in]* **m** MVP matrix | *[in]* **vp** viewport as [x, y, width, height] | *[out]* **dest** projected coordinates .. c:function:: float glm_project_z(vec3 pos, mat4 m) | map object's z coordinate to window coordinates this is same as :c:func:`glm_project` except this function projects only Z coordinate which reduces a few calculations and parameters. Computing MVP: .. code-block:: c glm_mat4_mul(proj, view, viewProj); glm_mat4_mul(viewProj, model, MVP); Parameters: | *[in]* **pos** object coordinates | *[in]* **m** MVP matrix Returns: projected z coordinatecglm-0.9.7/docs/source/quat.rst000066400000000000000000000314421526744317200164240ustar00rootroot00000000000000.. default-domain:: C quaternions =========== Header: cglm/quat.h **Important:** *cglm* stores quaternion as **[x, y, z, w]** in memory since **v0.4.0** it was **[w, x, y, z]** before v0.4.0 ( **v0.3.5 and earlier** ). w is real part. What you can do with quaternions with existing functions is (Some of them): - You can rotate transform matrix using quaternion - You can rotate vector using quaternion - You can create view matrix using quaternion - You can create a lookrotation (from source point to dest) Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Macros: 1. GLM_QUAT_IDENTITY_INIT #. GLM_QUAT_IDENTITY Functions: 1. :c:func:`glm_quat_identity` #. :c:func:`glm_quat_identity_array` #. :c:func:`glm_quat_init` #. :c:func:`glm_quat` #. :c:func:`glm_quatv` #. :c:func:`glm_quat_copy` #. :c:func:`glm_quat_from_vecs` #. :c:func:`glm_quat_norm` #. :c:func:`glm_quat_normalize` #. :c:func:`glm_quat_normalize_to` #. :c:func:`glm_quat_dot` #. :c:func:`glm_quat_conjugate` #. :c:func:`glm_quat_inv` #. :c:func:`glm_quat_add` #. :c:func:`glm_quat_sub` #. :c:func:`glm_quat_real` #. :c:func:`glm_quat_imag` #. :c:func:`glm_quat_imagn` #. :c:func:`glm_quat_imaglen` #. :c:func:`glm_quat_angle` #. :c:func:`glm_quat_axis` #. :c:func:`glm_quat_mul` #. :c:func:`glm_quat_mat4` #. :c:func:`glm_quat_mat4t` #. :c:func:`glm_quat_mat3` #. :c:func:`glm_quat_mat3t` #. :c:func:`glm_quat_lerp` #. :c:func:`glm_quat_nlerp` #. :c:func:`glm_quat_slerp` #. :c:func:`glm_quat_slerp_longest` #. :c:func:`glm_quat_look` #. :c:func:`glm_quat_for` #. :c:func:`glm_quat_forp` #. :c:func:`glm_quat_rotatev` #. :c:func:`glm_quat_rotate` #. :c:func:`glm_quat_rotate_at` #. :c:func:`glm_quat_rotate_atm` #. :c:func:`glm_quat_make` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_quat_identity(versor q) | makes given quat to identity Parameters: | *[in, out]* **q** quaternion .. c:function:: void glm_quat_identity_array(versor * __restrict q, size_t count) | make given quaternion array's each element identity quaternion Parameters: | *[in, out]* **q** quat array (must be aligned (16) if alignment is not disabled) | *[in]* **count** count of quaternions .. c:function:: void glm_quat_init(versor q, float x, float y, float z, float w) | inits quaternion with given values Parameters: | *[out]* **q** quaternion | *[in]* **x** imag.x | *[in]* **y** imag.y | *[in]* **z** imag.z | *[in]* **w** w (real part) .. c:function:: void glm_quat(versor q, float angle, float x, float y, float z) | creates NEW quaternion with individual axis components | given axis will be normalized Parameters: | *[out]* **q** quaternion | *[in]* **angle** angle (radians) | *[in]* **x** axis.x | *[in]* **y** axis.y | *[in]* **z** axis.z .. c:function:: void glm_quatv(versor q, float angle, vec3 axis) | creates NEW quaternion with axis vector | given axis will be normalized Parameters: | *[out]* **q** quaternion | *[in]* **angle** angle (radians) | *[in]* **axis** axis (will be normalized) .. c:function:: void glm_quat_copy(versor q, versor dest) | copy quaternion to another one Parameters: | *[in]* **q** source quaternion | *[out]* **dest** destination quaternion .. c:function:: void glm_quat_from_vecs(vec3 a, vec3 b, versor dest) | compute unit quaternion needed to rotate a into b References: * `Finding quaternion representing the rotation from one vector to another `_ * `Quaternion from two vectors `_ * `Angle between vectors `_ Parameters: | *[in]* **a** unit vector | *[in]* **b** unit vector | *[in]* **dest** unit quaternion .. c:function:: float glm_quat_norm(versor q) | returns norm (magnitude) of quaternion Parameters: | *[in]* **a** quaternion Returns: norm (magnitude) .. c:function:: void glm_quat_normalize_to(versor q, versor dest) | normalize quaternion and store result in dest, original one will not be normalized Parameters: | *[in]* **q** quaternion to normalize into | *[out]* **dest** destination quaternion .. c:function:: void glm_quat_normalize(versor q) | normalize quaternion Parameters: | *[in, out]* **q** quaternion .. c:function:: float glm_quat_dot(versor p, versor q) dot product of two quaternion Parameters: | *[in]* **p** quaternion 1 | *[in]* **q** quaternion 2 Returns: dot product .. c:function:: void glm_quat_conjugate(versor q, versor dest) conjugate of quaternion Parameters: | *[in]* **q** quaternion | *[in]* **dest** conjugate .. c:function:: void glm_quat_inv(versor q, versor dest) inverse of non-zero quaternion Parameters: | *[in]* **q** quaternion | *[in]* **dest** inverse quaternion .. c:function:: void glm_quat_add(versor p, versor q, versor dest) add (componentwise) two quaternions and store result in dest Parameters: | *[in]* **p** quaternion 1 | *[in]* **q** quaternion 2 | *[in]* **dest** result quaternion .. c:function:: void glm_quat_sub(versor p, versor q, versor dest) subtract (componentwise) two quaternions and store result in dest Parameters: | *[in]* **p** quaternion 1 | *[in]* **q** quaternion 2 | *[in]* **dest** result quaternion .. c:function:: float glm_quat_real(versor q) returns real part of quaternion Parameters: | *[in]* **q** quaternion Returns: real part (quat.w) .. c:function:: void glm_quat_imag(versor q, vec3 dest) returns imaginary part of quaternion Parameters: | *[in]* **q** quaternion | *[out]* **dest** imag .. c:function:: void glm_quat_imagn(versor q, vec3 dest) returns normalized imaginary part of quaternion Parameters: | *[in]* **q** quaternion | *[out]* **dest** imag .. c:function:: float glm_quat_imaglen(versor q) returns length of imaginary part of quaternion Parameters: | *[in]* **q** quaternion Returns: norm of imaginary part .. c:function:: float glm_quat_angle(versor q) returns angle of quaternion Parameters: | *[in]* **q** quaternion Returns: angles of quat (radians) .. c:function:: void glm_quat_axis(versor q, versor dest) axis of quaternion Parameters: | *[in]* **p** quaternion | *[out]* **dest** axis of quaternion .. c:function:: void glm_quat_mul(versor p, versor q, versor dest) | multiplies two quaternion and stores result in dest | this is also called Hamilton Product | According to WikiPedia: | The product of two rotation quaternions [clarification needed] will be equivalent to the rotation q followed by the rotation p Parameters: | *[in]* **p** quaternion 1 (first rotation) | *[in]* **q** quaternion 2 (second rotation) | *[out]* **dest** result quaternion .. c:function:: void glm_quat_mat4(versor q, mat4 dest) | convert quaternion to mat4 Parameters: | *[in]* **q** quaternion | *[out]* **dest** result matrix .. c:function:: void glm_quat_mat4t(versor q, mat4 dest) | convert quaternion to mat4 (transposed). This is transposed version of glm_quat_mat4 Parameters: | *[in]* **q** quaternion | *[out]* **dest** result matrix .. c:function:: void glm_quat_mat3(versor q, mat3 dest) | convert quaternion to mat3 Parameters: | *[in]* **q** quaternion | *[out]* **dest** result matrix .. c:function:: void glm_quat_mat3t(versor q, mat3 dest) | convert quaternion to mat3 (transposed). This is transposed version of glm_quat_mat3 Parameters: | *[in]* **q** quaternion | *[out]* **dest** result matrix .. c:function:: void glm_quat_lerp(versor from, versor to, float t, versor dest) | interpolates between two quaternions | using spherical linear interpolation (LERP) Parameters: | *[in]* **from** from | *[in]* **to** to | *[in]* **t** interpolant (amount) clamped between 0 and 1 | *[out]* **dest** result quaternion .. c:function:: void glm_quat_nlerp(versor q, versor r, float t, versor dest) | interpolates between two quaternions | taking the shortest rotation path using | normalized linear interpolation (NLERP) | This is a cheaper alternative to slerp; most games use nlerp | for animations as it visually makes little difference. References: * `Understanding Slerp, Then Not Using it `_ * `Lerp, Slerp and Nlerp `_ Parameters: | *[in]* **from** from | *[in]* **to** to | *[in]* **t** interpolant (amount) clamped between 0 and 1 | *[out]* **dest** result quaternion .. c:function:: void glm_quat_slerp(versor q, versor r, float t, versor dest) | interpolates between two quaternions | using spherical linear interpolation (SLERP) Parameters: | *[in]* **from** from | *[in]* **to** to | *[in]* **t** interpolant (amount) clamped between 0 and 1 | *[out]* **dest** result quaternion .. c:function:: void glm_quat_slerp_longest(versor q, versor r, float t, versor dest) | interpolates between two quaternions | using spherical linear interpolation (SLERP) and always takes the longest path Parameters: | *[in]* **from** from | *[in]* **to** to | *[in]* **t** interpolant (amount) clamped between 0 and 1 | *[out]* **dest** result quaternion .. c:function:: void glm_quat_look(vec3 eye, versor ori, mat4 dest) | creates view matrix using quaternion as camera orientation Parameters: | *[in]* **eye** eye | *[in]* **ori** orientation in world space as quaternion | *[out]* **dest** result matrix .. c:function:: void glm_quat_for(vec3 dir, vec3 up, versor dest) | creates look rotation quaternion Parameters: | *[in]* **dir** direction to look | *[in]* **up** up vector | *[out]* **dest** result matrix .. c:function:: void glm_quat_forp(vec3 from, vec3 to, vec3 up, versor dest) | creates look rotation quaternion using source and destination positions p suffix stands for position | this is similar to glm_quat_for except this computes direction for glm_quat_for for you. Parameters: | *[in]* **from** source point | *[in]* **to** destination point | *[in]* **up** up vector | *[out]* **dest** result matrix .. c:function:: void glm_quat_rotatev(versor q, vec3 v, vec3 dest) | crotate vector using using quaternion Parameters: | *[in]* **q** quaternion | *[in]* **v** vector to rotate | *[out]* **dest** rotated vector .. c:function:: void glm_quat_rotate(mat4 m, versor q, mat4 dest) | rotate existing transform matrix using quaternion instead of passing identity matrix, consider to use quat_mat4 functions Parameters: | *[in]* **m** existing transform matrix to rotate | *[in]* **q** quaternion | *[out]* **dest** rotated matrix/transform .. c:function:: void glm_quat_rotate_at(mat4 m, versor q, vec3 pivot) | rotate existing transform matrix using quaternion at pivot point Parameters: | *[in, out]* **m** existing transform matrix to rotate | *[in]* **q** quaternion | *[in]* **pivot** pivot .. c:function:: void glm_quat_rotate_atm(mat4 m, versor q, vec3 pivot) | rotate NEW transform matrix using quaternion at pivot point | this creates rotation matrix, it assumes you don't have a matrix | this should work faster than glm_quat_rotate_at because it reduces one glm_translate. Parameters: | *[in, out]* **m** existing transform matrix to rotate | *[in]* **q** quaternion | *[in]* **pivot** pivot .. c:function:: void glm_quat_make(const float * __restrict src, versor dest) Create quaternion from pointer .. note:: **@src** must contain at least 4 elements. cglm store quaternions as [x, y, z, w]. Parameters: | *[in]* **src** pointer to an array of floats | *[out]* **dest** destination quaternion cglm-0.9.7/docs/source/ray.rst000066400000000000000000000044541526744317200162500ustar00rootroot00000000000000.. default-domain:: C ray ==== Header: cglm/ray.h This is for collision-checks used by ray-tracers and the like. Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions: 1. :c:func:`glm_ray_triangle` #. :c:func:`glm_ray_sphere` #. :c:func:`glm_ray_at` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: bool glm_ray_triangle(vec3 origin, vec3 direction, vec3 v0, vec3 v1, vec3 v2, float *d) Möller–Trumbore ray-triangle intersection algorithm Parameters: | *[in]* **origin** origin of ray | *[in]* **direction** direction of ray | *[in]* **v0** first vertex of triangle | *[in]* **v1** second vertex of triangle | *[in]* **v2** third vertex of triangle | *[in, out]* **d** float pointer to save distance to intersection | *[out]* **intersection** whether there is intersection .. c:function:: bool glm_ray_sphere(vec3 origin, vec3 dir, vec4 s, float * __restrict t1, float * __restrict t2) ray sphere intersection returns false if there is no intersection if true: - t1 > 0, t2 > 0: ray intersects the sphere at t1 and t2 both ahead of the origin - t1 < 0, t2 > 0: ray starts inside the sphere, exits at t2 - t1 < 0, t2 < 0: no intersection ahead of the ray ( returns false ) - the caller can check if the intersection points (t1 and t2) fall within a specific range (for example, tmin < t1, t2 < tmax) to determine if the intersections are within a desired segment of the ray Parameters: | *[in]* **origin** ray origin | *[in]* **dir** normalized ray direction | *[in]* **s** sphere [center.x, center.y, center.z, radii] | *[out]* **t1** near point1 (closer to origin) | *[out]* **t2** far point2 (farther from origin) Return: | whether there is intersection .. c:function:: bool glm_ray_at(vec3 orig, vec3 dir, float t, vec3 point) point using t by ð���(ð�‘¡)=ð��€+ð�‘¡ð��› Parameters: | *[in]* **origin** ray origin | *[in]* **dir** ray direction | *[out]* **t** parameter | *[out]* **point** point at t Return: | point at t cglm-0.9.7/docs/source/sphere.rst000066400000000000000000000035721526744317200167430ustar00rootroot00000000000000.. default-domain:: C Sphere ================================================================================ Header: cglm/sphere.h **Definition of sphere:** Sphere Representation in cglm is *vec4*: **[center.x, center.y, center.z, radii]** You can call any vec3 function by passing sphere. Because first three elements defines center of sphere. Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions: 1. :c:func:`glm_sphere_radii` #. :c:func:`glm_sphere_transform` #. :c:func:`glm_sphere_merge` #. :c:func:`glm_sphere_sphere` #. :c:func:`glm_sphere_point` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: float glm_sphere_radii(vec4 s) | helper for getting sphere radius Parameters: | *[in]* **s** sphere Returns: returns radii .. c:function:: void glm_sphere_transform(vec4 s, mat4 m, vec4 dest) | apply transform to sphere, it is just wrapper for glm_mat4_mulv3 Parameters: | *[in]* **s** sphere | *[in]* **m** transform matrix | *[out]* **dest** transformed sphere .. c:function:: void glm_sphere_merge(vec4 s1, vec4 s2, vec4 dest) | merges two spheres and creates a new one two sphere must be in same space, for instance if one in world space then the other must be in world space too, not in local space. Parameters: | *[in]* **s1** sphere 1 | *[in]* **s2** sphere 2 | *[out]* **dest** merged/extended sphere .. c:function:: bool glm_sphere_sphere(vec4 s1, vec4 s2) | check if two sphere intersects Parameters: | *[in]* **s1** sphere | *[in]* **s2** other sphere .. c:function:: bool glm_sphere_point(vec4 s, vec3 point) | check if sphere intersects with point Parameters: | *[in]* **s** sphere | *[in]* **point** point cglm-0.9.7/docs/source/sphinx-static/000077500000000000000000000000001526744317200175125ustar00rootroot00000000000000cglm-0.9.7/docs/source/sphinx-static/theme_overrides.css000066400000000000000000000004541526744317200234130ustar00rootroot00000000000000@media screen { /* content column * * RTD theme's default is 800px as max width for the content, but we have * tables with tons of columns, which need the full width of the view-port. * * Comment from yocto project theme_overrides.css */ .wy-nav-content{ max-width: none; } } cglm-0.9.7/docs/source/troubleshooting.rst000066400000000000000000000101551526744317200206770ustar00rootroot00000000000000.. default-domain:: C Troubleshooting ================================================================================ It is possible that you may sometimes get crashes or wrong results. Follow these topics Memory Allocation: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Recall that **cglm** does not alloc any memory on the heap. cglm functions work like memcpy; they copy data from src, make calculations, then copy the result to dest. You are responsible for allocation of **src** and **dest** parameters. Alignment: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **vec4** and **mat4** types require 16 byte alignment. These types are marked with the align attribute to let the compiler know about this requirement. Since MSVC (Windows) throws this error: **"formal parameter with requested alignment of 16 won't be aligned"** The alignment attribute has been commented out for MSVC .. code-block:: c #if defined(_MSC_VER) # define CGLM_ALIGN(X) /* __declspec(align(X)) */ #else # define CGLM_ALIGN(X) __attribute((aligned(X))) #endif. So MSVC may not know about alignment requirements when creating variables. The interesting thing is that, if I remember correctly, Visual Studio 2017 doesn't throw the above error. So we may uncomment that line for Visual Studio 2017, you may do it yourself. **This MSVC issue is still in TODOs.** **UPDATE:** Starting with v0.4.5, cglm provides an option to disable the alignment requirement. Also, alignment is disabled for older msvc versions by default. Now alignment is only required in Visual Studio 2017 version 15.6+ if the CGLM_ALL_UNALIGNED macro is not defined. Crashes, Invalid Memory Access: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Most likely, you are trying to write to an invalid memory location. You may have used a wrong function for what you want to do. For example, you may have called a **glm_vec4_** function for a **vec3** data type. It will try to write 32 bytes, but since **vec3** is 24 bytes, it should throw a memory access error or exit the app without saying anything. **UPDATE - IMPORTANT:** | On MSVC or some other compilers, if alignment is enabled (default) then double check alignment requirements if you got a crash. | If you send GLM_VEC4_ONE or similar macros directly to a function, it may crash. | Because the compiler may not apply alignment as defined on **typedef** to that macro while passing it (on stack) to a function. Wrong Results: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Again, you may have used a wrong function. For instance if you use **glm_normalize()** or **glm_vec3_normalize()** for a **vec4**, it will assume that the passed param is a **vec3**, and will normalize it for **vec3**. Since you need a **vec4** to be normalized in your case, you will get wrong results. Accessing a vec4 type with vec3 functions is valid, you will not get any error, exception or crash. You only get wrong results if you don't know what you are doing! So be careful, when your IDE (Xcode, Visual Studio ...) tries to autocomplete function names, READ IT :) **Also implementation may be wrong, please let us know by creating an issue on Github.** BAD_ACCESS : Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT) or Similar Errors/Crashes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This is a similar issue with alignment. For instance if you compiled **cglm** with AVX (**-mavx**, intentionally or not) and if you use **cglm** in an environment that doesn't support AVX (or if AVX is disabled intentionally) e.g. environment that max support SSE2/3/4, then you probably get **BAD ACCESS** or similar... Because if you compile **cglm** with AVX it aligns **mat4** with 32 byte boundary, and your project aligns that as a 16 byte boundary... Check alignment, supported vector extension, or simd in **cglm** and linked projects... Other Issues? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Please let us know by creating an issue on Github.** cglm-0.9.7/docs/source/util.rst000066400000000000000000000100071526744317200164210ustar00rootroot00000000000000.. default-domain:: C utils / helpers ================================================================================ Header: cglm/util.h Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions: 1. :c:func:`glm_sign` #. :c:func:`glm_signf` #. :c:func:`glm_rad` #. :c:func:`glm_deg` #. :c:func:`glm_make_rad` #. :c:func:`glm_make_deg` #. :c:func:`glm_pow2` #. :c:func:`glm_min` #. :c:func:`glm_max` #. :c:func:`glm_clamp` #. :c:func:`glm_lerp` #. :c:func:`glm_swapf` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: int glm_sign(int val) | returns sign of 32 bit integer as +1, -1, 0 | **Important**: It returns 0 for zero input Parameters: | *[in]* **val** an integer Returns: sign of given number .. c:function:: float glm_signf(float val) | returns sign of 32 bit integer as +1.0, -1.0, 0.0 | **Important**: It returns 0.0f for zero input Parameters: | *[in]* **val** a float Returns: sign of given number .. c:function:: float glm_rad(float deg) | convert degree to radians Parameters: | *[in]* **deg** angle in degrees .. c:function:: float glm_deg(float rad) | convert radians to degree Parameters: | *[in]* **rad** angle in radians .. c:function:: void glm_make_rad(float *degm) | convert existing degree to radians. this will override degrees value Parameters: | *[in, out]* **deg** pointer to angle in degrees .. c:function:: void glm_make_deg(float *rad) | convert existing radians to degree. this will override radians value Parameters: | *[in, out]* **rad** pointer to angle in radians .. c:function:: float glm_pow2(float x) | multiplies given parameter with itself = x * x or powf(x, 2) Parameters: | *[in]* **x** value Returns: square of a given number .. c:function:: float glm_min(float a, float b) | returns minimum of given two values Parameters: | *[in]* **a** number 1 | *[in]* **b** number 2 Returns: minimum value .. c:function:: float glm_max(float a, float b) | returns maximum of given two values Parameters: | *[in]* **a** number 1 | *[in]* **b** number 2 Returns: maximum value .. c:function:: void glm_clamp(float val, float minVal, float maxVal) constrain a value to lie between two further values Parameters: | *[in]* **val** input value | *[in]* **minVal** minimum value | *[in]* **maxVal** maximum value Returns: clamped value .. c:function:: float glm_lerp(float from, float to, float t) linear interpolation between two number | formula: from + s * (to - from) Parameters: | *[in]* **from** from value | *[in]* **to** to value | *[in]* **t** interpolant (amount) clamped between 0 and 1 Returns: interpolated value .. c:function:: bool glm_eq(float a, float b) check if two float equal with using EPSILON Parameters: | *[in]* **a** a | *[in]* **b** b Returns: true if a and b are equal .. c:function:: float glm_percent(float from, float to, float current) percentage of current value between start and end value Parameters: | *[in]* **from** from value | *[in]* **to** to value | *[in]* **current** value between from and to values Returns: percentage of current value .. c:function:: float glm_percentc(float from, float to, float current) clamped percentage of current value between start and end value Parameters: | *[in]* **from** from value | *[in]* **to** to value | *[in]* **current** value between from and to values Returns: clamped normalized percent (0-100 in 0-1) .. c:function:: void glm_swapf(float *a, float *b) swap two float values Parameters: | *[in]* **a** float 1 | *[in]* **b** float 2 cglm-0.9.7/docs/source/vec2-ext.rst000066400000000000000000000074521526744317200171130ustar00rootroot00000000000000.. default-domain:: C vec2 extra ========== Header: cglm/vec2-ext.h There are some functions are in called in extra header. These are called extra because they are not used like other functions in vec2.h in the future some of these functions ma be moved to vec2 header. Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions: 1. :c:func:`glm_vec2_fill` #. :c:func:`glm_vec2_eq` #. :c:func:`glm_vec2_eq_eps` #. :c:func:`glm_vec2_eq_all` #. :c:func:`glm_vec2_eqv` #. :c:func:`glm_vec2_eqv_eps` #. :c:func:`glm_vec2_max` #. :c:func:`glm_vec2_min` #. :c:func:`glm_vec2_isnan` #. :c:func:`glm_vec2_isinf` #. :c:func:`glm_vec2_isvalid` #. :c:func:`glm_vec2_sign` #. :c:func:`glm_vec2_abs` #. :c:func:`glm_vec2_fract` #. :c:func:`glm_vec2_floor` #. :c:func:`glm_vec2_sqrt` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_vec2_fill(vec2 v, float val) fill a vector with specified value Parameters: | *[in,out]* **dest** destination | *[in]* **val** value .. c:function:: bool glm_vec2_eq(vec2 v, float val) check if vector is equal to value (without epsilon) Parameters: | *[in]* **v** vector | *[in]* **val** value .. c:function:: bool glm_vec2_eq_eps(vec2 v, float val) check if vector is equal to value (with epsilon) Parameters: | *[in]* **v** vector | *[in]* **val** value .. c:function:: bool glm_vec2_eq_all(vec2 v) check if vectors members are equal (without epsilon) Parameters: | *[in]* **v** vector .. c:function:: bool glm_vec2_eqv(vec2 v1, vec2 v2) check if vector is equal to another (without epsilon) vector Parameters: | *[in]* **vec** vector 1 | *[in]* **vec** vector 2 .. c:function:: bool glm_vec2_eqv_eps(vec2 v1, vec2 v2) check if vector is equal to another (with epsilon) Parameters: | *[in]* **v1** vector1 | *[in]* **v2** vector2 .. c:function:: float glm_vec2_max(vec2 v) max value of vector Parameters: | *[in]* **v** vector .. c:function:: float glm_vec2_min(vec2 v) min value of vector Parameters: | *[in]* **v** vector .. c:function:: bool glm_vec2_isnan(vec2 v) | check if one of items is NaN (not a number) | you should only use this in DEBUG mode or very critical asserts Parameters: | *[in]* **v** vector .. c:function:: bool glm_vec2_isinf(vec2 v) | check if one of items is INFINITY | you should only use this in DEBUG mode or very critical asserts Parameters: | *[in]* **v** vector .. c:function:: bool glm_vec2_isvalid(vec2 v) | check if all items are valid number | you should only use this in DEBUG mode or very critical asserts Parameters: | *[in]* **v** vector .. c:function:: void glm_vec2_sign(vec2 v, vec2 dest) get sign of 32 bit float as +1, -1, 0 Parameters: | *[in]* **v** vector | *[out]* **dest** sign vector (only keeps signs as -1, 0, -1) .. c:function:: void glm_vec2_abs(vec2 v, vec2 dest) absolute value of each vector item Parameters: | *[in]* **v** vector | *[out]* **dest** destination vector .. c:function:: void glm_vec2_fract(vec2 v, vec2 dest) get fractional part of each vector item Parameters: | *[in]* **v** vector | *[out]* **dest** destination vector .. c:function:: void glm_vec2_floor(vec2 v, vec2 dest) floor value of each vector item Parameters: | *[in]* **v** vector | *[out]* **dest** destination vector .. c:function:: void glm_vec2_sqrt(vec2 v, vec2 dest) square root of each vector item Parameters: | *[in]* **v** vector | *[out]* **dest** destination vector (sqrt(v)) cglm-0.9.7/docs/source/vec2.rst000066400000000000000000000262331526744317200163130ustar00rootroot00000000000000.. default-domain:: C vec2 ==== Header: cglm/vec2.h Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Macros: 1. GLM_VEC2_ONE_INIT #. GLM_VEC2_ZERO_INIT #. GLM_VEC2_ONE #. GLM_VEC2_ZERO Functions: 1. :c:func:`glm_vec2` #. :c:func:`glm_vec2_copy` #. :c:func:`glm_vec2_zero` #. :c:func:`glm_vec2_one` #. :c:func:`glm_vec2_dot` #. :c:func:`glm_vec2_cross` #. :c:func:`glm_vec2_norm2` #. :c:func:`glm_vec2_norm` #. :c:func:`glm_vec2_add` #. :c:func:`glm_vec2_adds` #. :c:func:`glm_vec2_sub` #. :c:func:`glm_vec2_subs` #. :c:func:`glm_vec2_mul` #. :c:func:`glm_vec2_scale` #. :c:func:`glm_vec2_scale_as` #. :c:func:`glm_vec2_div` #. :c:func:`glm_vec2_divs` #. :c:func:`glm_vec2_addadd` #. :c:func:`glm_vec2_subadd` #. :c:func:`glm_vec2_muladd` #. :c:func:`glm_vec2_muladds` #. :c:func:`glm_vec2_maxadd` #. :c:func:`glm_vec2_minadd` #. :c:func:`glm_vec2_negate` #. :c:func:`glm_vec2_negate_to` #. :c:func:`glm_vec2_normalize` #. :c:func:`glm_vec2_normalize_to` #. :c:func:`glm_vec2_rotate` #. :c:func:`glm_vec2_center` #. :c:func:`glm_vec2_distance2` #. :c:func:`glm_vec2_distance` #. :c:func:`glm_vec2_maxv` #. :c:func:`glm_vec2_minv` #. :c:func:`glm_vec2_clamp` #. :c:func:`glm_vec2_lerp` #. :c:func:`glm_vec2_make` #. :c:func:`glm_vec2_reflect` #. :c:func:`glm_vec2_refract` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_vec2(float * v, vec2 dest) init vec2 using vec3 or vec4 Parameters: | *[in]* **v** vector | *[out]* **dest** destination .. c:function:: void glm_vec2_copy(vec2 a, vec2 dest) copy all members of [a] to [dest] Parameters: | *[in]* **a** source | *[out]* **dest** destination .. c:function:: void glm_vec2_zero(vec2 v) makes all members 0.0f (zero) Parameters: | *[in, out]* **v** vector .. c:function:: void glm_vec2_one(vec2 v) makes all members 1.0f (one) Parameters: | *[in, out]* **v** vector .. c:function:: float glm_vec2_dot(vec2 a, vec2 b) dot product of vec2 Parameters: | *[in]* **a** vector1 | *[in]* **b** vector2 Returns: dot product .. c:function:: void glm_vec2_cross(vec2 a, vec2 b, vec2 d) cross product of two vector (RH) | ref: http://allenchou.net/2013/07/cross-product-of-2d-vectors/ Parameters: | *[in]* **a** vector 1 | *[in]* **b** vector 2 | *[out]* **dest** destination Returns: Z component of cross product .. c:function:: float glm_vec2_norm2(vec2 v) norm * norm (magnitude) of vector we can use this func instead of calling norm * norm, because it would call sqrtf function twice but with this func we can avoid func call, maybe this is not good name for this func Parameters: | *[in]* **v** vector Returns: square of norm / magnitude .. c:function:: float glm_vec2_norm(vec2 vec) | euclidean norm (magnitude), also called L2 norm | this will give magnitude of vector in euclidean space Parameters: | *[in]* **vec** vector .. c:function:: void glm_vec2_add(vec2 a, vec2 b, vec2 dest) add a vector to b vector store result in dest Parameters: | *[in]* **a** vector1 | *[in]* **b** vector2 | *[out]* **dest** destination vector .. c:function:: void glm_vec2_adds(vec2 a, float s, vec2 dest) add scalar to v vector store result in dest (d = v + vec(s)) Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** destination vector .. c:function:: void glm_vec2_sub(vec2 v1, vec2 v2, vec2 dest) subtract b vector from a vector store result in dest (d = v1 - v2) Parameters: | *[in]* **a** vector1 | *[in]* **b** vector2 | *[out]* **dest** destination vector .. c:function:: void glm_vec2_subs(vec2 v, float s, vec2 dest) subtract scalar from v vector store result in dest (d = v - vec(s)) Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** destination vector .. c:function:: void glm_vec2_mul(vec2 a, vec2 b, vec2 d) multiply two vector (component-wise multiplication) Parameters: | *[in]* **a** vector | *[in]* **b** scalar | *[out]* **d** result = (a[0] * b[0], a[1] * b[1], a[2] * b[2]) .. c:function:: void glm_vec2_scale(vec2 v, float s, vec2 dest) multiply/scale vec2 vector with scalar: result = v * s Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** destination vector .. c:function:: void glm_vec2_scale_as(vec2 v, float s, vec2 dest) make vec2 vector scale as specified: result = unit(v) * s Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** destination vector .. c:function:: void glm_vec2_div(vec2 a, vec2 b, vec2 dest) div vector with another component-wise division: d = a / b Parameters: | *[in]* **a** vector 1 | *[in]* **b** vector 2 | *[out]* **dest** result = (a[0] / b[0], a[1] / b[1], a[2] / b[2]) .. c:function:: void glm_vec2_divs(vec2 v, float s, vec2 dest) div vector with scalar: d = v / s Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** result = (a[0] / s, a[1] / s, a[2] / s]) .. c:function:: void glm_vec2_addadd(vec2 a, vec2 b, vec2 dest) | add two vectors and add result to sum | it applies += operator so dest must be initialized Parameters: | *[in]* **a** vector 1 | *[in]* **b** vector 2 | *[out]* **dest** dest += (a + b) .. c:function:: void glm_vec2_subadd(vec2 a, vec2 b, vec2 dest) | sub two vectors and add result to sum | it applies += operator so dest must be initialized Parameters: | *[in]* **a** vector 1 | *[in]* **b** vector 2 | *[out]* **dest** dest += (a - b) .. c:function:: void glm_vec2_muladd(vec2 a, vec2 b, vec2 dest) | mul two vectors and add result to sum | it applies += operator so dest must be initialized Parameters: | *[in]* **a** vector 1 | *[in]* **b** vector 2 | *[out]* **dest** dest += (a * b) .. c:function:: void glm_vec2_muladds(vec2 a, float s, vec2 dest) | mul vector with scalar and add result to sum | it applies += operator so dest must be initialized Parameters: | *[in]* **a** vector | *[in]* **s** scalar | *[out]* **dest** dest += (a * b) .. c:function:: void glm_vec2_maxadd(vec2 a, vec2 b, vec2 dest) | add max of two vector to result/dest | it applies += operator so dest must be initialized Parameters: | *[in]* **a** vector 1 | *[in]* **b** vector 2 | *[out]* **dest** dest += (a * b) .. c:function:: void glm_vec2_minadd(vec2 a, vec2 b, vec2 dest) | add min of two vector to result/dest | it applies += operator so dest must be initialized Parameters: | *[in]* **a** vector 1 | *[in]* **b** vector 2 | *[out]* **dest** dest += (a * b) .. c:function:: void glm_vec2_negate(vec2 v) negate vector components Parameters: | *[in, out]* **v** vector .. c:function:: void glm_vec2_negate_to(vec2 v, vec2 dest) negate vector components and store result in dest Parameters: | *[in]* **v** vector | *[out]* **dest** negated vector .. c:function:: void glm_vec2_normalize(vec2 v) normalize vec2 and store result in same vec Parameters: | *[in, out]* **v** vector .. c:function:: void glm_vec2_normalize_to(vec2 vec, vec2 dest) normalize vec2 to dest Parameters: | *[in]* **vec** source | *[out]* **dest** destination .. c:function:: void glm_vec2_rotate(vec2 v, float angle, vec2 dest) rotate vec2 around axis by angle using Rodrigues' rotation formula Parameters: | *[in]* **v** vector | *[in]* **axis** axis vector | *[out]* **dest** destination .. c:function:: void glm_vec2_center(vec2 v1, vec2 v2, vec2 dest) find center point of two vector Parameters: | *[in]* **v1** vector1 | *[in]* **v2** vector2 | *[out]* **dest** center point .. c:function:: float glm_vec2_distance2(vec2 v1, vec2 v2) squared distance between two vectors Parameters: | *[in]* **mat** vector1 | *[in]* **row1** vector2 Returns: | squared distance (distance * distance) .. c:function:: float glm_vec2_distance(vec2 v1, vec2 v2) distance between two vectors Parameters: | *[in]* **mat** vector1 | *[in]* **row1** vector2 Returns: | distance .. c:function:: void glm_vec2_maxv(vec2 v1, vec2 v2, vec2 dest) max values of vectors Parameters: | *[in]* **v1** vector1 | *[in]* **v2** vector2 | *[out]* **dest** destination .. c:function:: void glm_vec2_minv(vec2 v1, vec2 v2, vec2 dest) min values of vectors Parameters: | *[in]* **v1** vector1 | *[in]* **v2** vector2 | *[out]* **dest** destination .. c:function:: void glm_vec2_clamp(vec2 v, float minVal, float maxVal) constrain a value to lie between two further values Parameters: | *[in, out]* **v** vector | *[in]* **minVal** minimum value | *[in]* **maxVal** maximum value .. c:function:: void glm_vec2_lerp(vec2 from, vec2 to, float t, vec2 dest) linear interpolation between two vector | formula: from + s * (to - from) Parameters: | *[in]* **from** from value | *[in]* **to** to value | *[in]* **t** interpolant (amount) clamped between 0 and 1 | *[out]* **dest** destination .. c:function:: void glm_vec2_make(const float * __restrict src, vec2 dest) Create two dimensional vector from pointer .. note:: **@src** must contain at least 2 elements. Parameters: | *[in]* **src** pointer to an array of floats | *[out]* **dest** destination vector .. c:function:: void glm_vec2_reflect(vec2 v, vec2 n, vec2 dest) Reflection vector using an incident ray and a surface normal Parameters: | *[in]* **v** incident vector | *[in]* **n** *â�—ï¸� normalized â�—ï¸�* normal vector | *[out]* **dest** destination: reflection result .. c:function:: bool glm_vec2_refract(vec2 v, vec2 n, float eta, vec2 dest) Computes refraction vector for an incident vector and a surface normal. Calculates the refraction vector based on Snell's law. If total internal reflection occurs (angle too great given eta), dest is set to zero and returns false. Otherwise, computes refraction vector, stores it in dest, and returns true. Parameters: | *[in]* **v** *â�—ï¸� normalized â�—ï¸�* incident vector | *[in]* **n** *â�—ï¸� normalized â�—ï¸�* normal vector | *[in]* **eta** ratio of indices of refraction (incident/transmitted) | *[out]* **dest** refraction vector if refraction occurs; zero vector otherwise Returns: returns true if refraction occurs; false if total internal reflection occurs. cglm-0.9.7/docs/source/vec3-ext.rst000066400000000000000000000103551526744317200171100ustar00rootroot00000000000000.. default-domain:: C vec3 extra ========== Header: cglm/vec3-ext.h There are some functions are in called in extra header. These are called extra because they are not used like other functions in vec3.h in the future some of these functions ma be moved to vec3 header. Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions: 1. :c:func:`glm_vec3_mulv` #. :c:func:`glm_vec3_broadcast` #. :c:func:`glm_vec3_eq` #. :c:func:`glm_vec3_eq_eps` #. :c:func:`glm_vec3_eq_all` #. :c:func:`glm_vec3_eqv` #. :c:func:`glm_vec3_eqv_eps` #. :c:func:`glm_vec3_max` #. :c:func:`glm_vec3_min` #. :c:func:`glm_vec3_isnan` #. :c:func:`glm_vec3_isinf` #. :c:func:`glm_vec3_isvalid` #. :c:func:`glm_vec3_sign` #. :c:func:`glm_vec3_abs` #. :c:func:`glm_vec3_fract` #. :c:func:`glm_vec3_floor` #. :c:func:`glm_vec3_sqrt` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_vec3_mulv(vec3 a, vec3 b, vec3 d) multiplies individual items Parameters: | *[in]* **a** vec1 | *[in]* **b** vec2 | *[out]* **d** destination (v1[0] * v2[0], v1[1] * v2[1], v1[2] * v2[2]) .. c:function:: void glm_vec3_broadcast(float val, vec3 d) fill a vector with specified value Parameters: | *[in]* **val** value | *[out]* **dest** destination .. c:function:: void glm_vec3_fill(vec3 v, float val) fill a vector with specified value Parameters: | *[out]* **v** vector | *[in]* **val** value .. c:function:: bool glm_vec3_eq(vec3 v, float val) check if vector is equal to value (without epsilon) Parameters: | *[in]* **v** vector | *[in]* **val** value .. c:function:: bool glm_vec3_eq_eps(vec3 v, float val) check if vector is equal to value (with epsilon) Parameters: | *[in]* **v** vector | *[in]* **val** value .. c:function:: bool glm_vec3_eq_all(vec3 v) check if vectors members are equal (without epsilon) Parameters: | *[in]* **v** vector .. c:function:: bool glm_vec3_eqv(vec3 v1, vec3 v2) check if vector is equal to another (without epsilon) vector Parameters: | *[in]* **vec** vector 1 | *[in]* **vec** vector 2 .. c:function:: bool glm_vec3_eqv_eps(vec3 v1, vec3 v2) check if vector is equal to another (with epsilon) Parameters: | *[in]* **v1** vector1 | *[in]* **v2** vector2 .. c:function:: float glm_vec3_max(vec3 v) max value of vector Parameters: | *[in]* **v** vector .. c:function:: float glm_vec3_min(vec3 v) min value of vector Parameters: | *[in]* **v** vector .. c:function:: bool glm_vec3_isnan(vec3 v) | check if one of items is NaN (not a number) | you should only use this in DEBUG mode or very critical asserts Parameters: | *[in]* **v** vector .. c:function:: bool glm_vec3_isinf(vec3 v) | check if one of items is INFINITY | you should only use this in DEBUG mode or very critical asserts Parameters: | *[in]* **v** vector .. c:function:: bool glm_vec3_isvalid(vec3 v) | check if all items are valid number | you should only use this in DEBUG mode or very critical asserts Parameters: | *[in]* **v** vector .. c:function:: void glm_vec3_sign(vec3 v, vec3 dest) get sign of 32 bit float as +1, -1, 0 Parameters: | *[in]* **v** vector | *[out]* **dest** sign vector (only keeps signs as -1, 0, -1) .. c:function:: void glm_vec3_abs(vec3 v, vec3 dest) absolute value of each vector item Parameters: | *[in]* **v** vector | *[out]* **dest** destination vector .. c:function:: void glm_vec3_fract(vec3 v, vec3 dest) fractional part of each vector item Parameters: | *[in]* **v** vector | *[out]* **dest** destination vector .. c:function:: void glm_vec3_floor(vec3 v, vec3 dest) floor of each vector item Parameters: | *[in]* **v** vector | *[out]* **dest** destination vector .. c:function:: void glm_vec3_sqrt(vec3 v, vec3 dest) square root of each vector item Parameters: | *[in]* **v** vector | *[out]* **dest** destination vector (sqrt(v)) cglm-0.9.7/docs/source/vec3.rst000066400000000000000000000352751526744317200163220ustar00rootroot00000000000000.. default-domain:: C vec3 ==== Header: cglm/vec3.h **Important:** *cglm* was used **glm_vec_** namespace for vec3 functions until **v0.5.0**, since **v0.5.0** cglm uses **glm_vec3_** namespace for vec3. Also `glm_vec3_flipsign` has been renamed to `glm_vec3_negate` We mostly use vectors in graphics math, to make writing code faster and easy to read, some *vec3* functions are aliased in global namespace. For instance :c:func:`glm_dot` is alias of :c:func:`glm_vec3_dot`, alias means inline wrapper here. There is no call version of alias functions There are also functions for rotating *vec3* vector. **_m4**, **_m3** prefixes rotate *vec3* with matrix. Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Macros: 1. glm_vec3_dup(v, dest) #. GLM_VEC3_ONE_INIT #. GLM_VEC3_ZERO_INIT #. GLM_VEC3_ONE #. GLM_VEC3_ZERO #. GLM_YUP #. GLM_ZUP #. GLM_XUP Functions: 1. :c:func:`glm_vec3` #. :c:func:`glm_vec3_copy` #. :c:func:`glm_vec3_zero` #. :c:func:`glm_vec3_one` #. :c:func:`glm_vec3_dot` #. :c:func:`glm_vec3_norm2` #. :c:func:`glm_vec3_norm` #. :c:func:`glm_vec3_add` #. :c:func:`glm_vec3_adds` #. :c:func:`glm_vec3_sub` #. :c:func:`glm_vec3_subs` #. :c:func:`glm_vec3_mul` #. :c:func:`glm_vec3_scale` #. :c:func:`glm_vec3_scale_as` #. :c:func:`glm_vec3_div` #. :c:func:`glm_vec3_divs` #. :c:func:`glm_vec3_addadd` #. :c:func:`glm_vec3_subadd` #. :c:func:`glm_vec3_muladd` #. :c:func:`glm_vec3_muladds` #. :c:func:`glm_vec3_maxadd` #. :c:func:`glm_vec3_minadd` #. :c:func:`glm_vec3_flipsign` #. :c:func:`glm_vec3_flipsign_to` #. :c:func:`glm_vec3_inv` #. :c:func:`glm_vec3_inv_to` #. :c:func:`glm_vec3_negate` #. :c:func:`glm_vec3_negate_to` #. :c:func:`glm_vec3_normalize` #. :c:func:`glm_vec3_normalize_to` #. :c:func:`glm_vec3_cross` #. :c:func:`glm_vec3_crossn` #. :c:func:`glm_vec3_distance2` #. :c:func:`glm_vec3_distance` #. :c:func:`glm_vec3_angle` #. :c:func:`glm_vec3_rotate` #. :c:func:`glm_vec3_rotate_m4` #. :c:func:`glm_vec3_rotate_m3` #. :c:func:`glm_vec3_proj` #. :c:func:`glm_vec3_center` #. :c:func:`glm_vec3_maxv` #. :c:func:`glm_vec3_minv` #. :c:func:`glm_vec3_ortho` #. :c:func:`glm_vec3_clamp` #. :c:func:`glm_vec3_lerp` #. :c:func:`glm_vec3_make` #. :c:func:`glm_vec3_faceforward` #. :c:func:`glm_vec3_reflect` #. :c:func:`glm_vec3_refract` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_vec3(vec4 v4, vec3 dest) init vec3 using vec4 Parameters: | *[in]* **v4** vector4 | *[out]* **dest** destination .. c:function:: void glm_vec3_copy(vec3 a, vec3 dest) copy all members of [a] to [dest] Parameters: | *[in]* **a** source | *[out]* **dest** destination .. c:function:: void glm_vec3_zero(vec3 v) makes all members 0.0f (zero) Parameters: | *[in, out]* **v** vector .. c:function:: void glm_vec3_one(vec3 v) makes all members 1.0f (one) Parameters: | *[in, out]* **v** vector .. c:function:: float glm_vec3_dot(vec3 a, vec3 b) dot product of vec3 Parameters: | *[in]* **a** vector1 | *[in]* **b** vector2 Returns: dot product .. c:function:: void glm_vec3_cross(vec3 a, vec3 b, vec3 d) cross product of two vector (RH) Parameters: | *[in]* **a** vector 1 | *[in]* **b** vector 2 | *[out]* **dest** destination .. c:function:: void glm_vec3_crossn(vec3 a, vec3 b, vec3 dest) cross product of two vector (RH) and normalize the result Parameters: | *[in]* **a** vector 1 | *[in]* **b** vector 2 | *[out]* **dest** destination .. c:function:: float glm_vec3_norm2(vec3 v) norm * norm (magnitude) of vector we can use this func instead of calling norm * norm, because it would call sqrtf function twice but with this func we can avoid func call, maybe this is not good name for this func Parameters: | *[in]* **v** vector Returns: square of norm / magnitude .. c:function:: float glm_vec3_norm(vec3 vec) | euclidean norm (magnitude), also called L2 norm | this will give magnitude of vector in euclidean space Parameters: | *[in]* **vec** vector .. c:function:: void glm_vec3_add(vec3 a, vec3 b, vec3 dest) add a vector to b vector store result in dest Parameters: | *[in]* **a** vector1 | *[in]* **b** vector2 | *[out]* **dest** destination vector .. c:function:: void glm_vec3_adds(vec3 a, float s, vec3 dest) add scalar to v vector store result in dest (d = v + vec(s)) Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** destination vector .. c:function:: void glm_vec3_sub(vec3 v1, vec3 v2, vec3 dest) subtract b vector from a vector store result in dest (d = v1 - v2) Parameters: | *[in]* **a** vector1 | *[in]* **b** vector2 | *[out]* **dest** destination vector .. c:function:: void glm_vec3_subs(vec3 v, float s, vec3 dest) subtract scalar from v vector store result in dest (d = v - vec(s)) Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** destination vector .. c:function:: void glm_vec3_mul(vec3 a, vec3 b, vec3 d) multiply two vector (component-wise multiplication) Parameters: | *[in]* **a** vector | *[in]* **b** scalar | *[out]* **d** result = (a[0] * b[0], a[1] * b[1], a[2] * b[2]) .. c:function:: void glm_vec3_scale(vec3 v, float s, vec3 dest) multiply/scale vec3 vector with scalar: result = v * s Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** destination vector .. c:function:: void glm_vec3_scale_as(vec3 v, float s, vec3 dest) make vec3 vector scale as specified: result = unit(v) * s Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** destination vector .. c:function:: void glm_vec3_div(vec3 a, vec3 b, vec3 dest) div vector with another component-wise division: d = a / b Parameters: | *[in]* **a** vector 1 | *[in]* **b** vector 2 | *[out]* **dest** result = (a[0] / b[0], a[1] / b[1], a[2] / b[2]) .. c:function:: void glm_vec3_divs(vec3 v, float s, vec3 dest) div vector with scalar: d = v / s Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** result = (a[0] / s, a[1] / s, a[2] / s]) .. c:function:: void glm_vec3_addadd(vec3 a, vec3 b, vec3 dest) | add two vectors and add result to sum | it applies += operator so dest must be initialized Parameters: | *[in]* **a** vector 1 | *[in]* **b** vector 2 | *[out]* **dest** dest += (a + b) .. c:function:: void glm_vec3_subadd(vec3 a, vec3 b, vec3 dest) | sub two vectors and add result to sum | it applies += operator so dest must be initialized Parameters: | *[in]* **a** vector 1 | *[in]* **b** vector 2 | *[out]* **dest** dest += (a - b) .. c:function:: void glm_vec3_muladd(vec3 a, vec3 b, vec3 dest) | mul two vectors and add result to sum | it applies += operator so dest must be initialized Parameters: | *[in]* **a** vector 1 | *[in]* **b** vector 2 | *[out]* **dest** dest += (a * b) .. c:function:: void glm_vec3_muladds(vec3 a, float s, vec3 dest) | mul vector with scalar and add result to sum | it applies += operator so dest must be initialized Parameters: | *[in]* **a** vector | *[in]* **s** scalar | *[out]* **dest** dest += (a * b) .. c:function:: void glm_vec3_maxadd(vec3 a, vec3 b, vec3 dest) | add max of two vector to result/dest | it applies += operator so dest must be initialized Parameters: | *[in]* **a** vector 1 | *[in]* **b** vector 2 | *[out]* **dest** dest += (a * b) .. c:function:: void glm_vec3_minadd(vec3 a, vec3 b, vec3 dest) | add min of two vector to result/dest | it applies += operator so dest must be initialized Parameters: | *[in]* **a** vector 1 | *[in]* **b** vector 2 | *[out]* **dest** dest += (a * b) .. c:function:: void glm_vec3_flipsign(vec3 v) **DEPRECATED!** use :c:func:`glm_vec3_negate` Parameters: | *[in, out]* **v** vector .. c:function:: void glm_vec3_flipsign_to(vec3 v, vec3 dest) **DEPRECATED!** use :c:func:`glm_vec3_negate_to` Parameters: | *[in]* **v** vector | *[out]* **dest** negated vector .. c:function:: void glm_vec3_inv(vec3 v) **DEPRECATED!** use :c:func:`glm_vec3_negate` Parameters: | *[in, out]* **v** vector .. c:function:: void glm_vec3_inv_to(vec3 v, vec3 dest) **DEPRECATED!** use :c:func:`glm_vec3_negate_to` Parameters: | *[in]* **v** source | *[out]* **dest** destination .. c:function:: void glm_vec3_negate(vec3 v) negate vector components Parameters: | *[in, out]* **v** vector .. c:function:: void glm_vec3_negate_to(vec3 v, vec3 dest) negate vector components and store result in dest Parameters: | *[in]* **v** vector | *[out]* **dest** negated vector .. c:function:: void glm_vec3_normalize(vec3 v) normalize vec3 and store result in same vec Parameters: | *[in, out]* **v** vector .. c:function:: void glm_vec3_normalize_to(vec3 vec, vec3 dest) normalize vec3 to dest Parameters: | *[in]* **vec** source | *[out]* **dest** destination .. c:function:: float glm_vec3_angle(vec3 v1, vec3 v2) angle between two vector Parameters: | *[in]* **v1** vector1 | *[in]* **v2** vector2 Return: | angle as radians .. c:function:: void glm_vec3_rotate(vec3 v, float angle, vec3 axis) rotate vec3 around axis by angle using Rodrigues' rotation formula Parameters: | *[in, out]* **v** vector | *[in]* **axis** axis vector (will be normalized) | *[in]* **angle** angle (radians) .. c:function:: void glm_vec3_rotate_m4(mat4 m, vec3 v, vec3 dest) apply rotation matrix to vector Parameters: | *[in]* **m** affine matrix or rot matrix | *[in]* **v** vector | *[out]* **dest** rotated vector .. c:function:: void glm_vec3_rotate_m3(mat3 m, vec3 v, vec3 dest) apply rotation matrix to vector Parameters: | *[in]* **m** affine matrix or rot matrix | *[in]* **v** vector | *[out]* **dest** rotated vector .. c:function:: void glm_vec3_proj(vec3 a, vec3 b, vec3 dest) project a vector onto b vector Parameters: | *[in]* **a** vector1 | *[in]* **b** vector2 | *[out]* **dest** projected vector .. c:function:: void glm_vec3_center(vec3 v1, vec3 v2, vec3 dest) find center point of two vector Parameters: | *[in]* **v1** vector1 | *[in]* **v2** vector2 | *[out]* **dest** center point .. c:function:: float glm_vec3_distance2(vec3 v1, vec3 v2) squared distance between two vectors Parameters: | *[in]* **v1** vector1 | *[in]* **v2** vector2 Returns: | squared distance (distance * distance) .. c:function:: float glm_vec3_distance(vec3 v1, vec3 v2) distance between two vectors Parameters: | *[in]* **v1** vector1 | *[in]* **v2** vector2 Returns: | distance .. c:function:: void glm_vec3_maxv(vec3 v1, vec3 v2, vec3 dest) max values of vectors Parameters: | *[in]* **v1** vector1 | *[in]* **v2** vector2 | *[out]* **dest** destination .. c:function:: void glm_vec3_minv(vec3 v1, vec3 v2, vec3 dest) min values of vectors Parameters: | *[in]* **v1** vector1 | *[in]* **v2** vector2 | *[out]* **dest** destination .. c:function:: void glm_vec3_ortho(vec3 v, vec3 dest) possible orthogonal/perpendicular vector References: * `On picking an orthogonal vector (and combing coconuts) `_ Parameters: | *[in]* **v** vector | *[out]* **dest** orthogonal/perpendicular vector .. c:function:: void glm_vec3_clamp(vec3 v, float minVal, float maxVal) constrain a value to lie between two further values Parameters: | *[in, out]* **v** vector | *[in]* **minVal** minimum value | *[in]* **maxVal** maximum value .. c:function:: void glm_vec3_lerp(vec3 from, vec3 to, float t, vec3 dest) linear interpolation between two vector | formula: from + s * (to - from) Parameters: | *[in]* **from** from value | *[in]* **to** to value | *[in]* **t** interpolant (amount) clamped between 0 and 1 | *[out]* **dest** destination .. c:function:: void glm_vec3_make(const float * __restrict src, vec3 dest) Create three dimensional vector from pointer .. note::: **@src** must contain at least 3 elements. Parameters: | *[in]* **src** pointer to an array of floats | *[out]* **dest** destination vector .. c:function:: void glm_vec3_faceforward(vec3 n, vec3 v, vec3 nref, vec3 dest) A vector pointing in the same direction as another Parameters: | *[in]* **n** vector to orient | *[in]* **v** incident vector | *[in]* **nref** reference vector | *[out]* **dest** destination: oriented vector, pointing away from the surface. .. c:function:: void glm_vec3_reflect(vec3 v, vec3 n, vec3 dest) Reflection vector using an incident ray and a surface normal Parameters: | *[in]* **v** incident vector | *[in]* **n** *â�—ï¸� normalized â�—ï¸�* normal vector | *[out]* **dest** destination: reflection result .. c:function:: bool glm_vec3_refract(vec3 v, vec3 n, float eta, vec3 dest) Computes refraction vector for an incident vector and a surface normal. Calculates the refraction vector based on Snell's law. If total internal reflection occurs (angle too great given eta), dest is set to zero and returns false. Otherwise, computes refraction vector, stores it in dest, and returns true. Parameters: | *[in]* **v** *â�—ï¸� normalized â�—ï¸�* incident vector | *[in]* **n** *â�—ï¸� normalized â�—ï¸�* normal vector | *[in]* **eta** ratio of indices of refraction (incident/transmitted) | *[out]* **dest** refraction vector if refraction occurs; zero vector otherwise Returns: returns true if refraction occurs; false if total internal reflection occurs. cglm-0.9.7/docs/source/vec4-ext.rst000066400000000000000000000100511526744317200171020ustar00rootroot00000000000000.. default-domain:: C vec4 extra ========== Header: cglm/vec4-ext.h There are some functions are in called in extra header. These are called extra because they are not used like other functions in vec4.h in the future some of these functions ma be moved to vec4 header. Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions: 1. :c:func:`glm_vec4_mulv` #. :c:func:`glm_vec4_broadcast` #. :c:func:`glm_vec4_eq` #. :c:func:`glm_vec4_eq_eps` #. :c:func:`glm_vec4_eq_all` #. :c:func:`glm_vec4_eqv` #. :c:func:`glm_vec4_eqv_eps` #. :c:func:`glm_vec4_max` #. :c:func:`glm_vec4_min` #. :c:func:`glm_vec4_isnan` #. :c:func:`glm_vec4_isinf` #. :c:func:`glm_vec4_isvalid` #. :c:func:`glm_vec4_sign` #. :c:func:`glm_vec4_abs` #. :c:func:`glm_vec4_fract` #. :c:func:`glm_vec4_floor` #. :c:func:`glm_vec4_sqrt` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_vec4_mulv(vec4 a, vec4 b, vec4 d) multiplies individual items Parameters: | *[in]* **a** vec1 | *[in]* **b** vec2 | *[out]* **d** destination .. c:function:: void glm_vec4_broadcast(float val, vec4 d) fill a vector with specified value Parameters: | *[in]* **val** value | *[out]* **dest** destination .. c:function:: bool glm_vec4_eq(vec4 v, float val) check if vector is equal to value (without epsilon) Parameters: | *[in]* **v** vector | *[in]* **val** value .. c:function:: bool glm_vec4_eq_eps(vec4 v, float val) check if vector is equal to value (with epsilon) Parameters: | *[in]* **v** vector | *[in]* **val** value .. c:function:: bool glm_vec4_eq_all(vec4 v) check if vectors members are equal (without epsilon) Parameters: | *[in]* **v** vector .. c:function:: bool glm_vec4_eqv(vec4 v1, vec4 v2) check if vector is equal to another (without epsilon) vector Parameters: | *[in]* **vec** vector 1 | *[in]* **vec** vector 2 .. c:function:: bool glm_vec4_eqv_eps(vec4 v1, vec4 v2) check if vector is equal to another (with epsilon) Parameters: | *[in]* **v1** vector1 | *[in]* **v2** vector2 .. c:function:: float glm_vec4_max(vec4 v) max value of vector Parameters: | *[in]* **v** vector .. c:function:: float glm_vec4_min(vec4 v) min value of vector Parameters: | *[in]* **v** vector .. c:function:: bool glm_vec4_isnan(vec4 v) | check if one of items is NaN (not a number) | you should only use this in DEBUG mode or very critical asserts Parameters: | *[in]* **v** vector .. c:function:: bool glm_vec4_isinf(vec4 v) | check if one of items is INFINITY | you should only use this in DEBUG mode or very critical asserts Parameters: | *[in]* **v** vector .. c:function:: bool glm_vec4_isvalid(vec4 v) | check if all items are valid number | you should only use this in DEBUG mode or very critical asserts Parameters: | *[in]* **v** vector .. c:function:: void glm_vec4_sign(vec4 v, vec4 dest) get sign of 32 bit float as +1, -1, 0 Parameters: | *[in]* **v** vector | *[out]* **dest** sign vector (only keeps signs as -1, 0, -1) .. c:function:: void glm_vec4_abs(vec4 v, vec4 dest) absolute value of each vector item Parameters: | *[in]* **v** vector | *[out]* **dest** destination vector (abs(v)) .. c:function:: void glm_vec4_fract(vec4 v, vec4 dest) fractional part of each vector item Parameters: | *[in]* **v** vector | *[out]* **dest** destination vector (fract(v)) .. c:function:: void glm_vec4_floor(vec4 v, vec4 dest) floor of each vector item Parameters: | *[in]* **v** vector | *[out]* **dest** destination vector (floor(v)) .. c:function:: void glm_vec4_sqrt(vec4 v, vec4 dest) square root of each vector item Parameters: | *[in]* **v** vector | *[out]* **dest** destination vector (sqrt(v)) cglm-0.9.7/docs/source/vec4.rst000066400000000000000000000300411526744317200163050ustar00rootroot00000000000000.. default-domain:: C vec4 ==== Header: cglm/vec4.h Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Macros: 1. glm_vec4_dup3(v, dest) #. glm_vec4_dup(v, dest) #. GLM_VEC4_ONE_INIT #. GLM_VEC4_BLACK_INIT #. GLM_VEC4_ZERO_INIT #. GLM_VEC4_ONE #. GLM_VEC4_BLACK #. GLM_VEC4_ZERO Functions: 1. :c:func:`glm_vec4` #. :c:func:`glm_vec4_copy3` #. :c:func:`glm_vec4_copy` #. :c:func:`glm_vec4_ucopy` #. :c:func:`glm_vec4_zero` #. :c:func:`glm_vec4_one` #. :c:func:`glm_vec4_dot` #. :c:func:`glm_vec4_norm2` #. :c:func:`glm_vec4_norm` #. :c:func:`glm_vec4_add` #. :c:func:`glm_vec4_adds` #. :c:func:`glm_vec4_sub` #. :c:func:`glm_vec4_subs` #. :c:func:`glm_vec4_mul` #. :c:func:`glm_vec4_scale` #. :c:func:`glm_vec4_scale_as` #. :c:func:`glm_vec4_div` #. :c:func:`glm_vec4_divs` #. :c:func:`glm_vec4_addadd` #. :c:func:`glm_vec4_subadd` #. :c:func:`glm_vec4_muladd` #. :c:func:`glm_vec4_muladds` #. :c:func:`glm_vec4_maxadd` #. :c:func:`glm_vec4_minadd` #. :c:func:`glm_vec4_flipsign` #. :c:func:`glm_vec4_flipsign_to` #. :c:func:`glm_vec4_inv` #. :c:func:`glm_vec4_inv_to` #. :c:func:`glm_vec4_negate` #. :c:func:`glm_vec4_negate_to` #. :c:func:`glm_vec4_normalize` #. :c:func:`glm_vec4_normalize_to` #. :c:func:`glm_vec4_distance` #. :c:func:`glm_vec4_maxv` #. :c:func:`glm_vec4_minv` #. :c:func:`glm_vec4_clamp` #. :c:func:`glm_vec4_lerp` #. :c:func:`glm_vec4_cubic` #. :c:func:`glm_vec4_make` #. :c:func:`glm_vec4_reflect` #. :c:func:`glm_vec4_refract` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ .. c:function:: void glm_vec4(vec3 v3, float last, vec4 dest) init vec4 using vec3, since you are initializing vec4 with vec3 you need to set last item. cglm could set it zero but making it parameter gives more control Parameters: | *[in]* **v3** vector4 | *[in]* **last** last item of vec4 | *[out]* **dest** destination .. c:function:: void glm_vec4_copy3(vec4 a, vec3 dest) copy first 3 members of [a] to [dest] Parameters: | *[in]* **a** source | *[out]* **dest** destination .. c:function:: void glm_vec4_copy(vec4 v, vec4 dest) copy all members of [a] to [dest] Parameters: | *[in]* **v** source | *[in]* **dest** destination .. c:function:: void glm_vec4_ucopy(vec4 v, vec4 dest) copy all members of [a] to [dest] | alignment is not required Parameters: | *[in]* **v** source | *[in]* **dest** destination .. c:function:: void glm_vec4_zero(vec4 v) makes all members zero Parameters: | *[in, out]* **v** vector .. c:function:: void glm_vec4_one(vec4 v) makes all members one Parameters: | *[in, out]* **v** vector .. c:function:: float glm_vec4_dot(vec4 a, vec4 b) dot product of vec4 Parameters: | *[in]* **a** vector1 | *[in]* **b** vector2 Returns: dot product .. c:function:: float glm_vec4_norm2(vec4 v) norm * norm (magnitude) of vector we can use this func instead of calling norm * norm, because it would call sqrtf function twice but with this func we can avoid func call, maybe this is not good name for this func Parameters: | *[in]* **v** vector Returns: square of norm / magnitude .. c:function:: float glm_vec4_norm(vec4 vec) | euclidean norm (magnitude), also called L2 norm | this will give magnitude of vector in euclidean space Parameters: | *[in]* **vec** vector .. c:function:: void glm_vec4_add(vec4 a, vec4 b, vec4 dest) add a vector to b vector store result in dest Parameters: | *[in]* **a** vector1 | *[in]* **b** vector2 | *[out]* **dest** destination vector .. c:function:: void glm_vec4_adds(vec4 v, float s, vec4 dest) add scalar to v vector store result in dest (d = v + vec(s)) Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** destination vector .. c:function:: void glm_vec4_sub(vec4 a, vec4 b, vec4 dest) subtract b vector from a vector store result in dest (d = v1 - v2) Parameters: | *[in]* **a** vector1 | *[in]* **b** vector2 | *[out]* **dest** destination vector .. c:function:: void glm_vec4_subs(vec4 v, float s, vec4 dest) subtract scalar from v vector store result in dest (d = v - vec(s)) Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** destination vector .. c:function:: void glm_vec4_mul(vec4 a, vec4 b, vec4 d) multiply two vector (component-wise multiplication) Parameters: | *[in]* **a** vector1 | *[in]* **b** vector2 | *[out]* **dest** result = (a[0] * b[0], a[1] * b[1], a[2] * b[2], a[3] * b[3]) .. c:function:: void glm_vec4_scale(vec4 v, float s, vec4 dest) multiply/scale vec4 vector with scalar: result = v * s Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** destination vector .. c:function:: void glm_vec4_scale_as(vec4 v, float s, vec4 dest) make vec4 vector scale as specified: result = unit(v) * s Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** destination vector .. c:function:: void glm_vec4_div(vec4 a, vec4 b, vec4 dest) div vector with another component-wise division: d = v1 / v2 Parameters: | *[in]* **a** vector1 | *[in]* **b** vector2 | *[out]* **dest** result = (a[0] / b[0], a[1] / b[1], a[2] / b[2], a[3] / b[3]) .. c:function:: void glm_vec4_divs(vec4 v, float s, vec4 dest) div vector with scalar: d = v / s Parameters: | *[in]* **v** vector | *[in]* **s** scalar | *[out]* **dest** result = (a[0] / s, a[1] / s, a[2] / s, a[3] / s) .. c:function:: void glm_vec4_addadd(vec4 a, vec4 b, vec4 dest) | add two vectors and add result to sum | it applies += operator so dest must be initialized Parameters: | *[in]* **a** vector 1 | *[in]* **b** vector 2 | *[out]* **dest** dest += (a + b) .. c:function:: void glm_vec4_subadd(vec4 a, vec4 b, vec4 dest) | sub two vectors and add result to sum | it applies += operator so dest must be initialized Parameters: | *[in]* **a** vector 1 | *[in]* **b** vector 2 | *[out]* **dest** dest += (a - b) .. c:function:: void glm_vec4_muladd(vec4 a, vec4 b, vec4 dest) | mul two vectors and add result to sum | it applies += operator so dest must be initialized Parameters: | *[in]* **a** vector 1 | *[in]* **b** vector 2 | *[out]* **dest** dest += (a * b) .. c:function:: void glm_vec4_muladds(vec4 a, float s, vec4 dest) | mul vector with scalar and add result to sum | it applies += operator so dest must be initialized Parameters: | *[in]* **a** vector | *[in]* **s** scalar | *[out]* **dest** dest += (a * b) .. c:function:: void glm_vec4_maxadd(vec4 a, vec4 b, vec4 dest) | add max of two vector to result/dest | it applies += operator so dest must be initialized Parameters: | *[in]* **a** vector 1 | *[in]* **b** vector 2 | *[out]* **dest** dest += (a * b) .. c:function:: void glm_vec4_minadd(vec4 a, vec4 b, vec4 dest) | add min of two vector to result/dest | it applies += operator so dest must be initialized Parameters: | *[in]* **a** vector 1 | *[in]* **b** vector 2 | *[out]* **dest** dest += (a * b) .. c:function:: void glm_vec4_flipsign(vec4 v) **DEPRECATED!** use :c:func:`glm_vec4_negate` Parameters: | *[in, out]* **v** vector .. c:function:: void glm_vec4_flipsign_to(vec4 v, vec4 dest) **DEPRECATED!** use :c:func:`glm_vec4_negate_to` Parameters: | *[in]* **v** vector | *[out]* **dest** negated vector .. c:function:: void glm_vec4_inv(vec4 v) **DEPRECATED!** use :c:func:`glm_vec4_negate` Parameters: | *[in, out]* **v** vector .. c:function:: void glm_vec4_inv_to(vec4 v, vec4 dest) **DEPRECATED!** use :c:func:`glm_vec4_negate_to` Parameters: | *[in]* **v** source | *[out]* **dest** destination .. c:function:: void glm_vec4_negate(vec4 v) negate vector components Parameters: | *[in, out]* **v** vector .. c:function:: void glm_vec4_negate_to(vec4 v, vec4 dest) negate vector components and store result in dest Parameters: | *[in]* **v** vector | *[out]* **dest** negated vector .. c:function:: void glm_vec4_normalize(vec4 v) normalize vec4 and store result in same vec Parameters: | *[in, out]* **v** vector .. c:function:: void glm_vec4_normalize_to(vec4 vec, vec4 dest) normalize vec4 to dest Parameters: | *[in]* **vec** source | *[out]* **dest** destination .. c:function:: float glm_vec4_distance(vec4 v1, vec4 v2) distance between two vectors Parameters: | *[in]* **mat** vector1 | *[in]* **row1** vector2 Returns: | distance .. c:function:: void glm_vec4_maxv(vec4 v1, vec4 v2, vec4 dest) max values of vectors Parameters: | *[in]* **v1** vector1 | *[in]* **v2** vector2 | *[out]* **dest** destination .. c:function:: void glm_vec4_minv(vec4 v1, vec4 v2, vec4 dest) min values of vectors Parameters: | *[in]* **v1** vector1 | *[in]* **v2** vector2 | *[out]* **dest** destination .. c:function:: void glm_vec4_clamp(vec4 v, float minVal, float maxVal) constrain a value to lie between two further values Parameters: | *[in, out]* **v** vector | *[in]* **minVal** minimum value | *[in]* **maxVal** maximum value .. c:function:: void glm_vec4_lerp(vec4 from, vec4 to, float t, vec4 dest) linear interpolation between two vector | formula: from + s * (to - from) Parameters: | *[in]* **from** from value | *[in]* **to** to value | *[in]* **t** interpolant (amount) clamped between 0 and 1 | *[out]* **dest** destination .. c:function:: void glm_vec4_cubic(float s, vec4 dest) helper to fill vec4 as [S^3, S^2, S, 1] Parameters: | *[in]* **s** parameter | *[out]* **dest** destination .. c:function:: void glm_vec4_make(const float * __restrict src, vec4 dest) Create four dimensional vector from pointer .. note:: **@src** must contain at least 4 elements. Parameters: | *[in]* **src** pointer to an array of floats | *[out]* **dest** destination vector .. c:function:: bool glm_vec4_reflect(vec4 v, vec4 n, vec4 dest) Reflection vector using an incident ray and a surface normal Parameters: | *[in]* **v** incident vector | *[in]* **n** *â�—ï¸� normalized â�—ï¸�* normal vector | *[out]* **dest** destination: reflection result .. c:function:: bool glm_vec4_refract(vec4 v, vec4 n, float eta, vec4 dest) computes refraction vector for an incident vector and a surface normal. Calculates the refraction vector based on Snell's law. If total internal reflection occurs (angle too great given eta), dest is set to zero and returns false. Otherwise, computes refraction vector, stores it in dest, and returns true. This implementation does not explicitly preserve the 'w' component of the incident vector 'I' in the output 'dest', users requiring the preservation of the 'w' component should manually adjust 'dest' after calling this function. Parameters: | *[in]* **v** *â�—ï¸� normalized â�—ï¸�* incident vector | *[in]* **n** *â�—ï¸� normalized â�—ï¸�* normal vector | *[in]* **eta** ratio of indices of refraction (incident/transmitted) | *[out]* **dest** refraction vector if refraction occurs; zero vector otherwise Returns: returns true if refraction occurs; false if total internal reflection occurs. cglm-0.9.7/docs/source/version.rst000066400000000000000000000007551526744317200171420ustar00rootroot00000000000000.. default-domain:: C version ================================================================================ Header: cglm/version.h **cglm** uses semantic versioning (http://semver.org) which is MAJOR.MINOR.PATCH | **CGLM_VERSION_MAJOR** is major number of the version. | **CGLM_VERSION_MINOR** is minor number of the version. | **CGLM_VERSION_PATCH** is patch number of the version. every release increases these numbers. You can check existing version by including `cglm/version.h` cglm-0.9.7/include/000077500000000000000000000000001526744317200141075ustar00rootroot00000000000000cglm-0.9.7/include/cglm/000077500000000000000000000000001526744317200150315ustar00rootroot00000000000000cglm-0.9.7/include/cglm/aabb2d.h000066400000000000000000000142341526744317200163210ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_aabb2d_h #define cglm_aabb2d_h #include "common.h" #include "vec2.h" #include "util.h" /* DEPRECATED! use _diag */ #define glm_aabb2d_size(aabb) glm_aabb2d_diag(aabb) /*! * @brief make [aabb] zero * * @param[in, out] aabb aabb */ CGLM_INLINE void glm_aabb2d_zero(vec2 aabb[2]) { glm_vec2_zero(aabb[0]); glm_vec2_zero(aabb[1]); } /*! * @brief copy all members of [aabb] to [dest] * * @param[in] aabb source * @param[out] dest destination */ CGLM_INLINE void glm_aabb2d_copy(vec2 aabb[2], vec2 dest[2]) { glm_vec2_copy(aabb[0], dest[0]); glm_vec2_copy(aabb[1], dest[1]); } /*! * @brief apply transform to Axis-Aligned Bounding aabb * * @param[in] aabb bounding aabb * @param[in] m transform matrix * @param[out] dest transformed bounding aabb */ CGLM_INLINE void glm_aabb2d_transform(vec2 aabb[2], mat3 m, vec2 dest[2]) { vec2 v[2], xa, xb, ya, yb; glm_vec2_scale(m[0], aabb[0][0], xa); glm_vec2_scale(m[0], aabb[1][0], xb); glm_vec2_scale(m[1], aabb[0][1], ya); glm_vec2_scale(m[1], aabb[1][1], yb); /* translation + min(xa, xb) + min(ya, yb) */ glm_vec2(m[2], v[0]); glm_vec2_minadd(xa, xb, v[0]); glm_vec2_minadd(ya, yb, v[0]); /* translation + max(xa, xb) + max(ya, yb) */ glm_vec2(m[2], v[1]); glm_vec2_maxadd(xa, xb, v[1]); glm_vec2_maxadd(ya, yb, v[1]); glm_vec2_copy(v[0], dest[0]); glm_vec2_copy(v[1], dest[1]); } /*! * @brief merges two AABB bounding aabb and creates new one * * two aabb must be in same space, if one of aabb is in different space then * you should consider to convert it's space by glm_aabb_space * * @param[in] aabb1 bounding aabb 1 * @param[in] aabb2 bounding aabb 2 * @param[out] dest merged bounding aabb */ CGLM_INLINE void glm_aabb2d_merge(vec2 aabb1[2], vec2 aabb2[2], vec2 dest[2]) { dest[0][0] = glm_min(aabb1[0][0], aabb2[0][0]); dest[0][1] = glm_min(aabb1[0][1], aabb2[0][1]); dest[1][0] = glm_max(aabb1[1][0], aabb2[1][0]); dest[1][1] = glm_max(aabb1[1][1], aabb2[1][1]); } /*! * @brief crops a bounding aabb with another one. * * this could be useful for getting a baabb which fits with view frustum and * object bounding aabbes. In this case you crop view frustum aabb with objects * aabb * * @param[in] aabb bounding aabb 1 * @param[in] cropAabb crop aabb * @param[out] dest cropped bounding aabb */ CGLM_INLINE void glm_aabb2d_crop(vec2 aabb[2], vec2 cropAabb[2], vec2 dest[2]) { dest[0][0] = glm_max(aabb[0][0], cropAabb[0][0]); dest[0][1] = glm_max(aabb[0][1], cropAabb[0][1]); dest[1][0] = glm_min(aabb[1][0], cropAabb[1][0]); dest[1][1] = glm_min(aabb[1][1], cropAabb[1][1]); } /*! * @brief crops a bounding aabb with another one. * * this could be useful for getting a baabb which fits with view frustum and * object bounding aabbes. In this case you crop view frustum aabb with objects * aabb * * @param[in] aabb bounding aabb * @param[in] cropAabb crop aabb * @param[in] clampAabb minimum aabb * @param[out] dest cropped bounding aabb */ CGLM_INLINE void glm_aabb2d_crop_until(vec2 aabb[2], vec2 cropAabb[2], vec2 clampAabb[2], vec2 dest[2]) { glm_aabb2d_crop(aabb, cropAabb, dest); glm_aabb2d_merge(clampAabb, dest, dest); } /*! * @brief invalidate AABB min and max values * * @param[in, out] aabb bounding aabb */ CGLM_INLINE void glm_aabb2d_invalidate(vec2 aabb[2]) { glm_vec2_fill(aabb[0], FLT_MAX); glm_vec2_fill(aabb[1], -FLT_MAX); } /*! * @brief check if AABB is valid or not * * @param[in] aabb bounding aabb */ CGLM_INLINE bool glm_aabb2d_isvalid(vec2 aabb[2]) { return glm_vec2_max(aabb[0]) != FLT_MAX && glm_vec2_min(aabb[1]) != -FLT_MAX; } /*! * @brief distance between of min and max * * @param[in] aabb bounding aabb */ CGLM_INLINE float glm_aabb2d_diag(vec2 aabb[2]) { return glm_vec2_distance(aabb[0], aabb[1]); } /*! * @brief size of aabb * * @param[in] aabb bounding aabb * @param[out] dest size */ CGLM_INLINE void glm_aabb2d_sizev(vec2 aabb[2], vec2 dest) { glm_vec2_sub(aabb[1], aabb[0], dest); } /*! * @brief radius of sphere which surrounds AABB * * @param[in] aabb bounding aabb */ CGLM_INLINE float glm_aabb2d_radius(vec2 aabb[2]) { return glm_aabb2d_diag(aabb) * 0.5f; } /*! * @brief computes center point of AABB * * @param[in] aabb bounding aabb * @param[out] dest center of bounding aabb */ CGLM_INLINE void glm_aabb2d_center(vec2 aabb[2], vec2 dest) { glm_vec2_center(aabb[0], aabb[1], dest); } /*! * @brief check if two AABB intersects * * @param[in] aabb bounding aabb * @param[in] other other bounding aabb */ CGLM_INLINE bool glm_aabb2d_aabb(vec2 aabb[2], vec2 other[2]) { return (aabb[0][0] <= other[1][0] && aabb[1][0] >= other[0][0]) && (aabb[0][1] <= other[1][1] && aabb[1][1] >= other[0][1]); } /*! * @brief check if AABB intersects with a circle * * Circle Representation in cglm: [center.x, center.y, radii] * * @param[in] aabb solid bounding aabb * @param[in] c solid circle */ CGLM_INLINE bool glm_aabb2d_circle(vec2 aabb[2], vec3 c) { float dmin; int a, b; a = (c[0] < aabb[0][0]) + (c[0] > aabb[1][0]); b = (c[1] < aabb[0][1]) + (c[1] > aabb[1][1]); dmin = glm_pow2((c[0] - aabb[c[0] > aabb[1][0]][0]) * (a != 0)) + glm_pow2((c[1] - aabb[c[1] > aabb[1][1]][1]) * (b != 0)); return dmin <= glm_pow2(c[2]); } /*! * @brief check if point is inside of AABB * * @param[in] aabb bounding aabb * @param[in] point point */ CGLM_INLINE bool glm_aabb2d_point(vec2 aabb[2], vec2 point) { return (point[0] >= aabb[0][0] && point[0] <= aabb[1][0]) && (point[1] >= aabb[0][1] && point[1] <= aabb[1][1]); } /*! * @brief check if AABB contains other AABB * * @param[in] aabb bounding aabb * @param[in] other other bounding aabb */ CGLM_INLINE bool glm_aabb2d_contains(vec2 aabb[2], vec2 other[2]) { return (aabb[0][0] <= other[0][0] && aabb[1][0] >= other[1][0]) && (aabb[0][1] <= other[0][1] && aabb[1][1] >= other[1][1]); } #endif /* cglm_aabb2d_h */ cglm-0.9.7/include/cglm/affine-mat.h000066400000000000000000000125331526744317200172150ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glm_mul(mat4 m1, mat4 m2, mat4 dest); CGLM_INLINE void glm_mul_rot(mat4 m1, mat4 m2, mat4 dest); CGLM_INLINE void glm_inv_tr(mat4 mat); */ #ifndef cglm_affine_mat_h #define cglm_affine_mat_h #include "common.h" #include "mat4.h" #include "mat3.h" #ifdef CGLM_SSE_FP # include "simd/sse2/affine.h" #endif #ifdef CGLM_AVX_FP # include "simd/avx/affine.h" #endif #ifdef CGLM_NEON_FP # include "simd/neon/affine.h" #endif #ifdef CGLM_SIMD_WASM # include "simd/wasm/affine.h" #endif /*! * @brief this is similar to glm_mat4_mul but specialized to affine transform * * Matrix format should be: * R R R X * R R R Y * R R R Z * 0 0 0 W * * this reduces some multiplications. It should be faster than mat4_mul. * if you are not sure about matrix format then DON'T use this! use mat4_mul * * @param[in] m1 affine matrix 1 * @param[in] m2 affine matrix 2 * @param[out] dest result matrix */ CGLM_INLINE void glm_mul(mat4 m1, mat4 m2, mat4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glm_mul_wasm(m1, m2, dest); #elif defined(__AVX__) glm_mul_avx(m1, m2, dest); #elif defined( __SSE__ ) || defined( __SSE2__ ) glm_mul_sse2(m1, m2, dest); #elif defined(CGLM_NEON_FP) glm_mul_neon(m1, m2, dest); #else float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], a03 = m1[0][3], a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], a13 = m1[1][3], a20 = m1[2][0], a21 = m1[2][1], a22 = m1[2][2], a23 = m1[2][3], a30 = m1[3][0], a31 = m1[3][1], a32 = m1[3][2], a33 = m1[3][3], b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2], b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2], b20 = m2[2][0], b21 = m2[2][1], b22 = m2[2][2], b30 = m2[3][0], b31 = m2[3][1], b32 = m2[3][2], b33 = m2[3][3]; dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02; dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02; dest[0][2] = a02 * b00 + a12 * b01 + a22 * b02; dest[0][3] = a03 * b00 + a13 * b01 + a23 * b02; dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12; dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12; dest[1][2] = a02 * b10 + a12 * b11 + a22 * b12; dest[1][3] = a03 * b10 + a13 * b11 + a23 * b12; dest[2][0] = a00 * b20 + a10 * b21 + a20 * b22; dest[2][1] = a01 * b20 + a11 * b21 + a21 * b22; dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22; dest[2][3] = a03 * b20 + a13 * b21 + a23 * b22; dest[3][0] = a00 * b30 + a10 * b31 + a20 * b32 + a30 * b33; dest[3][1] = a01 * b30 + a11 * b31 + a21 * b32 + a31 * b33; dest[3][2] = a02 * b30 + a12 * b31 + a22 * b32 + a32 * b33; dest[3][3] = a03 * b30 + a13 * b31 + a23 * b32 + a33 * b33; #endif } /*! * @brief this is similar to glm_mat4_mul but specialized to affine transform * * Right Matrix format should be: * R R R 0 * R R R 0 * R R R 0 * 0 0 0 1 * * this reduces some multiplications. It should be faster than mat4_mul. * if you are not sure about matrix format then DON'T use this! use mat4_mul * * @param[in] m1 affine matrix 1 * @param[in] m2 affine matrix 2 * @param[out] dest result matrix */ CGLM_INLINE void glm_mul_rot(mat4 m1, mat4 m2, mat4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glm_mul_rot_wasm(m1, m2, dest); #elif defined( __SSE__ ) || defined( __SSE2__ ) glm_mul_rot_sse2(m1, m2, dest); #elif defined(CGLM_NEON_FP) glm_mul_rot_neon(m1, m2, dest); #else float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], a03 = m1[0][3], a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], a13 = m1[1][3], a20 = m1[2][0], a21 = m1[2][1], a22 = m1[2][2], a23 = m1[2][3], a30 = m1[3][0], a31 = m1[3][1], a32 = m1[3][2], a33 = m1[3][3], b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2], b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2], b20 = m2[2][0], b21 = m2[2][1], b22 = m2[2][2]; dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02; dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02; dest[0][2] = a02 * b00 + a12 * b01 + a22 * b02; dest[0][3] = a03 * b00 + a13 * b01 + a23 * b02; dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12; dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12; dest[1][2] = a02 * b10 + a12 * b11 + a22 * b12; dest[1][3] = a03 * b10 + a13 * b11 + a23 * b12; dest[2][0] = a00 * b20 + a10 * b21 + a20 * b22; dest[2][1] = a01 * b20 + a11 * b21 + a21 * b22; dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22; dest[2][3] = a03 * b20 + a13 * b21 + a23 * b22; dest[3][0] = a30; dest[3][1] = a31; dest[3][2] = a32; dest[3][3] = a33; #endif } /*! * @brief inverse orthonormal rotation + translation matrix (ridig-body) * * @code * X = | R T | X' = | R' -R'T | * | 0 1 | | 0 1 | * @endcode * * @param[in,out] mat matrix */ CGLM_INLINE void glm_inv_tr(mat4 mat) { #if defined(__wasm__) && defined(__wasm_simd128__) glm_inv_tr_wasm(mat); #elif defined( __SSE__ ) || defined( __SSE2__ ) glm_inv_tr_sse2(mat); #elif defined(CGLM_NEON_FP) glm_inv_tr_neon(mat); #else CGLM_ALIGN_MAT mat3 r; CGLM_ALIGN(8) vec3 t; /* rotate */ glm_mat4_pick3t(mat, r); glm_mat4_ins3(r, mat); /* translate */ glm_mat3_mulv(r, mat[3], t); glm_vec3_negate(t); glm_vec3_copy(t, mat[3]); #endif } #endif /* cglm_affine_mat_h */ cglm-0.9.7/include/cglm/affine-post.h000066400000000000000000000136011526744317200174160ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_affine_post_h #define cglm_affine_post_h /* Functions: CGLM_INLINE void glm_translated_to(mat4 m, vec3 v, mat4 dest); CGLM_INLINE void glm_translated(mat4 m, vec3 v); CGLM_INLINE void glm_translated_x(mat4 m, float to); CGLM_INLINE void glm_translated_y(mat4 m, float to); CGLM_INLINE void glm_translated_z(mat4 m, float to); CGLM_INLINE void glm_rotated_x(mat4 m, float angle, mat4 dest); CGLM_INLINE void glm_rotated_y(mat4 m, float angle, mat4 dest); CGLM_INLINE void glm_rotated_z(mat4 m, float angle, mat4 dest); CGLM_INLINE void glm_rotated(mat4 m, float angle, vec3 axis); CGLM_INLINE void glm_rotated_at(mat4 m, vec3 pivot, float angle, vec3 axis); CGLM_INLINE void glm_spinned(mat4 m, float angle, vec3 axis); */ #include "common.h" #include "util.h" #include "vec3.h" #include "vec4.h" #include "mat4.h" #include "affine-mat.h" /*! * @brief translate existing transform matrix by v vector * and stores result in same matrix * * this is POST transform, applies to existing transform as last transform * * @param[in, out] m affine transform * @param[in] v translate vector [x, y, z] */ CGLM_INLINE void glm_translated(mat4 m, vec3 v) { glm_vec3_add(m[3], v, m[3]); } /*! * @brief translate existing transform matrix by v vector * and store result in dest * * source matrix will remain same * * this is POST transform, applies to existing transform as last transform * * @param[in] m affine transform * @param[in] v translate vector [x, y, z] * @param[out] dest translated matrix */ CGLM_INLINE void glm_translated_to(mat4 m, vec3 v, mat4 dest) { glm_mat4_copy(m, dest); glm_translated(dest, v); } /*! * @brief translate existing transform matrix by x factor * * this is POST transform, applies to existing transform as last transform * * @param[in, out] m affine transform * @param[in] x x factor */ CGLM_INLINE void glm_translated_x(mat4 m, float x) { m[3][0] += x; } /*! * @brief translate existing transform matrix by y factor * * this is POST transform, applies to existing transform as last transform * * @param[in, out] m affine transform * @param[in] y y factor */ CGLM_INLINE void glm_translated_y(mat4 m, float y) { m[3][1] += y; } /*! * @brief translate existing transform matrix by z factor * * this is POST transform, applies to existing transform as last transform * * @param[in, out] m affine transform * @param[in] z z factor */ CGLM_INLINE void glm_translated_z(mat4 m, float z) { m[3][2] += z; } /*! * @brief rotate existing transform matrix around X axis by angle * and store result in dest * * this is POST transform, applies to existing transform as last transform * * @param[in] m affine transform * @param[in] angle angle (radians) * @param[out] dest rotated matrix */ CGLM_INLINE void glm_rotated_x(mat4 m, float angle, mat4 dest) { CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; float c, s; c = cosf(angle); s = sinf(angle); t[1][1] = c; t[1][2] = s; t[2][1] = -s; t[2][2] = c; glm_mul_rot(t, m, dest); } /*! * @brief rotate existing transform matrix around Y axis by angle * and store result in dest * * this is POST transform, applies to existing transform as last transform * * @param[in] m affine transform * @param[in] angle angle (radians) * @param[out] dest rotated matrix */ CGLM_INLINE void glm_rotated_y(mat4 m, float angle, mat4 dest) { CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; float c, s; c = cosf(angle); s = sinf(angle); t[0][0] = c; t[0][2] = -s; t[2][0] = s; t[2][2] = c; glm_mul_rot(t, m, dest); } /*! * @brief rotate existing transform matrix around Z axis by angle * and store result in dest * * this is POST transform, applies to existing transform as last transform * * @param[in] m affine transform * @param[in] angle angle (radians) * @param[out] dest rotated matrix */ CGLM_INLINE void glm_rotated_z(mat4 m, float angle, mat4 dest) { CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; float c, s; c = cosf(angle); s = sinf(angle); t[0][0] = c; t[0][1] = s; t[1][0] = -s; t[1][1] = c; glm_mul_rot(t, m, dest); } /*! * @brief rotate existing transform matrix around given axis by angle * * this is POST transform, applies to existing transform as last transform * * @param[in, out] m affine transform * @param[in] angle angle (radians) * @param[in] axis axis */ CGLM_INLINE void glm_rotated(mat4 m, float angle, vec3 axis) { CGLM_ALIGN_MAT mat4 rot; glm_rotate_make(rot, angle, axis); glm_mul_rot(rot, m, m); } /*! * @brief rotate existing transform * around given axis by angle at given pivot point (rotation center) * * this is POST transform, applies to existing transform as last transform * * @param[in, out] m affine transform * @param[in] pivot rotation center * @param[in] angle angle (radians) * @param[in] axis axis */ CGLM_INLINE void glm_rotated_at(mat4 m, vec3 pivot, float angle, vec3 axis) { CGLM_ALIGN(8) vec3 pivotInv; glm_vec3_negate_to(pivot, pivotInv); glm_translated(m, pivot); glm_rotated(m, angle, axis); glm_translated(m, pivotInv); } /*! * @brief rotate existing transform matrix around given axis by angle around self (doesn't affected by position) * * this is POST transform, applies to existing transform as last transform * * @param[in, out] m affine transform * @param[in] angle angle (radians) * @param[in] axis axis */ CGLM_INLINE void glm_spinned(mat4 m, float angle, vec3 axis) { CGLM_ALIGN_MAT mat4 rot; glm_rotate_atm(rot, m[3], angle, axis); glm_mat4_mul(rot, m, m); } #endif /* cglm_affine_post_h */ cglm-0.9.7/include/cglm/affine-pre.h000066400000000000000000000170231526744317200172210ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_affine_pre_h #define cglm_affine_pre_h /* Functions: CGLM_INLINE void glm_translate_to(mat4 m, vec3 v, mat4 dest); CGLM_INLINE void glm_translate(mat4 m, vec3 v); CGLM_INLINE void glm_translate_x(mat4 m, float to); CGLM_INLINE void glm_translate_y(mat4 m, float to); CGLM_INLINE void glm_translate_z(mat4 m, float to); CGLM_INLINE void glm_rotate_x(mat4 m, float angle, mat4 dest); CGLM_INLINE void glm_rotate_y(mat4 m, float angle, mat4 dest); CGLM_INLINE void glm_rotate_z(mat4 m, float angle, mat4 dest); CGLM_INLINE void glm_rotate(mat4 m, float angle, vec3 axis); CGLM_INLINE void glm_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis); CGLM_INLINE void glm_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis); CGLM_INLINE void glm_spin(mat4 m, float angle, vec3 axis); */ #include "common.h" #include "util.h" #include "vec3.h" #include "vec4.h" #include "mat4.h" #include "affine-mat.h" /*! * @brief translate existing transform matrix by v vector * and stores result in same matrix * * @param[in, out] m affine transform * @param[in] v translate vector [x, y, z] */ CGLM_INLINE void glm_translate(mat4 m, vec3 v) { #if defined(CGLM_SIMD) glmm_128 m0, m1, m2, m3; m0 = glmm_load(m[0]); m1 = glmm_load(m[1]); m2 = glmm_load(m[2]); m3 = glmm_load(m[3]); glmm_store(m[3], glmm_fmadd(m0, glmm_set1(v[0]), glmm_fmadd(m1, glmm_set1(v[1]), glmm_fmadd(m2, glmm_set1(v[2]), m3)))); #else glm_vec4_muladds(m[0], v[0], m[3]); glm_vec4_muladds(m[1], v[1], m[3]); glm_vec4_muladds(m[2], v[2], m[3]); #endif } /*! * @brief translate existing transform matrix by v vector * and store result in dest * * source matrix will remain same * * @param[in] m affine transform * @param[in] v translate vector [x, y, z] * @param[out] dest translated matrix */ CGLM_INLINE void glm_translate_to(mat4 m, vec3 v, mat4 dest) { glm_mat4_copy(m, dest); glm_translate(dest, v); } /*! * @brief translate existing transform matrix by x factor * * @param[in, out] m affine transform * @param[in] x x factor */ CGLM_INLINE void glm_translate_x(mat4 m, float x) { #if defined(CGLM_SIMD) glmm_store(m[3], glmm_fmadd(glmm_load(m[0]), glmm_set1(x), glmm_load(m[3]))); #else vec4 v1; glm_vec4_scale(m[0], x, v1); glm_vec4_add(v1, m[3], m[3]); #endif } /*! * @brief translate existing transform matrix by y factor * * @param[in, out] m affine transform * @param[in] y y factor */ CGLM_INLINE void glm_translate_y(mat4 m, float y) { #if defined(CGLM_SIMD) glmm_store(m[3], glmm_fmadd(glmm_load(m[1]), glmm_set1(y), glmm_load(m[3]))); #else vec4 v1; glm_vec4_scale(m[1], y, v1); glm_vec4_add(v1, m[3], m[3]); #endif } /*! * @brief translate existing transform matrix by z factor * * @param[in, out] m affine transform * @param[in] z z factor */ CGLM_INLINE void glm_translate_z(mat4 m, float z) { #if defined(CGLM_SIMD) glmm_store(m[3], glmm_fmadd(glmm_load(m[2]), glmm_set1(z), glmm_load(m[3]))); #else vec4 v1; glm_vec4_scale(m[2], z, v1); glm_vec4_add(v1, m[3], m[3]); #endif } /*! * @brief rotate existing transform matrix around X axis by angle * and store result in dest * * @param[in] m affine transform * @param[in] angle angle (radians) * @param[out] dest rotated matrix */ CGLM_INLINE void glm_rotate_x(mat4 m, float angle, mat4 dest) { CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; float c, s; c = cosf(angle); s = sinf(angle); t[1][1] = c; t[1][2] = s; t[2][1] = -s; t[2][2] = c; glm_mul_rot(m, t, dest); } /*! * @brief rotate existing transform matrix around Y axis by angle * and store result in dest * * @param[in] m affine transform * @param[in] angle angle (radians) * @param[out] dest rotated matrix */ CGLM_INLINE void glm_rotate_y(mat4 m, float angle, mat4 dest) { CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; float c, s; c = cosf(angle); s = sinf(angle); t[0][0] = c; t[0][2] = -s; t[2][0] = s; t[2][2] = c; glm_mul_rot(m, t, dest); } /*! * @brief rotate existing transform matrix around Z axis by angle * and store result in dest * * @param[in] m affine transform * @param[in] angle angle (radians) * @param[out] dest rotated matrix */ CGLM_INLINE void glm_rotate_z(mat4 m, float angle, mat4 dest) { CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; float c, s; c = cosf(angle); s = sinf(angle); t[0][0] = c; t[0][1] = s; t[1][0] = -s; t[1][1] = c; glm_mul_rot(m, t, dest); } /*! * @brief rotate existing transform matrix * around given axis by angle at ORIGIN (0,0,0) * * **â�—ï¸�IMPORTANT â�—ï¸�** * * If you need to rotate object around itself e.g. center of object or at * some point [of object] then `glm_rotate_at()` would be better choice to do so. * * Even if object's model transform is identity, rotation may not be around * center of object if object does not lay out at ORIGIN perfectly. * * Using `glm_rotate_at()` with center of bounding shape ( AABB, Sphere ... ) * would be an easy option to rotate around object if object is not at origin. * * One another option to rotate around itself at any point is `glm_spin()` * which is perfect if only rotating around model position is desired e.g. not * specific point on model for instance center of geometry or center of mass, * again if geometry is not perfectly centered at origin at identity transform, * rotation may not be around geometry. * * @param[in, out] m affine transform * @param[in] angle angle (radians) * @param[in] axis axis */ CGLM_INLINE void glm_rotate(mat4 m, float angle, vec3 axis) { CGLM_ALIGN_MAT mat4 rot; glm_rotate_make(rot, angle, axis); glm_mul_rot(m, rot, m); } /*! * @brief rotate existing transform * around given axis by angle at given pivot point (rotation center) * * @param[in, out] m affine transform * @param[in] pivot rotation center * @param[in] angle angle (radians) * @param[in] axis axis */ CGLM_INLINE void glm_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis) { CGLM_ALIGN(8) vec3 pivotInv; glm_vec3_negate_to(pivot, pivotInv); glm_translate(m, pivot); glm_rotate(m, angle, axis); glm_translate(m, pivotInv); } /*! * @brief creates NEW rotation matrix by angle and axis at given point * * this creates rotation matrix, it assumes you don't have a matrix * * this should work faster than glm_rotate_at because it reduces * one glm_translate. * * @param[out] m affine transform * @param[in] pivot rotation center * @param[in] angle angle (radians) * @param[in] axis axis */ CGLM_INLINE void glm_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis) { CGLM_ALIGN(8) vec3 pivotInv; glm_vec3_negate_to(pivot, pivotInv); glm_translate_make(m, pivot); glm_rotate(m, angle, axis); glm_translate(m, pivotInv); } /*! * @brief rotate existing transform matrix * around given axis by angle around self (doesn't affected by position) * * @param[in, out] m affine transform * @param[in] angle angle (radians) * @param[in] axis axis */ CGLM_INLINE void glm_spin(mat4 m, float angle, vec3 axis) { CGLM_ALIGN_MAT mat4 rot; glm_rotate_make(rot, angle, axis); glm_mat4_mul(m, rot, m); } #endif /* cglm_affine_pre_h */ cglm-0.9.7/include/cglm/affine.h000066400000000000000000000140361526744317200164360ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glm_translate_to(mat4 m, vec3 v, mat4 dest); CGLM_INLINE void glm_translate(mat4 m, vec3 v); CGLM_INLINE void glm_translate_x(mat4 m, float to); CGLM_INLINE void glm_translate_y(mat4 m, float to); CGLM_INLINE void glm_translate_z(mat4 m, float to); CGLM_INLINE void glm_translate_make(mat4 m, vec3 v); CGLM_INLINE void glm_scale_to(mat4 m, vec3 v, mat4 dest); CGLM_INLINE void glm_scale_make(mat4 m, vec3 v); CGLM_INLINE void glm_scale(mat4 m, vec3 v); CGLM_INLINE void glm_scale_uni(mat4 m, float s); CGLM_INLINE void glm_rotate_x(mat4 m, float angle, mat4 dest); CGLM_INLINE void glm_rotate_y(mat4 m, float angle, mat4 dest); CGLM_INLINE void glm_rotate_z(mat4 m, float angle, mat4 dest); CGLM_INLINE void glm_rotate_make(mat4 m, float angle, vec3 axis); CGLM_INLINE void glm_rotate(mat4 m, float angle, vec3 axis); CGLM_INLINE void glm_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis); CGLM_INLINE void glm_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis); CGLM_INLINE void glm_spin(mat4 m, float angle, vec3 axis); CGLM_INLINE void glm_decompose_scalev(mat4 m, vec3 s); CGLM_INLINE bool glm_uniscaled(mat4 m); CGLM_INLINE void glm_decompose_rs(mat4 m, mat4 r, vec3 s); CGLM_INLINE void glm_decompose(mat4 m, vec4 t, mat4 r, vec3 s); */ #ifndef cglm_affine_h #define cglm_affine_h #include "common.h" #include "util.h" #include "vec3.h" #include "vec4.h" #include "mat4.h" #include "affine-mat.h" /*! * @brief creates NEW translate transform matrix by v vector * * @param[out] m affine transform * @param[in] v translate vector [x, y, z] */ CGLM_INLINE void glm_translate_make(mat4 m, vec3 v) { glm_mat4_identity(m); glm_vec3_copy(v, m[3]); } /*! * @brief scale existing transform matrix by v vector * and store result in dest * * @param[in] m affine transform * @param[in] v scale vector [x, y, z] * @param[out] dest scaled matrix */ CGLM_INLINE void glm_scale_to(mat4 m, vec3 v, mat4 dest) { glm_vec4_scale(m[0], v[0], dest[0]); glm_vec4_scale(m[1], v[1], dest[1]); glm_vec4_scale(m[2], v[2], dest[2]); glm_vec4_copy(m[3], dest[3]); } /*! * @brief creates NEW scale matrix by v vector * * @param[out] m affine transform * @param[in] v scale vector [x, y, z] */ CGLM_INLINE void glm_scale_make(mat4 m, vec3 v) { glm_mat4_identity(m); m[0][0] = v[0]; m[1][1] = v[1]; m[2][2] = v[2]; } /*! * @brief scales existing transform matrix by v vector * and stores result in same matrix * * @param[in, out] m affine transform * @param[in] v scale vector [x, y, z] */ CGLM_INLINE void glm_scale(mat4 m, vec3 v) { glm_scale_to(m, v, m); } /*! * @brief applies uniform scale to existing transform matrix v = [s, s, s] * and stores result in same matrix * * @param[in, out] m affine transform * @param[in] s scale factor */ CGLM_INLINE void glm_scale_uni(mat4 m, float s) { CGLM_ALIGN(8) vec3 v = { s, s, s }; glm_scale_to(m, v, m); } /*! * @brief creates NEW rotation matrix by angle and axis * * axis will be normalized so you don't need to normalize it * * @param[out] m affine transform * @param[in] angle angle (radians) * @param[in] axis axis */ CGLM_INLINE void glm_rotate_make(mat4 m, float angle, vec3 axis) { CGLM_ALIGN(8) vec3 axisn, v, vs; float c; c = cosf(angle); glm_vec3_normalize_to(axis, axisn); glm_vec3_scale(axisn, 1.0f - c, v); glm_vec3_scale(axisn, sinf(angle), vs); glm_vec3_scale(axisn, v[0], m[0]); glm_vec3_scale(axisn, v[1], m[1]); glm_vec3_scale(axisn, v[2], m[2]); m[0][0] += c; m[1][0] -= vs[2]; m[2][0] += vs[1]; m[0][1] += vs[2]; m[1][1] += c; m[2][1] -= vs[0]; m[0][2] -= vs[1]; m[1][2] += vs[0]; m[2][2] += c; m[0][3] = m[1][3] = m[2][3] = m[3][0] = m[3][1] = m[3][2] = 0.0f; m[3][3] = 1.0f; } /*! * @brief decompose scale vector * * @param[in] m affine transform * @param[out] s scale vector (Sx, Sy, Sz) */ CGLM_INLINE void glm_decompose_scalev(mat4 m, vec3 s) { s[0] = glm_vec3_norm(m[0]); s[1] = glm_vec3_norm(m[1]); s[2] = glm_vec3_norm(m[2]); } /*! * @brief returns true if matrix is uniform scaled. This is helpful for * creating normal matrix. * * @param[in] m m * * @return boolean */ CGLM_INLINE bool glm_uniscaled(mat4 m) { CGLM_ALIGN(8) vec3 s; glm_decompose_scalev(m, s); return glm_vec3_eq_all(s); } /*! * @brief decompose rotation matrix (mat4) and scale vector [Sx, Sy, Sz] * DON'T pass projected matrix here * * @param[in] m affine transform * @param[out] r rotation matrix * @param[out] s scale matrix */ CGLM_INLINE void glm_decompose_rs(mat4 m, mat4 r, vec3 s) { CGLM_ALIGN(16) vec4 t = {0.0f, 0.0f, 0.0f, 1.0f}; CGLM_ALIGN(8) vec3 v; glm_vec4_copy(m[0], r[0]); glm_vec4_copy(m[1], r[1]); glm_vec4_copy(m[2], r[2]); glm_vec4_copy(t, r[3]); s[0] = glm_vec3_norm(m[0]); s[1] = glm_vec3_norm(m[1]); s[2] = glm_vec3_norm(m[2]); glm_vec4_scale(r[0], 1.0f/s[0], r[0]); glm_vec4_scale(r[1], 1.0f/s[1], r[1]); glm_vec4_scale(r[2], 1.0f/s[2], r[2]); /* Note from Apple Open Source (assume that the matrix is orthonormal): check for a coordinate system flip. If the determinant is -1, then negate the matrix and the scaling factors. */ glm_vec3_cross(m[0], m[1], v); if (glm_vec3_dot(v, m[2]) < 0.0f) { glm_vec4_negate(r[0]); glm_vec4_negate(r[1]); glm_vec4_negate(r[2]); glm_vec3_negate(s); } } /*! * @brief decompose affine transform, TODO: extract shear factors. * DON'T pass projected matrix here * * @param[in] m affine transform * @param[out] t translation vector * @param[out] r rotation matrix (mat4) * @param[out] s scaling vector [X, Y, Z] */ CGLM_INLINE void glm_decompose(mat4 m, vec4 t, mat4 r, vec3 s) { glm_vec4_copy(m[3], t); glm_decompose_rs(m, r, s); } #include "affine-pre.h" #include "affine-post.h" #endif /* cglm_affine_h */ cglm-0.9.7/include/cglm/affine2d-post.h000066400000000000000000000056501526744317200176510ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_affine2d_post_h #define cglm_affine2d_post_h /* Functions: CGLM_INLINE void glm_translated2d(mat3 m, vec2 v); CGLM_INLINE void glm_translated2d_x(mat3 m, float to); CGLM_INLINE void glm_translated2d_y(mat3 m, float to); CGLM_INLINE void glm_rotated2d(mat3 m, float angle); CGLM_INLINE void glm_scaled2d(mat3 m, vec2 v); CGLM_INLINE void glm_scaled2d_uni(mat3 m, float s); */ #include "vec2.h" /*! * @brief translate existing transform matrix by v vector * and store result in same matrix * * this is POST transform, applies to existing transform as last transform * * @param[in, out] m affine transform * @param[in] v translate vector [x, y] */ CGLM_INLINE void glm_translated2d(mat3 m, vec2 v) { glm_vec2_add(m[2], v, m[2]); } /*! * @brief translate existing transform matrix by x factor * * this is POST transform, applies to existing transform as last transform * * @param[in, out] m affine transform * @param[in] x x factor */ CGLM_INLINE void glm_translated2d_x(mat3 m, float x) { m[2][0] += x; } /*! * @brief translate existing transform matrix by y factor * * this is POST transform, applies to existing transform as last transform * * @param[in, out] m affine transform * @param[in] y y factor */ CGLM_INLINE void glm_translated2d_y(mat3 m, float y) { m[2][1] += y; } /*! * @brief rotate existing transform matrix by angle * * this is POST transform, applies to existing transform as last transform * * @param[in, out] m affine transform * @param[in] angle angle (radians) */ CGLM_INLINE void glm_rotated2d(mat3 m, float angle) { float c = cosf(angle), s = sinf(angle), m00 = m[0][0], m10 = m[1][0], m20 = m[2][0], m01 = m[0][1], m11 = m[1][1], m21 = m[2][1]; m[0][0] = c * m00 - s * m01; m[1][0] = c * m10 - s * m11; m[2][0] = c * m20 - s * m21; m[0][1] = s * m00 + c * m01; m[1][1] = s * m10 + c * m11; m[2][1] = s * m20 + c * m21; } /*! * @brief scale existing 2d transform matrix by v vector * * this is POST transform, applies to existing transform as last transform * * @param[in, out] m affine transform * @param[in] v scale vector [x, y] */ CGLM_INLINE void glm_scaled2d(mat3 m, vec2 v) { m[0][0] *= v[0]; m[1][0] *= v[0]; m[2][0] *= v[0]; m[0][1] *= v[1]; m[1][1] *= v[1]; m[2][1] *= v[1]; } /*! * @brief applies uniform scale to existing 2d transform matrix v = [s, s] * * this is POST transform, applies to existing transform as last transform * * @param[in, out] m affine transform * @param[in] s scale factor */ CGLM_INLINE void glm_scaled2d_uni(mat3 m, float s) { m[0][0] *= s; m[1][0] *= s; m[2][0] *= s; m[0][1] *= s; m[1][1] *= s; m[2][1] *= s; } #endif /* cglm_affine2d_post_h */ cglm-0.9.7/include/cglm/affine2d.h000066400000000000000000000137351526744317200166710ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glm_translate2d(mat3 m, vec2 v) CGLM_INLINE void glm_translate2d_to(mat3 m, vec2 v, mat3 dest) CGLM_INLINE void glm_translate2d_x(mat3 m, float x) CGLM_INLINE void glm_translate2d_y(mat3 m, float y) CGLM_INLINE void glm_translate2d_make(mat3 m, vec2 v) CGLM_INLINE void glm_scale2d_to(mat3 m, vec2 v, mat3 dest) CGLM_INLINE void glm_scale2d_make(mat3 m, vec2 v) CGLM_INLINE void glm_scale2d(mat3 m, vec2 v) CGLM_INLINE void glm_scale2d_uni(mat3 m, float s) CGLM_INLINE void glm_rotate2d_make(mat3 m, float angle) CGLM_INLINE void glm_rotate2d(mat3 m, float angle) CGLM_INLINE void glm_rotate2d_to(mat3 m, float angle, mat3 dest) */ #ifndef cglm_affine2d_h #define cglm_affine2d_h #include "common.h" #include "util.h" #include "vec2.h" #include "mat3.h" /*! * @brief translate existing 2d transform matrix by v vector * and stores result in same matrix * * @param[in, out] m affine transform * @param[in] v translate vector [x, y] */ CGLM_INLINE void glm_translate2d(mat3 m, vec2 v) { m[2][0] = m[0][0] * v[0] + m[1][0] * v[1] + m[2][0]; m[2][1] = m[0][1] * v[0] + m[1][1] * v[1] + m[2][1]; m[2][2] = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2]; } /*! * @brief translate existing 2d transform matrix by v vector * and store result in dest * * source matrix will remain same * * @param[in] m affine transform * @param[in] v translate vector [x, y] * @param[out] dest translated matrix */ CGLM_INLINE void glm_translate2d_to(mat3 m, vec2 v, mat3 dest) { glm_mat3_copy(m, dest); glm_translate2d(dest, v); } /*! * @brief translate existing 2d transform matrix by x factor * * @param[in, out] m affine transform * @param[in] x x factor */ CGLM_INLINE void glm_translate2d_x(mat3 m, float x) { m[2][0] = m[0][0] * x + m[2][0]; m[2][1] = m[0][1] * x + m[2][1]; m[2][2] = m[0][2] * x + m[2][2]; } /*! * @brief translate existing 2d transform matrix by y factor * * @param[in, out] m affine transform * @param[in] y y factor */ CGLM_INLINE void glm_translate2d_y(mat3 m, float y) { m[2][0] = m[1][0] * y + m[2][0]; m[2][1] = m[1][1] * y + m[2][1]; m[2][2] = m[1][2] * y + m[2][2]; } /*! * @brief creates NEW translate 2d transform matrix by v vector * * @param[out] m affine transform * @param[in] v translate vector [x, y] */ CGLM_INLINE void glm_translate2d_make(mat3 m, vec2 v) { glm_mat3_identity(m); m[2][0] = v[0]; m[2][1] = v[1]; } /*! * @brief scale existing 2d transform matrix by v vector * and store result in dest * * @param[in] m affine transform * @param[in] v scale vector [x, y] * @param[out] dest scaled matrix */ CGLM_INLINE void glm_scale2d_to(mat3 m, vec2 v, mat3 dest) { dest[0][0] = m[0][0] * v[0]; dest[0][1] = m[0][1] * v[0]; dest[0][2] = m[0][2] * v[0]; dest[1][0] = m[1][0] * v[1]; dest[1][1] = m[1][1] * v[1]; dest[1][2] = m[1][2] * v[1]; dest[2][0] = m[2][0]; dest[2][1] = m[2][1]; dest[2][2] = m[2][2]; } /*! * @brief creates NEW 2d scale matrix by v vector * * @param[out] m affine transform * @param[in] v scale vector [x, y] */ CGLM_INLINE void glm_scale2d_make(mat3 m, vec2 v) { glm_mat3_identity(m); m[0][0] = v[0]; m[1][1] = v[1]; } /*! * @brief scales existing 2d transform matrix by v vector * and stores result in same matrix * * @param[in, out] m affine transform * @param[in] v scale vector [x, y] */ CGLM_INLINE void glm_scale2d(mat3 m, vec2 v) { m[0][0] = m[0][0] * v[0]; m[0][1] = m[0][1] * v[0]; m[0][2] = m[0][2] * v[0]; m[1][0] = m[1][0] * v[1]; m[1][1] = m[1][1] * v[1]; m[1][2] = m[1][2] * v[1]; } /*! * @brief applies uniform scale to existing 2d transform matrix v = [s, s] * and stores result in same matrix * * @param[in, out] m affine transform * @param[in] s scale factor */ CGLM_INLINE void glm_scale2d_uni(mat3 m, float s) { m[0][0] = m[0][0] * s; m[0][1] = m[0][1] * s; m[0][2] = m[0][2] * s; m[1][0] = m[1][0] * s; m[1][1] = m[1][1] * s; m[1][2] = m[1][2] * s; } /*! * @brief creates NEW rotation matrix by angle around Z axis * * @param[out] m affine transform * @param[in] angle angle (radians) */ CGLM_INLINE void glm_rotate2d_make(mat3 m, float angle) { float c, s; s = sinf(angle); c = cosf(angle); m[0][0] = c; m[0][1] = s; m[0][2] = 0; m[1][0] = -s; m[1][1] = c; m[1][2] = 0; m[2][0] = 0.0f; m[2][1] = 0.0f; m[2][2] = 1.0f; } /*! * @brief rotate existing 2d transform matrix around Z axis by angle * and store result in same matrix * * @param[in, out] m affine transform * @param[in] angle angle (radians) */ CGLM_INLINE void glm_rotate2d(mat3 m, float angle) { float m00 = m[0][0], m10 = m[1][0], m01 = m[0][1], m11 = m[1][1], m02 = m[0][2], m12 = m[1][2]; float c, s; s = sinf(angle); c = cosf(angle); m[0][0] = m00 * c + m10 * s; m[0][1] = m01 * c + m11 * s; m[0][2] = m02 * c + m12 * s; m[1][0] = m00 * -s + m10 * c; m[1][1] = m01 * -s + m11 * c; m[1][2] = m02 * -s + m12 * c; } /*! * @brief rotate existing 2d transform matrix around Z axis by angle * and store result in dest * * @param[in] m affine transform * @param[in] angle angle (radians) * @param[out] dest destination */ CGLM_INLINE void glm_rotate2d_to(mat3 m, float angle, mat3 dest) { float m00 = m[0][0], m10 = m[1][0], m01 = m[0][1], m11 = m[1][1], m02 = m[0][2], m12 = m[1][2]; float c, s; s = sinf(angle); c = cosf(angle); dest[0][0] = m00 * c + m10 * s; dest[0][1] = m01 * c + m11 * s; dest[0][2] = m02 * c + m12 * s; dest[1][0] = m00 * -s + m10 * c; dest[1][1] = m01 * -s + m11 * c; dest[1][2] = m02 * -s + m12 * c; dest[2][0] = m[2][0]; dest[2][1] = m[2][1]; dest[2][2] = m[2][2]; } #endif /* cglm_affine2d_h */ cglm-0.9.7/include/cglm/applesimd.h000066400000000000000000000074211526744317200171640ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_applesimd_h #define cglm_applesimd_h #if defined(__APPLE__) \ && defined(SIMD_COMPILER_HAS_REQUIRED_FEATURES) \ && defined(SIMD_BASE) \ && defined(SIMD_TYPES) \ && defined(SIMD_VECTOR_TYPES) #include "common.h" #include "struct.h" /*! * @brief converts mat4 to Apple's simd type simd_float4x4 * @return simd_float4x4 */ CGLM_INLINE simd_float4x4 glm_mat4_applesimd(mat4 m) { simd_float4x4 t; t.columns[0][0] = m[0][0]; t.columns[0][1] = m[0][1]; t.columns[0][2] = m[0][2]; t.columns[0][3] = m[0][3]; t.columns[1][0] = m[1][0]; t.columns[1][1] = m[1][1]; t.columns[1][2] = m[1][2]; t.columns[1][3] = m[1][3]; t.columns[2][0] = m[2][0]; t.columns[2][1] = m[2][1]; t.columns[2][2] = m[2][2]; t.columns[2][3] = m[2][3]; t.columns[3][0] = m[3][0]; t.columns[3][1] = m[3][1]; t.columns[3][2] = m[3][2]; t.columns[3][3] = m[3][3]; return t; } /*! * @brief converts mat3 to Apple's simd type simd_float3x3 * @return simd_float3x3 */ CGLM_INLINE simd_float3x3 glm_mat3_applesimd(mat3 m) { simd_float3x3 t; t.columns[0][0] = m[0][0]; t.columns[0][1] = m[0][1]; t.columns[0][2] = m[0][2]; t.columns[1][0] = m[1][0]; t.columns[1][1] = m[1][1]; t.columns[1][2] = m[1][2]; t.columns[2][0] = m[2][0]; t.columns[2][1] = m[2][1]; t.columns[2][2] = m[2][2]; return t; } /*! * @brief converts vec4 to Apple's simd type simd_float4 * @return simd_float4 */ CGLM_INLINE simd_float4 glm_vec4_applesimd(vec4 v) { return (simd_float4){v[0], v[1], v[2], v[3]}; } /*! * @brief converts vec3 to Apple's simd type simd_float3 * @return simd_float3 */ CGLM_INLINE simd_float3 glm_vec3_applesimd(vec3 v) { return (simd_float3){v[0], v[1], v[2]}; } /*! * @brief generic function to convert cglm types to Apple's simd types * * Example usage: * simd_float4x4 m = applesimd(mat4_value); * simd_float3 v = applesimd(vec3_value); * * @param x cglm type (mat4, mat3, vec4, vec3) * @return corresponding Apple simd type */ #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) # define applesimd(x) _Generic((x), \ mat4: glm_mat4_applesimd, \ mat3: glm_mat3_applesimd, \ vec4: glm_vec4_applesimd, \ vec3: glm_vec3_applesimd \ )((x)) #endif #ifdef cglm_types_struct_h CGLM_INLINE simd_float4x4 glms_mat4_(applesimd)(mat4s m) { return glm_mat4_applesimd(m.raw); } CGLM_INLINE simd_float3x3 glms_mat3_(applesimd)(mat3s m) { return glm_mat3_applesimd(m.raw); } CGLM_INLINE simd_float4 glms_vec4_(applesimd)(vec4s v) { return glm_vec4_applesimd(v.raw); } CGLM_INLINE simd_float3 glms_vec3_(applesimd)(vec3s v) { return glm_vec3_applesimd(v.raw); } #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) # undef applesimd # define applesimd(x) _Generic((x), \ mat4: glm_mat4_applesimd, \ mat3: glm_mat3_applesimd, \ vec4: glm_vec4_applesimd, \ vec3: glm_vec3_applesimd, \ mat4s: glms_mat4_(applesimd), \ mat3s: glms_mat3_(applesimd), \ vec4s: glms_vec4_(applesimd), \ vec3s: glms_vec3_(applesimd) \ )((x)) #endif #endif #endif #endif /* cglm_applesimd_h */ cglm-0.9.7/include/cglm/bezier.h000066400000000000000000000074121526744317200164660ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_bezier_h #define cglm_bezier_h #include "common.h" #define GLM_BEZIER_MAT_INIT {{-1.0f, 3.0f, -3.0f, 1.0f}, \ { 3.0f, -6.0f, 3.0f, 0.0f}, \ {-3.0f, 3.0f, 0.0f, 0.0f}, \ { 1.0f, 0.0f, 0.0f, 0.0f}} #define GLM_HERMITE_MAT_INIT {{ 2.0f, -3.0f, 0.0f, 1.0f}, \ {-2.0f, 3.0f, 0.0f, 0.0f}, \ { 1.0f, -2.0f, 1.0f, 0.0f}, \ { 1.0f, -1.0f, 0.0f, 0.0f}} /* for C only */ #define GLM_BEZIER_MAT ((mat4)GLM_BEZIER_MAT_INIT) #define GLM_HERMITE_MAT ((mat4)GLM_HERMITE_MAT_INIT) #define CGLM_DECASTEL_EPS 1e-9f #define CGLM_DECASTEL_MAX 1000 #define CGLM_DECASTEL_SMALL 1e-20f /*! * @brief cubic bezier interpolation * * Formula: * B(s) = P0*(1-s)^3 + 3*C0*s*(1-s)^2 + 3*C1*s^2*(1-s) + P1*s^3 * * similar result using matrix: * B(s) = glm_smc(t, GLM_BEZIER_MAT, (vec4){p0, c0, c1, p1}) * * glm_eq(glm_smc(...), glm_bezier(...)) should return TRUE * * @param[in] s parameter between 0 and 1 * @param[in] p0 begin point * @param[in] c0 control point 1 * @param[in] c1 control point 2 * @param[in] p1 end point * * @return B(s) */ CGLM_INLINE float glm_bezier(float s, float p0, float c0, float c1, float p1) { float x, xx, ss, xs3, a; x = 1.0f - s; xx = x * x; ss = s * s; xs3 = (s - ss) * 3.0f; a = p0 * xx + c0 * xs3; return a + s * (c1 * xs3 + p1 * ss - a); } /*! * @brief cubic hermite interpolation * * Formula: * H(s) = P0*(2*s^3 - 3*s^2 + 1) + T0*(s^3 - 2*s^2 + s) * + P1*(-2*s^3 + 3*s^2) + T1*(s^3 - s^2) * * similar result using matrix: * H(s) = glm_smc(t, GLM_HERMITE_MAT, (vec4){p0, p1, c0, c1}) * * glm_eq(glm_smc(...), glm_hermite(...)) should return TRUE * * @param[in] s parameter between 0 and 1 * @param[in] p0 begin point * @param[in] t0 tangent 1 * @param[in] t1 tangent 2 * @param[in] p1 end point * * @return H(s) */ CGLM_INLINE float glm_hermite(float s, float p0, float t0, float t1, float p1) { float ss, d, a, b, c, e, f; ss = s * s; a = ss + ss; c = a + ss; b = a * s; d = s * ss; f = d - ss; e = b - c; return p0 * (e + 1.0f) + t0 * (f - ss + s) + t1 * f - p1 * e; } /*! * @brief iterative way to solve cubic equation * * @param[in] prm parameter between 0 and 1 * @param[in] p0 begin point * @param[in] c0 control point 1 * @param[in] c1 control point 2 * @param[in] p1 end point * * @return parameter to use in cubic equation */ CGLM_INLINE float glm_decasteljau(float prm, float p0, float c0, float c1, float p1) { float u, v, a, b, c, d, e, f; int i; if (prm - p0 < CGLM_DECASTEL_SMALL) return 0.0f; if (p1 - prm < CGLM_DECASTEL_SMALL) return 1.0f; u = 0.0f; v = 1.0f; for (i = 0; i < CGLM_DECASTEL_MAX; i++) { /* de Casteljau Subdivision */ a = (p0 + c0) * 0.5f; b = (c0 + c1) * 0.5f; c = (c1 + p1) * 0.5f; d = (a + b) * 0.5f; e = (b + c) * 0.5f; f = (d + e) * 0.5f; /* this one is on the curve! */ /* The curve point is close enough to our wanted t */ if (fabsf(f - prm) < CGLM_DECASTEL_EPS) return glm_clamp_zo((u + v) * 0.5f); /* dichotomy */ if (f < prm) { p0 = f; c0 = e; c1 = c; u = (u + v) * 0.5f; } else { c0 = a; c1 = d; p1 = f; v = (u + v) * 0.5f; } } return glm_clamp_zo((u + v) * 0.5f); } #endif /* cglm_bezier_h */ cglm-0.9.7/include/cglm/box.h000066400000000000000000000156101526744317200157750ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_box_h #define cglm_box_h #include "common.h" #include "vec3.h" #include "vec4.h" #include "util.h" /*! * @brief apply transform to Axis-Aligned Bounding Box * * @param[in] box bounding box * @param[in] m transform matrix * @param[out] dest transformed bounding box */ CGLM_INLINE void glm_aabb_transform(vec3 box[2], mat4 m, vec3 dest[2]) { vec3 v[2], xa, xb, ya, yb, za, zb; glm_vec3_scale(m[0], box[0][0], xa); glm_vec3_scale(m[0], box[1][0], xb); glm_vec3_scale(m[1], box[0][1], ya); glm_vec3_scale(m[1], box[1][1], yb); glm_vec3_scale(m[2], box[0][2], za); glm_vec3_scale(m[2], box[1][2], zb); /* translation + min(xa, xb) + min(ya, yb) + min(za, zb) */ glm_vec3(m[3], v[0]); glm_vec3_minadd(xa, xb, v[0]); glm_vec3_minadd(ya, yb, v[0]); glm_vec3_minadd(za, zb, v[0]); /* translation + max(xa, xb) + max(ya, yb) + max(za, zb) */ glm_vec3(m[3], v[1]); glm_vec3_maxadd(xa, xb, v[1]); glm_vec3_maxadd(ya, yb, v[1]); glm_vec3_maxadd(za, zb, v[1]); glm_vec3_copy(v[0], dest[0]); glm_vec3_copy(v[1], dest[1]); } /*! * @brief merges two AABB bounding box and creates new one * * two box must be in same space, if one of box is in different space then * you should consider to convert it's space by glm_box_space * * @param[in] box1 bounding box 1 * @param[in] box2 bounding box 2 * @param[out] dest merged bounding box */ CGLM_INLINE void glm_aabb_merge(vec3 box1[2], vec3 box2[2], vec3 dest[2]) { dest[0][0] = glm_min(box1[0][0], box2[0][0]); dest[0][1] = glm_min(box1[0][1], box2[0][1]); dest[0][2] = glm_min(box1[0][2], box2[0][2]); dest[1][0] = glm_max(box1[1][0], box2[1][0]); dest[1][1] = glm_max(box1[1][1], box2[1][1]); dest[1][2] = glm_max(box1[1][2], box2[1][2]); } /*! * @brief crops a bounding box with another one. * * this could be useful for getting a bbox which fits with view frustum and * object bounding boxes. In this case you crop view frustum box with objects * box * * @param[in] box bounding box 1 * @param[in] cropBox crop box * @param[out] dest cropped bounding box */ CGLM_INLINE void glm_aabb_crop(vec3 box[2], vec3 cropBox[2], vec3 dest[2]) { dest[0][0] = glm_max(box[0][0], cropBox[0][0]); dest[0][1] = glm_max(box[0][1], cropBox[0][1]); dest[0][2] = glm_max(box[0][2], cropBox[0][2]); dest[1][0] = glm_min(box[1][0], cropBox[1][0]); dest[1][1] = glm_min(box[1][1], cropBox[1][1]); dest[1][2] = glm_min(box[1][2], cropBox[1][2]); } /*! * @brief crops a bounding box with another one. * * this could be useful for getting a bbox which fits with view frustum and * object bounding boxes. In this case you crop view frustum box with objects * box * * @param[in] box bounding box * @param[in] cropBox crop box * @param[in] clampBox minimum box * @param[out] dest cropped bounding box */ CGLM_INLINE void glm_aabb_crop_until(vec3 box[2], vec3 cropBox[2], vec3 clampBox[2], vec3 dest[2]) { glm_aabb_crop(box, cropBox, dest); glm_aabb_merge(clampBox, dest, dest); } /*! * @brief check if AABB intersects with frustum planes * * this could be useful for frustum culling using AABB. * * OPTIMIZATION HINT: * if planes order is similar to LEFT, RIGHT, BOTTOM, TOP, NEAR, FAR * then this method should run even faster because it would only use two * planes if object is not inside the two planes * fortunately cglm extracts planes as this order! just pass what you got! * * @param[in] box bounding box * @param[in] planes frustum planes */ CGLM_INLINE bool glm_aabb_frustum(vec3 box[2], vec4 planes[6]) { float *p, dp; int i; for (i = 0; i < 6; i++) { p = planes[i]; dp = p[0] * box[p[0] > 0.0f][0] + p[1] * box[p[1] > 0.0f][1] + p[2] * box[p[2] > 0.0f][2]; if (dp < -p[3]) return false; } return true; } /*! * @brief invalidate AABB min and max values * * @param[in, out] box bounding box */ CGLM_INLINE void glm_aabb_invalidate(vec3 box[2]) { glm_vec3_broadcast(FLT_MAX, box[0]); glm_vec3_broadcast(-FLT_MAX, box[1]); } /*! * @brief check if AABB is valid or not * * @param[in] box bounding box */ CGLM_INLINE bool glm_aabb_isvalid(vec3 box[2]) { return glm_vec3_max(box[0]) != FLT_MAX && glm_vec3_min(box[1]) != -FLT_MAX; } /*! * @brief distance between of min and max * * @param[in] box bounding box */ CGLM_INLINE float glm_aabb_size(vec3 box[2]) { return glm_vec3_distance(box[0], box[1]); } /*! * @brief radius of sphere which surrounds AABB * * @param[in] box bounding box */ CGLM_INLINE float glm_aabb_radius(vec3 box[2]) { return glm_aabb_size(box) * 0.5f; } /*! * @brief computes center point of AABB * * @param[in] box bounding box * @param[out] dest center of bounding box */ CGLM_INLINE void glm_aabb_center(vec3 box[2], vec3 dest) { glm_vec3_center(box[0], box[1], dest); } /*! * @brief check if two AABB intersects * * @param[in] box bounding box * @param[in] other other bounding box */ CGLM_INLINE bool glm_aabb_aabb(vec3 box[2], vec3 other[2]) { return (box[0][0] <= other[1][0] && box[1][0] >= other[0][0]) && (box[0][1] <= other[1][1] && box[1][1] >= other[0][1]) && (box[0][2] <= other[1][2] && box[1][2] >= other[0][2]); } /*! * @brief check if AABB intersects with sphere * * https://github.com/erich666/GraphicsGems/blob/master/gems/BoxSphere.c * Solid Box - Solid Sphere test. * * Sphere Representation in cglm: [center.x, center.y, center.z, radii] * * @param[in] box solid bounding box * @param[in] s solid sphere */ CGLM_INLINE bool glm_aabb_sphere(vec3 box[2], vec4 s) { float dmin; int a, b, c; a = (s[0] < box[0][0]) + (s[0] > box[1][0]); b = (s[1] < box[0][1]) + (s[1] > box[1][1]); c = (s[2] < box[0][2]) + (s[2] > box[1][2]); dmin = glm_pow2((s[0] - box[s[0] > box[1][0]][0]) * (a != 0)) + glm_pow2((s[1] - box[s[1] > box[1][1]][1]) * (b != 0)) + glm_pow2((s[2] - box[s[2] > box[1][2]][2]) * (c != 0)); return dmin <= glm_pow2(s[3]); } /*! * @brief check if point is inside of AABB * * @param[in] box bounding box * @param[in] point point */ CGLM_INLINE bool glm_aabb_point(vec3 box[2], vec3 point) { return (point[0] >= box[0][0] && point[0] <= box[1][0]) && (point[1] >= box[0][1] && point[1] <= box[1][1]) && (point[2] >= box[0][2] && point[2] <= box[1][2]); } /*! * @brief check if AABB contains other AABB * * @param[in] box bounding box * @param[in] other other bounding box */ CGLM_INLINE bool glm_aabb_contains(vec3 box[2], vec3 other[2]) { return (box[0][0] <= other[0][0] && box[1][0] >= other[1][0]) && (box[0][1] <= other[0][1] && box[1][1] >= other[1][1]) && (box[0][2] <= other[0][2] && box[1][2] >= other[1][2]); } #endif /* cglm_box_h */ cglm-0.9.7/include/cglm/call.h000066400000000000000000000020351526744317200161150ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_call_h #define cglm_call_h #ifdef __cplusplus extern "C" { #endif #include "call/vec2.h" #include "call/vec3.h" #include "call/vec4.h" #include "call/ivec2.h" #include "call/ivec3.h" #include "call/ivec4.h" #include "call/mat2.h" #include "call/mat2x3.h" #include "call/mat2x4.h" #include "call/mat3.h" #include "call/mat3x2.h" #include "call/mat3x4.h" #include "call/mat4.h" #include "call/mat4x2.h" #include "call/mat4x3.h" #include "call/affine.h" #include "call/cam.h" #include "call/quat.h" #include "call/euler.h" #include "call/plane.h" #include "call/noise.h" #include "call/frustum.h" #include "call/aabb2d.h" #include "call/box.h" #include "call/io.h" #include "call/project.h" #include "call/sphere.h" #include "call/ease.h" #include "call/curve.h" #include "call/bezier.h" #include "call/ray.h" #include "call/affine2d.h" #ifdef __cplusplus } #endif #endif /* cglm_call_h */ cglm-0.9.7/include/cglm/call/000077500000000000000000000000001526744317200157445ustar00rootroot00000000000000cglm-0.9.7/include/cglm/call/aabb2d.h000066400000000000000000000027571526744317200172430ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_aabb2d_h #define cglmc_aabb2d_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" /* DEPRECATED! use _diag */ #define glmc_aabb2d_size(aabb) glmc_aabb2d_diag(aabb) CGLM_EXPORT void glmc_aabb2d_zero(vec2 aabb[2]); CGLM_EXPORT void glmc_aabb2d_copy(vec2 aabb[2], vec2 dest[2]); CGLM_EXPORT void glmc_aabb2d_transform(vec2 aabb[2], mat3 m, vec2 dest[2]); CGLM_EXPORT void glmc_aabb2d_merge(vec2 aabb1[2], vec2 aabb2[2], vec2 dest[2]); CGLM_EXPORT void glmc_aabb2d_crop(vec2 aabb[2], vec2 cropAabb[2], vec2 dest[2]); CGLM_EXPORT void glmc_aabb2d_crop_until(vec2 aabb[2], vec2 cropAabb[2], vec2 clampAabb[2], vec2 dest[2]); CGLM_EXPORT void glmc_aabb2d_invalidate(vec2 aabb[2]); CGLM_EXPORT bool glmc_aabb2d_isvalid(vec2 aabb[2]); CGLM_EXPORT float glmc_aabb2d_diag(vec2 aabb[2]); CGLM_EXPORT void glmc_aabb2d_sizev(vec2 aabb[2], vec2 dest); CGLM_EXPORT float glmc_aabb2d_radius(vec2 aabb[2]); CGLM_EXPORT void glmc_aabb2d_center(vec2 aabb[2], vec2 dest); CGLM_EXPORT bool glmc_aabb2d_aabb(vec2 aabb[2], vec2 other[2]); CGLM_EXPORT bool glmc_aabb2d_point(vec2 aabb[2], vec2 point); CGLM_EXPORT bool glmc_aabb2d_contains(vec2 aabb[2], vec2 other[2]); CGLM_EXPORT bool glmc_aabb2d_circle(vec2 aabb[2], vec3 s); #ifdef __cplusplus } #endif #endif /* cglmc_aabb2d_h */ cglm-0.9.7/include/cglm/call/affine.h000066400000000000000000000047031526744317200173510ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_affine_h #define cglmc_affine_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT void glmc_translate_make(mat4 m, vec3 v); CGLM_EXPORT void glmc_translate_to(mat4 m, vec3 v, mat4 dest); CGLM_EXPORT void glmc_translate(mat4 m, vec3 v); CGLM_EXPORT void glmc_translate_x(mat4 m, float to); CGLM_EXPORT void glmc_translate_y(mat4 m, float to); CGLM_EXPORT void glmc_translate_z(mat4 m, float to); CGLM_EXPORT void glmc_scale_make(mat4 m, vec3 v); CGLM_EXPORT void glmc_scale_to(mat4 m, vec3 v, mat4 dest); CGLM_EXPORT void glmc_scale(mat4 m, vec3 v); CGLM_EXPORT void glmc_scale_uni(mat4 m, float s); CGLM_EXPORT void glmc_rotate_x(mat4 m, float rad, mat4 dest); CGLM_EXPORT void glmc_rotate_y(mat4 m, float rad, mat4 dest); CGLM_EXPORT void glmc_rotate_z(mat4 m, float rad, mat4 dest); CGLM_EXPORT void glmc_rotate_make(mat4 m, float angle, vec3 axis); CGLM_EXPORT void glmc_rotate(mat4 m, float angle, vec3 axis); CGLM_EXPORT void glmc_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis); CGLM_EXPORT void glmc_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis); CGLM_EXPORT void glmc_spin(mat4 m, float angle, vec3 axis); CGLM_EXPORT void glmc_decompose_scalev(mat4 m, vec3 s); CGLM_EXPORT bool glmc_uniscaled(mat4 m); CGLM_EXPORT void glmc_decompose_rs(mat4 m, mat4 r, vec3 s); CGLM_EXPORT void glmc_decompose(mat4 m, vec4 t, mat4 r, vec3 s); /* affine-post */ CGLM_EXPORT void glmc_translated(mat4 m, vec3 v); CGLM_EXPORT void glmc_translated_to(mat4 m, vec3 v, mat4 dest); CGLM_EXPORT void glmc_translated_x(mat4 m, float x); CGLM_EXPORT void glmc_translated_y(mat4 m, float y); CGLM_EXPORT void glmc_translated_z(mat4 m, float z); CGLM_EXPORT void glmc_rotated_x(mat4 m, float angle, mat4 dest); CGLM_EXPORT void glmc_rotated_y(mat4 m, float angle, mat4 dest); CGLM_EXPORT void glmc_rotated_z(mat4 m, float angle, mat4 dest); CGLM_EXPORT void glmc_rotated(mat4 m, float angle, vec3 axis); CGLM_EXPORT void glmc_rotated_at(mat4 m, vec3 pivot, float angle, vec3 axis); CGLM_EXPORT void glmc_spinned(mat4 m, float angle, vec3 axis); /* affine-mat */ CGLM_EXPORT void glmc_mul(mat4 m1, mat4 m2, mat4 dest); CGLM_EXPORT void glmc_mul_rot(mat4 m1, mat4 m2, mat4 dest); CGLM_EXPORT void glmc_inv_tr(mat4 mat); #ifdef __cplusplus } #endif #endif /* cglmc_affine_h */ cglm-0.9.7/include/cglm/call/affine2d.h000066400000000000000000000017571526744317200176050ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_affine2d_h #define cglmc_affine2d_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT void glmc_translate2d_make(mat3 m, vec2 v); CGLM_EXPORT void glmc_translate2d_to(mat3 m, vec2 v, mat3 dest); CGLM_EXPORT void glmc_translate2d(mat3 m, vec2 v); CGLM_EXPORT void glmc_translate2d_x(mat3 m, float to); CGLM_EXPORT void glmc_translate2d_y(mat3 m, float to); CGLM_EXPORT void glmc_scale2d_to(mat3 m, vec2 v, mat3 dest); CGLM_EXPORT void glmc_scale2d_make(mat3 m, vec2 v); CGLM_EXPORT void glmc_scale2d(mat3 m, vec2 v); CGLM_EXPORT void glmc_scale2d_uni(mat3 m, float s); CGLM_EXPORT void glmc_rotate2d_make(mat3 m, float angle); CGLM_EXPORT void glmc_rotate2d(mat3 m, float angle); CGLM_EXPORT void glmc_rotate2d_to(mat3 m, float angle, mat3 dest); #ifdef __cplusplus } #endif #endif /* cglmc_affine2d_h */ cglm-0.9.7/include/cglm/call/bezier.h000066400000000000000000000010701526744317200173730ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_bezier_h #define cglmc_bezier_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT float glmc_bezier(float s, float p0, float c0, float c1, float p1); CGLM_EXPORT float glmc_hermite(float s, float p0, float t0, float t1, float p1); CGLM_EXPORT float glmc_decasteljau(float prm, float p0, float c0, float c1, float p1); #ifdef __cplusplus } #endif #endif /* cglmc_bezier_h */ cglm-0.9.7/include/cglm/call/box.h000066400000000000000000000023721526744317200167110ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_box_h #define cglmc_box_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT void glmc_aabb_transform(vec3 box[2], mat4 m, vec3 dest[2]); CGLM_EXPORT void glmc_aabb_merge(vec3 box1[2], vec3 box2[2], vec3 dest[2]); CGLM_EXPORT void glmc_aabb_crop(vec3 box[2], vec3 cropBox[2], vec3 dest[2]); CGLM_EXPORT void glmc_aabb_crop_until(vec3 box[2], vec3 cropBox[2], vec3 clampBox[2], vec3 dest[2]); CGLM_EXPORT bool glmc_aabb_frustum(vec3 box[2], vec4 planes[6]); CGLM_EXPORT void glmc_aabb_invalidate(vec3 box[2]); CGLM_EXPORT bool glmc_aabb_isvalid(vec3 box[2]); CGLM_EXPORT float glmc_aabb_size(vec3 box[2]); CGLM_EXPORT float glmc_aabb_radius(vec3 box[2]); CGLM_EXPORT void glmc_aabb_center(vec3 box[2], vec3 dest); CGLM_EXPORT bool glmc_aabb_aabb(vec3 box[2], vec3 other[2]); CGLM_EXPORT bool glmc_aabb_point(vec3 box[2], vec3 point); CGLM_EXPORT bool glmc_aabb_contains(vec3 box[2], vec3 other[2]); CGLM_EXPORT bool glmc_aabb_sphere(vec3 box[2], vec4 s); #ifdef __cplusplus } #endif #endif /* cglmc_box_h */ cglm-0.9.7/include/cglm/call/cam.h000066400000000000000000000053271526744317200166640ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_cam_h #define cglmc_cam_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT void glmc_frustum(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest); CGLM_EXPORT void glmc_ortho(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest); CGLM_EXPORT void glmc_ortho_aabb(vec3 box[2], mat4 dest); CGLM_EXPORT void glmc_ortho_aabb_p(vec3 box[2], float padding, mat4 dest); CGLM_EXPORT void glmc_ortho_aabb_pz(vec3 box[2], float padding, mat4 dest); CGLM_EXPORT void glmc_ortho_default(float aspect, mat4 dest); CGLM_EXPORT void glmc_ortho_default_s(float aspect, float size, mat4 dest); CGLM_EXPORT void glmc_perspective(float fovy, float aspect, float nearZ, float farZ, mat4 dest); CGLM_EXPORT void glmc_perspective_infinite(float fovy, float aspect, float nearZ, mat4 dest); CGLM_EXPORT void glmc_persp_move_far(mat4 proj, float deltaFar); CGLM_EXPORT void glmc_perspective_default(float aspect, mat4 dest); CGLM_EXPORT void glmc_perspective_default_infinite(float aspect, mat4 dest); CGLM_EXPORT void glmc_perspective_resize(float aspect, mat4 proj); CGLM_EXPORT void glmc_lookat(vec3 eye, vec3 center, vec3 up, mat4 dest); CGLM_EXPORT void glmc_look(vec3 eye, vec3 dir, vec3 up, mat4 dest); CGLM_EXPORT void glmc_look_anyup(vec3 eye, vec3 dir, mat4 dest); CGLM_EXPORT void glmc_persp_decomp(mat4 proj, float * __restrict nearZ, float * __restrict farZ, float * __restrict top, float * __restrict bottom, float * __restrict left, float * __restrict right); CGLM_EXPORT void glmc_persp_decompv(mat4 proj, float dest[6]); CGLM_EXPORT void glmc_persp_decomp_x(mat4 proj, float * __restrict left, float * __restrict right); CGLM_EXPORT void glmc_persp_decomp_y(mat4 proj, float * __restrict top, float * __restrict bottom); CGLM_EXPORT void glmc_persp_decomp_z(mat4 proj, float * __restrict nearZ, float * __restrict farZ); CGLM_EXPORT void glmc_persp_decomp_far(mat4 proj, float * __restrict farZ); CGLM_EXPORT void glmc_persp_decomp_near(mat4 proj, float * __restrict nearZ); CGLM_EXPORT float glmc_persp_fovy(mat4 proj); CGLM_EXPORT float glmc_persp_aspect(mat4 proj); CGLM_EXPORT void glmc_persp_sizes(mat4 proj, float fovy, vec4 dest); #ifdef __cplusplus } #endif #endif /* cglmc_cam_h */ cglm-0.9.7/include/cglm/call/clipspace/000077500000000000000000000000001526744317200177075ustar00rootroot00000000000000cglm-0.9.7/include/cglm/call/clipspace/ortho_lh_no.h000066400000000000000000000016011526744317200223700ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_ortho_lh_no_h #define cglmc_ortho_lh_no_h #ifdef __cplusplus extern "C" { #endif #include "../../common.h" CGLM_EXPORT void glmc_ortho_lh_no(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest); CGLM_EXPORT void glmc_ortho_aabb_lh_no(vec3 box[2], mat4 dest); CGLM_EXPORT void glmc_ortho_aabb_p_lh_no(vec3 box[2], float padding, mat4 dest); CGLM_EXPORT void glmc_ortho_aabb_pz_lh_no(vec3 box[2], float padding, mat4 dest); CGLM_EXPORT void glmc_ortho_default_lh_no(float aspect, mat4 dest); CGLM_EXPORT void glmc_ortho_default_s_lh_no(float aspect, float size, mat4 dest); #ifdef __cplusplus } #endif #endif /* cglmc_ortho_lh_no_h */ cglm-0.9.7/include/cglm/call/clipspace/ortho_lh_zo.h000066400000000000000000000016011526744317200224040ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_ortho_lh_zo_h #define cglmc_ortho_lh_zo_h #ifdef __cplusplus extern "C" { #endif #include "../../common.h" CGLM_EXPORT void glmc_ortho_lh_zo(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest); CGLM_EXPORT void glmc_ortho_aabb_lh_zo(vec3 box[2], mat4 dest); CGLM_EXPORT void glmc_ortho_aabb_p_lh_zo(vec3 box[2], float padding, mat4 dest); CGLM_EXPORT void glmc_ortho_aabb_pz_lh_zo(vec3 box[2], float padding, mat4 dest); CGLM_EXPORT void glmc_ortho_default_lh_zo(float aspect, mat4 dest); CGLM_EXPORT void glmc_ortho_default_s_lh_zo(float aspect, float size, mat4 dest); #ifdef __cplusplus } #endif #endif /* cglmc_ortho_lh_zo_h */ cglm-0.9.7/include/cglm/call/clipspace/ortho_rh_no.h000066400000000000000000000016011526744317200223760ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_ortho_rh_no_h #define cglmc_ortho_rh_no_h #ifdef __cplusplus extern "C" { #endif #include "../../common.h" CGLM_EXPORT void glmc_ortho_rh_no(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest); CGLM_EXPORT void glmc_ortho_aabb_rh_no(vec3 box[2], mat4 dest); CGLM_EXPORT void glmc_ortho_aabb_p_rh_no(vec3 box[2], float padding, mat4 dest); CGLM_EXPORT void glmc_ortho_aabb_pz_rh_no(vec3 box[2], float padding, mat4 dest); CGLM_EXPORT void glmc_ortho_default_rh_no(float aspect, mat4 dest); CGLM_EXPORT void glmc_ortho_default_s_rh_no(float aspect, float size, mat4 dest); #ifdef __cplusplus } #endif #endif /* cglmc_ortho_rh_no_h */ cglm-0.9.7/include/cglm/call/clipspace/ortho_rh_zo.h000066400000000000000000000016011526744317200224120ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_ortho_rh_zo_h #define cglmc_ortho_rh_zo_h #ifdef __cplusplus extern "C" { #endif #include "../../common.h" CGLM_EXPORT void glmc_ortho_rh_zo(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest); CGLM_EXPORT void glmc_ortho_aabb_rh_zo(vec3 box[2], mat4 dest); CGLM_EXPORT void glmc_ortho_aabb_p_rh_zo(vec3 box[2], float padding, mat4 dest); CGLM_EXPORT void glmc_ortho_aabb_pz_rh_zo(vec3 box[2], float padding, mat4 dest); CGLM_EXPORT void glmc_ortho_default_rh_zo(float aspect, mat4 dest); CGLM_EXPORT void glmc_ortho_default_s_rh_zo(float aspect, float size, mat4 dest); #ifdef __cplusplus } #endif #endif /* cglmc_ortho_rh_zo_h */ cglm-0.9.7/include/cglm/call/clipspace/persp_lh_no.h000066400000000000000000000040311526744317200223660ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_persp_lh_no_h #define cglmc_persp_lh_no_h #ifdef __cplusplus extern "C" { #endif #include "../../common.h" CGLM_EXPORT void glmc_frustum_lh_no(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest); CGLM_EXPORT void glmc_perspective_lh_no(float fovy, float aspect, float nearVal, float farVal, mat4 dest); CGLM_EXPORT void glmc_perspective_resize_lh_no(float aspect, mat4 proj); CGLM_EXPORT void glmc_persp_move_far_lh_no(mat4 proj, float deltaFar); CGLM_EXPORT void glmc_persp_decomp_lh_no(mat4 proj, float * __restrict nearZ, float * __restrict farZ, float * __restrict top, float * __restrict bottom, float * __restrict left, float * __restrict right); CGLM_EXPORT void glmc_persp_decompv_lh_no(mat4 proj, float dest[6]); CGLM_EXPORT void glmc_persp_decomp_x_lh_no(mat4 proj, float * __restrict left, float * __restrict right); CGLM_EXPORT void glmc_persp_decomp_y_lh_no(mat4 proj, float * __restrict top, float * __restrict bottom); CGLM_EXPORT void glmc_persp_decomp_z_lh_no(mat4 proj, float * __restrict nearZ, float * __restrict farZ); CGLM_EXPORT void glmc_persp_decomp_far_lh_no(mat4 proj, float * __restrict farZ); CGLM_EXPORT void glmc_persp_decomp_near_lh_no(mat4 proj, float * __restrict nearZ); CGLM_EXPORT void glmc_persp_sizes_lh_no(mat4 proj, float fovy, vec4 dest); CGLM_EXPORT float glmc_persp_fovy_lh_no(mat4 proj); CGLM_EXPORT float glmc_persp_aspect_lh_no(mat4 proj); #ifdef __cplusplus } #endif #endif /* cglmc_persp_lh_no_h */ cglm-0.9.7/include/cglm/call/clipspace/persp_lh_zo.h000066400000000000000000000040311526744317200224020ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_persp_lh_zo_h #define cglmc_persp_lh_zo_h #ifdef __cplusplus extern "C" { #endif #include "../../common.h" CGLM_EXPORT void glmc_frustum_lh_zo(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest); CGLM_EXPORT void glmc_perspective_lh_zo(float fovy, float aspect, float nearVal, float farVal, mat4 dest); CGLM_EXPORT void glmc_perspective_resize_lh_zo(float aspect, mat4 proj); CGLM_EXPORT void glmc_persp_move_far_lh_zo(mat4 proj, float deltaFar); CGLM_EXPORT void glmc_persp_decomp_lh_zo(mat4 proj, float * __restrict nearZ, float * __restrict farZ, float * __restrict top, float * __restrict bottom, float * __restrict left, float * __restrict right); CGLM_EXPORT void glmc_persp_decompv_lh_zo(mat4 proj, float dest[6]); CGLM_EXPORT void glmc_persp_decomp_x_lh_zo(mat4 proj, float * __restrict left, float * __restrict right); CGLM_EXPORT void glmc_persp_decomp_y_lh_zo(mat4 proj, float * __restrict top, float * __restrict bottom); CGLM_EXPORT void glmc_persp_decomp_z_lh_zo(mat4 proj, float * __restrict nearZ, float * __restrict farZ); CGLM_EXPORT void glmc_persp_decomp_far_lh_zo(mat4 proj, float * __restrict farZ); CGLM_EXPORT void glmc_persp_decomp_near_lh_zo(mat4 proj, float * __restrict nearZ); CGLM_EXPORT void glmc_persp_sizes_lh_zo(mat4 proj, float fovy, vec4 dest); CGLM_EXPORT float glmc_persp_fovy_lh_zo(mat4 proj); CGLM_EXPORT float glmc_persp_aspect_lh_zo(mat4 proj); #ifdef __cplusplus } #endif #endif /* cglmc_persp_lh_zo_h */ cglm-0.9.7/include/cglm/call/clipspace/persp_rh_no.h000066400000000000000000000040311526744317200223740ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_persp_rh_no_h #define cglmc_persp_rh_no_h #ifdef __cplusplus extern "C" { #endif #include "../../common.h" CGLM_EXPORT void glmc_frustum_rh_no(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest); CGLM_EXPORT void glmc_perspective_rh_no(float fovy, float aspect, float nearVal, float farVal, mat4 dest); CGLM_EXPORT void glmc_perspective_resize_rh_no(float aspect, mat4 proj); CGLM_EXPORT void glmc_persp_move_far_rh_no(mat4 proj, float deltaFar); CGLM_EXPORT void glmc_persp_decomp_rh_no(mat4 proj, float * __restrict nearZ, float * __restrict farZ, float * __restrict top, float * __restrict bottom, float * __restrict left, float * __restrict right); CGLM_EXPORT void glmc_persp_decompv_rh_no(mat4 proj, float dest[6]); CGLM_EXPORT void glmc_persp_decomp_x_rh_no(mat4 proj, float * __restrict left, float * __restrict right); CGLM_EXPORT void glmc_persp_decomp_y_rh_no(mat4 proj, float * __restrict top, float * __restrict bottom); CGLM_EXPORT void glmc_persp_decomp_z_rh_no(mat4 proj, float * __restrict nearZ, float * __restrict farZ); CGLM_EXPORT void glmc_persp_decomp_far_rh_no(mat4 proj, float * __restrict farZ); CGLM_EXPORT void glmc_persp_decomp_near_rh_no(mat4 proj, float * __restrict nearZ); CGLM_EXPORT void glmc_persp_sizes_rh_no(mat4 proj, float fovy, vec4 dest); CGLM_EXPORT float glmc_persp_fovy_rh_no(mat4 proj); CGLM_EXPORT float glmc_persp_aspect_rh_no(mat4 proj); #ifdef __cplusplus } #endif #endif /* cglmc_persp_rh_no_h */ cglm-0.9.7/include/cglm/call/clipspace/persp_rh_zo.h000066400000000000000000000040311526744317200224100ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_persp_rh_zo_h #define cglmc_persp_rh_zo_h #ifdef __cplusplus extern "C" { #endif #include "../../common.h" CGLM_EXPORT void glmc_frustum_rh_zo(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest); CGLM_EXPORT void glmc_perspective_rh_zo(float fovy, float aspect, float nearVal, float farVal, mat4 dest); CGLM_EXPORT void glmc_perspective_resize_rh_zo(float aspect, mat4 proj); CGLM_EXPORT void glmc_persp_move_far_rh_zo(mat4 proj, float deltaFar); CGLM_EXPORT void glmc_persp_decomp_rh_zo(mat4 proj, float * __restrict nearZ, float * __restrict farZ, float * __restrict top, float * __restrict bottom, float * __restrict left, float * __restrict right); CGLM_EXPORT void glmc_persp_decompv_rh_zo(mat4 proj, float dest[6]); CGLM_EXPORT void glmc_persp_decomp_x_rh_zo(mat4 proj, float * __restrict left, float * __restrict right); CGLM_EXPORT void glmc_persp_decomp_y_rh_zo(mat4 proj, float * __restrict top, float * __restrict bottom); CGLM_EXPORT void glmc_persp_decomp_z_rh_zo(mat4 proj, float * __restrict nearZ, float * __restrict farZ); CGLM_EXPORT void glmc_persp_decomp_far_rh_zo(mat4 proj, float * __restrict farZ); CGLM_EXPORT void glmc_persp_decomp_near_rh_zo(mat4 proj, float * __restrict nearZ); CGLM_EXPORT void glmc_persp_sizes_rh_zo(mat4 proj, float fovy, vec4 dest); CGLM_EXPORT float glmc_persp_fovy_rh_zo(mat4 proj); CGLM_EXPORT float glmc_persp_aspect_rh_zo(mat4 proj); #ifdef __cplusplus } #endif #endif /* cglmc_persp_rh_zo_h */ cglm-0.9.7/include/cglm/call/clipspace/project_no.h000066400000000000000000000010361526744317200222220ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_project_no_h #define cglmc_project_no_h #ifdef __cplusplus extern "C" { #endif #include "../../common.h" CGLM_EXPORT void glmc_unprojecti_no(vec3 pos, mat4 invMat, vec4 vp, vec3 dest); CGLM_EXPORT void glmc_project_no(vec3 pos, mat4 m, vec4 vp, vec3 dest); CGLM_EXPORT float glmc_project_z_no(vec3 pos, mat4 m); #ifdef __cplusplus } #endif #endif /* cglmc_project_no_h */ cglm-0.9.7/include/cglm/call/clipspace/project_zo.h000066400000000000000000000010361526744317200222360ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_project_zo_h #define cglmc_project_zo_h #ifdef __cplusplus extern "C" { #endif #include "../../common.h" CGLM_EXPORT void glmc_unprojecti_zo(vec3 pos, mat4 invMat, vec4 vp, vec3 dest); CGLM_EXPORT void glmc_project_zo(vec3 pos, mat4 m, vec4 vp, vec3 dest); CGLM_EXPORT float glmc_project_z_zo(vec3 pos, mat4 m); #ifdef __cplusplus } #endif #endif /* cglmc_project_zo_h */ cglm-0.9.7/include/cglm/call/clipspace/view_lh_no.h000066400000000000000000000010571526744317200222140ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_view_lh_no_h #define cglmc_view_lh_no_h #ifdef __cplusplus extern "C" { #endif #include "../../common.h" CGLM_EXPORT void glmc_lookat_lh_no(vec3 eye, vec3 center, vec3 up, mat4 dest); CGLM_EXPORT void glmc_look_lh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest); CGLM_EXPORT void glmc_look_anyup_lh_no(vec3 eye, vec3 dir, mat4 dest); #ifdef __cplusplus } #endif #endif /* cglmc_view_lh_no_h */ cglm-0.9.7/include/cglm/call/clipspace/view_lh_zo.h000066400000000000000000000010571526744317200222300ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_view_lh_zo_h #define cglmc_view_lh_zo_h #ifdef __cplusplus extern "C" { #endif #include "../../common.h" CGLM_EXPORT void glmc_lookat_lh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest); CGLM_EXPORT void glmc_look_lh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest); CGLM_EXPORT void glmc_look_anyup_lh_zo(vec3 eye, vec3 dir, mat4 dest); #ifdef __cplusplus } #endif #endif /* cglmc_view_lh_zo_h */ cglm-0.9.7/include/cglm/call/clipspace/view_rh_no.h000066400000000000000000000010571526744317200222220ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_view_rh_no_h #define cglmc_view_rh_no_h #ifdef __cplusplus extern "C" { #endif #include "../../common.h" CGLM_EXPORT void glmc_lookat_rh_no(vec3 eye, vec3 center, vec3 up, mat4 dest); CGLM_EXPORT void glmc_look_rh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest); CGLM_EXPORT void glmc_look_anyup_rh_no(vec3 eye, vec3 dir, mat4 dest); #ifdef __cplusplus } #endif #endif /* cglmc_view_rh_no_h */ cglm-0.9.7/include/cglm/call/clipspace/view_rh_zo.h000066400000000000000000000010571526744317200222360ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_view_rh_zo_h #define cglmc_view_rh_zo_h #ifdef __cplusplus extern "C" { #endif #include "../../common.h" CGLM_EXPORT void glmc_lookat_rh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest); CGLM_EXPORT void glmc_look_rh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest); CGLM_EXPORT void glmc_look_anyup_rh_zo(vec3 eye, vec3 dir, mat4 dest); #ifdef __cplusplus } #endif #endif /* cglmc_view_rh_zo_h */ cglm-0.9.7/include/cglm/call/curve.h000066400000000000000000000005601526744317200172420ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_curve_h #define cglmc_curve_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT float glmc_smc(float s, mat4 m, vec4 c); #ifdef __cplusplus } #endif #endif /* cglmc_curve_h */ cglm-0.9.7/include/cglm/call/ease.h000066400000000000000000000034361526744317200170400ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_ease_h #define cglmc_ease_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT float glmc_ease_linear(float t); CGLM_EXPORT float glmc_ease_sine_in(float t); CGLM_EXPORT float glmc_ease_sine_out(float t); CGLM_EXPORT float glmc_ease_sine_inout(float t); CGLM_EXPORT float glmc_ease_quad_in(float t); CGLM_EXPORT float glmc_ease_quad_out(float t); CGLM_EXPORT float glmc_ease_quad_inout(float t); CGLM_EXPORT float glmc_ease_cubic_in(float t); CGLM_EXPORT float glmc_ease_cubic_out(float t); CGLM_EXPORT float glmc_ease_cubic_inout(float t); CGLM_EXPORT float glmc_ease_quart_in(float t); CGLM_EXPORT float glmc_ease_quart_out(float t); CGLM_EXPORT float glmc_ease_quart_inout(float t); CGLM_EXPORT float glmc_ease_quint_in(float t); CGLM_EXPORT float glmc_ease_quint_out(float t); CGLM_EXPORT float glmc_ease_quint_inout(float t); CGLM_EXPORT float glmc_ease_exp_in(float t); CGLM_EXPORT float glmc_ease_exp_out(float t); CGLM_EXPORT float glmc_ease_exp_inout(float t); CGLM_EXPORT float glmc_ease_circ_in(float t); CGLM_EXPORT float glmc_ease_circ_out(float t); CGLM_EXPORT float glmc_ease_circ_inout(float t); CGLM_EXPORT float glmc_ease_back_in(float t); CGLM_EXPORT float glmc_ease_back_out(float t); CGLM_EXPORT float glmc_ease_back_inout(float t); CGLM_EXPORT float glmc_ease_elast_in(float t); CGLM_EXPORT float glmc_ease_elast_out(float t); CGLM_EXPORT float glmc_ease_elast_inout(float t); CGLM_EXPORT float glmc_ease_bounce_out(float t); CGLM_EXPORT float glmc_ease_bounce_in(float t); CGLM_EXPORT float glmc_ease_bounce_inout(float t); #ifdef __cplusplus } #endif #endif /* cglmc_ease_h */ cglm-0.9.7/include/cglm/call/euler.h000066400000000000000000000023401526744317200172300ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_euler_h #define cglmc_euler_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT void glmc_euler_angles(mat4 m, vec3 dest); CGLM_EXPORT void glmc_euler(vec3 angles, mat4 dest); CGLM_EXPORT void glmc_euler_xyz(vec3 angles, mat4 dest); CGLM_EXPORT void glmc_euler_zyx(vec3 angles, mat4 dest); CGLM_EXPORT void glmc_euler_zxy(vec3 angles, mat4 dest); CGLM_EXPORT void glmc_euler_xzy(vec3 angles, mat4 dest); CGLM_EXPORT void glmc_euler_yzx(vec3 angles, mat4 dest); CGLM_EXPORT void glmc_euler_yxz(vec3 angles, mat4 dest); CGLM_EXPORT void glmc_euler_by_order(vec3 angles, glm_euler_seq axis, mat4 dest); CGLM_EXPORT void glmc_euler_xyz_quat(vec3 angles, versor dest); CGLM_EXPORT void glmc_euler_xzy_quat(vec3 angles, versor dest); CGLM_EXPORT void glmc_euler_yxz_quat(vec3 angles, versor dest); CGLM_EXPORT void glmc_euler_yzx_quat(vec3 angles, versor dest); CGLM_EXPORT void glmc_euler_zxy_quat(vec3 angles, versor dest); CGLM_EXPORT void glmc_euler_zyx_quat(vec3 angles, versor dest); #ifdef __cplusplus } #endif #endif /* cglmc_euler_h */ cglm-0.9.7/include/cglm/call/frustum.h000066400000000000000000000014101526744317200176160ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_frustum_h #define cglmc_frustum_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT void glmc_frustum_planes(mat4 m, vec4 dest[6]); CGLM_EXPORT void glmc_frustum_corners(mat4 invMat, vec4 dest[8]); CGLM_EXPORT void glmc_frustum_center(vec4 corners[8], vec4 dest); CGLM_EXPORT void glmc_frustum_box(vec4 corners[8], mat4 m, vec3 box[2]); CGLM_EXPORT void glmc_frustum_corners_at(vec4 corners[8], float splitDist, float farDist, vec4 planeCorners[4]); #ifdef __cplusplus } #endif #endif /* cglmc_frustum_h */ cglm-0.9.7/include/cglm/call/io.h000066400000000000000000000014131526744317200165230ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_io_h #define cglmc_io_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" #include CGLM_EXPORT void glmc_mat4_print(mat4 matrix, FILE * __restrict ostream); CGLM_EXPORT void glmc_mat3_print(mat3 matrix, FILE * __restrict ostream); CGLM_EXPORT void glmc_vec4_print(vec4 vec, FILE * __restrict ostream); CGLM_EXPORT void glmc_vec3_print(vec3 vec, FILE * __restrict ostream); CGLM_EXPORT void glmc_versor_print(versor vec, FILE * __restrict ostream); #ifdef __cplusplus } #endif #endif /* cglmc_io_h */ cglm-0.9.7/include/cglm/call/ivec2.h000066400000000000000000000054031526744317200171270ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_ivec2_h #define cglmc_ivec2_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT void glmc_ivec2(int * __restrict v, ivec2 dest); CGLM_EXPORT void glmc_ivec2_copy(ivec2 a, ivec2 dest); CGLM_EXPORT void glmc_ivec2_zero(ivec2 v); CGLM_EXPORT void glmc_ivec2_one(ivec2 v); CGLM_EXPORT int glmc_ivec2_dot(ivec2 a, ivec2 b); CGLM_EXPORT int glmc_ivec2_cross(ivec2 a, ivec2 b); CGLM_EXPORT void glmc_ivec2_add(ivec2 a, ivec2 b, ivec2 dest); CGLM_EXPORT void glmc_ivec2_adds(ivec2 v, int s, ivec2 dest); CGLM_EXPORT void glmc_ivec2_sub(ivec2 a, ivec2 b, ivec2 dest); CGLM_EXPORT void glmc_ivec2_subs(ivec2 v, int s, ivec2 dest); CGLM_EXPORT void glmc_ivec2_mul(ivec2 a, ivec2 b, ivec2 dest); CGLM_EXPORT void glmc_ivec2_scale(ivec2 v, int s, ivec2 dest); CGLM_EXPORT void glmc_ivec2_div(ivec2 a, ivec2 b, ivec2 dest); CGLM_EXPORT void glmc_ivec2_divs(ivec2 v, int s, ivec2 dest); CGLM_EXPORT void glmc_ivec2_mod(ivec2 a, ivec2 b, ivec2 dest); CGLM_EXPORT void glmc_ivec2_addadd(ivec2 a, ivec2 b, ivec2 dest); CGLM_EXPORT void glmc_ivec2_addadds(ivec2 a, int s, ivec2 dest); CGLM_EXPORT void glmc_ivec2_subadd(ivec2 a, ivec2 b, ivec2 dest); CGLM_EXPORT void glmc_ivec2_subadds(ivec2 a, int s, ivec2 dest); CGLM_EXPORT void glmc_ivec2_muladd(ivec2 a, ivec2 b, ivec2 dest); CGLM_EXPORT void glmc_ivec2_muladds(ivec2 a, int s, ivec2 dest); CGLM_EXPORT void glmc_ivec2_maxadd(ivec2 a, ivec2 b, ivec2 dest); CGLM_EXPORT void glmc_ivec2_minadd(ivec2 a, ivec2 b, ivec2 dest); CGLM_EXPORT void glmc_ivec2_subsub(ivec2 a, ivec2 b, ivec2 dest); CGLM_EXPORT void glmc_ivec2_subsubs(ivec2 a, int s, ivec2 dest); CGLM_EXPORT void glmc_ivec2_addsub(ivec2 a, ivec2 b, ivec2 dest); CGLM_EXPORT void glmc_ivec2_addsubs(ivec2 a, int s, ivec2 dest); CGLM_EXPORT void glmc_ivec2_mulsub(ivec2 a, ivec2 b, ivec2 dest); CGLM_EXPORT void glmc_ivec2_mulsubs(ivec2 a, int s, ivec2 dest); CGLM_EXPORT void glmc_ivec2_maxsub(ivec2 a, ivec2 b, ivec2 dest); CGLM_EXPORT void glmc_ivec2_minsub(ivec2 a, ivec2 b, ivec2 dest); CGLM_EXPORT int glmc_ivec2_distance2(ivec2 a, ivec2 b); CGLM_EXPORT float glmc_ivec2_distance(ivec2 a, ivec2 b); CGLM_EXPORT void glmc_ivec2_fill(ivec2 v, int val); CGLM_EXPORT bool glmc_ivec2_eq(ivec2 v, int val); CGLM_EXPORT bool glmc_ivec2_eqv(ivec2 a, ivec2 b); CGLM_EXPORT void glmc_ivec2_maxv(ivec2 a, ivec2 b, ivec2 dest); CGLM_EXPORT void glmc_ivec2_minv(ivec2 a, ivec2 b, ivec2 dest); CGLM_EXPORT void glmc_ivec2_clamp(ivec2 v, int minVal, int maxVal); CGLM_EXPORT void glmc_ivec2_abs(ivec2 v, ivec2 dest); #ifdef __cplusplus } #endif #endif /* cglmc_ivec2_h */ cglm-0.9.7/include/cglm/call/ivec3.h000066400000000000000000000054361526744317200171360ustar00rootroot00000000000000/* * Copyright (c);, Recep Aslantas. * * MIT License (MIT);, http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_ivec3_h #define cglmc_ivec3_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT void glmc_ivec3(ivec4 v4, ivec3 dest); CGLM_EXPORT void glmc_ivec3_copy(ivec3 a, ivec3 dest); CGLM_EXPORT void glmc_ivec3_zero(ivec3 v); CGLM_EXPORT void glmc_ivec3_one(ivec3 v); CGLM_EXPORT int glmc_ivec3_dot(ivec3 a, ivec3 b); CGLM_EXPORT int glmc_ivec3_norm2(ivec3 v); CGLM_EXPORT int glmc_ivec3_norm(ivec3 v); CGLM_EXPORT void glmc_ivec3_add(ivec3 a, ivec3 b, ivec3 dest); CGLM_EXPORT void glmc_ivec3_adds(ivec3 v, int s, ivec3 dest); CGLM_EXPORT void glmc_ivec3_sub(ivec3 a, ivec3 b, ivec3 dest); CGLM_EXPORT void glmc_ivec3_subs(ivec3 v, int s, ivec3 dest); CGLM_EXPORT void glmc_ivec3_mul(ivec3 a, ivec3 b, ivec3 dest); CGLM_EXPORT void glmc_ivec3_scale(ivec3 v, int s, ivec3 dest); CGLM_EXPORT void glmc_ivec3_div(ivec3 a, ivec3 b, ivec3 dest); CGLM_EXPORT void glmc_ivec3_divs(ivec3 v, int s, ivec3 dest); CGLM_EXPORT void glmc_ivec3_mod(ivec3 a, ivec3 b, ivec3 dest); CGLM_EXPORT void glmc_ivec3_addadd(ivec3 a, ivec3 b, ivec3 dest); CGLM_EXPORT void glmc_ivec3_addadds(ivec3 a, int s, ivec3 dest); CGLM_EXPORT void glmc_ivec3_subadd(ivec3 a, ivec3 b, ivec3 dest); CGLM_EXPORT void glmc_ivec3_subadds(ivec3 a, int s, ivec3 dest); CGLM_EXPORT void glmc_ivec3_muladd(ivec3 a, ivec3 b, ivec3 dest); CGLM_EXPORT void glmc_ivec3_muladds(ivec3 a, int s, ivec3 dest); CGLM_EXPORT void glmc_ivec3_maxadd(ivec3 a, ivec3 b, ivec3 dest); CGLM_EXPORT void glmc_ivec3_minadd(ivec3 a, ivec3 b, ivec3 dest); CGLM_EXPORT void glmc_ivec3_subsub(ivec3 a, ivec3 b, ivec3 dest); CGLM_EXPORT void glmc_ivec3_subsubs(ivec3 a, int s, ivec3 dest); CGLM_EXPORT void glmc_ivec3_addsub(ivec3 a, ivec3 b, ivec3 dest); CGLM_EXPORT void glmc_ivec3_addsubs(ivec3 a, int s, ivec3 dest); CGLM_EXPORT void glmc_ivec3_mulsub(ivec3 a, ivec3 b, ivec3 dest); CGLM_EXPORT void glmc_ivec3_mulsubs(ivec3 a, int s, ivec3 dest); CGLM_EXPORT void glmc_ivec3_maxsub(ivec3 a, ivec3 b, ivec3 dest); CGLM_EXPORT void glmc_ivec3_minsub(ivec3 a, ivec3 b, ivec3 dest); CGLM_EXPORT int glmc_ivec3_distance2(ivec3 a, ivec3 b); CGLM_EXPORT float glmc_ivec3_distance(ivec3 a, ivec3 b); CGLM_EXPORT void glmc_ivec3_fill(ivec3 v, int val); CGLM_EXPORT bool glmc_ivec3_eq(ivec3 v, int val); CGLM_EXPORT bool glmc_ivec3_eqv(ivec3 a, ivec3 b); CGLM_EXPORT void glmc_ivec3_maxv(ivec3 a, ivec3 b, ivec3 dest); CGLM_EXPORT void glmc_ivec3_minv(ivec3 a, ivec3 b, ivec3 dest); CGLM_EXPORT void glmc_ivec3_clamp(ivec3 v, int minVal, int maxVal); CGLM_EXPORT void glmc_ivec3_abs(ivec3 v, ivec3 dest); #ifdef __cplusplus } #endif #endif /* cglmc_ivec3_h */ cglm-0.9.7/include/cglm/call/ivec4.h000066400000000000000000000045011526744317200171270ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_ivec4_h #define cglmc_ivec4_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT void glmc_ivec4(ivec3 v3, int last, ivec4 dest); CGLM_EXPORT void glmc_ivec4_copy(ivec4 a, ivec4 dest); CGLM_EXPORT void glmc_ivec4_zero(ivec4 v); CGLM_EXPORT void glmc_ivec4_one(ivec4 v); CGLM_EXPORT void glmc_ivec4_add(ivec4 a, ivec4 b, ivec4 dest); CGLM_EXPORT void glmc_ivec4_adds(ivec4 v, int s, ivec4 dest); CGLM_EXPORT void glmc_ivec4_sub(ivec4 a, ivec4 b, ivec4 dest); CGLM_EXPORT void glmc_ivec4_subs(ivec4 v, int s, ivec4 dest); CGLM_EXPORT void glmc_ivec4_mul(ivec4 a, ivec4 b, ivec4 dest); CGLM_EXPORT void glmc_ivec4_scale(ivec4 v, int s, ivec4 dest); CGLM_EXPORT void glmc_ivec4_addadd(ivec4 a, ivec4 b, ivec4 dest); CGLM_EXPORT void glmc_ivec4_addadds(ivec4 a, int s, ivec4 dest); CGLM_EXPORT void glmc_ivec4_subadd(ivec4 a, ivec4 b, ivec4 dest); CGLM_EXPORT void glmc_ivec4_subadds(ivec4 a, int s, ivec4 dest); CGLM_EXPORT void glmc_ivec4_muladd(ivec4 a, ivec4 b, ivec4 dest); CGLM_EXPORT void glmc_ivec4_muladds(ivec4 a, int s, ivec4 dest); CGLM_EXPORT void glmc_ivec4_maxadd(ivec4 a, ivec4 b, ivec4 dest); CGLM_EXPORT void glmc_ivec4_minadd(ivec4 a, ivec4 b, ivec4 dest); CGLM_EXPORT void glmc_ivec4_subsub(ivec4 a, ivec4 b, ivec4 dest); CGLM_EXPORT void glmc_ivec4_subsubs(ivec4 a, int s, ivec4 dest); CGLM_EXPORT void glmc_ivec4_addsub(ivec4 a, ivec4 b, ivec4 dest); CGLM_EXPORT void glmc_ivec4_addsubs(ivec4 a, int s, ivec4 dest); CGLM_EXPORT void glmc_ivec4_mulsub(ivec4 a, ivec4 b, ivec4 dest); CGLM_EXPORT void glmc_ivec4_mulsubs(ivec4 a, int s, ivec4 dest); CGLM_EXPORT void glmc_ivec4_maxsub(ivec4 a, ivec4 b, ivec4 dest); CGLM_EXPORT void glmc_ivec4_minsub(ivec4 a, ivec4 b, ivec4 dest); CGLM_EXPORT int glmc_ivec4_distance2(ivec4 a, ivec4 b); CGLM_EXPORT float glmc_ivec4_distance(ivec4 a, ivec4 b); CGLM_EXPORT void glmc_ivec4_maxv(ivec4 a, ivec4 b, ivec4 dest); CGLM_EXPORT void glmc_ivec4_minv(ivec4 a, ivec4 b, ivec4 dest); CGLM_EXPORT void glmc_ivec4_clamp(ivec4 v, int minVal, int maxVal); CGLM_EXPORT void glmc_ivec4_abs(ivec4 v, ivec4 dest); #ifdef __cplusplus } #endif #endif /* cglmc_ivec4_h */ cglm-0.9.7/include/cglm/call/mat2.h000066400000000000000000000023161526744317200167620ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_mat2_h #define cglmc_mat2_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT void glmc_mat2_make(const float * __restrict src, mat2 dest); CGLM_EXPORT void glmc_mat2_copy(mat2 mat, mat2 dest); CGLM_EXPORT void glmc_mat2_identity(mat2 m); CGLM_EXPORT void glmc_mat2_identity_array(mat2 * __restrict mats, size_t count); CGLM_EXPORT void glmc_mat2_zero(mat2 m); CGLM_EXPORT void glmc_mat2_mul(mat2 m1, mat2 m2, mat2 dest); CGLM_EXPORT void glmc_mat2_mulv(mat2 m, vec2 v, vec2 dest); CGLM_EXPORT void glmc_mat2_transpose_to(mat2 mat, mat2 dest); CGLM_EXPORT void glmc_mat2_transpose(mat2 m); CGLM_EXPORT void glmc_mat2_scale(mat2 m, float s); CGLM_EXPORT void glmc_mat2_inv(mat2 mat, mat2 dest); CGLM_EXPORT void glmc_mat2_swap_col(mat2 mat, int col1, int col2); CGLM_EXPORT void glmc_mat2_swap_row(mat2 mat, int row1, int row2); CGLM_EXPORT float glmc_mat2_trace(mat2 m); CGLM_EXPORT float glmc_mat2_det(mat2 m); CGLM_EXPORT float glmc_mat2_rmc(vec2 r, mat2 m, vec2 c); #ifdef __cplusplus } #endif #endif /* cglmc_mat2_h */ cglm-0.9.7/include/cglm/call/mat2x3.h000066400000000000000000000013661526744317200172410ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_mat2x3_h #define cglmc_mat2x3_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT void glmc_mat2x3_copy(mat2x3 src, mat2x3 dest); CGLM_EXPORT void glmc_mat2x3_zero(mat2x3 m); CGLM_EXPORT void glmc_mat2x3_make(const float * __restrict src, mat2x3 dest); CGLM_EXPORT void glmc_mat2x3_mul(mat2x3 m1, mat3x2 m2, mat3 dest); CGLM_EXPORT void glmc_mat2x3_mulv(mat2x3 m, vec2 v, vec3 dest); CGLM_EXPORT void glmc_mat2x3_transpose(mat2x3 src, mat3x2 dest); CGLM_EXPORT void glmc_mat2x3_scale(mat2x3 m, float s); #ifdef __cplusplus } #endif #endif /* cglmc_mat2x3_h */ cglm-0.9.7/include/cglm/call/mat2x4.h000066400000000000000000000013661526744317200172420ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_mat2x4_h #define cglmc_mat2x4_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT void glmc_mat2x4_copy(mat2x4 src, mat2x4 dest); CGLM_EXPORT void glmc_mat2x4_zero(mat2x4 m); CGLM_EXPORT void glmc_mat2x4_make(const float * __restrict src, mat2x4 dest); CGLM_EXPORT void glmc_mat2x4_mul(mat2x4 m1, mat4x2 m2, mat4 dest); CGLM_EXPORT void glmc_mat2x4_mulv(mat2x4 m, vec2 v, vec4 dest); CGLM_EXPORT void glmc_mat2x4_transpose(mat2x4 src, mat4x2 dest); CGLM_EXPORT void glmc_mat2x4_scale(mat2x4 m, float s); #ifdef __cplusplus } #endif #endif /* cglmc_mat2x4_h */ cglm-0.9.7/include/cglm/call/mat3.h000066400000000000000000000027261526744317200167700ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_mat3_h #define cglmc_mat3_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" /* DEPRECATED! use _copy, _ucopy versions */ #define glmc_mat3_dup(mat, dest) glmc_mat3_copy(mat, dest) CGLM_EXPORT void glmc_mat3_copy(mat3 mat, mat3 dest); CGLM_EXPORT void glmc_mat3_identity(mat3 mat); CGLM_EXPORT void glmc_mat3_zero(mat3 mat); CGLM_EXPORT void glmc_mat3_identity_array(mat3 * __restrict mat, size_t count); CGLM_EXPORT void glmc_mat3_mul(mat3 m1, mat3 m2, mat3 dest); CGLM_EXPORT void glmc_mat3_transpose_to(mat3 m, mat3 dest); CGLM_EXPORT void glmc_mat3_transpose(mat3 m); CGLM_EXPORT void glmc_mat3_mulv(mat3 m, vec3 v, vec3 dest); CGLM_EXPORT float glmc_mat3_trace(mat3 m); CGLM_EXPORT void glmc_mat3_quat(mat3 m, versor dest); CGLM_EXPORT void glmc_mat3_scale(mat3 m, float s); CGLM_EXPORT float glmc_mat3_det(mat3 mat); CGLM_EXPORT void glmc_mat3_inv(mat3 mat, mat3 dest); CGLM_EXPORT void glmc_mat3_swap_col(mat3 mat, int col1, int col2); CGLM_EXPORT void glmc_mat3_swap_row(mat3 mat, int row1, int row2); CGLM_EXPORT float glmc_mat3_rmc(vec3 r, mat3 m, vec3 c); CGLM_EXPORT void glmc_mat3_make(const float * __restrict src, mat3 dest); CGLM_EXPORT void glmc_mat3_textrans(float sx, float sy, float rot, float tx, float ty, mat3 dest); #ifdef __cplusplus } #endif #endif /* cglmc_mat3_h */ cglm-0.9.7/include/cglm/call/mat3x2.h000066400000000000000000000013661526744317200172410ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_mat3x2_h #define cglmc_mat3x2_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT void glmc_mat3x2_copy(mat3x2 src, mat3x2 dest); CGLM_EXPORT void glmc_mat3x2_zero(mat3x2 m); CGLM_EXPORT void glmc_mat3x2_make(const float * __restrict src, mat3x2 dest); CGLM_EXPORT void glmc_mat3x2_mul(mat3x2 m1, mat2x3 m2, mat2 dest); CGLM_EXPORT void glmc_mat3x2_mulv(mat3x2 m, vec3 v, vec2 dest); CGLM_EXPORT void glmc_mat3x2_transpose(mat3x2 src, mat2x3 dest); CGLM_EXPORT void glmc_mat3x2_scale(mat3x2 m, float s); #ifdef __cplusplus } #endif #endif /* cglmc_mat3x2_h */ cglm-0.9.7/include/cglm/call/mat3x4.h000066400000000000000000000013661526744317200172430ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_mat3x4_h #define cglmc_mat3x4_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT void glmc_mat3x4_copy(mat3x4 src, mat3x4 dest); CGLM_EXPORT void glmc_mat3x4_zero(mat3x4 m); CGLM_EXPORT void glmc_mat3x4_make(const float * __restrict src, mat3x4 dest); CGLM_EXPORT void glmc_mat3x4_mul(mat3x4 m1, mat4x3 m2, mat4 dest); CGLM_EXPORT void glmc_mat3x4_mulv(mat3x4 m, vec3 v, vec4 dest); CGLM_EXPORT void glmc_mat3x4_transpose(mat3x4 src, mat4x3 dest); CGLM_EXPORT void glmc_mat3x4_scale(mat3x4 m, float s); #ifdef __cplusplus } #endif #endif /* cglmc_mat3x4_h */ cglm-0.9.7/include/cglm/call/mat4.h000066400000000000000000000041571526744317200167710ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_mat_h #define cglmc_mat_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" /* DEPRECATED! use _copy, _ucopy versions */ #define glmc_mat4_udup(mat, dest) glmc_mat4_ucopy(mat, dest) #define glmc_mat4_dup(mat, dest) glmc_mat4_copy(mat, dest) CGLM_EXPORT void glmc_mat4_ucopy(mat4 mat, mat4 dest); CGLM_EXPORT void glmc_mat4_copy(mat4 mat, mat4 dest); CGLM_EXPORT void glmc_mat4_identity(mat4 mat); CGLM_EXPORT void glmc_mat4_identity_array(mat4 * __restrict mat, size_t count); CGLM_EXPORT void glmc_mat4_zero(mat4 mat); CGLM_EXPORT void glmc_mat4_pick3(mat4 mat, mat3 dest); CGLM_EXPORT void glmc_mat4_pick3t(mat4 mat, mat3 dest); CGLM_EXPORT void glmc_mat4_ins3(mat3 mat, mat4 dest); CGLM_EXPORT void glmc_mat4_mul(mat4 m1, mat4 m2, mat4 dest); CGLM_EXPORT void glmc_mat4_mulN(mat4 * __restrict matrices[], uint32_t len, mat4 dest); CGLM_EXPORT void glmc_mat4_mulv(mat4 m, vec4 v, vec4 dest); CGLM_EXPORT void glmc_mat4_mulv3(mat4 m, vec3 v, float last, vec3 dest); CGLM_EXPORT float glmc_mat4_trace(mat4 m); CGLM_EXPORT float glmc_mat4_trace3(mat4 m); CGLM_EXPORT void glmc_mat4_quat(mat4 m, versor dest); CGLM_EXPORT void glmc_mat4_transpose_to(mat4 m, mat4 dest); CGLM_EXPORT void glmc_mat4_transpose(mat4 m); CGLM_EXPORT void glmc_mat4_scale_p(mat4 m, float s); CGLM_EXPORT void glmc_mat4_scale(mat4 m, float s); CGLM_EXPORT float glmc_mat4_det(mat4 mat); CGLM_EXPORT void glmc_mat4_inv(mat4 mat, mat4 dest); CGLM_EXPORT void glmc_mat4_inv_precise(mat4 mat, mat4 dest); CGLM_EXPORT void glmc_mat4_inv_fast(mat4 mat, mat4 dest); CGLM_EXPORT void glmc_mat4_swap_col(mat4 mat, int col1, int col2); CGLM_EXPORT void glmc_mat4_swap_row(mat4 mat, int row1, int row2); CGLM_EXPORT float glmc_mat4_rmc(vec4 r, mat4 m, vec4 c); CGLM_EXPORT void glmc_mat4_make(const float * __restrict src, mat4 dest); CGLM_EXPORT void glmc_mat4_textrans(float sx, float sy, float rot, float tx, float ty, mat4 dest); #ifdef __cplusplus } #endif #endif /* cglmc_mat_h */ cglm-0.9.7/include/cglm/call/mat4x2.h000066400000000000000000000013661526744317200172420ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_mat4x2_h #define cglmc_mat4x2_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT void glmc_mat4x2_copy(mat4x2 src, mat4x2 dest); CGLM_EXPORT void glmc_mat4x2_zero(mat4x2 m); CGLM_EXPORT void glmc_mat4x2_make(const float * __restrict src, mat4x2 dest); CGLM_EXPORT void glmc_mat4x2_mul(mat4x2 m1, mat2x4 m2, mat2 dest); CGLM_EXPORT void glmc_mat4x2_mulv(mat4x2 m, vec4 v, vec2 dest); CGLM_EXPORT void glmc_mat4x2_transpose(mat4x2 src, mat2x4 dest); CGLM_EXPORT void glmc_mat4x2_scale(mat4x2 m, float s); #ifdef __cplusplus } #endif #endif /* cglmc_mat4x2_h */ cglm-0.9.7/include/cglm/call/mat4x3.h000066400000000000000000000013661526744317200172430ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_mat4x3_h #define cglmc_mat4x3_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT void glmc_mat4x3_copy(mat4x3 src, mat4x3 dest); CGLM_EXPORT void glmc_mat4x3_zero(mat4x3 m); CGLM_EXPORT void glmc_mat4x3_make(const float * __restrict src, mat4x3 dest); CGLM_EXPORT void glmc_mat4x3_mul(mat4x3 m1, mat3x4 m2, mat3 dest); CGLM_EXPORT void glmc_mat4x3_mulv(mat4x3 m, vec4 v, vec3 dest); CGLM_EXPORT void glmc_mat4x3_transpose(mat4x3 src, mat3x4 dest); CGLM_EXPORT void glmc_mat4x3_scale(mat4x3 m, float s); #ifdef __cplusplus } #endif #endif /* cglmc_mat4x3_h */ cglm-0.9.7/include/cglm/call/noise.h000066400000000000000000000007151526744317200172350ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_noise_h #define cglmc_noise_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT float glmc_perlin_vec4(vec4 point); CGLM_EXPORT float glmc_perlin_vec3(vec3 point); CGLM_EXPORT float glmc_perlin_vec2(vec2 point); #ifdef __cplusplus } #endif #endif /* cglmc_noise_h */ cglm-0.9.7/include/cglm/call/plane.h000066400000000000000000000005561526744317200172220ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_plane_h #define cglmc_plane_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT void glmc_plane_normalize(vec4 plane); #ifdef __cplusplus } #endif #endif /* cglmc_plane_h */ cglm-0.9.7/include/cglm/call/project.h000066400000000000000000000012401526744317200175600ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_project_h #define cglmc_project_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT void glmc_unprojecti(vec3 pos, mat4 invMat, vec4 vp, vec3 dest); CGLM_EXPORT void glmc_unproject(vec3 pos, mat4 m, vec4 vp, vec3 dest); CGLM_EXPORT void glmc_project(vec3 pos, mat4 m, vec4 vp, vec3 dest); CGLM_EXPORT float glmc_project_z(vec3 pos, mat4 m); CGLM_EXPORT void glmc_pickmatrix(vec2 center, vec2 size, vec4 vp, mat4 dest); #ifdef __cplusplus } #endif #endif /* cglmc_project_h */ cglm-0.9.7/include/cglm/call/quat.h000066400000000000000000000053671526744317200171020ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_quat_h #define cglmc_quat_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT void glmc_quat_identity(versor q); CGLM_EXPORT void glmc_quat_identity_array(versor * __restrict q, size_t count); CGLM_EXPORT void glmc_quat_init(versor q, float x, float y, float z, float w); CGLM_EXPORT void glmc_quat(versor q, float angle, float x, float y, float z); CGLM_EXPORT void glmc_quatv(versor q, float angle, vec3 axis); CGLM_EXPORT void glmc_quat_copy(versor q, versor dest); CGLM_EXPORT void glmc_quat_from_vecs(vec3 a, vec3 b, versor dest); CGLM_EXPORT float glmc_quat_norm(versor q); CGLM_EXPORT void glmc_quat_normalize_to(versor q, versor dest); CGLM_EXPORT void glmc_quat_normalize(versor q); CGLM_EXPORT float glmc_quat_dot(versor p, versor q); CGLM_EXPORT void glmc_quat_conjugate(versor q, versor dest); CGLM_EXPORT void glmc_quat_inv(versor q, versor dest); CGLM_EXPORT void glmc_quat_add(versor p, versor q, versor dest); CGLM_EXPORT void glmc_quat_sub(versor p, versor q, versor dest); CGLM_EXPORT float glmc_quat_real(versor q); CGLM_EXPORT void glmc_quat_imag(versor q, vec3 dest); CGLM_EXPORT void glmc_quat_imagn(versor q, vec3 dest); CGLM_EXPORT float glmc_quat_imaglen(versor q); CGLM_EXPORT float glmc_quat_angle(versor q); CGLM_EXPORT void glmc_quat_axis(versor q, vec3 dest); CGLM_EXPORT void glmc_quat_mul(versor p, versor q, versor dest); CGLM_EXPORT void glmc_quat_mat4(versor q, mat4 dest); CGLM_EXPORT void glmc_quat_mat4t(versor q, mat4 dest); CGLM_EXPORT void glmc_quat_mat3(versor q, mat3 dest); CGLM_EXPORT void glmc_quat_mat3t(versor q, mat3 dest); CGLM_EXPORT void glmc_quat_lerp(versor from, versor to, float t, versor dest); CGLM_EXPORT void glmc_quat_lerpc(versor from, versor to, float t, versor dest); CGLM_EXPORT void glmc_quat_nlerp(versor q, versor r, float t, versor dest); CGLM_EXPORT void glmc_quat_slerp(versor q, versor r, float t, versor dest); CGLM_EXPORT void glmc_quat_slerp_longest(versor q, versor r, float t, versor dest); CGLM_EXPORT void glmc_quat_look(vec3 eye, versor ori, mat4 dest); CGLM_EXPORT void glmc_quat_for(vec3 dir, vec3 up, versor dest); CGLM_EXPORT void glmc_quat_forp(vec3 from, vec3 to, vec3 up, versor dest); CGLM_EXPORT void glmc_quat_rotatev(versor from, vec3 to, vec3 dest); CGLM_EXPORT void glmc_quat_rotate(mat4 m, versor q, mat4 dest); CGLM_EXPORT void glmc_quat_rotate_at(mat4 model, versor q, vec3 pivot); CGLM_EXPORT void glmc_quat_rotate_atm(mat4 m, versor q, vec3 pivot); CGLM_EXPORT void glmc_quat_make(const float * __restrict src, versor dest); #ifdef __cplusplus } #endif #endif /* cglmc_quat_h */ cglm-0.9.7/include/cglm/call/ray.h000066400000000000000000000013701526744317200167110ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_ray_h #define cglmc_ray_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT bool glmc_ray_triangle(vec3 origin, vec3 direction, vec3 v0, vec3 v1, vec3 v2, float *d); CGLM_EXPORT bool glmc_ray_sphere(vec3 origin, vec3 dir, vec4 s, float * __restrict t1, float * __restrict t2); CGLM_EXPORT void glmc_ray_at(vec3 orig, vec3 dir, float t, vec3 point); #ifdef __cplusplus } #endif #endif /* cglmc_ray_h */ cglm-0.9.7/include/cglm/call/sphere.h000066400000000000000000000011421526744317200174010ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_sphere_h #define cglmc_sphere_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT float glmc_sphere_radii(vec4 s); CGLM_EXPORT void glmc_sphere_transform(vec4 s, mat4 m, vec4 dest); CGLM_EXPORT void glmc_sphere_merge(vec4 s1, vec4 s2, vec4 dest); CGLM_EXPORT bool glmc_sphere_sphere(vec4 s1, vec4 s2); CGLM_EXPORT bool glmc_sphere_point(vec4 s, vec3 point); #ifdef __cplusplus } #endif #endif /* cglmc_sphere_h */ cglm-0.9.7/include/cglm/call/vec2.h000066400000000000000000000073731526744317200167660ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_vec2_h #define cglmc_vec2_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" CGLM_EXPORT void glmc_vec2(float * __restrict v, vec2 dest); CGLM_EXPORT void glmc_vec2_fill(vec2 v, float val); CGLM_EXPORT bool glmc_vec2_eq(vec2 v, float val); CGLM_EXPORT bool glmc_vec2_eqv(vec2 a, vec2 b); CGLM_EXPORT void glmc_vec2_copy(vec2 a, vec2 dest); CGLM_EXPORT void glmc_vec2_zero(vec2 v); CGLM_EXPORT void glmc_vec2_one(vec2 v); CGLM_EXPORT float glmc_vec2_dot(vec2 a, vec2 b); CGLM_EXPORT float glmc_vec2_cross(vec2 a, vec2 b); CGLM_EXPORT float glmc_vec2_norm2(vec2 v); CGLM_EXPORT float glmc_vec2_norm(vec2 v); CGLM_EXPORT void glmc_vec2_add(vec2 a, vec2 b, vec2 dest); CGLM_EXPORT void glmc_vec2_adds(vec2 v, float s, vec2 dest); CGLM_EXPORT void glmc_vec2_sub(vec2 a, vec2 b, vec2 dest); CGLM_EXPORT void glmc_vec2_subs(vec2 v, float s, vec2 dest); CGLM_EXPORT void glmc_vec2_mul(vec2 a, vec2 b, vec2 dest); CGLM_EXPORT void glmc_vec2_scale(vec2 v, float s, vec2 dest); CGLM_EXPORT void glmc_vec2_scale_as(vec2 v, float s, vec2 dest); CGLM_EXPORT void glmc_vec2_div(vec2 a, vec2 b, vec2 dest); CGLM_EXPORT void glmc_vec2_divs(vec2 v, float s, vec2 dest); CGLM_EXPORT void glmc_vec2_addadd(vec2 a, vec2 b, vec2 dest); CGLM_EXPORT void glmc_vec2_subadd(vec2 a, vec2 b, vec2 dest); CGLM_EXPORT void glmc_vec2_muladd(vec2 a, vec2 b, vec2 dest); CGLM_EXPORT void glmc_vec2_muladds(vec2 a, float s, vec2 dest); CGLM_EXPORT void glmc_vec2_maxadd(vec2 a, vec2 b, vec2 dest); CGLM_EXPORT void glmc_vec2_minadd(vec2 a, vec2 b, vec2 dest); CGLM_EXPORT void glmc_vec2_subsub(vec2 a, vec2 b, vec2 dest); CGLM_EXPORT void glmc_vec2_addsub(vec2 a, vec2 b, vec2 dest); CGLM_EXPORT void glmc_vec2_mulsub(vec2 a, vec2 b, vec2 dest); CGLM_EXPORT void glmc_vec2_mulsubs(vec2 a, float s, vec2 dest); CGLM_EXPORT void glmc_vec2_maxsub(vec2 a, vec2 b, vec2 dest); CGLM_EXPORT void glmc_vec2_minsub(vec2 a, vec2 b, vec2 dest); CGLM_EXPORT void glmc_vec2_negate_to(vec2 v, vec2 dest); CGLM_EXPORT void glmc_vec2_negate(vec2 v); CGLM_EXPORT void glmc_vec2_normalize(vec2 v); CGLM_EXPORT void glmc_vec2_normalize_to(vec2 v, vec2 dest); CGLM_EXPORT void glmc_vec2_rotate(vec2 v, float angle, vec2 dest); CGLM_EXPORT void glmc_vec2_center(vec2 a, vec2 b, vec2 dest); CGLM_EXPORT float glmc_vec2_distance2(vec2 a, vec2 b); CGLM_EXPORT float glmc_vec2_distance(vec2 a, vec2 b); CGLM_EXPORT void glmc_vec2_maxv(vec2 a, vec2 b, vec2 dest); CGLM_EXPORT void glmc_vec2_minv(vec2 a, vec2 b, vec2 dest); CGLM_EXPORT void glmc_vec2_clamp(vec2 v, float minval, float maxval); CGLM_EXPORT void glmc_vec2_abs(vec2 v, vec2 dest); CGLM_EXPORT void glmc_vec2_fract(vec2 v, vec2 dest); CGLM_EXPORT void glmc_vec2_floor(vec2 v, vec2 dest); CGLM_EXPORT void glmc_vec2_mods(vec2 v, float s, vec2 dest); CGLM_EXPORT void glmc_vec2_swizzle(vec2 v, int mask, vec2 dest); CGLM_EXPORT void glmc_vec2_lerp(vec2 from, vec2 to, float t, vec2 dest); CGLM_EXPORT void glmc_vec2_step(vec2 edge, vec2 x, vec2 dest); CGLM_EXPORT void glmc_vec2_steps(float edge, vec2 x, vec2 dest); CGLM_EXPORT void glmc_vec2_stepr(vec2 edge, float x, vec2 dest); CGLM_EXPORT void glmc_vec2_complex_mul(vec2 a, vec2 b, vec2 dest); CGLM_EXPORT void glmc_vec2_complex_div(vec2 a, vec2 b, vec2 dest); CGLM_EXPORT void glmc_vec2_complex_conjugate(vec2 a, vec2 dest); CGLM_EXPORT void glmc_vec2_make(const float * __restrict src, vec2 dest); CGLM_EXPORT void glmc_vec2_reflect(vec2 v, vec2 n, vec2 dest); CGLM_EXPORT bool glmc_vec2_refract(vec2 v, vec2 n, float eta, vec2 dest); CGLM_EXPORT void glmc_vec2_swap(vec2 a, vec2 b); #ifdef __cplusplus } #endif #endif /* cglmc_vec2_h */ cglm-0.9.7/include/cglm/call/vec3.h000066400000000000000000000133721526744317200167630ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_vec3_h #define cglmc_vec3_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" /* DEPRECATED! use _copy, _ucopy versions */ #define glmc_vec_dup(v, dest) glmc_vec3_copy(v, dest) #define glmc_vec3_flipsign(v) glmc_vec3_negate(v) #define glmc_vec3_flipsign_to(v, dest) glmc_vec3_negate_to(v, dest) #define glmc_vec3_inv(v) glmc_vec3_negate(v) #define glmc_vec3_inv_to(v, dest) glmc_vec3_negate_to(v, dest) #define glmc_vec3_step_uni(edge, x, dest) glmc_vec3_steps(edge, x, dest); CGLM_EXPORT void glmc_vec3(vec4 v4, vec3 dest); CGLM_EXPORT void glmc_vec3_copy(vec3 a, vec3 dest); CGLM_EXPORT void glmc_vec3_zero(vec3 v); CGLM_EXPORT void glmc_vec3_one(vec3 v); CGLM_EXPORT float glmc_vec3_dot(vec3 a, vec3 b); CGLM_EXPORT void glmc_vec3_cross(vec3 a, vec3 b, vec3 dest); CGLM_EXPORT void glmc_vec3_crossn(vec3 a, vec3 b, vec3 dest); CGLM_EXPORT float glmc_vec3_norm(vec3 v); CGLM_EXPORT float glmc_vec3_norm2(vec3 v); CGLM_EXPORT float glmc_vec3_norm_one(vec3 v); CGLM_EXPORT float glmc_vec3_norm_inf(vec3 v); CGLM_EXPORT void glmc_vec3_normalize_to(vec3 v, vec3 dest); CGLM_EXPORT void glmc_vec3_normalize(vec3 v); CGLM_EXPORT void glmc_vec3_add(vec3 a, vec3 b, vec3 dest); CGLM_EXPORT void glmc_vec3_adds(vec3 v, float s, vec3 dest); CGLM_EXPORT void glmc_vec3_sub(vec3 a, vec3 b, vec3 dest); CGLM_EXPORT void glmc_vec3_subs(vec3 v, float s, vec3 dest); CGLM_EXPORT void glmc_vec3_mul(vec3 a, vec3 b, vec3 d); CGLM_EXPORT void glmc_vec3_scale(vec3 v, float s, vec3 dest); CGLM_EXPORT void glmc_vec3_scale_as(vec3 v, float s, vec3 dest); CGLM_EXPORT void glmc_vec3_div(vec3 a, vec3 b, vec3 dest); CGLM_EXPORT void glmc_vec3_divs(vec3 a, float s, vec3 dest); CGLM_EXPORT void glmc_vec3_addadd(vec3 a, vec3 b, vec3 dest); CGLM_EXPORT void glmc_vec3_subadd(vec3 a, vec3 b, vec3 dest); CGLM_EXPORT void glmc_vec3_muladd(vec3 a, vec3 b, vec3 dest); CGLM_EXPORT void glmc_vec3_muladds(vec3 a, float s, vec3 dest); CGLM_EXPORT void glmc_vec3_maxadd(vec3 a, vec3 b, vec3 dest); CGLM_EXPORT void glmc_vec3_minadd(vec3 a, vec3 b, vec3 dest); CGLM_EXPORT void glmc_vec3_subsub(vec3 a, vec3 b, vec3 dest); CGLM_EXPORT void glmc_vec3_addsub(vec3 a, vec3 b, vec3 dest); CGLM_EXPORT void glmc_vec3_mulsub(vec3 a, vec3 b, vec3 dest); CGLM_EXPORT void glmc_vec3_mulsubs(vec3 a, float s, vec3 dest); CGLM_EXPORT void glmc_vec3_maxsub(vec3 a, vec3 b, vec3 dest); CGLM_EXPORT void glmc_vec3_minsub(vec3 a, vec3 b, vec3 dest); CGLM_EXPORT void glmc_vec3_negate(vec3 v); CGLM_EXPORT void glmc_vec3_negate_to(vec3 v, vec3 dest); CGLM_EXPORT float glmc_vec3_angle(vec3 a, vec3 b); CGLM_EXPORT void glmc_vec3_rotate(vec3 v, float angle, vec3 axis); CGLM_EXPORT void glmc_vec3_rotate_m4(mat4 m, vec3 v, vec3 dest); CGLM_EXPORT void glmc_vec3_rotate_m3(mat3 m, vec3 v, vec3 dest); CGLM_EXPORT void glmc_vec3_proj(vec3 a, vec3 b, vec3 dest); CGLM_EXPORT void glmc_vec3_center(vec3 a, vec3 b, vec3 dest); CGLM_EXPORT float glmc_vec3_distance2(vec3 a, vec3 b); CGLM_EXPORT float glmc_vec3_distance(vec3 a, vec3 b); CGLM_EXPORT void glmc_vec3_maxv(vec3 a, vec3 b, vec3 dest); CGLM_EXPORT void glmc_vec3_minv(vec3 a, vec3 b, vec3 dest); CGLM_EXPORT void glmc_vec3_clamp(vec3 v, float minVal, float maxVal); CGLM_EXPORT void glmc_vec3_ortho(vec3 v, vec3 dest); CGLM_EXPORT void glmc_vec3_lerp(vec3 from, vec3 to, float t, vec3 dest); CGLM_EXPORT void glmc_vec3_lerpc(vec3 from, vec3 to, float t, vec3 dest); CGLM_INLINE void glmc_vec3_mix(vec3 from, vec3 to, float t, vec3 dest) { glmc_vec3_lerp(from, to, t, dest); } CGLM_INLINE void glmc_vec3_mixc(vec3 from, vec3 to, float t, vec3 dest) { glmc_vec3_lerpc(from, to, t, dest); } CGLM_EXPORT void glmc_vec3_step(vec3 edge, vec3 x, vec3 dest); CGLM_EXPORT void glmc_vec3_smoothstep_uni(float edge0, float edge1, vec3 x, vec3 dest); CGLM_EXPORT void glmc_vec3_smoothstep(vec3 edge0, vec3 edge1, vec3 x, vec3 dest); CGLM_EXPORT void glmc_vec3_smoothinterp(vec3 from, vec3 to, float t, vec3 dest); CGLM_EXPORT void glmc_vec3_smoothinterpc(vec3 from, vec3 to, float t, vec3 dest); CGLM_EXPORT void glmc_vec3_swizzle(vec3 v, int mask, vec3 dest); /* ext */ CGLM_EXPORT void glmc_vec3_mulv(vec3 a, vec3 b, vec3 d); CGLM_EXPORT void glmc_vec3_broadcast(float val, vec3 d); CGLM_EXPORT void glmc_vec3_fill(vec3 v, float val); CGLM_EXPORT bool glmc_vec3_eq(vec3 v, float val); CGLM_EXPORT bool glmc_vec3_eq_eps(vec3 v, float val); CGLM_EXPORT bool glmc_vec3_eq_all(vec3 v); CGLM_EXPORT bool glmc_vec3_eqv(vec3 a, vec3 b); CGLM_EXPORT bool glmc_vec3_eqv_eps(vec3 a, vec3 b); CGLM_EXPORT float glmc_vec3_max(vec3 v); CGLM_EXPORT float glmc_vec3_min(vec3 v); CGLM_EXPORT bool glmc_vec3_isnan(vec3 v); CGLM_EXPORT bool glmc_vec3_isinf(vec3 v); CGLM_EXPORT bool glmc_vec3_isvalid(vec3 v); CGLM_EXPORT void glmc_vec3_sign(vec3 v, vec3 dest); CGLM_EXPORT void glmc_vec3_abs(vec3 v, vec3 dest); CGLM_EXPORT void glmc_vec3_fract(vec3 v, vec3 dest); CGLM_EXPORT void glmc_vec3_floor(vec3 v, vec3 dest); CGLM_EXPORT void glmc_vec3_mods(vec3 v, float s, vec3 dest); CGLM_EXPORT void glmc_vec3_steps(float edge, vec3 x, vec3 dest); CGLM_EXPORT void glmc_vec3_stepr(vec3 edge, float x, vec3 dest); CGLM_EXPORT float glmc_vec3_hadd(vec3 v); CGLM_EXPORT void glmc_vec3_sqrt(vec3 v, vec3 dest); CGLM_EXPORT void glmc_vec3_make(const float * __restrict src, vec3 dest); CGLM_EXPORT void glmc_vec3_faceforward(vec3 n, vec3 v, vec3 nref, vec3 dest); CGLM_EXPORT void glmc_vec3_reflect(vec3 v, vec3 n, vec3 dest); CGLM_EXPORT bool glmc_vec3_refract(vec3 v, vec3 n, float eta, vec3 dest); CGLM_EXPORT void glmc_vec3_swap(vec3 a, vec3 b); #ifdef __cplusplus } #endif #endif /* cglmc_vec3_h */ cglm-0.9.7/include/cglm/call/vec4.h000066400000000000000000000125641526744317200167660ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglmc_vec4_h #define cglmc_vec4_h #ifdef __cplusplus extern "C" { #endif #include "../common.h" /* DEPRECATED! use _copy, _ucopy versions */ #define glmc_vec4_dup3(v, dest) glmc_vec4_copy3(v, dest) #define glmc_vec4_dup(v, dest) glmc_vec4_copy(v, dest) #define glmc_vec4_flipsign(v) glmc_vec4_negate(v) #define glmc_vec4_flipsign_to(v, dest) glmc_vec4_negate_to(v, dest) #define glmc_vec4_inv(v) glmc_vec4_negate(v) #define glmc_vec4_inv_to(v, dest) glmc_vec4_negate_to(v, dest) #define glmc_vec4_step_uni(edge, x, dest) glmc_vec4_steps(edge, x, dest) CGLM_EXPORT void glmc_vec4(vec3 v3, float last, vec4 dest); CGLM_EXPORT void glmc_vec4_zero(vec4 v); CGLM_EXPORT void glmc_vec4_one(vec4 v); CGLM_EXPORT void glmc_vec4_copy3(vec4 v, vec3 dest); CGLM_EXPORT void glmc_vec4_copy(vec4 v, vec4 dest); CGLM_EXPORT void glmc_vec4_ucopy(vec4 v, vec4 dest); CGLM_EXPORT float glmc_vec4_dot(vec4 a, vec4 b); CGLM_EXPORT float glmc_vec4_norm(vec4 v); CGLM_EXPORT float glmc_vec4_norm2(vec4 v); CGLM_EXPORT float glmc_vec4_norm_one(vec4 v); CGLM_EXPORT float glmc_vec4_norm_inf(vec4 v); CGLM_EXPORT void glmc_vec4_normalize_to(vec4 v, vec4 dest); CGLM_EXPORT void glmc_vec4_normalize(vec4 v); CGLM_EXPORT void glmc_vec4_add(vec4 a, vec4 b, vec4 dest); CGLM_EXPORT void glmc_vec4_adds(vec4 v, float s, vec4 dest); CGLM_EXPORT void glmc_vec4_sub(vec4 a, vec4 b, vec4 dest); CGLM_EXPORT void glmc_vec4_subs(vec4 v, float s, vec4 dest); CGLM_EXPORT void glmc_vec4_mul(vec4 a, vec4 b, vec4 d); CGLM_EXPORT void glmc_vec4_scale(vec4 v, float s, vec4 dest); CGLM_EXPORT void glmc_vec4_scale_as(vec4 v, float s, vec4 dest); CGLM_EXPORT void glmc_vec4_div(vec4 a, vec4 b, vec4 dest); CGLM_EXPORT void glmc_vec4_divs(vec4 v, float s, vec4 dest); CGLM_EXPORT void glmc_vec4_addadd(vec4 a, vec4 b, vec4 dest); CGLM_EXPORT void glmc_vec4_subadd(vec4 a, vec4 b, vec4 dest); CGLM_EXPORT void glmc_vec4_muladd(vec4 a, vec4 b, vec4 dest); CGLM_EXPORT void glmc_vec4_muladds(vec4 a, float s, vec4 dest); CGLM_EXPORT void glmc_vec4_maxadd(vec4 a, vec4 b, vec4 dest); CGLM_EXPORT void glmc_vec4_minadd(vec4 a, vec4 b, vec4 dest); CGLM_EXPORT void glmc_vec4_subsub(vec4 a, vec4 b, vec4 dest); CGLM_EXPORT void glmc_vec4_addsub(vec4 a, vec4 b, vec4 dest); CGLM_EXPORT void glmc_vec4_mulsub(vec4 a, vec4 b, vec4 dest); CGLM_EXPORT void glmc_vec4_mulsubs(vec4 a, float s, vec4 dest); CGLM_EXPORT void glmc_vec4_maxsub(vec4 a, vec4 b, vec4 dest); CGLM_EXPORT void glmc_vec4_minsub(vec4 a, vec4 b, vec4 dest); CGLM_EXPORT void glmc_vec4_negate(vec4 v); CGLM_EXPORT void glmc_vec4_negate_to(vec4 v, vec4 dest); CGLM_EXPORT float glmc_vec4_distance(vec4 a, vec4 b); CGLM_EXPORT float glmc_vec4_distance2(vec4 a, vec4 b); CGLM_EXPORT void glmc_vec4_maxv(vec4 a, vec4 b, vec4 dest); CGLM_EXPORT void glmc_vec4_minv(vec4 a, vec4 b, vec4 dest); CGLM_EXPORT void glmc_vec4_clamp(vec4 v, float minVal, float maxVal); CGLM_EXPORT void glmc_vec4_lerp(vec4 from, vec4 to, float t, vec4 dest); CGLM_EXPORT void glmc_vec4_lerpc(vec4 from, vec4 to, float t, vec4 dest); CGLM_INLINE void glmc_vec4_mix(vec4 from, vec4 to, float t, vec4 dest) { glmc_vec4_lerp(from, to, t, dest); } CGLM_INLINE void glmc_vec4_mixc(vec4 from, vec4 to, float t, vec4 dest) { glmc_vec4_lerpc(from, to, t, dest); } CGLM_EXPORT void glmc_vec4_step(vec4 edge, vec4 x, vec4 dest); CGLM_EXPORT void glmc_vec4_smoothstep_uni(float edge0, float edge1, vec4 x, vec4 dest); CGLM_EXPORT void glmc_vec4_smoothstep(vec4 edge0, vec4 edge1, vec4 x, vec4 dest); CGLM_EXPORT void glmc_vec4_smoothinterp(vec4 from, vec4 to, float t, vec4 dest); CGLM_EXPORT void glmc_vec4_smoothinterpc(vec4 from, vec4 to, float t, vec4 dest); CGLM_EXPORT void glmc_vec4_cubic(float s, vec4 dest); CGLM_EXPORT void glmc_vec4_swizzle(vec4 v, int mask, vec4 dest); /* ext */ CGLM_EXPORT void glmc_vec4_mulv(vec4 a, vec4 b, vec4 d); CGLM_EXPORT void glmc_vec4_broadcast(float val, vec4 d); CGLM_EXPORT void glmc_vec4_fill(vec4 v, float val); CGLM_EXPORT bool glmc_vec4_eq(vec4 v, float val); CGLM_EXPORT bool glmc_vec4_eq_eps(vec4 v, float val); CGLM_EXPORT bool glmc_vec4_eq_all(vec4 v); CGLM_EXPORT bool glmc_vec4_eqv(vec4 a, vec4 b); CGLM_EXPORT bool glmc_vec4_eqv_eps(vec4 a, vec4 b); CGLM_EXPORT float glmc_vec4_max(vec4 v); CGLM_EXPORT float glmc_vec4_min(vec4 v); CGLM_EXPORT bool glmc_vec4_isnan(vec4 v); CGLM_EXPORT bool glmc_vec4_isinf(vec4 v); CGLM_EXPORT bool glmc_vec4_isvalid(vec4 v); CGLM_EXPORT void glmc_vec4_sign(vec4 v, vec4 dest); CGLM_EXPORT void glmc_vec4_abs(vec4 v, vec4 dest); CGLM_EXPORT void glmc_vec4_fract(vec4 v, vec4 dest); CGLM_EXPORT void glmc_vec4_floor(vec4 v, vec4 dest); CGLM_EXPORT void glmc_vec4_mods(vec4 v, float s, vec4 dest); CGLM_EXPORT void glmc_vec4_steps(float edge, vec4 x, vec4 dest); CGLM_EXPORT void glmc_vec4_stepr(vec4 edge, float x, vec4 dest); CGLM_EXPORT float glmc_vec4_hadd(vec4 v); CGLM_EXPORT void glmc_vec4_sqrt(vec4 v, vec4 dest); CGLM_EXPORT void glmc_vec4_make(const float * __restrict src, vec4 dest); CGLM_EXPORT void glmc_vec4_reflect(vec4 v, vec4 n, vec4 dest); CGLM_EXPORT bool glmc_vec4_refract(vec4 v, vec4 n, float eta, vec4 dest); CGLM_EXPORT void glmc_vec4_swap(vec4 a, vec4 b); #ifdef __cplusplus } #endif #endif /* cglmc_vec4_h */ cglm-0.9.7/include/cglm/cam.h000066400000000000000000000523271526744317200157530ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glm_frustum(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) CGLM_INLINE void glm_ortho(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) CGLM_INLINE void glm_ortho_aabb(vec3 box[2], mat4 dest) CGLM_INLINE void glm_ortho_aabb_p(vec3 box[2], float padding, mat4 dest) CGLM_INLINE void glm_ortho_aabb_pz(vec3 box[2], float padding, mat4 dest) CGLM_INLINE void glm_ortho_default(float aspect, mat4 dest) CGLM_INLINE void glm_ortho_default_s(float aspect, float size, mat4 dest) CGLM_INLINE void glm_perspective(float fovy, float aspect, float nearZ, float farZ, mat4 dest) CGLM_INLINE void glm_perspective_infinite(float fovy, float aspect, float nearZ, mat4 dest) CGLM_INLINE void glm_perspective_default(float aspect, mat4 dest) CGLM_INLINE void glm_perspective_default_infinite(float aspect, mat4 dest) CGLM_INLINE void glm_perspective_resize(float aspect, mat4 proj) CGLM_INLINE void glm_lookat(vec3 eye, vec3 center, vec3 up, mat4 dest) CGLM_INLINE void glm_look(vec3 eye, vec3 dir, vec3 up, mat4 dest) CGLM_INLINE void glm_look_anyup(vec3 eye, vec3 dir, mat4 dest) CGLM_INLINE void glm_persp_decomp(mat4 proj, float *nearZ, float *farZ, float *top, float *bottom, float *left, float *right) CGLM_INLINE void glm_persp_decompv(mat4 proj, float dest[6]) CGLM_INLINE void glm_persp_decomp_x(mat4 proj, float *left, float *right) CGLM_INLINE void glm_persp_decomp_y(mat4 proj, float *top, float *bottom) CGLM_INLINE void glm_persp_decomp_z(mat4 proj, float *nearv, float *farv) CGLM_INLINE void glm_persp_decomp_far(mat4 proj, float *farZ) CGLM_INLINE void glm_persp_decomp_near(mat4 proj, float *nearZ) CGLM_INLINE float glm_persp_fovy(mat4 proj) CGLM_INLINE float glm_persp_aspect(mat4 proj) CGLM_INLINE void glm_persp_sizes(mat4 proj, float fovy, vec4 dest) */ #ifndef cglm_cam_h #define cglm_cam_h #include "common.h" #include "plane.h" #include "clipspace/persp.h" #ifndef CGLM_CLIPSPACE_INCLUDE_ALL # if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO # include "clipspace/ortho_lh_zo.h" # include "clipspace/persp_lh_zo.h" # include "clipspace/view_lh_zo.h" # elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO # include "clipspace/ortho_lh_no.h" # include "clipspace/persp_lh_no.h" # include "clipspace/view_lh_no.h" # elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO # include "clipspace/ortho_rh_zo.h" # include "clipspace/persp_rh_zo.h" # include "clipspace/view_rh_zo.h" # elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO # include "clipspace/ortho_rh_no.h" # include "clipspace/persp_rh_no.h" # include "clipspace/view_rh_no.h" # endif #else # include "clipspace/ortho_lh_zo.h" # include "clipspace/persp_lh_zo.h" # include "clipspace/ortho_lh_no.h" # include "clipspace/persp_lh_no.h" # include "clipspace/ortho_rh_zo.h" # include "clipspace/persp_rh_zo.h" # include "clipspace/ortho_rh_no.h" # include "clipspace/persp_rh_no.h" # include "clipspace/view_lh_zo.h" # include "clipspace/view_lh_no.h" # include "clipspace/view_rh_zo.h" # include "clipspace/view_rh_no.h" #endif /*! * @brief set up perspective projection matrix * * @param[in] left viewport.left * @param[in] right viewport.right * @param[in] bottom viewport.bottom * @param[in] top viewport.top * @param[in] nearZ near clipping plane * @param[in] farZ far clipping plane * @param[out] dest result matrix */ CGLM_INLINE void glm_frustum(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glm_frustum_lh_zo(left, right, bottom, top, nearZ, farZ, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glm_frustum_lh_no(left, right, bottom, top, nearZ, farZ, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glm_frustum_rh_zo(left, right, bottom, top, nearZ, farZ, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glm_frustum_rh_no(left, right, bottom, top, nearZ, farZ, dest); #endif } /*! * @brief set up orthographic projection matrix * * @param[in] left viewport.left * @param[in] right viewport.right * @param[in] bottom viewport.bottom * @param[in] top viewport.top * @param[in] nearZ near clipping plane * @param[in] farZ far clipping plane * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glm_ortho_lh_zo(left, right, bottom, top, nearZ, farZ, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glm_ortho_lh_no(left, right, bottom, top, nearZ, farZ, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glm_ortho_rh_zo(left, right, bottom, top, nearZ, farZ, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glm_ortho_rh_no(left, right, bottom, top, nearZ, farZ, dest); #endif } /*! * @brief set up orthographic projection matrix using bounding box * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_aabb(vec3 box[2], mat4 dest) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glm_ortho_aabb_lh_zo(box, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glm_ortho_aabb_lh_no(box, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glm_ortho_aabb_rh_zo(box, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glm_ortho_aabb_rh_no(box, dest); #endif } /*! * @brief set up orthographic projection matrix using bounding box * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[in] padding padding * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_aabb_p(vec3 box[2], float padding, mat4 dest) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glm_ortho_aabb_p_lh_zo(box, padding, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glm_ortho_aabb_p_lh_no(box, padding, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glm_ortho_aabb_p_rh_zo(box, padding, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glm_ortho_aabb_p_rh_no(box, padding, dest); #endif } /*! * @brief set up orthographic projection matrix using bounding box * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[in] padding padding for near and far * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_aabb_pz(vec3 box[2], float padding, mat4 dest) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glm_ortho_aabb_pz_lh_zo(box, padding, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glm_ortho_aabb_pz_lh_no(box, padding, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glm_ortho_aabb_pz_rh_zo(box, padding, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glm_ortho_aabb_pz_rh_no(box, padding, dest); #endif } /*! * @brief set up unit orthographic projection matrix * * @param[in] aspect aspect ration ( width / height ) * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_default(float aspect, mat4 dest) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glm_ortho_default_lh_zo(aspect, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glm_ortho_default_lh_no(aspect, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glm_ortho_default_rh_zo(aspect, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glm_ortho_default_rh_no(aspect, dest); #endif } /*! * @brief set up orthographic projection matrix with given CUBE size * * @param[in] aspect aspect ratio ( width / height ) * @param[in] size cube size * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_default_s(float aspect, float size, mat4 dest) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glm_ortho_default_s_lh_zo(aspect, size, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glm_ortho_default_s_lh_no(aspect, size, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glm_ortho_default_s_rh_zo(aspect, size, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glm_ortho_default_s_rh_no(aspect, size, dest); #endif } /*! * @brief set up perspective projection matrix * * @param[in] fovy field of view angle * @param[in] aspect aspect ratio ( width / height ) * @param[in] nearZ near clipping plane * @param[in] farZ far clipping planes * @param[out] dest result matrix */ CGLM_INLINE void glm_perspective(float fovy, float aspect, float nearZ, float farZ, mat4 dest) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glm_perspective_lh_zo(fovy, aspect, nearZ, farZ, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glm_perspective_lh_no(fovy, aspect, nearZ, farZ, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glm_perspective_rh_zo(fovy, aspect, nearZ, farZ, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glm_perspective_rh_no(fovy, aspect, nearZ, farZ, dest); #endif } /*! * @brief set up perspective projection matrix with infinite far plane * * @param[in] fovy field of view angle * @param[in] aspect aspect ratio ( width / height ) * @param[in] nearZ near clipping plane * @param[out] dest result matrix */ CGLM_INLINE void glm_perspective_infinite(float fovy, float aspect, float nearZ, mat4 dest) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glm_perspective_infinite_lh_zo(fovy, aspect, nearZ, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glm_perspective_infinite_lh_no(fovy, aspect, nearZ, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glm_perspective_infinite_rh_zo(fovy, aspect, nearZ, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glm_perspective_infinite_rh_no(fovy, aspect, nearZ, dest); #endif } /*! * @brief extend perspective projection matrix's far distance * * this function does not guarantee far >= near, be aware of that! * * @param[in, out] proj projection matrix to extend * @param[in] deltaFar distance from existing far (negative to shink) */ CGLM_INLINE void glm_persp_move_far(mat4 proj, float deltaFar) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glm_persp_move_far_lh_zo(proj, deltaFar); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glm_persp_move_far_lh_no(proj, deltaFar); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glm_persp_move_far_rh_zo(proj, deltaFar); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glm_persp_move_far_rh_no(proj, deltaFar); #endif } /*! * @brief set up perspective projection matrix with default near/far * and angle values * * @param[in] aspect aspect ratio ( width / height ) * @param[out] dest result matrix */ CGLM_INLINE void glm_perspective_default(float aspect, mat4 dest) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glm_perspective_default_lh_zo(aspect, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glm_perspective_default_lh_no(aspect, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glm_perspective_default_rh_zo(aspect, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glm_perspective_default_rh_no(aspect, dest); #endif } /*! * @brief set up infinite perspective projection matrix with default near * and angle values * * @param[in] aspect aspect ratio ( width / height ) * @param[out] dest result matrix */ CGLM_INLINE void glm_perspective_default_infinite(float aspect, mat4 dest) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glm_perspective_default_infinite_lh_zo(aspect, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glm_perspective_default_infinite_lh_no(aspect, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glm_perspective_default_infinite_rh_zo(aspect, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glm_perspective_default_infinite_rh_no(aspect, dest); #endif } /*! * @brief resize perspective matrix by aspect ratio ( width / height ) * this makes very easy to resize proj matrix when window /viewport * reized * * @param[in] aspect aspect ratio ( width / height ) * @param[in, out] proj perspective projection matrix */ CGLM_INLINE void glm_perspective_resize(float aspect, mat4 proj) { if (proj[0][0] == 0.0f) return; proj[0][0] = proj[1][1] / aspect; } /*! * @brief set up view matrix * * NOTE: The UP vector must not be parallel to the line of sight from * the eye point to the reference point * * @param[in] eye eye vector * @param[in] center center vector * @param[in] up up vector * @param[out] dest result matrix */ CGLM_INLINE void glm_lookat(vec3 eye, vec3 center, vec3 up, mat4 dest) { #if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_LH_BIT glm_lookat_lh(eye, center, up, dest); #elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_RH_BIT glm_lookat_rh(eye, center, up, dest); #endif } /*! * @brief set up view matrix * * convenient wrapper for lookat: if you only have direction not target self * then this might be useful. Because you need to get target from direction. * * NOTE: The UP vector must not be parallel to the line of sight from * the eye point to the reference point * * @param[in] eye eye vector * @param[in] dir direction vector * @param[in] up up vector * @param[out] dest result matrix */ CGLM_INLINE void glm_look(vec3 eye, vec3 dir, vec3 up, mat4 dest) { #if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_LH_BIT glm_look_lh(eye, dir, up, dest); #elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_RH_BIT glm_look_rh(eye, dir, up, dest); #endif } /*! * @brief set up view matrix * * convenient wrapper for look: if you only have direction and if you don't * care what UP vector is then this might be useful to create view matrix * * @param[in] eye eye vector * @param[in] dir direction vector * @param[out] dest result matrix */ CGLM_INLINE void glm_look_anyup(vec3 eye, vec3 dir, mat4 dest) { #if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_LH_BIT glm_look_anyup_lh(eye, dir, dest); #elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_RH_BIT glm_look_anyup_rh(eye, dir, dest); #endif } /*! * @brief decomposes frustum values of perspective projection. * * @param[in] proj perspective projection matrix * @param[out] nearZ near * @param[out] farZ far * @param[out] top top * @param[out] bottom bottom * @param[out] left left * @param[out] right right */ CGLM_INLINE void glm_persp_decomp(mat4 proj, float * __restrict nearZ, float * __restrict farZ, float * __restrict top, float * __restrict bottom, float * __restrict left, float * __restrict right) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glm_persp_decomp_lh_zo(proj, nearZ, farZ, top, bottom, left, right); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glm_persp_decomp_lh_no(proj, nearZ, farZ, top, bottom, left, right); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glm_persp_decomp_rh_zo(proj, nearZ, farZ, top, bottom, left, right); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glm_persp_decomp_rh_no(proj, nearZ, farZ, top, bottom, left, right); #endif } /*! * @brief decomposes frustum values of perspective projection. * this makes easy to get all values at once * * @param[in] proj perspective projection matrix * @param[out] dest array */ CGLM_INLINE void glm_persp_decompv(mat4 proj, float dest[6]) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glm_persp_decompv_lh_zo(proj, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glm_persp_decompv_lh_no(proj, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glm_persp_decompv_rh_zo(proj, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glm_persp_decompv_rh_no(proj, dest); #endif } /*! * @brief decomposes left and right values of perspective projection. * x stands for x axis (left / right axis) * * @param[in] proj perspective projection matrix * @param[out] left left * @param[out] right right */ CGLM_INLINE void glm_persp_decomp_x(mat4 proj, float * __restrict left, float * __restrict right) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glm_persp_decomp_x_lh_zo(proj, left, right); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glm_persp_decomp_x_lh_no(proj, left, right); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glm_persp_decomp_x_rh_zo(proj, left, right); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glm_persp_decomp_x_rh_no(proj, left, right); #endif } /*! * @brief decomposes top and bottom values of perspective projection. * y stands for y axis (top / bottom axis) * * @param[in] proj perspective projection matrix * @param[out] top top * @param[out] bottom bottom */ CGLM_INLINE void glm_persp_decomp_y(mat4 proj, float * __restrict top, float * __restrict bottom) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glm_persp_decomp_y_lh_zo(proj, top, bottom); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glm_persp_decomp_y_lh_no(proj, top, bottom); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glm_persp_decomp_y_rh_zo(proj, top, bottom); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glm_persp_decomp_y_rh_no(proj, top, bottom); #endif } /*! * @brief decomposes near and far values of perspective projection. * z stands for z axis (near / far axis) * * @param[in] proj perspective projection matrix * @param[out] nearZ near * @param[out] farZ far */ CGLM_INLINE void glm_persp_decomp_z(mat4 proj, float * __restrict nearZ, float * __restrict farZ) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glm_persp_decomp_z_lh_zo(proj, nearZ, farZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glm_persp_decomp_z_lh_no(proj, nearZ, farZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glm_persp_decomp_z_rh_zo(proj, nearZ, farZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glm_persp_decomp_z_rh_no(proj, nearZ, farZ); #endif } /*! * @brief decomposes far value of perspective projection. * * @param[in] proj perspective projection matrix * @param[out] farZ far */ CGLM_INLINE void glm_persp_decomp_far(mat4 proj, float * __restrict farZ) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glm_persp_decomp_far_lh_zo(proj, farZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glm_persp_decomp_far_lh_no(proj, farZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glm_persp_decomp_far_rh_zo(proj, farZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glm_persp_decomp_far_rh_no(proj, farZ); #endif } /*! * @brief decomposes near value of perspective projection. * * @param[in] proj perspective projection matrix * @param[out] nearZ near */ CGLM_INLINE void glm_persp_decomp_near(mat4 proj, float * __restrict nearZ) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glm_persp_decomp_near_lh_zo(proj, nearZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glm_persp_decomp_near_lh_no(proj, nearZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glm_persp_decomp_near_rh_zo(proj, nearZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glm_persp_decomp_near_rh_no(proj, nearZ); #endif } /*! * @brief returns sizes of near and far planes of perspective projection * * @param[in] proj perspective projection matrix * @param[in] fovy fovy (see brief) * @param[out] dest sizes order: [Wnear, Hnear, Wfar, Hfar] */ CGLM_INLINE void glm_persp_sizes(mat4 proj, float fovy, vec4 dest) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glm_persp_sizes_lh_zo(proj, fovy, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glm_persp_sizes_lh_no(proj, fovy, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glm_persp_sizes_rh_zo(proj, fovy, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glm_persp_sizes_rh_no(proj, fovy, dest); #endif } #endif /* cglm_cam_h */ cglm-0.9.7/include/cglm/cglm.h000066400000000000000000000015771526744317200161360ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_h #define cglm_h #include "common.h" #include "vec2.h" #include "vec3.h" #include "vec4.h" #include "ivec2.h" #include "ivec3.h" #include "ivec4.h" #include "mat4.h" #include "mat4x2.h" #include "mat4x3.h" #include "mat3.h" #include "mat3x2.h" #include "mat3x4.h" #include "mat2.h" #include "mat2x3.h" #include "mat2x4.h" #include "affine.h" #include "cam.h" #include "frustum.h" #include "quat.h" #include "euler.h" #include "plane.h" #include "noise.h" #include "aabb2d.h" #include "box.h" #include "color.h" #include "util.h" #include "io.h" #include "project.h" #include "sphere.h" #include "ease.h" #include "curve.h" #include "bezier.h" #include "ray.h" #include "affine2d.h" #include "affine2d-post.h" #endif /* cglm_h */ cglm-0.9.7/include/cglm/clipspace/000077500000000000000000000000001526744317200167745ustar00rootroot00000000000000cglm-0.9.7/include/cglm/clipspace/ortho_lh_no.h000066400000000000000000000122211526744317200214550ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glm_ortho_lh_no(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) CGLM_INLINE void glm_ortho_aabb_lh_no(vec3 box[2], mat4 dest) CGLM_INLINE void glm_ortho_aabb_p_lh_no(vec3 box[2], float padding, mat4 dest) CGLM_INLINE void glm_ortho_aabb_pz_lh_no(vec3 box[2], float padding, mat4 dest) CGLM_INLINE void glm_ortho_default_lh_no(float aspect, mat4 dest) CGLM_INLINE void glm_ortho_default_s_lh_no(float aspect, float size, mat4 dest) */ #ifndef cglm_ortho_lh_no_h #define cglm_ortho_lh_no_h #include "../common.h" #include "../plane.h" #include "../mat4.h" /*! * @brief set up orthographic projection matrix * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] left viewport.left * @param[in] right viewport.right * @param[in] bottom viewport.bottom * @param[in] top viewport.top * @param[in] nearZ near clipping plane * @param[in] farZ far clipping plane * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_lh_no(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) { float rl, tb, fn; glm_mat4_zero(dest); rl = 1.0f / (right - left); tb = 1.0f / (top - bottom); fn =-1.0f / (farZ - nearZ); dest[0][0] = 2.0f * rl; dest[1][1] = 2.0f * tb; dest[2][2] =-2.0f * fn; dest[3][0] =-(right + left) * rl; dest[3][1] =-(top + bottom) * tb; dest[3][2] = (farZ + nearZ) * fn; dest[3][3] = 1.0f; } /*! * @brief set up orthographic projection matrix using bounding box * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_aabb_lh_no(vec3 box[2], mat4 dest) { glm_ortho_lh_no(box[0][0], box[1][0], box[0][1], box[1][1], -box[1][2], -box[0][2], dest); } /*! * @brief set up orthographic projection matrix using bounding box * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[in] padding padding * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_aabb_p_lh_no(vec3 box[2], float padding, mat4 dest) { glm_ortho_lh_no(box[0][0] - padding, box[1][0] + padding, box[0][1] - padding, box[1][1] + padding, -(box[1][2] + padding), -(box[0][2] - padding), dest); } /*! * @brief set up orthographic projection matrix using bounding box * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[in] padding padding for near and far * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_aabb_pz_lh_no(vec3 box[2], float padding, mat4 dest) { glm_ortho_lh_no(box[0][0], box[1][0], box[0][1], box[1][1], -(box[1][2] + padding), -(box[0][2] - padding), dest); } /*! * @brief set up unit orthographic projection matrix * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] aspect aspect ration ( width / height ) * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_default_lh_no(float aspect, mat4 dest) { if (aspect >= 1.0f) { glm_ortho_lh_no(-aspect, aspect, -1.0f, 1.0f, -100.0f, 100.0f, dest); return; } aspect = 1.0f / aspect; glm_ortho_lh_no(-1.0f, 1.0f, -aspect, aspect, -100.0f, 100.0f, dest); } /*! * @brief set up orthographic projection matrix with given CUBE size * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] aspect aspect ratio ( width / height ) * @param[in] size cube size * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_default_s_lh_no(float aspect, float size, mat4 dest) { if (aspect >= 1.0f) { glm_ortho_lh_no(-size * aspect, size * aspect, -size, size, -size - 100.0f, size + 100.0f, dest); return; } glm_ortho_lh_no(-size, size, -size / aspect, size / aspect, -size - 100.0f, size + 100.0f, dest); } #endif /*cglm_ortho_lh_no_h*/ cglm-0.9.7/include/cglm/clipspace/ortho_lh_zo.h000066400000000000000000000120771526744317200215020ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glm_ortho_lh_zo(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) CGLM_INLINE void glm_ortho_aabb_lh_zo(vec3 box[2], mat4 dest) CGLM_INLINE void glm_ortho_aabb_p_lh_zo(vec3 box[2], float padding, mat4 dest) CGLM_INLINE void glm_ortho_aabb_pz_lh_zo(vec3 box[2], float padding, mat4 dest) CGLM_INLINE void glm_ortho_default_lh_zo(float aspect, mat4 dest) CGLM_INLINE void glm_ortho_default_s_lh_zo(float aspect, float size, mat4 dest) */ #ifndef cglm_ortho_lh_zo_h #define cglm_ortho_lh_zo_h #include "../common.h" #include "../plane.h" #include "../mat4.h" /*! * @brief set up orthographic projection matrix with a left-hand coordinate * system and a clip-space of [0, 1]. * * @param[in] left viewport.left * @param[in] right viewport.right * @param[in] bottom viewport.bottom * @param[in] top viewport.top * @param[in] nearZ near clipping plane * @param[in] farZ far clipping plane * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_lh_zo(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) { float rl, tb, fn; glm_mat4_zero(dest); rl = 1.0f / (right - left); tb = 1.0f / (top - bottom); fn =-1.0f / (farZ - nearZ); dest[0][0] = 2.0f * rl; dest[1][1] = 2.0f * tb; dest[2][2] =-fn; dest[3][0] =-(right + left) * rl; dest[3][1] =-(top + bottom) * tb; dest[3][2] = nearZ * fn; dest[3][3] = 1.0f; } /*! * @brief set up orthographic projection matrix using bounding box * with a left-hand coordinate system and a clip-space of [0, 1]. * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_aabb_lh_zo(vec3 box[2], mat4 dest) { glm_ortho_lh_zo(box[0][0], box[1][0], box[0][1], box[1][1], -box[1][2], -box[0][2], dest); } /*! * @brief set up orthographic projection matrix using bounding box * with a left-hand coordinate system and a clip-space of [0, 1]. * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[in] padding padding * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_aabb_p_lh_zo(vec3 box[2], float padding, mat4 dest) { glm_ortho_lh_zo(box[0][0] - padding, box[1][0] + padding, box[0][1] - padding, box[1][1] + padding, -(box[1][2] + padding), -(box[0][2] - padding), dest); } /*! * @brief set up orthographic projection matrix using bounding box * with a left-hand coordinate system and a clip-space of [0, 1]. * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[in] padding padding for near and far * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_aabb_pz_lh_zo(vec3 box[2], float padding, mat4 dest) { glm_ortho_lh_zo(box[0][0], box[1][0], box[0][1], box[1][1], -(box[1][2] + padding), -(box[0][2] - padding), dest); } /*! * @brief set up unit orthographic projection matrix * with a left-hand coordinate system and a clip-space of [0, 1]. * * @param[in] aspect aspect ration ( width / height ) * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_default_lh_zo(float aspect, mat4 dest) { if (aspect >= 1.0f) { glm_ortho_lh_zo(-aspect, aspect, -1.0f, 1.0f, -100.0f, 100.0f, dest); return; } aspect = 1.0f / aspect; glm_ortho_lh_zo(-1.0f, 1.0f, -aspect, aspect, -100.0f, 100.0f, dest); } /*! * @brief set up orthographic projection matrix with given CUBE size * with a left-hand coordinate system and a clip-space of [0, 1]. * * @param[in] aspect aspect ratio ( width / height ) * @param[in] size cube size * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_default_s_lh_zo(float aspect, float size, mat4 dest) { if (aspect >= 1.0f) { glm_ortho_lh_zo(-size * aspect, size * aspect, -size, size, -size - 100.0f, size + 100.0f, dest); return; } glm_ortho_lh_zo(-size, size, -size / aspect, size / aspect, -size - 100.0f, size + 100.0f, dest); } #endif /*cglm_ortho_lh_zo_h*/ cglm-0.9.7/include/cglm/clipspace/ortho_rh_no.h000066400000000000000000000122271526744317200214710ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glm_ortho_rh_no(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) CGLM_INLINE void glm_ortho_aabb_rh_no(vec3 box[2], mat4 dest) CGLM_INLINE void glm_ortho_aabb_p_rh_no(vec3 box[2], float padding, mat4 dest) CGLM_INLINE void glm_ortho_aabb_pz_rh_no(vec3 box[2], float padding, mat4 dest) CGLM_INLINE void glm_ortho_default_rh_no(float aspect, mat4 dest) CGLM_INLINE void glm_ortho_default_s_rh_no(float aspect, float size, mat4 dest) */ #ifndef cglm_ortho_rh_no_h #define cglm_ortho_rh_no_h #include "../common.h" #include "../plane.h" #include "../mat4.h" /*! * @brief set up orthographic projection matrix * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] left viewport.left * @param[in] right viewport.right * @param[in] bottom viewport.bottom * @param[in] top viewport.top * @param[in] nearZ near clipping plane * @param[in] farZ far clipping plane * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_rh_no(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) { float rl, tb, fn; glm_mat4_zero(dest); rl = 1.0f / (right - left); tb = 1.0f / (top - bottom); fn =-1.0f / (farZ - nearZ); dest[0][0] = 2.0f * rl; dest[1][1] = 2.0f * tb; dest[2][2] = 2.0f * fn; dest[3][0] =-(right + left) * rl; dest[3][1] =-(top + bottom) * tb; dest[3][2] = (farZ + nearZ) * fn; dest[3][3] = 1.0f; } /*! * @brief set up orthographic projection matrix using bounding box * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_aabb_rh_no(vec3 box[2], mat4 dest) { glm_ortho_rh_no(box[0][0], box[1][0], box[0][1], box[1][1], -box[1][2], -box[0][2], dest); } /*! * @brief set up orthographic projection matrix using bounding box * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[in] padding padding * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_aabb_p_rh_no(vec3 box[2], float padding, mat4 dest) { glm_ortho_rh_no(box[0][0] - padding, box[1][0] + padding, box[0][1] - padding, box[1][1] + padding, -(box[1][2] + padding), -(box[0][2] - padding), dest); } /*! * @brief set up orthographic projection matrix using bounding box * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[in] padding padding for near and far * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_aabb_pz_rh_no(vec3 box[2], float padding, mat4 dest) { glm_ortho_rh_no(box[0][0], box[1][0], box[0][1], box[1][1], -(box[1][2] + padding), -(box[0][2] - padding), dest); } /*! * @brief set up unit orthographic projection matrix * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] aspect aspect ration ( width / height ) * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_default_rh_no(float aspect, mat4 dest) { if (aspect >= 1.0f) { glm_ortho_rh_no(-aspect, aspect, -1.0f, 1.0f, -100.0f, 100.0f, dest); return; } aspect = 1.0f / aspect; glm_ortho_rh_no(-1.0f, 1.0f, -aspect, aspect, -100.0f, 100.0f, dest); } /*! * @brief set up orthographic projection matrix with given CUBE size * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] aspect aspect ratio ( width / height ) * @param[in] size cube size * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_default_s_rh_no(float aspect, float size, mat4 dest) { if (aspect >= 1.0f) { glm_ortho_rh_no(-size * aspect, size * aspect, -size, size, -size - 100.0f, size + 100.0f, dest); return; } glm_ortho_rh_no(-size, size, -size / aspect, size / aspect, -size - 100.0f, size + 100.0f, dest); } #endif /*cglm_ortho_rh_no_h*/ cglm-0.9.7/include/cglm/clipspace/ortho_rh_zo.h000066400000000000000000000123211526744317200215000ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glm_ortho_rh_zo(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) CGLM_INLINE void glm_ortho_aabb_rh_zo(vec3 box[2], mat4 dest) CGLM_INLINE void glm_ortho_aabb_p_rh_zo(vec3 box[2], float padding, mat4 dest) CGLM_INLINE void glm_ortho_aabb_pz_rh_zo(vec3 box[2], float padding, mat4 dest) CGLM_INLINE void glm_ortho_default_rh_zo(float aspect, mat4 dest) CGLM_INLINE void glm_ortho_default_s_rh_zo(float aspect, float size, mat4 dest) */ #ifndef cglm_ortho_rh_zo_h #define cglm_ortho_rh_zo_h #include "../common.h" #include "../plane.h" #include "../mat4.h" /*! * @brief set up orthographic projection matrix with a right-hand coordinate * system and a clip-space of [0, 1]. * * @param[in] left viewport.left * @param[in] right viewport.right * @param[in] bottom viewport.bottom * @param[in] top viewport.top * @param[in] nearZ near clipping plane * @param[in] farZ far clipping plane * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_rh_zo(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) { float rl, tb, fn; glm_mat4_zero(dest); rl = 1.0f / (right - left); tb = 1.0f / (top - bottom); fn =-1.0f / (farZ - nearZ); dest[0][0] = 2.0f * rl; dest[1][1] = 2.0f * tb; dest[2][2] = fn; dest[3][0] =-(right + left) * rl; dest[3][1] =-(top + bottom) * tb; dest[3][2] = nearZ * fn; dest[3][3] = 1.0f; } /*! * @brief set up orthographic projection matrix using bounding box * with a right-hand coordinate system and a clip-space with depth * values from zero to one. * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_aabb_rh_zo(vec3 box[2], mat4 dest) { glm_ortho_rh_zo(box[0][0], box[1][0], box[0][1], box[1][1], -box[1][2], -box[0][2], dest); } /*! * @brief set up orthographic projection matrix using bounding box * with a right-hand coordinate system and a clip-space with depth * values from zero to one. * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[in] padding padding * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_aabb_p_rh_zo(vec3 box[2], float padding, mat4 dest) { glm_ortho_rh_zo(box[0][0] - padding, box[1][0] + padding, box[0][1] - padding, box[1][1] + padding, -(box[1][2] + padding), -(box[0][2] - padding), dest); } /*! * @brief set up orthographic projection matrix using bounding box * with a right-hand coordinate system and a clip-space with depth * values from zero to one. * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[in] padding padding for near and far * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_aabb_pz_rh_zo(vec3 box[2], float padding, mat4 dest) { glm_ortho_rh_zo(box[0][0], box[1][0], box[0][1], box[1][1], -(box[1][2] + padding), -(box[0][2] - padding), dest); } /*! * @brief set up unit orthographic projection matrix with a right-hand * coordinate system and a clip-space of [0, 1]. * * @param[in] aspect aspect ration ( width / height ) * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_default_rh_zo(float aspect, mat4 dest) { if (aspect >= 1.0f) { glm_ortho_rh_zo(-aspect, aspect, -1.0f, 1.0f, -100.0f, 100.0f, dest); return; } aspect = 1.0f / aspect; glm_ortho_rh_zo(-1.0f, 1.0f, -aspect, aspect, -100.0f, 100.0f, dest); } /*! * @brief set up orthographic projection matrix with given CUBE size * with a right-hand coordinate system and a clip-space with depth * values from zero to one. * * @param[in] aspect aspect ratio ( width / height ) * @param[in] size cube size * @param[out] dest result matrix */ CGLM_INLINE void glm_ortho_default_s_rh_zo(float aspect, float size, mat4 dest) { if (aspect >= 1.0f) { glm_ortho_rh_zo(-size * aspect, size * aspect, -size, size, -size - 100.0f, size + 100.0f, dest); return; } glm_ortho_rh_zo(-size, size, -size / aspect, size / aspect, -size - 100.0f, size + 100.0f, dest); } #endif /*cglm_ortho_rh_zo_h*/ cglm-0.9.7/include/cglm/clipspace/persp.h000066400000000000000000000020701526744317200202750ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glm_persp_decomp_far(mat4 proj, float *farZ) CGLM_INLINE float glm_persp_fovy(mat4 proj) CGLM_INLINE float glm_persp_aspect(mat4 proj) CGLM_INLINE void glm_persp_sizes(mat4 proj, float fovy, vec4 dest) */ #ifndef cglm_persp_h #define cglm_persp_h #include "../common.h" #include "../plane.h" #include "../mat4.h" /*! * @brief returns field of view angle along the Y-axis (in radians) * * if you need to degrees, use glm_deg to convert it or use this: * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) * * @param[in] proj perspective projection matrix */ CGLM_INLINE float glm_persp_fovy(mat4 proj) { return 2.0f * atanf(1.0f / proj[1][1]); } /*! * @brief returns aspect ratio of perspective projection * * @param[in] proj perspective projection matrix */ CGLM_INLINE float glm_persp_aspect(mat4 proj) { return proj[1][1] / proj[0][0]; } #endif /* cglm_persp_h */ cglm-0.9.7/include/cglm/clipspace/persp_lh_no.h000066400000000000000000000313211526744317200214550ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glm_frustum_lh_no(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) CGLM_INLINE void glm_perspective_lh_no(float fovy, float aspect, float nearZ, float farZ, mat4 dest) CGLM_INLINE void glm_perspective_infinite_lh_no(float fovy, float aspect, float nearZ, mat4 dest) CGLM_INLINE void glm_perspective_default_lh_no(float aspect, mat4 dest) CGLM_INLINE void glm_perspective_default_infinite_lh_no(float aspect, mat4 dest) CGLM_INLINE void glm_perspective_resize_lh_no(float aspect, mat4 proj) CGLM_INLINE void glm_persp_move_far_lh_no(mat4 proj, float deltaFar) CGLM_INLINE void glm_persp_decomp_lh_no(mat4 proj, float * __restrict nearZ, float * __restrict farZ, float * __restrict top, float * __restrict bottom, float * __restrict left, float * __restrict right) CGLM_INLINE void glm_persp_decompv_lh_no(mat4 proj, float dest[6]) CGLM_INLINE void glm_persp_decomp_x_lh_no(mat4 proj, float * __restrict left, float * __restrict right) CGLM_INLINE void glm_persp_decomp_y_lh_no(mat4 proj, float * __restrict top, float * __restrict bottom) CGLM_INLINE void glm_persp_decomp_z_lh_no(mat4 proj, float * __restrict nearZ, float * __restrict farZ) CGLM_INLINE void glm_persp_decomp_far_lh_no(mat4 proj, float * __restrict farZ) CGLM_INLINE void glm_persp_decomp_near_lh_no(mat4 proj, float * __restrict nearZ) CGLM_INLINE void glm_persp_sizes_lh_no(mat4 proj, float fovy, vec4 dest) */ #ifndef cglm_persp_lh_no_h #define cglm_persp_lh_no_h #include "../common.h" #include "persp.h" /*! * @brief set up perspective peprojection matrix * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] left viewport.left * @param[in] right viewport.right * @param[in] bottom viewport.bottom * @param[in] top viewport.top * @param[in] nearZ near clipping plane * @param[in] farZ far clipping plane * @param[out] dest result matrix */ CGLM_INLINE void glm_frustum_lh_no(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) { float rl, tb, fn, nv; glm_mat4_zero(dest); rl = 1.0f / (right - left); tb = 1.0f / (top - bottom); fn =-1.0f / (farZ - nearZ); nv = 2.0f * nearZ; dest[0][0] = nv * rl; dest[1][1] = nv * tb; dest[2][0] = (right + left) * rl; dest[2][1] = (top + bottom) * tb; dest[2][2] =-(farZ + nearZ) * fn; dest[2][3] = 1.0f; dest[3][2] = farZ * nv * fn; } /*! * @brief set up perspective projection matrix * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] fovy field of view angle * @param[in] aspect aspect ratio ( width / height ) * @param[in] nearZ near clipping plane * @param[in] farZ far clipping planes * @param[out] dest result matrix */ CGLM_INLINE void glm_perspective_lh_no(float fovy, float aspect, float nearZ, float farZ, mat4 dest) { float f, fn; glm_mat4_zero(dest); f = 1.0f / tanf(fovy * 0.5f); fn = 1.0f / (nearZ - farZ); dest[0][0] = f / aspect; dest[1][1] = f; dest[2][2] =-(nearZ + farZ) * fn; dest[2][3] = 1.0f; dest[3][2] = 2.0f * nearZ * farZ * fn; } /*! * @brief set up infinite perspective projection matrix * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] fovy field of view angle * @param[in] aspect aspect ratio ( width / height ) * @param[in] nearZ near clipping plane * @param[out] dest result matrix */ CGLM_INLINE void glm_perspective_infinite_lh_no(float fovy, float aspect, float nearZ, mat4 dest) { float f; glm_mat4_zero(dest); f = 1.0f / tanf(fovy * 0.5f); dest[0][0] = f / aspect; dest[1][1] = f; dest[2][2] = 1.0f; dest[2][3] = 1.0f; dest[3][2] =-2.0f * nearZ; } /*! * @brief set up perspective projection matrix with default near/far * and angle values with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] aspect aspect ratio ( width / height ) * @param[out] dest result matrix */ CGLM_INLINE void glm_perspective_default_lh_no(float aspect, mat4 dest) { glm_perspective_lh_no(GLM_PI_4f, aspect, 0.01f, 100.0f, dest); } /*! * @brief set up infinite perspective projection matrix with default near * and angle values with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] aspect aspect ratio ( width / height ) * @param[out] dest result matrix */ CGLM_INLINE void glm_perspective_default_infinite_lh_no(float aspect, mat4 dest) { glm_perspective_infinite_lh_no(GLM_PI_4f, aspect, 0.01f, dest); } /*! * @brief resize perspective matrix by aspect ratio ( width / height ) * this makes very easy to resize proj matrix when window /viewport * resized with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] aspect aspect ratio ( width / height ) * @param[in, out] proj perspective projection matrix */ CGLM_INLINE void glm_perspective_resize_lh_no(float aspect, mat4 proj) { if (proj[0][0] == 0.0f) return; proj[0][0] = proj[1][1] / aspect; } /*! * @brief extend perspective projection matrix's far distance * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * this function does not guarantee far >= near, be aware of that! * * @param[in, out] proj projection matrix to extend * @param[in] deltaFar distance from existing far (negative to shink) */ CGLM_INLINE void glm_persp_move_far_lh_no(mat4 proj, float deltaFar) { float fn, farZ, nearZ, p22, p32; p22 = -proj[2][2]; p32 = proj[3][2]; nearZ = p32 / (p22 - 1.0f); farZ = p32 / (p22 + 1.0f) + deltaFar; fn = 1.0f / (nearZ - farZ); proj[2][2] = -(farZ + nearZ) * fn; proj[3][2] = 2.0f * nearZ * farZ * fn; } /*! * @brief decomposes frustum values of perspective projection * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] proj perspective projection matrix * @param[out] nearZ near * @param[out] farZ far * @param[out] top top * @param[out] bottom bottom * @param[out] left left * @param[out] right right */ CGLM_INLINE void glm_persp_decomp_lh_no(mat4 proj, float * __restrict nearZ, float * __restrict farZ, float * __restrict top, float * __restrict bottom, float * __restrict left, float * __restrict right) { float m00, m11, m20, m21, m22, m32, n, f; float n_m11, n_m00; m00 = proj[0][0]; m11 = proj[1][1]; m20 = proj[2][0]; m21 = proj[2][1]; m22 =-proj[2][2]; m32 = proj[3][2]; n = m32 / (m22 - 1.0f); f = m32 / (m22 + 1.0f); n_m11 = n / m11; n_m00 = n / m00; *nearZ = n; *farZ = f; *bottom = n_m11 * (m21 - 1.0f); *top = n_m11 * (m21 + 1.0f); *left = n_m00 * (m20 - 1.0f); *right = n_m00 * (m20 + 1.0f); } /*! * @brief decomposes frustum values of perspective projection * with a left-hand coordinate system and a * clip-space of [-1, 1]. * this makes easy to get all values at once * * @param[in] proj perspective projection matrix * @param[out] dest array */ CGLM_INLINE void glm_persp_decompv_lh_no(mat4 proj, float dest[6]) { glm_persp_decomp_lh_no(proj, &dest[0], &dest[1], &dest[2], &dest[3], &dest[4], &dest[5]); } /*! * @brief decomposes left and right values of perspective projection * with a left-hand coordinate system and a * clip-space of [-1, 1]. * x stands for x axis (left / right axis) * * @param[in] proj perspective projection matrix * @param[out] left left * @param[out] right right */ CGLM_INLINE void glm_persp_decomp_x_lh_no(mat4 proj, float * __restrict left, float * __restrict right) { float nearZ, m20, m00, m22; m00 = proj[0][0]; m20 = proj[2][0]; m22 =-proj[2][2]; nearZ = proj[3][2] / (m22 - 1.0f); *left = nearZ * (m20 - 1.0f) / m00; *right = nearZ * (m20 + 1.0f) / m00; } /*! * @brief decomposes top and bottom values of perspective projection * with a left-hand coordinate system and a * clip-space of [-1, 1]. * y stands for y axis (top / bottom axis) * * @param[in] proj perspective projection matrix * @param[out] top top * @param[out] bottom bottom */ CGLM_INLINE void glm_persp_decomp_y_lh_no(mat4 proj, float * __restrict top, float * __restrict bottom) { float nearZ, m21, m11, m22; m21 = proj[2][1]; m11 = proj[1][1]; m22 =-proj[2][2]; nearZ = proj[3][2] / (m22 - 1.0f); *bottom = nearZ * (m21 - 1.0f) / m11; *top = nearZ * (m21 + 1.0f) / m11; } /*! * @brief decomposes near and far values of perspective projection * with a left-hand coordinate system and a * clip-space of [-1, 1]. * z stands for z axis (near / far axis) * * @param[in] proj perspective projection matrix * @param[out] nearZ near * @param[out] farZ far */ CGLM_INLINE void glm_persp_decomp_z_lh_no(mat4 proj, float * __restrict nearZ, float * __restrict farZ) { float m32, m22; m32 = proj[3][2]; m22 =-proj[2][2]; *nearZ = m32 / (m22 - 1.0f); *farZ = m32 / (m22 + 1.0f); } /*! * @brief decomposes far value of perspective projection * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] proj perspective projection matrix * @param[out] farZ far */ CGLM_INLINE void glm_persp_decomp_far_lh_no(mat4 proj, float * __restrict farZ) { *farZ = proj[3][2] / (-proj[2][2] + 1.0f); } /*! * @brief decomposes near value of perspective projection * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] proj perspective projection matrix * @param[out] nearZ near */ CGLM_INLINE void glm_persp_decomp_near_lh_no(mat4 proj, float * __restrict nearZ) { *nearZ = proj[3][2] / (-proj[2][2] - 1.0f); } /*! * @brief returns sizes of near and far planes of perspective projection * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] proj perspective projection matrix * @param[in] fovy fovy (see brief) * @param[out] dest sizes order: [Wnear, Hnear, Wfar, Hfar] */ CGLM_INLINE void glm_persp_sizes_lh_no(mat4 proj, float fovy, vec4 dest) { float t, a, nearZ, farZ; t = 2.0f * tanf(fovy * 0.5f); a = glm_persp_aspect(proj); glm_persp_decomp_z_lh_no(proj, &nearZ, &farZ); dest[1] = t * nearZ; dest[3] = t * farZ; dest[0] = a * dest[1]; dest[2] = a * dest[3]; } /*! * @brief returns field of view angle along the Y-axis (in radians) * with a left-hand coordinate system and a clip-space of [-1, 1]. * * if you need to degrees, use glm_deg to convert it or use this: * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) * * @param[in] proj perspective projection matrix */ CGLM_INLINE float glm_persp_fovy_lh_no(mat4 proj) { return glm_persp_fovy(proj); } /*! * @brief returns aspect ratio of perspective projection * with a left-hand coordinate system and a clip-space of [-1, 1]. * * @param[in] proj perspective projection matrix */ CGLM_INLINE float glm_persp_aspect_lh_no(mat4 proj) { return glm_persp_aspect(proj); } #endif /*cglm_cam_lh_no_h*/ cglm-0.9.7/include/cglm/clipspace/persp_lh_zo.h000066400000000000000000000310071526744317200214720ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glm_frustum_lh_zo(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) CGLM_INLINE void glm_perspective_lh_zo(float fovy, float aspect, float nearZ, float farZ, mat4 dest) CGLM_INLINE void glm_perspective_infinite_lh_zo(float fovy, float aspect, float nearZ, mat4 dest) CGLM_INLINE void glm_perspective_default_lh_zo(float aspect, mat4 dest) CGLM_INLINE void glm_perspective_default_infinite_lh_zo(float aspect, mat4 dest) CGLM_INLINE void glm_perspective_resize_lh_zo(float aspect, mat4 proj) CGLM_INLINE void glm_persp_move_far_lh_zo(mat4 proj, float deltaFar) CGLM_INLINE void glm_persp_decomp_lh_zo(mat4 proj, float * __restrict nearZ, float * __restrict farZ, float * __restrict top, float * __restrict bottom, float * __restrict left, float * __restrict right) CGLM_INLINE void glm_persp_decompv_lh_zo(mat4 proj, float dest[6]) CGLM_INLINE void glm_persp_decomp_x_lh_zo(mat4 proj, float * __restrict left, float * __restrict right) CGLM_INLINE void glm_persp_decomp_y_lh_zo(mat4 proj, float * __restrict top, float * __restrict bottom) CGLM_INLINE void glm_persp_decomp_z_lh_zo(mat4 proj, float * __restrict nearZ, float * __restrict farZ) CGLM_INLINE void glm_persp_decomp_far_lh_zo(mat4 proj, float * __restrict farZ) CGLM_INLINE void glm_persp_decomp_near_lh_zo(mat4 proj, float * __restrict nearZ) CGLM_INLINE void glm_persp_sizes_lh_zo(mat4 proj, float fovy, vec4 dest) */ #ifndef cglm_persp_lh_zo_h #define cglm_persp_lh_zo_h #include "../common.h" #include "persp.h" /*! * @brief set up perspective peprojection matrix with a left-hand coordinate * system and a clip-space of [0, 1]. * * @param[in] left viewport.left * @param[in] right viewport.right * @param[in] bottom viewport.bottom * @param[in] top viewport.top * @param[in] nearZ near clipping plane * @param[in] farZ far clipping plane * @param[out] dest result matrix */ CGLM_INLINE void glm_frustum_lh_zo(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) { float rl, tb, fn, nv; glm_mat4_zero(dest); rl = 1.0f / (right - left); tb = 1.0f / (top - bottom); fn =-1.0f / (farZ - nearZ); nv = 2.0f * nearZ; dest[0][0] = nv * rl; dest[1][1] = nv * tb; dest[2][0] = (right + left) * rl; dest[2][1] = (top + bottom) * tb; dest[2][2] =-farZ * fn; dest[2][3] = 1.0f; dest[3][2] = farZ * nearZ * fn; } /*! * @brief set up perspective projection matrix with a left-hand coordinate * system and a clip-space of [0, 1]. * * @param[in] fovy field of view angle * @param[in] aspect aspect ratio ( width / height ) * @param[in] nearZ near clipping plane * @param[in] farZ far clipping planes * @param[out] dest result matrix */ CGLM_INLINE void glm_perspective_lh_zo(float fovy, float aspect, float nearZ, float farZ, mat4 dest) { float f, fn; glm_mat4_zero(dest); f = 1.0f / tanf(fovy * 0.5f); fn = 1.0f / (nearZ - farZ); dest[0][0] = f / aspect; dest[1][1] = f; dest[2][2] =-farZ * fn; dest[2][3] = 1.0f; dest[3][2] = nearZ * farZ * fn; } /*! * @brief set up infinite perspective projection matrix * with a left-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] fovy field of view angle * @param[in] aspect aspect ratio ( width / height ) * @param[in] nearZ near clipping plane * @param[out] dest result matrix */ CGLM_INLINE void glm_perspective_infinite_lh_zo(float fovy, float aspect, float nearZ, mat4 dest) { float f; glm_mat4_zero(dest); f = 1.0f / tanf(fovy * 0.5f); dest[0][0] = f / aspect; dest[1][1] = f; dest[2][2] = 1.0f; dest[2][3] = 1.0f; dest[3][2] =-nearZ; } /*! * @brief extend perspective projection matrix's far distance with a * left-hand coordinate system and a clip-space with depth values * from zero to one. * * this function does not guarantee far >= near, be aware of that! * * @param[in, out] proj projection matrix to extend * @param[in] deltaFar distance from existing far (negative to shink) */ CGLM_INLINE void glm_persp_move_far_lh_zo(mat4 proj, float deltaFar) { float fn, farZ, nearZ, p22, p32; p22 = -proj[2][2]; p32 = proj[3][2]; nearZ = p32 / p22; farZ = p32 / (p22 + 1.0f) + deltaFar; fn = 1.0f / (nearZ - farZ); proj[2][2] = -farZ * fn; proj[3][2] = nearZ * farZ * fn; } /*! * @brief set up perspective projection matrix with default near/far * and angle values with a left-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] aspect aspect ratio ( width / height ) * @param[out] dest result matrix */ CGLM_INLINE void glm_perspective_default_lh_zo(float aspect, mat4 dest) { glm_perspective_lh_zo(GLM_PI_4f, aspect, 0.01f, 100.0f, dest); } /*! * @brief set up infinite perspective projection matrix with default near * and angle values with a left-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] aspect aspect ratio ( width / height ) * @param[out] dest result matrix */ CGLM_INLINE void glm_perspective_default_infinite_lh_zo(float aspect, mat4 dest) { glm_perspective_infinite_lh_zo(GLM_PI_4f, aspect, 0.01f, dest); } /*! * @brief resize perspective matrix by aspect ratio ( width / height ) * this makes very easy to resize proj matrix when window /viewport * reized * * @param[in] aspect aspect ratio ( width / height ) * @param[in, out] proj perspective projection matrix */ CGLM_INLINE void glm_perspective_resize_lh_zo(float aspect, mat4 proj) { if (proj[0][0] == 0.0f) return; proj[0][0] = proj[1][1] / aspect; } /*! * @brief decomposes frustum values of perspective projection * with angle values with a left-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] proj perspective projection matrix * @param[out] nearZ near * @param[out] farZ far * @param[out] top top * @param[out] bottom bottom * @param[out] left left * @param[out] right right */ CGLM_INLINE void glm_persp_decomp_lh_zo(mat4 proj, float * __restrict nearZ, float * __restrict farZ, float * __restrict top, float * __restrict bottom, float * __restrict left, float * __restrict right) { float m00, m11, m20, m21, m22, m32, n, f; float n_m11, n_m00; m00 = proj[0][0]; m11 = proj[1][1]; m20 = proj[2][0]; m21 = proj[2][1]; m22 =-proj[2][2]; m32 = proj[3][2]; n = m32 / m22; f = m32 / (m22 + 1.0f); n_m11 = n / m11; n_m00 = n / m00; *nearZ = n; *farZ = f; *bottom = n_m11 * (m21 - 1.0f); *top = n_m11 * (m21 + 1.0f); *left = n_m00 * (m20 - 1.0f); *right = n_m00 * (m20 + 1.0f); } /*! * @brief decomposes frustum values of perspective projection * with angle values with a left-hand coordinate system and a * clip-space of [0, 1]. * this makes easy to get all values at once * * @param[in] proj perspective projection matrix * @param[out] dest array */ CGLM_INLINE void glm_persp_decompv_lh_zo(mat4 proj, float dest[6]) { glm_persp_decomp_lh_zo(proj, &dest[0], &dest[1], &dest[2], &dest[3], &dest[4], &dest[5]); } /*! * @brief decomposes left and right values of perspective projection (ZO). * x stands for x axis (left / right axis) * * @param[in] proj perspective projection matrix * @param[out] left left * @param[out] right right */ CGLM_INLINE void glm_persp_decomp_x_lh_zo(mat4 proj, float * __restrict left, float * __restrict right) { float nearZ, m20, m00; m00 = proj[0][0]; m20 = proj[2][0]; nearZ = proj[3][2] / (proj[3][3]); *left = nearZ * (m20 - 1.0f) / m00; *right = nearZ * (m20 + 1.0f) / m00; } /*! * @brief decomposes top and bottom values of perspective projection * with angle values with a left-hand coordinate system and a * clip-space of [0, 1]. * y stands for y axis (top / bottom axis) * * @param[in] proj perspective projection matrix * @param[out] top top * @param[out] bottom bottom */ CGLM_INLINE void glm_persp_decomp_y_lh_zo(mat4 proj, float * __restrict top, float * __restrict bottom) { float nearZ, m21, m11; m21 = proj[2][1]; m11 = proj[1][1]; nearZ = proj[3][2] / (proj[3][3]); *bottom = nearZ * (m21 - 1) / m11; *top = nearZ * (m21 + 1) / m11; } /*! * @brief decomposes near and far values of perspective projection * with angle values with a left-hand coordinate system and a * clip-space of [0, 1]. * z stands for z axis (near / far axis) * * @param[in] proj perspective projection matrix * @param[out] nearZ near * @param[out] farZ far */ CGLM_INLINE void glm_persp_decomp_z_lh_zo(mat4 proj, float * __restrict nearZ, float * __restrict farZ) { float m32, m22; m32 = proj[3][2]; m22 = -proj[2][2]; *nearZ = m32 / m22; *farZ = m32 / (m22 + 1.0f); } /*! * @brief decomposes far value of perspective projection * with angle values with a left-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] proj perspective projection matrix * @param[out] farZ far */ CGLM_INLINE void glm_persp_decomp_far_lh_zo(mat4 proj, float * __restrict farZ) { *farZ = proj[3][2] / (-proj[2][2] + 1.0f); } /*! * @brief decomposes near value of perspective projection * with angle values with a left-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] proj perspective projection matrix * @param[out] nearZ near */ CGLM_INLINE void glm_persp_decomp_near_lh_zo(mat4 proj, float * __restrict nearZ) { *nearZ = proj[3][2] / -proj[2][2]; } /*! * @brief returns sizes of near and far planes of perspective projection * with a left-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] proj perspective projection matrix * @param[in] fovy fovy (see brief) * @param[out] dest sizes order: [Wnear, Hnear, Wfar, Hfar] */ CGLM_INLINE void glm_persp_sizes_lh_zo(mat4 proj, float fovy, vec4 dest) { float t, a, nearZ, farZ; t = 2.0f * tanf(fovy * 0.5f); a = glm_persp_aspect(proj); glm_persp_decomp_z_lh_zo(proj, &nearZ, &farZ); dest[1] = t * nearZ; dest[3] = t * farZ; dest[0] = a * dest[1]; dest[2] = a * dest[3]; } /*! * @brief returns field of view angle along the Y-axis (in radians) * with a left-hand coordinate system and a clip-space of [0, 1]. * * if you need to degrees, use glm_deg to convert it or use this: * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) * * @param[in] proj perspective projection matrix */ CGLM_INLINE float glm_persp_fovy_lh_zo(mat4 proj) { return glm_persp_fovy(proj); } /*! * @brief returns aspect ratio of perspective projection * with a left-hand coordinate system and a clip-space of [0, 1]. * * @param[in] proj perspective projection matrix */ CGLM_INLINE float glm_persp_aspect_lh_zo(mat4 proj) { return glm_persp_aspect(proj); } #endif /*cglm_persp_lh_zo_h*/ cglm-0.9.7/include/cglm/clipspace/persp_rh_no.h000066400000000000000000000313271526744317200214710ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glm_frustum_rh_no(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) CGLM_INLINE void glm_perspective_rh_no(float fovy, float aspect, float nearZ, float farZ, mat4 dest) CGLM_INLINE void glm_perspective_infinite_rh_no(float fovy, float aspect, float nearZ, mat4 dest) CGLM_INLINE void glm_perspective_default_rh_no(float aspect, mat4 dest) CGLM_INLINE void glm_perspective_default_infinite_rh_no(float aspect, mat4 dest) CGLM_INLINE void glm_perspective_resize_rh_no(float aspect, mat4 proj) CGLM_INLINE void glm_persp_move_far_rh_no(mat4 proj, float deltaFar) CGLM_INLINE void glm_persp_decomp_rh_no(mat4 proj, float * __restrict nearZ, float * __restrict farZ, float * __restrict top, float * __restrict bottom, float * __restrict left, float * __restrict right) CGLM_INLINE void glm_persp_decompv_rh_no(mat4 proj, float dest[6]) CGLM_INLINE void glm_persp_decomp_x_rh_no(mat4 proj, float * __restrict left, float * __restrict right) CGLM_INLINE void glm_persp_decomp_y_rh_no(mat4 proj, float * __restrict top, float * __restrict bottom) CGLM_INLINE void glm_persp_decomp_z_rh_no(mat4 proj, float * __restrict nearZ, float * __restrict farZ) CGLM_INLINE void glm_persp_decomp_far_rh_no(mat4 proj, float * __restrict farZ) CGLM_INLINE void glm_persp_decomp_near_rh_no(mat4 proj, float * __restrict nearZ) CGLM_INLINE void glm_persp_sizes_rh_no(mat4 proj, float fovy, vec4 dest) */ #ifndef cglm_persp_rh_no_h #define cglm_persp_rh_no_h #include "../common.h" #include "persp.h" /*! * @brief set up perspective peprojection matrix * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] left viewport.left * @param[in] right viewport.right * @param[in] bottom viewport.bottom * @param[in] top viewport.top * @param[in] nearZ near clipping plane * @param[in] farZ far clipping plane * @param[out] dest result matrix */ CGLM_INLINE void glm_frustum_rh_no(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) { float rl, tb, fn, nv; glm_mat4_zero(dest); rl = 1.0f / (right - left); tb = 1.0f / (top - bottom); fn =-1.0f / (farZ - nearZ); nv = 2.0f * nearZ; dest[0][0] = nv * rl; dest[1][1] = nv * tb; dest[2][0] = (right + left) * rl; dest[2][1] = (top + bottom) * tb; dest[2][2] = (farZ + nearZ) * fn; dest[2][3] =-1.0f; dest[3][2] = farZ * nv * fn; } /*! * @brief set up perspective projection matrix * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] fovy field of view angle * @param[in] aspect aspect ratio ( width / height ) * @param[in] nearZ near clipping plane * @param[in] farZ far clipping planes * @param[out] dest result matrix */ CGLM_INLINE void glm_perspective_rh_no(float fovy, float aspect, float nearZ, float farZ, mat4 dest) { float f, fn; glm_mat4_zero(dest); f = 1.0f / tanf(fovy * 0.5f); fn = 1.0f / (nearZ - farZ); dest[0][0] = f / aspect; dest[1][1] = f; dest[2][2] = (nearZ + farZ) * fn; dest[2][3] =-1.0f; dest[3][2] = 2.0f * nearZ * farZ * fn; } /*! * @brief set up infinite perspective projection matrix * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] fovy field of view angle * @param[in] aspect aspect ratio ( width / height ) * @param[in] nearZ near clipping plane * @param[out] dest result matrix */ CGLM_INLINE void glm_perspective_infinite_rh_no(float fovy, float aspect, float nearZ, mat4 dest) { float f; glm_mat4_zero(dest); f = 1.0f / tanf(fovy * 0.5f); dest[0][0] = f / aspect; dest[1][1] = f; dest[2][2] =-1.0f; dest[2][3] =-1.0f; dest[3][2] =-2.0f * nearZ; } /*! * @brief set up perspective projection matrix with default near/far * and angle values with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] aspect aspect ratio ( width / height ) * @param[out] dest result matrix */ CGLM_INLINE void glm_perspective_default_rh_no(float aspect, mat4 dest) { glm_perspective_rh_no(GLM_PI_4f, aspect, 0.01f, 100.0f, dest); } /*! * @brief set up infinite perspective projection matrix with default near * and angle values with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] aspect aspect ratio ( width / height ) * @param[out] dest result matrix */ CGLM_INLINE void glm_perspective_default_infinite_rh_no(float aspect, mat4 dest) { glm_perspective_infinite_rh_no(GLM_PI_4f, aspect, 0.01f, dest); } /*! * @brief resize perspective matrix by aspect ratio ( width / height ) * this makes very easy to resize proj matrix when window /viewport * resized with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] aspect aspect ratio ( width / height ) * @param[in, out] proj perspective projection matrix */ CGLM_INLINE void glm_perspective_resize_rh_no(float aspect, mat4 proj) { if (proj[0][0] == 0.0f) return; proj[0][0] = proj[1][1] / aspect; } /*! * @brief extend perspective projection matrix's far distance * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * this function does not guarantee far >= near, be aware of that! * * @param[in, out] proj projection matrix to extend * @param[in] deltaFar distance from existing far (negative to shink) */ CGLM_INLINE void glm_persp_move_far_rh_no(mat4 proj, float deltaFar) { float fn, farZ, nearZ, p22, p32; p22 = proj[2][2]; p32 = proj[3][2]; nearZ = p32 / (p22 - 1.0f); farZ = p32 / (p22 + 1.0f) + deltaFar; fn = 1.0f / (nearZ - farZ); proj[2][2] = (farZ + nearZ) * fn; proj[3][2] = 2.0f * nearZ * farZ * fn; } /*! * @brief decomposes frustum values of perspective projection * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] proj perspective projection matrix * @param[out] nearZ near * @param[out] farZ far * @param[out] top top * @param[out] bottom bottom * @param[out] left left * @param[out] right right */ CGLM_INLINE void glm_persp_decomp_rh_no(mat4 proj, float * __restrict nearZ, float * __restrict farZ, float * __restrict top, float * __restrict bottom, float * __restrict left, float * __restrict right) { float m00, m11, m20, m21, m22, m32, n, f; float n_m11, n_m00; m00 = proj[0][0]; m11 = proj[1][1]; m20 = proj[2][0]; m21 = proj[2][1]; m22 = proj[2][2]; m32 = proj[3][2]; n = m32 / (m22 - 1.0f); f = m32 / (m22 + 1.0f); n_m11 = n / m11; n_m00 = n / m00; *nearZ = n; *farZ = f; *bottom = n_m11 * (m21 - 1.0f); *top = n_m11 * (m21 + 1.0f); *left = n_m00 * (m20 - 1.0f); *right = n_m00 * (m20 + 1.0f); } /*! * @brief decomposes frustum values of perspective projection * with a right-hand coordinate system and a * clip-space of [-1, 1]. * this makes easy to get all values at once * * @param[in] proj perspective projection matrix * @param[out] dest array */ CGLM_INLINE void glm_persp_decompv_rh_no(mat4 proj, float dest[6]) { glm_persp_decomp_rh_no(proj, &dest[0], &dest[1], &dest[2], &dest[3], &dest[4], &dest[5]); } /*! * @brief decomposes left and right values of perspective projection * with a right-hand coordinate system and a * clip-space of [-1, 1]. * x stands for x axis (left / right axis) * * @param[in] proj perspective projection matrix * @param[out] left left * @param[out] right right */ CGLM_INLINE void glm_persp_decomp_x_rh_no(mat4 proj, float * __restrict left, float * __restrict right) { float nearZ, m20, m00, m22; m00 = proj[0][0]; m20 = proj[2][0]; m22 = proj[2][2]; nearZ = proj[3][2] / (m22 - 1.0f); *left = nearZ * (m20 - 1.0f) / m00; *right = nearZ * (m20 + 1.0f) / m00; } /*! * @brief decomposes top and bottom values of perspective projection * with a right-hand coordinate system and a * clip-space of [-1, 1]. * y stands for y axis (top / bottom axis) * * @param[in] proj perspective projection matrix * @param[out] top top * @param[out] bottom bottom */ CGLM_INLINE void glm_persp_decomp_y_rh_no(mat4 proj, float * __restrict top, float * __restrict bottom) { float nearZ, m21, m11, m22; m21 = proj[2][1]; m11 = proj[1][1]; m22 = proj[2][2]; nearZ = proj[3][2] / (m22 - 1.0f); *bottom = nearZ * (m21 - 1.0f) / m11; *top = nearZ * (m21 + 1.0f) / m11; } /*! * @brief decomposes near and far values of perspective projection * with a right-hand coordinate system and a * clip-space of [-1, 1]. * z stands for z axis (near / far axis) * * @param[in] proj perspective projection matrix * @param[out] nearZ near * @param[out] farZ far */ CGLM_INLINE void glm_persp_decomp_z_rh_no(mat4 proj, float * __restrict nearZ, float * __restrict farZ) { float m32, m22; m32 = proj[3][2]; m22 = proj[2][2]; *nearZ = m32 / (m22 - 1.0f); *farZ = m32 / (m22 + 1.0f); } /*! * @brief decomposes far value of perspective projection * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] proj perspective projection matrix * @param[out] farZ far */ CGLM_INLINE void glm_persp_decomp_far_rh_no(mat4 proj, float * __restrict farZ) { *farZ = proj[3][2] / (proj[2][2] + 1.0f); } /*! * @brief decomposes near value of perspective projection * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] proj perspective projection matrix * @param[out] nearZ near */ CGLM_INLINE void glm_persp_decomp_near_rh_no(mat4 proj, float * __restrict nearZ) { *nearZ = proj[3][2] / (proj[2][2] - 1.0f); } /*! * @brief returns sizes of near and far planes of perspective projection * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] proj perspective projection matrix * @param[in] fovy fovy (see brief) * @param[out] dest sizes order: [Wnear, Hnear, Wfar, Hfar] */ CGLM_INLINE void glm_persp_sizes_rh_no(mat4 proj, float fovy, vec4 dest) { float t, a, nearZ, farZ; t = 2.0f * tanf(fovy * 0.5f); a = glm_persp_aspect(proj); glm_persp_decomp_z_rh_no(proj, &nearZ, &farZ); dest[1] = t * nearZ; dest[3] = t * farZ; dest[0] = a * dest[1]; dest[2] = a * dest[3]; } /*! * @brief returns field of view angle along the Y-axis (in radians) * with a right-hand coordinate system and a clip-space of [-1, 1]. * * if you need to degrees, use glm_deg to convert it or use this: * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) * * @param[in] proj perspective projection matrix */ CGLM_INLINE float glm_persp_fovy_rh_no(mat4 proj) { return glm_persp_fovy(proj); } /*! * @brief returns aspect ratio of perspective projection * with a right-hand coordinate system and a clip-space of [-1, 1]. * * @param[in] proj perspective projection matrix */ CGLM_INLINE float glm_persp_aspect_rh_no(mat4 proj) { return glm_persp_aspect(proj); } #endif /*cglm_cam_rh_no_h*/ cglm-0.9.7/include/cglm/clipspace/persp_rh_zo.h000066400000000000000000000311351526744317200215020ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glm_frustum_rh_zo(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) CGLM_INLINE void glm_perspective_rh_zo(float fovy, float aspect, float nearZ, float farZ, mat4 dest) CGLM_INLINE void glm_perspective_infinite_rh_zo(float fovy, float aspect, float nearZ, mat4 dest) CGLM_INLINE void glm_perspective_default_rh_zo(float aspect, mat4 dest) CGLM_INLINE void glm_perspective_default_infinite_rh_zo(float aspect, mat4 dest) CGLM_INLINE void glm_perspective_resize_rh_zo(float aspect, mat4 proj) CGLM_INLINE void glm_persp_move_far_rh_zo(mat4 proj, float deltaFar) CGLM_INLINE void glm_persp_decomp_rh_zo(mat4 proj, float * __restrict nearZ, float * __restrict farZ, float * __restrict top, float * __restrict bottom, float * __restrict left, float * __restrict right) CGLM_INLINE void glm_persp_decompv_rh_zo(mat4 proj, float dest[6]) CGLM_INLINE void glm_persp_decomp_x_rh_zo(mat4 proj, float * __restrict left, float * __restrict right) CGLM_INLINE void glm_persp_decomp_y_rh_zo(mat4 proj, float * __restrict top, float * __restrict bottom) CGLM_INLINE void glm_persp_decomp_z_rh_zo(mat4 proj, float * __restrict nearZ, float * __restrict farZ) CGLM_INLINE void glm_persp_decomp_far_rh_zo(mat4 proj, float * __restrict farZ) CGLM_INLINE void glm_persp_decomp_near_rh_zo(mat4 proj, float * __restrict nearZ) CGLM_INLINE void glm_persp_sizes_rh_zo(mat4 proj, float fovy, vec4 dest) */ #ifndef cglm_persp_rh_zo_h #define cglm_persp_rh_zo_h #include "../common.h" #include "persp.h" /*! * @brief set up perspective peprojection matrix with a right-hand coordinate * system and a clip-space of [0, 1]. * * @param[in] left viewport.left * @param[in] right viewport.right * @param[in] bottom viewport.bottom * @param[in] top viewport.top * @param[in] nearZ near clipping plane * @param[in] farZ far clipping plane * @param[out] dest result matrix */ CGLM_INLINE void glm_frustum_rh_zo(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) { float rl, tb, fn, nv; glm_mat4_zero(dest); rl = 1.0f / (right - left); tb = 1.0f / (top - bottom); fn =-1.0f / (farZ - nearZ); nv = 2.0f * nearZ; dest[0][0] = nv * rl; dest[1][1] = nv * tb; dest[2][0] = (right + left) * rl; dest[2][1] = (top + bottom) * tb; dest[2][2] = farZ * fn; dest[2][3] =-1.0f; dest[3][2] = farZ * nearZ * fn; } /*! * @brief set up perspective projection matrix with a right-hand coordinate * system and a clip-space of [0, 1]. * * @param[in] fovy field of view angle * @param[in] aspect aspect ratio ( width / height ) * @param[in] nearZ near clipping plane * @param[in] farZ far clipping planes * @param[out] dest result matrix */ CGLM_INLINE void glm_perspective_rh_zo(float fovy, float aspect, float nearZ, float farZ, mat4 dest) { float f, fn; glm_mat4_zero(dest); f = 1.0f / tanf(fovy * 0.5f); fn = 1.0f / (nearZ - farZ); dest[0][0] = f / aspect; dest[1][1] = f; dest[2][2] = farZ * fn; dest[2][3] =-1.0f; dest[3][2] = nearZ * farZ * fn; } /*! * @brief set up infinite perspective projection matrix * with a right-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] fovy field of view angle * @param[in] aspect aspect ratio ( width / height ) * @param[in] nearZ near clipping plane * @param[out] dest result matrix */ CGLM_INLINE void glm_perspective_infinite_rh_zo(float fovy, float aspect, float nearZ, mat4 dest) { float f; glm_mat4_zero(dest); f = 1.0f / tanf(fovy * 0.5f); dest[0][0] = f / aspect; dest[1][1] = f; dest[2][2] =-1.0f; dest[2][3] =-1.0f; dest[3][2] =-nearZ; } /*! * @brief set up perspective projection matrix with default near/far * and angle values with a right-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] aspect aspect ratio ( width / height ) * @param[out] dest result matrix */ CGLM_INLINE void glm_perspective_default_rh_zo(float aspect, mat4 dest) { glm_perspective_rh_zo(GLM_PI_4f, aspect, 0.01f, 100.0f, dest); } /*! * @brief set up infinite perspective projection matrix with default near * and angle values with a right-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] aspect aspect ratio ( width / height ) * @param[out] dest result matrix */ CGLM_INLINE void glm_perspective_default_infinite_rh_zo(float aspect, mat4 dest) { glm_perspective_infinite_rh_zo(GLM_PI_4f, aspect, 0.01f, dest); } /*! * @brief resize perspective matrix by aspect ratio ( width / height ) * this makes very easy to resize proj matrix when window /viewport * resized with a right-hand coordinate system and a clip-space of * [0, 1]. * * @param[in] aspect aspect ratio ( width / height ) * @param[in, out] proj perspective projection matrix */ CGLM_INLINE void glm_perspective_resize_rh_zo(float aspect, mat4 proj) { if (proj[0][0] == 0.0f) return; proj[0][0] = proj[1][1] / aspect; } /*! * @brief extend perspective projection matrix's far distance with a * right-hand coordinate system and a clip-space of [0, 1]. * * this function does not guarantee far >= near, be aware of that! * * @param[in, out] proj projection matrix to extend * @param[in] deltaFar distance from existing far (negative to shink) */ CGLM_INLINE void glm_persp_move_far_rh_zo(mat4 proj, float deltaFar) { float fn, farZ, nearZ, p22, p32; p22 = proj[2][2]; p32 = proj[3][2]; nearZ = p32 / p22; farZ = p32 / (p22 + 1.0f) + deltaFar; fn = 1.0f / (nearZ - farZ); proj[2][2] = farZ * fn; proj[3][2] = nearZ * farZ * fn; } /*! * @brief decomposes frustum values of perspective projection * with angle values with a right-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] proj perspective projection matrix * @param[out] nearZ near * @param[out] farZ far * @param[out] top top * @param[out] bottom bottom * @param[out] left left * @param[out] right right */ CGLM_INLINE void glm_persp_decomp_rh_zo(mat4 proj, float * __restrict nearZ, float * __restrict farZ, float * __restrict top, float * __restrict bottom, float * __restrict left, float * __restrict right) { float m00, m11, m20, m21, m22, m32, n, f; float n_m11, n_m00; m00 = proj[0][0]; m11 = proj[1][1]; m20 = proj[2][0]; m21 = proj[2][1]; m22 = proj[2][2]; m32 = proj[3][2]; n = m32 / m22; f = m32 / (m22 + 1.0f); n_m11 = n / m11; n_m00 = n / m00; *nearZ = n; *farZ = f; *bottom = n_m11 * (m21 - 1.0f); *top = n_m11 * (m21 + 1.0f); *left = n_m00 * (m20 - 1.0f); *right = n_m00 * (m20 + 1.0f); } /*! * @brief decomposes frustum values of perspective projection * with angle values with a right-hand coordinate system and a * clip-space of [0, 1]. * this makes easy to get all values at once * * @param[in] proj perspective projection matrix * @param[out] dest array */ CGLM_INLINE void glm_persp_decompv_rh_zo(mat4 proj, float dest[6]) { glm_persp_decomp_rh_zo(proj, &dest[0], &dest[1], &dest[2], &dest[3], &dest[4], &dest[5]); } /*! * @brief decomposes left and right values of perspective projection (ZO). * x stands for x axis (left / right axis) * * @param[in] proj perspective projection matrix * @param[out] left left * @param[out] right right */ CGLM_INLINE void glm_persp_decomp_x_rh_zo(mat4 proj, float * __restrict left, float * __restrict right) { float nearZ, m20, m00, m22; m00 = proj[0][0]; m20 = proj[2][0]; m22 = proj[2][2]; nearZ = proj[3][2] / m22; *left = nearZ * (m20 - 1.0f) / m00; *right = nearZ * (m20 + 1.0f) / m00; } /*! * @brief decomposes top and bottom values of perspective projection * with angle values with a right-hand coordinate system and a * clip-space of [0, 1]. * y stands for y axis (top / bottom axis) * * @param[in] proj perspective projection matrix * @param[out] top top * @param[out] bottom bottom */ CGLM_INLINE void glm_persp_decomp_y_rh_zo(mat4 proj, float * __restrict top, float * __restrict bottom) { float nearZ, m21, m11, m22; m21 = proj[2][1]; m11 = proj[1][1]; m22 = proj[2][2]; nearZ = proj[3][2] / m22; *bottom = nearZ * (m21 - 1) / m11; *top = nearZ * (m21 + 1) / m11; } /*! * @brief decomposes near and far values of perspective projection * with angle values with a right-hand coordinate system and a * clip-space of [0, 1]. * z stands for z axis (near / far axis) * * @param[in] proj perspective projection matrix * @param[out] nearZ near * @param[out] farZ far */ CGLM_INLINE void glm_persp_decomp_z_rh_zo(mat4 proj, float * __restrict nearZ, float * __restrict farZ) { float m32, m22; m32 = proj[3][2]; m22 = proj[2][2]; *nearZ = m32 / m22; *farZ = m32 / (m22 + 1.0f); } /*! * @brief decomposes far value of perspective projection * with angle values with a right-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] proj perspective projection matrix * @param[out] farZ far */ CGLM_INLINE void glm_persp_decomp_far_rh_zo(mat4 proj, float * __restrict farZ) { *farZ = proj[3][2] / (proj[2][2] + 1.0f); } /*! * @brief decomposes near value of perspective projection * with angle values with a right-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] proj perspective projection matrix * @param[out] nearZ near */ CGLM_INLINE void glm_persp_decomp_near_rh_zo(mat4 proj, float * __restrict nearZ) { *nearZ = proj[3][2] / proj[2][2]; } /*! * @brief returns sizes of near and far planes of perspective projection * with a right-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] proj perspective projection matrix * @param[in] fovy fovy (see brief) * @param[out] dest sizes order: [Wnear, Hnear, Wfar, Hfar] */ CGLM_INLINE void glm_persp_sizes_rh_zo(mat4 proj, float fovy, vec4 dest) { float t, a, nearZ, farZ; t = 2.0f * tanf(fovy * 0.5f); a = glm_persp_aspect(proj); glm_persp_decomp_z_rh_zo(proj, &nearZ, &farZ); dest[1] = t * nearZ; dest[3] = t * farZ; dest[0] = a * dest[1]; dest[2] = a * dest[3]; } /*! * @brief returns field of view angle along the Y-axis (in radians) * with a right-hand coordinate system and a clip-space of [0, 1]. * * if you need to degrees, use glm_deg to convert it or use this: * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) * * @param[in] proj perspective projection matrix */ CGLM_INLINE float glm_persp_fovy_rh_zo(mat4 proj) { return glm_persp_fovy(proj); } /*! * @brief returns aspect ratio of perspective projection * with a right-hand coordinate system and a clip-space of [0, 1]. * * @param[in] proj perspective projection matrix */ CGLM_INLINE float glm_persp_aspect_rh_zo(mat4 proj) { return glm_persp_aspect(proj); } #endif /*cglm_persp_rh_zo_h*/ cglm-0.9.7/include/cglm/clipspace/project_no.h000066400000000000000000000055011526744317200213100ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_project_no_h #define cglm_project_no_h #include "../common.h" #include "../vec3.h" #include "../vec4.h" #include "../mat4.h" /*! * @brief maps the specified viewport coordinates into specified space [1] * the matrix should contain projection matrix. * * if you don't have ( and don't want to have ) an inverse matrix then use * glm_unproject version. You may use existing inverse of matrix in somewhere * else, this is why glm_unprojecti exists to save save inversion cost * * [1] space: * 1- if m = invProj: View Space * 2- if m = invViewProj: World Space * 3- if m = invMVP: Object Space * * You probably want to map the coordinates into object space * so use invMVP as m * * Computing viewProj: * glm_mat4_mul(proj, view, viewProj); * glm_mat4_mul(viewProj, model, MVP); * glm_mat4_inv(viewProj, invMVP); * * @param[in] pos point/position in viewport coordinates * @param[in] invMat matrix (see brief) * @param[in] vp viewport as [x, y, width, height] * @param[out] dest unprojected coordinates */ CGLM_INLINE void glm_unprojecti_no(vec3 pos, mat4 invMat, vec4 vp, vec3 dest) { vec4 v; v[0] = 2.0f * (pos[0] - vp[0]) / vp[2] - 1.0f; v[1] = 2.0f * (pos[1] - vp[1]) / vp[3] - 1.0f; v[2] = 2.0f * pos[2] - 1.0f; v[3] = 1.0f; glm_mat4_mulv(invMat, v, v); glm_vec4_scale(v, 1.0f / v[3], v); glm_vec3(v, dest); } /*! * @brief map object coordinates to window coordinates * * Computing MVP: * glm_mat4_mul(proj, view, viewProj); * glm_mat4_mul(viewProj, model, MVP); * * @param[in] pos object coordinates * @param[in] m MVP matrix * @param[in] vp viewport as [x, y, width, height] * @param[out] dest projected coordinates */ CGLM_INLINE void glm_project_no(vec3 pos, mat4 m, vec4 vp, vec3 dest) { CGLM_ALIGN(16) vec4 pos4; glm_vec4(pos, 1.0f, pos4); glm_mat4_mulv(m, pos4, pos4); glm_vec4_scale(pos4, 1.0f / pos4[3], pos4); /* pos = pos / pos.w */ glm_vec4_scale(pos4, 0.5f, pos4); glm_vec4_adds(pos4, 0.5f, pos4); dest[0] = pos4[0] * vp[2] + vp[0]; dest[1] = pos4[1] * vp[3] + vp[1]; dest[2] = pos4[2]; } /*! * @brief map object's z coordinate to window coordinates * * Computing MVP: * glm_mat4_mul(proj, view, viewProj); * glm_mat4_mul(viewProj, model, MVP); * * @param[in] v object coordinates * @param[in] m MVP matrix * * @returns projected z coordinate */ CGLM_INLINE float glm_project_z_no(vec3 v, mat4 m) { float z, w; z = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2]; w = m[0][3] * v[0] + m[1][3] * v[1] + m[2][3] * v[2] + m[3][3]; return 0.5f * (z / w) + 0.5f; } #endif /* cglm_project_no_h */ cglm-0.9.7/include/cglm/clipspace/project_zo.h000066400000000000000000000054251526744317200213310ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_project_zo_h #define cglm_project_zo_h #include "../common.h" #include "../vec3.h" #include "../vec4.h" #include "../mat4.h" /*! * @brief maps the specified viewport coordinates into specified space [1] * the matrix should contain projection matrix. * * if you don't have ( and don't want to have ) an inverse matrix then use * glm_unproject version. You may use existing inverse of matrix in somewhere * else, this is why glm_unprojecti exists to save save inversion cost * * [1] space: * 1- if m = invProj: View Space * 2- if m = invViewProj: World Space * 3- if m = invMVP: Object Space * * You probably want to map the coordinates into object space * so use invMVP as m * * Computing viewProj: * glm_mat4_mul(proj, view, viewProj); * glm_mat4_mul(viewProj, model, MVP); * glm_mat4_inv(viewProj, invMVP); * * @param[in] pos point/position in viewport coordinates * @param[in] invMat matrix (see brief) * @param[in] vp viewport as [x, y, width, height] * @param[out] dest unprojected coordinates */ CGLM_INLINE void glm_unprojecti_zo(vec3 pos, mat4 invMat, vec4 vp, vec3 dest) { vec4 v; v[0] = 2.0f * (pos[0] - vp[0]) / vp[2] - 1.0f; v[1] = 2.0f * (pos[1] - vp[1]) / vp[3] - 1.0f; v[2] = pos[2]; v[3] = 1.0f; glm_mat4_mulv(invMat, v, v); glm_vec4_scale(v, 1.0f / v[3], v); glm_vec3(v, dest); } /*! * @brief map object coordinates to window coordinates * * Computing MVP: * glm_mat4_mul(proj, view, viewProj); * glm_mat4_mul(viewProj, model, MVP); * * @param[in] pos object coordinates * @param[in] m MVP matrix * @param[in] vp viewport as [x, y, width, height] * @param[out] dest projected coordinates */ CGLM_INLINE void glm_project_zo(vec3 pos, mat4 m, vec4 vp, vec3 dest) { CGLM_ALIGN(16) vec4 pos4; glm_vec4(pos, 1.0f, pos4); glm_mat4_mulv(m, pos4, pos4); glm_vec4_scale(pos4, 1.0f / pos4[3], pos4); /* pos = pos / pos.w */ dest[2] = pos4[2]; glm_vec4_scale(pos4, 0.5f, pos4); glm_vec4_adds(pos4, 0.5f, pos4); dest[0] = pos4[0] * vp[2] + vp[0]; dest[1] = pos4[1] * vp[3] + vp[1]; } /*! * @brief map object's z coordinate to window coordinates * * Computing MVP: * glm_mat4_mul(proj, view, viewProj); * glm_mat4_mul(viewProj, model, MVP); * * @param[in] v object coordinates * @param[in] m MVP matrix * * @returns projected z coordinate */ CGLM_INLINE float glm_project_z_zo(vec3 v, mat4 m) { float z, w; z = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2]; w = m[0][3] * v[0] + m[1][3] * v[1] + m[2][3] * v[2] + m[3][3]; return z / w; } #endif /* cglm_project_zo_h */ cglm-0.9.7/include/cglm/clipspace/view_lh.h000066400000000000000000000050041526744317200206010ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glm_lookat_lh(vec3 eye, vec3 center, vec3 up, mat4 dest) CGLM_INLINE void glm_look_lh(vec3 eye, vec3 dir, vec3 up, mat4 dest) CGLM_INLINE void glm_look_anyup_lh(vec3 eye, vec3 dir, mat4 dest) */ #ifndef cglm_view_lh_h #define cglm_view_lh_h #include "../common.h" #include "../plane.h" /*! * @brief set up view matrix (LH) * * NOTE: The UP vector must not be parallel to the line of sight from * the eye point to the reference point * * @param[in] eye eye vector * @param[in] center center vector * @param[in] up up vector * @param[out] dest result matrix */ CGLM_INLINE void glm_lookat_lh(vec3 eye, vec3 center, vec3 up, mat4 dest) { CGLM_ALIGN(8) vec3 f, u, s; glm_vec3_sub(center, eye, f); glm_vec3_normalize(f); glm_vec3_crossn(up, f, s); glm_vec3_cross(f, s, u); dest[0][0] = s[0]; dest[0][1] = u[0]; dest[0][2] = f[0]; dest[1][0] = s[1]; dest[1][1] = u[1]; dest[1][2] = f[1]; dest[2][0] = s[2]; dest[2][1] = u[2]; dest[2][2] = f[2]; dest[3][0] =-glm_vec3_dot(s, eye); dest[3][1] =-glm_vec3_dot(u, eye); dest[3][2] =-glm_vec3_dot(f, eye); dest[0][3] = dest[1][3] = dest[2][3] = 0.0f; dest[3][3] = 1.0f; } /*! * @brief set up view matrix with left handed coordinate system * * convenient wrapper for lookat: if you only have direction not target self * then this might be useful. Because you need to get target from direction. * * NOTE: The UP vector must not be parallel to the line of sight from * the eye point to the reference point * * @param[in] eye eye vector * @param[in] dir direction vector * @param[in] up up vector * @param[out] dest result matrix */ CGLM_INLINE void glm_look_lh(vec3 eye, vec3 dir, vec3 up, mat4 dest) { CGLM_ALIGN(8) vec3 target; glm_vec3_add(eye, dir, target); glm_lookat_lh(eye, target, up, dest); } /*! * @brief set up view matrix with left handed coordinate system * * convenient wrapper for look: if you only have direction and if you don't * care what UP vector is then this might be useful to create view matrix * * @param[in] eye eye vector * @param[in] dir direction vector * @param[out] dest result matrix */ CGLM_INLINE void glm_look_anyup_lh(vec3 eye, vec3 dir, mat4 dest) { CGLM_ALIGN(8) vec3 up; glm_vec3_ortho(dir, up); glm_look_lh(eye, dir, up, dest); } #endif /*cglm_view_lh_h*/ cglm-0.9.7/include/cglm/clipspace/view_lh_no.h000066400000000000000000000037571526744317200213120ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glm_lookat_lh_no(vec3 eye, vec3 center, vec3 up, mat4 dest) CGLM_INLINE void glm_look_lh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest) CGLM_INLINE void glm_look_anyup_lh_no(vec3 eye, vec3 dir, mat4 dest) */ #ifndef cglm_view_lh_no_h #define cglm_view_lh_no_h #include "../common.h" #include "view_lh.h" /*! * @brief set up view matrix with left handed coordinate system. * * NOTE: The UP vector must not be parallel to the line of sight from * the eye point to the reference point * * @param[in] eye eye vector * @param[in] center center vector * @param[in] up up vector * @param[out] dest result matrix */ CGLM_INLINE void glm_lookat_lh_no(vec3 eye, vec3 center, vec3 up, mat4 dest) { glm_lookat_lh(eye, center, up, dest); } /*! * @brief set up view matrix with left handed coordinate system. * * convenient wrapper for lookat: if you only have direction not target self * then this might be useful. Because you need to get target from direction. * * NOTE: The UP vector must not be parallel to the line of sight from * the eye point to the reference point * * @param[in] eye eye vector * @param[in] dir direction vector * @param[in] up up vector * @param[out] dest result matrix */ CGLM_INLINE void glm_look_lh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest) { glm_look_lh(eye, dir, up, dest); } /*! * @brief set up view matrix with left handed coordinate system. * * convenient wrapper for look: if you only have direction and if you don't * care what UP vector is then this might be useful to create view matrix * * @param[in] eye eye vector * @param[in] dir direction vector * @param[out] dest result matrix */ CGLM_INLINE void glm_look_anyup_lh_no(vec3 eye, vec3 dir, mat4 dest) { glm_look_anyup_lh(eye, dir, dest); } #endif /*cglm_view_lh_no_h*/ cglm-0.9.7/include/cglm/clipspace/view_lh_zo.h000066400000000000000000000037571526744317200213260ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glm_lookat_lh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest) CGLM_INLINE void glm_look_lh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest) CGLM_INLINE void glm_look_anyup_lh_zo(vec3 eye, vec3 dir, mat4 dest) */ #ifndef cglm_view_lh_zo_h #define cglm_view_lh_zo_h #include "../common.h" #include "view_lh.h" /*! * @brief set up view matrix with left handed coordinate system. * * NOTE: The UP vector must not be parallel to the line of sight from * the eye point to the reference point * * @param[in] eye eye vector * @param[in] center center vector * @param[in] up up vector * @param[out] dest result matrix */ CGLM_INLINE void glm_lookat_lh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest) { glm_lookat_lh(eye, center, up, dest); } /*! * @brief set up view matrix with left handed coordinate system. * * convenient wrapper for lookat: if you only have direction not target self * then this might be useful. Because you need to get target from direction. * * NOTE: The UP vector must not be parallel to the line of sight from * the eye point to the reference point * * @param[in] eye eye vector * @param[in] dir direction vector * @param[in] up up vector * @param[out] dest result matrix */ CGLM_INLINE void glm_look_lh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest) { glm_look_lh(eye, dir, up, dest); } /*! * @brief set up view matrix with left handed coordinate system. * * convenient wrapper for look: if you only have direction and if you don't * care what UP vector is then this might be useful to create view matrix * * @param[in] eye eye vector * @param[in] dir direction vector * @param[out] dest result matrix */ CGLM_INLINE void glm_look_anyup_lh_zo(vec3 eye, vec3 dir, mat4 dest) { glm_look_anyup_lh(eye, dir, dest); } #endif /*cglm_view_lh_zo_h*/ cglm-0.9.7/include/cglm/clipspace/view_rh.h000066400000000000000000000050501526744317200206100ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glm_lookat_rh(vec3 eye, vec3 center, vec3 up, mat4 dest) CGLM_INLINE void glm_look_rh(vec3 eye, vec3 dir, vec3 up, mat4 dest) CGLM_INLINE void glm_look_anyup_rh(vec3 eye, vec3 dir, mat4 dest) */ #ifndef cglm_view_rh_h #define cglm_view_rh_h #include "../common.h" #include "../plane.h" /*! * @brief set up view matrix with right handed coordinate system. * * NOTE: The UP vector must not be parallel to the line of sight from * the eye point to the reference point * * @param[in] eye eye vector * @param[in] center center vector * @param[in] up up vector * @param[out] dest result matrix */ CGLM_INLINE void glm_lookat_rh(vec3 eye, vec3 center, vec3 up, mat4 dest) { CGLM_ALIGN(8) vec3 f, u, s; glm_vec3_sub(center, eye, f); glm_vec3_normalize(f); glm_vec3_crossn(f, up, s); glm_vec3_cross(s, f, u); dest[0][0] = s[0]; dest[0][1] = u[0]; dest[0][2] =-f[0]; dest[1][0] = s[1]; dest[1][1] = u[1]; dest[1][2] =-f[1]; dest[2][0] = s[2]; dest[2][1] = u[2]; dest[2][2] =-f[2]; dest[3][0] =-glm_vec3_dot(s, eye); dest[3][1] =-glm_vec3_dot(u, eye); dest[3][2] = glm_vec3_dot(f, eye); dest[0][3] = dest[1][3] = dest[2][3] = 0.0f; dest[3][3] = 1.0f; } /*! * @brief set up view matrix with right handed coordinate system. * * convenient wrapper for lookat: if you only have direction not target self * then this might be useful. Because you need to get target from direction. * * NOTE: The UP vector must not be parallel to the line of sight from * the eye point to the reference point * * @param[in] eye eye vector * @param[in] dir direction vector * @param[in] up up vector * @param[out] dest result matrix */ CGLM_INLINE void glm_look_rh(vec3 eye, vec3 dir, vec3 up, mat4 dest) { CGLM_ALIGN(8) vec3 target; glm_vec3_add(eye, dir, target); glm_lookat_rh(eye, target, up, dest); } /*! * @brief set up view matrix with right handed coordinate system. * * convenient wrapper for look: if you only have direction and if you don't * care what UP vector is then this might be useful to create view matrix * * @param[in] eye eye vector * @param[in] dir direction vector * @param[out] dest result matrix */ CGLM_INLINE void glm_look_anyup_rh(vec3 eye, vec3 dir, mat4 dest) { CGLM_ALIGN(8) vec3 up; glm_vec3_ortho(dir, up); glm_look_rh(eye, dir, up, dest); } #endif /*cglm_view_rh_h*/ cglm-0.9.7/include/cglm/clipspace/view_rh_no.h000066400000000000000000000037621526744317200213140ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glm_lookat_rh_no(vec3 eye, vec3 center, vec3 up, mat4 dest) CGLM_INLINE void glm_look_rh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest) CGLM_INLINE void glm_look_anyup_rh_no(vec3 eye, vec3 dir, mat4 dest) */ #ifndef cglm_view_rh_no_h #define cglm_view_rh_no_h #include "../common.h" #include "view_rh.h" /*! * @brief set up view matrix with right handed coordinate system. * * NOTE: The UP vector must not be parallel to the line of sight from * the eye point to the reference point * * @param[in] eye eye vector * @param[in] center center vector * @param[in] up up vector * @param[out] dest result matrix */ CGLM_INLINE void glm_lookat_rh_no(vec3 eye, vec3 center, vec3 up, mat4 dest) { glm_lookat_rh(eye, center, up, dest); } /*! * @brief set up view matrix with right handed coordinate system. * * convenient wrapper for lookat: if you only have direction not target self * then this might be useful. Because you need to get target from direction. * * NOTE: The UP vector must not be parallel to the line of sight from * the eye point to the reference point * * @param[in] eye eye vector * @param[in] dir direction vector * @param[in] up up vector * @param[out] dest result matrix */ CGLM_INLINE void glm_look_rh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest) { glm_look_rh(eye, dir, up, dest); } /*! * @brief set up view matrix with right handed coordinate system. * * convenient wrapper for look: if you only have direction and if you don't * care what UP vector is then this might be useful to create view matrix * * @param[in] eye eye vector * @param[in] dir direction vector * @param[out] dest result matrix */ CGLM_INLINE void glm_look_anyup_rh_no(vec3 eye, vec3 dir, mat4 dest) { glm_look_anyup_rh(eye, dir, dest); } #endif /*cglm_view_rh_no_h*/ cglm-0.9.7/include/cglm/clipspace/view_rh_zo.h000066400000000000000000000037621526744317200213300ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glm_lookat_rh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest) CGLM_INLINE void glm_look_rh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest) CGLM_INLINE void glm_look_anyup_rh_zo(vec3 eye, vec3 dir, mat4 dest) */ #ifndef cglm_view_rh_zo_h #define cglm_view_rh_zo_h #include "../common.h" #include "view_rh.h" /*! * @brief set up view matrix with right handed coordinate system. * * NOTE: The UP vector must not be parallel to the line of sight from * the eye point to the reference point * * @param[in] eye eye vector * @param[in] center center vector * @param[in] up up vector * @param[out] dest result matrix */ CGLM_INLINE void glm_lookat_rh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest) { glm_lookat_rh(eye, center, up, dest); } /*! * @brief set up view matrix with right handed coordinate system. * * convenient wrapper for lookat: if you only have direction not target self * then this might be useful. Because you need to get target from direction. * * NOTE: The UP vector must not be parallel to the line of sight from * the eye point to the reference point * * @param[in] eye eye vector * @param[in] dir direction vector * @param[in] up up vector * @param[out] dest result matrix */ CGLM_INLINE void glm_look_rh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest) { glm_look_rh(eye, dir, up, dest); } /*! * @brief set up view matrix with right handed coordinate system. * * convenient wrapper for look: if you only have direction and if you don't * care what UP vector is then this might be useful to create view matrix * * @param[in] eye eye vector * @param[in] dir direction vector * @param[out] dest result matrix */ CGLM_INLINE void glm_look_anyup_rh_zo(vec3 eye, vec3 dir, mat4 dest) { glm_look_anyup_rh(eye, dir, dest); } #endif /*cglm_view_rh_zo_h*/ cglm-0.9.7/include/cglm/color.h000066400000000000000000000007271526744317200163260ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_color_h #define cglm_color_h #include "common.h" #include "vec3.h" /*! * @brief averages the color channels into one value * * @param[in] rgb RGB color */ CGLM_INLINE float glm_luminance(vec3 rgb) { vec3 l = {0.212671f, 0.715160f, 0.072169f}; return glm_dot(rgb, l); } #endif /* cglm_color_h */ cglm-0.9.7/include/cglm/common.h000066400000000000000000000100441526744317200164710ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_common_h #define cglm_common_h #define __cglm__ 1 #ifndef _USE_MATH_DEFINES # define _USE_MATH_DEFINES /* for windows */ #endif #ifndef _CRT_SECURE_NO_WARNINGS # define _CRT_SECURE_NO_WARNINGS /* for windows */ #endif #include #include #include #include #include #include #if defined(_MSC_VER) # ifdef CGLM_STATIC # define CGLM_EXPORT # elif defined(CGLM_EXPORTS) # define CGLM_EXPORT __declspec(dllexport) # else # define CGLM_EXPORT __declspec(dllimport) # endif # define CGLM_INLINE __forceinline #else # define CGLM_EXPORT __attribute__((visibility("default"))) # define CGLM_INLINE static inline __attribute((always_inline)) #endif #if defined(__GNUC__) || defined(__clang__) # define CGLM_UNLIKELY(expr) __builtin_expect(!!(expr), 0) # define CGLM_LIKELY(expr) __builtin_expect(!!(expr), 1) #else # define CGLM_UNLIKELY(expr) (expr) # define CGLM_LIKELY(expr) (expr) #endif #if defined(_M_FP_FAST) || defined(__FAST_MATH__) # define CGLM_FAST_MATH #endif #define GLM_SHUFFLE4(z, y, x, w) (((z) << 6) | ((y) << 4) | ((x) << 2) | (w)) #define GLM_SHUFFLE3(z, y, x) (((z) << 4) | ((y) << 2) | (x)) #define GLM_SHUFFLE2(y, x) (((y) << 2) | (x)) #include "types.h" #include "simd/intrin.h" #ifndef CGLM_USE_DEFAULT_EPSILON # ifndef GLM_FLT_EPSILON # define GLM_FLT_EPSILON 1e-5f # endif #else # define GLM_FLT_EPSILON FLT_EPSILON #endif /* * Clip control: define CGLM_FORCE_DEPTH_ZERO_TO_ONE before including * CGLM to use a clip space between 0 to 1. * Coordinate system: define CGLM_FORCE_LEFT_HANDED before including * CGLM to use the left handed coordinate system by default. */ #define CGLM_CLIP_CONTROL_ZO_BIT (1 << 0) /* ZERO_TO_ONE */ #define CGLM_CLIP_CONTROL_NO_BIT (1 << 1) /* NEGATIVE_ONE_TO_ONE */ #define CGLM_CLIP_CONTROL_LH_BIT (1 << 2) /* LEFT_HANDED, For DirectX, Metal, Vulkan */ #define CGLM_CLIP_CONTROL_RH_BIT (1 << 3) /* RIGHT_HANDED, For OpenGL, default in GLM */ #define CGLM_CLIP_CONTROL_LH_ZO (CGLM_CLIP_CONTROL_LH_BIT | CGLM_CLIP_CONTROL_ZO_BIT) #define CGLM_CLIP_CONTROL_LH_NO (CGLM_CLIP_CONTROL_LH_BIT | CGLM_CLIP_CONTROL_NO_BIT) #define CGLM_CLIP_CONTROL_RH_ZO (CGLM_CLIP_CONTROL_RH_BIT | CGLM_CLIP_CONTROL_ZO_BIT) #define CGLM_CLIP_CONTROL_RH_NO (CGLM_CLIP_CONTROL_RH_BIT | CGLM_CLIP_CONTROL_NO_BIT) #ifdef CGLM_FORCE_DEPTH_ZERO_TO_ONE # ifdef CGLM_FORCE_LEFT_HANDED # define CGLM_CONFIG_CLIP_CONTROL CGLM_CLIP_CONTROL_LH_ZO # else # define CGLM_CONFIG_CLIP_CONTROL CGLM_CLIP_CONTROL_RH_ZO # endif #else # ifdef CGLM_FORCE_LEFT_HANDED # define CGLM_CONFIG_CLIP_CONTROL CGLM_CLIP_CONTROL_LH_NO # else # define CGLM_CONFIG_CLIP_CONTROL CGLM_CLIP_CONTROL_RH_NO # endif #endif /* struct API configurator */ /* TODO: move struct/common.h? */ /* WARN: dont use concant helpers outside cglm headers, because they may be changed */ #define CGLM_MACRO_CONCAT_HELPER(A, B, C, D, E, ...) A ## B ## C ## D ## E ## __VA_ARGS__ #define CGLM_MACRO_CONCAT(A, B, C, D, E, ...) CGLM_MACRO_CONCAT_HELPER(A, B, C, D, E,__VA_ARGS__) #ifndef CGLM_OMIT_NS_FROM_STRUCT_API # ifndef CGLM_STRUCT_API_NS # define CGLM_STRUCT_API_NS glms # endif # ifndef CGLM_STRUCT_API_NS_SEPERATOR # define CGLM_STRUCT_API_NS_SEPERATOR _ # endif #else # define CGLM_STRUCT_API_NS # define CGLM_STRUCT_API_NS_SEPERATOR #endif #ifndef CGLM_STRUCT_API_NAME_SUFFIX # define CGLM_STRUCT_API_NAME_SUFFIX #endif #define CGLM_STRUCTAPI(A, ...) CGLM_MACRO_CONCAT(CGLM_STRUCT_API_NS, \ CGLM_STRUCT_API_NS_SEPERATOR, \ A, \ CGLM_STRUCT_API_NAME_SUFFIX, \ _, \ __VA_ARGS__) #endif /* cglm_common_h */ cglm-0.9.7/include/cglm/curve.h000066400000000000000000000016221526744317200163270ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_curve_h #define cglm_curve_h #include "common.h" #include "vec4.h" #include "mat4.h" /*! * @brief helper function to calculate S*M*C multiplication for curves * * This function does not encourage you to use SMC, * instead it is a helper if you use SMC. * * if you want to specify S as vector then use more generic glm_mat4_rmc() func. * * Example usage: * B(s) = glm_smc(s, GLM_BEZIER_MAT, (vec4){p0, c0, c1, p1}) * * @param[in] s parameter between 0 and 1 (this will be [s3, s2, s, 1]) * @param[in] m basis matrix * @param[in] c position/control vector * * @return B(s) */ CGLM_INLINE float glm_smc(float s, mat4 m, vec4 c) { vec4 vs; glm_vec4_cubic(s, vs); return glm_mat4_rmc(vs, m, c); } #endif /* cglm_curve_h */ cglm-0.9.7/include/cglm/ease.h000066400000000000000000000112401526744317200161150ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_ease_h #define cglm_ease_h #include "common.h" CGLM_INLINE float glm_ease_linear(float t) { return t; } CGLM_INLINE float glm_ease_sine_in(float t) { return sinf((t - 1.0f) * GLM_PI_2f) + 1.0f; } CGLM_INLINE float glm_ease_sine_out(float t) { return sinf(t * GLM_PI_2f); } CGLM_INLINE float glm_ease_sine_inout(float t) { return 0.5f * (1.0f - cosf(t * GLM_PIf)); } CGLM_INLINE float glm_ease_quad_in(float t) { return t * t; } CGLM_INLINE float glm_ease_quad_out(float t) { return -(t * (t - 2.0f)); } CGLM_INLINE float glm_ease_quad_inout(float t) { float tt; tt = t * t; if (t < 0.5f) return 2.0f * tt; return (-2.0f * tt) + (4.0f * t) - 1.0f; } CGLM_INLINE float glm_ease_cubic_in(float t) { return t * t * t; } CGLM_INLINE float glm_ease_cubic_out(float t) { float f; f = t - 1.0f; return f * f * f + 1.0f; } CGLM_INLINE float glm_ease_cubic_inout(float t) { float f; if (t < 0.5f) return 4.0f * t * t * t; f = 2.0f * t - 2.0f; return 0.5f * f * f * f + 1.0f; } CGLM_INLINE float glm_ease_quart_in(float t) { float f; f = t * t; return f * f; } CGLM_INLINE float glm_ease_quart_out(float t) { float f; f = t - 1.0f; return f * f * f * (1.0f - t) + 1.0f; } CGLM_INLINE float glm_ease_quart_inout(float t) { float f, g; if (t < 0.5f) { f = t * t; return 8.0f * f * f; } f = t - 1.0f; g = f * f; return -8.0f * g * g + 1.0f; } CGLM_INLINE float glm_ease_quint_in(float t) { float f; f = t * t; return f * f * t; } CGLM_INLINE float glm_ease_quint_out(float t) { float f, g; f = t - 1.0f; g = f * f; return g * g * f + 1.0f; } CGLM_INLINE float glm_ease_quint_inout(float t) { float f, g; if (t < 0.5f) { f = t * t; return 16.0f * f * f * t; } f = 2.0f * t - 2.0f; g = f * f; return 0.5f * g * g * f + 1.0f; } CGLM_INLINE float glm_ease_exp_in(float t) { if (t == 0.0f) return t; return powf(2.0f, 10.0f * (t - 1.0f)); } CGLM_INLINE float glm_ease_exp_out(float t) { if (t == 1.0f) return t; return 1.0f - powf(2.0f, -10.0f * t); } CGLM_INLINE float glm_ease_exp_inout(float t) { if (t == 0.0f || t == 1.0f) return t; if (t < 0.5f) return 0.5f * powf(2.0f, (20.0f * t) - 10.0f); return -0.5f * powf(2.0f, (-20.0f * t) + 10.0f) + 1.0f; } CGLM_INLINE float glm_ease_circ_in(float t) { return 1.0f - sqrtf(1.0f - (t * t)); } CGLM_INLINE float glm_ease_circ_out(float t) { return sqrtf((2.0f - t) * t); } CGLM_INLINE float glm_ease_circ_inout(float t) { if (t < 0.5f) return 0.5f * (1.0f - sqrtf(1.0f - 4.0f * (t * t))); return 0.5f * (sqrtf(-((2.0f * t) - 3.0f) * ((2.0f * t) - 1.0f)) + 1.0f); } CGLM_INLINE float glm_ease_back_in(float t) { float o, z; o = 1.70158f; z = ((o + 1.0f) * t) - o; return t * t * z; } CGLM_INLINE float glm_ease_back_out(float t) { float o, z, n; o = 1.70158f; n = t - 1.0f; z = (o + 1.0f) * n + o; return n * n * z + 1.0f; } CGLM_INLINE float glm_ease_back_inout(float t) { float o, z, n, m, s, x; o = 1.70158f; s = o * 1.525f; x = 0.5f; n = t / 0.5f; if (n < 1.0f) { z = (s + 1) * n - s; m = n * n * z; return x * m; } n -= 2.0f; z = (s + 1.0f) * n + s; m = (n * n * z) + 2; return x * m; } CGLM_INLINE float glm_ease_elast_in(float t) { return sinf(13.0f * GLM_PI_2f * t) * powf(2.0f, 10.0f * (t - 1.0f)); } CGLM_INLINE float glm_ease_elast_out(float t) { return sinf(-13.0f * GLM_PI_2f * (t + 1.0f)) * powf(2.0f, -10.0f * t) + 1.0f; } CGLM_INLINE float glm_ease_elast_inout(float t) { float a; a = 2.0f * t; if (t < 0.5f) return 0.5f * sinf(13.0f * GLM_PI_2f * a) * powf(2.0f, 10.0f * (a - 1.0f)); return 0.5f * (sinf(-13.0f * GLM_PI_2f * a) * powf(2.0f, -10.0f * (a - 1.0f)) + 2.0f); } CGLM_INLINE float glm_ease_bounce_out(float t) { float tt; tt = t * t; if (t < (4.0f / 11.0f)) return (121.0f * tt) / 16.0f; if (t < 8.0f / 11.0f) return ((363.0f / 40.0f) * tt) - ((99.0f / 10.0f) * t) + (17.0f / 5.0f); if (t < (9.0f / 10.0f)) return (4356.0f / 361.0f) * tt - (35442.0f / 1805.0f) * t + (16061.0f / 1805.0f); return ((54.0f / 5.0f) * tt) - ((513.0f / 25.0f) * t) + (268.0f / 25.0f); } CGLM_INLINE float glm_ease_bounce_in(float t) { return 1.0f - glm_ease_bounce_out(1.0f - t); } CGLM_INLINE float glm_ease_bounce_inout(float t) { if (t < 0.5f) return 0.5f * (1.0f - glm_ease_bounce_out(t * 2.0f)); return 0.5f * glm_ease_bounce_out(t * 2.0f - 1.0f) + 0.5f; } #endif /* cglm_ease_h */ cglm-0.9.7/include/cglm/euler.h000066400000000000000000000347551526744317200163340ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* NOTE: angles must be passed as [X-Angle, Y-Angle, Z-angle] order For instance you don't pass angles as [Z-Angle, X-Angle, Y-angle] to glm_euler_zxy function, All RELATED functions accept angles same order which is [X, Y, Z]. */ /* Types: enum glm_euler_seq Functions: CGLM_INLINE glm_euler_seq glm_euler_order(int newOrder[3]); CGLM_INLINE void glm_euler_angles(mat4 m, vec3 dest); CGLM_INLINE void glm_euler(vec3 angles, mat4 dest); CGLM_INLINE void glm_euler_xyz(vec3 angles, mat4 dest); CGLM_INLINE void glm_euler_zyx(vec3 angles, mat4 dest); CGLM_INLINE void glm_euler_zxy(vec3 angles, mat4 dest); CGLM_INLINE void glm_euler_xzy(vec3 angles, mat4 dest); CGLM_INLINE void glm_euler_yzx(vec3 angles, mat4 dest); CGLM_INLINE void glm_euler_yxz(vec3 angles, mat4 dest); CGLM_INLINE void glm_euler_by_order(vec3 angles, glm_euler_seq ord, mat4 dest); CGLM_INLINE void glm_euler_xyz_quat(vec3 angles, versor dest); CGLM_INLINE void glm_euler_xzy_quat(vec3 angles, versor dest); CGLM_INLINE void glm_euler_yxz_quat(vec3 angles, versor dest); CGLM_INLINE void glm_euler_yzx_quat(vec3 angles, versor dest); CGLM_INLINE void glm_euler_zxy_quat(vec3 angles, versor dest); CGLM_INLINE void glm_euler_zyx_quat(vec3 angles, versor dest); */ #ifndef cglm_euler_h #define cglm_euler_h #include "common.h" #ifdef CGLM_FORCE_LEFT_HANDED # include "handed/euler_to_quat_lh.h" #else # include "handed/euler_to_quat_rh.h" #endif #ifndef CGLM_CLIPSPACE_INCLUDE_ALL # if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO # include "clipspace/ortho_lh_zo.h" # include "clipspace/persp_lh_zo.h" # include "clipspace/view_lh_zo.h" # elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO # include "clipspace/ortho_lh_no.h" # include "clipspace/persp_lh_no.h" # include "clipspace/view_lh_no.h" # elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO # include "clipspace/ortho_rh_zo.h" # include "clipspace/persp_rh_zo.h" # include "clipspace/view_rh_zo.h" # elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO # include "clipspace/ortho_rh_no.h" # include "clipspace/persp_rh_no.h" # include "clipspace/view_rh_no.h" # endif #else # include "clipspace/ortho_lh_zo.h" # include "clipspace/persp_lh_zo.h" # include "clipspace/ortho_lh_no.h" # include "clipspace/persp_lh_no.h" # include "clipspace/ortho_rh_zo.h" # include "clipspace/persp_rh_zo.h" # include "clipspace/ortho_rh_no.h" # include "clipspace/persp_rh_no.h" # include "clipspace/view_lh_zo.h" # include "clipspace/view_lh_no.h" # include "clipspace/view_rh_zo.h" # include "clipspace/view_rh_no.h" #endif CGLM_INLINE glm_euler_seq glm_euler_order(int ord[3]) { return (glm_euler_seq)(ord[0] << 0 | ord[1] << 2 | ord[2] << 4); } /*! * @brief extract euler angles (in radians) using xyz order * * @param[in] m affine transform * @param[out] dest angles vector [x, y, z] */ CGLM_INLINE void glm_euler_angles(mat4 m, vec3 dest) { float m00, m01, m10, m11, m20, m21, m22; float thetaX, thetaY, thetaZ; m00 = m[0][0]; m10 = m[1][0]; m20 = m[2][0]; m01 = m[0][1]; m11 = m[1][1]; m21 = m[2][1]; m22 = m[2][2]; if (m20 < 1.0f) { if (m20 > -1.0f) { thetaY = asinf(m20); thetaX = atan2f(-m21, m22); thetaZ = atan2f(-m10, m00); } else { /* m20 == -1 */ /* Not a unique solution */ thetaY = -GLM_PI_2f; thetaX = -atan2f(m01, m11); thetaZ = 0.0f; } } else { /* m20 == +1 */ thetaY = GLM_PI_2f; thetaX = atan2f(m01, m11); thetaZ = 0.0f; } dest[0] = thetaX; dest[1] = thetaY; dest[2] = thetaZ; } /*! * @brief build rotation matrix from euler angles * * @param[in] angles angles as vector [Xangle, Yangle, Zangle] * @param[out] dest rotation matrix */ CGLM_INLINE void glm_euler_xyz(vec3 angles, mat4 dest) { float cx, cy, cz, sx, sy, sz, czsx, cxcz, sysz; sx = sinf(angles[0]); cx = cosf(angles[0]); sy = sinf(angles[1]); cy = cosf(angles[1]); sz = sinf(angles[2]); cz = cosf(angles[2]); czsx = cz * sx; cxcz = cx * cz; sysz = sy * sz; dest[0][0] = cy * cz; dest[0][1] = czsx * sy + cx * sz; dest[0][2] = -cxcz * sy + sx * sz; dest[1][0] = -cy * sz; dest[1][1] = cxcz - sx * sysz; dest[1][2] = czsx + cx * sysz; dest[2][0] = sy; dest[2][1] = -cy * sx; dest[2][2] = cx * cy; dest[0][3] = 0.0f; dest[1][3] = 0.0f; dest[2][3] = 0.0f; dest[3][0] = 0.0f; dest[3][1] = 0.0f; dest[3][2] = 0.0f; dest[3][3] = 1.0f; } /*! * @brief build rotation matrix from euler angles * * @param[in] angles angles as vector [Xangle, Yangle, Zangle] * @param[out] dest rotation matrix */ CGLM_INLINE void glm_euler(vec3 angles, mat4 dest) { glm_euler_xyz(angles, dest); } /*! * @brief build rotation matrix from euler angles * * @param[in] angles angles as vector [Xangle, Yangle, Zangle] * @param[out] dest rotation matrix */ CGLM_INLINE void glm_euler_xzy(vec3 angles, mat4 dest) { float cx, cy, cz, sx, sy, sz, sxsy, cysx, cxsy, cxcy; sx = sinf(angles[0]); cx = cosf(angles[0]); sy = sinf(angles[1]); cy = cosf(angles[1]); sz = sinf(angles[2]); cz = cosf(angles[2]); sxsy = sx * sy; cysx = cy * sx; cxsy = cx * sy; cxcy = cx * cy; dest[0][0] = cy * cz; dest[0][1] = sxsy + cxcy * sz; dest[0][2] = -cxsy + cysx * sz; dest[1][0] = -sz; dest[1][1] = cx * cz; dest[1][2] = cz * sx; dest[2][0] = cz * sy; dest[2][1] = -cysx + cxsy * sz; dest[2][2] = cxcy + sxsy * sz; dest[0][3] = 0.0f; dest[1][3] = 0.0f; dest[2][3] = 0.0f; dest[3][0] = 0.0f; dest[3][1] = 0.0f; dest[3][2] = 0.0f; dest[3][3] = 1.0f; } /*! * @brief build rotation matrix from euler angles * * @param[in] angles angles as vector [Xangle, Yangle, Zangle] * @param[out] dest rotation matrix */ CGLM_INLINE void glm_euler_yxz(vec3 angles, mat4 dest) { float cx, cy, cz, sx, sy, sz, cycz, sysz, czsy, cysz; sx = sinf(angles[0]); cx = cosf(angles[0]); sy = sinf(angles[1]); cy = cosf(angles[1]); sz = sinf(angles[2]); cz = cosf(angles[2]); cycz = cy * cz; sysz = sy * sz; czsy = cz * sy; cysz = cy * sz; dest[0][0] = cycz + sx * sysz; dest[0][1] = cx * sz; dest[0][2] = -czsy + cysz * sx; dest[1][0] = -cysz + czsy * sx; dest[1][1] = cx * cz; dest[1][2] = cycz * sx + sysz; dest[2][0] = cx * sy; dest[2][1] = -sx; dest[2][2] = cx * cy; dest[0][3] = 0.0f; dest[1][3] = 0.0f; dest[2][3] = 0.0f; dest[3][0] = 0.0f; dest[3][1] = 0.0f; dest[3][2] = 0.0f; dest[3][3] = 1.0f; } /*! * @brief build rotation matrix from euler angles * * @param[in] angles angles as vector [Xangle, Yangle, Zangle] * @param[out] dest rotation matrix */ CGLM_INLINE void glm_euler_yzx(vec3 angles, mat4 dest) { float cx, cy, cz, sx, sy, sz, sxsy, cxcy, cysx, cxsy; sx = sinf(angles[0]); cx = cosf(angles[0]); sy = sinf(angles[1]); cy = cosf(angles[1]); sz = sinf(angles[2]); cz = cosf(angles[2]); sxsy = sx * sy; cxcy = cx * cy; cysx = cy * sx; cxsy = cx * sy; dest[0][0] = cy * cz; dest[0][1] = sz; dest[0][2] = -cz * sy; dest[1][0] = sxsy - cxcy * sz; dest[1][1] = cx * cz; dest[1][2] = cysx + cxsy * sz; dest[2][0] = cxsy + cysx * sz; dest[2][1] = -cz * sx; dest[2][2] = cxcy - sxsy * sz; dest[0][3] = 0.0f; dest[1][3] = 0.0f; dest[2][3] = 0.0f; dest[3][0] = 0.0f; dest[3][1] = 0.0f; dest[3][2] = 0.0f; dest[3][3] = 1.0f; } /*! * @brief build rotation matrix from euler angles * * @param[in] angles angles as vector [Xangle, Yangle, Zangle] * @param[out] dest rotation matrix */ CGLM_INLINE void glm_euler_zxy(vec3 angles, mat4 dest) { float cx, cy, cz, sx, sy, sz, cycz, sxsy, cysz; sx = sinf(angles[0]); cx = cosf(angles[0]); sy = sinf(angles[1]); cy = cosf(angles[1]); sz = sinf(angles[2]); cz = cosf(angles[2]); cycz = cy * cz; sxsy = sx * sy; cysz = cy * sz; dest[0][0] = cycz - sxsy * sz; dest[0][1] = cz * sxsy + cysz; dest[0][2] = -cx * sy; dest[1][0] = -cx * sz; dest[1][1] = cx * cz; dest[1][2] = sx; dest[2][0] = cz * sy + cysz * sx; dest[2][1] = -cycz * sx + sy * sz; dest[2][2] = cx * cy; dest[0][3] = 0.0f; dest[1][3] = 0.0f; dest[2][3] = 0.0f; dest[3][0] = 0.0f; dest[3][1] = 0.0f; dest[3][2] = 0.0f; dest[3][3] = 1.0f; } /*! * @brief build rotation matrix from euler angles * * @param[in] angles angles as vector [Xangle, Yangle, Zangle] * @param[out] dest rotation matrix */ CGLM_INLINE void glm_euler_zyx(vec3 angles, mat4 dest) { float cx, cy, cz, sx, sy, sz, czsx, cxcz, sysz; sx = sinf(angles[0]); cx = cosf(angles[0]); sy = sinf(angles[1]); cy = cosf(angles[1]); sz = sinf(angles[2]); cz = cosf(angles[2]); czsx = cz * sx; cxcz = cx * cz; sysz = sy * sz; dest[0][0] = cy * cz; dest[0][1] = cy * sz; dest[0][2] = -sy; dest[1][0] = czsx * sy - cx * sz; dest[1][1] = cxcz + sx * sysz; dest[1][2] = cy * sx; dest[2][0] = cxcz * sy + sx * sz; dest[2][1] = -czsx + cx * sysz; dest[2][2] = cx * cy; dest[0][3] = 0.0f; dest[1][3] = 0.0f; dest[2][3] = 0.0f; dest[3][0] = 0.0f; dest[3][1] = 0.0f; dest[3][2] = 0.0f; dest[3][3] = 1.0f; } /*! * @brief build rotation matrix from euler angles * * @param[in] angles angles as vector [Xangle, Yangle, Zangle] * @param[in] ord euler order * @param[out] dest rotation matrix */ CGLM_INLINE void glm_euler_by_order(vec3 angles, glm_euler_seq ord, mat4 dest) { float cx, cy, cz, sx, sy, sz; float cycz, cysz, cysx, cxcy, czsy, cxcz, czsx, cxsz, sysz; sx = sinf(angles[0]); cx = cosf(angles[0]); sy = sinf(angles[1]); cy = cosf(angles[1]); sz = sinf(angles[2]); cz = cosf(angles[2]); cycz = cy * cz; cysz = cy * sz; cysx = cy * sx; cxcy = cx * cy; czsy = cz * sy; cxcz = cx * cz; czsx = cz * sx; cxsz = cx * sz; sysz = sy * sz; switch (ord) { case GLM_EULER_XZY: dest[0][0] = cycz; dest[0][1] = sx * sy + cx * cysz; dest[0][2] = -cx * sy + cysx * sz; dest[1][0] = -sz; dest[1][1] = cxcz; dest[1][2] = czsx; dest[2][0] = czsy; dest[2][1] = -cysx + cx * sysz; dest[2][2] = cxcy + sx * sysz; break; case GLM_EULER_XYZ: dest[0][0] = cycz; dest[0][1] = czsx * sy + cxsz; dest[0][2] = -cx * czsy + sx * sz; dest[1][0] = -cysz; dest[1][1] = cxcz - sx * sysz; dest[1][2] = czsx + cx * sysz; dest[2][0] = sy; dest[2][1] = -cysx; dest[2][2] = cxcy; break; case GLM_EULER_YXZ: dest[0][0] = cycz + sx * sysz; dest[0][1] = cxsz; dest[0][2] = -czsy + cysx * sz; dest[1][0] = czsx * sy - cysz; dest[1][1] = cxcz; dest[1][2] = cycz * sx + sysz; dest[2][0] = cx * sy; dest[2][1] = -sx; dest[2][2] = cxcy; break; case GLM_EULER_YZX: dest[0][0] = cycz; dest[0][1] = sz; dest[0][2] = -czsy; dest[1][0] = sx * sy - cx * cysz; dest[1][1] = cxcz; dest[1][2] = cysx + cx * sysz; dest[2][0] = cx * sy + cysx * sz; dest[2][1] = -czsx; dest[2][2] = cxcy - sx * sysz; break; case GLM_EULER_ZXY: dest[0][0] = cycz - sx * sysz; dest[0][1] = czsx * sy + cysz; dest[0][2] = -cx * sy; dest[1][0] = -cxsz; dest[1][1] = cxcz; dest[1][2] = sx; dest[2][0] = czsy + cysx * sz; dest[2][1] = -cycz * sx + sysz; dest[2][2] = cxcy; break; case GLM_EULER_ZYX: dest[0][0] = cycz; dest[0][1] = cysz; dest[0][2] = -sy; dest[1][0] = czsx * sy - cxsz; dest[1][1] = cxcz + sx * sysz; dest[1][2] = cysx; dest[2][0] = cx * czsy + sx * sz; dest[2][1] = -czsx + cx * sysz; dest[2][2] = cxcy; break; } dest[0][3] = 0.0f; dest[1][3] = 0.0f; dest[2][3] = 0.0f; dest[3][0] = 0.0f; dest[3][1] = 0.0f; dest[3][2] = 0.0f; dest[3][3] = 1.0f; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in x y z order (roll pitch yaw) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE void glm_euler_xyz_quat(vec3 angles, versor dest) { #ifdef CGLM_FORCE_LEFT_HANDED glm_euler_xyz_quat_lh(angles, dest); #else glm_euler_xyz_quat_rh(angles, dest); #endif } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in x z y order (roll yaw pitch) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE void glm_euler_xzy_quat(vec3 angles, versor dest) { #ifdef CGLM_FORCE_LEFT_HANDED glm_euler_xzy_quat_lh(angles, dest); #else glm_euler_xzy_quat_rh(angles, dest); #endif } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in y x z order (pitch roll yaw) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE void glm_euler_yxz_quat(vec3 angles, versor dest) { #ifdef CGLM_FORCE_LEFT_HANDED glm_euler_yxz_quat_lh(angles, dest); #else glm_euler_yxz_quat_rh(angles, dest); #endif } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in y z x order (pitch yaw roll) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE void glm_euler_yzx_quat(vec3 angles, versor dest) { #ifdef CGLM_FORCE_LEFT_HANDED glm_euler_yzx_quat_lh(angles, dest); #else glm_euler_yzx_quat_rh(angles, dest); #endif } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in z x y order (yaw roll pitch) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE void glm_euler_zxy_quat(vec3 angles, versor dest) { #ifdef CGLM_FORCE_LEFT_HANDED glm_euler_zxy_quat_lh(angles, dest); #else glm_euler_zxy_quat_rh(angles, dest); #endif } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in z y x order (yaw pitch roll) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE void glm_euler_zyx_quat(vec3 angles, versor dest) { #ifdef CGLM_FORCE_LEFT_HANDED glm_euler_zyx_quat_lh(angles, dest); #else glm_euler_zyx_quat_rh(angles, dest); #endif } #endif /* cglm_euler_h */ cglm-0.9.7/include/cglm/frustum.h000066400000000000000000000161471526744317200167200ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_frustum_h #define cglm_frustum_h #include "common.h" #include "plane.h" #include "vec3.h" #include "vec4.h" #include "mat4.h" #define GLM_LBN 0 /* left bottom near */ #define GLM_LTN 1 /* left top near */ #define GLM_RTN 2 /* right top near */ #define GLM_RBN 3 /* right bottom near */ #define GLM_LBF 4 /* left bottom far */ #define GLM_LTF 5 /* left top far */ #define GLM_RTF 6 /* right top far */ #define GLM_RBF 7 /* right bottom far */ #define GLM_LEFT 0 #define GLM_RIGHT 1 #define GLM_BOTTOM 2 #define GLM_TOP 3 #define GLM_NEAR 4 #define GLM_FAR 5 /* you can override clip space coords but you have to provide all with same name e.g.: define GLM_CSCOORD_LBN {0.0f, 0.0f, 1.0f, 1.0f} */ #ifndef GLM_CUSTOM_CLIPSPACE /* near */ #define GLM_CSCOORD_LBN {-1.0f, -1.0f, -1.0f, 1.0f} #define GLM_CSCOORD_LTN {-1.0f, 1.0f, -1.0f, 1.0f} #define GLM_CSCOORD_RTN { 1.0f, 1.0f, -1.0f, 1.0f} #define GLM_CSCOORD_RBN { 1.0f, -1.0f, -1.0f, 1.0f} /* far */ #define GLM_CSCOORD_LBF {-1.0f, -1.0f, 1.0f, 1.0f} #define GLM_CSCOORD_LTF {-1.0f, 1.0f, 1.0f, 1.0f} #define GLM_CSCOORD_RTF { 1.0f, 1.0f, 1.0f, 1.0f} #define GLM_CSCOORD_RBF { 1.0f, -1.0f, 1.0f, 1.0f} #endif /*! * @brief extracts view frustum planes * * planes' space: * 1- if m = proj: View Space * 2- if m = viewProj: World Space * 3- if m = MVP: Object Space * * You probably want to extract planes in world space so use viewProj as m * Computing viewProj: * glm_mat4_mul(proj, view, viewProj); * * Exracted planes order: [left, right, bottom, top, near, far] * * @param[in] m matrix (see brief) * @param[out] dest extracted view frustum planes (see brief) */ CGLM_INLINE void glm_frustum_planes(mat4 m, vec4 dest[6]) { mat4 t; glm_mat4_transpose_to(m, t); glm_vec4_add(t[3], t[0], dest[0]); /* left */ glm_vec4_sub(t[3], t[0], dest[1]); /* right */ glm_vec4_add(t[3], t[1], dest[2]); /* bottom */ glm_vec4_sub(t[3], t[1], dest[3]); /* top */ glm_vec4_add(t[3], t[2], dest[4]); /* near */ glm_vec4_sub(t[3], t[2], dest[5]); /* far */ glm_plane_normalize(dest[0]); glm_plane_normalize(dest[1]); glm_plane_normalize(dest[2]); glm_plane_normalize(dest[3]); glm_plane_normalize(dest[4]); glm_plane_normalize(dest[5]); } /*! * @brief extracts view frustum corners using clip-space coordinates * * corners' space: * 1- if m = invViewProj: World Space * 2- if m = invMVP: Object Space * * You probably want to extract corners in world space so use invViewProj * Computing invViewProj: * glm_mat4_mul(proj, view, viewProj); * ... * glm_mat4_inv(viewProj, invViewProj); * * if you have a near coord at i index, you can get it's far coord by i + 4 * * Find center coordinates: * for (j = 0; j < 4; j++) { * glm_vec3_center(corners[i], corners[i + 4], centerCorners[i]); * } * * @param[in] invMat matrix (see brief) * @param[out] dest exracted view frustum corners (see brief) */ CGLM_INLINE void glm_frustum_corners(mat4 invMat, vec4 dest[8]) { vec4 c[8]; /* indexOf(nearCoord) = indexOf(farCoord) + 4 */ vec4 csCoords[8] = { GLM_CSCOORD_LBN, GLM_CSCOORD_LTN, GLM_CSCOORD_RTN, GLM_CSCOORD_RBN, GLM_CSCOORD_LBF, GLM_CSCOORD_LTF, GLM_CSCOORD_RTF, GLM_CSCOORD_RBF }; glm_mat4_mulv(invMat, csCoords[0], c[0]); glm_mat4_mulv(invMat, csCoords[1], c[1]); glm_mat4_mulv(invMat, csCoords[2], c[2]); glm_mat4_mulv(invMat, csCoords[3], c[3]); glm_mat4_mulv(invMat, csCoords[4], c[4]); glm_mat4_mulv(invMat, csCoords[5], c[5]); glm_mat4_mulv(invMat, csCoords[6], c[6]); glm_mat4_mulv(invMat, csCoords[7], c[7]); glm_vec4_scale(c[0], 1.0f / c[0][3], dest[0]); glm_vec4_scale(c[1], 1.0f / c[1][3], dest[1]); glm_vec4_scale(c[2], 1.0f / c[2][3], dest[2]); glm_vec4_scale(c[3], 1.0f / c[3][3], dest[3]); glm_vec4_scale(c[4], 1.0f / c[4][3], dest[4]); glm_vec4_scale(c[5], 1.0f / c[5][3], dest[5]); glm_vec4_scale(c[6], 1.0f / c[6][3], dest[6]); glm_vec4_scale(c[7], 1.0f / c[7][3], dest[7]); } /*! * @brief finds center of view frustum * * @param[in] corners view frustum corners * @param[out] dest view frustum center */ CGLM_INLINE void glm_frustum_center(vec4 corners[8], vec4 dest) { vec4 center; glm_vec4_copy(corners[0], center); glm_vec4_add(corners[1], center, center); glm_vec4_add(corners[2], center, center); glm_vec4_add(corners[3], center, center); glm_vec4_add(corners[4], center, center); glm_vec4_add(corners[5], center, center); glm_vec4_add(corners[6], center, center); glm_vec4_add(corners[7], center, center); glm_vec4_scale(center, 0.125f, dest); } /*! * @brief finds bounding box of frustum relative to given matrix e.g. view mat * * @param[in] corners view frustum corners * @param[in] m matrix to convert existing conners * @param[out] box bounding box as array [min, max] */ CGLM_INLINE void glm_frustum_box(vec4 corners[8], mat4 m, vec3 box[2]) { vec4 v; vec3 min, max; int i; glm_vec3_broadcast(FLT_MAX, min); glm_vec3_broadcast(-FLT_MAX, max); for (i = 0; i < 8; i++) { glm_mat4_mulv(m, corners[i], v); min[0] = glm_min(min[0], v[0]); min[1] = glm_min(min[1], v[1]); min[2] = glm_min(min[2], v[2]); max[0] = glm_max(max[0], v[0]); max[1] = glm_max(max[1], v[1]); max[2] = glm_max(max[2], v[2]); } glm_vec3_copy(min, box[0]); glm_vec3_copy(max, box[1]); } /*! * @brief finds planes corners which is between near and far planes (parallel) * * this will be helpful if you want to split a frustum e.g. CSM/PSSM. This will * find planes' corners but you will need to one more plane. * Actually you have it, it is near, far or created previously with this func ;) * * @param[in] corners view frustum corners * @param[in] splitDist split distance * @param[in] farDist far distance (zFar) * @param[out] planeCorners plane corners [LB, LT, RT, RB] */ CGLM_INLINE void glm_frustum_corners_at(vec4 corners[8], float splitDist, float farDist, vec4 planeCorners[4]) { vec4 corner; float dist, sc; /* because distance and scale is same for all */ dist = glm_vec3_distance(corners[GLM_RTF], corners[GLM_RTN]); sc = dist * (splitDist / farDist); /* left bottom */ glm_vec4_sub(corners[GLM_LBF], corners[GLM_LBN], corner); glm_vec4_scale_as(corner, sc, corner); glm_vec4_add(corners[GLM_LBN], corner, planeCorners[0]); /* left top */ glm_vec4_sub(corners[GLM_LTF], corners[GLM_LTN], corner); glm_vec4_scale_as(corner, sc, corner); glm_vec4_add(corners[GLM_LTN], corner, planeCorners[1]); /* right top */ glm_vec4_sub(corners[GLM_RTF], corners[GLM_RTN], corner); glm_vec4_scale_as(corner, sc, corner); glm_vec4_add(corners[GLM_RTN], corner, planeCorners[2]); /* right bottom */ glm_vec4_sub(corners[GLM_RBF], corners[GLM_RBN], corner); glm_vec4_scale_as(corner, sc, corner); glm_vec4_add(corners[GLM_RBN], corner, planeCorners[3]); } #endif /* cglm_frustum_h */ cglm-0.9.7/include/cglm/handed/000077500000000000000000000000001526744317200162545ustar00rootroot00000000000000cglm-0.9.7/include/cglm/handed/euler_to_quat_lh.h000066400000000000000000000114631526744317200217650ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glm_euler_xyz_quat_lh(vec3 angles, versor dest); CGLM_INLINE void glm_euler_xzy_quat_lh(vec3 angles, versor dest); CGLM_INLINE void glm_euler_yxz_quat_lh(vec3 angles, versor dest); CGLM_INLINE void glm_euler_yzx_quat_lh(vec3 angles, versor dest); CGLM_INLINE void glm_euler_zxy_quat_lh(vec3 angles, versor dest); CGLM_INLINE void glm_euler_zyx_quat_lh(vec3 angles, versor dest); */ /* Things to note: The only difference between euler to quat rh vs lh is that the zsin part is negative */ #ifndef cglm_euler_to_quat_lh_h #define cglm_euler_to_quat_lh_h #include "../common.h" /*! * @brief creates NEW quaternion using rotation angles and does * rotations in x y z order in left hand (roll pitch yaw) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE void glm_euler_xyz_quat_lh(vec3 angles, versor dest) { float xc, yc, zc, xs, ys, zs; xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); zs = -sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); dest[0] = xc * ys * zs + xs * yc * zc; dest[1] = xc * ys * zc - xs * yc * zs; dest[2] = xc * yc * zs + xs * ys * zc; dest[3] = xc * yc * zc - xs * ys * zs; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in x z y order in left hand (roll yaw pitch) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE void glm_euler_xzy_quat_lh(vec3 angles, versor dest) { float xc, yc, zc, xs, ys, zs; xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); zs = -sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); dest[0] = -xc * zs * ys + xs * zc * yc; dest[1] = xc * zc * ys - xs * zs * yc; dest[2] = xc * zs * yc + xs * zc * ys; dest[3] = xc * zc * yc + xs * zs * ys; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in y x z order in left hand (pitch roll yaw) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE void glm_euler_yxz_quat_lh(vec3 angles, versor dest) { float xc, yc, zc, xs, ys, zs; xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); zs = -sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); dest[0] = yc * xs * zc + ys * xc * zs; dest[1] = -yc * xs * zs + ys * xc * zc; dest[2] = yc * xc * zs - ys * xs * zc; dest[3] = yc * xc * zc + ys * xs * zs; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in y z x order in left hand (pitch yaw roll) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE void glm_euler_yzx_quat_lh(vec3 angles, versor dest) { float xc, yc, zc, xs, ys, zs; xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); zs = -sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); dest[0] = yc * zc * xs + ys * zs * xc; dest[1] = yc * zs * xs + ys * zc * xc; dest[2] = yc * zs * xc - ys * zc * xs; dest[3] = yc * zc * xc - ys * zs * xs; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in z x y order in left hand (yaw roll pitch) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE void glm_euler_zxy_quat_lh(vec3 angles, versor dest) { float xc, yc, zc, xs, ys, zs; xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); zs = -sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); dest[0] = zc * xs * yc - zs * xc * ys; dest[1] = zc * xc * ys + zs * xs * yc; dest[2] = zc * xs * ys + zs * xc * yc; dest[3] = zc * xc * yc - zs * xs * ys; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in z y x order in left hand (yaw pitch roll) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE void glm_euler_zyx_quat_lh(vec3 angles, versor dest) { float xc, yc, zc, xs, ys, zs; xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); zs = -sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); dest[0] = zc * yc * xs - zs * ys * xc; dest[1] = zc * ys * xc + zs * yc * xs; dest[2] = -zc * ys * xs + zs * yc * xc; dest[3] = zc * yc * xc + zs * ys * xs; } #endif /*cglm_euler_to_quat_lh_h*/ cglm-0.9.7/include/cglm/handed/euler_to_quat_rh.h000066400000000000000000000114521526744317200217710ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glm_euler_xyz_quat_rh(vec3 angles, versor dest); CGLM_INLINE void glm_euler_xzy_quat_rh(vec3 angles, versor dest); CGLM_INLINE void glm_euler_yxz_quat_rh(vec3 angles, versor dest); CGLM_INLINE void glm_euler_yzx_quat_rh(vec3 angles, versor dest); CGLM_INLINE void glm_euler_zxy_quat_rh(vec3 angles, versor dest); CGLM_INLINE void glm_euler_zyx_quat_rh(vec3 angles, versor dest); */ /* Things to note: The only difference between euler to quat rh vs lh is that the zsin part is negative */ #ifndef cglm_euler_to_quat_rh_h #define cglm_euler_to_quat_rh_h #include "../common.h" /*! * @brief creates NEW quaternion using rotation angles and does * rotations in x y z order in right hand (roll pitch yaw) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE void glm_euler_xyz_quat_rh(vec3 angles, versor dest) { float xc, yc, zc, xs, ys, zs; xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); zs = sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); dest[0] = xc * ys * zs + xs * yc * zc; dest[1] = xc * ys * zc - xs * yc * zs; dest[2] = xc * yc * zs + xs * ys * zc; dest[3] = xc * yc * zc - xs * ys * zs; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in x z y order in right hand (roll yaw pitch) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE void glm_euler_xzy_quat_rh(vec3 angles, versor dest) { float xc, yc, zc, xs, ys, zs; xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); zs = sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); dest[0] = -xc * zs * ys + xs * zc * yc; dest[1] = xc * zc * ys - xs * zs * yc; dest[2] = xc * zs * yc + xs * zc * ys; dest[3] = xc * zc * yc + xs * zs * ys; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in y x z order in right hand (pitch roll yaw) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE void glm_euler_yxz_quat_rh(vec3 angles, versor dest) { float xc, yc, zc, xs, ys, zs; xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); zs = sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); dest[0] = yc * xs * zc + ys * xc * zs; dest[1] = -yc * xs * zs + ys * xc * zc; dest[2] = yc * xc * zs - ys * xs * zc; dest[3] = yc * xc * zc + ys * xs * zs; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in y z x order in right hand (pitch yaw roll) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE void glm_euler_yzx_quat_rh(vec3 angles, versor dest) { float xc, yc, zc, xs, ys, zs; xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); zs = sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); dest[0] = yc * zc * xs + ys * zs * xc; dest[1] = yc * zs * xs + ys * zc * xc; dest[2] = yc * zs * xc - ys * zc * xs; dest[3] = yc * zc * xc - ys * zs * xs; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in z x y order in right hand (yaw roll pitch) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE void glm_euler_zxy_quat_rh(vec3 angles, versor dest) { float xc, yc, zc, xs, ys, zs; xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); zs = sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); dest[0] = zc * xs * yc - zs * xc * ys; dest[1] = zc * xc * ys + zs * xs * yc; dest[2] = zc * xs * ys + zs * xc * yc; dest[3] = zc * xc * yc - zs * xs * ys; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in z y x order in right hand (yaw pitch roll) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE void glm_euler_zyx_quat_rh(vec3 angles, versor dest) { float xc, yc, zc, xs, ys, zs; xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); zs = sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); dest[0] = zc * yc * xs - zs * ys * xc; dest[1] = zc * ys * xc + zs * yc * xs; dest[2] = -zc * ys * xs + zs * yc * xc; dest[3] = zc * yc * xc + zs * ys * xs; } #endif /*cglm_euler_to_quat_rh_h*/ cglm-0.9.7/include/cglm/io.h000066400000000000000000000240061526744317200156130ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glm_mat4_print(mat4 matrix, FILE *ostream); CGLM_INLINE void glm_mat3_print(mat3 matrix, FILE *ostream); CGLM_INLINE void glm_vec4_print(vec4 vec, FILE *ostream); CGLM_INLINE void glm_ivec4_print(ivec4 vec, FILE *ostream); CGLM_INLINE void glm_vec3_print(vec3 vec, FILE *ostream); CGLM_INLINE void glm_ivec3_print(ivec3 vec, FILE *ostream); CGLM_INLINE void glm_vec2_print(vec2 vec, FILE *ostream); CGLM_INLINE void glm_ivec2_print(ivec2 vec, FILE *ostream); CGLM_INLINE void glm_versor_print(versor vec, FILE *ostream); CGLM_INLINE void glm_arch_print(FILE *ostream); */ /* cglm tried to enable print functions in debug mode and disable them in release/production mode to eliminate printing costs. if you need to force enable then define CGLM_DEFINE_PRINTS macro not DEBUG one Print functions are enabled if: - DEBUG or _DEBUG macro is defined (mostly defined automatically in debugging) - CGLM_DEFINE_PRINTS macro is defined including release/production which makes enabled printing always - glmc_ calls for io are always prints */ /* DEPRECATED: CGLM_NO_PRINTS_NOOP (use CGLM_DEFINE_PRINTS) */ #ifndef cglm_io_h #define cglm_io_h #if !defined(NDEBUG) \ || defined(CGLM_DEFINE_PRINTS) || defined(CGLM_LIB_SRC) \ || defined(CGLM_NO_PRINTS_NOOP) #include "common.h" #include "util.h" #include #include #ifndef CGLM_PRINT_PRECISION # define CGLM_PRINT_PRECISION 5 #endif #ifndef CGLM_PRINT_MAX_TO_SHORT # define CGLM_PRINT_MAX_TO_SHORT 1e5f #endif #ifndef GLM_TESTS_NO_COLORFUL_OUTPUT # ifndef CGLM_PRINT_COLOR # define CGLM_PRINT_COLOR "\033[36m" # endif # ifndef CGLM_PRINT_COLOR_RESET # define CGLM_PRINT_COLOR_RESET "\033[0m" # endif #else # ifndef CGLM_PRINT_COLOR # define CGLM_PRINT_COLOR # endif # ifndef CGLM_PRINT_COLOR_RESET # define CGLM_PRINT_COLOR_RESET # endif #endif /*! * @brief prints current SIMD path in general * * @param[in] ostream stream to print e.g. stdout, stderr, FILE ... */ CGLM_INLINE void glm_arch_print(FILE* __restrict ostream) { fprintf(ostream, CGLM_PRINT_COLOR "arch: " #if defined(CGLM_SIMD_WASM) "wasm SIMD128" #elif defined(CGLM_SIMD_x86) "x86 SSE* " # ifdef __AVX__ " AVX" # endif #elif defined(CGLM_SIMD_ARM) "arm" # ifndef __ARM_NEON_FP " NEON_FP" # endif # ifdef CGLM_ARM64 " ARM64" # endif #else "uncommon" #endif CGLM_PRINT_COLOR_RESET); } /*! * @brief prints current SIMD path in general * * @param[in] ostream stream to print e.g. stdout, stderr, FILE ... */ CGLM_INLINE void glm_arch_print_name(FILE* __restrict ostream) { fprintf(ostream, CGLM_PRINT_COLOR "\ncglm "); glm_arch_print(ostream); fprintf(ostream, "\n\n" CGLM_PRINT_COLOR_RESET); } CGLM_INLINE void glm_mat4_print(mat4 matrix, FILE * __restrict ostream) { char buff[16]; int i, j, cw[4], cwi; #define m 4 #define n 4 fprintf(ostream, "Matrix (float%dx%d): " CGLM_PRINT_COLOR "\n" , m, n); cw[0] = cw[1] = cw[2] = cw[3] = 0; for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { if (matrix[i][j] < CGLM_PRINT_MAX_TO_SHORT) cwi = snprintf(buff, sizeof(buff), "% .*f", CGLM_PRINT_PRECISION, (double)matrix[i][j]); else cwi = snprintf(buff, sizeof(buff), "% g", (double)matrix[i][j]); cw[i] = GLM_MAX(cw[i], cwi); } } for (i = 0; i < m; i++) { fprintf(ostream, " |"); for (j = 0; j < n; j++) if (matrix[i][j] < CGLM_PRINT_MAX_TO_SHORT) fprintf(ostream, " % *.*f", cw[j], CGLM_PRINT_PRECISION, (double)matrix[j][i]); else fprintf(ostream, " % *g", cw[j], (double)matrix[j][i]); fprintf(ostream, " |\n"); } fprintf(ostream, CGLM_PRINT_COLOR_RESET "\n"); #undef m #undef n } CGLM_INLINE void glm_mat3_print(mat3 matrix, FILE * __restrict ostream) { char buff[16]; int i, j, cw[4], cwi; #define m 3 #define n 3 fprintf(ostream, "Matrix (float%dx%d): " CGLM_PRINT_COLOR "\n", m, n); cw[0] = cw[1] = cw[2] = 0; for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { if (matrix[i][j] < CGLM_PRINT_MAX_TO_SHORT) cwi = snprintf(buff, sizeof(buff), "% .*f", CGLM_PRINT_PRECISION, (double)matrix[i][j]); else cwi = snprintf(buff, sizeof(buff), "% g", (double)matrix[i][j]); cw[i] = GLM_MAX(cw[i], cwi); } } for (i = 0; i < m; i++) { fprintf(ostream, " |"); for (j = 0; j < n; j++) if (matrix[i][j] < CGLM_PRINT_MAX_TO_SHORT) fprintf(ostream, " % *.*f", cw[j], CGLM_PRINT_PRECISION, (double)matrix[j][i]); else fprintf(ostream, " % *g", cw[j], (double)matrix[j][i]); fprintf(ostream, " |\n"); } fprintf(ostream, CGLM_PRINT_COLOR_RESET "\n"); #undef m #undef n } CGLM_INLINE void glm_mat2_print(mat2 matrix, FILE * __restrict ostream) { char buff[16]; int i, j, cw[4], cwi; #define m 2 #define n 2 fprintf(ostream, "Matrix (float%dx%d): " CGLM_PRINT_COLOR "\n", m, n); cw[0] = cw[1] = 0; for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { if (matrix[i][j] < CGLM_PRINT_MAX_TO_SHORT) cwi = snprintf(buff, sizeof(buff), "% .*f", CGLM_PRINT_PRECISION, (double)matrix[i][j]); else cwi = snprintf(buff, sizeof(buff), "% g", (double)matrix[i][j]); cw[i] = GLM_MAX(cw[i], cwi); } } for (i = 0; i < m; i++) { fprintf(ostream, " |"); for (j = 0; j < n; j++) if (matrix[i][j] < CGLM_PRINT_MAX_TO_SHORT) fprintf(ostream, " % *.*f", cw[j], CGLM_PRINT_PRECISION, (double)matrix[j][i]); else fprintf(ostream, " % *g", cw[j], (double)matrix[j][i]); fprintf(ostream, " |\n"); } fprintf(ostream, CGLM_PRINT_COLOR_RESET "\n"); #undef m #undef n } CGLM_INLINE void glm_vec4_print(vec4 vec, FILE * __restrict ostream) { int i; #define m 4 fprintf(ostream, "Vector (float%d): " CGLM_PRINT_COLOR "\n (", m); for (i = 0; i < m; i++) { if (vec[i] < CGLM_PRINT_MAX_TO_SHORT) fprintf(ostream, " % .*f", CGLM_PRINT_PRECISION, (double)vec[i]); else fprintf(ostream, " % g", (double)vec[i]); } fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n"); #undef m } CGLM_INLINE void glm_ivec4_print(ivec4 vec, FILE * __restrict ostream) { int i; #define m 4 fprintf(ostream, "Vector (int%d): " CGLM_PRINT_COLOR "\n (", m); for (i = 0; i < m; i++) fprintf(ostream, " % d", vec[i]); fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n"); #undef m } CGLM_INLINE void glm_vec3_print(vec3 vec, FILE * __restrict ostream) { int i; #define m 3 fprintf(ostream, "Vector (float%d): " CGLM_PRINT_COLOR "\n (", m); for (i = 0; i < m; i++) { if (vec[i] < CGLM_PRINT_MAX_TO_SHORT) fprintf(ostream, " % .*f", CGLM_PRINT_PRECISION, (double)vec[i]); else fprintf(ostream, " % g", (double)vec[i]); } fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n"); #undef m } CGLM_INLINE void glm_ivec3_print(ivec3 vec, FILE * __restrict ostream) { int i; #define m 3 fprintf(ostream, "Vector (int%d): " CGLM_PRINT_COLOR "\n (", m); for (i = 0; i < m; i++) fprintf(ostream, " % d", vec[i]); fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n"); #undef m } CGLM_INLINE void glm_vec2_print(vec2 vec, FILE * __restrict ostream) { int i; #define m 2 fprintf(ostream, "Vector (float%d): " CGLM_PRINT_COLOR "\n (", m); for (i = 0; i < m; i++) { if (vec[i] < CGLM_PRINT_MAX_TO_SHORT) fprintf(ostream, " % .*f", CGLM_PRINT_PRECISION, (double)vec[i]); else fprintf(ostream, " % g", (double)vec[i]); } fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n"); #undef m } CGLM_INLINE void glm_ivec2_print(ivec2 vec, FILE * __restrict ostream) { int i; #define m 2 fprintf(ostream, "Vector (int%d): " CGLM_PRINT_COLOR "\n (", m); for (i = 0; i < m; i++) fprintf(ostream, " % d", vec[i]); fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n"); #undef m } CGLM_INLINE void glm_versor_print(versor vec, FILE * __restrict ostream) { int i; #define m 4 fprintf(ostream, "Quaternion (float%d): " CGLM_PRINT_COLOR "\n (", m); for (i = 0; i < m; i++) { if (vec[i] < CGLM_PRINT_MAX_TO_SHORT) fprintf(ostream, " % .*f", CGLM_PRINT_PRECISION, (double)vec[i]); else fprintf(ostream, " % g", (double)vec[i]); } fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n"); #undef m } CGLM_INLINE void glm_aabb_print(vec3 bbox[2], const char * __restrict tag, FILE * __restrict ostream) { int i, j; #define m 3 fprintf(ostream, "AABB (%s): " CGLM_PRINT_COLOR "\n", tag ? tag: "float"); for (i = 0; i < 2; i++) { fprintf(ostream, " ("); for (j = 0; j < m; j++) { if (bbox[i][j] < CGLM_PRINT_MAX_TO_SHORT) fprintf(ostream, " % .*f", CGLM_PRINT_PRECISION, (double)bbox[i][j]); else fprintf(ostream, " % g", (double)bbox[i][j]); } fprintf(ostream, " )\n"); } fprintf(ostream, CGLM_PRINT_COLOR_RESET "\n"); #undef m } #else #include "common.h" #include #include /* NOOP: Remove print from DEBUG */ #define glm_mat4_print(v, s) (void)v; (void)s; #define glm_mat3_print(v, s) (void)v; (void)s; #define glm_mat2_print(v, s) (void)v; (void)s; #define glm_vec4_print(v, s) (void)v; (void)s; #define glm_ivec4_print(v, s) (void)v; (void)s; #define glm_vec3_print(v, s) (void)v; (void)s; #define glm_ivec3_print(v, s) (void)v; (void)s; #define glm_vec2_print(v, s) (void)v; (void)s; #define glm_ivec2_print(v, s) (void)v; (void)s; #define glm_versor_print(v, s) (void)v; (void)s; #define glm_aabb_print(v, t, s) (void)v; (void)t; (void)s; #define glm_arch_print(s) (void)s; #define glm_arch_print_name(s) (void)s; #endif #endif /* cglm_io_h */ cglm-0.9.7/include/cglm/ivec2.h000066400000000000000000000351651526744317200162240ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLM_IVEC2_ONE_INIT GLM_IVEC2_ZERO_INIT GLM_IVEC2_ONE GLM_IVEC2_ZERO Functions: CGLM_INLINE void glm_ivec2(int * __restrict v, ivec2 dest) CGLM_INLINE void glm_ivec2_copy(ivec2 a, ivec2 dest) CGLM_INLINE void glm_ivec2_zero(ivec2 v) CGLM_INLINE void glm_ivec2_one(ivec2 v) CGLM_INLINE int glm_ivec2_dot(ivec2 a, ivec2 b) CGLM_INLINE int glm_ivec2_cross(ivec2 a, ivec2 b) CGLM_INLINE void glm_ivec2_add(ivec2 a, ivec2 b, ivec2 dest) CGLM_INLINE void glm_ivec2_adds(ivec2 v, int s, ivec2 dest) CGLM_INLINE void glm_ivec2_sub(ivec2 a, ivec2 b, ivec2 dest) CGLM_INLINE void glm_ivec2_subs(ivec2 v, int s, ivec2 dest) CGLM_INLINE void glm_ivec2_mul(ivec2 a, ivec2 b, ivec2 dest) CGLM_INLINE void glm_ivec2_scale(ivec2 v, int s, ivec2 dest) CGLM_INLINE void glm_ivec2_div(ivec2 a, ivec2 b, ivec2 dest) CGLM_INLINE void glm_ivec2_divs(ivec2 v, int s, ivec2 dest) CGLM_INLINE void glm_ivec2_mod(ivec2 a, ivec2 b, ivec2 dest) CGLM_INLINE void glm_ivec2_addadd(ivec2 a, ivec2 b, ivec2 dest) CGLM_INLINE void glm_ivec2_addadds(ivec2 a, int s, ivec2 dest) CGLM_INLINE void glm_ivec2_subadd(ivec2 a, ivec2 b, ivec2 dest) CGLM_INLINE void glm_ivec2_subadds(ivec2 a, int s, ivec2 dest) CGLM_INLINE void glm_ivec2_muladd(ivec2 a, ivec2 b, ivec2 dest) CGLM_INLINE void glm_ivec2_muladds(ivec2 a, int s, ivec2 dest) CGLM_INLINE void glm_ivec2_maxadd(ivec2 a, ivec2 b, ivec2 dest) CGLM_INLINE void glm_ivec2_minadd(ivec2 a, ivec2 b, ivec2 dest) CGLM_INLINE void glm_ivec2_subsub(ivec2 a, ivec2 b, ivec2 dest) CGLM_INLINE void glm_ivec2_subsubs(ivec2 a, int s, ivec2 dest) CGLM_INLINE void glm_ivec2_addsub(ivec2 a, ivec2 b, ivec2 dest) CGLM_INLINE void glm_ivec2_addsubs(ivec2 a, int s, ivec2 dest) CGLM_INLINE void glm_ivec2_mulsub(ivec2 a, ivec2 b, ivec2 dest) CGLM_INLINE void glm_ivec2_mulsubs(ivec2 a, int s, ivec2 dest) CGLM_INLINE void glm_ivec2_maxsub(ivec2 a, ivec2 b, ivec2 dest) CGLM_INLINE void glm_ivec2_minsub(ivec2 a, ivec2 b, ivec2 dest) CGLM_INLINE int glm_ivec2_distance2(ivec2 a, ivec2 b) CGLM_INLINE float glm_ivec2_distance(ivec2 a, ivec2 b) CGLM_INLINE void glm_ivec2_fill(ivec2 v, int val); CGLM_INLINE bool glm_ivec2_eq(ivec2 v, int val); CGLM_INLINE bool glm_ivec2_eqv(ivec2 a, ivec2 b); CGLM_INLINE void glm_ivec2_maxv(ivec2 a, ivec2 b, ivec2 dest) CGLM_INLINE void glm_ivec2_minv(ivec2 a, ivec2 b, ivec2 dest) CGLM_INLINE void glm_ivec2_clamp(ivec2 v, int minVal, int maxVal) CGLM_INLINE void glm_ivec2_abs(ivec2 v, ivec2 dest) */ #ifndef cglm_ivec2_h #define cglm_ivec2_h #include "common.h" #include "util.h" #define GLM_IVEC2_ONE_INIT {1, 1} #define GLM_IVEC2_ZERO_INIT {0, 0} #define GLM_IVEC2_ONE ((ivec2)GLM_IVEC2_ONE_INIT) #define GLM_IVEC2_ZERO ((ivec2)GLM_IVEC2_ZERO_INIT) /*! * @brief init ivec2 using vec3 or vec4 * * @param[in] v vector * @param[out] dest destination */ CGLM_INLINE void glm_ivec2(int * __restrict v, ivec2 dest) { dest[0] = v[0]; dest[1] = v[1]; } /*! * @brief copy all members of [a] to [dest] * * @param[in] a source vector * @param[out] dest destination */ CGLM_INLINE void glm_ivec2_copy(ivec2 a, ivec2 dest) { dest[0] = a[0]; dest[1] = a[1]; } /*! * @brief set all members of [v] to zero * * @param[out] v vector */ CGLM_INLINE void glm_ivec2_zero(ivec2 v) { v[0] = v[1] = 0; } /*! * @brief set all members of [v] to one * * @param[out] v vector */ CGLM_INLINE void glm_ivec2_one(ivec2 v) { v[0] = v[1] = 1; } /*! * @brief ivec2 dot product * * @param[in] a vector1 * @param[in] b vector2 * * @return dot product */ CGLM_INLINE int glm_ivec2_dot(ivec2 a, ivec2 b) { return a[0] * b[0] + a[1] * b[1]; } /*! * @brief ivec2 cross product * * REF: http://allenchou.net/2013/07/cross-product-of-2d-vectors/ * * @param[in] a vector1 * @param[in] b vector2 * * @return Z component of cross product */ CGLM_INLINE int glm_ivec2_cross(ivec2 a, ivec2 b) { return a[0] * b[1] - a[1] * b[0]; } /*! * @brief add vector [a] to vector [b] and store result in [dest] * * @param[in] a first vector * @param[in] b second vector * @param[out] dest destination */ CGLM_INLINE void glm_ivec2_add(ivec2 a, ivec2 b, ivec2 dest) { dest[0] = a[0] + b[0]; dest[1] = a[1] + b[1]; } /*! * @brief add scalar s to vector [v] and store result in [dest] * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination */ CGLM_INLINE void glm_ivec2_adds(ivec2 v, int s, ivec2 dest) { dest[0] = v[0] + s; dest[1] = v[1] + s; } /*! * @brief subtract vector [b] from vector [a] and store result in [dest] * * @param[in] a first vector * @param[in] b second vector * @param[out] dest destination */ CGLM_INLINE void glm_ivec2_sub(ivec2 a, ivec2 b, ivec2 dest) { dest[0] = a[0] - b[0]; dest[1] = a[1] - b[1]; } /*! * @brief subtract scalar s from vector [v] and store result in [dest] * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination */ CGLM_INLINE void glm_ivec2_subs(ivec2 v, int s, ivec2 dest) { dest[0] = v[0] - s; dest[1] = v[1] - s; } /*! * @brief multiply vector [a] with vector [b] and store result in [dest] * * @param[in] a first vector * @param[in] b second vector * @param[out] dest destination */ CGLM_INLINE void glm_ivec2_mul(ivec2 a, ivec2 b, ivec2 dest) { dest[0] = a[0] * b[0]; dest[1] = a[1] * b[1]; } /*! * @brief multiply vector [a] with scalar s and store result in [dest] * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination */ CGLM_INLINE void glm_ivec2_scale(ivec2 v, int s, ivec2 dest) { dest[0] = v[0] * s; dest[1] = v[1] * s; } /*! * @brief div vector with another component-wise division: d = a / b * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest result = (a[0]/b[0], a[1]/b[1]) */ CGLM_INLINE void glm_ivec2_div(ivec2 a, ivec2 b, ivec2 dest) { dest[0] = a[0] / b[0]; dest[1] = a[1] / b[1]; } /*! * @brief div vector with scalar: d = v / s * * @param[in] v vector * @param[in] s scalar * @param[out] dest result = (a[0]/s, a[1]/s) */ CGLM_INLINE void glm_ivec2_divs(ivec2 v, int s, ivec2 dest) { dest[0] = v[0] / s; dest[1] = v[1] / s; } /*! * @brief mod vector with another component-wise modulo: d = a % b * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest result = (a[0]%b[0], a[1]%b[1]) */ CGLM_INLINE void glm_ivec2_mod(ivec2 a, ivec2 b, ivec2 dest) { dest[0] = a[0] % b[0]; dest[1] = a[1] % b[1]; } /*! * @brief add vector [a] with vector [b] and add result to vector [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[out] dest dest += (a + b) */ CGLM_INLINE void glm_ivec2_addadd(ivec2 a, ivec2 b, ivec2 dest) { dest[0] += a[0] + b[0]; dest[1] += a[1] + b[1]; } /*! * @brief add scalar [s] onto vector [a] and add result to vector [dest] * * applies += operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[out] dest dest += (a + s) */ CGLM_INLINE void glm_ivec2_addadds(ivec2 a, int s, ivec2 dest) { dest[0] += a[0] + s; dest[1] += a[1] + s; } /*! * @brief subtract vector [a] from vector [b] and add result to [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[out] dest dest += (a - b) */ CGLM_INLINE void glm_ivec2_subadd(ivec2 a, ivec2 b, ivec2 dest) { dest[0] += a[0] - b[0]; dest[1] += a[1] - b[1]; } /*! * @brief subtract scalar [s] from vector [a] and add result to [dest] * * applies += operator so dest must be initialized * * @param[in] a first * @param[in] s scalar * @param[out] dest dest += (a - s) */ CGLM_INLINE void glm_ivec2_subadds(ivec2 a, int s, ivec2 dest) { dest[0] += a[0] - s; dest[1] += a[1] - s; } /*! * @brief multiply vector [a] with vector [b] and add result to [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[out] dest dest += (a * b) */ CGLM_INLINE void glm_ivec2_muladd(ivec2 a, ivec2 b, ivec2 dest) { dest[0] += a[0] * b[0]; dest[1] += a[1] * b[1]; } /*! * @brief multiply vector [a] with scalar [s] and add result to [dest] * * applies += operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[out] dest dest += (a * s) */ CGLM_INLINE void glm_ivec2_muladds(ivec2 a, int s, ivec2 dest) { dest[0] += a[0] * s; dest[1] += a[1] * s; } /*! * @brief add maximum of vector [a] and vector [b] to vector [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[out] dest dest += max(a, b) */ CGLM_INLINE void glm_ivec2_maxadd(ivec2 a, ivec2 b, ivec2 dest) { dest[0] += glm_imax(a[0], b[0]); dest[1] += glm_imax(a[1], b[1]); } /*! * @brief add minimum of vector [a] and vector [b] to vector [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[out] dest dest += min(a, b) */ CGLM_INLINE void glm_ivec2_minadd(ivec2 a, ivec2 b, ivec2 dest) { dest[0] += glm_imin(a[0], b[0]); dest[1] += glm_imin(a[1], b[1]); } /*! * @brief subtract vector [a] from vector [b] and subtract result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[out] dest dest -= (a - b) */ CGLM_INLINE void glm_ivec2_subsub(ivec2 a, ivec2 b, ivec2 dest) { dest[0] -= a[0] - b[0]; dest[1] -= a[1] - b[1]; } /*! * @brief subtract scalar [s] from vector [a] and subtract result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[out] dest dest -= (a - s) */ CGLM_INLINE void glm_ivec2_subsubs(ivec2 a, int s, ivec2 dest) { dest[0] -= a[0] - s; dest[1] -= a[1] - s; } /*! * @brief add vector [a] to vector [b] and subtract the result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] b scalar * @param[out] dest dest -= (a + b) */ CGLM_INLINE void glm_ivec2_addsub(ivec2 a, ivec2 b, ivec2 dest) { dest[0] -= a[0] + b[0]; dest[1] -= a[1] + b[1]; } /*! * @brief add scalar [s] to vector [a] and subtract the result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[out] dest dest -= (a + b) */ CGLM_INLINE void glm_ivec2_addsubs(ivec2 a, int s, ivec2 dest) { dest[0] -= a[0] + s; dest[1] -= a[1] + s; } /*! * @brief multiply vector [a] and vector [b] and subtract the result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] b scalar * @param[out] dest dest -= (a * b) */ CGLM_INLINE void glm_ivec2_mulsub(ivec2 a, ivec2 b, ivec2 dest) { dest[0] -= a[0] * b[0]; dest[1] -= a[1] * b[1]; } /*! * @brief multiply vector [a] with scalar [s] and subtract the result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[out] dest dest -= (a * s) */ CGLM_INLINE void glm_ivec2_mulsubs(ivec2 a, int s, ivec2 dest) { dest[0] -= a[0] * s; dest[1] -= a[1] * s; } /*! * @brief subtract maximum of vector [a] and vector [b] from vector [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[out] dest dest -= max(a, b) */ CGLM_INLINE void glm_ivec2_maxsub(ivec2 a, ivec2 b, ivec2 dest) { dest[0] -= glm_imax(a[0], b[0]); dest[1] -= glm_imax(a[1], b[1]); } /*! * @brief subtract minimum of vector [a] and vector [b] from vector [dest] * * applies -= operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[out] dest dest -= min(a, b) */ CGLM_INLINE void glm_ivec2_minsub(ivec2 a, ivec2 b, ivec2 dest) { dest[0] -= glm_imin(a[0], b[0]); dest[1] -= glm_imin(a[1], b[1]); } /*! * @brief squared distance between two vectors * * @param[in] a first vector * @param[in] b second vector * @return returns squared distance (distance * distance) */ CGLM_INLINE int glm_ivec2_distance2(ivec2 a, ivec2 b) { int xd, yd; xd = a[0] - b[0]; yd = a[1] - b[1]; return xd * xd + yd * yd; } /*! * @brief distance between two vectors * * @param[in] a first vector * @param[in] b second vector * @return returns distance */ CGLM_INLINE float glm_ivec2_distance(ivec2 a, ivec2 b) { return sqrtf((float)glm_ivec2_distance2(a, b)); } /*! * @brief fill a vector with specified value * * @param[out] v dest * @param[in] val value */ CGLM_INLINE void glm_ivec2_fill(ivec2 v, int val) { v[0] = v[1] = val; } /*! * @brief check if vector is equal to value * * @param[in] v vector * @param[in] val value */ CGLM_INLINE bool glm_ivec2_eq(ivec2 v, int val) { return v[0] == val && v[0] == v[1]; } /*! * @brief check if vector is equal to another * * @param[in] a vector * @param[in] b vector */ CGLM_INLINE bool glm_ivec2_eqv(ivec2 a, ivec2 b) { return a[0] == b[0] && a[1] == b[1]; } /*! * @brief set each member of dest to greater of vector a and b * * @param[in] a first vector * @param[in] b second vector * @param[out] dest destination */ CGLM_INLINE void glm_ivec2_maxv(ivec2 a, ivec2 b, ivec2 dest) { dest[0] = a[0] > b[0] ? a[0] : b[0]; dest[1] = a[1] > b[1] ? a[1] : b[1]; } /*! * @brief set each member of dest to lesser of vector a and b * * @param[in] a first vector * @param[in] b second vector * @param[out] dest destination */ CGLM_INLINE void glm_ivec2_minv(ivec2 a, ivec2 b, ivec2 dest) { dest[0] = a[0] < b[0] ? a[0] : b[0]; dest[1] = a[1] < b[1] ? a[1] : b[1]; } /*! * @brief clamp each member of [v] between minVal and maxVal (inclusive) * * @param[in, out] v vector * @param[in] minVal minimum value * @param[in] maxVal maximum value */ CGLM_INLINE void glm_ivec2_clamp(ivec2 v, int minVal, int maxVal) { if (v[0] < minVal) v[0] = minVal; else if(v[0] > maxVal) v[0] = maxVal; if (v[1] < minVal) v[1] = minVal; else if(v[1] > maxVal) v[1] = maxVal; } /*! * @brief absolute value of v * * @param[in] v vector * @param[out] dest destination */ CGLM_INLINE void glm_ivec2_abs(ivec2 v, ivec2 dest) { dest[0] = abs(v[0]); dest[1] = abs(v[1]); } #endif /* cglm_ivec2_h */ cglm-0.9.7/include/cglm/ivec3.h000066400000000000000000000400361526744317200162160ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLM_IVEC3_ONE_INIT GLM_IVEC3_ZERO_INIT GLM_IVEC3_ONE GLM_IVEC3_ZERO Functions: CGLM_INLINE void glm_ivec3(ivec4 v4, ivec3 dest) CGLM_INLINE void glm_ivec3_copy(ivec3 a, ivec3 dest) CGLM_INLINE void glm_ivec3_zero(ivec3 v) CGLM_INLINE void glm_ivec3_one(ivec3 v) CGLM_INLINE int glm_ivec3_dot(ivec3 a, ivec3 b) CGLM_INLINE int glm_ivec3_norm2(ivec3 v) CGLM_INLINE int glm_ivec3_norm(ivec3 v) CGLM_INLINE void glm_ivec3_add(ivec3 a, ivec3 b, ivec3 dest) CGLM_INLINE void glm_ivec3_adds(ivec3 v, int s, ivec3 dest) CGLM_INLINE void glm_ivec3_sub(ivec3 a, ivec3 b, ivec3 dest) CGLM_INLINE void glm_ivec3_subs(ivec3 v, int s, ivec3 dest) CGLM_INLINE void glm_ivec3_mul(ivec3 a, ivec3 b, ivec3 dest) CGLM_INLINE void glm_ivec3_scale(ivec3 v, int s, ivec3 dest) CGLM_INLINE void glm_ivec3_div(ivec3 a, ivec3 b, ivec3 dest) CGLM_INLINE void glm_ivec3_divs(ivec3 v, int s, ivec3 dest) CGLM_INLINE void glm_ivec3_mod(ivec3 a, ivec3 b, ivec3 dest) CGLM_INLINE void glm_ivec3_addadd(ivec3 a, ivec3 b, ivec3 dest) CGLM_INLINE void glm_ivec3_addadds(ivec3 a, int s, ivec3 dest) CGLM_INLINE void glm_ivec3_subadd(ivec3 a, ivec3 b, ivec3 dest) CGLM_INLINE void glm_ivec3_subadds(ivec3 a, int s, ivec3 dest) CGLM_INLINE void glm_ivec3_muladd(ivec3 a, ivec3 b, ivec3 dest) CGLM_INLINE void glm_ivec3_muladds(ivec3 a, int s, ivec3 dest) CGLM_INLINE void glm_ivec3_maxadd(ivec3 a, ivec3 b, ivec3 dest) CGLM_INLINE void glm_ivec3_minadd(ivec3 a, ivec3 b, ivec3 dest) CGLM_INLINE void glm_ivec3_subsub(ivec3 a, ivec3 b, ivec3 dest) CGLM_INLINE void glm_ivec3_subsubs(ivec3 a, int s, ivec3 dest) CGLM_INLINE void glm_ivec3_addsub(ivec3 a, ivec3 b, ivec3 dest) CGLM_INLINE void glm_ivec3_addsubs(ivec3 a, int s, ivec3 dest) CGLM_INLINE void glm_ivec3_mulsub(ivec3 a, ivec3 b, ivec3 dest) CGLM_INLINE void glm_ivec3_mulsubs(ivec3 a, int s, ivec3 dest) CGLM_INLINE void glm_ivec3_maxsub(ivec3 a, ivec3 b, ivec3 dest) CGLM_INLINE void glm_ivec3_minsub(ivec3 a, ivec3 b, ivec3 dest) CGLM_INLINE int glm_ivec3_distance2(ivec3 a, ivec3 b) CGLM_INLINE float glm_ivec3_distance(ivec3 a, ivec3 b) CGLM_INLINE void glm_ivec3_fill(ivec3 v, int val); CGLM_INLINE bool glm_ivec3_eq(ivec3 v, int val); CGLM_INLINE bool glm_ivec3_eqv(ivec3 a, ivec3 b); CGLM_INLINE void glm_ivec3_maxv(ivec3 a, ivec3 b, ivec3 dest) CGLM_INLINE void glm_ivec3_minv(ivec3 a, ivec3 b, ivec3 dest) CGLM_INLINE void glm_ivec3_clamp(ivec3 v, int minVal, int maxVal) CGLM_INLINE void glm_ivec3_abs(ivec3 v, ivec3 dest) */ #ifndef cglm_ivec3_h #define cglm_ivec3_h #include "common.h" #include "util.h" #define GLM_IVEC3_ONE_INIT {1, 1, 1} #define GLM_IVEC3_ZERO_INIT {0, 0, 0} #define GLM_IVEC3_ONE ((ivec3)GLM_IVEC3_ONE_INIT) #define GLM_IVEC3_ZERO ((ivec3)GLM_IVEC3_ZERO_INIT) /*! * @brief init ivec3 using ivec4 * * @param[in] v4 vector4 * @param[out] dest destination */ CGLM_INLINE void glm_ivec3(ivec4 v4, ivec3 dest) { dest[0] = v4[0]; dest[1] = v4[1]; dest[2] = v4[2]; } /*! * @brief copy all members of [a] to [dest] * * @param[in] a source vector * @param[out] dest destination */ CGLM_INLINE void glm_ivec3_copy(ivec3 a, ivec3 dest) { dest[0] = a[0]; dest[1] = a[1]; dest[2] = a[2]; } /*! * @brief set all members of [v] to zero * * @param[out] v vector */ CGLM_INLINE void glm_ivec3_zero(ivec3 v) { v[0] = v[1] = v[2] = 0; } /*! * @brief set all members of [v] to one * * @param[out] v vector */ CGLM_INLINE void glm_ivec3_one(ivec3 v) { v[0] = v[1] = v[2] = 1; } /*! * @brief ivec3 dot product * * @param[in] a vector1 * @param[in] b vector2 * * @return dot product */ CGLM_INLINE int glm_ivec3_dot(ivec3 a, ivec3 b) { return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; } /*! * @brief norm * norm (magnitude) of vec * * we can use this func instead of calling norm * norm, because it would call * sqrtf function twice but with this func we can avoid func call, maybe this is * not good name for this func * * @param[in] v vector * * @return norm * norm */ CGLM_INLINE int glm_ivec3_norm2(ivec3 v) { return glm_ivec3_dot(v, v); } /*! * @brief euclidean norm (magnitude), also called L2 norm * this will give magnitude of vector in euclidean space * * @param[in] v vector * * @return norm */ CGLM_INLINE int glm_ivec3_norm(ivec3 v) { return (int)sqrtf((float)glm_ivec3_norm2(v)); } /*! * @brief add vector [a] to vector [b] and store result in [dest] * * @param[in] a first vector * @param[in] b second vector * @param[out] dest destination */ CGLM_INLINE void glm_ivec3_add(ivec3 a, ivec3 b, ivec3 dest) { dest[0] = a[0] + b[0]; dest[1] = a[1] + b[1]; dest[2] = a[2] + b[2]; } /*! * @brief add scalar s to vector [v] and store result in [dest] * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination */ CGLM_INLINE void glm_ivec3_adds(ivec3 v, int s, ivec3 dest) { dest[0] = v[0] + s; dest[1] = v[1] + s; dest[2] = v[2] + s; } /*! * @brief subtract vector [b] from vector [a] and store result in [dest] * * @param[in] a first vector * @param[in] b second vector * @param[out] dest destination */ CGLM_INLINE void glm_ivec3_sub(ivec3 a, ivec3 b, ivec3 dest) { dest[0] = a[0] - b[0]; dest[1] = a[1] - b[1]; dest[2] = a[2] - b[2]; } /*! * @brief subtract scalar s from vector [v] and store result in [dest] * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination */ CGLM_INLINE void glm_ivec3_subs(ivec3 v, int s, ivec3 dest) { dest[0] = v[0] - s; dest[1] = v[1] - s; dest[2] = v[2] - s; } /*! * @brief multiply vector [a] with vector [b] and store result in [dest] * * @param[in] a first vector * @param[in] b second vector * @param[out] dest destination */ CGLM_INLINE void glm_ivec3_mul(ivec3 a, ivec3 b, ivec3 dest) { dest[0] = a[0] * b[0]; dest[1] = a[1] * b[1]; dest[2] = a[2] * b[2]; } /*! * @brief multiply vector [a] with scalar s and store result in [dest] * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination */ CGLM_INLINE void glm_ivec3_scale(ivec3 v, int s, ivec3 dest) { dest[0] = v[0] * s; dest[1] = v[1] * s; dest[2] = v[2] * s; } /*! * @brief div vector with another component-wise division: d = a / b * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest result = (a[0]/b[0], a[1]/b[1], a[2]/b[2]) */ CGLM_INLINE void glm_ivec3_div(ivec3 a, ivec3 b, ivec3 dest) { dest[0] = a[0] / b[0]; dest[1] = a[1] / b[1]; dest[2] = a[2] / b[2]; } /*! * @brief div vector with scalar: d = v / s * * @param[in] v vector * @param[in] s scalar * @param[out] dest result = (a[0]/s, a[1]/s, a[2]/s) */ CGLM_INLINE void glm_ivec3_divs(ivec3 v, int s, ivec3 dest) { dest[0] = v[0] / s; dest[1] = v[1] / s; dest[2] = v[2] / s; } /*! * @brief Element-wise modulo operation on ivec3 vectors: dest = a % b * * Performs element-wise modulo on each component of vectors `a` and `b`. * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest result = (a[0]%b[0], a[1]%b[1], a[2]%b[2]) */ CGLM_INLINE void glm_ivec3_mod(ivec3 a, ivec3 b, ivec3 dest) { dest[0] = a[0] % b[0]; dest[1] = a[1] % b[1]; dest[2] = a[2] % b[2]; } /*! * @brief add vector [a] with vector [b] and add result to vector [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[out] dest dest += (a + b) */ CGLM_INLINE void glm_ivec3_addadd(ivec3 a, ivec3 b, ivec3 dest) { dest[0] += a[0] + b[0]; dest[1] += a[1] + b[1]; dest[2] += a[2] + b[2]; } /*! * @brief add scalar [s] onto vector [a] and add result to vector [dest] * * applies += operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[out] dest dest += (a + s) */ CGLM_INLINE void glm_ivec3_addadds(ivec3 a, int s, ivec3 dest) { dest[0] += a[0] + s; dest[1] += a[1] + s; dest[2] += a[2] + s; } /*! * @brief subtract vector [a] from vector [b] and add result to [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[out] dest dest += (a - b) */ CGLM_INLINE void glm_ivec3_subadd(ivec3 a, ivec3 b, ivec3 dest) { dest[0] += a[0] - b[0]; dest[1] += a[1] - b[1]; dest[2] += a[2] - b[2]; } /*! * @brief subtract scalar [s] from vector [a] and add result to [dest] * * applies += operator so dest must be initialized * * @param[in] a first * @param[in] s scalar * @param[out] dest dest += (a - s) */ CGLM_INLINE void glm_ivec3_subadds(ivec3 a, int s, ivec3 dest) { dest[0] += a[0] - s; dest[1] += a[1] - s; dest[2] += a[2] - s; } /*! * @brief multiply vector [a] with vector [b] and add result to [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[out] dest dest += (a * b) */ CGLM_INLINE void glm_ivec3_muladd(ivec3 a, ivec3 b, ivec3 dest) { dest[0] += a[0] * b[0]; dest[1] += a[1] * b[1]; dest[2] += a[2] * b[2]; } /*! * @brief multiply vector [a] with scalar [s] and add result to [dest] * * applies += operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[out] dest dest += (a * s) */ CGLM_INLINE void glm_ivec3_muladds(ivec3 a, int s, ivec3 dest) { dest[0] += a[0] * s; dest[1] += a[1] * s; dest[2] += a[2] * s; } /*! * @brief add maximum of vector [a] and vector [b] to vector [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[out] dest dest += max(a, b) */ CGLM_INLINE void glm_ivec3_maxadd(ivec3 a, ivec3 b, ivec3 dest) { dest[0] += glm_imax(a[0], b[0]); dest[1] += glm_imax(a[1], b[1]); dest[2] += glm_imax(a[2], b[2]); } /*! * @brief add minimum of vector [a] and vector [b] to vector [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[out] dest dest += min(a, b) */ CGLM_INLINE void glm_ivec3_minadd(ivec3 a, ivec3 b, ivec3 dest) { dest[0] += glm_imin(a[0], b[0]); dest[1] += glm_imin(a[1], b[1]); dest[2] += glm_imin(a[2], b[2]); } /*! * @brief subtract vector [a] from vector [b] and subtract result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[out] dest dest -= (a - b) */ CGLM_INLINE void glm_ivec3_subsub(ivec3 a, ivec3 b, ivec3 dest) { dest[0] -= a[0] - b[0]; dest[1] -= a[1] - b[1]; dest[2] -= a[2] - b[2]; } /*! * @brief subtract scalar [s] from vector [a] and subtract result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[out] dest dest -= (a - s) */ CGLM_INLINE void glm_ivec3_subsubs(ivec3 a, int s, ivec3 dest) { dest[0] -= a[0] - s; dest[1] -= a[1] - s; dest[2] -= a[2] - s; } /*! * @brief add vector [a] to vector [b] and subtract the result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] b scalar * @param[out] dest dest -= (a + b) */ CGLM_INLINE void glm_ivec3_addsub(ivec3 a, ivec3 b, ivec3 dest) { dest[0] -= a[0] + b[0]; dest[1] -= a[1] + b[1]; dest[2] -= a[2] + b[2]; } /*! * @brief add scalar [s] to vector [a] and subtract the result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[out] dest dest -= (a + b) */ CGLM_INLINE void glm_ivec3_addsubs(ivec3 a, int s, ivec3 dest) { dest[0] -= a[0] + s; dest[1] -= a[1] + s; dest[2] -= a[2] + s; } /*! * @brief multiply vector [a] and vector [b] and subtract the result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] b scalar * @param[out] dest dest -= (a * b) */ CGLM_INLINE void glm_ivec3_mulsub(ivec3 a, ivec3 b, ivec3 dest) { dest[0] -= a[0] * b[0]; dest[1] -= a[1] * b[1]; dest[2] -= a[2] * b[2]; } /*! * @brief multiply vector [a] with scalar [s] and subtract the result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[out] dest dest -= (a * s) */ CGLM_INLINE void glm_ivec3_mulsubs(ivec3 a, int s, ivec3 dest) { dest[0] -= a[0] * s; dest[1] -= a[1] * s; dest[2] -= a[2] * s; } /*! * @brief subtract maximum of vector [a] and vector [b] from vector [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[out] dest dest -= max(a, b) */ CGLM_INLINE void glm_ivec3_maxsub(ivec3 a, ivec3 b, ivec3 dest) { dest[0] -= glm_imax(a[0], b[0]); dest[1] -= glm_imax(a[1], b[1]); dest[2] -= glm_imax(a[2], b[2]); } /*! * @brief subtract minimum of vector [a] and vector [b] from vector [dest] * * applies -= operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[out] dest dest -= min(a, b) */ CGLM_INLINE void glm_ivec3_minsub(ivec3 a, ivec3 b, ivec3 dest) { dest[0] -= glm_imin(a[0], b[0]); dest[1] -= glm_imin(a[1], b[1]); dest[2] -= glm_imin(a[2], b[2]); } /*! * @brief squared distance between two vectors * * @param[in] a first vector * @param[in] b second vector * @return returns squared distance (distance * distance) */ CGLM_INLINE int glm_ivec3_distance2(ivec3 a, ivec3 b) { int xd, yd, zd; xd = a[0] - b[0]; yd = a[1] - b[1]; zd = a[2] - b[2]; return xd * xd + yd * yd + zd * zd; } /*! * @brief distance between two vectors * * @param[in] a first vector * @param[in] b second vector * @return returns distance */ CGLM_INLINE float glm_ivec3_distance(ivec3 a, ivec3 b) { return sqrtf((float)glm_ivec3_distance2(a, b)); } /*! * @brief fill a vector with specified value * * @param[out] v dest * @param[in] val value */ CGLM_INLINE void glm_ivec3_fill(ivec3 v, int val) { v[0] = v[1] = v[2] = val; } /*! * @brief check if vector is equal to value * * @param[in] v vector * @param[in] val value */ CGLM_INLINE bool glm_ivec3_eq(ivec3 v, int val) { return v[0] == val && v[0] == v[1] && v[0] == v[2]; } /*! * @brief check if vector is equal to another * * @param[in] a vector * @param[in] b vector */ CGLM_INLINE bool glm_ivec3_eqv(ivec3 a, ivec3 b) { return a[0] == b[0] && a[1] == b[1] && a[2] == b[2]; } /*! * @brief set each member of dest to greater of vector a and b * * @param[in] a first vector * @param[in] b second vector * @param[out] dest destination */ CGLM_INLINE void glm_ivec3_maxv(ivec3 a, ivec3 b, ivec3 dest) { dest[0] = a[0] > b[0] ? a[0] : b[0]; dest[1] = a[1] > b[1] ? a[1] : b[1]; dest[2] = a[2] > b[2] ? a[2] : b[2]; } /*! * @brief set each member of dest to lesser of vector a and b * * @param[in] a first vector * @param[in] b second vector * @param[out] dest destination */ CGLM_INLINE void glm_ivec3_minv(ivec3 a, ivec3 b, ivec3 dest) { dest[0] = a[0] < b[0] ? a[0] : b[0]; dest[1] = a[1] < b[1] ? a[1] : b[1]; dest[2] = a[2] < b[2] ? a[2] : b[2]; } /*! * @brief clamp each member of [v] between minVal and maxVal (inclusive) * * @param[in, out] v vector * @param[in] minVal minimum value * @param[in] maxVal maximum value */ CGLM_INLINE void glm_ivec3_clamp(ivec3 v, int minVal, int maxVal) { if (v[0] < minVal) v[0] = minVal; else if(v[0] > maxVal) v[0] = maxVal; if (v[1] < minVal) v[1] = minVal; else if(v[1] > maxVal) v[1] = maxVal; if (v[2] < minVal) v[2] = minVal; else if(v[2] > maxVal) v[2] = maxVal; } /*! * @brief absolute value of v * * @param[in] v vector * @param[out] dest destination */ CGLM_INLINE void glm_ivec3_abs(ivec3 v, ivec3 dest) { dest[0] = abs(v[0]); dest[1] = abs(v[1]); dest[2] = abs(v[2]); } #endif /* cglm_ivec3_h */ cglm-0.9.7/include/cglm/ivec4.h000066400000000000000000000337301526744317200162220ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLM_IVEC4_ONE_INIT GLM_IVEC4_ZERO_INIT GLM_IVEC4_ONE GLM_IVEC4_ZERO Functions: CGLM_INLINE void glm_ivec4(ivec3 v3, int last, ivec4 dest) CGLM_INLINE void glm_ivec4_copy(ivec4 a, ivec4 dest) CGLM_INLINE void glm_ivec4_zero(ivec4 v) CGLM_INLINE void glm_ivec4_one(ivec4 v) CGLM_INLINE void glm_ivec4_add(ivec4 a, ivec4 b, ivec4 dest) CGLM_INLINE void glm_ivec4_adds(ivec4 v, int s, ivec4 dest) CGLM_INLINE void glm_ivec4_sub(ivec4 a, ivec4 b, ivec4 dest) CGLM_INLINE void glm_ivec4_subs(ivec4 v, int s, ivec4 dest) CGLM_INLINE void glm_ivec4_mul(ivec4 a, ivec4 b, ivec4 dest) CGLM_INLINE void glm_ivec4_scale(ivec4 v, int s, ivec4 dest) CGLM_INLINE void glm_ivec4_addadd(ivec4 a, ivec4 b, ivec4 dest) CGLM_INLINE void glm_ivec4_addadds(ivec4 a, int s, ivec4 dest) CGLM_INLINE void glm_ivec4_subadd(ivec4 a, ivec4 b, ivec4 dest) CGLM_INLINE void glm_ivec4_subadds(ivec4 a, int s, ivec4 dest) CGLM_INLINE void glm_ivec4_muladd(ivec4 a, ivec4 b, ivec4 dest) CGLM_INLINE void glm_ivec4_muladds(ivec4 a, int s, ivec4 dest) CGLM_INLINE void glm_ivec4_maxadd(ivec4 a, ivec4 b, ivec4 dest) CGLM_INLINE void glm_ivec4_minadd(ivec4 a, ivec4 b, ivec4 dest) CGLM_INLINE void glm_ivec4_subsub(ivec4 a, ivec4 b, ivec4 dest) CGLM_INLINE void glm_ivec4_subsubs(ivec4 a, int s, ivec4 dest) CGLM_INLINE void glm_ivec4_addsub(ivec4 a, ivec4 b, ivec4 dest) CGLM_INLINE void glm_ivec4_addsubs(ivec4 a, int s, ivec4 dest) CGLM_INLINE void glm_ivec4_mulsub(ivec4 a, ivec4 b, ivec4 dest) CGLM_INLINE void glm_ivec4_mulsubs(ivec4 a, int s, ivec4 dest) CGLM_INLINE void glm_ivec4_maxsub(ivec4 a, ivec4 b, ivec4 dest) CGLM_INLINE void glm_ivec4_minsub(ivec4 a, ivec4 b, ivec4 dest) CGLM_INLINE int glm_ivec4_distance2(ivec4 a, ivec4 b) CGLM_INLINE float glm_ivec4_distance(ivec4 a, ivec4 b) CGLM_INLINE void glm_ivec4_maxv(ivec4 a, ivec4 b, ivec4 dest) CGLM_INLINE void glm_ivec4_minv(ivec4 a, ivec4 b, ivec4 dest) CGLM_INLINE void glm_ivec4_clamp(ivec4 v, int minVal, int maxVal) CGLM_INLINE void glm_ivec4_abs(ivec4 v, ivec4 dest) */ #ifndef cglm_ivec4_h #define cglm_ivec4_h #include "common.h" #include "util.h" #define GLM_IVEC4_ONE_INIT {1, 1, 1, 1} #define GLM_IVEC4_ZERO_INIT {0, 0, 0, 0} #define GLM_IVEC4_ONE ((ivec4)GLM_IVEC4_ONE_INIT) #define GLM_IVEC4_ZERO ((ivec4)GLM_IVEC4_ZERO_INIT) /*! * @brief init ivec4 using ivec3 * * @param[in] v3 vector3 * @param[in] last last item * @param[out] dest destination */ CGLM_INLINE void glm_ivec4(ivec3 v3, int last, ivec4 dest) { dest[0] = v3[0]; dest[1] = v3[1]; dest[2] = v3[2]; dest[3] = last; } /*! * @brief copy all members of [a] to [dest] * * @param[in] a source vector * @param[out] dest destination */ CGLM_INLINE void glm_ivec4_copy(ivec4 a, ivec4 dest) { dest[0] = a[0]; dest[1] = a[1]; dest[2] = a[2]; dest[3] = a[3]; } /*! * @brief set all members of [v] to zero * * @param[out] v vector */ CGLM_INLINE void glm_ivec4_zero(ivec4 v) { v[0] = v[1] = v[2] = v[3] = 0; } /*! * @brief set all members of [v] to one * * @param[out] v vector */ CGLM_INLINE void glm_ivec4_one(ivec4 v) { v[0] = v[1] = v[2] = v[3] = 1; } /*! * @brief add vector [a] to vector [b] and store result in [dest] * * @param[in] a first vector * @param[in] b second vector * @param[out] dest destination */ CGLM_INLINE void glm_ivec4_add(ivec4 a, ivec4 b, ivec4 dest) { dest[0] = a[0] + b[0]; dest[1] = a[1] + b[1]; dest[2] = a[2] + b[2]; dest[3] = a[3] + b[3]; } /*! * @brief add scalar s to vector [v] and store result in [dest] * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination */ CGLM_INLINE void glm_ivec4_adds(ivec4 v, int s, ivec4 dest) { dest[0] = v[0] + s; dest[1] = v[1] + s; dest[2] = v[2] + s; dest[3] = v[3] + s; } /*! * @brief subtract vector [b] from vector [a] and store result in [dest] * * @param[in] a first vector * @param[in] b second vector * @param[out] dest destination */ CGLM_INLINE void glm_ivec4_sub(ivec4 a, ivec4 b, ivec4 dest) { dest[0] = a[0] - b[0]; dest[1] = a[1] - b[1]; dest[2] = a[2] - b[2]; dest[3] = a[3] - b[3]; } /*! * @brief subtract scalar s from vector [v] and store result in [dest] * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination */ CGLM_INLINE void glm_ivec4_subs(ivec4 v, int s, ivec4 dest) { dest[0] = v[0] - s; dest[1] = v[1] - s; dest[2] = v[2] - s; dest[3] = v[3] - s; } /*! * @brief multiply vector [a] with vector [b] and store result in [dest] * * @param[in] a first vector * @param[in] b second vector * @param[out] dest destination */ CGLM_INLINE void glm_ivec4_mul(ivec4 a, ivec4 b, ivec4 dest) { dest[0] = a[0] * b[0]; dest[1] = a[1] * b[1]; dest[2] = a[2] * b[2]; dest[3] = a[3] * b[3]; } /*! * @brief multiply vector [a] with scalar s and store result in [dest] * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination */ CGLM_INLINE void glm_ivec4_scale(ivec4 v, int s, ivec4 dest) { dest[0] = v[0] * s; dest[1] = v[1] * s; dest[2] = v[2] * s; dest[3] = v[3] * s; } /*! * @brief add vector [a] with vector [b] and add result to vector [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[out] dest dest += (a + b) */ CGLM_INLINE void glm_ivec4_addadd(ivec4 a, ivec4 b, ivec4 dest) { dest[0] += a[0] + b[0]; dest[1] += a[1] + b[1]; dest[2] += a[2] + b[2]; dest[3] += a[3] + b[3]; } /*! * @brief add scalar [s] onto vector [a] and add result to vector [dest] * * applies += operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[out] dest dest += (a + s) */ CGLM_INLINE void glm_ivec4_addadds(ivec4 a, int s, ivec4 dest) { dest[0] += a[0] + s; dest[1] += a[1] + s; dest[2] += a[2] + s; dest[3] += a[3] + s; } /*! * @brief subtract vector [a] from vector [b] and add result to [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[out] dest dest += (a - b) */ CGLM_INLINE void glm_ivec4_subadd(ivec4 a, ivec4 b, ivec4 dest) { dest[0] += a[0] - b[0]; dest[1] += a[1] - b[1]; dest[2] += a[2] - b[2]; dest[3] += a[3] - b[3]; } /*! * @brief subtract scalar [s] from vector [a] and add result to [dest] * * applies += operator so dest must be initialized * * @param[in] a first * @param[in] s scalar * @param[out] dest dest += (a - s) */ CGLM_INLINE void glm_ivec4_subadds(ivec4 a, int s, ivec4 dest) { dest[0] += a[0] - s; dest[1] += a[1] - s; dest[2] += a[2] - s; dest[3] += a[3] - s; } /*! * @brief multiply vector [a] with vector [b] and add result to [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[out] dest dest += (a * b) */ CGLM_INLINE void glm_ivec4_muladd(ivec4 a, ivec4 b, ivec4 dest) { dest[0] += a[0] * b[0]; dest[1] += a[1] * b[1]; dest[2] += a[2] * b[2]; dest[3] += a[3] * b[3]; } /*! * @brief multiply vector [a] with scalar [s] and add result to [dest] * * applies += operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[out] dest dest += (a * s) */ CGLM_INLINE void glm_ivec4_muladds(ivec4 a, int s, ivec4 dest) { dest[0] += a[0] * s; dest[1] += a[1] * s; dest[2] += a[2] * s; dest[3] += a[3] * s; } /*! * @brief add maximum of vector [a] and vector [b] to vector [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[out] dest dest += max(a, b) */ CGLM_INLINE void glm_ivec4_maxadd(ivec4 a, ivec4 b, ivec4 dest) { dest[0] += glm_imax(a[0], b[0]); dest[1] += glm_imax(a[1], b[1]); dest[2] += glm_imax(a[2], b[2]); dest[3] += glm_imax(a[3], b[3]); } /*! * @brief add minimum of vector [a] and vector [b] to vector [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[out] dest dest += min(a, b) */ CGLM_INLINE void glm_ivec4_minadd(ivec4 a, ivec4 b, ivec4 dest) { dest[0] += glm_imin(a[0], b[0]); dest[1] += glm_imin(a[1], b[1]); dest[2] += glm_imin(a[2], b[2]); dest[3] += glm_imin(a[3], b[3]); } /*! * @brief subtract vector [a] from vector [b] and subtract result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[out] dest dest -= (a - b) */ CGLM_INLINE void glm_ivec4_subsub(ivec4 a, ivec4 b, ivec4 dest) { dest[0] -= a[0] - b[0]; dest[1] -= a[1] - b[1]; dest[2] -= a[2] - b[2]; dest[3] -= a[3] - b[3]; } /*! * @brief subtract scalar [s] from vector [a] and subtract result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[out] dest dest -= (a - s) */ CGLM_INLINE void glm_ivec4_subsubs(ivec4 a, int s, ivec4 dest) { dest[0] -= a[0] - s; dest[1] -= a[1] - s; dest[2] -= a[2] - s; dest[3] -= a[3] - s; } /*! * @brief add vector [a] to vector [b] and subtract the result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] b scalar * @param[out] dest dest -= (a + b) */ CGLM_INLINE void glm_ivec4_addsub(ivec4 a, ivec4 b, ivec4 dest) { dest[0] -= a[0] + b[0]; dest[1] -= a[1] + b[1]; dest[2] -= a[2] + b[2]; dest[3] -= a[3] + b[3]; } /*! * @brief add scalar [s] to vector [a] and subtract the result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[out] dest dest -= (a + b) */ CGLM_INLINE void glm_ivec4_addsubs(ivec4 a, int s, ivec4 dest) { dest[0] -= a[0] + s; dest[1] -= a[1] + s; dest[2] -= a[2] + s; dest[3] -= a[3] + s; } /*! * @brief multiply vector [a] and vector [b] and subtract the result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] b scalar * @param[out] dest dest -= (a * b) */ CGLM_INLINE void glm_ivec4_mulsub(ivec4 a, ivec4 b, ivec4 dest) { dest[0] -= a[0] * b[0]; dest[1] -= a[1] * b[1]; dest[2] -= a[2] * b[2]; dest[3] -= a[3] * b[3]; } /*! * @brief multiply vector [a] with scalar [s] and subtract the result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[out] dest dest -= (a * s) */ CGLM_INLINE void glm_ivec4_mulsubs(ivec4 a, int s, ivec4 dest) { dest[0] -= a[0] * s; dest[1] -= a[1] * s; dest[2] -= a[2] * s; dest[3] -= a[3] * s; } /*! * @brief subtract maximum of vector [a] and vector [b] from vector [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[out] dest dest -= max(a, b) */ CGLM_INLINE void glm_ivec4_maxsub(ivec4 a, ivec4 b, ivec4 dest) { dest[0] -= glm_imax(a[0], b[0]); dest[1] -= glm_imax(a[1], b[1]); dest[2] -= glm_imax(a[2], b[2]); dest[3] -= glm_imax(a[3], b[3]); } /*! * @brief subtract minimum of vector [a] and vector [b] from vector [dest] * * applies -= operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[out] dest dest -= min(a, b) */ CGLM_INLINE void glm_ivec4_minsub(ivec4 a, ivec4 b, ivec4 dest) { dest[0] -= glm_imin(a[0], b[0]); dest[1] -= glm_imin(a[1], b[1]); dest[2] -= glm_imin(a[2], b[2]); dest[3] -= glm_imin(a[3], b[3]); } /*! * @brief squared distance between two vectors * * @param[in] a first vector * @param[in] b second vector * @return returns squared distance (distance * distance) */ CGLM_INLINE int glm_ivec4_distance2(ivec4 a, ivec4 b) { int xd, yd, zd, wd; xd = a[0] - b[0]; yd = a[1] - b[1]; zd = a[2] - b[2]; wd = a[3] - b[3]; return xd * xd + yd * yd + zd * zd + wd * wd; } /*! * @brief distance between two vectors * * @param[in] a first vector * @param[in] b second vector * @return returns distance */ CGLM_INLINE float glm_ivec4_distance(ivec4 a, ivec4 b) { return sqrtf((float)glm_ivec4_distance2(a, b)); } /*! * @brief set each member of dest to greater of vector a and b * * @param[in] a first vector * @param[in] b second vector * @param[out] dest destination */ CGLM_INLINE void glm_ivec4_maxv(ivec4 a, ivec4 b, ivec4 dest) { dest[0] = a[0] > b[0] ? a[0] : b[0]; dest[1] = a[1] > b[1] ? a[1] : b[1]; dest[2] = a[2] > b[2] ? a[2] : b[2]; dest[3] = a[3] > b[3] ? a[3] : b[3]; } /*! * @brief set each member of dest to lesser of vector a and b * * @param[in] a first vector * @param[in] b second vector * @param[out] dest destination */ CGLM_INLINE void glm_ivec4_minv(ivec4 a, ivec4 b, ivec4 dest) { dest[0] = a[0] < b[0] ? a[0] : b[0]; dest[1] = a[1] < b[1] ? a[1] : b[1]; dest[2] = a[2] < b[2] ? a[2] : b[2]; dest[3] = a[3] < b[3] ? a[3] : b[3]; } /*! * @brief clamp each member of [v] between minVal and maxVal (inclusive) * * @param[in, out] v vector * @param[in] minVal minimum value * @param[in] maxVal maximum value */ CGLM_INLINE void glm_ivec4_clamp(ivec4 v, int minVal, int maxVal) { if (v[0] < minVal) v[0] = minVal; else if(v[0] > maxVal) v[0] = maxVal; if (v[1] < minVal) v[1] = minVal; else if(v[1] > maxVal) v[1] = maxVal; if (v[2] < minVal) v[2] = minVal; else if(v[2] > maxVal) v[2] = maxVal; if (v[3] < minVal) v[3] = minVal; else if(v[3] > maxVal) v[3] = maxVal; } /*! * @brief absolute value of v * * @param[in] v vector * @param[out] dest destination */ CGLM_INLINE void glm_ivec4_abs(ivec4 v, ivec4 dest) { dest[0] = abs(v[0]); dest[1] = abs(v[1]); dest[2] = abs(v[2]); dest[3] = abs(v[3]); } #endif /* cglm_ivec4_h */ cglm-0.9.7/include/cglm/mat2.h000066400000000000000000000207711526744317200160540ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLM_MAT2_IDENTITY_INIT GLM_MAT2_ZERO_INIT GLM_MAT2_IDENTITY GLM_MAT2_ZERO Functions: CGLM_INLINE void glm_mat2_make(float * restrict src, mat2 dest) CGLM_INLINE void glm_mat2_copy(mat2 mat, mat2 dest) CGLM_INLINE void glm_mat2_identity(mat2 m) CGLM_INLINE void glm_mat2_identity_array(mat2 * restrict mats, size_t count) CGLM_INLINE void glm_mat2_zero(mat2 m) CGLM_INLINE void glm_mat2_mul(mat2 m1, mat2 m2, mat2 dest) CGLM_INLINE void glm_mat2_mulv(mat2 m, vec2 v, vec2 dest) CGLM_INLINE void glm_mat2_transpose_to(mat2 mat, mat2 dest) CGLM_INLINE void glm_mat2_transpose(mat2 m) CGLM_INLINE void glm_mat2_scale(mat2 m, float s) CGLM_INLINE void glm_mat2_inv(mat2 mat, mat2 dest) CGLM_INLINE void glm_mat2_swap_col(mat2 mat, int col1, int col2) CGLM_INLINE void glm_mat2_swap_row(mat2 mat, int row1, int row2) CGLM_INLINE float glm_mat2_det(mat2 m) CGLM_INLINE float glm_mat2_trace(mat2 m) CGLM_INLINE float glm_mat2_rmc(vec2 r, mat2 m, vec2 c) */ #ifndef cglm_mat2_h #define cglm_mat2_h #include "common.h" #include "vec2.h" #ifdef CGLM_SSE_FP # include "simd/sse2/mat2.h" #endif #ifdef CGLM_NEON_FP # include "simd/neon/mat2.h" #endif #ifdef CGLM_SIMD_WASM # include "simd/wasm/mat2.h" #endif #define GLM_MAT2_IDENTITY_INIT {{1.0f, 0.0f}, {0.0f, 1.0f}} #define GLM_MAT2_ZERO_INIT {{0.0f, 0.0f}, {0.0f, 0.0f}} /* for C only */ #define GLM_MAT2_IDENTITY ((mat2)GLM_MAT2_IDENTITY_INIT) #define GLM_MAT2_ZERO ((mat2)GLM_MAT2_ZERO_INIT) /*! * @brief Create mat2 (dest) from pointer (src). * * @param[in] src pointer to an array of floats (left) * @param[out] dest destination (result, mat2) */ CGLM_INLINE void glm_mat2_make(const float * __restrict src, mat2 dest) { dest[0][0] = src[0]; dest[0][1] = src[1]; dest[1][0] = src[2]; dest[1][1] = src[3]; } /*! * @brief Copy mat2 (mat) to mat2 (dest). * * @param[in] mat mat2 (left, src) * @param[out] dest destination (result, mat2) */ CGLM_INLINE void glm_mat2_copy(mat2 mat, mat2 dest) { glm_vec4_ucopy(mat[0], dest[0]); } /*! * @brief Copy a mat2 identity to mat2 (m), or makes mat2 (m) an identity. * * The same thing may be achieved with either of bellow methods, * but it is more easy to do that with this func especially for members * e.g. glm_mat2_identity(aStruct->aMatrix); * * @code * glm_mat2_copy(GLM_MAT2_IDENTITY, mat); // C only * * // or * mat2 mat = GLM_MAT2_IDENTITY_INIT; * @endcode * * @param[in, out] m mat2 (src, dest) */ CGLM_INLINE void glm_mat2_identity(mat2 m) { CGLM_ALIGN_MAT mat2 t = GLM_MAT2_IDENTITY_INIT; glm_mat2_copy(t, m); } /*! * @brief Given an array of mat2’s (mats) make each matrix an identity matrix. * * @param[in, out] mats Array of mat2’s (must be aligned (16/32) if alignment is not disabled) * @param[in] count Array size of mats or number of matrices */ CGLM_INLINE void glm_mat2_identity_array(mat2 * __restrict mats, size_t count) { CGLM_ALIGN_MAT mat2 t = GLM_MAT2_IDENTITY_INIT; size_t i; for (i = 0; i < count; i++) { glm_mat2_copy(t, mats[i]); } } /*! * @brief Zero out the mat2 (m). * * @param[in, out] m mat2 (src, dest) */ CGLM_INLINE void glm_mat2_zero(mat2 m) { CGLM_ALIGN_MAT mat2 t = GLM_MAT2_ZERO_INIT; glm_mat2_copy(t, m); } /*! * @brief Multiply mat2 (m1) by mat2 (m2) and store in mat2 (dest). * * m1, m2 and dest matrices can be same matrix, it is possible to write this: * * @code * mat2 m = GLM_MAT2_IDENTITY_INIT; * glm_mat2_mul(m, m, m); * @endcode * * @param[in] m1 mat2 (left) * @param[in] m2 mat2 (right) * @param[out] dest destination (result, mat2) */ CGLM_INLINE void glm_mat2_mul(mat2 m1, mat2 m2, mat2 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glm_mat2_mul_wasm(m1, m2, dest); #elif defined( __SSE__ ) || defined( __SSE2__ ) glm_mat2_mul_sse2(m1, m2, dest); #elif defined(CGLM_NEON_FP) glm_mat2_mul_neon(m1, m2, dest); #else float a00 = m1[0][0], a01 = m1[0][1], a10 = m1[1][0], a11 = m1[1][1], b00 = m2[0][0], b01 = m2[0][1], b10 = m2[1][0], b11 = m2[1][1]; dest[0][0] = a00 * b00 + a10 * b01; dest[0][1] = a01 * b00 + a11 * b01; dest[1][0] = a00 * b10 + a10 * b11; dest[1][1] = a01 * b10 + a11 * b11; #endif } /*! * @brief Multiply mat2 (m) by vec2 (v) and store in vec2 (dest). * * @param[in] m mat2 (left) * @param[in] v vec2 (right, column vector) * @param[out] dest destination (result, column vector) */ CGLM_INLINE void glm_mat2_mulv(mat2 m, vec2 v, vec2 dest) { dest[0] = m[0][0] * v[0] + m[1][0] * v[1]; dest[1] = m[0][1] * v[0] + m[1][1] * v[1]; } /*! * @brief Transpose mat2 (mat) and store in mat2 (dest). * * @param[in] mat mat2 (left, src) * @param[out] dest destination (result, mat2) */ CGLM_INLINE void glm_mat2_transpose_to(mat2 mat, mat2 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glm_mat2_transp_wasm(mat, dest); #elif defined( __SSE__ ) || defined( __SSE2__ ) glm_mat2_transp_sse2(mat, dest); #else dest[0][0] = mat[0][0]; dest[0][1] = mat[1][0]; dest[1][0] = mat[0][1]; dest[1][1] = mat[1][1]; #endif } /*! * @brief Transpose mat2 (m) and store result in the same matrix. * * @param[in, out] m mat2 (src, dest) */ CGLM_INLINE void glm_mat2_transpose(mat2 m) { float tmp; tmp = m[0][1]; m[0][1] = m[1][0]; m[1][0] = tmp; } /*! * @brief Multiply mat2 (m) by scalar constant (s). * * @param[in, out] m mat2 (src, dest) * @param[in] s float (scalar) */ CGLM_INLINE void glm_mat2_scale(mat2 m, float s) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(m[0], wasm_f32x4_mul(wasm_v128_load(m[0]), wasm_f32x4_splat(s))); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(m[0], _mm_mul_ps(_mm_loadu_ps(m[0]), glmm_set1(s))); #elif defined(CGLM_NEON_FP) vst1q_f32(m[0], vmulq_f32(vld1q_f32(m[0]), vdupq_n_f32(s))); #else m[0][0] = m[0][0] * s; m[0][1] = m[0][1] * s; m[1][0] = m[1][0] * s; m[1][1] = m[1][1] * s; #endif } /*! * @brief Inverse mat2 (mat) and store in mat2 (dest). * * @param[in] mat mat2 (left, src) * @param[out] dest destination (result, inverse mat2) */ CGLM_INLINE void glm_mat2_inv(mat2 mat, mat2 dest) { float det; float a = mat[0][0], b = mat[0][1], c = mat[1][0], d = mat[1][1]; det = 1.0f / (a * d - b * c); dest[0][0] = d * det; dest[0][1] = -b * det; dest[1][0] = -c * det; dest[1][1] = a * det; } /*! * @brief Swap two columns in mat2 (mat) and store in same matrix. * * @param[in, out] mat mat2 (src, dest) * @param[in] col1 Column 1 array index * @param[in] col2 Column 2 array index */ CGLM_INLINE void glm_mat2_swap_col(mat2 mat, int col1, int col2) { float a, b; a = mat[col1][0]; b = mat[col1][1]; mat[col1][0] = mat[col2][0]; mat[col1][1] = mat[col2][1]; mat[col2][0] = a; mat[col2][1] = b; } /*! * @brief Swap two rows in mat2 (mat) and store in same matrix. * * @param[in, out] mat mat2 (src, dest) * @param[in] row1 Row 1 array index * @param[in] row2 Row 2 array index */ CGLM_INLINE void glm_mat2_swap_row(mat2 mat, int row1, int row2) { float a, b; a = mat[0][row1]; b = mat[1][row1]; mat[0][row1] = mat[0][row2]; mat[1][row1] = mat[1][row2]; mat[0][row2] = a; mat[1][row2] = b; } /*! * @brief Returns mat2 determinant. * * @param[in] m mat2 (src) * * @return[out] mat2 determinant (float) */ CGLM_INLINE float glm_mat2_det(mat2 m) { return m[0][0] * m[1][1] - m[1][0] * m[0][1]; } /*! * @brief Returns trace of matrix. Which is: * * The sum of the elements on the main diagonal from * upper left corner to the bottom right corner. * * @param[in] m mat2 (src) * * @return[out] mat2 trace (float) */ CGLM_INLINE float glm_mat2_trace(mat2 m) { return m[0][0] + m[1][1]; } /*! * @brief Helper for R (row vector) * M (matrix) * C (column vector) * * rmc stands for Row * Matrix * Column * * the result is scalar because M * C = ResC (1x2, column vector), * then if you take the dot_product(R (2x1), ResC (1x2)) = scalar value. * * @param[in] r vec2 (2x1, row vector) * @param[in] m mat2 (2x2, matrix) * @param[in] c vec2 (1x2, column vector) * * @return[out] Scalar value (float, 1x1) */ CGLM_INLINE float glm_mat2_rmc(vec2 r, mat2 m, vec2 c) { vec2 tmp; glm_mat2_mulv(m, c, tmp); return glm_vec2_dot(r, tmp); } #endif /* cglm_mat2_h */ cglm-0.9.7/include/cglm/mat2x3.h000066400000000000000000000072521526744317200163260ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLM_MAT2X3_ZERO_INIT GLM_MAT2X3_ZERO Functions: CGLM_INLINE void glm_mat2x3_copy(mat2x3 src, mat2x3 dest); CGLM_INLINE void glm_mat2x3_zero(mat2x3 m); CGLM_INLINE void glm_mat2x3_make(const float * __restrict src, mat2x3 dest); CGLM_INLINE void glm_mat2x3_mul(mat2x3 m1, mat3x2 m2, mat3 dest); CGLM_INLINE void glm_mat2x3_mulv(mat2x3 m, vec2 v, vec3 dest); CGLM_INLINE void glm_mat2x3_transpose(mat2x3 src, mat3x2 dest); CGLM_INLINE void glm_mat2x3_scale(mat2x3 m, float s); */ #ifndef cglm_mat2x3_h #define cglm_mat2x3_h #include "common.h" #define GLM_MAT2X3_ZERO_INIT {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}} /* for C only */ #define GLM_MAT2X3_ZERO GLM_MAT2X3_ZERO_INIT /*! * @brief Copy mat2x3 (src) to mat2x3 (dest). * * @param[in] src mat2x3 (left) * @param[out] dest destination (result, mat2x3) */ CGLM_INLINE void glm_mat2x3_copy(mat2x3 src, mat2x3 dest) { glm_vec3_copy(src[0], dest[0]); glm_vec3_copy(src[1], dest[1]); } /*! * @brief Zero out the mat2x3 (m). * * @param[in, out] mat2x3 (src, dest) */ CGLM_INLINE void glm_mat2x3_zero(mat2x3 m) { CGLM_ALIGN_MAT mat2x3 t = GLM_MAT2X3_ZERO_INIT; glm_mat2x3_copy(t, m); } /*! * @brief Create mat2x3 (dest) from pointer (src). * * @param[in] src pointer to an array of floats (left) * @param[out] dest destination (result, mat2x3) */ CGLM_INLINE void glm_mat2x3_make(const float * __restrict src, mat2x3 dest) { dest[0][0] = src[0]; dest[0][1] = src[1]; dest[0][2] = src[2]; dest[1][0] = src[3]; dest[1][1] = src[4]; dest[1][2] = src[5]; } /*! * @brief Multiply mat2x3 (m1) by mat3x2 (m2) and store in mat3 (dest). * * @code * glm_mat2x3_mul(mat2x3, mat3x2, mat3); * @endcode * * @param[in] m1 mat2x3 (left) * @param[in] m2 mat3x2 (right) * @param[out] dest destination (result, mat3) */ CGLM_INLINE void glm_mat2x3_mul(mat2x3 m1, mat3x2 m2, mat3 dest) { float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], b00 = m2[0][0], b01 = m2[0][1], b10 = m2[1][0], b11 = m2[1][1], b20 = m2[2][0], b21 = m2[2][1]; dest[0][0] = a00 * b00 + a10 * b01; dest[0][1] = a01 * b00 + a11 * b01; dest[0][2] = a02 * b00 + a12 * b01; dest[1][0] = a00 * b10 + a10 * b11; dest[1][1] = a01 * b10 + a11 * b11; dest[1][2] = a02 * b10 + a12 * b11; dest[2][0] = a00 * b20 + a10 * b21; dest[2][1] = a01 * b20 + a11 * b21; dest[2][2] = a02 * b20 + a12 * b21; } /*! * @brief Multiply mat2x3 (m) by vec2 (v) and store in vec3 (dest). * * @param[in] m mat2x3 (left) * @param[in] v vec2 (right, column vector) * @param[out] dest destination (result, column vector) */ CGLM_INLINE void glm_mat2x3_mulv(mat2x3 m, vec2 v, vec3 dest) { float v0 = v[0], v1 = v[1]; dest[0] = m[0][0] * v0 + m[1][0] * v1; dest[1] = m[0][1] * v0 + m[1][1] * v1; dest[2] = m[0][2] * v0 + m[1][2] * v1; } /*! * @brief Transpose mat2x3 (src) and store in mat3x2 (dest). * * @param[in] src mat2x3 (left) * @param[out] dest destination (result, mat3x2) */ CGLM_INLINE void glm_mat2x3_transpose(mat2x3 src, mat3x2 dest) { dest[0][0] = src[0][0]; dest[0][1] = src[1][0]; dest[1][0] = src[0][1]; dest[1][1] = src[1][1]; dest[2][0] = src[0][2]; dest[2][1] = src[1][2]; } /*! * @brief Multiply mat2x3 (m) by scalar constant (s). * * @param[in, out] m (src, dest) * @param[in] float (scalar) */ CGLM_INLINE void glm_mat2x3_scale(mat2x3 m, float s) { m[0][0] *= s; m[0][1] *= s; m[0][2] *= s; m[1][0] *= s; m[1][1] *= s; m[1][2] *= s; } #endif cglm-0.9.7/include/cglm/mat2x4.h000066400000000000000000000103061526744317200163210ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLM_MAT2X4_ZERO_INIT GLM_MAT2X4_ZERO Functions: CGLM_INLINE void glm_mat2x4_copy(mat2x4 src, mat2x4 dest); CGLM_INLINE void glm_mat2x4_zero(mat2x4 m); CGLM_INLINE void glm_mat2x4_make(const float * __restrict src, mat2x4 dest); CGLM_INLINE void glm_mat2x4_mul(mat2x4 m1, mat4x2 m2, mat4 dest); CGLM_INLINE void glm_mat2x4_mulv(mat2x4 m, vec2 v, vec4 dest); CGLM_INLINE void glm_mat2x4_transpose(mat2x4 src, mat4x2 dest); CGLM_INLINE void glm_mat2x4_scale(mat2x4 m, float s); */ #ifndef cglm_mat2x4_h #define cglm_mat2x4_h #include "common.h" #include "vec4.h" #define GLM_MAT2X4_ZERO_INIT {{0.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 0.0f}} /* for C only */ #define GLM_MAT2X4_ZERO GLM_MAT2X4_ZERO_INIT /*! * @brief Copy mat2x4 (src) to mat2x4 (dest). * * @param[in] src mat2x4 (left) * @param[out] dest destination (result, mat2x4) */ CGLM_INLINE void glm_mat2x4_copy(mat2x4 src, mat2x4 dest) { glm_vec4_ucopy(src[0], dest[0]); glm_vec4_ucopy(src[1], dest[1]); } /*! * @brief Zero out the mat2x4 (m). * * @param[in, out] mat2x4 (src, dest) */ CGLM_INLINE void glm_mat2x4_zero(mat2x4 m) { CGLM_ALIGN_MAT mat2x4 t = GLM_MAT2X4_ZERO_INIT; glm_mat2x4_copy(t, m); } /*! * @brief Create mat2x4 (dest) from pointer (src). * * @param[in] src pointer to an array of floats (left) * @param[out] dest destination (result, mat2x4) */ CGLM_INLINE void glm_mat2x4_make(const float * __restrict src, mat2x4 dest) { dest[0][0] = src[0]; dest[0][1] = src[1]; dest[0][2] = src[2]; dest[0][3] = src[3]; dest[1][0] = src[4]; dest[1][1] = src[5]; dest[1][2] = src[6]; dest[1][3] = src[7]; } /*! * @brief Multiply mat2x4 (m1) by mat4x2 (m2) and store in mat4 (dest). * * @code * glm_mat2x4_mul(mat2x4, mat4x2, mat4); * @endcode * * @param[in] m1 mat2x4 (left) * @param[in] m2 mat4x2 (right) * @param[out] dest destination (result, mat4) */ CGLM_INLINE void glm_mat2x4_mul(mat2x4 m1, mat4x2 m2, mat4 dest) { float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], a03 = m1[0][3], a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], a13 = m1[1][3], b00 = m2[0][0], b01 = m2[0][1], b10 = m2[1][0], b11 = m2[1][1], b20 = m2[2][0], b21 = m2[2][1], b30 = m2[3][0], b31 = m2[3][1]; dest[0][0] = a00 * b00 + a10 * b01; dest[0][1] = a01 * b00 + a11 * b01; dest[0][2] = a02 * b00 + a12 * b01; dest[0][3] = a03 * b00 + a13 * b01; dest[1][0] = a00 * b10 + a10 * b11; dest[1][1] = a01 * b10 + a11 * b11; dest[1][2] = a02 * b10 + a12 * b11; dest[1][3] = a03 * b10 + a13 * b11; dest[2][0] = a00 * b20 + a10 * b21; dest[2][1] = a01 * b20 + a11 * b21; dest[2][2] = a02 * b20 + a12 * b21; dest[2][3] = a03 * b20 + a13 * b21; dest[3][0] = a00 * b30 + a10 * b31; dest[3][1] = a01 * b30 + a11 * b31; dest[3][2] = a02 * b30 + a12 * b31; dest[3][3] = a03 * b30 + a13 * b31; } /*! * @brief Multiply mat2x4 (m) by vec2 (v) and store in vec4 (dest). * * @param[in] m mat2x4 (left) * @param[in] v vec2 (right, column vector) * @param[out] dest destination (result, column vector) */ CGLM_INLINE void glm_mat2x4_mulv(mat2x4 m, vec2 v, vec4 dest) { float v0 = v[0], v1 = v[1]; dest[0] = m[0][0] * v0 + m[1][0] * v1; dest[1] = m[0][1] * v0 + m[1][1] * v1; dest[2] = m[0][2] * v0 + m[1][2] * v1; dest[3] = m[0][3] * v0 + m[1][3] * v1; } /*! * @brief Transpose mat2x4 (src) and store in mat4x2 (dest). * * @param[in] src mat2x4 (left) * @param[out] dest destination (result, mat4x2) */ CGLM_INLINE void glm_mat2x4_transpose(mat2x4 src, mat4x2 dest) { dest[0][0] = src[0][0]; dest[0][1] = src[1][0]; dest[1][0] = src[0][1]; dest[1][1] = src[1][1]; dest[2][0] = src[0][2]; dest[2][1] = src[1][2]; dest[3][0] = src[0][3]; dest[3][1] = src[1][3]; } /*! * @brief Multiply mat2x4 (m) by scalar constant (s). * * @param[in, out] m (src, dest) * @param[in] s float (scalar) */ CGLM_INLINE void glm_mat2x4_scale(mat2x4 m, float s) { m[0][0] *= s; m[0][1] *= s; m[0][2] *= s; m[0][3] *= s; m[1][0] *= s; m[1][1] *= s; m[1][2] *= s; m[1][3] *= s; } #endif cglm-0.9.7/include/cglm/mat3.h000066400000000000000000000273311526744317200160540ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLM_MAT3_IDENTITY_INIT GLM_MAT3_ZERO_INIT GLM_MAT3_IDENTITY GLM_MAT3_ZERO glm_mat3_dup(mat, dest) Functions: CGLM_INLINE void glm_mat3_copy(mat3 mat, mat3 dest); CGLM_INLINE void glm_mat3_identity(mat3 mat); CGLM_INLINE void glm_mat3_identity_array(mat3 * restrict mat, size_t count); CGLM_INLINE void glm_mat3_zero(mat3 mat); CGLM_INLINE void glm_mat3_mul(mat3 m1, mat3 m2, mat3 dest); CGLM_INLINE void glm_mat3_transpose_to(mat3 m, mat3 dest); CGLM_INLINE void glm_mat3_transpose(mat3 m); CGLM_INLINE void glm_mat3_mulv(mat3 m, vec3 v, vec3 dest); CGLM_INLINE float glm_mat3_trace(mat3 m); CGLM_INLINE void glm_mat3_quat(mat3 m, versor dest); CGLM_INLINE void glm_mat3_scale(mat3 m, float s); CGLM_INLINE float glm_mat3_det(mat3 mat); CGLM_INLINE void glm_mat3_inv(mat3 mat, mat3 dest); CGLM_INLINE void glm_mat3_swap_col(mat3 mat, int col1, int col2); CGLM_INLINE void glm_mat3_swap_row(mat3 mat, int row1, int row2); CGLM_INLINE float glm_mat3_rmc(vec3 r, mat3 m, vec3 c); CGLM_INLINE void glm_mat3_make(float * restrict src, mat3 dest); CGLM_INLINE void glm_mat3_textrans(float sx, float sy, float rot, float tx, float ty, mat3 dest); */ #ifndef cglm_mat3_h #define cglm_mat3_h #include "common.h" #include "vec3.h" #ifdef CGLM_SSE_FP # include "simd/sse2/mat3.h" #endif #ifdef CGLM_SIMD_WASM # include "simd/wasm/mat3.h" #endif #define GLM_MAT3_IDENTITY_INIT {{1.0f, 0.0f, 0.0f}, \ {0.0f, 1.0f, 0.0f}, \ {0.0f, 0.0f, 1.0f}} #define GLM_MAT3_ZERO_INIT {{0.0f, 0.0f, 0.0f}, \ {0.0f, 0.0f, 0.0f}, \ {0.0f, 0.0f, 0.0f}} /* for C only */ #define GLM_MAT3_IDENTITY ((mat3)GLM_MAT3_IDENTITY_INIT) #define GLM_MAT3_ZERO ((mat3)GLM_MAT3_ZERO_INIT) /* DEPRECATED! use _copy, _ucopy versions */ #define glm_mat3_dup(mat, dest) glm_mat3_copy(mat, dest) /*! * @brief copy all members of [mat] to [dest] * * @param[in] mat source * @param[out] dest destination */ CGLM_INLINE void glm_mat3_copy(mat3 mat, mat3 dest) { dest[0][0] = mat[0][0]; dest[0][1] = mat[0][1]; dest[0][2] = mat[0][2]; dest[1][0] = mat[1][0]; dest[1][1] = mat[1][1]; dest[1][2] = mat[1][2]; dest[2][0] = mat[2][0]; dest[2][1] = mat[2][1]; dest[2][2] = mat[2][2]; } /*! * @brief make given matrix identity. It is identical with below, * but it is more easy to do that with this func especially for members * e.g. glm_mat3_identity(aStruct->aMatrix); * * @code * glm_mat3_copy(GLM_MAT3_IDENTITY, mat); // C only * * // or * mat3 mat = GLM_MAT3_IDENTITY_INIT; * @endcode * * @param[in, out] mat destination */ CGLM_INLINE void glm_mat3_identity(mat3 mat) { CGLM_ALIGN_MAT mat3 t = GLM_MAT3_IDENTITY_INIT; glm_mat3_copy(t, mat); } /*! * @brief make given matrix array's each element identity matrix * * @param[in, out] mat matrix array (must be aligned (16/32) * if alignment is not disabled) * * @param[in] count count of matrices */ CGLM_INLINE void glm_mat3_identity_array(mat3 * __restrict mat, size_t count) { CGLM_ALIGN_MAT mat3 t = GLM_MAT3_IDENTITY_INIT; size_t i; for (i = 0; i < count; i++) { glm_mat3_copy(t, mat[i]); } } /*! * @brief make given matrix zero. * * @param[in, out] mat matrix */ CGLM_INLINE void glm_mat3_zero(mat3 mat) { CGLM_ALIGN_MAT mat3 t = GLM_MAT3_ZERO_INIT; glm_mat3_copy(t, mat); } /*! * @brief multiply m1 and m2 to dest * * m1, m2 and dest matrices can be same matrix, it is possible to write this: * * @code * mat3 m = GLM_MAT3_IDENTITY_INIT; * glm_mat3_mul(m, m, m); * @endcode * * @param[in] m1 left matrix * @param[in] m2 right matrix * @param[out] dest destination matrix */ CGLM_INLINE void glm_mat3_mul(mat3 m1, mat3 m2, mat3 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glm_mat3_mul_wasm(m1, m2, dest); #elif defined( __SSE__ ) || defined( __SSE2__ ) glm_mat3_mul_sse2(m1, m2, dest); #else float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], a20 = m1[2][0], a21 = m1[2][1], a22 = m1[2][2], b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2], b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2], b20 = m2[2][0], b21 = m2[2][1], b22 = m2[2][2]; dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02; dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02; dest[0][2] = a02 * b00 + a12 * b01 + a22 * b02; dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12; dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12; dest[1][2] = a02 * b10 + a12 * b11 + a22 * b12; dest[2][0] = a00 * b20 + a10 * b21 + a20 * b22; dest[2][1] = a01 * b20 + a11 * b21 + a21 * b22; dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22; #endif } /*! * @brief transpose mat3 and store in dest * * source matrix will not be transposed unless dest is m * * @param[in] m matrix * @param[out] dest result */ CGLM_INLINE void glm_mat3_transpose_to(mat3 m, mat3 dest) { dest[0][0] = m[0][0]; dest[0][1] = m[1][0]; dest[0][2] = m[2][0]; dest[1][0] = m[0][1]; dest[1][1] = m[1][1]; dest[1][2] = m[2][1]; dest[2][0] = m[0][2]; dest[2][1] = m[1][2]; dest[2][2] = m[2][2]; } /*! * @brief transpose mat3 and store result in same matrix * * @param[in, out] m source and dest */ CGLM_INLINE void glm_mat3_transpose(mat3 m) { CGLM_ALIGN_MAT mat3 tmp; tmp[0][1] = m[1][0]; tmp[0][2] = m[2][0]; tmp[1][0] = m[0][1]; tmp[1][2] = m[2][1]; tmp[2][0] = m[0][2]; tmp[2][1] = m[1][2]; m[0][1] = tmp[0][1]; m[0][2] = tmp[0][2]; m[1][0] = tmp[1][0]; m[1][2] = tmp[1][2]; m[2][0] = tmp[2][0]; m[2][1] = tmp[2][1]; } /*! * @brief multiply mat3 with vec3 (column vector) and store in dest vector * * @param[in] m mat3 (left) * @param[in] v vec3 (right, column vector) * @param[out] dest vec3 (result, column vector) */ CGLM_INLINE void glm_mat3_mulv(mat3 m, vec3 v, vec3 dest) { vec3 res; res[0] = m[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2]; res[1] = m[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2]; res[2] = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2]; glm_vec3_copy(res, dest); } /*! * @brief trace of matrix * * sum of the elements on the main diagonal from upper left to the lower right * * @param[in] m matrix */ CGLM_INLINE float glm_mat3_trace(mat3 m) { return m[0][0] + m[1][1] + m[2][2]; } /*! * @brief convert mat3 to quaternion * * @param[in] m rotation matrix * @param[out] dest destination quaternion */ CGLM_INLINE void glm_mat3_quat(mat3 m, versor dest) { float trace, r, rinv; /* it seems using like m12 instead of m[1][2] causes extra instructions */ trace = m[0][0] + m[1][1] + m[2][2]; if (trace >= 0.0f) { r = sqrtf(1.0f + trace); rinv = 0.5f / r; dest[0] = rinv * (m[1][2] - m[2][1]); dest[1] = rinv * (m[2][0] - m[0][2]); dest[2] = rinv * (m[0][1] - m[1][0]); dest[3] = r * 0.5f; } else if (m[0][0] >= m[1][1] && m[0][0] >= m[2][2]) { r = sqrtf(1.0f - m[1][1] - m[2][2] + m[0][0]); rinv = 0.5f / r; dest[0] = r * 0.5f; dest[1] = rinv * (m[0][1] + m[1][0]); dest[2] = rinv * (m[0][2] + m[2][0]); dest[3] = rinv * (m[1][2] - m[2][1]); } else if (m[1][1] >= m[2][2]) { r = sqrtf(1.0f - m[0][0] - m[2][2] + m[1][1]); rinv = 0.5f / r; dest[0] = rinv * (m[0][1] + m[1][0]); dest[1] = r * 0.5f; dest[2] = rinv * (m[1][2] + m[2][1]); dest[3] = rinv * (m[2][0] - m[0][2]); } else { r = sqrtf(1.0f - m[0][0] - m[1][1] + m[2][2]); rinv = 0.5f / r; dest[0] = rinv * (m[0][2] + m[2][0]); dest[1] = rinv * (m[1][2] + m[2][1]); dest[2] = r * 0.5f; dest[3] = rinv * (m[0][1] - m[1][0]); } } /*! * @brief scale (multiply with scalar) matrix * * multiply matrix with scalar * * @param[in, out] m matrix * @param[in] s scalar */ CGLM_INLINE void glm_mat3_scale(mat3 m, float s) { m[0][0] *= s; m[0][1] *= s; m[0][2] *= s; m[1][0] *= s; m[1][1] *= s; m[1][2] *= s; m[2][0] *= s; m[2][1] *= s; m[2][2] *= s; } /*! * @brief mat3 determinant * * @param[in] mat matrix * * @return determinant */ CGLM_INLINE float glm_mat3_det(mat3 mat) { float a = mat[0][0], b = mat[0][1], c = mat[0][2], d = mat[1][0], e = mat[1][1], f = mat[1][2], g = mat[2][0], h = mat[2][1], i = mat[2][2]; return a * (e * i - h * f) - d * (b * i - h * c) + g * (b * f - e * c); } /*! * @brief inverse mat3 and store in dest * * @param[in] mat matrix * @param[out] dest inverse matrix */ CGLM_INLINE void glm_mat3_inv(mat3 mat, mat3 dest) { float a = mat[0][0], b = mat[0][1], c = mat[0][2], d = mat[1][0], e = mat[1][1], f = mat[1][2], g = mat[2][0], h = mat[2][1], i = mat[2][2], c1 = e * i - f * h, c2 = d * i - g * f, c3 = d * h - g * e, idt = 1.0f / (a * c1 - b * c2 + c * c3), ndt = -idt; dest[0][0] = idt * c1; dest[0][1] = ndt * (b * i - h * c); dest[0][2] = idt * (b * f - e * c); dest[1][0] = ndt * c2; dest[1][1] = idt * (a * i - g * c); dest[1][2] = ndt * (a * f - d * c); dest[2][0] = idt * c3; dest[2][1] = ndt * (a * h - g * b); dest[2][2] = idt * (a * e - d * b); } /*! * @brief swap two matrix columns * * @param[in,out] mat matrix * @param[in] col1 col1 * @param[in] col2 col2 */ CGLM_INLINE void glm_mat3_swap_col(mat3 mat, int col1, int col2) { vec3 tmp; glm_vec3_copy(mat[col1], tmp); glm_vec3_copy(mat[col2], mat[col1]); glm_vec3_copy(tmp, mat[col2]); } /*! * @brief swap two matrix rows * * @param[in,out] mat matrix * @param[in] row1 row1 * @param[in] row2 row2 */ CGLM_INLINE void glm_mat3_swap_row(mat3 mat, int row1, int row2) { vec3 tmp; tmp[0] = mat[0][row1]; tmp[1] = mat[1][row1]; tmp[2] = mat[2][row1]; mat[0][row1] = mat[0][row2]; mat[1][row1] = mat[1][row2]; mat[2][row1] = mat[2][row2]; mat[0][row2] = tmp[0]; mat[1][row2] = tmp[1]; mat[2][row2] = tmp[2]; } /*! * @brief helper for R (row vector) * M (matrix) * C (column vector) * * rmc stands for Row * Matrix * Column * * the result is scalar because R * M = Matrix1x3 (row vector), * then Matrix1x3 * Vec3 (column vector) = Matrix1x1 (Scalar) * * @param[in] r row vector or matrix1x3 * @param[in] m matrix3x3 * @param[in] c column vector or matrix3x1 * * @return scalar value e.g. Matrix1x1 */ CGLM_INLINE float glm_mat3_rmc(vec3 r, mat3 m, vec3 c) { vec3 tmp; glm_mat3_mulv(m, c, tmp); return glm_vec3_dot(r, tmp); } /*! * @brief Create mat3 matrix from pointer * * @param[in] src pointer to an array of floats * @param[out] dest matrix */ CGLM_INLINE void glm_mat3_make(const float * __restrict src, mat3 dest) { dest[0][0] = src[0]; dest[0][1] = src[1]; dest[0][2] = src[2]; dest[1][0] = src[3]; dest[1][1] = src[4]; dest[1][2] = src[5]; dest[2][0] = src[6]; dest[2][1] = src[7]; dest[2][2] = src[8]; } /*! * @brief Create mat3 matrix from texture transform parameters * * @param[in] sx scale x * @param[in] sy scale y * @param[in] rot rotation in radians CCW/RH * @param[in] tx translate x * @param[in] ty translate y * @param[out] dest texture transform matrix */ CGLM_INLINE void glm_mat3_textrans(float sx, float sy, float rot, float tx, float ty, mat3 dest) { float c, s; c = cosf(rot); s = sinf(rot); glm_mat3_identity(dest); dest[0][0] = c * sx; dest[0][1] = -s * sy; dest[1][0] = s * sx; dest[1][1] = c * sy; dest[2][0] = tx; dest[2][1] = ty; } #endif /* cglm_mat3_h */ cglm-0.9.7/include/cglm/mat3x2.h000066400000000000000000000071001526744317200163160ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLM_MAT3X2_ZERO_INIT GLM_MAT3X2_ZERO Functions: CGLM_INLINE void glm_mat3x2_copy(mat3x2 src, mat3x2 dest); CGLM_INLINE void glm_mat3x2_zero(mat3x2 m); CGLM_INLINE void glm_mat3x2_make(const float * __restrict src, mat3x2 dest); CGLM_INLINE void glm_mat3x2_mul(mat3x2 m1, mat2x3 m2, mat2 dest); CGLM_INLINE void glm_mat3x2_mulv(mat3x2 m, vec3 v, vec2 dest); CGLM_INLINE void glm_mat3x2_transpose(mat3x2 src, mat2x3 dest); CGLM_INLINE void glm_mat3x2_scale(mat3x2 m, float s); */ #ifndef cglm_mat3x2_h #define cglm_mat3x2_h #include "common.h" #define GLM_MAT3X2_ZERO_INIT {{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}} /* for C only */ #define GLM_MAT3X2_ZERO GLM_MAT3X2_ZERO_INIT /*! * @brief Copy mat3x2 (src) to mat3x2 (dest). * * @param[in] src mat3x2 (left) * @param[out] dest destination (result, mat3x2) */ CGLM_INLINE void glm_mat3x2_copy(mat3x2 src, mat3x2 dest) { glm_vec2_copy(src[0], dest[0]); glm_vec2_copy(src[1], dest[1]); glm_vec2_copy(src[2], dest[2]); } /*! * @brief Zero out the mat3x2 (m). * * @param[in, out] mat3x2 (src, dest) */ CGLM_INLINE void glm_mat3x2_zero(mat3x2 m) { CGLM_ALIGN_MAT mat3x2 t = GLM_MAT3X2_ZERO_INIT; glm_mat3x2_copy(t, m); } /*! * @brief Create mat3x2 (dest) from pointer (src). * * @param[in] src pointer to an array of floats (left) * @param[out] dest destination (result, mat3x2) */ CGLM_INLINE void glm_mat3x2_make(const float * __restrict src, mat3x2 dest) { dest[0][0] = src[0]; dest[0][1] = src[1]; dest[1][0] = src[2]; dest[1][1] = src[3]; dest[2][0] = src[4]; dest[2][1] = src[5]; } /*! * @brief Multiply mat3x2 (m1) by mat2x3 (m2) and store in mat2 (dest). * * @code * glm_mat3x2_mul(mat3x2, mat2x3, mat2); * @endcode * * @param[in] m1 mat3x2 (left) * @param[in] m2 mat2x3 (right) * @param[out] dest destination (result, mat2) */ CGLM_INLINE void glm_mat3x2_mul(mat3x2 m1, mat2x3 m2, mat2 dest) { float a00 = m1[0][0], a01 = m1[0][1], a10 = m1[1][0], a11 = m1[1][1], a20 = m1[2][0], a21 = m1[2][1], b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2], b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2]; dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02; dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02; dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12; dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12; } /*! * @brief Multiply mat3x2 (m) by vec3 (v) and store in vec2 (dest). * * @param[in] m mat3x2 (left) * @param[in] v vec3 (right, column vector) * @param[out] dest destination (result, column vector) */ CGLM_INLINE void glm_mat3x2_mulv(mat3x2 m, vec3 v, vec2 dest) { float v0 = v[0], v1 = v[1], v2 = v[2]; dest[0] = m[0][0] * v0 + m[1][0] * v1 + m[2][0] * v2; dest[1] = m[0][1] * v0 + m[1][1] * v1 + m[2][1] * v2; } /*! * @brief Transpose mat3x2 (src) and store in mat2x3 (dest). * * @param[in] src mat3x2 (left) * @param[out] dest destination (result, mat2x3) */ CGLM_INLINE void glm_mat3x2_transpose(mat3x2 src, mat2x3 dest) { dest[0][0] = src[0][0]; dest[0][1] = src[1][0]; dest[0][2] = src[2][0]; dest[1][0] = src[0][1]; dest[1][1] = src[1][1]; dest[1][2] = src[2][1]; } /*! * @brief Multiply mat3x2 (m) by scalar constant (s). * * @param[in, out] m (src, dest) * @param[in] s float (scalar) */ CGLM_INLINE void glm_mat3x2_scale(mat3x2 m, float s) { m[0][0] *= s; m[0][1] *= s; m[1][0] *= s; m[1][1] *= s; m[2][0] *= s; m[2][1] *= s; } #endif cglm-0.9.7/include/cglm/mat3x4.h000066400000000000000000000116671526744317200163350ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLM_MAT3X4_ZERO_INIT GLM_MAT3X4_ZERO Functions: CGLM_INLINE void glm_mat3x4_copy(mat3x4 src, mat3x4 dest); CGLM_INLINE void glm_mat3x4_zero(mat3x4 m); CGLM_INLINE void glm_mat3x4_make(const float * __restrict src, mat3x4 dest); CGLM_INLINE void glm_mat3x4_mul(mat3x4 m1, mat4x3 m2, mat4 dest); CGLM_INLINE void glm_mat3x4_mulv(mat3x4 m, vec3 v, vec4 dest); CGLM_INLINE void glm_mat3x4_transpose(mat3x4 src, mat4x3 dest); CGLM_INLINE void glm_mat3x4_scale(mat3x4 m, float s); */ #ifndef cglm_mat3x4_h #define cglm_mat3x4_h #include "common.h" #define GLM_MAT3X4_ZERO_INIT {{0.0f, 0.0f, 0.0f, 0.0f}, \ {0.0f, 0.0f, 0.0f, 0.0f}, \ {0.0f, 0.0f, 0.0f, 0.0f}} /* for C only */ #define GLM_MAT3X4_ZERO GLM_MAT3X4_ZERO_INIT /*! * @brief Copy mat3x4 (src) to mat3x4 (dest). * * @param[in] src mat3x4 (left) * @param[out] dest destination (result, mat3x4) */ CGLM_INLINE void glm_mat3x4_copy(mat3x4 src, mat3x4 dest) { glm_vec4_ucopy(src[0], dest[0]); glm_vec4_ucopy(src[1], dest[1]); glm_vec4_ucopy(src[2], dest[2]); } /*! * @brief Zero out the mat3x4 (m). * * @param[in, out] mat3x4 (src, dest) */ CGLM_INLINE void glm_mat3x4_zero(mat3x4 m) { CGLM_ALIGN_MAT mat3x4 t = GLM_MAT3X4_ZERO_INIT; glm_mat3x4_copy(t, m); } /*! * @brief Create mat3x4 (dest) from pointer (src). * * @param[in] src pointer to an array of floats (left) * @param[out] dest destination (result, mat3x4) */ CGLM_INLINE void glm_mat3x4_make(const float * __restrict src, mat3x4 dest) { dest[0][0] = src[0]; dest[0][1] = src[1]; dest[0][2] = src[2]; dest[0][3] = src[3]; dest[1][0] = src[4]; dest[1][1] = src[5]; dest[1][2] = src[6]; dest[1][3] = src[7]; dest[2][0] = src[8]; dest[2][1] = src[9]; dest[2][2] = src[10]; dest[2][3] = src[11]; } /*! * @brief Multiply mat3x4 (m1) by mat4x3 (m2) and store in mat4 (dest). * * @code * glm_mat3x4_mul(mat3x4, mat4x3, mat4); * @endcode * * @param[in] m1 mat3x4 (left) * @param[in] m2 mat4x3 (right) * @param[out] dest destination (result, mat4) */ CGLM_INLINE void glm_mat3x4_mul(mat3x4 m1, mat4x3 m2, mat4 dest) { float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], a03 = m1[0][3], a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], a13 = m1[1][3], a20 = m1[2][0], a21 = m1[2][1], a22 = m1[2][2], a23 = m1[2][3], b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2], b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2], b20 = m2[2][0], b21 = m2[2][1], b22 = m2[2][2], b30 = m2[3][0], b31 = m2[3][1], b32 = m2[3][2]; dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02; dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02; dest[0][2] = a02 * b00 + a12 * b01 + a22 * b02; dest[0][3] = a03 * b00 + a13 * b01 + a23 * b02; dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12; dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12; dest[1][2] = a02 * b10 + a12 * b11 + a22 * b12; dest[1][3] = a03 * b10 + a13 * b11 + a23 * b12; dest[2][0] = a00 * b20 + a10 * b21 + a20 * b22; dest[2][1] = a01 * b20 + a11 * b21 + a21 * b22; dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22; dest[2][3] = a03 * b20 + a13 * b21 + a23 * b22; dest[3][0] = a00 * b30 + a10 * b31 + a20 * b32; dest[3][1] = a01 * b30 + a11 * b31 + a21 * b32; dest[3][2] = a02 * b30 + a12 * b31 + a22 * b32; dest[3][3] = a03 * b30 + a13 * b31 + a23 * b32; } /*! * @brief Multiply mat3x4 (m) by vec3 (v) and store in vec4 (dest). * * @param[in] m mat3x4 (left) * @param[in] v vec3 (right, column vector) * @param[out] dest destination (result, column vector) */ CGLM_INLINE void glm_mat3x4_mulv(mat3x4 m, vec3 v, vec4 dest) { float v0 = v[0], v1 = v[1], v2 = v[2]; dest[0] = m[0][0] * v0 + m[1][0] * v1 + m[2][0] * v2; dest[1] = m[0][1] * v0 + m[1][1] * v1 + m[2][1] * v2; dest[2] = m[0][2] * v0 + m[1][2] * v1 + m[2][2] * v2; dest[3] = m[0][3] * v0 + m[1][3] * v1 + m[2][3] * v2; } /*! * @brief Transpose mat3x4 (src) and store in mat4x3 (dest). * * @param[in] src mat3x4 (left) * @param[out] dest destination (result, mat4x3) */ CGLM_INLINE void glm_mat3x4_transpose(mat3x4 src, mat4x3 dest) { dest[0][0] = src[0][0]; dest[0][1] = src[1][0]; dest[0][2] = src[2][0]; dest[1][0] = src[0][1]; dest[1][1] = src[1][1]; dest[1][2] = src[2][1]; dest[2][0] = src[0][2]; dest[2][1] = src[1][2]; dest[2][2] = src[2][2]; dest[3][0] = src[0][3]; dest[3][1] = src[1][3]; dest[3][2] = src[2][3]; } /*! * @brief Multiply mat3x4 (m) by scalar constant (s). * * @param[in, out] m (src, dest) * @param[in] s float (scalar) */ CGLM_INLINE void glm_mat3x4_scale(mat3x4 m, float s) { m[0][0] *= s; m[0][1] *= s; m[0][2] *= s; m[0][3] *= s; m[1][0] *= s; m[1][1] *= s; m[1][2] *= s; m[1][3] *= s; m[2][0] *= s; m[2][1] *= s; m[2][2] *= s; m[2][3] *= s; } #endif cglm-0.9.7/include/cglm/mat4.h000066400000000000000000000552061526744317200160570ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /*! * Most of functions in this header are optimized manually with SIMD * if available. You dont need to call/incude SIMD headers manually */ /* Macros: GLM_MAT4_IDENTITY_INIT GLM_MAT4_ZERO_INIT GLM_MAT4_IDENTITY GLM_MAT4_ZERO Functions: CGLM_INLINE void glm_mat4_ucopy(mat4 mat, mat4 dest); CGLM_INLINE void glm_mat4_copy(mat4 mat, mat4 dest); CGLM_INLINE void glm_mat4_identity(mat4 mat); CGLM_INLINE void glm_mat4_identity_array(mat4 * restrict mat, size_t count); CGLM_INLINE void glm_mat4_zero(mat4 mat); CGLM_INLINE void glm_mat4_pick3(mat4 mat, mat3 dest); CGLM_INLINE void glm_mat4_pick3t(mat4 mat, mat3 dest); CGLM_INLINE void glm_mat4_ins3(mat3 mat, mat4 dest); CGLM_INLINE void glm_mat4_mul(mat4 m1, mat4 m2, mat4 dest); CGLM_INLINE void glm_mat4_mulN(mat4 *matrices[], int len, mat4 dest); CGLM_INLINE void glm_mat4_mulv(mat4 m, vec4 v, vec4 dest); CGLM_INLINE void glm_mat4_mulv3(mat4 m, vec3 v, float last, vec3 dest); CGLM_INLINE float glm_mat4_trace(mat4 m); CGLM_INLINE float glm_mat4_trace3(mat4 m); CGLM_INLINE void glm_mat4_quat(mat4 m, versor dest) ; CGLM_INLINE void glm_mat4_transpose_to(mat4 m, mat4 dest); CGLM_INLINE void glm_mat4_transpose(mat4 m); CGLM_INLINE void glm_mat4_scale_p(mat4 m, float s); CGLM_INLINE void glm_mat4_scale(mat4 m, float s); CGLM_INLINE float glm_mat4_det(mat4 mat); CGLM_INLINE void glm_mat4_inv(mat4 mat, mat4 dest); CGLM_INLINE void glm_mat4_inv_fast(mat4 mat, mat4 dest); CGLM_INLINE void glm_mat4_swap_col(mat4 mat, int col1, int col2); CGLM_INLINE void glm_mat4_swap_row(mat4 mat, int row1, int row2); CGLM_INLINE float glm_mat4_rmc(vec4 r, mat4 m, vec4 c); CGLM_INLINE void glm_mat4_make(float * restrict src, mat4 dest); CGLM_INLINE void glm_mat4_textrans(float sx, float sy, float rot, float tx, float ty, mat4 dest); */ #ifndef cglm_mat_h #define cglm_mat_h #include "common.h" #include "vec4.h" #include "vec3.h" #ifdef CGLM_SSE_FP # include "simd/sse2/mat4.h" #endif #ifdef CGLM_AVX_FP # include "simd/avx/mat4.h" #endif #ifdef CGLM_NEON_FP # include "simd/neon/mat4.h" #endif #ifdef CGLM_SIMD_WASM # include "simd/wasm/mat4.h" #endif #ifndef NDEBUG # include #endif #define GLM_MAT4_IDENTITY_INIT {{1.0f, 0.0f, 0.0f, 0.0f}, \ {0.0f, 1.0f, 0.0f, 0.0f}, \ {0.0f, 0.0f, 1.0f, 0.0f}, \ {0.0f, 0.0f, 0.0f, 1.0f}} #define GLM_MAT4_ZERO_INIT {{0.0f, 0.0f, 0.0f, 0.0f}, \ {0.0f, 0.0f, 0.0f, 0.0f}, \ {0.0f, 0.0f, 0.0f, 0.0f}, \ {0.0f, 0.0f, 0.0f, 0.0f}} /* for C only */ #define GLM_MAT4_IDENTITY ((mat4)GLM_MAT4_IDENTITY_INIT) #define GLM_MAT4_ZERO ((mat4)GLM_MAT4_ZERO_INIT) /* DEPRECATED! use _copy, _ucopy versions */ #define glm_mat4_udup(mat, dest) glm_mat4_ucopy(mat, dest) #define glm_mat4_dup(mat, dest) glm_mat4_copy(mat, dest) /* DEPRECATED! default is precise now. */ #define glm_mat4_inv_precise(mat, dest) glm_mat4_inv(mat, dest) /*! * @brief copy all members of [mat] to [dest] * * matrix may not be aligned, u stands for unaligned, this may be useful when * copying a matrix from external source e.g. asset importer... * * @param[in] mat source * @param[out] dest destination */ CGLM_INLINE void glm_mat4_ucopy(mat4 mat, mat4 dest) { dest[0][0] = mat[0][0]; dest[1][0] = mat[1][0]; dest[0][1] = mat[0][1]; dest[1][1] = mat[1][1]; dest[0][2] = mat[0][2]; dest[1][2] = mat[1][2]; dest[0][3] = mat[0][3]; dest[1][3] = mat[1][3]; dest[2][0] = mat[2][0]; dest[3][0] = mat[3][0]; dest[2][1] = mat[2][1]; dest[3][1] = mat[3][1]; dest[2][2] = mat[2][2]; dest[3][2] = mat[3][2]; dest[2][3] = mat[2][3]; dest[3][3] = mat[3][3]; } /*! * @brief copy all members of [mat] to [dest] * * @param[in] mat source * @param[out] dest destination */ CGLM_INLINE void glm_mat4_copy(mat4 mat, mat4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(dest[0], glmm_load(mat[0])); glmm_store(dest[1], glmm_load(mat[1])); glmm_store(dest[2], glmm_load(mat[2])); glmm_store(dest[3], glmm_load(mat[3])); #elif defined(__AVX__) glmm_store256(dest[0], glmm_load256(mat[0])); glmm_store256(dest[2], glmm_load256(mat[2])); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest[0], glmm_load(mat[0])); glmm_store(dest[1], glmm_load(mat[1])); glmm_store(dest[2], glmm_load(mat[2])); glmm_store(dest[3], glmm_load(mat[3])); #elif defined(CGLM_NEON_FP) vst1q_f32(dest[0], vld1q_f32(mat[0])); vst1q_f32(dest[1], vld1q_f32(mat[1])); vst1q_f32(dest[2], vld1q_f32(mat[2])); vst1q_f32(dest[3], vld1q_f32(mat[3])); #else glm_mat4_ucopy(mat, dest); #endif } /*! * @brief make given matrix identity. It is identical with below, * but it is more easy to do that with this func especially for members * e.g. glm_mat4_identity(aStruct->aMatrix); * * @code * glm_mat4_copy(GLM_MAT4_IDENTITY, mat); // C only * * // or * mat4 mat = GLM_MAT4_IDENTITY_INIT; * @endcode * * @param[in, out] mat destination */ CGLM_INLINE void glm_mat4_identity(mat4 mat) { CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; glm_mat4_copy(t, mat); } /*! * @brief make given matrix array's each element identity matrix * * @param[in, out] mat matrix array (must be aligned (16/32) * if alignment is not disabled) * * @param[in] count count of matrices */ CGLM_INLINE void glm_mat4_identity_array(mat4 * __restrict mat, size_t count) { CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; size_t i; for (i = 0; i < count; i++) { glm_mat4_copy(t, mat[i]); } } /*! * @brief make given matrix zero. * * @param[in, out] mat matrix */ CGLM_INLINE void glm_mat4_zero(mat4 mat) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_128 x0; x0 = wasm_f32x4_const_splat(0.f); glmm_store(mat[0], x0); glmm_store(mat[1], x0); glmm_store(mat[2], x0); glmm_store(mat[3], x0); #elif defined(__AVX__) __m256 y0; y0 = _mm256_setzero_ps(); glmm_store256(mat[0], y0); glmm_store256(mat[2], y0); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_128 x0; x0 = _mm_setzero_ps(); glmm_store(mat[0], x0); glmm_store(mat[1], x0); glmm_store(mat[2], x0); glmm_store(mat[3], x0); #elif defined(CGLM_NEON_FP) glmm_128 x0; x0 = vdupq_n_f32(0.0f); vst1q_f32(mat[0], x0); vst1q_f32(mat[1], x0); vst1q_f32(mat[2], x0); vst1q_f32(mat[3], x0); #else CGLM_ALIGN_MAT mat4 t = GLM_MAT4_ZERO_INIT; glm_mat4_copy(t, mat); #endif } /*! * @brief copy upper-left of mat4 to mat3 * * @param[in] mat source * @param[out] dest destination */ CGLM_INLINE void glm_mat4_pick3(mat4 mat, mat3 dest) { dest[0][0] = mat[0][0]; dest[0][1] = mat[0][1]; dest[0][2] = mat[0][2]; dest[1][0] = mat[1][0]; dest[1][1] = mat[1][1]; dest[1][2] = mat[1][2]; dest[2][0] = mat[2][0]; dest[2][1] = mat[2][1]; dest[2][2] = mat[2][2]; } /*! * @brief copy upper-left of mat4 to mat3 (transposed) * * the postfix t stands for transpose * * @param[in] mat source * @param[out] dest destination */ CGLM_INLINE void glm_mat4_pick3t(mat4 mat, mat3 dest) { dest[0][0] = mat[0][0]; dest[0][1] = mat[1][0]; dest[0][2] = mat[2][0]; dest[1][0] = mat[0][1]; dest[1][1] = mat[1][1]; dest[1][2] = mat[2][1]; dest[2][0] = mat[0][2]; dest[2][1] = mat[1][2]; dest[2][2] = mat[2][2]; } /*! * @brief copy mat3 to mat4's upper-left * * @param[in] mat source * @param[out] dest destination */ CGLM_INLINE void glm_mat4_ins3(mat3 mat, mat4 dest) { dest[0][0] = mat[0][0]; dest[0][1] = mat[0][1]; dest[0][2] = mat[0][2]; dest[1][0] = mat[1][0]; dest[1][1] = mat[1][1]; dest[1][2] = mat[1][2]; dest[2][0] = mat[2][0]; dest[2][1] = mat[2][1]; dest[2][2] = mat[2][2]; } /*! * @brief multiply m1 and m2 to dest * * m1, m2 and dest matrices can be same matrix, it is possible to write this: * * @code * mat4 m = GLM_MAT4_IDENTITY_INIT; * glm_mat4_mul(m, m, m); * @endcode * * @param[in] m1 left matrix * @param[in] m2 right matrix * @param[out] dest destination matrix */ CGLM_INLINE void glm_mat4_mul(mat4 m1, mat4 m2, mat4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glm_mat4_mul_wasm(m1, m2, dest); #elif defined(__AVX__) glm_mat4_mul_avx(m1, m2, dest); #elif defined( __SSE__ ) || defined( __SSE2__ ) glm_mat4_mul_sse2(m1, m2, dest); #elif defined(CGLM_NEON_FP) glm_mat4_mul_neon(m1, m2, dest); #else float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], a03 = m1[0][3], a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], a13 = m1[1][3], a20 = m1[2][0], a21 = m1[2][1], a22 = m1[2][2], a23 = m1[2][3], a30 = m1[3][0], a31 = m1[3][1], a32 = m1[3][2], a33 = m1[3][3], b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2], b03 = m2[0][3], b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2], b13 = m2[1][3], b20 = m2[2][0], b21 = m2[2][1], b22 = m2[2][2], b23 = m2[2][3], b30 = m2[3][0], b31 = m2[3][1], b32 = m2[3][2], b33 = m2[3][3]; dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03; dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03; dest[0][2] = a02 * b00 + a12 * b01 + a22 * b02 + a32 * b03; dest[0][3] = a03 * b00 + a13 * b01 + a23 * b02 + a33 * b03; dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13; dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13; dest[1][2] = a02 * b10 + a12 * b11 + a22 * b12 + a32 * b13; dest[1][3] = a03 * b10 + a13 * b11 + a23 * b12 + a33 * b13; dest[2][0] = a00 * b20 + a10 * b21 + a20 * b22 + a30 * b23; dest[2][1] = a01 * b20 + a11 * b21 + a21 * b22 + a31 * b23; dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22 + a32 * b23; dest[2][3] = a03 * b20 + a13 * b21 + a23 * b22 + a33 * b23; dest[3][0] = a00 * b30 + a10 * b31 + a20 * b32 + a30 * b33; dest[3][1] = a01 * b30 + a11 * b31 + a21 * b32 + a31 * b33; dest[3][2] = a02 * b30 + a12 * b31 + a22 * b32 + a32 * b33; dest[3][3] = a03 * b30 + a13 * b31 + a23 * b32 + a33 * b33; #endif } /*! * @brief mupliply N mat4 matrices and store result in dest * * this function lets you multiply multiple (more than two or more...) matrices *

multiplication will be done in loop, this may reduce instructions * size but if len is too small then compiler may unroll whole loop, * usage: * @code * mat4 m1, m2, m3, m4, res; * * glm_mat4_mulN((mat4 *[]){&m1, &m2, &m3, &m4}, 4, res); * @endcode * * @warning matrices parameter is pointer array not mat4 array! * * @param[in] matrices mat4 * array * @param[in] len matrices count * @param[out] dest result */ CGLM_INLINE void glm_mat4_mulN(mat4 * __restrict matrices[], uint32_t len, mat4 dest) { uint32_t i; #ifndef NDEBUG assert(len > 1 && "there must be least 2 matrices to go!"); #endif glm_mat4_mul(*matrices[0], *matrices[1], dest); for (i = 2; i < len; i++) glm_mat4_mul(dest, *matrices[i], dest); } /*! * @brief multiply mat4 with vec4 (column vector) and store in dest vector * * @param[in] m mat4 (left) * @param[in] v vec4 (right, column vector) * @param[out] dest vec4 (result, column vector) */ CGLM_INLINE void glm_mat4_mulv(mat4 m, vec4 v, vec4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glm_mat4_mulv_wasm(m, v, dest); #elif defined( __SSE__ ) || defined( __SSE2__ ) glm_mat4_mulv_sse2(m, v, dest); #elif defined(CGLM_NEON_FP) glm_mat4_mulv_neon(m, v, dest); #else vec4 res; res[0] = m[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2] + m[3][0] * v[3]; res[1] = m[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2] + m[3][1] * v[3]; res[2] = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2] * v[3]; res[3] = m[0][3] * v[0] + m[1][3] * v[1] + m[2][3] * v[2] + m[3][3] * v[3]; glm_vec4_copy(res, dest); #endif } /*! * @brief trace of matrix * * sum of the elements on the main diagonal from upper left to the lower right * * @param[in] m matrix */ CGLM_INLINE float glm_mat4_trace(mat4 m) { return m[0][0] + m[1][1] + m[2][2] + m[3][3]; } /*! * @brief trace of matrix (rotation part) * * sum of the elements on the main diagonal from upper left to the lower right * * @param[in] m matrix */ CGLM_INLINE float glm_mat4_trace3(mat4 m) { return m[0][0] + m[1][1] + m[2][2]; } /*! * @brief convert mat4's rotation part to quaternion * * @param[in] m affine matrix * @param[out] dest destination quaternion */ CGLM_INLINE void glm_mat4_quat(mat4 m, versor dest) { float trace, r, rinv; /* it seems using like m12 instead of m[1][2] causes extra instructions */ trace = m[0][0] + m[1][1] + m[2][2]; if (trace >= 0.0f) { r = sqrtf(1.0f + trace); rinv = 0.5f / r; dest[0] = rinv * (m[1][2] - m[2][1]); dest[1] = rinv * (m[2][0] - m[0][2]); dest[2] = rinv * (m[0][1] - m[1][0]); dest[3] = r * 0.5f; } else if (m[0][0] >= m[1][1] && m[0][0] >= m[2][2]) { r = sqrtf(1.0f - m[1][1] - m[2][2] + m[0][0]); rinv = 0.5f / r; dest[0] = r * 0.5f; dest[1] = rinv * (m[0][1] + m[1][0]); dest[2] = rinv * (m[0][2] + m[2][0]); dest[3] = rinv * (m[1][2] - m[2][1]); } else if (m[1][1] >= m[2][2]) { r = sqrtf(1.0f - m[0][0] - m[2][2] + m[1][1]); rinv = 0.5f / r; dest[0] = rinv * (m[0][1] + m[1][0]); dest[1] = r * 0.5f; dest[2] = rinv * (m[1][2] + m[2][1]); dest[3] = rinv * (m[2][0] - m[0][2]); } else { r = sqrtf(1.0f - m[0][0] - m[1][1] + m[2][2]); rinv = 0.5f / r; dest[0] = rinv * (m[0][2] + m[2][0]); dest[1] = rinv * (m[1][2] + m[2][1]); dest[2] = r * 0.5f; dest[3] = rinv * (m[0][1] - m[1][0]); } } /*! * @brief multiply vector with mat4 * * actually the result is vec4, after multiplication the last component * is trimmed. if you need it don't use this func. * * @param[in] m mat4(affine transform) * @param[in] v vec3 * @param[in] last 4th item to make it vec4 * @param[out] dest result vector (vec3) */ CGLM_INLINE void glm_mat4_mulv3(mat4 m, vec3 v, float last, vec3 dest) { vec4 res; glm_vec4(v, last, res); glm_mat4_mulv(m, res, res); glm_vec3(res, dest); } /*! * @brief transpose mat4 and store in dest * * source matrix will not be transposed unless dest is m * * @param[in] m matrix * @param[out] dest result */ CGLM_INLINE void glm_mat4_transpose_to(mat4 m, mat4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glm_mat4_transp_wasm(m, dest); #elif defined(__AVX__) glm_mat4_transp_avx(m, dest); #elif defined( __SSE__ ) || defined( __SSE2__ ) glm_mat4_transp_sse2(m, dest); #elif defined(CGLM_NEON_FP) glm_mat4_transp_neon(m, dest); #else dest[0][0] = m[0][0]; dest[1][0] = m[0][1]; dest[0][1] = m[1][0]; dest[1][1] = m[1][1]; dest[0][2] = m[2][0]; dest[1][2] = m[2][1]; dest[0][3] = m[3][0]; dest[1][3] = m[3][1]; dest[2][0] = m[0][2]; dest[3][0] = m[0][3]; dest[2][1] = m[1][2]; dest[3][1] = m[1][3]; dest[2][2] = m[2][2]; dest[3][2] = m[2][3]; dest[2][3] = m[3][2]; dest[3][3] = m[3][3]; #endif } /*! * @brief transpose mat4 and store result in same matrix * * @param[in, out] m source and dest */ CGLM_INLINE void glm_mat4_transpose(mat4 m) { #if defined(__wasm__) && defined(__wasm_simd128__) glm_mat4_transp_wasm(m, m); #elif defined(__AVX__) glm_mat4_transp_avx(m, m); #elif defined( __SSE__ ) || defined( __SSE2__ ) glm_mat4_transp_sse2(m, m); #elif defined(CGLM_NEON_FP) glm_mat4_transp_neon(m, m); #else mat4 d; glm_mat4_transpose_to(m, d); glm_mat4_ucopy(d, m); #endif } /*! * @brief scale (multiply with scalar) matrix without simd optimization * * multiply matrix with scalar * * @param[in, out] m matrix * @param[in] s scalar */ CGLM_INLINE void glm_mat4_scale_p(mat4 m, float s) { m[0][0] *= s; m[0][1] *= s; m[0][2] *= s; m[0][3] *= s; m[1][0] *= s; m[1][1] *= s; m[1][2] *= s; m[1][3] *= s; m[2][0] *= s; m[2][1] *= s; m[2][2] *= s; m[2][3] *= s; m[3][0] *= s; m[3][1] *= s; m[3][2] *= s; m[3][3] *= s; } /*! * @brief scale (multiply with scalar) matrix * * multiply matrix with scalar * * @param[in, out] m matrix * @param[in] s scalar */ CGLM_INLINE void glm_mat4_scale(mat4 m, float s) { #if defined(__wasm__) && defined(__wasm_simd128__) glm_mat4_scale_wasm(m, s); #elif defined(__AVX__) glm_mat4_scale_avx(m, s); #elif defined( __SSE__ ) || defined( __SSE2__ ) glm_mat4_scale_sse2(m, s); #elif defined(CGLM_NEON_FP) glm_mat4_scale_neon(m, s); #else glm_mat4_scale_p(m, s); #endif } /*! * @brief mat4 determinant * * @param[in] mat matrix * * @return determinant */ CGLM_INLINE float glm_mat4_det(mat4 mat) { #if defined(__wasm__) && defined(__wasm_simd128__) return glm_mat4_det_wasm(mat); #elif defined( __SSE__ ) || defined( __SSE2__ ) return glm_mat4_det_sse2(mat); #elif defined(CGLM_NEON_FP) return glm_mat4_det_neon(mat); #else /* [square] det(A) = det(At) */ float t[6]; float a = mat[0][0], b = mat[0][1], c = mat[0][2], d = mat[0][3], e = mat[1][0], f = mat[1][1], g = mat[1][2], h = mat[1][3], i = mat[2][0], j = mat[2][1], k = mat[2][2], l = mat[2][3], m = mat[3][0], n = mat[3][1], o = mat[3][2], p = mat[3][3]; t[0] = k * p - o * l; t[1] = j * p - n * l; t[2] = j * o - n * k; t[3] = i * p - m * l; t[4] = i * o - m * k; t[5] = i * n - m * j; return a * (f * t[0] - g * t[1] + h * t[2]) - b * (e * t[0] - g * t[3] + h * t[4]) + c * (e * t[1] - f * t[3] + h * t[5]) - d * (e * t[2] - f * t[4] + g * t[5]); #endif } /*! * @brief inverse mat4 and store in dest * * @param[in] mat matrix * @param[out] dest inverse matrix */ CGLM_INLINE void glm_mat4_inv(mat4 mat, mat4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glm_mat4_inv_wasm(mat, dest); #elif defined( __SSE__ ) || defined( __SSE2__ ) glm_mat4_inv_sse2(mat, dest); #elif defined(CGLM_NEON_FP) glm_mat4_inv_neon(mat, dest); #else float a = mat[0][0], b = mat[0][1], c = mat[0][2], d = mat[0][3], e = mat[1][0], f = mat[1][1], g = mat[1][2], h = mat[1][3], i = mat[2][0], j = mat[2][1], k = mat[2][2], l = mat[2][3], m = mat[3][0], n = mat[3][1], o = mat[3][2], p = mat[3][3], c1 = k * p - l * o, c2 = c * h - d * g, c3 = i * p - l * m, c4 = a * h - d * e, c5 = j * p - l * n, c6 = b * h - d * f, c7 = i * n - j * m, c8 = a * f - b * e, c9 = j * o - k * n, c10 = b * g - c * f, c11 = i * o - k * m, c12 = a * g - c * e, idt = 1.0f/(c8*c1+c4*c9+c10*c3+c2*c7-c12*c5-c6*c11), ndt = -idt; dest[0][0] = (f * c1 - g * c5 + h * c9) * idt; dest[0][1] = (b * c1 - c * c5 + d * c9) * ndt; dest[0][2] = (n * c2 - o * c6 + p * c10) * idt; dest[0][3] = (j * c2 - k * c6 + l * c10) * ndt; dest[1][0] = (e * c1 - g * c3 + h * c11) * ndt; dest[1][1] = (a * c1 - c * c3 + d * c11) * idt; dest[1][2] = (m * c2 - o * c4 + p * c12) * ndt; dest[1][3] = (i * c2 - k * c4 + l * c12) * idt; dest[2][0] = (e * c5 - f * c3 + h * c7) * idt; dest[2][1] = (a * c5 - b * c3 + d * c7) * ndt; dest[2][2] = (m * c6 - n * c4 + p * c8) * idt; dest[2][3] = (i * c6 - j * c4 + l * c8) * ndt; dest[3][0] = (e * c9 - f * c11 + g * c7) * ndt; dest[3][1] = (a * c9 - b * c11 + c * c7) * idt; dest[3][2] = (m * c10 - n * c12 + o * c8) * ndt; dest[3][3] = (i * c10 - j * c12 + k * c8) * idt; #endif } /*! * @brief inverse mat4 and store in dest * * this func uses reciprocal approximation without extra corrections * e.g Newton-Raphson. this should work faster than normal, * to get more precise use glm_mat4_inv version. * * NOTE: You will lose precision, glm_mat4_inv is more accurate * * @param[in] mat matrix * @param[out] dest inverse matrix */ CGLM_INLINE void glm_mat4_inv_fast(mat4 mat, mat4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glm_mat4_inv_fast_wasm(mat, dest); #elif defined( __SSE__ ) || defined( __SSE2__ ) glm_mat4_inv_fast_sse2(mat, dest); #else glm_mat4_inv(mat, dest); #endif } /*! * @brief swap two matrix columns * * @param[in,out] mat matrix * @param[in] col1 col1 * @param[in] col2 col2 */ CGLM_INLINE void glm_mat4_swap_col(mat4 mat, int col1, int col2) { CGLM_ALIGN(16) vec4 tmp; glm_vec4_copy(mat[col1], tmp); glm_vec4_copy(mat[col2], mat[col1]); glm_vec4_copy(tmp, mat[col2]); } /*! * @brief swap two matrix rows * * @param[in,out] mat matrix * @param[in] row1 row1 * @param[in] row2 row2 */ CGLM_INLINE void glm_mat4_swap_row(mat4 mat, int row1, int row2) { CGLM_ALIGN(16) vec4 tmp; tmp[0] = mat[0][row1]; tmp[1] = mat[1][row1]; tmp[2] = mat[2][row1]; tmp[3] = mat[3][row1]; mat[0][row1] = mat[0][row2]; mat[1][row1] = mat[1][row2]; mat[2][row1] = mat[2][row2]; mat[3][row1] = mat[3][row2]; mat[0][row2] = tmp[0]; mat[1][row2] = tmp[1]; mat[2][row2] = tmp[2]; mat[3][row2] = tmp[3]; } /*! * @brief helper for R (row vector) * M (matrix) * C (column vector) * * rmc stands for Row * Matrix * Column * * the result is scalar because R * M = Matrix1x4 (row vector), * then Matrix1x4 * Vec4 (column vector) = Matrix1x1 (Scalar) * * @param[in] r row vector or matrix1x4 * @param[in] m matrix4x4 * @param[in] c column vector or matrix4x1 * * @return scalar value e.g. B(s) */ CGLM_INLINE float glm_mat4_rmc(vec4 r, mat4 m, vec4 c) { vec4 tmp; glm_mat4_mulv(m, c, tmp); return glm_vec4_dot(r, tmp); } /*! * @brief Create mat4 matrix from pointer * * @param[in] src pointer to an array of floats * @param[out] dest matrix */ CGLM_INLINE void glm_mat4_make(const float * __restrict src, mat4 dest) { dest[0][0] = src[0]; dest[1][0] = src[4]; dest[0][1] = src[1]; dest[1][1] = src[5]; dest[0][2] = src[2]; dest[1][2] = src[6]; dest[0][3] = src[3]; dest[1][3] = src[7]; dest[2][0] = src[8]; dest[3][0] = src[12]; dest[2][1] = src[9]; dest[3][1] = src[13]; dest[2][2] = src[10]; dest[3][2] = src[14]; dest[2][3] = src[11]; dest[3][3] = src[15]; } /*! * @brief Create mat4 matrix from texture transform parameters * * @param[in] sx scale x * @param[in] sy scale y * @param[in] rot rotation in radians CCW/RH * @param[in] tx translate x * @param[in] ty translate y * @param[out] dest texture transform matrix */ CGLM_INLINE void glm_mat4_textrans(float sx, float sy, float rot, float tx, float ty, mat4 dest) { float c, s; c = cosf(rot); s = sinf(rot); glm_mat4_identity(dest); dest[0][0] = c * sx; dest[0][1] = -s * sy; dest[1][0] = s * sx; dest[1][1] = c * sy; dest[3][0] = tx; dest[3][1] = ty; } #endif /* cglm_mat_h */ cglm-0.9.7/include/cglm/mat4x2.h000066400000000000000000000075701526744317200163320ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLM_MAT4X2_ZERO_INIT GLM_MAT4X2_ZERO Functions: CGLM_INLINE void glm_mat4x2_copy(mat4x2 src, mat4x2 dest); CGLM_INLINE void glm_mat4x2_zero(mat4x2 m); CGLM_INLINE void glm_mat4x2_make(const float * __restrict src, mat4x2 dest); CGLM_INLINE void glm_mat4x2_mul(mat4x2 m1, mat2x4 m2, mat2 dest); CGLM_INLINE void glm_mat4x2_mulv(mat4x2 m, vec4 v, vec2 dest); CGLM_INLINE void glm_mat4x2_transpose(mat4x2 src, mat2x4 dest); CGLM_INLINE void glm_mat4x2_scale(mat4x2 m, float s); */ #ifndef cglm_mat4x2_h #define cglm_mat4x2_h #include "common.h" #define GLM_MAT4X2_ZERO_INIT {{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}} /* for C only */ #define GLM_MAT4X2_ZERO GLM_MAT4X2_ZERO_INIT /*! * @brief Copy mat4x2 (src) to mat4x2 (dest). * * @param[in] src mat4x2 (left) * @param[out] dest destination (result, mat4x2) */ CGLM_INLINE void glm_mat4x2_copy(mat4x2 src, mat4x2 dest) { glm_vec2_copy(src[0], dest[0]); glm_vec2_copy(src[1], dest[1]); glm_vec2_copy(src[2], dest[2]); glm_vec2_copy(src[3], dest[3]); } /*! * @brief Zero out the mat4x2 (m). * * @param[in, out] mat4x2 (src, dest) */ CGLM_INLINE void glm_mat4x2_zero(mat4x2 m) { CGLM_ALIGN_MAT mat4x2 t = GLM_MAT4X2_ZERO_INIT; glm_mat4x2_copy(t, m); } /*! * @brief Create mat4x2 (dest) from pointer (src). * * @param[in] src pointer to an array of floats (left) * @param[out] dest destination (result, mat4x2) */ CGLM_INLINE void glm_mat4x2_make(const float * __restrict src, mat4x2 dest) { dest[0][0] = src[0]; dest[0][1] = src[1]; dest[1][0] = src[2]; dest[1][1] = src[3]; dest[2][0] = src[4]; dest[2][1] = src[5]; dest[3][0] = src[6]; dest[3][1] = src[7]; } /*! * @brief Multiply mat4x2 (m1) by mat2x4 (m2) and store in mat2 (dest). * * @code * glm_mat4x2_mul(mat4x2, mat2x4, mat2); * @endcode * * @param[in] m1 mat4x2 (left) * @param[in] m2 mat2x4 (right) * @param[out] dest destination (result, mat2) */ CGLM_INLINE void glm_mat4x2_mul(mat4x2 m1, mat2x4 m2, mat2 dest) { float a00 = m1[0][0], a01 = m1[0][1], a10 = m1[1][0], a11 = m1[1][1], a20 = m1[2][0], a21 = m1[2][1], a30 = m1[3][0], a31 = m1[3][1], b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2], b03 = m2[0][3], b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2], b13 = m2[1][3]; dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03; dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03; dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13; dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13; } /*! * @brief Multiply mat4x2 (m) by vec4 (v) and store in vec2 (dest). * * @param[in] m mat4x2 (left) * @param[in] v vec4 (right, column vector) * @param[out] dest destination (result, column vector) */ CGLM_INLINE void glm_mat4x2_mulv(mat4x2 m, vec4 v, vec2 dest) { float v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3]; dest[0] = m[0][0] * v0 + m[1][0] * v1 + m[2][0] * v2 + m[3][0] * v3; dest[1] = m[0][1] * v0 + m[1][1] * v1 + m[2][1] * v2 + m[3][1] * v3; } /*! * @brief Transpose mat4x2 (src) and store in mat2x4 (dest). * * @param[in] src mat4x2 (left) * @param[out] dest destination (result, mat2x4) */ CGLM_INLINE void glm_mat4x2_transpose(mat4x2 m, mat2x4 dest) { dest[0][0] = m[0][0]; dest[0][1] = m[1][0]; dest[0][2] = m[2][0]; dest[0][3] = m[3][0]; dest[1][0] = m[0][1]; dest[1][1] = m[1][1]; dest[1][2] = m[2][1]; dest[1][3] = m[3][1]; } /*! * @brief Multiply mat4x2 (m) by scalar constant (s). * * @param[in, out] m (src, dest) * @param[in] s float (scalar) */ CGLM_INLINE void glm_mat4x2_scale(mat4x2 m, float s) { m[0][0] *= s; m[0][1] *= s; m[1][0] *= s; m[1][1] *= s; m[2][0] *= s; m[2][1] *= s; m[3][0] *= s; m[3][1] *= s; } #endif cglm-0.9.7/include/cglm/mat4x3.h000066400000000000000000000113311526744317200163210ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLM_MAT4X3_ZERO_INIT GLM_MAT4X3_ZERO Functions: CGLM_INLINE void glm_mat4x3_copy(mat4x3 src, mat4x3 dest); CGLM_INLINE void glm_mat4x3_zero(mat4x3 m); CGLM_INLINE void glm_mat4x3_make(const float * __restrict src, mat4x3 dest); CGLM_INLINE void glm_mat4x3_mul(mat4x3 m1, mat3x4 m2, mat3 dest); CGLM_INLINE void glm_mat4x3_mulv(mat4x3 m, vec4 v, vec3 dest); CGLM_INLINE void glm_mat4x3_transpose(mat4x3 src, mat3x4 dest); CGLM_INLINE void glm_mat4x3_scale(mat4x3 m, float s); */ #ifndef cglm_mat4x3_h #define cglm_mat4x3_h #include "common.h" #define GLM_MAT4X3_ZERO_INIT {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, \ {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}} /* for C only */ #define GLM_MAT4X3_ZERO GLM_MAT4X3_ZERO_INIT /*! * @brief Copy mat4x3 (src) to mat4x3 (dest). * * @param[in] src mat4x3 (left) * @param[out] dest destination (result, mat4x3) */ CGLM_INLINE void glm_mat4x3_copy(mat4x3 src, mat4x3 dest) { glm_vec3_copy(src[0], dest[0]); glm_vec3_copy(src[1], dest[1]); glm_vec3_copy(src[2], dest[2]); glm_vec3_copy(src[3], dest[3]); } /*! * @brief Zero out the mat4x3 (m). * * @param[in, out] mat4x3 (src, dest) */ CGLM_INLINE void glm_mat4x3_zero(mat4x3 m) { CGLM_ALIGN_MAT mat4x3 t = GLM_MAT4X3_ZERO_INIT; glm_mat4x3_copy(t, m); } /*! * @brief Create mat4x3 (dest) from pointer (src). * * @param[in] src pointer to an array of floats (left) * @param[out] dest destination (result, mat4x3) */ CGLM_INLINE void glm_mat4x3_make(const float * __restrict src, mat4x3 dest) { dest[0][0] = src[0]; dest[0][1] = src[1]; dest[0][2] = src[2]; dest[1][0] = src[3]; dest[1][1] = src[4]; dest[1][2] = src[5]; dest[2][0] = src[6]; dest[2][1] = src[7]; dest[2][2] = src[8]; dest[3][0] = src[9]; dest[3][1] = src[10]; dest[3][2] = src[11]; } /*! * @brief Multiply mat4x3 (m1) by mat3x4 (m2) and store in mat3 (dest). * * @code * glm_mat4x3_mul(mat4x3, mat3x4, mat3); * @endcode * * @param[in] m1 mat4x3 (left) * @param[in] m2 mat3x4 (right) * @param[out] dest destination (result, mat3) */ CGLM_INLINE void glm_mat4x3_mul(mat4x3 m1, mat3x4 m2, mat3 dest) { float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], a20 = m1[2][0], a21 = m1[2][1], a22 = m1[2][2], a30 = m1[3][0], a31 = m1[3][1], a32 = m1[3][2], b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2], b03 = m2[0][3], b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2], b13 = m2[1][3], b20 = m2[2][0], b21 = m2[2][1], b22 = m2[2][2], b23 = m2[2][3]; dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03; dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03; dest[0][2] = a02 * b00 + a12 * b01 + a22 * b02 + a32 * b03; dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13; dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13; dest[1][2] = a02 * b10 + a12 * b11 + a22 * b12 + a32 * b13; dest[2][0] = a00 * b20 + a10 * b21 + a20 * b22 + a30 * b23; dest[2][1] = a01 * b20 + a11 * b21 + a21 * b22 + a31 * b23; dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22 + a32 * b23; } /*! * @brief Multiply mat4x3 (m) by vec4 (v) and store in vec3 (dest). * * @param[in] m mat4x3 (left) * @param[in] v vec3 (right, column vector) * @param[out] dest destination (result, column vector) */ CGLM_INLINE void glm_mat4x3_mulv(mat4x3 m, vec4 v, vec3 dest) { float v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3]; dest[0] = m[0][0] * v0 + m[1][0] * v1 + m[2][0] * v2 + m[3][0] * v3; dest[1] = m[0][1] * v0 + m[1][1] * v1 + m[2][1] * v2 + m[3][1] * v3; dest[2] = m[0][2] * v0 + m[1][2] * v1 + m[2][2] * v2 + m[3][2] * v3; } /*! * @brief Transpose mat4x3 (src) and store in mat3x4 (dest). * * @param[in] src mat4x3 (left) * @param[out] dest destination (result, mat3x4) */ CGLM_INLINE void glm_mat4x3_transpose(mat4x3 src, mat3x4 dest) { dest[0][0] = src[0][0]; dest[0][1] = src[1][0]; dest[0][2] = src[2][0]; dest[0][3] = src[3][0]; dest[1][0] = src[0][1]; dest[1][1] = src[1][1]; dest[1][2] = src[2][1]; dest[1][3] = src[3][1]; dest[2][0] = src[0][2]; dest[2][1] = src[1][2]; dest[2][2] = src[2][2]; dest[2][3] = src[3][2]; } /*! * @brief Multiply mat4x3 (m) by scalar constant (s). * * @param[in, out] m (src, dest) * @param[in] s float (scalar) */ CGLM_INLINE void glm_mat4x3_scale(mat4x3 m, float s) { m[0][0] *= s; m[0][1] *= s; m[0][2] *= s; m[1][0] *= s; m[1][1] *= s; m[1][2] *= s; m[2][0] *= s; m[2][1] *= s; m[2][2] *= s; m[3][0] *= s; m[3][1] *= s; m[3][2] *= s; } #endif /* cglm_mat4x3_h */ cglm-0.9.7/include/cglm/noise.h000066400000000000000000000742531526744317200163320ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file * * Based on the work of Stefan Gustavson and Ashima Arts on "webgl-noise": * https://github.com/stegu/webgl-noise * Following Stefan Gustavson's paper "Simplex noise demystified": * http://www.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf * * Implementation based on glm::perlin function: * https://github.com/g-truc/glm/blob/master/glm/gtc/noise.inl */ #ifndef cglm_noise_h #define cglm_noise_h #include "vec4.h" #include "vec4-ext.h" #include "vec3.h" #include "vec3-ext.h" #include "vec2.h" #include "vec2-ext.h" #define glm__noiseDetail_mod289(x) (x - floorf(x * (1.0f / 289.0f)) * 289.0f) /* glm__noiseDetail_permute(vec4 x, vec4 dest) */ #define glm__noiseDetail_permute(x, dest) { \ dest[0] = glm__noiseDetail_mod289((x[0] * 34.0f + 1.0f) * x[0]); \ dest[1] = glm__noiseDetail_mod289((x[1] * 34.0f + 1.0f) * x[1]); \ dest[2] = glm__noiseDetail_mod289((x[2] * 34.0f + 1.0f) * x[2]); \ dest[3] = glm__noiseDetail_mod289((x[3] * 34.0f + 1.0f) * x[3]); \ } /* glm__noiseDetail_fade_vec4(vec4 t, vec4 dest) */ #define glm__noiseDetail_fade_vec4(t, dest) { \ /* dest = (t * t * t) * (t * (t * 6.0f - 15.0f) + 10.0f) */ \ vec4 temp; \ glm_vec4_mul(t, t, temp); \ glm_vec4_mul(temp, t, temp); \ /* dest = (t * (t * 6.0f - 15.0f) + 10.0f) */ \ glm_vec4_scale(t, 6.0f, dest); \ glm_vec4_subs(dest, 15.0f, dest); \ glm_vec4_mul(t, dest, dest); \ glm_vec4_adds(dest, 10.0f, dest); \ /* dest = temp * dest */ \ glm_vec4_mul(temp, dest, dest); \ } /* glm__noiseDetail_fade_vec3(vec3 t, vec3 dest) */ #define glm__noiseDetail_fade_vec3(t, dest) { \ /* dest = (t * t * t) * (t * (t * 6.0f - 15.0f) + 10.0f) */ \ /* temp = t * t * t */ \ vec3 temp; \ glm_vec3_mul(t, t, temp); \ glm_vec3_mul(temp, t, temp); \ /* dest = (t * (t * 6.0f - 15.0f) + 10.0f) */ \ glm_vec3_scale(t, 6.0f, dest); \ glm_vec3_subs(dest, 15.0f, dest); \ glm_vec3_mul(t, dest, dest); \ glm_vec3_adds(dest, 10.0f, dest); \ /* dest = temp * dest */ \ glm_vec3_mul(temp, dest, dest); \ } /* glm__noiseDetail_fade_vec2(vec2 t, vec2 dest) */ #define glm__noiseDetail_fade_vec2(t, dest) { \ /* dest = (t * t * t) * (t * (t * 6.0f - 15.0f) + 10.0f) */ \ /* temp = t * t * t */ \ vec2 temp; \ glm_vec2_mul(t, t, temp); \ glm_vec2_mul(temp, t, temp); \ /* dest = (t * (t * 6.0f - 15.0f) + 10.0f) */ \ glm_vec2_scale(t, 6.0f, dest); \ glm_vec2_subs(dest, 15.0f, dest); \ glm_vec2_mul(t, dest, dest); \ glm_vec2_adds(dest, 10.0f, dest); \ /* dest = temp * dest */ \ glm_vec2_mul(temp, dest, dest); \ } /* glm__noiseDetail_taylorInvSqrt(vec4 x, vec4 dest) */ #define glm__noiseDetail_taylorInvSqrt(x, dest) { \ /* dest = 1.79284291400159f - 0.85373472095314f * x */ \ vec4 temp; \ glm_vec4_scale(x, 0.85373472095314f, temp); /* temp = 0.853...f * x */ \ glm_vec4_fill(dest, 1.79284291400159f); /* dest = 1.792...f */ \ glm_vec4_sub(dest, temp, dest); /* dest = 1.79284291400159f - temp */ \ } /* norm = taylorInvSqrt(vec4( * dot(g00__, g00__), * dot(g01__, g01__), * dot(g10__, g10__), * dot(g11__, g11__) * )); */ /* glm__noiseDetail_gradNorm_vec4(vec4 g00__, vec4 g01__, vec4 g10__, vec4 g11__) */ #define glm__noiseDetail_gradNorm_vec4(g00__, g01__, g10__, g11__) { \ vec4 norm; \ norm[0] = glm_vec4_dot(g00__, g00__); /* norm.x = dot(g00__, g00__) */ \ norm[1] = glm_vec4_dot(g01__, g01__); /* norm.y = dot(g01__, g01__) */ \ norm[2] = glm_vec4_dot(g10__, g10__); /* norm.z = dot(g10__, g10__) */ \ norm[3] = glm_vec4_dot(g11__, g11__); /* norm.w = dot(g11__, g11__) */ \ glm__noiseDetail_taylorInvSqrt(norm, norm); /* norm = taylorInvSqrt(norm) */ \ \ glm_vec4_scale(g00__, norm[0], g00__); /* g00__ *= norm.x */ \ glm_vec4_scale(g01__, norm[1], g01__); /* g01__ *= norm.y */ \ glm_vec4_scale(g10__, norm[2], g10__); /* g10__ *= norm.z */ \ glm_vec4_scale(g11__, norm[3], g11__); /* g11__ *= norm.w */ \ } /* glm__noiseDetail_gradNorm_vec3(vec3 g00_, vec3 g01_, vec3 g10_, vec3 g11_) */ #define glm__noiseDetail_gradNorm_vec3(g00_, g01_, g10_, g11_) { \ vec4 norm; \ norm[0] = glm_vec3_dot(g00_, g00_); /* norm.x = dot(g00_, g00_) */ \ norm[1] = glm_vec3_dot(g01_, g01_); /* norm.y = dot(g01_, g01_) */ \ norm[2] = glm_vec3_dot(g10_, g10_); /* norm.z = dot(g10_, g10_) */ \ norm[3] = glm_vec3_dot(g11_, g11_); /* norm.w = dot(g11_, g11_) */ \ glm__noiseDetail_taylorInvSqrt(norm, norm); /* norm = taylorInvSqrt(norm) */ \ \ glm_vec3_scale(g00_, norm[0], g00_); /* g00_ *= norm.x */ \ glm_vec3_scale(g01_, norm[1], g01_); /* g01_ *= norm.y */ \ glm_vec3_scale(g10_, norm[2], g10_); /* g10_ *= norm.z */ \ glm_vec3_scale(g11_, norm[3], g11_); /* g11_ *= norm.w */ \ } /* glm__noiseDetail_gradNorm_vec2(vec2 g00, vec2 g01, vec2 g10, vec2 g11) */ #define glm__noiseDetail_gradNorm_vec2(g00, g01, g10, g11) { \ vec4 norm; \ norm[0] = glm_vec2_dot(g00, g00); /* norm.x = dot(g00, g00) */ \ norm[1] = glm_vec2_dot(g01, g01); /* norm.y = dot(g01, g01) */ \ norm[2] = glm_vec2_dot(g10, g10); /* norm.z = dot(g10, g10) */ \ norm[3] = glm_vec2_dot(g11, g11); /* norm.w = dot(g11, g11) */ \ glm__noiseDetail_taylorInvSqrt(norm, norm); /* norm = taylorInvSqrt(norm) */ \ \ glm_vec2_scale(g00, norm[0], g00); /* g00 *= norm.x */ \ glm_vec2_scale(g01, norm[1], g01); /* g01 *= norm.y */ \ glm_vec2_scale(g10, norm[2], g10); /* g10 *= norm.z */ \ glm_vec2_scale(g11, norm[3], g11); /* g11 *= norm.w */ \ } /* glm__noiseDetail_i2gxyzw(vec4 ixy, vec4 gx, vec4 gy, vec4 gz, vec4 gw) */ #define glm__noiseDetail_i2gxyzw(ixy, gx, gy, gz, gw) { \ /* gx = ixy / 7.0 */ \ glm_vec4_divs(ixy, 7.0f, gx); /* gx = ixy / 7.0 */ \ \ /* gy = fract(gx) / 7.0 */ \ glm_vec4_floor(gx, gy); /* gy = floor(gx) */ \ glm_vec4_divs(gy, 7.0f, gy); /* gy /= 7.0 */ \ \ /* gz = floor(gy) / 6.0 */ \ glm_vec4_floor(gy, gz); /* gz = floor(gy) */ \ glm_vec4_divs(gz, 6.0f, gz); /* gz /= 6.0 */ \ \ /* gx = fract(gx) - 0.5f */ \ glm_vec4_fract(gx, gx); /* gx = fract(gx) */ \ glm_vec4_subs(gx, 0.5f, gx); /* gx -= 0.5f */ \ \ /* gy = fract(gy) - 0.5f */ \ glm_vec4_fract(gy, gy); /* gy = fract(gy) */ \ glm_vec4_subs(gy, 0.5f, gy); /* gy -= 0.5f */ \ \ /* gz = fract(gz) - 0.5f */ \ glm_vec4_fract(gz, gz); /* gz = fract(gz) */ \ glm_vec4_subs(gz, 0.5f, gz); /* gz -= 0.5f */ \ \ /* abs(gx), abs(gy), abs(gz) */ \ vec4 gxa, gya, gza; \ glm_vec4_abs(gx, gxa); /* gxa = abs(gx) */ \ glm_vec4_abs(gy, gya); /* gya = abs(gy) */ \ glm_vec4_abs(gz, gza); /* gza = abs(gz) */ \ \ /* gw = 0.75 - abs(gx) - abs(gy) - abs(gz) */ \ glm_vec4_fill(gw, 0.75f); /* gw = 0.75 */ \ glm_vec4_sub(gw, gxa, gw); /* gw -= gxa */ \ glm_vec4_sub(gw, gza, gw); /* gw -= gza */ \ glm_vec4_sub(gw, gya, gw); /* gw -= gya */ \ \ /* sw = step(gw, 0.0); */ \ vec4 sw; \ glm_vec4_stepr(gw, 0.0f, sw); /* sw = step(gw, 0.0) */ \ \ /* gx -= sw * (step(vec4(0), gx) - T(0.5)); */ \ vec4 temp = {0.0f}; /* temp = 0.0 */ \ glm_vec4_step(temp, gx, temp); /* temp = step(temp, gx) */ \ glm_vec4_subs(temp, 0.5f, temp); /* temp -= 0.5 */ \ glm_vec4_mul(sw, temp, temp); /* temp *= sw */ \ glm_vec4_sub(gx, temp, gx); /* gx -= temp */ \ \ /* gy -= sw * (step(vec4(0), gy) - T(0.5)); */ \ glm_vec4_zero(temp); /* reset temp */ \ glm_vec4_step(temp, gy, temp); /* temp = step(temp, gy) */ \ glm_vec4_subs(temp, 0.5f, temp); /* temp -= 0.5 */ \ glm_vec4_mul(sw, temp, temp); /* temp *= sw */ \ glm_vec4_sub(gy, temp, gy); /* gy -= temp */ \ } /* NOTE: This function is not *quite* analogous to glm__noiseDetail_i2gxyzw * to try to match the output of glm::perlin. I think it might be a bug in * in the original implementation, but for now I'm keeping it consistent. -MK * * Follow up: The original implementation (glm v 1.0.1) does: * * vec<4, T, Q> gx0 = ixy0 * T(1.0 / 7.0); * * as opposed to: * * vec<4, T, Q> gx0 = ixy0 / T(7); * * This ends up mapping to different simd instructions, at least on AMD. * The delta is tiny but it gets amplified by the rest of the noise function. * Hence we too need to do `glm_vec4_scale` as opposed to `glm_vec4_divs`, to * match it. -MK */ /* glm__noiseDetail_i2gxyz(vec4 i, vec4 gx, vec4 gy, vec4 gz) */ #define glm__noiseDetail_i2gxyz(ixy, gx, gy, gz) { \ /* gx = ixy / 7.0 */ \ glm_vec4_scale(ixy, 1.0f / 7.0f, gx); /* gx = ixy * (1/7.0) */\ \ /* gy = fract(floor(gx0) / 7.0)) - 0.5; */ \ glm_vec4_floor(gx, gy); /* gy = floor(gx) */ \ glm_vec4_scale(gy, 1.0f / 7.0f, gy); /* gy *= 1 / 7.0 */ \ glm_vec4_fract(gy, gy); /* gy = fract(gy) */ \ glm_vec4_subs(gy, 0.5f, gy); /* gy -= 0.5f */ \ \ /* gx = fract(gx); */ \ glm_vec4_fract(gx, gx); /* gx = fract(gx) */ \ \ /* abs(gx), abs(gy) */ \ vec4 gxa, gya; \ glm_vec4_abs(gx, gxa); /* gxa = abs(gx) */ \ glm_vec4_abs(gy, gya); /* gya = abs(gy) */ \ \ /* gz = vec4(0.5) - abs(gx0) - abs(gy0); */ \ glm_vec4_fill(gz, 0.5f); /* gz = 0.5 */ \ glm_vec4_sub(gz, gxa, gz); /* gz -= gxa */ \ glm_vec4_sub(gz, gya, gz); /* gz -= gya */ \ \ /* sz = step(gw, 0.0); */ \ vec4 sz; \ glm_vec4_stepr(gz, 0.0f, sz); /* sz = step(gz, 0.0) */ \ \ /* gx0 -= sz0 * (step(0.0, gx0) - T(0.5)); */ \ vec4 temp = {0.0f}; /* temp = 0.0 */ \ glm_vec4_step(temp, gx, temp); /* temp = step(temp, gx) */ \ glm_vec4_subs(temp, 0.5f, temp); /* temp -= 0.5 */ \ glm_vec4_mul(sz, temp, temp); /* temp *= sz */ \ glm_vec4_sub(gx, temp, gx); /* gx -= temp */ \ \ /* gy0 -= sz0 * (step(0.0, gy0) - T(0.5)); */ \ glm_vec4_zero(temp); /* reset temp */ \ glm_vec4_step(temp, gy, temp); /* temp = step(temp, gy) */ \ glm_vec4_subs(temp, 0.5f, temp); /* temp -= 0.5 */ \ glm_vec4_mul(sz, temp, temp); /* temp *= sz */ \ glm_vec4_sub(gy, temp, gy); /* gy -= temp */ \ } /* glm__noiseDetail_i2gxy(vec4 i, vec4 gx, vec4 gy) */ #define glm__noiseDetail_i2gxy(i, gx, gy) { \ /* gx = 2.0 * fract(i / 41.0) - 1.0; */ \ glm_vec4_divs(i, 41.0f, gx); /* gx = i / 41.0 */ \ glm_vec4_fract(gx, gx); /* gx = fract(gx) */ \ glm_vec4_scale(gx, 2.0f, gx); /* gx *= 2.0 */ \ glm_vec4_subs(gx, 1.0f, gx); /* gx -= 1.0 */ \ \ /* gy = abs(gx) - 0.5; */ \ glm_vec4_abs(gx, gy); /* gy = abs(gx) */ \ glm_vec4_subs(gy, 0.5f, gy); /* gy -= 0.5 */ \ \ /* tx = floor(gx + 0.5); */ \ vec4 tx; \ glm_vec4_adds(gx, 0.5f, tx); /* tx = gx + 0.5 */ \ glm_vec4_floor(tx, tx); /* tx = floor(tx) */ \ \ /* gx = gx - tx; */ \ glm_vec4_sub(gx, tx, gx); /* gx -= tx */ \ } /* ============================================================================ * Classic perlin noise * ============================================================================ */ /*! * @brief Classic perlin noise * * @param[in] point 4D vector * @returns perlin noise value */ CGLM_INLINE float glm_perlin_vec4(vec4 point) { /* Integer part of p for indexing */ vec4 Pi0; glm_vec4_floor(point, Pi0); /* Pi0 = floor(point); */ /* Integer part + 1 */ vec4 Pi1; glm_vec4_adds(Pi0, 1.0f, Pi1); /* Pi1 = Pi0 + 1.0f; */ glm_vec4_mods(Pi0, 289.0f, Pi0); /* Pi0 = mod(Pi0, 289.0f); */ glm_vec4_mods(Pi1, 289.0f, Pi1); /* Pi1 = mod(Pi1, 289.0f); */ /* Fractional part of p for interpolation */ vec4 Pf0; glm_vec4_fract(point, Pf0); /* Fractional part - 1.0 */ vec4 Pf1; glm_vec4_subs(Pf0, 1.0f, Pf1); vec4 ix = {Pi0[0], Pi1[0], Pi0[0], Pi1[0]}; vec4 iy = {Pi0[1], Pi0[1], Pi1[1], Pi1[1]}; vec4 iz0 = {Pi0[2], Pi0[2], Pi0[2], Pi0[2]}; /* iz0 = vec4(Pi0.z); */ vec4 iz1 = {Pi1[2], Pi1[2], Pi1[2], Pi1[2]}; /* iz1 = vec4(Pi1.z); */ vec4 iw0 = {Pi0[3], Pi0[3], Pi0[3], Pi0[3]}; /* iw0 = vec4(Pi0.w); */ vec4 iw1 = {Pi1[3], Pi1[3], Pi1[3], Pi1[3]}; /* iw1 = vec4(Pi1.w); */ /* ------------ */ /* ixy = permute(permute(ix) + iy) */ vec4 ixy; glm__noiseDetail_permute(ix, ixy); /* ixy = permute(ix) */ glm_vec4_add(ixy, iy, ixy); /* ixy += iy; */ glm__noiseDetail_permute(ixy, ixy); /* ixy = permute(ixy) */ /* ixy0 = permute(ixy + iz0) */ vec4 ixy0; glm_vec4_add(ixy, iz0, ixy0); /* ixy0 = ixy + iz0 */ glm__noiseDetail_permute(ixy0, ixy0); /* ixy0 = permute(ixy0) */ /* ixy1 = permute(ixy + iz1) */ vec4 ixy1; glm_vec4_add(ixy, iz1, ixy1); /* ixy1 = ixy, iz1 */ glm__noiseDetail_permute(ixy1, ixy1); /* ixy1 = permute(ixy1) */ /* ixy00 = permute(ixy0 + iw0) */ vec4 ixy00; glm_vec4_add(ixy0, iw0, ixy00); /* ixy00 = ixy0 + iw0 */ glm__noiseDetail_permute(ixy00, ixy00); /* ixy00 = permute(ixy00) */ /* ixy01 = permute(ixy0 + iw1) */ vec4 ixy01; glm_vec4_add(ixy0, iw1, ixy01); /* ixy01 = ixy0 + iw1 */ glm__noiseDetail_permute(ixy01, ixy01); /* ixy01 = permute(ixy01) */ /* ixy10 = permute(ixy1 + iw0) */ vec4 ixy10; glm_vec4_add(ixy1, iw0, ixy10); /* ixy10 = ixy1 + iw0 */ glm__noiseDetail_permute(ixy10, ixy10); /* ixy10 = permute(ixy10) */ /* ixy11 = permute(ixy1 + iw1) */ vec4 ixy11; glm_vec4_add(ixy1, iw1, ixy11); /* ixy11 = ixy1 + iw1 */ glm__noiseDetail_permute(ixy11, ixy11); /* ixy11 = permute(ixy11) */ /* ------------ */ vec4 gx00, gy00, gz00, gw00; glm__noiseDetail_i2gxyzw(ixy00, gx00, gy00, gz00, gw00); vec4 gx01, gy01, gz01, gw01; glm__noiseDetail_i2gxyzw(ixy01, gx01, gy01, gz01, gw01); vec4 gx10, gy10, gz10, gw10; glm__noiseDetail_i2gxyzw(ixy10, gx10, gy10, gz10, gw10); vec4 gx11, gy11, gz11, gw11; glm__noiseDetail_i2gxyzw(ixy11, gx11, gy11, gz11, gw11); /* ------------ */ vec4 g0000 = {gx00[0], gy00[0], gz00[0], gw00[0]}; /* g0000 = vec4(gx00.x, gy00.x, gz00.x, gw00.x); */ vec4 g0100 = {gx00[2], gy00[2], gz00[2], gw00[2]}; /* g0100 = vec4(gx00.z, gy00.z, gz00.z, gw00.z); */ vec4 g1000 = {gx00[1], gy00[1], gz00[1], gw00[1]}; /* g1000 = vec4(gx00.y, gy00.y, gz00.y, gw00.y); */ vec4 g1100 = {gx00[3], gy00[3], gz00[3], gw00[3]}; /* g1100 = vec4(gx00.w, gy00.w, gz00.w, gw00.w); */ vec4 g0001 = {gx01[0], gy01[0], gz01[0], gw01[0]}; /* g0001 = vec4(gx01.x, gy01.x, gz01.x, gw01.x); */ vec4 g0101 = {gx01[2], gy01[2], gz01[2], gw01[2]}; /* g0101 = vec4(gx01.z, gy01.z, gz01.z, gw01.z); */ vec4 g1001 = {gx01[1], gy01[1], gz01[1], gw01[1]}; /* g1001 = vec4(gx01.y, gy01.y, gz01.y, gw01.y); */ vec4 g1101 = {gx01[3], gy01[3], gz01[3], gw01[3]}; /* g1101 = vec4(gx01.w, gy01.w, gz01.w, gw01.w); */ vec4 g0010 = {gx10[0], gy10[0], gz10[0], gw10[0]}; /* g0010 = vec4(gx10.x, gy10.x, gz10.x, gw10.x); */ vec4 g0110 = {gx10[2], gy10[2], gz10[2], gw10[2]}; /* g0110 = vec4(gx10.z, gy10.z, gz10.z, gw10.z); */ vec4 g1010 = {gx10[1], gy10[1], gz10[1], gw10[1]}; /* g1010 = vec4(gx10.y, gy10.y, gz10.y, gw10.y); */ vec4 g1110 = {gx10[3], gy10[3], gz10[3], gw10[3]}; /* g1110 = vec4(gx10.w, gy10.w, gz10.w, gw10.w); */ vec4 g0011 = {gx11[0], gy11[0], gz11[0], gw11[0]}; /* g0011 = vec4(gx11.x, gy11.x, gz11.x, gw11.x); */ vec4 g0111 = {gx11[2], gy11[2], gz11[2], gw11[2]}; /* g0111 = vec4(gx11.z, gy11.z, gz11.z, gw11.z); */ vec4 g1011 = {gx11[1], gy11[1], gz11[1], gw11[1]}; /* g1011 = vec4(gx11.y, gy11.y, gz11.y, gw11.y); */ vec4 g1111 = {gx11[3], gy11[3], gz11[3], gw11[3]}; /* g1111 = vec4(gx11.w, gy11.w, gz11.w, gw11.w); */ glm__noiseDetail_gradNorm_vec4(g0000, g0100, g1000, g1100); glm__noiseDetail_gradNorm_vec4(g0001, g0101, g1001, g1101); glm__noiseDetail_gradNorm_vec4(g0010, g0110, g1010, g1110); glm__noiseDetail_gradNorm_vec4(g0011, g0111, g1011, g1111); /* ------------ */ float n0000 = glm_vec4_dot(g0000, Pf0); /* n0000 = dot(g0000, Pf0) */ /* n1000 = dot(g1000, vec4(Pf1.x, Pf0.y, Pf0.z, Pf0.w)) */ vec4 n1000d = {Pf1[0], Pf0[1], Pf0[2], Pf0[3]}; float n1000 = glm_vec4_dot(g1000, n1000d); /* n0100 = dot(g0100, vec4(Pf0.x, Pf1.y, Pf0.z, Pf0.w)) */ vec4 n0100d = {Pf0[0], Pf1[1], Pf0[2], Pf0[3]}; float n0100 = glm_vec4_dot(g0100, n0100d); /* n1100 = dot(g1100, vec4(Pf1.x, Pf1.y, Pf0.z, Pf0.w)) */ vec4 n1100d = {Pf1[0], Pf1[1], Pf0[2], Pf0[3]}; float n1100 = glm_vec4_dot(g1100, n1100d); /* n0010 = dot(g0010, vec4(Pf0.x, Pf0.y, Pf1.z, Pf0.w)) */ vec4 n0010d = {Pf0[0], Pf0[1], Pf1[2], Pf0[3]}; float n0010 = glm_vec4_dot(g0010, n0010d); /* n1010 = dot(g1010, vec4(Pf1.x, Pf0.y, Pf1.z, Pf0.w)) */ vec4 n1010d = {Pf1[0], Pf0[1], Pf1[2], Pf0[3]}; float n1010 = glm_vec4_dot(g1010, n1010d); /* n0110 = dot(g0110, vec4(Pf0.x, Pf1.y, Pf1.z, Pf0.w)) */ vec4 n0110d = {Pf0[0], Pf1[1], Pf1[2], Pf0[3]}; float n0110 = glm_vec4_dot(g0110, n0110d); /* n1110 = dot(g1110, vec4(Pf1.x, Pf1.y, Pf1.z, Pf0.w)) */ vec4 n1110d = {Pf1[0], Pf1[1], Pf1[2], Pf0[3]}; float n1110 = glm_vec4_dot(g1110, n1110d); /* n0001 = dot(g0001, vec4(Pf0.x, Pf0.y, Pf0.z, Pf1.w)) */ vec4 n0001d = {Pf0[0], Pf0[1], Pf0[2], Pf1[3]}; float n0001 = glm_vec4_dot(g0001, n0001d); /* n1001 = dot(g1001, vec4(Pf1.x, Pf0.y, Pf0.z, Pf1.w)) */ vec4 n1001d = {Pf1[0], Pf0[1], Pf0[2], Pf1[3]}; float n1001 = glm_vec4_dot(g1001, n1001d); /* n0101 = dot(g0101, vec4(Pf0.x, Pf1.y, Pf0.z, Pf1.w)) */ vec4 n0101d = {Pf0[0], Pf1[1], Pf0[2], Pf1[3]}; float n0101 = glm_vec4_dot(g0101, n0101d); /* n1101 = dot(g1101, vec4(Pf1.x, Pf1.y, Pf0.z, Pf1.w)) */ vec4 n1101d = {Pf1[0], Pf1[1], Pf0[2], Pf1[3]}; float n1101 = glm_vec4_dot(g1101, n1101d); /* n0011 = dot(g0011, vec4(Pf0.x, Pf0.y, Pf1.z, Pf1.w)) */ vec4 n0011d = {Pf0[0], Pf0[1], Pf1[2], Pf1[3]}; float n0011 = glm_vec4_dot(g0011, n0011d); /* n1011 = dot(g1011, vec4(Pf1.x, Pf0.y, Pf1.z, Pf1.w)) */ vec4 n1011d = {Pf1[0], Pf0[1], Pf1[2], Pf1[3]}; float n1011 = glm_vec4_dot(g1011, n1011d); /* n0111 = dot(g0111, vec4(Pf0.x, Pf1.y, Pf1.z, Pf1.w)) */ vec4 n0111d = {Pf0[0], Pf1[1], Pf1[2], Pf1[3]}; float n0111 = glm_vec4_dot(g0111, n0111d); float n1111 = glm_vec4_dot(g1111, Pf1); /* n1111 = dot(g1111, Pf1) */ /* ------------ */ vec4 fade_xyzw; glm__noiseDetail_fade_vec4(Pf0, fade_xyzw); /* fade_xyzw = fade(Pf0) */ /* n_0w = lerp(vec4(n0000, n1000, n0100, n1100), vec4(n0001, n1001, n0101, n1101), fade_xyzw.w) */ vec4 n_0w1 = {n0000, n1000, n0100, n1100}; vec4 n_0w2 = {n0001, n1001, n0101, n1101}; vec4 n_0w; glm_vec4_lerp(n_0w1, n_0w2, fade_xyzw[3], n_0w); /* n_1w = lerp(vec4(n0010, n1010, n0110, n1110), vec4(n0011, n1011, n0111, n1111), fade_xyzw.w) */ vec4 n_1w1 = {n0010, n1010, n0110, n1110}; vec4 n_1w2 = {n0011, n1011, n0111, n1111}; vec4 n_1w; glm_vec4_lerp(n_1w1, n_1w2, fade_xyzw[3], n_1w); /* n_zw = lerp(n_0w, n_1w, fade_xyzw.z) */ vec4 n_zw; glm_vec4_lerp(n_0w, n_1w, fade_xyzw[2], n_zw); /* n_yzw = lerp(vec2(n_zw.x, n_zw.y), vec2(n_zw.z, n_zw.w), fade_xyzw.y) */ vec2 n_yzw; vec2 n_yzw1 = {n_zw[0], n_zw[1]}; vec2 n_yzw2 = {n_zw[2], n_zw[3]}; glm_vec2_lerp(n_yzw1, n_yzw2, fade_xyzw[1], n_yzw); /* n_xyzw = lerp(n_yzw.x, n_yzw.y, fade_xyzw.x) */ float n_xyzw = glm_lerp(n_yzw[0], n_yzw[1], fade_xyzw[0]); return n_xyzw * 2.2f; } /*! * @brief Classic perlin noise * * @param[in] point 3D vector * @returns perlin noise value */ CGLM_INLINE float glm_perlin_vec3(vec3 point) { /* Integer part of p for indexing */ vec3 Pi0; glm_vec3_floor(point, Pi0); /* Pi0 = floor(point); */ /* Integer part + 1 */ vec3 Pi1; glm_vec3_adds(Pi0, 1.0f, Pi1); /* Pi1 = Pi0 + 1.0f; */ glm_vec3_mods(Pi0, 289.0f, Pi0); /* Pi0 = mod(Pi0, 289.0f); */ glm_vec3_mods(Pi1, 289.0f, Pi1); /* Pi1 = mod(Pi1, 289.0f); */ /* Fractional part of p for interpolation */ vec3 Pf0; glm_vec3_fract(point, Pf0); /* Fractional part - 1.0 */ vec3 Pf1; glm_vec3_subs(Pf0, 1.0f, Pf1); vec4 ix = {Pi0[0], Pi1[0], Pi0[0], Pi1[0]}; vec4 iy = {Pi0[1], Pi0[1], Pi1[1], Pi1[1]}; vec4 iz0 = {Pi0[2], Pi0[2], Pi0[2], Pi0[2]}; /* iz0 = vec4(Pi0.z); */ vec4 iz1 = {Pi1[2], Pi1[2], Pi1[2], Pi1[2]}; /* iz1 = vec4(Pi1.z); */ /* ------------ */ /* ixy = permute(permute(ix) + iy) */ vec4 ixy; glm__noiseDetail_permute(ix, ixy); /* ixy = permute(ix) */ glm_vec4_add(ixy, iy, ixy); /* ixy += iy; */ glm__noiseDetail_permute(ixy, ixy); /* ixy = permute(ixy) */ /* ixy0 = permute(ixy + iz0) */ vec4 ixy0; glm_vec4_add(ixy, iz0, ixy0); /* ixy0 = ixy + iz0 */ glm__noiseDetail_permute(ixy0, ixy0); /* ixy0 = permute(ixy0) */ /* ixy1 = permute(ixy + iz1) */ vec4 ixy1; glm_vec4_add(ixy, iz1, ixy1); /* ixy1 = ixy, iz1 */ glm__noiseDetail_permute(ixy1, ixy1); /* ixy1 = permute(ixy1) */ /* ------------ */ vec4 gx0, gy0, gz0; glm__noiseDetail_i2gxyz(ixy0, gx0, gy0, gz0); vec4 gx1, gy1, gz1; glm__noiseDetail_i2gxyz(ixy1, gx1, gy1, gz1); /* ------------ */ vec3 g000 = {gx0[0], gy0[0], gz0[0]}; /* g000 = vec3(gx0.x, gy0.x, gz0.x); */ vec3 g100 = {gx0[1], gy0[1], gz0[1]}; /* g100 = vec3(gx0.y, gy0.y, gz0.y); */ vec3 g010 = {gx0[2], gy0[2], gz0[2]}; /* g010 = vec3(gx0.z, gy0.z, gz0.z); */ vec3 g110 = {gx0[3], gy0[3], gz0[3]}; /* g110 = vec3(gx0.w, gy0.w, gz0.w); */ vec3 g001 = {gx1[0], gy1[0], gz1[0]}; /* g001 = vec3(gx1.x, gy1.x, gz1.x); */ vec3 g101 = {gx1[1], gy1[1], gz1[1]}; /* g101 = vec3(gx1.y, gy1.y, gz1.y); */ vec3 g011 = {gx1[2], gy1[2], gz1[2]}; /* g011 = vec3(gx1.z, gy1.z, gz1.z); */ vec3 g111 = {gx1[3], gy1[3], gz1[3]}; /* g111 = vec3(gx1.w, gy1.w, gz1.w); */ glm__noiseDetail_gradNorm_vec3(g000, g010, g100, g110); glm__noiseDetail_gradNorm_vec3(g001, g011, g101, g111); /* ------------ */ float n000 = glm_vec3_dot(g000, Pf0); /* n000 = dot(g000, Pf0) */ /* n100 = dot(g100, vec3(Pf1.x, Pf0.y, Pf0.z)) */ vec3 n100d = {Pf1[0], Pf0[1], Pf0[2]}; float n100 = glm_vec3_dot(g100, n100d); /* n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z)) */ vec3 n010d = {Pf0[0], Pf1[1], Pf0[2]}; float n010 = glm_vec3_dot(g010, n010d); /* n110 = dot(g110, vec3(Pf1.x, Pf1.y, Pf0.z)) */ vec3 n110d = {Pf1[0], Pf1[1], Pf0[2]}; float n110 = glm_vec3_dot(g110, n110d); /* n001 = dot(g001, vec3(Pf0.x, Pf0.y, Pf1.z)) */ vec3 n001d = {Pf0[0], Pf0[1], Pf1[2]}; float n001 = glm_vec3_dot(g001, n001d); /* n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z)) */ vec3 n101d = {Pf1[0], Pf0[1], Pf1[2]}; float n101 = glm_vec3_dot(g101, n101d); /* n011 = dot(g011, vec3(Pf0.x, Pf1.y, Pf1.z)) */ vec3 n011d = {Pf0[0], Pf1[1], Pf1[2]}; float n011 = glm_vec3_dot(g011, n011d); float n111 = glm_vec3_dot(g111, Pf1); /* n111 = dot(g111, Pf1) */ /* ------------ */ vec3 fade_xyz; glm__noiseDetail_fade_vec3(Pf0, fade_xyz); /* fade_xyz = fade(Pf0) */ /* n_z = lerp(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z); */ vec4 n_z; vec4 n_z1 = {n000, n100, n010, n110}; vec4 n_z2 = {n001, n101, n011, n111}; glm_vec4_lerp(n_z1, n_z2, fade_xyz[2], n_z); /* vec2 n_yz = lerp(vec2(n_z.x, n_z.y), vec2(n_z.z, n_z.w), fade_xyz.y); */ vec2 n_yz; vec2 n_yz1 = {n_z[0], n_z[1]}; vec2 n_yz2 = {n_z[2], n_z[3]}; glm_vec2_lerp(n_yz1, n_yz2, fade_xyz[1], n_yz); /* n_xyz = lerp(n_yz.x, n_yz.y, fade_xyz.x); */ float n_xyz = glm_lerp(n_yz[0], n_yz[1], fade_xyz[0]); return n_xyz * 2.2f; } /*! * @brief Classic perlin noise * * @param[in] point 2D vector * @returns perlin noise value */ CGLM_INLINE float glm_perlin_vec2(vec2 point) { /* Integer part of p for indexing */ /* Pi = floor(vec4(point.x, point.y, point.x, point.y)) + vec4(0.0, 0.0, 1.0, 1.0); */ vec4 Pi = {point[0], point[1], point[0], point[1]}; /* Pi = vec4(point.x, point.y, point.x, point.y) */ glm_vec4_floor(Pi, Pi); /* Pi = floor(Pi) */ Pi[2] += 1.0f; /* Pi.z += 1.0 */ Pi[3] += 1.0f; /* Pi.w += 1.0 */ /* Fractional part of p for interpolation */ /* vec<4, T, Q> Pf = glm::fract(vec<4, T, Q>(Position.x, Position.y, Position.x, Position.y)) - vec<4, T, Q>(0.0, 0.0, 1.0, 1.0); */ vec4 Pf = {point[0], point[1], point[0], point[1]}; /* Pf = vec4(point.x, point.y, point.x, point.y) */ glm_vec4_fract(Pf, Pf); /* Pf = fract(Pf) */ Pf[2] -= 1.0f; /* Pf.z -= 1.0 */ Pf[3] -= 1.0f; /* Pf.w -= 1.0 */ /* Mod to avoid truncation effects in permutation */ glm_vec4_mods(Pi, 289.0f, Pi); /* Pi = mod(Pi, 289.0f); */ vec4 ix = {Pi[0], Pi[2], Pi[0], Pi[2]}; /* ix = vec4(Pi.x, Pi.z, Pi.x, Pi.z) */ vec4 iy = {Pi[1], Pi[1], Pi[3], Pi[3]}; /* iy = vec4(Pi.y, Pi.y, Pi.w, Pi.w) */ vec4 fx = {Pf[0], Pf[2], Pf[0], Pf[2]}; /* fx = vec4(Pf.x, Pf.z, Pf.x, Pf.z) */ vec4 fy = {Pf[1], Pf[1], Pf[3], Pf[3]}; /* fy = vec4(Pf.y, Pf.y, Pf.w, Pf.w) */ /* ------------ */ /* i = permute(permute(ix) + iy); */ vec4 i; glm__noiseDetail_permute(ix, i); /* i = permute(ix) */ glm_vec4_add(i, iy, i); /* i += iy; */ glm__noiseDetail_permute(i, i); /* i = permute(i) */ /* ------------ */ vec4 gx, gy; glm__noiseDetail_i2gxy(i, gx, gy); /* ------------ */ vec2 g00 = {gx[0], gy[0]}; /* g00 = vec2(gx.x, gy.x) */ vec2 g10 = {gx[1], gy[1]}; /* g10 = vec2(gx.y, gy.y) */ vec2 g01 = {gx[2], gy[2]}; /* g01 = vec2(gx.z, gy.z) */ vec2 g11 = {gx[3], gy[3]}; /* g11 = vec2(gx.w, gy.w) */ glm__noiseDetail_gradNorm_vec2(g00, g01, g10, g11); /* ------------ */ /* n00 = dot(g00, vec2(fx.x, fy.x)) */ vec2 n00d = {fx[0], fy[0]}; /* n00d = vec2(fx.x, fy.x) */ float n00 = glm_vec2_dot(g00, n00d); /* n00 = dot(g00, n00d) */ /* n10 = dot(g10, vec2(fx.y, fy.y)) */ vec2 n10d = {fx[1], fy[1]}; /* n10d = vec2(fx.y, fy.y) */ float n10 = glm_vec2_dot(g10, n10d); /* n10 = dot(g10, n10d) */ /* n01 = dot(g01, vec2(fx.z, fy.z)) */ vec2 n01d = {fx[2], fy[2]}; /* n01d = vec2(fx.z, fy.z) */ float n01 = glm_vec2_dot(g01, n01d); /* n01 = dot(g01, n01d) */ /* n11 = dot(g11, vec2(fx.w, fy.w)) */ vec2 n11d = {fx[3], fy[3]}; /* n11d = vec2(fx.w, fy.w) */ float n11 = glm_vec2_dot(g11, n11d); /* n11 = dot(g11, n11d) */ /* ------------ */ /* fade_xyz = fade(vec2(Pf.x, Pf.y)) */ vec2 fade_xy; vec2 temp2 = {Pf[0], Pf[1]}; /* temp = vec2(Pf.x, Pf.y) */ glm__noiseDetail_fade_vec2(temp2, fade_xy); /* fade_xy = fade(temp) */ /* n_x = lerp(vec2(n00, n01), vec2(n10, n11), fade_xy.x); */ vec2 n_x; vec2 n_x1 = {n00, n01}; /* n_x1 = vec2(n00, n01) */ vec2 n_x2 = {n10, n11}; /* n_x2 = vec2(n10, n11) */ glm_vec2_lerp(n_x1, n_x2, fade_xy[0], n_x); /* n_x = lerp(n_x1, n_x2, fade_xy.x) */ /* T n_xy = mix(n_x.x, n_x.y, fade_xy.y); */ /* n_xy = lerp(n_x.x, n_x.y, fade_xy.y); */ float n_xy = glm_lerp(n_x[0], n_x[1], fade_xy[1]); return n_xy * 2.3f; } /* Undefine all helper macros */ #undef glm__noiseDetail_mod289 #undef glm__noiseDetail_permute #undef glm__noiseDetail_fade_vec4 #undef glm__noiseDetail_fade_vec3 #undef glm__noiseDetail_fade_vec2 #undef glm__noiseDetail_taylorInvSqrt #undef glm__noiseDetail_gradNorm_vec4 #undef glm__noiseDetail_gradNorm_vec3 #undef glm__noiseDetail_gradNorm_vec2 #undef glm__noiseDetail_i2gxyzw #undef glm__noiseDetail_i2gxyz #undef glm__noiseDetail_i2gxy #endif /* cglm_noise_h */ cglm-0.9.7/include/cglm/plane.h000066400000000000000000000014221526744317200163000ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_plane_h #define cglm_plane_h #include "common.h" #include "vec3.h" #include "vec4.h" /* Plane equation: Ax + By + Cz + D = 0; It stored in vec4 as [A, B, C, D]. (A, B, C) is normal and D is distance */ /* Functions: CGLM_INLINE void glm_plane_normalize(vec4 plane); */ /*! * @brief normalizes a plane * * @param[in, out] plane plane to normalize */ CGLM_INLINE void glm_plane_normalize(vec4 plane) { float norm; if (CGLM_UNLIKELY((norm = glm_vec3_norm(plane)) < FLT_EPSILON)) { glm_vec4_zero(plane); return; } glm_vec4_scale(plane, 1.0f / norm, plane); } #endif /* cglm_plane_h */ cglm-0.9.7/include/cglm/project.h000066400000000000000000000111761526744317200166560ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_project_h #define cglm_project_h #include "common.h" #include "vec3.h" #include "vec4.h" #include "mat4.h" #ifndef CGLM_CLIPSPACE_INCLUDE_ALL # if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_ZO_BIT # include "clipspace/project_zo.h" # elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_NO_BIT # include "clipspace/project_no.h" # endif #else # include "clipspace/project_zo.h" # include "clipspace/project_no.h" #endif /*! * @brief maps the specified viewport coordinates into specified space [1] * the matrix should contain projection matrix. * * if you don't have ( and don't want to have ) an inverse matrix then use * glm_unproject version. You may use existing inverse of matrix in somewhere * else, this is why glm_unprojecti exists to save save inversion cost * * [1] space: * 1- if m = invProj: View Space * 2- if m = invViewProj: World Space * 3- if m = invMVP: Object Space * * You probably want to map the coordinates into object space * so use invMVP as m * * Computing viewProj: * glm_mat4_mul(proj, view, viewProj); * glm_mat4_mul(viewProj, model, MVP); * glm_mat4_inv(viewProj, invMVP); * * @param[in] pos point/position in viewport coordinates * @param[in] invMat matrix (see brief) * @param[in] vp viewport as [x, y, width, height] * @param[out] dest unprojected coordinates */ CGLM_INLINE void glm_unprojecti(vec3 pos, mat4 invMat, vec4 vp, vec3 dest) { #if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_ZO_BIT glm_unprojecti_zo(pos, invMat, vp, dest); #elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_NO_BIT glm_unprojecti_no(pos, invMat, vp, dest); #endif } /*! * @brief maps the specified viewport coordinates into specified space [1] * the matrix should contain projection matrix. * * this is same as glm_unprojecti except this function get inverse matrix for * you. * * [1] space: * 1- if m = proj: View Space * 2- if m = viewProj: World Space * 3- if m = MVP: Object Space * * You probably want to map the coordinates into object space * so use MVP as m * * Computing viewProj and MVP: * glm_mat4_mul(proj, view, viewProj); * glm_mat4_mul(viewProj, model, MVP); * * @param[in] pos point/position in viewport coordinates * @param[in] m matrix (see brief) * @param[in] vp viewport as [x, y, width, height] * @param[out] dest unprojected coordinates */ CGLM_INLINE void glm_unproject(vec3 pos, mat4 m, vec4 vp, vec3 dest) { mat4 inv; glm_mat4_inv(m, inv); glm_unprojecti(pos, inv, vp, dest); } /*! * @brief map object coordinates to window coordinates * * Computing MVP: * glm_mat4_mul(proj, view, viewProj); * glm_mat4_mul(viewProj, model, MVP); * * @param[in] pos object coordinates * @param[in] m MVP matrix * @param[in] vp viewport as [x, y, width, height] * @param[out] dest projected coordinates */ CGLM_INLINE void glm_project(vec3 pos, mat4 m, vec4 vp, vec3 dest) { #if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_ZO_BIT glm_project_zo(pos, m, vp, dest); #elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_NO_BIT glm_project_no(pos, m, vp, dest); #endif } /*! * @brief map object's z coordinate to window coordinates * * Computing MVP: * glm_mat4_mul(proj, view, viewProj); * glm_mat4_mul(viewProj, model, MVP); * * @param[in] v object coordinates * @param[in] m MVP matrix * * @returns projected z coordinate */ CGLM_INLINE float glm_project_z(vec3 v, mat4 m) { #if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_ZO_BIT return glm_project_z_zo(v, m); #elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_NO_BIT return glm_project_z_no(v, m); #endif } /*! * @brief define a picking region * * @param[in] center center [x, y] of a picking region in window coordinates * @param[in] size size [width, height] of the picking region in window coordinates * @param[in] vp viewport as [x, y, width, height] * @param[out] dest projected coordinates */ CGLM_INLINE void glm_pickmatrix(vec2 center, vec2 size, vec4 vp, mat4 dest) { mat4 res; vec3 v; if (size[0] <= 0.0f || size[1] <= 0.0f) return; /* Translate and scale the picked region to the entire window */ v[0] = (vp[2] - 2.0f * (center[0] - vp[0])) / size[0]; v[1] = (vp[3] - 2.0f * (center[1] - vp[1])) / size[1]; v[2] = 0.0f; glm_translate_make(res, v); v[0] = vp[2] / size[0]; v[1] = vp[3] / size[1]; v[2] = 1.0f; glm_scale(res, v); glm_mat4_copy(res, dest); } #endif /* cglm_project_h */ cglm-0.9.7/include/cglm/quat.h000066400000000000000000000527201526744317200161620ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLM_QUAT_IDENTITY_INIT GLM_QUAT_IDENTITY Functions: CGLM_INLINE void glm_quat_identity(versor q); CGLM_INLINE void glm_quat_init(versor q, float x, float y, float z, float w); CGLM_INLINE void glm_quat(versor q, float angle, float x, float y, float z); CGLM_INLINE void glm_quatv(versor q, float angle, vec3 axis); CGLM_INLINE void glm_quat_copy(versor q, versor dest); CGLM_INLINE void glm_quat_from_vecs(vec3 a, vec3 b, versor dest); CGLM_INLINE float glm_quat_norm(versor q); CGLM_INLINE void glm_quat_normalize(versor q); CGLM_INLINE void glm_quat_normalize_to(versor q, versor dest); CGLM_INLINE float glm_quat_dot(versor p, versor q); CGLM_INLINE void glm_quat_conjugate(versor q, versor dest); CGLM_INLINE void glm_quat_inv(versor q, versor dest); CGLM_INLINE void glm_quat_add(versor p, versor q, versor dest); CGLM_INLINE void glm_quat_sub(versor p, versor q, versor dest); CGLM_INLINE float glm_quat_real(versor q); CGLM_INLINE void glm_quat_imag(versor q, vec3 dest); CGLM_INLINE void glm_quat_imagn(versor q, vec3 dest); CGLM_INLINE float glm_quat_imaglen(versor q); CGLM_INLINE float glm_quat_angle(versor q); CGLM_INLINE void glm_quat_axis(versor q, vec3 dest); CGLM_INLINE void glm_quat_mul(versor p, versor q, versor dest); CGLM_INLINE void glm_quat_mat4(versor q, mat4 dest); CGLM_INLINE void glm_quat_mat4t(versor q, mat4 dest); CGLM_INLINE void glm_quat_mat3(versor q, mat3 dest); CGLM_INLINE void glm_quat_mat3t(versor q, mat3 dest); CGLM_INLINE void glm_quat_lerp(versor from, versor to, float t, versor dest); CGLM_INLINE void glm_quat_lerpc(versor from, versor to, float t, versor dest); CGLM_INLINE void glm_quat_slerp(versor q, versor r, float t, versor dest); CGLM_INLINE void glm_quat_slerp_longest(versor q, versor r, float t, versor dest); CGLM_INLINE void glm_quat_nlerp(versor q, versor r, float t, versor dest); CGLM_INLINE void glm_quat_look(vec3 eye, versor ori, mat4 dest); CGLM_INLINE void glm_quat_for(vec3 dir, vec3 fwd, vec3 up, versor dest); CGLM_INLINE void glm_quat_forp(vec3 from, vec3 to, vec3 fwd, vec3 up, versor dest); CGLM_INLINE void glm_quat_rotatev(versor q, vec3 v, vec3 dest); CGLM_INLINE void glm_quat_rotate(mat4 m, versor q, mat4 dest); CGLM_INLINE void glm_quat_make(float * restrict src, versor dest); */ #ifndef cglm_quat_h #define cglm_quat_h #include "common.h" #include "vec3.h" #include "vec4.h" #include "mat4.h" #include "mat3.h" #include "affine-mat.h" #include "affine.h" #ifdef CGLM_SSE_FP # include "simd/sse2/quat.h" #endif #ifdef CGLM_NEON_FP # include "simd/neon/quat.h" #endif #ifdef CGLM_SIMD_WASM # include "simd/wasm/quat.h" #endif CGLM_INLINE void glm_quat_normalize(versor q); /* * IMPORTANT: * ---------------------------------------------------------------------------- * cglm stores quat as [x, y, z, w] since v0.3.6 * * it was [w, x, y, z] before v0.3.6 it has been changed to [x, y, z, w] * with v0.3.6 version. * ---------------------------------------------------------------------------- */ #define GLM_QUAT_IDENTITY_INIT {0.0f, 0.0f, 0.0f, 1.0f} #define GLM_QUAT_IDENTITY ((versor)GLM_QUAT_IDENTITY_INIT) /*! * @brief makes given quat to identity * * @param[in, out] q quaternion */ CGLM_INLINE void glm_quat_identity(versor q) { CGLM_ALIGN(16) versor v = GLM_QUAT_IDENTITY_INIT; glm_vec4_copy(v, q); } /*! * @brief make given quaternion array's each element identity quaternion * * @param[in, out] q quat array (must be aligned (16) * if alignment is not disabled) * * @param[in] count count of quaternions */ CGLM_INLINE void glm_quat_identity_array(versor * __restrict q, size_t count) { CGLM_ALIGN(16) versor v = GLM_QUAT_IDENTITY_INIT; size_t i; for (i = 0; i < count; i++) { glm_vec4_copy(v, q[i]); } } /*! * @brief inits quaternion with raw values * * @param[out] q quaternion * @param[in] x x * @param[in] y y * @param[in] z z * @param[in] w w (real part) */ CGLM_INLINE void glm_quat_init(versor q, float x, float y, float z, float w) { q[0] = x; q[1] = y; q[2] = z; q[3] = w; } /*! * @brief creates NEW quaternion with axis vector * * @param[out] q quaternion * @param[in] angle angle (radians) * @param[in] axis axis */ CGLM_INLINE void glm_quatv(versor q, float angle, vec3 axis) { CGLM_ALIGN(8) vec3 k; float a, c, s; a = angle * 0.5f; c = cosf(a); s = sinf(a); glm_normalize_to(axis, k); q[0] = s * k[0]; q[1] = s * k[1]; q[2] = s * k[2]; q[3] = c; } /*! * @brief creates NEW quaternion with individual axis components * * @param[out] q quaternion * @param[in] angle angle (radians) * @param[in] x axis.x * @param[in] y axis.y * @param[in] z axis.z */ CGLM_INLINE void glm_quat(versor q, float angle, float x, float y, float z) { CGLM_ALIGN(8) vec3 axis = {x, y, z}; glm_quatv(q, angle, axis); } /*! * @brief copy quaternion to another one * * @param[in] q quaternion * @param[out] dest destination */ CGLM_INLINE void glm_quat_copy(versor q, versor dest) { glm_vec4_copy(q, dest); } /*! * @brief compute quaternion rotating vector A to vector B * * @param[in] a vec3 (must have unit length) * @param[in] b vec3 (must have unit length) * @param[out] dest quaternion (of unit length) */ CGLM_INLINE void glm_quat_from_vecs(vec3 a, vec3 b, versor dest) { CGLM_ALIGN(8) vec3 axis; float cos_theta; float cos_half_theta; cos_theta = glm_vec3_dot(a, b); if (cos_theta >= 1.f - GLM_FLT_EPSILON) { /* a ∥ b */ glm_quat_identity(dest); return; } if (cos_theta < -1.f + GLM_FLT_EPSILON) { /* angle(a, b) = π */ glm_vec3_ortho(a, axis); cos_half_theta = 0.f; /* cos π/2 */ } else { glm_vec3_cross(a, b, axis); cos_half_theta = 1.0f + cos_theta; /* cos 0 + cos θ */ } glm_quat_init(dest, axis[0], axis[1], axis[2], cos_half_theta); glm_quat_normalize(dest); } /*! * @brief returns norm (magnitude) of quaternion * * @param[in] q quaternion */ CGLM_INLINE float glm_quat_norm(versor q) { return glm_vec4_norm(q); } /*! * @brief normalize quaternion and store result in dest * * @param[in] q quaternion to normalze * @param[out] dest destination quaternion */ CGLM_INLINE void glm_quat_normalize_to(versor q, versor dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_128 xdot, x0; float dot; x0 = glmm_load(q); xdot = glmm_vdot(x0, x0); /* dot = _mm_cvtss_f32(xdot); */ dot = wasm_f32x4_extract_lane(xdot, 0); if (dot <= 0.0f) { glm_quat_identity(dest); return; } glmm_store(dest, wasm_f32x4_div(x0, wasm_f32x4_sqrt(xdot))); #elif defined( __SSE__ ) || defined( __SSE2__ ) __m128 xdot, x0; float dot; x0 = glmm_load(q); xdot = glmm_vdot(x0, x0); dot = _mm_cvtss_f32(xdot); if (dot <= 0.0f) { glm_quat_identity(dest); return; } glmm_store(dest, _mm_div_ps(x0, _mm_sqrt_ps(xdot))); #else float dot; dot = glm_vec4_norm2(q); if (dot <= 0.0f) { glm_quat_identity(dest); return; } glm_vec4_scale(q, 1.0f / sqrtf(dot), dest); #endif } /*! * @brief normalize quaternion * * @param[in, out] q quaternion */ CGLM_INLINE void glm_quat_normalize(versor q) { glm_quat_normalize_to(q, q); } /*! * @brief dot product of two quaternion * * @param[in] p quaternion 1 * @param[in] q quaternion 2 */ CGLM_INLINE float glm_quat_dot(versor p, versor q) { return glm_vec4_dot(p, q); } /*! * @brief conjugate of quaternion * * @param[in] q quaternion * @param[out] dest conjugate */ CGLM_INLINE void glm_quat_conjugate(versor q, versor dest) { glm_vec4_negate_to(q, dest); dest[3] = -dest[3]; } /*! * @brief inverse of non-zero quaternion * * @param[in] q quaternion * @param[out] dest inverse quaternion */ CGLM_INLINE void glm_quat_inv(versor q, versor dest) { CGLM_ALIGN(16) versor conj; glm_quat_conjugate(q, conj); glm_vec4_scale(conj, 1.0f / glm_vec4_norm2(q), dest); } /*! * @brief add (componentwise) two quaternions and store result in dest * * @param[in] p quaternion 1 * @param[in] q quaternion 2 * @param[out] dest result quaternion */ CGLM_INLINE void glm_quat_add(versor p, versor q, versor dest) { glm_vec4_add(p, q, dest); } /*! * @brief subtract (componentwise) two quaternions and store result in dest * * @param[in] p quaternion 1 * @param[in] q quaternion 2 * @param[out] dest result quaternion */ CGLM_INLINE void glm_quat_sub(versor p, versor q, versor dest) { glm_vec4_sub(p, q, dest); } /*! * @brief returns real part of quaternion * * @param[in] q quaternion */ CGLM_INLINE float glm_quat_real(versor q) { return q[3]; } /*! * @brief returns imaginary part of quaternion * * @param[in] q quaternion * @param[out] dest imag */ CGLM_INLINE void glm_quat_imag(versor q, vec3 dest) { dest[0] = q[0]; dest[1] = q[1]; dest[2] = q[2]; } /*! * @brief returns normalized imaginary part of quaternion * * @param[in] q quaternion */ CGLM_INLINE void glm_quat_imagn(versor q, vec3 dest) { glm_normalize_to(q, dest); } /*! * @brief returns length of imaginary part of quaternion * * @param[in] q quaternion */ CGLM_INLINE float glm_quat_imaglen(versor q) { return glm_vec3_norm(q); } /*! * @brief returns angle of quaternion * * @param[in] q quaternion */ CGLM_INLINE float glm_quat_angle(versor q) { /* sin(theta / 2) = length(x*x + y*y + z*z) cos(theta / 2) = w theta = 2 * atan(sin(theta / 2) / cos(theta / 2)) */ return 2.0f * atan2f(glm_quat_imaglen(q), glm_quat_real(q)); } /*! * @brief axis of quaternion * * @param[in] q quaternion * @param[out] dest axis of quaternion */ CGLM_INLINE void glm_quat_axis(versor q, vec3 dest) { glm_quat_imagn(q, dest); } /*! * @brief multiplies two quaternion and stores result in dest * this is also called Hamilton Product * * According to WikiPedia: * The product of two rotation quaternions [clarification needed] will be * equivalent to the rotation q followed by the rotation p * * @param[in] p quaternion 1 * @param[in] q quaternion 2 * @param[out] dest result quaternion */ CGLM_INLINE void glm_quat_mul(versor p, versor q, versor dest) { /* + (a1 b2 + b1 a2 + c1 d2 − d1 c2)i + (a1 c2 − b1 d2 + c1 a2 + d1 b2)j + (a1 d2 + b1 c2 − c1 b2 + d1 a2)k a1 a2 − b1 b2 − c1 c2 − d1 d2 */ #if defined(__wasm__) && defined(__wasm_simd128__) glm_quat_mul_wasm(p, q, dest); #elif defined( __SSE__ ) || defined( __SSE2__ ) glm_quat_mul_sse2(p, q, dest); #elif defined(CGLM_NEON_FP) glm_quat_mul_neon(p, q, dest); #else dest[0] = p[3] * q[0] + p[0] * q[3] + p[1] * q[2] - p[2] * q[1]; dest[1] = p[3] * q[1] - p[0] * q[2] + p[1] * q[3] + p[2] * q[0]; dest[2] = p[3] * q[2] + p[0] * q[1] - p[1] * q[0] + p[2] * q[3]; dest[3] = p[3] * q[3] - p[0] * q[0] - p[1] * q[1] - p[2] * q[2]; #endif } /*! * @brief convert quaternion to mat4 * * @param[in] q quaternion * @param[out] dest result matrix */ CGLM_INLINE void glm_quat_mat4(versor q, mat4 dest) { CGLM_ALIGN(16) versor p; float w, x, y, z, xx, yy, zz, xy, yz, xz, wx, wy, wz; glm_quat_normalize_to(q, p); x = p[0]; y = p[1]; z = p[2]; w = p[3]; xx = 2.0f * x * x; xy = 2.0f * x * y; wx = 2.0f * w * x; yy = 2.0f * y * y; yz = 2.0f * y * z; wy = 2.0f * w * y; zz = 2.0f * z * z; xz = 2.0f * x * z; wz = 2.0f * w * z; dest[0][0] = 1.0f - yy - zz; dest[1][1] = 1.0f - xx - zz; dest[2][2] = 1.0f - xx - yy; dest[0][1] = xy + wz; dest[1][2] = yz + wx; dest[2][0] = xz + wy; dest[1][0] = xy - wz; dest[2][1] = yz - wx; dest[0][2] = xz - wy; dest[0][3] = 0.0f; dest[1][3] = 0.0f; dest[2][3] = 0.0f; dest[3][0] = 0.0f; dest[3][1] = 0.0f; dest[3][2] = 0.0f; dest[3][3] = 1.0f; } /*! * @brief convert quaternion to mat4 (transposed) * * @param[in] q quaternion * @param[out] dest result matrix as transposed */ CGLM_INLINE void glm_quat_mat4t(versor q, mat4 dest) { CGLM_ALIGN(16) versor p; float w, x, y, z, xx, yy, zz, xy, yz, xz, wx, wy, wz; glm_quat_normalize_to(q, p); x = p[0]; y = p[1]; z = p[2]; w = p[3]; xx = 2.0f * x * x; xy = 2.0f * x * y; wx = 2.0f * w * x; yy = 2.0f * y * y; yz = 2.0f * y * z; wy = 2.0f * w * y; zz = 2.0f * z * z; xz = 2.0f * x * z; wz = 2.0f * w * z; dest[0][0] = 1.0f - yy - zz; dest[1][1] = 1.0f - xx - zz; dest[2][2] = 1.0f - xx - yy; dest[1][0] = xy + wz; dest[2][1] = yz + wx; dest[0][2] = xz + wy; dest[0][1] = xy - wz; dest[1][2] = yz - wx; dest[2][0] = xz - wy; dest[0][3] = 0.0f; dest[1][3] = 0.0f; dest[2][3] = 0.0f; dest[3][0] = 0.0f; dest[3][1] = 0.0f; dest[3][2] = 0.0f; dest[3][3] = 1.0f; } /*! * @brief convert quaternion to mat3 * * @param[in] q quaternion * @param[out] dest result matrix */ CGLM_INLINE void glm_quat_mat3(versor q, mat3 dest) { CGLM_ALIGN(16) versor p; float w, x, y, z, xx, yy, zz, xy, yz, xz, wx, wy, wz; glm_quat_normalize_to(q, p); x = p[0]; y = p[1]; z = p[2]; w = p[3]; xx = 2.0f * x * x; xy = 2.0f * x * y; wx = 2.0f * w * x; yy = 2.0f * y * y; yz = 2.0f * y * z; wy = 2.0f * w * y; zz = 2.0f * z * z; xz = 2.0f * x * z; wz = 2.0f * w * z; dest[0][0] = 1.0f - yy - zz; dest[1][1] = 1.0f - xx - zz; dest[2][2] = 1.0f - xx - yy; dest[0][1] = xy + wz; dest[1][2] = yz + wx; dest[2][0] = xz + wy; dest[1][0] = xy - wz; dest[2][1] = yz - wx; dest[0][2] = xz - wy; } /*! * @brief convert quaternion to mat3 (transposed) * * @param[in] q quaternion * @param[out] dest result matrix */ CGLM_INLINE void glm_quat_mat3t(versor q, mat3 dest) { CGLM_ALIGN(16) versor p; float w, x, y, z, xx, yy, zz, xy, yz, xz, wx, wy, wz; glm_quat_normalize_to(q, p); x = p[0]; y = p[1]; z = p[2]; w = p[3]; xx = 2.0f * x * x; xy = 2.0f * x * y; wx = 2.0f * w * x; yy = 2.0f * y * y; yz = 2.0f * y * z; wy = 2.0f * w * y; zz = 2.0f * z * z; xz = 2.0f * x * z; wz = 2.0f * w * z; dest[0][0] = 1.0f - yy - zz; dest[1][1] = 1.0f - xx - zz; dest[2][2] = 1.0f - xx - yy; dest[1][0] = xy + wz; dest[2][1] = yz + wx; dest[0][2] = xz + wy; dest[0][1] = xy - wz; dest[1][2] = yz - wx; dest[2][0] = xz - wy; } /*! * @brief interpolates between two quaternions * using linear interpolation (LERP) * * @param[in] from from * @param[in] to to * @param[in] t interpolant (amount) * @param[out] dest result quaternion */ CGLM_INLINE void glm_quat_lerp(versor from, versor to, float t, versor dest) { glm_vec4_lerp(from, to, t, dest); } /*! * @brief interpolates between two quaternions * using linear interpolation (LERP) * * @param[in] from from * @param[in] to to * @param[in] t interpolant (amount) clamped between 0 and 1 * @param[out] dest result quaternion */ CGLM_INLINE void glm_quat_lerpc(versor from, versor to, float t, versor dest) { glm_vec4_lerpc(from, to, t, dest); } /*! * @brief interpolates between two quaternions * taking the shortest rotation path using * normalized linear interpolation (NLERP) * * @param[in] from from * @param[in] to to * @param[in] t interpolant (amount) * @param[out] dest result quaternion */ CGLM_INLINE void glm_quat_nlerp(versor from, versor to, float t, versor dest) { versor target; float dot; dot = glm_vec4_dot(from, to); glm_vec4_scale(to, (dot >= 0) ? 1.0f : -1.0f, target); glm_quat_lerp(from, target, t, dest); glm_quat_normalize(dest); } /*! * @brief interpolates between two quaternions * using spherical linear interpolation (SLERP) * * @param[in] from from * @param[in] to to * @param[in] t amount * @param[out] dest result quaternion */ CGLM_INLINE void glm_quat_slerp(versor from, versor to, float t, versor dest) { CGLM_ALIGN(16) vec4 q1, q2; float cosTheta, sinTheta, angle; cosTheta = glm_quat_dot(from, to); glm_quat_copy(from, q1); if (fabsf(cosTheta) >= 1.0f) { glm_quat_copy(q1, dest); return; } if (cosTheta < 0.0f) { glm_vec4_negate(q1); cosTheta = -cosTheta; } sinTheta = sqrtf(1.0f - cosTheta * cosTheta); /* LERP to avoid zero division */ if (fabsf(sinTheta) < 0.001f) { glm_quat_lerp(from, to, t, dest); return; } /* SLERP */ angle = acosf(cosTheta); glm_vec4_scale(q1, sinf((1.0f - t) * angle), q1); glm_vec4_scale(to, sinf(t * angle), q2); glm_vec4_add(q1, q2, q1); glm_vec4_scale(q1, 1.0f / sinTheta, dest); } /*! * @brief interpolates between two quaternions * using spherical linear interpolation (SLERP) and always takes the long path * * @param[in] from from * @param[in] to to * @param[in] t amount * @param[out] dest result quaternion */ CGLM_INLINE void glm_quat_slerp_longest(versor from, versor to, float t, versor dest) { CGLM_ALIGN(16) vec4 q1, q2; float cosTheta, sinTheta, angle; cosTheta = glm_quat_dot(from, to); glm_quat_copy(from, q1); if (fabsf(cosTheta) >= 1.0f) { glm_quat_copy(q1, dest); return; } /* longest path */ if (!(cosTheta < 0.0f)) { glm_vec4_negate(q1); cosTheta = -cosTheta; } sinTheta = sqrtf(1.0f - cosTheta * cosTheta); /* LERP to avoid zero division */ if (fabsf(sinTheta) < 0.001f) { glm_quat_lerp(from, to, t, dest); return; } /* SLERP */ angle = acosf(cosTheta); glm_vec4_scale(q1, sinf((1.0f - t) * angle), q1); glm_vec4_scale(to, sinf(t * angle), q2); glm_vec4_add(q1, q2, q1); glm_vec4_scale(q1, 1.0f / sinTheta, dest); } /*! * @brief creates view matrix using quaternion as camera orientation * * @param[in] eye eye * @param[in] ori orientation in world space as quaternion * @param[out] dest view matrix */ CGLM_INLINE void glm_quat_look(vec3 eye, versor ori, mat4 dest) { /* orientation */ glm_quat_mat4t(ori, dest); /* translate */ glm_mat4_mulv3(dest, eye, 1.0f, dest[3]); glm_vec3_negate(dest[3]); } /*! * @brief creates look rotation quaternion * * @param[in] dir direction to look * @param[in] up up vector * @param[out] dest destination quaternion */ CGLM_INLINE void glm_quat_for(vec3 dir, vec3 up, versor dest) { CGLM_ALIGN_MAT mat3 m; glm_vec3_normalize_to(dir, m[2]); /* No need to negate in LH, but we use RH here */ glm_vec3_negate(m[2]); glm_vec3_crossn(up, m[2], m[0]); glm_vec3_cross(m[2], m[0], m[1]); glm_mat3_quat(m, dest); } /*! * @brief creates look rotation quaternion using source and * destination positions p suffix stands for position * * @param[in] from source point * @param[in] to destination point * @param[in] up up vector * @param[out] dest destination quaternion */ CGLM_INLINE void glm_quat_forp(vec3 from, vec3 to, vec3 up, versor dest) { CGLM_ALIGN(8) vec3 dir; glm_vec3_sub(to, from, dir); glm_quat_for(dir, up, dest); } /*! * @brief rotate vector using using quaternion * * @param[in] q quaternion * @param[in] v vector to rotate * @param[out] dest rotated vector */ CGLM_INLINE void glm_quat_rotatev(versor q, vec3 v, vec3 dest) { CGLM_ALIGN(16) versor p; CGLM_ALIGN(8) vec3 u, v1, v2; float s; glm_quat_normalize_to(q, p); glm_quat_imag(p, u); s = glm_quat_real(p); glm_vec3_scale(u, 2.0f * glm_vec3_dot(u, v), v1); glm_vec3_scale(v, s * s - glm_vec3_dot(u, u), v2); glm_vec3_add(v1, v2, v1); glm_vec3_cross(u, v, v2); glm_vec3_scale(v2, 2.0f * s, v2); glm_vec3_add(v1, v2, dest); } /*! * @brief rotate existing transform matrix using quaternion * * @param[in] m existing transform matrix * @param[in] q quaternion * @param[out] dest rotated matrix/transform */ CGLM_INLINE void glm_quat_rotate(mat4 m, versor q, mat4 dest) { CGLM_ALIGN_MAT mat4 rot; glm_quat_mat4(q, rot); glm_mul_rot(m, rot, dest); } /*! * @brief rotate existing transform matrix using quaternion at pivot point * * @param[in, out] m existing transform matrix * @param[in] q quaternion * @param[out] pivot pivot */ CGLM_INLINE void glm_quat_rotate_at(mat4 m, versor q, vec3 pivot) { CGLM_ALIGN(8) vec3 pivotInv; glm_vec3_negate_to(pivot, pivotInv); glm_translate(m, pivot); glm_quat_rotate(m, q, m); glm_translate(m, pivotInv); } /*! * @brief rotate NEW transform matrix using quaternion at pivot point * * this creates rotation matrix, it assumes you don't have a matrix * * this should work faster than glm_quat_rotate_at because it reduces * one glm_translate. * * @param[out] m existing transform matrix * @param[in] q quaternion * @param[in] pivot pivot */ CGLM_INLINE void glm_quat_rotate_atm(mat4 m, versor q, vec3 pivot) { CGLM_ALIGN(8) vec3 pivotInv; glm_vec3_negate_to(pivot, pivotInv); glm_translate_make(m, pivot); glm_quat_rotate(m, q, m); glm_translate(m, pivotInv); } /*! * @brief Create quaternion from pointer * * @param[in] src pointer to an array of floats * @param[out] dest quaternion */ CGLM_INLINE void glm_quat_make(const float * __restrict src, versor dest) { dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; dest[3] = src[3]; } #endif /* cglm_quat_h */ cglm-0.9.7/include/cglm/ray.h000066400000000000000000000107301526744317200157760ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE bool glm_ray_triangle(vec3 origin, vec3 direction, vec3 v0, vec3 v1, vec3 v2, float *d); CGLM_INLINE bool glm_ray_sphere(vec3 origin, vec3 dir, vec4 s, float * __restrict t1, float * __restrict t2) CGLM_INLINE void glm_ray_at(vec3 orig, vec3 dir, float t, vec3 point); */ #ifndef cglm_ray_h #define cglm_ray_h #include "vec3.h" /*! * @brief Möller–Trumbore ray-triangle intersection algorithm * * @param[in] origin origin of ray * @param[in] direction direction of ray * @param[in] v0 first vertex of triangle * @param[in] v1 second vertex of triangle * @param[in] v2 third vertex of triangle * @param[in, out] d distance to intersection * @return whether there is intersection */ CGLM_INLINE bool glm_ray_triangle(vec3 origin, vec3 direction, vec3 v0, vec3 v1, vec3 v2, float *d) { vec3 edge1, edge2, p, t, q; float det, inv_det, u, v, dist; const float epsilon = 0.000001f; glm_vec3_sub(v1, v0, edge1); glm_vec3_sub(v2, v0, edge2); glm_vec3_cross(direction, edge2, p); det = glm_vec3_dot(edge1, p); if (det > -epsilon && det < epsilon) return false; inv_det = 1.0f / det; glm_vec3_sub(origin, v0, t); u = inv_det * glm_vec3_dot(t, p); if (u < 0.0f || u > 1.0f) return false; glm_vec3_cross(t, edge1, q); v = inv_det * glm_vec3_dot(direction, q); if (v < 0.0f || u + v > 1.0f) return false; dist = inv_det * glm_vec3_dot(edge2, q); if (d) *d = dist; return dist > epsilon; } /*! * @brief ray sphere intersection * * returns false if there is no intersection if true: * * - t1 > 0, t2 > 0: ray intersects the sphere at t1 and t2 both ahead of the origin * - t1 < 0, t2 > 0: ray starts inside the sphere, exits at t2 * - t1 < 0, t2 < 0: no intersection ahead of the ray ( returns false ) * - the caller can check if the intersection points (t1 and t2) fall within a * specific range (for example, tmin < t1, t2 < tmax) to determine if the * intersections are within a desired segment of the ray * * @param[in] origin ray origin * @param[out] dir normalized ray direction * @param[in] s sphere [center.x, center.y, center.z, radii] * @param[in] t1 near point1 (closer to origin) * @param[in] t2 far point2 (farther from origin) * * @returns whether there is intersection */ CGLM_INLINE bool glm_ray_sphere(vec3 origin, vec3 dir, vec4 s, float * __restrict t1, float * __restrict t2) { vec3 dp; float r2, ddp, dpp, dscr, q, tmp, _t1, _t2; glm_vec3_sub(s, origin, dp); ddp = glm_vec3_dot(dir, dp); dpp = glm_vec3_norm2(dp); /* compute the remedy term for numerical stability */ glm_vec3_mulsubs(dir, ddp, dp); /* dp: remedy term */ r2 = s[3] * s[3]; dscr = r2 - glm_vec3_norm2(dp); if (dscr < 0.0f) { /* no intersection */ return false; } dscr = sqrtf(dscr); q = (ddp >= 0.0f) ? (ddp + dscr) : (ddp - dscr); /* include Press, William H., Saul A. Teukolsky, William T. Vetterling, and Brian P. Flannery, "Numerical Recipes in C," Cambridge University Press, 1992. */ _t1 = q; _t2 = (dpp - r2) / q; /* adjust t1 and t2 to ensure t1 is the closer intersection */ if (_t1 > _t2) { tmp = _t1; _t1 = _t2; _t2 = tmp; } *t1 = _t1; *t2 = _t2; /* check if the closest intersection (t1) is behind the ray's origin */ if (_t1 < 0.0f && _t2 < 0.0f) { /* both intersections are behind the ray, no visible intersection */ return false; } return true; } /*! * @brief point using t by �(�)=�+�� * * @param[in] orig origin of ray * @param[in] dir direction of ray * @param[in] t parameter * @param[out] point point at t */ CGLM_INLINE void glm_ray_at(vec3 orig, vec3 dir, float t, vec3 point) { vec3 dst; glm_vec3_scale(dir, t, dst); glm_vec3_add(orig, dst, point); } #endif cglm-0.9.7/include/cglm/simd/000077500000000000000000000000001526744317200157655ustar00rootroot00000000000000cglm-0.9.7/include/cglm/simd/arm.h000066400000000000000000000123111526744317200167130ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_simd_arm_h #define cglm_simd_arm_h #include "intrin.h" #ifdef CGLM_SIMD_ARM #if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || defined(__aarch64__) # define CGLM_ARM64 1 #else # define CGLM_ARM64 0 #endif #define glmm_load(p) vld1q_f32(p) #define glmm_store(p, a) vst1q_f32(p, a) #define glmm_set1(x) vdupq_n_f32(x) #define glmm_set1_ptr(x) vdupq_n_f32(*x) #define glmm_set1_rval(x) vdupq_n_f32(x) #define glmm_128 float32x4_t #define glmm_splat_x(x) vdupq_lane_f32(vget_low_f32(x), 0) #define glmm_splat_y(x) vdupq_lane_f32(vget_low_f32(x), 1) #define glmm_splat_z(x) vdupq_lane_f32(vget_high_f32(x), 0) #define glmm_splat_w(x) vdupq_lane_f32(vget_high_f32(x), 1) #define glmm_xor(a, b) \ vreinterpretq_f32_s32(veorq_s32(vreinterpretq_s32_f32(a), \ vreinterpretq_s32_f32(b))) #define glmm_swplane(v) vextq_f32(v, v, 2) #define glmm_low(x) vget_low_f32(x) #define glmm_high(x) vget_high_f32(x) #define glmm_combine_ll(x, y) vcombine_f32(vget_low_f32(x), vget_low_f32(y)) #define glmm_combine_hl(x, y) vcombine_f32(vget_high_f32(x), vget_low_f32(y)) #define glmm_combine_lh(x, y) vcombine_f32(vget_low_f32(x), vget_high_f32(y)) #define glmm_combine_hh(x, y) vcombine_f32(vget_high_f32(x), vget_high_f32(y)) #if defined(_WIN32) && defined(_MSC_VER) /* # define glmm_float32x4_init(x, y, z, w) { .n128_f32 = { x, y, z, w } } */ CGLM_INLINE float32x4_t glmm_float32x4_init(float x, float y, float z, float w) { CGLM_ALIGN(16) float v[4] = {x, y, z, w}; return vld1q_f32(v); } #else # define glmm_float32x4_init(x, y, z, w) { x, y, z, w } #endif #define glmm_float32x4_SIGNMASK_PNPN glmm_float32x4_init( 0.f, -0.f, 0.f, -0.f) #define glmm_float32x4_SIGNMASK_NPNP glmm_float32x4_init(-0.f, 0.f, -0.f, 0.f) #define glmm_float32x4_SIGNMASK_NPPN glmm_float32x4_init(-0.f, 0.f, 0.f, -0.f) static inline float32x4_t glmm_abs(float32x4_t v) { return vabsq_f32(v); } static inline float32x4_t glmm_min(float32x4_t a, float32x4_t b) { return vminq_f32(a, b); } static inline float32x4_t glmm_max(float32x4_t a, float32x4_t b) { return vmaxq_f32(a, b); } static inline float32x4_t glmm_vhadd(float32x4_t v) { #if CGLM_ARM64 float32x4_t p; p = vpaddq_f32(v, v); /* [a+b, c+d, a+b, c+d] */ return vpaddq_f32(p, p); /* [t, t, t, t] */; #else return vaddq_f32(vaddq_f32(glmm_splat_x(v), glmm_splat_y(v)), vaddq_f32(glmm_splat_z(v), glmm_splat_w(v))); #endif /* TODO: measure speed of this compare to above */ /* return vdupq_n_f32(vaddvq_f32(v)); */ /* return vaddq_f32(vaddq_f32(glmm_splat_x(v), glmm_splat_y(v)), vaddq_f32(glmm_splat_z(v), glmm_splat_w(v))); */ /* this seems slower: v = vaddq_f32(v, vrev64q_f32(v)); return vaddq_f32(v, vcombine_f32(vget_high_f32(v), vget_low_f32(v))); */ } static inline float glmm_hadd(float32x4_t v) { #if CGLM_ARM64 return vaddvq_f32(v); #else v = vaddq_f32(v, vrev64q_f32(v)); v = vaddq_f32(v, vcombine_f32(vget_high_f32(v), vget_low_f32(v))); return vgetq_lane_f32(v, 0); #endif } static inline float glmm_hmin(float32x4_t v) { float32x2_t t; t = vpmin_f32(vget_low_f32(v), vget_high_f32(v)); t = vpmin_f32(t, t); return vget_lane_f32(t, 0); } static inline float glmm_hmax(float32x4_t v) { float32x2_t t; t = vpmax_f32(vget_low_f32(v), vget_high_f32(v)); t = vpmax_f32(t, t); return vget_lane_f32(t, 0); } static inline float glmm_dot(float32x4_t a, float32x4_t b) { return glmm_hadd(vmulq_f32(a, b)); } static inline float32x4_t glmm_vdot(float32x4_t a, float32x4_t b) { return glmm_vhadd(vmulq_f32(a, b)); } static inline float glmm_norm(float32x4_t a) { return sqrtf(glmm_dot(a, a)); } static inline float glmm_norm2(float32x4_t a) { return glmm_dot(a, a); } static inline float glmm_norm_one(float32x4_t a) { return glmm_hadd(glmm_abs(a)); } static inline float glmm_norm_inf(float32x4_t a) { return glmm_hmax(glmm_abs(a)); } static inline float32x4_t glmm_div(float32x4_t a, float32x4_t b) { #if CGLM_ARM64 return vdivq_f32(a, b); #else /* 2 iterations of Newton-Raphson refinement of reciprocal */ float32x4_t r0, r1; r0 = vrecpeq_f32(b); r1 = vrecpsq_f32(r0, b); r0 = vmulq_f32(r1, r0); r1 = vrecpsq_f32(r0, b); r0 = vmulq_f32(r1, r0); return vmulq_f32(a, r0); #endif } static inline float32x4_t glmm_fmadd(float32x4_t a, float32x4_t b, float32x4_t c) { #if CGLM_ARM64 return vfmaq_f32(c, a, b); /* why vfmaq_f32 is slower than vmlaq_f32 ??? */ #else return vmlaq_f32(c, a, b); #endif } static inline float32x4_t glmm_fnmadd(float32x4_t a, float32x4_t b, float32x4_t c) { #if CGLM_ARM64 return vfmsq_f32(c, a, b); #else return vmlsq_f32(c, a, b); #endif } static inline float32x4_t glmm_fmsub(float32x4_t a, float32x4_t b, float32x4_t c) { return glmm_fmadd(a, b, vnegq_f32(c)); } static inline float32x4_t glmm_fnmsub(float32x4_t a, float32x4_t b, float32x4_t c) { return vsubq_f32(vdupq_n_f32(0.0f), glmm_fmadd(a, b, c)); } #endif #endif /* cglm_simd_arm_h */ cglm-0.9.7/include/cglm/simd/avx/000077500000000000000000000000001526744317200165635ustar00rootroot00000000000000cglm-0.9.7/include/cglm/simd/avx/affine.h000066400000000000000000000043011526744317200201620ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_affine_mat_avx_h #define cglm_affine_mat_avx_h #ifdef __AVX__ #include "../../common.h" #include "../intrin.h" #include CGLM_INLINE void glm_mul_avx(mat4 m1, mat4 m2, mat4 dest) { /* D = R * L (Column-Major) */ __m256 y0, y1, y2, y3, y4, y5, y6, y7, y8, y9; y0 = glmm_load256(m2[0]); /* h g f e d c b a */ y1 = glmm_load256(m2[2]); /* p o n m l k j i */ y2 = glmm_load256(m1[0]); /* h g f e d c b a */ y3 = glmm_load256(m1[2]); /* p o n m l k j i */ /* 0x03: 0b00000011 */ y4 = _mm256_permute2f128_ps(y2, y2, 0x03); /* d c b a h g f e */ y5 = _mm256_permute2f128_ps(y3, y3, 0x03); /* l k j i p o n m */ /* f f f f a a a a */ /* h h h h c c c c */ /* e e e e b b b b */ /* g g g g d d d d */ y6 = _mm256_permutevar_ps(y0, _mm256_set_epi32(1, 1, 1, 1, 0, 0, 0, 0)); y7 = _mm256_permutevar_ps(y0, _mm256_set_epi32(3, 3, 3, 3, 2, 2, 2, 2)); y8 = _mm256_permutevar_ps(y0, _mm256_set_epi32(0, 0, 0, 0, 1, 1, 1, 1)); y9 = _mm256_permutevar_ps(y0, _mm256_set_epi32(2, 2, 2, 2, 3, 3, 3, 3)); glmm_store256(dest[0], _mm256_add_ps(_mm256_add_ps(_mm256_mul_ps(y2, y6), _mm256_mul_ps(y3, y7)), _mm256_add_ps(_mm256_mul_ps(y4, y8), _mm256_mul_ps(y5, y9)))); /* n n n n i i i i */ /* p p p p k k k k */ /* m m m m j j j j */ /* o o o o l l l l */ y6 = _mm256_permutevar_ps(y1, _mm256_set_epi32(1, 1, 1, 1, 0, 0, 0, 0)); y7 = _mm256_permutevar_ps(y1, _mm256_set_epi32(3, 3, 3, 3, 2, 2, 2, 2)); y8 = _mm256_permutevar_ps(y1, _mm256_set_epi32(0, 0, 0, 0, 1, 1, 1, 1)); y9 = _mm256_permutevar_ps(y1, _mm256_set_epi32(2, 2, 2, 2, 3, 3, 3, 3)); glmm_store256(dest[2], _mm256_add_ps(_mm256_add_ps(_mm256_mul_ps(y2, y6), _mm256_mul_ps(y3, y7)), _mm256_add_ps(_mm256_mul_ps(y4, y8), _mm256_mul_ps(y5, y9)))); } #endif #endif /* cglm_affine_mat_avx_h */ cglm-0.9.7/include/cglm/simd/avx/mat4.h000066400000000000000000000061461526744317200176100ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_mat_simd_avx_h #define cglm_mat_simd_avx_h #ifdef __AVX__ #include "../../common.h" #include "../intrin.h" CGLM_INLINE void glm_mat4_scale_avx(mat4 m, float s) { __m256 y0, y1, y2, y3, y4; y0 = glmm_load256(m[0]); /* h g f e d c b a */ y1 = glmm_load256(m[2]); /* p o n m l k j i */ y2 = _mm256_broadcast_ss(&s); y3 = _mm256_mul_ps(y0, y2); y4 = _mm256_mul_ps(y1, y2); glmm_store256(m[0], y3); glmm_store256(m[2], y4); } /* TODO: this must be tested and compared to SSE version, may be slower!!! */ CGLM_INLINE void glm_mat4_transp_avx(mat4 m, mat4 dest) { __m256 y0, y1, y2, y3; y0 = glmm_load256(m[0]); /* h g f e d c b a */ y1 = glmm_load256(m[2]); /* p o n m l k j i */ y2 = _mm256_unpacklo_ps(y0, y1); /* n f m e j b i a */ y3 = _mm256_unpackhi_ps(y0, y1); /* p h o g l d k c */ y0 = _mm256_permute2f128_ps(y2, y3, 0x20); /* l d k c j b i a */ y1 = _mm256_permute2f128_ps(y2, y3, 0x31); /* p h o g n f m e */ y2 = _mm256_unpacklo_ps(y0, y1); /* o k g c m i e a */ y3 = _mm256_unpackhi_ps(y0, y1); /* p l h d n j f b */ y0 = _mm256_permute2f128_ps(y2, y3, 0x20); /* n j f b m i e a */ y1 = _mm256_permute2f128_ps(y2, y3, 0x31); /* p l h d o k g c */ glmm_store256(dest[0], y0); glmm_store256(dest[2], y1); } CGLM_INLINE void glm_mat4_mul_avx(mat4 m1, mat4 m2, mat4 dest) { /* D = R * L (Column-Major) */ __m256 y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13; __m256i yi0, yi1, yi2, yi3; y0 = glmm_load256(m2[0]); /* h g f e d c b a */ y1 = glmm_load256(m2[2]); /* p o n m l k j i */ y2 = glmm_load256(m1[0]); /* h g f e d c b a */ y3 = glmm_load256(m1[2]); /* p o n m l k j i */ /* 0x03: 0b00000011 */ y4 = _mm256_permute2f128_ps(y2, y2, 0x03); /* d c b a h g f e */ y5 = _mm256_permute2f128_ps(y3, y3, 0x03); /* l k j i p o n m */ yi0 = _mm256_set_epi32(1, 1, 1, 1, 0, 0, 0, 0); yi1 = _mm256_set_epi32(3, 3, 3, 3, 2, 2, 2, 2); yi2 = _mm256_set_epi32(0, 0, 0, 0, 1, 1, 1, 1); yi3 = _mm256_set_epi32(2, 2, 2, 2, 3, 3, 3, 3); /* f f f f a a a a */ /* h h h h c c c c */ /* e e e e b b b b */ /* g g g g d d d d */ y6 = _mm256_permutevar_ps(y0, yi0); y7 = _mm256_permutevar_ps(y0, yi1); y8 = _mm256_permutevar_ps(y0, yi2); y9 = _mm256_permutevar_ps(y0, yi3); /* n n n n i i i i */ /* p p p p k k k k */ /* m m m m j j j j */ /* o o o o l l l l */ y10 = _mm256_permutevar_ps(y1, yi0); y11 = _mm256_permutevar_ps(y1, yi1); y12 = _mm256_permutevar_ps(y1, yi2); y13 = _mm256_permutevar_ps(y1, yi3); y0 = _mm256_mul_ps(y2, y6); y1 = _mm256_mul_ps(y2, y10); y0 = glmm256_fmadd(y3, y7, y0); y1 = glmm256_fmadd(y3, y11, y1); y0 = glmm256_fmadd(y4, y8, y0); y1 = glmm256_fmadd(y4, y12, y1); y0 = glmm256_fmadd(y5, y9, y0); y1 = glmm256_fmadd(y5, y13, y1); glmm_store256(dest[0], y0); glmm_store256(dest[2], y1); } #endif #endif /* cglm_mat_simd_avx_h */ cglm-0.9.7/include/cglm/simd/intrin.h000066400000000000000000000062011526744317200174400ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_intrin_h #define cglm_intrin_h #if defined(_MSC_VER) && !defined(_M_ARM64EC) # if (defined(_M_AMD64) || defined(_M_X64)) || _M_IX86_FP == 2 # ifndef __SSE__ # define __SSE__ # endif # ifndef __SSE2__ # define __SSE2__ # endif # elif _M_IX86_FP == 1 # ifndef __SSE__ # define __SSE__ # endif # endif /* do not use alignment for older visual studio versions */ /* also ARM32 also causes similar error, disable it for now on ARM32 too */ # if _MSC_VER < 1913 || _M_ARM /* Visual Studio 2017 version 15.6 */ # define CGLM_ALL_UNALIGNED # endif #endif #ifdef __AVX__ # include # define CGLM_AVX_FP 1 # ifndef __SSE2__ # define __SSE2__ # endif # ifndef __SSE3__ # define __SSE3__ # endif # ifndef __SSE4__ # define __SSE4__ # endif # ifndef __SSE4_1__ # define __SSE4_1__ # endif # ifndef __SSE4_2__ # define __SSE4_2__ # endif # ifndef CGLM_SIMD_x86 # define CGLM_SIMD_x86 # endif #endif #if defined(__SSE__) # include # define CGLM_SSE_FP 1 # ifndef CGLM_SIMD_x86 # define CGLM_SIMD_x86 # endif #endif #if defined(__SSE2__) # include # define CGLM_SSE2_FP 1 # ifndef CGLM_SIMD_x86 # define CGLM_SIMD_x86 # endif #endif #if defined(__SSE3__) # include # ifndef CGLM_SIMD_x86 # define CGLM_SIMD_x86 # endif #endif #if defined(__SSE4_1__) # include # ifndef CGLM_SIMD_x86 # define CGLM_SIMD_x86 # endif #endif #if defined(__SSE4_2__) # include # ifndef CGLM_SIMD_x86 # define CGLM_SIMD_x86 # endif #endif /* ARM Neon */ #if defined(_WIN32) && defined(_MSC_VER) /* TODO: non-ARM stuff already inported, will this be better option */ /* # include */ # if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) # include # include # ifndef CGLM_NEON_FP # define CGLM_NEON_FP 1 # endif # ifndef CGLM_SIMD_ARM # define CGLM_SIMD_ARM # endif # elif defined(_M_ARM) # include # include # ifndef CGLM_NEON_FP # define CGLM_NEON_FP 1 # endif # ifndef CGLM_SIMD_ARM # define CGLM_SIMD_ARM # endif # endif #else /* non-windows */ # if defined(__ARM_NEON) || defined(__ARM_NEON__) # include # if defined(__ARM_NEON_FP) || defined(__ARM_FP) # define CGLM_NEON_FP 1 # endif # ifndef CGLM_SIMD_ARM # define CGLM_SIMD_ARM # endif # endif #endif /* WebAssembly */ #if defined(__wasm__) && defined(__wasm_simd128__) # ifndef CGLM_SIMD_WASM # define CGLM_SIMD_WASM # endif #endif #if defined(CGLM_SIMD_x86) || defined(CGLM_SIMD_ARM) || defined(CGLM_SIMD_WASM) # ifndef CGLM_SIMD # define CGLM_SIMD # endif #endif #if defined(CGLM_SIMD_x86) && !defined(CGLM_SIMD_WASM) # include "x86.h" #endif #if defined(CGLM_SIMD_ARM) # include "arm.h" #endif #if defined(CGLM_SIMD_WASM) # include "wasm.h" #endif #endif /* cglm_intrin_h */ cglm-0.9.7/include/cglm/simd/neon/000077500000000000000000000000001526744317200167245ustar00rootroot00000000000000cglm-0.9.7/include/cglm/simd/neon/affine.h000066400000000000000000000054731526744317200203360ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_affine_neon_h #define cglm_affine_neon_h #if defined(CGLM_NEON_FP) #include "../../common.h" #include "../intrin.h" CGLM_INLINE void glm_mul_neon(mat4 m1, mat4 m2, mat4 dest) { /* D = R * L (Column-Major) */ glmm_128 l, r0, r1, r2, r3, v0, v1, v2, v3; l = glmm_load(m1[0]); r0 = glmm_load(m2[0]); r1 = glmm_load(m2[1]); r2 = glmm_load(m2[2]); r3 = glmm_load(m2[3]); v0 = vmulq_f32(glmm_splat_x(r0), l); v1 = vmulq_f32(glmm_splat_x(r1), l); v2 = vmulq_f32(glmm_splat_x(r2), l); v3 = vmulq_f32(glmm_splat_x(r3), l); l = glmm_load(m1[1]); v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); v3 = glmm_fmadd(glmm_splat_y(r3), l, v3); l = glmm_load(m1[2]); v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); v3 = glmm_fmadd(glmm_splat_z(r3), l, v3); v3 = glmm_fmadd(glmm_splat_w(r3), glmm_load(m1[3]), v3); glmm_store(dest[0], v0); glmm_store(dest[1], v1); glmm_store(dest[2], v2); glmm_store(dest[3], v3); } CGLM_INLINE void glm_mul_rot_neon(mat4 m1, mat4 m2, mat4 dest) { /* D = R * L (Column-Major) */ glmm_128 l, r0, r1, r2, v0, v1, v2; l = glmm_load(m1[0]); r0 = glmm_load(m2[0]); r1 = glmm_load(m2[1]); r2 = glmm_load(m2[2]); v0 = vmulq_f32(glmm_splat_x(r0), l); v1 = vmulq_f32(glmm_splat_x(r1), l); v2 = vmulq_f32(glmm_splat_x(r2), l); l = glmm_load(m1[1]); v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); l = glmm_load(m1[2]); v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); glmm_store(dest[0], v0); glmm_store(dest[1], v1); glmm_store(dest[2], v2); glmm_store(dest[3], glmm_load(m1[3])); } CGLM_INLINE void glm_inv_tr_neon(mat4 mat) { float32x4x4_t vmat; glmm_128 r0, r1, r2, x0; vmat = vld4q_f32(mat[0]); r0 = vmat.val[0]; r1 = vmat.val[1]; r2 = vmat.val[2]; x0 = glmm_fmadd(r0, glmm_splat_w(r0), glmm_fmadd(r1, glmm_splat_w(r1), vmulq_f32(r2, glmm_splat_w(r2)))); x0 = vnegq_f32(x0); glmm_store(mat[0], r0); glmm_store(mat[1], r1); glmm_store(mat[2], r2); glmm_store(mat[3], x0); mat[0][3] = 0.0f; mat[1][3] = 0.0f; mat[2][3] = 0.0f; mat[3][3] = 1.0f; /* TODO: ? zo = vget_high_f32(r3); vst1_lane_f32(&mat[0][3], zo, 0); vst1_lane_f32(&mat[1][3], zo, 0); vst1_lane_f32(&mat[2][3], zo, 0); vst1_lane_f32(&mat[3][3], zo, 1); */ } #endif #endif /* cglm_affine_neon_h */ cglm-0.9.7/include/cglm/simd/neon/mat2.h000066400000000000000000000016251526744317200177440ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_mat2_neon_h #define cglm_mat2_neon_h #if defined(CGLM_NEON_FP) #include "../../common.h" #include "../intrin.h" CGLM_INLINE void glm_mat2_mul_neon(mat2 m1, mat2 m2, mat2 dest) { float32x4x2_t a1; glmm_128 x0, x1, x2; float32x2_t dc, ba; x1 = glmm_load(m1[0]); /* d c b a */ x2 = glmm_load(m2[0]); /* h g f e */ dc = vget_high_f32(x1); ba = vget_low_f32(x1); /* g g e e, h h f f */ a1 = vtrnq_f32(x2, x2); /* dest[0][0] = a * e + c * f; dest[0][1] = b * e + d * f; dest[1][0] = a * g + c * h; dest[1][1] = b * g + d * h; */ x0 = glmm_fmadd(vcombine_f32(ba, ba), a1.val[0], vmulq_f32(vcombine_f32(dc, dc), a1.val[1])); glmm_store(dest[0], x0); } #endif #endif /* cglm_mat2_neon_h */ cglm-0.9.7/include/cglm/simd/neon/mat4.h000066400000000000000000000333271526744317200177520ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_mat4_neon_h #define cglm_mat4_neon_h #if defined(CGLM_NEON_FP) #include "../../common.h" #include "../intrin.h" CGLM_INLINE void glm_mat4_scale_neon(mat4 m, float s) { float32x4_t v0; v0 = vdupq_n_f32(s); vst1q_f32(m[0], vmulq_f32(vld1q_f32(m[0]), v0)); vst1q_f32(m[1], vmulq_f32(vld1q_f32(m[1]), v0)); vst1q_f32(m[2], vmulq_f32(vld1q_f32(m[2]), v0)); vst1q_f32(m[3], vmulq_f32(vld1q_f32(m[3]), v0)); } CGLM_INLINE void glm_mat4_transp_neon(mat4 m, mat4 dest) { float32x4x4_t vmat; vmat = vld4q_f32(m[0]); vst1q_f32(dest[0], vmat.val[0]); vst1q_f32(dest[1], vmat.val[1]); vst1q_f32(dest[2], vmat.val[2]); vst1q_f32(dest[3], vmat.val[3]); } CGLM_INLINE void glm_mat4_mul_neon(mat4 m1, mat4 m2, mat4 dest) { /* D = R * L (Column-Major) */ glmm_128 l, r0, r1, r2, r3, v0, v1, v2, v3; l = glmm_load(m1[0]); r0 = glmm_load(m2[0]); r1 = glmm_load(m2[1]); r2 = glmm_load(m2[2]); r3 = glmm_load(m2[3]); v0 = vmulq_f32(glmm_splat_x(r0), l); v1 = vmulq_f32(glmm_splat_x(r1), l); v2 = vmulq_f32(glmm_splat_x(r2), l); v3 = vmulq_f32(glmm_splat_x(r3), l); l = glmm_load(m1[1]); v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); v3 = glmm_fmadd(glmm_splat_y(r3), l, v3); l = glmm_load(m1[2]); v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); v3 = glmm_fmadd(glmm_splat_z(r3), l, v3); l = glmm_load(m1[3]); v0 = glmm_fmadd(glmm_splat_w(r0), l, v0); v1 = glmm_fmadd(glmm_splat_w(r1), l, v1); v2 = glmm_fmadd(glmm_splat_w(r2), l, v2); v3 = glmm_fmadd(glmm_splat_w(r3), l, v3); glmm_store(dest[0], v0); glmm_store(dest[1], v1); glmm_store(dest[2], v2); glmm_store(dest[3], v3); } CGLM_INLINE void glm_mat4_mulv_neon(mat4 m, vec4 v, vec4 dest) { float32x4_t l0, l1, l2, l3; float32x2_t vlo, vhi; l0 = vld1q_f32(m[0]); l1 = vld1q_f32(m[1]); l2 = vld1q_f32(m[2]); l3 = vld1q_f32(m[3]); vlo = vld1_f32(&v[0]); vhi = vld1_f32(&v[2]); l0 = vmulq_lane_f32(l0, vlo, 0); l0 = vmlaq_lane_f32(l0, l1, vlo, 1); l0 = vmlaq_lane_f32(l0, l2, vhi, 0); l0 = vmlaq_lane_f32(l0, l3, vhi, 1); vst1q_f32(dest, l0); } CGLM_INLINE float glm_mat4_det_neon(mat4 mat) { float32x4_t r0, r1, r2, r3, x0, x1, x2; float32x2_t ij, op, mn, kl, nn, mm, jj, ii, gh, ef, t12, t34; float32x4x2_t a1; float32x4_t x3 = glmm_float32x4_SIGNMASK_PNPN; /* 127 <- 0, [square] det(A) = det(At) */ r0 = glmm_load(mat[0]); /* d c b a */ r1 = vrev64q_f32(glmm_load(mat[1])); /* g h e f */ r2 = vrev64q_f32(glmm_load(mat[2])); /* l k i j */ r3 = vrev64q_f32(glmm_load(mat[3])); /* o p m n */ gh = vget_high_f32(r1); ef = vget_low_f32(r1); kl = vget_high_f32(r2); ij = vget_low_f32(r2); op = vget_high_f32(r3); mn = vget_low_f32(r3); mm = vdup_lane_f32(mn, 1); nn = vdup_lane_f32(mn, 0); ii = vdup_lane_f32(ij, 1); jj = vdup_lane_f32(ij, 0); /* t[1] = j * p - n * l; t[2] = j * o - n * k; t[3] = i * p - m * l; t[4] = i * o - m * k; */ x0 = glmm_fnmadd(vcombine_f32(kl, kl), vcombine_f32(nn, mm), vmulq_f32(vcombine_f32(op, op), vcombine_f32(jj, ii))); t12 = vget_low_f32(x0); t34 = vget_high_f32(x0); /* 1 3 1 3 2 4 2 4 */ a1 = vuzpq_f32(x0, x0); /* t[0] = k * p - o * l; t[0] = k * p - o * l; t[5] = i * n - m * j; t[5] = i * n - m * j; */ x1 = glmm_fnmadd(vcombine_f32(vdup_lane_f32(kl, 0), jj), vcombine_f32(vdup_lane_f32(op, 1), mm), vmulq_f32(vcombine_f32(vdup_lane_f32(op, 0), nn), vcombine_f32(vdup_lane_f32(kl, 1), ii))); /* a * (f * t[0] - g * t[1] + h * t[2]) - b * (e * t[0] - g * t[3] + h * t[4]) + c * (e * t[1] - f * t[3] + h * t[5]) - d * (e * t[2] - f * t[4] + g * t[5]) */ x2 = glmm_fnmadd(vcombine_f32(vdup_lane_f32(gh, 1), vdup_lane_f32(ef, 0)), vcombine_f32(vget_low_f32(a1.val[0]), t34), vmulq_f32(vcombine_f32(ef, vdup_lane_f32(ef, 1)), vcombine_f32(vget_low_f32(x1), t12))); x2 = glmm_fmadd(vcombine_f32(vdup_lane_f32(gh, 0), gh), vcombine_f32(vget_low_f32(a1.val[1]), vget_high_f32(x1)), x2); x2 = glmm_xor(x2, x3); return glmm_hadd(vmulq_f32(x2, r0)); } /* old one */ #if 0 CGLM_INLINE void glm_mat4_inv_neon(mat4 mat, mat4 dest) { float32x4_t r0, r1, r2, r3, v0, v1, v2, v3, t0, t1, t2, t3, t4, t5, x0, x1, x2, x3, x4, x5, x6, x7, x8; float32x4x2_t a1; float32x2_t lp, ko, hg, jn, im, fe, ae, bf, cg, dh; float32x4_t x9 = glmm_float32x4_SIGNMASK_NPNP; x8 = vrev64q_f32(x9); /* 127 <- 0 */ r0 = glmm_load(mat[0]); /* d c b a */ r1 = glmm_load(mat[1]); /* h g f e */ r2 = glmm_load(mat[2]); /* l k j i */ r3 = glmm_load(mat[3]); /* p o n m */ /* l p k o, j n i m */ a1 = vzipq_f32(r3, r2); jn = vget_high_f32(a1.val[0]); im = vget_low_f32(a1.val[0]); lp = vget_high_f32(a1.val[1]); ko = vget_low_f32(a1.val[1]); hg = vget_high_f32(r1); x1 = vcombine_f32(vdup_lane_f32(lp, 0), lp); /* l p p p */ x2 = vcombine_f32(vdup_lane_f32(ko, 0), ko); /* k o o o */ x0 = vcombine_f32(vdup_lane_f32(lp, 1), vdup_lane_f32(hg, 1)); /* h h l l */ x3 = vcombine_f32(vdup_lane_f32(ko, 1), vdup_lane_f32(hg, 0)); /* g g k k */ /* t1[0] = k * p - o * l; t1[0] = k * p - o * l; t2[0] = g * p - o * h; t3[0] = g * l - k * h; */ t0 = glmm_fnmadd(x2, x0, vmulq_f32(x3, x1)); fe = vget_low_f32(r1); x4 = vcombine_f32(vdup_lane_f32(jn, 0), jn); /* j n n n */ x5 = vcombine_f32(vdup_lane_f32(jn, 1), vdup_lane_f32(fe, 1)); /* f f j j */ /* t1[1] = j * p - n * l; t1[1] = j * p - n * l; t2[1] = f * p - n * h; t3[1] = f * l - j * h; */ t1 = glmm_fnmadd(x4, x0, vmulq_f32(x5, x1)); /* t1[2] = j * o - n * k t1[2] = j * o - n * k; t2[2] = f * o - n * g; t3[2] = f * k - j * g; */ t2 = glmm_fnmadd(x4, x3, vmulq_f32(x5, x2)); x6 = vcombine_f32(vdup_lane_f32(im, 1), vdup_lane_f32(fe, 0)); /* e e i i */ x7 = vcombine_f32(vdup_lane_f32(im, 0), im); /* i m m m */ /* t1[3] = i * p - m * l; t1[3] = i * p - m * l; t2[3] = e * p - m * h; t3[3] = e * l - i * h; */ t3 = glmm_fnmadd(x7, x0, vmulq_f32(x6, x1)); /* t1[4] = i * o - m * k; t1[4] = i * o - m * k; t2[4] = e * o - m * g; t3[4] = e * k - i * g; */ t4 = glmm_fnmadd(x7, x3, vmulq_f32(x6, x2)); /* t1[5] = i * n - m * j; t1[5] = i * n - m * j; t2[5] = e * n - m * f; t3[5] = e * j - i * f; */ t5 = glmm_fnmadd(x7, x5, vmulq_f32(x6, x4)); /* h d f b, g c e a */ a1 = vtrnq_f32(r0, r1); x4 = vrev64q_f32(a1.val[0]); /* c g a e */ x5 = vrev64q_f32(a1.val[1]); /* d h b f */ ae = vget_low_f32(x4); cg = vget_high_f32(x4); bf = vget_low_f32(x5); dh = vget_high_f32(x5); x0 = vcombine_f32(ae, vdup_lane_f32(ae, 1)); /* a a a e */ x1 = vcombine_f32(bf, vdup_lane_f32(bf, 1)); /* b b b f */ x2 = vcombine_f32(cg, vdup_lane_f32(cg, 1)); /* c c c g */ x3 = vcombine_f32(dh, vdup_lane_f32(dh, 1)); /* d d d h */ /* dest[0][0] = f * t1[0] - g * t1[1] + h * t1[2]; dest[0][1] =-(b * t1[0] - c * t1[1] + d * t1[2]); dest[0][2] = b * t2[0] - c * t2[1] + d * t2[2]; dest[0][3] =-(b * t3[0] - c * t3[1] + d * t3[2]); */ v0 = glmm_xor(glmm_fmadd(x3, t2, glmm_fnmadd(x2, t1, vmulq_f32(x1, t0))), x8); /* dest[2][0] = e * t1[1] - f * t1[3] + h * t1[5]; dest[2][1] =-(a * t1[1] - b * t1[3] + d * t1[5]); dest[2][2] = a * t2[1] - b * t2[3] + d * t2[5]; dest[2][3] =-(a * t3[1] - b * t3[3] + d * t3[5]);*/ v2 = glmm_xor(glmm_fmadd(x3, t5, glmm_fnmadd(x1, t3, vmulq_f32(x0, t1))), x8); /* dest[1][0] =-(e * t1[0] - g * t1[3] + h * t1[4]); dest[1][1] = a * t1[0] - c * t1[3] + d * t1[4]; dest[1][2] =-(a * t2[0] - c * t2[3] + d * t2[4]); dest[1][3] = a * t3[0] - c * t3[3] + d * t3[4]; */ v1 = glmm_xor(glmm_fmadd(x3, t4, glmm_fnmadd(x2, t3, vmulq_f32(x0, t0))), x9); /* dest[3][0] =-(e * t1[2] - f * t1[4] + g * t1[5]); dest[3][1] = a * t1[2] - b * t1[4] + c * t1[5]; dest[3][2] =-(a * t2[2] - b * t2[4] + c * t2[5]); dest[3][3] = a * t3[2] - b * t3[4] + c * t3[5]; */ v3 = glmm_xor(glmm_fmadd(x2, t5, glmm_fnmadd(x1, t4, vmulq_f32(x0, t2))), x9); /* determinant */ x0 = vcombine_f32(vget_low_f32(vzipq_f32(v0, v1).val[0]), vget_low_f32(vzipq_f32(v2, v3).val[0])); /* x0 = glmm_div(glmm_set1_rval(1.0f), glmm_vhadd(vmulq_f32(x0, r0))); glmm_store(dest[0], vmulq_f32(v0, x0)); glmm_store(dest[1], vmulq_f32(v1, x0)); glmm_store(dest[2], vmulq_f32(v2, x0)); glmm_store(dest[3], vmulq_f32(v3, x0)); */ x0 = glmm_vhadd(vmulq_f32(x0, r0)); glmm_store(dest[0], glmm_div(v0, x0)); glmm_store(dest[1], glmm_div(v1, x0)); glmm_store(dest[2], glmm_div(v2, x0)); glmm_store(dest[3], glmm_div(v3, x0)); } #endif CGLM_INLINE void glm_mat4_inv_neon(mat4 mat, mat4 dest) { float32x4_t r0, r1, r2, r3, v0, v1, v2, v3, v4, v5, t0, t1, t2; float32x4x2_t a0, a1, a2, a3, a4; float32x4_t s1 = glmm_float32x4_SIGNMASK_PNPN, s2; #if !CGLM_ARM64 float32x2_t l0, l1; #endif s2 = vrev64q_f32(s1); /* 127 <- 0 */ r0 = glmm_load(mat[0]); /* d c b a */ r1 = glmm_load(mat[1]); /* h g f e */ r2 = glmm_load(mat[2]); /* l k j i */ r3 = glmm_load(mat[3]); /* p o n m */ a1 = vzipq_f32(r0, r2); /* l d k c, j b i a */ a2 = vzipq_f32(r1, r3); /* p h o g, n f m e */ a3 = vzipq_f32(a2.val[0], a1.val[0]); /* j n b f, i m a e */ a4 = vzipq_f32(a2.val[1], a1.val[1]); /* l p d h, k o c g */ v0 = vextq_f32(a1.val[0], a1.val[1], 2); /* k c j b */ v1 = vextq_f32(a2.val[0], a2.val[1], 2); /* o g n f */ v2 = vextq_f32(a1.val[1], a2.val[0], 2); /* m e l d */ v3 = vextq_f32(a2.val[1], a1.val[0], 2); /* i a p h */ v4 = vextq_f32(v1, v2, 2); /* l d o g */ v5 = vextq_f32(v0, v3, 2); /* p h k c */ /* c2 = c * h - g * d c12 = a * g - c * e c8 = a * f - b * e c1 = k * p - o * l c11 = i * o - k * m c7 = i * n - j * m c4 = h * a - d * e c6 = b * h - d * f c10 = b * g - c * f c3 = p * i - l * m c5 = j * p - l * n c9 = j * o - k * n */ t0 = vmulq_f32(v5, v3); t1 = vmulq_f32(a1.val[0], a2.val[1]); t2 = vmulq_f32(a1.val[0], v1); t0 = glmm_fnmadd(v4, v2, t0); t1 = glmm_fnmadd(a1.val[1], a2.val[0], t1); t2 = glmm_fnmadd(v0, a2.val[0], t2); t0 = vrev64q_f32(t0); t1 = vrev64q_f32(t1); t2 = vrev64q_f32(t2); /* det */ v0 = vrev64q_f32(t2); v1 = vextq_f32(t1, t1, 2); v0 = vmulq_f32(t0, v0); v1 = vrev64q_f32(v1); v1 = vmulq_f32(v1, t1); /* c3 * c10 + c4 * c9 + c1 * c8 + c2 * c7 */ #if CGLM_ARM64 v0 = vpaddq_f32(v0, v0); v0 = vpaddq_f32(v0, v0); #else l0 = vget_low_f32(v0); l1 = vget_high_f32(v0); l0 = vpadd_f32(l0, l0); /* [a+b, a+b] */ l1 = vpadd_f32(l1, l1); /* [c+d, c+d] */ l0 = vadd_f32(l0, l1); /* [sum, sum] */ v0 = vcombine_f32(l0, l0); #endif /* c5 * c12 + c6 * c11 */ #if CGLM_ARM64 v1 = vpaddq_f32(v1, v1); #else l0 = vget_low_f32(v1); l1 = vget_high_f32(v1); l0 = vpadd_f32(l0, l0); /* [a+b, a+b] */ l1 = vpadd_f32(l1, l1); /* [c+d, c+d] */ v1 = vcombine_f32(l0, l1); #endif v0 = vsubq_f32(v0, v1); /* det */ /* inv div */ v1 = vdupq_n_f32(1.0f); v0 = glmm_div(v1, v0); /* inv div */ /* multiply t0,t1,t2 by idt to reduce 1mul below: 2eor+4mul vs 3mul+4eor */ t0 = vmulq_f32(t0, v0); t1 = vmulq_f32(t1, v0); t2 = vmulq_f32(t2, v0); a0 = vzipq_f32(t0, t0); /* c4 c4 c3 c3, c2 c2 c1 c1 */ a1 = vzipq_f32(t1, t1); /* c6 c6 c5 c5, c12 c12 c11 c11 */ a2 = vzipq_f32(t2, t2); /* c10 c10 c9 c9, c8 c8 c7 c7 */ /* result */ /* dest[0][0] = (f * c1 - g * c5 + h * c9) * idt; dest[0][1] = (b * c1 - c * c5 + d * c9) * ndt; dest[0][2] = (n * c2 - o * c6 + p * c10) * idt; dest[0][3] = (j * c2 - k * c6 + l * c10) * ndt; dest[1][0] = (e * c1 - g * c3 + h * c11) * ndt; dest[1][1] = (a * c1 - c * c3 + d * c11) * idt; dest[1][2] = (m * c2 - o * c4 + p * c12) * ndt; dest[1][3] = (i * c2 - k * c4 + l * c12) * idt; dest[2][0] = (e * c5 - f * c3 + h * c7) * idt; dest[2][1] = (a * c5 - b * c3 + d * c7) * ndt; dest[2][2] = (m * c6 - n * c4 + p * c8) * idt; dest[2][3] = (i * c6 - j * c4 + l * c8) * ndt; dest[3][0] = (e * c9 - f * c11 + g * c7) * ndt; dest[3][1] = (a * c9 - b * c11 + c * c7) * idt; dest[3][2] = (m * c10 - n * c12 + o * c8) * ndt; dest[3][3] = (i * c10 - j * c12 + k * c8) * idt; */ r0 = vmulq_f32(a3.val[1], a0.val[0]); r1 = vmulq_f32(a3.val[0], a0.val[0]); r2 = vmulq_f32(a3.val[0], a1.val[1]); r3 = vmulq_f32(a3.val[0], a2.val[1]); r0 = glmm_fnmadd(a4.val[0], a1.val[1], r0); r1 = glmm_fnmadd(a4.val[0], a0.val[1], r1); r2 = glmm_fnmadd(a3.val[1], a0.val[1], r2); r3 = glmm_fnmadd(a3.val[1], a1.val[0], r3); r0 = glmm_fmadd(a4.val[1], a2.val[1], r0); r1 = glmm_fmadd(a4.val[1], a1.val[0], r1); r2 = glmm_fmadd(a4.val[1], a2.val[0], r2); r3 = glmm_fmadd(a4.val[0], a2.val[0], r3); /* 4xor may be fastart then 4mul, see above */ r0 = glmm_xor(r0, s1); r1 = glmm_xor(r1, s2); r2 = glmm_xor(r2, s1); r3 = glmm_xor(r3, s2); glmm_store(dest[0], r0); glmm_store(dest[1], r1); glmm_store(dest[2], r2); glmm_store(dest[3], r3); } #endif #endif /* cglm_mat4_neon_h */ cglm-0.9.7/include/cglm/simd/neon/quat.h000066400000000000000000000024451526744317200200540ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_quat_neon_h #define cglm_quat_neon_h #if defined(CGLM_NEON_FP) #include "../../common.h" #include "../intrin.h" CGLM_INLINE void glm_quat_mul_neon(versor p, versor q, versor dest) { /* + (a1 b2 + b1 a2 + c1 d2 − d1 c2)i + (a1 c2 − b1 d2 + c1 a2 + d1 b2)j + (a1 d2 + b1 c2 − c1 b2 + d1 a2)k a1 a2 − b1 b2 − c1 c2 − d1 d2 */ glmm_128 xp, xq, xqr, r, x, y, z, s2, s3; glmm_128 s1 = glmm_float32x4_SIGNMASK_NPPN; float32x2_t qh, ql; xp = glmm_load(p); /* 3 2 1 0 */ xq = glmm_load(q); r = vmulq_f32(glmm_splat_w(xp), xq); x = glmm_splat_x(xp); y = glmm_splat_y(xp); z = glmm_splat_z(xp); ql = vget_high_f32(s1); s3 = vcombine_f32(ql, ql); s2 = vzipq_f32(s3, s3).val[0]; xqr = vrev64q_f32(xq); qh = vget_high_f32(xqr); ql = vget_low_f32(xqr); r = glmm_fmadd(glmm_xor(x, s3), vcombine_f32(qh, ql), r); r = glmm_fmadd(glmm_xor(y, s2), vcombine_f32(vget_high_f32(xq), vget_low_f32(xq)), r); r = glmm_fmadd(glmm_xor(z, s1), vcombine_f32(ql, qh), r); glmm_store(dest, r); } #endif #endif /* cglm_quat_neon_h */ cglm-0.9.7/include/cglm/simd/sse2/000077500000000000000000000000001526744317200166415ustar00rootroot00000000000000cglm-0.9.7/include/cglm/simd/sse2/affine.h000066400000000000000000000054071526744317200202500ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_affine_mat_sse2_h #define cglm_affine_mat_sse2_h #if defined( __SSE__ ) || defined( __SSE2__ ) #include "../../common.h" #include "../intrin.h" CGLM_INLINE void glm_mul_sse2(mat4 m1, mat4 m2, mat4 dest) { /* D = R * L (Column-Major) */ glmm_128 l, r0, r1, r2, r3, v0, v1, v2, v3; l = glmm_load(m1[0]); r0 = glmm_load(m2[0]); r1 = glmm_load(m2[1]); r2 = glmm_load(m2[2]); r3 = glmm_load(m2[3]); v0 = _mm_mul_ps(glmm_splat_x(r0), l); v1 = _mm_mul_ps(glmm_splat_x(r1), l); v2 = _mm_mul_ps(glmm_splat_x(r2), l); v3 = _mm_mul_ps(glmm_splat_x(r3), l); l = glmm_load(m1[1]); v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); v3 = glmm_fmadd(glmm_splat_y(r3), l, v3); l = glmm_load(m1[2]); v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); v3 = glmm_fmadd(glmm_splat_z(r3), l, v3); l = glmm_load(m1[3]); v3 = glmm_fmadd(glmm_splat_w(r3), l, v3); glmm_store(dest[0], v0); glmm_store(dest[1], v1); glmm_store(dest[2], v2); glmm_store(dest[3], v3); } CGLM_INLINE void glm_mul_rot_sse2(mat4 m1, mat4 m2, mat4 dest) { /* D = R * L (Column-Major) */ glmm_128 l, r0, r1, r2, v0, v1, v2; l = glmm_load(m1[0]); r0 = glmm_load(m2[0]); r1 = glmm_load(m2[1]); r2 = glmm_load(m2[2]); v0 = _mm_mul_ps(glmm_splat_x(r0), l); v1 = _mm_mul_ps(glmm_splat_x(r1), l); v2 = _mm_mul_ps(glmm_splat_x(r2), l); l = glmm_load(m1[1]); v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); l = glmm_load(m1[2]); v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); glmm_store(dest[0], v0); glmm_store(dest[1], v1); glmm_store(dest[2], v2); glmm_store(dest[3], glmm_load(m1[3])); } CGLM_INLINE void glm_inv_tr_sse2(mat4 mat) { __m128 r0, r1, r2, r3, x0, x1, x2, x3, x4, x5; r0 = glmm_load(mat[0]); r1 = glmm_load(mat[1]); r2 = glmm_load(mat[2]); r3 = glmm_load(mat[3]); x1 = _mm_set_ps(1.0f, 0.0f, 0.0f, 0.0f); _MM_TRANSPOSE4_PS(r0, r1, r2, x1); x2 = glmm_shuff1(r3, 0, 0, 0, 0); x3 = glmm_shuff1(r3, 1, 1, 1, 1); x4 = glmm_shuff1(r3, 2, 2, 2, 2); x5 = glmm_float32x4_SIGNMASK_NEG; x0 = glmm_fmadd(r0, x2, glmm_fmadd(r1, x3, _mm_mul_ps(r2, x4))); x0 = _mm_xor_ps(x0, x5); x0 = _mm_add_ps(x0, x1); glmm_store(mat[0], r0); glmm_store(mat[1], r1); glmm_store(mat[2], r2); glmm_store(mat[3], x0); } #endif #endif /* cglm_affine_mat_sse2_h */ cglm-0.9.7/include/cglm/simd/sse2/mat2.h000066400000000000000000000017641526744317200176650ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_mat2_sse_h #define cglm_mat2_sse_h #if defined( __SSE__ ) || defined( __SSE2__ ) #include "../../common.h" #include "../intrin.h" CGLM_INLINE void glm_mat2_mul_sse2(mat2 m1, mat2 m2, mat2 dest) { __m128 x0, x1, x2, x3, x4; x1 = glmm_load(m1[0]); /* d c b a */ x2 = glmm_load(m2[0]); /* h g f e */ x3 = glmm_shuff1(x2, 2, 2, 0, 0); x4 = glmm_shuff1(x2, 3, 3, 1, 1); x0 = _mm_movelh_ps(x1, x1); x2 = _mm_movehl_ps(x1, x1); /* dest[0][0] = a * e + c * f; dest[0][1] = b * e + d * f; dest[1][0] = a * g + c * h; dest[1][1] = b * g + d * h; */ x0 = glmm_fmadd(x0, x3, _mm_mul_ps(x2, x4)); glmm_store(dest[0], x0); } CGLM_INLINE void glm_mat2_transp_sse2(mat2 m, mat2 dest) { /* d c b a */ /* d b c a */ glmm_store(dest[0], glmm_shuff1(glmm_load(m[0]), 3, 1, 2, 0)); } #endif #endif /* cglm_mat2_sse_h */ cglm-0.9.7/include/cglm/simd/sse2/mat3.h000066400000000000000000000055321526744317200176630ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_mat3_sse_h #define cglm_mat3_sse_h #if defined( __SSE__ ) || defined( __SSE2__ ) #include "../../common.h" #include "../intrin.h" CGLM_INLINE void glm_mat3_mul_sse2(mat3 m1, mat3 m2, mat3 dest) { __m128 l0, l1, l2, r0, r1, r2, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9; l0 = _mm_loadu_ps(m1[0]); l1 = _mm_loadu_ps(&m1[1][1]); r0 = _mm_loadu_ps(m2[0]); r1 = _mm_loadu_ps(&m2[1][1]); x8 = glmm_shuff1(l0, 0, 2, 1, 0); /* a00 a02 a01 a00 */ x1 = glmm_shuff1(r0, 3, 0, 0, 0); /* b10 b00 b00 b00 */ x2 = _mm_shuffle_ps(l0, l1, _MM_SHUFFLE(1, 0, 3, 3)); /* a12 a11 a10 a10 */ x3 = _mm_shuffle_ps(r0, r1, _MM_SHUFFLE(2, 0, 3, 1)); /* b20 b11 b10 b01 */ x0 = _mm_mul_ps(x8, x1); x6 = glmm_shuff1(l0, 1, 0, 2, 1); /* a01 a00 a02 a01 */ x7 = glmm_shuff1(x3, 3, 3, 1, 1); /* b20 b20 b10 b10 */ l2 = _mm_load_ss(&m1[2][2]); r2 = _mm_load_ss(&m2[2][2]); x1 = _mm_mul_ps(x6, x7); l2 = glmm_shuff1(l2, 0, 0, 1, 0); /* a22 a22 0.f a22 */ r2 = glmm_shuff1(r2, 0, 0, 1, 0); /* b22 b22 0.f b22 */ x4 = glmm_shuff1(x2, 0, 3, 2, 0); /* a10 a12 a11 a10 */ x5 = glmm_shuff1(x2, 2, 0, 3, 2); /* a11 a10 a12 a11 */ x6 = glmm_shuff1(x3, 2, 0, 0, 0); /* b11 b01 b01 b01 */ x2 = glmm_shuff1(r1, 3, 3, 0, 0); /* b21 b21 b11 b11 */ x8 = _mm_unpackhi_ps(x8, x4); /* a10 a00 a12 a02 */ x9 = _mm_unpackhi_ps(x7, x2); /* b21 b20 b21 b20 */ x0 = glmm_fmadd(x4, x6, x0); x1 = glmm_fmadd(x5, x2, x1); x2 = _mm_movehl_ps(l2, l1); /* a22 a22 a21 a20 */ x3 = glmm_shuff1(x2, 0, 2, 1, 0); /* a20 a22 a21 a20 */ x2 = glmm_shuff1(x2, 1, 0, 2, 1); /* a21 a20 a22 a21 */ x4 = _mm_shuffle_ps(r0, r1, _MM_SHUFFLE(1, 1, 2, 2)); /* b12 b12 b02 b02 */ x5 = glmm_shuff1(x4, 3, 0, 0, 0); /* b12 b02 b02 b02 */ x4 = _mm_movehl_ps(r2, x4); /* b22 b22 b12 b12 */ x0 = glmm_fmadd(x3, x5, x0); x1 = glmm_fmadd(x2, x4, x1); /* Dot Product : dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22 + 0 * 00 */ x2 = _mm_movelh_ps(x8, l2); /* 0.f a22 a12 a02 */ x3 = _mm_movelh_ps(x9, r2); /* 0.f b22 b21 b20 */ x2 = glmm_vdots(x2, x3); _mm_storeu_ps(&dest[0][0], x0); _mm_storeu_ps(&dest[1][1], x1); _mm_store_ss (&dest[2][2], x2); } #endif #endif /* cglm_mat3_sse_h */ cglm-0.9.7/include/cglm/simd/sse2/mat4.h000066400000000000000000000421461526744317200176660ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_mat_sse_h #define cglm_mat_sse_h #if defined( __SSE__ ) || defined( __SSE2__ ) #include "../../common.h" #include "../intrin.h" #define glm_mat4_inv_precise_sse2(mat, dest) glm_mat4_inv_sse2(mat, dest) CGLM_INLINE void glm_mat4_scale_sse2(mat4 m, float s) { __m128 x0; x0 = glmm_set1(s); glmm_store(m[0], _mm_mul_ps(glmm_load(m[0]), x0)); glmm_store(m[1], _mm_mul_ps(glmm_load(m[1]), x0)); glmm_store(m[2], _mm_mul_ps(glmm_load(m[2]), x0)); glmm_store(m[3], _mm_mul_ps(glmm_load(m[3]), x0)); } CGLM_INLINE void glm_mat4_transp_sse2(mat4 m, mat4 dest) { __m128 r0, r1, r2, r3; r0 = glmm_load(m[0]); r1 = glmm_load(m[1]); r2 = glmm_load(m[2]); r3 = glmm_load(m[3]); _MM_TRANSPOSE4_PS(r0, r1, r2, r3); glmm_store(dest[0], r0); glmm_store(dest[1], r1); glmm_store(dest[2], r2); glmm_store(dest[3], r3); } CGLM_INLINE void glm_mat4_mul_sse2(mat4 m1, mat4 m2, mat4 dest) { /* D = R * L (Column-Major) */ glmm_128 l, r0, r1, r2, r3, v0, v1, v2, v3; l = glmm_load(m1[0]); r0 = glmm_load(m2[0]); r1 = glmm_load(m2[1]); r2 = glmm_load(m2[2]); r3 = glmm_load(m2[3]); v0 = _mm_mul_ps(glmm_splat_x(r0), l); v1 = _mm_mul_ps(glmm_splat_x(r1), l); v2 = _mm_mul_ps(glmm_splat_x(r2), l); v3 = _mm_mul_ps(glmm_splat_x(r3), l); l = glmm_load(m1[1]); v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); v3 = glmm_fmadd(glmm_splat_y(r3), l, v3); l = glmm_load(m1[2]); v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); v3 = glmm_fmadd(glmm_splat_z(r3), l, v3); l = glmm_load(m1[3]); v0 = glmm_fmadd(glmm_splat_w(r0), l, v0); v1 = glmm_fmadd(glmm_splat_w(r1), l, v1); v2 = glmm_fmadd(glmm_splat_w(r2), l, v2); v3 = glmm_fmadd(glmm_splat_w(r3), l, v3); glmm_store(dest[0], v0); glmm_store(dest[1], v1); glmm_store(dest[2], v2); glmm_store(dest[3], v3); } CGLM_INLINE void glm_mat4_mulv_sse2(mat4 m, vec4 v, vec4 dest) { __m128 x0, x1, m0, m1, m2, m3, v0, v1, v2, v3; m0 = glmm_load(m[0]); m1 = glmm_load(m[1]); m2 = glmm_load(m[2]); m3 = glmm_load(m[3]); x0 = glmm_load(v); v0 = glmm_splat_x(x0); v1 = glmm_splat_y(x0); v2 = glmm_splat_z(x0); v3 = glmm_splat_w(x0); x1 = _mm_mul_ps(m3, v3); x1 = glmm_fmadd(m2, v2, x1); x1 = glmm_fmadd(m1, v1, x1); x1 = glmm_fmadd(m0, v0, x1); glmm_store(dest, x1); } CGLM_INLINE float glm_mat4_det_sse2(mat4 mat) { __m128 r0, r1, r2, r3, x0, x1, x2; /* 127 <- 0, [square] det(A) = det(At) */ r0 = glmm_load(mat[0]); /* d c b a */ r1 = glmm_load(mat[1]); /* h g f e */ r2 = glmm_load(mat[2]); /* l k j i */ r3 = glmm_load(mat[3]); /* p o n m */ /* t[1] = j * p - n * l; t[2] = j * o - n * k; t[3] = i * p - m * l; t[4] = i * o - m * k; */ x0 = glmm_fnmadd(glmm_shuff1(r3, 0, 0, 1, 1), glmm_shuff1(r2, 2, 3, 2, 3), _mm_mul_ps(glmm_shuff1(r2, 0, 0, 1, 1), glmm_shuff1(r3, 2, 3, 2, 3))); /* t[0] = k * p - o * l; t[0] = k * p - o * l; t[5] = i * n - m * j; t[5] = i * n - m * j; */ x1 = glmm_fnmadd(glmm_shuff1(r3, 0, 0, 2, 2), glmm_shuff1(r2, 1, 1, 3, 3), _mm_mul_ps(glmm_shuff1(r2, 0, 0, 2, 2), glmm_shuff1(r3, 1, 1, 3, 3))); /* a * (f * t[0] - g * t[1] + h * t[2]) - b * (e * t[0] - g * t[3] + h * t[4]) + c * (e * t[1] - f * t[3] + h * t[5]) - d * (e * t[2] - f * t[4] + g * t[5]) */ x2 = glmm_fnmadd(glmm_shuff1(r1, 1, 1, 2, 2), glmm_shuff1(x0, 3, 2, 2, 0), _mm_mul_ps(glmm_shuff1(r1, 0, 0, 0, 1), _mm_shuffle_ps(x1, x0, _MM_SHUFFLE(1, 0, 0, 0)))); x2 = glmm_fmadd(glmm_shuff1(r1, 2, 3, 3, 3), _mm_shuffle_ps(x0, x1, _MM_SHUFFLE(2, 2, 3, 1)), x2); x2 = _mm_xor_ps(x2, glmm_float32x4_SIGNMASK_NPNP); return glmm_hadd(_mm_mul_ps(x2, r0)); } CGLM_INLINE void glm_mat4_inv_fast_sse2(mat4 mat, mat4 dest) { __m128 r0, r1, r2, r3, v0, v1, v2, v3, t0, t1, t2, t3, t4, t5, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9; /* x8 = _mm_set_ps(-0.f, 0.f, -0.f, 0.f); */ x8 = glmm_float32x4_SIGNMASK_NPNP; x9 = glmm_shuff1(x8, 2, 1, 2, 1); /* 127 <- 0 */ r0 = glmm_load(mat[0]); /* d c b a */ r1 = glmm_load(mat[1]); /* h g f e */ r2 = glmm_load(mat[2]); /* l k j i */ r3 = glmm_load(mat[3]); /* p o n m */ x0 = _mm_movehl_ps(r3, r2); /* p o l k */ x3 = _mm_movelh_ps(r2, r3); /* n m j i */ x1 = glmm_shuff1(x0, 1, 3, 3 ,3); /* l p p p */ x2 = glmm_shuff1(x0, 0, 2, 2, 2); /* k o o o */ x4 = glmm_shuff1(x3, 1, 3, 3, 3); /* j n n n */ x7 = glmm_shuff1(x3, 0, 2, 2, 2); /* i m m m */ x6 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(0, 0, 0, 0)); /* e e i i */ x5 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(1, 1, 1, 1)); /* f f j j */ x3 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(2, 2, 2, 2)); /* g g k k */ x0 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(3, 3, 3, 3)); /* h h l l */ t0 = _mm_mul_ps(x3, x1); t1 = _mm_mul_ps(x5, x1); t2 = _mm_mul_ps(x5, x2); t3 = _mm_mul_ps(x6, x1); t4 = _mm_mul_ps(x6, x2); t5 = _mm_mul_ps(x6, x4); /* t1[0] = k * p - o * l; t1[0] = k * p - o * l; t2[0] = g * p - o * h; t3[0] = g * l - k * h; */ t0 = glmm_fnmadd(x2, x0, t0); /* t1[1] = j * p - n * l; t1[1] = j * p - n * l; t2[1] = f * p - n * h; t3[1] = f * l - j * h; */ t1 = glmm_fnmadd(x4, x0, t1); /* t1[2] = j * o - n * k t1[2] = j * o - n * k; t2[2] = f * o - n * g; t3[2] = f * k - j * g; */ t2 = glmm_fnmadd(x4, x3, t2); /* t1[3] = i * p - m * l; t1[3] = i * p - m * l; t2[3] = e * p - m * h; t3[3] = e * l - i * h; */ t3 = glmm_fnmadd(x7, x0, t3); /* t1[4] = i * o - m * k; t1[4] = i * o - m * k; t2[4] = e * o - m * g; t3[4] = e * k - i * g; */ t4 = glmm_fnmadd(x7, x3, t4); /* t1[5] = i * n - m * j; t1[5] = i * n - m * j; t2[5] = e * n - m * f; t3[5] = e * j - i * f; */ t5 = glmm_fnmadd(x7, x5, t5); x4 = _mm_movelh_ps(r0, r1); /* f e b a */ x5 = _mm_movehl_ps(r1, r0); /* h g d c */ x0 = glmm_shuff1(x4, 0, 0, 0, 2); /* a a a e */ x1 = glmm_shuff1(x4, 1, 1, 1, 3); /* b b b f */ x2 = glmm_shuff1(x5, 0, 0, 0, 2); /* c c c g */ x3 = glmm_shuff1(x5, 1, 1, 1, 3); /* d d d h */ v2 = _mm_mul_ps(x0, t1); v1 = _mm_mul_ps(x0, t0); v3 = _mm_mul_ps(x0, t2); v0 = _mm_mul_ps(x1, t0); v2 = glmm_fnmadd(x1, t3, v2); v3 = glmm_fnmadd(x1, t4, v3); v0 = glmm_fnmadd(x2, t1, v0); v1 = glmm_fnmadd(x2, t3, v1); v3 = glmm_fmadd(x2, t5, v3); v0 = glmm_fmadd(x3, t2, v0); v2 = glmm_fmadd(x3, t5, v2); v1 = glmm_fmadd(x3, t4, v1); /* dest[0][0] = f * t1[0] - g * t1[1] + h * t1[2]; dest[0][1] =-(b * t1[0] - c * t1[1] + d * t1[2]); dest[0][2] = b * t2[0] - c * t2[1] + d * t2[2]; dest[0][3] =-(b * t3[0] - c * t3[1] + d * t3[2]); */ v0 = _mm_xor_ps(v0, x8); /* dest[2][0] = e * t1[1] - f * t1[3] + h * t1[5]; dest[2][1] =-(a * t1[1] - b * t1[3] + d * t1[5]); dest[2][2] = a * t2[1] - b * t2[3] + d * t2[5]; dest[2][3] =-(a * t3[1] - b * t3[3] + d * t3[5]);*/ v2 = _mm_xor_ps(v2, x8); /* dest[1][0] =-(e * t1[0] - g * t1[3] + h * t1[4]); dest[1][1] = a * t1[0] - c * t1[3] + d * t1[4]; dest[1][2] =-(a * t2[0] - c * t2[3] + d * t2[4]); dest[1][3] = a * t3[0] - c * t3[3] + d * t3[4]; */ v1 = _mm_xor_ps(v1, x9); /* dest[3][0] =-(e * t1[2] - f * t1[4] + g * t1[5]); dest[3][1] = a * t1[2] - b * t1[4] + c * t1[5]; dest[3][2] =-(a * t2[2] - b * t2[4] + c * t2[5]); dest[3][3] = a * t3[2] - b * t3[4] + c * t3[5]; */ v3 = _mm_xor_ps(v3, x9); /* determinant */ x0 = _mm_shuffle_ps(v0, v1, _MM_SHUFFLE(0, 0, 0, 0)); x1 = _mm_shuffle_ps(v2, v3, _MM_SHUFFLE(0, 0, 0, 0)); x0 = _mm_shuffle_ps(x0, x1, _MM_SHUFFLE(2, 0, 2, 0)); x0 = _mm_rcp_ps(glmm_vhadd(_mm_mul_ps(x0, r0))); glmm_store(dest[0], _mm_mul_ps(v0, x0)); glmm_store(dest[1], _mm_mul_ps(v1, x0)); glmm_store(dest[2], _mm_mul_ps(v2, x0)); glmm_store(dest[3], _mm_mul_ps(v3, x0)); } /* old one */ #if 0 CGLM_INLINE void glm_mat4_inv_sse2(mat4 mat, mat4 dest) { __m128 r0, r1, r2, r3, v0, v1, v2, v3, t0, t1, t2, t3, t4, t5, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9; /* x8 = _mm_set_ps(-0.f, 0.f, -0.f, 0.f); */ x8 = glmm_float32x4_SIGNMASK_NPNP; x9 = glmm_shuff1(x8, 2, 1, 2, 1); /* 127 <- 0 */ r0 = glmm_load(mat[0]); /* d c b a */ r1 = glmm_load(mat[1]); /* h g f e */ r2 = glmm_load(mat[2]); /* l k j i */ r3 = glmm_load(mat[3]); /* p o n m */ x0 = _mm_movehl_ps(r3, r2); /* p o l k */ x3 = _mm_movelh_ps(r2, r3); /* n m j i */ x1 = glmm_shuff1(x0, 1, 3, 3 ,3); /* l p p p */ x2 = glmm_shuff1(x0, 0, 2, 2, 2); /* k o o o */ x4 = glmm_shuff1(x3, 1, 3, 3, 3); /* j n n n */ x7 = glmm_shuff1(x3, 0, 2, 2, 2); /* i m m m */ x6 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(0, 0, 0, 0)); /* e e i i */ x5 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(1, 1, 1, 1)); /* f f j j */ x3 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(2, 2, 2, 2)); /* g g k k */ x0 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(3, 3, 3, 3)); /* h h l l */ t0 = _mm_mul_ps(x3, x1); t1 = _mm_mul_ps(x5, x1); t2 = _mm_mul_ps(x5, x2); t3 = _mm_mul_ps(x6, x1); t4 = _mm_mul_ps(x6, x2); t5 = _mm_mul_ps(x6, x4); /* t1[0] = k * p - o * l; t1[0] = k * p - o * l; t2[0] = g * p - o * h; t3[0] = g * l - k * h; */ t0 = glmm_fnmadd(x2, x0, t0); /* t1[1] = j * p - n * l; t1[1] = j * p - n * l; t2[1] = f * p - n * h; t3[1] = f * l - j * h; */ t1 = glmm_fnmadd(x4, x0, t1); /* t1[2] = j * o - n * k t1[2] = j * o - n * k; t2[2] = f * o - n * g; t3[2] = f * k - j * g; */ t2 = glmm_fnmadd(x4, x3, t2); /* t1[3] = i * p - m * l; t1[3] = i * p - m * l; t2[3] = e * p - m * h; t3[3] = e * l - i * h; */ t3 = glmm_fnmadd(x7, x0, t3); /* t1[4] = i * o - m * k; t1[4] = i * o - m * k; t2[4] = e * o - m * g; t3[4] = e * k - i * g; */ t4 = glmm_fnmadd(x7, x3, t4); /* t1[5] = i * n - m * j; t1[5] = i * n - m * j; t2[5] = e * n - m * f; t3[5] = e * j - i * f; */ t5 = glmm_fnmadd(x7, x5, t5); x4 = _mm_movelh_ps(r0, r1); /* f e b a */ x5 = _mm_movehl_ps(r1, r0); /* h g d c */ x0 = glmm_shuff1(x4, 0, 0, 0, 2); /* a a a e */ x1 = glmm_shuff1(x4, 1, 1, 1, 3); /* b b b f */ x2 = glmm_shuff1(x5, 0, 0, 0, 2); /* c c c g */ x3 = glmm_shuff1(x5, 1, 1, 1, 3); /* d d d h */ v2 = _mm_mul_ps(x0, t1); v1 = _mm_mul_ps(x0, t0); v3 = _mm_mul_ps(x0, t2); v0 = _mm_mul_ps(x1, t0); v2 = glmm_fnmadd(x1, t3, v2); v3 = glmm_fnmadd(x1, t4, v3); v0 = glmm_fnmadd(x2, t1, v0); v1 = glmm_fnmadd(x2, t3, v1); v3 = glmm_fmadd(x2, t5, v3); v0 = glmm_fmadd(x3, t2, v0); v2 = glmm_fmadd(x3, t5, v2); v1 = glmm_fmadd(x3, t4, v1); /* dest[0][0] = f * t1[0] - g * t1[1] + h * t1[2]; dest[0][1] =-(b * t1[0] - c * t1[1] + d * t1[2]); dest[0][2] = b * t2[0] - c * t2[1] + d * t2[2]; dest[0][3] =-(b * t3[0] - c * t3[1] + d * t3[2]); */ v0 = _mm_xor_ps(v0, x8); /* dest[2][0] = e * t1[1] - f * t1[3] + h * t1[5]; dest[2][1] =-(a * t1[1] - b * t1[3] + d * t1[5]); dest[2][2] = a * t2[1] - b * t2[3] + d * t2[5]; dest[2][3] =-(a * t3[1] - b * t3[3] + d * t3[5]);*/ v2 = _mm_xor_ps(v2, x8); /* dest[1][0] =-(e * t1[0] - g * t1[3] + h * t1[4]); dest[1][1] = a * t1[0] - c * t1[3] + d * t1[4]; dest[1][2] =-(a * t2[0] - c * t2[3] + d * t2[4]); dest[1][3] = a * t3[0] - c * t3[3] + d * t3[4]; */ v1 = _mm_xor_ps(v1, x9); /* dest[3][0] =-(e * t1[2] - f * t1[4] + g * t1[5]); dest[3][1] = a * t1[2] - b * t1[4] + c * t1[5]; dest[3][2] =-(a * t2[2] - b * t2[4] + c * t2[5]); dest[3][3] = a * t3[2] - b * t3[4] + c * t3[5]; */ v3 = _mm_xor_ps(v3, x9); /* determinant */ x0 = _mm_shuffle_ps(v0, v1, _MM_SHUFFLE(0, 0, 0, 0)); x1 = _mm_shuffle_ps(v2, v3, _MM_SHUFFLE(0, 0, 0, 0)); x0 = _mm_shuffle_ps(x0, x1, _MM_SHUFFLE(2, 0, 2, 0)); x0 = _mm_div_ps(glmm_set1(1.0f), glmm_vhadd(_mm_mul_ps(x0, r0))); glmm_store(dest[0], _mm_mul_ps(v0, x0)); glmm_store(dest[1], _mm_mul_ps(v1, x0)); glmm_store(dest[2], _mm_mul_ps(v2, x0)); glmm_store(dest[3], _mm_mul_ps(v3, x0)); } #endif CGLM_INLINE void glm_mat4_inv_sse2(mat4 mat, mat4 dest) { __m128 r0, r1, r2, r3, s1, s2, v0, v1, v2, v3, v4, v5, t0, t1, t2, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13; /* s1 = _mm_set_ps(-0.f, 0.f, -0.f, 0.f); */ s1 = glmm_float32x4_SIGNMASK_NPNP; s2 = glmm_shuff1(s1, 2, 1, 2, 1); /* 127 <- 0 */ r1 = glmm_load(mat[1]); /* h g f e */ r0 = glmm_load(mat[0]); /* d c b a */ r3 = glmm_load(mat[3]); /* p o n m */ r2 = glmm_load(mat[2]); /* l k j i */ x4 = _mm_unpackhi_ps(r0, r2); /* l d k c */ x5 = _mm_unpacklo_ps(r0, r2); /* j b i a */ x6 = _mm_unpackhi_ps(r1, r3); /* p h o g */ x7 = _mm_unpacklo_ps(r1, r3); /* n f m e */ x0 = _mm_unpackhi_ps(x7, x5); /* j n b f */ x1 = _mm_unpacklo_ps(x7, x5); /* i m a e */ x2 = _mm_unpackhi_ps(x6, x4); /* l p d h */ x3 = _mm_unpacklo_ps(x6, x4); /* k o c g */ /* c2 = c * h - d * g c12 = a * g - c * e c8 = a * f - b * e c1 = k * p - l * o c11 = i * o - k * m c7 = i * n - j * m c4 = a * h - d * e c6 = b * h - d * f c10 = b * g - c * f c3 = i * p - l * m c5 = j * p - l * n c9 = j * o - k * n */ x8 = _mm_shuffle_ps(x0, x3, _MM_SHUFFLE(3, 1, 3, 1)); /* k c j b */ x9 = _mm_shuffle_ps(x0, x3, _MM_SHUFFLE(2, 0, 2, 0)); /* o g n f */ x10 = glmm_shuff1(x2, 2, 0, 2, 0); /* p h p h */ x11 = glmm_shuff1(x2, 3, 1, 3, 1); /* l d l d */ #if 0 /* TODO measure both */ x12 = _mm_shuffle_ps(x4, x5, _MM_SHUFFLE(1, 0, 1, 0)); /* i a k c */ x13 = _mm_shuffle_ps(x6, x7, _MM_SHUFFLE(1, 0, 1, 0)); /* m e o g */ #else x12 = _mm_movelh_ps(x4, x5); /* i a k c */ x13 = _mm_movelh_ps(x6, x7); /* m e o g */ #endif t0 = _mm_mul_ps(x12, x10); t1 = _mm_mul_ps(x5, x6); t2 = _mm_mul_ps(x5, x9); t0 = glmm_fnmadd(x11, x13, t0); t1 = glmm_fnmadd(x4, x7, t1); t2 = glmm_fnmadd(x8, x7, t2); /* det */ /* v0: c3 * c10 + c4 * c9 + c1 * c8 + c2 * c7 */ /* v1: c5 * c12 + c6 * c11 */ v5 = glmm_set1_rval(1.0f); v0 = glmm_shuff1(t2, 2, 3, 0, 1); v1 = glmm_shuff1(t1, 0, 1, 2, 3); v0 = _mm_mul_ps(t0, v0); v1 = _mm_mul_ps(t1, v1); v2 = glmm_shuff1(v1, 1, 0, 0, 1); v3 = glmm_shuff1(v0, 0, 1, 2, 3); v1 = _mm_add_ps(v1, v2); v0 = _mm_add_ps(v0, v3); v2 = glmm_shuff1(v0, 1, 0, 0, 1); v0 = _mm_add_ps(v0, v2); v0 = _mm_sub_ps(v0, v1); /* det */ v0 = _mm_div_ps(v5, v0); /* idt */ /* multiply t0,t1,t2 by idt to reduce 1mul below: 2eor+4mul vs 3mul+4eor */ t0 = _mm_mul_ps(t0, v0); t1 = _mm_mul_ps(t1, v0); t2 = _mm_mul_ps(t2, v0); v0 = glmm_shuff1(t0, 0, 0, 1, 1); /* c2 c2 c1 c1 */ v1 = glmm_shuff1(t0, 2, 2, 3, 3); /* c4 c4 c3 c3 */ v2 = glmm_shuff1(t1, 0, 0, 1, 1); /* c12 c12 c11 c11 */ v3 = glmm_shuff1(t1, 2, 2, 3, 3); /* c6 c6 c5 c5 */ v4 = glmm_shuff1(t2, 0, 0, 1, 1); /* c8 c8 c7 c7 */ v5 = glmm_shuff1(t2, 2, 2, 3, 3); /* c10 c10 c9 c9 */ /* result */ /* dest[0][0] = (f * c1 - g * c5 + h * c9) * idt; dest[0][1] = (b * c1 - c * c5 + d * c9) * ndt; dest[0][2] = (n * c2 - o * c6 + p * c10) * idt; dest[0][3] = (j * c2 - k * c6 + l * c10) * ndt; dest[1][0] = (e * c1 - g * c3 + h * c11) * ndt; dest[1][1] = (a * c1 - c * c3 + d * c11) * idt; dest[1][2] = (m * c2 - o * c4 + p * c12) * ndt; dest[1][3] = (i * c2 - k * c4 + l * c12) * idt; dest[2][0] = (e * c5 - f * c3 + h * c7) * idt; dest[2][1] = (a * c5 - b * c3 + d * c7) * ndt; dest[2][2] = (m * c6 - n * c4 + p * c8) * idt; dest[2][3] = (i * c6 - j * c4 + l * c8) * ndt; dest[3][0] = (e * c9 - f * c11 + g * c7) * ndt; dest[3][1] = (a * c9 - b * c11 + c * c7) * idt; dest[3][2] = (m * c10 - n * c12 + o * c8) * ndt; dest[3][3] = (i * c10 - j * c12 + k * c8) * idt; */ r0 = _mm_mul_ps(x0, v0); r1 = _mm_mul_ps(x1, v0); r2 = _mm_mul_ps(x1, v3); r3 = _mm_mul_ps(x1, v5); r0 = glmm_fnmadd(x3, v3, r0); r1 = glmm_fnmadd(x3, v1, r1); r2 = glmm_fnmadd(x0, v1, r2); r3 = glmm_fnmadd(x0, v2, r3); r0 = glmm_fmadd(x2, v5, r0); r1 = glmm_fmadd(x2, v2, r1); r2 = glmm_fmadd(x2, v4, r2); r3 = glmm_fmadd(x3, v4, r3); /* 4xor may be fastart then 4mul, see above */ r0 = _mm_xor_ps(r0, s1); r1 = _mm_xor_ps(r1, s2); r2 = _mm_xor_ps(r2, s1); r3 = _mm_xor_ps(r3, s2); glmm_store(dest[0], r0); glmm_store(dest[1], r1); glmm_store(dest[2], r2); glmm_store(dest[3], r3); } #endif #endif /* cglm_mat_sse_h */ cglm-0.9.7/include/cglm/simd/sse2/quat.h000066400000000000000000000023311526744317200177630ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_quat_simd_h #define cglm_quat_simd_h #if defined( __SSE__ ) || defined( __SSE2__ ) #include "../../common.h" #include "../intrin.h" CGLM_INLINE void glm_quat_mul_sse2(versor p, versor q, versor dest) { /* + (a1 b2 + b1 a2 + c1 d2 − d1 c2)i + (a1 c2 − b1 d2 + c1 a2 + d1 b2)j + (a1 d2 + b1 c2 − c1 b2 + d1 a2)k a1 a2 − b1 b2 − c1 c2 − d1 d2 */ __m128 xp, xq, x1, x2, x3, r, x, y, z; xp = glmm_load(p); /* 3 2 1 0 */ xq = glmm_load(q); x1 = glmm_float32x4_SIGNMASK_NPNP; /* TODO: _mm_set1_ss() + shuff ? */ r = _mm_mul_ps(glmm_splat_w(xp), xq); x2 = _mm_unpackhi_ps(x1, x1); x3 = glmm_shuff1(x1, 3, 2, 0, 1); x = glmm_splat_x(xp); y = glmm_splat_y(xp); z = glmm_splat_z(xp); x = _mm_xor_ps(x, x1); y = _mm_xor_ps(y, x2); z = _mm_xor_ps(z, x3); x1 = glmm_shuff1(xq, 0, 1, 2, 3); x2 = glmm_shuff1(xq, 1, 0, 3, 2); x3 = glmm_shuff1(xq, 2, 3, 0, 1); r = glmm_fmadd(x, x1, r); r = glmm_fmadd(y, x2, r); r = glmm_fmadd(z, x3, r); glmm_store(dest, r); } #endif #endif /* cglm_quat_simd_h */ cglm-0.9.7/include/cglm/simd/wasm.h000066400000000000000000000116251526744317200171120ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_simd_wasm_h #define cglm_simd_wasm_h #include "intrin.h" #ifdef CGLM_SIMD_WASM #include #define glmm_load(p) wasm_v128_load(p) #define glmm_store(p, a) wasm_v128_store(p, (a)) #define glmm_set1(x) wasm_f32x4_splat(x) #define glmm_set1_ptr(x) wasm_f32x4_splat(*x) #define glmm_set1_rval(x) wasm_f32x4_splat(x) #define glmm_128 v128_t #define glmm_shuff1(xmm, z, y, x, w) wasm_i32x4_shuffle(xmm, xmm, w, x, y, z) #define glmm_splat(x, lane) glmm_shuff1(x, lane, lane, lane, lane) #define glmm_splat_x(x) glmm_splat(x, 0) #define glmm_splat_y(x) glmm_splat(x, 1) #define glmm_splat_z(x) glmm_splat(x, 2) #define glmm_splat_w(x) glmm_splat(x, 3) #define GLMM_NEGZEROf 0x80000000 /* 0x80000000 ---> -0.0f */ /* _mm_set_ps(X, Y, Z, W); */ #define GLMM__SIGNMASKf(X, Y, Z, W) wasm_i32x4_const(X, Y, Z, W) #define glmm_float32x4_SIGNMASK_PNPN GLMM__SIGNMASKf(0, GLMM_NEGZEROf, 0, GLMM_NEGZEROf) #define glmm_float32x4_SIGNMASK_NPNP GLMM__SIGNMASKf(GLMM_NEGZEROf, 0, GLMM_NEGZEROf, 0) #define glmm_float32x4_SIGNMASK_NPPN GLMM__SIGNMASKf(GLMM_NEGZEROf, 0, 0, GLMM_NEGZEROf) #define glmm_float32x4_SIGNMASK_NEG wasm_i32x4_const_splat(GLMM_NEGZEROf) static inline glmm_128 glmm_abs(glmm_128 x) { return wasm_f32x4_abs(x); } static inline glmm_128 glmm_min(glmm_128 a, glmm_128 b) { return wasm_f32x4_pmin(b, a); } static inline glmm_128 glmm_max(glmm_128 a, glmm_128 b) { return wasm_f32x4_pmax(b, a); } static inline glmm_128 glmm_vhadd(glmm_128 v) { glmm_128 x0; x0 = wasm_f32x4_add(v, glmm_shuff1(v, 0, 1, 2, 3)); x0 = wasm_f32x4_add(x0, glmm_shuff1(x0, 1, 0, 0, 1)); return x0; } static inline glmm_128 glmm_vhadds(glmm_128 v) { glmm_128 shuf, sums; shuf = glmm_shuff1(v, 2, 3, 0, 1); sums = wasm_f32x4_add(v, shuf); /* shuf = _mm_movehl_ps(shuf, sums); */ shuf = wasm_i32x4_shuffle(shuf, sums, 6, 7, 2, 3); sums = wasm_i32x4_shuffle(sums, wasm_f32x4_add(sums, shuf), 4, 1, 2, 3); return sums; } static inline float glmm_hadd(glmm_128 v) { return wasm_f32x4_extract_lane(glmm_vhadds(v), 0); } static inline glmm_128 glmm_vhmin(glmm_128 v) { glmm_128 x0, x1, x2; x0 = glmm_shuff1(v, 2, 3, 2, 3); /* [2, 3, 2, 3] */ x1 = wasm_f32x4_pmin(x0, v); /* [0|2, 1|3, 2|2, 3|3] */ x2 = glmm_splat(x1, 1); /* [1|3, 1|3, 1|3, 1|3] */ return wasm_f32x4_pmin(x1, x2); } static inline float glmm_hmin(glmm_128 v) { return wasm_f32x4_extract_lane(glmm_vhmin(v), 0); } static inline glmm_128 glmm_vhmax(glmm_128 v) { glmm_128 x0, x1, x2; x0 = glmm_shuff1(v, 2, 3, 2, 3); /* [2, 3, 2, 3] */ x1 = wasm_f32x4_pmax(x0, v); /* [0|2, 1|3, 2|2, 3|3] */ x2 = glmm_splat(x1, 1); /* [1|3, 1|3, 1|3, 1|3] */ /* _mm_max_ss */ return wasm_i32x4_shuffle(x1, wasm_f32x4_pmax(x1, x2), 4, 1, 2, 3); } static inline float glmm_hmax(glmm_128 v) { return wasm_f32x4_extract_lane(glmm_vhmax(v), 0); } static inline glmm_128 glmm_vdots(glmm_128 a, glmm_128 b) { return glmm_vhadds(wasm_f32x4_mul(a, b)); } static inline glmm_128 glmm_vdot(glmm_128 a, glmm_128 b) { glmm_128 x0; x0 = wasm_f32x4_mul(a, b); x0 = wasm_f32x4_add(x0, glmm_shuff1(x0, 1, 0, 3, 2)); return wasm_f32x4_add(x0, glmm_shuff1(x0, 0, 1, 0, 1)); } static inline float glmm_dot(glmm_128 a, glmm_128 b) { return wasm_f32x4_extract_lane(glmm_vdots(a, b), 0); } static inline float glmm_norm(glmm_128 a) { glmm_128 x0; x0 = glmm_vhadds(wasm_f32x4_mul(a, a)); return wasm_f32x4_extract_lane( wasm_i32x4_shuffle(x0, wasm_f32x4_sqrt(x0),4, 1, 2, 3), 0); } static inline float glmm_norm2(glmm_128 a) { return wasm_f32x4_extract_lane(glmm_vhadds(wasm_f32x4_mul(a, a)), 0); } static inline float glmm_norm_one(glmm_128 a) { return wasm_f32x4_extract_lane(glmm_vhadds(glmm_abs(a)), 0); } static inline float glmm_norm_inf(glmm_128 a) { return wasm_f32x4_extract_lane(glmm_vhmax(glmm_abs(a)), 0); } static inline glmm_128 glmm_load3(float v[3]) { glmm_128 xy = wasm_v128_load64_zero(v); return wasm_f32x4_replace_lane(xy, 2, v[2]); } static inline void glmm_store3(float v[3], glmm_128 vx) { wasm_v128_store64_lane(v, vx, 0); wasm_v128_store32_lane(&v[2], vx, 2); } static inline glmm_128 glmm_div(glmm_128 a, glmm_128 b) { return wasm_f32x4_div(a, b); } static inline glmm_128 glmm_fmadd(glmm_128 a, glmm_128 b, glmm_128 c) { return wasm_f32x4_add(c, wasm_f32x4_mul(a, b)); } static inline glmm_128 glmm_fnmadd(glmm_128 a, glmm_128 b, glmm_128 c) { return wasm_f32x4_sub(c, wasm_f32x4_mul(a, b)); } static inline glmm_128 glmm_fmsub(glmm_128 a, glmm_128 b, glmm_128 c) { return wasm_f32x4_sub(wasm_f32x4_mul(a, b), c); } static inline glmm_128 glmm_fnmsub(glmm_128 a, glmm_128 b, glmm_128 c) { return wasm_f32x4_neg(wasm_f32x4_add(wasm_f32x4_mul(a, b), c)); } #endif #endif /* cglm_simd_wasm_h */ cglm-0.9.7/include/cglm/simd/wasm/000077500000000000000000000000001526744317200167345ustar00rootroot00000000000000cglm-0.9.7/include/cglm/simd/wasm/affine.h000066400000000000000000000064641526744317200203470ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_affine_mat_wasm_h #define cglm_affine_mat_wasm_h #if defined(__wasm__) && defined(__wasm_simd128__) #include "../../common.h" #include "../intrin.h" CGLM_INLINE void glm_mul_wasm(mat4 m1, mat4 m2, mat4 dest) { /* D = R * L (Column-Major) */ glmm_128 l, r0, r1, r2, r3, v0, v1, v2, v3; l = glmm_load(m1[0]); r0 = glmm_load(m2[0]); r1 = glmm_load(m2[1]); r2 = glmm_load(m2[2]); r3 = glmm_load(m2[3]); v0 = wasm_f32x4_mul(glmm_splat_x(r0), l); v1 = wasm_f32x4_mul(glmm_splat_x(r1), l); v2 = wasm_f32x4_mul(glmm_splat_x(r2), l); v3 = wasm_f32x4_mul(glmm_splat_x(r3), l); l = glmm_load(m1[1]); v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); v3 = glmm_fmadd(glmm_splat_y(r3), l, v3); l = glmm_load(m1[2]); v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); v3 = glmm_fmadd(glmm_splat_z(r3), l, v3); l = glmm_load(m1[3]); v3 = glmm_fmadd(glmm_splat_w(r3), l, v3); glmm_store(dest[0], v0); glmm_store(dest[1], v1); glmm_store(dest[2], v2); glmm_store(dest[3], v3); } CGLM_INLINE void glm_mul_rot_wasm(mat4 m1, mat4 m2, mat4 dest) { /* D = R * L (Column-Major) */ glmm_128 l, r0, r1, r2, v0, v1, v2; l = glmm_load(m1[0]); r0 = glmm_load(m2[0]); r1 = glmm_load(m2[1]); r2 = glmm_load(m2[2]); v0 = wasm_f32x4_mul(glmm_splat_x(r0), l); v1 = wasm_f32x4_mul(glmm_splat_x(r1), l); v2 = wasm_f32x4_mul(glmm_splat_x(r2), l); l = glmm_load(m1[1]); v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); l = glmm_load(m1[2]); v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); glmm_store(dest[0], v0); glmm_store(dest[1], v1); glmm_store(dest[2], v2); glmm_store(dest[3], glmm_load(m1[3])); } CGLM_INLINE void glm_inv_tr_wasm(mat4 mat) { glmm_128 r0, r1, r2, r3, x0, x1, x2, x3, x4, x5; r0 = glmm_load(mat[0]); r1 = glmm_load(mat[1]); r2 = glmm_load(mat[2]); r3 = glmm_load(mat[3]); x1 = wasm_f32x4_const(0.0f, 0.0f, 0.0f, 1.0f); /* _MM_TRANSPOSE4_PS(r0, r1, r2, x1); */ x2 = wasm_i32x4_shuffle(r0, r1, 0, 4, 1, 5); x3 = wasm_i32x4_shuffle(r0, r1, 2, 6, 3, 7); x4 = wasm_i32x4_shuffle(r2, x1, 0, 4, 1, 5); x5 = wasm_i32x4_shuffle(r2, x1, 2, 6, 3, 7); /* r0 = _mm_movelh_ps(x2, x4); */ r0 = wasm_i32x4_shuffle(x2, x4, 0, 1, 4, 5); /* r1 = _mm_movehl_ps(x4, x2); */ r1 = wasm_i32x4_shuffle(x4, x2, 6, 7, 2, 3); /* r2 = _mm_movelh_ps(x3, x5); */ r2 = wasm_i32x4_shuffle(x3, x5, 0, 1, 4, 5); /* x1 = _mm_movehl_ps(x5, x3); */ x1 = wasm_i32x4_shuffle(x5, x3, 6, 7, 2, 3); x2 = glmm_shuff1(r3, 0, 0, 0, 0); x3 = glmm_shuff1(r3, 1, 1, 1, 1); x4 = glmm_shuff1(r3, 2, 2, 2, 2); x0 = glmm_fmadd(r0, x2, glmm_fmadd(r1, x3, wasm_f32x4_mul(r2, x4))); x0 = wasm_f32x4_neg(x0); x0 = wasm_f32x4_add(x0, x1); glmm_store(mat[0], r0); glmm_store(mat[1], r1); glmm_store(mat[2], r2); glmm_store(mat[3], x0); } #endif #endif /* cglm_affine_mat_wasm_h */ cglm-0.9.7/include/cglm/simd/wasm/mat2.h000066400000000000000000000021541526744317200177520ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_mat2_wasm_h #define cglm_mat2_wasm_h #if defined(__wasm__) && defined(__wasm_simd128__) #include "../../common.h" #include "../intrin.h" CGLM_INLINE void glm_mat2_mul_wasm(mat2 m1, mat2 m2, mat2 dest) { glmm_128 x0, x1, x2, x3, x4; x1 = glmm_load(m1[0]); /* d c b a */ x2 = glmm_load(m2[0]); /* h g f e */ x3 = glmm_shuff1(x2, 2, 2, 0, 0); x4 = glmm_shuff1(x2, 3, 3, 1, 1); /* x0 = _mm_movelh_ps(x1, x1); */ x0 = wasm_i32x4_shuffle(x1, x1, 0, 1, 4, 5); /* x2 = _mm_movehl_ps(x1, x1); */ x2 = wasm_i32x4_shuffle(x1, x1, 6, 7, 2, 3); /* dest[0][0] = a * e + c * f; dest[0][1] = b * e + d * f; dest[1][0] = a * g + c * h; dest[1][1] = b * g + d * h; */ x0 = glmm_fmadd(x0, x3, wasm_f32x4_mul(x2, x4)); glmm_store(dest[0], x0); } CGLM_INLINE void glm_mat2_transp_wasm(mat2 m, mat2 dest) { /* d c b a */ /* d b c a */ glmm_store(dest[0], glmm_shuff1(glmm_load(m[0]), 3, 1, 2, 0)); } #endif #endif /* cglm_mat2_wasm_h */ cglm-0.9.7/include/cglm/simd/wasm/mat3.h000066400000000000000000000063561526744317200177630ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_mat3_wasm_h #define cglm_mat3_wasm_h #if defined(__wasm__) && defined(__wasm_simd128__) #include "../../common.h" #include "../intrin.h" CGLM_INLINE void glm_mat3_mul_wasm(mat3 m1, mat3 m2, mat3 dest) { glmm_128 l0, l1, l2, r0, r1, r2, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9; l0 = wasm_v128_load(m1[0]); l1 = wasm_v128_load(&m1[1][1]); r0 = wasm_v128_load(m2[0]); r1 = wasm_v128_load(&m2[1][1]); x8 = glmm_shuff1(l0, 0, 2, 1, 0); /* a00 a02 a01 a00 */ x1 = glmm_shuff1(r0, 3, 0, 0, 0); /* b10 b00 b00 b00 */ x2 = wasm_i32x4_shuffle(l0, l1, 3, 3, 4, 5); /* a12 a11 a10 a10 */ x3 = wasm_i32x4_shuffle(r0, r1, 1, 3, 4, 6); /* b20 b11 b10 b01 */ x0 = wasm_f32x4_mul(x8, x1); x6 = glmm_shuff1(l0, 1, 0, 2, 1); /* a01 a00 a02 a01 */ x7 = glmm_shuff1(x3, 3, 3, 1, 1); /* b20 b20 b10 b10 */ l2 = wasm_v128_load32_zero(&m1[2][2]); r2 = wasm_v128_load32_zero(&m2[2][2]); x1 = wasm_f32x4_mul(x6, x7); l2 = glmm_shuff1(l2, 0, 0, 1, 0); /* a22 a22 0.f a22 */ r2 = glmm_shuff1(r2, 0, 0, 1, 0); /* b22 b22 0.f b22 */ x4 = glmm_shuff1(x2, 0, 3, 2, 0); /* a10 a12 a11 a10 */ x5 = glmm_shuff1(x2, 2, 0, 3, 2); /* a11 a10 a12 a11 */ x6 = glmm_shuff1(x3, 2, 0, 0, 0); /* b11 b01 b01 b01 */ x2 = glmm_shuff1(r1, 3, 3, 0, 0); /* b21 b21 b11 b11 */ /* x8 = _mm_unpackhi_ps(x8, x4); */ /* x9 = _mm_unpackhi_ps(x7, x2); */ x8 = wasm_i32x4_shuffle(x8, x4, 2, 6, 3, 7); /* a10 a00 a12 a02 */ x9 = wasm_i32x4_shuffle(x7, x2, 2, 6, 3, 7); /* b21 b20 b21 b20 */ x0 = glmm_fmadd(x4, x6, x0); x1 = glmm_fmadd(x5, x2, x1); /* x2 = _mm_movehl_ps(l2, l1); */ x2 = wasm_i32x4_shuffle(l2, l1, 6, 7, 2, 3); /* a22 a22 a21 a20 */ x3 = glmm_shuff1(x2, 0, 2, 1, 0); /* a20 a22 a21 a20 */ x2 = glmm_shuff1(x2, 1, 0, 2, 1); /* a21 a20 a22 a21 */ x4 = wasm_i32x4_shuffle(r0, r1, 2, 2, 5, 5); /* b12 b12 b02 b02 */ x5 = glmm_shuff1(x4, 3, 0, 0, 0); /* b12 b02 b02 b02 */ /* x4 = _mm_movehl_ps(r2, x4); */ x4 = wasm_i32x4_shuffle(r2, x4, 6, 7, 2, 3); /* b22 b22 b12 b12 */ x0 = glmm_fmadd(x3, x5, x0); x1 = glmm_fmadd(x2, x4, x1); /* Dot Product : dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22 + 0 * 00 */ /* x2 = _mm_movelh_ps(x8, l2); */ /* x3 = _mm_movelh_ps(x9, r2); */ x2 = wasm_i32x4_shuffle(x8, l2, 0, 1, 4, 5); /* 0.f a22 a12 a02 */ x3 = wasm_i32x4_shuffle(x9, r2, 0, 1, 4, 5); /* 0.f b22 b21 b20 */ x2 = glmm_vdots(x2, x3); /* _mm_storeu_ps(&dest[0][0], x0); */ wasm_v128_store(&dest[0][0], x0); /* _mm_storeu_ps(&dest[1][1], x1); */ wasm_v128_store(&dest[1][1], x1); /* _mm_store_ss (&dest[2][2], x2); */ wasm_v128_store32_lane(&dest[2][2], x2, 0); } #endif #endif /* cglm_mat3_wasm_h */ cglm-0.9.7/include/cglm/simd/wasm/mat4.h000066400000000000000000000341121526744317200177530ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_mat_wasm_h #define cglm_mat_wasm_h #if defined(__wasm__) && defined(__wasm_simd128__) #include "../../common.h" #include "../intrin.h" #define glm_mat4_inv_precise_wasm(mat, dest) glm_mat4_inv_wasm(mat, dest) CGLM_INLINE void glm_mat4_scale_wasm(mat4 m, float s) { glmm_128 x0; x0 = wasm_f32x4_splat(s); glmm_store(m[0], wasm_f32x4_mul(glmm_load(m[0]), x0)); glmm_store(m[1], wasm_f32x4_mul(glmm_load(m[1]), x0)); glmm_store(m[2], wasm_f32x4_mul(glmm_load(m[2]), x0)); glmm_store(m[3], wasm_f32x4_mul(glmm_load(m[3]), x0)); } CGLM_INLINE void glm_mat4_transp_wasm(mat4 m, mat4 dest) { glmm_128 r0, r1, r2, r3, tmp0, tmp1, tmp2, tmp3; r0 = glmm_load(m[0]); r1 = glmm_load(m[1]); r2 = glmm_load(m[2]); r3 = glmm_load(m[3]); /* _MM_TRANSPOSE4_PS(r0, r1, r2, r3); */ tmp0 = wasm_i32x4_shuffle(r0, r1, 0, 4, 1, 5); tmp1 = wasm_i32x4_shuffle(r0, r1, 2, 6, 3, 7); tmp2 = wasm_i32x4_shuffle(r2, r3, 0, 4, 1, 5); tmp3 = wasm_i32x4_shuffle(r2, r3, 2, 6, 3, 7); /* r0 = _mm_movelh_ps(tmp0, tmp2); */ r0 = wasm_i32x4_shuffle(tmp0, tmp2, 0, 1, 4, 5); /* r1 = _mm_movehl_ps(tmp2, tmp0); */ r1 = wasm_i32x4_shuffle(tmp2, tmp0, 6, 7, 2, 3); /* r2 = _mm_movelh_ps(tmp1, tmp3); */ r2 = wasm_i32x4_shuffle(tmp1, tmp3, 0, 1, 4, 5); /* r3 = _mm_movehl_ps(tmp3, tmp1); */ r3 = wasm_i32x4_shuffle(tmp3, tmp1, 6, 7, 2, 3); glmm_store(dest[0], r0); glmm_store(dest[1], r1); glmm_store(dest[2], r2); glmm_store(dest[3], r3); } CGLM_INLINE void glm_mat4_mul_wasm(mat4 m1, mat4 m2, mat4 dest) { /* D = R * L (Column-Major) */ glmm_128 l, r0, r1, r2, r3, v0, v1, v2, v3; l = glmm_load(m1[0]); r0 = glmm_load(m2[0]); r1 = glmm_load(m2[1]); r2 = glmm_load(m2[2]); r3 = glmm_load(m2[3]); v0 = wasm_f32x4_mul(glmm_splat_x(r0), l); v1 = wasm_f32x4_mul(glmm_splat_x(r1), l); v2 = wasm_f32x4_mul(glmm_splat_x(r2), l); v3 = wasm_f32x4_mul(glmm_splat_x(r3), l); l = glmm_load(m1[1]); v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); v3 = glmm_fmadd(glmm_splat_y(r3), l, v3); l = glmm_load(m1[2]); v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); v3 = glmm_fmadd(glmm_splat_z(r3), l, v3); l = glmm_load(m1[3]); v0 = glmm_fmadd(glmm_splat_w(r0), l, v0); v1 = glmm_fmadd(glmm_splat_w(r1), l, v1); v2 = glmm_fmadd(glmm_splat_w(r2), l, v2); v3 = glmm_fmadd(glmm_splat_w(r3), l, v3); glmm_store(dest[0], v0); glmm_store(dest[1], v1); glmm_store(dest[2], v2); glmm_store(dest[3], v3); } CGLM_INLINE void glm_mat4_mulv_wasm(mat4 m, vec4 v, vec4 dest) { glmm_128 x0, x1, m0, m1, m2, m3, v0, v1, v2, v3; m0 = glmm_load(m[0]); m1 = glmm_load(m[1]); m2 = glmm_load(m[2]); m3 = glmm_load(m[3]); x0 = glmm_load(v); v0 = glmm_splat_x(x0); v1 = glmm_splat_y(x0); v2 = glmm_splat_z(x0); v3 = glmm_splat_w(x0); x1 = wasm_f32x4_mul(m3, v3); x1 = glmm_fmadd(m2, v2, x1); x1 = glmm_fmadd(m1, v1, x1); x1 = glmm_fmadd(m0, v0, x1); glmm_store(dest, x1); } CGLM_INLINE float glm_mat4_det_wasm(mat4 mat) { glmm_128 r0, r1, r2, r3, x0, x1, x2; /* 127 <- 0, [square] det(A) = det(At) */ r0 = glmm_load(mat[0]); /* d c b a */ r1 = glmm_load(mat[1]); /* h g f e */ r2 = glmm_load(mat[2]); /* l k j i */ r3 = glmm_load(mat[3]); /* p o n m */ /* t[1] = j * p - n * l; t[2] = j * o - n * k; t[3] = i * p - m * l; t[4] = i * o - m * k; */ x0 = glmm_fnmadd(glmm_shuff1(r3, 0, 0, 1, 1), glmm_shuff1(r2, 2, 3, 2, 3), wasm_f32x4_mul(glmm_shuff1(r2, 0, 0, 1, 1), glmm_shuff1(r3, 2, 3, 2, 3))); /* t[0] = k * p - o * l; t[0] = k * p - o * l; t[5] = i * n - m * j; t[5] = i * n - m * j; */ x1 = glmm_fnmadd(glmm_shuff1(r3, 0, 0, 2, 2), glmm_shuff1(r2, 1, 1, 3, 3), wasm_f32x4_mul(glmm_shuff1(r2, 0, 0, 2, 2), glmm_shuff1(r3, 1, 1, 3, 3))); /* a * (f * t[0] - g * t[1] + h * t[2]) - b * (e * t[0] - g * t[3] + h * t[4]) + c * (e * t[1] - f * t[3] + h * t[5]) - d * (e * t[2] - f * t[4] + g * t[5]) */ x2 = glmm_fnmadd(glmm_shuff1(r1, 1, 1, 2, 2), glmm_shuff1(x0, 3, 2, 2, 0), wasm_f32x4_mul(glmm_shuff1(r1, 0, 0, 0, 1), wasm_i32x4_shuffle(x1, x0, 0, 0, 4, 5))); x2 = glmm_fmadd(glmm_shuff1(r1, 2, 3, 3, 3), wasm_i32x4_shuffle(x0, x1, 1, 3, 6, 6), x2); /* x2 = wasm_v128_xor(x2, wasm_f32x4_const(0.f, -0.f, 0.f, -0.f)); */ x2 = wasm_v128_xor(x2, glmm_float32x4_SIGNMASK_PNPN); return glmm_hadd(wasm_f32x4_mul(x2, r0)); } CGLM_INLINE void glm_mat4_inv_fast_wasm(mat4 mat, mat4 dest) { glmm_128 r0, r1, r2, r3, v0, v1, v2, v3, t0, t1, t2, t3, t4, t5, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9; /* x8 = wasm_f32x4_const(0.f, -0.f, 0.f, -0.f); */ x8 = glmm_float32x4_SIGNMASK_PNPN; x9 = glmm_shuff1(x8, 2, 1, 2, 1); /* 127 <- 0 */ r0 = glmm_load(mat[0]); /* d c b a */ r1 = glmm_load(mat[1]); /* h g f e */ r2 = glmm_load(mat[2]); /* l k j i */ r3 = glmm_load(mat[3]); /* p o n m */ /* x0 = _mm_movehl_ps(r3, r2); */ x0 = wasm_i32x4_shuffle(r3, r2, 6, 7, 2, 3); /* p o l k */ /* x3 = _mm_movelh_ps(r2, r3); */ x3 = wasm_i32x4_shuffle(r2, r3, 0, 1, 4, 5); /* n m j i */ x1 = glmm_shuff1(x0, 1, 3, 3 ,3); /* l p p p */ x2 = glmm_shuff1(x0, 0, 2, 2, 2); /* k o o o */ x4 = glmm_shuff1(x3, 1, 3, 3, 3); /* j n n n */ x7 = glmm_shuff1(x3, 0, 2, 2, 2); /* i m m m */ x6 = wasm_i32x4_shuffle(r2, r1, 0, 0, 4, 4); /* e e i i */ x5 = wasm_i32x4_shuffle(r2, r1, 1, 1, 5, 5); /* f f j j */ x3 = wasm_i32x4_shuffle(r2, r1, 2, 2, 6, 6); /* g g k k */ x0 = wasm_i32x4_shuffle(r2, r1, 3, 3, 7, 7); /* h h l l */ t0 = wasm_f32x4_mul(x3, x1); t1 = wasm_f32x4_mul(x5, x1); t2 = wasm_f32x4_mul(x5, x2); t3 = wasm_f32x4_mul(x6, x1); t4 = wasm_f32x4_mul(x6, x2); t5 = wasm_f32x4_mul(x6, x4); /* t1[0] = k * p - o * l; t1[0] = k * p - o * l; t2[0] = g * p - o * h; t3[0] = g * l - k * h; */ t0 = glmm_fnmadd(x2, x0, t0); /* t1[1] = j * p - n * l; t1[1] = j * p - n * l; t2[1] = f * p - n * h; t3[1] = f * l - j * h; */ t1 = glmm_fnmadd(x4, x0, t1); /* t1[2] = j * o - n * k t1[2] = j * o - n * k; t2[2] = f * o - n * g; t3[2] = f * k - j * g; */ t2 = glmm_fnmadd(x4, x3, t2); /* t1[3] = i * p - m * l; t1[3] = i * p - m * l; t2[3] = e * p - m * h; t3[3] = e * l - i * h; */ t3 = glmm_fnmadd(x7, x0, t3); /* t1[4] = i * o - m * k; t1[4] = i * o - m * k; t2[4] = e * o - m * g; t3[4] = e * k - i * g; */ t4 = glmm_fnmadd(x7, x3, t4); /* t1[5] = i * n - m * j; t1[5] = i * n - m * j; t2[5] = e * n - m * f; t3[5] = e * j - i * f; */ t5 = glmm_fnmadd(x7, x5, t5); /* x4 = _mm_movelh_ps(r0, r1); */ x4 = wasm_i32x4_shuffle(r0, r1, 0, 1, 4, 5); /* f e b a */ /* x5 = _mm_movehl_ps(r1, r0); */ x5 = wasm_i32x4_shuffle(r1, r0, 6, 7, 2, 3); /* h g d c */ x0 = glmm_shuff1(x4, 0, 0, 0, 2); /* a a a e */ x1 = glmm_shuff1(x4, 1, 1, 1, 3); /* b b b f */ x2 = glmm_shuff1(x5, 0, 0, 0, 2); /* c c c g */ x3 = glmm_shuff1(x5, 1, 1, 1, 3); /* d d d h */ v2 = wasm_f32x4_mul(x0, t1); v1 = wasm_f32x4_mul(x0, t0); v3 = wasm_f32x4_mul(x0, t2); v0 = wasm_f32x4_mul(x1, t0); v2 = glmm_fnmadd(x1, t3, v2); v3 = glmm_fnmadd(x1, t4, v3); v0 = glmm_fnmadd(x2, t1, v0); v1 = glmm_fnmadd(x2, t3, v1); v3 = glmm_fmadd(x2, t5, v3); v0 = glmm_fmadd(x3, t2, v0); v2 = glmm_fmadd(x3, t5, v2); v1 = glmm_fmadd(x3, t4, v1); /* dest[0][0] = f * t1[0] - g * t1[1] + h * t1[2]; dest[0][1] =-(b * t1[0] - c * t1[1] + d * t1[2]); dest[0][2] = b * t2[0] - c * t2[1] + d * t2[2]; dest[0][3] =-(b * t3[0] - c * t3[1] + d * t3[2]); */ v0 = wasm_v128_xor(v0, x8); /* dest[2][0] = e * t1[1] - f * t1[3] + h * t1[5]; dest[2][1] =-(a * t1[1] - b * t1[3] + d * t1[5]); dest[2][2] = a * t2[1] - b * t2[3] + d * t2[5]; dest[2][3] =-(a * t3[1] - b * t3[3] + d * t3[5]);*/ v2 = wasm_v128_xor(v2, x8); /* dest[1][0] =-(e * t1[0] - g * t1[3] + h * t1[4]); dest[1][1] = a * t1[0] - c * t1[3] + d * t1[4]; dest[1][2] =-(a * t2[0] - c * t2[3] + d * t2[4]); dest[1][3] = a * t3[0] - c * t3[3] + d * t3[4]; */ v1 = wasm_v128_xor(v1, x9); /* dest[3][0] =-(e * t1[2] - f * t1[4] + g * t1[5]); dest[3][1] = a * t1[2] - b * t1[4] + c * t1[5]; dest[3][2] =-(a * t2[2] - b * t2[4] + c * t2[5]); dest[3][3] = a * t3[2] - b * t3[4] + c * t3[5]; */ v3 = wasm_v128_xor(v3, x9); /* determinant */ x0 = wasm_i32x4_shuffle(v0, v1, 0, 0, 4, 4); x1 = wasm_i32x4_shuffle(v2, v3, 0, 0, 4, 4); x0 = wasm_i32x4_shuffle(x0, x1, 0, 2, 4, 6); /* x0 = _mm_rcp_ps(glmm_vhadd(wasm_f32x4_mul(x0, r0))); */ x0 = wasm_f32x4_div(wasm_f32x4_const_splat(1.0f), glmm_vhadd(wasm_f32x4_mul(x0, r0))); glmm_store(dest[0], wasm_f32x4_mul(v0, x0)); glmm_store(dest[1], wasm_f32x4_mul(v1, x0)); glmm_store(dest[2], wasm_f32x4_mul(v2, x0)); glmm_store(dest[3], wasm_f32x4_mul(v3, x0)); } CGLM_INLINE void glm_mat4_inv_wasm(mat4 mat, mat4 dest) { glmm_128 r0, r1, r2, r3, v0, v1, v2, v3, t0, t1, t2, t3, t4, t5, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9; /* x8 = wasm_f32x4_const(0.f, -0.f, 0.f, -0.f); */ x8 = glmm_float32x4_SIGNMASK_PNPN; x9 = glmm_shuff1(x8, 2, 1, 2, 1); /* 127 <- 0 */ r0 = glmm_load(mat[0]); /* d c b a */ r1 = glmm_load(mat[1]); /* h g f e */ r2 = glmm_load(mat[2]); /* l k j i */ r3 = glmm_load(mat[3]); /* p o n m */ /* x0 = _mm_movehl_ps(r3, r2); */ x0 = wasm_i32x4_shuffle(r3, r2, 6, 7, 2, 3); /* p o l k */ /* x3 = _mm_movelh_ps(r2, r3); */ x3 = wasm_i32x4_shuffle(r2, r3, 0, 1, 4, 5); /* n m j i */ x1 = glmm_shuff1(x0, 1, 3, 3 ,3); /* l p p p */ x2 = glmm_shuff1(x0, 0, 2, 2, 2); /* k o o o */ x4 = glmm_shuff1(x3, 1, 3, 3, 3); /* j n n n */ x7 = glmm_shuff1(x3, 0, 2, 2, 2); /* i m m m */ x6 = wasm_i32x4_shuffle(r2, r1, 0, 0, 4, 4); /* e e i i */ x5 = wasm_i32x4_shuffle(r2, r1, 1, 1, 5, 5); /* f f j j */ x3 = wasm_i32x4_shuffle(r2, r1, 2, 2, 6, 6); /* g g k k */ x0 = wasm_i32x4_shuffle(r2, r1, 3, 3, 7, 7); /* h h l l */ t0 = wasm_f32x4_mul(x3, x1); t1 = wasm_f32x4_mul(x5, x1); t2 = wasm_f32x4_mul(x5, x2); t3 = wasm_f32x4_mul(x6, x1); t4 = wasm_f32x4_mul(x6, x2); t5 = wasm_f32x4_mul(x6, x4); /* t1[0] = k * p - o * l; t1[0] = k * p - o * l; t2[0] = g * p - o * h; t3[0] = g * l - k * h; */ t0 = glmm_fnmadd(x2, x0, t0); /* t1[1] = j * p - n * l; t1[1] = j * p - n * l; t2[1] = f * p - n * h; t3[1] = f * l - j * h; */ t1 = glmm_fnmadd(x4, x0, t1); /* t1[2] = j * o - n * k t1[2] = j * o - n * k; t2[2] = f * o - n * g; t3[2] = f * k - j * g; */ t2 = glmm_fnmadd(x4, x3, t2); /* t1[3] = i * p - m * l; t1[3] = i * p - m * l; t2[3] = e * p - m * h; t3[3] = e * l - i * h; */ t3 = glmm_fnmadd(x7, x0, t3); /* t1[4] = i * o - m * k; t1[4] = i * o - m * k; t2[4] = e * o - m * g; t3[4] = e * k - i * g; */ t4 = glmm_fnmadd(x7, x3, t4); /* t1[5] = i * n - m * j; t1[5] = i * n - m * j; t2[5] = e * n - m * f; t3[5] = e * j - i * f; */ t5 = glmm_fnmadd(x7, x5, t5); /* x4 = _mm_movelh_ps(r0, r1); */ x4 = wasm_i32x4_shuffle(r0, r1, 0, 1, 4, 5); /* f e b a */ /* x5 = _mm_movehl_ps(r1, r0); */ x5 = wasm_i32x4_shuffle(r1, r0, 6, 7, 2, 3); /* h g d c */ x0 = glmm_shuff1(x4, 0, 0, 0, 2); /* a a a e */ x1 = glmm_shuff1(x4, 1, 1, 1, 3); /* b b b f */ x2 = glmm_shuff1(x5, 0, 0, 0, 2); /* c c c g */ x3 = glmm_shuff1(x5, 1, 1, 1, 3); /* d d d h */ v2 = wasm_f32x4_mul(x0, t1); v1 = wasm_f32x4_mul(x0, t0); v3 = wasm_f32x4_mul(x0, t2); v0 = wasm_f32x4_mul(x1, t0); v2 = glmm_fnmadd(x1, t3, v2); v3 = glmm_fnmadd(x1, t4, v3); v0 = glmm_fnmadd(x2, t1, v0); v1 = glmm_fnmadd(x2, t3, v1); v3 = glmm_fmadd(x2, t5, v3); v0 = glmm_fmadd(x3, t2, v0); v2 = glmm_fmadd(x3, t5, v2); v1 = glmm_fmadd(x3, t4, v1); /* dest[0][0] = f * t1[0] - g * t1[1] + h * t1[2]; dest[0][1] =-(b * t1[0] - c * t1[1] + d * t1[2]); dest[0][2] = b * t2[0] - c * t2[1] + d * t2[2]; dest[0][3] =-(b * t3[0] - c * t3[1] + d * t3[2]); */ v0 = wasm_v128_xor(v0, x8); /* dest[2][0] = e * t1[1] - f * t1[3] + h * t1[5]; dest[2][1] =-(a * t1[1] - b * t1[3] + d * t1[5]); dest[2][2] = a * t2[1] - b * t2[3] + d * t2[5]; dest[2][3] =-(a * t3[1] - b * t3[3] + d * t3[5]);*/ v2 = wasm_v128_xor(v2, x8); /* dest[1][0] =-(e * t1[0] - g * t1[3] + h * t1[4]); dest[1][1] = a * t1[0] - c * t1[3] + d * t1[4]; dest[1][2] =-(a * t2[0] - c * t2[3] + d * t2[4]); dest[1][3] = a * t3[0] - c * t3[3] + d * t3[4]; */ v1 = wasm_v128_xor(v1, x9); /* dest[3][0] =-(e * t1[2] - f * t1[4] + g * t1[5]); dest[3][1] = a * t1[2] - b * t1[4] + c * t1[5]; dest[3][2] =-(a * t2[2] - b * t2[4] + c * t2[5]); dest[3][3] = a * t3[2] - b * t3[4] + c * t3[5]; */ v3 = wasm_v128_xor(v3, x9); /* determinant */ x0 = wasm_i32x4_shuffle(v0, v1, 0, 0, 4, 4); x1 = wasm_i32x4_shuffle(v2, v3, 0, 0, 4, 4); x0 = wasm_i32x4_shuffle(x0, x1, 0, 2, 4, 6); x0 = wasm_f32x4_div(wasm_f32x4_splat(1.0f), glmm_vhadd(wasm_f32x4_mul(x0, r0))); glmm_store(dest[0], wasm_f32x4_mul(v0, x0)); glmm_store(dest[1], wasm_f32x4_mul(v1, x0)); glmm_store(dest[2], wasm_f32x4_mul(v2, x0)); glmm_store(dest[3], wasm_f32x4_mul(v3, x0)); } #endif #endif /* cglm_mat_wasm_h */ cglm-0.9.7/include/cglm/simd/wasm/quat.h000066400000000000000000000025261526744317200200640ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_quat_wasm_h #define cglm_quat_wasm_h #if defined(__wasm__) && defined(__wasm_simd128__) #include "../../common.h" #include "../intrin.h" CGLM_INLINE void glm_quat_mul_wasm(versor p, versor q, versor dest) { /* + (a1 b2 + b1 a2 + c1 d2 − d1 c2)i + (a1 c2 − b1 d2 + c1 a2 + d1 b2)j + (a1 d2 + b1 c2 − c1 b2 + d1 a2)k a1 a2 − b1 b2 − c1 c2 − d1 d2 */ glmm_128 xp, xq, x1, x2, x3, r, x, y, z; xp = glmm_load(p); /* 3 2 1 0 */ xq = glmm_load(q); /* x1 = wasm_f32x4_const(0.f, -0.f, 0.f, -0.f); */ x1 = glmm_float32x4_SIGNMASK_PNPN; /* TODO: _mm_set1_ss() + shuff ? */ r = wasm_f32x4_mul(glmm_splat_w(xp), xq); /* x2 = _mm_unpackhi_ps(x1, x1); */ x2 = wasm_i32x4_shuffle(x1, x1, 2, 6, 3, 7); x3 = glmm_shuff1(x1, 3, 2, 0, 1); x = glmm_splat_x(xp); y = glmm_splat_y(xp); z = glmm_splat_z(xp); x = wasm_v128_xor(x, x1); y = wasm_v128_xor(y, x2); z = wasm_v128_xor(z, x3); x1 = glmm_shuff1(xq, 0, 1, 2, 3); x2 = glmm_shuff1(xq, 1, 0, 3, 2); x3 = glmm_shuff1(xq, 2, 3, 0, 1); r = glmm_fmadd(x, x1, r); r = glmm_fmadd(y, x2, r); r = glmm_fmadd(z, x3, r); glmm_store(dest, r); } #endif #endif /* cglm_quat_wasm_h */ cglm-0.9.7/include/cglm/simd/x86.h000066400000000000000000000214001526744317200165600ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_simd_x86_h #define cglm_simd_x86_h #include "intrin.h" #ifdef CGLM_SIMD_x86 #ifdef CGLM_ALL_UNALIGNED # define glmm_load(p) _mm_loadu_ps(p) # define glmm_store(p, a) _mm_storeu_ps(p, a) #else # define glmm_load(p) _mm_load_ps(p) # define glmm_store(p, a) _mm_store_ps(p, a) #endif #define glmm_128 __m128 #ifdef __AVX__ # define glmm_shuff1(xmm, z, y, x, w) \ _mm_permute_ps((xmm), _MM_SHUFFLE(z, y, x, w)) #else # if !defined(CGLM_NO_INT_DOMAIN) && defined(__SSE2__) # define glmm_shuff1(xmm, z, y, x, w) \ _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(xmm), \ _MM_SHUFFLE(z, y, x, w))) # else # define glmm_shuff1(xmm, z, y, x, w) \ _mm_shuffle_ps(xmm, xmm, _MM_SHUFFLE(z, y, x, w)) # endif #endif #define glmm_splat(x, lane) glmm_shuff1(x, lane, lane, lane, lane) #ifdef __AVX__ # define glmm_set1(x) _mm_broadcast_ss(&x) # define glmm_set1_ptr(x) _mm_broadcast_ss(x) # define glmm_set1_rval(x) _mm_set1_ps(x) # ifdef __AVX2__ # define glmm_splat_x(x) _mm_broadcastss_ps(x) # else # define glmm_splat_x(x) _mm_permute_ps(x, _MM_SHUFFLE(0, 0, 0, 0)) # endif # define glmm_splat_y(x) _mm_permute_ps(x, _MM_SHUFFLE(1, 1, 1, 1)) # define glmm_splat_z(x) _mm_permute_ps(x, _MM_SHUFFLE(2, 2, 2, 2)) # define glmm_splat_w(x) _mm_permute_ps(x, _MM_SHUFFLE(3, 3, 3, 3)) #else # define glmm_set1(x) _mm_set1_ps(x) # define glmm_set1_ptr(x) _mm_set1_ps(*x) # define glmm_set1_rval(x) _mm_set1_ps(x) # define glmm_splat_x(x) glmm_splat(x, 0) # define glmm_splat_y(x) glmm_splat(x, 1) # define glmm_splat_z(x) glmm_splat(x, 2) # define glmm_splat_w(x) glmm_splat(x, 3) #endif #ifdef __AVX__ # ifdef CGLM_ALL_UNALIGNED # define glmm_load256(p) _mm256_loadu_ps(p) # define glmm_store256(p, a) _mm256_storeu_ps(p, a) # else # define glmm_load256(p) _mm256_load_ps(p) # define glmm_store256(p, a) _mm256_store_ps(p, a) # endif #endif /* Note that `0x80000000` corresponds to `INT_MIN` for a 32-bit int. */ #if defined(__SSE2__) # define GLMM_NEGZEROf ((int)0x80000000) /* 0x80000000 ---> -0.0f */ # define GLMM_POSZEROf ((int)0x00000000) /* 0x00000000 ---> +0.0f */ #else # ifdef CGLM_FAST_MATH union { int i; float f; } static GLMM_NEGZEROf_TU = { .i = (int)0x80000000 }; # define GLMM_NEGZEROf GLMM_NEGZEROf_TU.f # define GLMM_POSZEROf 0.0f # else # define GLMM_NEGZEROf -0.0f # define GLMM_POSZEROf 0.0f # endif #endif #if defined(__SSE2__) # define GLMM__SIGNMASKf(X, Y, Z, W) \ _mm_castsi128_ps(_mm_set_epi32(X, Y, Z, W)) /* _mm_set_ps(X, Y, Z, W); */ #else # define GLMM__SIGNMASKf(X, Y, Z, W) _mm_set_ps(X, Y, Z, W) #endif #define glmm_float32x4_SIGNMASK_PNPN GLMM__SIGNMASKf(GLMM_POSZEROf, GLMM_NEGZEROf, GLMM_POSZEROf, GLMM_NEGZEROf) #define glmm_float32x4_SIGNMASK_NPNP GLMM__SIGNMASKf(GLMM_NEGZEROf, GLMM_POSZEROf, GLMM_NEGZEROf, GLMM_POSZEROf) #define glmm_float32x4_SIGNMASK_NPPN GLMM__SIGNMASKf(GLMM_NEGZEROf, GLMM_POSZEROf, GLMM_POSZEROf, GLMM_NEGZEROf) /* fasth math prevents -0.0f to work */ #if defined(__SSE2__) # define glmm_float32x4_SIGNMASK_NEG _mm_castsi128_ps(_mm_set1_epi32(GLMM_NEGZEROf)) /* _mm_set1_ps(-0.0f) */ #else # define glmm_float32x4_SIGNMASK_NEG glmm_set1(GLMM_NEGZEROf) #endif #define glmm_float32x8_SIGNMASK_NEG _mm256_castsi256_ps(_mm256_set1_epi32(GLMM_NEGZEROf)) static inline __m128 glmm_abs(__m128 x) { return _mm_andnot_ps(glmm_float32x4_SIGNMASK_NEG, x); } static inline __m128 glmm_min(__m128 a, __m128 b) { return _mm_min_ps(a, b); } static inline __m128 glmm_max(__m128 a, __m128 b) { return _mm_max_ps(a, b); } static inline __m128 glmm_vhadd(__m128 v) { __m128 x0; x0 = _mm_add_ps(v, glmm_shuff1(v, 0, 1, 2, 3)); x0 = _mm_add_ps(x0, glmm_shuff1(x0, 1, 0, 0, 1)); return x0; } static inline __m128 glmm_vhadds(__m128 v) { #if defined(__SSE3__) __m128 shuf, sums; shuf = _mm_movehdup_ps(v); sums = _mm_add_ps(v, shuf); shuf = _mm_movehl_ps(shuf, sums); sums = _mm_add_ss(sums, shuf); return sums; #else __m128 shuf, sums; shuf = glmm_shuff1(v, 2, 3, 0, 1); sums = _mm_add_ps(v, shuf); shuf = _mm_movehl_ps(shuf, sums); sums = _mm_add_ss(sums, shuf); return sums; #endif } static inline float glmm_hadd(__m128 v) { return _mm_cvtss_f32(glmm_vhadds(v)); } static inline __m128 glmm_vhmin(__m128 v) { __m128 x0, x1, x2; x0 = _mm_movehl_ps(v, v); /* [2, 3, 2, 3] */ x1 = _mm_min_ps(x0, v); /* [0|2, 1|3, 2|2, 3|3] */ x2 = glmm_splat(x1, 1); /* [1|3, 1|3, 1|3, 1|3] */ return _mm_min_ss(x1, x2); } static inline float glmm_hmin(__m128 v) { return _mm_cvtss_f32(glmm_vhmin(v)); } static inline __m128 glmm_vhmax(__m128 v) { __m128 x0, x1, x2; x0 = _mm_movehl_ps(v, v); /* [2, 3, 2, 3] */ x1 = _mm_max_ps(x0, v); /* [0|2, 1|3, 2|2, 3|3] */ x2 = glmm_splat(x1, 1); /* [1|3, 1|3, 1|3, 1|3] */ return _mm_max_ss(x1, x2); } static inline float glmm_hmax(__m128 v) { return _mm_cvtss_f32(glmm_vhmax(v)); } static inline __m128 glmm_vdots(__m128 a, __m128 b) { #if (defined(__SSE4_1__) || defined(__SSE4_2__)) && defined(CGLM_SSE4_DOT) return _mm_dp_ps(a, b, 0xFF); #elif defined(__SSE3__) && defined(CGLM_SSE3_DOT) __m128 x0, x1; x0 = _mm_mul_ps(a, b); x1 = _mm_hadd_ps(x0, x0); return _mm_hadd_ps(x1, x1); #else return glmm_vhadds(_mm_mul_ps(a, b)); #endif } static inline __m128 glmm_vdot(__m128 a, __m128 b) { #if (defined(__SSE4_1__) || defined(__SSE4_2__)) && defined(CGLM_SSE4_DOT) return _mm_dp_ps(a, b, 0xFF); #elif defined(__SSE3__) && defined(CGLM_SSE3_DOT) __m128 x0, x1; x0 = _mm_mul_ps(a, b); x1 = _mm_hadd_ps(x0, x0); return _mm_hadd_ps(x1, x1); #else __m128 x0; x0 = _mm_mul_ps(a, b); x0 = _mm_add_ps(x0, glmm_shuff1(x0, 1, 0, 3, 2)); return _mm_add_ps(x0, glmm_shuff1(x0, 0, 1, 0, 1)); #endif } static inline float glmm_dot(__m128 a, __m128 b) { return _mm_cvtss_f32(glmm_vdots(a, b)); } static inline float glmm_norm(__m128 a) { return _mm_cvtss_f32(_mm_sqrt_ss(glmm_vhadds(_mm_mul_ps(a, a)))); } static inline float glmm_norm2(__m128 a) { return _mm_cvtss_f32(glmm_vhadds(_mm_mul_ps(a, a))); } static inline float glmm_norm_one(__m128 a) { return _mm_cvtss_f32(glmm_vhadds(glmm_abs(a))); } static inline float glmm_norm_inf(__m128 a) { return _mm_cvtss_f32(glmm_vhmax(glmm_abs(a))); } #if defined(__SSE2__) static inline __m128 glmm_load3(float v[3]) { __m128i xy; __m128 z; xy = _mm_loadl_epi64(CGLM_CASTPTR_ASSUME_ALIGNED(v, const __m128i)); z = _mm_load_ss(&v[2]); return _mm_movelh_ps(_mm_castsi128_ps(xy), z); } static inline void glmm_store3(float v[3], __m128 vx) { _mm_storel_pi(CGLM_CASTPTR_ASSUME_ALIGNED(v, __m64), vx); _mm_store_ss(&v[2], glmm_shuff1(vx, 2, 2, 2, 2)); } #endif static inline __m128 glmm_div(__m128 a, __m128 b) { return _mm_div_ps(a, b); } /* enable FMA macro for MSVC? */ #if defined(_MSC_VER) && !defined(__FMA__) && defined(__AVX2__) # define __FMA__ 1 #endif static inline __m128 glmm_fmadd(__m128 a, __m128 b, __m128 c) { #ifdef __FMA__ return _mm_fmadd_ps(a, b, c); #else return _mm_add_ps(c, _mm_mul_ps(a, b)); #endif } static inline __m128 glmm_fnmadd(__m128 a, __m128 b, __m128 c) { #ifdef __FMA__ return _mm_fnmadd_ps(a, b, c); #else return _mm_sub_ps(c, _mm_mul_ps(a, b)); #endif } static inline __m128 glmm_fmsub(__m128 a, __m128 b, __m128 c) { #ifdef __FMA__ return _mm_fmsub_ps(a, b, c); #else return _mm_sub_ps(_mm_mul_ps(a, b), c); #endif } static inline __m128 glmm_fnmsub(__m128 a, __m128 b, __m128 c) { #ifdef __FMA__ return _mm_fnmsub_ps(a, b, c); #else return _mm_xor_ps(_mm_add_ps(_mm_mul_ps(a, b), c), glmm_float32x4_SIGNMASK_NEG); #endif } #if defined(__AVX__) static inline __m256 glmm256_fmadd(__m256 a, __m256 b, __m256 c) { #ifdef __FMA__ return _mm256_fmadd_ps(a, b, c); #else return _mm256_add_ps(c, _mm256_mul_ps(a, b)); #endif } static inline __m256 glmm256_fnmadd(__m256 a, __m256 b, __m256 c) { #ifdef __FMA__ return _mm256_fnmadd_ps(a, b, c); #else return _mm256_sub_ps(c, _mm256_mul_ps(a, b)); #endif } static inline __m256 glmm256_fmsub(__m256 a, __m256 b, __m256 c) { #ifdef __FMA__ return _mm256_fmsub_ps(a, b, c); #else return _mm256_sub_ps(_mm256_mul_ps(a, b), c); #endif } static inline __m256 glmm256_fnmsub(__m256 a, __m256 b, __m256 c) { #ifdef __FMA__ return _mm256_fmsub_ps(a, b, c); #else return _mm256_xor_ps(_mm256_sub_ps(_mm256_mul_ps(a, b), c), glmm_float32x8_SIGNMASK_NEG); #endif } #endif #endif #endif /* cglm_simd_x86_h */ cglm-0.9.7/include/cglm/sphere.h000066400000000000000000000037061526744317200164760ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_sphere_h #define cglm_sphere_h #include "common.h" #include "mat4.h" /* Sphere Representation in cglm: [center.x, center.y, center.z, radii] You could use this representation or you can convert it to vec4 before call any function */ /*! * @brief helper for getting sphere radius * * @param[in] s sphere * * @return returns radii */ CGLM_INLINE float glm_sphere_radii(vec4 s) { return s[3]; } /*! * @brief apply transform to sphere, it is just wrapper for glm_mat4_mulv3 * * @param[in] s sphere * @param[in] m transform matrix * @param[out] dest transformed sphere */ CGLM_INLINE void glm_sphere_transform(vec4 s, mat4 m, vec4 dest) { glm_mat4_mulv3(m, s, 1.0f, dest); dest[3] = s[3]; } /*! * @brief merges two spheres and creates a new one * * two sphere must be in same space, for instance if one in world space then * the other must be in world space too, not in local space. * * @param[in] s1 sphere 1 * @param[in] s2 sphere 2 * @param[out] dest merged/extended sphere */ CGLM_INLINE void glm_sphere_merge(vec4 s1, vec4 s2, vec4 dest) { float dist, radii; dist = glm_vec3_distance(s1, s2); radii = dist + s1[3] + s2[3]; radii = glm_max(radii, s1[3]); radii = glm_max(radii, s2[3]); glm_vec3_center(s1, s2, dest); dest[3] = radii; } /*! * @brief check if two sphere intersects * * @param[in] s1 sphere * @param[in] s2 other sphere */ CGLM_INLINE bool glm_sphere_sphere(vec4 s1, vec4 s2) { return glm_vec3_distance2(s1, s2) <= glm_pow2(s1[3] + s2[3]); } /*! * @brief check if sphere intersects with point * * @param[in] s sphere * @param[in] point point */ CGLM_INLINE bool glm_sphere_point(vec4 s, vec3 point) { float rr; rr = s[3] * s[3]; return glm_vec3_distance2(point, s) <= rr; } #endif /* cglm_sphere_h */ cglm-0.9.7/include/cglm/struct.h000066400000000000000000000021351526744317200165270ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_structs_h #define cglm_structs_h #ifdef __cplusplus extern "C" { #endif #include "cglm.h" #include "types-struct.h" #include "struct/vec2.h" #include "struct/vec3.h" #include "struct/vec4.h" #include "struct/ivec2.h" #include "struct/ivec3.h" #include "struct/ivec4.h" #include "struct/mat2.h" #include "struct/mat2x3.h" #include "struct/mat2x4.h" #include "struct/mat3.h" #include "struct/mat3x2.h" #include "struct/mat3x4.h" #include "struct/mat4.h" #include "struct/mat4x2.h" #include "struct/mat4x3.h" #include "struct/affine.h" #include "struct/frustum.h" #include "struct/plane.h" #include "struct/noise.h" #include "struct/box.h" #include "struct/color.h" #include "struct/io.h" #include "struct/cam.h" #include "struct/quat.h" #include "struct/euler.h" #include "struct/project.h" #include "struct/sphere.h" #include "struct/curve.h" #include "struct/affine2d.h" #include "struct/ray.h" #ifdef __cplusplus } #endif #endif /* cglm_structs_h */ cglm-0.9.7/include/cglm/struct/000077500000000000000000000000001526744317200163555ustar00rootroot00000000000000cglm-0.9.7/include/cglm/struct/aabb2d.h000066400000000000000000000131111526744317200176360ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglms_aabb2ds_h #define cglms_aabb2ds_h #include "../common.h" #include "../types-struct.h" #include "../aabb2d.h" #include "vec2.h" #include "vec4.h" #include "mat4.h" /* api definition */ #define glms_aabb2d_(NAME) CGLM_STRUCTAPI(aabb2d, NAME) /*! * @brief apply transform to Axis-Aligned Bounding Box * * @param[in] aabb bounding box * @param[in] m transform matrix * @param[out] dest transformed bounding box */ CGLM_INLINE void glms_aabb2d_(transform)(vec2s aabb[2], mat3s m, vec2s dest[2]) { vec2 rawAabb[2]; vec2 rawDest[2]; glms_vec2_(unpack)(rawAabb, aabb, 2); glm_aabb2d_transform(rawAabb, m.raw, rawDest); glms_vec2_(pack)(dest, rawDest, 2); } /*! * @brief merges two AABB bounding box and creates new one * * two box must be in same space, if one of box is in different space then * you should consider to convert it's space by glm_box_space * * @param[in] aabb1 bounding box 1 * @param[in] aabb2 bounding box 2 * @param[out] dest merged bounding box */ CGLM_INLINE void glms_aabb2d_(merge)(vec2s aabb1[2], vec2s aabb2[2], vec2s dest[2]) { vec2 rawAabb1[2]; vec2 rawAabb2[2]; vec2 rawDest[2]; glms_vec2_(unpack)(rawAabb1, aabb1, 2); glms_vec2_(unpack)(rawAabb2, aabb2, 2); glm_aabb2d_merge(rawAabb1, rawAabb2, rawDest); glms_vec2_(pack)(dest, rawDest, 2); } /*! * @brief crops a bounding box with another one. * * this could be useful for getting a bbox which fits with view frustum and * object bounding boxes. In this case you crop view frustum box with objects * box * * @param[in] aabb bounding box 1 * @param[in] cropAabb crop box * @param[out] dest cropped bounding box */ CGLM_INLINE void glms_aabb2d_(crop)(vec2s aabb[2], vec2s cropAabb[2], vec2s dest[2]) { vec2 rawAabb[2]; vec2 rawCropAabb[2]; vec2 rawDest[2]; glms_vec2_(unpack)(rawAabb, aabb, 2); glms_vec2_(unpack)(rawCropAabb, cropAabb, 2); glm_aabb2d_crop(rawAabb, rawCropAabb, rawDest); glms_vec2_(pack)(dest, rawDest, 2); } /*! * @brief crops a bounding box with another one. * * this could be useful for getting a bbox which fits with view frustum and * object bounding boxes. In this case you crop view frustum box with objects * box * * @param[in] aabb bounding box * @param[in] cropAabb crop box * @param[in] clampAabb minimum box * @param[out] dest cropped bounding box */ CGLM_INLINE void glms_aabb2d_(crop_until)(vec2s aabb[2], vec2s cropAabb[2], vec2s clampAabb[2], vec2s dest[2]) { glms_aabb2d_(crop)(aabb, cropAabb, dest); glms_aabb2d_(merge)(clampAabb, dest, dest); } /*! * @brief invalidate AABB min and max values * * @param[in, out] aabb bounding box */ CGLM_INLINE void glms_aabb2d_(invalidate)(vec2s box[2]) { box[0] = glms_vec2_(fill)(FLT_MAX); box[1] = glms_vec2_(fill)(-FLT_MAX); } /*! * @brief check if AABB is valid or not * * @param[in] aabb bounding box */ CGLM_INLINE bool glms_aabb2d_(isvalid)(vec2s aabb[2]) { vec2 rawAabb[2]; glms_vec2_(unpack)(rawAabb, aabb, 2); return glm_aabb2d_isvalid(rawAabb); } /*! * @brief distance between of min and max * * @param[in] aabb bounding box */ CGLM_INLINE float glms_aabb2d_(diag)(vec2s aabb[2]) { vec2 rawAabb[2]; glms_vec2_(unpack)(rawAabb, aabb, 2); return glm_aabb2d_diag(rawAabb); } /*! * @brief size of aabb * * @param[in] aabb bounding aabb * @param[out] dest size */ CGLM_INLINE vec2s glms_aabb2d_(sizev)(vec2s aabb[2]) { vec2s size; vec2 rawAabb[2]; glms_vec2_(unpack)(rawAabb, aabb, 2); glm_aabb2d_sizev(rawAabb, size.raw); return size; } /*! * @brief radius of sphere which surrounds AABB * * @param[in] aabb bounding box */ CGLM_INLINE float glms_aabb2d_(radius)(vec2s aabb[2]) { return glms_aabb2d_(diag)(aabb) * 0.5f; } /*! * @brief computes center point of AABB * * @param[in] aabb bounding box * @returns center of bounding box */ CGLM_INLINE vec2s glms_aabb2d_(center)(vec2s aabb[2]) { return glms_vec2_(center)(aabb[0], aabb[1]); } /*! * @brief check if two AABB intersects * * @param[in] aabb bounding box * @param[in] other other bounding box */ CGLM_INLINE bool glms_aabb2d_(aabb)(vec2s aabb[2], vec2s other[2]) { vec2 rawAabb[2]; vec2 rawOther[2]; glms_vec2_(unpack)(rawAabb, aabb, 2); glms_vec2_(unpack)(rawOther, other, 2); return glm_aabb2d_aabb(rawAabb, rawOther); } /*! * @brief check if AABB intersects with a circle * * https://github.com/erich666/GraphicsGems/blob/master/gems/BoxSphere.c * Solid Box - Solid Sphere test. * * @param[in] aabb solid bounding box * @param[in] s solid sphere */ CGLM_INLINE bool glms_aabb2d_(circle)(vec2s aabb[2], vec3s c) { vec2 rawAabb[2]; glms_vec2_(unpack)(rawAabb, aabb, 2); return glm_aabb2d_circle(rawAabb, c.raw); } /*! * @brief check if point is inside of AABB * * @param[in] aabb bounding box * @param[in] point point */ CGLM_INLINE bool glms_aabb2d_(point)(vec2s aabb[2], vec2s point) { vec2 rawAabb[2]; glms_vec2_(unpack)(rawAabb, aabb, 2); return glm_aabb2d_point(rawAabb, point.raw); } /*! * @brief check if AABB contains other AABB * * @param[in] box bounding box * @param[in] other other bounding box */ CGLM_INLINE bool glms_aabb2d_(contains)(vec2s aabb[2], vec2s other[2]) { vec2 rawAabb[2]; vec2 rawOther[2]; glms_vec2_(unpack)(rawAabb, aabb, 2); glms_vec2_(unpack)(rawOther, other, 2); return glm_aabb2d_contains(rawAabb, rawOther); } #endif /* cglms_aabb2ds_h */ cglm-0.9.7/include/cglm/struct/affine-mat.h000066400000000000000000000036731526744317200205460ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE mat4s glms_mul(mat4 m1, mat4 m2); CGLM_INLINE mat4s glms_mul_rot(mat4 m1, mat4 m2); CGLM_INLINE mat4s glms_inv_tr(); */ #ifndef cglms_affine_mat_h #define cglms_affine_mat_h #include "../common.h" #include "../types-struct.h" #include "../affine-mat.h" #include "vec3.h" #include "vec4.h" #include "mat4.h" /*! * @brief this is similar to glms_mat4_mul but specialized to affine transform * * Matrix format should be: * R R R X * R R R Y * R R R Z * 0 0 0 W * * this reduces some multiplications. It should be faster than mat4_mul. * if you are not sure about matrix format then DON'T use this! use mat4_mul * * @param[in] m1 affine matrix 1 * @param[in] m2 affine matrix 2 * @returns destination matrix */ CGLM_INLINE mat4s glms_mul(mat4s m1, mat4s m2){ mat4s r; glm_mul(m1.raw, m2.raw, r.raw); return r; } /*! * @brief this is similar to glm_mat4_mul but specialized to affine transform * * Right Matrix format should be: * R R R 0 * R R R 0 * R R R 0 * 0 0 0 1 * * this reduces some multiplications. It should be faster than mat4_mul. * if you are not sure about matrix format then DON'T use this! use mat4_mul * * @param[in] m1 affine matrix 1 * @param[in] m2 affine matrix 2 * @returns destination matrix */ CGLM_INLINE mat4s glms_mul_rot(mat4s m1, mat4s m2){ mat4s r; glm_mul_rot(m1.raw, m2.raw, r.raw); return r; } /*! * @brief inverse orthonormal rotation + translation matrix (ridig-body) * * @code * X = | R T | X' = | R' -R'T | * | 0 1 | | 0 1 | * @endcode * * @param[in] m matrix * @returns destination matrix */ CGLM_INLINE mat4s glms_inv_tr(mat4s m){ glm_inv_tr(m.raw); return m; } #endif /* cglms_affine_mat_h */ cglm-0.9.7/include/cglm/struct/affine-post.h000066400000000000000000000107041526744317200207430ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE mat4s glms_translated(mat4s m, vec3s v); CGLM_INLINE mat4s glms_translated_x(mat4s m, float x); CGLM_INLINE mat4s glms_translated_y(mat4s m, float y); CGLM_INLINE mat4s glms_translated_z(mat4s m, float z); CGLM_INLINE mat4s glms_rotated_x(mat4s m, float angle); CGLM_INLINE mat4s glms_rotated_y(mat4s m, float angle); CGLM_INLINE mat4s glms_rotated_z(mat4s m, float angle); CGLM_INLINE mat4s glms_rotated(mat4s m, float angle, vec3s axis); CGLM_INLINE mat4s glms_rotated_at(mat4s m, vec3s pivot, float angle, vec3s axis); CGLM_INLINE mat4s glms_spinned(mat4s m, float angle, vec3s axis); */ #ifndef cglms_affines_post_h #define cglms_affines_post_h #include "../common.h" #include "../types-struct.h" #include "../affine.h" #include "vec3.h" #include "vec4.h" #include "mat4.h" /*! * @brief translate existing transform matrix by v vector * and stores result in same matrix * * @param[in] m affine transform * @param[in] v translate vector [x, y, z] * @returns affine transform */ CGLM_INLINE mat4s glms_translated(mat4s m, vec3s v) { glm_translated(m.raw, v.raw); return m; } /*! * @brief translate existing transform matrix by x factor * * @param[in] m affine transform * @param[in] x x factor * @returns affine transform */ CGLM_INLINE mat4s glms_translated_x(mat4s m, float x) { glm_translated_x(m.raw, x); return m; } /*! * @brief translate existing transform matrix by y factor * * @param[in] m affine transform * @param[in] y y factor * @returns affine transform */ CGLM_INLINE mat4s glms_translated_y(mat4s m, float y) { glm_translated_y(m.raw, y); return m; } /*! * @brief translate existing transform matrix by z factor * * @param[in] m affine transform * @param[in] z z factor * @returns affine transform */ CGLM_INLINE mat4s glms_translated_z(mat4s m, float z) { glm_translated_z(m.raw, z); return m; } /*! * @brief rotate existing transform matrix around X axis by angle * and store result in dest * * @param[in] m affine transform * @param[in] angle angle (radians) * @returns rotated matrix */ CGLM_INLINE mat4s glms_rotated_x(mat4s m, float angle) { mat4s r; glm_rotated_x(m.raw, angle, r.raw); return r; } /*! * @brief rotate existing transform matrix around Y axis by angle * and store result in dest * * @param[in] m affine transform * @param[in] angle angle (radians) * @returns rotated matrix */ CGLM_INLINE mat4s glms_rotated_y(mat4s m, float angle) { mat4s r; glm_rotated_y(m.raw, angle, r.raw); return r; } /*! * @brief rotate existing transform matrix around Z axis by angle * and store result in dest * * @param[in] m affine transform * @param[in] angle angle (radians) * @returns rotated matrix */ CGLM_INLINE mat4s glms_rotated_z(mat4s m, float angle) { mat4s r; glm_rotated_z(m.raw, angle, r.raw); return r; } /*! * @brief rotate existing transform matrix around given axis by angle * * @param[in] m affine transform * @param[in] angle angle (radians) * @param[in] axis axis * @returns affine transform */ CGLM_INLINE mat4s glms_rotated(mat4s m, float angle, vec3s axis) { glm_rotated(m.raw, angle, axis.raw); return m; } /*! * @brief rotate existing transform * around given axis by angle at given pivot point (rotation center) * * @param[in] m affine transform * @param[in] pivot rotation center * @param[in] angle angle (radians) * @param[in] axis axis * @returns affine transform */ CGLM_INLINE mat4s glms_rotated_at(mat4s m, vec3s pivot, float angle, vec3s axis) { glm_rotated_at(m.raw, pivot.raw, angle, axis.raw); return m; } /*! * @brief rotate existing transform matrix around given axis by angle around self (doesn't affected by position) * * @param[in] m affine transform * @param[in] angle angle (radians) * @param[in] axis axis * @returns affine transform */ CGLM_INLINE mat4s glms_spinned(mat4s m, float angle, vec3s axis) { glm_spinned(m.raw, angle, axis.raw); return m; } #endif /* cglms_affines_post_h */ cglm-0.9.7/include/cglm/struct/affine-pre.h000066400000000000000000000106351526744317200205470ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE mat4s glms_translate(mat4s m, vec3s v); CGLM_INLINE mat4s glms_translate_x(mat4s m, float x); CGLM_INLINE mat4s glms_translate_y(mat4s m, float y); CGLM_INLINE mat4s glms_translate_z(mat4s m, float z); CGLM_INLINE mat4s glms_rotate_x(mat4s m, float angle); CGLM_INLINE mat4s glms_rotate_y(mat4s m, float angle); CGLM_INLINE mat4s glms_rotate_z(mat4s m, float angle); CGLM_INLINE mat4s glms_rotate(mat4s m, float angle, vec3s axis); CGLM_INLINE mat4s glms_rotate_at(mat4s m, vec3s pivot, float angle, vec3s axis); CGLM_INLINE mat4s glms_spin(mat4s m, float angle, vec3s axis); */ #ifndef cglms_affines_pre_h #define cglms_affines_pre_h #include "../common.h" #include "../types-struct.h" #include "../affine.h" #include "vec3.h" #include "vec4.h" #include "mat4.h" /*! * @brief translate existing transform matrix by v vector * and stores result in same matrix * * @param[in] m affine transform * @param[in] v translate vector [x, y, z] * @returns affine transform */ CGLM_INLINE mat4s glms_translate(mat4s m, vec3s v) { glm_translate(m.raw, v.raw); return m; } /*! * @brief translate existing transform matrix by x factor * * @param[in] m affine transform * @param[in] x x factor * @returns affine transform */ CGLM_INLINE mat4s glms_translate_x(mat4s m, float x) { glm_translate_x(m.raw, x); return m; } /*! * @brief translate existing transform matrix by y factor * * @param[in] m affine transform * @param[in] y y factor * @returns affine transform */ CGLM_INLINE mat4s glms_translate_y(mat4s m, float y) { glm_translate_y(m.raw, y); return m; } /*! * @brief translate existing transform matrix by z factor * * @param[in] m affine transform * @param[in] z z factor * @returns affine transform */ CGLM_INLINE mat4s glms_translate_z(mat4s m, float z) { glm_translate_z(m.raw, z); return m; } /*! * @brief rotate existing transform matrix around X axis by angle * and store result in dest * * @param[in] m affine transform * @param[in] angle angle (radians) * @returns rotated matrix */ CGLM_INLINE mat4s glms_rotate_x(mat4s m, float angle) { mat4s r; glm_rotate_x(m.raw, angle, r.raw); return r; } /*! * @brief rotate existing transform matrix around Y axis by angle * and store result in dest * * @param[in] m affine transform * @param[in] angle angle (radians) * @returns rotated matrix */ CGLM_INLINE mat4s glms_rotate_y(mat4s m, float angle) { mat4s r; glm_rotate_y(m.raw, angle, r.raw); return r; } /*! * @brief rotate existing transform matrix around Z axis by angle * and store result in dest * * @param[in] m affine transform * @param[in] angle angle (radians) * @returns rotated matrix */ CGLM_INLINE mat4s glms_rotate_z(mat4s m, float angle) { mat4s r; glm_rotate_z(m.raw, angle, r.raw); return r; } /*! * @brief rotate existing transform matrix around given axis by angle * * @param[in] m affine transform * @param[in] angle angle (radians) * @param[in] axis axis * @returns affine transform */ CGLM_INLINE mat4s glms_rotate(mat4s m, float angle, vec3s axis) { glm_rotate(m.raw, angle, axis.raw); return m; } /*! * @brief rotate existing transform * around given axis by angle at given pivot point (rotation center) * * @param[in] m affine transform * @param[in] pivot rotation center * @param[in] angle angle (radians) * @param[in] axis axis * @returns affine transform */ CGLM_INLINE mat4s glms_rotate_at(mat4s m, vec3s pivot, float angle, vec3s axis) { glm_rotate_at(m.raw, pivot.raw, angle, axis.raw); return m; } /*! * @brief rotate existing transform matrix around given axis by angle around self (doesn't affected by position) * * @param[in] m affine transform * @param[in] angle angle (radians) * @param[in] axis axis * @returns affine transform */ CGLM_INLINE mat4s glms_spin(mat4s m, float angle, vec3s axis) { glm_spin(m.raw, angle, axis.raw); return m; } #endif /* cglms_affines_pre_h */ cglm-0.9.7/include/cglm/struct/affine.h000066400000000000000000000117031526744317200177600ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE mat4s glms_translate(mat4s m, vec3s v); CGLM_INLINE mat4s glms_translate_x(mat4s m, float x); CGLM_INLINE mat4s glms_translate_y(mat4s m, float y); CGLM_INLINE mat4s glms_translate_z(mat4s m, float z); CGLM_INLINE mat4s glms_translate_make(vec3s v); CGLM_INLINE mat4s glms_scale_to(mat4s m, vec3s v); CGLM_INLINE mat4s glms_scale_make(vec3s v); CGLM_INLINE mat4s glms_scale(mat4s m, vec3s v); CGLM_INLINE mat4s glms_scale_uni(mat4s m, float s); CGLM_INLINE mat4s glms_rotate_x(mat4s m, float angle); CGLM_INLINE mat4s glms_rotate_y(mat4s m, float angle); CGLM_INLINE mat4s glms_rotate_z(mat4s m, float angle); CGLM_INLINE mat4s glms_rotate_make(float angle, vec3s axis); CGLM_INLINE mat4s glms_rotate(mat4s m, float angle, vec3s axis); CGLM_INLINE mat4s glms_rotate_at(mat4s m, vec3s pivot, float angle, vec3s axis); CGLM_INLINE mat4s glms_rotate_atm(vec3s pivot, float angle, vec3s axis); CGLM_INLINE mat4s glms_spin(mat4s m, float angle, vec3s axis); CGLM_INLINE vec3s glms_decompose_scalev(mat4s m); CGLM_INLINE bool glms_uniscaled(mat4s m); CGLM_INLINE void glms_decompose_rs(mat4s m, mat4s * r, vec3s * s); CGLM_INLINE void glms_decompose(mat4s m, vec4s t, mat4s * r, vec3s * s); */ #ifndef cglms_affines_h #define cglms_affines_h #include "../common.h" #include "../types-struct.h" #include "../affine.h" #include "vec3.h" #include "vec4.h" #include "mat4.h" #include "affine-mat.h" /*! * @brief creates NEW translate transform matrix by v vector * * @param[in] v translate vector [x, y, z] * @returns affine transform */ CGLM_INLINE mat4s glms_translate_make(vec3s v) { mat4s m; glm_translate_make(m.raw, v.raw); return m; } /*! * @brief creates NEW scale matrix by v vector * * @param[in] v scale vector [x, y, z] * @returns affine transform */ CGLM_INLINE mat4s glms_scale_make(vec3s v) { mat4s m; glm_scale_make(m.raw, v.raw); return m; } /*! * @brief scales existing transform matrix by v vector * and stores result in same matrix * * @param[in] m affine transform * @param[in] v scale vector [x, y, z] * @returns affine transform */ CGLM_INLINE mat4s glms_scale(mat4s m, vec3s v) { mat4s r; glm_scale_to(m.raw, v.raw, r.raw); return r; } /*! * @brief applies uniform scale to existing transform matrix v = [s, s, s] * and stores result in same matrix * * @param[in] m affine transform * @param[in] s scale factor * @returns affine transform */ CGLM_INLINE mat4s glms_scale_uni(mat4s m, float s) { glm_scale_uni(m.raw, s); return m; } /*! * @brief creates NEW rotation matrix by angle and axis * * axis will be normalized so you don't need to normalize it * * @param[in] angle angle (radians) * @param[in] axis axis * @returns affine transform */ CGLM_INLINE mat4s glms_rotate_make(float angle, vec3s axis) { mat4s m; glm_rotate_make(m.raw, angle, axis.raw); return m; } /*! * @brief creates NEW rotation matrix by angle and axis at given point * * this creates rotation matrix, it assumes you don't have a matrix * * this should work faster than glm_rotate_at because it reduces * one glm_translate. * * @param[in] pivot rotation center * @param[in] angle angle (radians) * @param[in] axis axis * @returns affine transform */ CGLM_INLINE mat4s glms_rotate_atm(vec3s pivot, float angle, vec3s axis) { mat4s m; glm_rotate_atm(m.raw, pivot.raw, angle, axis.raw); return m; } /*! * @brief decompose scale vector * * @param[in] m affine transform * @returns scale vector (Sx, Sy, Sz) */ CGLM_INLINE vec3s glms_decompose_scalev(mat4s m) { vec3s r; glm_decompose_scalev(m.raw, r.raw); return r; } /*! * @brief returns true if matrix is uniform scaled. This is helpful for * creating normal matrix. * * @param[in] m m * * @return boolean */ CGLM_INLINE bool glms_uniscaled(mat4s m) { return glm_uniscaled(m.raw); } /*! * @brief decompose rotation matrix (mat4) and scale vector [Sx, Sy, Sz] * DON'T pass projected matrix here * * @param[in] m affine transform * @param[out] r rotation matrix * @param[out] s scale matrix */ CGLM_INLINE void glms_decompose_rs(mat4s m, mat4s * __restrict r, vec3s * __restrict s) { glm_decompose_rs(m.raw, r->raw, s->raw); } /*! * @brief decompose affine transform, TODO: extract shear factors. * DON'T pass projected matrix here * * @param[in] m affine transform * @param[out] t translation vector * @param[out] r rotation matrix (mat4) * @param[out] s scaling vector [X, Y, Z] */ CGLM_INLINE void glms_decompose(mat4s m, vec4s * __restrict t, mat4s * __restrict r, vec3s * __restrict s) { glm_decompose(m.raw, t->raw, r->raw, s->raw); } #include "affine-pre.h" #include "affine-post.h" #endif /* cglms_affines_h */ cglm-0.9.7/include/cglm/struct/affine2d.h000066400000000000000000000074421526744317200202130ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE mat3s glms_translate2d(mat3 m, vec2 v) CGLM_INLINE mat3s glms_translate2d_x(mat3s m, float x) CGLM_INLINE mat3s glms_translate2d_y(mat3s m, float y) CGLM_INLINE mat3s glms_translate2d_make(vec2s v) CGLM_INLINE mat3s glms_scale2d_make(vec2s v) CGLM_INLINE mat3s glms_scale2d(mat3s m, vec2s v) CGLM_INLINE mat3s glms_scale2d_uni(mat3s m, float s) CGLM_INLINE mat3s glms_rotate2d_make(float angle) CGLM_INLINE mat3s glms_rotate2d(mat3s m, float angle) CGLM_INLINE mat3s glms_rotate2d_to(mat3s m, float angle) */ #ifndef cglms_affine2ds_h #define cglms_affine2ds_h #include "../common.h" #include "../types-struct.h" #include "../affine2d.h" #include "vec3.h" #include "mat3.h" /*! * @brief translate existing 2d transform matrix by v vector * and stores result in same matrix * * @param[in] m affine transform * @param[in] v translate vector [x, y] * @returns affine transform */ CGLM_INLINE mat3s glms_translate2d(mat3s m, vec2s v) { glm_translate2d(m.raw, v.raw); return m; } /*! * @brief translate existing 2d transform matrix by x factor * * @param[in] m affine transform * @param[in] x x factor * @returns affine transform */ CGLM_INLINE mat3s glms_translate2d_x(mat3s m, float x) { glm_translate2d_x(m.raw, x); return m; } /*! * @brief translate existing 2d transform matrix by y factor * * @param[in] m affine transform * @param[in] y y factor * @returns affine transform */ CGLM_INLINE mat3s glms_translate2d_y(mat3s m, float y) { glm_translate2d_y(m.raw, y); return m; } /*! * @brief creates NEW translate 2d transform matrix by v vector * * @param[in] v translate vector [x, y] * @returns affine transform */ CGLM_INLINE mat3s glms_translate2d_make(vec2s v) { mat3s m; glm_translate2d_make(m.raw, v.raw); return m; } /*! * @brief creates NEW 2d scale matrix by v vector * * @param[in] v scale vector [x, y] * @returns affine transform */ CGLM_INLINE mat3s glms_scale2d_make(vec2s v) { mat3s m; glm_scale2d_make(m.raw, v.raw); return m; } /*! * @brief scales existing 2d transform matrix by v vector * and stores result in same matrix * * @param[in] m affine transform * @param[in] v scale vector [x, y, z] * @returns affine transform */ CGLM_INLINE mat3s glms_scale2d(mat3s m, vec2s v) { mat3s r; glm_scale2d_to(m.raw, v.raw, r.raw); return r; } /*! * @brief applies uniform scale to existing 2d transform matrix v = [s, s, s] * and stores result in same matrix * * @param[in] m affine transform * @param[in] s scale factor * @returns affine transform */ CGLM_INLINE mat3s glms_scale2d_uni(mat3s m, float s) { glm_scale2d_uni(m.raw, s); return m; } /*! * @brief creates NEW 2d rotation matrix by angle and axis * * axis will be normalized so you don't need to normalize it * * @param[in] angle angle (radians) * @returns affine transform */ CGLM_INLINE mat3s glms_rotate2d_make(float angle) { mat3s m; glm_rotate2d_make(m.raw, angle); return m; } /*! * @brief rotate existing 2d transform matrix around given axis by angle * * @param[in] m affine transform * @param[in] angle angle (radians) * @returns affine transform */ CGLM_INLINE mat3s glms_rotate2d(mat3s m, float angle) { glm_rotate2d(m.raw, angle); return m; } /*! * @brief rotate existing 2d transform matrix around given axis by angle * * @param[in] m affine transform * @param[in] angle angle (radians) * @returns affine transform */ CGLM_INLINE mat3s glms_rotate2d_to(mat3s m, float angle) { glm_rotate2d(m.raw, angle); return m; } #endif /* cglms_affine2ds_h */ cglm-0.9.7/include/cglm/struct/box.h000066400000000000000000000135421526744317200173230ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglms_boxs_h #define cglms_boxs_h #include "../common.h" #include "../types-struct.h" #include "../box.h" #include "vec3.h" #include "vec4.h" #include "mat4.h" /* api definition */ #define glms_aabb_(NAME) CGLM_STRUCTAPI(aabb, NAME) /*! * @brief apply transform to Axis-Aligned Bounding Box * * @param[in] box bounding box * @param[in] m transform matrix * @param[out] dest transformed bounding box */ CGLM_INLINE void glms_aabb_(transform)(vec3s box[2], mat4s m, vec3s dest[2]) { vec3 rawBox[2]; vec3 rawDest[2]; glms_vec3_(unpack)(rawBox, box, 2); glm_aabb_transform(rawBox, m.raw, rawDest); glms_vec3_(pack)(dest, rawDest, 2); } /*! * @brief merges two AABB bounding box and creates new one * * two box must be in same space, if one of box is in different space then * you should consider to convert it's space by glm_box_space * * @param[in] box1 bounding box 1 * @param[in] box2 bounding box 2 * @param[out] dest merged bounding box */ CGLM_INLINE void glms_aabb_(merge)(vec3s box1[2], vec3s box2[2], vec3s dest[2]) { vec3 rawBox1[2]; vec3 rawBox2[2]; vec3 rawDest[2]; glms_vec3_(unpack)(rawBox1, box1, 2); glms_vec3_(unpack)(rawBox2, box2, 2); glm_aabb_merge(rawBox1, rawBox2, rawDest); glms_vec3_(pack)(dest, rawDest, 2); } /*! * @brief crops a bounding box with another one. * * this could be useful for getting a bbox which fits with view frustum and * object bounding boxes. In this case you crop view frustum box with objects * box * * @param[in] box bounding box 1 * @param[in] cropBox crop box * @param[out] dest cropped bounding box */ CGLM_INLINE void glms_aabb_(crop)(vec3s box[2], vec3s cropBox[2], vec3s dest[2]) { vec3 rawBox[2]; vec3 rawCropBox[2]; vec3 rawDest[2]; glms_vec3_(unpack)(rawBox, box, 2); glms_vec3_(unpack)(rawCropBox, cropBox, 2); glm_aabb_crop(rawBox, rawCropBox, rawDest); glms_vec3_(pack)(dest, rawDest, 2); } /*! * @brief crops a bounding box with another one. * * this could be useful for getting a bbox which fits with view frustum and * object bounding boxes. In this case you crop view frustum box with objects * box * * @param[in] box bounding box * @param[in] cropBox crop box * @param[in] clampBox minimum box * @param[out] dest cropped bounding box */ CGLM_INLINE void glms_aabb_(crop_until)(vec3s box[2], vec3s cropBox[2], vec3s clampBox[2], vec3s dest[2]) { glms_aabb_(crop)(box, cropBox, dest); glms_aabb_(merge)(clampBox, dest, dest); } /*! * @brief check if AABB intersects with frustum planes * * this could be useful for frustum culling using AABB. * * OPTIMIZATION HINT: * if planes order is similar to LEFT, RIGHT, BOTTOM, TOP, NEAR, FAR * then this method should run even faster because it would only use two * planes if object is not inside the two planes * fortunately cglm extracts planes as this order! just pass what you got! * * @param[in] box bounding box * @param[in] planes frustum planes */ CGLM_INLINE bool glms_aabb_(frustum)(vec3s box[2], vec4s planes[6]) { vec3 rawBox[2]; vec4 rawPlanes[6]; glms_vec3_(unpack)(rawBox, box, 2); glms_vec4_(unpack)(rawPlanes, planes, 6); return glm_aabb_frustum(rawBox, rawPlanes); } /*! * @brief invalidate AABB min and max values * * @param[in, out] box bounding box */ CGLM_INLINE void glms_aabb_(invalidate)(vec3s box[2]) { box[0] = glms_vec3_(broadcast)(FLT_MAX); box[1] = glms_vec3_(broadcast)(-FLT_MAX); } /*! * @brief check if AABB is valid or not * * @param[in] box bounding box */ CGLM_INLINE bool glms_aabb_(isvalid)(vec3s box[2]) { vec3 rawBox[2]; glms_vec3_(unpack)(rawBox, box, 2); return glm_aabb_isvalid(rawBox); } /*! * @brief distance between of min and max * * @param[in] box bounding box */ CGLM_INLINE float glms_aabb_(size)(vec3s box[2]) { return glm_vec3_distance(box[0].raw, box[1].raw); } /*! * @brief radius of sphere which surrounds AABB * * @param[in] box bounding box */ CGLM_INLINE float glms_aabb_(radius)(vec3s box[2]) { return glms_aabb_(size)(box) * 0.5f; } /*! * @brief computes center point of AABB * * @param[in] box bounding box * @returns center of bounding box */ CGLM_INLINE vec3s glms_aabb_(center)(vec3s box[2]) { return glms_vec3_(center)(box[0], box[1]); } /*! * @brief check if two AABB intersects * * @param[in] box bounding box * @param[in] other other bounding box */ CGLM_INLINE bool glms_aabb_(aabb)(vec3s box[2], vec3s other[2]) { vec3 rawBox[2]; vec3 rawOther[2]; glms_vec3_(unpack)(rawBox, box, 2); glms_vec3_(unpack)(rawOther, other, 2); return glm_aabb_aabb(rawBox, rawOther); } /*! * @brief check if AABB intersects with sphere * * https://github.com/erich666/GraphicsGems/blob/master/gems/BoxSphere.c * Solid Box - Solid Sphere test. * * @param[in] box solid bounding box * @param[in] s solid sphere */ CGLM_INLINE bool glms_aabb_(sphere)(vec3s box[2], vec4s s) { vec3 rawBox[2]; glms_vec3_(unpack)(rawBox, box, 2); return glm_aabb_sphere(rawBox, s.raw); } /*! * @brief check if point is inside of AABB * * @param[in] box bounding box * @param[in] point point */ CGLM_INLINE bool glms_aabb_(point)(vec3s box[2], vec3s point) { vec3 rawBox[2]; glms_vec3_(unpack)(rawBox, box, 2); return glm_aabb_point(rawBox, point.raw); } /*! * @brief check if AABB contains other AABB * * @param[in] box bounding box * @param[in] other other bounding box */ CGLM_INLINE bool glms_aabb_(contains)(vec3s box[2], vec3s other[2]) { vec3 rawBox[2]; vec3 rawOther[2]; glms_vec3_(unpack)(rawBox, box, 2); glms_vec3_(unpack)(rawOther, other, 2); return glm_aabb_contains(rawBox, rawOther); } #endif /* cglms_boxs_h */ cglm-0.9.7/include/cglm/struct/cam.h000066400000000000000000000535371526744317200173030ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE mat4s glms_frustum(float left, float right, float bottom, float top, float nearZ, float farZ) CGLM_INLINE mat4s glms_ortho(float left, float right, float bottom, float top, float nearZ, float farZ) CGLM_INLINE mat4s glms_ortho_aabb(vec3s box[2]); CGLM_INLINE mat4s glms_ortho_aabb_p(vec3s box[2], float padding); CGLM_INLINE mat4s glms_ortho_aabb_pz(vec3s box[2], float padding); CGLM_INLINE mat4s glms_ortho_default(float aspect) CGLM_INLINE mat4s glms_ortho_default_s(float aspect, float size) CGLM_INLINE mat4s glms_perspective(float fovy, float aspect, float nearZ, float farZ) CGLM_INLINE void glms_persp_move_far(mat4s proj, float deltaFar) CGLM_INLINE mat4s glms_perspective_default(float aspect) CGLM_INLINE void glms_perspective_resize(mat4s proj, float aspect) CGLM_INLINE mat4s glms_lookat(vec3s eye, vec3s center, vec3s up) CGLM_INLINE mat4s glms_look(vec3s eye, vec3s dir, vec3s up) CGLM_INLINE mat4s glms_look_anyup(vec3s eye, vec3s dir) CGLM_INLINE void glms_persp_decomp(mat4s proj, float *nearv, float *farv, float *top, float *bottom, float *left, float *right) CGLM_INLINE void glms_persp_decompv(mat4s proj, float dest[6]) CGLM_INLINE void glms_persp_decomp_x(mat4s proj, float *left, float *right) CGLM_INLINE void glms_persp_decomp_y(mat4s proj, float *top, float *bottom) CGLM_INLINE void glms_persp_decomp_z(mat4s proj, float *nearv, float *farv) CGLM_INLINE void glms_persp_decomp_far(mat4s proj, float *farZ) CGLM_INLINE void glms_persp_decomp_near(mat4s proj, float *nearZ) CGLM_INLINE float glms_persp_fovy(mat4s proj) CGLM_INLINE float glms_persp_aspect(mat4s proj) CGLM_INLINE vec4s glms_persp_sizes(mat4s proj, float fovy) */ #ifndef cglms_cam_h #define cglms_cam_h #include "../common.h" #include "../types-struct.h" #include "../plane.h" #include "../cam.h" #ifndef CGLM_CLIPSPACE_INCLUDE_ALL # if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO # include "clipspace/ortho_lh_zo.h" # include "clipspace/persp_lh_zo.h" # include "clipspace/view_lh_zo.h" # elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO # include "clipspace/ortho_lh_no.h" # include "clipspace/persp_lh_no.h" # include "clipspace/view_lh_no.h" # elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO # include "clipspace/ortho_rh_zo.h" # include "clipspace/persp_rh_zo.h" # include "clipspace/view_rh_zo.h" # elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO # include "clipspace/ortho_rh_no.h" # include "clipspace/persp_rh_no.h" # include "clipspace/view_rh_no.h" # endif #else # include "clipspace/ortho_lh_zo.h" # include "clipspace/persp_lh_zo.h" # include "clipspace/ortho_lh_no.h" # include "clipspace/persp_lh_no.h" # include "clipspace/ortho_rh_zo.h" # include "clipspace/persp_rh_zo.h" # include "clipspace/ortho_rh_no.h" # include "clipspace/persp_rh_no.h" # include "clipspace/view_lh_zo.h" # include "clipspace/view_lh_no.h" # include "clipspace/view_rh_zo.h" # include "clipspace/view_rh_no.h" #endif /*! * @brief set up perspective peprojection matrix * * @param[in] left viewport.left * @param[in] right viewport.right * @param[in] bottom viewport.bottom * @param[in] top viewport.top * @param[in] nearZ near clipping plane * @param[in] farZ far clipping plane * @returns result matrix */ CGLM_INLINE mat4s glms_frustum(float left, float right, float bottom, float top, float nearZ, float farZ) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO return glms_frustum_lh_zo(left, right, bottom, top, nearZ, farZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO return glms_frustum_lh_no(left, right, bottom, top, nearZ, farZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO return glms_frustum_rh_zo(left, right, bottom, top, nearZ, farZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO return glms_frustum_rh_no(left, right, bottom, top, nearZ, farZ); #endif } /*! * @brief set up orthographic projection matrix * * @param[in] left viewport.left * @param[in] right viewport.right * @param[in] bottom viewport.bottom * @param[in] top viewport.top * @param[in] nearZ near clipping plane * @param[in] farZ far clipping plane * @returns result matrix */ CGLM_INLINE mat4s glms_ortho(float left, float right, float bottom, float top, float nearZ, float farZ) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO return glms_ortho_lh_zo(left, right, bottom, top, nearZ, farZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO return glms_ortho_lh_no(left, right, bottom, top, nearZ, farZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO return glms_ortho_rh_zo(left, right, bottom, top, nearZ, farZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO return glms_ortho_rh_no(left, right, bottom, top, nearZ, farZ); #endif } /*! * @brief set up orthographic projection matrix using bounding box * * bounding box (AABB) must be in view space * * @param[in] box AABB * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_aabb(vec3s box[2]) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO return glms_ortho_aabb_lh_zo(box); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO return glms_ortho_aabb_lh_no(box); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO return glms_ortho_aabb_rh_zo(box); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO return glms_ortho_aabb_rh_no(box); #endif } /*! * @brief set up orthographic projection matrix using bounding box * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[in] padding padding * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_aabb_p(vec3s box[2], float padding) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO return glms_ortho_aabb_p_lh_zo(box, padding); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO return glms_ortho_aabb_p_lh_no(box, padding); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO return glms_ortho_aabb_p_rh_zo(box, padding); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO return glms_ortho_aabb_p_rh_no(box, padding); #endif } /*! * @brief set up orthographic projection matrix using bounding box * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[in] padding padding for near and far * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_aabb_pz(vec3s box[2], float padding) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO return glms_ortho_aabb_pz_lh_zo(box, padding); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO return glms_ortho_aabb_pz_lh_no(box, padding); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO return glms_ortho_aabb_pz_rh_zo(box, padding); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO return glms_ortho_aabb_pz_rh_no(box, padding); #endif } /*! * @brief set up unit orthographic projection matrix * * @param[in] aspect aspect ration ( width / height ) * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_default(float aspect) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO return glms_ortho_default_lh_zo(aspect); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO return glms_ortho_default_lh_no(aspect); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO return glms_ortho_default_rh_zo(aspect); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO return glms_ortho_default_rh_no(aspect); #endif } /*! * @brief set up orthographic projection matrix with given CUBE size * * @param[in] aspect aspect ratio ( width / height ) * @param[in] size cube size * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_default_s(float aspect, float size) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO return glms_ortho_default_s_lh_zo(aspect, size); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO return glms_ortho_default_s_lh_no(aspect, size); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO return glms_ortho_default_s_rh_zo(aspect, size); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO return glms_ortho_default_s_rh_no(aspect, size); #endif } /*! * @brief set up perspective projection matrix * * @param[in] fovy field of view angle * @param[in] aspect aspect ratio ( width / height ) * @param[in] nearZ near clipping plane * @param[in] farZ far clipping planes * @returns result matrix */ CGLM_INLINE mat4s glms_perspective(float fovy, float aspect, float nearZ, float farZ) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO return glms_perspective_lh_zo(fovy, aspect, nearZ, farZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO return glms_perspective_lh_no(fovy, aspect, nearZ, farZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO return glms_perspective_rh_zo(fovy, aspect, nearZ, farZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO return glms_perspective_rh_no(fovy, aspect, nearZ, farZ); #endif } /*! * @brief extend perspective projection matrix's far distance * * NOTE: if you dodn't want to create new matrix then use array api on struct.raw * like glm_persp_move_far(prooj.raw, deltaFar) to avoid create new mat4 * each time * * this function does not guarantee far >= near, be aware of that! * * @param[in, out] proj projection matrix to extend * @param[in] deltaFar distance from existing far (negative to shink) */ CGLM_INLINE mat4s glms_persp_move_far(mat4s proj, float deltaFar) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO return glms_persp_move_far_lh_zo(proj, deltaFar); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO return glms_persp_move_far_lh_no(proj, deltaFar); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO return glms_persp_move_far_rh_zo(proj, deltaFar); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO return glms_persp_move_far_rh_no(proj, deltaFar); #endif } /*! * @brief set up perspective projection matrix with default near/far * and angle values * * @param[in] aspect aspect ratio ( width / height ) * @returns result matrix */ CGLM_INLINE mat4s glms_perspective_default(float aspect) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO return glms_perspective_default_lh_zo(aspect); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO return glms_perspective_default_lh_no(aspect); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO return glms_perspective_default_rh_zo(aspect); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO return glms_perspective_default_rh_no(aspect); #endif } /*! * @brief resize perspective matrix by aspect ratio ( width / height ) * this makes very easy to resize proj matrix when window /viewport * reized * * NOTE: if you dodn't want to create new matrix then use array api on struct.raw * like glms_perspective_resize(proj.raw, aspect) to avoid create new mat4 * each time * * @param[in, out] proj perspective projection matrix * @param[in] aspect aspect ratio ( width / height ) */ CGLM_INLINE mat4s glms_perspective_resize(mat4s proj, float aspect) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO return glms_perspective_resize_lh_zo(proj, aspect); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO return glms_perspective_resize_lh_no(proj, aspect); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO return glms_perspective_resize_rh_zo(proj, aspect); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO return glms_perspective_resize_rh_no(proj, aspect); #endif } /*! * @brief set up view matrix * * NOTE: The UP vector must not be parallel to the line of sight from * the eye point to the reference point * * @param[in] eye eye vector * @param[in] center center vector * @param[in] up up vector * @returns result matrix */ CGLM_INLINE mat4s glms_lookat(vec3s eye, vec3s center, vec3s up) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO return glms_lookat_lh_zo(eye, center, up); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO return glms_lookat_lh_no(eye, center, up); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO return glms_lookat_rh_zo(eye, center, up); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO return glms_lookat_rh_no(eye, center, up); #endif } /*! * @brief set up view matrix * * convenient wrapper for lookat: if you only have direction not target self * then this might be useful. Because you need to get target from direction. * * NOTE: The UP vector must not be parallel to the line of sight from * the eye point to the reference point * * @param[in] eye eye vector * @param[in] dir direction vector * @param[in] up up vector * @returns result matrix */ CGLM_INLINE mat4s glms_look(vec3s eye, vec3s dir, vec3s up) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO return glms_look_lh_zo(eye, dir, up); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO return glms_look_lh_no(eye, dir, up); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO return glms_look_rh_zo(eye, dir, up); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO return glms_look_rh_no(eye, dir, up); #endif } /*! * @brief set up view matrix * * convenient wrapper for look: if you only have direction and if you don't * care what UP vector is then this might be useful to create view matrix * * @param[in] eye eye vector * @param[in] dir direction vector * @returns result matrix */ CGLM_INLINE mat4s glms_look_anyup(vec3s eye, vec3s dir) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO return glms_look_anyup_lh_zo(eye, dir); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO return glms_look_anyup_lh_no(eye, dir); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO return glms_look_anyup_rh_zo(eye, dir); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO return glms_look_anyup_rh_no(eye, dir); #endif } /*! * @brief decomposes frustum values of perspective projection. * * @param[in] proj perspective projection matrix * @param[out] nearZ near * @param[out] farZ far * @param[out] top top * @param[out] bottom bottom * @param[out] left left * @param[out] right right */ CGLM_INLINE void glms_persp_decomp(mat4s proj, float * __restrict nearZ, float * __restrict farZ, float * __restrict top, float * __restrict bottom, float * __restrict left, float * __restrict right) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glms_persp_decomp_lh_zo(proj, nearZ, farZ, top, bottom, left, right); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glms_persp_decomp_lh_no(proj, nearZ, farZ, top, bottom, left, right); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glms_persp_decomp_rh_zo(proj, nearZ, farZ, top, bottom, left, right); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glms_persp_decomp_rh_no(proj, nearZ, farZ, top, bottom, left, right); #endif } /*! * @brief decomposes frustum values of perspective projection. * this makes easy to get all values at once * * @param[in] proj perspective projection matrix * @param[out] dest array */ CGLM_INLINE void glms_persp_decompv(mat4s proj, float dest[6]) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glms_persp_decompv_lh_zo(proj, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glms_persp_decompv_lh_no(proj, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glms_persp_decompv_rh_zo(proj, dest); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glms_persp_decompv_rh_no(proj, dest); #endif } /*! * @brief decomposes left and right values of perspective projection. * x stands for x axis (left / right axis) * * @param[in] proj perspective projection matrix * @param[out] left left * @param[out] right right */ CGLM_INLINE void glms_persp_decomp_x(mat4s proj, float * __restrict left, float * __restrict right) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glms_persp_decomp_x_lh_zo(proj, left, right); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glms_persp_decomp_x_lh_no(proj, left, right); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glms_persp_decomp_x_rh_zo(proj, left, right); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glms_persp_decomp_x_rh_no(proj, left, right); #endif } /*! * @brief decomposes top and bottom values of perspective projection. * y stands for y axis (top / bottom axis) * * @param[in] proj perspective projection matrix * @param[out] top top * @param[out] bottom bottom */ CGLM_INLINE void glms_persp_decomp_y(mat4s proj, float * __restrict top, float * __restrict bottom) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glms_persp_decomp_y_lh_zo(proj, top, bottom); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glms_persp_decomp_y_lh_no(proj, top, bottom); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glms_persp_decomp_y_rh_zo(proj, top, bottom); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glms_persp_decomp_y_rh_no(proj, top, bottom); #endif } /*! * @brief decomposes near and far values of perspective projection. * z stands for z axis (near / far axis) * * @param[in] proj perspective projection matrix * @param[out] nearZ near * @param[out] farZ far */ CGLM_INLINE void glms_persp_decomp_z(mat4s proj, float * __restrict nearZ, float * __restrict farZ) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glms_persp_decomp_z_lh_zo(proj, nearZ, farZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glms_persp_decomp_z_lh_no(proj, nearZ, farZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glms_persp_decomp_z_rh_zo(proj, nearZ, farZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glms_persp_decomp_z_rh_no(proj, nearZ, farZ); #endif } /*! * @brief decomposes far value of perspective projection. * * @param[in] proj perspective projection matrix * @param[out] farZ far */ CGLM_INLINE void glms_persp_decomp_far(mat4s proj, float * __restrict farZ) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glms_persp_decomp_far_lh_zo(proj, farZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glms_persp_decomp_far_lh_no(proj, farZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glms_persp_decomp_far_rh_zo(proj, farZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glms_persp_decomp_far_rh_no(proj, farZ); #endif } /*! * @brief decomposes near value of perspective projection. * * @param[in] proj perspective projection matrix * @param[out] nearZ near */ CGLM_INLINE void glms_persp_decomp_near(mat4s proj, float * __restrict nearZ) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO glms_persp_decomp_near_lh_zo(proj, nearZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO glms_persp_decomp_near_lh_no(proj, nearZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO glms_persp_decomp_near_rh_zo(proj, nearZ); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO glms_persp_decomp_near_rh_no(proj, nearZ); #endif } /*! * @brief returns field of view angle along the Y-axis (in radians) * * if you need to degrees, use glm_deg to convert it or use this: * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) * * @param[in] proj perspective projection matrix */ CGLM_INLINE float glms_persp_fovy(mat4s proj) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO return glms_persp_fovy_lh_zo(proj); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO return glms_persp_fovy_lh_no(proj); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO return glms_persp_fovy_rh_zo(proj); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO return glms_persp_fovy_rh_no(proj); #endif } /*! * @brief returns aspect ratio of perspective projection * * @param[in] proj perspective projection matrix */ CGLM_INLINE float glms_persp_aspect(mat4s proj) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO return glms_persp_aspect_lh_zo(proj); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO return glms_persp_aspect_lh_no(proj); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO return glms_persp_aspect_rh_zo(proj); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO return glms_persp_aspect_rh_no(proj); #endif } /*! * @brief returns sizes of near and far planes of perspective projection * * @param[in] proj perspective projection matrix * @param[in] fovy fovy (see brief) * @returns sizes as vector, sizes order: [Wnear, Hnear, Wfar, Hfar] */ CGLM_INLINE vec4s glms_persp_sizes(mat4s proj, float fovy) { #if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO return glms_persp_sizes_lh_zo(proj, fovy); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO return glms_persp_sizes_lh_no(proj, fovy); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO return glms_persp_sizes_rh_zo(proj, fovy); #elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO return glms_persp_sizes_rh_no(proj, fovy); #endif } #endif /* cglms_cam_h */ cglm-0.9.7/include/cglm/struct/clipspace/000077500000000000000000000000001526744317200203205ustar00rootroot00000000000000cglm-0.9.7/include/cglm/struct/clipspace/ortho_lh_no.h000066400000000000000000000075351526744317200230150ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE mat4s glms_ortho_lh_no(float left, float right, float bottom, float top, float nearZ, float farZ) CGLM_INLINE mat4s glms_ortho_aabb_lh_no(vec3s box[2]); CGLM_INLINE mat4s glms_ortho_aabb_p_lh_no(vec3s box[2], float padding); CGLM_INLINE mat4s glms_ortho_aabb_pz_lh_no(vec3s box[2], float padding); CGLM_INLINE mat4s glms_ortho_default_lh_no(float aspect) CGLM_INLINE mat4s glms_ortho_default_s_lh_no(float aspect, float size) */ #ifndef cglms_ortho_lh_no_h #define cglms_ortho_lh_no_h #include "../../common.h" #include "../../types-struct.h" #include "../../plane.h" #include "../../cam.h" #include "../vec3.h" #include "../../clipspace/ortho_lh_no.h" /*! * @brief set up orthographic projection matrix * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] left viewport.left * @param[in] right viewport.right * @param[in] bottom viewport.bottom * @param[in] top viewport.top * @param[in] nearZ near clipping plane * @param[in] farZ far clipping plane * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_lh_no(float left, float right, float bottom, float top, float nearZ, float farZ) { mat4s dest; glm_ortho_lh_no(left, right, bottom, top, nearZ, farZ, dest.raw); return dest; } /*! * @brief set up orthographic projection matrix using bounding box * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * bounding box (AABB) must be in view space * * @param[in] box AABB * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_aabb_lh_no(vec3s box[2]) { mat4s dest; vec3 rawBox[2]; glms_vec3_(unpack)(rawBox, box, 2); glm_ortho_aabb_lh_no(rawBox, dest.raw); return dest; } /*! * @brief set up orthographic projection matrix using bounding box * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[in] padding padding * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_aabb_p_lh_no(vec3s box[2], float padding) { mat4s dest; vec3 rawBox[2]; glms_vec3_(unpack)(rawBox, box, 2); glm_ortho_aabb_p_lh_no(rawBox, padding, dest.raw); return dest; } /*! * @brief set up orthographic projection matrix using bounding box * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[in] padding padding for near and far * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_aabb_pz_lh_no(vec3s box[2], float padding) { mat4s dest; vec3 rawBox[2]; glms_vec3_(unpack)(rawBox, box, 2); glm_ortho_aabb_pz_lh_no(rawBox, padding, dest.raw); return dest; } /*! * @brief set up unit orthographic projection matrix * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] aspect aspect ration ( width / height ) * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_default_lh_no(float aspect) { mat4s dest; glm_ortho_default_lh_no(aspect, dest.raw); return dest; } /*! * @brief set up orthographic projection matrix with given CUBE size * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] aspect aspect ratio ( width / height ) * @param[in] size cube size * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_default_s_lh_no(float aspect, float size) { mat4s dest; glm_ortho_default_s_lh_no(aspect, size, dest.raw); return dest; } #endif /* cglms_ortho_lh_no_h */ cglm-0.9.7/include/cglm/struct/clipspace/ortho_lh_zo.h000066400000000000000000000075271526744317200230320ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE mat4s glms_ortho_lh_zo(float left, float right, float bottom, float top, float nearZ, float farZ) CGLM_INLINE mat4s glms_ortho_aabb_lh_zo(vec3s box[2]); CGLM_INLINE mat4s glms_ortho_aabb_p_lh_zo(vec3s box[2], float padding); CGLM_INLINE mat4s glms_ortho_aabb_pz_lh_zo(vec3s box[2], float padding); CGLM_INLINE mat4s glms_ortho_default_lh_zo(float aspect) CGLM_INLINE mat4s glms_ortho_default_s_lh_zo(float aspect, float size) */ #ifndef cglms_ortho_lh_zo_h #define cglms_ortho_lh_zo_h #include "../../common.h" #include "../../types-struct.h" #include "../../plane.h" #include "../../cam.h" #include "../vec3.h" #include "../../clipspace/ortho_lh_zo.h" /*! * @brief set up orthographic projection matrix * with a left-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] left viewport.left * @param[in] right viewport.right * @param[in] bottom viewport.bottom * @param[in] top viewport.top * @param[in] nearZ near clipping plane * @param[in] farZ far clipping plane * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_lh_zo(float left, float right, float bottom, float top, float nearZ, float farZ) { mat4s dest; glm_ortho_lh_zo(left, right, bottom, top, nearZ, farZ, dest.raw); return dest; } /*! * @brief set up orthographic projection matrix using bounding box * with a left-hand coordinate system and a * clip-space of [0, 1]. * * bounding box (AABB) must be in view space * * @param[in] box AABB * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_aabb_lh_zo(vec3s box[2]) { mat4s dest; vec3 rawBox[2]; glms_vec3_(unpack)(rawBox, box, 2); glm_ortho_aabb_lh_zo(rawBox, dest.raw); return dest; } /*! * @brief set up orthographic projection matrix using bounding box * with a left-hand coordinate system and a * clip-space of [0, 1]. * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[in] padding padding * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_aabb_p_lh_zo(vec3s box[2], float padding) { mat4s dest; vec3 rawBox[2]; glms_vec3_(unpack)(rawBox, box, 2); glm_ortho_aabb_p_lh_zo(rawBox, padding, dest.raw); return dest; } /*! * @brief set up orthographic projection matrix using bounding box * with a left-hand coordinate system and a * clip-space of [0, 1]. * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[in] padding padding for near and far * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_aabb_pz_lh_zo(vec3s box[2], float padding) { mat4s dest; vec3 rawBox[2]; glms_vec3_(unpack)(rawBox, box, 2); glm_ortho_aabb_pz_lh_zo(rawBox, padding, dest.raw); return dest; } /*! * @brief set up unit orthographic projection matrix * with a left-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] aspect aspect ration ( width / height ) * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_default_lh_zo(float aspect) { mat4s dest; glm_ortho_default_lh_zo(aspect, dest.raw); return dest; } /*! * @brief set up orthographic projection matrix with given CUBE size * with a left-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] aspect aspect ratio ( width / height ) * @param[in] size cube size * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_default_s_lh_zo(float aspect, float size) { mat4s dest; glm_ortho_default_s_lh_zo(aspect, size, dest.raw); return dest; } #endif /* cglms_ortho_lh_zo_h */ cglm-0.9.7/include/cglm/struct/clipspace/ortho_rh_no.h000066400000000000000000000075431526744317200230220ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE mat4s glms_ortho_rh_no(float left, float right, float bottom, float top, float nearZ, float farZ) CGLM_INLINE mat4s glms_ortho_aabb_rh_no(vec3s box[2]); CGLM_INLINE mat4s glms_ortho_aabb_p_rh_no(vec3s box[2], float padding); CGLM_INLINE mat4s glms_ortho_aabb_pz_rh_no(vec3s box[2], float padding); CGLM_INLINE mat4s glms_ortho_default_rh_no(float aspect) CGLM_INLINE mat4s glms_ortho_default_s_rh_no(float aspect, float size) */ #ifndef cglms_ortho_rh_no_h #define cglms_ortho_rh_no_h #include "../../common.h" #include "../../types-struct.h" #include "../../plane.h" #include "../../cam.h" #include "../vec3.h" #include "../../clipspace/ortho_rh_no.h" /*! * @brief set up orthographic projection matrix * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] left viewport.left * @param[in] right viewport.right * @param[in] bottom viewport.bottom * @param[in] top viewport.top * @param[in] nearZ near clipping plane * @param[in] farZ far clipping plane * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_rh_no(float left, float right, float bottom, float top, float nearZ, float farZ) { mat4s dest; glm_ortho_rh_no(left, right, bottom, top, nearZ, farZ, dest.raw); return dest; } /*! * @brief set up orthographic projection matrix using bounding box * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * bounding box (AABB) must be in view space * * @param[in] box AABB * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_aabb_rh_no(vec3s box[2]) { mat4s dest; vec3 rawBox[2]; glms_vec3_(unpack)(rawBox, box, 2); glm_ortho_aabb_rh_no(rawBox, dest.raw); return dest; } /*! * @brief set up orthographic projection matrix using bounding box * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[in] padding padding * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_aabb_p_rh_no(vec3s box[2], float padding) { mat4s dest; vec3 rawBox[2]; glms_vec3_(unpack)(rawBox, box, 2); glm_ortho_aabb_p_rh_no(rawBox, padding, dest.raw); return dest; } /*! * @brief set up orthographic projection matrix using bounding box * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[in] padding padding for near and far * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_aabb_pz_rh_no(vec3s box[2], float padding) { mat4s dest; vec3 rawBox[2]; glms_vec3_(unpack)(rawBox, box, 2); glm_ortho_aabb_pz_rh_no(rawBox, padding, dest.raw); return dest; } /*! * @brief set up unit orthographic projection matrix * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] aspect aspect ration ( width / height ) * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_default_rh_no(float aspect) { mat4s dest; glm_ortho_default_rh_no(aspect, dest.raw); return dest; } /*! * @brief set up orthographic projection matrix with given CUBE size * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] aspect aspect ratio ( width / height ) * @param[in] size cube size * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_default_s_rh_no(float aspect, float size) { mat4s dest; glm_ortho_default_s_rh_no(aspect, size, dest.raw); return dest; } #endif /* cglms_ortho_rh_no_h */ cglm-0.9.7/include/cglm/struct/clipspace/ortho_rh_zo.h000066400000000000000000000075351526744317200230370ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE mat4s glms_ortho_rh_zo(float left, float right, float bottom, float top, float nearZ, float farZ) CGLM_INLINE mat4s glms_ortho_aabb_rh_zo(vec3s box[2]); CGLM_INLINE mat4s glms_ortho_aabb_p_rh_zo(vec3s box[2], float padding); CGLM_INLINE mat4s glms_ortho_aabb_pz_rh_zo(vec3s box[2], float padding); CGLM_INLINE mat4s glms_ortho_default_rh_zo(float aspect) CGLM_INLINE mat4s glms_ortho_default_s_rh_zo(float aspect, float size) */ #ifndef cglms_ortho_rh_zo_h #define cglms_ortho_rh_zo_h #include "../../common.h" #include "../../types-struct.h" #include "../../plane.h" #include "../../cam.h" #include "../vec3.h" #include "../../clipspace/ortho_rh_zo.h" /*! * @brief set up orthographic projection matrix * with a right-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] left viewport.left * @param[in] right viewport.right * @param[in] bottom viewport.bottom * @param[in] top viewport.top * @param[in] nearZ near clipping plane * @param[in] farZ far clipping plane * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_rh_zo(float left, float right, float bottom, float top, float nearZ, float farZ) { mat4s dest; glm_ortho_rh_zo(left, right, bottom, top, nearZ, farZ, dest.raw); return dest; } /*! * @brief set up orthographic projection matrix using bounding box * with a right-hand coordinate system and a * clip-space of [0, 1]. * * bounding box (AABB) must be in view space * * @param[in] box AABB * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_aabb_rh_zo(vec3s box[2]) { mat4s dest; vec3 rawBox[2]; glms_vec3_(unpack)(rawBox, box, 2); glm_ortho_aabb_rh_zo(rawBox, dest.raw); return dest; } /*! * @brief set up orthographic projection matrix using bounding box * with a right-hand coordinate system and a * clip-space of [0, 1]. * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[in] padding padding * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_aabb_p_rh_zo(vec3s box[2], float padding) { mat4s dest; vec3 rawBox[2]; glms_vec3_(unpack)(rawBox, box, 2); glm_ortho_aabb_p_rh_zo(rawBox, padding, dest.raw); return dest; } /*! * @brief set up orthographic projection matrix using bounding box * with a right-hand coordinate system and a * clip-space of [0, 1]. * * bounding box (AABB) must be in view space * * @param[in] box AABB * @param[in] padding padding for near and far * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_aabb_pz_rh_zo(vec3s box[2], float padding) { mat4s dest; vec3 rawBox[2]; glms_vec3_(unpack)(rawBox, box, 2); glm_ortho_aabb_pz_rh_zo(rawBox, padding, dest.raw); return dest; } /*! * @brief set up unit orthographic projection matrix * with a right-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] aspect aspect ration ( width / height ) * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_default_rh_zo(float aspect) { mat4s dest; glm_ortho_default_rh_zo(aspect, dest.raw); return dest; } /*! * @brief set up orthographic projection matrix with given CUBE size * with a right-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] aspect aspect ratio ( width / height ) * @param[in] size cube size * @returns result matrix */ CGLM_INLINE mat4s glms_ortho_default_s_rh_zo(float aspect, float size) { mat4s dest; glm_ortho_default_s_rh_zo(aspect, size, dest.raw); return dest; } #endif /* cglms_ortho_rh_zo_h */ cglm-0.9.7/include/cglm/struct/clipspace/persp_lh_no.h000066400000000000000000000230351526744317200230040ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE mat4s glms_frustum_lh_no(float left, float right, float bottom, float top, float nearZ, float farZ) CGLM_INLINE mat4s glms_perspective_lh_no(float fovy, float aspect, float nearZ, float farZ) CGLM_INLINE void glms_persp_move_far_lh_no(mat4s proj, float deltaFar) CGLM_INLINE mat4s glms_perspective_default_lh_no(float aspect) CGLM_INLINE void glms_perspective_resize_lh_no(mat4s proj, float aspect) CGLM_INLINE void glms_persp_decomp_lh_no(mat4s proj, float *nearv, float *farv, float *top, float *bottom, float *left, float *right) CGLM_INLINE void glms_persp_decompv_lh_no(mat4s proj, float dest[6]) CGLM_INLINE void glms_persp_decomp_x_lh_no(mat4s proj, float *left, float *right) CGLM_INLINE void glms_persp_decomp_y_lh_no(mat4s proj, float *top, float *bottom) CGLM_INLINE void glms_persp_decomp_z_lh_no(mat4s proj, float *nearv, float *farv) CGLM_INLINE void glms_persp_decomp_far_lh_no(mat4s proj, float *farZ) CGLM_INLINE void glms_persp_decomp_near_lh_no(mat4s proj, float *nearZ) CGLM_INLINE float glms_persp_fovy_lh_no(mat4s proj) CGLM_INLINE float glms_persp_aspect_lh_no(mat4s proj) CGLM_INLINE vec4s glms_persp_sizes_lh_no(mat4s proj, float fovy) */ #ifndef cglms_persp_lh_no_h #define cglms_persp_lh_no_h #include "../../common.h" #include "../../types-struct.h" #include "../../plane.h" #include "../../cam.h" #include "../../clipspace/persp_lh_no.h" /*! * @brief set up perspective peprojection matrix * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] left viewport.left * @param[in] right viewport.right * @param[in] bottom viewport.bottom * @param[in] top viewport.top * @param[in] nearZ near clipping plane * @param[in] farZ far clipping plane * @returns result matrix */ CGLM_INLINE mat4s glms_frustum_lh_no(float left, float right, float bottom, float top, float nearZ, float farZ) { mat4s dest; glm_frustum_lh_no(left, right, bottom, top, nearZ, farZ, dest.raw); return dest; } /*! * @brief set up perspective projection matrix * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] fovy field of view angle * @param[in] aspect aspect ratio ( width / height ) * @param[in] nearZ near clipping plane * @param[in] farZ far clipping planes * @returns result matrix */ CGLM_INLINE mat4s glms_perspective_lh_no(float fovy, float aspect, float nearZ, float farZ) { mat4s dest; glm_perspective_lh_no(fovy, aspect, nearZ, farZ, dest.raw); return dest; } /*! * @brief extend perspective projection matrix's far distance * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * NOTE: if you dodn't want to create new matrix then use array api on struct.raw * like glms_persp_move_far_lh_no(prooj.raw, deltaFar) to avoid create new mat4 * each time * * this function does not guarantee far >= near, be aware of that! * * @param[in, out] proj projection matrix to extend * @param[in] deltaFar distance from existing far (negative to shink) */ CGLM_INLINE mat4s glms_persp_move_far_lh_no(mat4s proj, float deltaFar) { mat4s dest; dest = proj; glm_persp_move_far_lh_no(dest.raw, deltaFar); return dest; } /*! * @brief set up perspective projection matrix with default near/far * and angle values with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] aspect aspect ratio ( width / height ) * @returns result matrix */ CGLM_INLINE mat4s glms_perspective_default_lh_no(float aspect) { mat4s dest; glm_perspective_default_lh_no(aspect, dest.raw); return dest; } /*! * @brief resize perspective matrix by aspect ratio ( width / height ) * this makes very easy to resize proj matrix when window /viewport * reized with a left-hand coordinate system and a * clip-space of [-1, 1]. * * NOTE: if you dodn't want to create new matrix then use array api on struct.raw * like glm_perspective_resize_lh_no(proj.raw, aspect) to avoid create new mat4 * each time * * @param[in, out] proj perspective projection matrix * @param[in] aspect aspect ratio ( width / height ) */ CGLM_INLINE mat4s glms_perspective_resize_lh_no(mat4s proj, float aspect) { mat4s dest; dest = proj; glm_perspective_resize_lh_no(aspect, dest.raw); return dest; } /*! * @brief decomposes frustum values of perspective projection. * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] proj perspective projection matrix * @param[out] nearZ near * @param[out] farZ far * @param[out] top top * @param[out] bottom bottom * @param[out] left left * @param[out] right right */ CGLM_INLINE void glms_persp_decomp_lh_no(mat4s proj, float * __restrict nearZ, float * __restrict farZ, float * __restrict top, float * __restrict bottom, float * __restrict left, float * __restrict right) { glm_persp_decomp_lh_no(proj.raw, nearZ, farZ, top, bottom, left, right); } /*! * @brief decomposes frustum values of perspective projection. * this makes easy to get all values at once * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] proj perspective projection matrix * @param[out] dest array */ CGLM_INLINE void glms_persp_decompv_lh_no(mat4s proj, float dest[6]) { glm_persp_decompv_lh_no(proj.raw, dest); } /*! * @brief decomposes left and right values of perspective projection * with a left-hand coordinate system and a * clip-space of [-1, 1]. * x stands for x axis (left / right axis) * * @param[in] proj perspective projection matrix * @param[out] left left * @param[out] right right */ CGLM_INLINE void glms_persp_decomp_x_lh_no(mat4s proj, float * __restrict left, float * __restrict right) { glm_persp_decomp_x_lh_no(proj.raw, left, right); } /*! * @brief decomposes top and bottom values of perspective projection * with a left-hand coordinate system and a * clip-space of [-1, 1]. * y stands for y axis (top / bottom axis) * * @param[in] proj perspective projection matrix * @param[out] top top * @param[out] bottom bottom */ CGLM_INLINE void glms_persp_decomp_y_lh_no(mat4s proj, float * __restrict top, float * __restrict bottom) { glm_persp_decomp_y_lh_no(proj.raw, top, bottom); } /*! * @brief decomposes near and far values of perspective projection * with a left-hand coordinate system and a * clip-space of [-1, 1]. * z stands for z axis (near / far axis) * * @param[in] proj perspective projection matrix * @param[out] nearZ near * @param[out] farZ far */ CGLM_INLINE void glms_persp_decomp_z_lh_no(mat4s proj, float * __restrict nearZ, float * __restrict farZ) { glm_persp_decomp_z_lh_no(proj.raw, nearZ, farZ); } /*! * @brief decomposes far value of perspective projection * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] proj perspective projection matrix * @param[out] farZ far */ CGLM_INLINE void glms_persp_decomp_far_lh_no(mat4s proj, float * __restrict farZ) { glm_persp_decomp_far_lh_no(proj.raw, farZ); } /*! * @brief decomposes near value of perspective projection * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] proj perspective projection matrix * @param[out] nearZ near */ CGLM_INLINE void glms_persp_decomp_near_lh_no(mat4s proj, float * __restrict nearZ) { glm_persp_decomp_near_lh_no(proj.raw, nearZ); } /*! * @brief returns field of view angle along the Y-axis (in radians) * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * if you need to degrees, use glm_deg to convert it or use this: * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) * * @param[in] proj perspective projection matrix */ CGLM_INLINE float glms_persp_fovy_lh_no(mat4s proj) { return glm_persp_fovy_lh_no(proj.raw); } /*! * @brief returns aspect ratio of perspective projection * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] proj perspective projection matrix */ CGLM_INLINE float glms_persp_aspect_lh_no(mat4s proj) { return glm_persp_aspect_lh_no(proj.raw); } /*! * @brief returns sizes of near and far planes of perspective projection * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] proj perspective projection matrix * @param[in] fovy fovy (see brief) * @returns sizes as vector, sizes order: [Wnear, Hnear, Wfar, Hfar] */ CGLM_INLINE vec4s glms_persp_sizes_lh_no(mat4s proj, float fovy) { vec4s dest; glm_persp_sizes_lh_no(proj.raw, fovy, dest.raw); return dest; } #endif /* cglms_persp_lh_no_h */ cglm-0.9.7/include/cglm/struct/clipspace/persp_lh_zo.h000066400000000000000000000230101526744317200230110ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE mat4s glms_frustum_lh_zo(float left, float right, float bottom, float top, float nearZ, float farZ) CGLM_INLINE mat4s glms_perspective_lh_zo(float fovy, float aspect, float nearZ, float farZ) CGLM_INLINE void glms_persp_move_far_lh_zo(mat4s proj, float deltaFar) CGLM_INLINE mat4s glms_perspective_default_lh_zo(float aspect) CGLM_INLINE void glms_perspective_resize_lh_zo(mat4s proj, float aspect) CGLM_INLINE void glms_persp_decomp_lh_zo(mat4s proj, float *nearv, float *farv, float *top, float *bottom, float *left, float *right) CGLM_INLINE void glms_persp_decompv_lh_zo(mat4s proj, float dest[6]) CGLM_INLINE void glms_persp_decomp_x_lh_zo(mat4s proj, float *left, float *right) CGLM_INLINE void glms_persp_decomp_y_lh_zo(mat4s proj, float *top, float *bottom) CGLM_INLINE void glms_persp_decomp_z_lh_zo(mat4s proj, float *nearv, float *farv) CGLM_INLINE void glms_persp_decomp_far_lh_zo(mat4s proj, float *farZ) CGLM_INLINE void glms_persp_decomp_near_lh_zo(mat4s proj, float *nearZ) CGLM_INLINE float glms_persp_fovy_lh_zo(mat4s proj) CGLM_INLINE float glms_persp_aspect_lh_zo(mat4s proj) CGLM_INLINE vec4s glms_persp_sizes_lh_zo(mat4s proj, float fovy) */ #ifndef cglms_persp_lh_zo_h #define cglms_persp_lh_zo_h #include "../../common.h" #include "../../types-struct.h" #include "../../plane.h" #include "../../cam.h" #include "../../clipspace/persp_lh_zo.h" /*! * @brief set up perspective peprojection matrix * with a left-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] left viewport.left * @param[in] right viewport.right * @param[in] bottom viewport.bottom * @param[in] top viewport.top * @param[in] nearZ near clipping plane * @param[in] farZ far clipping plane * @returns result matrix */ CGLM_INLINE mat4s glms_frustum_lh_zo(float left, float right, float bottom, float top, float nearZ, float farZ) { mat4s dest; glm_frustum_lh_zo(left, right, bottom, top, nearZ, farZ, dest.raw); return dest; } /*! * @brief set up perspective projection matrix * with a left-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] fovy field of view angle * @param[in] aspect aspect ratio ( width / height ) * @param[in] nearZ near clipping plane * @param[in] farZ far clipping planes * @returns result matrix */ CGLM_INLINE mat4s glms_perspective_lh_zo(float fovy, float aspect, float nearZ, float farZ) { mat4s dest; glm_perspective_lh_zo(fovy, aspect, nearZ, farZ, dest.raw); return dest; } /*! * @brief extend perspective projection matrix's far distance * with a left-hand coordinate system and a * clip-space of [0, 1]. * * NOTE: if you dodn't want to create new matrix then use array api on struct.raw * like glms_persp_move_far_lh_zo(prooj.raw, deltaFar) to avoid create new mat4 * each time * * this function does not guarantee far >= near, be aware of that! * * @param[in, out] proj projection matrix to extend * @param[in] deltaFar distance from existing far (negative to shink) */ CGLM_INLINE mat4s glms_persp_move_far_lh_zo(mat4s proj, float deltaFar) { mat4s dest; dest = proj; glm_persp_move_far_lh_zo(dest.raw, deltaFar); return dest; } /*! * @brief set up perspective projection matrix with default near/far * and angle values with a left-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] aspect aspect ratio ( width / height ) * @returns result matrix */ CGLM_INLINE mat4s glms_perspective_default_lh_zo(float aspect) { mat4s dest; glm_perspective_default_lh_zo(aspect, dest.raw); return dest; } /*! * @brief resize perspective matrix by aspect ratio ( width / height ) * this makes very easy to resize proj matrix when window /viewport * reized with a left-hand coordinate system and a * clip-space of [0, 1]. * * NOTE: if you dodn't want to create new matrix then use array api on struct.raw * like glms_perspective_resize_lh_zo(proj.raw, aspect) to avoid create new mat4 * each time * * @param[in, out] proj perspective projection matrix * @param[in] aspect aspect ratio ( width / height ) */ CGLM_INLINE mat4s glms_perspective_resize_lh_zo(mat4s proj, float aspect) { mat4s dest; dest = proj; glm_perspective_resize_lh_zo(aspect, dest.raw); return dest; } /*! * @brief decomposes frustum values of perspective projection. * with a left-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] proj perspective projection matrix * @param[out] nearZ near * @param[out] farZ far * @param[out] top top * @param[out] bottom bottom * @param[out] left left * @param[out] right right */ CGLM_INLINE void glms_persp_decomp_lh_zo(mat4s proj, float * __restrict nearZ, float * __restrict farZ, float * __restrict top, float * __restrict bottom, float * __restrict left, float * __restrict right) { glm_persp_decomp_lh_zo(proj.raw, nearZ, farZ, top, bottom, left, right); } /*! * @brief decomposes frustum values of perspective projection. * this makes easy to get all values at once * with a left-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] proj perspective projection matrix * @param[out] dest array */ CGLM_INLINE void glms_persp_decompv_lh_zo(mat4s proj, float dest[6]) { glm_persp_decompv_lh_zo(proj.raw, dest); } /*! * @brief decomposes left and right values of perspective projection * with a left-hand coordinate system and a * clip-space of [0, 1]. * x stands for x axis (left / right axis) * * @param[in] proj perspective projection matrix * @param[out] left left * @param[out] right right */ CGLM_INLINE void glms_persp_decomp_x_lh_zo(mat4s proj, float * __restrict left, float * __restrict right) { glm_persp_decomp_x_lh_zo(proj.raw, left, right); } /*! * @brief decomposes top and bottom values of perspective projection * with a left-hand coordinate system and a * clip-space of [0, 1]. * y stands for y axis (top / bottom axis) * * @param[in] proj perspective projection matrix * @param[out] top top * @param[out] bottom bottom */ CGLM_INLINE void glms_persp_decomp_y_lh_zo(mat4s proj, float * __restrict top, float * __restrict bottom) { glm_persp_decomp_y_lh_zo(proj.raw, top, bottom); } /*! * @brief decomposes near and far values of perspective projection * with a left-hand coordinate system and a * clip-space of [0, 1]. * z stands for z axis (near / far axis) * * @param[in] proj perspective projection matrix * @param[out] nearZ near * @param[out] farZ far */ CGLM_INLINE void glms_persp_decomp_z_lh_zo(mat4s proj, float * __restrict nearZ, float * __restrict farZ) { glm_persp_decomp_z_lh_zo(proj.raw, nearZ, farZ); } /*! * @brief decomposes far value of perspective projection * with a left-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] proj perspective projection matrix * @param[out] farZ far */ CGLM_INLINE void glms_persp_decomp_far_lh_zo(mat4s proj, float * __restrict farZ) { glm_persp_decomp_far_lh_zo(proj.raw, farZ); } /*! * @brief decomposes near value of perspective projection * with a left-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] proj perspective projection matrix * @param[out] nearZ near */ CGLM_INLINE void glms_persp_decomp_near_lh_zo(mat4s proj, float * __restrict nearZ) { glm_persp_decomp_near_lh_zo(proj.raw, nearZ); } /*! * @brief returns field of view angle along the Y-axis (in radians) * with a left-hand coordinate system and a * clip-space of [0, 1]. * * if you need to degrees, use glm_deg to convert it or use this: * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) * * @param[in] proj perspective projection matrix */ CGLM_INLINE float glms_persp_fovy_lh_zo(mat4s proj) { return glm_persp_fovy_lh_zo(proj.raw); } /*! * @brief returns aspect ratio of perspective projection * with a left-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] proj perspective projection matrix */ CGLM_INLINE float glms_persp_aspect_lh_zo(mat4s proj) { return glm_persp_aspect_lh_zo(proj.raw); } /*! * @brief returns sizes of near and far planes of perspective projection * with a left-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] proj perspective projection matrix * @param[in] fovy fovy (see brief) * @returns sizes as vector, sizes order: [Wnear, Hnear, Wfar, Hfar] */ CGLM_INLINE vec4s glms_persp_sizes_lh_zo(mat4s proj, float fovy) { vec4s dest; glm_persp_sizes_lh_zo(proj.raw, fovy, dest.raw); return dest; } #endif /* cglms_persp_lh_zo_h */ cglm-0.9.7/include/cglm/struct/clipspace/persp_rh_no.h000066400000000000000000000230551526744317200230140ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE mat4s glms_frustum_rh_no(float left, float right, float bottom, float top, float nearZ, float farZ) CGLM_INLINE mat4s glms_perspective_rh_no(float fovy, float aspect, float nearZ, float farZ) CGLM_INLINE void glms_persp_move_far_rh_no(mat4s proj, float deltaFar) CGLM_INLINE mat4s glms_perspective_default_rh_no(float aspect) CGLM_INLINE void glms_perspective_resize_rh_no(mat4s proj, float aspect) CGLM_INLINE void glms_persp_decomp_rh_no(mat4s proj, float *nearv, float *farv, float *top, float *bottom, float *left, float *right) CGLM_INLINE void glms_persp_decompv_rh_no(mat4s proj, float dest[6]) CGLM_INLINE void glms_persp_decomp_x_rh_no(mat4s proj, float *left, float *right) CGLM_INLINE void glms_persp_decomp_y_rh_no(mat4s proj, float *top, float *bottom) CGLM_INLINE void glms_persp_decomp_z_rh_no(mat4s proj, float *nearv, float *farv) CGLM_INLINE void glms_persp_decomp_far_rh_no(mat4s proj, float *farZ) CGLM_INLINE void glms_persp_decomp_near_rh_no(mat4s proj, float *nearZ) CGLM_INLINE float glms_persp_fovy_rh_no(mat4s proj) CGLM_INLINE float glms_persp_aspect_rh_no(mat4s proj) CGLM_INLINE vec4s glms_persp_sizes_rh_no(mat4s proj, float fovy) */ #ifndef cglms_persp_rh_no_h #define cglms_persp_rh_no_h #include "../../common.h" #include "../../types-struct.h" #include "../../plane.h" #include "../../cam.h" #include "../../clipspace/persp_rh_no.h" /*! * @brief set up perspective peprojection matrix * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] left viewport.left * @param[in] right viewport.right * @param[in] bottom viewport.bottom * @param[in] top viewport.top * @param[in] nearZ near clipping plane * @param[in] farZ far clipping plane * @returns result matrix */ CGLM_INLINE mat4s glms_frustum_rh_no(float left, float right, float bottom, float top, float nearZ, float farZ) { mat4s dest; glm_frustum_rh_no(left, right, bottom, top, nearZ, farZ, dest.raw); return dest; } /*! * @brief set up perspective projection matrix * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] fovy field of view angle * @param[in] aspect aspect ratio ( width / height ) * @param[in] nearZ near clipping plane * @param[in] farZ far clipping planes * @returns result matrix */ CGLM_INLINE mat4s glms_perspective_rh_no(float fovy, float aspect, float nearZ, float farZ) { mat4s dest; glm_perspective_rh_no(fovy, aspect, nearZ, farZ, dest.raw); return dest; } /*! * @brief extend perspective projection matrix's far distance * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * NOTE: if you dodn't want to create new matrix then use array api on struct.raw * like glms_persp_move_far_rh_no(prooj.raw, deltaFar) to avoid create new mat4 * each time * s * this function does not guarantee far >= near, be aware of that! * * @param[in, out] proj projection matrix to extend * @param[in] deltaFar distance from existing far (negative to shink) */ CGLM_INLINE mat4s glms_persp_move_far_rh_no(mat4s proj, float deltaFar) { mat4s dest; dest = proj; glm_persp_move_far_rh_no(dest.raw, deltaFar); return dest; } /*! * @brief set up perspective projection matrix with default near/far * and angle values with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] aspect aspect ratio ( width / height ) * @returns result matrix */ CGLM_INLINE mat4s glms_perspective_default_rh_no(float aspect) { mat4s dest; glm_perspective_default_rh_no(aspect, dest.raw); return dest; } /*! * @brief resize perspective matrix by aspect ratio ( width / height ) * this makes very easy to resize proj matrix when window /viewport * reized with a right-hand coordinate system and a * clip-space of [-1, 1]. * * NOTE: if you dodn't want to create new matrix then use array api on struct.raw * like glm_perspective_resize_rh_no(proj.raw, aspect) to avoid create new mat4 * each time * * @param[in, out] proj perspective projection matrix * @param[in] aspect aspect ratio ( width / height ) */ CGLM_INLINE mat4s glms_perspective_resize_rh_no(mat4s proj, float aspect) { mat4s dest; dest = proj; glm_perspective_resize_rh_no(aspect, dest.raw); return dest; } /*! * @brief decomposes frustum values of perspective projection. * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] proj perspective projection matrix * @param[out] nearZ near * @param[out] farZ far * @param[out] top top * @param[out] bottom bottom * @param[out] left left * @param[out] right right */ CGLM_INLINE void glms_persp_decomp_rh_no(mat4s proj, float * __restrict nearZ, float * __restrict farZ, float * __restrict top, float * __restrict bottom, float * __restrict left, float * __restrict right) { glm_persp_decomp_rh_no(proj.raw, nearZ, farZ, top, bottom, left, right); } /*! * @brief decomposes frustum values of perspective projection. * this makes easy to get all values at once * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] proj perspective projection matrix * @param[out] dest array */ CGLM_INLINE void glms_persp_decompv_rh_no(mat4s proj, float dest[6]) { glm_persp_decompv_rh_no(proj.raw, dest); } /*! * @brief decomposes left and right values of perspective projection * with a right-hand coordinate system and a * clip-space of [-1, 1]. * x stands for x axis (left / right axis) * * @param[in] proj perspective projection matrix * @param[out] left left * @param[out] right right */ CGLM_INLINE void glms_persp_decomp_x_rh_no(mat4s proj, float * __restrict left, float * __restrict right) { glm_persp_decomp_x_rh_no(proj.raw, left, right); } /*! * @brief decomposes top and bottom values of perspective projection * with a right-hand coordinate system and a * clip-space of [-1, 1]. * y stands for y axis (top / bottom axis) * * @param[in] proj perspective projection matrix * @param[out] top top * @param[out] bottom bottom */ CGLM_INLINE void glms_persp_decomp_y_rh_no(mat4s proj, float * __restrict top, float * __restrict bottom) { glm_persp_decomp_y_rh_no(proj.raw, top, bottom); } /*! * @brief decomposes near and far values of perspective projection * with a right-hand coordinate system and a * clip-space of [-1, 1]. * z stands for z axis (near / far axis) * * @param[in] proj perspective projection matrix * @param[out] nearZ near * @param[out] farZ far */ CGLM_INLINE void glms_persp_decomp_z_rh_no(mat4s proj, float * __restrict nearZ, float * __restrict farZ) { glm_persp_decomp_z_rh_no(proj.raw, nearZ, farZ); } /*! * @brief decomposes far value of perspective projection * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] proj perspective projection matrix * @param[out] farZ far */ CGLM_INLINE void glms_persp_decomp_far_rh_no(mat4s proj, float * __restrict farZ) { glm_persp_decomp_far_rh_no(proj.raw, farZ); } /*! * @brief decomposes near value of perspective projection * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] proj perspective projection matrix * @param[out] nearZ near */ CGLM_INLINE void glms_persp_decomp_near_rh_no(mat4s proj, float * __restrict nearZ) { glm_persp_decomp_near_rh_no(proj.raw, nearZ); } /*! * @brief returns field of view angle along the Y-axis (in radians) * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * if you need to degrees, use glm_deg to convert it or use this: * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) * * @param[in] proj perspective projection matrix */ CGLM_INLINE float glms_persp_fovy_rh_no(mat4s proj) { return glm_persp_fovy_rh_no(proj.raw); } /*! * @brief returns aspect ratio of perspective projection * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] proj perspective projection matrix */ CGLM_INLINE float glms_persp_aspect_rh_no(mat4s proj) { return glm_persp_aspect_rh_no(proj.raw); } /*! * @brief returns sizes of near and far planes of perspective projection * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * @param[in] proj perspective projection matrix * @param[in] fovy fovy (see brief) * @returns sizes as vector, sizes order: [Wnear, Hnear, Wfar, Hfar] */ CGLM_INLINE vec4s glms_persp_sizes_rh_no(mat4s proj, float fovy) { vec4s dest; glm_persp_sizes_rh_no(proj.raw, fovy, dest.raw); return dest; } #endif /* cglms_persp_rh_no_h */ cglm-0.9.7/include/cglm/struct/clipspace/persp_rh_zo.h000066400000000000000000000230351526744317200230260ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE mat4s glms_frustum_rh_zo(float left, float right, float bottom, float top, float nearZ, float farZ) CGLM_INLINE mat4s glms_perspective_rh_zo(float fovy, float aspect, float nearZ, float farZ) CGLM_INLINE void glms_persp_move_far_rh_zo(mat4s proj, float deltaFar) CGLM_INLINE mat4s glms_perspective_default_rh_zo(float aspect) CGLM_INLINE void glms_perspective_resize_rh_zo(mat4s proj, float aspect) CGLM_INLINE void glms_persp_decomp_rh_zo(mat4s proj, float *nearv, float *farv, float *top, float *bottom, float *left, float *right) CGLM_INLINE void glms_persp_decompv_rh_zo(mat4s proj, float dest[6]) CGLM_INLINE void glms_persp_decomp_x_rh_zo(mat4s proj, float *left, float *right) CGLM_INLINE void glms_persp_decomp_y_rh_zo(mat4s proj, float *top, float *bottom) CGLM_INLINE void glms_persp_decomp_z_rh_zo(mat4s proj, float *nearv, float *farv) CGLM_INLINE void glms_persp_decomp_far_rh_zo(mat4s proj, float *farZ) CGLM_INLINE void glms_persp_decomp_near_rh_zo(mat4s proj, float *nearZ) CGLM_INLINE float glms_persp_fovy_rh_zo(mat4s proj) CGLM_INLINE float glms_persp_aspect_rh_zo(mat4s proj) CGLM_INLINE vec4s glms_persp_sizes_rh_zo(mat4s proj, float fovy) */ #ifndef cglms_persp_rh_zo_h #define cglms_persp_rh_zo_h #include "../../common.h" #include "../../types-struct.h" #include "../../plane.h" #include "../../cam.h" #include "../../clipspace/persp_rh_zo.h" /*! * @brief set up perspective peprojection matrix * with a right-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] left viewport.left * @param[in] right viewport.right * @param[in] bottom viewport.bottom * @param[in] top viewport.top * @param[in] nearZ near clipping plane * @param[in] farZ far clipping plane * @returns result matrix */ CGLM_INLINE mat4s glms_frustum_rh_zo(float left, float right, float bottom, float top, float nearZ, float farZ) { mat4s dest; glm_frustum_rh_zo(left, right, bottom, top, nearZ, farZ, dest.raw); return dest; } /*! * @brief set up perspective projection matrix * with a right-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] fovy field of view angle * @param[in] aspect aspect ratio ( width / height ) * @param[in] nearZ near clipping plane * @param[in] farZ far clipping planes * @returns result matrix */ CGLM_INLINE mat4s glms_perspective_rh_zo(float fovy, float aspect, float nearZ, float farZ) { mat4s dest; glm_perspective_rh_zo(fovy, aspect, nearZ, farZ, dest.raw); return dest; } /*! * @brief extend perspective projection matrix's far distance * with a right-hand coordinate system and a * clip-space of [0, 1]. * * NOTE: if you dodn't want to create new matrix then use array api on struct.raw * like glms_persp_move_far_rh_zo(prooj.raw, deltaFar) to avoid create new mat4 * each time * * this function does not guarantee far >= near, be aware of that! * * @param[in, out] proj projection matrix to extend * @param[in] deltaFar distance from existing far (negative to shink) */ CGLM_INLINE mat4s glms_persp_move_far_rh_zo(mat4s proj, float deltaFar) { mat4s dest; dest = proj; glm_persp_move_far_rh_zo(dest.raw, deltaFar); return dest; } /*! * @brief set up perspective projection matrix with default near/far * and angle values with a right-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] aspect aspect ratio ( width / height ) * @returns result matrix */ CGLM_INLINE mat4s glms_perspective_default_rh_zo(float aspect) { mat4s dest; glm_perspective_default_rh_zo(aspect, dest.raw); return dest; } /*! * @brief resize perspective matrix by aspect ratio ( width / height ) * this makes very easy to resize proj matrix when window /viewport * reized with a right-hand coordinate system and a * clip-space of [0, 1]. * * NOTE: if you dodn't want to create new matrix then use array api on struct.raw * like glm_perspective_resize_rh_zo(proj.raw, aspect) to avoid create new mat4 * each time * * @param[in, out] proj perspective projection matrix * @param[in] aspect aspect ratio ( width / height ) */ CGLM_INLINE mat4s glms_perspective_resize_rh_zo(mat4s proj, float aspect) { mat4s dest; dest = proj; glm_perspective_resize_rh_zo(aspect, dest.raw); return dest; } /*! * @brief decomposes frustum values of perspective projection. * with a right-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] proj perspective projection matrix * @param[out] nearZ near * @param[out] farZ far * @param[out] top top * @param[out] bottom bottom * @param[out] left left * @param[out] right right */ CGLM_INLINE void glms_persp_decomp_rh_zo(mat4s proj, float * __restrict nearZ, float * __restrict farZ, float * __restrict top, float * __restrict bottom, float * __restrict left, float * __restrict right) { glm_persp_decomp_rh_zo(proj.raw, nearZ, farZ, top, bottom, left, right); } /*! * @brief decomposes frustum values of perspective projection. * this makes easy to get all values at once * with a right-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] proj perspective projection matrix * @param[out] dest array */ CGLM_INLINE void glms_persp_decompv_rh_zo(mat4s proj, float dest[6]) { glm_persp_decompv_rh_zo(proj.raw, dest); } /*! * @brief decomposes left and right values of perspective projection * with a right-hand coordinate system and a * clip-space of [0, 1]. * x stands for x axis (left / right axis) * * @param[in] proj perspective projection matrix * @param[out] left left * @param[out] right right */ CGLM_INLINE void glms_persp_decomp_x_rh_zo(mat4s proj, float * __restrict left, float * __restrict right) { glm_persp_decomp_x_rh_zo(proj.raw, left, right); } /*! * @brief decomposes top and bottom values of perspective projection * with a right-hand coordinate system and a * clip-space of [0, 1]. * y stands for y axis (top / bottom axis) * * @param[in] proj perspective projection matrix * @param[out] top top * @param[out] bottom bottom */ CGLM_INLINE void glms_persp_decomp_y_rh_zo(mat4s proj, float * __restrict top, float * __restrict bottom) { glm_persp_decomp_y_rh_zo(proj.raw, top, bottom); } /*! * @brief decomposes near and far values of perspective projection * with a right-hand coordinate system and a * clip-space of [0, 1]. * z stands for z axis (near / far axis) * * @param[in] proj perspective projection matrix * @param[out] nearZ near * @param[out] farZ far */ CGLM_INLINE void glms_persp_decomp_z_rh_zo(mat4s proj, float * __restrict nearZ, float * __restrict farZ) { glm_persp_decomp_z_rh_zo(proj.raw, nearZ, farZ); } /*! * @brief decomposes far value of perspective projection * with a right-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] proj perspective projection matrix * @param[out] farZ far */ CGLM_INLINE void glms_persp_decomp_far_rh_zo(mat4s proj, float * __restrict farZ) { glm_persp_decomp_far_rh_zo(proj.raw, farZ); } /*! * @brief decomposes near value of perspective projection * with a right-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] proj perspective projection matrix * @param[out] nearZ near */ CGLM_INLINE void glms_persp_decomp_near_rh_zo(mat4s proj, float * __restrict nearZ) { glm_persp_decomp_near_rh_zo(proj.raw, nearZ); } /*! * @brief returns field of view angle along the Y-axis (in radians) * with a right-hand coordinate system and a * clip-space of [0, 1]. * * if you need to degrees, use glm_deg to convert it or use this: * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) * * @param[in] proj perspective projection matrix */ CGLM_INLINE float glms_persp_fovy_rh_zo(mat4s proj) { return glm_persp_fovy_rh_zo(proj.raw); } /*! * @brief returns aspect ratio of perspective projection * with a right-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] proj perspective projection matrix */ CGLM_INLINE float glms_persp_aspect_rh_zo(mat4s proj) { return glm_persp_aspect_rh_zo(proj.raw); } /*! * @brief returns sizes of near and far planes of perspective projection * with a right-hand coordinate system and a * clip-space of [0, 1]. * * @param[in] proj perspective projection matrix * @param[in] fovy fovy (see brief) * @returns sizes as vector, sizes order: [Wnear, Hnear, Wfar, Hfar] */ CGLM_INLINE vec4s glms_persp_sizes_rh_zo(mat4s proj, float fovy) { vec4s dest; glm_persp_sizes_rh_zo(proj.raw, fovy, dest.raw); return dest; } #endif /* cglms_persp_rh_zo_h */ cglm-0.9.7/include/cglm/struct/clipspace/project_no.h000066400000000000000000000050341526744317200226350ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE vec3s glms_unprojecti_no(vec3s pos, mat4s invMat, vec4s vp) CGLM_INLINE vec3s glms_project_no(vec3s pos, mat4s m, vec4s vp) CGLM_INLINE float glms_project_z_no(vec3s v, mat4s m) */ #ifndef cglms_project_no_h #define cglms_project_no_h #include "../../common.h" #include "../../types-struct.h" #include "../../plane.h" #include "../../cam.h" #include "../../clipspace/project_no.h" /*! * @brief maps the specified viewport coordinates into specified space [1] * the matrix should contain projection matrix. * * if you don't have ( and don't want to have ) an inverse matrix then use * glm_unproject version. You may use existing inverse of matrix in somewhere * else, this is why glm_unprojecti exists to save save inversion cost * * [1] space: * 1- if m = invProj: View Space * 2- if m = invViewProj: World Space * 3- if m = invMVP: Object Space * * You probably want to map the coordinates into object space * so use invMVP as m * * Computing viewProj: * glm_mat4_mul(proj, view, viewProj); * glm_mat4_mul(viewProj, model, MVP); * glm_mat4_inv(viewProj, invMVP); * * @param[in] pos point/position in viewport coordinates * @param[in] invMat matrix (see brief) * @param[in] vp viewport as [x, y, width, height] * * @returns unprojected coordinates */ CGLM_INLINE vec3s glms_unprojecti_no(vec3s pos, mat4s invMat, vec4s vp) { vec3s dest; glm_unprojecti_no(pos.raw, invMat.raw, vp.raw, dest.raw); return dest; } /*! * @brief map object coordinates to window coordinates * * Computing MVP: * glm_mat4_mul(proj, view, viewProj); * glm_mat4_mul(viewProj, model, MVP); * * @param[in] pos object coordinates * @param[in] m MVP matrix * @param[in] vp viewport as [x, y, width, height] * * @returns projected coordinates */ CGLM_INLINE vec3s glms_project_no(vec3s pos, mat4s m, vec4s vp) { vec3s dest; glm_project_no(pos.raw, m.raw, vp.raw, dest.raw); return dest; } /*! * @brief map object's z coordinate to window coordinates * * Computing MVP: * glm_mat4_mul(proj, view, viewProj); * glm_mat4_mul(viewProj, model, MVP); * * @param[in] v object coordinates * @param[in] m MVP matrix * * @returns projected z coordinate */ CGLM_INLINE float glms_project_z_no(vec3s v, mat4s m) { return glm_project_z_no(v.raw, m.raw); } #endif /* cglms_project_rh_no_h */ cglm-0.9.7/include/cglm/struct/clipspace/project_zo.h000066400000000000000000000050301526744317200226450ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE vec3s glms_unprojecti_no(vec3s pos, mat4s invMat, vec4s vp) CGLM_INLINE vec3s glms_project_no(vec3s pos, mat4s m, vec4s vp) CGLM_INLINE float glms_project_z_zo(vec3s v, mat4s m) */ #ifndef cglms_project_zo_h #define cglms_project_zo_h #include "../../common.h" #include "../../types-struct.h" #include "../../plane.h" #include "../../cam.h" #include "../../clipspace/project_zo.h" /*! * @brief maps the specified viewport coordinates into specified space [1] * the matrix should contain projection matrix. * * if you don't have ( and don't want to have ) an inverse matrix then use * glm_unproject version. You may use existing inverse of matrix in somewhere * else, this is why glm_unprojecti exists to save save inversion cost * * [1] space: * 1- if m = invProj: View Space * 2- if m = invViewProj: World Space * 3- if m = invMVP: Object Space * * You probably want to map the coordinates into object space * so use invMVP as m * * Computing viewProj: * glm_mat4_mul(proj, view, viewProj); * glm_mat4_mul(viewProj, model, MVP); * glm_mat4_inv(viewProj, invMVP); * * @param[in] pos point/position in viewport coordinates * @param[in] invMat matrix (see brief) * @param[in] vp viewport as [x, y, width, height] * * @returns unprojected coordinates */ CGLM_INLINE vec3s glms_unprojecti_zo(vec3s pos, mat4s invMat, vec4s vp) { vec3s dest; glm_unprojecti_zo(pos.raw, invMat.raw, vp.raw, dest.raw); return dest; } /*! * @brief map object coordinates to window coordinates * * Computing MVP: * glm_mat4_mul(proj, view, viewProj); * glm_mat4_mul(viewProj, model, MVP); * * @param[in] pos object coordinates * @param[in] m MVP matrix * @param[in] vp viewport as [x, y, width, height] * * @returns projected coordinates */ CGLM_INLINE vec3s glms_project_zo(vec3s pos, mat4s m, vec4s vp) { vec3s dest; glm_project_zo(pos.raw, m.raw, vp.raw, dest.raw); return dest; } /*! * @brief map object's z coordinate to window coordinates * * Computing MVP: * glm_mat4_mul(proj, view, viewProj); * glm_mat4_mul(viewProj, model, MVP); * * @param[in] v object coordinates * @param[in] m MVP matrix * * @returns projected z coordinate */ CGLM_INLINE float glms_project_z_zo(vec3s v, mat4s m) { return glm_project_z_zo(v.raw, m.raw); } #endif /* cglm_project_zo_h */ cglm-0.9.7/include/cglm/struct/clipspace/view_lh_no.h000066400000000000000000000044731526744317200226320ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE mat4s glms_lookat_lh_no(vec3s eye, vec3s center, vec3s up) CGLM_INLINE mat4s glms_look_lh_no(vec3s eye, vec3s dir, vec3s up) CGLM_INLINE mat4s glms_look_anyup_lh_no(vec3s eye, vec3s dir) */ #ifndef cglms_view_lh_no_h #define cglms_view_lh_no_h #include "../../common.h" #include "../../types-struct.h" #include "../../plane.h" #include "../../cam.h" #include "../../clipspace/view_lh_no.h" /*! * @brief set up view matrix * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * NOTE: The UP vector must not be parallel to the line of sight from * the eye point to the reference point * * @param[in] eye eye vector * @param[in] center center vector * @param[in] up up vector * @returns result matrix */ CGLM_INLINE mat4s glms_lookat_lh_no(vec3s eye, vec3s center, vec3s up) { mat4s dest; glm_lookat_lh_no(eye.raw, center.raw, up.raw, dest.raw); return dest; } /*! * @brief set up view matrix * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * convenient wrapper for lookat: if you only have direction not target self * then this might be useful. Because you need to get target from direction. * * NOTE: The UP vector must not be parallel to the line of sight from * the eye point to the reference point * * @param[in] eye eye vector * @param[in] dir direction vector * @param[in] up up vector * @returns result matrix */ CGLM_INLINE mat4s glms_look_lh_no(vec3s eye, vec3s dir, vec3s up) { mat4s dest; glm_look_lh_no(eye.raw, dir.raw, up.raw, dest.raw); return dest; } /*! * @brief set up view matrix * with a left-hand coordinate system and a * clip-space of [-1, 1]. * * convenient wrapper for look: if you only have direction and if you don't * care what UP vector is then this might be useful to create view matrix * * @param[in] eye eye vector * @param[in] dir direction vector * @returns result matrix */ CGLM_INLINE mat4s glms_look_anyup_lh_no(vec3s eye, vec3s dir) { mat4s dest; glm_look_anyup_lh_no(eye.raw, dir.raw, dest.raw); return dest; } #endif /* cglms_view_lh_no_h */ cglm-0.9.7/include/cglm/struct/clipspace/view_lh_zo.h000066400000000000000000000044701526744317200226430ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE mat4s glms_lookat_lh_zo(vec3s eye, vec3s center, vec3s up) CGLM_INLINE mat4s glms_look_lh_zo(vec3s eye, vec3s dir, vec3s up) CGLM_INLINE mat4s glms_look_anyup_lh_zo(vec3s eye, vec3s dir) */ #ifndef cglms_view_lh_zo_h #define cglms_view_lh_zo_h #include "../../common.h" #include "../../types-struct.h" #include "../../plane.h" #include "../../cam.h" #include "../../clipspace/view_lh_zo.h" /*! * @brief set up view matrix * with a left-hand coordinate system and a * clip-space of [0, 1]. * * NOTE: The UP vector must not be parallel to the line of sight from * the eye point to the reference point * * @param[in] eye eye vector * @param[in] center center vector * @param[in] up up vector * @returns result matrix */ CGLM_INLINE mat4s glms_lookat_lh_zo(vec3s eye, vec3s center, vec3s up) { mat4s dest; glm_lookat_lh_zo(eye.raw, center.raw, up.raw, dest.raw); return dest; } /*! * @brief set up view matrix * with a left-hand coordinate system and a * clip-space of [0, 1]. * * convenient wrapper for lookat: if you only have direction not target self * then this might be useful. Because you need to get target from direction. * * NOTE: The UP vector must not be parallel to the line of sight from * the eye point to the reference point * * @param[in] eye eye vector * @param[in] dir direction vector * @param[in] up up vector * @returns result matrix */ CGLM_INLINE mat4s glms_look_lh_zo(vec3s eye, vec3s dir, vec3s up) { mat4s dest; glm_look_lh_zo(eye.raw, dir.raw, up.raw, dest.raw); return dest; } /*! * @brief set up view matrix * with a left-hand coordinate system and a * clip-space of [0, 1]. * * convenient wrapper for look: if you only have direction and if you don't * care what UP vector is then this might be useful to create view matrix * * @param[in] eye eye vector * @param[in] dir direction vector * @returns result matrix */ CGLM_INLINE mat4s glms_look_anyup_lh_zo(vec3s eye, vec3s dir) { mat4s dest; glm_look_anyup_lh_zo(eye.raw, dir.raw, dest.raw); return dest; } #endif /* cglms_view_lh_zo_h */ cglm-0.9.7/include/cglm/struct/clipspace/view_rh_no.h000066400000000000000000000044761526744317200226430ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE mat4s glms_lookat_rh_no(vec3s eye, vec3s center, vec3s up) CGLM_INLINE mat4s glms_look_rh_no(vec3s eye, vec3s dir, vec3s up) CGLM_INLINE mat4s glms_look_anyup_rh_no(vec3s eye, vec3s dir) */ #ifndef cglms_view_rh_no_h #define cglms_view_rh_no_h #include "../../common.h" #include "../../types-struct.h" #include "../../plane.h" #include "../../cam.h" #include "../../clipspace/view_rh_no.h" /*! * @brief set up view matrix * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * NOTE: The UP vector must not be parallel to the line of sight from * the eye point to the reference point * * @param[in] eye eye vector * @param[in] center center vector * @param[in] up up vector * @returns result matrix */ CGLM_INLINE mat4s glms_lookat_rh_no(vec3s eye, vec3s center, vec3s up) { mat4s dest; glm_lookat_rh_no(eye.raw, center.raw, up.raw, dest.raw); return dest; } /*! * @brief set up view matrix * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * convenient wrapper for lookat: if you only have direction not target self * then this might be useful. Because you need to get target from direction. * * NOTE: The UP vector must not be parallel to the line of sight from * the eye point to the reference point * * @param[in] eye eye vector * @param[in] dir direction vector * @param[in] up up vector * @returns result matrix */ CGLM_INLINE mat4s glms_look_rh_no(vec3s eye, vec3s dir, vec3s up) { mat4s dest; glm_look_rh_no(eye.raw, dir.raw, up.raw, dest.raw); return dest; } /*! * @brief set up view matrix * with a right-hand coordinate system and a * clip-space of [-1, 1]. * * convenient wrapper for look: if you only have direction and if you don't * care what UP vector is then this might be useful to create view matrix * * @param[in] eye eye vector * @param[in] dir direction vector * @returns result matrix */ CGLM_INLINE mat4s glms_look_anyup_rh_no(vec3s eye, vec3s dir) { mat4s dest; glm_look_anyup_rh_no(eye.raw, dir.raw, dest.raw); return dest; } #endif /* cglms_view_rh_no_h */ cglm-0.9.7/include/cglm/struct/clipspace/view_rh_zo.h000066400000000000000000000044731526744317200226540ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE mat4s glms_lookat_rh_zo(vec3s eye, vec3s center, vec3s up) CGLM_INLINE mat4s glms_look_rh_zo(vec3s eye, vec3s dir, vec3s up) CGLM_INLINE mat4s glms_look_anyup_rh_zo(vec3s eye, vec3s dir) */ #ifndef cglms_view_rh_zo_h #define cglms_view_rh_zo_h #include "../../common.h" #include "../../types-struct.h" #include "../../plane.h" #include "../../cam.h" #include "../../clipspace/view_rh_zo.h" /*! * @brief set up view matrix * with a right-hand coordinate system and a * clip-space of [0, 1]. * * NOTE: The UP vector must not be parallel to the line of sight from * the eye point to the reference point * * @param[in] eye eye vector * @param[in] center center vector * @param[in] up up vector * @returns result matrix */ CGLM_INLINE mat4s glms_lookat_rh_zo(vec3s eye, vec3s center, vec3s up) { mat4s dest; glm_lookat_rh_zo(eye.raw, center.raw, up.raw, dest.raw); return dest; } /*! * @brief set up view matrix * with a right-hand coordinate system and a * clip-space of [0, 1]. * * convenient wrapper for lookat: if you only have direction not target self * then this might be useful. Because you need to get target from direction. * * NOTE: The UP vector must not be parallel to the line of sight from * the eye point to the reference point * * @param[in] eye eye vector * @param[in] dir direction vector * @param[in] up up vector * @returns result matrix */ CGLM_INLINE mat4s glms_look_rh_zo(vec3s eye, vec3s dir, vec3s up) { mat4s dest; glm_look_rh_zo(eye.raw, dir.raw, up.raw, dest.raw); return dest; } /*! * @brief set up view matrix * with a right-hand coordinate system and a * clip-space of [0, 1]. * * convenient wrapper for look: if you only have direction and if you don't * care what UP vector is then this might be useful to create view matrix * * @param[in] eye eye vector * @param[in] dir direction vector * @returns result matrix */ CGLM_INLINE mat4s glms_look_anyup_rh_zo(vec3s eye, vec3s dir) { mat4s dest; glm_look_anyup_rh_zo(eye.raw, dir.raw, dest.raw); return dest; } #endif /* cglms_view_rh_zo_h */ cglm-0.9.7/include/cglm/struct/color.h000066400000000000000000000007561526744317200176540ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglms_colors_h #define cglms_colors_h #include "../common.h" #include "../types-struct.h" #include "../color.h" #include "vec3.h" /*! * @brief averages the color channels into one value * * @param[in] rgb RGB color */ CGLM_INLINE float glms_luminance(vec3s rgb) { return glm_luminance(rgb.raw); } #endif /* cglms_colors_h */ cglm-0.9.7/include/cglm/struct/curve.h000066400000000000000000000016571526744317200176630ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglms_curves_h #define cglms_curves_h #include "../common.h" #include "../types-struct.h" #include "../curve.h" #include "vec4.h" #include "mat4.h" /*! * @brief helper function to calculate S*M*C multiplication for curves * * This function does not encourage you to use SMC, * instead it is a helper if you use SMC. * * if you want to specify S as vector then use more generic glm_mat4_rmc() func. * * Example usage: * B(s) = glm_smc(s, GLM_BEZIER_MAT, (vec4){p0, c0, c1, p1}) * * @param[in] s parameter between 0 and 1 (this will be [s3, s2, s, 1]) * @param[in] m basis matrix * @param[in] c position/control vector * * @return B(s) */ CGLM_INLINE float glms_smc(float s, mat4s m, vec4s c) { return glm_smc(s, m.raw, c.raw); } #endif /* cglms_curves_h */ cglm-0.9.7/include/cglm/struct/euler.h000066400000000000000000000127161526744317200176510ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* NOTE: angles must be passed as [X-Angle, Y-Angle, Z-angle] order For instance you don't pass angles as [Z-Angle, X-Angle, Y-angle] to glm_euler_zxy function, All RELATED functions accept angles same order which is [X, Y, Z]. */ /* Types: enum glm_euler_seq Functions: CGLM_INLINE vec3s glms_euler_angles(mat4s m) CGLM_INLINE mat4s glms_euler_xyz(vec3s angles) CGLM_INLINE mat4s glms_euler_xzy(vec3s angles) CGLM_INLINE mat4s glms_euler_yxz(vec3s angles) CGLM_INLINE mat4s glms_euler_yzx(vec3s angles) CGLM_INLINE mat4s glms_euler_zxy(vec3s angles) CGLM_INLINE mat4s glms_euler_zyx(vec3s angles) CGLM_INLINE mat4s glms_euler_by_order(vec3s angles, glm_euler_seq ord) CGLM_INLINE versors glms_euler_xyz_quat(vec3s angles) CGLM_INLINE versors glms_euler_xzy_quat(vec3s angles) CGLM_INLINE versors glms_euler_yxz_quat(vec3s angles) CGLM_INLINE versors glms_euler_yzx_quat(vec3s angles) CGLM_INLINE versors glms_euler_zxy_quat(vec3s angles) CGLM_INLINE versors glms_euler_zyx_quat(vec3s angles) */ #ifndef cglms_euler_h #define cglms_euler_h #include "../common.h" #include "../types-struct.h" #include "../euler.h" /*! * @brief extract euler angles (in radians) using xyz order * * @param[in] m affine transform * @returns angles vector [x, y, z] */ CGLM_INLINE vec3s glms_euler_angles(mat4s m) { vec3s dest; glm_euler_angles(m.raw, dest.raw); return dest; } /*! * @brief build rotation matrix from euler angles * * @param[in] angles angles as vector [Xangle, Yangle, Zangle] * @returns rotation matrix */ CGLM_INLINE mat4s glms_euler_xyz(vec3s angles) { mat4s dest; glm_euler_xyz(angles.raw, dest.raw); return dest; } /*! * @brief build rotation matrix from euler angles * * @param[in] angles angles as vector [Xangle, Yangle, Zangle] * @returns rotation matrix */ CGLM_INLINE mat4s glms_euler_xzy(vec3s angles) { mat4s dest; glm_euler_xzy(angles.raw, dest.raw); return dest; } /*! * @brief build rotation matrix from euler angles * * @param[in] angles angles as vector [Xangle, Yangle, Zangle] * @returns rotation matrix */ CGLM_INLINE mat4s glms_euler_yxz(vec3s angles) { mat4s dest; glm_euler_yxz(angles.raw, dest.raw); return dest; } /*! * @brief build rotation matrix from euler angles * * @param[in] angles angles as vector [Xangle, Yangle, Zangle] * @returns rotation matrix */ CGLM_INLINE mat4s glms_euler_yzx(vec3s angles) { mat4s dest; glm_euler_yzx(angles.raw, dest.raw); return dest; } /*! * @brief build rotation matrix from euler angles * * @param[in] angles angles as vector [Xangle, Yangle, Zangle] * @returns rotation matrix */ CGLM_INLINE mat4s glms_euler_zxy(vec3s angles) { mat4s dest; glm_euler_zxy(angles.raw, dest.raw); return dest; } /*! * @brief build rotation matrix from euler angles * * @param[in] angles angles as vector [Xangle, Yangle, Zangle] * @returns rotation matrix */ CGLM_INLINE mat4s glms_euler_zyx(vec3s angles) { mat4s dest; glm_euler_zyx(angles.raw, dest.raw); return dest; } /*! * @brief build rotation matrix from euler angles * * @param[in] angles angles as vector [Xangle, Yangle, Zangle] * @param[in] ord euler order * @returns rotation matrix */ CGLM_INLINE mat4s glms_euler_by_order(vec3s angles, glm_euler_seq ord) { mat4s dest; glm_euler_by_order(angles.raw, ord, dest.raw); return dest; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in x y z order (roll pitch yaw) * * @param[in] angles angles x y z (radians) * @returns quaternion */ CGLM_INLINE versors glms_euler_xyz_quat(vec3s angles) { versors dest; glm_euler_xyz_quat(angles.raw, dest.raw); return dest; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in x z y order (roll yaw pitch) * * @param[in] angles angles x y z (radians) * @returns quaternion */ CGLM_INLINE versors glms_euler_xzy_quat(vec3s angles) { versors dest; glm_euler_xzy_quat(angles.raw, dest.raw); return dest; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in y x z order (pitch roll yaw) * * @param[in] angles angles x y z (radians) * @returns quaternion */ CGLM_INLINE versors glms_euler_yxz_quat(vec3s angles) { versors dest; glm_euler_yxz_quat(angles.raw, dest.raw); return dest; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in y z x order (pitch yaw roll) * * @param[in] angles angles x y z (radians) * @returns quaternion */ CGLM_INLINE versors glms_euler_yzx_quat(vec3s angles) { versors dest; glm_euler_yzx_quat(angles.raw, dest.raw); return dest; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in z x y order (yaw roll pitch) * * @param[in] angles angles x y z (radians) * @returns quaternion */ CGLM_INLINE versors glms_euler_zxy_quat(vec3s angles) { versors dest; glm_euler_zxy_quat(angles.raw, dest.raw); return dest; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in z y x order (yaw pitch roll) * * @param[in] angles angles x y z (radians) * @returns quaternion */ CGLM_INLINE versors glms_euler_zyx_quat(vec3s angles) { versors dest; glm_euler_zyx_quat(angles.raw, dest.raw); return dest; } #endif /* cglms_euler_h */ cglm-0.9.7/include/cglm/struct/frustum.h000066400000000000000000000103021526744317200202270ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglms_frustums_h #define cglms_frustums_h #include "../common.h" #include "../types-struct.h" #include "../frustum.h" #include "plane.h" #include "vec3.h" #include "vec4.h" #include "mat4.h" /* you can override clip space coords but you have to provide all with same name e.g.: define GLM_CSCOORD_LBN {0.0f, 0.0f, 1.0f, 1.0f} */ #ifndef GLM_CUSTOM_CLIPSPACE /* near */ #define GLMS_CSCOORD_LBN {-1.0f, -1.0f, -1.0f, 1.0f} #define GLMS_CSCOORD_LTN {-1.0f, 1.0f, -1.0f, 1.0f} #define GLMS_CSCOORD_RTN { 1.0f, 1.0f, -1.0f, 1.0f} #define GLMS_CSCOORD_RBN { 1.0f, -1.0f, -1.0f, 1.0f} /* far */ #define GLMS_CSCOORD_LBF {-1.0f, -1.0f, 1.0f, 1.0f} #define GLMS_CSCOORD_LTF {-1.0f, 1.0f, 1.0f, 1.0f} #define GLMS_CSCOORD_RTF { 1.0f, 1.0f, 1.0f, 1.0f} #define GLMS_CSCOORD_RBF { 1.0f, -1.0f, 1.0f, 1.0f} #endif /*! * @brief extracts view frustum planes * * planes' space: * 1- if m = proj: View Space * 2- if m = viewProj: World Space * 3- if m = MVP: Object Space * * You probably want to extract planes in world space so use viewProj as m * Computing viewProj: * glm_mat4_mul(proj, view, viewProj); * * Exracted planes order: [left, right, bottom, top, near, far] * * @param[in] m matrix (see brief) * @param[out] dest extracted view frustum planes (see brief) */ CGLM_INLINE void glms_frustum_planes(mat4s m, vec4s dest[6]) { vec4 rawDest[6]; glm_frustum_planes(m.raw, rawDest); glms_vec4_(pack)(dest, rawDest, 6); } /*! * @brief extracts view frustum corners using clip-space coordinates * * corners' space: * 1- if m = invViewProj: World Space * 2- if m = invMVP: Object Space * * You probably want to extract corners in world space so use invViewProj * Computing invViewProj: * glm_mat4_mul(proj, view, viewProj); * ... * glm_mat4_inv(viewProj, invViewProj); * * if you have a near coord at i index, you can get it's far coord by i + 4 * * Find center coordinates: * for (j = 0; j < 4; j++) { * glm_vec3_center(corners[i], corners[i + 4], centerCorners[i]); * } * * @param[in] invMat matrix (see brief) * @param[out] dest exracted view frustum corners (see brief) */ CGLM_INLINE void glms_frustum_corners(mat4s invMat, vec4s dest[8]) { vec4 rawDest[8]; glm_frustum_corners(invMat.raw, rawDest); glms_vec4_(pack)(dest, rawDest, 8); } /*! * @brief finds center of view frustum * * @param[in] corners view frustum corners * @returns view frustum center */ CGLM_INLINE vec4s glms_frustum_center(vec4s corners[8]) { vec4 rawCorners[8]; vec4s r; glms_vec4_(unpack)(rawCorners, corners, 8); glm_frustum_center(rawCorners, r.raw); return r; } /*! * @brief finds bounding box of frustum relative to given matrix e.g. view mat * * @param[in] corners view frustum corners * @param[in] m matrix to convert existing conners * @param[out] box bounding box as array [min, max] */ CGLM_INLINE void glms_frustum_box(vec4s corners[8], mat4s m, vec3s box[2]) { vec4 rawCorners[8]; vec3 rawBox[2]; glms_vec4_(unpack)(rawCorners, corners, 8); glm_frustum_box(rawCorners, m.raw, rawBox); glms_vec3_(pack)(box, rawBox, 2); } /*! * @brief finds planes corners which is between near and far planes (parallel) * * this will be helpful if you want to split a frustum e.g. CSM/PSSM. This will * find planes' corners but you will need to one more plane. * Actually you have it, it is near, far or created previously with this func ;) * * @param[in] corners view frustum corners * @param[in] splitDist split distance * @param[in] farDist far distance (zFar) * @param[out] planeCorners plane corners [LB, LT, RT, RB] */ CGLM_INLINE void glms_frustum_corners_at(vec4s corners[8], float splitDist, float farDist, vec4s planeCorners[4]) { vec4 rawCorners[8]; vec4 rawPlaneCorners[4]; glms_vec4_(unpack)(rawCorners, corners, 8); glm_frustum_corners_at(rawCorners, splitDist, farDist, rawPlaneCorners); glms_vec4_(pack)(planeCorners, rawPlaneCorners, 8); } #endif /* cglms_frustums_h */ cglm-0.9.7/include/cglm/struct/handed/000077500000000000000000000000001526744317200176005ustar00rootroot00000000000000cglm-0.9.7/include/cglm/struct/handed/euler_to_quat_lh.h000066400000000000000000000055101526744317200233050ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glms_euler_xyz_quat_lh(vec3 angles, versor dest); CGLM_INLINE void glms_euler_xzy_quat_lh(vec3 angles, versor dest); CGLM_INLINE void glms_euler_yxz_quat_lh(vec3 angles, versor dest); CGLM_INLINE void glms_euler_yzx_quat_lh(vec3 angles, versor dest); CGLM_INLINE void glms_euler_zxy_quat_lh(vec3 angles, versor dest); CGLM_INLINE void glms_euler_zyx_quat_lh(vec3 angles, versor dest); */ #ifndef cglms_euler_to_quat_lh_h #define cglms_euler_to_quat_lh_h #include "../common.h" /*! * @brief creates NEW quaternion using rotation angles and does * rotations in x y z order in left hand (roll pitch yaw) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE versors glms_euler_xyz_quat_lh(vec3s angles) { versors dest; glm_euler_xyz_quat_lh(angles.raw, dest.raw); return dest; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in x z y order in left hand (roll yaw pitch) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE versors glms_euler_xzy_quat_lh(vec3s angles) { versors dest; glm_euler_xzy_quat_lh(angles.raw, dest.raw); return dest; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in y x z order in left hand (pitch roll yaw) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE versors glms_euler_yxz_quat_lh(vec3s angles) { versors dest; glm_euler_yxz_quat_lh(angles.raw, dest.raw); return dest; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in y z x order in left hand (pitch yaw roll) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE versors glms_euler_yzx_quat_lh(vec3s angles) { versors dest; glm_euler_yzx_quat_lh(angles.raw, dest.raw); return dest; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in z x y order in left hand (yaw roll pitch) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE versors glms_euler_zxy_quat_lh(vec3s angles) { versors dest; glm_euler_zxy_quat_lh(angles.raw, dest.raw); return dest; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in z y x order in left hand (yaw pitch roll) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE versors glms_euler_zyx_quat_lh(vec3s angles) { versors dest; glm_euler_zyx_quat_lh(angles.raw, dest.raw); return dest; } #endif /* cglms_euler_to_quat_lh_h */ cglm-0.9.7/include/cglm/struct/handed/euler_to_quat_rh.h000066400000000000000000000055161526744317200233210ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glms_euler_xyz_quat_rh(vec3 angles, versor dest); CGLM_INLINE void glms_euler_xzy_quat_rh(vec3 angles, versor dest); CGLM_INLINE void glms_euler_yxz_quat_rh(vec3 angles, versor dest); CGLM_INLINE void glms_euler_yzx_quat_rh(vec3 angles, versor dest); CGLM_INLINE void glms_euler_zxy_quat_rh(vec3 angles, versor dest); CGLM_INLINE void glms_euler_zyx_quat_rh(vec3 angles, versor dest); */ #ifndef cglms_euler_to_quat_rh_h #define cglms_euler_to_quat_rh_h #include "../common.h" /*! * @brief creates NEW quaternion using rotation angles and does * rotations in x y z order in right hand (roll pitch yaw) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE versors glms_euler_xyz_quat_rh(vec3s angles) { versors dest; glm_euler_xyz_quat_rh(angles.raw, dest.raw); return dest; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in x z y order in right hand (roll yaw pitch) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE versors glms_euler_xzy_quat_rh(vec3s angles) { versors dest; glm_euler_xzy_quat_rh(angles.raw, dest.raw); return dest; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in y x z order in right hand (pitch roll yaw) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE versors glms_euler_yxz_quat_rh(vec3s angles) { versors dest; glm_euler_yxz_quat_rh(angles.raw, dest.raw); return dest; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in y z x order in right hand (pitch yaw roll) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE versors glms_euler_yzx_quat_rh(vec3s angles) { versors dest; glm_euler_yzx_quat_rh(angles.raw, dest.raw); return dest; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in z x y order in right hand (yaw roll pitch) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE versors glms_euler_zxy_quat_rh(vec3s angles) { versors dest; glm_euler_zxy_quat_rh(angles.raw, dest.raw); return dest; } /*! * @brief creates NEW quaternion using rotation angles and does * rotations in z y x order in right hand (yaw pitch roll) * * @param[in] angles angles x y z (radians) * @param[out] dest quaternion */ CGLM_INLINE versors glms_euler_zyx_quat_rh(vec3s angles) { versors dest; glm_euler_zyx_quat_rh(angles.raw, dest.raw); return dest; } #endif /* cglms_euler_to_quat_rh_h */ cglm-0.9.7/include/cglm/struct/io.h000066400000000000000000000047761526744317200171530ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glms_mat4_print(mat4s matrix, FILE *ostream); CGLM_INLINE void glms_mat3_print(mat3s matrix, FILE *ostream); CGLM_INLINE void glms_vec4_print(vec4s vec, FILE *ostream); CGLM_INLINE void glms_ivec4_print(ivec3s vec, FILE *ostream); CGLM_INLINE void glms_vec3_print(vec3s vec, FILE *ostream); CGLM_INLINE void glms_ivec3_print(ivec3s vec, FILE *ostream); CGLM_INLINE void glms_vec2_print(vec2s vec, FILE *ostream); CGLM_INLINE void glms_ivec2_print(ivec3s vec, FILE *ostream); CGLM_INLINE void glms_versor_print(versor vec, FILE *ostream); CGLM_INLINE void glms_aabb_print(vec3s bbox[2], const char *tag, FILE *ostream); */ #ifndef cglms_ios_h #define cglms_ios_h #include "../common.h" #include "../io.h" #include "mat4.h" #include #include CGLM_INLINE void glms_mat4_print(mat4s matrix, FILE * __restrict ostream) { glm_mat4_print(matrix.raw, ostream); } CGLM_INLINE void glms_mat3_print(mat3s matrix, FILE * __restrict ostream) { glm_mat3_print(matrix.raw, ostream); } CGLM_INLINE void glms_vec4_print(vec4s vec, FILE * __restrict ostream) { glm_vec4_print(vec.raw, ostream); } CGLM_INLINE void glms_ivec4_print(ivec4s vec, FILE * __restrict ostream) { glm_ivec4_print(vec.raw, ostream); } CGLM_INLINE void glms_vec3_print(vec3s vec, FILE * __restrict ostream) { glm_vec3_print(vec.raw, ostream); } CGLM_INLINE void glms_ivec3_print(ivec3s vec, FILE * __restrict ostream) { glm_ivec3_print(vec.raw, ostream); } CGLM_INLINE void glms_vec2_print(vec2s vec, FILE * __restrict ostream) { glm_vec2_print(vec.raw, ostream); } CGLM_INLINE void glms_ivec2_print(ivec2s vec, FILE * __restrict ostream) { glm_ivec2_print(vec.raw, ostream); } CGLM_INLINE void glms_versor_print(versors vec, FILE * __restrict ostream) { glm_versor_print(vec.raw, ostream); } CGLM_INLINE void glms_aabb_print(vec3s bbox[2], const char * __restrict tag, FILE * __restrict ostream) { vec3 rawBbox[2]; glms_vec3_(unpack)(rawBbox, bbox, 2); glm_aabb_print(rawBbox, tag, ostream); } #endif /* cglms_ios_h */ cglm-0.9.7/include/cglm/struct/ivec2.h000066400000000000000000000373111526744317200175430ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLMS_IVEC2_ONE_INIT GLMS_IVEC2_ZERO_INIT GLMS_IVEC2_ONE GLMS_IVEC2_ZERO Functions: CGLM_INLINE ivec2s glms_ivec2(int * __restrict v) CGLM_INLINE void glms_ivec2_pack(ivec2s dst[], ivec2s src[], size_t len) CGLM_INLINE void glms_ivec2_unpack(ivec2 dst[], ivec2 src[], size_t len) CGLM_INLINE ivec2s glms_ivec2_zero(ivec2s v) CGLM_INLINE ivec2s glms_ivec2_one(ivec2s v) CGLM_INLINE int glms_ivec2_dot(ivec2s a, ivec2s b) CGLM_INLINE int glms_ivec2_cross(ivec2s a, ivec2s b) CGLM_INLINE ivec2s glms_ivec2_add(ivec2s a, ivec2s b) CGLM_INLINE ivec2s glms_ivec2_adds(ivec2s v, int s) CGLM_INLINE ivec2s glms_ivec2_sub(ivec2s a, ivec2s b) CGLM_INLINE ivec2s glms_ivec2_subs(ivec2s v, int s) CGLM_INLINE ivec2s glms_ivec2_mul(ivec2s a, ivec2s b) CGLM_INLINE ivec2s glms_ivec2_scale(ivec2s v, int s) CGLM_INLINE ivec2s glms_ivec2_div(ivec2s a, ivec2s b) CGLM_INLINE ivec2s glms_ivec2_divs(ivec2s v, int s) CGLM_INLINE ivec2s glms_ivec2_mod(ivec2s a, ivec2s b) CGLM_INLINE ivec2s glms_ivec2_addadd(ivec2s a, ivec2s b) CGLM_INLINE ivec2s glms_ivec2_addadds(ivec2s a, int s) CGLM_INLINE ivec2s glms_ivec2_subadd(ivec2s a, ivec2s b) CGLM_INLINE ivec2s glms_ivec2_subadds(ivec2s a, int s) CGLM_INLINE ivec2s glms_ivec2_muladd(ivec2s a, ivec2s b) CGLM_INLINE ivec2s glms_ivec2_muladds(ivec2s a, int s) CGLM_INLINE ivec2s glms_ivec2_maxadd(ivec2s a, ivec2s b) CGLM_INLINE ivec2s glms_ivec2_minadd(ivec2s a, ivec2s b) CGLM_INLINE ivec2s glms_ivec2_subsub(ivec2s a, ivec2s b) CGLM_INLINE ivec2s glms_ivec2_subsubs(ivec2s a, int s) CGLM_INLINE ivec2s glms_ivec2_addsub(ivec2s a, ivec2s b) CGLM_INLINE ivec2s glms_ivec2_addsubs(ivec2s a, int s) CGLM_INLINE ivec2s glms_ivec2_mulsub(ivec2s a, ivec2s b) CGLM_INLINE ivec2s glms_ivec2_mulsubs(ivec2s a, int s) CGLM_INLINE ivec2s glms_ivec2_maxsub(ivec2s a, ivec2s b) CGLM_INLINE ivec2s glms_ivec2_minsub(ivec2s a, ivec2s b) CGLM_INLINE int glms_ivec2_distance2(ivec2s a, ivec2s b) CGLM_INLINE float glms_ivec2_distance(ivec2s a, ivec2s b) CGLM_INLINE ivec2s glms_ivec2_fill(int val) CGLM_INLINE bool glms_ivec2_eq(ivec2s v, int val); CGLM_INLINE bool glms_ivec2_eqv(ivec2s a, ivec2s b); CGLM_INLINE ivec2s glms_ivec2_maxv(ivec2s a, ivec2s b) CGLM_INLINE ivec2s glms_ivec2_minv(ivec2s a, ivec2s b) CGLM_INLINE ivec2s glms_ivec2_clamp(ivec2s v, int minVal, int maxVal) CGLM_INLINE ivec2s glms_ivec2_abs(ivec2s v) */ #ifndef cglms_ivec2_h #define cglms_ivec2_h #include "../common.h" #include "../types-struct.h" #include "../ivec2.h" #define glms_ivec2_(NAME) CGLM_STRUCTAPI(ivec2, NAME) #define GLMS_IVEC2_ONE_INIT {GLM_IVEC2_ONE_INIT} #define GLMS_IVEC2_ZERO_INIT {GLM_IVEC2_ZERO_INIT} #define GLMS_IVEC2_ONE ((ivec2s)GLMS_IVEC2_ONE_INIT) #define GLMS_IVEC2_ZERO ((ivec2s)GLMS_IVEC2_ZERO_INIT) /*! * @brief init ivec2 using ivec3 or ivec4 * * @param[in] v vector * @returns destination */ CGLM_INLINE ivec2s glms_ivec2(int * __restrict v) { ivec2s r; glm_ivec2(v, r.raw); return r; } /*! * @brief pack an array of ivec2 into an array of ivec2s * * @param[out] dst array of ivec2s * @param[in] src array of ivec2 * @param[in] len number of elements */ CGLM_INLINE void glms_ivec2_(pack)(ivec2s dst[], ivec2 src[], size_t len) { size_t i; for (i = 0; i < len; i++) { glm_ivec2_copy(src[i], dst[i].raw); } } /*! * @brief unpack an array of ivec2s into an array of ivec2 * * @param[out] dst array of ivec2 * @param[in] src array of ivec2s * @param[in] len number of elements */ CGLM_INLINE void glms_ivec2_(unpack)(ivec2 dst[], ivec2s src[], size_t len) { size_t i; for (i = 0; i < len; i++) { glm_ivec2_copy(src[i].raw, dst[i]); } } /*! * @brief set all members of [v] to zero * * @returns vector */ CGLM_INLINE ivec2s glms_ivec2_(zero)(void) { ivec2s r; glm_ivec2_zero(r.raw); return r; } /*! * @brief set all members of [v] to one * * @returns vector */ CGLM_INLINE ivec2s glms_ivec2_(one)(void) { ivec2s r; glm_ivec2_one(r.raw); return r; } /*! * @brief ivec2 dot product * * @param[in] a vector1 * @param[in] b vector2 * * @return dot product */ CGLM_INLINE int glms_ivec2_(dot)(ivec2s a, ivec2s b) { return glm_ivec2_dot(a.raw, b.raw); } /*! * @brief ivec2 cross product * * REF: http://allenchou.net/2013/07/cross-product-of-2d-vectors/ * * @param[in] a vector1 * @param[in] b vector2 * * @return Z component of cross product */ CGLM_INLINE int glms_ivec2_(cross)(ivec2s a, ivec2s b) { return glm_ivec2_cross(a.raw, b.raw); } /*! * @brief add vector [a] to vector [b] and store result in [dest] * * @param[in] a first vector * @param[in] b second vector * @returns destination */ CGLM_INLINE ivec2s glms_ivec2_(add)(ivec2s a, ivec2s b) { ivec2s r; glm_ivec2_add(a.raw, b.raw, r.raw); return r; } /*! * @brief add scalar s to vector [v] and store result in [dest] * * @param[in] v vector * @param[in] s scalar * @returns destination */ CGLM_INLINE ivec2s glms_ivec2_(adds)(ivec2s v, int s) { ivec2s r; glm_ivec2_adds(v.raw, s, r.raw); return r; } /*! * @brief subtract vector [b] from vector [a] and store result in [dest] * * @param[in] a first vector * @param[in] b second vector * @returns destination */ CGLM_INLINE ivec2s glms_ivec2_(sub)(ivec2s a, ivec2s b) { ivec2s r; glm_ivec2_sub(a.raw, b.raw, r.raw); return r; } /*! * @brief subtract scalar s from vector [v] and store result in [dest] * * @param[in] v vector * @param[in] s scalar * @returns destination */ CGLM_INLINE ivec2s glms_ivec2_(subs)(ivec2s v, int s) { ivec2s r; glm_ivec2_subs(v.raw, s, r.raw); return r; } /*! * @brief multiply vector [a] with vector [b] and store result in [dest] * * @param[in] a first vector * @param[in] b second vector * @returns destination */ CGLM_INLINE ivec2s glms_ivec2_(mul)(ivec2s a, ivec2s b) { ivec2s r; glm_ivec2_mul(a.raw, b.raw, r.raw); return r; } /*! * @brief multiply vector [a] with scalar s and store result in [dest] * * @param[in] v vector * @param[in] s scalar * @returns destination */ CGLM_INLINE ivec2s glms_ivec2_(scale)(ivec2s v, int s) { ivec2s r; glm_ivec2_scale(v.raw, s, r.raw); return r; } /*! * @brief div vector with another component-wise division: d = a / b * * @param[in] a vector 1 * @param[in] b vector 2 * @returns result = (a[0]/b[0], a[1]/b[1]) */ CGLM_INLINE ivec2s glms_ivec2_(div)(ivec2s a, ivec2s b) { ivec2s r; glm_ivec2_div(a.raw, b.raw, r.raw); return r; } /*! * @brief div vector with scalar: d = v / s * * @param[in] v vector * @param[in] s scalar * @returns result = (a[0]/s, a[1]/s) */ CGLM_INLINE ivec2s glms_ivec2_(divs)(ivec2s v, int s) { ivec2s r; glm_ivec2_divs(v.raw, s, r.raw); return r; } /*! * @brief mod vector with another component-wise modulo: d = a % b * * @param[in] a vector 1 * @param[in] b vector 2 * @returns result = (a[0]%b[0], a[1]%b[1]) */ CGLM_INLINE ivec2s glms_ivec2_(mod)(ivec2s a, ivec2s b) { ivec2s r; glm_ivec2_mod(a.raw, b.raw, r.raw); return r; } /*! * @brief add vector [a] with vector [b] and add result to vector [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[in] dest dest += (a + b) * @returns dest */ CGLM_INLINE ivec2s glms_ivec2_(addadd)(ivec2s a, ivec2s b, ivec2s dest) { glm_ivec2_addadd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief add scalar [s] onto vector [a] and add result to vector [dest] * * applies += operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[in] dest dest += (a + s) * @returns dest */ CGLM_INLINE ivec2s glms_ivec2_(addadds)(ivec2s a, int s, ivec2s dest) { glm_ivec2_addadds(a.raw, s, dest.raw); return dest; } /*! * @brief subtract vector [a] from vector [b] and add result to [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[in] dest dest += (a - b) * @returns dest */ CGLM_INLINE ivec2s glms_ivec2_(subadd)(ivec2s a, ivec2s b, ivec2s dest) { glm_ivec2_subadd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief subtract scalar [s] from vector [a] and add result to [dest] * * applies += operator so dest must be initialized * * @param[in] a first * @param[in] s scalar * @param[in] dest dest += (a - s) * @returns dest */ CGLM_INLINE ivec2s glms_ivec2_(subadds)(ivec2s a, int s, ivec2s dest) { glm_ivec2_subadds(a.raw, s, dest.raw); return dest; } /*! * @brief multiply vector [a] with vector [b] and add result to [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[in] dest dest += (a * b) * @returns dest */ CGLM_INLINE ivec2s glms_ivec2_(muladd)(ivec2s a, ivec2s b, ivec2s dest) { glm_ivec2_muladd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief multiply vector [a] with scalar [s] and add result to [dest] * * applies += operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[in] dest dest += (a * s) * @returns dest */ CGLM_INLINE ivec2s glms_ivec2_(muladds)(ivec2s a, int s, ivec2s dest) { glm_ivec2_muladds(a.raw, s, dest.raw); return dest; } /*! * @brief add maximum of vector [a] and vector [b] to vector [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[in] dest dest += max(a, b) * @returns dest */ CGLM_INLINE ivec2s glms_ivec2_(maxadd)(ivec2s a, ivec2s b, ivec2s dest) { glm_ivec2_maxadd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief add minimum of vector [a] and vector [b] to vector [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[in] dest dest += min(a, b) * @returns dest */ CGLM_INLINE ivec2s glms_ivec2_(minadd)(ivec2s a, ivec2s b, ivec2s dest) { glm_ivec2_minadd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief subtract vector [a] from vector [b] and subtract result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[in] dest dest -= (a - b) * @returns dest */ CGLM_INLINE ivec2s glms_ivec2_(subsub)(ivec2s a, ivec2s b, ivec2s dest) { glm_ivec2_subsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief subtract scalar [s] from vector [a] and subtract result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[in] dest dest -= (a - s) * @returns dest */ CGLM_INLINE ivec2s glms_ivec2_(subsubs)(ivec2s a, int s, ivec2s dest) { glm_ivec2_subsubs(a.raw, s, dest.raw); return dest; } /*! * @brief add vector [a] to vector [b] and subtract the result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] b scalar * @param[in] dest dest -= (a + b) * @returns dest */ CGLM_INLINE ivec2s glms_ivec2_(addsub)(ivec2s a, ivec2s b, ivec2s dest) { glm_ivec2_addsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief add scalar [s] to vector [a] and subtract the result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[in] dest dest -= (a + b) * @returns dest */ CGLM_INLINE ivec2s glms_ivec2_(addsubs)(ivec2s a, int s, ivec2s dest) { glm_ivec2_addsubs(a.raw, s, dest.raw); return dest; } /*! * @brief multiply vector [a] and vector [b] and subtract the result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] b scalar * @param[in] dest dest -= (a * b) * @returns dest */ CGLM_INLINE ivec2s glms_ivec2_(mulsub)(ivec2s a, ivec2s b, ivec2s dest) { glm_ivec2_mulsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief multiply vector [a] with scalar [s] and subtract the result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[in] dest dest -= (a * s) * @returns dest */ CGLM_INLINE ivec2s glms_ivec2_(mulsubs)(ivec2s a, int s, ivec2s dest) { glm_ivec2_mulsubs(a.raw, s, dest.raw); return dest; } /*! * @brief subtract maximum of vector [a] and vector [b] from vector [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[in] dest dest -= max(a, b) * @returns dest */ CGLM_INLINE ivec2s glms_ivec2_(maxsub)(ivec2s a, ivec2s b, ivec2s dest) { glm_ivec2_maxsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief subtract minimum of vector [a] and vector [b] from vector [dest] * * applies -= operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[in] dest dest -= min(a, b) * @returns dest */ CGLM_INLINE ivec2s glms_ivec2_(minsub)(ivec2s a, ivec2s b, ivec2s dest) { glm_ivec2_minsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief squared distance between two vectors * * @param[in] a first vector * @param[in] b second vector * @return returns squared distance (distance * distance) */ CGLM_INLINE int glms_ivec2_(distance2)(ivec2s a, ivec2s b) { return glm_ivec2_distance2(a.raw, b.raw); } /*! * @brief distance between two vectors * * @param[in] a first vector * @param[in] b second vector * @return returns distance */ CGLM_INLINE float glms_ivec2_(distance)(ivec2s a, ivec2s b) { return glm_ivec2_distance(a.raw, b.raw); } /*! * @brief fill a vector with specified value * * @param[in] val value * @returns dest */ CGLM_INLINE ivec2s glms_ivec2_(fill)(int val) { ivec2s r; glm_ivec2_fill(r.raw, val); return r; } /*! * @brief check if vector is equal to value * * @param[in] v vector * @param[in] val value */ CGLM_INLINE bool glms_ivec2_(eq)(ivec2s v, int val) { return glm_ivec2_eq(v.raw, val); } /*! * @brief check if vector is equal to another * * @param[in] a vector * @param[in] b vector */ CGLM_INLINE bool glms_ivec2_(eqv)(ivec2s a, ivec2s b) { return glm_ivec2_eqv(a.raw, b.raw); } /*! * @brief set each member of dest to greater of vector a and b * * @param[in] a first vector * @param[in] b second vector * @returns destination */ CGLM_INLINE ivec2s glms_ivec2_(maxv)(ivec2s a, ivec2s b) { ivec2s r; glm_ivec2_maxv(a.raw, b.raw, r.raw); return r; } /*! * @brief set each member of dest to lesser of vector a and b * * @param[in] a first vector * @param[in] b second vector * @returns destination */ CGLM_INLINE ivec2s glms_ivec2_(minv)(ivec2s a, ivec2s b) { ivec2s r; glm_ivec2_minv(a.raw, b.raw, r.raw); return r; } /*! * @brief clamp each member of [v] between minVal and maxVal (inclusive) * * @param[in] v vector * @param[in] minVal minimum value * @param[in] maxVal maximum value * @returns clamped vector */ CGLM_INLINE ivec2s glms_ivec2_(clamp)(ivec2s v, int minVal, int maxVal) { glm_ivec2_clamp(v.raw, minVal, maxVal); return v; } /*! * @brief absolute value of v * * @param[in] v vector * @returns destination */ CGLM_INLINE ivec2s glms_ivec2_(abs)(ivec2s v) { ivec2s r; glm_ivec2_abs(v.raw, r.raw); return r; } #endif /* cglms_ivec2_h */ cglm-0.9.7/include/cglm/struct/ivec3.h000066400000000000000000000404221526744317200175410ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLMS_IVEC3_ONE_INIT GLMS_IVEC3_ZERO_INIT GLMS_IVEC3_ONE GLMS_IVEC3_ZERO Functions: CGLM_INLINE ivec3s glms_ivec3(ivec4s v4) CGLM_INLINE void glms_ivec3_pack(ivec3s dst[], ivec3 src[], size_t len) CGLM_INLINE void glms_ivec3_unpack(ivec3 dst[], ivec3s src[], size_t len) CGLM_INLINE ivec3s glms_ivec3_zero(void) CGLM_INLINE ivec3s glms_ivec3_one(void) CGLM_INLINE int glms_ivec3_dot(ivec3s a, ivec3s b) CGLM_INLINE int glms_ivec3_norm2(ivec3s v) CGLM_INLINE int glms_ivec3_norm(ivec3s v) CGLM_INLINE ivec3s glms_ivec3_add(ivec3s a, ivec3s b) CGLM_INLINE ivec3s glms_ivec3_adds(ivec3s v, int s) CGLM_INLINE ivec3s glms_ivec3_sub(ivec3s a, ivec3s b) CGLM_INLINE ivec3s glms_ivec3_subs(ivec3s v, int s) CGLM_INLINE ivec3s glms_ivec3_mul(ivec3s a, ivec3s b) CGLM_INLINE ivec3s glms_ivec3_scale(ivec3s v, int s) CGLM_INLINE ivec3s glms_ivec3_div(ivec3s a, ivec3s b) CGLM_INLINE ivec3s glms_ivec3_divs(ivec3s v, int s) CGLM_INLINE ivec3s glms_ivec3_mod(ivec3s a, ivec3s b) CGLM_INLINE ivec3s glms_ivec3_addadd(ivec3s a, ivec3s b, ivec3s dest) CGLM_INLINE ivec3s glms_ivec3_addadds(ivec3s a, int s, ivec3s dest) CGLM_INLINE ivec3s glms_ivec3_subadd(ivec3s a, ivec3s b, ivec3s dest) CGLM_INLINE ivec3s glms_ivec3_subadds(ivec3s a, int s, ivec3s dest) CGLM_INLINE ivec3s glms_ivec3_muladd(ivec3s a, ivec3s b, ivec3s dest) CGLM_INLINE ivec3s glms_ivec3_muladds(ivec3s a, int s, ivec3s dest) CGLM_INLINE ivec3s glms_ivec3_minadd(ivec3s a, ivec3s b, ivec3s dest) CGLM_INLINE ivec3s glms_ivec3_subsub(ivec3s a, ivec3s b, ivec3s dest) CGLM_INLINE ivec3s glms_ivec3_subsubs(ivec3s a, int s, ivec3s dest) CGLM_INLINE ivec3s glms_ivec3_addsub(ivec3s a, ivec3s b, ivec3s dest) CGLM_INLINE ivec3s glms_ivec3_addsubs(ivec3s a, int s, ivec3s dest) CGLM_INLINE ivec3s glms_ivec3_mulsub(ivec3s a, ivec3s b, ivec3s dest) CGLM_INLINE ivec3s glms_ivec3_mulsubs(ivec3s a, int s, ivec3s dest) CGLM_INLINE ivec3s glms_ivec3_maxsub(ivec3s a, ivec3s b, ivec3s dest) CGLM_INLINE ivec3s glms_ivec3_minsub(ivec3s a, ivec3s b, ivec3s dest) CGLM_INLINE int glms_ivec3_distance2(ivec3s a, ivec3s b) CGLM_INLINE float glms_ivec3_distance(ivec3s a, ivec3s b) CGLM_INLINE ivec3s glms_ivec3_fill(int val) CGLM_INLINE bool glms_ivec3_eq(ivec3s v, int val) CGLM_INLINE bool glms_ivec3_eqv(ivec3s a, ivec3s b) CGLM_INLINE ivec3s glms_ivec3_maxv(ivec3s a, ivec3s b) CGLM_INLINE ivec3s glms_ivec3_minv(ivec3s a, ivec3s b) CGLM_INLINE ivec3s glms_ivec3_clamp(ivec3s v, int minVal, int maxVal) CGLM_INLINE ivec3s glms_ivec3_abs(ivec3s v) */ #ifndef cglms_ivec3_h #define cglms_ivec3_h #include "../common.h" #include "../types-struct.h" #include "../ivec3.h" #define glms_ivec3_(NAME) CGLM_STRUCTAPI(ivec3, NAME) #define GLMS_IVEC3_ONE_INIT {GLM_IVEC3_ONE_INIT} #define GLMS_IVEC3_ZERO_INIT {GLM_IVEC3_ZERO_INIT} #define GLMS_IVEC3_ONE ((ivec3s)GLMS_IVEC3_ONE_INIT) #define GLMS_IVEC3_ZERO ((ivec3s)GLMS_IVEC3_ZERO_INIT) /*! * @brief init ivec3 using ivec4 * * @param[in] v4 vector4 * @returns destination */ CGLM_INLINE ivec3s glms_ivec3(ivec4s v4) { ivec3s r; glm_ivec3(v4.raw, r.raw); return r; } /*! * @brief pack an array of ivec3 into an array of ivec3s * * @param[out] dst array of ivec3s * @param[in] src array of ivec3 * @param[in] len number of elements */ CGLM_INLINE void glms_ivec3_(pack)(ivec3s dst[], ivec3 src[], size_t len) { size_t i; for (i = 0; i < len; i++) { glm_ivec3_copy(src[i], dst[i].raw); } } /*! * @brief unpack an array of ivec3s into an array of ivec3 * * @param[out] dst array of ivec3 * @param[in] src array of ivec3s * @param[in] len number of elements */ CGLM_INLINE void glms_ivec3_(unpack)(ivec3 dst[], ivec3s src[], size_t len) { size_t i; for (i = 0; i < len; i++) { glm_ivec3_copy(src[i].raw, dst[i]); } } /*! * @brief set all members of [v] to zero * * @returns vector */ CGLM_INLINE ivec3s glms_ivec3_(zero)(void) { ivec3s r; glm_ivec3_zero(r.raw); return r; } /*! * @brief set all members of [v] to one * * @returns vector */ CGLM_INLINE ivec3s glms_ivec3_(one)(void) { ivec3s r; glm_ivec3_one(r.raw); return r; } /*! * @brief ivec3 dot product * * @param[in] a vector1 * @param[in] b vector2 * * @return dot product */ CGLM_INLINE int glms_ivec3_(dot)(ivec3s a, ivec3s b) { return glm_ivec3_dot(a.raw, b.raw); } /*! * @brief norm * norm (magnitude) of vec * * we can use this func instead of calling norm * norm, because it would call * sqrtf function twice but with this func we can avoid func call, maybe this is * not good name for this func * * @param[in] v vector * * @return norm * norm */ CGLM_INLINE int glms_ivec3_(norm2)(ivec3s v) { return glm_ivec3_norm2(v.raw); } /*! * @brief euclidean norm (magnitude), also called L2 norm * this will give magnitude of vector in euclidean space * * @param[in] v vector * * @return norm */ CGLM_INLINE int glms_ivec3_(norm)(ivec3s v) { return glm_ivec3_norm(v.raw); } /*! * @brief add vector [a] to vector [b] and store result in [dest] * * @param[in] a first vector * @param[in] b second vector * @returns destination */ CGLM_INLINE ivec3s glms_ivec3_(add)(ivec3s a, ivec3s b) { ivec3s r; glm_ivec3_add(a.raw, b.raw, r.raw); return r; } /*! * @brief add scalar s to vector [v] and store result in [dest] * * @param[in] v vector * @param[in] s scalar * @returns destination */ CGLM_INLINE ivec3s glms_ivec3_(adds)(ivec3s v, int s) { ivec3s r; glm_ivec3_adds(v.raw, s, r.raw); return r; } /*! * @brief subtract vector [b] from vector [a] and store result in [dest] * * @param[in] a first vector * @param[in] b second vector * @returns destination */ CGLM_INLINE ivec3s glms_ivec3_(sub)(ivec3s a, ivec3s b) { ivec3s r; glm_ivec3_sub(a.raw, b.raw, r.raw); return r; } /*! * @brief subtract scalar s from vector [v] and store result in [dest] * * @param[in] v vector * @param[in] s scalar * @returns destination */ CGLM_INLINE ivec3s glms_ivec3_(subs)(ivec3s v, int s) { ivec3s r; glm_ivec3_subs(v.raw, s, r.raw); return r; } /*! * @brief multiply vector [a] with vector [b] and store result in [dest] * * @param[in] a first vector * @param[in] b second vector * @returns destination */ CGLM_INLINE ivec3s glms_ivec3_(mul)(ivec3s a, ivec3s b) { ivec3s r; glm_ivec3_mul(a.raw, b.raw, r.raw); return r; } /*! * @brief multiply vector [a] with scalar s and store result in [dest] * * @param[in] v vector * @param[in] s scalar * @returns destination */ CGLM_INLINE ivec3s glms_ivec3_(scale)(ivec3s v, int s) { ivec3s r; glm_ivec3_scale(v.raw, s, r.raw); return r; } /*! * @brief div vector with another component-wise division: d = a / b * * @param[in] a vector 1 * @param[in] b vector 2 * @returns result = (a[0]/b[0], a[1]/b[1], a[2]/b[2]) */ CGLM_INLINE ivec3s glms_ivec3_(div)(ivec3s a, ivec3s b) { ivec3s r; glm_ivec3_div(a.raw, b.raw, r.raw); return r; } /*! * @brief div vector with scalar: d = v / s * * @param[in] v vector * @param[in] s scalar * @returns result = (a[0]/s, a[1]/s, a[2]/s) */ CGLM_INLINE ivec3s glms_ivec3_(divs)(ivec3s v, int s) { ivec3s r; glm_ivec3_divs(v.raw, s, r.raw); return r; } /*! * @brief Element-wise modulo operation on ivec3 vectors: dest = a % b * * Performs element-wise modulo on each component of vectors `a` and `b`. * * @param[in] a vector 1 * @param[in] b vector 2 * @returns result = (a[0]%b[0], a[1]%b[1], a[2]%b[2]) */ CGLM_INLINE ivec3s glms_ivec3_(mod)(ivec3s a, ivec3s b) { ivec3s r; glm_ivec3_mod(a.raw, b.raw, r.raw); return r; } /*! * @brief add vector [a] with vector [b] and add result to vector [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[in] dest dest += (a + b) * @returns dest */ CGLM_INLINE ivec3s glms_ivec3_(addadd)(ivec3s a, ivec3s b, ivec3s dest) { glm_ivec3_addadd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief add scalar [s] onto vector [a] and add result to vector [dest] * * applies += operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[in] dest dest += (a + s) * @returns dest */ CGLM_INLINE ivec3s glms_ivec3_(addadds)(ivec3s a, int s, ivec3s dest) { glm_ivec3_addadds(a.raw, s, dest.raw); return dest; } /*! * @brief subtract vector [a] from vector [b] and add result to [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[in] dest dest += (a - b) * @returns dest */ CGLM_INLINE ivec3s glms_ivec3_(subadd)(ivec3s a, ivec3s b, ivec3s dest) { glm_ivec3_subadd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief subtract scalar [s] from vector [a] and add result to [dest] * * applies += operator so dest must be initialized * * @param[in] a first * @param[in] s scalar * @param[in] dest dest += (a - s) * @returns dest */ CGLM_INLINE ivec3s glms_ivec3_(subadds)(ivec3s a, int s, ivec3s dest) { glm_ivec3_subadds(a.raw, s, dest.raw); return dest; } /*! * @brief multiply vector [a] with vector [b] and add result to [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[in] dest dest += (a * b) * @returns dest */ CGLM_INLINE ivec3s glms_ivec3_(muladd)(ivec3s a, ivec3s b, ivec3s dest) { glm_ivec3_muladd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief multiply vector [a] with scalar [s] and add result to [dest] * * applies += operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[in] dest dest += (a * s) * @returns dest */ CGLM_INLINE ivec3s glms_ivec3_(muladds)(ivec3s a, int s, ivec3s dest) { glm_ivec3_muladds(a.raw, s, dest.raw); return dest; } /*! * @brief add maximum of vector [a] and vector [b] to vector [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[in] dest dest += max(a, b) * @returns dest */ CGLM_INLINE ivec3s glms_ivec3_(maxadd)(ivec3s a, ivec3s b, ivec3s dest) { glm_ivec3_maxadd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief add minimum of vector [a] and vector [b] to vector [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[in] dest dest += min(a, b) * @returns dest */ CGLM_INLINE ivec3s glms_ivec3_(minadd)(ivec3s a, ivec3s b, ivec3s dest) { glm_ivec3_minadd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief subtract vector [a] from vector [b] and subtract result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[in] dest dest -= (a - b) * @returns dest */ CGLM_INLINE ivec3s glms_ivec3_(subsub)(ivec3s a, ivec3s b, ivec3s dest) { glm_ivec3_subsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief subtract scalar [s] from vector [a] and subtract result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[in] dest dest -= (a - s) * @returns dest */ CGLM_INLINE ivec3s glms_ivec3_(subsubs)(ivec3s a, int s, ivec3s dest) { glm_ivec3_subsubs(a.raw, s, dest.raw); return dest; } /*! * @brief add vector [a] to vector [b] and subtract the result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] b scalar * @param[in] dest dest -= (a + b) * @returns dest */ CGLM_INLINE ivec3s glms_ivec3_(addsub)(ivec3s a, ivec3s b, ivec3s dest) { glm_ivec3_addsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief add scalar [s] to vector [a] and subtract the result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[in] dest dest -= (a + b) * @returns dest */ CGLM_INLINE ivec3s glms_ivec3_(addsubs)(ivec3s a, int s, ivec3s dest) { glm_ivec3_addsubs(a.raw, s, dest.raw); return dest; } /*! * @brief multiply vector [a] and vector [b] and subtract the result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] b scalar * @param[in] dest dest -= (a * b) * @returns dest */ CGLM_INLINE ivec3s glms_ivec3_(mulsub)(ivec3s a, ivec3s b, ivec3s dest) { glm_ivec3_mulsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief multiply vector [a] with scalar [s] and subtract the result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[in] dest dest -= (a * s) * @returns dest */ CGLM_INLINE ivec3s glms_ivec3_(mulsubs)(ivec3s a, int s, ivec3s dest) { glm_ivec3_mulsubs(a.raw, s, dest.raw); return dest; } /*! * @brief subtract maximum of vector [a] and vector [b] from vector [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[in] dest dest -= max(a, b) * @returns dest */ CGLM_INLINE ivec3s glms_ivec3_(maxsub)(ivec3s a, ivec3s b, ivec3s dest) { glm_ivec3_maxsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief subtract minimum of vector [a] and vector [b] from vector [dest] * * applies -= operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[in] dest dest -= min(a, b) * @returns dest */ CGLM_INLINE ivec3s glms_ivec3_(minsub)(ivec3s a, ivec3s b, ivec3s dest) { glm_ivec3_minsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief squared distance between two vectors * * @param[in] a first vector * @param[in] b second vector * @return returns squared distance (distance * distance) */ CGLM_INLINE int glms_ivec3_(distance2)(ivec3s a, ivec3s b) { return glm_ivec3_distance2(a.raw, b.raw); } /*! * @brief distance between two vectors * * @param[in] a first vector * @param[in] b second vector * @return returns distance */ CGLM_INLINE float glms_ivec3_(distance)(ivec3s a, ivec3s b) { return glm_ivec3_distance(a.raw, b.raw); } /*! * @brief fill a vector with specified value * * @param[in] val value * @returns destination */ CGLM_INLINE ivec3s glms_ivec3_(fill)(int val) { ivec3s r; glm_ivec3_fill(r.raw, val); return r; } /*! * @brief check if vector is equal to value * * @param[in] v vector * @param[in] val value */ CGLM_INLINE bool glms_ivec3_(eq)(ivec3s v, int val) { return glm_ivec3_eq(v.raw, val); } /*! * @brief check if vector is equal to another * * @param[in] a vector * @param[in] b vector */ CGLM_INLINE bool glms_ivec3_(eqv)(ivec3s a, ivec3s b) { return glm_ivec3_eqv(a.raw, b.raw); } /*! * @brief set each member of dest to greater of vector a and b * * @param[in] a first vector * @param[in] b second vector * @returns destination */ CGLM_INLINE ivec3s glms_ivec3_(maxv)(ivec3s a, ivec3s b) { ivec3s r; glm_ivec3_maxv(a.raw, b.raw, r.raw); return r; } /*! * @brief set each member of dest to lesser of vector a and b * * @param[in] a first vector * @param[in] b second vector * @returns destination */ CGLM_INLINE ivec3s glms_ivec3_(minv)(ivec3s a, ivec3s b) { ivec3s r; glm_ivec3_minv(a.raw, b.raw, r.raw); return r; } /*! * @brief clamp each member of [v] between minVal and maxVal (inclusive) * * @param[in] v vector * @param[in] minVal minimum value * @param[in] maxVal maximum value * @returns clamped vector */ CGLM_INLINE ivec3s glms_ivec3_(clamp)(ivec3s v, int minVal, int maxVal) { glm_ivec3_clamp(v.raw, minVal, maxVal); return v; } /*! * @brief absolute value of v * * @param[in] v vector * @returns destination */ CGLM_INLINE ivec3s glms_ivec3_(abs)(ivec3s v) { ivec3s r; glm_ivec3_abs(v.raw, r.raw); return r; } #endif /* cglms_ivec3_h */ cglm-0.9.7/include/cglm/struct/ivec4.h000066400000000000000000000330521526744317200175430ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLMS_IVEC4_ONE_INIT GLMS_IVEC4_ZERO_INIT GLMS_IVEC4_ONE GLMS_IVEC4_ZERO Functions: CGLM_INLINE ivec4s glms_ivec4(ivec3s v3, int last) CGLM_INLINE void glms_ivec4_pack(ivec4s dst[], ivec4 src[], size_t len) CGLM_INLINE void glms_ivec4_unpack(ivec4 dst[], ivec4s src[], size_t len) CGLM_INLINE ivec4s glms_ivec4_zero(void) CGLM_INLINE ivec4s glms_ivec4_one(void) CGLM_INLINE ivec4s glms_ivec4_add(ivec4s a, ivec4s b) CGLM_INLINE ivec4s glms_ivec4_adds(ivec4s v, int s) CGLM_INLINE ivec4s glms_ivec4_sub(ivec4s a, ivec4s b) CGLM_INLINE ivec4s glms_ivec4_subs(ivec4s v, int s) CGLM_INLINE ivec4s glms_ivec4_mul(ivec4s a, ivec4s b) CGLM_INLINE ivec4s glms_ivec4_scale(ivec4s v, int s) CGLM_INLINE ivec4s glms_ivec4_addadd(ivec4s a, ivec4s b, ivec4s dest) CGLM_INLINE ivec4s glms_ivec4_addadds(ivec4s a, int s, ivec4s dest) CGLM_INLINE ivec4s glms_ivec4_subadd(ivec4s a, ivec4s b, ivec4s dest) CGLM_INLINE ivec4s glms_ivec4_subadds(ivec4s a, int s, ivec4s dest) CGLM_INLINE ivec4s glms_ivec4_muladd(ivec4s a, ivec4s b, ivec4s dest) CGLM_INLINE ivec4s glms_ivec4_muladds(ivec4s a, int s, ivec4s dest) CGLM_INLINE ivec4s glms_ivec4_maxadd(ivec4s a, ivec4s b, ivec4s dest) CGLM_INLINE ivec4s glms_ivec4_minadd(ivec4s a, ivec4s b, ivec4s dest) CGLM_INLINE ivec4s glms_ivec4_subsub(ivec4s a, ivec4s b, ivec4s dest) CGLM_INLINE ivec4s glms_ivec4_subsubs(ivec4s a, int s, ivec4s dest) CGLM_INLINE ivec4s glms_ivec4_addsub(ivec4s a, ivec4s b, ivec4s dest) CGLM_INLINE ivec4s glms_ivec4_addsubs(ivec4s a, int s, ivec4s dest) CGLM_INLINE ivec4s glms_ivec4_mulsub(ivec4s a, ivec4s b, ivec4s dest) CGLM_INLINE ivec4s glms_ivec4_mulsubs(ivec4s a, int s, ivec4s dest) CGLM_INLINE ivec4s glms_ivec4_maxsub(ivec4s a, ivec4s b, ivec4s dest) CGLM_INLINE ivec4s glms_ivec4_minsub(ivec4s a, ivec4s b, ivec4s dest) CGLM_INLINE int glms_ivec4_distance2(ivec4s a, ivec4s b) CGLM_INLINE float glms_ivec4_distance(ivec4s a, ivec4s b) CGLM_INLINE ivec4s glms_ivec4_maxv(ivec4s a, ivec4s b) CGLM_INLINE ivec4s glms_ivec4_minv(ivec4s a, ivec4s b) CGLM_INLINE ivec4s glms_ivec4_clamp(ivec4s v, int minVal, int maxVal) CGLM_INLINE ivec4s glms_ivec4_abs(ivec4s v) */ #ifndef cglms_ivec4_h #define cglms_ivec4_h #include "../common.h" #include "../types-struct.h" #include "../ivec4.h" #define glms_ivec4_(NAME) CGLM_STRUCTAPI(ivec4, NAME) #define GLMS_IVEC4_ONE_INIT {GLM_IVEC4_ONE_INIT} #define GLMS_IVEC4_ZERO_INIT {GLM_IVEC4_ZERO_INIT} #define GLMS_IVEC4_ONE ((ivec4s)GLMS_IVEC4_ONE_INIT) #define GLMS_IVEC4_ZERO ((ivec4s)GLMS_IVEC4_ZERO_INIT) /*! * @brief init ivec4 using ivec3 * * @param[in] v3 vector3 * @param[in] last last item * @returns destination */ CGLM_INLINE ivec4s glms_ivec4(ivec3s v3, int last) { ivec4s r; glm_ivec4(v3.raw, last, r.raw); return r; } /*! * @brief pack an array of ivec4 into an array of ivec4s * * @param[out] dst array of ivec4s * @param[in] src array of ivec4 * @param[in] len number of elements */ CGLM_INLINE void glms_ivec4_(pack)(ivec4s dst[], ivec4 src[], size_t len) { size_t i; for (i = 0; i < len; i++) { glm_ivec4_copy(src[i], dst[i].raw); } } /*! * @brief unpack an array of ivec4s into an array of ivec4 * * @param[out] dst array of ivec4 * @param[in] src array of ivec4s * @param[in] len number of elements */ CGLM_INLINE void glms_ivec4_(unpack)(ivec4 dst[], ivec4s src[], size_t len) { size_t i; for (i = 0; i < len; i++) { glm_ivec4_copy(src[i].raw, dst[i]); } } /*! * @brief set all members of [v] to zero * * @returns vector */ CGLM_INLINE ivec4s glms_ivec4_(zero)(void) { ivec4s r; glm_ivec4_zero(r.raw); return r; } /*! * @brief set all members of [v] to one * * @returns vector */ CGLM_INLINE ivec4s glms_ivec4_(one)(void) { ivec4s r; glm_ivec4_one(r.raw); return r; } /*! * @brief add vector [a] to vector [b] and store result in [dest] * * @param[in] a first vector * @param[in] b second vector * @returns destination */ CGLM_INLINE ivec4s glms_ivec4_(add)(ivec4s a, ivec4s b) { ivec4s r; glm_ivec4_add(a.raw, b.raw, r.raw); return r; } /*! * @brief add scalar s to vector [v] and store result in [dest] * * @param[in] v vector * @param[in] s scalar * @returns destination */ CGLM_INLINE ivec4s glms_ivec4_(adds)(ivec4s v, int s) { ivec4s r; glm_ivec4_adds(v.raw, s, r.raw); return r; } /*! * @brief subtract vector [b] from vector [a] and store result in [dest] * * @param[in] a first vector * @param[in] b second vector * @returns destination */ CGLM_INLINE ivec4s glms_ivec4_(sub)(ivec4s a, ivec4s b) { ivec4s r; glm_ivec4_sub(a.raw, b.raw, r.raw); return r; } /*! * @brief subtract scalar s from vector [v] and store result in [dest] * * @param[in] v vector * @param[in] s scalar * @returns destination */ CGLM_INLINE ivec4s glms_ivec4_(subs)(ivec4s v, int s) { ivec4s r; glm_ivec4_subs(v.raw, s, r.raw); return r; } /*! * @brief multiply vector [a] with vector [b] and store result in [dest] * * @param[in] a first vector * @param[in] b second vector * @returns destination */ CGLM_INLINE ivec4s glms_ivec4_(mul)(ivec4s a, ivec4s b) { ivec4s r; glm_ivec4_mul(a.raw, b.raw, r.raw); return r; } /*! * @brief multiply vector [a] with scalar s and store result in [dest] * * @param[in] v vector * @param[in] s scalar * @returns destination */ CGLM_INLINE ivec4s glms_ivec4_(scale)(ivec4s v, int s) { ivec4s r; glm_ivec4_scale(v.raw, s, r.raw); return r; } /*! * @brief add vector [a] with vector [b] and add result to vector [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[in] dest dest += (a + b) * @returns dest */ CGLM_INLINE ivec4s glms_ivec4_(addadd)(ivec4s a, ivec4s b, ivec4s dest) { glm_ivec4_addadd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief add scalar [s] onto vector [a] and add result to vector [dest] * * applies += operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[in] dest dest += (a + s) * @returns dest */ CGLM_INLINE ivec4s glms_ivec4_(addadds)(ivec4s a, int s, ivec4s dest) { glm_ivec4_addadds(a.raw, s, dest.raw); return dest; } /*! * @brief subtract vector [a] from vector [b] and add result to [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[in] dest dest += (a - b) * @returns dest */ CGLM_INLINE ivec4s glms_ivec4_(subadd)(ivec4s a, ivec4s b, ivec4s dest) { glm_ivec4_subadd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief subtract scalar [s] from vector [a] and add result to [dest] * * applies += operator so dest must be initialized * * @param[in] a first * @param[in] s scalar * @param[in] dest dest += (a - s) * @returns dest */ CGLM_INLINE ivec4s glms_ivec4_(subadds)(ivec4s a, int s, ivec4s dest) { glm_ivec4_subadds(a.raw, s, dest.raw); return dest; } /*! * @brief multiply vector [a] with vector [b] and add result to [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[in] dest dest += (a * b) * @returns dest */ CGLM_INLINE ivec4s glms_ivec4_(muladd)(ivec4s a, ivec4s b, ivec4s dest) { glm_ivec4_muladd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief multiply vector [a] with scalar [s] and add result to [dest] * * applies += operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[in] dest dest += (a * s) * @returns dest */ CGLM_INLINE ivec4s glms_ivec4_(muladds)(ivec4s a, int s, ivec4s dest) { glm_ivec4_muladds(a.raw, s, dest.raw); return dest; } /*! * @brief add maximum of vector [a] and vector [b] to vector [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[in] dest dest += max(a, b) * @returns dest */ CGLM_INLINE ivec4s glms_ivec4_(maxadd)(ivec4s a, ivec4s b, ivec4s dest) { glm_ivec4_maxadd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief add minimum of vector [a] and vector [b] to vector [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[in] dest dest += min(a, b) * @returns dest */ CGLM_INLINE ivec4s glms_ivec4_(minadd)(ivec4s a, ivec4s b, ivec4s dest) { glm_ivec4_minadd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief subtract vector [a] from vector [b] and subtract result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[in] dest dest -= (a - b) * @returns dest */ CGLM_INLINE ivec4s glms_ivec4_(subsub)(ivec4s a, ivec4s b, ivec4s dest) { glm_ivec4_subsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief subtract scalar [s] from vector [a] and subtract result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[in] dest dest -= (a - s) * @returns dest */ CGLM_INLINE ivec4s glms_ivec4_(subsubs)(ivec4s a, int s, ivec4s dest) { glm_ivec4_subsubs(a.raw, s, dest.raw); return dest; } /*! * @brief add vector [a] to vector [b] and subtract the result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] b scalar * @param[in] dest dest -= (a + b) * @returns dest */ CGLM_INLINE ivec4s glms_ivec4_(addsub)(ivec4s a, ivec4s b, ivec4s dest) { glm_ivec4_addsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief add scalar [s] to vector [a] and subtract the result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[in] dest dest -= (a + b) * @returns dest */ CGLM_INLINE ivec4s glms_ivec4_(addsubs)(ivec4s a, int s, ivec4s dest) { glm_ivec4_addsubs(a.raw, s, dest.raw); return dest; } /*! * @brief multiply vector [a] and vector [b] and subtract the result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] b scalar * @param[in] dest dest -= (a * b) * @returns dest */ CGLM_INLINE ivec4s glms_ivec4_(mulsub)(ivec4s a, ivec4s b, ivec4s dest) { glm_ivec4_mulsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief multiply vector [a] with scalar [s] and subtract the result from [dest] * * applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[in] dest dest -= (a * s) * @returns dest */ CGLM_INLINE ivec4s glms_ivec4_(mulsubs)(ivec4s a, int s, ivec4s dest) { glm_ivec4_mulsubs(a.raw, s, dest.raw); return dest; } /*! * @brief subtract maximum of vector [a] and vector [b] from vector [dest] * * applies += operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[in] dest dest -= max(a, b) * @returns dest */ CGLM_INLINE ivec4s glms_ivec4_(maxsub)(ivec4s a, ivec4s b, ivec4s dest) { glm_ivec4_maxsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief subtract minimum of vector [a] and vector [b] from vector [dest] * * applies -= operator so dest must be initialized * * @param[in] a first vector * @param[in] b second vector * @param[in] dest dest -= min(a, b) * @returns dest */ CGLM_INLINE ivec4s glms_ivec4_(minsub)(ivec4s a, ivec4s b, ivec4s dest) { glm_ivec4_minsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief squared distance between two vectors * * @param[in] a first vector * @param[in] b second vector * @return returns squared distance (distance * distance) */ CGLM_INLINE int glms_ivec4_(distance2)(ivec4s a, ivec4s b) { return glm_ivec4_distance2(a.raw, b.raw); } /*! * @brief distance between two vectors * * @param[in] a first vector * @param[in] b second vector * @return returns distance */ CGLM_INLINE float glms_ivec4_(distance)(ivec4s a, ivec4s b) { return glm_ivec4_distance(a.raw, b.raw); } /*! * @brief set each member of dest to greater of vector a and b * * @param[in] a first vector * @param[in] b second vector * @returns destination */ CGLM_INLINE ivec4s glms_ivec4_(maxv)(ivec4s a, ivec4s b) { ivec4s r; glm_ivec4_maxv(a.raw, b.raw, r.raw); return r; } /*! * @brief set each member of dest to lesser of vector a and b * * @param[in] a first vector * @param[in] b second vector * @returns destination */ CGLM_INLINE ivec4s glms_ivec4_(minv)(ivec4s a, ivec4s b) { ivec4s r; glm_ivec4_minv(a.raw, b.raw, r.raw); return r; } /*! * @brief clamp each member of [v] between minVal and maxVal (inclusive) * * @param[in] v vector * @param[in] minVal minimum value * @param[in] maxVal maximum value * @returns clamped vector */ CGLM_INLINE ivec4s glms_ivec4_(clamp)(ivec4s v, int minVal, int maxVal) { glm_ivec4_clamp(v.raw, minVal, maxVal); return v; } /*! * @brief absolute value of v * * @param[in] v vector * @returns destination */ CGLM_INLINE ivec4s glms_ivec4_(abs)(ivec4s v) { ivec4s r; glm_ivec4_abs(v.raw, r.raw); return r; } #endif /* cglms_ivec4_h */ cglm-0.9.7/include/cglm/struct/mat2.h000066400000000000000000000145501526744317200173760ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLM_MAT2_IDENTITY_INIT GLM_MAT2_ZERO_INIT GLM_MAT2_IDENTITY GLM_MAT2_ZERO Functions: CGLM_INLINE mat2s glms_mat2_make(const float * __restrict src); CGLM_INLINE mat2s glms_mat2_identity(void) CGLM_INLINE void glms_mat2_identity_array(mat2 * restrict mats, size_t count) CGLM_INLINE mat2s glms_mat2_zero(void) CGLM_INLINE mat2s glms_mat2_mul(mat2 m1, mat2 m2) CGLM_INLINE vec2s glms_mat2_mulv(mat2 m, vec2 v) CGLM_INLINE mat2s glms_mat2_transpose(mat2 m) CGLM_INLINE mat2s glms_mat2_scale(mat2 m, float s) CGLM_INLINE mat2s glms_mat2_inv(mat2 m) CGLM_INLINE mat2s glms_mat2_swap_col(mat2 mat, int col1, int col2) CGLM_INLINE mat2s glms_mat2_swap_row(mat2 mat, int row1, int row2) CGLM_INLINE float glms_mat2_det(mat2 m) CGLM_INLINE float glms_mat2_trace(mat2 m) CGLM_INLINE float glms_mat2_rmc(vec2 r, mat2 m, vec2 c) */ #ifndef cglms_mat2_h #define cglms_mat2_h #include "../common.h" #include "../types-struct.h" #include "../mat2.h" /* api definition */ #define glms_mat2_(NAME) CGLM_STRUCTAPI(mat2, NAME) #define GLMS_MAT2_IDENTITY_INIT {GLM_MAT2_IDENTITY_INIT} #define GLMS_MAT2_ZERO_INIT {GLM_MAT2_ZERO_INIT} /* for C only */ #define GLMS_MAT2_IDENTITY ((mat2s)GLMS_MAT2_IDENTITY_INIT) #define GLMS_MAT2_ZERO ((mat2s)GLMS_MAT2_ZERO_INIT) /*! * @brief Returns mat2s (r) from pointer (src). * * @param[in] src pointer to an array of floats * @return[out] r constructed mat2s from raw pointer */ CGLM_INLINE mat2s glms_mat2_(make)(const float * __restrict src) { mat2s r; glm_mat2_make(src, r.raw); return r; } /*! * @brief Return a identity mat2s (r). * * The same thing may be achieved with either of bellow methods, * but it is more easy to do that with this func especially for members * e.g. glm_mat2_identity(aStruct->aMatrix); * * @code * glm_mat2_copy(GLM_MAT2_IDENTITY, mat); // C only * * // or * mat2 mat = GLM_MAT2_IDENTITY_INIT; * @endcode * * @return[out] r constructed mat2s from raw pointer */ CGLM_INLINE mat2s glms_mat2_(identity)(void) { mat2s r; glm_mat2_identity(r.raw); return r; } /*! * @brief Given an array of mat2s’s (mats) make each matrix an identity matrix. * * @param[in, out] mats Array of mat2s’s (must be aligned (16/32) if alignment is not disabled) * @param[in] count Array size of mats or number of matrices */ CGLM_INLINE void glms_mat2_(identity_array)(mat2s * __restrict mats, size_t count) { CGLM_ALIGN_MAT mat2s t = GLMS_MAT2_IDENTITY_INIT; size_t i; for (i = 0; i < count; i++) { glm_mat2_copy(t.raw, mats[i].raw); } } /*! * @brief Return zero'd out mat2 (r). * * @return[out] r constructed mat2s from raw pointer */ CGLM_INLINE mat2s glms_mat2_(zero)(void) { mat2s r; glm_mat2_zero(r.raw); return r; } /*! * @brief Multiply mat2 (m1) by mat2 (m2) and return in mat2s (r) * * m1 and m2 matrices can be the same matrix, it is possible to write this: * * @code * mat2 m = GLM_MAT2_IDENTITY_INIT; * mat2s r = glms_mat2_mul(m, m); * @endcode * * @param[in] m1 mat2s (left) * @param[in] m2 mat2s (right) * @return[out] r constructed mat2s from raw pointers */ CGLM_INLINE mat2s glms_mat2_(mul)(mat2s m1, mat2s m2) { mat2s r; glm_mat2_mul(m1.raw, m2.raw, r.raw); return r; } /* * @brief Multiply mat2s (m) by vec2s (v) and return in vec2s (r). * * @param[in] m mat2s (left) * @param[in] v vec2s (right, column vector) * @return[out] r constructed vec2s from raw pointers */ CGLM_INLINE vec2s glms_mat2_(mulv)(mat2s m, vec2s v) { vec2s r; glm_mat2_mulv(m.raw, v.raw, r.raw); return r; } /*! * @brief Transpose mat2s (m) and store result in the same matrix. * * @param[in] m mat2s (src) * @return[out] m constructed mat2s from raw pointers */ CGLM_INLINE mat2s glms_mat2_(transpose)(mat2s m) { glm_mat2_transpose(m.raw); return m; } /*! * @brief Multiply mat2s (m) by scalar constant (s) * * @param[in] m mat2s (src) * @param[in] s scalar value * @return[out] m constructed mat2s from raw pointers */ CGLM_INLINE mat2s glms_mat2_(scale)(mat2s m, float s) { glm_mat2_scale(m.raw, s); return m; } /*! * @brief Inverse mat2s (m) and return in mat2s (r). * * @param[in] m mat2s (left, src) * @return[out] r constructed mat2s from raw pointers */ CGLM_INLINE mat2s glms_mat2_(inv)(mat2s m) { mat2s r; glm_mat2_inv(m.raw, r.raw); return r; } /*! * @brief Swap two columns in mat2s (mat) and store in same matrix. * * @param[in] mat mat2s * @param[in] col1 column 1 array index * @param[in] col2 column 2 array index * @return[out] mat constructed mat2s from raw pointers columns swapped */ CGLM_INLINE mat2s glms_mat2_(swap_col)(mat2s mat, int col1, int col2) { glm_mat2_swap_col(mat.raw, col1, col2); return mat; } /*! * @brief Swap two rows in mat2s (mat) and store in same matrix. * * @param[in] mat mat2s * @param[in] row1 row 1 array index * @param[in] row2 row 2 array index * @return[out] mat constructed mat2s from raw pointers rows swapped */ CGLM_INLINE mat2s glms_mat2_(swap_row)(mat2s mat, int row1, int row2) { glm_mat2_swap_row(mat.raw, row1, row2); return mat; } /*! * @brief Returns mat2 determinant. * * @param[in] m mat2 (src) * * @return[out] mat2s raw pointers determinant (float) */ CGLM_INLINE float glms_mat2_(det)(mat2s m) { return glm_mat2_det(m.raw); } /*! * @brief Returns trace of matrix. Which is: * * The sum of the elements on the main diagonal from * upper left corner to the bottom right corner. * * @param[in] m mat2 (m) * * @return[out] mat2s raw pointers trace (float) */ CGLM_INLINE float glms_mat2_(trace)(mat2s m) { return glm_mat2_trace(m.raw); } /*! * @brief Helper for R (row vector) * M (matrix) * C (column vector) * * rmc stands for Row * Matrix * Column * * the result is scalar because M * C = ResC (1x2, column vector), * then if you take the dot_product(R (2x1), ResC (1x2)) = scalar value. * * @param[in] r vec2s (2x1, row vector) * @param[in] m mat2s (2x2, matrix) * @param[in] c vec2s (1x2, column vector) * * @return[out] Scalar value (float, 1x1) */ CGLM_INLINE float glms_mat2_(rmc)(vec2s r, mat2s m, vec2s c) { return glm_mat2_rmc(r.raw, m.raw, c.raw); } #endif /* cglms_mat2_h */ cglm-0.9.7/include/cglm/struct/mat2x3.h000066400000000000000000000053631526744317200176530ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLMS_MAT2X3_ZERO_INIT GLMS_MAT2X3_ZERO Functions: CGLM_INLINE mat2x3s glms_mat2x3_zero(void); CGLM_INLINE mat2x3s glms_mat2x3_make(const float * __restrict src); CGLM_INLINE mat2s glms_mat2x3_mul(mat2x3s m1, mat3x2s m2); CGLM_INLINE vec3s glms_mat2x3_mulv(mat2x3s m, vec2s v); CGLM_INLINE mat3x2s glms_mat2x3_transpose(mat2x3s m); CGLM_INLINE mat2x3s glms_mat2x3_scale(mat2x3s m, float s); */ #ifndef cglms_mat2x3_h #define cglms_mat2x3_h #include "../common.h" #include "../types-struct.h" #include "../mat2x3.h" /* api definition */ #define glms_mat2x3_(NAME) CGLM_STRUCTAPI(mat2x3, NAME) #define GLMS_MAT2X3_ZERO_INIT {GLM_MAT2X3_ZERO_INIT} /* for C only */ #define GLMS_MAT2X3_ZERO ((mat2x3s)GLMS_MAT2X3_ZERO_INIT) /*! * @brief Zero out the mat2x3s (dest). * * @return[out] dest constructed mat2x3s from raw pointer */ CGLM_INLINE mat2x3s glms_mat2x3_(zero)(void) { mat2x3s dest; glm_mat2x3_zero(dest.raw); return dest; } /*! * @brief Create mat2x3s (dest) from pointer (src). * * @param[in] src pointer to an array of floats * @return[out] dest constructed mat2x3s from raw pointer */ CGLM_INLINE mat2x3s glms_mat2x3_(make)(const float * __restrict src) { mat2x3s dest; glm_mat2x3_make(src, dest.raw); return dest; } /*! * @brief Multiply mat2x3s (m1) by mat3x2s (m2) and store in mat3s (dest). * * @code * r = glms_mat2x3_mul(mat2x3s, mat3x2s); * @endcode * * @param[in] m1 mat2x3s (left) * @param[in] m2 mat3x2s (right) * @return[out] dest constructed mat3s from raw pointers */ CGLM_INLINE mat3s glms_mat2x3_(mul)(mat2x3s m1, mat3x2s m2) { mat3s dest; glm_mat2x3_mul(m1.raw, m2.raw, dest.raw); return dest; } /*! * @brief Multiply mat2x3s (m) by vec2s (v) and store in vec3s (dest). * * @param[in] m mat2x3s (left) * @param[in] v vec2s (right, column vector) * @return[out] dest constructed vec3s from raw pointers */ CGLM_INLINE vec3s glms_mat2x3_(mulv)(mat2x3s m, vec2s v) { vec3s dest; glm_mat2x3_mulv(m.raw, v.raw, dest.raw); return dest; } /*! * @brief Transpose mat2x3s (m) and store in mat3x2s (dest). * * @param[in] m mat2x3s (left) * @return[out] dest constructed mat3x2s from raw pointers */ CGLM_INLINE mat3x2s glms_mat2x3_(transpose)(mat2x3s m) { mat3x2s dest; glm_mat2x3_transpose(m.raw, dest.raw); return dest; } /*! * @brief Multiply mat2x3s (m) by scalar constant (s). * * @param[in, out] m mat2x3 (src, dest) * @param[in] s float (scalar) */ CGLM_INLINE mat2x3s glms_mat2x3_(scale)(mat2x3s m, float s) { glm_mat2x3_scale(m.raw, s); return m; } #endif /* cglms_mat2x3_h */ cglm-0.9.7/include/cglm/struct/mat2x4.h000066400000000000000000000053641526744317200176550ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLMS_MAT2X4_ZERO_INIT GLMS_MAT2X4_ZERO Functions: CGLM_INLINE mat2x4s glms_mat2x4_zero(void); CGLM_INLINE mat2x4s glms_mat2x4_make(const float * __restrict src); CGLM_INLINE mat2s glms_mat2x4_mul(mat2x4s m1, mat4x2s m2); CGLM_INLINE vec4s glms_mat2x4_mulv(mat2x4s m, vec2s v); CGLM_INLINE mat4x2s glms_mat2x4_transpose(mat2x4s m); CGLM_INLINE mat2x4s glms_mat2x4_scale(mat2x4s m, float s); */ #ifndef cglms_mat2x4_h #define cglms_mat2x4_h #include "../common.h" #include "../types-struct.h" #include "../mat2x4.h" /* api definition */ #define glms_mat2x4_(NAME) CGLM_STRUCTAPI(mat2x4, NAME) #define GLMS_MAT2X4_ZERO_INIT {GLM_MAT2X4_ZERO_INIT} /* for C only */ #define GLMS_MAT2X4_ZERO ((mat2x4s)GLMS_MAT2X4_ZERO_INIT) /*! * @brief Zero out the mat2x4s (dest). * * @return[out] dest constructed mat2x4s from raw pointer */ CGLM_INLINE mat2x4s glms_mat2x4_(zero)(void) { mat2x4s dest; glm_mat2x4_zero(dest.raw); return dest; } /*! * @brief Create mat2x4s (dest) from pointer (src). * * @param[in] src pointer to an array of floats * @return[out] dest constructed mat2x4s from raw pointer */ CGLM_INLINE mat2x4s glms_mat2x4_(make)(const float * __restrict src) { mat2x4s dest; glm_mat2x4_make(src, dest.raw); return dest; } /*! * @brief Multiply mat2x4s (m1) by mat4x2s (m2) and store in mat4s (dest). * * @code * r = glms_mat2x4_mul(mat2x4s, mat4x2s); * @endcode * * @param[in] m1 mat2x4s (left) * @param[in] m2 mat4x2s (right) * @return[out] dest constructed mat4s from raw pointers */ CGLM_INLINE mat4s glms_mat2x4_(mul)(mat2x4s m1, mat4x2s m2) { mat4s dest; glm_mat2x4_mul(m1.raw, m2.raw, dest.raw); return dest; } /*! * @brief Multiply mat2x4s (m) by vec2s (v) and store in vec4s (dest). * * @param[in] m mat2x4s (left) * @param[in] v vec2s (right, column vector) * @return[out] dest constructed vec4s from raw pointers */ CGLM_INLINE vec4s glms_mat2x4_(mulv)(mat2x4s m, vec2s v) { vec4s dest; glm_mat2x4_mulv(m.raw, v.raw, dest.raw); return dest; } /*! * @brief Transpose mat2x4s (m) and store in mat4x2s (dest). * * @param[in] m mat2x4s (left) * @return[out] dest constructed mat4x2s from raw pointers */ CGLM_INLINE mat4x2s glms_mat2x4_(transpose)(mat2x4s m) { mat4x2s dest; glm_mat2x4_transpose(m.raw, dest.raw); return dest; } /*! * @brief Multiply mat2x4s (m) by scalar constant (s). * * @param[in, out] m mat2x4s (src, dest) * @param[in] s float (scalar) */ CGLM_INLINE mat2x4s glms_mat2x4_(scale)(mat2x4s m, float s) { glm_mat2x4_scale(m.raw, s); return m; } #endif /* cglms_mat2x4_h */ cglm-0.9.7/include/cglm/struct/mat3.h000066400000000000000000000155161526744317200174020ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLMS_MAT3_IDENTITY_INIT GLMS_MAT3_ZERO_INIT GLMS_MAT3_IDENTITY GLMS_MAT3_ZERO Functions: CGLM_INLINE mat3s glms_mat3_copy(mat3s mat); CGLM_INLINE mat3s glms_mat3_identity(void); CGLM_INLINE void glms_mat3_identity_array(mat3s * __restrict mat, size_t count); CGLM_INLINE mat3s glms_mat3_zero(void); CGLM_INLINE mat3s glms_mat3_mul(mat3s m1, mat3s m2); CGLM_INLINE ma3s glms_mat3_transpose(mat3s m); CGLM_INLINE vec3s glms_mat3_mulv(mat3s m, vec3s v); CGLM_INLINE float glms_mat3_trace(mat3s m); CGLM_INLINE versor glms_mat3_quat(mat3s m); CGLM_INLINE mat3s glms_mat3_scale(mat3s m, float s); CGLM_INLINE float glms_mat3_det(mat3s mat); CGLM_INLINE mat3s glms_mat3_inv(mat3s mat); CGLM_INLINE mat3s glms_mat3_swap_col(mat3s mat, int col1, int col2); CGLM_INLINE mat3s glms_mat3_swap_row(mat3s mat, int row1, int row2); CGLM_INLINE float glms_mat3_rmc(vec3s r, mat3s m, vec3s c); CGLM_INLINE mat3s glms_mat3_make(const float * __restrict src); CGLM_INLINE mat3s glms_mat3_textrans(float sx, float sy, float rot, float tx, float ty); */ #ifndef cglms_mat3s_h #define cglms_mat3s_h #include "../common.h" #include "../types-struct.h" #include "../mat3.h" #include "vec3.h" /* api definition */ #define glms_mat3_(NAME) CGLM_STRUCTAPI(mat3, NAME) #define GLMS_MAT3_IDENTITY_INIT {GLM_MAT3_IDENTITY_INIT} #define GLMS_MAT3_ZERO_INIT {GLM_MAT3_ZERO_INIT} /* for C only */ #define GLMS_MAT3_IDENTITY ((mat3s)GLMS_MAT3_IDENTITY_INIT) #define GLMS_MAT3_ZERO ((mat3s)GLMS_MAT3_ZERO_INIT) /*! * @brief copy all members of [mat] to [dest] * * @param[in] mat source * @returns destination */ CGLM_INLINE mat3s glms_mat3_(copy)(mat3s mat) { mat3s r; glm_mat3_copy(mat.raw, r.raw); return r; } /*! * @brief make given matrix identity. It is identical with below, * but it is more easy to do that with this func especially for members * e.g. glm_mat3_identity(aStruct->aMatrix); * * @code * glm_mat3_copy(GLM_MAT3_IDENTITY, mat); // C only * * // or * mat3 mat = GLM_MAT3_IDENTITY_INIT; * @endcode * * @returns destination */ CGLM_INLINE mat3s glms_mat3_(identity)(void) { mat3s r; glm_mat3_identity(r.raw); return r; } /*! * @brief make given matrix array's each element identity matrix * * @param[in, out] mat matrix array (must be aligned (16/32) * if alignment is not disabled) * * @param[in] count count of matrices */ CGLM_INLINE void glms_mat3_(identity_array)(mat3s * __restrict mat, size_t count) { CGLM_ALIGN_MAT mat3s t = GLMS_MAT3_IDENTITY_INIT; size_t i; for (i = 0; i < count; i++) { glm_mat3_copy(t.raw, mat[i].raw); } } /*! * @brief make given matrix zero. * * @returns matrix */ CGLM_INLINE mat3s glms_mat3_(zero)(void) { mat3s r; glm_mat3_zero(r.raw); return r; } /*! * @brief multiply m1 and m2 to dest * * m1, m2 and dest matrices can be same matrix, it is possible to write this: * * @code * mat3 m = GLM_MAT3_IDENTITY_INIT; * r = glms_mat3_mul(m, m); * @endcode * * @param[in] m1 left matrix * @param[in] m2 right matrix * @returns destination matrix */ CGLM_INLINE mat3s glms_mat3_(mul)(mat3s m1, mat3s m2) { mat3s r; glm_mat3_mul(m1.raw, m2.raw, r.raw); return r; } /*! * @brief transpose mat3 and store result in same matrix * * @param[in, out] m source and dest */ CGLM_INLINE mat3s glms_mat3_(transpose)(mat3s m) { glm_mat3_transpose(m.raw); return m; } /*! * @brief multiply mat3 with vec3 (column vector) and store in dest vector * * @param[in] m mat3 (left) * @param[in] v vec3 (right, column vector) * @returns vec3 (result, column vector) */ CGLM_INLINE vec3s glms_mat3_(mulv)(mat3s m, vec3s v) { vec3s r; glm_mat3_mulv(m.raw, v.raw, r.raw); return r; } /*! * @brief trace of matrix * * sum of the elements on the main diagonal from upper left to the lower right * * @param[in] m matrix */ CGLM_INLINE float glms_mat3_(trace)(mat3s m) { return glm_mat3_trace(m.raw); } /*! * @brief convert mat3 to quaternion * * @param[in] m rotation matrix * @returns destination quaternion */ CGLM_INLINE versors glms_mat3_(quat)(mat3s m) { versors r; glm_mat3_quat(m.raw, r.raw); return r; } /*! * @brief scale (multiply with scalar) matrix * * multiply matrix with scalar * * @param[in] m matrix * @param[in] s scalar * @returns scaled matrix */ CGLM_INLINE mat3s glms_mat3_(scale)(mat3s m, float s) { glm_mat3_scale(m.raw, s); return m; } /*! * @brief mat3 determinant * * @param[in] mat matrix * * @return determinant */ CGLM_INLINE float glms_mat3_(det)(mat3s mat) { return glm_mat3_det(mat.raw); } /*! * @brief inverse mat3 and store in dest * * @param[in] mat matrix * @returns inverse matrix */ CGLM_INLINE mat3s glms_mat3_(inv)(mat3s mat) { mat3s r; glm_mat3_inv(mat.raw, r.raw); return r; } /*! * @brief swap two matrix columns * * @param[in] mat matrix * @param[in] col1 col1 * @param[in] col2 col2 * @returns matrix */ CGLM_INLINE mat3s glms_mat3_(swap_col)(mat3s mat, int col1, int col2) { glm_mat3_swap_col(mat.raw, col1, col2); return mat; } /*! * @brief swap two matrix rows * * @param[in] mat matrix * @param[in] row1 row1 * @param[in] row2 row2 * @returns matrix */ CGLM_INLINE mat3s glms_mat3_(swap_row)(mat3s mat, int row1, int row2) { glm_mat3_swap_row(mat.raw, row1, row2); return mat; } /*! * @brief helper for R (row vector) * M (matrix) * C (column vector) * * rmc stands for Row * Matrix * Column * * the result is scalar because R * M = Matrix1x3 (row vector), * then Matrix1x3 * Vec3 (column vector) = Matrix1x1 (Scalar) * * @param[in] r row vector or matrix1x3 * @param[in] m matrix3x3 * @param[in] c column vector or matrix3x1 * * @return scalar value e.g. Matrix1x1 */ CGLM_INLINE float glms_mat3_(rmc)(vec3s r, mat3s m, vec3s c) { return glm_mat3_rmc(r.raw, m.raw, c.raw); } /*! * @brief Create mat3 matrix from pointer * * @param[in] src pointer to an array of floats * @return constructed matrix from raw pointer */ CGLM_INLINE mat3s glms_mat3_(make)(const float * __restrict src) { mat3s r; glm_mat3_make(src, r.raw); return r; } /*! * @brief Create mat3 matrix from texture transform parameters * * @param[in] sx scale x * @param[in] sy scale y * @param[in] rot rotation in radians CCW/RH * @param[in] tx translate x * @param[in] ty translate y * @return texture transform matrix */ CGLM_INLINE mat3s glms_mat3_(textrans)(float sx, float sy, float rot, float tx, float ty) { mat3s r; glm_mat3_textrans(sx, sy, rot, tx, ty, r.raw); return r; } #endif /* cglms_mat3s_h */ cglm-0.9.7/include/cglm/struct/mat3x2.h000066400000000000000000000053641526744317200176540ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLMS_MAT3X2_ZERO_INIT GLMS_MAT3X2_ZERO Functions: CGLM_INLINE mat3x2s glms_mat3x2_zero(void); CGLM_INLINE mat3x2s glms_mat3x2_make(const float * __restrict src); CGLM_INLINE mat2s glms_mat3x2_mul(mat3x2s m1, mat2x3s m2); CGLM_INLINE vec2s glms_mat3x2_mulv(mat3x2s m, vec3s v); CGLM_INLINE mat2x3s glms_mat3x2_transpose(mat3x2s m); CGLM_INLINE mat3x2s glms_mat3x2_scale(mat3x2s m, float s); */ #ifndef cglms_mat3x2_h #define cglms_mat3x2_h #include "../common.h" #include "../types-struct.h" #include "../mat3x2.h" /* api definition */ #define glms_mat3x2_(NAME) CGLM_STRUCTAPI(mat3x2, NAME) #define GLMS_MAT3X2_ZERO_INIT {GLM_MAT3X2_ZERO_INIT} /* for C only */ #define GLMS_MAT3X2_ZERO ((mat3x2s)GLMS_MAT3X2_ZERO_INIT) /*! * @brief Zero out the mat3x2s (dest). * * @return[out] dest constructed mat3x2s from raw pointer */ CGLM_INLINE mat3x2s glms_mat3x2_(zero)(void) { mat3x2s dest; glm_mat3x2_zero(dest.raw); return dest; } /*! * @brief Create mat3x2s (dest) from pointer (src). * * @param[in] src pointer to an array of floats * @return[out] dest constructed mat3x2s from raw pointer */ CGLM_INLINE mat3x2s glms_mat3x2_(make)(const float * __restrict src) { mat3x2s dest; glm_mat3x2_make(src, dest.raw); return dest; } /*! * @brief Multiply mat3x2s (m1) by mat2x3s (m2) and store in mat2s (dest). * * @code * r = glms_mat3x2_mul(mat3x2s, mat2x3s); * @endcode * * @param[in] m1 mat3x2s (left) * @param[in] m2 mat2x3s (right) * @return[out] dest constructed mat2s from raw pointers */ CGLM_INLINE mat2s glms_mat3x2_(mul)(mat3x2s m1, mat2x3s m2) { mat2s dest; glm_mat3x2_mul(m1.raw, m2.raw, dest.raw); return dest; } /*! * @brief Multiply mat3x2s (m) by vec3s (v) and store in vec2s (dest). * * @param[in] m mat3x2s (left) * @param[in] v vec3s (right, column vector) * @return[out] dest constructed vec2s from raw pointers */ CGLM_INLINE vec2s glms_mat3x2_(mulv)(mat3x2s m, vec3s v) { vec2s dest; glm_mat3x2_mulv(m.raw, v.raw, dest.raw); return dest; } /*! * @brief Transpose mat3x2s (m) and store in mat2x3s (dest). * * @param[in] m mat3x2s (left) * @return[out] dest constructed mat2x3s from raw pointers */ CGLM_INLINE mat2x3s glms_mat3x2_(transpose)(mat3x2s m) { mat2x3s dest; glm_mat3x2_transpose(m.raw, dest.raw); return dest; } /*! * @brief Multiply mat3x2s (m) by scalar constant (s). * * @param[in, out] m mat3x2s (src, dest) * @param[in] s float (scalar) */ CGLM_INLINE mat3x2s glms_mat3x2_(scale)(mat3x2s m, float s) { glm_mat3x2_scale(m.raw, s); return m; } #endif /* cglms_mat3x2_h */ cglm-0.9.7/include/cglm/struct/mat3x4.h000066400000000000000000000053641526744317200176560ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLMS_MAT3X4_ZERO_INIT GLMS_MAT3X4_ZERO Functions: CGLM_INLINE mat3x4s glms_mat3x4_zero(void); CGLM_INLINE mat3x4s glms_mat3x4_make(const float * __restrict src); CGLM_INLINE mat4s glms_mat3x4_mul(mat3x4s m1, mat4x3s m2); CGLM_INLINE vec4s glms_mat3x4_mulv(mat3x4s m, vec3s v); CGLM_INLINE mat4x3s glms_mat3x4_transpose(mat3x4s m); CGLM_INLINE mat3x4s glms_mat3x4_scale(mat3x4s m, float s); */ #ifndef cglms_mat3x4_h #define cglms_mat3x4_h #include "../common.h" #include "../types-struct.h" #include "../mat3x4.h" /* api definition */ #define glms_mat3x4_(NAME) CGLM_STRUCTAPI(mat3x4, NAME) #define GLMS_MAT3X4_ZERO_INIT {GLM_MAT3X4_ZERO_INIT} /* for C only */ #define GLMS_MAT3X4_ZERO ((mat3x4s)GLMS_MAT3X4_ZERO_INIT) /*! * @brief Zero out the mat3x4s (dest). * * @return[out] dest constructed mat3x4s from raw pointer */ CGLM_INLINE mat3x4s glms_mat3x4_(zero)(void) { mat3x4s dest; glm_mat3x4_zero(dest.raw); return dest; } /*! * @brief Create mat3x4s (dest) from pointer (src). * * @param[in] src pointer to an array of floats * @return[out] dest constructed mat3x4s from raw pointer */ CGLM_INLINE mat3x4s glms_mat3x4_(make)(const float * __restrict src) { mat3x4s dest; glm_mat3x4_make(src, dest.raw); return dest; } /*! * @brief Multiply mat3x4s (m1) by mat4x3s (m2) and store in mat4s (dest). * * @code * r = glms_mat3x4_mul(mat3x4s, mat4x3s); * @endcode * * @param[in] m1 mat3x4s (left) * @param[in] m2 mat4x3s (right) * @return[out] dest constructed mat4s from raw pointers */ CGLM_INLINE mat4s glms_mat3x4_(mul)(mat3x4s m1, mat4x3s m2) { mat4s dest; glm_mat3x4_mul(m1.raw, m2.raw, dest.raw); return dest; } /*! * @brief Multiply mat3x4s (m) by vec3s (v) and store in vec4s (dest). * * @param[in] m mat3x4s (left) * @param[in] v vec3s (right, column vector) * @return[out] dest constructed vec4s from raw pointers */ CGLM_INLINE vec4s glms_mat3x4_(mulv)(mat3x4s m, vec3s v) { vec4s dest; glm_mat3x4_mulv(m.raw, v.raw, dest.raw); return dest; } /*! * @brief Transpose mat3x4s (m) and store in mat4x3s (dest). * * @param[in] m mat3x4s (left) * @return[out] dest constructed mat4x3s from raw pointers */ CGLM_INLINE mat4x3s glms_mat3x4_(transpose)(mat3x4s m) { mat4x3s dest; glm_mat3x4_transpose(m.raw, dest.raw); return dest; } /*! * @brief Multiply mat3x4s (m) by scalar constant (s). * * @param[in, out] m mat3x4s (src, dest) * @param[in] s float (scalar) */ CGLM_INLINE mat3x4s glms_mat3x4_(scale)(mat3x4s m, float s) { glm_mat3x4_scale(m.raw, s); return m; } #endif /* cglms_mat3x4_h */ cglm-0.9.7/include/cglm/struct/mat4.h000066400000000000000000000253701526744317200174020ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /*! * Most of functions in this header are optimized manually with SIMD * if available. You dont need to call/incude SIMD headers manually */ /* Macros: GLMS_MAT4_IDENTITY_INIT GLMS_MAT4_ZERO_INIT GLMS_MAT4_IDENTITY GLMS_MAT4_ZERO Functions: CGLM_INLINE mat4s glms_mat4_ucopy(mat4s mat); CGLM_INLINE mat4s glms_mat4_copy(mat4s mat); CGLM_INLINE mat4s glms_mat4_identity(void); CGLM_INLINE void glms_mat4_identity_array(mat4s * __restrict mat, size_t count); CGLM_INLINE mat4s glms_mat4_zero(void); CGLM_INLINE mat3s glms_mat4_pick3(mat4s mat); CGLM_INLINE mat3s glms_mat4_pick3t(mat4s mat); CGLM_INLINE mat4s glms_mat4_ins3(mat3s mat, mat4s dest); CGLM_INLINE mat4s glms_mat4_mul(mat4s m1, mat4s m2); CGLM_INLINE mat4s glms_mat4_mulN(mat4s * __restrict matrices[], uint32_t len); CGLM_INLINE vec4s glms_mat4_mulv(mat4s m, vec4s v); CGLM_INLINE float glms_mat4_trace(mat4s m); CGLM_INLINE float glms_mat4_trace3(mat4s m); CGLM_INLINE versors glms_mat4_quat(mat4s m); CGLM_INLINE vec3s glms_mat4_mulv3(mat4s m, vec3s v, float last); CGLM_INLINE mat4s glms_mat4_transpose(mat4s m); CGLM_INLINE mat4s glms_mat4_scale_p(mat4s m, float s); CGLM_INLINE mat4s glms_mat4_scale(mat4s m, float s); CGLM_INLINE float glms_mat4_det(mat4s mat); CGLM_INLINE mat4s glms_mat4_inv(mat4s mat); CGLM_INLINE mat4s glms_mat4_inv_fast(mat4s mat); CGLM_INLINE mat4s glms_mat4_swap_col(mat4s mat, int col1, int col2); CGLM_INLINE mat4s glms_mat4_swap_row(mat4s mat, int row1, int row2); CGLM_INLINE float glms_mat4_rmc(vec4s r, mat4s m, vec4s c); CGLM_INLINE mat4s glms_mat4_make(const float * __restrict src); CGLM_INLINE mat4s glms_mat4_textrans(float sx, float sy, float rot, float tx, float ty); */ #ifndef cglms_mat4s_h #define cglms_mat4s_h #include "../common.h" #include "../types-struct.h" #include "../mat4.h" #include "vec4.h" #include "vec3.h" /* api definition */ #define glms_mat4_(NAME) CGLM_STRUCTAPI(mat4, NAME) #define GLMS_MAT4_IDENTITY_INIT {GLM_MAT4_IDENTITY_INIT} #define GLMS_MAT4_ZERO_INIT {GLM_MAT4_ZERO_INIT} /* for C only */ #define GLMS_MAT4_IDENTITY ((mat4s)GLMS_MAT4_IDENTITY_INIT) #define GLMS_MAT4_ZERO ((mat4s)GLMS_MAT4_ZERO_INIT) /*! * @brief copy all members of [mat] to [dest] * * matrix may not be aligned, u stands for unaligned, this may be useful when * copying a matrix from external source e.g. asset importer... * * @param[in] mat source * @returns destination */ CGLM_INLINE mat4s glms_mat4_(ucopy)(mat4s mat) { mat4s r; glm_mat4_ucopy(mat.raw, r.raw); return r; } /*! * @brief copy all members of [mat] to [dest] * * @param[in] mat source * @returns destination */ CGLM_INLINE mat4s glms_mat4_(copy)(mat4s mat) { mat4s r; glm_mat4_copy(mat.raw, r.raw); return r; } /*! * @brief make given matrix identity. It is identical with below, * but it is more easy to do that with this func especially for members * e.g. glm_mat4_identity(aStruct->aMatrix); * * @code * glm_mat4_copy(GLM_MAT4_IDENTITY, mat); // C only * * // or * mat4 mat = GLM_MAT4_IDENTITY_INIT; * @endcode * * @returns destination */ CGLM_INLINE mat4s glms_mat4_(identity)(void) { mat4s r; glm_mat4_identity(r.raw); return r; } /*! * @brief make given matrix array's each element identity matrix * * @param[in, out] mat matrix array (must be aligned (16/32) * if alignment is not disabled) * * @param[in] count count of matrices */ CGLM_INLINE void glms_mat4_(identity_array)(mat4s * __restrict mat, size_t count) { CGLM_ALIGN_MAT mat4s t = GLMS_MAT4_IDENTITY_INIT; size_t i; for (i = 0; i < count; i++) { glm_mat4_copy(t.raw, mat[i].raw); } } /*! * @brief make given matrix zero. * * @returns matrix */ CGLM_INLINE mat4s glms_mat4_(zero)(void) { mat4s r; glm_mat4_zero(r.raw); return r; } /*! * @brief copy upper-left of mat4 to mat3 * * @param[in] mat source * @returns destination */ CGLM_INLINE mat3s glms_mat4_(pick3)(mat4s mat) { mat3s r; glm_mat4_pick3(mat.raw, r.raw); return r; } /*! * @brief copy upper-left of mat4 to mat3 (transposed) * * the postfix t stands for transpose * * @param[in] mat source * @returns destination */ CGLM_INLINE mat3s glms_mat4_(pick3t)(mat4s mat) { mat3s r; glm_mat4_pick3t(mat.raw, r.raw); return r; } /*! * @brief copy mat3 to mat4's upper-left * * @param[in] mat source * @param[in] dest destination * @returns destination */ CGLM_INLINE mat4s glms_mat4_(ins3)(mat3s mat, mat4s dest) { glm_mat4_ins3(mat.raw, dest.raw); return dest; } /*! * @brief multiply m1 and m2 to dest * * m1, m2 and dest matrices can be same matrix, it is possible to write this: * * @code * mat4 m = GLM_MAT4_IDENTITY_INIT; * r = glms_mat4_mul(m, m); * @endcode * * @param[in] m1 left matrix * @param[in] m2 right matrix * @returns destination matrix */ CGLM_INLINE mat4s glms_mat4_(mul)(mat4s m1, mat4s m2) { mat4s r; glm_mat4_mul(m1.raw, m2.raw, r.raw); return r; } /*! * @brief mupliply N mat4 matrices and store result in dest * * this function lets you multiply multiple (more than two or more...) matrices *

multiplication will be done in loop, this may reduce instructions * size but if len is too small then compiler may unroll whole loop, * usage: * @code * mat4 m1, m2, m3, m4, res; * * res = glm_mat4_mulN((mat4 *[]){&m1, &m2, &m3, &m4}, 4); * @endcode * * @warning matrices parameter is pointer array not mat4 array! * * @param[in] matrices mat4 * array * @param[in] len matrices count * @returns result matrix */ CGLM_INLINE mat4s glms_mat4_(mulN)(mat4s * __restrict matrices[], uint32_t len) { CGLM_ALIGN_MAT mat4s r = GLMS_MAT4_IDENTITY_INIT; size_t i; for (i = 0; i < len; i++) { r = glms_mat4_(mul)(r, *matrices[i]); } return r; } /*! * @brief multiply mat4 with vec4 (column vector) and store in dest vector * * @param[in] m mat4 (left) * @param[in] v vec4 (right, column vector) * @returns vec4 (result, column vector) */ CGLM_INLINE vec4s glms_mat4_(mulv)(mat4s m, vec4s v) { vec4s r; glm_mat4_mulv(m.raw, v.raw, r.raw); return r; } /*! * @brief trace of matrix * * sum of the elements on the main diagonal from upper left to the lower right * * @param[in] m matrix */ CGLM_INLINE float glms_mat4_(trace)(mat4s m) { return glm_mat4_trace(m.raw); } /*! * @brief trace of matrix (rotation part) * * sum of the elements on the main diagonal from upper left to the lower right * * @param[in] m matrix */ CGLM_INLINE float glms_mat4_(trace3)(mat4s m) { return glm_mat4_trace3(m.raw); } /*! * @brief convert mat4's rotation part to quaternion * * @param[in] m affine matrix * @returns destination quaternion */ CGLM_INLINE versors glms_mat4_(quat)(mat4s m) { versors r; glm_mat4_quat(m.raw, r.raw); return r; } /*! * @brief multiply vector with mat4 * * @param[in] m mat4(affine transform) * @param[in] v vec3 * @param[in] last 4th item to make it vec4 * @returns result vector (vec3) */ CGLM_INLINE vec3s glms_mat4_(mulv3)(mat4s m, vec3s v, float last) { vec3s r; glm_mat4_mulv3(m.raw, v.raw, last, r.raw); return r; } /*! * @brief transpose mat4 and store result in same matrix * * @param[in] m source * @returns result */ CGLM_INLINE mat4s glms_mat4_(transpose)(mat4s m) { glm_mat4_transpose(m.raw); return m; } /*! * @brief scale (multiply with scalar) matrix without simd optimization * * multiply matrix with scalar * * @param[in] m matrix * @param[in] s scalar * @returns matrix */ CGLM_INLINE mat4s glms_mat4_(scale_p)(mat4s m, float s) { glm_mat4_scale_p(m.raw, s); return m; } /*! * @brief scale (multiply with scalar) matrix * * multiply matrix with scalar * * @param[in] m matrix * @param[in] s scalar * @returns matrix */ CGLM_INLINE mat4s glms_mat4_(scale)(mat4s m, float s) { glm_mat4_scale(m.raw, s); return m; } /*! * @brief mat4 determinant * * @param[in] mat matrix * * @return determinant */ CGLM_INLINE float glms_mat4_(det)(mat4s mat) { return glm_mat4_det(mat.raw); } /*! * @brief inverse mat4 and store in dest * * @param[in] mat matrix * @returns inverse matrix */ CGLM_INLINE mat4s glms_mat4_(inv)(mat4s mat) { mat4s r; glm_mat4_inv(mat.raw, r.raw); return r; } /*! * @brief inverse mat4 and store in dest * * this func uses reciprocal approximation without extra corrections * e.g Newton-Raphson. this should work faster than normal, * to get more precise use glm_mat4_inv version. * * NOTE: You will lose precision, glm_mat4_inv is more accurate * * @param[in] mat matrix * @returns inverse matrix */ CGLM_INLINE mat4s glms_mat4_(inv_fast)(mat4s mat) { mat4s r; glm_mat4_inv_fast(mat.raw, r.raw); return r; } /*! * @brief swap two matrix columns * * @param[in] mat matrix * @param[in] col1 col1 * @param[in] col2 col2 * @returns matrix */ CGLM_INLINE mat4s glms_mat4_(swap_col)(mat4s mat, int col1, int col2) { glm_mat4_swap_col(mat.raw, col1, col2); return mat; } /*! * @brief swap two matrix rows * * @param[in] mat matrix * @param[in] row1 row1 * @param[in] row2 row2 * @returns matrix */ CGLM_INLINE mat4s glms_mat4_(swap_row)(mat4s mat, int row1, int row2) { glm_mat4_swap_row(mat.raw, row1, row2); return mat; } /*! * @brief helper for R (row vector) * M (matrix) * C (column vector) * * rmc stands for Row * Matrix * Column * * the result is scalar because R * M = Matrix1x4 (row vector), * then Matrix1x4 * Vec4 (column vector) = Matrix1x1 (Scalar) * * @param[in] r row vector or matrix1x4 * @param[in] m matrix4x4 * @param[in] c column vector or matrix4x1 * * @return scalar value e.g. B(s) */ CGLM_INLINE float glms_mat4_(rmc)(vec4s r, mat4s m, vec4s c) { return glm_mat4_rmc(r.raw, m.raw, c.raw); } /*! * @brief Create mat4 matrix from pointer * * @param[in] src pointer to an array of floats * @return constructed matrix from raw pointer */ CGLM_INLINE mat4s glms_mat4_(make)(const float * __restrict src) { mat4s r; glm_mat4_make(src, r.raw); return r; } /*! * @brief Create mat4 matrix from texture transform parameters * * @param[in] sx scale x * @param[in] sy scale y * @param[in] rot rotation in radians CCW/RH * @param[in] tx translate x * @param[in] ty translate y * @return texture transform matrix */ CGLM_INLINE mat4s glms_mat4_(textrans)(float sx, float sy, float rot, float tx, float ty) { mat4s r; glm_mat4_textrans(sx, sy, rot, tx, ty, r.raw); return r; } #endif /* cglms_mat4s_h */ cglm-0.9.7/include/cglm/struct/mat4x2.h000066400000000000000000000053651526744317200176560ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLMS_MAT4X2_ZERO_INIT GLMS_MAT4X2_ZERO Functions: CGLM_INLINE mat4x2s glms_mat4x2_zero(void); CGLM_INLINE mat4x2s glms_mat4x2_make(const float * __restrict src); CGLM_INLINE mat2s glms_mat4x2_mul(mat4x2s m1, mat2x4s m2); CGLM_INLINE vec2s glms_mat4x2_mulv(mat4x2s m, vec4s v); CGLM_INLINE mat2x4s glms_mat4x2_transpose(mat4x2s m); CGLM_INLINE mat4x2s glms_mat4x2_scale(mat4x2s m, float s); */ #ifndef cglms_mat4x2_h #define cglms_mat4x2_h #include "../common.h" #include "../types-struct.h" #include "../mat4x2.h" /* api definition */ #define glms_mat4x2_(NAME) CGLM_STRUCTAPI(mat4x2, NAME) #define GLMS_MAT4X2_ZERO_INIT {GLM_MAT4X2_ZERO_INIT} /* for C only */ #define GLMS_MAT4X2_ZERO ((mat4x2s)GLMS_MAT4X2_ZERO_INIT) /*! * @brief Zero out the mat4x2s (dest). * * @return[out] dest constructed mat4x2s from raw pointer */ CGLM_INLINE mat4x2s glms_mat4x2_(zero)(void) { mat4x2s dest; glm_mat4x2_zero(dest.raw); return dest; } /*! * @brief Create mat4x2s (dest) from pointer (src). * * @param[in] src pointer to an array of floats * @return[out] dest constructed mat4x2s from raw pointer */ CGLM_INLINE mat4x2s glms_mat4x2_(make)(const float * __restrict src) { mat4x2s dest; glm_mat4x2_make(src, dest.raw); return dest; } /*! * @brief Multiply mat4x2s (m1) by mat2x4s (m2) and store in mat2s (dest). * * @code * r = glms_mat4x2_mul(mat4x2s, mat2x4s); * @endcode * * @param[in] m1 mat4x2s (left) * @param[in] m2 mat2x4s (right) * @return[out] dest constructed mat2s from raw pointers */ CGLM_INLINE mat2s glms_mat4x2_(mul)(mat4x2s m1, mat2x4s m2) { mat2s dest; glm_mat4x2_mul(m1.raw, m2.raw, dest.raw); return dest; } /*! * @brief Multiply mat4x2s (m) by vec4s (v) and store in vec2s (dest). * * @param[in] m mat4x2s (left) * @param[in] v vec4s (right, column vector) * @return[out] dest constructed vec2s from raw pointers */ CGLM_INLINE vec2s glms_mat4x2_(mulv)(mat4x2s m, vec4s v) { vec2s dest; glm_mat4x2_mulv(m.raw, v.raw, dest.raw); return dest; } /*! * @brief Transpose mat4x2s (m) and store in mat2x4s (dest). * * @param[in] m mat4x2s (left) * @return[out] dest constructed mat2x4s from raw pointers */ CGLM_INLINE mat2x4s glms_mat4x2_(transpose)(mat4x2s m) { mat2x4s dest; glm_mat4x2_transpose(m.raw, dest.raw); return dest; } /*! * @brief Multiply mat4x2s (m) by scalar constant (s). * * @param[in, out] m mat4x2s (src, dest) * @param[in] s float (scalar) */ CGLM_INLINE mat4x2s glms_mat4x2_(scale)(mat4x2s m, float s) { glm_mat4x2_scale(m.raw, s); return m; } #endif /* cglms_mat4x2_h */ cglm-0.9.7/include/cglm/struct/mat4x3.h000066400000000000000000000053641526744317200176560ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLMS_MAT4X3_ZERO_INIT GLMS_MAT4X3_ZERO Functions: CGLM_INLINE mat4x3s glms_mat4x3_zero(void); CGLM_INLINE mat4x3s glms_mat4x3_make(const float * __restrict src); CGLM_INLINE mat3s glms_mat4x3_mul(mat4x3s m1, mat3x4s m2); CGLM_INLINE vec3s glms_mat4x3_mulv(mat4x3s m, vec4s v); CGLM_INLINE mat3x4s glms_mat4x3_transpose(mat4x3s m); CGLM_INLINE mat4x3s glms_mat4x3_scale(mat4x3s m, float s); */ #ifndef cglms_mat4x3_h #define cglms_mat4x3_h #include "../common.h" #include "../types-struct.h" #include "../mat4x3.h" /* api definition */ #define glms_mat4x3_(NAME) CGLM_STRUCTAPI(mat4x3, NAME) #define GLMS_MAT4X3_ZERO_INIT {GLM_MAT4X3_ZERO_INIT} /* for C only */ #define GLMS_MAT4X3_ZERO ((mat4x3s)GLMS_MAT4X3_ZERO_INIT) /*! * @brief Zero out the mat4x3s (dest). * * @return[out] dest constructed mat4x3s from raw pointer */ CGLM_INLINE mat4x3s glms_mat4x3_(zero)(void) { mat4x3s dest; glm_mat4x3_zero(dest.raw); return dest; } /*! * @brief Create mat4x3s (dest) from pointer (src). * * @param[in] src pointer to an array of floats * @return[out] dest constructed mat4x3s from raw pointer */ CGLM_INLINE mat4x3s glms_mat4x3_(make)(const float * __restrict src) { mat4x3s dest; glm_mat4x3_make(src, dest.raw); return dest; } /*! * @brief Multiply mat4x3s (m1) by mat3x4s (m2) and store in mat3s (dest). * * @code * r = glms_mat4x3_mul(mat4x3s, mat3x4s); * @endcode * * @param[in] m1 mat4x3s (left) * @param[in] m2 mat3x4s (right) * @return[out] dest constructed mat3s from raw pointers */ CGLM_INLINE mat3s glms_mat4x3_(mul)(mat4x3s m1, mat3x4s m2) { mat3s dest; glm_mat4x3_mul(m1.raw, m2.raw, dest.raw); return dest; } /*! * @brief Multiply mat4x3s (m) by vec4s (v) and store in vec3s (dest). * * @param[in] m mat4x3s (left) * @param[in] v vec4s (right, column vector) * @return[out] dest constructed vec3s from raw pointers */ CGLM_INLINE vec3s glms_mat4x3_(mulv)(mat4x3s m, vec4s v) { vec3s dest; glm_mat4x3_mulv(m.raw, v.raw, dest.raw); return dest; } /*! * @brief Transpose mat4x3s (m) and store in mat3x4s (dest). * * @param[in] m mat4x3s (left) * @return[out] dest constructed mat3x4s from raw pointers */ CGLM_INLINE mat3x4s glms_mat4x3_(transpose)(mat4x3s m) { mat3x4s dest; glm_mat4x3_transpose(m.raw, dest.raw); return dest; } /*! * @brief Multiply mat4x3s (m) by scalar constant (s). * * @param[in, out] m mat4x3s (src, dest) * @param[in] s float (scalar) */ CGLM_INLINE mat4x3s glms_mat4x3_(scale)(mat4x3s m, float s) { glm_mat4x3_scale(m.raw, s); return m; } #endif /* cglms_mat4x3_h */ cglm-0.9.7/include/cglm/struct/noise.h000066400000000000000000000017561526744317200176540ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglms_noises_h #define cglms_noises_h #include "../common.h" #include "../types-struct.h" #include "../noise.h" #include "vec4.h" /* Functions: CGLM_INLINE float glms_perlin_vec4(vec4s point); */ /*! * @brief Classic perlin noise * * @param[in] point 4D vector * @returns perlin noise value */ CGLM_INLINE float glms_perlin_vec4(vec4s point) { return glm_perlin_vec4(point.raw); } /*! * @brief Classic perlin noise * * @param[in] point 3D vector * @returns perlin noise value */ CGLM_INLINE float glms_perlin_vec3(vec3s point) { return glm_perlin_vec3(point.raw); } /*! * @brief Classic perlin noise * * @param[in] point 2D vector * @returns perlin noise value */ CGLM_INLINE float glms_perlin_vec2(vec2s point) { return glm_perlin_vec2(point.raw); } #endif /* cglms_noises_h */ cglm-0.9.7/include/cglm/struct/plane.h000066400000000000000000000013441526744317200176270ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglms_planes_h #define cglms_planes_h #include "../common.h" #include "../types-struct.h" #include "../plane.h" #include "vec4.h" /* Plane equation: Ax + By + Cz + D = 0; It stored in vec4 as [A, B, C, D]. (A, B, C) is normal and D is distance */ /* Functions: CGLM_INLINE vec4s glms_plane_normalize(vec4s plane); */ /*! * @brief normalizes a plane * * @param[in] plane plane to normalize * @returns normalized plane */ CGLM_INLINE vec4s glms_plane_normalize(vec4s plane) { glm_plane_normalize(plane.raw); return plane; } #endif /* cglms_planes_h */ cglm-0.9.7/include/cglm/struct/project.h000066400000000000000000000104211526744317200201720ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglms_projects_h #define cglms_projects_h #include "../common.h" #include "../types-struct.h" #include "../project.h" #include "vec3.h" #include "vec4.h" #include "mat4.h" #ifndef CGLM_CLIPSPACE_INCLUDE_ALL # if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_ZO_BIT # include "clipspace/project_zo.h" # elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_NO_BIT # include "clipspace/project_no.h" # endif #else # include "clipspace/project_zo.h" # include "clipspace/project_no.h" #endif /*! * @brief maps the specified viewport coordinates into specified space [1] * the matrix should contain projection matrix. * * if you don't have ( and don't want to have ) an inverse matrix then use * glm_unproject version. You may use existing inverse of matrix in somewhere * else, this is why glm_unprojecti exists to save save inversion cost * * [1] space: * 1- if m = invProj: View Space * 2- if m = invViewProj: World Space * 3- if m = invMVP: Object Space * * You probably want to map the coordinates into object space * so use invMVP as m * * Computing viewProj: * glm_mat4_mul(proj, view, viewProj); * glm_mat4_mul(viewProj, model, MVP); * glm_mat4_inv(viewProj, invMVP); * * @param[in] pos point/position in viewport coordinates * @param[in] invMat matrix (see brief) * @param[in] vp viewport as [x, y, width, height] * @returns unprojected coordinates */ CGLM_INLINE vec3s glms_unprojecti(vec3s pos, mat4s invMat, vec4s vp) { vec3s r; glm_unprojecti(pos.raw, invMat.raw, vp.raw, r.raw); return r; } /*! * @brief maps the specified viewport coordinates into specified space [1] * the matrix should contain projection matrix. * * this is same as glm_unprojecti except this function get inverse matrix for * you. * * [1] space: * 1- if m = proj: View Space * 2- if m = viewProj: World Space * 3- if m = MVP: Object Space * * You probably want to map the coordinates into object space * so use MVP as m * * Computing viewProj and MVP: * glm_mat4_mul(proj, view, viewProj); * glm_mat4_mul(viewProj, model, MVP); * * or in struct api: * MVP = mat4_mul(mat4_mul(proj, view), model) * * @param[in] pos point/position in viewport coordinates * @param[in] m matrix (see brief) * @param[in] vp viewport as [x, y, width, height] * @returns unprojected coordinates */ CGLM_INLINE vec3s glms_unproject(vec3s pos, mat4s m, vec4s vp) { vec3s r; glm_unproject(pos.raw, m.raw, vp.raw, r.raw); return r; } /*! * @brief map object coordinates to window coordinates * * Computing MVP: * glm_mat4_mul(proj, view, viewProj); * glm_mat4_mul(viewProj, model, MVP); * * or in struct api: * MVP = mat4_mul(mat4_mul(proj, view), model) * * @param[in] pos object coordinates * @param[in] m MVP matrix * @param[in] vp viewport as [x, y, width, height] * @returns projected coordinates */ CGLM_INLINE vec3s glms_project(vec3s pos, mat4s m, vec4s vp) { vec3s r; glm_project(pos.raw, m.raw, vp.raw, r.raw); return r; } /*! * @brief map object's z coordinate to window coordinates * * Computing MVP: * glm_mat4_mul(proj, view, viewProj); * glm_mat4_mul(viewProj, model, MVP); * * or in struct api: * MVP = mat4_mul(mat4_mul(proj, view), model) * * @param[in] v object coordinates * @param[in] m MVP matrix * * @returns projected z coordinate */ CGLM_INLINE float glms_project_z(vec3s v, mat4s m) { #if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_ZO_BIT return glms_project_z_zo(v, m); #elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_NO_BIT return glms_project_z_no(v, m); #endif } /*! * @brief define a picking region * * @param[in] center center [x, y] of a picking region in window coordinates * @param[in] size size [width, height] of the picking region in window coordinates * @param[in] vp viewport as [x, y, width, height] * @returns projected coordinates */ CGLM_INLINE mat4s glms_pickmatrix(vec2s center, vec2s size, vec4s vp) { mat4s res; glm_pickmatrix(center.raw, size.raw, vp.raw, res.raw); return res; } #endif /* cglms_projects_h */ cglm-0.9.7/include/cglm/struct/quat.h000066400000000000000000000330071526744317200175030ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLMS_QUAT_IDENTITY_INIT GLMS_QUAT_IDENTITY Functions: CGLM_INLINE versors glms_quat_identity(void) CGLM_INLINE void glms_quat_identity_array(versor *q, size_t count) CGLM_INLINE versors glms_quat_init(float x, float y, float z, float w) CGLM_INLINE versors glms_quatv(float angle, vec3s axis) CGLM_INLINE versors glms_quat(float angle, float x, float y, float z) CGLM_INLINE versors glms_quat_from_vecs(vec3s a, vec3s b) CGLM_INLINE float glms_quat_norm(versors q) CGLM_INLINE versors glms_quat_normalize(versors q) CGLM_INLINE float glms_quat_dot(versors p, versors q) CGLM_INLINE versors glms_quat_conjugate(versors q) CGLM_INLINE versors glms_quat_inv(versors q) CGLM_INLINE versors glms_quat_add(versors p, versors q) CGLM_INLINE versors glms_quat_sub(versors p, versors q) CGLM_INLINE vec3s glms_quat_imagn(versors q) CGLM_INLINE float glms_quat_imaglen(versors q) CGLM_INLINE float glms_quat_angle(versors q) CGLM_INLINE vec3s glms_quat_axis(versors q) CGLM_INLINE versors glms_quat_mul(versors p, versors q) CGLM_INLINE mat4s glms_quat_mat4(versors q) CGLM_INLINE mat4s glms_quat_mat4t(versors q) CGLM_INLINE mat3s glms_quat_mat3(versors q) CGLM_INLINE mat3s glms_quat_mat3t(versors q) CGLM_INLINE versors glms_quat_lerp(versors from, versors to, float t) CGLM_INLINE versors glms_quat_lerpc(versors from, versors to, float t) CGLM_INLINE versors glms_quat_nlerp(versors from, versors to, float t) CGLM_INLINE versors glms_quat_slerp(versors from, versors to, float t) CGLM_INLINE versors glms_quat_slerp_longest(versors from, versors to, float t) CGLM_INLINE mat4s. glms_quat_look(vec3s eye, versors ori) CGLM_INLINE versors glms_quat_for(vec3s dir, vec3s fwd, vec3s up) CGLM_INLINE versors glms_quat_forp(vec3s from, vec3s to, vec3s fwd, vec3s up) CGLM_INLINE vec3s glms_quat_rotatev(versors q, vec3s v) CGLM_INLINE mat4s glms_quat_rotate(mat4s m, versors q) CGLM_INLINE mat4s glms_quat_rotate_at(mat4s m, versors q, vec3s pivot) CGLM_INLINE mat4s glms_quat_rotate_atm(versors q, vec3s pivot) CGLM_INLINE versors glms_quat_make(float * restrict src) */ #ifndef cglms_quat_h #define cglms_quat_h #include "../common.h" #include "../types-struct.h" #include "../plane.h" #include "../quat.h" /* api definition */ #define glms_quat_(NAME) CGLM_STRUCTAPI(quat, NAME) /* * IMPORTANT: * ---------------------------------------------------------------------------- * cglm stores quat as [x, y, z, w] since v0.3.6 * * it was [w, x, y, z] before v0.3.6 it has been changed to [x, y, z, w] * with v0.3.6 version. * ---------------------------------------------------------------------------- */ #define GLMS_QUAT_IDENTITY_INIT {GLM_QUAT_IDENTITY_INIT} #define GLMS_QUAT_IDENTITY ((versors)GLMS_QUAT_IDENTITY_INIT) /*! * @brief makes given quat to identity * * @returns identity quaternion */ CGLM_INLINE versors glms_quat_(identity)(void) { versors dest; glm_quat_identity(dest.raw); return dest; } /*! * @brief make given quaternion array's each element identity quaternion * * @param[in, out] q quat array (must be aligned (16) * if alignment is not disabled) * * @param[in] count count of quaternions */ CGLM_INLINE void glms_quat_(identity_array)(versors * __restrict q, size_t count) { CGLM_ALIGN(16) versor v = GLM_QUAT_IDENTITY_INIT; size_t i; for (i = 0; i < count; i++) { glm_vec4_copy(v, q[i].raw); } } /*! * @brief inits quaternion with raw values * * @param[in] x x * @param[in] y y * @param[in] z z * @param[in] w w (real part) * @returns quaternion */ CGLM_INLINE versors glms_quat_(init)(float x, float y, float z, float w) { versors dest; glm_quat_init(dest.raw, x, y, z, w); return dest; } /*! * @brief creates NEW quaternion with axis vector * * @param[in] angle angle (radians) * @param[in] axis axis * @returns quaternion */ CGLM_INLINE versors glms_quatv(float angle, vec3s axis) { versors dest; glm_quatv(dest.raw, angle, axis.raw); return dest; } /*! * @brief creates NEW quaternion with individual axis components * * @param[in] angle angle (radians) * @param[in] x axis.x * @param[in] y axis.y * @param[in] z axis.z * @returns quaternion */ CGLM_INLINE versors glms_quat(float angle, float x, float y, float z) { versors dest; glm_quat(dest.raw, angle, x, y, z); return dest; } /*! * @brief compute quaternion rotating vector A to vector B * * @param[in] a vec3 (must have unit length) * @param[in] b vec3 (must have unit length) * @returns quaternion (of unit length) */ CGLM_INLINE versors glms_quat_(from_vecs)(vec3s a, vec3s b) { versors dest; glm_quat_from_vecs(a.raw, b.raw, dest.raw); return dest; } /*! * @brief returns norm (magnitude) of quaternion * * @param[in] q quaternion */ CGLM_INLINE float glms_quat_(norm)(versors q) { return glm_quat_norm(q.raw); } /*! * @brief normalize quaternion * * @param[in] q quaternion * @returns quaternion */ CGLM_INLINE versors glms_quat_(normalize)(versors q) { versors dest; glm_quat_normalize_to(q.raw, dest.raw); return dest; } /*! * @brief dot product of two quaternion * * @param[in] p quaternion 1 * @param[in] q quaternion 2 * @returns dot product */ CGLM_INLINE float glms_quat_(dot)(versors p, versors q) { return glm_quat_dot(p.raw, q.raw); } /*! * @brief conjugate of quaternion * * @param[in] q quaternion * @returns conjugate */ CGLM_INLINE versors glms_quat_(conjugate)(versors q) { versors dest; glm_quat_conjugate(q.raw, dest.raw); return dest; } /*! * @brief inverse of non-zero quaternion * * @param[in] q quaternion * @returns inverse quaternion */ CGLM_INLINE versors glms_quat_(inv)(versors q) { versors dest; glm_quat_inv(q.raw, dest.raw); return dest; } /*! * @brief add (componentwise) two quaternions and store result in dest * * @param[in] p quaternion 1 * @param[in] q quaternion 2 * @returns result quaternion */ CGLM_INLINE versors glms_quat_(add)(versors p, versors q) { versors dest; glm_quat_add(p.raw, q.raw, dest.raw); return dest; } /*! * @brief subtract (componentwise) two quaternions and store result in dest * * @param[in] p quaternion 1 * @param[in] q quaternion 2 * @returns result quaternion */ CGLM_INLINE versors glms_quat_(sub)(versors p, versors q) { versors dest; glm_quat_sub(p.raw, q.raw, dest.raw); return dest; } /*! * @brief returns normalized imaginary part of quaternion * * @param[in] q quaternion */ CGLM_INLINE vec3s glms_quat_(imagn)(versors q) { vec3s dest; glm_normalize_to(q.raw, dest.raw); return dest; } /*! * @brief returns length of imaginary part of quaternion * * @param[in] q quaternion */ CGLM_INLINE float glms_quat_(imaglen)(versors q) { return glm_quat_imaglen(q.raw); } /*! * @brief returns angle of quaternion * * @param[in] q quaternion */ CGLM_INLINE float glms_quat_(angle)(versors q) { return glm_quat_angle(q.raw); } /*! * @brief axis of quaternion * * @param[in] q quaternion * @returns axis of quaternion */ CGLM_INLINE vec3s glms_quat_(axis)(versors q) { vec3s dest; glm_quat_axis(q.raw, dest.raw); return dest; } /*! * @brief multiplies two quaternion and stores result in dest * this is also called Hamilton Product * * According to WikiPedia: * The product of two rotation quaternions [clarification needed] will be * equivalent to the rotation q followed by the rotation p * * @param[in] p quaternion 1 * @param[in] q quaternion 2 * @returns result quaternion */ CGLM_INLINE versors glms_quat_(mul)(versors p, versors q) { versors dest; glm_quat_mul(p.raw, q.raw, dest.raw); return dest; } /*! * @brief convert quaternion to mat4 * * @param[in] q quaternion * @returns result matrix */ CGLM_INLINE mat4s glms_quat_(mat4)(versors q) { mat4s dest; glm_quat_mat4(q.raw, dest.raw); return dest; } /*! * @brief convert quaternion to mat4 (transposed) * * @param[in] q quaternion * @returns result matrix as transposed */ CGLM_INLINE mat4s glms_quat_(mat4t)(versors q) { mat4s dest; glm_quat_mat4t(q.raw, dest.raw); return dest; } /*! * @brief convert quaternion to mat3 * * @param[in] q quaternion * @returns result matrix */ CGLM_INLINE mat3s glms_quat_(mat3)(versors q) { mat3s dest; glm_quat_mat3(q.raw, dest.raw); return dest; } /*! * @brief convert quaternion to mat3 (transposed) * * @param[in] q quaternion * @returns result matrix */ CGLM_INLINE mat3s glms_quat_(mat3t)(versors q) { mat3s dest; glm_quat_mat3t(q.raw, dest.raw); return dest; } /*! * @brief interpolates between two quaternions * using linear interpolation (LERP) * * @param[in] from from * @param[in] to to * @param[in] t interpolant (amount) * @returns result quaternion */ CGLM_INLINE versors glms_quat_(lerp)(versors from, versors to, float t) { versors dest; glm_quat_lerp(from.raw, to.raw, t, dest.raw); return dest; } /*! * @brief interpolates between two quaternions * using linear interpolation (LERP) * * @param[in] from from * @param[in] to to * @param[in] t interpolant (amount) clamped between 0 and 1 * @returns result quaternion */ CGLM_INLINE versors glms_quat_(lerpc)(versors from, versors to, float t) { versors dest; glm_quat_lerpc(from.raw, to.raw, t, dest.raw); return dest; } /*! * @brief interpolates between two quaternions * taking the shortest rotation path using * normalized linear interpolation (NLERP) * * @param[in] from from * @param[in] to to * @param[in] t interpolant (amount) * @returns result quaternion */ CGLM_INLINE versors glms_quat_(nlerp)(versors from, versors to, float t) { versors dest; glm_quat_nlerp(from.raw, to.raw, t, dest.raw); return dest; } /*! * @brief interpolates between two quaternions * using spherical linear interpolation (SLERP) * * @param[in] from from * @param[in] to to * @param[in] t amount * @returns result quaternion */ CGLM_INLINE versors glms_quat_(slerp)(versors from, versors to, float t) { versors dest; glm_quat_slerp(from.raw, to.raw, t, dest.raw); return dest; } /*! * @brief interpolates between two quaternions * using spherical linear interpolation (SLERP) and always takes the longest path * * @param[in] from from * @param[in] to to * @param[in] t amount * @returns result quaternion */ CGLM_INLINE versors glms_quat_(slerp_longest)(versors from, versors to, float t) { versors dest; glm_quat_slerp_longest(from.raw, to.raw, t, dest.raw); return dest; } /*! * @brief creates view matrix using quaternion as camera orientation * * @param[in] eye eye * @param[in] ori orientation in world space as quaternion * @returns view matrix */ CGLM_INLINE mat4s glms_quat_(look)(vec3s eye, versors ori) { mat4s dest; glm_quat_look(eye.raw, ori.raw, dest.raw); return dest; } /*! * @brief creates look rotation quaternion * * @param[in] dir direction to look * @param[in] up up vector * @returns destination quaternion */ CGLM_INLINE versors glms_quat_(for)(vec3s dir, vec3s up) { versors dest; glm_quat_for(dir.raw, up.raw, dest.raw); return dest; } /*! * @brief creates look rotation quaternion using source and * destination positions p suffix stands for position * * @param[in] from source point * @param[in] to destination point * @param[in] up up vector * @returns destination quaternion */ CGLM_INLINE versors glms_quat_(forp)(vec3s from, vec3s to, vec3s up) { versors dest; glm_quat_forp(from.raw, to.raw, up.raw, dest.raw); return dest; } /*! * @brief rotate vector using using quaternion * * @param[in] q quaternion * @param[in] v vector to rotate * @returns rotated vector */ CGLM_INLINE vec3s glms_quat_(rotatev)(versors q, vec3s v) { vec3s dest; glm_quat_rotatev(q.raw, v.raw, dest.raw); return dest; } /*! * @brief rotate existing transform matrix using quaternion * * @param[in] m existing transform matrix * @param[in] q quaternion * @returns rotated matrix/transform */ CGLM_INLINE mat4s glms_quat_(rotate)(mat4s m, versors q) { glm_quat_rotate(m.raw, q.raw, m.raw); return m; } /*! * @brief rotate existing transform matrix using quaternion at pivot point * * @param[in, out] m existing transform matrix * @param[in] q quaternion * @returns pivot */ CGLM_INLINE mat4s glms_quat_(rotate_at)(mat4s m, versors q, vec3s pivot) { glm_quat_rotate_at(m.raw, q.raw, pivot.raw); return m; } /*! * @brief rotate NEW transform matrix using quaternion at pivot point * * this creates rotation matrix, it assumes you don't have a matrix * * this should work faster than glm_quat_rotate_at because it reduces * one glm_translate. * * @param[in] q quaternion * @returns pivot */ CGLM_INLINE mat4s glms_quat_(rotate_atm)(versors q, vec3s pivot) { mat4s dest; glm_quat_rotate_atm(dest.raw, q.raw, pivot.raw); return dest; } /*! * @brief Create CGLM quaternion from pointer * * @param[in] src pointer to an array of floats * @returns constructed quaternion from raw pointer */ CGLM_INLINE versors glms_quat_(make)(const float * __restrict src) { versors dest; glm_quat_make(src, dest.raw); return dest; } #endif /* cglms_quat_h */ cglm-0.9.7/include/cglm/struct/ray.h000066400000000000000000000047141526744317200173270ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglms_ray_h #define cglms_ray_h #include "../common.h" #include "../types-struct.h" #include "../ray.h" /* api definition */ #define glms_ray_(NAME) CGLM_STRUCTAPI(ray, NAME) /*! * @brief Möller–Trumbore ray-triangle intersection algorithm * * @param[in] origin origin of ray * @param[in] direction direction of ray * @param[in] v0 first vertex of triangle * @param[in] v1 second vertex of triangle * @param[in] v2 third vertex of triangle * @param[in, out] d distance to intersection * @return whether there is intersection */ CGLM_INLINE bool glms_ray_(triangle)(vec3s origin, vec3s direction, vec3s v0, vec3s v1, vec3s v2, float *d) { return glm_ray_triangle(origin.raw, direction.raw, v0.raw, v1.raw, v2.raw, d); } /*! * @brief ray sphere intersection * * returns false if there is no intersection if true: * * - t1 > 0, t2 > 0: ray intersects the sphere at t1 and t2 both ahead of the origin * - t1 < 0, t2 > 0: ray starts inside the sphere, exits at t2 * - t1 < 0, t2 < 0: no intersection ahead of the ray ( returns false ) * - the caller can check if the intersection points (t1 and t2) fall within a * specific range (for example, tmin < t1, t2 < tmax) to determine if the * intersections are within a desired segment of the ray * * @param[in] origin ray origin * @param[out] dir normalized ray direction * @param[in] s sphere [center.x, center.y, center.z, radii] * @param[in] t1 near point1 (closer to origin) * @param[in] t2 far point2 (farther from origin) * * @returns whether there is intersection */ CGLM_INLINE bool glms_ray_(sphere)(vec3s origin, vec3s dir, vec4s s, float * __restrict t1, float * __restrict t2) { return glm_ray_sphere(origin.raw, dir.raw, s.raw, t1, t2); } /*! * @brief point using t by �(�)=�+�� * * @param[in] orig origin of ray * @param[in] dir direction of ray * @param[in] t parameter * @returns point point at t */ CGLM_INLINE vec3s glms_ray_(at)(vec3s orig, vec3s dir, float t) { vec3s r; glm_ray_at(orig.raw, dir.raw, t, r.raw); return r; } #endif /* cglms_ray_h */ cglm-0.9.7/include/cglm/struct/sphere.h000066400000000000000000000035311526744317200200160ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglms_spheres_h #define cglms_spheres_h #include "../common.h" #include "../types-struct.h" #include "../sphere.h" #include "mat4.h" /* Sphere Representation in cglm: [center.x, center.y, center.z, radii] You could use this representation or you can convert it to vec4 before call any function */ /*! * @brief helper for getting sphere radius * * @param[in] s sphere * * @return returns radii */ CGLM_INLINE float glms_sphere_radii(vec4s s) { return glm_sphere_radii(s.raw); } /*! * @brief apply transform to sphere, it is just wrapper for glm_mat4_mulv3 * * @param[in] s sphere * @param[in] m transform matrix * @returns transformed sphere */ CGLM_INLINE vec4s glms_sphere_transform(vec4s s, mat4s m) { vec4s r; glm_sphere_transform(s.raw, m.raw, r.raw); return r; } /*! * @brief merges two spheres and creates a new one * * two sphere must be in same space, for instance if one in world space then * the other must be in world space too, not in local space. * * @param[in] s1 sphere 1 * @param[in] s2 sphere 2 * returns merged/extended sphere */ CGLM_INLINE vec4s glms_sphere_merge(vec4s s1, vec4s s2) { vec4s r; glm_sphere_merge(s1.raw, s2.raw, r.raw); return r; } /*! * @brief check if two sphere intersects * * @param[in] s1 sphere * @param[in] s2 other sphere */ CGLM_INLINE bool glms_sphere_sphere(vec4s s1, vec4s s2) { return glm_sphere_sphere(s1.raw, s2.raw); } /*! * @brief check if sphere intersects with point * * @param[in] s sphere * @param[in] point point */ CGLM_INLINE bool glms_sphere_point(vec4s s, vec3s point) { return glm_sphere_point(s.raw, point.raw); } #endif /* cglms_spheres_h */ cglm-0.9.7/include/cglm/struct/vec2-ext.h000066400000000000000000000151401526744317200201640ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /*! * @brief SIMD like functions */ /* Functions: CGLM_INLINE vec2s glms_vec2_fill(float val) CGLM_INLINE bool glms_vec2_eq(vec2s v, float val) CGLM_INLINE bool glms_vec2_eq_eps(vec2s v, float val) CGLM_INLINE bool glms_vec2_eq_all(vec2s v) CGLM_INLINE bool glms_vec2_eqv(vec2s a, vec2s b) CGLM_INLINE bool glms_vec2_eqv_eps(vec2s a, vec2s b) CGLM_INLINE float glms_vec2_max(vec2s v) CGLM_INLINE float glms_vec2_min(vec2s v) CGLM_INLINE bool glms_vec2_isnan(vec2s v) CGLM_INLINE bool glms_vec2_isinf(vec2s v) CGLM_INLINE bool glms_vec2_isvalid(vec2s v) CGLM_INLINE vec2s glms_vec2_sign(vec2s v) CGLM_INLINE vec2s glms_vec2_abs(vec2s v) CGLM_INLINE vec2s glms_vec2_fract(vec2s v) CGLM_INLINE vec2s glms_vec2_floor(vec2s v) CGLM_INLINE vec2s glms_vec2_mods(vec2s v, float s) CGLM_INLINE vec2s glms_vec2_steps(float edge, vec2s v) CGLM_INLINE vec2s glms_vec2_stepr(vec2s edge, float v) CGLM_INLINE vec2s glms_vec2_sqrt(vec2s v) */ #ifndef cglms_vec2s_ext_h #define cglms_vec2s_ext_h #include "../common.h" #include "../types-struct.h" #include "../util.h" #include "../vec2-ext.h" /* api definition */ #define glms_vec2_(NAME) CGLM_STRUCTAPI(vec2, NAME) /*! * @brief fill a vector with specified value * * @param[in] val value * @returns dest */ CGLM_INLINE vec2s glms_vec2_(fill)(float val) { vec2s r; glm_vec2_fill(r.raw, val); return r; } /*! * @brief check if vector is equal to value (without epsilon) * * @param[in] v vector * @param[in] val value */ CGLM_INLINE bool glms_vec2_(eq)(vec2s v, float val) { return glm_vec2_eq(v.raw, val); } /*! * @brief check if vector is equal to value (with epsilon) * * @param[in] v vector * @param[in] val value */ CGLM_INLINE bool glms_vec2_(eq_eps)(vec2s v, float val) { return glm_vec2_eq_eps(v.raw, val); } /*! * @brief check if vector members are equal (without epsilon) * * @param[in] v vector */ CGLM_INLINE bool glms_vec2_(eq_all)(vec2s v) { return glm_vec2_eq_all(v.raw); } /*! * @brief check if vector is equal to another (without epsilon) * * @param[in] a vector * @param[in] b vector */ CGLM_INLINE bool glms_vec2_(eqv)(vec2s a, vec2s b) { return glm_vec2_eqv(a.raw, b.raw); } /*! * @brief check if vector is equal to another (with epsilon) * * @param[in] a vector * @param[in] b vector */ CGLM_INLINE bool glms_vec2_(eqv_eps)(vec2s a, vec2s b) { return glm_vec2_eqv_eps(a.raw, b.raw); } /*! * @brief max value of vector * * @param[in] v vector */ CGLM_INLINE float glms_vec2_(max)(vec2s v) { return glm_vec2_max(v.raw); } /*! * @brief min value of vector * * @param[in] v vector */ CGLM_INLINE float glms_vec2_min(vec2s v) { return glm_vec2_min(v.raw); } /*! * @brief check if one of items is NaN (not a number) * you should only use this in DEBUG mode or very critical asserts * * @param[in] v vector */ CGLM_INLINE bool glms_vec2_(isnan)(vec2s v) { return glm_vec2_isnan(v.raw); } /*! * @brief check if one of items is INFINITY * you should only use this in DEBUG mode or very critical asserts * * @param[in] v vector */ CGLM_INLINE bool glms_vec2_(isinf)(vec2s v) { return glm_vec2_isinf(v.raw); } /*! * @brief check if all items are valid number * you should only use this in DEBUG mode or very critical asserts * * @param[in] v vector */ CGLM_INLINE bool glms_vec2_isvalid(vec2s v) { return glm_vec2_isvalid(v.raw); } /*! * @brief get sign of 32 bit float as +1, -1, 0 * * Important: It returns 0 for zero/NaN input * * @param v vector * @returns sign vector */ CGLM_INLINE vec2s glms_vec2_(sign)(vec2s v) { vec2s r; glm_vec2_sign(v.raw, r.raw); return r; } /*! * @brief fractional part of each vector item * * @param v vector * @returns abs vector */ CGLM_INLINE vec2s glms_vec2_(abs)(vec2s v) { vec2s r; glm_vec2_abs(v.raw, r.raw); return r; } /*! * @brief fractional part of each vector item * * @param[in] v vector * @returns destination vector */ CGLM_INLINE vec2s glms_vec2_(fract)(vec2s v) { vec2s r; glm_vec2_fract(v.raw, r.raw); return r; } /*! * @brief floor of each vector item * * @param[in] v vector * @returns destination vector */ CGLM_INLINE vec2s glms_vec2_(floor)(vec2s v) { vec2s r; glm_vec2_floor(v.raw, r.raw); return r; } /*! * @brief mod of each vector item by scalar * * @param[in] v vector * @param[in] s scalar * @returns destination vector */ CGLM_INLINE vec2s glms_vec2_(mods)(vec2s v, float s) { vec2s r; glm_vec2_mods(v.raw, s, r.raw); return r; } /*! * @brief threshold each vector item with scalar * condition is: (x[i] < edge) ? 0.0 : 1.0 * * @param[in] edge threshold * @param[in] x vector to test against threshold * @returns destination */ CGLM_INLINE vec2s glms_vec2_(steps)(float edge, vec2s x) { vec2s r; glm_vec2_steps(edge, x.raw, r.raw); return r; } /*! * @brief threshold a value with *vector* as the threshold * condition is: (x < edge[i]) ? 0.0 : 1.0 * * @param[in] edge threshold vector * @param[in] x value to test against threshold * @returns destination */ CGLM_INLINE vec2s glms_vec2_(stepr)(vec2s edge, float x) { vec2s r; glm_vec2_stepr(edge.raw, x, r.raw); return r; } /*! * @brief square root of each vector item * * @param[in] v vector * @returns destination vector */ CGLM_INLINE vec2s glms_vec2_(sqrt)(vec2s v) { vec2s r; glm_vec2_sqrt(v.raw, r.raw); return r; } /*! * @brief treat vectors as complex numbers and multiply them as such. * * @param[in] a left number * @param[in] b right number * @param[out] dest destination number */ CGLM_INLINE vec2s glms_vec2_(complex_mul)(vec2s a, vec2s b, vec2s dest) { glm_vec2_complex_mul(a.raw, b.raw, dest.raw); return dest; } /*! * @brief treat vectors as complex numbers and divide them as such. * * @param[in] a left number (numerator) * @param[in] b right number (denominator) * @param[out] dest destination number */ CGLM_INLINE vec2s glms_vec2_(complex_div)(vec2s a, vec2s b, vec2s dest) { glm_vec2_complex_div(a.raw, b.raw, dest.raw); return dest; } /*! * @brief treat the vector as a complex number and conjugate it as such. * * @param[in] a the number * @param[out] dest destination number */ CGLM_INLINE vec2s glms_vec2_(complex_conjugate)(vec2s a, vec2s dest) { glm_vec2_complex_conjugate(a.raw, dest.raw); return dest; } #endif /* cglms_vec2s_ext_h */ cglm-0.9.7/include/cglm/struct/vec2.h000066400000000000000000000404231526744317200173700ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLMS_VEC2_ONE_INIT GLMS_VEC2_ZERO_INIT GLMS_VEC2_ONE GLMS_VEC2_ZERO Functions: CGLM_INLINE vec2s glms_vec2(vec3s v3) CGLM_INLINE void glms_vec2_pack(vec2s dst[], vec2 src[], size_t len) CGLM_INLINE void glms_vec2_unpack(vec2 dst[], vec2s src[], size_t len) CGLM_INLINE vec2s glms_vec2_zero(void) CGLM_INLINE vec2s glms_vec2_one(void) CGLM_INLINE float glms_vec2_dot(vec2s a, vec2s b) CGLM_INLINE float glms_vec2_cross(vec2s a, vec2s b) CGLM_INLINE float glms_vec2_norm2(vec2s v) CGLM_INLINE float glms_vec2_norm(vec2s v) CGLM_INLINE vec2s glms_vec2_add(vec2s a, vec2s b) CGLM_INLINE vec2s glms_vec2_adds(vec2s a, float s) CGLM_INLINE vec2s glms_vec2_sub(vec2s a, vec2s b) CGLM_INLINE vec2s glms_vec2_subs(vec2s a, float s) CGLM_INLINE vec2s glms_vec2_mul(vec2s a, vec2s b) CGLM_INLINE vec2s glms_vec2_scale(vec2s v, float s) CGLM_INLINE vec2s glms_vec2_scale_as(vec2s v, float s) CGLM_INLINE vec2s glms_vec2_div(vec2s a, vec2s b) CGLM_INLINE vec2s glms_vec2_divs(vec2s a, float s) CGLM_INLINE vec2s glms_vec2_addadd(vec2s a, vec2s b, vec2s dest) CGLM_INLINE vec2s glms_vec2_subadd(vec2s a, vec2s b, vec2s dest) CGLM_INLINE vec2s glms_vec2_muladd(vec2s a, vec2s b, vec2s dest) CGLM_INLINE vec2s glms_vec2_muladds(vec2s a, float s, vec2s dest) CGLM_INLINE vec2s glms_vec2_maxadd(vec2s a, vec2s b, vec2s dest) CGLM_INLINE vec2s glms_vec2_minadd(vec2s a, vec2s b, vec2s dest) CGLM_INLINE vec2s glms_vec2_subsub(vec2s a, vec2s b, vec2s dest) CGLM_INLINE vec2s glms_vec2_addsub(vec2s a, vec2s b, vec2s dest) CGLM_INLINE vec2s glms_vec2_mulsub(vec2s a, vec2s b, vec2s dest) CGLM_INLINE vec2s glms_vec2_mulsubs(vec2s a, float s, vec2s dest) CGLM_INLINE vec2s glms_vec2_maxsub(vec2s a, vec2s b, vec2s dest) CGLM_INLINE vec2s glms_vec2_minsub(vec2s a, vec2s b, vec2s dest) CGLM_INLINE vec2s glms_vec2_negate(vec2s v) CGLM_INLINE vec2s glms_vec2_normalize(vec2s v) CGLM_INLINE vec2s glms_vec2_rotate(vec2s v, float angle, vec2s axis) CGLM_INLINE vec2s glms_vec2_center(vec2s a, vec2s b) CGLM_INLINE float glms_vec2_distance(vec2s a, vec2s b) CGLM_INLINE float glms_vec2_distance2(vec2s a, vec2s b) CGLM_INLINE vec2s glms_vec2_maxv(vec2s a, vec2s b) CGLM_INLINE vec2s glms_vec2_minv(vec2s a, vec2s b) CGLM_INLINE vec2s glms_vec2_clamp(vec2s v, float minVal, float maxVal) CGLM_INLINE vec2s glms_vec2_lerp(vec2s from, vec2s to, float t) CGLM_INLINE vec2s glms_vec2_step(vec2s edge, vec2s x) CGLM_INLINE vec2s glms_vec2_make(float * restrict src) CGLM_INLINE vec2s glms_vec2_reflect(vec2s v, vec2s n) CGLM_INLINE bool glms_vec2_refract(vec2s v, vec2s n, float eta, vec2s *dest) */ #ifndef cglms_vec2s_h #define cglms_vec2s_h #include "../common.h" #include "../types-struct.h" #include "../util.h" #include "../vec2.h" #include "vec2-ext.h" #define GLMS_VEC2_ONE_INIT {GLM_VEC2_ONE_INIT} #define GLMS_VEC2_ZERO_INIT {GLM_VEC2_ZERO_INIT} #define GLMS_VEC2_ONE ((vec2s)GLMS_VEC2_ONE_INIT) #define GLMS_VEC2_ZERO ((vec2s)GLMS_VEC2_ZERO_INIT) /*! * @brief init vec2 using vec2 * * @param[in] v3 vector3 * @returns destination */ CGLM_INLINE vec2s glms_vec2(vec3s v3) { vec2s r; glm_vec2(v3.raw, r.raw); return r; } /*! * @brief pack an array of vec2 into an array of vec2s * * @param[out] dst array of vec2 * @param[in] src array of vec2s * @param[in] len number of elements */ CGLM_INLINE void glms_vec2_(pack)(vec2s dst[], vec2 src[], size_t len) { size_t i; for (i = 0; i < len; i++) { glm_vec2_copy(src[i], dst[i].raw); } } /*! * @brief unpack an array of vec2s into an array of vec2 * * @param[out] dst array of vec2s * @param[in] src array of vec2 * @param[in] len number of elements */ CGLM_INLINE void glms_vec2_(unpack)(vec2 dst[], vec2s src[], size_t len) { size_t i; for (i = 0; i < len; i++) { glm_vec2_copy(src[i].raw, dst[i]); } } /*! * @brief make vector zero * * @returns zero vector */ CGLM_INLINE vec2s glms_vec2_(zero)(void) { vec2s r; glm_vec2_zero(r.raw); return r; } /*! * @brief make vector one * * @returns one vector */ CGLM_INLINE vec2s glms_vec2_(one)(void) { vec2s r; glm_vec2_one(r.raw); return r; } /*! * @brief vec2 dot product * * @param[in] a vector1 * @param[in] b vector2 * * @return dot product */ CGLM_INLINE float glms_vec2_(dot)(vec2s a, vec2s b) { return glm_vec2_dot(a.raw, b.raw); } /*! * @brief vec2 cross product * * REF: http://allenchou.net/2013/07/cross-product-of-2d-vectors/ * * @param[in] a vector1 * @param[in] b vector2 * * @return Z component of cross product */ CGLM_INLINE float glms_vec2_(cross)(vec2s a, vec2s b) { return glm_vec2_cross(a.raw, b.raw); } /*! * @brief norm * norm (magnitude) of vec * * we can use this func instead of calling norm * norm, because it would call * sqrtf function twice but with this func we can avoid func call, maybe this is * not good name for this func * * @param[in] v vector * * @return norm * norm */ CGLM_INLINE float glms_vec2_(norm2)(vec2s v) { return glm_vec2_norm2(v.raw); } /*! * @brief norm (magnitude) of vec2 * * @param[in] v vector * * @return norm */ CGLM_INLINE float glms_vec2_(norm)(vec2s v) { return glm_vec2_norm(v.raw); } /*! * @brief add a vector to b vector store result in dest * * @param[in] a vector1 * @param[in] b vector2 * @returns destination vector */ CGLM_INLINE vec2s glms_vec2_(add)(vec2s a, vec2s b) { vec2s r; glm_vec2_add(a.raw, b.raw, r.raw); return r; } /*! * @brief add scalar to v vector store result in dest (d = v + s) * * @param[in] a vector * @param[in] s scalar * @returns destination vector */ CGLM_INLINE vec2s glms_vec2_(adds)(vec2s a, float s) { vec2s r; glm_vec2_adds(a.raw, s, r.raw); return r; } /*! * @brief subtract b vector from a vector store result in dest * * @param[in] a vector1 * @param[in] b vector2 * @returns destination vector */ CGLM_INLINE vec2s glms_vec2_(sub)(vec2s a, vec2s b) { vec2s r; glm_vec2_sub(a.raw, b.raw, r.raw); return r; } /*! * @brief subtract scalar from v vector store result in dest (d = v - s) * * @param[in] a vector * @param[in] s scalar * @returns destination vector */ CGLM_INLINE vec2s glms_vec2_(subs)(vec2s a, float s) { vec2s r; glm_vec2_subs(a.raw, s, r.raw); return r; } /*! * @brief multiply two vectors (component-wise multiplication) * * @param a vector1 * @param b vector2 * @returns result = (a[0] * b[0], a[1] * b[1]) */ CGLM_INLINE vec2s glms_vec2_(mul)(vec2s a, vec2s b) { vec2s r; glm_vec2_mul(a.raw, b.raw, r.raw); return r; } /*! * @brief multiply/scale vec2 vector with scalar: result = v * s * * @param[in] v vector * @param[in] s scalar * @returns destination vector */ CGLM_INLINE vec2s glms_vec2_(scale)(vec2s v, float s) { vec2s r; glm_vec2_scale(v.raw, s, r.raw); return r; } /*! * @brief make vec2 vector scale as specified: result = unit(v) * s * * @param[in] v vector * @param[in] s scalar * @returns destination vector */ CGLM_INLINE vec2s glms_vec2_(scale_as)(vec2s v, float s) { vec2s r; glm_vec2_scale_as(v.raw, s, r.raw); return r; } /*! * @brief div vector with another component-wise division: d = a / b * * @param[in] a vector 1 * @param[in] b vector 2 * @returns result = (a[0]/b[0], a[1]/b[1]) */ CGLM_INLINE vec2s glms_vec2_(div)(vec2s a, vec2s b) { vec2s r; glm_vec2_div(a.raw, b.raw, r.raw); return r; } /*! * @brief div vector with scalar: d = v / s * * @param[in] a vector * @param[in] s scalar * @returns result = (a[0]/s, a[1]/s) */ CGLM_INLINE vec2s glms_vec2_(divs)(vec2s a, float s) { vec2s r; glm_vec2_divs(a.raw, s, r.raw); return r; } /*! * @brief add two vectors and add result to sum * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest += (a + b) */ CGLM_INLINE vec2s glms_vec2_(addadd)(vec2s a, vec2s b, vec2s dest) { glm_vec2_addadd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief sub two vectors and add result to dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest += (a + b) */ CGLM_INLINE vec2s glms_vec2_(subadd)(vec2s a, vec2s b, vec2s dest) { glm_vec2_subadd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief mul two vectors and add result to dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest += (a * b) */ CGLM_INLINE vec2s glms_vec2_(muladd)(vec2s a, vec2s b, vec2s dest) { glm_vec2_muladd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief mul vector with scalar and add result to sum * * it applies += operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @returns dest += (a * b) */ CGLM_INLINE vec2s glms_vec2_(muladds)(vec2s a, float s, vec2s dest) { glm_vec2_muladds(a.raw, s, dest.raw); return dest; } /*! * @brief add max of two vectors to result/dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest += max(a, b) */ CGLM_INLINE vec2s glms_vec2_(maxadd)(vec2s a, vec2s b, vec2s dest) { glm_vec2_maxadd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief add min of two vectors to result/dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest += min(a, b) */ CGLM_INLINE vec2s glms_vec2_(minadd)(vec2s a, vec2s b, vec2s dest) { glm_vec2_minadd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief sub two vectors and sub result to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest -= (a - b) */ CGLM_INLINE vec2s glms_vec2_(subsub)(vec2s a, vec2s b, vec2s dest) { glm_vec2_subsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief add two vectors and sub result to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest -= (a + b) */ CGLM_INLINE vec2s glms_vec2_(addsub)(vec2s a, vec2s b, vec2s dest) { glm_vec2_addsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief mul two vectors and sub result to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest -= (a * b) */ CGLM_INLINE vec2s glms_vec2_(mulsub)(vec2s a, vec2s b, vec2s dest) { glm_vec2_mulsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief mul vector with scalar and sub result to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @returns dest -= (a * b) */ CGLM_INLINE vec2s glms_vec2_(mulsubs)(vec2s a, float s, vec2s dest) { glm_vec2_mulsubs(a.raw, s, dest.raw); return dest; } /*! * @brief sub max of two vectors to dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest -= max(a, b) */ CGLM_INLINE vec2s glms_vec2_(maxsub)(vec2s a, vec2s b, vec2s dest) { glm_vec2_maxsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief sub min of two vectors to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest -= min(a, b) */ CGLM_INLINE vec2s glms_vec2_(minsub)(vec2s a, vec2s b, vec2s dest) { glm_vec2_minsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief negate vector components * * @param[in] v vector * @returns negated vector */ CGLM_INLINE vec2s glms_vec2_(negate)(vec2s v) { glm_vec2_negate(v.raw); return v; } /*! * @brief normalize vec2 and store result in same vec * * @param[in] v vector * @returns normalized vector */ CGLM_INLINE vec2s glms_vec2_(normalize)(vec2s v) { glm_vec2_normalize(v.raw); return v; } /*! * @brief rotate vec2 by angle using Rodrigues' rotation formula * * @param[in] v vector * @param[in] angle angle by radians * @returns rotated vector */ CGLM_INLINE vec2s glms_vec2_(rotate)(vec2s v, float angle) { vec2s r; glm_vec2_rotate(v.raw, angle, r.raw); return r; } /** * @brief find center point of two vector * * @param[in] a vector1 * @param[in] b vector2 * @returns center point */ CGLM_INLINE vec2s glms_vec2_(center)(vec2s a, vec2s b) { vec2s r; glm_vec2_center(a.raw, b.raw, r.raw); return r; } /** * @brief distance between two vectors * * @param[in] a vector1 * @param[in] b vector2 * @return distance */ CGLM_INLINE float glms_vec2_(distance)(vec2s a, vec2s b) { return glm_vec2_distance(a.raw, b.raw); } /** * @brief squared distance between two vectors * * @param[in] a vector1 * @param[in] b vector2 * @return squared distance (distance * distance) */ CGLM_INLINE float glms_vec2_(distance2)(vec2s a, vec2s b) { return glm_vec2_distance2(a.raw, b.raw); } /*! * @brief max values of vectors * * @param[in] a vector1 * @param[in] b vector2 * @returns destination */ CGLM_INLINE vec2s glms_vec2_(maxv)(vec2s a, vec2s b) { vec2s r; glm_vec2_maxv(a.raw, b.raw, r.raw); return r; } /*! * @brief min values of vectors * * @param[in] a vector1 * @param[in] b vector2 * @returns destination */ CGLM_INLINE vec2s glms_vec2_(minv)(vec2s a, vec2s b) { vec2s r; glm_vec2_minv(a.raw, b.raw, r.raw); return r; } /*! * @brief clamp vector's individual members between min and max values * * @param[in] v vector * @param[in] minVal minimum value * @param[in] maxVal maximum value * @returns clamped vector */ CGLM_INLINE vec2s glms_vec2_(clamp)(vec2s v, float minVal, float maxVal) { glm_vec2_clamp(v.raw, minVal, maxVal); return v; } /*! * @brief linear interpolation between two vectors * * formula: from + s * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) * @returns destination */ CGLM_INLINE vec2s glms_vec2_(lerp)(vec2s from, vec2s to, float t) { vec2s r; glm_vec2_lerp(from.raw, to.raw, t, r.raw); return r; } /*! * @brief threshold function * * @param[in] edge threshold * @param[in] x value to test against threshold * @returns destination */ CGLM_INLINE vec2s glms_vec2_(step)(vec2s edge, vec2s x) { vec2s r; glm_vec2_step(edge.raw, x.raw, r.raw); return r; } /*! * @brief Create two dimensional vector from pointer * * @param[in] src pointer to an array of floats * @returns constructed 2D vector from raw pointer */ CGLM_INLINE vec2s glms_vec2_(make)(const float * __restrict src) { vec2s dest; glm_vec2_make(src, dest.raw); return dest; } /*! * @brief reflection vector using an incident ray and a surface normal * * @param[in] I incident vector * @param[in] N normalized normal vector * @returns reflection result */ CGLM_INLINE vec2s glms_vec2_(reflect)(vec2s v, vec2s n) { vec2s dest; glm_vec2_reflect(v.raw, n.raw, dest.raw); return dest; } /*! * @brief computes refraction vector for an incident vector and a surface normal. * * calculates the refraction vector based on Snell's law. If total internal reflection * occurs (angle too great given eta), dest is set to zero and returns false. * Otherwise, computes refraction vector, stores it in dest, and returns true. * * @param[in] v normalized incident vector * @param[in] n normalized normal vector * @param[in] eta ratio of indices of refraction (incident/transmitted) * @param[out] dest refraction vector if refraction occurs; zero vector otherwise * * @returns true if refraction occurs; false if total internal reflection occurs. */ CGLM_INLINE bool glms_vec2_(refract)(vec2s v, vec2s n, float eta, vec2s * __restrict dest) { return glm_vec2_refract(v.raw, n.raw, eta, dest->raw); } #endif /* cglms_vec2s_h */ cglm-0.9.7/include/cglm/struct/vec3-ext.h000066400000000000000000000143601526744317200201700ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /*! * @brief SIMD like functions */ /* Functions: CGLM_INLINE vec3s glms_vec3_broadcast(float val); CGLM_INLINE vec3s glms_vec3_fill(float val); CGLM_INLINE bool glms_vec3_eq(vec3s v, float val); CGLM_INLINE bool glms_vec3_eq_eps(vec3s v, float val); CGLM_INLINE bool glms_vec3_eq_all(vec3s v); CGLM_INLINE bool glms_vec3_eqv(vec3s a, vec3s b); CGLM_INLINE bool glms_vec3_eqv_eps(vec3s a, vec3s b); CGLM_INLINE float glms_vec3_max(vec3s v); CGLM_INLINE float glms_vec3_min(vec3s v); CGLM_INLINE bool glms_vec3_isnan(vec3s v); CGLM_INLINE bool glms_vec3_isinf(vec3s v); CGLM_INLINE bool glms_vec3_isvalid(vec3s v); CGLM_INLINE vec3s glms_vec3_sign(vec3s v); CGLM_INLINE vec3s glms_vec3_abs(vec3s v); CGLM_INLINE vec3s glms_vec3_fract(vec3s v); CGLM_INLINE vec3s glms_vec3_floor(vec3s v); CGLM_INLINE vec3s glms_vec3_mods(vec3s v, float s); CGLM_INLINE vec3s glms_vec3_steps(float edge, vec3s v); CGLM_INLINE vec3s glms_vec3_stepr(vec3s edge, float v); CGLM_INLINE float glms_vec3_hadd(vec3s v); CGLM_INLINE vec3s glms_vec3_sqrt(vec3s v); */ #ifndef cglms_vec3s_ext_h #define cglms_vec3s_ext_h #include "../common.h" #include "../types-struct.h" #include "../util.h" #include "../vec3-ext.h" /* api definition */ #define glms_vec3_(NAME) CGLM_STRUCTAPI(vec3, NAME) /*! * @brief fill a vector with specified value * * @param[in] val value * @returns dest */ CGLM_INLINE vec3s glms_vec3_(broadcast)(float val) { vec3s r; glm_vec3_broadcast(val, r.raw); return r; } /*! * @brief fill a vector with specified value * * @param[in] val value * @returns dest */ CGLM_INLINE vec3s glms_vec3_(fill)(float val) { vec3s r; glm_vec3_fill(r.raw, val); return r; } /*! * @brief check if vector is equal to value (without epsilon) * * @param[in] v vector * @param[in] val value */ CGLM_INLINE bool glms_vec3_(eq)(vec3s v, float val) { return glm_vec3_eq(v.raw, val); } /*! * @brief check if vector is equal to value (with epsilon) * * @param[in] v vector * @param[in] val value */ CGLM_INLINE bool glms_vec3_(eq_eps)(vec3s v, float val) { return glm_vec3_eq_eps(v.raw, val); } /*! * @brief check if vector members are equal (without epsilon) * * @param[in] v vector */ CGLM_INLINE bool glms_vec3_(eq_all)(vec3s v) { return glm_vec3_eq_all(v.raw); } /*! * @brief check if vector is equal to another (without epsilon) * * @param[in] a vector * @param[in] b vector */ CGLM_INLINE bool glms_vec3_(eqv)(vec3s a, vec3s b) { return glm_vec3_eqv(a.raw, b.raw); } /*! * @brief check if vector is equal to another (with epsilon) * * @param[in] a vector * @param[in] b vector */ CGLM_INLINE bool glms_vec3_(eqv_eps)(vec3s a, vec3s b) { return glm_vec3_eqv_eps(a.raw, b.raw); } /*! * @brief max value of vector * * @param[in] v vector */ CGLM_INLINE float glms_vec3_(max)(vec3s v) { return glm_vec3_max(v.raw); } /*! * @brief min value of vector * * @param[in] v vector */ CGLM_INLINE float glms_vec3_(min)(vec3s v) { return glm_vec3_min(v.raw); } /*! * @brief check if one of items is NaN (not a number) * you should only use this in DEBUG mode or very critical asserts * * @param[in] v vector */ CGLM_INLINE bool glms_vec3_(isnan)(vec3s v) { return glm_vec3_isnan(v.raw); } /*! * @brief check if one of items is INFINITY * you should only use this in DEBUG mode or very critical asserts * * @param[in] v vector */ CGLM_INLINE bool glms_vec3_(isinf)(vec3s v) { return glm_vec3_isinf(v.raw); } /*! * @brief check if all items are valid number * you should only use this in DEBUG mode or very critical asserts * * @param[in] v vector */ CGLM_INLINE bool glms_vec3_(isvalid)(vec3s v) { return glm_vec3_isvalid(v.raw); } /*! * @brief get sign of 32 bit float as +1, -1, 0 * * Important: It returns 0 for zero/NaN input * * @param v vector * @returns sign vector */ CGLM_INLINE vec3s glms_vec3_(sign)(vec3s v) { vec3s r; glm_vec3_sign(v.raw, r.raw); return r; } /*! * @brief absolute value of each vector item * * @param[in] v vector * @return destination vector */ CGLM_INLINE vec3s glms_vec3_(abs)(vec3s v) { vec3s r; glm_vec3_abs(v.raw, r.raw); return r; } /*! * @brief fractional part of each vector item * * @param[in] v vector * @return dest destination vector */ CGLM_INLINE vec3s glms_vec3_(fract)(vec3s v) { vec3s r; glm_vec3_fract(v.raw, r.raw); return r; } /*! * @brief floor of each vector item * * @param[in] v vector * @return dest destination vector */ CGLM_INLINE vec3s glms_vec3_(floor)(vec3s v) { vec3s r; glm_vec3_floor(v.raw, r.raw); return r; } /*! * @brief mod of each vector item by scalar * * @param[in] v vector * @param[in] s scalar * @returns destination vector */ CGLM_INLINE vec3s glms_vec3_(mods)(vec3s v, float s) { vec3s r; glm_vec3_mods(v.raw, s, r.raw); return r; } /*! * @brief threshold each vector item with scalar * condition is: (x[i] < edge) ? 0.0 : 1.0 * * @param[in] edge threshold * @param[in] x vector to test against threshold * @returns destination */ CGLM_INLINE vec3s glms_vec3_(steps)(float edge, vec3s x) { vec3s r; glm_vec3_steps(edge, x.raw, r.raw); return r; } /*! * @brief threshold a value with *vector* as the threshold * condition is: (x < edge[i]) ? 0.0 : 1.0 * * @param[in] edge threshold vector * @param[in] x value to test against threshold * @returns destination */ CGLM_INLINE vec3s glms_vec3_(stepr)(vec3s edge, float x) { vec3s r; glm_vec3_stepr(edge.raw, x, r.raw); return r; } /*! * @brief vector reduction by summation * @warning could overflow * * @param[in] v vector * @return sum of all vector's elements */ CGLM_INLINE float glms_vec3_(hadd)(vec3s v) { return glm_vec3_hadd(v.raw); } /*! * @brief square root of each vector item * * @param[in] v vector * @returns destination vector */ CGLM_INLINE vec3s glms_vec3_(sqrt)(vec3s v) { vec3s r; glm_vec3_sqrt(v.raw, r.raw); return r; } #endif /* cglms_vec3s_ext_h */ cglm-0.9.7/include/cglm/struct/vec3.h000066400000000000000000000622151526744317200173740ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLMS_VEC3_ONE_INIT GLMS_VEC3_ZERO_INIT GLMS_VEC3_ONE GLMS_VEC3_ZERO GLMS_YUP GLMS_ZUP GLMS_XUP Functions: CGLM_INLINE vec3s glms_vec3(vec4s v4); CGLM_INLINE void glms_vec3_pack(vec3s dst[], vec3 src[], size_t len); CGLM_INLINE void glms_vec3_unpack(vec3 dst[], vec3s src[], size_t len); CGLM_INLINE vec3s glms_vec3_zero(void); CGLM_INLINE vec3s glms_vec3_one(void); CGLM_INLINE float glms_vec3_dot(vec3s a, vec3s b); CGLM_INLINE float glms_vec3_norm2(vec3s v); CGLM_INLINE float glms_vec3_norm(vec3s v); CGLM_INLINE float glms_vec3_norm_one(vec3s v); CGLM_INLINE float glms_vec3_norm_inf(vec3s v); CGLM_INLINE vec3s glms_vec3_add(vec3s a, vec3s b); CGLM_INLINE vec3s glms_vec3_adds(vec3s a, float s); CGLM_INLINE vec3s glms_vec3_sub(vec3s a, vec3s b); CGLM_INLINE vec3s glms_vec3_subs(vec3s a, float s); CGLM_INLINE vec3s glms_vec3_mul(vec3s a, vec3s b); CGLM_INLINE vec3s glms_vec3_scale(vec3s v, float s); CGLM_INLINE vec3s glms_vec3_scale_as(vec3s v, float s); CGLM_INLINE vec3s glms_vec3_div(vec3s a, vec3s b); CGLM_INLINE vec3s glms_vec3_divs(vec3s a, float s); CGLM_INLINE vec3s glms_vec3_addadd(vec3s a, vec3s b, vec3s dest); CGLM_INLINE vec3s glms_vec3_subadd(vec3s a, vec3s b, vec3s dest); CGLM_INLINE vec3s glms_vec3_muladd(vec3s a, vec3s b, vec3s dest); CGLM_INLINE vec3s glms_vec3_muladds(vec3s a, float s, vec3s dest); CGLM_INLINE vec3s glms_vec3_maxadd(vec3s a, vec3s b, vec3s dest); CGLM_INLINE vec3s glms_vec3_minadd(vec3s a, vec3s b, vec3s dest); CGLM_INLINE vec3s glms_vec3_subsub(vec3s a, vec3s b, vec3s dest); CGLM_INLINE vec3s glms_vec3_addsub(vec3s a, vec3s b, vec3s dest); CGLM_INLINE vec3s glms_vec3_mulsub(vec3s a, vec3s b, vec3s dest); CGLM_INLINE vec3s glms_vec3_mulsubs(vec3s a, float s, vec3s dest); CGLM_INLINE vec3s glms_vec3_maxsub(vec3s a, vec3s b, vec3s dest); CGLM_INLINE vec3s glms_vec3_minsub(vec3s a, vec3s b, vec3s dest); CGLM_INLINE vec3s glms_vec3_flipsign(vec3s v); CGLM_INLINE vec3s glms_vec3_negate(vec3s v); CGLM_INLINE vec3s glms_vec3_normalize(vec3s v); CGLM_INLINE vec3s glms_vec3_cross(vec3s a, vec3s b); CGLM_INLINE vec3s glms_vec3_crossn(vec3s a, vec3s b); CGLM_INLINE float glms_vec3_angle(vec3s a, vec3s b); CGLM_INLINE vec3s glms_vec3_rotate(vec3s v, float angle, vec3s axis); CGLM_INLINE vec3s glms_vec3_rotate_m4(mat4s m, vec3s v); CGLM_INLINE vec3s glms_vec3_rotate_m3(mat3s m, vec3s v); CGLM_INLINE vec3s glms_vec3_proj(vec3s a, vec3s b); CGLM_INLINE vec3s glms_vec3_center(vec3s a, vec3s b); CGLM_INLINE float glms_vec3_distance(vec3s a, vec3s b); CGLM_INLINE float glms_vec3_distance2(vec3s a, vec3s b); CGLM_INLINE vec3s glms_vec3_maxv(vec3s a, vec3s b); CGLM_INLINE vec3s glms_vec3_minv(vec3s a, vec3s b); CGLM_INLINE vec3s glms_vec3_ortho(vec3s v); CGLM_INLINE vec3s glms_vec3_clamp(vec3s v, float minVal, float maxVal); CGLM_INLINE vec3s glms_vec3_lerp(vec3s from, vec3s to, float t); CGLM_INLINE vec3s glms_vec3_lerpc(vec3s from, vec3s to, float t); CGLM_INLINE vec3s glms_vec3_mix(vec3s from, vec3s to, float t); CGLM_INLINE vec3s glms_vec3_mixc(vec3s from, vec3s to, float t); CGLM_INLINE vec3s glms_vec3_step(vec3s edge, vec3s x); CGLM_INLINE vec3s glms_vec3_smoothstep_uni(float edge0, float edge1, vec3s x); CGLM_INLINE vec3s glms_vec3_smoothstep(vec3s edge0, vec3s edge1, vec3s x); CGLM_INLINE vec3s glms_vec3_smoothinterp(vec3s from, vec3s to, float t); CGLM_INLINE vec3s glms_vec3_smoothinterpc(vec3s from, vec3s to, float t); CGLM_INLINE vec3s glms_vec3_swizzle(vec3s v, int mask); CGLM_INLINE vec3s glms_vec3_make(float * restrict src); CGLM_INLINE vec3s glms_vec3_faceforward(vec3s n, vec3s v, vec3s nref); CGLM_INLINE vec3s glms_vec3_reflect(vec3s v, vec3s n); CGLM_INLINE bool glms_vec3_refract(vec3s v, vec3s n, float eta, vec3s *dest) Convenient: CGLM_INLINE vec3s glms_cross(vec3s a, vec3s b); CGLM_INLINE float glms_dot(vec3s a, vec3s b); CGLM_INLINE vec3s glms_normalize(vec3s v); Deprecated: glms_vec3_step_uni --> use glms_vec3_steps */ #ifndef cglms_vec3s_h #define cglms_vec3s_h #include "../common.h" #include "../types-struct.h" #include "../util.h" #include "../vec3.h" #include "vec3-ext.h" /* DEPRECATED! */ #define glms_vec3_step_uni(edge, x) glms_vec3_steps(edge, x) #define GLMS_VEC3_ONE_INIT {GLM_VEC3_ONE_INIT} #define GLMS_VEC3_ZERO_INIT {GLM_VEC3_ZERO_INIT} #define GLMS_VEC3_ONE ((vec3s)GLMS_VEC3_ONE_INIT) #define GLMS_VEC3_ZERO ((vec3s)GLMS_VEC3_ZERO_INIT) #define GLMS_YUP ((vec3s){{0.0f, 1.0f, 0.0f}}) #define GLMS_ZUP ((vec3s){{0.0f, 0.0f, 1.0f}}) #define GLMS_XUP ((vec3s){{1.0f, 0.0f, 0.0f}}) /*! * @brief init vec3 using vec4 * * @param[in] v4 vector4 * @returns destination */ CGLM_INLINE vec3s glms_vec3(vec4s v4) { vec3s r; glm_vec3(v4.raw, r.raw); return r; } /*! * @brief pack an array of vec3 into an array of vec3s * * @param[out] dst array of vec3 * @param[in] src array of vec3s * @param[in] len number of elements */ CGLM_INLINE void glms_vec3_(pack)(vec3s dst[], vec3 src[], size_t len) { size_t i; for (i = 0; i < len; i++) { glm_vec3_copy(src[i], dst[i].raw); } } /*! * @brief unpack an array of vec3s into an array of vec3 * * @param[out] dst array of vec3s * @param[in] src array of vec3 * @param[in] len number of elements */ CGLM_INLINE void glms_vec3_(unpack)(vec3 dst[], vec3s src[], size_t len) { size_t i; for (i = 0; i < len; i++) { glm_vec3_copy(src[i].raw, dst[i]); } } /*! * @brief make vector zero * * @returns zero vector */ CGLM_INLINE vec3s glms_vec3_(zero)(void) { vec3s r; glm_vec3_zero(r.raw); return r; } /*! * @brief make vector one * * @returns one vector */ CGLM_INLINE vec3s glms_vec3_(one)(void) { vec3s r; glm_vec3_one(r.raw); return r; } /*! * @brief vec3 dot product * * @param[in] a vector1 * @param[in] b vector2 * * @return dot product */ CGLM_INLINE float glms_vec3_(dot)(vec3s a, vec3s b) { return glm_vec3_dot(a.raw, b.raw); } /*! * @brief norm * norm (magnitude) of vec * * we can use this func instead of calling norm * norm, because it would call * sqrtf function twice but with this func we can avoid func call, maybe this is * not good name for this func * * @param[in] v vector * * @return norm * norm */ CGLM_INLINE float glms_vec3_(norm2)(vec3s v) { return glm_vec3_norm2(v.raw); } /*! * @brief norm (magnitude) of vec3 * * @param[in] v vector * * @return norm */ CGLM_INLINE float glms_vec3_(norm)(vec3s v) { return glm_vec3_norm(v.raw); } /*! * @brief L1 norm of vec3 * Also known as Manhattan Distance or Taxicab norm. * L1 Norm is the sum of the magnitudes of the vectors in a space. * It is calculated as the sum of the absolute values of the vector components. * In this norm, all the components of the vector are weighted equally. * * This computes: * R = |v[0]| + |v[1]| + |v[2]| * * @param[in] v vector * * @return L1 norm */ CGLM_INLINE float glms_vec3_(norm_one)(vec3s v) { return glm_vec3_norm_one(v.raw); } /*! * @brief Infinity norm of vec3 * Also known as Maximum norm. * Infinity Norm is the largest magnitude among each element of a vector. * It is calculated as the maximum of the absolute values of the vector components. * * This computes: * inf norm = max(|v[0]|, |v[1]|, |v[2]|) * * @param[in] v vector * * @return Infinity norm */ CGLM_INLINE float glms_vec3_(norm_inf)(vec3s v) { return glm_vec3_norm_inf(v.raw); } /*! * @brief add a vector to b vector store result in dest * * @param[in] a vector1 * @param[in] b vector2 * @returns destination vector */ CGLM_INLINE vec3s glms_vec3_(add)(vec3s a, vec3s b) { vec3s r; glm_vec3_add(a.raw, b.raw, r.raw); return r; } /*! * @brief add scalar to v vector store result in dest (d = v + s) * * @param[in] a vector * @param[in] s scalar * @returns destination vector */ CGLM_INLINE vec3s glms_vec3_(adds)(vec3s a, float s) { vec3s r; glm_vec3_adds(a.raw, s, r.raw); return r; } /*! * @brief subtract b vector from a vector store result in dest * * @param[in] a vector1 * @param[in] b vector2 * @returns destination vector */ CGLM_INLINE vec3s glms_vec3_(sub)(vec3s a, vec3s b) { vec3s r; glm_vec3_sub(a.raw, b.raw, r.raw); return r; } /*! * @brief subtract scalar from v vector store result in dest (d = v - s) * * @param[in] a vector * @param[in] s scalar * @returns destination vector */ CGLM_INLINE vec3s glms_vec3_(subs)(vec3s a, float s) { vec3s r; glm_vec3_subs(a.raw, s, r.raw); return r; } /*! * @brief multiply two vectors (component-wise multiplication) * * @param a vector1 * @param b vector2 * @returns v3 = (a[0] * b[0], a[1] * b[1], a[2] * b[2]) */ CGLM_INLINE vec3s glms_vec3_(mul)(vec3s a, vec3s b) { vec3s r; glm_vec3_mul(a.raw, b.raw, r.raw); return r; } /*! * @brief multiply/scale vec3 vector with scalar: result = v * s * * @param[in] v vector * @param[in] s scalar * @returns destination vector */ CGLM_INLINE vec3s glms_vec3_(scale)(vec3s v, float s) { vec3s r; glm_vec3_scale(v.raw, s, r.raw); return r; } /*! * @brief make vec3 vector scale as specified: result = unit(v) * s * * @param[in] v vector * @param[in] s scalar * @returns destination vector */ CGLM_INLINE vec3s glms_vec3_(scale_as)(vec3s v, float s) { vec3s r; glm_vec3_scale_as(v.raw, s, r.raw); return r; } /*! * @brief div vector with another component-wise division: d = a / b * * @param[in] a vector 1 * @param[in] b vector 2 * @returns result = (a[0]/b[0], a[1]/b[1], a[2]/b[2]) */ CGLM_INLINE vec3s glms_vec3_(div)(vec3s a, vec3s b) { vec3s r; glm_vec3_div(a.raw, b.raw, r.raw); return r; } /*! * @brief div vector with scalar: d = v / s * * @param[in] a vector * @param[in] s scalar * @returns result = (a[0]/s, a[1]/s, a[2]/s) */ CGLM_INLINE vec3s glms_vec3_(divs)(vec3s a, float s) { vec3s r; glm_vec3_divs(a.raw, s, r.raw); return r; } /*! * @brief add two vectors and add result to sum * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest += (a + b) */ CGLM_INLINE vec3s glms_vec3_(addadd)(vec3s a, vec3s b, vec3s dest) { glm_vec3_addadd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief sub two vectors and add result to dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest += (a + b) */ CGLM_INLINE vec3s glms_vec3_(subadd)(vec3s a, vec3s b, vec3s dest) { glm_vec3_subadd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief mul two vectors and add result to dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest += (a * b) */ CGLM_INLINE vec3s glms_vec3_(muladd)(vec3s a, vec3s b, vec3s dest) { glm_vec3_muladd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief mul vector with scalar and add result to sum * * it applies += operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @returns dest += (a * b) */ CGLM_INLINE vec3s glms_vec3_(muladds)(vec3s a, float s, vec3s dest) { glm_vec3_muladds(a.raw, s, dest.raw); return dest; } /*! * @brief add max of two vectors to result/dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest += max(a, b) */ CGLM_INLINE vec3s glms_vec3_(maxadd)(vec3s a, vec3s b, vec3s dest) { glm_vec3_maxadd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief add min of two vectors to result/dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest += min(a, b) */ CGLM_INLINE vec3s glms_vec3_(minadd)(vec3s a, vec3s b, vec3s dest) { glm_vec3_minadd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief sub two vectors and sub result to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest -= (a - b) */ CGLM_INLINE vec3s glms_vec3_(subsub)(vec3s a, vec3s b, vec3s dest) { glm_vec3_subsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief add two vectors and sub result to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest -= (a + b) */ CGLM_INLINE vec3s glms_vec3_(addsub)(vec3s a, vec3s b, vec3s dest) { glm_vec3_addsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief mul two vectors and sub result to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest -= (a * b) */ CGLM_INLINE vec3s glms_vec3_(mulsub)(vec3s a, vec3s b, vec3s dest) { glm_vec3_mulsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief mul vector with scalar and sub result to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @returns dest -= (a * b) */ CGLM_INLINE vec3s glms_vec3_(mulsubs)(vec3s a, float s, vec3s dest) { glm_vec3_mulsubs(a.raw, s, dest.raw); return dest; } /*! * @brief sub max of two vectors to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest -= max(a, b) */ CGLM_INLINE vec3s glms_vec3_(maxsub)(vec3s a, vec3s b, vec3s dest) { glm_vec3_maxsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief sub min of two vectors to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest -= min(a, b) */ CGLM_INLINE vec3s glms_vec3_(minsub)(vec3s a, vec3s b, vec3s dest) { glm_vec3_minsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief negate vector components and store result in dest * * @param[in] v vector * @returns result vector */ CGLM_INLINE vec3s glms_vec3_(flipsign)(vec3s v) { glm_vec3_flipsign(v.raw); return v; } /*! * @brief negate vector components * * @param[in] v vector * @returns negated vector */ CGLM_INLINE vec3s glms_vec3_(negate)(vec3s v) { glm_vec3_negate(v.raw); return v; } /*! * @brief normalize vec3 and store result in same vec * * @param[in] v vector * @returns normalized vector */ CGLM_INLINE vec3s glms_vec3_(normalize)(vec3s v) { glm_vec3_normalize(v.raw); return v; } /*! * @brief cross product of two vector (RH) * * @param[in] a vector 1 * @param[in] b vector 2 * @returns destination */ CGLM_INLINE vec3s glms_vec3_(cross)(vec3s a, vec3s b) { vec3s r; glm_vec3_cross(a.raw, b.raw, r.raw); return r; } /*! * @brief cross product of two vector (RH) and normalize the result * * @param[in] a vector 1 * @param[in] b vector 2 * @returns destination */ CGLM_INLINE vec3s glms_vec3_(crossn)(vec3s a, vec3s b) { vec3s r; glm_vec3_crossn(a.raw, b.raw, r.raw); return r; } /*! * @brief angle between two vector * * @param[in] a vector1 * @param[in] b vector2 * * @return angle as radians */ CGLM_INLINE float glms_vec3_(angle)(vec3s a, vec3s b) { return glm_vec3_angle(a.raw, b.raw); } /*! * @brief rotate vec3 around axis by angle using Rodrigues' rotation formula * * @param[in] v vector * @param[in] axis axis vector (must be unit vector) * @param[in] angle angle by radians * @returns rotated vector */ CGLM_INLINE vec3s glms_vec3_(rotate)(vec3s v, float angle, vec3s axis) { glm_vec3_rotate(v.raw, angle, axis.raw); return v; } /*! * @brief apply rotation matrix to vector * * matrix format should be (no perspective): * a b c x * e f g y * i j k z * 0 0 0 w * * @param[in] m affine matrix or rot matrix * @param[in] v vector * @returns rotated vector */ CGLM_INLINE vec3s glms_vec3_(rotate_m4)(mat4s m, vec3s v) { vec3s r; glm_vec3_rotate_m4(m.raw, v.raw, r.raw); return r; } /*! * @brief apply rotation matrix to vector * * @param[in] m affine matrix or rot matrix * @param[in] v vector * @returns rotated vector */ CGLM_INLINE vec3s glms_vec3_(rotate_m3)(mat3s m, vec3s v) { vec3s r; glm_vec3_rotate_m3(m.raw, v.raw, r.raw); return r; } /*! * @brief project a vector onto b vector * * @param[in] a vector1 * @param[in] b vector2 * @returns projected vector */ CGLM_INLINE vec3s glms_vec3_(proj)(vec3s a, vec3s b) { vec3s r; glm_vec3_proj(a.raw, b.raw, r.raw); return r; } /** * @brief find center point of two vector * * @param[in] a vector1 * @param[in] b vector2 * @returns center point */ CGLM_INLINE vec3s glms_vec3_(center)(vec3s a, vec3s b) { vec3s r; glm_vec3_center(a.raw, b.raw, r.raw); return r; } /** * @brief distance between two vectors * * @param[in] a vector1 * @param[in] b vector2 * @return distance */ CGLM_INLINE float glms_vec3_(distance)(vec3s a, vec3s b) { return glm_vec3_distance(a.raw, b.raw); } /** * @brief squared distance between two vectors * * @param[in] a vector1 * @param[in] b vector2 * @return squared distance (distance * distance) */ CGLM_INLINE float glms_vec3_(distance2)(vec3s a, vec3s b) { return glm_vec3_distance2(a.raw, b.raw); } /*! * @brief max values of vectors * * @param[in] a vector1 * @param[in] b vector2 * @returns destination */ CGLM_INLINE vec3s glms_vec3_(maxv)(vec3s a, vec3s b) { vec3s r; glm_vec3_maxv(a.raw, b.raw, r.raw); return r; } /*! * @brief min values of vectors * * @param[in] a vector1 * @param[in] b vector2 * @returns destination */ CGLM_INLINE vec3s glms_vec3_(minv)(vec3s a, vec3s b) { vec3s r; glm_vec3_minv(a.raw, b.raw, r.raw); return r; } /*! * @brief possible orthogonal/perpendicular vector * * @param[in] v vector * @returns orthogonal/perpendicular vector */ CGLM_INLINE vec3s glms_vec3_(ortho)(vec3s v) { vec3s r; glm_vec3_ortho(v.raw, r.raw); return r; } /*! * @brief clamp vector's individual members between min and max values * * @param[in] v vector * @param[in] minVal minimum value * @param[in] maxVal maximum value * @returns clamped vector */ CGLM_INLINE vec3s glms_vec3_(clamp)(vec3s v, float minVal, float maxVal) { glm_vec3_clamp(v.raw, minVal, maxVal); return v; } /*! * @brief linear interpolation between two vectors * * formula: from + s * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) * @returns destination */ CGLM_INLINE vec3s glms_vec3_(lerp)(vec3s from, vec3s to, float t) { vec3s r; glm_vec3_lerp(from.raw, to.raw, t, r.raw); return r; } /*! * @brief linear interpolation between two vectors (clamped) * * formula: from + s * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) clamped between 0 and 1 * @returns destination */ CGLM_INLINE vec3s glms_vec3_(lerpc)(vec3s from, vec3s to, float t) { vec3s r; glm_vec3_lerpc(from.raw, to.raw, t, r.raw); return r; } /*! * @brief linear interpolation between two vectors * * formula: from + s * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) * @returns destination */ CGLM_INLINE vec3s glms_vec3_(mix)(vec3s from, vec3s to, float t) { vec3s r; glm_vec3_mix(from.raw, to.raw, t, r.raw); return r; } /*! * @brief linear interpolation between two vectors (clamped) * * formula: from + s * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) clamped between 0 and 1 * @returns destination */ CGLM_INLINE vec3s glms_vec3_(mixc)(vec3s from, vec3s to, float t) { vec3s r; glm_vec3_mixc(from.raw, to.raw, t, r.raw); return r; } /*! * @brief threshold function * * @param[in] edge threshold * @param[in] x value to test against threshold * @returns 0.0 if x < edge, else 1.0 */ CGLM_INLINE vec3s glms_vec3_(step)(vec3s edge, vec3s x) { vec3s r; glm_vec3_step(edge.raw, x.raw, r.raw); return r; } /*! * @brief threshold function with a smooth transition (unidimensional) * * @param[in] edge0 low threshold * @param[in] edge1 high threshold * @param[in] x value to test against threshold * @returns destination */ CGLM_INLINE vec3s glms_vec3_(smoothstep_uni)(float edge0, float edge1, vec3s x) { vec3s r; glm_vec3_smoothstep_uni(edge0, edge1, x.raw, r.raw); return r; } /*! * @brief threshold function with a smooth transition * * @param[in] edge0 low threshold * @param[in] edge1 high threshold * @param[in] x value to test against threshold * @returns destination */ CGLM_INLINE vec3s glms_vec3_(smoothstep)(vec3s edge0, vec3s edge1, vec3s x) { vec3s r; glm_vec3_smoothstep(edge0.raw, edge1.raw, x.raw, r.raw); return r; } /*! * @brief smooth Hermite interpolation between two vectors * * formula: from + s * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) * @returns destination */ CGLM_INLINE vec3s glms_vec3_(smoothinterp)(vec3s from, vec3s to, float t) { vec3s r; glm_vec3_smoothinterp(from.raw, to.raw, t, r.raw); return r; } /*! * @brief smooth Hermite interpolation between two vectors (clamped) * * formula: from + s * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) clamped between 0 and 1 * @returns destination */ CGLM_INLINE vec3s glms_vec3_(smoothinterpc)(vec3s from, vec3s to, float t) { vec3s r; glm_vec3_smoothinterpc(from.raw, to.raw, t, r.raw); return r; } /*! * @brief vec3 cross product * * this is just convenient wrapper * * @param[in] a source 1 * @param[in] b source 2 * @returns destination */ CGLM_INLINE vec3s glms_cross(vec3s a, vec3s b) { vec3s r; glm_cross(a.raw, b.raw, r.raw); return r; } /*! * @brief vec3 dot product * * this is just convenient wrapper * * @param[in] a vector1 * @param[in] b vector2 * @return dot product */ CGLM_INLINE float glms_dot(vec3s a, vec3s b) { return glm_dot(a.raw, b.raw); } /*! * @brief normalize vec3 and store result in same vec * * this is just convenient wrapper * * @param[in] v vector * @returns normalized vector */ CGLM_INLINE vec3s glms_normalize(vec3s v) { glm_normalize(v.raw); return v; } /*! * @brief swizzle vector components * * you can use existing masks e.g. GLM_XXX, GLM_ZYX * * @param[in] v source * @param[in] mask mask * @returns swizzled vector */ CGLM_INLINE vec3s glms_vec3_(swizzle)(vec3s v, int mask) { vec3s dest; glm_vec3_swizzle(v.raw, mask, dest.raw); return dest; } /*! * @brief Create three dimensional vector from pointer * * @param[in] src pointer to an array of floats * @returns constructed 3D vector from raw pointer */ CGLM_INLINE vec3s glms_vec3_(make)(const float * __restrict src) { vec3s dest; glm_vec3_make(src, dest.raw); return dest; } /*! * @brief a vector pointing in the same direction as another * * orients a vector to point away from a surface as defined by its normal * * @param[in] n vector to orient. * @param[in] v incident vector * @param[in] nref reference vector * @returns oriented vector, pointing away from the surface. */ CGLM_INLINE vec3s glms_vec3_(faceforward)(vec3s n, vec3s v, vec3s nref) { vec3s dest; glm_vec3_faceforward(n.raw, v.raw, nref.raw, dest.raw); return dest; } /*! * @brief reflection vector using an incident ray and a surface normal * * @param[in] I incident vector * @param[in] N normalized normal vector * @returns reflection result */ CGLM_INLINE vec3s glms_vec3_(reflect)(vec3s v, vec3s n) { vec3s dest; glm_vec3_reflect(v.raw, n.raw, dest.raw); return dest; } /*! * @brief computes refraction vector for an incident vector and a surface normal. * * calculates the refraction vector based on Snell's law. If total internal reflection * occurs (angle too great given eta), dest is set to zero and returns false. * Otherwise, computes refraction vector, stores it in dest, and returns true. * * @param[in] v normalized incident vector * @param[in] n normalized normal vector * @param[in] eta ratio of indices of refraction (incident/transmitted) * @param[out] dest refraction vector if refraction occurs; zero vector otherwise * * @returns true if refraction occurs; false if total internal reflection occurs. */ CGLM_INLINE bool glms_vec3_(refract)(vec3s v, vec3s n, float eta, vec3s * __restrict dest) { return glm_vec3_refract(v.raw, n.raw, eta, dest->raw); } #endif /* cglms_vec3s_h */ cglm-0.9.7/include/cglm/struct/vec4-ext.h000066400000000000000000000142561526744317200201750ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /*! * @brief SIMD like functions */ /* Functions: CGLM_INLINE vec4s glms_vec4_broadcast(float val); CGLM_INLINE vec4s glms_vec4_fill(float val); CGLM_INLINE bool glms_vec4_eq(vec4s v, float val); CGLM_INLINE bool glms_vec4_eq_eps(vec4s v, float val); CGLM_INLINE bool glms_vec4_eq_all(vec4s v); CGLM_INLINE bool glms_vec4_eqv(vec4s a, vec4s b); CGLM_INLINE bool glms_vec4_eqv_eps(vec4s a, vec4s b); CGLM_INLINE float glms_vec4_max(vec4s v); CGLM_INLINE float glms_vec4_min(vec4s v); CGLM_INLINE bool glms_vec4_isnan(vec4s v); CGLM_INLINE bool glms_vec4_isinf(vec4s v); CGLM_INLINE bool glms_vec4_isvalid(vec4s v); CGLM_INLINE vec4s glms_vec4_sign(vec4s v); CGLM_INLINE vec4s glms_vec4_abs(vec4s v); CGLM_INLINE vec4s glms_vec4_fract(vec4s v); CGLM_INLINE float glms_vec4_floor(vec4s v); CGLM_INLINE float glms_vec4_mods(vec4s v, float s); CGLM_INLINE float glms_vec4_steps(float edge, vec4s v); CGLM_INLINE void glms_vec4_stepr(vec4s edge, float v); CGLM_INLINE float glms_vec4_hadd(vec4s v); CGLM_INLINE vec4s glms_vec4_sqrt(vec4s v); */ #ifndef cglms_vec4s_ext_h #define cglms_vec4s_ext_h #include "../common.h" #include "../types-struct.h" #include "../util.h" #include "../vec4-ext.h" /* api definition */ #define glms_vec4_(NAME) CGLM_STRUCTAPI(vec4, NAME) /*! * @brief fill a vector with specified value * * @param val value * @returns dest */ CGLM_INLINE vec4s glms_vec4_(broadcast)(float val) { vec4s r; glm_vec4_broadcast(val, r.raw); return r; } /*! * @brief fill a vector with specified value * * @param val value * @returns dest */ CGLM_INLINE vec4s glms_vec4_(fill)(float val) { vec4s r; glm_vec4_fill(r.raw, val); return r; } /*! * @brief check if vector is equal to value (without epsilon) * * @param v vector * @param val value */ CGLM_INLINE bool glms_vec4_(eq)(vec4s v, float val) { return glm_vec4_eq(v.raw, val); } /*! * @brief check if vector is equal to value (with epsilon) * * @param v vector * @param val value */ CGLM_INLINE bool glms_vec4_(eq_eps)(vec4s v, float val) { return glm_vec4_eq_eps(v.raw, val); } /*! * @brief check if vector members are equal (without epsilon) * * @param v vector */ CGLM_INLINE bool glms_vec4_(eq_all)(vec4s v) { return glm_vec4_eq_all(v.raw); } /*! * @brief check if vector is equal to another (without epsilon) * * @param a vector * @param b vector */ CGLM_INLINE bool glms_vec4_(eqv)(vec4s a, vec4s b) { return glm_vec4_eqv(a.raw, b.raw); } /*! * @brief check if vector is equal to another (with epsilon) * * @param a vector * @param b vector */ CGLM_INLINE bool glms_vec4_(eqv_eps)(vec4s a, vec4s b) { return glm_vec4_eqv_eps(a.raw, b.raw); } /*! * @brief max value of vector * * @param v vector */ CGLM_INLINE float glms_vec4_(max)(vec4s v) { return glm_vec4_max(v.raw); } /*! * @brief min value of vector * * @param v vector */ CGLM_INLINE float glms_vec4_(min)(vec4s v) { return glm_vec4_min(v.raw); } /*! * @brief check if one of items is NaN (not a number) * you should only use this in DEBUG mode or very critical asserts * * @param[in] v vector */ CGLM_INLINE bool glms_vec4_(isnan)(vec4s v) { return glm_vec4_isnan(v.raw); } /*! * @brief check if one of items is INFINITY * you should only use this in DEBUG mode or very critical asserts * * @param[in] v vector */ CGLM_INLINE bool glms_vec4_(isinf)(vec4s v) { return glm_vec4_isinf(v.raw); } /*! * @brief check if all items are valid number * you should only use this in DEBUG mode or very critical asserts * * @param[in] v vector */ CGLM_INLINE bool glms_vec4_(isvalid)(vec4s v) { return glm_vec4_isvalid(v.raw); } /*! * @brief get sign of 32 bit float as +1, -1, 0 * * Important: It returns 0 for zero/NaN input * * @param v vector * @returns sign vector */ CGLM_INLINE vec4s glms_vec4_(sign)(vec4s v) { vec4s r; glm_vec4_sign(v.raw, r.raw); return r; } /*! * @brief absolute value of each vector item * * @param[in] v vector * @returns destination vector */ CGLM_INLINE vec4s glms_vec4_(abs)(vec4s v) { vec4s r; glm_vec4_abs(v.raw, r.raw); return r; } /*! * @brief fractional part of each vector item * * @param[in] v vector * @returns dest destination vector */ CGLM_INLINE vec4s glms_vec4_(fract)(vec4s v) { vec4s r; glm_vec4_fract(v.raw, r.raw); return r; } /*! * @brief floor of each vector item * * @param[in] v vector * @returns dest destination vector */ CGLM_INLINE vec4s glms_vec4_(floor)(vec4s v) { vec4s r; glm_vec4_floor(v.raw, r.raw); return r; } /*! * @brief mod of each vector item by scalar * * @param[in] v vector * @param[in] s scalar * @returns destination vector */ CGLM_INLINE vec4s glms_vec4_(mods)(vec4s v, float s) { vec4s r; glm_vec4_mods(v.raw, s, r.raw); return r; } /*! * @brief threshold each vector item with scalar * condition is: (x[i] < edge) ? 0.0 : 1.0 * * @param[in] edge threshold * @param[in] x vector to test against threshold * @returns destination */ CGLM_INLINE vec4s glms_vec4_(steps)(float edge, vec4s x) { vec4s r; glm_vec4_steps(edge, x.raw, r.raw); return r; } /*! * @brief threshold a value with *vector* as the threshold * condition is: (x < edge[i]) ? 0.0 : 1.0 * * @param[in] edge threshold vector * @param[in] x value to test against threshold * @returns destination */ CGLM_INLINE vec4s glms_vec4_(stepr)(vec4s edge, float x) { vec4s r; glm_vec4_stepr(edge.raw, x, r.raw); return r; } /*! * @brief vector reduction by summation * @warning could overflow * * @param[in] v vector * @return sum of all vector's elements */ CGLM_INLINE float glms_vec4_(hadd)(vec4s v) { return glm_vec4_hadd(v.raw); } /*! * @brief square root of each vector item * * @param[in] v vector * @returns destination vector */ CGLM_INLINE vec4s glms_vec4_(sqrt)(vec4s v) { vec4s r; glm_vec4_sqrt(v.raw, r.raw); return r; } #endif /* cglms_vec4s_ext_h */ cglm-0.9.7/include/cglm/struct/vec4.h000066400000000000000000000532341526744317200173760ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLMS_VEC4_ONE_INIT GLMS_VEC4_BLACK_INIT GLMS_VEC4_ZERO_INIT GLMS_VEC4_ONE GLMS_VEC4_BLACK GLMS_VEC4_ZERO Functions: CGLM_INLINE vec4s glms_vec4(vec3s v3, float last); CGLM_INLINE vec3s glms_vec4_copy3(vec4s v); CGLM_INLINE vec4s glms_vec4_copy(vec4s v); CGLM_INLINE vec4s glms_vec4_ucopy(vec4s v); CGLM_INLINE void glms_vec4_pack(vec4s dst[], vec4 src[], size_t len); CGLM_INLINE void glms_vec4_unpack(vec4 dst[], vec4s src[], size_t len); CGLM_INLINE float glms_vec4_dot(vec4s a, vec4s b); CGLM_INLINE float glms_vec4_norm2(vec4s v); CGLM_INLINE float glms_vec4_norm(vec4s v); CGLM_INLINE float glms_vec4_norm_one(vec4s v); CGLM_INLINE float glms_vec4_norm_inf(vec4s v); CGLM_INLINE vec4s glms_vec4_add(vec4s a, vec4s b); CGLM_INLINE vec4s glms_vec4_adds(vec4s v, float s); CGLM_INLINE vec4s glms_vec4_sub(vec4s a, vec4s b); CGLM_INLINE vec4s glms_vec4_subs(vec4s v, float s); CGLM_INLINE vec4s glms_vec4_mul(vec4s a, vec4s b); CGLM_INLINE vec4s glms_vec4_scale(vec4s v, float s); CGLM_INLINE vec4s glms_vec4_scale_as(vec4s v, float s); CGLM_INLINE vec4s glms_vec4_div(vec4s a, vec4s b); CGLM_INLINE vec4s glms_vec4_divs(vec4s v, float s); CGLM_INLINE vec4s glms_vec4_addadd(vec4s a, vec4s b, vec4s dest); CGLM_INLINE vec4s glms_vec4_subadd(vec4s a, vec4s b, vec4s dest); CGLM_INLINE vec4s glms_vec4_muladd(vec4s a, vec4s b, vec4s dest); CGLM_INLINE vec4s glms_vec4_muladds(vec4s a, float s, vec4s dest); CGLM_INLINE vec4s glms_vec4_maxadd(vec4s a, vec4s b, vec4s dest); CGLM_INLINE vec4s glms_vec4_minadd(vec4s a, vec4s b, vec4s dest); CGLM_INLINE vec4s glms_vec4_subsub(vec4s a, vec4s b, vec4s dest); CGLM_INLINE vec4s glms_vec4_addsub(vec4s a, vec4s b, vec4s dest); CGLM_INLINE vec4s glms_vec4_mulsub(vec4s a, vec4s b, vec4s dest); CGLM_INLINE vec4s glms_vec4_mulsubs(vec4s a, float s, vec4s dest); CGLM_INLINE vec4s glms_vec4_maxsub(vec4s a, vec4s b, vec4s dest); CGLM_INLINE vec4s glms_vec4_minsub(vec4s a, vec4s b, vec4s dest); CGLM_INLINE vec4s glms_vec4_negate(vec4s v); CGLM_INLINE vec4s glms_vec4_normalize(vec4s v); CGLM_INLINE float glms_vec4_distance(vec4s a, vec4s b); CGLM_INLINE float glms_vec4_distance2(vec4s a, vec4s b); CGLM_INLINE vec4s glms_vec4_maxv(vec4s a, vec4s b); CGLM_INLINE vec4s glms_vec4_minv(vec4s a, vec4s b); CGLM_INLINE vec4s glms_vec4_clamp(vec4s v, float minVal, float maxVal); CGLM_INLINE vec4s glms_vec4_lerp(vec4s from, vec4s to, float t); CGLM_INLINE vec4s glms_vec4_lerpc(vec4s from, vec4s to, float t); CGLM_INLINE vec4s glms_vec4_mix(vec4s from, vec4s to, float t); CGLM_INLINE vec4s glms_vec4_mixc(vec4s from, vec4s to, float t); CGLM_INLINE vec4s glms_vec4_step(vec4s edge, vec4s x); CGLM_INLINE vec4s glms_vec4_smoothstep_uni(float edge0, float edge1, vec4s x); CGLM_INLINE vec4s glms_vec4_smoothstep(vec4s edge0, vec4s edge1, vec4s x); CGLM_INLINE vec4s glms_vec4_smoothinterp(vec4s from, vec4s to, float t); CGLM_INLINE vec4s glms_vec4_smoothinterpc(vec4s from, vec4s to, float t); CGLM_INLINE vec4s glms_vec4_cubic(float s); CGLM_INLINE vec4s glms_vec4_swizzle(vec4s v, int mask); CGLM_INLINE vec4s glms_vec4_make(float * restrict src); CGLM_INLINE vec4s glms_vec4_reflect(vec4s v, vec4s n); CGLM_INLINE bool glms_vec4_refract(vec4s v, vec4s n, float eta, vec4s *dest) Deprecated: glms_vec4_step_uni --> use glms_vec4_steps */ #ifndef cglms_vec4s_h #define cglms_vec4s_h #include "../common.h" #include "../types-struct.h" #include "../util.h" #include "../vec4.h" #include "vec4-ext.h" /* DEPRECATED! */ #define glms_vec4_step_uni(edge, x) glms_vec4_steps(edge, x) #define GLMS_VEC4_ONE_INIT {GLM_VEC4_ONE_INIT} #define GLMS_VEC4_BLACK_INIT {GLM_VEC4_BLACK_INIT} #define GLMS_VEC4_ZERO_INIT {GLM_VEC4_ZERO_INIT} #define GLMS_VEC4_ONE ((vec4s)GLM_VEC4_ONE_INIT) #define GLMS_VEC4_BLACK ((vec4s)GLM_VEC4_BLACK_INIT) #define GLMS_VEC4_ZERO ((vec4s)GLM_VEC4_ZERO_INIT) /*! * @brief init vec4 using vec3 * * @param[in] v3 vector3 * @param[in] last last item * @returns destination */ CGLM_INLINE vec4s glms_vec4(vec3s v3, float last) { vec4s r; glm_vec4(v3.raw, last, r.raw); return r; } /*! * @brief copy first 3 members of [a] to [dest] * * @param[in] v source * @returns vec3 */ CGLM_INLINE vec3s glms_vec4_(copy3)(vec4s v) { vec3s r; glm_vec4_copy3(v.raw, r.raw); return r; } /*! * @brief copy all members of [a] to [dest] * * @param[in] v source * @returns destination */ CGLM_INLINE vec4s glms_vec4_(copy)(vec4s v) { vec4s r; glm_vec4_copy(v.raw, r.raw); return r; } /*! * @brief copy all members of [a] to [dest] * * alignment is not required * * @param[in] v source * @returns destination */ CGLM_INLINE vec4s glms_vec4_(ucopy)(vec4s v) { vec4s r; glm_vec4_ucopy(v.raw, r.raw); return r; } /*! * @brief pack an array of vec4 into an array of vec4s * * @param[out] dst array of vec4 * @param[in] src array of vec4s * @param[in] len number of elements */ CGLM_INLINE void glms_vec4_(pack)(vec4s dst[], vec4 src[], size_t len) { size_t i; for (i = 0; i < len; i++) { glm_vec4_copy(src[i], dst[i].raw); } } /*! * @brief unpack an array of vec4s into an array of vec4 * * @param[out] dst array of vec4s * @param[in] src array of vec4 * @param[in] len number of elements */ CGLM_INLINE void glms_vec4_(unpack)(vec4 dst[], vec4s src[], size_t len) { size_t i; for (i = 0; i < len; i++) { glm_vec4_copy(src[i].raw, dst[i]); } } /*! * @brief make vector zero * * @returns zero vector */ CGLM_INLINE vec4s glms_vec4_(zero)(void) { vec4s r; glm_vec4_zero(r.raw); return r; } /*! * @brief make vector one * * @returns one vector */ CGLM_INLINE vec4s glms_vec4_(one)(void) { vec4s r; glm_vec4_one(r.raw); return r; } /*! * @brief vec4 dot product * * @param[in] a vector1 * @param[in] b vector2 * * @return dot product */ CGLM_INLINE float glms_vec4_(dot)(vec4s a, vec4s b) { return glm_vec4_dot(a.raw, b.raw); } /*! * @brief norm * norm (magnitude) of vec * * we can use this func instead of calling norm * norm, because it would call * sqrtf function twice but with this func we can avoid func call, maybe this is * not good name for this func * * @param[in] v vec4 * * @return norm * norm */ CGLM_INLINE float glms_vec4_(norm2)(vec4s v) { return glm_vec4_norm2(v.raw); } /*! * @brief norm (magnitude) of vec4 * * @param[in] v vector * * @return norm */ CGLM_INLINE float glms_vec4_(norm)(vec4s v) { return glm_vec4_norm(v.raw); } /*! * @brief L1 norm of vec4 * Also known as Manhattan Distance or Taxicab norm. * L1 Norm is the sum of the magnitudes of the vectors in a space. * It is calculated as the sum of the absolute values of the vector components. * In this norm, all the components of the vector are weighted equally. * * This computes: * R = |v[0]| + |v[1]| + |v[2]| + |v[3]| * * @param[in] v vector * * @return L1 norm */ CGLM_INLINE float glms_vec4_(norm_one)(vec4s v) { return glm_vec4_norm_one(v.raw); } /*! * @brief Infinity norm of vec4 * Also known as Maximum norm. * Infinity Norm is the largest magnitude among each element of a vector. * It is calculated as the maximum of the absolute values of the vector components. * * This computes: * inf norm = max(|v[0]|, |v[1]|, |v[2]|, |v[3]|) * * @param[in] v vector * * @return Infinity norm */ CGLM_INLINE float glms_vec4_(norm_inf)(vec4s v) { return glm_vec4_norm_inf(v.raw); } /*! * @brief add b vector to a vector store result in dest * * @param[in] a vector1 * @param[in] b vector2 * @returns destination vector */ CGLM_INLINE vec4s glms_vec4_(add)(vec4s a, vec4s b) { vec4s r; glm_vec4_add(a.raw, b.raw, r.raw); return r; } /*! * @brief add scalar to v vector store result in dest (d = v + vec(s)) * * @param[in] v vector * @param[in] s scalar * @returns destination vector */ CGLM_INLINE vec4s glms_vec4_(adds)(vec4s v, float s) { vec4s r; glm_vec4_adds(v.raw, s, r.raw); return r; } /*! * @brief subtract b vector from a vector store result in dest (d = a - b) * * @param[in] a vector1 * @param[in] b vector2 * @returns destination vector */ CGLM_INLINE vec4s glms_vec4_(sub)(vec4s a, vec4s b) { vec4s r; glm_vec4_sub(a.raw, b.raw, r.raw); return r; } /*! * @brief subtract scalar from v vector store result in dest (d = v - vec(s)) * * @param[in] v vector * @param[in] s scalar * @returns destination vector */ CGLM_INLINE vec4s glms_vec4_(subs)(vec4s v, float s) { vec4s r; glm_vec4_subs(v.raw, s, r.raw); return r; } /*! * @brief multiply two vectors (component-wise multiplication) * * @param a vector1 * @param b vector2 * @returns dest = (a[0] * b[0], a[1] * b[1], a[2] * b[2], a[3] * b[3]) */ CGLM_INLINE vec4s glms_vec4_(mul)(vec4s a, vec4s b) { vec4s r; glm_vec4_mul(a.raw, b.raw, r.raw); return r; } /*! * @brief multiply/scale vec4 vector with scalar: result = v * s * * @param[in] v vector * @param[in] s scalar * @returns destination vector */ CGLM_INLINE vec4s glms_vec4_(scale)(vec4s v, float s) { vec4s r; glm_vec4_scale(v.raw, s, r.raw); return r; } /*! * @brief make vec4 vector scale as specified: result = unit(v) * s * * @param[in] v vector * @param[in] s scalar * @returns destination vector */ CGLM_INLINE vec4s glms_vec4_(scale_as)(vec4s v, float s) { vec4s r; glm_vec4_scale_as(v.raw, s, r.raw); return r; } /*! * @brief div vector with another component-wise division: d = a / b * * @param[in] a vector 1 * @param[in] b vector 2 * @returns result = (a[0]/b[0], a[1]/b[1], a[2]/b[2], a[3]/b[3]) */ CGLM_INLINE vec4s glms_vec4_(div)(vec4s a, vec4s b) { vec4s r; glm_vec4_div(a.raw, b.raw, r.raw); return r; } /*! * @brief div vec4 vector with scalar: d = v / s * * @param[in] v vector * @param[in] s scalar * @returns destination vector */ CGLM_INLINE vec4s glms_vec4_(divs)(vec4s v, float s) { vec4s r; glm_vec4_divs(v.raw, s, r.raw); return r; } /*! * @brief add two vectors and add result to sum * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest += (a + b) */ CGLM_INLINE vec4s glms_vec4_(addadd)(vec4s a, vec4s b, vec4s dest) { glm_vec4_addadd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief sub two vectors and add result to dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest += (a - b) */ CGLM_INLINE vec4s glms_vec4_(subadd)(vec4s a, vec4s b, vec4s dest) { glm_vec4_subadd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief mul two vectors and add result to dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest += (a * b) */ CGLM_INLINE vec4s glms_vec4_(muladd)(vec4s a, vec4s b, vec4s dest) { glm_vec4_muladd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief mul vector with scalar and add result to sum * * it applies += operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @returns dest += (a * b) */ CGLM_INLINE vec4s glms_vec4_(muladds)(vec4s a, float s, vec4s dest) { glm_vec4_muladds(a.raw, s, dest.raw); return dest; } /*! * @brief add max of two vectors to result/dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest += max(a, b) */ CGLM_INLINE vec4s glms_vec4_(maxadd)(vec4s a, vec4s b, vec4s dest) { glm_vec4_maxadd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief add min of two vectors to result/dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest += min(a, b) */ CGLM_INLINE vec4s glms_vec4_(minadd)(vec4s a, vec4s b, vec4s dest) { glm_vec4_minadd(a.raw, b.raw, dest.raw); return dest; } /*! * @brief sub two vectors and sub result to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest -= (a + b) */ CGLM_INLINE vec4s glms_vec4_(subsub)(vec4s a, vec4s b, vec4s dest) { glm_vec4_subsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief add two vectors and sub result to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest -= (a + b) */ CGLM_INLINE vec4s glms_vec4_(addsub)(vec4s a, vec4s b, vec4s dest) { glm_vec4_addsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief mul two vectors and sub result to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest -= (a * b) */ CGLM_INLINE vec4s glms_vec4_(mulsub)(vec4s a, vec4s b, vec4s dest) { glm_vec4_mulsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief mul vector with scalar and sub result to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @returns dest -= (a * b) */ CGLM_INLINE vec4s glms_vec4_(mulsubs)(vec4s a, float s, vec4s dest) { glm_vec4_mulsubs(a.raw, s, dest.raw); return dest; } /*! * @brief sub max of two vectors to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest -= max(a, b) */ CGLM_INLINE vec4s glms_vec4_(maxsub)(vec4s a, vec4s b, vec4s dest) { glm_vec4_maxsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief sub min of two vectors to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @returns dest -= min(a, b) */ CGLM_INLINE vec4s glms_vec4_(minsub)(vec4s a, vec4s b, vec4s dest) { glm_vec4_minsub(a.raw, b.raw, dest.raw); return dest; } /*! * @brief negate vector components and store result in dest * * @param[in] v vector * @returns result vector */ CGLM_INLINE vec4s glms_vec4_(negate)(vec4s v) { glm_vec4_negate(v.raw); return v; } /*! * @brief normalize vec4 and store result in same vec * * @param[in] v vector * @returns normalized vector */ CGLM_INLINE vec4s glms_vec4_(normalize)(vec4s v) { glm_vec4_normalize(v.raw); return v; } /** * @brief distance between two vectors * * @param[in] a vector1 * @param[in] b vector2 * @return returns distance */ CGLM_INLINE float glms_vec4_(distance)(vec4s a, vec4s b) { return glm_vec4_distance(a.raw, b.raw); } /** * @brief squared distance between two vectors * * @param[in] a vector1 * @param[in] b vector2 * @return returns squared distance */ CGLM_INLINE float glms_vec4_(distance2)(vec4s a, vec4s b) { return glm_vec4_distance2(a.raw, b.raw); } /*! * @brief max values of vectors * * @param[in] a vector1 * @param[in] b vector2 * @returns destination */ CGLM_INLINE vec4s glms_vec4_(maxv)(vec4s a, vec4s b) { vec4s r; glm_vec4_maxv(a.raw, b.raw, r.raw); return r; } /*! * @brief min values of vectors * * @param[in] a vector1 * @param[in] b vector2 * @returns destination */ CGLM_INLINE vec4s glms_vec4_(minv)(vec4s a, vec4s b) { vec4s r; glm_vec4_minv(a.raw, b.raw, r.raw); return r; } /*! * @brief clamp vector's individual members between min and max values * * @param[in] v vector * @param[in] minVal minimum value * @param[in] maxVal maximum value * @returns clamped vector */ CGLM_INLINE vec4s glms_vec4_(clamp)(vec4s v, float minVal, float maxVal) { glm_vec4_clamp(v.raw, minVal, maxVal); return v; } /*! * @brief linear interpolation between two vectors * * formula: from + s * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) * @returns destination */ CGLM_INLINE vec4s glms_vec4_(lerp)(vec4s from, vec4s to, float t) { vec4s r; glm_vec4_lerp(from.raw, to.raw, t, r.raw); return r; } /*! * @brief linear interpolation between two vectors (clamped) * * formula: from + s * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) clamped between 0 and 1 * @returns destination */ CGLM_INLINE vec4s glms_vec4_(lerpc)(vec4s from, vec4s to, float t) { vec4s r; glm_vec4_lerpc(from.raw, to.raw, t, r.raw); return r; } /*! * @brief linear interpolation between two vectors * * formula: from + s * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) * @returns destination */ CGLM_INLINE vec4s glms_vec4_(mix)(vec4s from, vec4s to, float t) { vec4s r; glm_vec4_mix(from.raw, to.raw, t, r.raw); return r; } /*! * @brief linear interpolation between two vectors (clamped) * * formula: from + s * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) clamped between 0 and 1 * @returns destination */ CGLM_INLINE vec4s glms_vec4_(mixc)(vec4s from, vec4s to, float t) { vec4s r; glm_vec4_mixc(from.raw, to.raw, t, r.raw); return r; } /*! * @brief threshold function * * @param[in] edge threshold * @param[in] x value to test against threshold * @returns 0.0 if x < edge, else 1.0 */ CGLM_INLINE vec4s glms_vec4_(step)(vec4s edge, vec4s x) { vec4s r; glm_vec4_step(edge.raw, x.raw, r.raw); return r; } /*! * @brief threshold function with a smooth transition (unidimensional) * * @param[in] edge0 low threshold * @param[in] edge1 high threshold * @param[in] x value to test against threshold * @returns destination */ CGLM_INLINE vec4s glms_vec4_(smoothstep_uni)(float edge0, float edge1, vec4s x) { vec4s r; glm_vec4_smoothstep_uni(edge0, edge1, x.raw, r.raw); return r; } /*! * @brief threshold function with a smooth transition * * @param[in] edge0 low threshold * @param[in] edge1 high threshold * @param[in] x value to test against threshold * @returns destination */ CGLM_INLINE vec4s glms_vec4_(smoothstep)(vec4s edge0, vec4s edge1, vec4s x) { vec4s r; glm_vec4_smoothstep(edge0.raw, edge1.raw, x.raw, r.raw); return r; } /*! * @brief smooth Hermite interpolation between two vectors * * formula: from + s * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) * @returns destination */ CGLM_INLINE vec4s glms_vec4_(smoothinterp)(vec4s from, vec4s to, float t) { vec4s r; glm_vec4_smoothinterp(from.raw, to.raw, t, r.raw); return r; } /*! * @brief smooth Hermite interpolation between two vectors (clamped) * * formula: from + s * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) clamped between 0 and 1 * @returns destination */ CGLM_INLINE vec4s glms_vec4_(smoothinterpc)(vec4s from, vec4s to, float t) { vec4s r; glm_vec4_smoothinterpc(from.raw, to.raw, t, r.raw); return r; } /*! * @brief helper to fill vec4 as [S^3, S^2, S, 1] * * @param[in] s parameter * @returns destination */ CGLM_INLINE vec4s glms_vec4_(cubic)(float s) { vec4s r; glm_vec4_cubic(s, r.raw); return r; } /*! * @brief swizzle vector components * * you can use existing masks e.g. GLM_XXXX, GLM_WZYX * * @param[in] v source * @param[in] mask mask * @returns swizzled vector */ CGLM_INLINE vec4s glms_vec4_(swizzle)(vec4s v, int mask) { vec4s dest; glm_vec4_swizzle(v.raw, mask, dest.raw); return dest; } /*! * @brief Create four dimensional vector from pointer * * @param[in] src pointer to an array of floats * @returns constructed 4D vector from raw pointer */ CGLM_INLINE vec4s glms_vec4_(make)(const float * __restrict src) { vec4s dest; glm_vec4_make(src, dest.raw); return dest; } /*! * @brief reflection vector using an incident ray and a surface normal * * @param[in] v incident vector * @param[in] n normalized normal vector * @returns reflection result */ CGLM_INLINE vec4s glms_vec4_(reflect)(vec4s v, vec4s n) { vec4s dest; glm_vec4_reflect(v.raw, n.raw, dest.raw); return dest; } /*! * @brief computes refraction vector for an incident vector and a surface normal. * * calculates the refraction vector based on Snell's law. If total internal reflection * occurs (angle too great given eta), dest is set to zero and returns false. * Otherwise, computes refraction vector, stores it in dest, and returns true. * * this implementation does not explicitly preserve the 'w' component of the * incident vector 'I' in the output 'dest', users requiring the preservation of * the 'w' component should manually adjust 'dest' after calling this function. * * @param[in] v normalized incident vector * @param[in] n normalized normal vector * @param[in] eta ratio of indices of refraction (incident/transmitted) * @param[out] dest refraction vector if refraction occurs; zero vector otherwise * * @returns true if refraction occurs; false if total internal reflection occurs. */ CGLM_INLINE bool glms_vec4_(refract)(vec4s v, vec4s n, float eta, vec4s * __restrict dest) { return glm_vec4_refract(v.raw, n.raw, eta, dest->raw); } #endif /* cglms_vec4s_h */ cglm-0.9.7/include/cglm/types-struct.h000066400000000000000000000135501526744317200176740ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_types_struct_h #define cglm_types_struct_h #include "types.h" /* * Anonymous structs are available since C11, but we'd like to be compatible * with C99 and C89 too. So let's figure out if we should be using them or not. * It's simply a convenience feature, you can e.g. build the library with * anonymous structs and your application without them and they'll still be * compatible, cglm doesn't use the anonymous structs internally. */ #ifndef CGLM_USE_ANONYMOUS_STRUCT /* If the user doesn't explicitly specify if they want anonymous structs or * not, then we'll try to intuit an appropriate choice. */ # if defined(CGLM_NO_ANONYMOUS_STRUCT) /* The user has defined CGLM_NO_ANONYMOUS_STRUCT. This used to be the * only #define governing the use of anonymous structs, so for backward * compatibility, we still honor that choice and disable them. */ # define CGLM_USE_ANONYMOUS_STRUCT 0 /* Disable anonymous structs if strict ANSI mode is enabled for C89 or C99 */ # elif defined(__STRICT_ANSI__) && \ (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 201112L)) /* __STRICT_ANSI__ is defined and we're in C89 * or C99 mode (C11 or later not detected) */ # define CGLM_USE_ANONYMOUS_STRUCT 0 # elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || \ (defined(__cplusplus) && __cplusplus >= 201103L) /* We're compiling for C11 or this is the MSVC compiler. In either * case, anonymous structs are available, so use them. */ # define CGLM_USE_ANONYMOUS_STRUCT 1 # elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) /* GCC 4.6 and onwards support anonymous structs as an extension */ # define CGLM_USE_ANONYMOUS_STRUCT 1 # elif defined(__clang__) && __clang_major__ >= 3 /* Clang 3.0 and onwards support anonymous structs as an extension */ # define CGLM_USE_ANONYMOUS_STRUCT 1 # elif defined(_MSC_VER) && (_MSC_VER >= 1900) /* Visual Studio 2015 */ /* We can support anonymous structs * since Visual Studio 2015 or 2017 (1910) maybe? */ # define CGLM_USE_ANONYMOUS_STRUCT 1 # else /* Otherwise, we're presumably building for C99 or C89 and can't rely * on anonymous structs being available. Turn them off. */ # define CGLM_USE_ANONYMOUS_STRUCT 0 # endif #endif typedef union vec2s { vec2 raw; #if CGLM_USE_ANONYMOUS_STRUCT struct { float x; float y; }; struct { float r; float i; }; struct { float u; float v; }; struct { float s; float t; }; #endif } vec2s; typedef union vec3s { vec3 raw; #if CGLM_USE_ANONYMOUS_STRUCT struct { float x; float y; float z; }; struct { float r; float g; float b; }; #endif } vec3s; typedef union ivec2s { ivec2 raw; #if CGLM_USE_ANONYMOUS_STRUCT struct { int x; int y; }; struct { int r; int i; }; struct { int u; int v; }; struct { int s; int t; }; #endif } ivec2s; typedef union ivec3s { ivec3 raw; #if CGLM_USE_ANONYMOUS_STRUCT struct { int x; int y; int z; }; struct { int r; int g; int b; }; #endif } ivec3s; typedef union ivec4s { ivec4 raw; #if CGLM_USE_ANONYMOUS_STRUCT struct { int x; int y; int z; int w; }; struct { int r; int g; int b; int a; }; #endif } ivec4s; typedef union CGLM_ALIGN_IF(16) vec4s { vec4 raw; #if CGLM_USE_ANONYMOUS_STRUCT struct { float x; float y; float z; float w; }; struct { float r; float g; float b; float a; }; #endif } vec4s; typedef union CGLM_ALIGN_IF(16) versors { vec4 raw; #if CGLM_USE_ANONYMOUS_STRUCT struct { float x; float y; float z; float w; }; struct { vec3s imag; float real; }; #endif } versors; typedef union mat2s { mat2 raw; vec2s col[2]; #if CGLM_USE_ANONYMOUS_STRUCT struct { float m00, m01; float m10, m11; }; #endif } mat2s; typedef union mat2x3s { mat2x3 raw; vec3s col[2]; /* [col (2), row (3)] */ #if CGLM_USE_ANONYMOUS_STRUCT struct { float m00, m01, m02; float m10, m11, m12; }; #endif } mat2x3s; typedef union mat2x4s { mat2x4 raw; vec4s col[2]; /* [col (2), row (4)] */ #if CGLM_USE_ANONYMOUS_STRUCT struct { float m00, m01, m02, m03; float m10, m11, m12, m13; }; #endif } mat2x4s; typedef union mat3s { mat3 raw; vec3s col[3]; #if CGLM_USE_ANONYMOUS_STRUCT struct { float m00, m01, m02; float m10, m11, m12; float m20, m21, m22; }; #endif } mat3s; typedef union mat3x2s { mat3x2 raw; vec2s col[3]; /* [col (3), row (2)] */ #if CGLM_USE_ANONYMOUS_STRUCT struct { float m00, m01; float m10, m11; float m20, m21; }; #endif } mat3x2s; typedef union mat3x4s { mat3x4 raw; vec4s col[3]; /* [col (3), row (4)] */ #if CGLM_USE_ANONYMOUS_STRUCT struct { float m00, m01, m02, m03; float m10, m11, m12, m13; float m20, m21, m22, m23; }; #endif } mat3x4s; typedef union CGLM_ALIGN_MAT mat4s { mat4 raw; vec4s col[4]; #if CGLM_USE_ANONYMOUS_STRUCT struct { float m00, m01, m02, m03; float m10, m11, m12, m13; float m20, m21, m22, m23; float m30, m31, m32, m33; }; #endif } mat4s; typedef union mat4x2s { mat4x2 raw; vec2s col[4]; /* [col (4), row (2)] */ #if CGLM_USE_ANONYMOUS_STRUCT struct { float m00, m01; float m10, m11; float m20, m21; float m30, m31; }; #endif } mat4x2s; typedef union mat4x3s { mat4x3 raw; vec3s col[4]; /* [col (4), row (3)] */ #if CGLM_USE_ANONYMOUS_STRUCT struct { float m00, m01, m02; float m10, m11, m12; float m20, m21, m22; float m30, m31, m32; }; #endif } mat4x3s; #endif /* cglm_types_struct_h */ cglm-0.9.7/include/cglm/types.h000066400000000000000000000140071526744317200163500ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_types_h #define cglm_types_h #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) # include #endif #if defined(_MSC_VER) /* do not use alignment for older visual studio versions */ /* also ARM32 also causes similar error, disable it for now on ARM32 too */ # if _MSC_VER < 1913 || _M_ARM /* Visual Studio 2017 version 15.6 */ # define CGLM_ALL_UNALIGNED # define CGLM_ALIGN(X) /* no alignment */ # else # define CGLM_ALIGN(X) __declspec(align(X)) # endif #else # define CGLM_ALIGN(X) __attribute((aligned(X))) #endif #ifndef CGLM_ALL_UNALIGNED # define CGLM_ALIGN_IF(X) CGLM_ALIGN(X) #else # define CGLM_ALIGN_IF(X) /* no alignment */ #endif #ifdef __AVX__ # define CGLM_ALIGN_MAT CGLM_ALIGN(32) #else # define CGLM_ALIGN_MAT CGLM_ALIGN(16) #endif #ifndef CGLM_HAVE_BUILTIN_ASSUME_ALIGNED # if defined(__has_builtin) # if __has_builtin(__builtin_assume_aligned) # define CGLM_HAVE_BUILTIN_ASSUME_ALIGNED 1 # endif # elif defined(__GNUC__) && defined(__GNUC_MINOR__) # if __GNUC__ >= 4 && __GNUC_MINOR__ >= 7 # define CGLM_HAVE_BUILTIN_ASSUME_ALIGNED 1 # endif # endif # ifndef CGLM_HAVE_BUILTIN_ASSUME_ALIGNED # define CGLM_HAVE_BUILTIN_ASSUME_ALIGNED 0 # endif #endif #if CGLM_HAVE_BUILTIN_ASSUME_ALIGNED # define CGLM_ASSUME_ALIGNED(expr, alignment) \ __builtin_assume_aligned((expr), (alignment)) #else # define CGLM_ASSUME_ALIGNED(expr, alignment) (expr) #endif #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) # define CGLM_CASTPTR_ASSUME_ALIGNED(expr, type) \ ((type*)CGLM_ASSUME_ALIGNED((expr), alignof(type))) #elif defined(_MSC_VER) # define CGLM_CASTPTR_ASSUME_ALIGNED(expr, type) \ ((type*)CGLM_ASSUME_ALIGNED((expr), __alignof(type))) #else # define CGLM_CASTPTR_ASSUME_ALIGNED(expr, type) \ ((type*)CGLM_ASSUME_ALIGNED((expr), __alignof__(type))) #endif typedef int ivec2[2]; typedef int ivec3[3]; typedef int ivec4[4]; typedef float vec2[2]; typedef float vec3[3]; typedef CGLM_ALIGN_IF(16) float vec4[4]; typedef vec4 versor; /* |x, y, z, w| -> w is the last */ typedef vec3 mat3[3]; typedef vec2 mat3x2[3]; /* [col (3), row (2)] */ typedef vec4 mat3x4[3]; /* [col (3), row (4)] */ typedef CGLM_ALIGN_IF(16) vec2 mat2[2]; typedef vec3 mat2x3[2]; /* [col (2), row (3)] */ typedef vec4 mat2x4[2]; /* [col (2), row (4)] */ typedef CGLM_ALIGN_MAT vec4 mat4[4]; typedef vec2 mat4x2[4]; /* [col (4), row (2)] */ typedef vec3 mat4x3[4]; /* [col (4), row (3)] */ /*! * if you have axis order like vec3 orderVec = [0, 1, 2] or [0, 2, 1]... * vector then you can convert it to this enum by doing this: * @code * glm_euler_seq order; * order = orderVec[0] | orderVec[1] << 2 | orderVec[2] << 4; * @endcode * you may need to explicit cast if required */ typedef enum glm_euler_seq { GLM_EULER_XYZ = 0 << 0 | 1 << 2 | 2 << 4, GLM_EULER_XZY = 0 << 0 | 2 << 2 | 1 << 4, GLM_EULER_YZX = 1 << 0 | 2 << 2 | 0 << 4, GLM_EULER_YXZ = 1 << 0 | 0 << 2 | 2 << 4, GLM_EULER_ZXY = 2 << 0 | 0 << 2 | 1 << 4, GLM_EULER_ZYX = 2 << 0 | 1 << 2 | 0 << 4 } glm_euler_seq; /* Important: cglm stores quaternion as [x, y, z, w] in memory since v0.4.0 it was [w, x, y, z] before v0.4.0 ( v0.3.5 and earlier ). w is real part. */ #define GLM_E 2.71828182845904523536028747135266250 /* e */ #define GLM_LOG2E 1.44269504088896340735992468100189214 /* log2(e) */ #define GLM_LOG10E 0.434294481903251827651128918916605082 /* log10(e) */ #define GLM_LN2 0.693147180559945309417232121458176568 /* loge(2) */ #define GLM_LN10 2.30258509299404568401799145468436421 /* loge(10) */ #define GLM_PI 3.14159265358979323846264338327950288 /* pi */ #define GLM_PI_2 1.57079632679489661923132169163975144 /* pi/2 */ #define GLM_PI_4 0.785398163397448309615660845819875721 /* pi/4 */ #define GLM_1_PI 0.318309886183790671537767526745028724 /* 1/pi */ #define GLM_2_PI 0.636619772367581343075535053490057448 /* 2/pi */ #define GLM_TAU 6.283185307179586476925286766559005768 /* tau */ #define GLM_TAU_2 GLM_PI /* tau/2 */ #define GLM_TAU_4 GLM_PI_2 /* tau/4 */ #define GLM_1_TAU 0.159154943091895335768883763372514362 /* 1/tau */ #define GLM_2_TAU 0.318309886183790671537767526745028724 /* 2/tau */ #define GLM_2_SQRTPI 1.12837916709551257389615890312154517 /* 2/sqrt(pi) */ #define GLM_SQRTTAU 2.506628274631000502415765284811045253 /* sqrt(tau) */ #define GLM_SQRT2 1.41421356237309504880168872420969808 /* sqrt(2) */ #define GLM_SQRT1_2 0.707106781186547524400844362104849039 /* 1/sqrt(2) */ #define GLM_Ef ((float)GLM_E) #define GLM_LOG2Ef ((float)GLM_LOG2E) #define GLM_LOG10Ef ((float)GLM_LOG10E) #define GLM_LN2f ((float)GLM_LN2) #define GLM_LN10f ((float)GLM_LN10) #define GLM_PIf ((float)GLM_PI) #define GLM_PI_2f ((float)GLM_PI_2) #define GLM_PI_4f ((float)GLM_PI_4) #define GLM_1_PIf ((float)GLM_1_PI) #define GLM_2_PIf ((float)GLM_2_PI) #define GLM_TAUf ((float)GLM_TAU) #define GLM_TAU_2f ((float)GLM_TAU_2) #define GLM_TAU_4f ((float)GLM_TAU_4) #define GLM_1_TAUf ((float)GLM_1_TAU) #define GLM_2_TAUf ((float)GLM_2_TAU) #define GLM_2_SQRTPIf ((float)GLM_2_SQRTPI) #define GLM_2_SQRTTAUf ((float)GLM_SQRTTAU) #define GLM_SQRT2f ((float)GLM_SQRT2) #define GLM_SQRT1_2f ((float)GLM_SQRT1_2) /* DEPRECATED! use GLM_PI and friends */ #define CGLM_PI GLM_PIf #define CGLM_PI_2 GLM_PI_2f #define CGLM_PI_4 GLM_PI_4f #endif /* cglm_types_h */ cglm-0.9.7/include/cglm/util.h000066400000000000000000000170471526744317200161700ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE int glm_sign(int val); CGLM_INLINE float glm_signf(float val); CGLM_INLINE float glm_rad(float deg); CGLM_INLINE float glm_deg(float rad); CGLM_INLINE void glm_make_rad(float *deg); CGLM_INLINE void glm_make_deg(float *rad); CGLM_INLINE float glm_pow2(float x); CGLM_INLINE float glm_min(float a, float b); CGLM_INLINE float glm_max(float a, float b); CGLM_INLINE float glm_clamp(float val, float minVal, float maxVal); CGLM_INLINE float glm_clamp_zo(float val, float minVal, float maxVal); CGLM_INLINE float glm_lerp(float from, float to, float t); CGLM_INLINE float glm_lerpc(float from, float to, float t); CGLM_INLINE float glm_step(float edge, float x); CGLM_INLINE float glm_smooth(float t); CGLM_INLINE float glm_smoothstep(float edge0, float edge1, float x); CGLM_INLINE float glm_smoothinterp(float from, float to, float t); CGLM_INLINE float glm_smoothinterpc(float from, float to, float t); CGLM_INLINE bool glm_eq(float a, float b); CGLM_INLINE float glm_percent(float from, float to, float current); CGLM_INLINE float glm_percentc(float from, float to, float current); */ #ifndef cglm_util_h #define cglm_util_h #include "common.h" #define GLM_MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) #define GLM_MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) /*! * @brief get sign of 32 bit integer as +1, -1, 0 * * Important: It returns 0 for zero input * * @param val integer value */ CGLM_INLINE int glm_sign(int val) { return ((val >> 31) - (-val >> 31)); } /*! * @brief get sign of 32 bit float as +1, -1, 0 * * Important: It returns 0 for zero/NaN input * * @param val float value */ CGLM_INLINE float glm_signf(float val) { return (float)((val > 0.0f) - (val < 0.0f)); } /*! * @brief convert degree to radians * * @param[in] deg angle in degrees */ CGLM_INLINE float glm_rad(float deg) { return deg * GLM_PIf / 180.0f; } /*! * @brief convert radians to degree * * @param[in] rad angle in radians */ CGLM_INLINE float glm_deg(float rad) { return rad * 180.0f / GLM_PIf; } /*! * @brief convert existing degree to radians. this will override degrees value * * @param[in, out] deg pointer to angle in degrees */ CGLM_INLINE void glm_make_rad(float *deg) { *deg = *deg * GLM_PIf / 180.0f; } /*! * @brief convert existing radians to degree. this will override radians value * * @param[in, out] rad pointer to angle in radians */ CGLM_INLINE void glm_make_deg(float *rad) { *rad = *rad * 180.0f / GLM_PIf; } /*! * @brief multiplies given parameter with itself = x * x or powf(x, 2) * * @param[in] x x */ CGLM_INLINE float glm_pow2(float x) { return x * x; } /*! * @brief find minimum of given two values * * @param[in] a number 1 * @param[in] b number 2 */ CGLM_INLINE float glm_min(float a, float b) { if (a < b) return a; return b; } /*! * @brief find maximum of given two values * * @param[in] a number 1 * @param[in] b number 2 */ CGLM_INLINE float glm_max(float a, float b) { if (a > b) return a; return b; } /*! * @brief find minimum of given two values * * @param[in] a number 1 * @param[in] b number 2 * * @return smallest of the two values */ CGLM_INLINE int glm_imin(int a, int b) { if (a < b) return a; return b; } /*! * @brief find maximum of given two values * * @param[in] a number 1 * @param[in] b number 2 * * @return largest of the two values */ CGLM_INLINE int glm_imax(int a, int b) { if (a > b) return a; return b; } /*! * @brief clamp a number between min and max * * @param[in] val value to clamp * @param[in] minVal minimum value * @param[in] maxVal maximum value */ CGLM_INLINE float glm_clamp(float val, float minVal, float maxVal) { return glm_min(glm_max(val, minVal), maxVal); } /*! * @brief clamp a number to zero and one * * @param[in] val value to clamp */ CGLM_INLINE float glm_clamp_zo(float val) { return glm_clamp(val, 0.0f, 1.0f); } /*! * @brief linear interpolation between two numbers * * formula: from + t * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) */ CGLM_INLINE float glm_lerp(float from, float to, float t) { return from + t * (to - from); } /*! * @brief clamped linear interpolation between two numbers * * formula: from + t * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) clamped between 0 and 1 */ CGLM_INLINE float glm_lerpc(float from, float to, float t) { return glm_lerp(from, to, glm_clamp_zo(t)); } /*! * @brief threshold function * * @param[in] edge threshold * @param[in] x value to test against threshold * @return returns 0.0 if x < edge, else 1.0 */ CGLM_INLINE float glm_step(float edge, float x) { /* branching - no type conversion */ return (x < edge) ? 0.0f : 1.0f; /* * An alternative implementation without branching * but with type conversion could be: * return !(x < edge); */ } /*! * @brief smooth Hermite interpolation * * formula: t^2 * (3-2t) * * @param[in] t interpolant (amount) */ CGLM_INLINE float glm_smooth(float t) { return t * t * (3.0f - 2.0f * t); } /*! * @brief threshold function with a smooth transition (according to OpenCL specs) * * formula: t^2 * (3-2t) * * @param[in] edge0 low threshold * @param[in] edge1 high threshold * @param[in] x interpolant (amount) */ CGLM_INLINE float glm_smoothstep(float edge0, float edge1, float x) { float t; t = glm_clamp_zo((x - edge0) / (edge1 - edge0)); return glm_smooth(t); } /*! * @brief smoothstep interpolation between two numbers * * formula: from + smoothstep(t) * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) */ CGLM_INLINE float glm_smoothinterp(float from, float to, float t) { return from + glm_smooth(t) * (to - from); } /*! * @brief clamped smoothstep interpolation between two numbers * * formula: from + smoothstep(t) * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) clamped between 0 and 1 */ CGLM_INLINE float glm_smoothinterpc(float from, float to, float t) { return glm_smoothinterp(from, to, glm_clamp_zo(t)); } /*! * @brief check if two float equal with using EPSILON * * @param[in] a a * @param[in] b b */ CGLM_INLINE bool glm_eq(float a, float b) { return fabsf(a - b) <= GLM_FLT_EPSILON; } /*! * @brief percentage of current value between start and end value * * maybe fraction could be alternative name. * * @param[in] from from value * @param[in] to to value * @param[in] current current value */ CGLM_INLINE float glm_percent(float from, float to, float current) { float t; if ((t = to - from) == 0.0f) return 1.0f; return (current - from) / t; } /*! * @brief clamped percentage of current value between start and end value * * @param[in] from from value * @param[in] to to value * @param[in] current current value */ CGLM_INLINE float glm_percentc(float from, float to, float current) { return glm_clamp_zo(glm_percent(from, to, current)); } /*! * @brief swap two float values * * @param[in] a float value 1 (pointer) * @param[in] b float value 2 (pointer) */ CGLM_INLINE void glm_swapf(float * __restrict a, float * __restrict b) { float t; t = *a; *a = *b; *b = t; } #endif /* cglm_util_h */ cglm-0.9.7/include/cglm/vec2-ext.h000066400000000000000000000162551526744317200166500ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Functions: CGLM_INLINE void glm_vec2_fill(vec2 v, float val) CGLM_INLINE bool glm_vec2_eq(vec2 v, float val); CGLM_INLINE bool glm_vec2_eq_eps(vec2 v, float val); CGLM_INLINE bool glm_vec2_eq_all(vec2 v); CGLM_INLINE bool glm_vec2_eqv(vec2 a, vec2 b); CGLM_INLINE bool glm_vec2_eqv_eps(vec2 a, vec2 b); CGLM_INLINE float glm_vec2_max(vec2 v); CGLM_INLINE float glm_vec2_min(vec2 v); CGLM_INLINE bool glm_vec2_isnan(vec2 v); CGLM_INLINE bool glm_vec2_isinf(vec2 v); CGLM_INLINE bool glm_vec2_isvalid(vec2 v); CGLM_INLINE void glm_vec2_sign(vec2 v, vec2 dest); CGLM_INLINE void glm_vec2_abs(vec2 v, vec2 dest); CGLM_INLINE void glm_vec2_fract(vec2 v, vec2 dest); CGLM_INLINE void glm_vec2_floor(vec2 v, vec2 dest); CGLM_INLINE float glm_vec2_mods(vec2 v, float s, vec2 dest); CGLM_INLINE float glm_vec2_steps(float edge, vec2 v, vec2 dest); CGLM_INLINE void glm_vec2_stepr(vec2 edge, float v, vec2 dest); CGLM_INLINE void glm_vec2_sqrt(vec2 v, vec2 dest); CGLM_INLINE void glm_vec2_complex_mul(vec2 a, vec2 b, vec2 dest) CGLM_INLINE void glm_vec2_complex_div(vec2 a, vec2 b, vec2 dest) CGLM_INLINE void glm_vec2_complex_conjugate(vec2 a, vec2 dest) */ #ifndef cglm_vec2_ext_h #define cglm_vec2_ext_h #include "common.h" #include "util.h" /*! * @brief fill a vector with specified value * * @param[out] v dest * @param[in] val value */ CGLM_INLINE void glm_vec2_fill(vec2 v, float val) { v[0] = v[1] = val; } /*! * @brief check if vector is equal to value (without epsilon) * * @param[in] v vector * @param[in] val value */ CGLM_INLINE bool glm_vec2_eq(vec2 v, float val) { return v[0] == val && v[0] == v[1]; } /*! * @brief check if vector is equal to value (with epsilon) * * @param[in] v vector * @param[in] val value */ CGLM_INLINE bool glm_vec2_eq_eps(vec2 v, float val) { return fabsf(v[0] - val) <= GLM_FLT_EPSILON && fabsf(v[1] - val) <= GLM_FLT_EPSILON; } /*! * @brief check if vector members are equal (without epsilon) * * @param[in] v vector */ CGLM_INLINE bool glm_vec2_eq_all(vec2 v) { return glm_vec2_eq_eps(v, v[0]); } /*! * @brief check if vector is equal to another (without epsilon) * * @param[in] a vector * @param[in] b vector */ CGLM_INLINE bool glm_vec2_eqv(vec2 a, vec2 b) { return a[0] == b[0] && a[1] == b[1]; } /*! * @brief check if vector is equal to another (with epsilon) * * @param[in] a vector * @param[in] b vector */ CGLM_INLINE bool glm_vec2_eqv_eps(vec2 a, vec2 b) { return fabsf(a[0] - b[0]) <= GLM_FLT_EPSILON && fabsf(a[1] - b[1]) <= GLM_FLT_EPSILON; } /*! * @brief max value of vector * * @param[in] v vector */ CGLM_INLINE float glm_vec2_max(vec2 v) { return glm_max(v[0], v[1]); } /*! * @brief min value of vector * * @param[in] v vector */ CGLM_INLINE float glm_vec2_min(vec2 v) { return glm_min(v[0], v[1]); } /*! * @brief check if one of items is NaN (not a number) * you should only use this in DEBUG mode or very critical asserts * * @param[in] v vector */ CGLM_INLINE bool glm_vec2_isnan(vec2 v) { #ifndef CGLM_FAST_MATH return isnan(v[0]) || isnan(v[1]); #else (void)v; return false; #endif } /*! * @brief check if one of items is INFINITY * you should only use this in DEBUG mode or very critical asserts * * @param[in] v vector */ CGLM_INLINE bool glm_vec2_isinf(vec2 v) { #ifndef CGLM_FAST_MATH return isinf(v[0]) || isinf(v[1]); #else (void)v; return false; #endif } /*! * @brief check if all items are valid number * you should only use this in DEBUG mode or very critical asserts * * @param[in] v vector */ CGLM_INLINE bool glm_vec2_isvalid(vec2 v) { return !glm_vec2_isnan(v) && !glm_vec2_isinf(v); } /*! * @brief get sign of 32 bit float as +1, -1, 0 * * Important: It returns 0 for zero/NaN input * * @param v vector */ CGLM_INLINE void glm_vec2_sign(vec2 v, vec2 dest) { dest[0] = glm_signf(v[0]); dest[1] = glm_signf(v[1]); } /*! * @brief absolute value of v * * @param[in] v vector * @param[out] dest destination */ CGLM_INLINE void glm_vec2_abs(vec2 v, vec2 dest) { dest[0] = fabsf(v[0]); dest[1] = fabsf(v[1]); } /*! * @brief fractional part of each vector item * * @param[in] v vector * @param[out] dest destination vector */ CGLM_INLINE void glm_vec2_fract(vec2 v, vec2 dest) { dest[0] = fminf(v[0] - floorf(v[0]), 0.999999940395355224609375f); dest[1] = fminf(v[1] - floorf(v[1]), 0.999999940395355224609375f); } /*! * @brief floor of each vector item * * @param[in] v vector * @param[out] dest destination vector */ CGLM_INLINE void glm_vec2_floor(vec2 v, vec2 dest) { dest[0] = floorf(v[0]); dest[1] = floorf(v[1]); } /*! * @brief mod of each vector item, result is written to dest (dest = v % s) * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination vector */ CGLM_INLINE void glm_vec2_mods(vec2 v, float s, vec2 dest) { dest[0] = fmodf(v[0], s); dest[1] = fmodf(v[1], s); } /*! * @brief square root of each vector item * * @param[in] v vector * @param[out] dest destination vector */ CGLM_INLINE void glm_vec2_sqrt(vec2 v, vec2 dest) { dest[0] = sqrtf(v[0]); dest[1] = sqrtf(v[1]); } /*! * @brief treat vectors as complex numbers and multiply them as such. * * @param[in] a left number * @param[in] b right number * @param[out] dest destination number */ CGLM_INLINE void glm_vec2_complex_mul(vec2 a, vec2 b, vec2 dest) { float tr, ti; tr = a[0] * b[0] - a[1] * b[1]; ti = a[0] * b[1] + a[1] * b[0]; dest[0] = tr; dest[1] = ti; } /*! * @brief threshold each vector item with scalar * condition is: (x[i] < edge) ? 0.0 : 1.0 * * @param[in] edge threshold * @param[in] x vector to test against threshold * @param[out] dest destination */ CGLM_INLINE void glm_vec2_steps(float edge, vec2 x, vec2 dest) { dest[0] = glm_step(edge, x[0]); dest[1] = glm_step(edge, x[1]); } /*! * @brief threshold a value with *vector* as the threshold * condition is: (x < edge[i]) ? 0.0 : 1.0 * * @param[in] edge threshold vector * @param[in] x value to test against threshold * @param[out] dest destination */ CGLM_INLINE void glm_vec2_stepr(vec2 edge, float x, vec2 dest) { dest[0] = glm_step(edge[0], x); dest[1] = glm_step(edge[1], x); } /*! * @brief treat vectors as complex numbers and divide them as such. * * @param[in] a left number (numerator) * @param[in] b right number (denominator) * @param[out] dest destination number */ CGLM_INLINE void glm_vec2_complex_div(vec2 a, vec2 b, vec2 dest) { float tr, ti; float const ibnorm2 = 1.0f / (b[0] * b[0] + b[1] * b[1]); tr = ibnorm2 * (a[0] * b[0] + a[1] * b[1]); ti = ibnorm2 * (a[1] * b[0] - a[0] * b[1]); dest[0] = tr; dest[1] = ti; } /*! * @brief treat the vector as a complex number and conjugate it as such. * * @param[in] a the number * @param[out] dest destination number */ CGLM_INLINE void glm_vec2_complex_conjugate(vec2 a, vec2 dest) { dest[0] = a[0]; dest[1] = -a[1]; } #endif /* cglm_vec2_ext_h */ cglm-0.9.7/include/cglm/vec2.h000066400000000000000000000431341526744317200160460ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLM_VEC2_ONE_INIT GLM_VEC2_ZERO_INIT GLM_VEC2_ONE GLM_VEC2_ZERO Functions: CGLM_INLINE void glm_vec2(float * __restrict v, vec2 dest) CGLM_INLINE void glm_vec2_copy(vec2 a, vec2 dest) CGLM_INLINE void glm_vec2_zero(vec2 v) CGLM_INLINE void glm_vec2_one(vec2 v) CGLM_INLINE float glm_vec2_dot(vec2 a, vec2 b) CGLM_INLINE float glm_vec2_cross(vec2 a, vec2 b) CGLM_INLINE float glm_vec2_norm2(vec2 v) CGLM_INLINE float glm_vec2_norm(vec2 vec) CGLM_INLINE void glm_vec2_add(vec2 a, vec2 b, vec2 dest) CGLM_INLINE void glm_vec2_adds(vec2 v, float s, vec2 dest) CGLM_INLINE void glm_vec2_sub(vec2 a, vec2 b, vec2 dest) CGLM_INLINE void glm_vec2_subs(vec2 v, float s, vec2 dest) CGLM_INLINE void glm_vec2_mul(vec2 a, vec2 b, vec2 d) CGLM_INLINE void glm_vec2_scale(vec2 v, float s, vec2 dest) CGLM_INLINE void glm_vec2_scale_as(vec2 v, float s, vec2 dest) CGLM_INLINE void glm_vec2_div(vec2 a, vec2 b, vec2 dest) CGLM_INLINE void glm_vec2_divs(vec2 v, float s, vec2 dest) CGLM_INLINE void glm_vec2_addadd(vec2 a, vec2 b, vec2 dest) CGLM_INLINE void glm_vec2_subadd(vec2 a, vec2 b, vec2 dest) CGLM_INLINE void glm_vec2_muladd(vec2 a, vec2 b, vec2 dest) CGLM_INLINE void glm_vec2_muladds(vec2 a, float s, vec2 dest) CGLM_INLINE void glm_vec2_maxadd(vec2 a, vec2 b, vec2 dest) CGLM_INLINE void glm_vec2_minadd(vec2 a, vec2 b, vec2 dest) CGLM_INLINE void glm_vec2_subsub(vec2 a, vec2 b, vec2 dest) CGLM_INLINE void glm_vec2_addsub(vec2 a, vec2 b, vec2 dest) CGLM_INLINE void glm_vec2_mulsub(vec2 a, vec2 b, vec2 dest) CGLM_INLINE void glm_vec2_mulsubs(vec2 a, float s, vec2 dest) CGLM_INLINE void glm_vec2_maxsub(vec2 a, vec2 b, vec2 dest) CGLM_INLINE void glm_vec2_minsub(vec2 a, vec2 b, vec2 dest) CGLM_INLINE void glm_vec2_negate_to(vec2 v, vec2 dest) CGLM_INLINE void glm_vec2_negate(vec2 v) CGLM_INLINE void glm_vec2_normalize(vec2 v) CGLM_INLINE void glm_vec2_normalize_to(vec2 vec, vec2 dest) CGLM_INLINE void glm_vec2_rotate(vec2 v, float angle, vec2 dest) CGLM_INLINE void glm_vec2_center(vec2 a, vec2 b, vec2 dest) CGLM_INLINE float glm_vec2_distance2(vec2 a, vec2 b) CGLM_INLINE float glm_vec2_distance(vec2 a, vec2 b) CGLM_INLINE void glm_vec2_maxv(vec2 v1, vec2 v2, vec2 dest) CGLM_INLINE void glm_vec2_minv(vec2 v1, vec2 v2, vec2 dest) CGLM_INLINE void glm_vec2_clamp(vec2 v, float minVal, float maxVal) CGLM_INLINE void glm_vec2_swizzle(vec2 v, int mask, vec2 dest) CGLM_INLINE void glm_vec2_lerp(vec2 from, vec2 to, float t, vec2 dest) CGLM_INLINE void glm_vec2_step(vec2 edge, vec2 x, vec2 dest) CGLM_INLINE void glm_vec2_make(float * restrict src, vec2 dest) CGLM_INLINE void glm_vec2_reflect(vec2 v, vec2 n, vec2 dest) CGLM_INLINE void glm_vec2_refract(vec2 v, vec2 n, float eta, vec2 dest) CGLM_INLINE void glm_vec2_swap(vec2 a, vec2 b) */ #ifndef cglm_vec2_h #define cglm_vec2_h #include "common.h" #include "util.h" #include "vec2-ext.h" #define GLM_VEC2_ONE_INIT {1.0f, 1.0f} #define GLM_VEC2_ZERO_INIT {0.0f, 0.0f} #define GLM_VEC2_ONE ((vec2)GLM_VEC2_ONE_INIT) #define GLM_VEC2_ZERO ((vec2)GLM_VEC2_ZERO_INIT) /*! * @brief init vec2 using another vector * * @param[in] v a vector * @param[out] dest destination */ CGLM_INLINE void glm_vec2(float * __restrict v, vec2 dest) { dest[0] = v[0]; dest[1] = v[1]; } /*! * @brief copy all members of [a] to [dest] * * @param[in] a source * @param[out] dest destination */ CGLM_INLINE void glm_vec2_copy(vec2 a, vec2 dest) { dest[0] = a[0]; dest[1] = a[1]; } /*! * @brief make vector zero * * @param[in, out] v vector */ CGLM_INLINE void glm_vec2_zero(vec2 v) { v[0] = v[1] = 0.0f; } /*! * @brief make vector one * * @param[in, out] v vector */ CGLM_INLINE void glm_vec2_one(vec2 v) { v[0] = v[1] = 1.0f; } /*! * @brief vec2 dot product * * @param[in] a vector1 * @param[in] b vector2 * * @return dot product */ CGLM_INLINE float glm_vec2_dot(vec2 a, vec2 b) { return a[0] * b[0] + a[1] * b[1]; } /*! * @brief vec2 cross product * * REF: http://allenchou.net/2013/07/cross-product-of-2d-vectors/ * * @param[in] a vector1 * @param[in] b vector2 * * @return Z component of cross product */ CGLM_INLINE float glm_vec2_cross(vec2 a, vec2 b) { /* just calculate the z-component */ return a[0] * b[1] - a[1] * b[0]; } /*! * @brief norm * norm (magnitude) of vec * * we can use this func instead of calling norm * norm, because it would call * sqrtf function twice but with this func we can avoid func call, maybe this is * not good name for this func * * @param[in] v vector * * @return norm * norm */ CGLM_INLINE float glm_vec2_norm2(vec2 v) { return glm_vec2_dot(v, v); } /*! * @brief norm (magnitude) of vec2 * * @param[in] vec vector * * @return norm */ CGLM_INLINE float glm_vec2_norm(vec2 vec) { return sqrtf(glm_vec2_norm2(vec)); } /*! * @brief add a vector to b vector store result in dest * * @param[in] a vector1 * @param[in] b vector2 * @param[out] dest destination vector */ CGLM_INLINE void glm_vec2_add(vec2 a, vec2 b, vec2 dest) { dest[0] = a[0] + b[0]; dest[1] = a[1] + b[1]; } /*! * @brief add scalar to v vector store result in dest (d = v + s) * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination vector */ CGLM_INLINE void glm_vec2_adds(vec2 v, float s, vec2 dest) { dest[0] = v[0] + s; dest[1] = v[1] + s; } /*! * @brief subtract b vector from a vector store result in dest * * @param[in] a vector1 * @param[in] b vector2 * @param[out] dest destination vector */ CGLM_INLINE void glm_vec2_sub(vec2 a, vec2 b, vec2 dest) { dest[0] = a[0] - b[0]; dest[1] = a[1] - b[1]; } /*! * @brief subtract scalar from v vector store result in dest (d = v - s) * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination vector */ CGLM_INLINE void glm_vec2_subs(vec2 v, float s, vec2 dest) { dest[0] = v[0] - s; dest[1] = v[1] - s; } /*! * @brief multiply two vectors (component-wise multiplication) * * @param a v1 * @param b v2 * @param dest v3 = (a[0] * b[0], a[1] * b[1]) */ CGLM_INLINE void glm_vec2_mul(vec2 a, vec2 b, vec2 dest) { dest[0] = a[0] * b[0]; dest[1] = a[1] * b[1]; } /*! * @brief multiply/scale vector with scalar: result = v * s * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination vector */ CGLM_INLINE void glm_vec2_scale(vec2 v, float s, vec2 dest) { dest[0] = v[0] * s; dest[1] = v[1] * s; } /*! * @brief scale as vector specified: result = unit(v) * s * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination vector */ CGLM_INLINE void glm_vec2_scale_as(vec2 v, float s, vec2 dest) { float norm; norm = glm_vec2_norm(v); if (CGLM_UNLIKELY(norm < FLT_EPSILON)) { glm_vec2_zero(dest); return; } glm_vec2_scale(v, s / norm, dest); } /*! * @brief div vector with another component-wise division: d = a / b * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest result = (a[0]/b[0], a[1]/b[1]) */ CGLM_INLINE void glm_vec2_div(vec2 a, vec2 b, vec2 dest) { dest[0] = a[0] / b[0]; dest[1] = a[1] / b[1]; } /*! * @brief div vector with scalar: d = v / s * * @param[in] v vector * @param[in] s scalar * @param[out] dest result = (a[0]/s, a[1]/s) */ CGLM_INLINE void glm_vec2_divs(vec2 v, float s, vec2 dest) { dest[0] = v[0] / s; dest[1] = v[1] / s; } /*! * @brief add two vectors and add result to sum * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest += (a + b) */ CGLM_INLINE void glm_vec2_addadd(vec2 a, vec2 b, vec2 dest) { dest[0] += a[0] + b[0]; dest[1] += a[1] + b[1]; } /*! * @brief sub two vectors and add result to dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest += (a + b) */ CGLM_INLINE void glm_vec2_subadd(vec2 a, vec2 b, vec2 dest) { dest[0] += a[0] - b[0]; dest[1] += a[1] - b[1]; } /*! * @brief mul two vectors and add result to dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest += (a * b) */ CGLM_INLINE void glm_vec2_muladd(vec2 a, vec2 b, vec2 dest) { dest[0] += a[0] * b[0]; dest[1] += a[1] * b[1]; } /*! * @brief mul vector with scalar and add result to sum * * it applies += operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[out] dest dest += (a * b) */ CGLM_INLINE void glm_vec2_muladds(vec2 a, float s, vec2 dest) { dest[0] += a[0] * s; dest[1] += a[1] * s; } /*! * @brief add max of two vectors to result/dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest += max(a, b) */ CGLM_INLINE void glm_vec2_maxadd(vec2 a, vec2 b, vec2 dest) { dest[0] += glm_max(a[0], b[0]); dest[1] += glm_max(a[1], b[1]); } /*! * @brief add min of two vectors to result/dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest += min(a, b) */ CGLM_INLINE void glm_vec2_minadd(vec2 a, vec2 b, vec2 dest) { dest[0] += glm_min(a[0], b[0]); dest[1] += glm_min(a[1], b[1]); } /*! * @brief sub two vectors and sub result to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest -= (a - b) */ CGLM_INLINE void glm_vec2_subsub(vec2 a, vec2 b, vec2 dest) { dest[0] -= a[0] - b[0]; dest[1] -= a[1] - b[1]; } /*! * @brief add two vectors and sub result to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest -= (a + b) */ CGLM_INLINE void glm_vec2_addsub(vec2 a, vec2 b, vec2 dest) { dest[0] -= a[0] + b[0]; dest[1] -= a[1] + b[1]; } /*! * @brief mul two vectors and sub result to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest -= (a * b) */ CGLM_INLINE void glm_vec2_mulsub(vec2 a, vec2 b, vec2 dest) { dest[0] -= a[0] * b[0]; dest[1] -= a[1] * b[1]; } /*! * @brief mul vector with scalar and sub result to sum * * it applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[out] dest dest -= (a * b) */ CGLM_INLINE void glm_vec2_mulsubs(vec2 a, float s, vec2 dest) { dest[0] -= a[0] * s; dest[1] -= a[1] * s; } /*! * @brief sub max of two vectors to result/dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest -= max(a, b) */ CGLM_INLINE void glm_vec2_maxsub(vec2 a, vec2 b, vec2 dest) { dest[0] -= glm_max(a[0], b[0]); dest[1] -= glm_max(a[1], b[1]); } /*! * @brief sub min of two vectors to result/dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest -= min(a, b) */ CGLM_INLINE void glm_vec2_minsub(vec2 a, vec2 b, vec2 dest) { dest[0] -= glm_min(a[0], b[0]); dest[1] -= glm_min(a[1], b[1]); } /*! * @brief negate vector components and store result in dest * * @param[in] v vector * @param[out] dest result vector */ CGLM_INLINE void glm_vec2_negate_to(vec2 v, vec2 dest) { dest[0] = -v[0]; dest[1] = -v[1]; } /*! * @brief negate vector components * * @param[in, out] v vector */ CGLM_INLINE void glm_vec2_negate(vec2 v) { glm_vec2_negate_to(v, v); } /*! * @brief normalize vector and store result in same vec * * @param[in, out] v vector */ CGLM_INLINE void glm_vec2_normalize(vec2 v) { float norm; norm = glm_vec2_norm(v); if (CGLM_UNLIKELY(norm < FLT_EPSILON)) { v[0] = v[1] = 0.0f; return; } glm_vec2_scale(v, 1.0f / norm, v); } /*! * @brief normalize vector to dest * * @param[in] v source * @param[out] dest destination */ CGLM_INLINE void glm_vec2_normalize_to(vec2 v, vec2 dest) { float norm; norm = glm_vec2_norm(v); if (CGLM_UNLIKELY(norm < FLT_EPSILON)) { glm_vec2_zero(dest); return; } glm_vec2_scale(v, 1.0f / norm, dest); } /*! * @brief rotate vec2 around origin by angle (CCW: counterclockwise) * * Formula: * �2 = cos(a)�1 − sin(a)�1 * �2 = sin(a)�1 + cos(a)�1 * * @param[in] v vector to rotate * @param[in] angle angle by radians * @param[out] dest destination vector */ CGLM_INLINE void glm_vec2_rotate(vec2 v, float angle, vec2 dest) { float c, s, x1, y1; c = cosf(angle); s = sinf(angle); x1 = v[0]; y1 = v[1]; dest[0] = c * x1 - s * y1; dest[1] = s * x1 + c * y1; } /** * @brief find center point of two vector * * @param[in] a vector1 * @param[in] b vector2 * @param[out] dest center point */ CGLM_INLINE void glm_vec2_center(vec2 a, vec2 b, vec2 dest) { glm_vec2_add(a, b, dest); glm_vec2_scale(dest, 0.5f, dest); } /** * @brief squared distance between two vectors * * @param[in] a vector1 * @param[in] b vector2 * @return returns squared distance (distance * distance) */ CGLM_INLINE float glm_vec2_distance2(vec2 a, vec2 b) { return glm_pow2(b[0] - a[0]) + glm_pow2(b[1] - a[1]); } /** * @brief distance between two vectors * * @param[in] a vector1 * @param[in] b vector2 * @return returns distance */ CGLM_INLINE float glm_vec2_distance(vec2 a, vec2 b) { return sqrtf(glm_vec2_distance2(a, b)); } /*! * @brief max values of vectors * * @param[in] a vector1 * @param[in] b vector2 * @param[out] dest destination */ CGLM_INLINE void glm_vec2_maxv(vec2 a, vec2 b, vec2 dest) { dest[0] = glm_max(a[0], b[0]); dest[1] = glm_max(a[1], b[1]); } /*! * @brief min values of vectors * * @param[in] a vector1 * @param[in] b vector2 * @param[out] dest destination */ CGLM_INLINE void glm_vec2_minv(vec2 a, vec2 b, vec2 dest) { dest[0] = glm_min(a[0], b[0]); dest[1] = glm_min(a[1], b[1]); } /*! * @brief clamp vector's individual members between min and max values * * @param[in, out] v vector * @param[in] minval minimum value * @param[in] maxval maximum value */ CGLM_INLINE void glm_vec2_clamp(vec2 v, float minval, float maxval) { v[0] = glm_clamp(v[0], minval, maxval); v[1] = glm_clamp(v[1], minval, maxval); } /*! * @brief swizzle vector components * * @param[in] v source * @param[in] mask mask * @param[out] dest destination */ CGLM_INLINE void glm_vec2_swizzle(vec2 v, int mask, vec2 dest) { vec2 t; t[0] = v[(mask & (3 << 0))]; t[1] = v[(mask & (3 << 2)) >> 2]; glm_vec2_copy(t, dest); } /*! * @brief linear interpolation between two vector * * formula: from + s * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) clamped between 0 and 1 * @param[out] dest destination */ CGLM_INLINE void glm_vec2_lerp(vec2 from, vec2 to, float t, vec2 dest) { vec2 s, v; /* from + s * (to - from) */ glm_vec2_fill(s, glm_clamp_zo(t)); glm_vec2_sub(to, from, v); glm_vec2_mul(s, v, v); glm_vec2_add(from, v, dest); } /*! * @brief threshold function * * @param[in] edge threshold * @param[in] x value to test against threshold * @param[out] dest destination */ CGLM_INLINE void glm_vec2_step(vec2 edge, vec2 x, vec2 dest) { dest[0] = glm_step(edge[0], x[0]); dest[1] = glm_step(edge[1], x[1]); } /*! * @brief Create two dimensional vector from pointer * * @param[in] src pointer to an array of floats * @param[out] dest destination vector */ CGLM_INLINE void glm_vec2_make(const float * __restrict src, vec2 dest) { dest[0] = src[0]; dest[1] = src[1]; } /*! * @brief reflection vector using an incident ray and a surface normal * * @param[in] v incident vector * @param[in] n normalized normal vector * @param[out] dest destination vector for the reflection result */ CGLM_INLINE void glm_vec2_reflect(vec2 v, vec2 n, vec2 dest) { vec2 temp; glm_vec2_scale(n, 2.0f * glm_vec2_dot(v, n), temp); glm_vec2_sub(v, temp, dest); } /*! * @brief computes refraction vector for an incident vector and a surface normal. * * calculates the refraction vector based on Snell's law. If total internal reflection * occurs (angle too great given eta), dest is set to zero and returns false. * Otherwise, computes refraction vector, stores it in dest, and returns true. * * @param[in] v normalized incident vector * @param[in] n normalized normal vector * @param[in] eta ratio of indices of refraction (incident/transmitted) * @param[out] dest refraction vector if refraction occurs; zero vector otherwise * * @returns true if refraction occurs; false if total internal reflection occurs. */ CGLM_INLINE bool glm_vec2_refract(vec2 v, vec2 n, float eta, vec2 dest) { float ndi, eni, k; ndi = glm_vec2_dot(n, v); eni = eta * ndi; k = 1.0f - eta * eta + eni * eni; if (k < 0.0f) { glm_vec2_zero(dest); return false; } glm_vec2_scale(v, eta, dest); glm_vec2_mulsubs(n, eni + sqrtf(k), dest); return true; } /*! * @brief swap two vectors * @param a the first vector to swap * @param b the second vector to swap */ CGLM_INLINE void glm_vec2_swap(vec2 a, vec2 b) { vec2 tmp; glm_vec2_copy(a, tmp); glm_vec2_copy(b, a); glm_vec2_copy(tmp, b); } #endif /* cglm_vec2_h */ cglm-0.9.7/include/cglm/vec3-ext.h000066400000000000000000000160761526744317200166520ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /*! * @brief SIMD like functions */ /* Functions: CGLM_INLINE void glm_vec3_broadcast(float val, vec3 d); CGLM_INLINE void glm_vec3_fill(vec3 v, float val); CGLM_INLINE bool glm_vec3_eq(vec3 v, float val); CGLM_INLINE bool glm_vec3_eq_eps(vec3 v, float val); CGLM_INLINE bool glm_vec3_eq_all(vec3 v); CGLM_INLINE bool glm_vec3_eqv(vec3 a, vec3 b); CGLM_INLINE bool glm_vec3_eqv_eps(vec3 a, vec3 b); CGLM_INLINE float glm_vec3_max(vec3 v); CGLM_INLINE float glm_vec3_min(vec3 v); CGLM_INLINE bool glm_vec3_isnan(vec3 v); CGLM_INLINE bool glm_vec3_isinf(vec3 v); CGLM_INLINE bool glm_vec3_isvalid(vec3 v); CGLM_INLINE void glm_vec3_sign(vec3 v, vec3 dest); CGLM_INLINE void glm_vec3_abs(vec3 v, vec3 dest); CGLM_INLINE void glm_vec3_fract(vec3 v, vec3 dest); CGLM_INLINE void glm_vec3_floor(vec3 v, vec3 dest); CGLM_INLINE float glm_vec3_mods(vec3 v, float s, vec3 dest); CGLM_INLINE float glm_vec3_steps(float edge, vec3 v, vec3 dest); CGLM_INLINE void glm_vec3_stepr(vec3 edge, float v, vec3 dest); CGLM_INLINE float glm_vec3_hadd(vec3 v); CGLM_INLINE void glm_vec3_sqrt(vec3 v, vec3 dest); */ #ifndef cglm_vec3_ext_h #define cglm_vec3_ext_h #include "common.h" #include "util.h" /*! * @brief fill a vector with specified value * * @param[in] val value * @param[out] d dest */ CGLM_INLINE void glm_vec3_broadcast(float val, vec3 d) { d[0] = d[1] = d[2] = val; } /*! * @brief fill a vector with specified value * * @param[out] v dest * @param[in] val value */ CGLM_INLINE void glm_vec3_fill(vec3 v, float val) { v[0] = v[1] = v[2] = val; } /*! * @brief check if vector is equal to value (without epsilon) * * @param[in] v vector * @param[in] val value */ CGLM_INLINE bool glm_vec3_eq(vec3 v, float val) { return v[0] == val && v[0] == v[1] && v[0] == v[2]; } /*! * @brief check if vector is equal to value (with epsilon) * * @param[in] v vector * @param[in] val value */ CGLM_INLINE bool glm_vec3_eq_eps(vec3 v, float val) { return fabsf(v[0] - val) <= GLM_FLT_EPSILON && fabsf(v[1] - val) <= GLM_FLT_EPSILON && fabsf(v[2] - val) <= GLM_FLT_EPSILON; } /*! * @brief check if vector members are equal (without epsilon) * * @param[in] v vector */ CGLM_INLINE bool glm_vec3_eq_all(vec3 v) { return glm_vec3_eq_eps(v, v[0]); } /*! * @brief check if vector is equal to another (without epsilon) * * @param[in] a vector * @param[in] b vector */ CGLM_INLINE bool glm_vec3_eqv(vec3 a, vec3 b) { return a[0] == b[0] && a[1] == b[1] && a[2] == b[2]; } /*! * @brief check if vector is equal to another (with epsilon) * * @param[in] a vector * @param[in] b vector */ CGLM_INLINE bool glm_vec3_eqv_eps(vec3 a, vec3 b) { return fabsf(a[0] - b[0]) <= GLM_FLT_EPSILON && fabsf(a[1] - b[1]) <= GLM_FLT_EPSILON && fabsf(a[2] - b[2]) <= GLM_FLT_EPSILON; } /*! * @brief max value of vector * * @param[in] v vector */ CGLM_INLINE float glm_vec3_max(vec3 v) { float max; max = v[0]; if (v[1] > max) max = v[1]; if (v[2] > max) max = v[2]; return max; } /*! * @brief min value of vector * * @param[in] v vector */ CGLM_INLINE float glm_vec3_min(vec3 v) { float min; min = v[0]; if (v[1] < min) min = v[1]; if (v[2] < min) min = v[2]; return min; } /*! * @brief check if one of items is NaN (not a number) * you should only use this in DEBUG mode or very critical asserts * * @param[in] v vector */ CGLM_INLINE bool glm_vec3_isnan(vec3 v) { #ifndef CGLM_FAST_MATH return isnan(v[0]) || isnan(v[1]) || isnan(v[2]); #else (void)v; return false; #endif } /*! * @brief check if one of items is INFINITY * you should only use this in DEBUG mode or very critical asserts * * @param[in] v vector */ CGLM_INLINE bool glm_vec3_isinf(vec3 v) { #ifndef CGLM_FAST_MATH return isinf(v[0]) || isinf(v[1]) || isinf(v[2]); #else (void)v; return false; #endif } /*! * @brief check if all items are valid number * you should only use this in DEBUG mode or very critical asserts * * @param[in] v vector */ CGLM_INLINE bool glm_vec3_isvalid(vec3 v) { return !glm_vec3_isnan(v) && !glm_vec3_isinf(v); } /*! * @brief get sign of 32 bit float as +1, -1, 0 * * Important: It returns 0 for zero/NaN input * * @param v vector */ CGLM_INLINE void glm_vec3_sign(vec3 v, vec3 dest) { dest[0] = glm_signf(v[0]); dest[1] = glm_signf(v[1]); dest[2] = glm_signf(v[2]); } /*! * @brief absolute value of each vector item * * @param[in] v vector * @param[out] dest destination vector */ CGLM_INLINE void glm_vec3_abs(vec3 v, vec3 dest) { dest[0] = fabsf(v[0]); dest[1] = fabsf(v[1]); dest[2] = fabsf(v[2]); } /*! * @brief fractional part of each vector item * * @param[in] v vector * @param[out] dest destination vector */ CGLM_INLINE void glm_vec3_fract(vec3 v, vec3 dest) { dest[0] = fminf(v[0] - floorf(v[0]), 0.999999940395355224609375f); dest[1] = fminf(v[1] - floorf(v[1]), 0.999999940395355224609375f); dest[2] = fminf(v[2] - floorf(v[2]), 0.999999940395355224609375f); } /*! * @brief floor of each vector item * * @param[in] v vector * @param[out] dest destination vector */ CGLM_INLINE void glm_vec3_floor(vec3 v, vec3 dest) { dest[0] = floorf(v[0]); dest[1] = floorf(v[1]); dest[2] = floorf(v[2]); } /*! * @brief mod of each vector item, result is written to dest (dest = v % s) * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination vector */ CGLM_INLINE void glm_vec3_mods(vec3 v, float s, vec3 dest) { dest[0] = fmodf(v[0], s); dest[1] = fmodf(v[1], s); dest[2] = fmodf(v[2], s); } /*! * @brief threshold each vector item with scalar * condition is: (x[i] < edge) ? 0.0 : 1.0 * * @param[in] edge threshold * @param[in] x vector to test against threshold * @param[out] dest destination */ CGLM_INLINE void glm_vec3_steps(float edge, vec3 x, vec3 dest) { dest[0] = glm_step(edge, x[0]); dest[1] = glm_step(edge, x[1]); dest[2] = glm_step(edge, x[2]); } /*! * @brief threshold a value with *vector* as the threshold * condition is: (x < edge[i]) ? 0.0 : 1.0 * * @param[in] edge threshold vector * @param[in] x value to test against threshold * @param[out] dest destination */ CGLM_INLINE void glm_vec3_stepr(vec3 edge, float x, vec3 dest) { dest[0] = glm_step(edge[0], x); dest[1] = glm_step(edge[1], x); dest[2] = glm_step(edge[2], x); } /*! * @brief vector reduction by summation * @warning could overflow * * @param[in] v vector * @return sum of all vector's elements */ CGLM_INLINE float glm_vec3_hadd(vec3 v) { return v[0] + v[1] + v[2]; } /*! * @brief square root of each vector item * * @param[in] v vector * @param[out] dest destination vector */ CGLM_INLINE void glm_vec3_sqrt(vec3 v, vec3 dest) { dest[0] = sqrtf(v[0]); dest[1] = sqrtf(v[1]); dest[2] = sqrtf(v[2]); } #endif /* cglm_vec3_ext_h */ cglm-0.9.7/include/cglm/vec3.h000066400000000000000000000724121526744317200160500ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLM_VEC3_ONE_INIT GLM_VEC3_ZERO_INIT GLM_VEC3_ONE GLM_VEC3_ZERO GLM_YUP GLM_ZUP GLM_XUP Functions: CGLM_INLINE void glm_vec3(vec4 v4, vec3 dest); CGLM_INLINE void glm_vec3_copy(vec3 a, vec3 dest); CGLM_INLINE void glm_vec3_zero(vec3 v); CGLM_INLINE void glm_vec3_one(vec3 v); CGLM_INLINE float glm_vec3_dot(vec3 a, vec3 b); CGLM_INLINE float glm_vec3_norm2(vec3 v); CGLM_INLINE float glm_vec3_norm(vec3 v); CGLM_INLINE float glm_vec3_norm_one(vec3 v); CGLM_INLINE float glm_vec3_norm_inf(vec3 v); CGLM_INLINE void glm_vec3_add(vec3 a, vec3 b, vec3 dest); CGLM_INLINE void glm_vec3_adds(vec3 a, float s, vec3 dest); CGLM_INLINE void glm_vec3_sub(vec3 a, vec3 b, vec3 dest); CGLM_INLINE void glm_vec3_subs(vec3 a, float s, vec3 dest); CGLM_INLINE void glm_vec3_mul(vec3 a, vec3 b, vec3 dest); CGLM_INLINE void glm_vec3_scale(vec3 v, float s, vec3 dest); CGLM_INLINE void glm_vec3_scale_as(vec3 v, float s, vec3 dest); CGLM_INLINE void glm_vec3_div(vec3 a, vec3 b, vec3 dest); CGLM_INLINE void glm_vec3_divs(vec3 a, float s, vec3 dest); CGLM_INLINE void glm_vec3_addadd(vec3 a, vec3 b, vec3 dest); CGLM_INLINE void glm_vec3_subadd(vec3 a, vec3 b, vec3 dest); CGLM_INLINE void glm_vec3_muladd(vec3 a, vec3 b, vec3 dest); CGLM_INLINE void glm_vec3_muladds(vec3 a, float s, vec3 dest); CGLM_INLINE void glm_vec3_maxadd(vec3 a, vec3 b, vec3 dest); CGLM_INLINE void glm_vec3_minadd(vec3 a, vec3 b, vec3 dest); CGLM_INLINE void glm_vec3_subsub(vec3 a, vec3 b, vec3 dest); CGLM_INLINE void glm_vec3_addsub(vec3 a, vec3 b, vec3 dest); CGLM_INLINE void glm_vec3_mulsub(vec3 a, vec3 b, vec3 dest); CGLM_INLINE void glm_vec3_mulsubs(vec3 a, float s, vec3 dest); CGLM_INLINE void glm_vec3_maxsub(vec3 a, vec3 b, vec3 dest); CGLM_INLINE void glm_vec3_minsub(vec3 a, vec3 b, vec3 dest); CGLM_INLINE void glm_vec3_flipsign(vec3 v); CGLM_INLINE void glm_vec3_flipsign_to(vec3 v, vec3 dest); CGLM_INLINE void glm_vec3_negate_to(vec3 v, vec3 dest); CGLM_INLINE void glm_vec3_negate(vec3 v); CGLM_INLINE void glm_vec3_inv(vec3 v); CGLM_INLINE void glm_vec3_inv_to(vec3 v, vec3 dest); CGLM_INLINE void glm_vec3_normalize(vec3 v); CGLM_INLINE void glm_vec3_normalize_to(vec3 v, vec3 dest); CGLM_INLINE void glm_vec3_cross(vec3 a, vec3 b, vec3 d); CGLM_INLINE void glm_vec3_crossn(vec3 a, vec3 b, vec3 dest); CGLM_INLINE float glm_vec3_angle(vec3 a, vec3 b); CGLM_INLINE void glm_vec3_rotate(vec3 v, float angle, vec3 axis); CGLM_INLINE void glm_vec3_rotate_m4(mat4 m, vec3 v, vec3 dest); CGLM_INLINE void glm_vec3_rotate_m3(mat3 m, vec3 v, vec3 dest); CGLM_INLINE void glm_vec3_proj(vec3 a, vec3 b, vec3 dest); CGLM_INLINE void glm_vec3_center(vec3 a, vec3 b, vec3 dest); CGLM_INLINE float glm_vec3_distance(vec3 a, vec3 b); CGLM_INLINE float glm_vec3_distance2(vec3 a, vec3 b); CGLM_INLINE void glm_vec3_maxv(vec3 a, vec3 b, vec3 dest); CGLM_INLINE void glm_vec3_minv(vec3 a, vec3 b, vec3 dest); CGLM_INLINE void glm_vec3_ortho(vec3 v, vec3 dest); CGLM_INLINE void glm_vec3_clamp(vec3 v, float minVal, float maxVal); CGLM_INLINE void glm_vec3_lerp(vec3 from, vec3 to, float t, vec3 dest); CGLM_INLINE void glm_vec3_lerpc(vec3 from, vec3 to, float t, vec3 dest); CGLM_INLINE void glm_vec3_mix(vec3 from, vec3 to, float t, vec3 dest); CGLM_INLINE void glm_vec3_mixc(vec3 from, vec3 to, float t, vec3 dest); CGLM_INLINE void glm_vec3_step(vec3 edge, vec3 x, vec3 dest); CGLM_INLINE void glm_vec3_smoothstep_uni(float edge0, float edge1, vec3 x, vec3 dest); CGLM_INLINE void glm_vec3_smoothstep(vec3 edge0, vec3 edge1, vec3 x, vec3 dest); CGLM_INLINE void glm_vec3_smoothinterp(vec3 from, vec3 to, float t, vec3 dest); CGLM_INLINE void glm_vec3_smoothinterpc(vec3 from, vec3 to, float t, vec3 dest); CGLM_INLINE void glm_vec3_swizzle(vec3 v, int mask, vec3 dest); CGLM_INLINE void glm_vec3_make(float * restrict src, vec3 dest); CGLM_INLINE void glm_vec3_faceforward(vec3 n, vec3 v, vec3 nref, vec3 dest); CGLM_INLINE void glm_vec3_reflect(vec3 v, vec3 n, vec3 dest); CGLM_INLINE void glm_vec3_refract(vec3 v, vec3 n, float eta, vec3 dest); CGLM_INLINE void glm_vec3_swap(vec3 a, vec3 b) Convenient: CGLM_INLINE void glm_cross(vec3 a, vec3 b, vec3 d); CGLM_INLINE float glm_dot(vec3 a, vec3 b); CGLM_INLINE void glm_normalize(vec3 v); CGLM_INLINE void glm_normalize_to(vec3 v, vec3 dest); DEPRECATED: glm_vec3_dup glm_vec3_flipsign glm_vec3_flipsign_to glm_vec3_inv glm_vec3_inv_to glm_vec3_mulv glm_vec3_step_uni --> use glm_vec3_steps */ #ifndef cglm_vec3_h #define cglm_vec3_h #include "common.h" #include "vec4.h" #include "vec3-ext.h" #include "util.h" /* DEPRECATED! use _copy, _ucopy versions */ #define glm_vec3_dup(v, dest) glm_vec3_copy(v, dest) #define glm_vec3_flipsign(v) glm_vec3_negate(v) #define glm_vec3_flipsign_to(v, dest) glm_vec3_negate_to(v, dest) #define glm_vec3_inv(v) glm_vec3_negate(v) #define glm_vec3_inv_to(v, dest) glm_vec3_negate_to(v, dest) #define glm_vec3_mulv(a, b, d) glm_vec3_mul(a, b, d) #define glm_vec3_step_uni(edge, x, dest) glm_vec3_steps(edge, x, dest) #define GLM_VEC3_ONE_INIT {1.0f, 1.0f, 1.0f} #define GLM_VEC3_ZERO_INIT {0.0f, 0.0f, 0.0f} #define GLM_VEC3_ONE ((vec3)GLM_VEC3_ONE_INIT) #define GLM_VEC3_ZERO ((vec3)GLM_VEC3_ZERO_INIT) #define GLM_YUP ((vec3){0.0f, 1.0f, 0.0f}) #define GLM_ZUP ((vec3){0.0f, 0.0f, 1.0f}) #define GLM_XUP ((vec3){1.0f, 0.0f, 0.0f}) #define GLM_FORWARD ((vec3){0.0f, 0.0f, -1.0f}) #define GLM_XXX GLM_SHUFFLE3(0, 0, 0) #define GLM_YYY GLM_SHUFFLE3(1, 1, 1) #define GLM_ZZZ GLM_SHUFFLE3(2, 2, 2) #define GLM_ZYX GLM_SHUFFLE3(0, 1, 2) /*! * @brief init vec3 using vec4 * * @param[in] v4 vector4 * @param[out] dest destination */ CGLM_INLINE void glm_vec3(vec4 v4, vec3 dest) { dest[0] = v4[0]; dest[1] = v4[1]; dest[2] = v4[2]; } /*! * @brief copy all members of [a] to [dest] * * @param[in] a source * @param[out] dest destination */ CGLM_INLINE void glm_vec3_copy(vec3 a, vec3 dest) { dest[0] = a[0]; dest[1] = a[1]; dest[2] = a[2]; } /*! * @brief make vector zero * * @param[in, out] v vector */ CGLM_INLINE void glm_vec3_zero(vec3 v) { v[0] = v[1] = v[2] = 0.0f; } /*! * @brief make vector one * * @param[in, out] v vector */ CGLM_INLINE void glm_vec3_one(vec3 v) { v[0] = v[1] = v[2] = 1.0f; } /*! * @brief vec3 dot product * * @param[in] a vector1 * @param[in] b vector2 * * @return dot product */ CGLM_INLINE float glm_vec3_dot(vec3 a, vec3 b) { return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; } /*! * @brief norm * norm (magnitude) of vec * * we can use this func instead of calling norm * norm, because it would call * sqrtf function twice but with this func we can avoid func call, maybe this is * not good name for this func * * @param[in] v vector * * @return norm * norm */ CGLM_INLINE float glm_vec3_norm2(vec3 v) { return glm_vec3_dot(v, v); } /*! * @brief euclidean norm (magnitude), also called L2 norm * this will give magnitude of vector in euclidean space * * @param[in] v vector * * @return norm */ CGLM_INLINE float glm_vec3_norm(vec3 v) { return sqrtf(glm_vec3_norm2(v)); } /*! * @brief L1 norm of vec3 * Also known as Manhattan Distance or Taxicab norm. * L1 Norm is the sum of the magnitudes of the vectors in a space. * It is calculated as the sum of the absolute values of the vector components. * In this norm, all the components of the vector are weighted equally. * * This computes: * R = |v[0]| + |v[1]| + |v[2]| * * @param[in] v vector * * @return L1 norm */ CGLM_INLINE float glm_vec3_norm_one(vec3 v) { vec3 t; glm_vec3_abs(v, t); return glm_vec3_hadd(t); } /*! * @brief infinity norm of vec3 * Also known as Maximum norm. * Infinity Norm is the largest magnitude among each element of a vector. * It is calculated as the maximum of the absolute values of the vector components. * * This computes: * inf norm = max(|v[0]|, |v[1]|, |v[2]|) * * @param[in] v vector * * @return infinity norm */ CGLM_INLINE float glm_vec3_norm_inf(vec3 v) { vec3 t; glm_vec3_abs(v, t); return glm_vec3_max(t); } /*! * @brief add a vector to b vector store result in dest * * @param[in] a vector1 * @param[in] b vector2 * @param[out] dest destination vector */ CGLM_INLINE void glm_vec3_add(vec3 a, vec3 b, vec3 dest) { dest[0] = a[0] + b[0]; dest[1] = a[1] + b[1]; dest[2] = a[2] + b[2]; } /*! * @brief add scalar to v vector store result in dest (d = v + s) * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination vector */ CGLM_INLINE void glm_vec3_adds(vec3 v, float s, vec3 dest) { dest[0] = v[0] + s; dest[1] = v[1] + s; dest[2] = v[2] + s; } /*! * @brief subtract b vector from a vector store result in dest * * @param[in] a vector1 * @param[in] b vector2 * @param[out] dest destination vector */ CGLM_INLINE void glm_vec3_sub(vec3 a, vec3 b, vec3 dest) { dest[0] = a[0] - b[0]; dest[1] = a[1] - b[1]; dest[2] = a[2] - b[2]; } /*! * @brief subtract scalar from v vector store result in dest (d = v - s) * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination vector */ CGLM_INLINE void glm_vec3_subs(vec3 v, float s, vec3 dest) { dest[0] = v[0] - s; dest[1] = v[1] - s; dest[2] = v[2] - s; } /*! * @brief multiply two vectors (component-wise multiplication) * * @param a vector1 * @param b vector2 * @param dest v3 = (a[0] * b[0], a[1] * b[1], a[2] * b[2]) */ CGLM_INLINE void glm_vec3_mul(vec3 a, vec3 b, vec3 dest) { dest[0] = a[0] * b[0]; dest[1] = a[1] * b[1]; dest[2] = a[2] * b[2]; } /*! * @brief multiply/scale vec3 vector with scalar: result = v * s * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination vector */ CGLM_INLINE void glm_vec3_scale(vec3 v, float s, vec3 dest) { dest[0] = v[0] * s; dest[1] = v[1] * s; dest[2] = v[2] * s; } /*! * @brief make vec3 vector scale as specified: result = unit(v) * s * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination vector */ CGLM_INLINE void glm_vec3_scale_as(vec3 v, float s, vec3 dest) { float norm; norm = glm_vec3_norm(v); if (CGLM_UNLIKELY(norm < FLT_EPSILON)) { glm_vec3_zero(dest); return; } glm_vec3_scale(v, s / norm, dest); } /*! * @brief div vector with another component-wise division: d = a / b * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest result = (a[0]/b[0], a[1]/b[1], a[2]/b[2]) */ CGLM_INLINE void glm_vec3_div(vec3 a, vec3 b, vec3 dest) { dest[0] = a[0] / b[0]; dest[1] = a[1] / b[1]; dest[2] = a[2] / b[2]; } /*! * @brief div vector with scalar: d = v / s * * @param[in] v vector * @param[in] s scalar * @param[out] dest result = (a[0]/s, a[1]/s, a[2]/s) */ CGLM_INLINE void glm_vec3_divs(vec3 v, float s, vec3 dest) { dest[0] = v[0] / s; dest[1] = v[1] / s; dest[2] = v[2] / s; } /*! * @brief add two vectors and add result to sum * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest += (a + b) */ CGLM_INLINE void glm_vec3_addadd(vec3 a, vec3 b, vec3 dest) { dest[0] += a[0] + b[0]; dest[1] += a[1] + b[1]; dest[2] += a[2] + b[2]; } /*! * @brief sub two vectors and add result to dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest += (a + b) */ CGLM_INLINE void glm_vec3_subadd(vec3 a, vec3 b, vec3 dest) { dest[0] += a[0] - b[0]; dest[1] += a[1] - b[1]; dest[2] += a[2] - b[2]; } /*! * @brief mul two vectors and add result to dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest += (a * b) */ CGLM_INLINE void glm_vec3_muladd(vec3 a, vec3 b, vec3 dest) { dest[0] += a[0] * b[0]; dest[1] += a[1] * b[1]; dest[2] += a[2] * b[2]; } /*! * @brief mul vector with scalar and add result to sum * * it applies += operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[out] dest dest += (a * b) */ CGLM_INLINE void glm_vec3_muladds(vec3 a, float s, vec3 dest) { dest[0] += a[0] * s; dest[1] += a[1] * s; dest[2] += a[2] * s; } /*! * @brief add max of two vectors to result/dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest += max(a, b) */ CGLM_INLINE void glm_vec3_maxadd(vec3 a, vec3 b, vec3 dest) { dest[0] += glm_max(a[0], b[0]); dest[1] += glm_max(a[1], b[1]); dest[2] += glm_max(a[2], b[2]); } /*! * @brief add min of two vectors to result/dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest += min(a, b) */ CGLM_INLINE void glm_vec3_minadd(vec3 a, vec3 b, vec3 dest) { dest[0] += glm_min(a[0], b[0]); dest[1] += glm_min(a[1], b[1]); dest[2] += glm_min(a[2], b[2]); } /*! * @brief sub two vectors and sub result to dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest -= (a - b) */ CGLM_INLINE void glm_vec3_subsub(vec3 a, vec3 b, vec3 dest) { dest[0] -= a[0] - b[0]; dest[1] -= a[1] - b[1]; dest[2] -= a[2] - b[2]; } /*! * @brief add two vectors and sub result to dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest -= (a + b) */ CGLM_INLINE void glm_vec3_addsub(vec3 a, vec3 b, vec3 dest) { dest[0] -= a[0] + b[0]; dest[1] -= a[1] + b[1]; dest[2] -= a[2] + b[2]; } /*! * @brief mul two vectors and sub result to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest -= (a * b) */ CGLM_INLINE void glm_vec3_mulsub(vec3 a, vec3 b, vec3 dest) { dest[0] -= a[0] * b[0]; dest[1] -= a[1] * b[1]; dest[2] -= a[2] * b[2]; } /*! * @brief mul vector with scalar and sub result to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[out] dest dest -= (a * b) */ CGLM_INLINE void glm_vec3_mulsubs(vec3 a, float s, vec3 dest) { dest[0] -= a[0] * s; dest[1] -= a[1] * s; dest[2] -= a[2] * s; } /*! * @brief sub max of two vectors to result/dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest -= max(a, b) */ CGLM_INLINE void glm_vec3_maxsub(vec3 a, vec3 b, vec3 dest) { dest[0] -= glm_max(a[0], b[0]); dest[1] -= glm_max(a[1], b[1]); dest[2] -= glm_max(a[2], b[2]); } /*! * @brief sub min of two vectors to result/dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest -= min(a, b) */ CGLM_INLINE void glm_vec3_minsub(vec3 a, vec3 b, vec3 dest) { dest[0] -= glm_min(a[0], b[0]); dest[1] -= glm_min(a[1], b[1]); dest[2] -= glm_min(a[2], b[2]); } /*! * @brief negate vector components and store result in dest * * @param[in] v vector * @param[out] dest result vector */ CGLM_INLINE void glm_vec3_negate_to(vec3 v, vec3 dest) { dest[0] = -v[0]; dest[1] = -v[1]; dest[2] = -v[2]; } /*! * @brief negate vector components * * @param[in, out] v vector */ CGLM_INLINE void glm_vec3_negate(vec3 v) { glm_vec3_negate_to(v, v); } /*! * @brief normalize vec3 and store result in same vec * * @param[in, out] v vector */ CGLM_INLINE void glm_vec3_normalize(vec3 v) { float norm; norm = glm_vec3_norm(v); if (CGLM_UNLIKELY(norm < FLT_EPSILON)) { v[0] = v[1] = v[2] = 0.0f; return; } glm_vec3_scale(v, 1.0f / norm, v); } /*! * @brief normalize vec3 to dest * * @param[in] v source * @param[out] dest destination */ CGLM_INLINE void glm_vec3_normalize_to(vec3 v, vec3 dest) { float norm; norm = glm_vec3_norm(v); if (CGLM_UNLIKELY(norm < FLT_EPSILON)) { glm_vec3_zero(dest); return; } glm_vec3_scale(v, 1.0f / norm, dest); } /*! * @brief cross product of two vector (RH) * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest destination */ CGLM_INLINE void glm_vec3_cross(vec3 a, vec3 b, vec3 dest) { vec3 c; /* (u2.v3 - u3.v2, u3.v1 - u1.v3, u1.v2 - u2.v1) */ c[0] = a[1] * b[2] - a[2] * b[1]; c[1] = a[2] * b[0] - a[0] * b[2]; c[2] = a[0] * b[1] - a[1] * b[0]; glm_vec3_copy(c, dest); } /*! * @brief cross product of two vector (RH) and normalize the result * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest destination */ CGLM_INLINE void glm_vec3_crossn(vec3 a, vec3 b, vec3 dest) { glm_vec3_cross(a, b, dest); glm_vec3_normalize(dest); } /*! * @brief angle between two vector * * @param[in] a vector1 * @param[in] b vector2 * * @return angle as radians */ CGLM_INLINE float glm_vec3_angle(vec3 a, vec3 b) { float norm, dot; /* maybe compiler generate approximation instruction (rcp) */ norm = 1.0f / (glm_vec3_norm(a) * glm_vec3_norm(b)); dot = glm_vec3_dot(a, b) * norm; if (dot > 1.0f) return 0.0f; else if (dot < -1.0f) return CGLM_PI; return acosf(dot); } /*! * @brief rotate vec3 around axis by angle using Rodrigues' rotation formula * * @param[in, out] v vector * @param[in] axis axis vector (must be unit vector) * @param[in] angle angle by radians */ CGLM_INLINE void glm_vec3_rotate(vec3 v, float angle, vec3 axis) { vec3 v1, v2, k; float c, s; c = cosf(angle); s = sinf(angle); glm_vec3_normalize_to(axis, k); /* Right Hand, Rodrigues' rotation formula: v = v*cos(t) + (kxv)sin(t) + k*(k.v)(1 - cos(t)) */ glm_vec3_scale(v, c, v1); glm_vec3_cross(k, v, v2); glm_vec3_scale(v2, s, v2); glm_vec3_add(v1, v2, v1); glm_vec3_scale(k, glm_vec3_dot(k, v) * (1.0f - c), v2); glm_vec3_add(v1, v2, v); } /*! * @brief apply rotation matrix to vector * * matrix format should be (no perspective): * a b c x * e f g y * i j k z * 0 0 0 w * * @param[in] m affine matrix or rot matrix * @param[in] v vector * @param[out] dest rotated vector */ CGLM_INLINE void glm_vec3_rotate_m4(mat4 m, vec3 v, vec3 dest) { vec4 x, y, z, res; glm_vec4_normalize_to(m[0], x); glm_vec4_normalize_to(m[1], y); glm_vec4_normalize_to(m[2], z); glm_vec4_scale(x, v[0], res); glm_vec4_muladds(y, v[1], res); glm_vec4_muladds(z, v[2], res); glm_vec3(res, dest); } /*! * @brief apply rotation matrix to vector * * @param[in] m affine matrix or rot matrix * @param[in] v vector * @param[out] dest rotated vector */ CGLM_INLINE void glm_vec3_rotate_m3(mat3 m, vec3 v, vec3 dest) { vec4 res, x, y, z; glm_vec4(m[0], 0.0f, x); glm_vec4(m[1], 0.0f, y); glm_vec4(m[2], 0.0f, z); glm_vec4_normalize(x); glm_vec4_normalize(y); glm_vec4_normalize(z); glm_vec4_scale(x, v[0], res); glm_vec4_muladds(y, v[1], res); glm_vec4_muladds(z, v[2], res); glm_vec3(res, dest); } /*! * @brief project a vector onto b vector * * @param[in] a vector1 * @param[in] b vector2 * @param[out] dest projected vector */ CGLM_INLINE void glm_vec3_proj(vec3 a, vec3 b, vec3 dest) { glm_vec3_scale(b, glm_vec3_dot(a, b) / glm_vec3_norm2(b), dest); } /** * @brief find center point of two vector * * @param[in] a vector1 * @param[in] b vector2 * @param[out] dest center point */ CGLM_INLINE void glm_vec3_center(vec3 a, vec3 b, vec3 dest) { glm_vec3_add(a, b, dest); glm_vec3_scale(dest, 0.5f, dest); } /** * @brief squared distance between two vectors * * @param[in] a vector1 * @param[in] b vector2 * @return returns squared distance (distance * distance) */ CGLM_INLINE float glm_vec3_distance2(vec3 a, vec3 b) { return glm_pow2(a[0] - b[0]) + glm_pow2(a[1] - b[1]) + glm_pow2(a[2] - b[2]); } /** * @brief distance between two vectors * * @param[in] a vector1 * @param[in] b vector2 * @return returns distance */ CGLM_INLINE float glm_vec3_distance(vec3 a, vec3 b) { return sqrtf(glm_vec3_distance2(a, b)); } /*! * @brief max values of vectors * * @param[in] a vector1 * @param[in] b vector2 * @param[out] dest destination */ CGLM_INLINE void glm_vec3_maxv(vec3 a, vec3 b, vec3 dest) { dest[0] = glm_max(a[0], b[0]); dest[1] = glm_max(a[1], b[1]); dest[2] = glm_max(a[2], b[2]); } /*! * @brief min values of vectors * * @param[in] a vector1 * @param[in] b vector2 * @param[out] dest destination */ CGLM_INLINE void glm_vec3_minv(vec3 a, vec3 b, vec3 dest) { dest[0] = glm_min(a[0], b[0]); dest[1] = glm_min(a[1], b[1]); dest[2] = glm_min(a[2], b[2]); } /*! * @brief possible orthogonal/perpendicular vector * * @param[in] v vector * @param[out] dest orthogonal/perpendicular vector */ CGLM_INLINE void glm_vec3_ortho(vec3 v, vec3 dest) { float ignore; float f = modff(fabsf(v[0]) + 0.5f, &ignore); vec3 result = {-v[1], v[0] - f * v[2], f * v[1]}; glm_vec3_copy(result, dest); } /*! * @brief clamp vector's individual members between min and max values * * @param[in, out] v vector * @param[in] minVal minimum value * @param[in] maxVal maximum value */ CGLM_INLINE void glm_vec3_clamp(vec3 v, float minVal, float maxVal) { v[0] = glm_clamp(v[0], minVal, maxVal); v[1] = glm_clamp(v[1], minVal, maxVal); v[2] = glm_clamp(v[2], minVal, maxVal); } /*! * @brief linear interpolation between two vectors * * formula: from + s * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) * @param[out] dest destination */ CGLM_INLINE void glm_vec3_lerp(vec3 from, vec3 to, float t, vec3 dest) { vec3 s, v; /* from + s * (to - from) */ glm_vec3_broadcast(t, s); glm_vec3_sub(to, from, v); glm_vec3_mul(s, v, v); glm_vec3_add(from, v, dest); } /*! * @brief linear interpolation between two vectors (clamped) * * formula: from + s * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) clamped between 0 and 1 * @param[out] dest destination */ CGLM_INLINE void glm_vec3_lerpc(vec3 from, vec3 to, float t, vec3 dest) { glm_vec3_lerp(from, to, glm_clamp_zo(t), dest); } /*! * @brief linear interpolation between two vectors * * formula: from + s * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) * @param[out] dest destination */ CGLM_INLINE void glm_vec3_mix(vec3 from, vec3 to, float t, vec3 dest) { glm_vec3_lerp(from, to, t, dest); } /*! * @brief linear interpolation between two vectors (clamped) * * formula: from + s * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) clamped between 0 and 1 * @param[out] dest destination */ CGLM_INLINE void glm_vec3_mixc(vec3 from, vec3 to, float t, vec3 dest) { glm_vec3_lerpc(from, to, t, dest); } /*! * @brief threshold function * * @param[in] edge threshold * @param[in] x value to test against threshold * @param[out] dest destination */ CGLM_INLINE void glm_vec3_step(vec3 edge, vec3 x, vec3 dest) { dest[0] = glm_step(edge[0], x[0]); dest[1] = glm_step(edge[1], x[1]); dest[2] = glm_step(edge[2], x[2]); } /*! * @brief threshold function with a smooth transition (unidimensional) * * @param[in] edge0 low threshold * @param[in] edge1 high threshold * @param[in] x value to test against threshold * @param[out] dest destination */ CGLM_INLINE void glm_vec3_smoothstep_uni(float edge0, float edge1, vec3 x, vec3 dest) { dest[0] = glm_smoothstep(edge0, edge1, x[0]); dest[1] = glm_smoothstep(edge0, edge1, x[1]); dest[2] = glm_smoothstep(edge0, edge1, x[2]); } /*! * @brief threshold function with a smooth transition * * @param[in] edge0 low threshold * @param[in] edge1 high threshold * @param[in] x value to test against threshold * @param[out] dest destination */ CGLM_INLINE void glm_vec3_smoothstep(vec3 edge0, vec3 edge1, vec3 x, vec3 dest) { dest[0] = glm_smoothstep(edge0[0], edge1[0], x[0]); dest[1] = glm_smoothstep(edge0[1], edge1[1], x[1]); dest[2] = glm_smoothstep(edge0[2], edge1[2], x[2]); } /*! * @brief smooth Hermite interpolation between two vectors * * formula: from + s * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) * @param[out] dest destination */ CGLM_INLINE void glm_vec3_smoothinterp(vec3 from, vec3 to, float t, vec3 dest) { vec3 s, v; /* from + s * (to - from) */ glm_vec3_broadcast(glm_smooth(t), s); glm_vec3_sub(to, from, v); glm_vec3_mul(s, v, v); glm_vec3_add(from, v, dest); } /*! * @brief smooth Hermite interpolation between two vectors (clamped) * * formula: from + s * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) clamped between 0 and 1 * @param[out] dest destination */ CGLM_INLINE void glm_vec3_smoothinterpc(vec3 from, vec3 to, float t, vec3 dest) { glm_vec3_smoothinterp(from, to, glm_clamp_zo(t), dest); } /*! * @brief swizzle vector components * * you can use existing masks e.g. GLM_XXX, GLM_ZYX * * @param[in] v source * @param[in] mask mask * @param[out] dest destination */ CGLM_INLINE void glm_vec3_swizzle(vec3 v, int mask, vec3 dest) { vec3 t; t[0] = v[(mask & (3 << 0))]; t[1] = v[(mask & (3 << 2)) >> 2]; t[2] = v[(mask & (3 << 4)) >> 4]; glm_vec3_copy(t, dest); } /*! * @brief vec3 cross product * * this is just convenient wrapper * * @param[in] a source 1 * @param[in] b source 2 * @param[out] d destination */ CGLM_INLINE void glm_cross(vec3 a, vec3 b, vec3 d) { glm_vec3_cross(a, b, d); } /*! * @brief vec3 dot product * * this is just convenient wrapper * * @param[in] a vector1 * @param[in] b vector2 * * @return dot product */ CGLM_INLINE float glm_dot(vec3 a, vec3 b) { return glm_vec3_dot(a, b); } /*! * @brief normalize vec3 and store result in same vec * * this is just convenient wrapper * * @param[in, out] v vector */ CGLM_INLINE void glm_normalize(vec3 v) { glm_vec3_normalize(v); } /*! * @brief normalize vec3 to dest * * this is just convenient wrapper * * @param[in] v source * @param[out] dest destination */ CGLM_INLINE void glm_normalize_to(vec3 v, vec3 dest) { glm_vec3_normalize_to(v, dest); } /*! * @brief Create three dimensional vector from pointer * * @param[in] src pointer to an array of floats * @param[out] dest destination vector */ CGLM_INLINE void glm_vec3_make(const float * __restrict src, vec3 dest) { dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; } /*! * @brief a vector pointing in the same direction as another * * orients a vector to point away from a surface as defined by its normal * * @param[in] n vector to orient * @param[in] v incident vector * @param[in] nref reference vector * @param[out] dest oriented vector, pointing away from the surface */ CGLM_INLINE void glm_vec3_faceforward(vec3 n, vec3 v, vec3 nref, vec3 dest) { if (glm_vec3_dot(v, nref) < 0.0f) { /* N is facing away from I */ glm_vec3_copy(n, dest); } else { /* N is facing towards I, negate it */ glm_vec3_negate_to(n, dest); } } /*! * @brief reflection vector using an incident ray and a surface normal * * @param[in] v incident vector * @param[in] n normalized normal vector * @param[out] dest reflection result */ CGLM_INLINE void glm_vec3_reflect(vec3 v, vec3 n, vec3 dest) { vec3 temp; glm_vec3_scale(n, 2.0f * glm_vec3_dot(v, n), temp); glm_vec3_sub(v, temp, dest); } /*! * @brief computes refraction vector for an incident vector and a surface normal. * * calculates the refraction vector based on Snell's law. If total internal reflection * occurs (angle too great given eta), dest is set to zero and returns false. * Otherwise, computes refraction vector, stores it in dest, and returns true. * * @param[in] v normalized incident vector * @param[in] n normalized normal vector * @param[in] eta ratio of indices of refraction (incident/transmitted) * @param[out] dest refraction vector if refraction occurs; zero vector otherwise * * @returns true if refraction occurs; false if total internal reflection occurs. */ CGLM_INLINE bool glm_vec3_refract(vec3 v, vec3 n, float eta, vec3 dest) { float ndi, eni, k; ndi = glm_vec3_dot(n, v); eni = eta * ndi; k = 1.0f - eta * eta + eni * eni; if (k < 0.0f) { glm_vec3_zero(dest); return false; } glm_vec3_scale(v, eta, dest); glm_vec3_mulsubs(n, eni + sqrtf(k), dest); return true; } /*! * @brief swap two vectors * @param a the first vector to swap * @param b the second vector to swap */ CGLM_INLINE void glm_vec3_swap(vec3 a, vec3 b) { vec3 tmp; glm_vec3_copy(a, tmp); glm_vec3_copy(b, a); glm_vec3_copy(tmp, b); } #endif /* cglm_vec3_h */ cglm-0.9.7/include/cglm/vec4-ext.h000066400000000000000000000214331526744317200166440ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /*! * @brief SIMD like functions */ /* Functions: CGLM_INLINE void glm_vec4_broadcast(float val, vec4 d); CGLM_INLINE void glm_vec4_fill(vec4 v, float val); CGLM_INLINE bool glm_vec4_eq(vec4 v, float val); CGLM_INLINE bool glm_vec4_eq_eps(vec4 v, float val); CGLM_INLINE bool glm_vec4_eq_all(vec4 v); CGLM_INLINE bool glm_vec4_eqv(vec4 a, vec4 b); CGLM_INLINE bool glm_vec4_eqv_eps(vec4 a, vec4 b); CGLM_INLINE float glm_vec4_max(vec4 v); CGLM_INLINE float glm_vec4_min(vec4 v); CGLM_INLINE bool glm_vec4_isnan(vec4 v); CGLM_INLINE bool glm_vec4_isinf(vec4 v); CGLM_INLINE bool glm_vec4_isvalid(vec4 v); CGLM_INLINE void glm_vec4_sign(vec4 v, vec4 dest); CGLM_INLINE void glm_vec4_abs(vec4 v, vec4 dest); CGLM_INLINE void glm_vec4_fract(vec4 v, vec4 dest); CGLM_INLINE void glm_vec4_floor(vec4 v, vec4 dest); CGLM_INLINE float glm_vec4_mods(vec4 v, float s, vec4 dest); CGLM_INLINE float glm_vec4_steps(float edge, vec4 v, vec4 dest); CGLM_INLINE void glm_vec4_stepr(vec4 edge, float v, vec4 dest); CGLM_INLINE float glm_vec4_hadd(vec4 v); CGLM_INLINE void glm_vec4_sqrt(vec4 v, vec4 dest); */ #ifndef cglm_vec4_ext_h #define cglm_vec4_ext_h #include "common.h" #include "vec3-ext.h" /*! * @brief fill a vector with specified value * * @param val value * @param d dest */ CGLM_INLINE void glm_vec4_broadcast(float val, vec4 d) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(d, wasm_f32x4_splat(val)); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(d, glmm_set1(val)); #else d[0] = d[1] = d[2] = d[3] = val; #endif } /*! * @brief fill a vector with specified value * * @param v dest * @param val value */ CGLM_INLINE void glm_vec4_fill(vec4 v, float val) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(v, wasm_f32x4_splat(val)); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(v, glmm_set1(val)); #else v[0] = v[1] = v[2] = v[3] = val; #endif } /*! * @brief check if vector is equal to value (without epsilon) * * @param v vector * @param val value */ CGLM_INLINE bool glm_vec4_eq(vec4 v, float val) { return v[0] == val && v[0] == v[1] && v[0] == v[2] && v[0] == v[3]; } /*! * @brief check if vector is equal to value (with epsilon) * * @param v vector * @param val value */ CGLM_INLINE bool glm_vec4_eq_eps(vec4 v, float val) { return fabsf(v[0] - val) <= GLM_FLT_EPSILON && fabsf(v[1] - val) <= GLM_FLT_EPSILON && fabsf(v[2] - val) <= GLM_FLT_EPSILON && fabsf(v[3] - val) <= GLM_FLT_EPSILON; } /*! * @brief check if vector members are equal (without epsilon) * * @param v vector */ CGLM_INLINE bool glm_vec4_eq_all(vec4 v) { return glm_vec4_eq_eps(v, v[0]); } /*! * @brief check if vector is equal to another (without epsilon) * * @param a vector * @param b vector */ CGLM_INLINE bool glm_vec4_eqv(vec4 a, vec4 b) { return a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3]; } /*! * @brief check if vector is equal to another (with epsilon) * * @param a vector * @param b vector */ CGLM_INLINE bool glm_vec4_eqv_eps(vec4 a, vec4 b) { return fabsf(a[0] - b[0]) <= GLM_FLT_EPSILON && fabsf(a[1] - b[1]) <= GLM_FLT_EPSILON && fabsf(a[2] - b[2]) <= GLM_FLT_EPSILON && fabsf(a[3] - b[3]) <= GLM_FLT_EPSILON; } /*! * @brief max value of vector * * @param v vector */ CGLM_INLINE float glm_vec4_max(vec4 v) { float max; max = glm_vec3_max(v); if (v[3] > max) max = v[3]; return max; } /*! * @brief min value of vector * * @param v vector */ CGLM_INLINE float glm_vec4_min(vec4 v) { float min; min = glm_vec3_min(v); if (v[3] < min) min = v[3]; return min; } /*! * @brief check if one of items is NaN (not a number) * you should only use this in DEBUG mode or very critical asserts * * @param[in] v vector */ CGLM_INLINE bool glm_vec4_isnan(vec4 v) { #ifndef CGLM_FAST_MATH return isnan(v[0]) || isnan(v[1]) || isnan(v[2]) || isnan(v[3]); #else (void)v; return false; #endif } /*! * @brief check if one of items is INFINITY * you should only use this in DEBUG mode or very critical asserts * * @param[in] v vector */ CGLM_INLINE bool glm_vec4_isinf(vec4 v) { #ifndef CGLM_FAST_MATH return isinf(v[0]) || isinf(v[1]) || isinf(v[2]) || isinf(v[3]); #else (void)v; return false; #endif } /*! * @brief check if all items are valid number * you should only use this in DEBUG mode or very critical asserts * * @param[in] v vector */ CGLM_INLINE bool glm_vec4_isvalid(vec4 v) { return !glm_vec4_isnan(v) && !glm_vec4_isinf(v); } /*! * @brief get sign of 32 bit float as +1, -1, 0 * * Important: It returns 0 for zero/NaN input * * @param v vector */ CGLM_INLINE void glm_vec4_sign(vec4 v, vec4 dest) { #if defined( __SSE__ ) || defined( __SSE2__ ) __m128 x0, x1, x2, x3, x4; x0 = glmm_load(v); x1 = _mm_set_ps(0.0f, 0.0f, 1.0f, -1.0f); x2 = glmm_splat(x1, 2); x3 = _mm_and_ps(_mm_cmpgt_ps(x0, x2), glmm_splat(x1, 1)); x4 = _mm_and_ps(_mm_cmplt_ps(x0, x2), glmm_splat(x1, 0)); glmm_store(dest, _mm_or_ps(x3, x4)); #else dest[0] = glm_signf(v[0]); dest[1] = glm_signf(v[1]); dest[2] = glm_signf(v[2]); dest[3] = glm_signf(v[3]); #endif } /*! * @brief absolute value of each vector item * * @param[in] v vector * @param[out] dest destination vector */ CGLM_INLINE void glm_vec4_abs(vec4 v, vec4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(dest, glmm_abs(glmm_load(v))); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, glmm_abs(glmm_load(v))); #elif defined(CGLM_NEON_FP) vst1q_f32(dest, vabsq_f32(vld1q_f32(v))); #else dest[0] = fabsf(v[0]); dest[1] = fabsf(v[1]); dest[2] = fabsf(v[2]); dest[3] = fabsf(v[3]); #endif } /*! * @brief fractional part of each vector item * * @param[in] v vector * @param[out] dest destination vector */ CGLM_INLINE void glm_vec4_fract(vec4 v, vec4 dest) { dest[0] = fminf(v[0] - floorf(v[0]), 0.999999940395355224609375f); dest[1] = fminf(v[1] - floorf(v[1]), 0.999999940395355224609375f); dest[2] = fminf(v[2] - floorf(v[2]), 0.999999940395355224609375f); dest[3] = fminf(v[3] - floorf(v[3]), 0.999999940395355224609375f); } /*! * @brief floor of each vector item * * @param[in] v vector * @param[out] dest destination vector */ CGLM_INLINE void glm_vec4_floor(vec4 v, vec4 dest) { dest[0] = floorf(v[0]); dest[1] = floorf(v[1]); dest[2] = floorf(v[2]); dest[3] = floorf(v[3]); } /*! * @brief mod of each vector item, result is written to dest (dest = v % s) * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination vector */ CGLM_INLINE void glm_vec4_mods(vec4 v, float s, vec4 dest) { dest[0] = fmodf(v[0], s); dest[1] = fmodf(v[1], s); dest[2] = fmodf(v[2], s); dest[3] = fmodf(v[3], s); } /*! * @brief threshold each vector item with scalar * condition is: (x[i] < edge) ? 0.0 : 1.0 * * @param[in] edge threshold * @param[in] x vector to test against threshold * @param[out] dest destination */ CGLM_INLINE void glm_vec4_steps(float edge, vec4 x, vec4 dest) { dest[0] = glm_step(edge, x[0]); dest[1] = glm_step(edge, x[1]); dest[2] = glm_step(edge, x[2]); dest[3] = glm_step(edge, x[3]); } /*! * @brief threshold a value with *vector* as the threshold * condition is: (x < edge[i]) ? 0.0 : 1.0 * * @param[in] edge threshold vector * @param[in] x value to test against threshold * @param[out] dest destination */ CGLM_INLINE void glm_vec4_stepr(vec4 edge, float x, vec4 dest) { dest[0] = glm_step(edge[0], x); dest[1] = glm_step(edge[1], x); dest[2] = glm_step(edge[2], x); dest[3] = glm_step(edge[3], x); } /*! * @brief vector reduction by summation * @warning could overflow * * @param[in] v vector * @return sum of all vector's elements */ CGLM_INLINE float glm_vec4_hadd(vec4 v) { #if defined(__wasm__) && defined(__wasm_simd128__) return glmm_hadd(glmm_load(v)); #elif defined( __SSE__ ) || defined( __SSE2__ ) return glmm_hadd(glmm_load(v)); #else return v[0] + v[1] + v[2] + v[3]; #endif } /*! * @brief square root of each vector item * * @param[in] v vector * @param[out] dest destination vector */ CGLM_INLINE void glm_vec4_sqrt(vec4 v, vec4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(dest, wasm_f32x4_sqrt(glmm_load(v))); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_sqrt_ps(glmm_load(v))); #else dest[0] = sqrtf(v[0]); dest[1] = sqrtf(v[1]); dest[2] = sqrtf(v[2]); dest[3] = sqrtf(v[3]); #endif } #endif /* cglm_vec4_ext_h */ cglm-0.9.7/include/cglm/vec4.h000066400000000000000000001062071526744317200160510ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* Macros: GLM_VEC4_ONE_INIT GLM_VEC4_BLACK_INIT GLM_VEC4_ZERO_INIT GLM_VEC4_ONE GLM_VEC4_BLACK GLM_VEC4_ZERO Functions: CGLM_INLINE void glm_vec4(vec3 v3, float last, vec4 dest); CGLM_INLINE void glm_vec4_copy3(vec4 a, vec3 dest); CGLM_INLINE void glm_vec4_copy(vec4 v, vec4 dest); CGLM_INLINE void glm_vec4_ucopy(vec4 v, vec4 dest); CGLM_INLINE float glm_vec4_dot(vec4 a, vec4 b); CGLM_INLINE float glm_vec4_norm2(vec4 v); CGLM_INLINE float glm_vec4_norm(vec4 v); CGLM_INLINE float glm_vec4_norm_one(vec4 v); CGLM_INLINE float glm_vec4_norm_inf(vec4 v); CGLM_INLINE void glm_vec4_add(vec4 a, vec4 b, vec4 dest); CGLM_INLINE void glm_vec4_adds(vec4 v, float s, vec4 dest); CGLM_INLINE void glm_vec4_sub(vec4 a, vec4 b, vec4 dest); CGLM_INLINE void glm_vec4_subs(vec4 v, float s, vec4 dest); CGLM_INLINE void glm_vec4_mul(vec4 a, vec4 b, vec4 dest); CGLM_INLINE void glm_vec4_scale(vec4 v, float s, vec4 dest); CGLM_INLINE void glm_vec4_scale_as(vec4 v, float s, vec4 dest); CGLM_INLINE void glm_vec4_div(vec4 a, vec4 b, vec4 dest); CGLM_INLINE void glm_vec4_divs(vec4 v, float s, vec4 dest); CGLM_INLINE void glm_vec4_addadd(vec4 a, vec4 b, vec4 dest); CGLM_INLINE void glm_vec4_subadd(vec4 a, vec4 b, vec4 dest); CGLM_INLINE void glm_vec4_muladd(vec4 a, vec4 b, vec4 dest); CGLM_INLINE void glm_vec4_muladds(vec4 a, float s, vec4 dest); CGLM_INLINE void glm_vec4_maxadd(vec4 a, vec4 b, vec4 dest); CGLM_INLINE void glm_vec4_minadd(vec4 a, vec4 b, vec4 dest); CGLM_INLINE void glm_vec4_subsub(vec4 a, vec4 b, vec4 dest); CGLM_INLINE void glm_vec4_addsub(vec4 a, vec4 b, vec4 dest); CGLM_INLINE void glm_vec4_mulsub(vec4 a, vec4 b, vec4 dest); CGLM_INLINE void glm_vec4_mulsubs(vec4 a, float s, vec4 dest); CGLM_INLINE void glm_vec4_maxsub(vec4 a, vec4 b, vec4 dest); CGLM_INLINE void glm_vec4_minsub(vec4 a, vec4 b, vec4 dest); CGLM_INLINE void glm_vec4_negate(vec4 v); CGLM_INLINE void glm_vec4_inv(vec4 v); CGLM_INLINE void glm_vec4_inv_to(vec4 v, vec4 dest); CGLM_INLINE void glm_vec4_normalize(vec4 v); CGLM_INLINE void glm_vec4_normalize_to(vec4 vec, vec4 dest); CGLM_INLINE float glm_vec4_distance(vec4 a, vec4 b); CGLM_INLINE float glm_vec4_distance2(vec4 a, vec4 b); CGLM_INLINE void glm_vec4_maxv(vec4 a, vec4 b, vec4 dest); CGLM_INLINE void glm_vec4_minv(vec4 a, vec4 b, vec4 dest); CGLM_INLINE void glm_vec4_clamp(vec4 v, float minVal, float maxVal); CGLM_INLINE void glm_vec4_lerp(vec4 from, vec4 to, float t, vec4 dest); CGLM_INLINE void glm_vec4_lerpc(vec4 from, vec4 to, float t, vec4 dest); CGLM_INLINE void glm_vec4_step(vec4 edge, vec4 x, vec4 dest); CGLM_INLINE void glm_vec4_smoothstep_uni(float edge0, float edge1, vec4 x, vec4 dest); CGLM_INLINE void glm_vec4_smoothstep(vec4 edge0, vec4 edge1, vec4 x, vec4 dest); CGLM_INLINE void glm_vec4_smoothinterp(vec4 from, vec4 to, float t, vec4 dest); CGLM_INLINE void glm_vec4_smoothinterpc(vec4 from, vec4 to, float t, vec4 dest); CGLM_INLINE void glm_vec4_swizzle(vec4 v, int mask, vec4 dest); CGLM_INLINE void glm_vec4_make(float * restrict src, vec4 dest); CGLM_INLINE void glm_vec4_reflect(vec4 v, vec4 n, vec4 dest); CGLM_INLINE void glm_vec4_refract(vec4 v, vec4 n, float eta, vec4 dest); CGLM_INLINE void glm_vec4_swap(vec4 a, vec4 b) DEPRECATED: glm_vec4_dup glm_vec4_flipsign glm_vec4_flipsign_to glm_vec4_inv glm_vec4_inv_to glm_vec4_mulv glm_vec4_step_uni --> use glm_vec4_steps */ #ifndef cglm_vec4_h #define cglm_vec4_h #include "common.h" #include "vec4-ext.h" #include "util.h" /* DEPRECATED! functions */ #define glm_vec4_dup3(v, dest) glm_vec4_copy3(v, dest) #define glm_vec4_dup(v, dest) glm_vec4_copy(v, dest) #define glm_vec4_flipsign(v) glm_vec4_negate(v) #define glm_vec4_flipsign_to(v, dest) glm_vec4_negate_to(v, dest) #define glm_vec4_inv(v) glm_vec4_negate(v) #define glm_vec4_inv_to(v, dest) glm_vec4_negate_to(v, dest) #define glm_vec4_mulv(a, b, d) glm_vec4_mul(a, b, d) #define glm_vec4_step_uni(edge, x, dest) glm_vec4_steps(edge, x, dest) #define GLM_VEC4_ONE_INIT {1.0f, 1.0f, 1.0f, 1.0f} #define GLM_VEC4_BLACK_INIT {0.0f, 0.0f, 0.0f, 1.0f} #define GLM_VEC4_ZERO_INIT {0.0f, 0.0f, 0.0f, 0.0f} #define GLM_VEC4_ONE ((vec4)GLM_VEC4_ONE_INIT) #define GLM_VEC4_BLACK ((vec4)GLM_VEC4_BLACK_INIT) #define GLM_VEC4_ZERO ((vec4)GLM_VEC4_ZERO_INIT) #define GLM_XXXX GLM_SHUFFLE4(0, 0, 0, 0) #define GLM_YYYY GLM_SHUFFLE4(1, 1, 1, 1) #define GLM_ZZZZ GLM_SHUFFLE4(2, 2, 2, 2) #define GLM_WWWW GLM_SHUFFLE4(3, 3, 3, 3) #define GLM_WZYX GLM_SHUFFLE4(0, 1, 2, 3) /*! * @brief init vec4 using vec3 * * @param[in] v3 vector3 * @param[in] last last item * @param[out] dest destination */ CGLM_INLINE void glm_vec4(vec3 v3, float last, vec4 dest) { dest[0] = v3[0]; dest[1] = v3[1]; dest[2] = v3[2]; dest[3] = last; } /*! * @brief copy first 3 members of [a] to [dest] * * @param[in] a source * @param[out] dest destination */ CGLM_INLINE void glm_vec4_copy3(vec4 a, vec3 dest) { dest[0] = a[0]; dest[1] = a[1]; dest[2] = a[2]; } /*! * @brief copy all members of [a] to [dest] * * @param[in] v source * @param[out] dest destination */ CGLM_INLINE void glm_vec4_copy(vec4 v, vec4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(dest, glmm_load(v)); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, glmm_load(v)); #elif defined(CGLM_NEON_FP) vst1q_f32(dest, vld1q_f32(v)); #else dest[0] = v[0]; dest[1] = v[1]; dest[2] = v[2]; dest[3] = v[3]; #endif } /*! * @brief copy all members of [a] to [dest] * * alignment is not required * * @param[in] v source * @param[out] dest destination */ CGLM_INLINE void glm_vec4_ucopy(vec4 v, vec4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) /* note here wasm v128.load/v128.store support unaligned loads and stores */ wasm_v128_store(dest, wasm_v128_load(v)); #else dest[0] = v[0]; dest[1] = v[1]; dest[2] = v[2]; dest[3] = v[3]; #endif } /*! * @brief make vector zero * * @param[in, out] v vector */ CGLM_INLINE void glm_vec4_zero(vec4 v) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(v, wasm_f32x4_const_splat(0.f)); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(v, _mm_setzero_ps()); #elif defined(CGLM_NEON_FP) vst1q_f32(v, vdupq_n_f32(0.0f)); #else v[0] = 0.0f; v[1] = 0.0f; v[2] = 0.0f; v[3] = 0.0f; #endif } /*! * @brief make vector one * * @param[in, out] v vector */ CGLM_INLINE void glm_vec4_one(vec4 v) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(v, wasm_f32x4_const_splat(1.0f)); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(v, glmm_set1_rval(1.0f)); #elif defined(CGLM_NEON_FP) vst1q_f32(v, vdupq_n_f32(1.0f)); #else v[0] = 1.0f; v[1] = 1.0f; v[2] = 1.0f; v[3] = 1.0f; #endif } /*! * @brief vec4 dot product * * @param[in] a vector1 * @param[in] b vector2 * * @return dot product */ CGLM_INLINE float glm_vec4_dot(vec4 a, vec4 b) { #if defined(CGLM_SIMD) return glmm_dot(glmm_load(a), glmm_load(b)); #else return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; #endif } /*! * @brief norm * norm (magnitude) of vec * * we can use this func instead of calling norm * norm, because it would call * sqrtf function twice but with this func we can avoid func call, maybe this is * not good name for this func * * @param[in] v vec4 * * @return norm * norm */ CGLM_INLINE float glm_vec4_norm2(vec4 v) { return glm_vec4_dot(v, v); } /*! * @brief euclidean norm (magnitude), also called L2 norm * this will give magnitude of vector in euclidean space * * @param[in] v vector * * @return norm */ CGLM_INLINE float glm_vec4_norm(vec4 v) { #if defined(CGLM_SIMD) return glmm_norm(glmm_load(v)); #else return sqrtf(glm_vec4_dot(v, v)); #endif } /*! * @brief L1 norm of vec4 * Also known as Manhattan Distance or Taxicab norm. * L1 Norm is the sum of the magnitudes of the vectors in a space. * It is calculated as the sum of the absolute values of the vector components. * In this norm, all the components of the vector are weighted equally. * * This computes: * L1 norm = |v[0]| + |v[1]| + |v[2]| + |v[3]| * * @param[in] v vector * * @return L1 norm */ CGLM_INLINE float glm_vec4_norm_one(vec4 v) { #if defined(CGLM_SIMD) return glmm_norm_one(glmm_load(v)); #else vec4 t; glm_vec4_abs(v, t); return glm_vec4_hadd(t); #endif } /*! * @brief infinity norm of vec4 * Also known as Maximum norm. * Infinity Norm is the largest magnitude among each element of a vector. * It is calculated as the maximum of the absolute values of the vector components. * * This computes: * inf norm = max(|v[0]|, |v[1]|, |v[2]|, |v[3]|) * * @param[in] v vector * * @return infinity norm */ CGLM_INLINE float glm_vec4_norm_inf(vec4 v) { #if defined(CGLM_SIMD) return glmm_norm_inf(glmm_load(v)); #else vec4 t; glm_vec4_abs(v, t); return glm_vec4_max(t); #endif } /*! * @brief add b vector to a vector store result in dest * * @param[in] a vector1 * @param[in] b vector2 * @param[out] dest destination vector */ CGLM_INLINE void glm_vec4_add(vec4 a, vec4 b, vec4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(dest, wasm_f32x4_add(glmm_load(a), glmm_load(b))); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_add_ps(glmm_load(a), glmm_load(b))); #elif defined(CGLM_NEON_FP) vst1q_f32(dest, vaddq_f32(vld1q_f32(a), vld1q_f32(b))); #else dest[0] = a[0] + b[0]; dest[1] = a[1] + b[1]; dest[2] = a[2] + b[2]; dest[3] = a[3] + b[3]; #endif } /*! * @brief add scalar to v vector store result in dest (d = v + vec(s)) * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination vector */ CGLM_INLINE void glm_vec4_adds(vec4 v, float s, vec4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(dest, wasm_f32x4_add(glmm_load(v), wasm_f32x4_splat(s))); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_add_ps(glmm_load(v), glmm_set1(s))); #elif defined(CGLM_NEON_FP) vst1q_f32(dest, vaddq_f32(vld1q_f32(v), vdupq_n_f32(s))); #else dest[0] = v[0] + s; dest[1] = v[1] + s; dest[2] = v[2] + s; dest[3] = v[3] + s; #endif } /*! * @brief subtract b vector from a vector store result in dest (d = a - b) * * @param[in] a vector1 * @param[in] b vector2 * @param[out] dest destination vector */ CGLM_INLINE void glm_vec4_sub(vec4 a, vec4 b, vec4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(dest, wasm_f32x4_sub(glmm_load(a), glmm_load(b))); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_sub_ps(glmm_load(a), glmm_load(b))); #elif defined(CGLM_NEON_FP) vst1q_f32(dest, vsubq_f32(vld1q_f32(a), vld1q_f32(b))); #else dest[0] = a[0] - b[0]; dest[1] = a[1] - b[1]; dest[2] = a[2] - b[2]; dest[3] = a[3] - b[3]; #endif } /*! * @brief subtract scalar from v vector store result in dest (d = v - vec(s)) * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination vector */ CGLM_INLINE void glm_vec4_subs(vec4 v, float s, vec4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(dest, wasm_f32x4_sub(glmm_load(v), wasm_f32x4_splat(s))); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_sub_ps(glmm_load(v), glmm_set1(s))); #elif defined(CGLM_NEON_FP) vst1q_f32(dest, vsubq_f32(vld1q_f32(v), vdupq_n_f32(s))); #else dest[0] = v[0] - s; dest[1] = v[1] - s; dest[2] = v[2] - s; dest[3] = v[3] - s; #endif } /*! * @brief multiply two vectors (component-wise multiplication) * * @param a vector1 * @param b vector2 * @param dest dest = (a[0] * b[0], a[1] * b[1], a[2] * b[2], a[3] * b[3]) */ CGLM_INLINE void glm_vec4_mul(vec4 a, vec4 b, vec4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(dest, wasm_f32x4_mul(glmm_load(a), glmm_load(b))); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_mul_ps(glmm_load(a), glmm_load(b))); #elif defined(CGLM_NEON_FP) vst1q_f32(dest, vmulq_f32(vld1q_f32(a), vld1q_f32(b))); #else dest[0] = a[0] * b[0]; dest[1] = a[1] * b[1]; dest[2] = a[2] * b[2]; dest[3] = a[3] * b[3]; #endif } /*! * @brief multiply/scale vec4 vector with scalar: result = v * s * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination vector */ CGLM_INLINE void glm_vec4_scale(vec4 v, float s, vec4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(dest, wasm_f32x4_mul(glmm_load(v), wasm_f32x4_splat(s))); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_mul_ps(glmm_load(v), glmm_set1(s))); #elif defined(CGLM_NEON_FP) vst1q_f32(dest, vmulq_f32(vld1q_f32(v), vdupq_n_f32(s))); #else dest[0] = v[0] * s; dest[1] = v[1] * s; dest[2] = v[2] * s; dest[3] = v[3] * s; #endif } /*! * @brief make vec4 vector scale as specified: result = unit(v) * s * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination vector */ CGLM_INLINE void glm_vec4_scale_as(vec4 v, float s, vec4 dest) { float norm; norm = glm_vec4_norm(v); if (CGLM_UNLIKELY(norm < FLT_EPSILON)) { glm_vec4_zero(dest); return; } glm_vec4_scale(v, s / norm, dest); } /*! * @brief div vector with another component-wise division: d = a / b * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest result = (a[0]/b[0], a[1]/b[1], a[2]/b[2], a[3]/b[3]) */ CGLM_INLINE void glm_vec4_div(vec4 a, vec4 b, vec4 dest) { #if defined(CGLM_SIMD) glmm_store(dest, glmm_div(glmm_load(a), glmm_load(b))); #else dest[0] = a[0] / b[0]; dest[1] = a[1] / b[1]; dest[2] = a[2] / b[2]; dest[3] = a[3] / b[3]; #endif } /*! * @brief div vec4 vector with scalar: d = v / s * * @param[in] v vector * @param[in] s scalar * @param[out] dest destination vector */ CGLM_INLINE void glm_vec4_divs(vec4 v, float s, vec4 dest) { #if defined(CGLM_SIMD) glmm_store(dest, glmm_div(glmm_load(v), glmm_set1(s))); #else glm_vec4_scale(v, 1.0f / s, dest); #endif } /*! * @brief add two vectors and add result to sum * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest += (a + b) */ CGLM_INLINE void glm_vec4_addadd(vec4 a, vec4 b, vec4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(dest, wasm_f32x4_add( glmm_load(dest), wasm_f32x4_add(glmm_load(a), glmm_load(b)))); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_add_ps(glmm_load(dest), _mm_add_ps(glmm_load(a), glmm_load(b)))); #elif defined(CGLM_NEON_FP) vst1q_f32(dest, vaddq_f32(vld1q_f32(dest), vaddq_f32(vld1q_f32(a), vld1q_f32(b)))); #else dest[0] += a[0] + b[0]; dest[1] += a[1] + b[1]; dest[2] += a[2] + b[2]; dest[3] += a[3] + b[3]; #endif } /*! * @brief sub two vectors and add result to dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest += (a - b) */ CGLM_INLINE void glm_vec4_subadd(vec4 a, vec4 b, vec4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(dest, wasm_f32x4_add( glmm_load(dest), wasm_f32x4_sub(glmm_load(a), glmm_load(b)))); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_add_ps(glmm_load(dest), _mm_sub_ps(glmm_load(a), glmm_load(b)))); #elif defined(CGLM_NEON_FP) vst1q_f32(dest, vaddq_f32(vld1q_f32(dest), vsubq_f32(vld1q_f32(a), vld1q_f32(b)))); #else dest[0] += a[0] - b[0]; dest[1] += a[1] - b[1]; dest[2] += a[2] - b[2]; dest[3] += a[3] - b[3]; #endif } /*! * @brief mul two vectors and add result to dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest += (a * b) */ CGLM_INLINE void glm_vec4_muladd(vec4 a, vec4 b, vec4 dest) { #if defined(CGLM_SIMD) glmm_store(dest, glmm_fmadd(glmm_load(a), glmm_load(b), glmm_load(dest))); #else dest[0] += a[0] * b[0]; dest[1] += a[1] * b[1]; dest[2] += a[2] * b[2]; dest[3] += a[3] * b[3]; #endif } /*! * @brief mul vector with scalar and add result to sum * * it applies += operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[out] dest dest += (a * b) */ CGLM_INLINE void glm_vec4_muladds(vec4 a, float s, vec4 dest) { #if defined(CGLM_SIMD) glmm_store(dest, glmm_fmadd(glmm_load(a), glmm_set1(s), glmm_load(dest))); #else dest[0] += a[0] * s; dest[1] += a[1] * s; dest[2] += a[2] * s; dest[3] += a[3] * s; #endif } /*! * @brief add max of two vectors to result/dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest += max(a, b) */ CGLM_INLINE void glm_vec4_maxadd(vec4 a, vec4 b, vec4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(dest, wasm_f32x4_add(glmm_load(dest), glmm_max(glmm_load(a), glmm_load(b)))); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_add_ps(glmm_load(dest), glmm_max(glmm_load(a), glmm_load(b)))); #elif defined(CGLM_NEON_FP) glmm_store(dest, vaddq_f32(glmm_load(dest), glmm_max(glmm_load(a), glmm_load(b)))); #else dest[0] += glm_max(a[0], b[0]); dest[1] += glm_max(a[1], b[1]); dest[2] += glm_max(a[2], b[2]); dest[3] += glm_max(a[3], b[3]); #endif } /*! * @brief add min of two vectors to result/dest * * it applies += operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest += min(a, b) */ CGLM_INLINE void glm_vec4_minadd(vec4 a, vec4 b, vec4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(dest, wasm_f32x4_add(glmm_load(dest), glmm_min(glmm_load(a), glmm_load(b)))); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_add_ps(glmm_load(dest), glmm_min(glmm_load(a), glmm_load(b)))); #elif defined(CGLM_NEON_FP) glmm_store(dest, vaddq_f32(glmm_load(dest), glmm_min(glmm_load(a), glmm_load(b)))); #else dest[0] += glm_min(a[0], b[0]); dest[1] += glm_min(a[1], b[1]); dest[2] += glm_min(a[2], b[2]); dest[3] += glm_min(a[3], b[3]); #endif } /*! * @brief sub two vectors and sub result to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest -= (a - b) */ CGLM_INLINE void glm_vec4_subsub(vec4 a, vec4 b, vec4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(dest, wasm_f32x4_sub( glmm_load(dest), wasm_f32x4_sub(glmm_load(a), glmm_load(b)))); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_sub_ps(glmm_load(dest), _mm_sub_ps(glmm_load(a), glmm_load(b)))); #elif defined(CGLM_NEON_FP) vst1q_f32(dest, vsubq_f32(vld1q_f32(dest), vsubq_f32(vld1q_f32(a), vld1q_f32(b)))); #else dest[0] -= a[0] - b[0]; dest[1] -= a[1] - b[1]; dest[2] -= a[2] - b[2]; dest[3] -= a[3] - b[3]; #endif } /*! * @brief add two vectors and sub result to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest -= (a + b) */ CGLM_INLINE void glm_vec4_addsub(vec4 a, vec4 b, vec4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(dest, wasm_f32x4_sub( glmm_load(dest), wasm_f32x4_add(glmm_load(a), glmm_load(b)))); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_sub_ps(glmm_load(dest), _mm_add_ps(glmm_load(a), glmm_load(b)))); #elif defined(CGLM_NEON_FP) vst1q_f32(dest, vsubq_f32(vld1q_f32(dest), vaddq_f32(vld1q_f32(a), vld1q_f32(b)))); #else dest[0] -= a[0] + b[0]; dest[1] -= a[1] + b[1]; dest[2] -= a[2] + b[2]; dest[3] -= a[3] + b[3]; #endif } /*! * @brief mul two vectors and sub result to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest -= (a * b) */ CGLM_INLINE void glm_vec4_mulsub(vec4 a, vec4 b, vec4 dest) { #if defined(CGLM_SIMD) glmm_store(dest, glmm_fnmadd(glmm_load(a), glmm_load(b), glmm_load(dest))); #else dest[0] -= a[0] * b[0]; dest[1] -= a[1] * b[1]; dest[2] -= a[2] * b[2]; dest[3] -= a[3] * b[3]; #endif } /*! * @brief mul vector with scalar and sub result to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector * @param[in] s scalar * @param[out] dest dest -= (a * b) */ CGLM_INLINE void glm_vec4_mulsubs(vec4 a, float s, vec4 dest) { #if defined(CGLM_SIMD) glmm_store(dest, glmm_fnmadd(glmm_load(a), glmm_set1(s), glmm_load(dest))); #else dest[0] -= a[0] * s; dest[1] -= a[1] * s; dest[2] -= a[2] * s; dest[3] -= a[3] * s; #endif } /*! * @brief sub max of two vectors to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest -= max(a, b) */ CGLM_INLINE void glm_vec4_maxsub(vec4 a, vec4 b, vec4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(dest, wasm_f32x4_sub(glmm_load(dest), glmm_max(glmm_load(a), glmm_load(b)))); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_sub_ps(glmm_load(dest), glmm_max(glmm_load(a), glmm_load(b)))); #elif defined(CGLM_NEON_FP) glmm_store(dest, vsubq_f32(glmm_load(dest), glmm_max(glmm_load(a), glmm_load(b)))); #else dest[0] -= glm_max(a[0], b[0]); dest[1] -= glm_max(a[1], b[1]); dest[2] -= glm_max(a[2], b[2]); dest[3] -= glm_max(a[3], b[3]); #endif } /*! * @brief sub min of two vectors to dest * * it applies -= operator so dest must be initialized * * @param[in] a vector 1 * @param[in] b vector 2 * @param[out] dest dest -= min(a, b) */ CGLM_INLINE void glm_vec4_minsub(vec4 a, vec4 b, vec4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(dest, wasm_f32x4_sub(glmm_load(dest), glmm_min(glmm_load(a), glmm_load(b)))); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_sub_ps(glmm_load(dest), glmm_min(glmm_load(a), glmm_load(b)))); #elif defined(CGLM_NEON_FP) glmm_store(dest, vsubq_f32(vld1q_f32(dest), glmm_min(glmm_load(a), glmm_load(b)))); #else dest[0] -= glm_min(a[0], b[0]); dest[1] -= glm_min(a[1], b[1]); dest[2] -= glm_min(a[2], b[2]); dest[3] -= glm_min(a[3], b[3]); #endif } /*! * @brief negate vector components and store result in dest * * @param[in] v vector * @param[out] dest result vector */ CGLM_INLINE void glm_vec4_negate_to(vec4 v, vec4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(dest, wasm_f32x4_neg(glmm_load(v))); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(dest, _mm_xor_ps(glmm_load(v), glmm_float32x4_SIGNMASK_NEG)); #elif defined(CGLM_NEON_FP) vst1q_f32(dest, vnegq_f32(vld1q_f32(v))); #else dest[0] = -v[0]; dest[1] = -v[1]; dest[2] = -v[2]; dest[3] = -v[3]; #endif } /*! * @brief flip sign of all vec4 members * * @param[in, out] v vector */ CGLM_INLINE void glm_vec4_negate(vec4 v) { glm_vec4_negate_to(v, v); } /*! * @brief normalize vec4 to dest * * @param[in] v source * @param[out] dest destination */ CGLM_INLINE void glm_vec4_normalize_to(vec4 v, vec4 dest) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_128 xdot, x0; float dot; x0 = glmm_load(v); xdot = glmm_vdot(x0, x0); /* dot = _mm_cvtss_f32(xdot); */ dot = wasm_f32x4_extract_lane(xdot, 0); if (CGLM_UNLIKELY(dot < FLT_EPSILON)) { glmm_store(dest, wasm_f32x4_const_splat(0.f)); return; } glmm_store(dest, glmm_div(x0, wasm_f32x4_sqrt(xdot))); #elif defined( __SSE__ ) || defined( __SSE2__ ) __m128 xdot, x0; float dot; x0 = glmm_load(v); xdot = glmm_vdot(x0, x0); dot = _mm_cvtss_f32(xdot); if (CGLM_UNLIKELY(dot < FLT_EPSILON)) { glmm_store(dest, _mm_setzero_ps()); return; } glmm_store(dest, glmm_div(x0, _mm_sqrt_ps(xdot))); #else float norm; norm = glm_vec4_norm(v); if (CGLM_UNLIKELY(norm < FLT_EPSILON)) { glm_vec4_zero(dest); return; } glm_vec4_scale(v, 1.0f / norm, dest); #endif } /*! * @brief normalize vec4 and store result in same vec * * @param[in, out] v vector */ CGLM_INLINE void glm_vec4_normalize(vec4 v) { glm_vec4_normalize_to(v, v); } /** * @brief distance between two vectors * * @param[in] a vector1 * @param[in] b vector2 * @return returns distance */ CGLM_INLINE float glm_vec4_distance(vec4 a, vec4 b) { #if defined(__wasm__) && defined(__wasm_simd128__) return glmm_norm(wasm_f32x4_sub(glmm_load(a), glmm_load(b))); #elif defined( __SSE__ ) || defined( __SSE2__ ) return glmm_norm(_mm_sub_ps(glmm_load(a), glmm_load(b))); #elif defined(CGLM_NEON_FP) return glmm_norm(vsubq_f32(glmm_load(a), glmm_load(b))); #else return sqrtf(glm_pow2(a[0] - b[0]) + glm_pow2(a[1] - b[1]) + glm_pow2(a[2] - b[2]) + glm_pow2(a[3] - b[3])); #endif } /** * @brief squared distance between two vectors * * @param[in] a vector1 * @param[in] b vector2 * @return returns squared distance */ CGLM_INLINE float glm_vec4_distance2(vec4 a, vec4 b) { #if defined(__wasm__) && defined(__wasm_simd128__) return glmm_norm2(wasm_f32x4_sub(glmm_load(a), glmm_load(b))); #elif defined( __SSE__ ) || defined( __SSE2__ ) return glmm_norm2(_mm_sub_ps(glmm_load(a), glmm_load(b))); #elif defined(CGLM_NEON_FP) return glmm_norm2(vsubq_f32(glmm_load(a), glmm_load(b))); #else return glm_pow2(a[0] - b[0]) + glm_pow2(a[1] - b[1]) + glm_pow2(a[2] - b[2]) + glm_pow2(a[3] - b[3]); #endif } /*! * @brief max values of vectors * * @param[in] a vector1 * @param[in] b vector2 * @param[out] dest destination */ CGLM_INLINE void glm_vec4_maxv(vec4 a, vec4 b, vec4 dest) { #if defined(CGLM_SIMD) glmm_store(dest, glmm_max(glmm_load(a), glmm_load(b))); #else dest[0] = glm_max(a[0], b[0]); dest[1] = glm_max(a[1], b[1]); dest[2] = glm_max(a[2], b[2]); dest[3] = glm_max(a[3], b[3]); #endif } /*! * @brief min values of vectors * * @param[in] a vector1 * @param[in] b vector2 * @param[out] dest destination */ CGLM_INLINE void glm_vec4_minv(vec4 a, vec4 b, vec4 dest) { #if defined(CGLM_SIMD) glmm_store(dest, glmm_min(glmm_load(a), glmm_load(b))); #else dest[0] = glm_min(a[0], b[0]); dest[1] = glm_min(a[1], b[1]); dest[2] = glm_min(a[2], b[2]); dest[3] = glm_min(a[3], b[3]); #endif } /*! * @brief clamp vector's individual members between min and max values * * @param[in, out] v vector * @param[in] minVal minimum value * @param[in] maxVal maximum value */ CGLM_INLINE void glm_vec4_clamp(vec4 v, float minVal, float maxVal) { #if defined(__wasm__) && defined(__wasm_simd128__) glmm_store(v, glmm_min(glmm_max(glmm_load(v), wasm_f32x4_splat(minVal)), wasm_f32x4_splat(maxVal))); #elif defined( __SSE__ ) || defined( __SSE2__ ) glmm_store(v, glmm_min(glmm_max(glmm_load(v), glmm_set1(minVal)), glmm_set1(maxVal))); #elif defined(CGLM_NEON_FP) glmm_store(v, glmm_min(glmm_max(vld1q_f32(v), vdupq_n_f32(minVal)), vdupq_n_f32(maxVal))); #else v[0] = glm_clamp(v[0], minVal, maxVal); v[1] = glm_clamp(v[1], minVal, maxVal); v[2] = glm_clamp(v[2], minVal, maxVal); v[3] = glm_clamp(v[3], minVal, maxVal); #endif } /*! * @brief linear interpolation between two vectors * * formula: from + t * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) * @param[out] dest destination */ CGLM_INLINE void glm_vec4_lerp(vec4 from, vec4 to, float t, vec4 dest) { vec4 s, v; /* from + s * (to - from) */ glm_vec4_broadcast(t, s); glm_vec4_sub(to, from, v); glm_vec4_mul(s, v, v); glm_vec4_add(from, v, dest); } /*! * @brief linear interpolation between two vectors (clamped) * * formula: from + t * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) clamped between 0 and 1 * @param[out] dest destination */ CGLM_INLINE void glm_vec4_lerpc(vec4 from, vec4 to, float t, vec4 dest) { glm_vec4_lerp(from, to, glm_clamp_zo(t), dest); } /*! * @brief linear interpolation between two vectors * * formula: from + t * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) * @param[out] dest destination */ CGLM_INLINE void glm_vec4_mix(vec4 from, vec4 to, float t, vec4 dest) { glm_vec4_lerp(from, to, t, dest); } /*! * @brief linear interpolation between two vectors (clamped) * * formula: from + t * (to - from) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) clamped between 0 and 1 * @param[out] dest destination */ CGLM_INLINE void glm_vec4_mixc(vec4 from, vec4 to, float t, vec4 dest) { glm_vec4_lerpc(from, to, t, dest); } /*! * @brief threshold function * * @param[in] edge threshold * @param[in] x value to test against threshold * @param[out] dest destination */ CGLM_INLINE void glm_vec4_step(vec4 edge, vec4 x, vec4 dest) { dest[0] = glm_step(edge[0], x[0]); dest[1] = glm_step(edge[1], x[1]); dest[2] = glm_step(edge[2], x[2]); dest[3] = glm_step(edge[3], x[3]); } /*! * @brief threshold function with a smooth transition (unidimensional) * * @param[in] edge0 low threshold * @param[in] edge1 high threshold * @param[in] x value to test against threshold * @param[out] dest destination */ CGLM_INLINE void glm_vec4_smoothstep_uni(float edge0, float edge1, vec4 x, vec4 dest) { dest[0] = glm_smoothstep(edge0, edge1, x[0]); dest[1] = glm_smoothstep(edge0, edge1, x[1]); dest[2] = glm_smoothstep(edge0, edge1, x[2]); dest[3] = glm_smoothstep(edge0, edge1, x[3]); } /*! * @brief threshold function with a smooth transition * * @param[in] edge0 low threshold * @param[in] edge1 high threshold * @param[in] x value to test against threshold * @param[out] dest destination */ CGLM_INLINE void glm_vec4_smoothstep(vec4 edge0, vec4 edge1, vec4 x, vec4 dest) { dest[0] = glm_smoothstep(edge0[0], edge1[0], x[0]); dest[1] = glm_smoothstep(edge0[1], edge1[1], x[1]); dest[2] = glm_smoothstep(edge0[2], edge1[2], x[2]); dest[3] = glm_smoothstep(edge0[3], edge1[3], x[3]); } /*! * @brief smooth Hermite interpolation between two vectors * * formula: t^2 * (3 - 2*t) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) * @param[out] dest destination */ CGLM_INLINE void glm_vec4_smoothinterp(vec4 from, vec4 to, float t, vec4 dest) { vec4 s, v; /* from + smoothstep * (to - from) */ glm_vec4_broadcast(glm_smooth(t), s); glm_vec4_sub(to, from, v); glm_vec4_mul(s, v, v); glm_vec4_add(from, v, dest); } /*! * @brief smooth Hermite interpolation between two vectors (clamped) * * formula: t^2 * (3 - 2*t) * * @param[in] from from value * @param[in] to to value * @param[in] t interpolant (amount) clamped between 0 and 1 * @param[out] dest destination */ CGLM_INLINE void glm_vec4_smoothinterpc(vec4 from, vec4 to, float t, vec4 dest) { glm_vec4_smoothinterp(from, to, glm_clamp_zo(t), dest); } /*! * @brief helper to fill vec4 as [S^3, S^2, S, 1] * * @param[in] s parameter * @param[out] dest destination */ CGLM_INLINE void glm_vec4_cubic(float s, vec4 dest) { float ss; ss = s * s; dest[0] = ss * s; dest[1] = ss; dest[2] = s; dest[3] = 1.0f; } /*! * @brief swizzle vector components * * you can use existing masks e.g. GLM_XXXX, GLM_WZYX * * @param[in] v source * @param[in] mask mask * @param[out] dest destination */ CGLM_INLINE void glm_vec4_swizzle(vec4 v, int mask, vec4 dest) { vec4 t; t[0] = v[(mask & (3 << 0))]; t[1] = v[(mask & (3 << 2)) >> 2]; t[2] = v[(mask & (3 << 4)) >> 4]; t[3] = v[(mask & (3 << 6)) >> 6]; glm_vec4_copy(t, dest); } /*! * @brief Create four dimensional vector from pointer * * @param[in] src pointer to an array of floats * @param[out] dest destination vector */ CGLM_INLINE void glm_vec4_make(const float * __restrict src, vec4 dest) { dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; dest[3] = src[3]; } /*! * @brief reflection vector using an incident ray and a surface normal * * @param[in] v incident vector * @param[in] n normalized normal vector * @param[out] dest destination vector for the reflection result */ CGLM_INLINE void glm_vec4_reflect(vec4 v, vec4 n, vec4 dest) { vec4 temp; /* TODO: direct simd touch */ glm_vec4_scale(n, 2.0f * glm_vec4_dot(v, n), temp); glm_vec4_sub(v, temp, dest); dest[3] = v[3]; } /*! * @brief computes refraction vector for an incident vector and a surface normal. * * calculates the refraction vector based on Snell's law. If total internal reflection * occurs (angle too great given eta), dest is set to zero and returns false. * Otherwise, computes refraction vector, stores it in dest, and returns true. * * this implementation does not explicitly preserve the 'w' component of the * incident vector 'I' in the output 'dest', users requiring the preservation of * the 'w' component should manually adjust 'dest' after calling this function. * * @param[in] v normalized incident vector * @param[in] n normalized normal vector * @param[in] eta ratio of indices of refraction (incident/transmitted) * @param[out] dest refraction vector if refraction occurs; zero vector otherwise * * @returns true if refraction occurs; false if total internal reflection occurs. */ CGLM_INLINE bool glm_vec4_refract(vec4 v, vec4 n, float eta, vec4 dest) { float ndi, eni, k; ndi = glm_vec4_dot(n, v); eni = eta * ndi; k = 1.0f - eta * eta + eni * eni; if (k < 0.0f) { glm_vec4_zero(dest); return false; } glm_vec4_scale(v, eta, dest); glm_vec4_mulsubs(n, eni + sqrtf(k), dest); return true; } /*! * @brief swap two vectors * @param a the first vector to swap * @param b the second vector to swap */ CGLM_INLINE void glm_vec4_swap(vec4 a, vec4 b) { vec4 tmp; glm_vec4_copy(a, tmp); glm_vec4_copy(b, a); glm_vec4_copy(tmp, b); } #endif /* cglm_vec4_h */ cglm-0.9.7/include/cglm/version.h000066400000000000000000000004721526744317200166720ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm_version_h #define cglm_version_h #define CGLM_VERSION_MAJOR 0 #define CGLM_VERSION_MINOR 9 #define CGLM_VERSION_PATCH 7 #endif /* cglm_version_h */ cglm-0.9.7/include/module.modulemap000066400000000000000000000003071526744317200173010ustar00rootroot00000000000000module cglm { header "cglm/cglm.h" header "cglm/struct.h" export * } module cglmc { header "cglm/cglm.h" header "cglm/struct.h" header "cglm/call.h" export * } cglm-0.9.7/meson.build000066400000000000000000000064741526744317200146410ustar00rootroot00000000000000project('cglm', 'c', version : '0.9.7', license : 'mit', default_options : [ 'c_std=c11', 'warning_level=2', 'buildtype=release' ] ) cc = meson.get_compiler('c') cglm_install = get_option('install') cglm_deps = cc.find_library('m', required : false) cglm_args = [] build_args = [] if get_option('default_library') == 'static' cglm_args += '-DCGLM_STATIC' endif if cc.compiles( 'int *test(char *p) { return (int*)__builtin_assume_aligned(p, 4); }', name : '__builtin_assume_aligned test') cglm_args += '-DCGLM_HAVE_BUILTIN_ASSUME_ALIGNED=1' else cglm_args += '-DCGLM_HAVE_BUILTIN_ASSUME_ALIGNED=0' endif if host_machine.system() == 'windows' build_args += '-DCGLM_EXPORTS' endif cglm_inc = include_directories('include') cglm_src = files( 'src/euler.c', 'src/affine.c', 'src/io.c', 'src/quat.c', 'src/cam.c', 'src/vec2.c', 'src/ivec2.c', 'src/vec3.c', 'src/ivec3.c', 'src/vec4.c', 'src/ivec4.c', 'src/mat2.c', 'src/mat2x3.c', 'src/mat2x4.c', 'src/mat3.c', 'src/mat3x2.c', 'src/mat3x4.c', 'src/mat4.c', 'src/mat4x2.c', 'src/mat4x3.c', 'src/plane.c', 'src/noise.c', 'src/frustum.c', 'src/box.c', 'src/aabb2d.c', 'src/project.c', 'src/sphere.c', 'src/ease.c', 'src/curve.c', 'src/bezier.c', 'src/ray.c', 'src/affine2d.c', 'src/clipspace/ortho_lh_no.c', 'src/clipspace/ortho_lh_zo.c', 'src/clipspace/ortho_rh_no.c', 'src/clipspace/ortho_rh_zo.c', 'src/clipspace/persp_lh_no.c', 'src/clipspace/persp_lh_zo.c', 'src/clipspace/persp_rh_no.c', 'src/clipspace/persp_rh_zo.c', 'src/clipspace/view_lh_no.c', 'src/clipspace/view_lh_zo.c', 'src/clipspace/view_rh_no.c', 'src/clipspace/view_rh_zo.c', 'src/clipspace/project_no.c', 'src/clipspace/project_zo.c' ) cglm_lib = library('cglm', cglm_src, install : cglm_install, dependencies : cglm_deps, c_args : [ build_args, cglm_args ], version : meson.project_version(), soversion : '0', build_by_default: not meson.is_subproject() ) cglm_dep = declare_dependency( link_with : cglm_lib, dependencies : cglm_deps, compile_args : cglm_args, include_directories : cglm_inc, version : meson.project_version() ) if meson.version().version_compare('>= 0.54.0') meson.override_dependency('cglm', cglm_dep) endif if cglm_install install_subdir('include/cglm', install_dir : get_option('includedir')) pkg = import('pkgconfig') pkg.generate( name : 'cglm', libraries : cglm_lib, extra_cflags : cglm_args, version : meson.project_version(), url : 'https://github.com/recp/cglm', description : 'OpenGL Mathematics (glm) for C' ) endif if get_option('build_tests') == true test_src = files( 'test/runner.c', 'test/src/test_bezier.c', 'test/src/test_clamp.c', 'test/src/test_common.c', 'test/src/test_euler.c', 'test/src/tests.c', 'test/src/test_struct.c', ) test_exe = executable('tests', test_src, dependencies : cglm_dep, c_args : '-DGLM_TESTS_NO_COLORFUL_OUTPUT' ) test('cglm.tests', test_exe) endif cglm-0.9.7/meson_options.txt000066400000000000000000000003371526744317200161240ustar00rootroot00000000000000option('build_tests', type : 'boolean', value : false, description : 'Build tests') option('install', type : 'boolean', value : true, description : 'Include the library, headers, and pkg-config file in the install target') cglm-0.9.7/src/000077500000000000000000000000001526744317200132535ustar00rootroot00000000000000cglm-0.9.7/src/aabb2d.c000066400000000000000000000036701526744317200145400ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_aabb2d_zero(vec2 aabb[2]) { glm_aabb2d_zero(aabb); } CGLM_EXPORT void glmc_aabb2d_copy(vec2 aabb[2], vec2 dest[2]) { glm_aabb2d_copy(aabb, dest); } CGLM_EXPORT void glmc_aabb2d_transform(vec2 aabb[2], mat3 m, vec2 dest[2]) { glm_aabb2d_transform(aabb, m, dest); } CGLM_EXPORT void glmc_aabb2d_merge(vec2 aabb1[2], vec2 aabb2[2], vec2 dest[2]) { glm_aabb2d_merge(aabb1, aabb2, dest); } CGLM_EXPORT void glmc_aabb2d_crop(vec2 aabb[2], vec2 cropAabb[2], vec2 dest[2]) { glm_aabb2d_crop(aabb, cropAabb, dest); } CGLM_EXPORT void glmc_aabb2d_crop_until(vec2 aabb[2], vec2 cropAabb[2], vec2 clampAabb[2], vec2 dest[2]) { glm_aabb2d_crop_until(aabb, cropAabb, clampAabb, dest); } CGLM_EXPORT void glmc_aabb2d_invalidate(vec2 aabb[2]) { glm_aabb2d_invalidate(aabb); } CGLM_EXPORT bool glmc_aabb2d_isvalid(vec2 aabb[2]) { return glm_aabb2d_isvalid(aabb); } CGLM_EXPORT float glmc_aabb2d_diag(vec2 aabb[2]) { return glm_aabb2d_diag(aabb); } CGLM_EXPORT void glmc_aabb2d_sizev(vec2 aabb[2], vec2 dest) { glm_aabb2d_sizev(aabb, dest); } CGLM_EXPORT float glmc_aabb2d_radius(vec2 aabb[2]) { return glm_aabb2d_radius(aabb); } CGLM_EXPORT void glmc_aabb2d_center(vec2 aabb[2], vec2 dest) { glm_aabb2d_center(aabb, dest); } CGLM_EXPORT bool glmc_aabb2d_aabb(vec2 aabb[2], vec2 other[2]) { return glm_aabb2d_aabb(aabb, other); } CGLM_EXPORT bool glmc_aabb2d_point(vec2 aabb[2], vec2 point) { return glm_aabb2d_point(aabb, point); } CGLM_EXPORT bool glmc_aabb2d_contains(vec2 aabb[2], vec2 other[2]) { return glm_aabb2d_contains(aabb, other); } CGLM_EXPORT bool glmc_aabb2d_circle(vec2 aabb[2], vec3 s) { return glm_aabb2d_circle(aabb, s); } cglm-0.9.7/src/affine.c000066400000000000000000000066741526744317200146640ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_translate_make(mat4 m, vec3 v) { glm_translate_make(m, v); } CGLM_EXPORT void glmc_translate_to(mat4 m, vec3 v, mat4 dest) { glm_translate_to(m, v, dest); } CGLM_EXPORT void glmc_translate(mat4 m, vec3 v) { glm_translate(m, v); } CGLM_EXPORT void glmc_translate_x(mat4 m, float to) { glm_translate_x(m, to); } CGLM_EXPORT void glmc_translate_y(mat4 m, float to) { glm_translate_y(m, to); } CGLM_EXPORT void glmc_translate_z(mat4 m, float to) { glm_translate_z(m, to); } CGLM_EXPORT void glmc_scale_make(mat4 m, vec3 v) { glm_scale_make(m, v); } CGLM_EXPORT void glmc_scale_to(mat4 m, vec3 v, mat4 dest) { glm_scale_to(m, v, dest); } CGLM_EXPORT void glmc_scale(mat4 m, vec3 v) { glm_scale(m, v); } CGLM_EXPORT void glmc_scale_uni(mat4 m, float s) { glm_scale_uni(m, s); } CGLM_EXPORT void glmc_rotate_x(mat4 m, float rad, mat4 dest) { glm_rotate_x(m, rad, dest); } CGLM_EXPORT void glmc_rotate_y(mat4 m, float rad, mat4 dest) { glm_rotate_y(m, rad, dest); } CGLM_EXPORT void glmc_rotate_z(mat4 m, float rad, mat4 dest) { glm_rotate_z(m, rad, dest); } CGLM_EXPORT void glmc_rotate_make(mat4 m, float angle, vec3 axis) { glm_rotate_make(m, angle, axis); } CGLM_EXPORT void glmc_rotate(mat4 m, float angle, vec3 axis) { glm_rotate(m, angle, axis); } CGLM_EXPORT void glmc_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis) { glm_rotate_at(m, pivot, angle, axis); } CGLM_EXPORT void glmc_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis) { glm_rotate_atm(m, pivot, angle, axis); } CGLM_EXPORT void glmc_spin(mat4 m, float angle, vec3 axis) { glm_spin(m, angle, axis); } CGLM_EXPORT void glmc_decompose_scalev(mat4 m, vec3 s) { glm_decompose_scalev(m, s); } CGLM_EXPORT bool glmc_uniscaled(mat4 m) { return glm_uniscaled(m); } CGLM_EXPORT void glmc_decompose_rs(mat4 m, mat4 r, vec3 s) { glm_decompose_rs(m, r, s); } CGLM_EXPORT void glmc_translated(mat4 m, vec3 v) { glm_translated(m, v); } CGLM_EXPORT void glmc_translated_to(mat4 m, vec3 v, mat4 dest) { glm_translated_to(m, v, dest); } CGLM_EXPORT void glmc_translated_x(mat4 m, float x) { glm_translated_x(m, x); } CGLM_EXPORT void glmc_translated_y(mat4 m, float y) { glm_translated_y(m, y); } CGLM_EXPORT void glmc_translated_z(mat4 m, float z) { glm_translated_z(m, z); } CGLM_EXPORT void glmc_rotated_x(mat4 m, float angle, mat4 dest) { glm_rotated_x(m, angle, dest); } CGLM_EXPORT void glmc_rotated_y(mat4 m, float angle, mat4 dest) { glm_rotated_y(m, angle, dest); } CGLM_EXPORT void glmc_rotated_z(mat4 m, float angle, mat4 dest) { glm_rotated_z(m, angle, dest); } CGLM_EXPORT void glmc_rotated(mat4 m, float angle, vec3 axis) { glm_rotated(m, angle, axis); } CGLM_EXPORT void glmc_rotated_at(mat4 m, vec3 pivot, float angle, vec3 axis) { glm_rotated_at(m, pivot, angle, axis); } CGLM_EXPORT void glmc_spinned(mat4 m, float angle, vec3 axis) { glm_spinned(m, angle, axis); } CGLM_EXPORT void glmc_decompose(mat4 m, vec4 t, mat4 r, vec3 s) { glm_decompose(m, t, r, s); } CGLM_EXPORT void glmc_mul(mat4 m1, mat4 m2, mat4 dest) { glm_mul(m1, m2, dest); } CGLM_EXPORT void glmc_mul_rot(mat4 m1, mat4 m2, mat4 dest) { glm_mul_rot(m1, m2, dest); } CGLM_EXPORT void glmc_inv_tr(mat4 mat) { glm_inv_tr(mat); } cglm-0.9.7/src/affine2d.c000066400000000000000000000023761526744317200151050ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_translate2d_make(mat3 m, vec2 v) { glm_translate2d_make(m, v); } CGLM_EXPORT void glmc_translate2d_to(mat3 m, vec2 v, mat3 dest) { glm_translate2d_to(m, v, dest); } CGLM_EXPORT void glmc_translate2d(mat3 m, vec2 v) { glm_translate2d(m, v); } CGLM_EXPORT void glmc_translate2d_x(mat3 m, float to) { glm_translate2d_x(m, to); } CGLM_EXPORT void glmc_translate2d_y(mat3 m, float to) { glm_translate2d_y(m, to); } CGLM_EXPORT void glmc_scale2d_to(mat3 m, vec2 v, mat3 dest) { glm_scale2d_to(m, v, dest); } CGLM_EXPORT void glmc_scale2d_make(mat3 m, vec2 v) { glm_scale2d_make(m, v); } CGLM_EXPORT void glmc_scale2d(mat3 m, vec2 v) { glm_scale2d(m, v); } CGLM_EXPORT void glmc_scale2d_uni(mat3 m, float s) { glm_scale2d_uni(m, s); } CGLM_EXPORT void glmc_rotate2d_make(mat3 m, float angle) { glm_rotate2d_make(m, angle); } CGLM_EXPORT void glmc_rotate2d(mat3 m, float angle) { glm_rotate2d(m, angle); } CGLM_EXPORT void glmc_rotate2d_to(mat3 m, float angle, mat3 dest) { glm_rotate2d_to(m, angle, dest); } cglm-0.9.7/src/bezier.c000066400000000000000000000011371526744317200147010ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT float glmc_bezier(float s, float p0, float c0, float c1, float p1) { return glm_bezier(s, p0, c0, c1, p1); } CGLM_EXPORT float glmc_hermite(float s, float p0, float t0, float t1, float p1) { return glm_hermite(s, p0, t0, t1, p1); } CGLM_EXPORT float glmc_decasteljau(float prm, float p0, float c0, float c1, float p1) { return glm_decasteljau(prm, p0, c0, c1, p1); } cglm-0.9.7/src/box.c000066400000000000000000000032761526744317200142170ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_aabb_transform(vec3 box[2], mat4 m, vec3 dest[2]) { glm_aabb_transform(box, m, dest); } CGLM_EXPORT void glmc_aabb_merge(vec3 box1[2], vec3 box2[2], vec3 dest[2]) { glm_aabb_merge(box1, box2, dest); } CGLM_EXPORT void glmc_aabb_crop(vec3 box[2], vec3 cropBox[2], vec3 dest[2]) { glm_aabb_crop(box, cropBox, dest); } CGLM_EXPORT void glmc_aabb_crop_until(vec3 box[2], vec3 cropBox[2], vec3 clampBox[2], vec3 dest[2]) { glm_aabb_crop_until(box, cropBox, clampBox, dest); } CGLM_EXPORT bool glmc_aabb_frustum(vec3 box[2], vec4 planes[6]) { return glm_aabb_frustum(box, planes); } CGLM_EXPORT void glmc_aabb_invalidate(vec3 box[2]) { glm_aabb_invalidate(box); } CGLM_EXPORT bool glmc_aabb_isvalid(vec3 box[2]) { return glm_aabb_isvalid(box); } CGLM_EXPORT float glmc_aabb_size(vec3 box[2]) { return glm_aabb_size(box); } CGLM_EXPORT float glmc_aabb_radius(vec3 box[2]) { return glm_aabb_radius(box); } CGLM_EXPORT void glmc_aabb_center(vec3 box[2], vec3 dest) { glm_aabb_center(box, dest); } CGLM_EXPORT bool glmc_aabb_aabb(vec3 box[2], vec3 other[2]) { return glm_aabb_aabb(box, other); } CGLM_EXPORT bool glmc_aabb_point(vec3 box[2], vec3 point) { return glm_aabb_point(box, point); } CGLM_EXPORT bool glmc_aabb_contains(vec3 box[2], vec3 other[2]) { return glm_aabb_contains(box, other); } CGLM_EXPORT bool glmc_aabb_sphere(vec3 box[2], vec4 s) { return glm_aabb_sphere(box, s); } cglm-0.9.7/src/cam.c000066400000000000000000000074041526744317200141640ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_frustum(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) { glm_frustum(left, right, bottom, top, nearZ, farZ, dest); } CGLM_EXPORT void glmc_ortho(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) { glm_ortho(left, right, bottom, top, nearZ, farZ, dest); } CGLM_EXPORT void glmc_ortho_aabb(vec3 box[2], mat4 dest) { glm_ortho_aabb(box, dest); } CGLM_EXPORT void glmc_ortho_aabb_p(vec3 box[2], float padding, mat4 dest) { glm_ortho_aabb_p(box, padding, dest); } CGLM_EXPORT void glmc_ortho_aabb_pz(vec3 box[2], float padding, mat4 dest) { glm_ortho_aabb_pz(box, padding, dest); } CGLM_EXPORT void glmc_ortho_default(float aspect, mat4 dest) { glm_ortho_default(aspect, dest); } CGLM_EXPORT void glmc_ortho_default_s(float aspect, float size, mat4 dest) { glm_ortho_default_s(aspect, size, dest); } CGLM_EXPORT void glmc_perspective(float fovy, float aspect, float nearZ, float farZ, mat4 dest) { glm_perspective(fovy, aspect, nearZ, farZ, dest); } CGLM_EXPORT void glmc_perspective_infinite(float fovy, float aspect, float nearZ, mat4 dest) { glm_perspective_infinite(fovy, aspect, nearZ, dest); } CGLM_EXPORT void glmc_persp_move_far(mat4 proj, float deltaFar) { glm_persp_move_far(proj, deltaFar); } CGLM_EXPORT void glmc_perspective_default(float aspect, mat4 dest) { glm_perspective_default(aspect, dest); } CGLM_EXPORT void glmc_perspective_default_infinite(float aspect, mat4 dest) { glm_perspective_default_infinite(aspect, dest); } CGLM_EXPORT void glmc_perspective_resize(float aspect, mat4 proj) { glm_perspective_resize(aspect, proj); } CGLM_EXPORT void glmc_lookat(vec3 eye, vec3 center, vec3 up, mat4 dest) { glm_lookat(eye, center, up, dest); } CGLM_EXPORT void glmc_look(vec3 eye, vec3 dir, vec3 up, mat4 dest) { glm_look(eye, dir, up, dest); } CGLM_EXPORT void glmc_look_anyup(vec3 eye, vec3 dir, mat4 dest) { glm_look_anyup(eye, dir, dest); } CGLM_EXPORT void glmc_persp_decomp(mat4 proj, float * __restrict nearZ, float * __restrict farZ, float * __restrict top, float * __restrict bottom, float * __restrict left, float * __restrict right) { glm_persp_decomp(proj, nearZ, farZ, top, bottom, left, right); } CGLM_EXPORT void glmc_persp_decompv(mat4 proj, float dest[6]) { glm_persp_decompv(proj, dest); } CGLM_EXPORT void glmc_persp_decomp_x(mat4 proj, float * __restrict left, float * __restrict right) { glm_persp_decomp_x(proj, left, right); } CGLM_EXPORT void glmc_persp_decomp_y(mat4 proj, float * __restrict top, float * __restrict bottom) { glm_persp_decomp_y(proj, top, bottom); } CGLM_EXPORT void glmc_persp_decomp_z(mat4 proj, float * __restrict nearZ, float * __restrict farZ) { glm_persp_decomp_z(proj, nearZ, farZ); } CGLM_EXPORT void glmc_persp_decomp_far(mat4 proj, float * __restrict farZ) { glm_persp_decomp_far(proj, farZ); } CGLM_EXPORT void glmc_persp_decomp_near(mat4 proj, float * __restrict nearZ) { glm_persp_decomp_near(proj, nearZ); } CGLM_EXPORT float glmc_persp_fovy(mat4 proj) { return glm_persp_fovy(proj); } CGLM_EXPORT float glmc_persp_aspect(mat4 proj) { return glm_persp_aspect(proj); } CGLM_EXPORT void glmc_persp_sizes(mat4 proj, float fovy, vec4 dest) { glm_persp_sizes(proj, fovy, dest); } cglm-0.9.7/src/clipspace/000077500000000000000000000000001526744317200152165ustar00rootroot00000000000000cglm-0.9.7/src/clipspace/ortho_lh_no.c000066400000000000000000000022351526744317200176760ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../../include/cglm/clipspace/ortho_lh_no.h" #include "../../include/cglm/call/clipspace/ortho_lh_no.h" CGLM_EXPORT void glmc_ortho_lh_no(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) { glm_ortho_lh_no(left, right, bottom, top, nearZ, farZ, dest); } CGLM_EXPORT void glmc_ortho_aabb_lh_no(vec3 box[2], mat4 dest) { glm_ortho_aabb_lh_no(box, dest); } CGLM_EXPORT void glmc_ortho_aabb_p_lh_no(vec3 box[2], float padding, mat4 dest) { glm_ortho_aabb_p_lh_no(box, padding, dest); } CGLM_EXPORT void glmc_ortho_aabb_pz_lh_no(vec3 box[2], float padding, mat4 dest) { glm_ortho_aabb_pz_lh_no(box, padding, dest); } CGLM_EXPORT void glmc_ortho_default_lh_no(float aspect, mat4 dest) { glm_ortho_default_lh_no(aspect, dest); } CGLM_EXPORT void glmc_ortho_default_s_lh_no(float aspect, float size, mat4 dest) { glm_ortho_default_s_lh_no(aspect, size, dest); } cglm-0.9.7/src/clipspace/ortho_lh_zo.c000066400000000000000000000022351526744317200177120ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../../include/cglm/clipspace/ortho_lh_zo.h" #include "../../include/cglm/call/clipspace/ortho_lh_zo.h" CGLM_EXPORT void glmc_ortho_lh_zo(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) { glm_ortho_lh_zo(left, right, bottom, top, nearZ, farZ, dest); } CGLM_EXPORT void glmc_ortho_aabb_lh_zo(vec3 box[2], mat4 dest) { glm_ortho_aabb_lh_zo(box, dest); } CGLM_EXPORT void glmc_ortho_aabb_p_lh_zo(vec3 box[2], float padding, mat4 dest) { glm_ortho_aabb_p_lh_zo(box, padding, dest); } CGLM_EXPORT void glmc_ortho_aabb_pz_lh_zo(vec3 box[2], float padding, mat4 dest) { glm_ortho_aabb_pz_lh_zo(box, padding, dest); } CGLM_EXPORT void glmc_ortho_default_lh_zo(float aspect, mat4 dest) { glm_ortho_default_lh_zo(aspect, dest); } CGLM_EXPORT void glmc_ortho_default_s_lh_zo(float aspect, float size, mat4 dest) { glm_ortho_default_s_lh_zo(aspect, size, dest); } cglm-0.9.7/src/clipspace/ortho_rh_no.c000066400000000000000000000022351526744317200177040ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../../include/cglm/clipspace/ortho_rh_no.h" #include "../../include/cglm/call/clipspace/ortho_rh_no.h" CGLM_EXPORT void glmc_ortho_rh_no(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) { glm_ortho_rh_no(left, right, bottom, top, nearZ, farZ, dest); } CGLM_EXPORT void glmc_ortho_aabb_rh_no(vec3 box[2], mat4 dest) { glm_ortho_aabb_rh_no(box, dest); } CGLM_EXPORT void glmc_ortho_aabb_p_rh_no(vec3 box[2], float padding, mat4 dest) { glm_ortho_aabb_p_rh_no(box, padding, dest); } CGLM_EXPORT void glmc_ortho_aabb_pz_rh_no(vec3 box[2], float padding, mat4 dest) { glm_ortho_aabb_pz_rh_no(box, padding, dest); } CGLM_EXPORT void glmc_ortho_default_rh_no(float aspect, mat4 dest) { glm_ortho_default_rh_no(aspect, dest); } CGLM_EXPORT void glmc_ortho_default_s_rh_no(float aspect, float size, mat4 dest) { glm_ortho_default_s_rh_no(aspect, size, dest); } cglm-0.9.7/src/clipspace/ortho_rh_zo.c000066400000000000000000000022351526744317200177200ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../../include/cglm/clipspace/ortho_rh_zo.h" #include "../../include/cglm/call/clipspace/ortho_rh_zo.h" CGLM_EXPORT void glmc_ortho_rh_zo(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) { glm_ortho_rh_zo(left, right, bottom, top, nearZ, farZ, dest); } CGLM_EXPORT void glmc_ortho_aabb_rh_zo(vec3 box[2], mat4 dest) { glm_ortho_aabb_rh_zo(box, dest); } CGLM_EXPORT void glmc_ortho_aabb_p_rh_zo(vec3 box[2], float padding, mat4 dest) { glm_ortho_aabb_p_rh_zo(box, padding, dest); } CGLM_EXPORT void glmc_ortho_aabb_pz_rh_zo(vec3 box[2], float padding, mat4 dest) { glm_ortho_aabb_pz_rh_zo(box, padding, dest); } CGLM_EXPORT void glmc_ortho_default_rh_zo(float aspect, mat4 dest) { glm_ortho_default_rh_zo(aspect, dest); } CGLM_EXPORT void glmc_ortho_default_s_rh_zo(float aspect, float size, mat4 dest) { glm_ortho_default_s_rh_zo(aspect, size, dest); } cglm-0.9.7/src/clipspace/persp_lh_no.c000066400000000000000000000054411526744317200176760ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../../include/cglm/clipspace/persp_lh_no.h" #include "../../include/cglm/call/clipspace/persp_lh_no.h" CGLM_EXPORT void glmc_frustum_lh_no(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) { glm_frustum_lh_no(left, right, bottom, top, nearZ, farZ, dest); } CGLM_EXPORT void glmc_perspective_lh_no(float fovy, float aspect, float nearVal, float farVal, mat4 dest) { glm_perspective_lh_no(fovy, aspect, nearVal, farVal, dest); } CGLM_EXPORT void glmc_perspective_resize_lh_no(float aspect, mat4 proj) { glm_perspective_resize_lh_no(aspect, proj); } CGLM_EXPORT void glmc_persp_move_far_lh_no(mat4 proj, float deltaFar) { glm_persp_move_far_lh_no(proj, deltaFar); } CGLM_EXPORT void glmc_persp_decomp_lh_no(mat4 proj, float * __restrict nearZ, float * __restrict farZ, float * __restrict top, float * __restrict bottom, float * __restrict left, float * __restrict right) { glm_persp_decomp_lh_no(proj, nearZ, farZ, top, bottom, left, right); } CGLM_EXPORT void glmc_persp_decompv_lh_no(mat4 proj, float dest[6]) { glm_persp_decompv_lh_no(proj, dest); } CGLM_EXPORT void glmc_persp_decomp_x_lh_no(mat4 proj, float * __restrict left, float * __restrict right) { glm_persp_decomp_x_lh_no(proj, left, right); } CGLM_EXPORT void glmc_persp_decomp_y_lh_no(mat4 proj, float * __restrict top, float * __restrict bottom) { glm_persp_decomp_y_lh_no(proj, top, bottom); } CGLM_EXPORT void glmc_persp_decomp_z_lh_no(mat4 proj, float * __restrict nearZ, float * __restrict farZ) { glm_persp_decomp_z_lh_no(proj, nearZ, farZ); } CGLM_EXPORT void glmc_persp_decomp_far_lh_no(mat4 proj, float * __restrict farZ) { glm_persp_decomp_far_lh_no(proj, farZ); } CGLM_EXPORT void glmc_persp_decomp_near_lh_no(mat4 proj, float * __restrict nearZ) { glm_persp_decomp_near_lh_no(proj, nearZ); } CGLM_EXPORT void glmc_persp_sizes_lh_no(mat4 proj, float fovy, vec4 dest) { glm_persp_sizes_lh_no(proj, fovy, dest); } CGLM_EXPORT float glmc_persp_fovy_lh_no(mat4 proj) { return glm_persp_fovy_lh_no(proj); } CGLM_EXPORT float glmc_persp_aspect_lh_no(mat4 proj) { return glm_persp_aspect_lh_no(proj); } cglm-0.9.7/src/clipspace/persp_lh_zo.c000066400000000000000000000054411526744317200177120ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../../include/cglm/clipspace/persp_lh_zo.h" #include "../../include/cglm/call/clipspace/persp_lh_zo.h" CGLM_EXPORT void glmc_frustum_lh_zo(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) { glm_frustum_lh_zo(left, right, bottom, top, nearZ, farZ, dest); } CGLM_EXPORT void glmc_perspective_lh_zo(float fovy, float aspect, float nearVal, float farVal, mat4 dest) { glm_perspective_lh_zo(fovy, aspect, nearVal, farVal, dest); } CGLM_EXPORT void glmc_perspective_resize_lh_zo(float aspect, mat4 proj) { glm_perspective_resize_lh_zo(aspect, proj); } CGLM_EXPORT void glmc_persp_move_far_lh_zo(mat4 proj, float deltaFar) { glm_persp_move_far_lh_zo(proj, deltaFar); } CGLM_EXPORT void glmc_persp_decomp_lh_zo(mat4 proj, float * __restrict nearZ, float * __restrict farZ, float * __restrict top, float * __restrict bottom, float * __restrict left, float * __restrict right) { glm_persp_decomp_lh_zo(proj, nearZ, farZ, top, bottom, left, right); } CGLM_EXPORT void glmc_persp_decompv_lh_zo(mat4 proj, float dest[6]) { glm_persp_decompv_lh_zo(proj, dest); } CGLM_EXPORT void glmc_persp_decomp_x_lh_zo(mat4 proj, float * __restrict left, float * __restrict right) { glm_persp_decomp_x_lh_zo(proj, left, right); } CGLM_EXPORT void glmc_persp_decomp_y_lh_zo(mat4 proj, float * __restrict top, float * __restrict bottom) { glm_persp_decomp_y_lh_zo(proj, top, bottom); } CGLM_EXPORT void glmc_persp_decomp_z_lh_zo(mat4 proj, float * __restrict nearZ, float * __restrict farZ) { glm_persp_decomp_z_lh_zo(proj, nearZ, farZ); } CGLM_EXPORT void glmc_persp_decomp_far_lh_zo(mat4 proj, float * __restrict farZ) { glm_persp_decomp_far_lh_zo(proj, farZ); } CGLM_EXPORT void glmc_persp_decomp_near_lh_zo(mat4 proj, float * __restrict nearZ) { glm_persp_decomp_near_lh_zo(proj, nearZ); } CGLM_EXPORT void glmc_persp_sizes_lh_zo(mat4 proj, float fovy, vec4 dest) { glm_persp_sizes_lh_zo(proj, fovy, dest); } CGLM_EXPORT float glmc_persp_fovy_lh_zo(mat4 proj) { return glm_persp_fovy_lh_zo(proj); } CGLM_EXPORT float glmc_persp_aspect_lh_zo(mat4 proj) { return glm_persp_aspect_lh_zo(proj); } cglm-0.9.7/src/clipspace/persp_rh_no.c000066400000000000000000000054411526744317200177040ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../../include/cglm/clipspace/persp_rh_no.h" #include "../../include/cglm/call/clipspace/persp_rh_no.h" CGLM_EXPORT void glmc_frustum_rh_no(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) { glm_frustum_rh_no(left, right, bottom, top, nearZ, farZ, dest); } CGLM_EXPORT void glmc_perspective_rh_no(float fovy, float aspect, float nearVal, float farVal, mat4 dest) { glm_perspective_rh_no(fovy, aspect, nearVal, farVal, dest); } CGLM_EXPORT void glmc_perspective_resize_rh_no(float aspect, mat4 proj) { glm_perspective_resize_rh_no(aspect, proj); } CGLM_EXPORT void glmc_persp_move_far_rh_no(mat4 proj, float deltaFar) { glm_persp_move_far_rh_no(proj, deltaFar); } CGLM_EXPORT void glmc_persp_decomp_rh_no(mat4 proj, float * __restrict nearZ, float * __restrict farZ, float * __restrict top, float * __restrict bottom, float * __restrict left, float * __restrict right) { glm_persp_decomp_rh_no(proj, nearZ, farZ, top, bottom, left, right); } CGLM_EXPORT void glmc_persp_decompv_rh_no(mat4 proj, float dest[6]) { glm_persp_decompv_rh_no(proj, dest); } CGLM_EXPORT void glmc_persp_decomp_x_rh_no(mat4 proj, float * __restrict left, float * __restrict right) { glm_persp_decomp_x_rh_no(proj, left, right); } CGLM_EXPORT void glmc_persp_decomp_y_rh_no(mat4 proj, float * __restrict top, float * __restrict bottom) { glm_persp_decomp_y_rh_no(proj, top, bottom); } CGLM_EXPORT void glmc_persp_decomp_z_rh_no(mat4 proj, float * __restrict nearZ, float * __restrict farZ) { glm_persp_decomp_z_rh_no(proj, nearZ, farZ); } CGLM_EXPORT void glmc_persp_decomp_far_rh_no(mat4 proj, float * __restrict farZ) { glm_persp_decomp_far_rh_no(proj, farZ); } CGLM_EXPORT void glmc_persp_decomp_near_rh_no(mat4 proj, float * __restrict nearZ) { glm_persp_decomp_near_rh_no(proj, nearZ); } CGLM_EXPORT void glmc_persp_sizes_rh_no(mat4 proj, float fovy, vec4 dest) { glm_persp_sizes_rh_no(proj, fovy, dest); } CGLM_EXPORT float glmc_persp_fovy_rh_no(mat4 proj) { return glm_persp_fovy_rh_no(proj); } CGLM_EXPORT float glmc_persp_aspect_rh_no(mat4 proj) { return glm_persp_aspect_rh_no(proj); } cglm-0.9.7/src/clipspace/persp_rh_zo.c000066400000000000000000000054411526744317200177200ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../../include/cglm/clipspace/persp_rh_zo.h" #include "../../include/cglm/call/clipspace/persp_rh_zo.h" CGLM_EXPORT void glmc_frustum_rh_zo(float left, float right, float bottom, float top, float nearZ, float farZ, mat4 dest) { glm_frustum_rh_zo(left, right, bottom, top, nearZ, farZ, dest); } CGLM_EXPORT void glmc_perspective_rh_zo(float fovy, float aspect, float nearVal, float farVal, mat4 dest) { glm_perspective_rh_zo(fovy, aspect, nearVal, farVal, dest); } CGLM_EXPORT void glmc_perspective_resize_rh_zo(float aspect, mat4 proj) { glm_perspective_resize_rh_zo(aspect, proj); } CGLM_EXPORT void glmc_persp_move_far_rh_zo(mat4 proj, float deltaFar) { glm_persp_move_far_rh_zo(proj, deltaFar); } CGLM_EXPORT void glmc_persp_decomp_rh_zo(mat4 proj, float * __restrict nearZ, float * __restrict farZ, float * __restrict top, float * __restrict bottom, float * __restrict left, float * __restrict right) { glm_persp_decomp_rh_zo(proj, nearZ, farZ, top, bottom, left, right); } CGLM_EXPORT void glmc_persp_decompv_rh_zo(mat4 proj, float dest[6]) { glm_persp_decompv_rh_zo(proj, dest); } CGLM_EXPORT void glmc_persp_decomp_x_rh_zo(mat4 proj, float * __restrict left, float * __restrict right) { glm_persp_decomp_x_rh_zo(proj, left, right); } CGLM_EXPORT void glmc_persp_decomp_y_rh_zo(mat4 proj, float * __restrict top, float * __restrict bottom) { glm_persp_decomp_y_rh_zo(proj, top, bottom); } CGLM_EXPORT void glmc_persp_decomp_z_rh_zo(mat4 proj, float * __restrict nearZ, float * __restrict farZ) { glm_persp_decomp_z_rh_zo(proj, nearZ, farZ); } CGLM_EXPORT void glmc_persp_decomp_far_rh_zo(mat4 proj, float * __restrict farZ) { glm_persp_decomp_far_rh_zo(proj, farZ); } CGLM_EXPORT void glmc_persp_decomp_near_rh_zo(mat4 proj, float * __restrict nearZ) { glm_persp_decomp_near_rh_zo(proj, nearZ); } CGLM_EXPORT void glmc_persp_sizes_rh_zo(mat4 proj, float fovy, vec4 dest) { glm_persp_sizes_rh_zo(proj, fovy, dest); } CGLM_EXPORT float glmc_persp_fovy_rh_zo(mat4 proj) { return glm_persp_fovy_rh_zo(proj); } CGLM_EXPORT float glmc_persp_aspect_rh_zo(mat4 proj) { return glm_persp_aspect_rh_zo(proj); } cglm-0.9.7/src/clipspace/project_no.c000066400000000000000000000011241526744317200175220ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../../include/cglm/clipspace/project_no.h" #include "../../include/cglm/call/clipspace/project_no.h" CGLM_EXPORT void glmc_unprojecti_no(vec3 pos, mat4 invMat, vec4 vp, vec3 dest) { glm_unprojecti_no(pos, invMat, vp, dest); } CGLM_EXPORT void glmc_project_no(vec3 pos, mat4 m, vec4 vp, vec3 dest) { glm_project_no(pos, m, vp, dest); } CGLM_EXPORT float glmc_project_z_no(vec3 pos, mat4 m) { return glm_project_z_no(pos, m); } cglm-0.9.7/src/clipspace/project_zo.c000066400000000000000000000011241526744317200175360ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../../include/cglm/clipspace/project_zo.h" #include "../../include/cglm/call/clipspace/project_zo.h" CGLM_EXPORT void glmc_unprojecti_zo(vec3 pos, mat4 invMat, vec4 vp, vec3 dest) { glm_unprojecti_zo(pos, invMat, vp, dest); } CGLM_EXPORT void glmc_project_zo(vec3 pos, mat4 m, vec4 vp, vec3 dest) { glm_project_zo(pos, m, vp, dest); } CGLM_EXPORT float glmc_project_z_zo(vec3 pos, mat4 m) { return glm_project_z_zo(pos, m); } cglm-0.9.7/src/clipspace/view_lh_no.c000066400000000000000000000011531526744317200175130ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../../include/cglm/clipspace/view_lh_no.h" #include "../../include/cglm/call/clipspace/view_lh_no.h" CGLM_EXPORT void glmc_lookat_lh_no(vec3 eye, vec3 center, vec3 up, mat4 dest) { glm_lookat_lh_no(eye, center, up, dest); } CGLM_EXPORT void glmc_look_lh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest) { glm_look_lh_no(eye, dir, up, dest); } CGLM_EXPORT void glmc_look_anyup_lh_no(vec3 eye, vec3 dir, mat4 dest) { glm_look_anyup_lh_no(eye, dir, dest); } cglm-0.9.7/src/clipspace/view_lh_zo.c000066400000000000000000000011531526744317200175270ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../../include/cglm/clipspace/view_lh_zo.h" #include "../../include/cglm/call/clipspace/view_lh_zo.h" CGLM_EXPORT void glmc_lookat_lh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest) { glm_lookat_lh_zo(eye, center, up, dest); } CGLM_EXPORT void glmc_look_lh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest) { glm_look_lh_zo(eye, dir, up, dest); } CGLM_EXPORT void glmc_look_anyup_lh_zo(vec3 eye, vec3 dir, mat4 dest) { glm_look_anyup_lh_zo(eye, dir, dest); } cglm-0.9.7/src/clipspace/view_rh_no.c000066400000000000000000000011531526744317200175210ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../../include/cglm/clipspace/view_rh_no.h" #include "../../include/cglm/call/clipspace/view_rh_no.h" CGLM_EXPORT void glmc_lookat_rh_no(vec3 eye, vec3 center, vec3 up, mat4 dest) { glm_lookat_rh_no(eye, center, up, dest); } CGLM_EXPORT void glmc_look_rh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest) { glm_look_rh_no(eye, dir, up, dest); } CGLM_EXPORT void glmc_look_anyup_rh_no(vec3 eye, vec3 dir, mat4 dest) { glm_look_anyup_rh_no(eye, dir, dest); } cglm-0.9.7/src/clipspace/view_rh_zo.c000066400000000000000000000011531526744317200175350ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../../include/cglm/clipspace/view_rh_zo.h" #include "../../include/cglm/call/clipspace/view_rh_zo.h" CGLM_EXPORT void glmc_lookat_rh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest) { glm_lookat_rh_zo(eye, center, up, dest); } CGLM_EXPORT void glmc_look_rh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest) { glm_look_rh_zo(eye, dir, up, dest); } CGLM_EXPORT void glmc_look_anyup_rh_zo(vec3 eye, vec3 dir, mat4 dest) { glm_look_anyup_rh_zo(eye, dir, dest); } cglm-0.9.7/src/config.h000066400000000000000000000006711526744317200146750ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef cglm__config__h_ #define cglm__config__h_ #if defined(_WIN32) || defined(WIN32) /* Exclude rarely-used stuff from Windows headers */ # define WIN32_LEAN_AND_MEAN # include /* Windows Header Files: */ # include #endif #endif /* cglm__config__h_ */ cglm-0.9.7/src/curve.c000066400000000000000000000004571526744317200145510ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT float glmc_smc(float s, mat4 m, vec4 c) { return glm_smc(s, m, c); } cglm-0.9.7/src/ease.c000066400000000000000000000053671526744317200143470ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT float glmc_ease_linear(float t) { return glm_ease_linear(t); } CGLM_EXPORT float glmc_ease_sine_in(float t) { return glm_ease_sine_in(t); } CGLM_EXPORT float glmc_ease_sine_out(float t) { return glm_ease_sine_out(t); } CGLM_EXPORT float glmc_ease_sine_inout(float t) { return glm_ease_sine_inout(t); } CGLM_EXPORT float glmc_ease_quad_in(float t) { return glm_ease_quad_in(t); } CGLM_EXPORT float glmc_ease_quad_out(float t) { return glm_ease_quad_out(t); } CGLM_EXPORT float glmc_ease_quad_inout(float t) { return glm_ease_quad_inout(t); } CGLM_EXPORT float glmc_ease_cubic_in(float t) { return glm_ease_cubic_in(t); } CGLM_EXPORT float glmc_ease_cubic_out(float t) { return glm_ease_cubic_out(t); } CGLM_EXPORT float glmc_ease_cubic_inout(float t) { return glm_ease_cubic_inout(t); } CGLM_EXPORT float glmc_ease_quart_in(float t) { return glm_ease_quart_in(t); } CGLM_EXPORT float glmc_ease_quart_out(float t) { return glm_ease_quart_out(t); } CGLM_EXPORT float glmc_ease_quart_inout(float t) { return glm_ease_quart_inout(t); } CGLM_EXPORT float glmc_ease_quint_in(float t) { return glm_ease_quint_in(t); } CGLM_EXPORT float glmc_ease_quint_out(float t) { return glm_ease_quint_out(t); } CGLM_EXPORT float glmc_ease_quint_inout(float t) { return glm_ease_quint_inout(t); } CGLM_EXPORT float glmc_ease_exp_in(float t) { return glm_ease_exp_in(t); } CGLM_EXPORT float glmc_ease_exp_out(float t) { return glm_ease_exp_out(t); } CGLM_EXPORT float glmc_ease_exp_inout(float t) { return glm_ease_exp_inout(t); } CGLM_EXPORT float glmc_ease_circ_in(float t) { return glm_ease_circ_in(t); } CGLM_EXPORT float glmc_ease_circ_out(float t) { return glm_ease_circ_out(t); } CGLM_EXPORT float glmc_ease_circ_inout(float t) { return glm_ease_circ_inout(t); } CGLM_EXPORT float glmc_ease_back_in(float t) { return glm_ease_back_in(t); } CGLM_EXPORT float glmc_ease_back_out(float t) { return glm_ease_back_out(t); } CGLM_EXPORT float glmc_ease_back_inout(float t) { return glm_ease_back_inout(t); } CGLM_EXPORT float glmc_ease_elast_in(float t) { return glm_ease_elast_in(t); } CGLM_EXPORT float glmc_ease_elast_out(float t) { return glm_ease_elast_out(t); } CGLM_EXPORT float glmc_ease_elast_inout(float t) { return glm_ease_elast_inout(t); } CGLM_EXPORT float glmc_ease_bounce_out(float t) { return glm_ease_bounce_out(t); } CGLM_EXPORT float glmc_ease_bounce_in(float t) { return glm_ease_bounce_in(t); } CGLM_EXPORT float glmc_ease_bounce_inout(float t) { return glm_ease_bounce_inout(t); } cglm-0.9.7/src/euler.c000066400000000000000000000032411526744317200145330ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_euler_angles(mat4 m, vec3 dest) { glm_euler_angles(m, dest); } CGLM_EXPORT void glmc_euler(vec3 angles, mat4 dest) { glm_euler(angles, dest); } CGLM_EXPORT void glmc_euler_xyz(vec3 angles, mat4 dest) { glm_euler_xyz(angles, dest); } CGLM_EXPORT void glmc_euler_zyx(vec3 angles, mat4 dest) { glm_euler_zyx(angles, dest); } CGLM_EXPORT void glmc_euler_zxy(vec3 angles, mat4 dest) { glm_euler_zxy(angles, dest); } CGLM_EXPORT void glmc_euler_xzy(vec3 angles, mat4 dest) { glm_euler_xzy(angles, dest); } CGLM_EXPORT void glmc_euler_yzx(vec3 angles, mat4 dest) { glm_euler_yzx(angles, dest); } CGLM_EXPORT void glmc_euler_yxz(vec3 angles, mat4 dest) { glm_euler_yxz(angles, dest); } CGLM_EXPORT void glmc_euler_by_order(vec3 angles, glm_euler_seq axis, mat4 dest) { glm_euler_by_order(angles, axis, dest); } CGLM_EXPORT void glmc_euler_xyz_quat(vec3 angles, versor dest) { glm_euler_xyz_quat(angles, dest); } CGLM_EXPORT void glmc_euler_xzy_quat(vec3 angles, versor dest) { glm_euler_xzy_quat(angles, dest); } CGLM_EXPORT void glmc_euler_yxz_quat(vec3 angles, versor dest) { glm_euler_yxz_quat(angles, dest); } CGLM_EXPORT void glmc_euler_yzx_quat(vec3 angles, versor dest) { glm_euler_yzx_quat(angles, dest); } CGLM_EXPORT void glmc_euler_zxy_quat(vec3 angles, versor dest) { glm_euler_zxy_quat(angles, dest); } CGLM_EXPORT void glmc_euler_zyx_quat(vec3 angles, versor dest) { glm_euler_zyx_quat(angles, dest); } cglm-0.9.7/src/frustum.c000066400000000000000000000016051526744317200151260ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_frustum_planes(mat4 m, vec4 dest[6]) { glm_frustum_planes(m, dest); } CGLM_EXPORT void glmc_frustum_corners(mat4 invMat, vec4 dest[8]) { glm_frustum_corners(invMat, dest); } CGLM_EXPORT void glmc_frustum_center(vec4 corners[8], vec4 dest) { glm_frustum_center(corners, dest); } CGLM_EXPORT void glmc_frustum_box(vec4 corners[8], mat4 m, vec3 box[2]) { glm_frustum_box(corners, m, box); } CGLM_EXPORT void glmc_frustum_corners_at(vec4 corners[8], float splitDist, float farDist, vec4 planeCorners[4]) { glm_frustum_corners_at(corners, splitDist, farDist, planeCorners); } cglm-0.9.7/src/io.c000066400000000000000000000015561526744317200140350ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #define CGLM_LIB_SRC #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_mat4_print(mat4 matrix, FILE * __restrict ostream) { glm_mat4_print(matrix, ostream); } CGLM_EXPORT void glmc_mat3_print(mat3 matrix, FILE * __restrict ostream) { glm_mat3_print(matrix, ostream); } CGLM_EXPORT void glmc_vec4_print(vec4 vec, FILE * __restrict ostream) { glm_vec4_print(vec, ostream); } CGLM_EXPORT void glmc_vec3_print(vec3 vec, FILE * __restrict ostream) { glm_vec3_print(vec, ostream); } CGLM_EXPORT void glmc_versor_print(versor vec, FILE * __restrict ostream) { glm_versor_print(vec, ostream); } cglm-0.9.7/src/ivec2.c000066400000000000000000000076761526744317200144470ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_ivec2(int * __restrict v, ivec2 dest) { glm_ivec2(v, dest); } CGLM_EXPORT void glmc_ivec2_copy(ivec2 a, ivec2 dest) { glm_ivec2_copy(a, dest); } CGLM_EXPORT void glmc_ivec2_zero(ivec2 v) { glm_ivec2_zero(v); } CGLM_EXPORT void glmc_ivec2_one(ivec2 v) { glm_ivec2_one(v); } CGLM_EXPORT int glmc_ivec2_dot(ivec2 a, ivec2 b) { return glm_ivec2_dot(a, b); } CGLM_EXPORT int glmc_ivec2_cross(ivec2 a, ivec2 b) { return glm_ivec2_cross(a, b); } CGLM_EXPORT void glmc_ivec2_add(ivec2 a, ivec2 b, ivec2 dest) { glm_ivec2_add(a, b, dest); } CGLM_EXPORT void glmc_ivec2_adds(ivec2 v, int s, ivec2 dest) { glm_ivec2_adds(v, s, dest); } CGLM_EXPORT void glmc_ivec2_sub(ivec2 a, ivec2 b, ivec2 dest) { glm_ivec2_sub(a, b, dest); } CGLM_EXPORT void glmc_ivec2_subs(ivec2 v, int s, ivec2 dest) { glm_ivec2_subs(v, s, dest); } CGLM_EXPORT void glmc_ivec2_mul(ivec2 a, ivec2 b, ivec2 dest) { glm_ivec2_mul(a, b, dest); } CGLM_EXPORT void glmc_ivec2_scale(ivec2 v, int s, ivec2 dest) { glm_ivec2_scale(v, s, dest); } CGLM_EXPORT void glmc_ivec2_div(ivec2 a, ivec2 b, ivec2 dest) { glm_ivec2_div(a, b, dest); } CGLM_EXPORT void glmc_ivec2_divs(ivec2 v, int s, ivec2 dest) { glm_ivec2_divs(v, s, dest); } CGLM_EXPORT void glmc_ivec2_mod(ivec2 a, ivec2 b, ivec2 dest) { glm_ivec2_mod(a, b, dest); } CGLM_EXPORT void glmc_ivec2_addadd(ivec2 a, ivec2 b, ivec2 dest) { glm_ivec2_addadd(a, b, dest); } CGLM_EXPORT void glmc_ivec2_addadds(ivec2 a, int s, ivec2 dest) { glm_ivec2_addadds(a, s, dest); } CGLM_EXPORT void glmc_ivec2_subadd(ivec2 a, ivec2 b, ivec2 dest) { glm_ivec2_subadd(a, b, dest); } CGLM_EXPORT void glmc_ivec2_subadds(ivec2 a, int s, ivec2 dest) { glm_ivec2_subadds(a, s, dest); } CGLM_EXPORT void glmc_ivec2_muladd(ivec2 a, ivec2 b, ivec2 dest) { glm_ivec2_muladd(a, b, dest); } CGLM_EXPORT void glmc_ivec2_muladds(ivec2 a, int s, ivec2 dest) { glm_ivec2_muladds(a, s, dest); } CGLM_EXPORT void glmc_ivec2_maxadd(ivec2 a, ivec2 b, ivec2 dest) { glm_ivec2_maxadd(a, b, dest); } CGLM_EXPORT void glmc_ivec2_minadd(ivec2 a, ivec2 b, ivec2 dest) { glm_ivec2_minadd(a, b, dest); } CGLM_EXPORT void glmc_ivec2_subsub(ivec2 a, ivec2 b, ivec2 dest) { glm_ivec2_subsub(a, b, dest); } CGLM_EXPORT void glmc_ivec2_subsubs(ivec2 a, int s, ivec2 dest) { glm_ivec2_subsubs(a, s, dest); } CGLM_EXPORT void glmc_ivec2_addsub(ivec2 a, ivec2 b, ivec2 dest) { glm_ivec2_addsub(a, b, dest); } CGLM_EXPORT void glmc_ivec2_addsubs(ivec2 a, int s, ivec2 dest) { glm_ivec2_addsubs(a, s, dest); } CGLM_EXPORT void glmc_ivec2_mulsub(ivec2 a, ivec2 b, ivec2 dest) { glm_ivec2_mulsub(a, b, dest); } CGLM_EXPORT void glmc_ivec2_mulsubs(ivec2 a, int s, ivec2 dest) { glm_ivec2_mulsubs(a, s, dest); } CGLM_EXPORT void glmc_ivec2_maxsub(ivec2 a, ivec2 b, ivec2 dest) { glm_ivec2_maxsub(a, b, dest); } CGLM_EXPORT void glmc_ivec2_minsub(ivec2 a, ivec2 b, ivec2 dest) { glm_ivec2_minsub(a, b, dest); } CGLM_EXPORT int glmc_ivec2_distance2(ivec2 a, ivec2 b) { return glm_ivec2_distance2(a, b); } CGLM_EXPORT float glmc_ivec2_distance(ivec2 a, ivec2 b) { return glm_ivec2_distance(a, b); } CGLM_EXPORT void glmc_ivec2_fill(ivec2 v, int val) { glm_ivec2_fill(v, val); } CGLM_EXPORT bool glmc_ivec2_eq(ivec2 v, int val) { return glm_ivec2_eq(v, val); } CGLM_EXPORT bool glmc_ivec2_eqv(ivec2 a, ivec2 b) { return glm_ivec2_eqv(a, b); } CGLM_EXPORT void glmc_ivec2_maxv(ivec2 a, ivec2 b, ivec2 dest) { glm_ivec2_maxv(a, b, dest); } CGLM_EXPORT void glmc_ivec2_minv(ivec2 a, ivec2 b, ivec2 dest) { glm_ivec2_minv(a, b, dest); } CGLM_EXPORT void glmc_ivec2_clamp(ivec2 v, int minVal, int maxVal) { glm_ivec2_clamp(v, minVal, maxVal); } CGLM_EXPORT void glmc_ivec2_abs(ivec2 v, ivec2 dest) { glm_ivec2_abs(v, dest); } cglm-0.9.7/src/ivec3.c000066400000000000000000000100241526744317200144250ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_ivec3(ivec4 v4, ivec3 dest) { glm_ivec3(v4, dest); } CGLM_EXPORT void glmc_ivec3_copy(ivec3 a, ivec3 dest) { glm_ivec3_copy(a, dest); } CGLM_EXPORT void glmc_ivec3_zero(ivec3 v) { glm_ivec3_zero(v); } CGLM_EXPORT void glmc_ivec3_one(ivec3 v) { glm_ivec3_one(v); } CGLM_EXPORT int glmc_ivec3_dot(ivec3 a, ivec3 b) { return glm_ivec3_dot(a, b); } CGLM_EXPORT int glmc_ivec3_norm2(ivec3 v) { return glm_ivec3_norm2(v); } CGLM_EXPORT int glmc_ivec3_norm(ivec3 v) { return glm_ivec3_norm(v); } CGLM_EXPORT void glmc_ivec3_add(ivec3 a, ivec3 b, ivec3 dest) { glm_ivec3_add(a, b, dest); } CGLM_EXPORT void glmc_ivec3_adds(ivec3 v, int s, ivec3 dest) { glm_ivec3_adds(v, s, dest); } CGLM_EXPORT void glmc_ivec3_sub(ivec3 a, ivec3 b, ivec3 dest) { glm_ivec3_sub(a, b, dest); } CGLM_EXPORT void glmc_ivec3_subs(ivec3 v, int s, ivec3 dest) { glm_ivec3_subs(v, s, dest); } CGLM_EXPORT void glmc_ivec3_mul(ivec3 a, ivec3 b, ivec3 dest) { glm_ivec3_mul(a, b, dest); } CGLM_EXPORT void glmc_ivec3_scale(ivec3 v, int s, ivec3 dest) { glm_ivec3_scale(v, s, dest); } CGLM_EXPORT void glmc_ivec3_div(ivec3 a, ivec3 b, ivec3 dest) { glm_ivec3_div(a, b, dest); } CGLM_EXPORT void glmc_ivec3_divs(ivec3 v, int s, ivec3 dest) { glm_ivec3_divs(v, s, dest); } CGLM_EXPORT void glmc_ivec3_mod(ivec3 a, ivec3 b, ivec3 dest) { glm_ivec3_mod(a, b, dest); } CGLM_EXPORT void glmc_ivec3_addadd(ivec3 a, ivec3 b, ivec3 dest) { glm_ivec3_addadd(a, b, dest); } CGLM_EXPORT void glmc_ivec3_addadds(ivec3 a, int s, ivec3 dest) { glm_ivec3_addadds(a, s, dest); } CGLM_EXPORT void glmc_ivec3_subadd(ivec3 a, ivec3 b, ivec3 dest) { glm_ivec3_subadd(a, b, dest); } CGLM_EXPORT void glmc_ivec3_subadds(ivec3 a, int s, ivec3 dest) { glm_ivec3_subadds(a, s, dest); } CGLM_EXPORT void glmc_ivec3_muladd(ivec3 a, ivec3 b, ivec3 dest) { glm_ivec3_muladd(a, b, dest); } CGLM_EXPORT void glmc_ivec3_muladds(ivec3 a, int s, ivec3 dest) { glm_ivec3_muladds(a, s, dest); } CGLM_EXPORT void glmc_ivec3_maxadd(ivec3 a, ivec3 b, ivec3 dest) { glm_ivec3_maxadd(a, b, dest); } CGLM_EXPORT void glmc_ivec3_minadd(ivec3 a, ivec3 b, ivec3 dest) { glm_ivec3_minadd(a, b, dest); } CGLM_EXPORT void glmc_ivec3_subsub(ivec3 a, ivec3 b, ivec3 dest) { glm_ivec3_subsub(a, b, dest); } CGLM_EXPORT void glmc_ivec3_subsubs(ivec3 a, int s, ivec3 dest) { glm_ivec3_subsubs(a, s, dest); } CGLM_EXPORT void glmc_ivec3_addsub(ivec3 a, ivec3 b, ivec3 dest) { glm_ivec3_addsub(a, b, dest); } CGLM_EXPORT void glmc_ivec3_addsubs(ivec3 a, int s, ivec3 dest) { glm_ivec3_addsubs(a, s, dest); } CGLM_EXPORT void glmc_ivec3_mulsub(ivec3 a, ivec3 b, ivec3 dest) { glm_ivec3_mulsub(a, b, dest); } CGLM_EXPORT void glmc_ivec3_mulsubs(ivec3 a, int s, ivec3 dest) { glm_ivec3_mulsubs(a, s, dest); } CGLM_EXPORT void glmc_ivec3_maxsub(ivec3 a, ivec3 b, ivec3 dest) { glm_ivec3_maxsub(a, b, dest); } CGLM_EXPORT void glmc_ivec3_minsub(ivec3 a, ivec3 b, ivec3 dest) { glm_ivec3_minsub(a, b, dest); } CGLM_EXPORT int glmc_ivec3_distance2(ivec3 a, ivec3 b) { return glm_ivec3_distance2(a, b); } CGLM_EXPORT float glmc_ivec3_distance(ivec3 a, ivec3 b) { return glm_ivec3_distance(a, b); } CGLM_EXPORT void glmc_ivec3_fill(ivec3 v, int val) { glm_ivec3_fill(v, val); } CGLM_EXPORT bool glmc_ivec3_eq(ivec3 v, int val) { return glm_ivec3_eq(v, val); } CGLM_EXPORT bool glmc_ivec3_eqv(ivec3 a, ivec3 b) { return glm_ivec3_eqv(a, b); } CGLM_EXPORT void glmc_ivec3_maxv(ivec3 a, ivec3 b, ivec3 dest) { glm_ivec3_maxv(a, b, dest); } CGLM_EXPORT void glmc_ivec3_minv(ivec3 a, ivec3 b, ivec3 dest) { glm_ivec3_minv(a, b, dest); } CGLM_EXPORT void glmc_ivec3_clamp(ivec3 v, int minVal, int maxVal) { glm_ivec3_clamp(v, minVal, maxVal); } CGLM_EXPORT void glmc_ivec3_abs(ivec3 v, ivec3 dest) { glm_ivec3_abs(v, dest); } cglm-0.9.7/src/ivec4.c000066400000000000000000000064361526744317200144420ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_ivec4(ivec3 v3, int last, ivec4 dest) { glm_ivec4(v3, last, dest); } CGLM_EXPORT void glmc_ivec4_copy(ivec4 a, ivec4 dest) { glm_ivec4_copy(a, dest); } CGLM_EXPORT void glmc_ivec4_zero(ivec4 v) { glm_ivec4_zero(v); } CGLM_EXPORT void glmc_ivec4_one(ivec4 v) { glm_ivec4_one(v); } CGLM_EXPORT void glmc_ivec4_add(ivec4 a, ivec4 b, ivec4 dest) { glm_ivec4_add(a, b, dest); } CGLM_EXPORT void glmc_ivec4_adds(ivec4 v, int s, ivec4 dest) { glm_ivec4_adds(v, s, dest); } CGLM_EXPORT void glmc_ivec4_sub(ivec4 a, ivec4 b, ivec4 dest) { glm_ivec4_sub(a, b, dest); } CGLM_EXPORT void glmc_ivec4_subs(ivec4 v, int s, ivec4 dest) { glm_ivec4_subs(v, s, dest); } CGLM_EXPORT void glmc_ivec4_mul(ivec4 a, ivec4 b, ivec4 dest) { glm_ivec4_mul(a, b, dest); } CGLM_EXPORT void glmc_ivec4_scale(ivec4 v, int s, ivec4 dest) { glm_ivec4_scale(v, s, dest); } CGLM_EXPORT void glmc_ivec4_addadd(ivec4 a, ivec4 b, ivec4 dest) { glm_ivec4_addadd(a, b, dest); } CGLM_EXPORT void glmc_ivec4_addadds(ivec4 a, int s, ivec4 dest) { glm_ivec4_addadds(a, s, dest); } CGLM_EXPORT void glmc_ivec4_subadd(ivec4 a, ivec4 b, ivec4 dest) { glm_ivec4_subadd(a, b, dest); } CGLM_EXPORT void glmc_ivec4_subadds(ivec4 a, int s, ivec4 dest) { glm_ivec4_subadds(a, s, dest); } CGLM_EXPORT void glmc_ivec4_muladd(ivec4 a, ivec4 b, ivec4 dest) { glm_ivec4_muladd(a, b, dest); } CGLM_EXPORT void glmc_ivec4_muladds(ivec4 a, int s, ivec4 dest) { glm_ivec4_muladds(a, s, dest); } CGLM_EXPORT void glmc_ivec4_maxadd(ivec4 a, ivec4 b, ivec4 dest) { glm_ivec4_maxadd(a, b, dest); } CGLM_EXPORT void glmc_ivec4_minadd(ivec4 a, ivec4 b, ivec4 dest) { glm_ivec4_minadd(a, b, dest); } CGLM_EXPORT void glmc_ivec4_subsub(ivec4 a, ivec4 b, ivec4 dest) { glm_ivec4_subsub(a, b, dest); } CGLM_EXPORT void glmc_ivec4_subsubs(ivec4 a, int s, ivec4 dest) { glm_ivec4_subsubs(a, s, dest); } CGLM_EXPORT void glmc_ivec4_addsub(ivec4 a, ivec4 b, ivec4 dest) { glm_ivec4_addsub(a, b, dest); } CGLM_EXPORT void glmc_ivec4_addsubs(ivec4 a, int s, ivec4 dest) { glm_ivec4_addsubs(a, s, dest); } CGLM_EXPORT void glmc_ivec4_mulsub(ivec4 a, ivec4 b, ivec4 dest) { glm_ivec4_mulsub(a, b, dest); } CGLM_EXPORT void glmc_ivec4_mulsubs(ivec4 a, int s, ivec4 dest) { glm_ivec4_mulsubs(a, s, dest); } CGLM_EXPORT void glmc_ivec4_maxsub(ivec4 a, ivec4 b, ivec4 dest) { glm_ivec4_maxsub(a, b, dest); } CGLM_EXPORT void glmc_ivec4_minsub(ivec4 a, ivec4 b, ivec4 dest) { glm_ivec4_minsub(a, b, dest); } CGLM_EXPORT int glmc_ivec4_distance2(ivec4 a, ivec4 b) { return glm_ivec4_distance2(a, b); } CGLM_EXPORT float glmc_ivec4_distance(ivec4 a, ivec4 b) { return glm_ivec4_distance(a, b); } CGLM_EXPORT void glmc_ivec4_maxv(ivec4 a, ivec4 b, ivec4 dest) { glm_ivec4_maxv(a, b, dest); } CGLM_EXPORT void glmc_ivec4_minv(ivec4 a, ivec4 b, ivec4 dest) { glm_ivec4_minv(a, b, dest); } CGLM_EXPORT void glmc_ivec4_clamp(ivec4 v, int minVal, int maxVal) { glm_ivec4_clamp(v, minVal, maxVal); } CGLM_EXPORT void glmc_ivec4_abs(ivec4 v, ivec4 dest) { glm_ivec4_abs(v, dest); } cglm-0.9.7/src/mat2.c000066400000000000000000000031731526744317200142660ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_mat2_make(const float * __restrict src, mat2 dest) { glm_mat2_make(src, dest); } CGLM_EXPORT void glmc_mat2_copy(mat2 mat, mat2 dest) { glm_mat2_copy(mat, dest); } CGLM_EXPORT void glmc_mat2_identity(mat2 m) { glm_mat2_identity(m); } CGLM_EXPORT void glmc_mat2_identity_array(mat2 * __restrict mats, size_t count) { glm_mat2_identity_array(mats, count); } CGLM_EXPORT void glmc_mat2_zero(mat2 m) { glm_mat2_zero(m); } CGLM_EXPORT void glmc_mat2_mul(mat2 m1, mat2 m2, mat2 dest) { glm_mat2_mul(m1, m2, dest); } CGLM_EXPORT void glmc_mat2_mulv(mat2 m, vec2 v, vec2 dest) { glm_mat2_mulv(m, v, dest); } CGLM_EXPORT void glmc_mat2_transpose_to(mat2 mat, mat2 dest) { glm_mat2_transpose_to(mat, dest); } CGLM_EXPORT void glmc_mat2_transpose(mat2 m) { glm_mat2_transpose(m); } CGLM_EXPORT void glmc_mat2_scale(mat2 m, float s) { glm_mat2_scale(m, s); } CGLM_EXPORT void glmc_mat2_inv(mat2 mat, mat2 dest) { glm_mat2_inv(mat, dest); } CGLM_EXPORT void glmc_mat2_swap_col(mat2 mat, int col1, int col2) { glm_mat2_swap_col(mat, col1, col2); } CGLM_EXPORT void glmc_mat2_swap_row(mat2 mat, int row1, int row2) { glm_mat2_swap_row(mat, row1, row2); } CGLM_EXPORT float glmc_mat2_det(mat2 m) { return glm_mat2_det(m); } CGLM_EXPORT float glmc_mat2_trace(mat2 m) { return glm_mat2_trace(m); } CGLM_EXPORT float glmc_mat2_rmc(vec2 r, mat2 m, vec2 c) { return glm_mat2_rmc(r, m, c); } cglm-0.9.7/src/mat2x3.c000066400000000000000000000015671526744317200145460ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_mat2x3_copy(mat2x3 src, mat2x3 dest) { glm_mat2x3_copy(src, dest); } CGLM_EXPORT void glmc_mat2x3_zero(mat2x3 m) { glm_mat2x3_zero(m); } CGLM_EXPORT void glmc_mat2x3_make(const float * __restrict src, mat2x3 dest) { glm_mat2x3_make(src, dest); } CGLM_EXPORT void glmc_mat2x3_mul(mat2x3 m1, mat3x2 m2, mat3 dest) { glm_mat2x3_mul(m1, m2, dest); } CGLM_EXPORT void glmc_mat2x3_mulv(mat2x3 m, vec2 v, vec3 dest) { glm_mat2x3_mulv(m, v, dest); } CGLM_EXPORT void glmc_mat2x3_transpose(mat2x3 src, mat3x2 dest) { glm_mat2x3_transpose(src, dest); } CGLM_EXPORT void glmc_mat2x3_scale(mat2x3 m, float s) { glm_mat2x3_scale(m, s); } cglm-0.9.7/src/mat2x4.c000066400000000000000000000015671526744317200145470ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_mat2x4_copy(mat2x4 src, mat2x4 dest) { glm_mat2x4_copy(src, dest); } CGLM_EXPORT void glmc_mat2x4_zero(mat2x4 m) { glm_mat2x4_zero(m); } CGLM_EXPORT void glmc_mat2x4_make(const float * __restrict src, mat2x4 dest) { glm_mat2x4_make(src, dest); } CGLM_EXPORT void glmc_mat2x4_mul(mat2x4 m1, mat4x2 m2, mat4 dest) { glm_mat2x4_mul(m1, m2, dest); } CGLM_EXPORT void glmc_mat2x4_mulv(mat2x4 m, vec2 v, vec4 dest) { glm_mat2x4_mulv(m, v, dest); } CGLM_EXPORT void glmc_mat2x4_transpose(mat2x4 src, mat4x2 dest) { glm_mat2x4_transpose(src, dest); } CGLM_EXPORT void glmc_mat2x4_scale(mat2x4 m, float s) { glm_mat2x4_scale(m, s); } cglm-0.9.7/src/mat3.c000066400000000000000000000035541526744317200142720ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_mat3_copy(mat3 mat, mat3 dest) { glm_mat3_copy(mat, dest); } CGLM_EXPORT void glmc_mat3_identity(mat3 mat) { glm_mat3_identity(mat); } CGLM_EXPORT void glmc_mat3_zero(mat3 mat) { glm_mat3_zero(mat); } CGLM_EXPORT void glmc_mat3_identity_array(mat3 * __restrict mat, size_t count) { glm_mat3_identity_array(mat, count); } CGLM_EXPORT void glmc_mat3_mul(mat3 m1, mat3 m2, mat3 dest) { glm_mat3_mul(m1, m2, dest); } CGLM_EXPORT void glmc_mat3_transpose_to(mat3 m, mat3 dest) { glm_mat3_transpose_to(m, dest); } CGLM_EXPORT void glmc_mat3_transpose(mat3 m) { glm_mat3_transpose(m); } CGLM_EXPORT void glmc_mat3_mulv(mat3 m, vec3 v, vec3 dest) { glm_mat3_mulv(m, v, dest); } CGLM_EXPORT float glmc_mat3_trace(mat3 m) { return glm_mat3_trace(m); } CGLM_EXPORT void glmc_mat3_quat(mat3 m, versor dest) { glm_mat3_quat(m, dest); } CGLM_EXPORT void glmc_mat3_scale(mat3 m, float s) { glm_mat3_scale(m, s); } CGLM_EXPORT float glmc_mat3_det(mat3 mat) { return glm_mat3_det(mat); } CGLM_EXPORT void glmc_mat3_inv(mat3 mat, mat3 dest) { glm_mat3_inv(mat, dest); } CGLM_EXPORT void glmc_mat3_swap_col(mat3 mat, int col1, int col2) { glm_mat3_swap_col(mat, col1, col2); } CGLM_EXPORT void glmc_mat3_swap_row(mat3 mat, int row1, int row2) { glm_mat3_swap_row(mat, row1, row2); } CGLM_EXPORT float glmc_mat3_rmc(vec3 r, mat3 m, vec3 c) { return glm_mat3_rmc(r, m, c); } CGLM_EXPORT void glmc_mat3_make(const float * __restrict src, mat3 dest) { glm_mat3_make(src, dest); } CGLM_EXPORT void glmc_mat3_textrans(float sx, float sy, float rot, float tx, float ty, mat3 dest) { glm_mat3_textrans(sx, sy, rot, tx, ty, dest); } cglm-0.9.7/src/mat3x2.c000066400000000000000000000015671526744317200145460ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_mat3x2_copy(mat3x2 src, mat3x2 dest) { glm_mat3x2_copy(src, dest); } CGLM_EXPORT void glmc_mat3x2_zero(mat3x2 m) { glm_mat3x2_zero(m); } CGLM_EXPORT void glmc_mat3x2_make(const float * __restrict src, mat3x2 dest) { glm_mat3x2_make(src, dest); } CGLM_EXPORT void glmc_mat3x2_mul(mat3x2 m1, mat2x3 m2, mat2 dest) { glm_mat3x2_mul(m1, m2, dest); } CGLM_EXPORT void glmc_mat3x2_mulv(mat3x2 m, vec3 v, vec2 dest) { glm_mat3x2_mulv(m, v, dest); } CGLM_EXPORT void glmc_mat3x2_transpose(mat3x2 src, mat2x3 dest) { glm_mat3x2_transpose(src, dest); } CGLM_EXPORT void glmc_mat3x2_scale(mat3x2 m, float s) { glm_mat3x2_scale(m, s); } cglm-0.9.7/src/mat3x4.c000066400000000000000000000015671526744317200145500ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_mat3x4_copy(mat3x4 src, mat3x4 dest) { glm_mat3x4_copy(src, dest); } CGLM_EXPORT void glmc_mat3x4_zero(mat3x4 m) { glm_mat3x4_zero(m); } CGLM_EXPORT void glmc_mat3x4_make(const float * __restrict src, mat3x4 dest) { glm_mat3x4_make(src, dest); } CGLM_EXPORT void glmc_mat3x4_mul(mat3x4 m1, mat4x3 m2, mat4 dest) { glm_mat3x4_mul(m1, m2, dest); } CGLM_EXPORT void glmc_mat3x4_mulv(mat3x4 m, vec3 v, vec4 dest) { glm_mat3x4_mulv(m, v, dest); } CGLM_EXPORT void glmc_mat3x4_transpose(mat3x4 src, mat4x3 dest) { glm_mat3x4_transpose(src, dest); } CGLM_EXPORT void glmc_mat3x4_scale(mat3x4 m, float s) { glm_mat3x4_scale(m, s); } cglm-0.9.7/src/mat4.c000066400000000000000000000054401526744317200142670ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_mat4_ucopy(mat4 mat, mat4 dest) { glm_mat4_copy(mat, dest); } CGLM_EXPORT void glmc_mat4_copy(mat4 mat, mat4 dest) { glm_mat4_copy(mat, dest); } CGLM_EXPORT void glmc_mat4_identity(mat4 mat) { glm_mat4_identity(mat); } CGLM_EXPORT void glmc_mat4_identity_array(mat4 * __restrict mat, size_t count) { glm_mat4_identity_array(mat, count); } CGLM_EXPORT void glmc_mat4_zero(mat4 mat) { glm_mat4_zero(mat); } CGLM_EXPORT void glmc_mat4_pick3(mat4 mat, mat3 dest) { glm_mat4_pick3(mat, dest); } CGLM_EXPORT void glmc_mat4_pick3t(mat4 mat, mat3 dest) { glm_mat4_pick3t(mat, dest); } CGLM_EXPORT void glmc_mat4_ins3(mat3 mat, mat4 dest) { glm_mat4_ins3(mat, dest); } CGLM_EXPORT void glmc_mat4_mul(mat4 m1, mat4 m2, mat4 dest) { glm_mat4_mul(m1, m2, dest); } CGLM_EXPORT void glmc_mat4_mulN(mat4 * __restrict matrices[], uint32_t len, mat4 dest) { glm_mat4_mulN(matrices, len, dest); } CGLM_EXPORT void glmc_mat4_mulv(mat4 m, vec4 v, vec4 dest) { glm_mat4_mulv(m, v, dest); } CGLM_EXPORT void glmc_mat4_mulv3(mat4 m, vec3 v, float last, vec3 dest) { glm_mat4_mulv3(m, v, last, dest); } CGLM_EXPORT float glmc_mat4_trace(mat4 m) { return glm_mat4_trace(m); } CGLM_EXPORT float glmc_mat4_trace3(mat4 m) { return glm_mat4_trace3(m); } CGLM_EXPORT void glmc_mat4_quat(mat4 m, versor dest) { glm_mat4_quat(m, dest); } CGLM_EXPORT void glmc_mat4_transpose_to(mat4 m, mat4 dest) { glm_mat4_transpose_to(m, dest); } CGLM_EXPORT void glmc_mat4_transpose(mat4 m) { glm_mat4_transpose(m); } CGLM_EXPORT void glmc_mat4_scale_p(mat4 m, float s) { glm_mat4_scale_p(m, s); } CGLM_EXPORT void glmc_mat4_scale(mat4 m, float s) { glm_mat4_scale(m, s); } CGLM_EXPORT float glmc_mat4_det(mat4 mat) { return glm_mat4_det(mat); } CGLM_EXPORT void glmc_mat4_inv(mat4 mat, mat4 dest) { glm_mat4_inv(mat, dest); } CGLM_EXPORT void glmc_mat4_inv_precise(mat4 mat, mat4 dest) { glm_mat4_inv_precise(mat, dest); } CGLM_EXPORT void glmc_mat4_inv_fast(mat4 mat, mat4 dest) { glm_mat4_inv_fast(mat, dest); } CGLM_EXPORT void glmc_mat4_swap_col(mat4 mat, int col1, int col2) { glm_mat4_swap_col(mat, col1, col2); } CGLM_EXPORT void glmc_mat4_swap_row(mat4 mat, int row1, int row2) { glm_mat4_swap_row(mat, row1, row2); } CGLM_EXPORT float glmc_mat4_rmc(vec4 r, mat4 m, vec4 c) { return glm_mat4_rmc(r, m, c); } CGLM_EXPORT void glmc_mat4_make(const float * __restrict src, mat4 dest) { glm_mat4_make(src, dest); } CGLM_EXPORT void glmc_mat4_textrans(float sx, float sy, float rot, float tx, float ty, mat4 dest) { glm_mat4_textrans(sx, sy, rot, tx, ty, dest); } cglm-0.9.7/src/mat4x2.c000066400000000000000000000015671526744317200145470ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_mat4x2_copy(mat4x2 src, mat4x2 dest) { glm_mat4x2_copy(src, dest); } CGLM_EXPORT void glmc_mat4x2_zero(mat4x2 m) { glm_mat4x2_zero(m); } CGLM_EXPORT void glmc_mat4x2_make(const float * __restrict src, mat4x2 dest) { glm_mat4x2_make(src, dest); } CGLM_EXPORT void glmc_mat4x2_mul(mat4x2 m1, mat2x4 m2, mat2 dest) { glm_mat4x2_mul(m1, m2, dest); } CGLM_EXPORT void glmc_mat4x2_mulv(mat4x2 m, vec4 v, vec2 dest) { glm_mat4x2_mulv(m, v, dest); } CGLM_EXPORT void glmc_mat4x2_transpose(mat4x2 src, mat2x4 dest) { glm_mat4x2_transpose(src, dest); } CGLM_EXPORT void glmc_mat4x2_scale(mat4x2 m, float s) { glm_mat4x2_scale(m, s); } cglm-0.9.7/src/mat4x3.c000066400000000000000000000015671526744317200145500ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_mat4x3_copy(mat4x3 src, mat4x3 dest) { glm_mat4x3_copy(src, dest); } CGLM_EXPORT void glmc_mat4x3_zero(mat4x3 m) { glm_mat4x3_zero(m); } CGLM_EXPORT void glmc_mat4x3_make(const float * __restrict src, mat4x3 dest) { glm_mat4x3_make(src, dest); } CGLM_EXPORT void glmc_mat4x3_mul(mat4x3 m1, mat3x4 m2, mat3 dest) { glm_mat4x3_mul(m1, m2, dest); } CGLM_EXPORT void glmc_mat4x3_mulv(mat4x3 m, vec4 v, vec3 dest) { glm_mat4x3_mulv(m, v, dest); } CGLM_EXPORT void glmc_mat4x3_transpose(mat4x3 src, mat3x4 dest) { glm_mat4x3_transpose(src, dest); } CGLM_EXPORT void glmc_mat4x3_scale(mat4x3 m, float s) { glm_mat4x3_scale(m, s); } cglm-0.9.7/src/noise.c000066400000000000000000000007021526744317200145330ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT float glmc_perlin_vec4(vec4 p) { return glm_perlin_vec4(p); } CGLM_EXPORT float glmc_perlin_vec3(vec3 p) { return glm_perlin_vec3(p); } CGLM_EXPORT float glmc_perlin_vec2(vec2 p) { return glm_perlin_vec2(p); } cglm-0.9.7/src/plane.c000066400000000000000000000004601526744317200145160ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_plane_normalize(vec4 plane) { glm_plane_normalize(plane); } cglm-0.9.7/src/project.c000066400000000000000000000014011526744317200150610ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_unprojecti(vec3 pos, mat4 invMat, vec4 vp, vec3 dest) { glm_unprojecti(pos, invMat, vp, dest); } CGLM_EXPORT void glmc_unproject(vec3 pos, mat4 m, vec4 vp, vec3 dest) { glm_unproject(pos, m, vp, dest); } CGLM_EXPORT void glmc_project(vec3 pos, mat4 m, vec4 vp, vec3 dest) { glm_project(pos, m, vp, dest); } CGLM_EXPORT float glmc_project_z(vec3 pos, mat4 m) { return glm_project_z(pos, m); } CGLM_EXPORT void glmc_pickmatrix(vec2 center, vec2 size, vec4 vp, mat4 dest) { glm_pickmatrix(center, size, vp, dest); } cglm-0.9.7/src/quat.c000066400000000000000000000077051526744317200144020ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_quat_identity(versor q) { glm_quat_identity(q); } CGLM_EXPORT void glmc_quat_identity_array(versor * __restrict q, size_t count) { glm_quat_identity_array(q, count); } CGLM_EXPORT void glmc_quat_init(versor q, float x, float y, float z, float w) { glm_quat_init(q, x, y, z, w); } CGLM_EXPORT void glmc_quat(versor q, float angle, float x, float y, float z) { glm_quat(q, angle, x, y, z); } CGLM_EXPORT void glmc_quatv(versor q, float angle, vec3 axis) { glm_quatv(q, angle, axis); } CGLM_EXPORT void glmc_quat_copy(versor q, versor dest) { glm_quat_copy(q, dest); } CGLM_EXPORT void glmc_quat_from_vecs(vec3 a, vec3 b, versor dest) { glm_quat_from_vecs(a, b, dest); } CGLM_EXPORT float glmc_quat_norm(versor q) { return glm_quat_norm(q); } CGLM_EXPORT void glmc_quat_normalize_to(versor q, versor dest) { glm_quat_normalize_to(q, dest); } CGLM_EXPORT void glmc_quat_normalize(versor q) { glm_quat_normalize(q); } CGLM_EXPORT float glmc_quat_dot(versor p, versor q) { return glm_quat_dot(p, q); } CGLM_EXPORT void glmc_quat_conjugate(versor q, versor dest) { glm_quat_conjugate(q, dest); } CGLM_EXPORT void glmc_quat_inv(versor q, versor dest) { glm_quat_inv(q, dest); } CGLM_EXPORT void glmc_quat_add(versor p, versor q, versor dest) { glm_quat_add(p, q, dest); } CGLM_EXPORT void glmc_quat_sub(versor p, versor q, versor dest) { glm_quat_sub(p, q, dest); } CGLM_EXPORT float glmc_quat_real(versor q) { return glm_quat_real(q); } CGLM_EXPORT void glmc_quat_imag(versor q, vec3 dest) { glm_quat_imag(q, dest); } CGLM_EXPORT void glmc_quat_imagn(versor q, vec3 dest) { glm_quat_imagn(q, dest); } CGLM_EXPORT float glmc_quat_imaglen(versor q) { return glm_quat_imaglen(q); } CGLM_EXPORT float glmc_quat_angle(versor q) { return glm_quat_angle(q); } CGLM_EXPORT void glmc_quat_axis(versor q, vec3 dest) { glm_quat_axis(q, dest); } CGLM_EXPORT void glmc_quat_mul(versor p, versor q, versor dest) { glm_quat_mul(p, q, dest); } CGLM_EXPORT void glmc_quat_mat4(versor q, mat4 dest) { glm_quat_mat4(q, dest); } CGLM_EXPORT void glmc_quat_mat4t(versor q, mat4 dest) { glm_quat_mat4t(q, dest); } CGLM_EXPORT void glmc_quat_mat3(versor q, mat3 dest) { glm_quat_mat3(q, dest); } CGLM_EXPORT void glmc_quat_mat3t(versor q, mat3 dest) { glm_quat_mat3t(q, dest); } CGLM_EXPORT void glmc_quat_lerp(versor from, versor to, float t, versor dest) { glm_quat_lerp(from, to, t, dest); } CGLM_EXPORT void glmc_quat_lerpc(versor from, versor to, float t, versor dest) { glm_quat_lerpc(from, to, t, dest); } CGLM_EXPORT void glmc_quat_nlerp(versor from, versor to, float t, versor dest) { glm_quat_nlerp(from, to, t, dest); } CGLM_EXPORT void glmc_quat_slerp(versor from, versor to, float t, versor dest) { glm_quat_slerp(from, to, t, dest); } CGLM_EXPORT void glmc_quat_slerp_longest(versor from, versor to, float t, versor dest) { glm_quat_slerp_longest(from, to, t, dest); } CGLM_EXPORT void glmc_quat_look(vec3 eye, versor ori, mat4 dest) { glm_quat_look(eye, ori, dest); } CGLM_EXPORT void glmc_quat_for(vec3 dir, vec3 up, versor dest) { glm_quat_for(dir, up, dest); } CGLM_EXPORT void glmc_quat_forp(vec3 from, vec3 to, vec3 up, versor dest) { glm_quat_forp(from, to, up, dest); } CGLM_EXPORT void glmc_quat_rotatev(versor q, vec3 v, vec3 dest) { glm_quat_rotatev(q, v, dest); } CGLM_EXPORT void glmc_quat_rotate(mat4 m, versor q, mat4 dest) { glm_quat_rotate(m, q, dest); } CGLM_EXPORT void glmc_quat_rotate_at(mat4 model, versor q, vec3 pivot) { glm_quat_rotate_at(model, q, pivot); } CGLM_EXPORT void glmc_quat_rotate_atm(mat4 m, versor q, vec3 pivot) { glm_quat_rotate_atm(m, q, pivot); } CGLM_EXPORT void glmc_quat_make(const float * __restrict src, versor dest) { glm_quat_make(src, dest); } cglm-0.9.7/src/ray.c000066400000000000000000000012421526744317200142110ustar00rootroot00000000000000#include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT bool glmc_ray_triangle(vec3 origin, vec3 direction, vec3 v0, vec3 v1, vec3 v2, float *d) { return glm_ray_triangle(origin, direction, v0, v1, v2, d); } CGLM_EXPORT bool glmc_ray_sphere(vec3 origin, vec3 dir, vec4 s, float * __restrict t1, float * __restrict t2) { return glm_ray_sphere(origin, dir, s, t1, t2); } CGLM_EXPORT void glmc_ray_at(vec3 orig, vec3 dir, float t, vec3 point) { glm_ray_at(orig, dir, t, point); } cglm-0.9.7/src/sphere.c000066400000000000000000000012741526744317200147110ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT float glmc_sphere_radii(vec4 s) { return glm_sphere_radii(s); } CGLM_EXPORT void glmc_sphere_transform(vec4 s, mat4 m, vec4 dest) { glm_sphere_transform(s, m, dest); } CGLM_EXPORT void glmc_sphere_merge(vec4 s1, vec4 s2, vec4 dest) { glm_sphere_merge(s1, s2, dest); } CGLM_EXPORT bool glmc_sphere_sphere(vec4 s1, vec4 s2) { return glm_sphere_sphere(s1, s2); } CGLM_EXPORT bool glmc_sphere_point(vec4 s, vec3 point) { return glm_sphere_point(s, point); } cglm-0.9.7/src/swift/000077500000000000000000000000001526744317200144075ustar00rootroot00000000000000cglm-0.9.7/src/swift/empty.c000066400000000000000000000002421526744317200157070ustar00rootroot00000000000000// This empty file is needed to trick swiftpm to build the header-only version of cglm as swiftpm itself does not support C targets that have no source code filescglm-0.9.7/src/vec2.c000066400000000000000000000131021526744317200142530ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_vec2(float * __restrict v, vec2 dest) { glm_vec2(v, dest); } CGLM_EXPORT void glmc_vec2_fill(vec2 v, float val) { glm_vec2_fill(v, val); } CGLM_EXPORT bool glmc_vec2_eq(vec2 v, float val) { return glm_vec2_eq(v, val); } CGLM_EXPORT bool glmc_vec2_eqv(vec2 a, vec2 b) { return glm_vec2_eqv(a, b); } CGLM_EXPORT void glmc_vec2_copy(vec2 a, vec2 dest) { glm_vec2_copy(a, dest); } CGLM_EXPORT void glmc_vec2_zero(vec2 v) { glm_vec2_zero(v); } CGLM_EXPORT void glmc_vec2_one(vec2 v) { glm_vec2_one(v); } CGLM_EXPORT float glmc_vec2_dot(vec2 a, vec2 b) { return glm_vec2_dot(a, b); } CGLM_EXPORT float glmc_vec2_cross(vec2 a, vec2 b) { return glm_vec2_cross(a, b); } CGLM_EXPORT float glmc_vec2_norm2(vec2 v) { return glm_vec2_norm2(v); } CGLM_EXPORT float glmc_vec2_norm(vec2 v) { return glm_vec2_norm(v); } CGLM_EXPORT void glmc_vec2_add(vec2 a, vec2 b, vec2 dest) { glm_vec2_add(a, b, dest); } CGLM_EXPORT void glmc_vec2_adds(vec2 v, float s, vec2 dest) { glm_vec2_adds(v, s, dest); } CGLM_EXPORT void glmc_vec2_sub(vec2 a, vec2 b, vec2 dest) { glm_vec2_sub(a, b, dest); } CGLM_EXPORT void glmc_vec2_subs(vec2 v, float s, vec2 dest) { glm_vec2_subs(v, s, dest); } CGLM_EXPORT void glmc_vec2_mul(vec2 a, vec2 b, vec2 dest) { glm_vec2_mul(a, b, dest); } CGLM_EXPORT void glmc_vec2_scale(vec2 v, float s, vec2 dest) { glm_vec2_scale(v, s, dest); } CGLM_EXPORT void glmc_vec2_scale_as(vec2 v, float s, vec2 dest) { glm_vec2_scale_as(v, s, dest); } CGLM_EXPORT void glmc_vec2_div(vec2 a, vec2 b, vec2 dest) { glm_vec2_div(a, b, dest); } CGLM_EXPORT void glmc_vec2_divs(vec2 v, float s, vec2 dest) { glm_vec2_divs(v, s, dest); } CGLM_EXPORT void glmc_vec2_addadd(vec2 a, vec2 b, vec2 dest) { glm_vec2_addadd(a, b, dest); } CGLM_EXPORT void glmc_vec2_subadd(vec2 a, vec2 b, vec2 dest) { glm_vec2_subadd(a, b, dest); } CGLM_EXPORT void glmc_vec2_muladd(vec2 a, vec2 b, vec2 dest) { glm_vec2_muladd(a, b, dest); } CGLM_EXPORT void glmc_vec2_muladds(vec2 a, float s, vec2 dest) { glm_vec2_muladds(a, s, dest); } CGLM_EXPORT void glmc_vec2_maxadd(vec2 a, vec2 b, vec2 dest) { glm_vec2_maxadd(a, b, dest); } CGLM_EXPORT void glmc_vec2_minadd(vec2 a, vec2 b, vec2 dest) { glm_vec2_minadd(a, b, dest); } CGLM_EXPORT void glmc_vec2_subsub(vec2 a, vec2 b, vec2 dest) { glm_vec2_subsub(a, b, dest); } CGLM_EXPORT void glmc_vec2_addsub(vec2 a, vec2 b, vec2 dest) { glm_vec2_addsub(a, b, dest); } CGLM_EXPORT void glmc_vec2_mulsub(vec2 a, vec2 b, vec2 dest) { glm_vec2_mulsub(a, b, dest); } CGLM_EXPORT void glmc_vec2_mulsubs(vec2 a, float s, vec2 dest) { glm_vec2_mulsubs(a, s, dest); } CGLM_EXPORT void glmc_vec2_maxsub(vec2 a, vec2 b, vec2 dest) { glm_vec2_maxsub(a, b, dest); } CGLM_EXPORT void glmc_vec2_minsub(vec2 a, vec2 b, vec2 dest) { glm_vec2_minsub(a, b, dest); } CGLM_EXPORT void glmc_vec2_negate_to(vec2 v, vec2 dest) { glm_vec2_negate_to(v, dest); } CGLM_EXPORT void glmc_vec2_negate(vec2 v) { glm_vec2_negate(v); } CGLM_EXPORT void glmc_vec2_normalize(vec2 v) { glm_vec2_normalize(v); } CGLM_EXPORT void glmc_vec2_normalize_to(vec2 v, vec2 dest) { glm_vec2_normalize_to(v, dest); } CGLM_EXPORT void glmc_vec2_rotate(vec2 v, float angle, vec2 dest) { glm_vec2_rotate(v, angle, dest); } CGLM_EXPORT void glmc_vec2_center(vec2 a, vec2 b, vec2 dest) { glm_vec2_center(a, b, dest); } CGLM_EXPORT float glmc_vec2_distance2(vec2 a, vec2 b) { return glm_vec2_distance2(a, b); } CGLM_EXPORT float glmc_vec2_distance(vec2 a, vec2 b) { return glm_vec2_distance(a, b); } CGLM_EXPORT void glmc_vec2_maxv(vec2 a, vec2 b, vec2 dest) { glm_vec2_maxv(a, b, dest); } CGLM_EXPORT void glmc_vec2_minv(vec2 a, vec2 b, vec2 dest) { glm_vec2_minv(a, b, dest); } CGLM_EXPORT void glmc_vec2_clamp(vec2 v, float minval, float maxval) { glm_vec2_clamp(v, minval, maxval); } CGLM_EXPORT void glmc_vec2_abs(vec2 v, vec2 dest) { glm_vec2_abs(v, dest); } CGLM_EXPORT void glmc_vec2_fract(vec2 v, vec2 dest) { glm_vec2_fract(v, dest); } CGLM_EXPORT void glmc_vec2_floor(vec2 v, vec2 dest) { glm_vec2_floor(v, dest); } CGLM_EXPORT void glmc_vec2_mods(vec2 v, float s, vec2 dest) { glm_vec2_mods(v, s, dest); } CGLM_EXPORT void glmc_vec2_step(vec2 edge, vec2 v, vec2 dest) { glm_vec2_step(edge, v, dest); } CGLM_EXPORT void glmc_vec2_steps(float edge, vec2 v, vec2 dest) { glm_vec2_steps(edge, v, dest); } CGLM_EXPORT void glmc_vec2_stepr(vec2 edge, float v, vec2 dest) { glm_vec2_stepr(edge, v, dest); } CGLM_EXPORT void glmc_vec2_swizzle(vec2 v, int mask, vec2 dest) { glm_vec2_swizzle(v, mask, dest); } CGLM_EXPORT void glmc_vec2_lerp(vec2 from, vec2 to, float t, vec2 dest) { glm_vec2_lerp(from, to, t, dest); } CGLM_EXPORT void glmc_vec2_complex_mul(vec2 a, vec2 b, vec2 dest) { glm_vec2_complex_mul(a, b, dest); } CGLM_EXPORT void glmc_vec2_complex_div(vec2 a, vec2 b, vec2 dest) { glm_vec2_complex_div(a, b, dest); } CGLM_EXPORT void glmc_vec2_complex_conjugate(vec2 a, vec2 dest) { glm_vec2_complex_conjugate(a, dest); } CGLM_EXPORT void glmc_vec2_make(const float * __restrict src, vec2 dest) { glm_vec2_make(src, dest); } CGLM_EXPORT void glmc_vec2_reflect(vec2 v, vec2 n, vec2 dest) { glm_vec2_reflect(v, n, dest); } CGLM_EXPORT bool glmc_vec2_refract(vec2 v, vec2 n, float eta, vec2 dest) { return glm_vec2_refract(v, n, eta, dest); } CGLM_EXPORT void glmc_vec2_swap(vec2 a, vec2 b) { glm_vec2_swap(a, b); } cglm-0.9.7/src/vec3.c000066400000000000000000000173561526744317200142730ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_vec3(vec4 v4, vec3 dest) { glm_vec3(v4, dest); } CGLM_EXPORT void glmc_vec3_copy(vec3 a, vec3 dest) { glm_vec3_copy(a, dest); } CGLM_EXPORT void glmc_vec3_zero(vec3 v) { glm_vec3_zero(v); } CGLM_EXPORT void glmc_vec3_one(vec3 v) { glm_vec3_one(v); } CGLM_EXPORT float glmc_vec3_dot(vec3 a, vec3 b) { return glm_vec3_dot(a, b); } CGLM_EXPORT void glmc_vec3_cross(vec3 a, vec3 b, vec3 dest) { glm_vec3_cross(a, b, dest); } CGLM_EXPORT void glmc_vec3_crossn(vec3 a, vec3 b, vec3 dest) { glm_vec3_crossn(a, b, dest); } CGLM_EXPORT float glmc_vec3_norm(vec3 v) { return glm_vec3_norm(v); } CGLM_EXPORT void glmc_vec3_normalize_to(vec3 v, vec3 dest) { glm_vec3_normalize_to(v, dest); } CGLM_EXPORT void glmc_vec3_normalize(vec3 v) { glm_vec3_normalize(v); } CGLM_EXPORT float glmc_vec3_norm2(vec3 v) { return glm_vec3_norm2(v); } CGLM_EXPORT float glmc_vec3_norm_one(vec3 v) { return glm_vec3_norm_one(v); } CGLM_EXPORT float glmc_vec3_norm_inf(vec3 v) { return glm_vec3_norm_inf(v); } CGLM_EXPORT void glmc_vec3_add(vec3 a, vec3 b, vec3 dest) { glm_vec3_add(a, b, dest); } CGLM_EXPORT void glmc_vec3_adds(vec3 v, float s, vec3 dest) { glm_vec3_adds(v, s, dest); } CGLM_EXPORT void glmc_vec3_sub(vec3 a, vec3 b, vec3 dest) { glm_vec3_sub(a, b, dest); } CGLM_EXPORT void glmc_vec3_subs(vec3 v, float s, vec3 dest) { glm_vec3_subs(v, s, dest); } CGLM_EXPORT void glmc_vec3_mul(vec3 a, vec3 b, vec3 d) { glm_vec3_mul(a, b, d); } CGLM_EXPORT void glmc_vec3_scale(vec3 v, float s, vec3 dest) { glm_vec3_scale(v, s, dest); } CGLM_EXPORT void glmc_vec3_scale_as(vec3 v, float s, vec3 dest) { glm_vec3_scale_as(v, s, dest); } CGLM_EXPORT void glmc_vec3_div(vec3 a, vec3 b, vec3 dest) { glm_vec3_div(a, b, dest); } CGLM_EXPORT void glmc_vec3_divs(vec3 a, float s, vec3 dest) { glm_vec3_divs(a, s, dest); } CGLM_EXPORT void glmc_vec3_addadd(vec3 a, vec3 b, vec3 dest) { glm_vec3_addadd(a, b, dest); } CGLM_EXPORT void glmc_vec3_subadd(vec3 a, vec3 b, vec3 dest) { glm_vec3_subadd(a, b, dest); } CGLM_EXPORT void glmc_vec3_muladd(vec3 a, vec3 b, vec3 dest) { glm_vec3_muladd(a, b, dest); } CGLM_EXPORT void glmc_vec3_muladds(vec3 a, float s, vec3 dest) { glm_vec3_muladds(a, s, dest); } CGLM_EXPORT void glmc_vec3_maxadd(vec3 a, vec3 b, vec3 dest) { glm_vec3_maxadd(a, b, dest); } CGLM_EXPORT void glmc_vec3_minadd(vec3 a, vec3 b, vec3 dest) { glm_vec3_minadd(a, b, dest); } CGLM_EXPORT void glmc_vec3_subsub(vec3 a, vec3 b, vec3 dest) { glm_vec3_subsub(a, b, dest); } CGLM_EXPORT void glmc_vec3_addsub(vec3 a, vec3 b, vec3 dest) { glm_vec3_addsub(a, b, dest); } CGLM_EXPORT void glmc_vec3_mulsub(vec3 a, vec3 b, vec3 dest) { glm_vec3_mulsub(a, b, dest); } CGLM_EXPORT void glmc_vec3_mulsubs(vec3 a, float s, vec3 dest) { glm_vec3_mulsubs(a, s, dest); } CGLM_EXPORT void glmc_vec3_maxsub(vec3 a, vec3 b, vec3 dest) { glm_vec3_maxsub(a, b, dest); } CGLM_EXPORT void glmc_vec3_minsub(vec3 a, vec3 b, vec3 dest) { glm_vec3_minsub(a, b, dest); } CGLM_EXPORT void glmc_vec3_negate(vec3 v) { glm_vec3_negate(v); } CGLM_EXPORT void glmc_vec3_negate_to(vec3 v, vec3 dest) { glm_vec3_negate_to(v, dest); } CGLM_EXPORT float glmc_vec3_angle(vec3 a, vec3 b) { return glm_vec3_angle(a, b); } CGLM_EXPORT void glmc_vec3_rotate(vec3 v, float angle, vec3 axis) { glm_vec3_rotate(v, angle, axis); } CGLM_EXPORT void glmc_vec3_rotate_m4(mat4 m, vec3 v, vec3 dest) { glm_vec3_rotate_m4(m, v, dest); } CGLM_EXPORT void glmc_vec3_rotate_m3(mat3 m, vec3 v, vec3 dest) { glm_vec3_rotate_m3(m, v, dest); } CGLM_EXPORT void glmc_vec3_proj(vec3 a, vec3 b, vec3 dest) { glm_vec3_proj(a, b, dest); } CGLM_EXPORT void glmc_vec3_center(vec3 a, vec3 b, vec3 dest) { glm_vec3_center(a, b, dest); } CGLM_EXPORT float glmc_vec3_distance(vec3 a, vec3 b) { return glm_vec3_distance(a, b); } CGLM_EXPORT float glmc_vec3_distance2(vec3 a, vec3 b) { return glm_vec3_distance2(a, b); } CGLM_EXPORT void glmc_vec3_maxv(vec3 a, vec3 b, vec3 dest) { glm_vec3_maxv(a, b, dest); } CGLM_EXPORT void glmc_vec3_minv(vec3 a, vec3 b, vec3 dest) { glm_vec3_minv(a, b, dest); } CGLM_EXPORT void glmc_vec3_clamp(vec3 v, float minVal, float maxVal) { glm_vec3_clamp(v, minVal, maxVal); } CGLM_EXPORT void glmc_vec3_ortho(vec3 v, vec3 dest) { glm_vec3_ortho(v, dest); } CGLM_EXPORT void glmc_vec3_lerp(vec3 from, vec3 to, float t, vec3 dest) { glm_vec3_lerp(from, to, t, dest); } CGLM_EXPORT void glmc_vec3_lerpc(vec3 from, vec3 to, float t, vec3 dest) { glm_vec3_lerpc(from, to, t, dest); } CGLM_EXPORT void glmc_vec3_step(vec3 edge, vec3 x, vec3 dest) { glm_vec3_step(edge, x, dest); } CGLM_EXPORT void glmc_vec3_smoothstep_uni(float edge0, float edge1, vec3 x, vec3 dest) { glm_vec3_smoothstep_uni(edge0, edge1, x, dest); } CGLM_EXPORT void glmc_vec3_smoothstep(vec3 edge0, vec3 edge1, vec3 x, vec3 dest) { glm_vec3_smoothstep(edge0, edge1, x, dest); } CGLM_EXPORT void glmc_vec3_smoothinterp(vec3 from, vec3 to, float t, vec3 dest) { glm_vec3_smoothinterp(from, to, t, dest); } CGLM_EXPORT void glmc_vec3_smoothinterpc(vec3 from, vec3 to, float t, vec3 dest) { glm_vec3_smoothinterpc(from, to, t, dest); } CGLM_EXPORT void glmc_vec3_swizzle(vec3 v, int mask, vec3 dest) { glm_vec3_swizzle(v, mask, dest); } /* ext */ CGLM_EXPORT void glmc_vec3_mulv(vec3 a, vec3 b, vec3 d) { glm_vec3_mulv(a, b, d); } CGLM_EXPORT void glmc_vec3_broadcast(float val, vec3 d) { glm_vec3_broadcast(val, d); } CGLM_EXPORT void glmc_vec3_fill(vec3 v, float val) { glm_vec3_fill(v, val); } CGLM_EXPORT bool glmc_vec3_eq(vec3 v, float val) { return glm_vec3_eq(v, val); } CGLM_EXPORT bool glmc_vec3_eq_eps(vec3 v, float val) { return glm_vec3_eq_eps(v, val); } CGLM_EXPORT bool glmc_vec3_eq_all(vec3 v) { return glm_vec3_eq_all(v); } CGLM_EXPORT bool glmc_vec3_eqv(vec3 a, vec3 b) { return glm_vec3_eqv(a, b); } CGLM_EXPORT bool glmc_vec3_eqv_eps(vec3 a, vec3 b) { return glm_vec3_eqv_eps(a, b); } CGLM_EXPORT float glmc_vec3_max(vec3 v) { return glm_vec3_max(v); } CGLM_EXPORT float glmc_vec3_min(vec3 v) { return glm_vec3_min(v); } CGLM_EXPORT bool glmc_vec3_isnan(vec3 v) { return glm_vec3_isnan(v); } CGLM_EXPORT bool glmc_vec3_isinf(vec3 v) { return glm_vec3_isinf(v); } CGLM_EXPORT bool glmc_vec3_isvalid(vec3 v) { return glm_vec3_isvalid(v); } CGLM_EXPORT void glmc_vec3_sign(vec3 v, vec3 dest) { glm_vec3_sign(v, dest); } CGLM_EXPORT void glmc_vec3_abs(vec3 v, vec3 dest) { glm_vec3_abs(v, dest); } CGLM_EXPORT void glmc_vec3_fract(vec3 v, vec3 dest) { glm_vec3_fract(v, dest); } CGLM_EXPORT void glmc_vec3_floor(vec3 v, vec3 dest) { glm_vec3_floor(v, dest); } CGLM_EXPORT void glmc_vec3_mods(vec3 v, float s, vec3 dest) { glm_vec3_mods(v, s, dest); } CGLM_EXPORT void glmc_vec3_steps(float edge, vec3 v, vec3 dest) { glm_vec3_steps(edge, v, dest); } CGLM_EXPORT void glmc_vec3_stepr(vec3 edge, float v, vec3 dest) { glm_vec3_stepr(edge, v, dest); } CGLM_EXPORT float glmc_vec3_hadd(vec3 v) { return glm_vec3_hadd(v); } CGLM_EXPORT void glmc_vec3_sqrt(vec3 v, vec3 dest) { glm_vec3_sqrt(v, dest); } CGLM_EXPORT void glmc_vec3_make(const float * __restrict src, vec3 dest) { glm_vec3_make(src, dest); } CGLM_EXPORT void glmc_vec3_faceforward(vec3 n, vec3 v, vec3 nref, vec3 dest) { glm_vec3_faceforward(n, v, nref, dest); } CGLM_EXPORT void glmc_vec3_reflect(vec3 v, vec3 n, vec3 dest) { glm_vec3_reflect(v, n, dest); } CGLM_EXPORT bool glmc_vec3_refract(vec3 v, vec3 n, float eta, vec3 dest) { return glm_vec3_refract(v, n, eta, dest); } CGLM_EXPORT void glmc_vec3_swap(vec3 a, vec3 b) { glm_vec3_swap(a, b); } cglm-0.9.7/src/vec4.c000066400000000000000000000160411526744317200142620ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "../include/cglm/cglm.h" #include "../include/cglm/call.h" CGLM_EXPORT void glmc_vec4(vec3 v3, float last, vec4 dest) { glm_vec4(v3, last, dest); } CGLM_EXPORT void glmc_vec4_zero(vec4 v) { glm_vec4_zero(v); } CGLM_EXPORT void glmc_vec4_one(vec4 v) { glm_vec4_one(v); } CGLM_EXPORT void glmc_vec4_copy3(vec4 v, vec3 dest) { glm_vec4_copy3(v, dest); } CGLM_EXPORT void glmc_vec4_copy(vec4 v, vec4 dest) { glm_vec4_copy(v, dest); } CGLM_EXPORT void glmc_vec4_ucopy(vec4 v, vec4 dest) { glm_vec4_ucopy(v, dest); } CGLM_EXPORT float glmc_vec4_dot(vec4 a, vec4 b) { return glm_vec4_dot(a, b); } CGLM_EXPORT float glmc_vec4_norm(vec4 v) { return glm_vec4_norm(v); } CGLM_EXPORT void glmc_vec4_normalize_to(vec4 v, vec4 dest) { glm_vec4_normalize_to(v, dest); } CGLM_EXPORT void glmc_vec4_normalize(vec4 v) { glm_vec4_normalize(v); } CGLM_EXPORT float glmc_vec4_norm2(vec4 v) { return glm_vec4_norm2(v); } CGLM_EXPORT float glmc_vec4_norm_one(vec4 v) { return glm_vec4_norm_one(v); } CGLM_EXPORT float glmc_vec4_norm_inf(vec4 v) { return glm_vec4_norm_inf(v); } CGLM_EXPORT void glmc_vec4_add(vec4 a, vec4 b, vec4 dest) { glm_vec4_add(a, b, dest); } CGLM_EXPORT void glmc_vec4_adds(vec4 v, float s, vec4 dest) { glm_vec4_adds(v, s, dest); } CGLM_EXPORT void glmc_vec4_sub(vec4 a, vec4 b, vec4 dest) { glm_vec4_sub(a, b, dest); } CGLM_EXPORT void glmc_vec4_subs(vec4 v, float s, vec4 dest) { glm_vec4_subs(v, s, dest); } CGLM_EXPORT void glmc_vec4_mul(vec4 a, vec4 b, vec4 d) { glm_vec4_mul(a, b, d); } CGLM_EXPORT void glmc_vec4_scale(vec4 v, float s, vec4 dest) { glm_vec4_scale(v, s, dest); } CGLM_EXPORT void glmc_vec4_scale_as(vec4 v, float s, vec4 dest) { glm_vec4_scale_as(v, s, dest); } CGLM_EXPORT void glmc_vec4_div(vec4 a, vec4 b, vec4 dest) { glm_vec4_div(a, b, dest); } CGLM_EXPORT void glmc_vec4_divs(vec4 v, float s, vec4 dest) { glm_vec4_divs(v, s, dest); } CGLM_EXPORT void glmc_vec4_addadd(vec4 a, vec4 b, vec4 dest) { glm_vec4_addadd(a, b, dest); } CGLM_EXPORT void glmc_vec4_subadd(vec4 a, vec4 b, vec4 dest) { glm_vec4_subadd(a, b, dest); } CGLM_EXPORT void glmc_vec4_muladd(vec4 a, vec4 b, vec4 dest) { glm_vec4_muladd(a, b, dest); } CGLM_EXPORT void glmc_vec4_muladds(vec4 a, float s, vec4 dest) { glm_vec4_muladds(a, s, dest); } CGLM_EXPORT void glmc_vec4_maxadd(vec4 a, vec4 b, vec4 dest) { glm_vec4_maxadd(a, b, dest); } CGLM_EXPORT void glmc_vec4_minadd(vec4 a, vec4 b, vec4 dest) { glm_vec4_minadd(a, b, dest); } CGLM_EXPORT void glmc_vec4_subsub(vec4 a, vec4 b, vec4 dest) { glm_vec4_subsub(a, b, dest); } CGLM_EXPORT void glmc_vec4_addsub(vec4 a, vec4 b, vec4 dest) { glm_vec4_addsub(a, b, dest); } CGLM_EXPORT void glmc_vec4_mulsub(vec4 a, vec4 b, vec4 dest) { glm_vec4_mulsub(a, b, dest); } CGLM_EXPORT void glmc_vec4_mulsubs(vec4 a, float s, vec4 dest) { glm_vec4_mulsubs(a, s, dest); } CGLM_EXPORT void glmc_vec4_maxsub(vec4 a, vec4 b, vec4 dest) { glm_vec4_maxsub(a, b, dest); } CGLM_EXPORT void glmc_vec4_minsub(vec4 a, vec4 b, vec4 dest) { glm_vec4_minsub(a, b, dest); } CGLM_EXPORT void glmc_vec4_negate(vec4 v) { glm_vec4_negate(v); } CGLM_EXPORT void glmc_vec4_negate_to(vec4 v, vec4 dest) { glm_vec4_negate_to(v, dest); } CGLM_EXPORT float glmc_vec4_distance(vec4 a, vec4 b) { return glm_vec4_distance(a, b); } CGLM_EXPORT float glmc_vec4_distance2(vec4 a, vec4 b) { return glm_vec4_distance2(a, b); } CGLM_EXPORT void glmc_vec4_maxv(vec4 a, vec4 b, vec4 dest) { glm_vec4_maxv(a, b, dest); } CGLM_EXPORT void glmc_vec4_minv(vec4 a, vec4 b, vec4 dest) { glm_vec4_minv(a, b, dest); } CGLM_EXPORT void glmc_vec4_clamp(vec4 v, float minVal, float maxVal) { glm_vec4_clamp(v, minVal, maxVal); } CGLM_EXPORT void glmc_vec4_lerp(vec4 from, vec4 to, float t, vec4 dest) { glm_vec4_lerp(from, to, t, dest); } CGLM_EXPORT void glmc_vec4_lerpc(vec4 from, vec4 to, float t, vec4 dest) { glm_vec4_lerpc(from, to, t, dest); } CGLM_EXPORT void glmc_vec4_step(vec4 edge, vec4 x, vec4 dest) { glm_vec4_step(edge, x, dest); } CGLM_EXPORT void glmc_vec4_smoothstep_uni(float edge0, float edge1, vec4 x, vec4 dest) { glm_vec4_smoothstep_uni(edge0, edge1, x, dest); } CGLM_EXPORT void glmc_vec4_smoothstep(vec4 edge0, vec4 edge1, vec4 x, vec4 dest) { glm_vec4_smoothstep(edge0, edge1, x, dest); } CGLM_EXPORT void glmc_vec4_smoothinterp(vec4 from, vec4 to, float t, vec4 dest) { glm_vec4_smoothinterp(from, to, t, dest); } CGLM_EXPORT void glmc_vec4_smoothinterpc(vec4 from, vec4 to, float t, vec4 dest) { glm_vec4_smoothinterpc(from, to, t, dest); } CGLM_EXPORT void glmc_vec4_cubic(float s, vec4 dest) { glm_vec4_cubic(s, dest); } CGLM_EXPORT void glmc_vec4_swizzle(vec4 v, int mask, vec4 dest) { glm_vec4_swizzle(v, mask, dest); } /* ext */ CGLM_EXPORT void glmc_vec4_mulv(vec4 a, vec4 b, vec4 d) { glm_vec4_mulv(a, b, d); } CGLM_EXPORT void glmc_vec4_broadcast(float val, vec4 d) { glm_vec4_broadcast(val, d); } CGLM_EXPORT void glmc_vec4_fill(vec4 v, float val) { glm_vec4_fill(v, val); } CGLM_EXPORT bool glmc_vec4_eq(vec4 v, float val) { return glm_vec4_eq(v, val); } CGLM_EXPORT bool glmc_vec4_eq_eps(vec4 v, float val) { return glm_vec4_eq_eps(v, val); } CGLM_EXPORT bool glmc_vec4_eq_all(vec4 v) { return glm_vec4_eq_all(v); } CGLM_EXPORT bool glmc_vec4_eqv(vec4 a, vec4 b) { return glm_vec4_eqv(a, b); } CGLM_EXPORT bool glmc_vec4_eqv_eps(vec4 a, vec4 b) { return glm_vec4_eqv_eps(a, b); } CGLM_EXPORT float glmc_vec4_max(vec4 v) { return glm_vec4_max(v); } CGLM_EXPORT float glmc_vec4_min(vec4 v) { return glm_vec4_min(v); } CGLM_EXPORT bool glmc_vec4_isnan(vec4 v) { return glm_vec4_isnan(v); } CGLM_EXPORT bool glmc_vec4_isinf(vec4 v) { return glm_vec4_isinf(v); } CGLM_EXPORT bool glmc_vec4_isvalid(vec4 v) { return glm_vec4_isvalid(v); } CGLM_EXPORT void glmc_vec4_sign(vec4 v, vec4 dest) { glm_vec4_sign(v, dest); } CGLM_EXPORT void glmc_vec4_abs(vec4 v, vec4 dest) { glm_vec4_abs(v, dest); } CGLM_EXPORT void glmc_vec4_fract(vec4 v, vec4 dest) { glm_vec4_fract(v, dest); } CGLM_EXPORT void glmc_vec4_floor(vec4 v, vec4 dest) { glm_vec4_floor(v, dest); } CGLM_EXPORT void glmc_vec4_mods(vec4 v, float s, vec4 dest) { glm_vec4_mods(v, s, dest); } CGLM_EXPORT void glmc_vec4_steps(float edge, vec4 v, vec4 dest) { glm_vec4_steps(edge, v, dest); } CGLM_EXPORT void glmc_vec4_stepr(vec4 edge, float v, vec4 dest) { glm_vec4_stepr(edge, v, dest); } CGLM_EXPORT float glmc_vec4_hadd(vec4 v) { return glm_vec4_hadd(v); } CGLM_EXPORT void glmc_vec4_sqrt(vec4 v, vec4 dest) { glm_vec4_sqrt(v, dest); } CGLM_EXPORT void glmc_vec4_make(const float * __restrict src, vec4 dest) { glm_vec4_make(src, dest); } CGLM_EXPORT void glmc_vec4_reflect(vec4 v, vec4 n, vec4 dest) { glm_vec4_reflect(v, n, dest); } CGLM_EXPORT bool glmc_vec4_refract(vec4 v, vec4 n, float eta, vec4 dest) { return glm_vec4_refract(v, n, eta, dest); } CGLM_EXPORT void glmc_vec4_swap(vec4 a, vec4 b) { glm_vec4_swap(a, b); } cglm-0.9.7/test/000077500000000000000000000000001526744317200134435ustar00rootroot00000000000000cglm-0.9.7/test/CMakeLists.txt000066400000000000000000000022411526744317200162020ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.8.2) # List all files containing tests. (Change as needed) set(TESTFILES runner.c src/test_euler.c src/test_bezier.c src/test_struct.c src/test_clamp.c src/test_common.c src/tests.c ) set(TEST_MAIN tests) set(TEST_RUNNER_PARAMS "") add_executable(${TEST_MAIN} ${TESTFILES}) target_compile_definitions(${TEST_MAIN} PRIVATE CGLM_DEFINE_PRINTS=1) if(CMAKE_SYSTEM_NAME STREQUAL WASI) target_compile_definitions(${TEST_MAIN} PRIVATE _WASI_EMULATED_PROCESS_CLOCKS=1) target_link_options(${TEST_MAIN} PRIVATE "-lwasi-emulated-process-clocks") endif() if(NOT MSVC) target_link_libraries(${TEST_MAIN} PRIVATE m) endif() target_link_libraries(${TEST_MAIN} PRIVATE cglm) target_include_directories(${TEST_MAIN} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include ${CMAKE_CURRENT_LIST_DIR}/src ) set_target_properties(${TEST_MAIN} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) if(LDFLAGS) target_compile_options(${TEST_MAIN} PRIVATE ${LDFLAGS}) endif() add_test( NAME cglm.${TEST_MAIN} COMMAND ${TEST_MAIN} ${TEST_RUNNER_PARAMS}) add_custom_target(check make COMMAND ${CMAKE_CTEST_COMMAND} -V DEPENDS cglm) cglm-0.9.7/test/include/000077500000000000000000000000001526744317200150665ustar00rootroot00000000000000cglm-0.9.7/test/include/common.h000066400000000000000000000125771526744317200165430ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef tests_common_h #define tests_common_h #ifndef _USE_MATH_DEFINES # define _USE_MATH_DEFINES /* for windows */ #endif #ifndef _CRT_SECURE_NO_WARNINGS # define _CRT_SECURE_NO_WARNINGS /* for windows */ #endif #ifndef _GNU_SOURCE # define _GNU_SOURCE /* for drand48() */ #endif #ifndef CGLM_CLIPSPACE_INCLUDE_ALL # define CGLM_CLIPSPACE_INCLUDE_ALL #endif #include #include #include #include #include #include typedef struct test_status_t { const char *msg; int status; } test_status_t; typedef test_status_t (*fntest)(void); typedef struct test_entry_t { char *name; fntest entry; int ret; int show_output; } test_entry_t; #ifndef GLM_TESTS_NO_COLORFUL_OUTPUT #define RESET "\033[0m" #define BLACK "\033[30m" /* Black */ #define RED "\033[31m" /* Red */ #define GREEN "\033[32m" /* Green */ #define YELLOW "\033[33m" /* Yellow */ #define BLUE "\033[34m" /* Blue */ #define MAGENTA "\033[35m" /* Magenta */ #define CYAN "\033[36m" /* Cyan */ #define WHITE "\033[37m" /* White */ #define BOLDBLACK "\033[1m\033[30m" /* Bold Black */ #define BOLDRED "\033[1m\033[31m" /* Bold Red */ #define BOLDGREEN "\033[1m\033[32m" /* Bold Green */ #define BOLDYELLOW "\033[1m\033[33m" /* Bold Yellow */ #define BOLDBLUE "\033[1m\033[34m" /* Bold Blue */ #define BOLDMAGENTA "\033[1m\033[35m" /* Bold Magenta */ #define BOLDCYAN "\033[1m\033[36m" /* Bold Cyan */ #define BOLDWHITE "\033[1m\033[37m" /* Bold White */ #else #define RESET #define BLACK #define RED #define GREEN #define YELLOW #define BLUE #define MAGENTA #define CYAN #define WHITE #define BOLDBLACK #define BOLDRED #define BOLDGREEN #define BOLDYELLOW #define BOLDBLUE #define BOLDMAGENTA #define BOLDCYAN #define BOLDWHITE #endif #define TEST_DECLARE(FUN) test_status_t test_ ## FUN(void); #define TEST_ENTRY(FUN) { #FUN, test_ ## FUN, 0, 0 }, #define TEST_LIST static test_entry_t tests[] = /* __VA_ARGS__ workaround for MSVC: https://stackoverflow.com/a/5134656 */ #define EXPAND(x) x #define TEST_OK 1 #define TEST_SUCCESS return (test_status_t){NULL, TEST_OK}; #define TEST_IMPL_ARG1(FUN) \ test_status_t test_ ## FUN (void); \ test_status_t test_ ## FUN() #define TEST_IMPL_ARG2(PREFIX, FUN) TEST_IMPL_ARG1(PREFIX ## FUN) #define TEST_IMPL_ARG3(arg1, arg2, arg3, ...) arg3 #define TEST_IMPL_CHOOSER(...) \ EXPAND(TEST_IMPL_ARG3(__VA_ARGS__, TEST_IMPL_ARG2, TEST_IMPL_ARG1,)) #define TEST_IMPL(...) EXPAND(TEST_IMPL_CHOOSER(__VA_ARGS__)(__VA_ARGS__)) #define ASSERT_EXT(expr, msg) \ if (!(expr)) { \ fprintf(stderr, \ RED " assert fail" RESET \ " in " BOLDCYAN "%s " RESET \ "on " BOLDMAGENTA "line %d" RESET \ " : " BOLDWHITE " ASSERT(%s)\n" RESET, \ __FILE__, \ __LINE__, \ #expr); \ return (test_status_t){msg, 0}; \ } #define ASSERT_ARG1(expr) ASSERT_EXT(expr, NULL) #define ASSERT_ARG2(expr, msg) ASSERT_EXT(expr, msg) #define ASSERT_ARG3(arg1, arg2, arg3, ...) arg3 #define ASSERT_CHOOSER(...) ASSERT_ARG3(__VA_ARGS__, ASSERT_ARG2, ASSERT_ARG1,) #define ASSERT(...) do { ASSERT_CHOOSER(__VA_ARGS__)(__VA_ARGS__) } while(0); #define ASSERTIFY(expr) do { \ test_status_t ts; \ ts = expr; \ if (ts.status != TEST_OK) { \ fprintf(stderr, \ RED " assert fail" RESET \ " in " BOLDCYAN "%s " RESET \ "on " BOLDMAGENTA "line %d" RESET \ " : " BOLDWHITE " ASSERTIFY(%s)\n" RESET, \ __FILE__, \ __LINE__, \ #expr); \ return (test_status_t){ts.msg, 0}; \ } \ } while(0); #if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) # define drand48() ((float)(rand() / (RAND_MAX + 1.0))) # define OK_TEXT "ok:" # define FAIL_TEXT "fail:" # define FINAL_TEXT "^_^" #else # define OK_TEXT "✔︎" # define FAIL_TEXT "�" # define FINAL_TEXT "🎉" #endif #endif /* common_h */ cglm-0.9.7/test/runner.c000066400000000000000000000042661526744317200151300ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "include/common.h" #include "tests.h" #include #include #include int main(int argc, const char * argv[]) { test_entry_t *entry; test_status_t st; int32_t i, count, passed, failed, maxlen; clock_t start, end, elapsed, total; (void)argc; (void)argv; passed = failed = maxlen = 0; total = 0.0; count = sizeof(tests) / sizeof(tests[0]); fprintf(stderr, CYAN "\nWelcome to cglm tests ( " RESET); glm_arch_print(stderr); fprintf(stderr, CYAN " )\n\n" RESET); srand((unsigned int)time(NULL)); for (i = 0; i < count; i++) { int32_t len; entry = tests + i; len = (int32_t)strlen(entry->name); maxlen = GLM_MAX(maxlen, len); } maxlen += 5; fprintf(stderr, BOLDWHITE " %-*s %-*s\n", maxlen, "Test Name", maxlen, "Elapsed Time"); for (i = 0; i < count; i++) { entry = tests + i; start = clock(); st = entry->entry(); end = clock(); elapsed = (end - start) / CLOCKS_PER_SEC; total += elapsed; if (!st.status) { fprintf(stderr, BOLDRED " " FAIL_TEXT BOLDWHITE " %s " RESET, entry->name); if (st.msg) { fprintf(stderr, YELLOW "- %s" RESET, st.msg); } fprintf(stderr, "\n"); failed++; } else { fprintf(stderr, GREEN " " OK_TEXT RESET " %-*s ", maxlen, entry->name); if (elapsed > 0.01) fprintf(stderr, YELLOW "%.2lus", elapsed); else fprintf(stderr, "0"); fprintf(stderr, "\n" RESET); passed++; } } if (failed == 0) { fprintf(stderr, BOLDGREEN "\n All tests passed " FINAL_TEXT "\n" RESET); } fprintf(stderr, CYAN "\ncglm test results (%0.2lus):\n" RESET "--------------------------\n" MAGENTA "%d" RESET " tests ran, " GREEN "%d" RESET " passed, " RED "%d" RESET " failed\n\n" RESET, total, count, passed, failed); return failed; } cglm-0.9.7/test/src/000077500000000000000000000000001526744317200142325ustar00rootroot00000000000000cglm-0.9.7/test/src/test_aabb2d.h000066400000000000000000000010211526744317200165470ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" #ifndef CGLM_TEST_AABB2D_ONCE #define CGLM_TEST_AABB2D_ONCE /* Macros */ /* Deprecated */ #endif /* CGLM_TEST_VEC4_ONCE */ /* --- */ TEST_IMPL(GLM_PREFIX, aabb2d_sizev) { vec2 a[2] = {{10.0f, 10.0f}, {20.0f, 20.0f}}; vec2 size = {0}; GLM(aabb2d_sizev)(a, size); ASSERTIFY(test_assert_vec2_eq(size, (vec2){10.0f, 10.0f})) TEST_SUCCESS } cglm-0.9.7/test/src/test_affine.h000066400000000000000000000366301526744317200167020ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" TEST_IMPL(GLM_PREFIX, translate) { mat4 m1; vec4 v1 = {1.0f, 2.0f, 3.0f, 1.0f}, v2; glm_mat4_identity(m1); GLM(translate)(m1, (vec3){13.0f, 11.0f, 7.0f}); glm_mat4_mulv(m1, v1, v2); ASSERT(test_eq(v2[0], 14.0f)) ASSERT(test_eq(v2[1], 13.0f)) ASSERT(test_eq(v2[2], 10.0f)) ASSERT(test_eq(v2[3], 1.0f)) glm_mat4_identity(m1); GLM(translate)(m1, (vec3){1.0f, -1.0f, -5.0f}); glm_mat4_mulv(m1, v2, v2); ASSERT(test_eq(v2[0], 15.0f)) ASSERT(test_eq(v2[1], 12.0f)) ASSERT(test_eq(v2[2], 5.0f)) ASSERT(test_eq(v2[3], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, translate_to) { mat4 m1, m2; vec4 v1 = {1.0f, 2.0f, 3.0f, 1.0f}, v2; glm_mat4_identity(m1); GLM(translate_to)(m1, (vec3){13.0f, 11.0f, 7.0f}, m2); glm_mat4_mulv(m2, v1, v2); ASSERT(test_eq(v2[0], 14.0f)) ASSERT(test_eq(v2[1], 13.0f)) ASSERT(test_eq(v2[2], 10.0f)) ASSERT(test_eq(v2[3], 1.0f)) glm_mat4_identity(m1); GLM(translate_to)(m1, (vec3){1.0f, -1.0f, -5.0f}, m2); glm_mat4_mulv(m2, v2, v2); ASSERT(test_eq(v2[0], 15.0f)) ASSERT(test_eq(v2[1], 12.0f)) ASSERT(test_eq(v2[2], 5.0f)) ASSERT(test_eq(v2[3], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, translate_x) { mat4 m1; vec4 v1 = {1.0f, 2.0f, 3.0f, 1.0f}, v2; glm_mat4_identity(m1); GLM(translate_x)(m1, 13.0f); glm_mat4_mulv(m1, v1, v2); ASSERT(test_eq(v2[0], 14.0f)) ASSERT(test_eq(v2[1], 2.0f)) ASSERT(test_eq(v2[2], 3.0f)) ASSERT(test_eq(v2[3], 1.0f)) glm_mat4_identity(m1); GLM(translate_x)(m1, -1.0f); glm_mat4_mulv(m1, v2, v2); ASSERT(test_eq(v2[0], 13.0f)) ASSERT(test_eq(v2[1], 2.0f)) ASSERT(test_eq(v2[2], 3.0f)) ASSERT(test_eq(v2[3], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, translate_y) { mat4 m1; vec4 v1 = {1.0f, 2.0f, 3.0f, 1.0f}, v2; glm_mat4_identity(m1); GLM(translate_y)(m1, 11.0f); glm_mat4_mulv(m1, v1, v2); ASSERT(test_eq(v2[0], 1.0f)) ASSERT(test_eq(v2[1], 13.0f)) ASSERT(test_eq(v2[2], 3.0f)) ASSERT(test_eq(v2[3], 1.0f)) glm_mat4_identity(m1); GLM(translate_y)(m1, -1.0f); glm_mat4_mulv(m1, v2, v2); ASSERT(test_eq(v2[0], 1.0f)) ASSERT(test_eq(v2[1], 12.0f)) ASSERT(test_eq(v2[2], 3.0f)) ASSERT(test_eq(v2[3], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, translate_z) { mat4 m1; vec4 v1 = {1.0f, 2.0f, 3.0f, 1.0f}, v2; glm_mat4_identity(m1); GLM(translate_z)(m1, 7.0f); glm_mat4_mulv(m1, v1, v2); ASSERT(test_eq(v2[0], 1.0f)) ASSERT(test_eq(v2[1], 2.0f)) ASSERT(test_eq(v2[2], 10.0f)) ASSERT(test_eq(v2[3], 1.0f)) glm_mat4_identity(m1); GLM(translate_z)(m1, -5.0f); glm_mat4_mulv(m1, v2, v2); ASSERT(test_eq(v2[0], 1.0f)) ASSERT(test_eq(v2[1], 2.0f)) ASSERT(test_eq(v2[2], 5.0f)) ASSERT(test_eq(v2[3], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, translate_make) { mat4 m1; vec4 v1 = {1.0f, 2.0f, 3.0f, 1.0f}, v2; glm_mat4_identity(m1); GLM(translate_make)(m1, (vec3){13.0f, 11.0f, 7.0f}); glm_mat4_mulv(m1, v1, v2); ASSERT(test_eq(v2[0], 14.0f)) ASSERT(test_eq(v2[1], 13.0f)) ASSERT(test_eq(v2[2], 10.0f)) ASSERT(test_eq(v2[3], 1.0f)) glm_mat4_identity(m1); GLM(translate_make)(m1, (vec3){1.0f, -1.0f, -5.0f}); glm_mat4_mulv(m1, v2, v2); ASSERT(test_eq(v2[0], 15.0f)) ASSERT(test_eq(v2[1], 12.0f)) ASSERT(test_eq(v2[2], 5.0f)) ASSERT(test_eq(v2[3], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, scale_to) { mat4 m1, m2; vec4 v1 = {1.0f, 2.0f, 3.0f, 1.0f}, v2; glm_mat4_identity(m1); GLM(scale_to)(m1, (vec3){13.0f, 11.0f, 7.0f}, m2); glm_mat4_mulv(m2, v1, v2); ASSERT(test_eq(v2[0], 13.0f)) ASSERT(test_eq(v2[1], 22.0f)) ASSERT(test_eq(v2[2], 21.0f)) ASSERT(test_eq(v2[3], 1.0f)) glm_mat4_identity(m1); GLM(scale_to)(m1, (vec3){1.0f, -1.0f, -5.0f}, m2); glm_mat4_mulv(m2, v2, v2); ASSERT(test_eq(v2[0], 13.0f)) ASSERT(test_eq(v2[1], -22.0f)) ASSERT(test_eq(v2[2], -105.0f)) ASSERT(test_eq(v2[3], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, scale_make) { mat4 m1; vec4 v1 = {1.0f, 2.0f, 3.0f, 1.0f}, v2; GLM(scale_make)(m1, (vec3){13.0f, 11.0f, 7.0f}); glm_mat4_mulv(m1, v1, v2); ASSERT(test_eq(v2[0], 13.0f)) ASSERT(test_eq(v2[1], 22.0f)) ASSERT(test_eq(v2[2], 21.0f)) ASSERT(test_eq(v2[3], 1.0f)) GLM(scale_make)(m1, (vec3){1.0f, -1.0f, -5.0f}); glm_mat4_mulv(m1, v2, v2); ASSERT(test_eq(v2[0], 13.0f)) ASSERT(test_eq(v2[1], -22.0f)) ASSERT(test_eq(v2[2], -105.0f)) ASSERT(test_eq(v2[3], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, scale) { mat4 m1; vec4 v1 = {1.0f, 2.0f, 3.0f, 1.0f}, v2; glm_mat4_identity(m1); GLM(scale)(m1, (vec3){13.0f, 11.0f, 7.0f}); glm_mat4_mulv(m1, v1, v2); ASSERT(test_eq(v2[0], 13.0f)) ASSERT(test_eq(v2[1], 22.0f)) ASSERT(test_eq(v2[2], 21.0f)) ASSERT(test_eq(v2[3], 1.0f)) glm_mat4_identity(m1); GLM(scale)(m1, (vec3){1.0f, -1.0f, -5.0f}); glm_mat4_mulv(m1, v2, v2); ASSERT(test_eq(v2[0], 13.0f)) ASSERT(test_eq(v2[1], -22.0f)) ASSERT(test_eq(v2[2], -105.0f)) ASSERT(test_eq(v2[3], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, scale_uni) { mat4 m1; vec4 v1 = {1.0f, 2.0f, 3.0f, 1.0f}, v2; glm_mat4_identity(m1); GLM(scale_uni)(m1, 13.0f); glm_mat4_mulv(m1, v1, v2); ASSERT(test_eq(v2[0], 13.0f)) ASSERT(test_eq(v2[1], 26.0f)) ASSERT(test_eq(v2[2], 39.0f)) ASSERT(test_eq(v2[3], 1.0f)) glm_mat4_identity(m1); GLM(scale_uni)(m1, -5.0f); glm_mat4_mulv(m1, v2, v2); ASSERT(test_eq(v2[0], -65.0f)) ASSERT(test_eq(v2[1], -130.0f)) ASSERT(test_eq(v2[2], -195.0f)) ASSERT(test_eq(v2[3], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, rotate_x) { mat4 m1 = GLM_MAT4_IDENTITY_INIT; vec4 v1 = {0.0f, 1.0f, 0.0f, 1.0f}, v2 = {0.0f, 1.0f, 0.0f, 1.0f}; GLM(rotate_x)(m1, GLM_PI_2f, m1); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 1.0f)) glm_vec3_copy(v2, v1); GLM(rotate_x)(m1, GLM_PI_2f, m1); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], -1.0f)) ASSERT(test_eq(v1[2], 0.0f)) glm_vec3_copy(v2, v1); GLM(rotate_x)(m1, GLM_PI_2f, m1); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], -1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, rotate_y) { mat4 m1 = GLM_MAT4_IDENTITY_INIT; vec4 v1 = {1.0f, 0.0f, 0.0f, 1.0f}, v2 = {1.0f, 0.0f, 0.0f, 1.0f}; GLM(rotate_y)(m1, GLM_PI_2f, m1); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], -1.0f)) glm_vec3_copy(v2, v1); GLM(rotate_y)(m1, GLM_PI_2f, m1); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], -1.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 0.0f)) glm_vec3_copy(v2, v1); GLM(rotate_y)(m1, GLM_PI_2f, m1); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, rotate_z) { mat4 m1 = GLM_MAT4_IDENTITY_INIT; vec4 v1 = {0.0f, 1.0f, 0.0f, 1.0f}, v2 = {0.0f, 1.0f, 0.0f, 1.0f}; GLM(rotate_z)(m1, GLM_PI_2f, m1); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], -1.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 0.0f)) glm_vec3_copy(v2, v1); GLM(rotate_z)(m1, GLM_PI_2f, m1); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], -1.0f)) ASSERT(test_eq(v1[2], 0.0f)) glm_vec3_copy(v2, v1); GLM(rotate_z)(m1, GLM_PI_2f, m1); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 1.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 0.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, rotate_make) { mat4 m1 = GLM_MAT4_IDENTITY_INIT; vec4 v1 = {1.0f, 0.0f, 0.0f, 1.0f}; /* rotate X around Y = -Z */ GLM(rotate_make)(m1, GLM_PI_2f, GLM_YUP); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], -1.0f)) /* rotate -Z around X = Y */ GLM(rotate_make)(m1, GLM_PI_2f, GLM_XUP); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 1.0f)) ASSERT(test_eq(v1[2], 0.0f)) /* rotate Y around X = +Z */ GLM(rotate_make)(m1, GLM_PI_2f, GLM_XUP); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, rotate) { mat4 m1 = GLM_MAT4_IDENTITY_INIT, m2 = GLM_MAT4_IDENTITY_INIT; vec4 v1 = {1.0f, 0.0f, 0.0f, 1.0f}; /* 360 deg */ glm_rotate(m1, GLM_PI_2f, GLM_YUP); glm_rotate(m1, GLM_PI_2f, GLM_YUP); glm_rotate(m1, GLM_PI_2f, GLM_YUP); glm_rotate(m1, GLM_PI_2f, GLM_YUP); ASSERTIFY(test_assert_mat4_eq(m1, m2)) /* rotate X around Y = -Z */ GLM(rotate)(m1, GLM_PI_2f, GLM_YUP); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], -1.0f)) glm_mat4_identity(m1); /* rotate -Z around X = Y */ GLM(rotate)(m1, GLM_PI_2f, GLM_XUP); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 1.0f)) ASSERT(test_eq(v1[2], 0.0f)) glm_mat4_identity(m1); /* rotate Y around X = +Z */ GLM(rotate)(m1, GLM_PI_2f, GLM_XUP); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, rotate_at) { mat4 m1 = GLM_MAT4_IDENTITY_INIT; vec4 v1 = {1.0f, 0.0f, 0.0f, 1.0f}; GLM(rotate_at)(m1, (vec3){0.5f, 0.0f, 0.0f}, GLM_PI_2f, GLM_YUP); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.5f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], -0.5f)) glm_mat4_identity(m1); GLM(rotate_at)(m1, GLM_VEC3_ZERO, GLM_PI_2f, GLM_ZUP); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.5f)) ASSERT(test_eq(v1[2], -0.5f)) glm_mat4_identity(m1); v1[0] = 1.0f; v1[1] = 1.0f; v1[2] = 1.0f; GLM(rotate_at)(m1, GLM_VEC3_ZERO, GLM_PI_2f, GLM_XUP); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 1.0f)) ASSERT(test_eq(v1[1], -1.0f)) ASSERT(test_eq(v1[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, rotate_atm) { mat4 m1 = GLM_MAT4_IDENTITY_INIT; vec4 v1 = {1.0f, 0.0f, 0.0f, 1.0f}; GLM(rotate_atm)(m1, (vec3){0.5f, 0.0f, 0.0f}, GLM_PI_2f, GLM_YUP); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.5f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], -0.5f)) GLM(rotate_atm)(m1, GLM_VEC3_ZERO, GLM_PI_2f, GLM_ZUP); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.5f)) ASSERT(test_eq(v1[2], -0.5f)) v1[0] = 1.0f; v1[1] = 1.0f; v1[2] = 1.0f; GLM(rotate_atm)(m1, GLM_VEC3_ZERO, GLM_PI_2f, GLM_XUP); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 1.0f)) ASSERT(test_eq(v1[1], -1.0f)) ASSERT(test_eq(v1[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, spin) { mat4 m; mat4 expected = {{ 0.0f, 1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, 1.0f, 0.0f}, { 5.0f, 0.0f, 0.0f, 1.0f}}; glm_translate_make(m, (vec3){5.0f, 0.0f, 0.0f}); GLM(spin)(m, GLM_PI_2f, GLM_ZUP); ASSERTIFY(test_assert_mat4_eq(m, expected)); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, spin_affine) { mat4 m, original = {{0.0f, 2.0f, 0.0f, 0.0f}, {-3.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 4.0f, 0.0f}, {5.0f, -2.0f, 7.0f, 1.0f}}; mat4 expected = {{-3.0f, 0.0f, 0.0f, 0.0f}, {0.0f, -2.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 4.0f, 0.0f}, {5.0f, -2.0f, 7.0f, 1.0f}}; vec3 axis = {0.0f, 0.0f, 2.0f}; glm_mat4_copy(original, m); GLM(spin)(m, GLM_PI_2f, axis); ASSERTIFY(test_assert_mat4_eq(m, expected)); ASSERT(test_eq(axis[2], 2.0f)) GLM(spin)(m, -GLM_PI_2f, axis); ASSERTIFY(test_assert_mat4_eq(m, original)); GLM(spin)(m, 0.0f, GLM_XUP); ASSERTIFY(test_assert_mat4_eq(m, original)); glm_vec3_zero(m[3]); glm_vec3_zero(expected[3]); GLM(spin)(m, GLM_PI_2f, axis); ASSERTIFY(test_assert_mat4_eq(m, expected)); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, decompose_scalev) { mat4 m1; vec3 s1; GLM(scale_make)(m1, (vec3){7.0f, 8.0f, 9.0f}); GLM(decompose_scalev)(m1, s1); ASSERT(test_eq(s1[0], 7.0f)) ASSERT(test_eq(s1[1], 8.0f)) ASSERT(test_eq(s1[2], 9.0f)) GLM(scale)(m1, (vec3){7.0f, 8.0f, 9.0f}); GLM(decompose_scalev)(m1, s1); ASSERT(test_eq(s1[0], 49.0f)) ASSERT(test_eq(s1[1], 64.0f)) ASSERT(test_eq(s1[2], 81.0f)) glm_rotate(m1, GLM_PI_4f, (vec3){23.0f, 45.0f, 66.0f}); ASSERT(test_eq(s1[0], 49.0f)) ASSERT(test_eq(s1[1], 64.0f)) ASSERT(test_eq(s1[2], 81.0f)) glm_translate(m1, (vec3){4.0f, 5.0f, 6.0f}); ASSERT(test_eq(s1[0], 49.0f)) ASSERT(test_eq(s1[1], 64.0f)) ASSERT(test_eq(s1[2], 81.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, uniscaled) { mat4 m1; GLM(scale_make)(m1, (vec3){7.0f, 8.0f, 9.0f}); ASSERT(!GLM(uniscaled)(m1)) GLM(scale_make)(m1, (vec3){7.0f, 7.0f, 7.0f}); ASSERT(GLM(uniscaled)(m1)) glm_rotate(m1, GLM_PI_4f, (vec3){23.0f, 45.0f, 66.0f}); ASSERT(GLM(uniscaled)(m1)) glm_translate(m1, (vec3){4.0f, 5.0f, 6.0f}); ASSERT(GLM(uniscaled)(m1)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, decompose_rs) { mat4 m1, m2, r; vec3 s1; GLM(scale_make)(m1, (vec3){7.0f, 8.0f, 9.0f}); GLM(decompose_rs)(m1, r, s1); ASSERT(test_eq(s1[0], 7.0f)) ASSERT(test_eq(s1[1], 8.0f)) ASSERT(test_eq(s1[2], 9.0f)) ASSERTIFY(test_assert_mat4_eq_identity(r)); GLM(scale)(m1, (vec3){7.0f, 8.0f, 9.0f}); GLM(decompose_rs)(m1, r, s1); ASSERT(test_eq(s1[0], 49.0f)) ASSERT(test_eq(s1[1], 64.0f)) ASSERT(test_eq(s1[2], 81.0f)) ASSERTIFY(test_assert_mat4_eq_identity(r)); glm_rotate(m1, GLM_PI_4f, (vec3){23.0f, 45.0f, 66.0f}); ASSERT(test_eq(s1[0], 49.0f)) ASSERT(test_eq(s1[1], 64.0f)) ASSERT(test_eq(s1[2], 81.0f)) GLM(decompose_rs)(m1, r, s1); glm_mat4_identity(m2); glm_mat4_mul(m2, r, m2); glm_scale(m2, s1); ASSERTIFY(test_assert_mat4_eq2(m1, m2, 0.00001f)); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, decompose) { mat4 m1, m2, r; vec4 t; vec3 s; GLM(scale_make)(m1, (vec3){7.0f, 8.0f, 9.0f}); GLM(decompose)(m1, t, r, s); ASSERT(test_eq(s[0], 7.0f)) ASSERT(test_eq(s[1], 8.0f)) ASSERT(test_eq(s[2], 9.0f)) ASSERTIFY(test_assert_mat4_eq_identity(r)); GLM(scale)(m1, (vec3){7.0f, 8.0f, 9.0f}); GLM(decompose)(m1, t, r, s); ASSERT(test_eq(s[0], 49.0f)) ASSERT(test_eq(s[1], 64.0f)) ASSERT(test_eq(s[2], 81.0f)) ASSERTIFY(test_assert_mat4_eq_identity(r)); glm_rotate(m1, GLM_PI_4f, (vec3){23.0f, 45.0f, 66.0f}); ASSERT(test_eq(s[0], 49.0f)) ASSERT(test_eq(s[1], 64.0f)) ASSERT(test_eq(s[2], 81.0f)) GLM(decompose)(m1, t, r, s); glm_mat4_identity(m2); glm_mat4_mul(m2, r, m2); glm_scale(m2, s); ASSERTIFY(test_assert_mat4_eq2(m1, m2, 0.00001f)); glm_mat4_identity(m1); glm_translate(m1, (vec3){56.0f, 13.0f, 90.0f}); glm_rotate(m1, GLM_PI_4f, (vec3){23.0f, 45.0f, 66.0f}); glm_scale(m1, (vec3){12.0f, 34.0f, 23.0f}); GLM(decompose)(m1, t, r, s); ASSERT(test_eq(t[0], 56.0f)) ASSERT(test_eq(t[1], 13.0f)) ASSERT(test_eq(t[2], 90.0f)) ASSERT(test_eq(s[0], 12.0f)) ASSERT(test_eq(s[1], 34.0f)) ASSERT(test_eq(s[2], 23.0f)) glm_mat4_identity(m2); glm_translate(m2, t); glm_mat4_mul(m2, r, m2); glm_scale(m2, s); ASSERTIFY(test_assert_mat4_eq2(m1, m2, 0.00001f)); TEST_SUCCESS } cglm-0.9.7/test/src/test_affine2d.h000066400000000000000000000147641526744317200171340ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" TEST_IMPL(GLM_PREFIX, translate2d) { mat3 m1; vec3 v1 = {2.0f, 3.0f, 1.0f}, v2; glm_mat3_identity(m1); GLM(translate2d)(m1, (vec2){13.0f, 11.0f}); glm_mat3_mulv(m1, v1, v2); ASSERT(test_eq(v2[0], 15.0f)) ASSERT(test_eq(v2[1], 14.0f)) ASSERT(test_eq(v2[2], 1.0f)) glm_mat3_identity(m1); GLM(translate2d)(m1, (vec2){1.0f, -1.0f}); glm_mat3_mulv(m1, v2, v2); ASSERT(test_eq(v2[0], 16.0f)) ASSERT(test_eq(v2[1], 13.0f)) ASSERT(test_eq(v2[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, translate2d_to) { mat3 m1, m2; vec3 v1 = {2.0f, 3.0f, 1.0f}, v2; glm_mat3_identity(m1); GLM(translate2d_to)(m1, (vec2){13.0f, 11.0f}, m2); glm_mat3_mulv(m2, v1, v2); ASSERT(test_eq(v2[0], 15.0f)) ASSERT(test_eq(v2[1], 14.0f)) ASSERT(test_eq(v2[2], 1.0f)) glm_mat3_identity(m1); GLM(translate2d_to)(m1, (vec2){1.0f, -1.0f}, m2); glm_mat3_mulv(m2, v2, v2); ASSERT(test_eq(v2[0], 16.0f)) ASSERT(test_eq(v2[1], 13.0f)) ASSERT(test_eq(v2[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, translate2d_x) { mat3 m1; vec3 v1 = {2.0f, 3.0f, 1.0f}, v2; glm_mat3_identity(m1); GLM(translate2d_x)(m1, 13.0f); glm_mat3_mulv(m1, v1, v2); ASSERT(test_eq(v2[0], 15.0f)) ASSERT(test_eq(v2[1], 3.0f)) ASSERT(test_eq(v2[2], 1.0f)) glm_mat3_identity(m1); GLM(translate2d_x)(m1, -1.0f); glm_mat3_mulv(m1, v2, v2); ASSERT(test_eq(v2[0], 14.0f)) ASSERT(test_eq(v2[1], 3.0f)) ASSERT(test_eq(v2[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, translate2d_y) { mat3 m1; vec3 v1 = {2.0f, 3.0f, 1.0f}, v2; glm_mat3_identity(m1); GLM(translate2d_y)(m1, 11.0f); glm_mat3_mulv(m1, v1, v2); ASSERT(test_eq(v2[0], 2.0f)) ASSERT(test_eq(v2[1], 14.0f)) ASSERT(test_eq(v2[2], 1.0f)) glm_mat3_identity(m1); GLM(translate2d_y)(m1, -1.0f); glm_mat3_mulv(m1, v2, v2); ASSERT(test_eq(v2[0], 2.0f)) ASSERT(test_eq(v2[1], 13.0f)) ASSERT(test_eq(v2[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, translate2d_make) { mat3 m1; vec3 v1 = {2.0f, 3.0f, 1.0f}, v2; glm_mat3_identity(m1); GLM(translate2d_make)(m1, (vec2){13.0f, 11.0f}); glm_mat3_mulv(m1, v1, v2); ASSERT(test_eq(v2[0], 15.0f)) ASSERT(test_eq(v2[1], 14.0f)) ASSERT(test_eq(v2[2], 1.0f)) glm_mat3_identity(m1); GLM(translate2d_make)(m1, (vec2){-1.0f, -5.0f}); glm_mat3_mulv(m1, v2, v2); ASSERT(test_eq(v2[0], 14.0f)) ASSERT(test_eq(v2[1], 9.0f)) ASSERT(test_eq(v2[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, scale2d_to) { mat3 m1, m2; vec3 v1 = {2.0f, 3.0f, 1.0f}, v2; glm_mat3_identity(m1); GLM(scale2d_to)(m1, (vec2){13.0f, 11.0f}, m2); glm_mat3_mulv(m2, v1, v2); ASSERT(test_eq(v2[0], 26.0f)) ASSERT(test_eq(v2[1], 33.0f)) ASSERT(test_eq(v2[2], 1.0f)) glm_mat3_identity(m1); GLM(scale2d_to)(m1, (vec2){-1.0f, -5.0f}, m2); glm_mat3_mulv(m2, v2, v2); ASSERT(test_eq(v2[0], -26.0f)) ASSERT(test_eq(v2[1], -165.0f)) ASSERT(test_eq(v2[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, scale2d_make) { mat3 m1; vec3 v1 = {2.0f, 3.0f, 1.0f}, v2; GLM(scale2d_make)(m1, (vec2){13.0f, 11.0f}); glm_mat3_mulv(m1, v1, v2); ASSERT(test_eq(v2[0], 26.0f)) ASSERT(test_eq(v2[1], 33.0f)) ASSERT(test_eq(v2[2], 1.0f)) GLM(scale2d_make)(m1, (vec3){-1.0f, -5.0f}); glm_mat3_mulv(m1, v2, v2); ASSERT(test_eq(v2[0], -26.0f)) ASSERT(test_eq(v2[1], -165.0f)) ASSERT(test_eq(v2[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, scale2d) { mat3 m1; vec3 v1 = {2.0f, 3.0f, 1.0f}, v2; glm_mat3_identity(m1); GLM(scale2d)(m1, (vec2){13.0f, 11.0f}); glm_mat3_mulv(m1, v1, v2); ASSERT(test_eq(v2[0], 26.0f)) ASSERT(test_eq(v2[1], 33.0f)) ASSERT(test_eq(v2[2], 1.0f)) glm_mat3_identity(m1); GLM(scale2d)(m1, (vec2){-1.0f, -5.0f}); glm_mat3_mulv(m1, v2, v2); ASSERT(test_eq(v2[0], -26.0f)) ASSERT(test_eq(v2[1], -165.0f)) ASSERT(test_eq(v2[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, scale2d_uni) { mat3 m1; vec3 v1 = {2.0f, 3.0f, 1.0f}, v2; glm_mat3_identity(m1); GLM(scale2d_uni)(m1, 13.0f); glm_mat3_mulv(m1, v1, v2); ASSERT(test_eq(v2[0], 26.0f)) ASSERT(test_eq(v2[1], 39.0f)) ASSERT(test_eq(v2[2], 1.0f)) glm_mat3_identity(m1); GLM(scale2d_uni)(m1, -5.0f); glm_mat3_mulv(m1, v2, v2); ASSERT(test_eq(v2[0], -130.0f)) ASSERT(test_eq(v2[1], -195.0f)) ASSERT(test_eq(v2[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, rotate2d_make) { mat3 m1 = GLM_MAT3_IDENTITY_INIT; vec3 v1 = {0.0f, 1.0f, 1.0f}, v2 = {0.0f, 1.0f, 1.0f}; GLM(rotate2d_make)(m1, GLM_PI_2f); glm_mat3_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], -1.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 1.0f)) glm_vec3_copy(v2, v1); GLM(rotate2d_make)(m1, -GLM_PI_2f); glm_mat3_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 1.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 1.0f)) glm_vec3_copy(v2, v1); GLM(rotate2d_make)(m1, GLM_PIf); glm_mat3_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], -1.0f)) ASSERT(test_eq(v1[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, rotate2d) { mat3 m1 = GLM_MAT3_IDENTITY_INIT; vec3 v1 = {0.0f, 1.0f, 1.0f}, v2 = {0.0f, 1.0f, 1.0f}; GLM(rotate2d)(m1, GLM_PI_2f); glm_mat3_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], -1.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 1.0f)) glm_vec3_copy(v2, v1); GLM(rotate2d)(m1, GLM_PI_2f); glm_mat3_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], -1.0f)) ASSERT(test_eq(v1[2], 1.0f)) glm_vec3_copy(v2, v1); GLM(rotate2d)(m1, GLM_PI_2f); glm_mat3_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 1.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, rotate2d_to) { mat3 m1 = GLM_MAT3_IDENTITY_INIT, m2; vec3 v1 = {0.0f, 1.0f, 1.0f}, v2 = {0.0f, 1.0f, 1.0f}; GLM(rotate2d_to)(m1, GLM_PI_2f, m1); glm_mat3_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], -1.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 1.0f)) glm_vec3_copy(v2, v1); GLM(rotate2d_to)(m1, GLM_PI_2f, m2); glm_mat3_mulv(m2, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], -1.0f)) ASSERT(test_eq(v1[2], 1.0f)) glm_vec3_copy(v2, v1); GLM(rotate2d_to)(m2, GLM_PI_2f, m1); glm_mat3_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 1.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 1.0f)) TEST_SUCCESS } cglm-0.9.7/test/src/test_affine2d_post.h000066400000000000000000000035531526744317200201730ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" TEST_IMPL(GLM_PREFIX, translated2d) { mat3 m1, m2, tmp; vec2 v = { 1.2f, 3.4f }; test_rand_transform2d(m1); glm_mat3_copy(m1, m2); GLM(translated2d)(m2, v); glm_translate2d_make(tmp, v); glm_mat3_mul(tmp, m1, m1); test_assert_mat3_eq(m1, m2); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, translated2d_x) { mat3 m1, m2, tmp; float x = test_rand(); test_rand_transform2d(m1); glm_mat3_copy(m1, m2); GLM(translated2d_x)(m2, x); glm_translate2d_make(tmp, (vec2) { x, 0.0f }); glm_mat3_mul(tmp, m1, m1); test_assert_mat3_eq(m1, m2); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, translated2d_y) { mat3 m1, m2, tmp; float y = test_rand(); test_rand_transform2d(m1); glm_mat3_copy(m1, m2); GLM(translated2d_y)(m2, y); glm_translate2d_make(tmp, (vec2) { 0.0f, y }); glm_mat3_mul(tmp, m1, m1); test_assert_mat3_eq(m1, m2); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, rotated2d) { mat3 m1, m2, tmp; float a = test_rand(); test_rand_transform2d(m1); glm_mat3_copy(m1, m2); GLM(rotated2d)(m2, a); glm_rotate2d_make(tmp, a); glm_mat3_mul(tmp, m1, m1); test_assert_mat3_eq(m1, m2); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, scaled2d) { mat3 m1, m2, tmp; vec2 v = { test_rand(), test_rand() }; test_rand_transform2d(m1); glm_mat3_copy(m1, m2); GLM(scaled2d)(m2, v); glm_scale2d_make(tmp, v); glm_mat3_mul(tmp, m1, m1); test_assert_mat3_eq(m1, m2); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, scaled2d_uni) { mat3 m1, m2, tmp; float s = test_rand(); test_rand_transform2d(m1); glm_mat3_copy(m1, m2); GLM(scaled2d_uni)(m2, s); glm_scale2d_make(tmp, (vec2) { s, s }); glm_mat3_mul(tmp, m1, m1); test_assert_mat3_eq(m1, m2); TEST_SUCCESS } cglm-0.9.7/test/src/test_affine_mat.h000066400000000000000000000043371526744317200175420ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" #ifndef glm_affine_mat_test_guard #define glm_affine_mat_test_guard CGLM_INLINE void glm_inv_tr_raw(mat4 mat) { CGLM_ALIGN_MAT mat3 r; CGLM_ALIGN(8) vec3 t; /* rotate */ glm_mat4_pick3t(mat, r); glm_mat4_ins3(r, mat); /* translate */ glm_mat3_mulv(r, mat[3], t); glm_vec3_negate(t); glm_vec3_copy(t, mat[3]); } #endif TEST_IMPL(GLM_PREFIX, mul) { mat4 m1 = GLM_MAT4_IDENTITY_INIT; mat4 m2 = GLM_MAT4_IDENTITY_INIT; mat4 m3; mat4 m4 = GLM_MAT4_ZERO_INIT; int i, j, k; test_rand_mat4(m1); test_rand_mat4(m2); GLM(mul)(m1, m2, m3); for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { for (k = 0; k < 4; k++) /* column-major */ m4[i][j] += m1[k][j] * m2[i][k]; } } ASSERTIFY(test_assert_mat4_eq(m3, m4)) /* test pre compiled */ GLM(mul)(m1, m2, m3); ASSERTIFY(test_assert_mat4_eq(m3, m4)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mul_rot) { mat4 m1 = GLM_MAT4_IDENTITY_INIT; mat4 m2 = GLM_MAT4_IDENTITY_INIT; mat4 m3; mat4 m4 = GLM_MAT4_ZERO_INIT; int i, j, k; glm_rotate(m1, frand48(), (vec3){frand48(), frand48(), frand48()}); glm_rotate(m2, frand48(), (vec3){frand48(), frand48(), frand48()}); GLM(mul_rot)(m1, m2, m3); for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { for (k = 0; k < 4; k++) /* column-major */ m4[i][j] += m1[k][j] * m2[i][k]; } } ASSERTIFY(test_assert_mat4_eq(m3, m4)) /* test pre compiled */ GLM(mul_rot)(m1, m2, m3); ASSERTIFY(test_assert_mat4_eq(m3, m4)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, inv_tr) { mat4 m1, m2; int i; for (i = 0; i < 10000; i++) { test_rand_mat4(m1); glm_mat4_copy(m1, m2); /* test inverse precise */ GLM(inv_tr)(m1); GLM(inv_tr)(m1); ASSERTIFY(test_assert_mat4_eq(m1, m2)) /* test inverse precise */ GLM(mat4_inv)(m1, m2); GLM(inv_tr)(m2); ASSERTIFY(test_assert_mat4_eq(m1, m2)) /* test with raw */ glm_mat4_copy(m1, m2); glm_inv_tr_raw(m2); GLM(inv_tr)(m1); ASSERTIFY(test_assert_mat4_eq(m1, m2)) } TEST_SUCCESS } cglm-0.9.7/test/src/test_bezier.c000066400000000000000000000030121526744317200167110ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" CGLM_INLINE float test_bezier_plain(float s, float p0, float c0, float c1, float p1) { float x, xx, xxx, ss, sss; x = 1.0f - s; xx = x * x; xxx = xx * x; ss = s * s; sss = ss * s; return p0 * xxx + 3.0f * (c0 * s * xx + c1 * ss * x) + p1 * sss; } CGLM_INLINE float test_hermite_plain(float s, float p0, float t0, float t1, float p1) { float ss, sss; ss = s * s; sss = ss * s; return p0 * (2.0f * sss - 3.0f * ss + 1.0f) + t0 * (sss - 2.0f * ss + s) + p1 * (-2.0f * sss + 3.0f * ss) + t1 * (sss - ss); } TEST_IMPL(bezier) { float s, p0, p1, c0, c1, smc, Bs, Bs_plain; s = test_rand(); p0 = test_rand(); p1 = test_rand(); c0 = test_rand(); c1 = test_rand(); /* test cubic bezier */ smc = glm_smc(s, GLM_BEZIER_MAT, (vec4){p0, c0, c1, p1}); Bs = glm_bezier(s, p0, c0, c1, p1); Bs_plain = test_bezier_plain(s, p0, c0, c1, p1); ASSERT(test_eq(Bs, Bs_plain)); ASSERTIFY(test_assert_eqf(smc, Bs_plain)) ASSERTIFY(test_assert_eqf(Bs, smc)) /* test cubic hermite */ smc = glm_smc(s, GLM_HERMITE_MAT, (vec4){p0, p1, c0, c1}); Bs = glm_hermite(s, p0, c0, c1, p1); Bs_plain = test_hermite_plain(s, p0, c0, c1, p1); ASSERT(test_eq(Bs, Bs_plain)); ASSERT(test_eq(smc, Bs_plain)); ASSERT(test_eq(Bs, smc)); TEST_SUCCESS } cglm-0.9.7/test/src/test_cam.h000066400000000000000000000051511526744317200162040ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" TEST_IMPL(GLM_PREFIX, frustum) { mat4 proj; vec4 vp = {0.0f, 0.0f, 800.0f, 600.0f}; float left, right, top, bottom, znear, zfar; znear = 0.1f; zfar = 100.0f; left = -100.0f; right = 100.0f; bottom = -100.0f; top = 100.0f; GLM(frustum)(left, right, bottom, top, znear, zfar, proj); ASSERT(test_eq(proj[0][1], 0.0f)) ASSERT(test_eq(proj[0][2], 0.0f)) ASSERT(test_eq(proj[0][3], 0.0f)) ASSERT(test_eq(proj[1][0], 0.0f)) ASSERT(test_eq(proj[1][2], 0.0f)) ASSERT(test_eq(proj[1][3], 0.0f)) ASSERT(test_eq(proj[2][3], -1.0f)) ASSERT(test_eq(proj[3][0], 0.0f)) ASSERT(test_eq(proj[3][1], 0.0f)) ASSERT(test_eq(proj[3][3], 0.0f)) vec4 v1 = {1.0f, 20.0f, znear}; vec4 v2 = {1.0f, 20.0f, zfar}; vec4 v3, v4; /* perspective test */ GLM(mat4_mulv)(proj, v1, v3); GLM(project)(v3, proj, vp, v3); ASSERT(v3[0] > v1[0]) ASSERT(v3[1] > v1[1]) GLM(mat4_mulv)(proj, v2, v4); GLM(project)(v4, proj, vp, v4); ASSERT(v4[0] < v3[0]) ASSERT(v4[1] < v3[1]) /* not infinity */ ASSERT(!GLM(vec4_isinf)(proj[0])) ASSERT(!GLM(vec4_isinf)(proj[1])) ASSERT(!GLM(vec4_isinf)(proj[2])) ASSERT(!GLM(vec4_isinf)(proj[3])) /* not NaN */ ASSERT(!GLM(vec4_isnan)(proj[0])) ASSERT(!GLM(vec4_isnan)(proj[1])) ASSERT(!GLM(vec4_isnan)(proj[2])) ASSERT(!GLM(vec4_isnan)(proj[3])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, camera_lookat) { mat4 view1, view2; vec3 center, eye = {0.024f, 14.6f, 67.04f}, dir = {0.0f, 0.0f, -1.0f}, up = {0.0f, 1.0f, 0.0f}; glm_vec3_add(eye, dir, center); glm_lookat(eye, center, up, view1); glm_look(eye, dir, up, view2); ASSERTIFY(test_assert_mat4_eq(view1, view2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, camera_decomp) { mat4 proj, proj2; vec4 sizes; float aspect, fovy, nearZ, farZ; aspect = 0.782f; fovy = glm_rad(49.984f); nearZ = 0.1f; farZ = 100.0f; glm_perspective(fovy, aspect, nearZ, farZ, proj); ASSERT(fabsf(aspect - glm_persp_aspect(proj)) < GLM_FLT_EPSILON) ASSERT(fabsf(fovy - glm_persp_fovy(proj)) < GLM_FLT_EPSILON) ASSERT(fabsf(49.984f - glm_deg(glm_persp_fovy(proj))) < GLM_FLT_EPSILON) glm_persp_sizes(proj, fovy, sizes); glm_frustum(-sizes[0] * 0.5f, sizes[0] * 0.5f, -sizes[1] * 0.5f, sizes[1] * 0.5f, nearZ, farZ, proj2); ASSERTIFY(test_assert_mat4_eq(proj, proj2)) TEST_SUCCESS } cglm-0.9.7/test/src/test_cam_lh_no.h000066400000000000000000000022201526744317200173550ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" #include "../../include/cglm/clipspace/persp_lh_no.h" #include "../../include/cglm/call/clipspace/persp_lh_no.h" TEST_IMPL(GLM_PREFIX, perspective_lh_no) { mat4 dst; const float fovy = glm_rad(45.0f); const float aspect = 640/480.0f; const float zNearVal = 0.1f; const float zFarVal = 100.0f; GLM(perspective_lh_no)(fovy, aspect, zNearVal, zFarVal, dst); /* Sanity mk. I: longhand version */ ASSERT(test_eq(dst[0][0], 1.0f / (tanf(fovy / 2) * aspect))) ASSERT(test_eq(dst[1][1], 1.0f / tanf(fovy / 2))) ASSERT(test_eq(dst[2][2], (zFarVal + zNearVal) / (zFarVal - zNearVal))) ASSERT(test_eq(dst[2][3], 1.0f)) ASSERT(test_eq(dst[3][2], -2 * zFarVal * zNearVal / (zFarVal - zNearVal))) /* Sanity mk. II */ /*reference test data for glm_perspective_lh_no*/ mat4 cmp = {0}; cmp[0][0] = 1.8106601f; cmp[1][1] = 2.4142134f; cmp[2][2] = 1.0020020f; cmp[2][3] = 1.0000000f; cmp[3][2] = -0.2002002f; return test_assert_mat4_eq(dst, cmp); } cglm-0.9.7/test/src/test_cam_lh_zo.h000066400000000000000000000022231526744317200173740ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" #include "../../include/cglm/clipspace/persp_lh_zo.h" #include "../../include/cglm/call/clipspace/persp_lh_zo.h" TEST_IMPL(GLM_PREFIX, perspective_lh_zo) { mat4 dst; const float fovy = glm_rad(45.0f); const float aspect = 640/480.0f; const float zNearVal = 0.1f; const float zFarVal = 100.0f; GLM(perspective_lh_zo)(fovy, aspect, zNearVal, zFarVal, dst); /* Sanity mk. I: longhand version */ ASSERT(test_eq(dst[0][0], 1.0f / (tanf(fovy / 2) * aspect))) ASSERT(test_eq(dst[1][1], 1.0f / tanf(fovy / 2))) ASSERT(test_eq(dst[2][2], zFarVal / (zFarVal - zNearVal))) ASSERT(test_eq(dst[2][3], 1.0f)) ASSERT(test_eq(dst[3][2], -1 * zFarVal * zNearVal / (zFarVal - zNearVal))) /* Sanity mk. II */ /* "Reference values" generated by GLM's glm::perspectiveLH_ZO */ mat4 cmp = {0}; cmp[0][0] = 1.8106601f; cmp[1][1] = 2.4142134f; cmp[2][2] = 1.0010010f; cmp[2][3] = 1.0000000f; cmp[3][2] = -0.1001001f; return test_assert_mat4_eq(dst, cmp); } cglm-0.9.7/test/src/test_cam_rh_no.h000066400000000000000000000022271526744317200173720ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" #include "../../include/cglm/clipspace/persp_rh_no.h" #include "../../include/cglm/call/clipspace/persp_rh_no.h" TEST_IMPL(GLM_PREFIX, perspective_rh_no) { mat4 dst; const float fovy = glm_rad(45.0f); const float aspect = 640/480.0f; const float zNearVal = 0.1f; const float zFarVal = 100.0f; GLM(perspective_rh_no)(fovy, aspect, zNearVal, zFarVal, dst); /* Sanity mk. I: longhand version */ ASSERT(test_eq(dst[0][0], 1.0f / (tanf(fovy / 2) * aspect))) ASSERT(test_eq(dst[1][1], 1.0f / tanf(fovy / 2))) ASSERT(test_eq(dst[2][2], -1.0f * (zFarVal + zNearVal) / (zFarVal - zNearVal))) ASSERT(test_eq(dst[2][3], -1.0f)) ASSERT(test_eq(dst[3][2], -2 * zFarVal * zNearVal / (zFarVal - zNearVal))) /* Sanity mk. II */ /*reference test data for glm_perspective_rh_no*/ mat4 cmp = {0}; cmp[0][0] = 1.8106601f; cmp[1][1] = 2.4142134f; cmp[2][2] = -1.0020020f; cmp[2][3] = -1.0000000f; cmp[3][2] = -0.2002002f; return test_assert_mat4_eq(dst, cmp); } cglm-0.9.7/test/src/test_cam_rh_zo.h000066400000000000000000000021741526744317200174070ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" #include "../../include/cglm/clipspace/persp_rh_zo.h" #include "../../include/cglm/call/clipspace/persp_rh_zo.h" TEST_IMPL(GLM_PREFIX, perspective_rh_zo) { mat4 dst; const float fovy = glm_rad(45.0f); const float aspect = 640/480.0f; const float zNearVal = 0.1f; const float zFarVal = 100.0f; GLM(perspective_rh_zo)(fovy, aspect, zNearVal, zFarVal, dst); /* Sanity mk. I: longhand version */ ASSERT(test_eq(dst[0][0], 1 / (tanf(fovy / 2) * aspect))) ASSERT(test_eq(dst[1][1], 1 / tanf(fovy / 2))) ASSERT(test_eq(dst[2][2], zFarVal / (zNearVal - zFarVal))) ASSERT(test_eq(dst[2][3], -1.0f)) ASSERT(test_eq(dst[3][2], -1 * zFarVal * zNearVal / (zFarVal - zNearVal))) /* Sanity mk. II */ /*reference test data for glm_perspective_rh_zo*/ mat4 cmp = {0}; cmp[0][0] = 1.8106601f; cmp[1][1] = 2.4142134f; cmp[2][2] = -1.0010010f; cmp[2][3] = -1.0000000f; cmp[3][2] = -0.1001001f; return test_assert_mat4_eq(dst, cmp); } cglm-0.9.7/test/src/test_clamp.c000066400000000000000000000013301526744317200165260ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" TEST_IMPL(clamp) { vec3 v3 = {15.07f, 0.4f, 17.3f}; vec4 v4 = {5.07f, 2.3f, 1.3f, 1.4f}; ASSERT(glm_eq(glm_clamp(1.6f, 0.0f, 1.0f), 1.0f)) ASSERT(glm_eq(glm_clamp(-1.6f, 0.0f, 1.0f), 0.0f)) ASSERT(glm_eq(glm_clamp(0.6f, 0.0f, 1.0f), 0.6f)) glm_vec3_clamp(v3, 0.0, 1.0); glm_vec4_clamp(v4, 1.5, 3.0); ASSERT(glm_eq(v3[0], 1.0f)) ASSERT(glm_eq(v3[1], 0.4f)) ASSERT(glm_eq(v3[2], 1.0f)) ASSERT(glm_eq(v4[0], 3.0f)) ASSERT(glm_eq(v4[1], 2.3f)) ASSERT(glm_eq(v4[2], 1.5f)) ASSERT(glm_eq(v4[3], 1.5f)) TEST_SUCCESS } cglm-0.9.7/test/src/test_common.c000066400000000000000000000244741526744317200167400ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * MIT License (MIT), http://opensource.org/licenses/MIT */ #include "test_common.h" #include void test_rand_mat4(mat4 dest) { glm_mat4_copy(GLM_MAT4_IDENTITY, dest); /* random position */ dest[3][0] = frand48(); dest[3][1] = frand48(); dest[3][2] = frand48(); /* random rotatation around random axis with random angle */ glm_rotate(dest, frand48(), (vec3){frand48(), frand48(), frand48()}); /* random scale */ /* glm_scale(dest, (vec3){frand48(), frand48(), frand48()}); */ } void test_rand_mat4x2(mat4x2 dest) { dest[0][0] = frand48(); dest[0][1] = frand48(); dest[1][0] = frand48(); dest[1][1] = frand48(); dest[2][0] = frand48(); dest[2][1] = frand48(); dest[3][0] = frand48(); dest[3][1] = frand48(); } void test_rand_mat4x3(mat4x3 dest) { dest[0][0] = frand48(); dest[0][1] = frand48(); dest[0][2] = frand48(); dest[1][0] = frand48(); dest[1][1] = frand48(); dest[1][2] = frand48(); dest[2][0] = frand48(); dest[2][1] = frand48(); dest[2][2] = frand48(); dest[3][0] = frand48(); dest[3][1] = frand48(); dest[3][2] = frand48(); } void test_rand_mat3(mat3 dest) { mat4 m4; /* random rotatation around random axis with random angle */ glm_rotate_make(m4, frand48(), (vec3){frand48(), frand48(), frand48()}); glm_mat4_pick3(m4, dest); } void test_rand_mat3x2(mat3x2 dest) { dest[0][0] = frand48(); dest[0][1] = frand48(); dest[1][0] = frand48(); dest[1][1] = frand48(); dest[2][0] = frand48(); dest[2][1] = frand48(); } void test_rand_mat3x4(mat3x4 dest) { dest[0][0] = frand48(); dest[0][1] = frand48(); dest[0][2] = frand48(); dest[0][3] = frand48(); dest[1][0] = frand48(); dest[1][1] = frand48(); dest[1][2] = frand48(); dest[1][3] = frand48(); dest[2][0] = frand48(); dest[2][1] = frand48(); dest[2][2] = frand48(); dest[2][3] = frand48(); } void test_rand_mat2(mat2 dest) { dest[0][0] = frand48(); dest[0][1] = frand48(); dest[1][0] = frand48(); dest[1][1] = frand48(); } void test_rand_mat2x3(mat2x3 dest) { dest[0][0] = frand48(); dest[0][1] = frand48(); dest[0][2] = frand48(); dest[1][0] = frand48(); dest[1][1] = frand48(); dest[1][2] = frand48(); } void test_rand_mat2x4(mat2x4 dest) { dest[0][0] = frand48(); dest[0][1] = frand48(); dest[0][2] = frand48(); dest[0][3] = frand48(); dest[1][0] = frand48(); dest[1][1] = frand48(); dest[1][2] = frand48(); dest[1][3] = frand48(); } void test_rand_transform2d(mat3 dest) { glm_translate2d_make(dest, (vec2) { frand48(), frand48() }); glm_rotate2d(dest, frand48()); glm_scale2d(dest, (vec2) { frand48(), frand48() }); } void test_rand_vec3(vec3 dest) { dest[0] = frand48(); dest[1] = frand48(); dest[2] = frand48(); } vec3s test_rand_vec3s(void) { vec3s r; test_rand_vec3(r.raw); return r; } void test_rand_vec4(vec4 dest) { dest[0] = frand48(); dest[1] = frand48(); dest[2] = frand48(); dest[3] = frand48(); } vec4s test_rand_vec4s(void) { vec4s r; test_rand_vec4(r.raw); return r; } float test_rand(void) { return frand48(); } void test_rand_quat(versor q) { glm_quat(q, frand48(), frand48(), frand48(), frand48()); glm_quat_normalize(q); } test_status_t test_assert_mat4_eq(mat4 m1, mat4 m2) { int i, j; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { ASSERT(fabsf(m1[i][j] - m2[i][j]) <= 0.0000009f) } } TEST_SUCCESS } test_status_t test_assert_mat4_eqt(mat4 m1, mat4 m2) { int i, j; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { ASSERT(fabsf(m1[j][i] - m2[i][j]) <= 0.0000009f) } } TEST_SUCCESS } test_status_t test_assert_mat4_eq2(mat4 m1, mat4 m2, float eps) { int i, j; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { ASSERT(fabsf(m1[i][j] - m2[i][j]) <= eps); } } TEST_SUCCESS } test_status_t test_assert_mat2_eqt(mat2 m1, mat2 m2) { int i, j; for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) { ASSERT(fabsf(m1[j][i] - m2[i][j]) <= 0.0000009f); } } TEST_SUCCESS } test_status_t test_assert_mat2_eq(mat2 m1, mat2 m2) { int i, j; for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) { ASSERT(fabsf(m1[i][j] - m2[i][j]) <= 0.0000009f); } } TEST_SUCCESS } test_status_t test_assert_mat2_eq_identity(mat2 m2) { int i, j; for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) { if (i == j) { ASSERT(test_eq(m2[i][j], 1.0f)) } else { ASSERT(test_eq(m2[i][j], 0.0f)) } } } TEST_SUCCESS } test_status_t test_assert_mat2_eq_zero(mat2 m2) { int i, j; for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) { ASSERT(test_eq(m2[i][j], 0.0f)) } } TEST_SUCCESS } test_status_t test_assert_mat2x3_eq_zero(mat2x3 m2x3) { int i, j; for (i = 0; i < 2; i++) { for (j = 0; j < 3; j++) { ASSERT(test_eq(m2x3[i][j], 0.0f)) } } TEST_SUCCESS } test_status_t test_assert_mat2x3_eq(mat2x3 m1, mat2x3 m2) { int i, j; for (i = 0; i < 2; i++) { for (j = 0; j < 3; j++) { ASSERT(fabsf(m1[i][j] - m2[i][j]) <= 0.0000009f) } } TEST_SUCCESS } test_status_t test_assert_mat2x4_eq_zero(mat2x4 m2x4) { int i, j; for (i = 0; i < 2; i++) { for (j = 0; j < 4; j++) { ASSERT(test_eq(m2x4[i][j], 0.0f)) } } TEST_SUCCESS } test_status_t test_assert_mat2x4_eq(mat2x4 m1, mat2x4 m2) { int i, j; for (i = 0; i < 2; i++) { for (j = 0; j < 4; j++) { ASSERT(fabsf(m1[i][j] - m2[i][j]) <= 0.0000009f) } } TEST_SUCCESS } test_status_t test_assert_mat3_eq(mat3 m1, mat3 m2) { int i, j; for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { ASSERT(fabsf(m1[i][j] - m2[i][j]) <= 0.0000009f); } } TEST_SUCCESS } test_status_t test_assert_mat3_eqt(mat3 m1, mat3 m2) { int i, j; for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { ASSERT(fabsf(m1[j][i] - m2[i][j]) <= 0.0000009f); } } TEST_SUCCESS } test_status_t test_assert_mat3_eq_identity(mat3 m3) { int i, j; for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { if (i == j) { ASSERT(test_eq(m3[i][j], 1.0f)) } else { ASSERT(test_eq(m3[i][j], 0.0f)) } } } TEST_SUCCESS } test_status_t test_assert_mat3_eq_zero(mat3 m3) { int i, j; for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { ASSERT(test_eq(m3[i][j], 0.0f)) } } TEST_SUCCESS } test_status_t test_assert_mat3x2_eq_zero(mat3x2 m3x2) { int i, j; for (i = 0; i < 3; i++) { for (j = 0; j < 2; j++) { ASSERT(test_eq(m3x2[i][j], 0.0f)) } } TEST_SUCCESS } test_status_t test_assert_mat3x2_eq(mat3x2 m1, mat3x2 m2) { int i, j; for (i = 0; i < 3; i++) { for (j = 0; j < 2; j++) { ASSERT(fabsf(m1[i][j] - m2[i][j]) <= 0.0000009f) } } TEST_SUCCESS } test_status_t test_assert_mat3x4_eq_zero(mat3x4 m3x4) { int i, j; for (i = 0; i < 3; i++) { for (j = 0; j < 4; j++) { ASSERT(test_eq(m3x4[i][j], 0.0f)) } } TEST_SUCCESS } test_status_t test_assert_mat3x4_eq(mat3x4 m1, mat3x4 m2) { int i, j; for (i = 0; i < 3; i++) { for (j = 0; j < 4; j++) { ASSERT(fabsf(m1[i][j] - m2[i][j]) <= 0.0000009f) } } TEST_SUCCESS } test_status_t test_assert_mat4_eq_identity(mat4 m4) { int i, j; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { if (i == j) { ASSERT(test_eq(m4[i][j], 1.0f)) } else { ASSERT(test_eq(m4[i][j], 0.0f)) } } } TEST_SUCCESS } test_status_t test_assert_mat4_eq_zero(mat4 m4) { int i, j; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { ASSERT(test_eq(m4[i][j], 0.0f)) } } TEST_SUCCESS } test_status_t test_assert_mat4x2_eq_zero(mat4x2 m4x2) { int i, j; for (i = 0; i < 4; i++) { for (j = 0; j < 2; j++) { ASSERT(test_eq(m4x2[i][j], 0.0f)) } } TEST_SUCCESS } test_status_t test_assert_mat4x2_eq(mat4x2 m1, mat4x2 m2) { int i, j; for (i = 0; i < 4; i++) { for (j = 0; j < 2; j++) { ASSERT(fabsf(m1[i][j] - m2[i][j]) <= 0.0000009f) } } TEST_SUCCESS } test_status_t test_assert_mat4x3_eq_zero(mat4x3 m4x3) { int i, j; for (i = 0; i < 4; i++) { for (j = 0; j < 3; j++) { ASSERT(test_eq(m4x3[i][j], 0.0f)) } } TEST_SUCCESS } test_status_t test_assert_mat4x3_eq(mat4x3 m1, mat4x3 m2) { int i, j; for (i = 0; i < 4; i++) { for (j = 0; j < 3; j++) { ASSERT(fabsf(m1[i][j] - m2[i][j]) <= 0.0000009f) } } TEST_SUCCESS } test_status_t test_assert_eqf(float a, float b) { ASSERT(fabsf(a - b) <= 0.000009f); /* rounding errors */ TEST_SUCCESS } test_status_t test_assert_vec2_eq(vec2 v1, vec2 v2) { ASSERT(fabsf(v1[0] - v2[0]) <= 0.000009f); /* rounding errors */ ASSERT(fabsf(v1[1] - v2[1]) <= 0.000009f); TEST_SUCCESS } test_status_t test_assert_vec3_eq(vec3 v1, vec3 v2) { ASSERT(fabsf(v1[0] - v2[0]) <= 0.000009f); /* rounding errors */ ASSERT(fabsf(v1[1] - v2[1]) <= 0.000009f); ASSERT(fabsf(v1[2] - v2[2]) <= 0.000009f); TEST_SUCCESS } test_status_t test_assert_vec3s_eq(vec3s v1, vec3s v2) { test_assert_vec3_eq(v1.raw, v2.raw); TEST_SUCCESS } test_status_t test_assert_vec4_eq(vec4 v1, vec4 v2) { ASSERT(fabsf(v1[0] - v2[0]) <= 0.000009f); /* rounding errors */ ASSERT(fabsf(v1[1] - v2[1]) <= 0.000009f); ASSERT(fabsf(v1[2] - v2[2]) <= 0.000009f); ASSERT(fabsf(v1[3] - v2[3]) <= 0.000009f); TEST_SUCCESS } test_status_t test_assert_vec4s_eq(vec4s v1, vec4s v2) { test_assert_vec4_eq(v1.raw, v2.raw); TEST_SUCCESS } test_status_t test_assert_quat_eq_abs(versor v1, versor v2) { ASSERT(fabsf(fabsf(v1[0]) - fabsf(v2[0])) <= 0.0009f); /* rounding errors */ ASSERT(fabsf(fabsf(v1[1]) - fabsf(v2[1])) <= 0.0009f); ASSERT(fabsf(fabsf(v1[2]) - fabsf(v2[2])) <= 0.0009f); ASSERT(fabsf(fabsf(v1[3]) - fabsf(v2[3])) <= 0.0009f); TEST_SUCCESS } test_status_t test_assert_quat_eq(versor v1, versor v2) { ASSERT(fabsf(v1[0] - v2[0]) <= 0.000009f); /* rounding errors */ ASSERT(fabsf(v1[1] - v2[1]) <= 0.000009f); ASSERT(fabsf(v1[2] - v2[2]) <= 0.000009f); ASSERT(fabsf(v1[3] - v2[3]) <= 0.000009f); TEST_SUCCESS } test_status_t test_assert_quat_eq_identity(versor q) { versor p = GLM_QUAT_IDENTITY_INIT; ASSERT(fabsf(q[0] - p[0]) <= 0.000009f); /* rounding errors */ ASSERT(fabsf(q[1] - p[1]) <= 0.000009f); ASSERT(fabsf(q[2] - p[2]) <= 0.000009f); ASSERT(fabsf(q[3] - p[3]) <= 0.000009f); TEST_SUCCESS } cglm-0.9.7/test/src/test_common.h000066400000000000000000000060501526744317200167330ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef test_common_h #define test_common_h #include "../include/common.h" #if !defined(_WIN32) && !defined(_MSC_VER) # pragma GCC diagnostic ignored "-Wstrict-prototypes" #endif void test_rand_mat4(mat4 dest); void test_rand_mat4x2(mat4x2 dest); void test_rand_mat4x3(mat4x3 dest); void test_rand_mat3(mat3 dest); void test_rand_mat3x2(mat3x2 dest); void test_rand_mat3x4(mat3x4 dest); void test_rand_mat2(mat2 dest); void test_rand_mat2x3(mat2x3 dest); void test_rand_mat2x4(mat2x4 dest); void test_rand_transform2d(mat3 dest); test_status_t test_assert_eqf(float a, float b); test_status_t test_assert_mat4_eq(mat4 m1, mat4 m2); test_status_t test_assert_mat4_eqt(mat4 m1, mat4 m2); test_status_t test_assert_mat4_eq2(mat4 m1, mat4 m2, float eps); test_status_t test_assert_mat4_eq_identity(mat4 m4); test_status_t test_assert_mat4_eq_zero(mat4 m4); test_status_t test_assert_mat4x2_eq_zero(mat4x2 m4x2); test_status_t test_assert_mat4x2_eq(mat4x2 m1, mat4x2 m2); test_status_t test_assert_mat4x3_eq_zero(mat4x3 m4x3); test_status_t test_assert_mat4x3_eq(mat4x3 m1, mat4x3 m2); test_status_t test_assert_mat2_eqt(mat2 m1, mat2 m2); test_status_t test_assert_mat2_eq(mat2 m1, mat2 m2); test_status_t test_assert_mat2_eq_identity(mat2 m2); test_status_t test_assert_mat2_eq_zero(mat2 m2); test_status_t test_assert_mat2x3_eq_zero(mat2x3 m2x3); test_status_t test_assert_mat2x3_eq(mat2x3 m1, mat2x3 m2); test_status_t test_assert_mat2x4_eq_zero(mat2x4 m2x4); test_status_t test_assert_mat2x4_eq(mat2x4 m1, mat2x4 m2); test_status_t test_assert_mat3_eq(mat3 m1, mat3 m2); test_status_t test_assert_vec2_eq(vec2 v1, vec2 v2); test_status_t test_assert_mat3_eqt(mat3 m1, mat3 m2); test_status_t test_assert_mat3_eq_identity(mat3 m3); test_status_t test_assert_mat3_eq_zero(mat3 m3); test_status_t test_assert_mat3x2_eq_zero(mat3x2 m3x2); test_status_t test_assert_mat3x2_eq(mat3x2 m1, mat3x2 m2); test_status_t test_assert_mat3x4_eq_zero(mat3x4 m3x4); test_status_t test_assert_mat3x4_eq(mat3x4 m1, mat3x4 m2); test_status_t test_assert_vec3_eq(vec3 v1, vec3 v2); test_status_t test_assert_vec3s_eq(vec3s v1, vec3s v2); test_status_t test_assert_vec4_eq(vec4 v1, vec4 v2); test_status_t test_assert_vec4s_eq(vec4s v1, vec4s v2); test_status_t test_assert_quat_eq(versor v1, versor v2); test_status_t test_assert_quat_eq_identity(versor q) ; test_status_t test_assert_quat_eq_abs(versor v1, versor v2); void test_rand_vec3(vec3 dest); vec3s test_rand_vec3s(void); void test_rand_vec4(vec4 dest); vec4s test_rand_vec4s(void); float test_rand(void); void test_rand_quat(versor q); CGLM_INLINE bool test_eq(float a, float b) { return fabsf(a - b) <= GLM_FLT_EPSILON * 10; } CGLM_INLINE bool test_eq_th(float a, float b, float th) { return fabsf(a - b) <= th; } /* drand with explicit conversion to lower precision */ CGLM_INLINE float frand48(void) { return (float)drand48(); } #endif /* test_common_h */ cglm-0.9.7/test/src/test_euler.c000066400000000000000000000021351526744317200165520ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" TEST_IMPL(euler) { mat4 rot1, rot2; vec3 inAngles, outAngles; inAngles[0] = glm_rad(-45.0f); /* X angle */ inAngles[1] = glm_rad(88.0f); /* Y angle */ inAngles[2] = glm_rad(18.0f); /* Z angle */ glm_euler_xyz(inAngles, rot1); /* extract angles */ glmc_euler_angles(rot1, outAngles); /* angles must be equal in that range */ ASSERTIFY(test_assert_vec3_eq(inAngles, outAngles)) /* matrices must be equal */ glmc_euler_xyz(outAngles, rot2); ASSERTIFY(test_assert_mat4_eq(rot1, rot2)) /* change range */ inAngles[0] = glm_rad(-145.0f); /* X angle */ inAngles[1] = glm_rad(818.0f); /* Y angle */ inAngles[2] = glm_rad(181.0f); /* Z angle */ glm_euler_xyz(inAngles, rot1); glmc_euler_angles(rot1, outAngles); /* angles may not be equal but matrices MUST! */ /* matrices must be equal */ glmc_euler_xyz(outAngles, rot2); ASSERTIFY(test_assert_mat4_eq(rot1, rot2)) TEST_SUCCESS } cglm-0.9.7/test/src/test_euler_to_quat_lh.h000066400000000000000000000347461526744317200210130ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" #include "../../include/cglm/handed/euler_to_quat_lh.h" TEST_IMPL(GLM_PREFIX, euler_xyz_quat_lh) { vec3 axis_x = {1.0f, 0.0f, 0.0f}; vec3 axis_y = {0.0f, 1.0f, 0.0f}; vec3 axis_z = {0.0f, 0.0f,-1.0f}; /* random angles for testing */ vec3 angles; /* quaternion representations for rotations */ versor rot_x, rot_y, rot_z; versor expected; versor result; versor tmp; /* 100 randomized tests */ for (int i = 0; i < 100; i++) { test_rand_vec3(angles); /* create the rotation quaternions using the angles and axises */ glm_quatv(rot_x, angles[0], axis_x); glm_quatv(rot_y, angles[1], axis_y); glm_quatv(rot_z, angles[2], axis_z); /* apply the rotations to a unit quaternion in xyz order */ glm_quat_identity(expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_x, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_y, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_z, expected); glm_euler_xyz_quat_lh(angles, result); /* verify if the magnitude of the quaternion stays 1 */ ASSERT(test_eq(glm_quat_norm(result), 1.0f)) /* verify that it acts the same as rotating by 3 axis quaternions */ ASSERTIFY(test_assert_quat_eq(result, expected)) } /* Start gimbal lock tests */ for (float x = -90.0f; x <= 90.0f; x += 90.0f) { for (float y = -90.0f; y <= 90.0f; y += 90.0f) { for (float z = -90.0f; z <= 90.0f; z += 90.0f) { angles[0] = x; angles[1] = y; angles[2] = z; /* create the rotation quaternions using the angles and axises */ glm_quatv(rot_x, angles[0], axis_x); glm_quatv(rot_y, angles[1], axis_y); glm_quatv(rot_z, angles[2], axis_z); /* apply the rotations to a unit quaternion in xyz order */ glm_quat_identity(expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_x, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_y, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_z, expected); /* use my function to get the quaternion */ glm_euler_xyz_quat_lh(angles, result); /* verify if the magnitude of the quaternion stays 1 */ ASSERT(test_eq(glm_quat_norm(result), 1.0f)) /* verify that it acts the same as rotating by 3 axis quaternions */ ASSERTIFY(test_assert_quat_eq(result, expected)) } } } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, euler_xzy_quat_lh) { vec3 axis_x = {1.0f, 0.0f, 0.0f}; vec3 axis_y = {0.0f, 1.0f, 0.0f}; vec3 axis_z = {0.0f, 0.0f,-1.0f}; /* random angles for testing */ vec3 angles; /* quaternion representations for rotations */ versor rot_x, rot_y, rot_z; versor expected; versor result; versor tmp; /* 100 randomized tests */ for (int i = 0; i < 100; i++) { test_rand_vec3(angles); /* create the rotation quaternions using the angles and axises */ glm_quatv(rot_x, angles[0], axis_x); glm_quatv(rot_y, angles[1], axis_y); glm_quatv(rot_z, angles[2], axis_z); /* apply the rotations to a unit quaternion in xzy order */ glm_quat_identity(expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_x, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_z, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_y, expected); glm_euler_xzy_quat_lh(angles, result); /* verify if the magnitude of the quaternion stays 1 */ ASSERT(test_eq(glm_quat_norm(result), 1.0f)) /* verify that it acts the same as rotating by 3 axis quaternions */ ASSERTIFY(test_assert_quat_eq(result, expected)) } /* Start gimbal lock tests */ for (float x = -90.0f; x <= 90.0f; x += 90.0f) { for (float y = -90.0f; y <= 90.0f; y += 90.0f) { for (float z = -90.0f; z <= 90.0f; z += 90.0f) { angles[0] = x; angles[1] = y; angles[2] = z; /* create the rotation quaternions using the angles and axises */ glm_quatv(rot_x, angles[0], axis_x); glm_quatv(rot_y, angles[1], axis_y); glm_quatv(rot_z, angles[2], axis_z); /* apply the rotations to a unit quaternion in xzy order */ glm_quat_identity(expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_x, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_z, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_y, expected); /* use my function to get the quaternion */ glm_euler_xzy_quat_lh(angles, result); /* verify if the magnitude of the quaternion stays 1 */ ASSERT(test_eq(glm_quat_norm(result), 1.0f)) /* verify that it acts the same as rotating by 3 axis quaternions */ ASSERTIFY(test_assert_quat_eq(result, expected)) } } } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, euler_yxz_quat_lh) { vec3 axis_x = {1.0f, 0.0f, 0.0f}; vec3 axis_y = {0.0f, 1.0f, 0.0f}; vec3 axis_z = {0.0f, 0.0f,-1.0f}; /* random angles for testing */ vec3 angles; /* quaternion representations for rotations */ versor rot_x, rot_y, rot_z; versor expected; versor result; versor tmp; /* 100 randomized tests */ for (int i = 0; i < 100; i++) { test_rand_vec3(angles); /* create the rotation quaternions using the angles and axises */ glm_quatv(rot_x, angles[0], axis_x); glm_quatv(rot_y, angles[1], axis_y); glm_quatv(rot_z, angles[2], axis_z); /* apply the rotations to a unit quaternion in yxz order */ glm_quat_identity(expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_y, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_x, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_z, expected); glm_euler_yxz_quat_lh(angles, result); /* verify if the magnitude of the quaternion stays 1 */ ASSERT(test_eq(glm_quat_norm(result), 1.0f)) /* verify that it acts the same as rotating by 3 axis quaternions */ ASSERTIFY(test_assert_quat_eq(result, expected)) } /* Start gimbal lock tests */ for (float x = -90.0f; x <= 90.0f; x += 90.0f) { for (float y = -90.0f; y <= 90.0f; y += 90.0f) { for (float z = -90.0f; z <= 90.0f; z += 90.0f) { angles[0] = x; angles[1] = y; angles[2] = z; /* create the rotation quaternions using the angles and axises */ glm_quatv(rot_x, angles[0], axis_x); glm_quatv(rot_y, angles[1], axis_y); glm_quatv(rot_z, angles[2], axis_z); /* apply the rotations to a unit quaternion in yxz order */ glm_quat_identity(expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_y, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_x, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_z, expected); /* use my function to get the quaternion */ glm_euler_yxz_quat_lh(angles, result); /* verify if the magnitude of the quaternion stays 1 */ ASSERT(test_eq(glm_quat_norm(result), 1.0f)) ASSERTIFY(test_assert_quat_eq(result, expected)) } } } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, euler_yzx_quat_lh) { vec3 axis_x = {1.0f, 0.0f, 0.0f}; vec3 axis_y = {0.0f, 1.0f, 0.0f}; vec3 axis_z = {0.0f, 0.0f,-1.0f}; /* random angles for testing */ vec3 angles; /* quaternion representations for rotations */ versor rot_x, rot_y, rot_z; versor expected; versor result; versor tmp; /* 100 randomized tests */ for (int i = 0; i < 100; i++) { test_rand_vec3(angles); /* create the rotation quaternions using the angles and axises */ glm_quatv(rot_x, angles[0], axis_x); glm_quatv(rot_y, angles[1], axis_y); glm_quatv(rot_z, angles[2], axis_z); /* apply the rotations to a unit quaternion in yzx order */ glm_quat_identity(expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_y, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_z, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_x, expected); glm_euler_yzx_quat_lh(angles, result); /* verify if the magnitude of the quaternion stays 1 */ ASSERT(test_eq(glm_quat_norm(result), 1.0f)) /* verify that it acts the same as rotating by 3 axis quaternions */ ASSERTIFY(test_assert_quat_eq(result, expected)) } /* Start gimbal lock tests */ for (float x = -90.0f; x <= 90.0f; x += 90.0f) { for (float y = -90.0f; y <= 90.0f; y += 90.0f) { for (float z = -90.0f; z <= 90.0f; z += 90.0f) { angles[0] = x; angles[1] = y; angles[2] = z; /* create the rotation quaternions using the angles and axises */ glm_quatv(rot_x, angles[0], axis_x); glm_quatv(rot_y, angles[1], axis_y); glm_quatv(rot_z, angles[2], axis_z); /* apply the rotations to a unit quaternion in yzx order */ glm_quat_identity(expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_y, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_z, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_x, expected); /* use my function to get the quaternion */ glm_euler_yzx_quat_lh(angles, result); /* verify if the magnitude of the quaternion stays 1 */ ASSERT(test_eq(glm_quat_norm(result), 1.0f)) ASSERTIFY(test_assert_quat_eq(result, expected)) } } } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, euler_zxy_quat_lh) { vec3 axis_x = {1.0f, 0.0f, 0.0f}; vec3 axis_y = {0.0f, 1.0f, 0.0f}; vec3 axis_z = {0.0f, 0.0f,-1.0f}; /* random angles for testing */ vec3 angles; /* quaternion representations for rotations */ versor rot_x, rot_y, rot_z; versor expected; versor result; versor tmp; /* 100 randomized tests */ for (int i = 0; i < 100; i++) { test_rand_vec3(angles); /* create the rotation quaternions using the angles and axises */ glm_quatv(rot_x, angles[0], axis_x); glm_quatv(rot_y, angles[1], axis_y); glm_quatv(rot_z, angles[2], axis_z); /* apply the rotations to a unit quaternion in zxy order */ glm_quat_identity(expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_z, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_x, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_y, expected); glm_euler_zxy_quat_lh(angles, result); /* verify if the magnitude of the quaternion stays 1 */ ASSERT(test_eq(glm_quat_norm(result), 1.0f)) /* verify that it acts the same as rotating by 3 axis quaternions */ ASSERTIFY(test_assert_quat_eq(result, expected)) } /* Start gimbal lock tests */ for (float x = -90.0f; x <= 90.0f; x += 90.0f) { for (float y = -90.0f; y <= 90.0f; y += 90.0f) { for (float z = -90.0f; z <= 90.0f; z += 90.0f) { angles[0] = x; angles[1] = y; angles[2] = z; /* create the rotation quaternions using the angles and axises */ glm_quatv(rot_x, angles[0], axis_x); glm_quatv(rot_y, angles[1], axis_y); glm_quatv(rot_z, angles[2], axis_z); /* apply the rotations to a unit quaternion in zxy order */ glm_quat_identity(expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_z, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_x, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_y, expected); /* use my function to get the quaternion */ glm_euler_zxy_quat_lh(angles, result); /* verify if the magnitude of the quaternion stays 1 */ ASSERT(test_eq(glm_quat_norm(result), 1.0f)) /* verify that it acts the same as rotating by 3 axis quaternions */ ASSERTIFY(test_assert_quat_eq(result, expected)) } } } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, euler_zyx_quat_lh) { vec3 axis_x = {1.0f, 0.0f, 0.0f}; vec3 axis_y = {0.0f, 1.0f, 0.0f}; vec3 axis_z = {0.0f, 0.0f,-1.0f}; /* random angles for testing */ vec3 angles; /* quaternion representations for rotations */ versor rot_x, rot_y, rot_z; versor expected; versor result; versor tmp; /* 100 randomized tests */ for (int i = 0; i < 100; i++) { test_rand_vec3(angles); /* create the rotation quaternions using the angles and axises */ glm_quatv(rot_x, angles[0], axis_x); glm_quatv(rot_y, angles[1], axis_y); glm_quatv(rot_z, angles[2], axis_z); /* apply the rotations to a unit quaternion in zyx order */ glm_quat_identity(expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_z, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_y, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_x, expected); glm_euler_zyx_quat_lh(angles, result); /* verify if the magnitude of the quaternion stays 1 */ ASSERT(test_eq(glm_quat_norm(result), 1.0f)) /* verify that it acts the same as rotating by 3 axis quaternions */ ASSERTIFY(test_assert_quat_eq(result, expected)) } /* Start gimbal lock tests */ for (float x = -90.0f; x <= 90.0f; x += 90.0f) { for (float y = -90.0f; y <= 90.0f; y += 90.0f) { for (float z = -90.0f; z <= 90.0f; z += 90.0f) { angles[0] = x; angles[1] = y; angles[2] = z; /* create the rotation quaternions using the angles and axises */ glm_quatv(rot_x, angles[0], axis_x); glm_quatv(rot_y, angles[1], axis_y); glm_quatv(rot_z, angles[2], axis_z); /* apply the rotations to a unit quaternion in xyz order */ glm_quat_identity(expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_z, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_y, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_x, expected); /* use my function to get the quaternion */ glm_euler_zyx_quat_lh(angles, result); /* verify if the magnitude of the quaternion stays 1 */ ASSERT(test_eq(glm_quat_norm(result), 1.0f)) /* verify that it acts the same as rotating by 3 axis quaternions */ ASSERTIFY(test_assert_quat_eq(result, expected)) } } } TEST_SUCCESS } cglm-0.9.7/test/src/test_euler_to_quat_rh.h000066400000000000000000000421441526744317200210100ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" #include "../../include/cglm/handed/euler_to_quat_rh.h" TEST_IMPL(GLM_PREFIX, euler_xyz_quat_rh) { vec3 axis_x = {1.0f, 0.0f, 0.0f}; vec3 axis_y = {0.0f, 1.0f, 0.0f}; vec3 axis_z = {0.0f, 0.0f, 1.0f}; /* random angles for testing */ vec3 angles; /* quaternion representations for rotations */ versor rot_x, rot_y, rot_z; versor expected; versor result; versor tmp; mat4 expected_mat4; /* 100 randomized tests */ for (int i = 0; i < 100; i++) { test_rand_vec3(angles); /* create the rotation quaternions using the angles and axises */ glm_quatv(rot_x, angles[0], axis_x); glm_quatv(rot_y, angles[1], axis_y); glm_quatv(rot_z, angles[2], axis_z); /* apply the rotations to a unit quaternion in xyz order */ glm_quat_identity(expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_x, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_y, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_z, expected); glm_euler_xyz_quat_rh(angles, result); /* verify if the magnitude of the quaternion stays 1 */ ASSERT(test_eq(glm_quat_norm(result), 1.0f)) /* verify that it acts the same as rotating by 3 axis quaternions */ ASSERTIFY(test_assert_quat_eq(result, expected)) /* verify that it acts the same as glm_euler_by_order */ glm_euler_by_order(angles, GLM_EULER_XYZ, expected_mat4); glm_mat4_quat(expected_mat4, expected); ASSERTIFY(test_assert_quat_eq_abs(result, expected)); } /* Start gimbal lock tests */ for (float x = -90.0f; x <= 90.0f; x += 90.0f) { for (float y = -90.0f; y <= 90.0f; y += 90.0f) { for (float z = -90.0f; z <= 90.0f; z += 90.0f) { angles[0] = x; angles[1] = y; angles[2] = z; /* create the rotation quaternions using the angles and axises */ glm_quatv(rot_x, angles[0], axis_x); glm_quatv(rot_y, angles[1], axis_y); glm_quatv(rot_z, angles[2], axis_z); /* apply the rotations to a unit quaternion in xyz order */ glm_quat_identity(expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_x, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_y, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_z, expected); /* use my function to get the quaternion */ glm_euler_xyz_quat_rh(angles, result); /* verify if the magnitude of the quaternion stays 1 */ ASSERT(test_eq(glm_quat_norm(result), 1.0f)) ASSERTIFY(test_assert_quat_eq(result, expected)) /* verify that it acts the same as glm_euler_by_order */ glm_euler_by_order(angles, GLM_EULER_XYZ, expected_mat4); glm_mat4_quat(expected_mat4, expected); ASSERTIFY(test_assert_quat_eq_abs(result, expected)); } } } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, euler_xzy_quat_rh) { vec3 axis_x = {1.0f, 0.0f, 0.0f}; vec3 axis_y = {0.0f, 1.0f, 0.0f}; vec3 axis_z = {0.0f, 0.0f, 1.0f}; /* random angles for testing */ vec3 angles; /* quaternion representations for rotations */ versor rot_x, rot_y, rot_z; versor expected; versor result; versor tmp; mat4 expected_mat4; /* 100 randomized tests */ for (int i = 0; i < 100; i++) { test_rand_vec3(angles); /* create the rotation quaternions using the angles and axises */ glm_quatv(rot_x, angles[0], axis_x); glm_quatv(rot_y, angles[1], axis_y); glm_quatv(rot_z, angles[2], axis_z); /* apply the rotations to a unit quaternion in xzy order */ glm_quat_identity(expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_x, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_z, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_y, expected); glm_euler_xzy_quat_rh(angles, result); /* verify if the magnitude of the quaternion stays 1 */ ASSERT(test_eq(glm_quat_norm(result), 1.0f)) /* verify that it acts the same as rotating by 3 axis quaternions */ ASSERTIFY(test_assert_quat_eq(result, expected)) /* verify that it acts the same as glm_euler_by_order */ glm_euler_by_order(angles, GLM_EULER_XZY, expected_mat4); glm_mat4_quat(expected_mat4, expected); ASSERTIFY(test_assert_quat_eq_abs(result, expected)); } /* Start gimbal lock tests */ for (float x = -90.0f; x <= 90.0f; x += 90.0f) { for (float y = -90.0f; y <= 90.0f; y += 90.0f) { for (float z = -90.0f; z <= 90.0f; z += 90.0f) { angles[0] = x; angles[1] = y; angles[2] = z; /* create the rotation quaternions using the angles and axises */ glm_quatv(rot_x, angles[0], axis_x); glm_quatv(rot_y, angles[1], axis_y); glm_quatv(rot_z, angles[2], axis_z); /* apply the rotations to a unit quaternion in xzy order */ glm_quat_identity(expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_x, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_z, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_y, expected); /* use my function to get the quaternion */ glm_euler_xzy_quat_rh(angles, result); /* verify if the magnitude of the quaternion stays 1 */ ASSERT(test_eq(glm_quat_norm(result), 1.0f)) ASSERTIFY(test_assert_quat_eq(result, expected)) /* verify that it acts the same as glm_euler_by_order */ glm_euler_by_order(angles, GLM_EULER_XZY, expected_mat4); glm_mat4_quat(expected_mat4, expected); ASSERTIFY(test_assert_quat_eq_abs(result, expected)); } } } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, euler_yxz_quat_rh) { vec3 axis_x = {1.0f, 0.0f, 0.0f}; vec3 axis_y = {0.0f, 1.0f, 0.0f}; vec3 axis_z = {0.0f, 0.0f, 1.0f}; /* random angles for testing */ vec3 angles; /* quaternion representations for rotations */ versor rot_x, rot_y, rot_z; versor expected; versor result; versor tmp; mat4 expected_mat4; /* 100 randomized tests */ for (int i = 0; i < 100; i++) { test_rand_vec3(angles); /* create the rotation quaternions using the angles and axises */ glm_quatv(rot_x, angles[0], axis_x); glm_quatv(rot_y, angles[1], axis_y); glm_quatv(rot_z, angles[2], axis_z); /* apply the rotations to a unit quaternion in yxz order */ glm_quat_identity(expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_y, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_x, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_z, expected); glm_euler_yxz_quat_rh(angles, result); /* verify if the magnitude of the quaternion stays 1 */ ASSERT(test_eq(glm_quat_norm(result), 1.0f)) /* verify that it acts the same as rotating by 3 axis quaternions */ ASSERTIFY(test_assert_quat_eq(result, expected)) /* verify that it acts the same as glm_euler_by_order */ glm_euler_by_order(angles, GLM_EULER_YXZ, expected_mat4); glm_mat4_quat(expected_mat4, expected); ASSERTIFY(test_assert_quat_eq_abs(result, expected)); } /* Start gimbal lock tests */ for (float x = -90.0f; x <= 90.0f; x += 90.0f) { for (float y = -90.0f; y <= 90.0f; y += 90.0f) { for (float z = -90.0f; z <= 90.0f; z += 90.0f) { angles[0] = x; angles[1] = y; angles[2] = z; /* create the rotation quaternions using the angles and axises */ glm_quatv(rot_x, angles[0], axis_x); glm_quatv(rot_y, angles[1], axis_y); glm_quatv(rot_z, angles[2], axis_z); /* apply the rotations to a unit quaternion in yxz order */ glm_quat_identity(expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_y, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_x, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_z, expected); /* use my function to get the quaternion */ glm_euler_yxz_quat_rh(angles, result); /* verify if the magnitude of the quaternion stays 1 */ ASSERT(test_eq(glm_quat_norm(result), 1.0f)) ASSERTIFY(test_assert_quat_eq(result, expected)) /* verify that it acts the same as glm_euler_by_order */ glm_euler_by_order(angles, GLM_EULER_YXZ, expected_mat4); glm_mat4_quat(expected_mat4, expected); ASSERTIFY(test_assert_quat_eq_abs(result, expected)); } } } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, euler_yzx_quat_rh) { vec3 axis_x = {1.0f, 0.0f, 0.0f}; vec3 axis_y = {0.0f, 1.0f, 0.0f}; vec3 axis_z = {0.0f, 0.0f, 1.0f}; /* random angles for testing */ vec3 angles; /* quaternion representations for rotations */ versor rot_x, rot_y, rot_z; versor expected; versor result; versor tmp; mat4 expected_mat4; /* 100 randomized tests */ for (int i = 0; i < 100; i++) { test_rand_vec3(angles); /* create the rotation quaternions using the angles and axises */ glm_quatv(rot_x, angles[0], axis_x); glm_quatv(rot_y, angles[1], axis_y); glm_quatv(rot_z, angles[2], axis_z); /* apply the rotations to a unit quaternion in yzx order */ glm_quat_identity(expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_y, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_z, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_x, expected); glm_euler_yzx_quat_rh(angles, result); /* verify if the magnitude of the quaternion stays 1 */ ASSERT(test_eq(glm_quat_norm(result), 1.0f)) /* verify that it acts the same as rotating by 3 axis quaternions */ ASSERTIFY(test_assert_quat_eq(result, expected)) /* verify that it acts the same as glm_euler_by_order */ glm_euler_by_order(angles, GLM_EULER_YZX, expected_mat4); glm_mat4_quat(expected_mat4, expected); ASSERTIFY(test_assert_quat_eq_abs(result, expected)); } /* Start gimbal lock tests */ for (float x = -90.0f; x <= 90.0f; x += 90.0f) { for (float y = -90.0f; y <= 90.0f; y += 90.0f) { for (float z = -90.0f; z <= 90.0f; z += 90.0f) { angles[0] = x; angles[1] = y; angles[2] = z; /* create the rotation quaternions using the angles and axises */ glm_quatv(rot_x, angles[0], axis_x); glm_quatv(rot_y, angles[1], axis_y); glm_quatv(rot_z, angles[2], axis_z); /* apply the rotations to a unit quaternion in yzx order */ glm_quat_identity(expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_y, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_z, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_x, expected); /* use my function to get the quaternion */ glm_euler_yzx_quat_rh(angles, result); /* verify if the magnitude of the quaternion stays 1 */ ASSERT(test_eq(glm_quat_norm(result), 1.0f)) ASSERTIFY(test_assert_quat_eq(result, expected)) /* verify that it acts the same as glm_euler_by_order */ glm_euler_by_order(angles, GLM_EULER_YZX, expected_mat4); glm_mat4_quat(expected_mat4, expected); ASSERTIFY(test_assert_quat_eq_abs(result, expected)); } } } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, euler_zxy_quat_rh) { vec3 axis_x = {1.0f, 0.0f, 0.0f}; vec3 axis_y = {0.0f, 1.0f, 0.0f}; vec3 axis_z = {0.0f, 0.0f, 1.0f}; /* random angles for testing */ vec3 angles; /* quaternion representations for rotations */ versor rot_x, rot_y, rot_z; versor expected; versor result; versor tmp; mat4 expected_mat4; /* 100 randomized tests */ for (int i = 0; i < 100; i++) { test_rand_vec3(angles); /* create the rotation quaternions using the angles and axises */ glm_quatv(rot_x, angles[0], axis_x); glm_quatv(rot_y, angles[1], axis_y); glm_quatv(rot_z, angles[2], axis_z); /* apply the rotations to a unit quaternion in zxy order */ glm_quat_identity(expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_z, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_x, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_y, expected); glm_euler_zxy_quat_rh(angles, result); /* verify if the magnitude of the quaternion stays 1 */ ASSERT(test_eq(glm_quat_norm(result), 1.0f)) /* verify that it acts the same as rotating by 3 axis quaternions */ ASSERTIFY(test_assert_quat_eq(result, expected)) /* verify that it acts the same as glm_euler_by_order */ glm_euler_by_order(angles, GLM_EULER_ZXY, expected_mat4); glm_mat4_quat(expected_mat4, expected); ASSERTIFY(test_assert_quat_eq_abs(result, expected)); } /* Start gimbal lock tests */ for (float x = -90.0f; x <= 90.0f; x += 90.0f) { for (float y = -90.0f; y <= 90.0f; y += 90.0f) { for (float z = -90.0f; z <= 90.0f; z += 90.0f) { angles[0] = x; angles[1] = y; angles[2] = z; /* create the rotation quaternions using the angles and axises */ glm_quatv(rot_x, angles[0], axis_x); glm_quatv(rot_y, angles[1], axis_y); glm_quatv(rot_z, angles[2], axis_z); /* apply the rotations to a unit quaternion in zxy order */ glm_quat_identity(expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_z, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_x, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_y, expected); /* use my function to get the quaternion */ glm_euler_zxy_quat_rh(angles, result); /* verify if the magnitude of the quaternion stays 1 */ ASSERT(test_eq(glm_quat_norm(result), 1.0f)) ASSERTIFY(test_assert_quat_eq(result, expected)) /* verify that it acts the same as glm_euler_by_order */ glm_euler_by_order(angles, GLM_EULER_ZXY, expected_mat4); glm_mat4_quat(expected_mat4, expected); ASSERTIFY(test_assert_quat_eq_abs(result, expected)); } } } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, euler_zyx_quat_rh) { vec3 axis_x = {1.0f, 0.0f, 0.0f}; vec3 axis_y = {0.0f, 1.0f, 0.0f}; vec3 axis_z = {0.0f, 0.0f, 1.0f}; /* random angles for testing */ vec3 angles; /* quaternion representations for rotations */ versor rot_x, rot_y, rot_z; versor expected; versor result; versor tmp; mat4 expected_mat4; /* 100 randomized tests */ for (int i = 0; i < 100; i++) { test_rand_vec3(angles); /* create the rotation quaternions using the angles and axises */ glm_quatv(rot_x, angles[0], axis_x); glm_quatv(rot_y, angles[1], axis_y); glm_quatv(rot_z, angles[2], axis_z); /* apply the rotations to a unit quaternion in zyx order */ glm_quat_identity(expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_z, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_y, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_x, expected); glm_euler_zyx_quat_rh(angles, result); /* verify if the magnitude of the quaternion stays 1 */ ASSERT(test_eq(glm_quat_norm(result), 1.0f)) /* verify that it acts the same as rotating by 3 axis quaternions */ ASSERTIFY(test_assert_quat_eq(result, expected)) /* verify that it acts the same as glm_euler_by_order */ glm_euler_by_order(angles, GLM_EULER_ZYX, expected_mat4); glm_mat4_quat(expected_mat4, expected); ASSERTIFY(test_assert_quat_eq_abs(result, expected)); } /* Start gimbal lock tests */ for (float x = -90.0f; x <= 90.0f; x += 90.0f) { for (float y = -90.0f; y <= 90.0f; y += 90.0f) { for (float z = -90.0f; z <= 90.0f; z += 90.0f) { angles[0] = x; angles[1] = y; angles[2] = z; /* create the rotation quaternions using the angles and axises */ glm_quatv(rot_x, angles[0], axis_x); glm_quatv(rot_y, angles[1], axis_y); glm_quatv(rot_z, angles[2], axis_z); /* apply the rotations to a unit quaternion in xyz order */ glm_quat_identity(expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_z, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_y, expected); glm_quat_copy(expected, tmp); glm_quat_mul(tmp, rot_x, expected); /* use my function to get the quaternion */ glm_euler_zyx_quat_rh(angles, result); /* verify if the magnitude of the quaternion stays 1 */ ASSERT(test_eq(glm_quat_norm(result), 1.0f)) ASSERTIFY(test_assert_quat_eq(result, expected)) /* verify that it acts the same as glm_euler_by_order */ glm_euler_by_order(angles, GLM_EULER_ZYX, expected_mat4); glm_mat4_quat(expected_mat4, expected); ASSERTIFY(test_assert_quat_eq_abs(result, expected)); } } } TEST_SUCCESS } cglm-0.9.7/test/src/test_ivec2.h000066400000000000000000000213431526744317200164550ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" TEST_IMPL(GLM_PREFIX, ivec2) { ivec4 v4 = {2, 3, 5, 7}; ivec3 v3 = {11, 13, 17}; ivec2 v2; GLM(ivec2)(v4, v2); ASSERT(v2[0] == 2) ASSERT(v2[1] == 3) GLM(ivec2)(v3, v2); ASSERT(v2[0] == 11) ASSERT(v2[1] == 13) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_copy) { ivec2 src = {7, 5}; ivec2 dst = {99, 99}; GLM(ivec2_copy)(src, dst); ASSERT(dst[0] == 7) ASSERT(dst[1] == 5) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_zero) { ivec2 v = {2, 3}; GLM(ivec2_zero)(v); ASSERT(v[0] == 0) ASSERT(v[1] == 0) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_one) { ivec2 v = {-2, 9}; GLM(ivec2_one)(v); ASSERT(v[0] == 1) ASSERT(v[1] == 1) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_dot) { ivec2 a = {2, 3}; ivec2 b = {4, 4}; int dot1, dot2; dot1 = GLM(ivec2_dot)(a, b); dot2 = a[0] * b[0] + a[1] * b[1]; ASSERT(dot1 == dot2) ASSERT(dot1 == 20) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_cross) { ivec2 a = {10, 9}; ivec2 b = {1, 2}; int cross1, cross2; cross1 = GLM(ivec2_cross)(a, b); cross2 = a[0] * b[1] - a[1] * b[0]; ASSERT(cross1 == cross2) ASSERT(cross1 == 11) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_add) { ivec2 a = {14, 3}; ivec2 b = {-3, 2}; ivec2 v = {99, 99}; GLM(ivec2_add)(a, b, v); ASSERT(v[0] == 11) ASSERT(v[1] == 5) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_adds) { ivec2 a = {-3, 1}; ivec2 v = {99, 99}; int s = 2; GLM(ivec2_adds)(a, s, v); ASSERT(v[0] == -1) ASSERT(v[1] == 3) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_sub) { ivec2 a = {-2, 9}; ivec2 b = {3, 2}; ivec2 v = {99, 99}; GLM(ivec2_sub)(a, b, v); ASSERT(v[0] == -5) ASSERT(v[1] == 7) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_subs) { ivec2 a = {5, -2}; ivec2 v = {99, 99}; int s = -3; GLM(ivec2_subs)(a, s, v); ASSERT(v[0] == 8) ASSERT(v[1] == 1) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_mul) { ivec2 a = {3, 4}; ivec2 b = {-2, 3}; ivec2 v = {99, 99}; GLM(ivec2_mul)(a, b, v); ASSERT(v[0] == -6) ASSERT(v[1] == 12) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_scale) { ivec2 a = {-9, 2}; ivec2 v = {99, 99}; int s = -2; GLM(ivec2_scale)(a, s, v); ASSERT(v[0] == 18) ASSERT(v[1] == -4) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_div) { ivec2 v1 = {6, 5}, v2 = {-2, 4}, v3; GLM(ivec2_div)(v1, v2, v3); ASSERT(v1[0] / v2[0] == v3[0]) ASSERT(v1[1] / v2[1] == v3[1]) ASSERT(v3[0] == -3) ASSERT(v3[1] == 1) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_divs) { ivec2 v1 = {16, -8}, v2; int s = 4; GLM(ivec2_divs)(v1, s, v2); ASSERT(v1[0] / s == v2[0]) ASSERT(v1[1] / s == v2[1]) ASSERT(v2[0] == 4) ASSERT(v2[1] == -2) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_mod) { ivec2 a = {16, -8}; ivec2 b = {3, 5}; ivec2 dest; GLM(ivec2_mod)(a, b, dest); ASSERT(a[0] % b[0] == dest[0]) ASSERT(a[1] % b[1] == dest[1]) ASSERT(dest[0] == 1) ASSERT(dest[1] == -3) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_addadd) { ivec2 a = {2, -3}, b = {-3, 4}, c = {1, 2}, d = {1, 2}; GLM(ivec2_addadd)(a, b, c); ASSERT(d[0] + a[0] + b[0] == c[0]) ASSERT(d[1] + a[1] + b[1] == c[1]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_addadds) { ivec2 a = {2, -3}, c = {1, 2}, d = {1, 2}; int s = 9; GLM(ivec2_addadds)(a, s, c); ASSERT(d[0] + a[0] + s == c[0]) ASSERT(d[1] + a[1] + s == c[1]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_subadd) { ivec2 a = {2, -3}, b = {-3, 4}, c = {1, 2}, d = {1, 2}; GLM(ivec2_subadd)(a, b, c); ASSERT(d[0] + (a[0] - b[0]) == c[0]) ASSERT(d[1] + (a[1] - b[1]) == c[1]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_subadds) { ivec2 a = {2, -3}, c = {1, 2}, d = {1, 2}; int s = 9; GLM(ivec2_subadds)(a, s, c); ASSERT(d[0] + a[0] - s == c[0]) ASSERT(d[1] + a[1] - s == c[1]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_muladd) { ivec2 a = {2, -3}, b = {-3, 4}, c = {1, 2}, d = {1, 2}; GLM(ivec2_muladd)(a, b, c); ASSERT(d[0] + a[0] * b[0] == c[0]) ASSERT(d[1] + a[1] * b[1] == c[1]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_muladds) { ivec2 a = {2, -3}, c = {1, 2}, d = {1, 2}; int s = 9; GLM(ivec2_muladds)(a, s, c); ASSERT(d[0] + a[0] * s == c[0]) ASSERT(d[1] + a[1] * s == c[1]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_maxadd) { ivec2 a = {2, -3}, b = {-3, 4}, c = {1, 2}, d = {1, 2}; GLM(ivec2_maxadd)(a, b, c); ASSERT(d[0] += glm_imax(a[0], b[0]) == c[0]) ASSERT(d[1] += glm_imax(a[1], b[1]) == c[1]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_minadd) { ivec2 a = {2, -3}, b = {-3, 4}, c = {1, 2}, d = {1, 2}; GLM(ivec2_minadd)(a, b, c); ASSERT(d[0] += glm_imin(a[0], b[0]) == c[0]) ASSERT(d[1] += glm_imin(a[1], b[1]) == c[1]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_subsub) { ivec2 a = {2, -3}, b = {-3, 4}, c = {1, 2}, d = {1, 2}; GLM(ivec2_subsub)(a, b, c); ASSERT(d[0] - (a[0] - b[0]) == c[0]) ASSERT(d[1] - (a[1] - b[1]) == c[1]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_subsubs) { ivec2 a = {2, -3}, c = {1, 2}, d = {1, 2}; int s = 9; GLM(ivec2_subsubs)(a, s, c); ASSERT(d[0] - (a[0] - s) == c[0]) ASSERT(d[1] - (a[1] - s) == c[1]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_addsub) { ivec2 a = {2, -3}, b = {-3, 4}, c = {1, 2}, d = {1, 2}; GLM(ivec2_addsub)(a, b, c); ASSERT(d[0] - (a[0] + b[0]) == c[0]) ASSERT(d[1] - (a[1] + b[1]) == c[1]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_addsubs) { ivec2 a = {2, -3}, c = {1, 2}, d = {1, 2}; int s = 9; GLM(ivec2_addsubs)(a, s, c); ASSERT(d[0] - (a[0] + s) == c[0]) ASSERT(d[1] - (a[1] + s) == c[1]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_mulsub) { ivec2 a = {2, -3}, b = {-3, 4}, c = {1, 2}, d = {1, 2}; GLM(ivec2_mulsub)(a, b, c); ASSERT(d[0] - a[0] * b[0] == c[0]) ASSERT(d[1] - a[1] * b[1] == c[1]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_mulsubs) { ivec2 a = {2, -3}, c = {1, 2}, d = {1, 2}; int s = 9; GLM(ivec2_mulsubs)(a, s, c); ASSERT(d[0] - a[0] * s == c[0]) ASSERT(d[1] - a[1] * s == c[1]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_maxsub) { ivec2 a = {2, -3}, b = {-3, 4}, c = {1, 2}, d = {1, 2}; GLM(ivec2_maxsub)(a, b, c); ASSERT(d[0] -= glm_imax(a[0], b[0]) == c[0]) ASSERT(d[1] -= glm_imax(a[1], b[1]) == c[1]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_minsub) { ivec2 a = {2, -3}, b = {-3, 4}, c = {1, 2}, d = {1, 2}; GLM(ivec2_minsub)(a, b, c); ASSERT(d[0] -= glm_imin(a[0], b[0]) == c[0]) ASSERT(d[1] -= glm_imin(a[1], b[1]) == c[1]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_distance2) { ivec2 a = {-1, 3}; ivec2 b = {5, 4}; int v; v = GLM(ivec2_distance2)(a, b); ASSERT(v == 37) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_distance) { ivec2 a = {3, 2}; ivec2 b = {-2, 5}; float v; v = GLM(ivec2_distance)(a, b); ASSERT(test_eq(v, 5.8309518948f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_fill) { ivec2 v1; ivec2 v2 = {-1, 3}; GLM(ivec2_fill)(v1, 1); GLM(ivec2_fill)(v2, 2); ASSERT(GLM(ivec2_eq)(v1, 1)) ASSERT(GLM(ivec2_eq)(v2, 2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_eq) { ivec2 v1 = {-1, 2}; GLM(ivec2_fill)(v1, 2); ASSERT(GLM(ivec2_eq)(v1, 2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_eqv) { ivec2 v1, v2, v3; GLM(ivec2_fill)(v1, 1); GLM(ivec2_fill)(v2, 2); GLM(ivec2_fill)(v3, 1); ASSERT(GLM(ivec2_eqv)(v1, v3)) ASSERT(!GLM(ivec2_eqv)(v1, v2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_maxv) { ivec2 a = {9, -20}; ivec2 b = {8, -1}; ivec2 v = {99, 99}; GLM(ivec2_maxv)(a, b, v); ASSERT(v[0] == 9) ASSERT(v[1] == -1) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_minv) { ivec2 a = {16, 0}; ivec2 b = {-15, 10}; ivec2 v = {99, 99}; GLM(ivec2_minv)(a, b, v); ASSERT(v[0] == -15) ASSERT(v[1] == 0) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_clamp) { ivec2 v = {3, -1}; GLM(ivec2_clamp)(v, -2, 4); ASSERT(v[0] == 3) ASSERT(v[1] == -1) v[0] = -15; v[1] = 4; GLM(ivec2_clamp)(v, -9, 3); ASSERT(v[0] == -9) ASSERT(v[1] == 3) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec2_abs) { ivec2 v1 = {2, -3}, v2 = {-12, -31}; ivec2 v3, v4; GLM(ivec2_abs)(v1, v3); GLM(ivec2_abs)(v2, v4); ASSERT(v3[0] == 2) ASSERT(v3[1] == 3) ASSERT(v4[0] == 12) ASSERT(v4[1] == 31) TEST_SUCCESS } cglm-0.9.7/test/src/test_ivec3.h000066400000000000000000000244761526744317200164700ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" TEST_IMPL(GLM_PREFIX, ivec3) { ivec4 v4 = {2, 3, 5, 7}; ivec3 v3 = {99, 99, 99}; GLM(ivec3)(v4, v3); ASSERT(v3[0] == 2) ASSERT(v3[1] == 3) ASSERT(v3[2] == 5) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_copy) { ivec3 src = {7, 5, 2}; ivec3 dst = {99, 99, 99}; GLM(ivec3_copy)(src, dst); ASSERT(dst[0] == 7) ASSERT(dst[1] == 5) ASSERT(dst[2] == 2) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_zero) { ivec3 v = {2, 3, 5}; GLM(ivec3_zero)(v); ASSERT(v[0] == 0) ASSERT(v[1] == 0) ASSERT(v[2] == 0) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_one) { ivec3 v = {-2, 9, 12}; GLM(ivec3_one)(v); ASSERT(v[0] == 1) ASSERT(v[1] == 1) ASSERT(v[2] == 1) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_dot) { ivec3 a = {2, 3, 1}; ivec3 b = {4, 4, 2}; int dot1, dot2; dot1 = GLM(ivec3_dot)(a, b); dot2 = a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; ASSERT(dot1 == dot2) ASSERT(dot1 == 22) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_norm2) { ivec3 v = {2, 3, 4}; int norm2_1, norm2_2; norm2_1 = GLM(ivec3_norm2)(v); norm2_2 = v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; ASSERT(norm2_1 == norm2_2) ASSERT(norm2_1 == 29) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_norm) { ivec3 v = {2, 3, 4}; int norm1, norm2; norm1 = GLM(ivec3_norm)(v); norm2 = (int)sqrtf((float)(v[0] * v[0] + v[1] * v[1] + v[2] * v[2])); ASSERT(norm1 == norm2) ASSERT(norm1 == 5) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_add) { ivec3 a = {14, 3, 2}; ivec3 b = {-3, 2, 1}; ivec3 v = {99, 99, 99}; GLM(ivec3_add)(a, b, v); ASSERT(v[0] == 11) ASSERT(v[1] == 5) ASSERT(v[2] == 3) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_adds) { ivec3 a = {-3, 1, 4}; ivec3 v = {99, 99, 99}; int s = 2; GLM(ivec3_adds)(a, s, v); ASSERT(v[0] == -1) ASSERT(v[1] == 3) ASSERT(v[2] == 6) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_sub) { ivec3 a = {-2, 9, 1}; ivec3 b = {3, 2, -1}; ivec3 v = {99, 99, 99}; GLM(ivec3_sub)(a, b, v); ASSERT(v[0] == -5) ASSERT(v[1] == 7) ASSERT(v[2] == 2) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_subs) { ivec3 a = {5, -2, 6}; ivec3 v = {99, 99, 99}; int s = -3; GLM(ivec3_subs)(a, s, v); ASSERT(v[0] == 8) ASSERT(v[1] == 1) ASSERT(v[2] == 9) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_mul) { ivec3 a = {3, 4, 5}; ivec3 b = {-2, 3, 1}; ivec3 v = {99, 99, 99}; GLM(ivec3_mul)(a, b, v); ASSERT(v[0] == -6) ASSERT(v[1] == 12) ASSERT(v[2] == 5) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_scale) { ivec3 a = {-9, 2, 3}; ivec3 v = {99, 99, 99}; int s = -2; GLM(ivec3_scale)(a, s, v); ASSERT(v[0] == 18) ASSERT(v[1] == -4) ASSERT(v[2] == -6) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_div) { ivec3 v1 = {6, 5, 8}, v2 = {-2, 4, 2}, v3; GLM(ivec3_div)(v1, v2, v3); ASSERT(v1[0] / v2[0] == v3[0]) ASSERT(v1[1] / v2[1] == v3[1]) ASSERT(v1[2] / v2[2] == v3[2]) ASSERT(v3[0] == -3) ASSERT(v3[1] == 1) ASSERT(v3[2] == 4) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_divs) { ivec3 v1 = {16, -8, 12}, v2; int s = 4; GLM(ivec3_divs)(v1, s, v2); ASSERT(v1[0] / s == v2[0]) ASSERT(v1[1] / s == v2[1]) ASSERT(v1[2] / s == v2[2]) ASSERT(v2[0] == 4) ASSERT(v2[1] == -2) ASSERT(v2[2] == 3) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_mod) { ivec3 a = {16, -8, 10}; ivec3 b = {3, 5, 4}; ivec3 dest; GLM(ivec3_mod)(a, b, dest); ASSERT(a[0] % b[0] == dest[0]) ASSERT(a[1] % b[1] == dest[1]) ASSERT(a[2] % b[2] == dest[2]) ASSERT(dest[0] == 1) ASSERT(dest[1] == -3) ASSERT(dest[2] == 2) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_addadd) { ivec3 a = {2, -3, 8}, b = {-3, 4, 5}, c = {1, 2, 6}, d = {1, 2, 6}; GLM(ivec3_addadd)(a, b, c); ASSERT(d[0] + a[0] + b[0] == c[0]) ASSERT(d[1] + a[1] + b[1] == c[1]) ASSERT(d[2] + a[2] + b[2] == c[2]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_addadds) { ivec3 a = {2, -3, 5}, c = {1, 2, -9}, d = {1, 2, -9}; int s = 9; GLM(ivec3_addadds)(a, s, c); ASSERT(d[0] + a[0] + s == c[0]) ASSERT(d[1] + a[1] + s == c[1]) ASSERT(d[2] + a[2] + s == c[2]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_subadd) { ivec3 a = {2, -3, 8}, b = {-3, 4, 5}, c = {1, 2, 6}, d = {1, 2, 6}; GLM(ivec3_subadd)(a, b, c); ASSERT(d[0] + a[0] - b[0] == c[0]) ASSERT(d[1] + a[1] - b[1] == c[1]) ASSERT(d[2] + a[2] - b[2] == c[2]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_subadds) { ivec3 a = {2, -3, 5}, c = {1, 2, -9}, d = {1, 2, -9}; int s = 9; GLM(ivec3_subadds)(a, s, c); ASSERT(d[0] + a[0] - s == c[0]) ASSERT(d[1] + a[1] - s == c[1]) ASSERT(d[2] + a[2] - s == c[2]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_muladd) { ivec3 a = {2, -3, 8}, b = {-3, 4, 5}, c = {1, 2, 6}, d = {1, 2, 6}; GLM(ivec3_muladd)(a, b, c); ASSERT(d[0] + a[0] * b[0] == c[0]) ASSERT(d[1] + a[1] * b[1] == c[1]) ASSERT(d[2] + a[2] * b[2] == c[2]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_muladds) { ivec3 a = {2, -3, 5}, c = {1, 2, -9}, d = {1, 2, -9}; int s = 9; GLM(ivec3_muladds)(a, s, c); ASSERT(d[0] + a[0] * s == c[0]) ASSERT(d[1] + a[1] * s == c[1]) ASSERT(d[2] + a[2] * s == c[2]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_maxadd) { ivec3 a = {2, -3, 8}, b = {-3, 4, 5}, c = {1, 2, 6}, d = {1, 2, 6}; GLM(ivec3_maxadd)(a, b, c); ASSERT(d[0] += glm_imax(a[0], b[0]) == c[0]) ASSERT(d[1] += glm_imax(a[1], b[1]) == c[1]) ASSERT(d[2] += glm_imax(a[2], b[2]) == c[2]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_minadd) { ivec3 a = {2, -3, 8}, b = {-3, 4, 5}, c = {1, 2, 6}, d = {1, 2, 6}; GLM(ivec3_minadd)(a, b, c); ASSERT(d[0] += glm_imin(a[0], b[0]) == c[0]) ASSERT(d[1] += glm_imin(a[1], b[1]) == c[1]) ASSERT(d[2] += glm_imin(a[2], b[2]) == c[2]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_subsub) { ivec3 a = {2, -3, 8}, b = {-3, 4, 5}, c = {1, 2, 6}, d = {1, 2, 6}; GLM(ivec3_subsub)(a, b, c); ASSERT(d[0] - (a[0] - b[0]) == c[0]) ASSERT(d[1] - (a[1] - b[1]) == c[1]) ASSERT(d[2] - (a[2] - b[2]) == c[2]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_subsubs) { ivec3 a = {2, -3, 5}, c = {1, 2, -9}, d = {1, 2, -9}; int s = 9; GLM(ivec3_subsubs)(a, s, c); ASSERT(d[0] - (a[0] - s) == c[0]) ASSERT(d[1] - (a[1] - s) == c[1]) ASSERT(d[2] - (a[2] - s) == c[2]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_addsub) { ivec3 a = {2, -3, 8}, b = {-3, 4, 5}, c = {1, 2, 6}, d = {1, 2, 6}; GLM(ivec3_addsub)(a, b, c); ASSERT(d[0] - (a[0] + b[0]) == c[0]) ASSERT(d[1] - (a[1] + b[1]) == c[1]) ASSERT(d[2] - (a[2] + b[2]) == c[2]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_addsubs) { ivec3 a = {2, -3, 5}, c = {1, 2, -9}, d = {1, 2, -9}; int s = 9; GLM(ivec3_addsubs)(a, s, c); ASSERT(d[0] - (a[0] + s) == c[0]) ASSERT(d[1] - (a[1] + s) == c[1]) ASSERT(d[2] - (a[2] + s) == c[2]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_mulsub) { ivec3 a = {2, -3, 8}, b = {-3, 4, 5}, c = {1, 2, 6}, d = {1, 2, 6}; GLM(ivec3_mulsub)(a, b, c); ASSERT(d[0] - a[0] * b[0] == c[0]) ASSERT(d[1] - a[1] * b[1] == c[1]) ASSERT(d[2] - a[2] * b[2] == c[2]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_mulsubs) { ivec3 a = {2, -3, 5}, c = {1, 2, -9}, d = {1, 2, -9}; int s = 9; GLM(ivec3_mulsubs)(a, s, c); ASSERT(d[0] - a[0] * s == c[0]) ASSERT(d[1] - a[1] * s == c[1]) ASSERT(d[2] - a[2] * s == c[2]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_maxsub) { ivec3 a = {2, -3, 8}, b = {-3, 4, 5}, c = {1, 2, 6}, d = {1, 2, 6}; GLM(ivec3_maxsub)(a, b, c); ASSERT(d[0] -= glm_imax(a[0], b[0]) == c[0]) ASSERT(d[1] -= glm_imax(a[1], b[1]) == c[1]) ASSERT(d[2] -= glm_imax(a[2], b[2]) == c[2]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_minsub) { ivec3 a = {2, -3, 8}, b = {-3, 4, 5}, c = {1, 2, 6}, d = {1, 2, 6}; GLM(ivec3_minsub)(a, b, c); ASSERT(d[0] -= glm_imin(a[0], b[0]) == c[0]) ASSERT(d[1] -= glm_imin(a[1], b[1]) == c[1]) ASSERT(d[2] -= glm_imin(a[2], b[2]) == c[2]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_distance2) { ivec3 a = {-1, 3, 0}; ivec3 b = {5, 4, 2}; int v; v = GLM(ivec3_distance2)(a, b); ASSERT(v == 41) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_distance) { ivec3 a = {3, 2, 4}; ivec3 b = {-2, 5, 2}; float v; v = GLM(ivec3_distance)(a, b); ASSERT(test_eq(v, 6.1644140029f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_fill) { ivec3 v1; ivec3 v2 = {-1, 3, 4}; GLM(ivec3_fill)(v1, 1); GLM(ivec3_fill)(v2, 2); ASSERT(GLM(ivec3_eq)(v1, 1)) ASSERT(GLM(ivec3_eq)(v2, 2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_eq) { ivec3 v1 = { -1, 2, 4 }; GLM(ivec3_fill)(v1, 2); ASSERT(GLM(ivec3_eq)(v1, 2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_eqv) { ivec3 v1, v2, v3; GLM(ivec3_fill)(v1, 1); GLM(ivec3_fill)(v2, 2); GLM(ivec3_fill)(v3, 1); ASSERT(GLM(ivec3_eqv)(v1, v3)) ASSERT(!GLM(ivec3_eqv)(v1, v2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_maxv) { ivec3 a = {9, -20, 5}; ivec3 b = {8, -1, 2}; ivec3 v = {99, 99, 99}; GLM(ivec3_maxv)(a, b, v); ASSERT(v[0] == 9) ASSERT(v[1] == -1) ASSERT(v[2] == 5) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_minv) { ivec3 a = {16, 0, 4}; ivec3 b = {-15, 10, 8}; ivec3 v = {99, 99, 99}; GLM(ivec3_minv)(a, b, v); ASSERT(v[0] == -15) ASSERT(v[1] == 0) ASSERT(v[2] == 4) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_clamp) { ivec3 v = {3, -1, 10}; GLM(ivec3_clamp)(v, -2, 4); ASSERT(v[0] == 3) ASSERT(v[1] == -1) ASSERT(v[2] == 4) v[0] = -15; v[1] = 4; v[2] = 1; GLM(ivec3_clamp)(v, -9, 3); ASSERT(v[0] == -9) ASSERT(v[1] == 3) ASSERT(v[2] == 1) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec3_abs) { ivec3 v1 = {2, -3, 4}, v2 = {-12, -31, -42}; ivec3 v3, v4; GLM(ivec3_abs)(v1, v3); GLM(ivec3_abs)(v2, v4); ASSERT(v3[0] == 2) ASSERT(v3[1] == 3) ASSERT(v3[2] == 4) ASSERT(v4[0] == 12) ASSERT(v4[1] == 31) ASSERT(v4[2] == 42) TEST_SUCCESS } cglm-0.9.7/test/src/test_ivec4.h000066400000000000000000000226151526744317200164620ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" TEST_IMPL(GLM_PREFIX, ivec4) { ivec4 v3 = {2, 3, 5}; ivec4 v4; GLM(ivec4)(v3, 7, v4); ASSERT(v4[0] == 2) ASSERT(v4[1] == 3) ASSERT(v4[2] == 5) ASSERT(v4[3] == 7) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_copy) { ivec4 src = {7, 5, 2, 11}; ivec4 dst = {99, 99, 99, 99}; GLM(ivec4_copy)(src, dst); ASSERT(dst[0] == 7) ASSERT(dst[1] == 5) ASSERT(dst[2] == 2) ASSERT(dst[3] == 11) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_zero) { ivec4 v = {2, 3, 5, 7}; GLM(ivec4_zero)(v); ASSERT(v[0] == 0) ASSERT(v[1] == 0) ASSERT(v[2] == 0) ASSERT(v[3] == 0) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_one) { ivec4 v = {-2, 9, 12, 7}; GLM(ivec4_one)(v); ASSERT(v[0] == 1) ASSERT(v[1] == 1) ASSERT(v[2] == 1) ASSERT(v[3] == 1) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_add) { ivec4 a = {14, 3, 2, -4}; ivec4 b = {-3, 2, 1, -1}; ivec4 v = {99, 99, 99, 99}; GLM(ivec4_add)(a, b, v); ASSERT(v[0] == 11) ASSERT(v[1] == 5) ASSERT(v[2] == 3) ASSERT(v[3] == -5) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_adds) { ivec4 a = {-3, 1, 4, 2}; ivec4 v = {99, 99, 99, 99}; int s = -2; GLM(ivec4_adds)(a, s, v); ASSERT(v[0] == -5) ASSERT(v[1] == -1) ASSERT(v[2] == 2) ASSERT(v[3] == 0) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_sub) { ivec4 a = {-2, 9, 1, 5}; ivec4 b = {3, 2, -1, 2}; ivec4 v = {99, 99, 99, 99}; GLM(ivec4_sub)(a, b, v); ASSERT(v[0] == -5) ASSERT(v[1] == 7) ASSERT(v[2] == 2) ASSERT(v[3] == 3) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_subs) { ivec4 a = {5, -2, 6, 1}; ivec4 v = {99, 99, 99, 99}; int s = 2; GLM(ivec4_subs)(a, s, v); ASSERT(v[0] == 3) ASSERT(v[1] == -4) ASSERT(v[2] == 4) ASSERT(v[3] == -1) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_mul) { ivec4 a = {3, 4, 5, -3}; ivec4 b = {-2, 3, 1, 2}; ivec4 v = {99, 99, 99, 99}; GLM(ivec4_mul)(a, b, v); ASSERT(v[0] == -6) ASSERT(v[1] == 12) ASSERT(v[2] == 5) ASSERT(v[3] == -6) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_scale) { ivec4 a = {-9, 2, 3, 0}; ivec4 v = {99, 99, 99, 99}; int s = -2; GLM(ivec4_scale)(a, s, v); ASSERT(v[0] == 18) ASSERT(v[1] == -4) ASSERT(v[2] == -6) ASSERT(v[3] == 0) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_addadd) { ivec4 a = {2, -3, 8, -7}, b = {-3, 4, 5, -2}, c = {1, 2, 6, 15}, d = {1, 2, 6, 15}; GLM(ivec4_addadd)(a, b, c); ASSERT(d[0] + a[0] + b[0] == c[0]) ASSERT(d[1] + a[1] + b[1] == c[1]) ASSERT(d[2] + a[2] + b[2] == c[2]) ASSERT(d[3] + a[3] + b[3] == c[3]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_addadds) { ivec4 a = {2, -3, 4, 7}, c = {1, 2, -8, 5}, d = {1, 2, -8, 5}; int s = 9; GLM(ivec4_addadds)(a, s, c); ASSERT(d[0] + a[0] + s == c[0]) ASSERT(d[1] + a[1] + s == c[1]) ASSERT(d[2] + a[2] + s == c[2]) ASSERT(d[3] + a[3] + s == c[3]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_subadd) { ivec4 a = {2, -3, 8, -7}, b = {-3, 4, 5, -2}, c = {1, 2, 6, 15}, d = {1, 2, 6, 15}; GLM(ivec4_subadd)(a, b, c); ASSERT(d[0] + a[0] - b[0] == c[0]) ASSERT(d[1] + a[1] - b[1] == c[1]) ASSERT(d[2] + a[2] - b[2] == c[2]) ASSERT(d[3] + a[3] - b[3] == c[3]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_subadds) { ivec4 a = {2, -3, 4, 7}, c = {1, 2, -8, 5}, d = {1, 2, -8, 5}; int s = 9; GLM(ivec4_subadds)(a, s, c); ASSERT(d[0] + a[0] - s == c[0]) ASSERT(d[1] + a[1] - s == c[1]) ASSERT(d[2] + a[2] - s == c[2]) ASSERT(d[3] + a[3] - s == c[3]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_muladd) { ivec4 a = {2, -3, 8, -7}, b = {-3, 4, 5, -2}, c = {1, 2, 6, 15}, d = {1, 2, 6, 15}; GLM(ivec4_muladd)(a, b, c); ASSERT(d[0] + a[0] * b[0] == c[0]) ASSERT(d[1] + a[1] * b[1] == c[1]) ASSERT(d[2] + a[2] * b[2] == c[2]) ASSERT(d[3] + a[3] * b[3] == c[3]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_muladds) { ivec4 a = {2, -3, 4, 7}, c = {1, 2, -8, 5}, d = {1, 2, -8, 5}; int s = 9; GLM(ivec4_muladds)(a, s, c); ASSERT(d[0] + a[0] * s == c[0]) ASSERT(d[1] + a[1] * s == c[1]) ASSERT(d[2] + a[2] * s == c[2]) ASSERT(d[3] + a[3] * s == c[3]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_maxadd) { ivec4 a = {2, -3, 8, -7}, b = {-3, 4, 5, -2}, c = {1, 2, 6, 15}, d = {1, 2, 6, 15}; GLM(ivec4_maxadd)(a, b, c); ASSERT(d[0] += glm_imax(a[0], b[0]) == c[0]) ASSERT(d[1] += glm_imax(a[1], b[1]) == c[1]) ASSERT(d[2] += glm_imax(a[2], b[2]) == c[2]) ASSERT(d[3] += glm_imax(a[3], b[3]) == c[3]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_minadd) { ivec4 a = {2, -3, 8, -7}, b = {-3, 4, 5, -2}, c = {1, 2, 6, 15}, d = {1, 2, 6, 15}; GLM(ivec4_minadd)(a, b, c); ASSERT(d[0] += glm_imin(a[0], b[0]) == c[0]) ASSERT(d[1] += glm_imin(a[1], b[1]) == c[1]) ASSERT(d[2] += glm_imin(a[2], b[2]) == c[2]) ASSERT(d[3] += glm_imin(a[3], b[3]) == c[3]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_subsub) { ivec4 a = {2, -3, 8, -7}, b = {-3, 4, 5, -2}, c = {1, 2, 6, 15}, d = {1, 2, 6, 15}; GLM(ivec4_subsub)(a, b, c); ASSERT(d[0] - (a[0] - b[0]) == c[0]) ASSERT(d[1] - (a[1] - b[1]) == c[1]) ASSERT(d[2] - (a[2] - b[2]) == c[2]) ASSERT(d[3] - (a[3] - b[3]) == c[3]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_subsubs) { ivec4 a = {2, -3, 4, 7}, c = {1, 2, -8, 5}, d = {1, 2, -8, 5}; int s = 9; GLM(ivec4_subsubs)(a, s, c); ASSERT(d[0] - (a[0] - s) == c[0]) ASSERT(d[1] - (a[1] - s) == c[1]) ASSERT(d[2] - (a[2] - s) == c[2]) ASSERT(d[3] - (a[3] - s) == c[3]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_addsub) { ivec4 a = {2, -3, 8, -7}, b = {-3, 4, 5, -2}, c = {1, 2, 6, 15}, d = {1, 2, 6, 15}; GLM(ivec4_addsub)(a, b, c); ASSERT(d[0] - (a[0] + b[0]) == c[0]) ASSERT(d[1] - (a[1] + b[1]) == c[1]) ASSERT(d[2] - (a[2] + b[2]) == c[2]) ASSERT(d[3] - (a[3] + b[3]) == c[3]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_addsubs) { ivec4 a = {2, -3, 4, 7}, c = {1, 2, -8, 5}, d = {1, 2, -8, 5}; int s = 9; GLM(ivec4_addsubs)(a, s, c); ASSERT(d[0] - (a[0] + s) == c[0]) ASSERT(d[1] - (a[1] + s) == c[1]) ASSERT(d[2] - (a[2] + s) == c[2]) ASSERT(d[3] - (a[3] + s) == c[3]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_mulsub) { ivec4 a = {2, -3, 8, -7}, b = {-3, 4, 5, -2}, c = {1, 2, 6, 15}, d = {1, 2, 6, 15}; GLM(ivec4_mulsub)(a, b, c); ASSERT(d[0] - a[0] * b[0] == c[0]) ASSERT(d[1] - a[1] * b[1] == c[1]) ASSERT(d[2] - a[2] * b[2] == c[2]) ASSERT(d[3] - a[3] * b[3] == c[3]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_mulsubs) { ivec4 a = {2, -3, 4, 7}, c = {1, 2, -8, 5}, d = {1, 2, -8, 5}; int s = 9; GLM(ivec4_mulsubs)(a, s, c); ASSERT(d[0] - a[0] * s == c[0]) ASSERT(d[1] - a[1] * s == c[1]) ASSERT(d[2] - a[2] * s == c[2]) ASSERT(d[3] - a[3] * s == c[3]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_maxsub) { ivec4 a = {2, -3, 8, -7}, b = {-3, 4, 5, -2}, c = {1, 2, 6, 15}, d = {1, 2, 6, 15}; GLM(ivec4_maxsub)(a, b, c); ASSERT(d[0] -= glm_imax(a[0], b[0]) == c[0]) ASSERT(d[1] -= glm_imax(a[1], b[1]) == c[1]) ASSERT(d[2] -= glm_imax(a[2], b[2]) == c[2]) ASSERT(d[3] -= glm_imax(a[3], b[3]) == c[3]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_minsub) { ivec4 a = {2, -3, 8, -7}, b = {-3, 4, 5, -2}, c = {1, 2, 6, 15}, d = {1, 2, 6, 15}; GLM(ivec4_minsub)(a, b, c); ASSERT(d[0] -= glm_imin(a[0], b[0]) == c[0]) ASSERT(d[1] -= glm_imin(a[1], b[1]) == c[1]) ASSERT(d[2] -= glm_imin(a[2], b[2]) == c[2]) ASSERT(d[3] -= glm_imin(a[3], b[3]) == c[3]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_distance2) { ivec4 a = {-1, 3, 0, 4}; ivec4 b = {5, 4, 2, 6}; int v; v = GLM(ivec4_distance2)(a, b); ASSERT(v == 45) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_distance) { ivec4 a = {3, 2, 4, -1}; ivec4 b = {-2, 5, 2, 4}; float v; v = GLM(ivec4_distance)(a, b); ASSERT(test_eq(v, 7.9372539331f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_maxv) { ivec4 a = {9, -20, 5, -3}; ivec4 b = {8, -1, 2, 2}; ivec4 v = {99, 99, 99, 99}; GLM(ivec4_maxv)(a, b, v); ASSERT(v[0] == 9) ASSERT(v[1] == -1) ASSERT(v[2] == 5) ASSERT(v[3] == 2) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_minv) { ivec4 a = {16, 0, 4, 5}; ivec4 b = {-15, 10, 8, 2}; ivec4 v = {99, 99, 99, 99}; GLM(ivec4_minv)(a, b, v); ASSERT(v[0] == -15) ASSERT(v[1] == 0) ASSERT(v[2] == 4) ASSERT(v[3] == 2) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_clamp) { ivec4 v = {3, -1, 10, -100}; GLM(ivec4_clamp)(v, -2, 4); ASSERT(v[0] == 3) ASSERT(v[1] == -1) ASSERT(v[2] == 4) ASSERT(v[3] == -2) v[0] = -15; v[1] = 4; v[2] = 1; v[3] = 0; GLM(ivec4_clamp)(v, -9, 3); ASSERT(v[0] == -9) ASSERT(v[1] == 3) ASSERT(v[2] == 1) ASSERT(v[3] == 0) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ivec4_abs) { ivec4 v1 = {2, -3, 4, -5}, v2 = {-12, -31, -42, -50}; ivec4 v3, v4; GLM(ivec4_abs)(v1, v3); GLM(ivec4_abs)(v2, v4); ASSERT(v3[0] == 2) ASSERT(v3[1] == 3) ASSERT(v3[2] == 4) ASSERT(v3[3] == 5) ASSERT(v4[0] == 12) ASSERT(v4[1] == 31) ASSERT(v4[2] == 42) ASSERT(v4[3] == 50) TEST_SUCCESS } cglm-0.9.7/test/src/test_mat2.h000066400000000000000000000131411526744317200163050ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" #define A_MATRIX2x2 {{1,2},{5,6}} #define MAT2_ARRAY {1, 5, 2, 7} #ifndef CGLM_TEST_MAT2_ONCE #define CGLM_TEST_MAT2_ONCE TEST_IMPL(MACRO_GLM_MAT2_IDENTITY_INIT) { mat2 m = GLM_MAT2_IDENTITY_INIT; ASSERT(test_eq(m[0][0], 1.0f)) ASSERT(test_eq(m[0][1], 0.0f)) ASSERT(test_eq(m[1][0], 0.0f)) ASSERT(test_eq(m[1][1], 1.0f)) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_MAT2_ZERO_INIT) { mat2 m = GLM_MAT2_ZERO_INIT; ASSERT(test_eq(m[0][0], 0.0f)) ASSERT(test_eq(m[0][1], 0.0f)) ASSERT(test_eq(m[1][0], 0.0f)) ASSERT(test_eq(m[1][1], 0.0f)) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_MAT2_IDENTITY) { ASSERT(test_eq(GLM_MAT2_IDENTITY[0][0], 1.0f)) ASSERT(test_eq(GLM_MAT2_IDENTITY[0][1], 0.0f)) ASSERT(test_eq(GLM_MAT2_IDENTITY[1][0], 0.0f)) ASSERT(test_eq(GLM_MAT2_IDENTITY[1][1], 1.0f)) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_MAT2_ZERO) { ASSERT(test_eq(GLM_MAT2_ZERO[0][0], 0.0f)) ASSERT(test_eq(GLM_MAT2_ZERO[0][1], 0.0f)) ASSERT(test_eq(GLM_MAT2_ZERO[1][0], 0.0f)) ASSERT(test_eq(GLM_MAT2_ZERO[1][1], 0.0f)) TEST_SUCCESS } #endif /* CGLM_TEST_MAT2_ONCE */ TEST_IMPL(GLM_PREFIX, mat2_copy) { mat2 m1 = A_MATRIX2x2; mat2 m2 = GLM_MAT2_IDENTITY_INIT; GLM(mat2_copy)(m1, m2); test_assert_mat2_eq(m1, m2); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2_identity) { mat2 m1 = GLM_MAT2_IDENTITY_INIT; mat2 m2 = GLM_MAT2_IDENTITY_INIT; mat2 m3; GLM(mat2_identity)(m3); ASSERTIFY(test_assert_mat2_eq_identity(m1)) ASSERTIFY(test_assert_mat2_eq_identity(m2)) ASSERTIFY(test_assert_mat2_eq_identity(m3)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2_identity_array) { size_t i, count; mat2 matrices[4] = { A_MATRIX2x2, A_MATRIX2x2, A_MATRIX2x2, A_MATRIX2x2 }; count = 4; GLM(mat2_identity_array)(matrices, count); for (i = 0; i < count; i++) { ASSERTIFY(test_assert_mat2_eq_identity(matrices[i])) } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2_zero) { mat2 m1 = GLM_MAT2_ZERO_INIT; mat2 m2 = GLM_MAT2_ZERO_INIT; mat2 m3; GLM(mat2_zero)(m3); ASSERTIFY(test_assert_mat2_eq_zero(m1)) ASSERTIFY(test_assert_mat2_eq_zero(m2)) ASSERTIFY(test_assert_mat2_eq_zero(m3)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2_mul) { mat2 m1 = GLM_MAT2_IDENTITY_INIT; mat2 m2 = GLM_MAT2_IDENTITY_INIT; mat2 m3; mat2 m4 = GLM_MAT2_ZERO_INIT; int i, j, k; /* test random matrices */ /* random matrices */ test_rand_mat2(m1); test_rand_mat2(m2); GLM(mat2_mul)(m1, m2, m3); for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) { for (k = 0; k < 2; k++) /* column-major */ m4[i][j] += m1[k][j] * m2[i][k]; } } ASSERTIFY(test_assert_mat2_eq(m3, m4)) /* test pre compiled */ GLM(mat2_mul)(m1, m2, m3); ASSERTIFY(test_assert_mat2_eq(m3, m4)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2_transpose_to) { mat2 mat = A_MATRIX2x2; mat2 m1; GLM(mat2_transpose_to)(mat, m1); ASSERTIFY(test_assert_mat2_eqt(mat, m1)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2_transpose) { mat2 mat = A_MATRIX2x2; mat2 m1; GLM(mat2_copy)(mat, m1); GLM(mat2_transpose)(m1); ASSERTIFY(test_assert_mat2_eqt(mat, m1)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2_mulv) { vec2 res; mat2 mat = A_MATRIX2x2; vec2 v = {11.0f, 21.0f}; int i; GLM(mat2_mulv)(mat, v, res); for (i = 0; i < 2; i++) { ASSERT(test_eq(res[i], v[0] * mat[0][i] + v[1] * mat[1][i])) } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2_trace) { mat2 mat = A_MATRIX2x2; float trace; trace = GLM(mat2_trace)(mat); ASSERT(test_eq(trace, mat[0][0] + mat[1][1])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2_scale) { mat2 m1 = A_MATRIX2x2; mat2 m2 = A_MATRIX2x2; int i, j; float scale; scale = (float)(rand() % 100); GLM(mat2_scale)(m1, scale); for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) { ASSERT(test_eq(m1[i][j], m2[i][j] * scale)) } } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2_det) { TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2_inv) { mat2 m1 = GLM_MAT2_IDENTITY_INIT; mat2 m2 = GLM_MAT2_IDENTITY_INIT; mat2 m3; int i; m1[0][0] = 41.0f; m1[0][1] = 0.0f; m1[1][0] = 0.0f; m1[1][1] = 70.0f; for (i = 0; i < 10000; i++) { /* test inverse precise */ GLM(mat2_inv)(m1, m2); GLM(mat2_inv)(m2, m3); ASSERTIFY(test_assert_mat2_eq(m1, m3)) } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2_swap_col) { mat2 m1 = A_MATRIX2x2; mat2 m2 = A_MATRIX2x2; GLM(mat2_swap_col)(m1, 0, 1); ASSERTIFY(test_assert_vec2_eq(m1[0], m2[1])) ASSERTIFY(test_assert_vec2_eq(m1[1], m2[0])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2_swap_row) { mat2 m1 = A_MATRIX2x2; mat2 m2 = A_MATRIX2x2; GLM(mat2_swap_row)(m1, 0, 1); ASSERT(test_eq(m1[0][0], m2[0][1])) ASSERT(test_eq(m1[0][1], m2[0][0])) ASSERT(test_eq(m1[1][0], m2[1][1])) ASSERT(test_eq(m1[1][1], m2[1][0])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2_rmc) { mat2 mat = A_MATRIX2x2; vec2 v = {11.0f, 12.0f}; vec2 v1; float r1, r2; int i; r1 = GLM(mat2_rmc)(v, mat, v); for (i = 0; i < 2; i++) { v1[i] = v[0] * mat[i][0] + v[1] * mat[i][1]; } r2 = v[0] * v1[0] + v[1] * v1[1]; ASSERT(test_eq(r1, r2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2_make) { mat2 dest; unsigned int i, j; float src[4] = MAT2_ARRAY; GLM(mat2_make)(src, dest); for (i = 0, j = 0; i < sizeof(src) / sizeof(float); i+=2, j++) { ASSERT(test_eq(dest[j][0], src[i])) ASSERT(test_eq(dest[j][1], src[i+1])) } TEST_SUCCESS } #undef A_MATRIX2x2 cglm-0.9.7/test/src/test_mat2x3.h000066400000000000000000000061541526744317200165660ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" #define A_MATRIX2X3 {{1,2,3},{5,6,7}} #define A_MATRIX2X3_TRANSPOSE {{1,5}, {2,6}, {3,7}} #ifndef CGLM_TEST_MAT2X3_ONCE #define CGLM_TEST_MAT2X3_ONCE TEST_IMPL(MACRO_GLM_MAT2X3_ZERO_INIT) { mat2x3 mat2x3_zero = GLM_MAT2X3_ZERO_INIT; test_assert_mat2x3_eq_zero(mat2x3_zero); TEST_SUCCESS } TEST_IMPL(MACRO_GLM_MAT2X3_ZERO) { mat2x3 mat2x3_zero = GLM_MAT2X3_ZERO; test_assert_mat2x3_eq_zero(mat2x3_zero); TEST_SUCCESS } #endif /* CGLM_TEST_MAT2X3_ONCE */ TEST_IMPL(GLM_PREFIX, mat2x3_copy) { mat2x3 m1 = A_MATRIX2X3; mat2x3 m2 = GLM_MAT2X3_ZERO_INIT; GLM(mat2x3_copy)(m1, m2); test_assert_mat2x3_eq(m1, m2); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2x3_zero) { mat2x3 m1 = GLM_MAT2X3_ZERO_INIT; mat2x3 m2 = GLM_MAT2X3_ZERO_INIT; mat2x3 m3; GLM(mat2x3_zero)(m3); ASSERTIFY(test_assert_mat2x3_eq_zero(m1)) ASSERTIFY(test_assert_mat2x3_eq_zero(m2)) ASSERTIFY(test_assert_mat2x3_eq_zero(m3)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2x3_make) { float src[18] = { 0.5f, 1.7f, 10.3f, 4.2f, 8.9f, 1.1f, 2.3f, 4.2f, 66.5f, 23.7f, 6.6f, 8.9f, 5.3f, 4.8f, 96.3f, 13.7f, 4.7f, 5.5f }; mat2x3 dest[3]; float *srcp = src; unsigned int i, j, k; for (i = 0, j = 0, k = 0; i < sizeof(src) / sizeof(float); i+=6,j++) { GLM(mat2x3_make)(srcp + i, dest[j]); ASSERT(test_eq(src[ i ], dest[j][k][0])); ASSERT(test_eq(src[i+1], dest[j][k][1])); ASSERT(test_eq(src[i+2], dest[j][k][2])); ASSERT(test_eq(src[i+3], dest[j][k+1][0])); ASSERT(test_eq(src[i+4], dest[j][k+1][1])); ASSERT(test_eq(src[i+5], dest[j][k+1][2])); } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2x3_mul) { mat2x3 m1 = GLM_MAT2X3_ZERO_INIT; mat3x2 m2 = GLM_MAT3X2_ZERO_INIT; mat3 m3 = GLM_MAT3_ZERO_INIT; mat3 m4 = GLM_MAT3_ZERO_INIT; int c, r, k; /* test random matrices */ /* random matrices */ test_rand_mat2x3(m1); test_rand_mat3x2(m2); for (r = 0; r < 3; r++) { for (c = 0; c < 3; c++) { for (k = 0; k < 2; k++) { m4[c][r] += m1[k][r] * m2[c][k]; } } } GLM(mat2x3_mul)(m1, m2, m3); ASSERTIFY(test_assert_mat3_eq(m3, m4)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2x3_mulv) { mat2x3 mat = A_MATRIX2X3; vec2 v = {11.0f, 21.0f}; int i; vec3 dest; float res = 0.0; GLM(mat2x3_mulv)(mat, v, dest); for (i = 0; i < 3; i++) { res = mat[0][i] * v[0] + mat[1][i] * v[1]; ASSERT(test_eq(dest[i], res)) } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2x3_transpose) { mat2x3 m1 = A_MATRIX2X3; mat3x2 m2; mat3x2 m3 = A_MATRIX2X3_TRANSPOSE; GLM(mat2x3_transpose)(m1, m2); ASSERTIFY(test_assert_mat3x2_eq(m2, m3)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2x3_scale) { mat2x3 m1 = A_MATRIX2X3; mat2x3 m2 = A_MATRIX2X3; int i, j; float scale; scale = (float)(rand() % 100); GLM(mat2x3_scale)(m1, scale); for (i = 0; i < 2; i++) { for (j = 0; j < 3; j++) { ASSERT(test_eq(m1[i][j], m2[i][j] * scale)) } } TEST_SUCCESS } cglm-0.9.7/test/src/test_mat2x4.h000066400000000000000000000063731526744317200165720ustar00rootroot00000000000000 /* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" #define A_MATRIX2X4 {{1,2,3,4},{5,6,7,8}} #define A_MATRIX2X4_TRANSPOSE {{1,5}, {2,6}, {3,7}, {4,8}} #ifndef CGLM_TEST_MAT2X4_ONCE #define CGLM_TEST_MAT2X4_ONCE TEST_IMPL(MACRO_GLM_MAT2X4_ZERO_INIT) { mat2x4 mat2x4_zero = GLM_MAT2X4_ZERO_INIT; test_assert_mat2x4_eq_zero(mat2x4_zero); TEST_SUCCESS } TEST_IMPL(MACRO_GLM_MAT2X4_ZERO) { mat2x4 mat2x4_zero = GLM_MAT2X4_ZERO; test_assert_mat2x4_eq_zero(mat2x4_zero); TEST_SUCCESS } #endif /* CGLM_TEST_MAT2X4_ONCE */ TEST_IMPL(GLM_PREFIX, mat2x4_copy) { mat2x4 m1 = A_MATRIX2X4; mat2x4 m2 = GLM_MAT2X4_ZERO_INIT; GLM(mat2x4_copy)(m1, m2); test_assert_mat2x4_eq(m1, m2); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2x4_zero) { mat2x4 m1 = GLM_MAT2X4_ZERO_INIT; mat2x4 m2 = GLM_MAT2X4_ZERO_INIT; mat2x4 m3; GLM(mat2x4_zero)(m3); ASSERTIFY(test_assert_mat2x4_eq_zero(m1)) ASSERTIFY(test_assert_mat2x4_eq_zero(m2)) ASSERTIFY(test_assert_mat2x4_eq_zero(m3)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2x4_make) { float src[24] = { 0.5f, 1.7f, 10.3f, 4.2f, 8.9f, 1.1f, 77.3f, 88.4f, 2.3f, 4.2f, 66.5f, 23.7f, 6.6f, 8.9f, 90.3f, 34.2f, 5.3f, 4.8f, 96.3f, 13.7f, 4.7f, 5.5f, 22.9f, 5.5f }; mat2x4 dest[3]; float *srcp = src; unsigned int i, j, k; for (i = 0, j = 0, k = 0; i < sizeof(src) / sizeof(float); i+=8,j++) { GLM(mat2x4_make)(srcp + i, dest[j]); ASSERT(test_eq(src[ i ], dest[j][k][0])); ASSERT(test_eq(src[i+1], dest[j][k][1])); ASSERT(test_eq(src[i+2], dest[j][k][2])); ASSERT(test_eq(src[i+3], dest[j][k][3])); ASSERT(test_eq(src[i+4], dest[j][k+1][0])); ASSERT(test_eq(src[i+5], dest[j][k+1][1])); ASSERT(test_eq(src[i+6], dest[j][k+1][2])); ASSERT(test_eq(src[i+7], dest[j][k+1][3])); } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2x4_mul) { mat2x4 m1 = GLM_MAT2X4_ZERO_INIT; mat4x2 m2 = GLM_MAT4X2_ZERO_INIT; mat4 m3 = GLM_MAT4_ZERO_INIT; mat4 m4 = GLM_MAT4_ZERO_INIT; int c, r, k; /* test random matrices */ /* random matrices */ test_rand_mat2x4(m1); test_rand_mat4x2(m2); for (r = 0; r < 4; r++) { for (c = 0; c < 4; c++) { for (k = 0; k < 2; k++) { m4[c][r] += m1[k][r] * m2[c][k]; } } } GLM(mat2x4_mul)(m1, m2, m3); ASSERTIFY(test_assert_mat4_eq(m3, m4)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2x4_mulv) { mat2x4 mat = A_MATRIX2X4; vec2 v = {11.0f, 21.0f}; int i; vec4 dest; float res = 0.0; GLM(mat2x4_mulv)(mat, v, dest); for (i = 0; i < 4; i++) { res = mat[0][i] * v[0] + mat[1][i] * v[1]; ASSERT(test_eq(dest[i], res)) } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2x4_transpose) { mat2x4 m1 = A_MATRIX2X4; mat4x2 m2; mat4x2 m3 = A_MATRIX2X4_TRANSPOSE; GLM(mat2x4_transpose)(m1, m2); ASSERTIFY(test_assert_mat4x2_eq(m2, m3)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat2x4_scale) { mat2x4 m1 = A_MATRIX2X4; mat2x4 m2 = A_MATRIX2X4; int i, j; float scale; scale = (float)(rand() % 100); GLM(mat2x4_scale)(m1, scale); for (i = 0; i < 2; i++) { for (j = 0; j < 4; j++) { ASSERT(test_eq(m1[i][j], m2[i][j] * scale)) } } TEST_SUCCESS } cglm-0.9.7/test/src/test_mat3.h000066400000000000000000000156461526744317200163220ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" #define A_MATRIX {{1,2,3},{5,6,7},{9,10,11}} #define MAT3_ARRAY {1, 5, 2, 7, 12, 1, 4, 6, 0} TEST_IMPL(GLM_PREFIX, mat3_copy) { mat3 m1 = A_MATRIX; mat3 m2 = GLM_MAT3_IDENTITY_INIT; GLM(mat3_copy)(m1, m2); test_assert_mat3_eq(m1, m2); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3_identity) { mat3 m1 = GLM_MAT3_IDENTITY_INIT; mat3 m2 = GLM_MAT3_IDENTITY_INIT; mat3 m3; GLM(mat3_identity)(m3); ASSERTIFY(test_assert_mat3_eq_identity(m1)) ASSERTIFY(test_assert_mat3_eq_identity(m2)) ASSERTIFY(test_assert_mat3_eq_identity(m3)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3_identity_array) { size_t i, count; mat3 matrices[4] = { A_MATRIX, A_MATRIX, A_MATRIX, A_MATRIX }; count = 4; GLM(mat3_identity_array)(matrices, count); for (i = 0; i < count; i++) { ASSERTIFY(test_assert_mat3_eq_identity(matrices[i])) } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3_zero) { mat3 m1 = GLM_MAT3_ZERO_INIT; mat3 m2 = GLM_MAT3_ZERO_INIT; mat3 m3; GLM(mat3_zero)(m3); ASSERTIFY(test_assert_mat3_eq_zero(m1)) ASSERTIFY(test_assert_mat3_eq_zero(m2)) ASSERTIFY(test_assert_mat3_eq_zero(m3)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3_mul) { mat3 m1 = GLM_MAT3_IDENTITY_INIT; mat3 m2 = GLM_MAT3_IDENTITY_INIT; mat3 m3; mat3 m4 = GLM_MAT3_ZERO_INIT; int i, j, k; /* test random matrices */ /* random matrices */ test_rand_mat3(m1); test_rand_mat3(m2); GLM(mat3_mul)(m1, m2, m3); for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { for (k = 0; k < 3; k++) /* column-major */ m4[i][j] += m1[k][j] * m2[i][k]; } } ASSERTIFY(test_assert_mat3_eq(m3, m4)) /* test pre compiled */ GLM(mat3_mul)(m1, m2, m3); ASSERTIFY(test_assert_mat3_eq(m3, m4)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3_mulv) { vec4 res; mat3 mat = A_MATRIX; vec4 v = {1.0f, 2.0f, 3.0f, 4.0f}; int i; GLM(mat3_mulv)(mat, v, res); for (i = 0; i < 3; i++) { ASSERT(test_eq(res[i], v[0] * mat[0][i] + v[1] * mat[1][i] + v[2] * mat[2][i])) } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3_trace) { mat3 mat = A_MATRIX; float trace; trace = GLM(mat3_trace)(mat); ASSERT(test_eq(trace, mat[0][0] + mat[1][1] + mat[2][2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3_quat) { mat3 m1, m3; mat4 m2; versor q1, q2, q3; vec3 axis1; vec3 axis2 = {1.9f, 2.3f, 4.5f}; GLM(quat)(q1, GLM_PI_4f, 1.9f, 2.3f, 4.5f); GLM(quat_mat3)(q1, m1); GLM(mat3_quat)(m1, q2); GLM(rotate_make)(m2, GLM_PI_4f, axis2); GLM(mat3_quat)(m1, q3); GLM(quat_axis)(q3, axis1); GLM(vec3_normalize)(axis1); GLM(vec3_normalize)(axis2); GLM(mat4_pick3)(m2, m3); ASSERT(test_eq(glm_quat_angle(q3), GLM_PI_4f)) ASSERTIFY(test_assert_vec3_eq(axis1, axis2)) ASSERTIFY(test_assert_vec4_eq(q1, q2)) ASSERTIFY(test_assert_mat3_eq(m1, m3)) ASSERTIFY(test_assert_vec4_eq(q1, q3)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3_transpose_to) { mat3 mat = A_MATRIX; mat3 m1; GLM(mat3_transpose_to)(mat, m1); ASSERTIFY(test_assert_mat3_eqt(mat, m1)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3_transpose) { mat3 mat = A_MATRIX; mat3 m1; GLM(mat3_copy)(mat, m1); GLM(mat3_transpose)(m1); ASSERTIFY(test_assert_mat3_eqt(mat, m1)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3_scale) { mat3 m1 = A_MATRIX; mat3 m2 = A_MATRIX; int i, j, k; float scale; scale = (float)(rand() % 100); GLM(mat3_scale)(m1, scale); for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { for (k = 0; k < 3; k++) ASSERT(test_eq(m1[i][j], m2[i][j] * scale)) } } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3_det) { mat3 mat; float a, b, c, d, e, f, g, h, i; float det1, det2; test_rand_mat3(mat); a = mat[0][0]; b = mat[0][1]; c = mat[0][2]; d = mat[1][0]; e = mat[1][1]; f = mat[1][2]; g = mat[2][0]; h = mat[2][1]; i = mat[2][2]; det1 = a * (e * i - h * f) - d * (b * i - c * h) + g * (b * f - c * e); det2 = GLM(mat3_det)(mat); ASSERT(test_eq(det1, det2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3_inv) { mat3 m1 = GLM_MAT3_IDENTITY_INIT; mat3 m2 = GLM_MAT3_IDENTITY_INIT; mat3 m3; int i; for (i = 0; i < 100000; i++) { test_rand_mat3(m1); test_rand_mat3(m2); /* test inverse precise */ GLM(mat3_inv)(m1, m2); GLM(mat3_inv)(m2, m3); ASSERTIFY(test_assert_mat3_eq(m1, m3)) } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3_swap_col) { mat3 m1 = A_MATRIX; mat3 m2 = A_MATRIX; GLM(mat3_swap_col)(m1, 0, 1); ASSERTIFY(test_assert_vec3_eq(m1[0], m2[1])) ASSERTIFY(test_assert_vec3_eq(m1[1], m2[0])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3_swap_row) { mat3 m1 = A_MATRIX; mat3 m2 = A_MATRIX; GLM(mat3_swap_row)(m1, 0, 1); ASSERT(test_eq(m1[0][0], m2[0][1])) ASSERT(test_eq(m1[0][1], m2[0][0])) ASSERT(test_eq(m1[0][2], m2[0][2])) ASSERT(test_eq(m1[1][0], m2[1][1])) ASSERT(test_eq(m1[1][1], m2[1][0])) ASSERT(test_eq(m1[1][2], m2[1][2])) ASSERT(test_eq(m1[2][0], m2[2][1])) ASSERT(test_eq(m1[2][1], m2[2][0])) ASSERT(test_eq(m1[2][2], m2[2][2])) GLM(mat3_swap_row)(m1, 1, 2); ASSERT(test_eq(m1[0][0], m2[0][1])) ASSERT(test_eq(m1[0][1], m2[0][2])) ASSERT(test_eq(m1[0][2], m2[0][0])) ASSERT(test_eq(m1[1][0], m2[1][1])) ASSERT(test_eq(m1[1][1], m2[1][2])) ASSERT(test_eq(m1[1][2], m2[1][0])) ASSERT(test_eq(m1[2][0], m2[2][1])) ASSERT(test_eq(m1[2][1], m2[2][2])) ASSERT(test_eq(m1[2][2], m2[2][0])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3_rmc) { mat3 mat = A_MATRIX; vec3 v = {11.0f, 12.0f, 13.0f}; vec3 v1; float r1, r2; int i; r1 = GLM(mat3_rmc)(v, mat, v); for (i = 0; i < 3; i++) { v1[i] = v[0] * mat[i][0] + v[1] * mat[i][1] + v[2] * mat[i][2]; } r2 = v[0] * v1[0] + v[1] * v1[1] + v[2] * v1[2]; ASSERT(test_eq(r1, r2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3_make) { mat3 dest; unsigned int i, j; float src[9] = MAT3_ARRAY; GLM(mat3_make)(src, dest); for (i = 0, j = 0; i < sizeof(src) / sizeof(float); i+=3, j++) { ASSERT(test_eq(dest[j][0], src[i])) ASSERT(test_eq(dest[j][1], src[i+1])) ASSERT(test_eq(dest[j][2], src[i+2])) } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3_textrans) { mat3 m, expected; float sx = 2.0f, sy = 3.0f, rot = GLM_PI_4f; float tx = 10.0f, ty = 20.0f; GLM(mat3_textrans)(sx, sy, rot, tx, ty, m); ASSERT(test_eq(m[0][0], cosf(rot) * sx)) ASSERT(test_eq(m[0][1],-sinf(rot) * sy)) ASSERT(test_eq(m[1][0], sinf(rot) * sx)) ASSERT(test_eq(m[1][1], cosf(rot) * sy)) ASSERT(test_eq(m[2][0], tx)) ASSERT(test_eq(m[2][1], ty)) GLM(mat3_textrans)(1.0f, 1.0f, 0.0f, 0.0f, 0.0f, m); GLM(mat3_identity)(expected); ASSERTIFY(test_assert_mat3_eq(m, expected)) TEST_SUCCESS } #undef A_MATRIX cglm-0.9.7/test/src/test_mat3x2.h000066400000000000000000000061171526744317200165650ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" #define A_MATRIX3X2 {{1,2},{5,6},{3,7}} #define A_MATRIX3X2_TRANSPOSE {{1,5,3}, {2,6,7}} #ifndef CGLM_TEST_MAT3X2_ONCE #define CGLM_TEST_MAT3X2_ONCE TEST_IMPL(MACRO_GLM_MAT3X2_ZERO_INIT) { mat3x2 mat3x2_zero = GLM_MAT3X2_ZERO_INIT; test_assert_mat3x2_eq_zero(mat3x2_zero); TEST_SUCCESS } TEST_IMPL(MACRO_GLM_MAT3X2_ZERO) { mat3x2 mat3x2_zero = GLM_MAT3X2_ZERO; test_assert_mat3x2_eq_zero(mat3x2_zero); TEST_SUCCESS } #endif /* CGLM_TEST_MAT3X2_ONCE */ TEST_IMPL(GLM_PREFIX, mat3x2_copy) { mat3x2 m1 = A_MATRIX3X2; mat3x2 m2 = GLM_MAT3X2_ZERO_INIT; GLM(mat3x2_copy)(m1, m2); test_assert_mat3x2_eq(m1, m2); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3x2_zero) { mat3x2 m1 = GLM_MAT3X2_ZERO_INIT; mat3x2 m2 = GLM_MAT3X2_ZERO_INIT; mat3x2 m3; GLM(mat3x2_zero)(m3); ASSERTIFY(test_assert_mat3x2_eq_zero(m1)) ASSERTIFY(test_assert_mat3x2_eq_zero(m2)) ASSERTIFY(test_assert_mat3x2_eq_zero(m3)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3x2_make) { float src[18] = { 0.5f, 1.7f, 10.3f, 4.2f, 8.9f, 1.1f, 2.3f, 4.2f, 66.5f, 23.7f, 6.6f, 8.9f, 5.3f, 4.8f, 96.3f, 13.7f, 4.7f, 5.5f }; mat3x2 dest[3]; float *srcp = src; unsigned int i, j, k; for (i = 0, j = 0, k = 0; i < sizeof(src) / sizeof(float); i+=6,j++) { GLM(mat3x2_make)(srcp + i, dest[j]); ASSERT(test_eq(src[ i ], dest[j][k][0])); ASSERT(test_eq(src[i+1], dest[j][k][1])); ASSERT(test_eq(src[i+2], dest[j][k+1][0])); ASSERT(test_eq(src[i+3], dest[j][k+1][1])); ASSERT(test_eq(src[i+4], dest[j][k+2][0])); ASSERT(test_eq(src[i+5], dest[j][k+2][1])); } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3x2_mul) { mat3x2 m1 = GLM_MAT3X2_ZERO_INIT; mat2x3 m2 = GLM_MAT2X3_ZERO_INIT; mat2 m3 = GLM_MAT2_ZERO_INIT; mat2 m4 = GLM_MAT2_ZERO_INIT; int c, r, k; test_rand_mat3x2(m1); test_rand_mat2x3(m2); for (r = 0; r < 2; r++) { for (c = 0; c < 2; c++) { for (k = 0; k < 3; k++) { m4[c][r] += m1[k][r] * m2[c][k]; } } } GLM(mat3x2_mul)(m1, m2, m3); ASSERTIFY(test_assert_mat2_eq(m3, m4)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3x2_mulv) { mat3x2 mat = A_MATRIX3X2; vec3 v = {11.0f, 21.0f, 31.0f}; int i; vec2 dest; float res = 0.0; GLM(mat3x2_mulv)(mat, v, dest); for (i = 0; i < 2; i++) { res = mat[0][i] * v[0] + mat[1][i] * v[1] + mat[2][i] * v[2]; ASSERT(test_eq(dest[i], res)) } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3x2_transpose) { mat3x2 m1 = A_MATRIX3X2; mat2x3 m2; mat2x3 m3 = A_MATRIX3X2_TRANSPOSE; GLM(mat3x2_transpose)(m1, m2); ASSERTIFY(test_assert_mat2x3_eq(m2, m3)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3x2_scale) { mat3x2 m1 = A_MATRIX3X2; mat3x2 m2 = A_MATRIX3X2; int i, j; float scale; scale = (float)(rand() % 100); GLM(mat3x2_scale)(m1, scale); for (i = 0; i < 3; i++) { for (j = 0; j < 2; j++) { ASSERT(test_eq(m1[i][j], m2[i][j] * scale)) } } TEST_SUCCESS } cglm-0.9.7/test/src/test_mat3x4.h000066400000000000000000000070041526744317200165630ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" #define A_MATRIX3X4 {{1,2,4,5},{6,7,8,9},{10,11,12,13}} #define A_MATRIX3X4_TRANSPOSE {{1,6,10}, {2,7,1}, {4,8,12}, {5,9,13}} #ifndef CGLM_TEST_MAT3X4_ONCE #define CGLM_TEST_MAT3X4_ONCE TEST_IMPL(MACRO_GLM_MAT3X4_ZERO_INIT) { mat3x4 mat3x4_zero = GLM_MAT3X4_ZERO_INIT; test_assert_mat3x4_eq_zero(mat3x4_zero); TEST_SUCCESS } TEST_IMPL(MACRO_GLM_MAT3X4_ZERO) { mat3x4 mat3x4_zero = GLM_MAT3X4_ZERO; test_assert_mat3x4_eq_zero(mat3x4_zero); TEST_SUCCESS } #endif /* CGLM_TEST_MAT3X4_ONCE */ TEST_IMPL(GLM_PREFIX, mat3x4_copy) { mat3x4 m1 = A_MATRIX3X4; mat3x4 m2 = GLM_MAT3X4_ZERO_INIT; GLM(mat3x4_copy)(m1, m2); test_assert_mat3x4_eq(m1, m2); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3x4_zero) { mat3x4 m1 = GLM_MAT3X4_ZERO_INIT; mat3x4 m2 = GLM_MAT3X4_ZERO_INIT; mat3x4 m3; GLM(mat3x4_zero)(m3); ASSERTIFY(test_assert_mat3x4_eq_zero(m1)) ASSERTIFY(test_assert_mat3x4_eq_zero(m2)) ASSERTIFY(test_assert_mat3x4_eq_zero(m3)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3x4_make) { float src[36] = { 0.5f, 1.7f, 10.3f, 4.2f, 8.9f, 1.1f, 2.3f, 4.2f, 66.5f, 23.7f, 6.6f, 8.9f, 2.3f, 4.2f, 66.5f, 23.7f, 6.6f, 8.9f, 0.5f, 1.7f, 10.3f, 4.2f, 8.9f, 1.1f, 5.3f, 4.8f, 96.3f, 13.7f, 4.7f, 5.5f, 2.3f, 4.2f, 66.5f, 23.7f, 6.6f, 8.9f }; mat3x4 dest[3]; float *srcp = src; unsigned int i, j, k; for (i = 0, j = 0, k = 0; i < sizeof(src) / sizeof(float); i+=12,j++) { GLM(mat3x4_make)(srcp + i, dest[j]); ASSERT(test_eq(src[ i ], dest[j][k][0])); ASSERT(test_eq(src[i+1], dest[j][k][1])); ASSERT(test_eq(src[i+2], dest[j][k][2])); ASSERT(test_eq(src[i+3], dest[j][k][3])); ASSERT(test_eq(src[i+4], dest[j][k+1][0])); ASSERT(test_eq(src[i+5], dest[j][k+1][1])); ASSERT(test_eq(src[i+6], dest[j][k+1][2])); ASSERT(test_eq(src[i+7], dest[j][k+1][3])); ASSERT(test_eq(src[i+8], dest[j][k+2][0])); ASSERT(test_eq(src[i+9], dest[j][k+2][1])); ASSERT(test_eq(src[i+10], dest[j][k+2][2])); ASSERT(test_eq(src[i+11], dest[j][k+2][3])); } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3x4_mul) { mat3x4 m1 = GLM_MAT3X4_ZERO_INIT; mat4x3 m2 = GLM_MAT4X3_ZERO_INIT; mat4 m3 = GLM_MAT4_ZERO_INIT; mat4 m4 = GLM_MAT4_ZERO_INIT; int c, r, k; test_rand_mat3x4(m1); test_rand_mat4x3(m2); for (r = 0; r < 4; r++) { for (c = 0; c < 4; c++) { for (k = 0; k < 3; k++) { m4[c][r] += m1[k][r] * m2[c][k]; } } } GLM(mat3x4_mul)(m1, m2, m3); ASSERTIFY(test_assert_mat4_eq(m3, m4)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3x4_mulv) { mat3x4 mat = A_MATRIX3X4; vec4 v = {11.0f, 21.0f, 31.0f}; int i; vec4 dest; float res = 0.0; GLM(mat3x4_mulv)(mat, v, dest); for (i = 0; i < 4; i++) { res = mat[0][i] * v[0] + mat[1][i] * v[1] + mat[2][i] * v[2]; ASSERT(test_eq(dest[i], res)) } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3x4_transpose) { mat3x4 m1 = A_MATRIX3X4; mat4x3 m2; mat4x3 m3 = A_MATRIX3X2_TRANSPOSE; GLM(mat3x4_transpose)(m1, m2); ASSERTIFY(test_assert_mat4x3_eq(m2, m3)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat3x4_scale) { mat3x4 m1 = A_MATRIX3X4; mat3x4 m2 = A_MATRIX3X4; int i, j; float scale; scale = (float)(rand() % 100); GLM(mat3x4_scale)(m1, scale); for (i = 0; i < 3; i++) { for (j = 0; j < 4; j++) { ASSERT(test_eq(m1[i][j], m2[i][j] * scale)) } } TEST_SUCCESS } cglm-0.9.7/test/src/test_mat4.h000066400000000000000000000250771526744317200163220ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" #define A_MATRIX {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}} #define A_MATRIX3 {{1,2,3},{5,6,7},{9,10,11}} #define MAT4_ARRAY {1, 5, 2, 7, 12, 1, 4, 6, 0, 8, 1, 0, 6, 5, 0, 1} TEST_IMPL(GLM_PREFIX, mat4_ucopy) { mat4 m1 = A_MATRIX; mat4 m2 = GLM_MAT4_IDENTITY_INIT; GLM(mat4_ucopy)(m1, m2); ASSERTIFY(test_assert_mat4_eq(m1, m2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_copy) { mat4 m1 = A_MATRIX; mat4 m2 = GLM_MAT4_IDENTITY_INIT; GLM(mat4_copy)(m1, m2); test_assert_mat4_eq(m1, m2); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_identity) { mat4 m1 = GLM_MAT4_IDENTITY_INIT; mat4 m2 = GLM_MAT4_IDENTITY_INIT; mat4 m3; GLM(mat4_identity)(m3); ASSERTIFY(test_assert_mat4_eq_identity(m1)) ASSERTIFY(test_assert_mat4_eq_identity(m2)) ASSERTIFY(test_assert_mat4_eq_identity(m3)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_identity_array) { size_t i, count; mat4 matrices[4] = { A_MATRIX, A_MATRIX, A_MATRIX, A_MATRIX }; count = 4; GLM(mat4_identity_array)(matrices, count); for (i = 0; i < count; i++) { ASSERTIFY(test_assert_mat4_eq_identity(matrices[i])) } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_zero) { mat4 m1 = GLM_MAT4_ZERO_INIT; mat4 m2 = GLM_MAT4_ZERO_INIT; mat4 m3; GLM(mat4_zero)(m3); ASSERTIFY(test_assert_mat4_eq_zero(m1)) ASSERTIFY(test_assert_mat4_eq_zero(m2)) ASSERTIFY(test_assert_mat4_eq_zero(m3)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_pick3) { mat4 m1 = A_MATRIX; mat3 m2 = GLM_MAT3_ZERO_INIT; mat3 m3 = A_MATRIX3; GLM(mat4_pick3)(m1, m2); ASSERTIFY(test_assert_mat3_eq(m2, m3)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_pick3t) { mat4 m1 = A_MATRIX; mat3 m2 = GLM_MAT3_ZERO_INIT; mat3 m3 = A_MATRIX3; GLM(mat4_pick3t)(m1, m2); ASSERTIFY(test_assert_mat3_eqt(m2, m3)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_ins3) { mat4 m1 = GLM_MAT4_IDENTITY_INIT; mat3 m2 = A_MATRIX3; int i, j; GLM(mat4_ins3)(m2, m1); for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { ASSERT(m1[i][j] == m2[i][j]) } } ASSERT(test_eq(m1[3][0], 0.0f)) ASSERT(test_eq(m1[3][1], 0.0f)) ASSERT(test_eq(m1[3][2], 0.0f)) ASSERT(test_eq(m1[3][3], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_mul) { mat4 m1 = GLM_MAT4_IDENTITY_INIT; mat4 m2 = GLM_MAT4_IDENTITY_INIT; mat4 m3; mat4 m4 = GLM_MAT4_ZERO_INIT; int i, j, k; /* test random matrices */ /* random matrices */ test_rand_mat4(m1); test_rand_mat4(m2); GLM(mat4_mul)(m1, m2, m3); for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { for (k = 0; k < 4; k++) /* column-major */ m4[i][j] += m1[k][j] * m2[i][k]; } } ASSERTIFY(test_assert_mat4_eq(m3, m4)) /* test pre compiled */ GLM(mat4_mul)(m1, m2, m3); ASSERTIFY(test_assert_mat4_eq(m3, m4)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_mulN) { mat4 res1, res2; mat4 m1 = A_MATRIX; mat4 m2 = A_MATRIX; mat4 m3 = A_MATRIX; mat4 *matrices[] = { &m1, &m2, &m3 }; GLM(mat4_mulN)(matrices, sizeof(matrices) / sizeof(matrices[0]), res1); GLM(mat4_mul)(*matrices[0], *matrices[1], res2); GLM(mat4_mul)(res2, *matrices[2], res2); ASSERTIFY(test_assert_mat4_eq(res1, res1)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_mulv) { vec4 res; mat4 mat = A_MATRIX; vec4 v = {1.0f, 2.0f, 3.0f, 4.0f}; int i; GLM(mat4_mulv)(mat, v, res); for (i = 0; i < 4; i++) { ASSERT(test_eq(res[i], v[0] * mat[0][i] + v[1] * mat[1][i] + v[2] * mat[2][i] + v[3] * mat[3][i])) } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_mulv3) { vec4 res; mat4 mat = A_MATRIX; vec3 v = {1.0f, 2.0f, 3.0f}; float last; int i; last = 1.0f; GLM(mat4_mulv3)(mat, v, last, res); for (i = 0; i < 3; i++) { ASSERT(test_eq(res[i], v[0] * mat[0][i] + v[1] * mat[1][i] + v[2] * mat[2][i] + last * mat[3][i])) } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_trace) { mat4 mat = A_MATRIX; float trace; trace = GLM(mat4_trace)(mat); ASSERT(test_eq(trace, mat[0][0] + mat[1][1] + mat[2][2] + mat[3][3])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_trace3) { mat4 mat = A_MATRIX; float trace; trace = GLM(mat4_trace3)(mat); ASSERT(test_eq(trace, mat[0][0] + mat[1][1] + mat[2][2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_quat) { mat4 m1, m2; versor q1, q2, q3; vec3 axis1; vec3 axis2 = {1.9f, 2.3f, 4.5f}; GLM(quat)(q1, GLM_PI_4f, 1.9f, 2.3f, 4.5f); GLM(quat_mat4)(q1, m1); GLM(mat4_quat)(m1, q2); GLM(rotate_make)(m2, GLM_PI_4f, axis2); GLM(mat4_quat)(m1, q3); GLM(quat_axis)(q3, axis1); GLM(vec3_normalize)(axis1); GLM(vec3_normalize)(axis2); ASSERT(test_eq(glm_quat_angle(q3), GLM_PI_4f)) ASSERTIFY(test_assert_vec3_eq(axis1, axis2)) ASSERTIFY(test_assert_vec4_eq(q1, q2)) ASSERTIFY(test_assert_mat4_eq(m1, m2)) ASSERTIFY(test_assert_vec4_eq(q1, q3)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_transpose_to) { mat4 mat = A_MATRIX; mat4 m1; GLM(mat4_transpose_to)(mat, m1); ASSERTIFY(test_assert_mat4_eqt(mat, m1)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_transpose) { mat4 mat = A_MATRIX; mat4 m1; GLM(mat4_copy)(mat, m1); GLM(mat4_transpose)(m1); ASSERTIFY(test_assert_mat4_eqt(mat, m1)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_scale_p) { mat4 m1 = A_MATRIX; mat4 m2 = A_MATRIX; int i, j, k; float scale; scale = (float)(rand() % 100); GLM(mat4_scale_p)(m1, scale); for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { for (k = 0; k < 4; k++) ASSERT(test_eq(m1[i][j], m2[i][j] * scale)) } } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_scale) { mat4 m1 = A_MATRIX; mat4 m2 = A_MATRIX; int i, j, k; float scale; scale = (float)(rand() % 100); GLM(mat4_scale)(m1, scale); for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { for (k = 0; k < 4; k++) ASSERT(test_eq(m1[i][j], m2[i][j] * scale)) } } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_det) { mat4 mat = GLM_MAT4_IDENTITY_INIT; float t[6]; float a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p; float det1, det2; test_rand_mat4(mat); a = mat[0][0]; b = mat[0][1]; c = mat[0][2]; d = mat[0][3]; e = mat[1][0]; f = mat[1][1]; g = mat[1][2]; h = mat[1][3]; i = mat[2][0]; j = mat[2][1]; k = mat[2][2]; l = mat[2][3]; m = mat[3][0]; n = mat[3][1]; o = mat[3][2]; p = mat[3][3]; t[0] = k * p - o * l; t[1] = j * p - n * l; t[2] = j * o - n * k; t[3] = i * p - m * l; t[4] = i * o - m * k; t[5] = i * n - m * j; det1 = a * (f * t[0] - g * t[1] + h * t[2]) - b * (e * t[0] - g * t[3] + h * t[4]) + c * (e * t[1] - f * t[3] + h * t[5]) - d * (e * t[2] - f * t[4] + g * t[5]); det2 = GLM(mat4_det(mat)); ASSERT(test_eq(det1, det2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_inv) { mat4 m1, m2, m3; int i; for (i = 0; i < 100000; i++) { test_rand_mat4(m1); test_rand_mat4(m2); /* test inverse precise */ GLM(mat4_inv)(m1, m2); GLM(mat4_inv)(m2, m3); ASSERTIFY(test_assert_mat4_eq(m1, m3)) } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_inv_precise) { mat4 m1, m2, m3; mat4 m4, m5, m6; int i; for (i = 0; i < 100000; i++) { test_rand_mat4(m1); test_rand_mat4(m2); glm_mat4_inv_precise(m1, m2); glm_mat4_inv_precise(m2, m3); ASSERTIFY(test_assert_mat4_eq(m1, m3)) test_rand_mat4(m4); test_rand_mat4(m5); glmc_mat4_inv_precise(m4, m5); glmc_mat4_inv_precise(m5, m6); ASSERTIFY(test_assert_mat4_eq(m4, m6)) } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_inv_fast) { mat4 m1, m2, m3; int i; for (i = 0; i < 100000; i++) { test_rand_mat4(m1); test_rand_mat4(m2); /* test inverse precise */ GLM(mat4_inv_fast)(m1, m2); GLM(mat4_inv_fast)(m2, m3); ASSERTIFY(test_assert_mat4_eq2(m1, m3, 0.0009f)) } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_swap_col) { mat4 m1 = A_MATRIX; mat4 m2 = A_MATRIX; GLM(mat4_swap_col)(m1, 0, 1); GLM(mat4_swap_col)(m1, 2, 3); ASSERTIFY(test_assert_vec4_eq(m1[0], m2[1])) ASSERTIFY(test_assert_vec4_eq(m1[1], m2[0])) ASSERTIFY(test_assert_vec4_eq(m1[2], m2[3])) ASSERTIFY(test_assert_vec4_eq(m1[3], m2[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_swap_row) { mat4 m1 = A_MATRIX; mat4 m2 = A_MATRIX; GLM(mat4_swap_row)(m1, 0, 1); GLM(mat4_swap_row)(m1, 2, 3); ASSERT(test_eq(m1[0][0], m2[0][1])) ASSERT(test_eq(m1[0][1], m2[0][0])) ASSERT(test_eq(m1[0][2], m2[0][3])) ASSERT(test_eq(m1[0][3], m2[0][2])) ASSERT(test_eq(m1[1][0], m2[1][1])) ASSERT(test_eq(m1[1][1], m2[1][0])) ASSERT(test_eq(m1[1][2], m2[1][3])) ASSERT(test_eq(m1[1][3], m2[1][2])) ASSERT(test_eq(m1[2][0], m2[2][1])) ASSERT(test_eq(m1[2][1], m2[2][0])) ASSERT(test_eq(m1[2][2], m2[2][3])) ASSERT(test_eq(m1[2][3], m2[2][2])) ASSERT(test_eq(m1[3][0], m2[3][1])) ASSERT(test_eq(m1[3][1], m2[3][0])) ASSERT(test_eq(m1[3][2], m2[3][3])) ASSERT(test_eq(m1[3][3], m2[3][2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_rmc) { mat4 mat = A_MATRIX; vec4 v = {1.0f, 2.0f, 3.0f, 4.0f}; vec4 v1; float r1, r2; int i; r1 = GLM(mat4_rmc)(v, mat, v); for (i = 0; i < 4; i++) { v1[i] = v[0] * mat[i][0] + v[1] * mat[i][1] + v[2] * mat[i][2] + v[3] * mat[i][3]; } r2 = v[0] * v1[0] + v[1] * v1[1] + v[2] * v1[2] + v[3] * v1[3]; ASSERT(test_eq(r1, r2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_make) { mat4 dest; unsigned int i, j; float src[16] = MAT4_ARRAY; GLM(mat4_make)(src, dest); for (i = 0, j = 0; i < sizeof(src) / sizeof(float); i+=4, j++) { ASSERT(test_eq(dest[j][0], src[i])) ASSERT(test_eq(dest[j][1], src[i+1])) ASSERT(test_eq(dest[j][2], src[i+2])) ASSERT(test_eq(dest[j][3], src[i+3])) } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4_textrans) { mat4 m, expected; float sx = 2.0f, sy = 3.0f, rot = GLM_PI_4f; float tx = 10.0f, ty = 20.0f; GLM(mat4_textrans)(sx, sy, rot, tx, ty, m); ASSERT(test_eq(m[0][0], cosf(rot) * sx)) ASSERT(test_eq(m[0][1],-sinf(rot) * sy)) ASSERT(test_eq(m[1][0], sinf(rot) * sx)) ASSERT(test_eq(m[1][1], cosf(rot) * sy)) ASSERT(test_eq(m[3][0], tx)) ASSERT(test_eq(m[3][1], ty)) GLM(mat4_textrans)(1.0f, 1.0f, 0.0f, 0.0f, 0.0f, m); GLM(mat4_identity)(expected); ASSERTIFY(test_assert_mat4_eq(m, expected)) TEST_SUCCESS } #undef A_MATRIX #undef A_MATRIX3 cglm-0.9.7/test/src/test_mat4x2.h000066400000000000000000000063701526744317200165670ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" #define A_MATRIX4X2 {{1,2},{3,4},{5,6},{7,8}} #define A_MATRIX4X2_TRANSPOSE {{1,3,5,7}, {2,4,6,8}} #ifndef CGLM_TEST_MAT4X2_ONCE #define CGLM_TEST_MAT4X2_ONCE TEST_IMPL(MACRO_GLM_MAT4X2_ZERO_INIT) { mat4x2 mat4x2_zero = GLM_MAT4X2_ZERO_INIT; test_assert_mat4x2_eq_zero(mat4x2_zero); TEST_SUCCESS } TEST_IMPL(MACRO_GLM_MAT4X2_ZERO) { mat4x2 mat4x2_zero = GLM_MAT4X2_ZERO; test_assert_mat4x2_eq_zero(mat4x2_zero); TEST_SUCCESS } #endif /* CGLM_TEST_MAT4X2_ONCE */ TEST_IMPL(GLM_PREFIX, mat4x2_copy) { mat4x2 m1 = A_MATRIX4X2; mat4x2 m2 = GLM_MAT4X2_ZERO_INIT; GLM(mat4x2_copy)(m1, m2); test_assert_mat4x2_eq(m1, m2); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4x2_zero) { mat4x2 m1 = GLM_MAT4X2_ZERO_INIT; mat4x2 m2 = GLM_MAT4X2_ZERO_INIT; mat4x2 m3; GLM(mat4x2_zero)(m3); ASSERTIFY(test_assert_mat4x2_eq_zero(m1)) ASSERTIFY(test_assert_mat4x2_eq_zero(m2)) ASSERTIFY(test_assert_mat4x2_eq_zero(m3)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4x2_make) { float src[24] = { 0.5f, 1.7f, 10.3f, 4.2f, 8.9f, 1.1f, 2.3f, 4.2f, 2.3f, 4.2f, 66.5f, 23.7f, 6.6f, 8.9f, 0.5f, 1.7f, 5.3f, 4.8f, 96.3f, 13.7f, 4.7f, 5.5f, 2.3f, 4.2f }; mat4x2 dest[3]; float *srcp = src; unsigned int i, j, k; for (i = 0, j = 0, k = 0; i < sizeof(src) / sizeof(float); i+=8,j++) { GLM(mat4x2_make)(srcp + i, dest[j]); ASSERT(test_eq(src[ i ], dest[j][k][0])); ASSERT(test_eq(src[i+1], dest[j][k][1])); ASSERT(test_eq(src[i+2], dest[j][k+1][0])); ASSERT(test_eq(src[i+3], dest[j][k+1][1])); ASSERT(test_eq(src[i+4], dest[j][k+2][0])); ASSERT(test_eq(src[i+5], dest[j][k+2][1])); ASSERT(test_eq(src[i+6], dest[j][k+3][0])); ASSERT(test_eq(src[i+7], dest[j][k+3][1])); } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4x2_mul) { mat4x2 m1 = GLM_MAT4X2_ZERO_INIT; mat2x4 m2 = GLM_MAT2X4_ZERO_INIT; mat2 m3 = GLM_MAT2_ZERO_INIT; mat2 m4 = GLM_MAT2_ZERO_INIT; int c, r, k; test_rand_mat4x2(m1); test_rand_mat2x4(m2); for (r = 0; r < 2; r++) { for (c = 0; c < 2; c++) { for (k = 0; k < 4; k++) { m4[c][r] += m1[k][r] * m2[c][k]; } } } GLM(mat4x2_mul)(m1, m2, m3); ASSERTIFY(test_assert_mat2_eq(m3, m4)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4x2_mulv) { mat4x2 mat = A_MATRIX4X2; vec4 v = {11.0f, 21.0f, 31.0f, 41.0f}; int i; vec2 dest; float res = 0.0; GLM(mat4x2_mulv)(mat, v, dest); for (i = 0; i < 2; i++) { res = mat[0][i] * v[0] + mat[1][i] * v[1] + mat[2][i] * v[2] + mat[3][i] * v[3]; ASSERT(test_eq(dest[i], res)) } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4x2_transpose) { mat4x2 m1 = A_MATRIX4X2; mat2x4 m2; mat2x4 m3 = A_MATRIX4X2_TRANSPOSE; GLM(mat4x2_transpose)(m1, m2); ASSERTIFY(test_assert_mat2x4_eq(m2, m3)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4x2_scale) { mat4x2 m1 = A_MATRIX4X2; mat4x2 m2 = A_MATRIX4X2; int i, j; float scale; scale = (float)(rand() % 100); GLM(mat4x2_scale)(m1, scale); for (i = 0; i < 4; i++) { for (j = 0; j < 2; j++) { ASSERT(test_eq(m1[i][j], m2[i][j] * scale)) } } TEST_SUCCESS } cglm-0.9.7/test/src/test_mat4x3.h000066400000000000000000000070331526744317200165650ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" #define A_MATRIX4X3 {{1,2,3},{4,5,6},{7,8,9},{10,11,12}} #define A_MATRIX4X3_TRANSPOSE {{1,4,7,10},{2,5,8,11},{3,6,9,12}} #ifndef CGLM_TEST_MAT4X3_ONCE #define CGLM_TEST_MAT4X3_ONCE TEST_IMPL(MACRO_GLM_MAT4X3_ZERO_INIT) { mat4x3 mat4x3_zero = GLM_MAT4X3_ZERO_INIT; test_assert_mat4x3_eq_zero(mat4x3_zero); TEST_SUCCESS } TEST_IMPL(MACRO_GLM_MAT4X3_ZERO) { mat4x3 mat4x3_zero = GLM_MAT4X3_ZERO; test_assert_mat4x3_eq_zero(mat4x3_zero); TEST_SUCCESS } #endif /* CGLM_TEST_MAT4X3_ONCE */ TEST_IMPL(GLM_PREFIX, mat4x3_copy) { mat4x3 m1 = A_MATRIX4X3; mat4x3 m2 = GLM_MAT4X3_ZERO_INIT; GLM(mat4x3_copy)(m1, m2); test_assert_mat4x3_eq(m1, m2); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4x3_zero) { mat4x3 m1 = GLM_MAT4X3_ZERO_INIT; mat4x3 m2 = GLM_MAT4X3_ZERO_INIT; mat4x3 m3; GLM(mat4x3_zero)(m3); ASSERTIFY(test_assert_mat4x3_eq_zero(m1)) ASSERTIFY(test_assert_mat4x3_eq_zero(m2)) ASSERTIFY(test_assert_mat4x3_eq_zero(m3)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4x3_make) { float src[36] = { 0.5f, 1.7f, 10.3f, 4.2f, 8.9f, 1.1f, 2.3f, 4.2f, 5.3f, 4.8f, 96.3f, 13.7f, 4.7f, 5.5f, 2.3f, 4.2f, 2.3f, 4.2f, 66.5f, 23.7f, 6.6f, 8.9f, 0.5f, 1.7f, 5.3f, 4.8f, 96.3f, 13.7f, 4.7f, 5.5f, 2.3f, 4.2f, 0.5f, 1.7f, 10.3f, 4.2f }; mat4x3 dest[3]; float *srcp = src; unsigned int i, j, k; for (i = 0, j = 0, k = 0; i < sizeof(src) / sizeof(float); i+=12,j++) { GLM(mat4x3_make)(srcp + i, dest[j]); ASSERT(test_eq(src[ i ], dest[j][k][0])); ASSERT(test_eq(src[i+1], dest[j][k][1])); ASSERT(test_eq(src[i+2], dest[j][k][2])); ASSERT(test_eq(src[i+3], dest[j][k+1][0])); ASSERT(test_eq(src[i+4], dest[j][k+1][1])); ASSERT(test_eq(src[i+5], dest[j][k+1][2])); ASSERT(test_eq(src[i+6], dest[j][k+2][0])); ASSERT(test_eq(src[i+7], dest[j][k+2][1])); ASSERT(test_eq(src[i+8], dest[j][k+2][2])); ASSERT(test_eq(src[i+9], dest[j][k+3][0])); ASSERT(test_eq(src[i+10], dest[j][k+3][1])); ASSERT(test_eq(src[i+11], dest[j][k+3][2])); } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4x3_mul) { mat4x3 m1 = GLM_MAT4X3_ZERO_INIT; mat3x4 m2 = GLM_MAT3X4_ZERO_INIT; mat3 m3 = GLM_MAT3_ZERO_INIT; mat3 m4 = GLM_MAT3_ZERO_INIT; int c, r, k; test_rand_mat4x3(m1); test_rand_mat3x4(m2); for (r = 0; r < 3; r++) { for (c = 0; c < 3; c++) { for (k = 0; k < 4; k++) { m4[c][r] += m1[k][r] * m2[c][k]; } } } GLM(mat4x3_mul)(m1, m2, m3); ASSERTIFY(test_assert_mat3_eq(m3, m4)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4x3_mulv) { mat4x3 mat = A_MATRIX4X3; vec4 v = {11.0f, 21.0f, 31.0f, 41.0f}; int i; vec3 dest; float res = 0.0; GLM(mat4x3_mulv)(mat, v, dest); for (i = 0; i < 3; i++) { res = mat[0][i] * v[0] + mat[1][i] * v[1] + mat[2][i] * v[2] + mat[3][i] * v[3]; ASSERT(test_eq(dest[i], res)) } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4x3_transpose) { mat4x3 m1 = A_MATRIX4X3; mat3x4 m2; mat3x4 m3 = A_MATRIX4X3_TRANSPOSE; GLM(mat4x3_transpose)(m1, m2); ASSERTIFY(test_assert_mat3x4_eq(m2, m3)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, mat4x3_scale) { mat4x3 m1 = A_MATRIX4X3; mat4x3 m2 = A_MATRIX4X3; int i, j; float scale; scale = (float)(rand() % 100); GLM(mat4x3_scale)(m1, scale); for (i = 0; i < 4; i++) { for (j = 0; j < 3; j++) { ASSERT(test_eq(m1[i][j], m2[i][j] * scale)) } } TEST_SUCCESS } cglm-0.9.7/test/src/test_noise.h000066400000000000000000000045251526744317200165650ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" TEST_IMPL(GLM_PREFIX, perlin_vec4) { vec4 p1[] = { {0.1f, 0.2f, 0.3f, 0.4f}, {0.2f, 0.3f, 0.4f, 0.5f}, {0.3f, 0.4f, 0.5f, 0.6f}, {0.4f, 0.5f, 0.6f, 0.7f}, {0.5f, 0.6f, 0.7f, 0.8f}, {0.6f, 0.7f, 0.8f, 0.9f}, {0.7f, 0.8f, 0.9f, 1.0f}, {0.8f, 0.9f, 1.0f, 1.1f}, {0.9f, 1.0f, 1.1f, 1.2f}, {1.0f, 1.1f, 1.2f, 1.3f}, }; /* expected values calculated by glm::perlin */ float e[] = { -0.5091819763183594f, -0.4375732541084290f, -0.3212279379367828f, -0.2279999703168869f, -0.1577337533235550f, -0.0445968918502331f, 0.1069696992635727f, 0.2067739963531494f, 0.2106968611478806f, 0.1397782564163208f }; for (int i = 0; i < 10; i++) { ASSERT(test_eq(GLM(perlin_vec4)(p1[i]), e[i])); } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, perlin_vec3) { vec3 p1[] = { {0.1f, 0.2f, 0.3f}, {0.2f, 0.3f, 0.4f}, {0.3f, 0.4f, 0.5f}, {0.4f, 0.5f, 0.6f}, {0.5f, 0.6f, 0.7f}, {0.6f, 0.7f, 0.8f}, {0.7f, 0.8f, 0.9f}, {0.8f, 0.9f, 1.0f}, {0.9f, 1.0f, 1.1f}, {1.0f, 1.1f, 1.2f}, }; /* expected values calculated by glm::perlin */ float e[] = { -0.2909241318702698f, -0.4667602181434631f, -0.4679279625415802f, -0.2616460621356964f, 0.0562822706997395f, 0.3178773224353790f, 0.3981811404228210f, 0.3011017739772797f, 0.1263920217752457f, -0.0602480024099350f }; for (int i = 0; i < 10; i++) { ASSERT(test_eq(GLM(perlin_vec3)(p1[i]), e[i])); } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, perlin_vec2) { vec2 p1[] = { {0.1f, 0.2f}, {0.2f, 0.3f}, {0.3f, 0.4f}, {0.4f, 0.5f}, {0.5f, 0.6f}, {0.6f, 0.7f}, {0.7f, 0.8f}, {0.8f, 0.9f}, {0.9f, 1.0f}, {1.0f, 1.1f}, }; /* expected values calculated by glm::perlin */ float e[] = { 0.2841092348098755f, 0.2328013032674789f, -0.0017980185803026f, -0.3300299644470215f, -0.5998955368995667f, -0.6914522647857666f, -0.5896517634391785f, -0.3778679668903351f, -0.1557840555906296f, 0.0453133136034012f }; for (int i = 0; i < 10; i++) { ASSERT(test_eq(GLM(perlin_vec2)(p1[i]), e[i])); } TEST_SUCCESS } cglm-0.9.7/test/src/test_plane.h000066400000000000000000000015751526744317200165510ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" TEST_IMPL(GLM_PREFIX, plane_normalize) { vec4 p1 = {2.0f, -3.0f, 4.0f, 5.0f}, p2 = {2.0f, -3.0f, 4.0f, 5.0f}; float s = 1.0f; float norm; GLM(plane_normalize)(p2); norm = sqrtf(p1[0] * p1[0] + p1[1] * p1[1] + p1[2] * p1[2]); if (norm == 0.0f) { ASSERT(test_eq(p1[0], 0.0f)) ASSERT(test_eq(p1[1], 0.0f)) ASSERT(test_eq(p1[2], 0.0f)) ASSERT(test_eq(p1[3], 0.0f)) TEST_SUCCESS } norm = s / norm; ASSERT(test_eq(p1[0] * norm, p2[0])) ASSERT(test_eq(p1[1] * norm, p2[1])) ASSERT(test_eq(p1[2] * norm, p2[2])) ASSERT(test_eq(p1[3] * norm, p2[3])) glm_vec4_zero(p1); GLM(plane_normalize)(p1); ASSERTIFY(test_assert_vec4_eq(p1, GLM_VEC4_ZERO)) TEST_SUCCESS } cglm-0.9.7/test/src/test_project.h000066400000000000000000000066071526744317200171210ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" TEST_IMPL(GLM_PREFIX, unprojecti) { mat4 model, view, proj, mvp; vec4 viewport = {0.0f, 0.0f, 800.0f, 600.0f}; vec3 pos = {13.0f, 45.0f, 0.74f}; vec3 projected, unprojected; glm_translate_make(model, (vec3){0.0f, 0.0f, -10.0f}); glm_lookat((vec3){0.0f, 0.0f, 0.0f}, pos, GLM_YUP, view); glm_perspective_default(0.5f, proj); glm_mat4_mulN((mat4 *[]){&proj, &view, &model}, 3, mvp); GLM(project)(pos, mvp, viewport, projected); glm_mat4_inv(mvp, mvp); GLM(unprojecti)(projected, mvp, viewport, unprojected); /* unprojected of projected vector must be same as original one */ /* we used 0.01 because of projection floating point errors */ #ifndef CGLM_FAST_MATH ASSERT(fabsf(pos[0] - unprojected[0]) < 0.01f) ASSERT(fabsf(pos[1] - unprojected[1]) < 0.01f) ASSERT(fabsf(pos[2] - unprojected[2]) < 0.01f) #else ASSERT(fabsf(pos[0] - unprojected[0]) < 0.1f) ASSERT(fabsf(pos[1] - unprojected[1]) < 0.1f) ASSERT(fabsf(pos[2] - unprojected[2]) < 0.1f) #endif TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, unproject) { mat4 model, view, proj, mvp; vec4 viewport = {0.0f, 0.0f, 800.0f, 600.0f}; vec3 pos = {13.0f, 45.0f, 0.74f}; vec3 projected, unprojected; glm_translate_make(model, (vec3){0.0f, 0.0f, -10.0f}); glm_lookat((vec3){0.0f, 0.0f, 0.0f}, pos, GLM_YUP, view); glm_perspective_default(0.5f, proj); glm_mat4_mulN((mat4 *[]){&proj, &view, &model}, 3, mvp); GLM(project)(pos, mvp, viewport, projected); GLM(unproject)(projected, mvp, viewport, unprojected); /* unprojected of projected vector must be same as original one */ /* we used 0.01 because of projection floating point errors */ #ifndef CGLM_FAST_MATH ASSERT(fabsf(pos[0] - unprojected[0]) < 0.01f) ASSERT(fabsf(pos[1] - unprojected[1]) < 0.01f) ASSERT(fabsf(pos[2] - unprojected[2]) < 0.01f) #else ASSERT(fabsf(pos[0] - unprojected[0]) < 0.1f) ASSERT(fabsf(pos[1] - unprojected[1]) < 0.1f) ASSERT(fabsf(pos[2] - unprojected[2]) < 0.1f) #endif TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, project) { mat4 model, view, proj, mvp; vec4 viewport = {0.0f, 0.0f, 800.0f, 600.0f}; vec3 pos = {13.0f, 45.0f, 0.74f}; vec3 projected, unprojected; glm_translate_make(model, (vec3){0.0f, 0.0f, -10.0f}); glm_lookat((vec3){0.0f, 0.0f, 0.0f}, pos, GLM_YUP, view); glm_perspective_default(0.5f, proj); glm_mat4_mulN((mat4 *[]){&proj, &view, &model}, 3, mvp); GLM(project)(pos, mvp, viewport, projected); GLM(unproject)(projected, mvp, viewport, unprojected); /* unprojected of projected vector must be same as original one */ /* we used 0.01 because of projection floating point errors */ #ifndef CGLM_FAST_MATH ASSERT(fabsf(pos[0] - unprojected[0]) < 0.01f) ASSERT(fabsf(pos[1] - unprojected[1]) < 0.01f) ASSERT(fabsf(pos[2] - unprojected[2]) < 0.01f) #else ASSERT(fabsf(pos[0] - unprojected[0]) < 0.1f) ASSERT(fabsf(pos[1] - unprojected[1]) < 0.1f) ASSERT(fabsf(pos[2] - unprojected[2]) < 0.1f) #endif /* test with no projection */ glm_mat4_identity(mvp); GLM(project)(pos, mvp, viewport, projected); GLM(unproject)(projected, mvp, viewport, unprojected); ASSERT(test_eq(pos[0], unprojected[0])) ASSERT(test_eq(pos[1], unprojected[1])) ASSERT(test_eq(pos[2], unprojected[2])) TEST_SUCCESS } cglm-0.9.7/test/src/test_quat.h000066400000000000000000000770061526744317200164260ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" #ifndef CGLM_TEST_QUAT_ONCE #define CGLM_TEST_QUAT_ONCE /* Macros */ TEST_IMPL(MACRO_GLM_QUAT_IDENTITY_INIT) { versor v = GLM_QUAT_IDENTITY_INIT; ASSERT(test_eq(v[0], 0.0f)) ASSERT(test_eq(v[1], 0.0f)) ASSERT(test_eq(v[2], 0.0f)) ASSERT(test_eq(v[3], 1.0f)) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_QUAT_IDENTITY) { ASSERT(test_eq(GLM_QUAT_IDENTITY[0], 0.0f)) ASSERT(test_eq(GLM_QUAT_IDENTITY[1], 0.0f)) ASSERT(test_eq(GLM_QUAT_IDENTITY[2], 0.0f)) ASSERT(test_eq(GLM_QUAT_IDENTITY[3], 1.0f)) TEST_SUCCESS } #endif /* CGLM_TEST_QUAT_ONCE */ TEST_IMPL(GLM_PREFIX, quat_identity) { versor a = GLM_QUAT_IDENTITY_INIT; versor b = GLM_QUAT_IDENTITY_INIT; versor c; mat4 r; GLM(quat_identity)(c); ASSERTIFY(test_assert_quat_eq_identity(a)) ASSERTIFY(test_assert_quat_eq_identity(b)) ASSERTIFY(test_assert_quat_eq_identity(c)) glm_quat_identity(c); ASSERT(test_eq(glm_quat_real(c), cosf(glm_rad(0.0f) * 0.5f))) glm_quat_mat4(c, r); ASSERTIFY(test_assert_mat4_eq2(r, GLM_MAT4_IDENTITY, 0.000009f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_identity_array) { size_t i, count; versor quats[4] = { {1.0f, 2.0f, 3.0f, 4.0f}, {1.0f, 2.0f, 3.0f, 4.0f}, {1.0f, 2.0f, 3.0f, 4.0f}, {1.0f, 2.0f, 3.0f, 4.0f}, }; count = 4; GLM(quat_identity_array)(quats, count); for (i = 0; i < count; i++) { ASSERTIFY(test_assert_quat_eq_identity(quats[i])) } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_init) { versor q1 = {1.0f, 2.0f, 3.0f, 4.0f}; versor q2 = {1.0f, 2.0f, 3.0f, 4.0f}; versor q3 = {1.0f, 2.0f, 3.0f, 4.0f}; GLM(quat_init)(q1, 10.0f, 11.0f, 12.0f, 13.0f); GLM(quat_init)(q2, 100.0f, 110.0f, 120.0f, 130.0f); GLM(quat_init)(q3, 1000.0f, 1100.0f, 1200.0f, 1300.0f); ASSERT(q1[0] == 10.0f) ASSERT(q1[1] == 11.0f) ASSERT(q1[2] == 12.0f) ASSERT(q1[3] == 13.0f) ASSERT(q2[0] == 100.0f) ASSERT(q2[1] == 110.0f) ASSERT(q2[2] == 120.0f) ASSERT(q2[3] == 130.0f) ASSERT(q3[0] == 1000.0f) ASSERT(q3[1] == 1100.0f) ASSERT(q3[2] == 1200.0f) ASSERT(q3[3] == 1300.0f) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quatv) { versor q1 = {1.0f, 2.0f, 3.0f, 4.0f}; vec3 v1, v2; float a1; test_rand_vec3(v1); GLM(quatv)(q1, glm_rad(60.0f), v1); glm_quat_axis(q1, v2); a1 = glm_quat_angle(q1); ASSERT(test_eq(a1, glm_rad(60.0f))) glm_vec3_normalize(v1); ASSERTIFY(test_assert_vec3_eq(v1, v2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat) { versor q1 = {1.0f, 2.0f, 3.0f, 4.0f}; vec3 v1, v2; float a1; test_rand_vec3(v1); GLM(quat)(q1, glm_rad(60.0f), v1[0], v1[1], v1[2]); glm_quat_axis(q1, v2); a1 = glm_quat_angle(q1); ASSERT(test_eq(a1, glm_rad(60.0f))) glm_vec3_normalize(v1); ASSERTIFY(test_assert_vec3_eq(v1, v2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_copy) { versor v1 = {10.0f, 9.0f, 8.0f, 78.0f}; versor v2 = {1.0f, 2.0f, 3.0f, 4.0f}; GLM(quat_copy)(v1, v2); ASSERTIFY(test_assert_vec4_eq(v1, v2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_from_vecs) { versor q1, q2, q3, q4, q5, q6, q7; vec3 v1 = {1.f, 0.f, 0.f}, v2 = {1.f, 0.f, 0.f}; /* parallel */ vec3 v3 = {0.f, 1.f, 0.f}, v4 = {1.f, 0.f, 0.f}; /* perpendicular */ vec3 v5 = {0.f, 0.f, 1.f}, v6 = {0.f, 0.f, -1.f}; /* straight */ vec3 v7, v8; /* random */ vec3 v9 = {0.57735026f, 0.57735026f, 0.57735026f}, /* acute */ v10 = {0.70710678f, 0.70710678f, 0.f}; vec3 v11 = {0.87287156f, 0.21821789f, 0.43643578f}, /* obtuse */ v12 = {-0.87287156f, 0.21821789f, 0.43643578f}; vec3 v13 = GLM_VEC3_ZERO_INIT; /* zero */ GLM(quat_from_vecs)(v1, v2, q1); ASSERTIFY(test_assert_quat_eq_identity(q1)) GLM(quat_from_vecs)(v3, v4, q2); GLM(quat_rotatev)(q2, v3, v3); ASSERT(test_eq(GLM(vec3_dot)(v3, v4), 1.f)) ASSERT(test_eq(q2[0], 0.f)) ASSERT(test_eq(q2[1], 0.f)) ASSERT(test_eq(q2[2], -0.707106781187f)) ASSERT(test_eq(q2[3], 0.707106781187f)) GLM(quat_from_vecs)(v5, v6, q3); GLM(quat_rotatev)(q3, v5, v5); ASSERT(test_eq(GLM(vec3_dot)(v5, v6), 1.f)) ASSERT(test_eq(q3[0], 0.f)) ASSERT(test_eq(q3[1], -1.f)) ASSERT(test_eq(q3[2], 0.f)) ASSERT(test_eq(q3[3], 0.f)) test_rand_vec3(v7); test_rand_vec3(v8); GLM(vec3_normalize(v7)); GLM(vec3_normalize(v8)); GLM(quat_from_vecs)(v7, v8, q4); GLM(quat_rotatev)(q4, v7, v7); ASSERT(test_eq(GLM(vec3_dot)(v7, v8), 1.f)) GLM(quat_from_vecs)(v9, v10, q5); GLM(quat_rotatev)(q5, v9, v9); ASSERT(test_eq(GLM(vec3_dot)(v9, v10), 1.f)) GLM(quat_from_vecs)(v11, v12, q6); GLM(quat_rotatev)(q6, v11, v11); ASSERT(test_eq(GLM(vec3_dot)(v11, v12), 1.f)) GLM(quat_from_vecs)(v13, v1, q7); ASSERTIFY(test_assert_quat_eq_identity(q7)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_norm) { versor a = {10.0f, 9.0f, 8.0f, 78.0f}; float n1, n2; n1 = GLM(quat_norm)(a); n2 = sqrtf(a[0] * a[0] + a[1] * a[1] + a[2] * a[2] + a[3] * a[3]); ASSERT(test_eq(n1, n2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_normalize_to) { versor v1 = {2.0f, -3.0f, 4.0f, 5.0f}, v2; float s = 1.0f; float norm; GLM(quat_normalize_to)(v1, v2); norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2] + v1[3] * v1[3]); if (norm <= 0.0f) { ASSERTIFY(test_assert_quat_eq_identity(v1)) TEST_SUCCESS } norm = s / norm; ASSERT(test_eq(v1[0] * norm, v2[0])) ASSERT(test_eq(v1[1] * norm, v2[1])) ASSERT(test_eq(v1[2] * norm, v2[2])) ASSERT(test_eq(v1[3] * norm, v2[3])) glm_vec4_zero(v1); GLM(quat_normalize_to)(v1, v2); ASSERTIFY(test_assert_quat_eq_identity(v2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_normalize) { versor v1 = {2.0f, -3.0f, 4.0f, 5.0f}, v2 = {2.0f, -3.0f, 4.0f, 5.0f}; float s = 1.0f; float norm; GLM(quat_normalize)(v2); norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2] + v1[3] * v1[3]); if (norm <= 0.0f) { ASSERTIFY(test_assert_quat_eq_identity(v1)) TEST_SUCCESS } norm = s / norm; ASSERT(test_eq(v1[0] * norm, v2[0])) ASSERT(test_eq(v1[1] * norm, v2[1])) ASSERT(test_eq(v1[2] * norm, v2[2])) ASSERT(test_eq(v1[3] * norm, v2[3])) glm_vec4_zero(v1); GLM(quat_normalize)(v1); ASSERTIFY(test_assert_quat_eq_identity(v1)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_dot) { versor a = {10.0f, 9.0f, 8.0f, 78.0f}; versor b = {1.0f, 2.0f, 3.0f, 4.0f}; float dot1, dot2; dot1 = GLM(quat_dot)(a, b); dot2 = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; ASSERT(test_eq(dot1, dot2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_conjugate) { versor a = {10.0f, 9.0f, 8.0f, 78.0f}; versor b = {1.0f, 2.0f, 3.0f, 4.0f}; versor d, e; GLM(quat_conjugate)(a, d); GLM(quat_conjugate)(b, e); ASSERT(test_eq(d[0], -a[0])) ASSERT(test_eq(d[1], -a[1])) ASSERT(test_eq(d[2], -a[2])) ASSERT(test_eq(d[3], a[3])) ASSERT(test_eq(e[0], -b[0])) ASSERT(test_eq(e[1], -b[1])) ASSERT(test_eq(e[2], -b[2])) ASSERT(test_eq(e[3], b[3])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_inv) { versor a = {10.0f, 9.0f, 8.0f, 78.0f}; versor b = {1.0f, 2.0f, 3.0f, 4.0f}; versor d, e; float n1, n2; n1 = 1.0f / glm_vec4_norm2(a); n2 = 1.0f / glm_vec4_norm2(b); GLM(quat_inv)(a, d); GLM(quat_inv)(b, e); ASSERT(test_eq(d[0], -a[0] * n1)) ASSERT(test_eq(d[1], -a[1] * n1)) ASSERT(test_eq(d[2], -a[2] * n1)) ASSERT(test_eq(d[3], a[3] * n1)) ASSERT(test_eq(e[0], -b[0] * n2)) ASSERT(test_eq(e[1], -b[1] * n2)) ASSERT(test_eq(e[2], -b[2] * n2)) ASSERT(test_eq(e[3], b[3] * n2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_add) { versor a = {-10.0f, 9.0f, -8.0f, 56.0f}; versor b = {12.0f, 19.0f, -18.0f, 1.0f}; versor c, d; c[0] = a[0] + b[0]; c[1] = a[1] + b[1]; c[2] = a[2] + b[2]; c[3] = a[3] + b[3]; GLM(quat_add)(a, b, d); ASSERTIFY(test_assert_quat_eq(c, d)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_sub) { vec4 a = {-10.0f, 9.0f, -8.0f, 56.0f}; vec4 b = {12.0f, 19.0f, -18.0f, 1.0f}; vec4 c, d; c[0] = a[0] - b[0]; c[1] = a[1] - b[1]; c[2] = a[2] - b[2]; c[3] = a[3] - b[3]; GLM(quat_sub)(a, b, d); ASSERTIFY(test_assert_quat_eq(c, d)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_real) { versor a = {10.0f, 9.0f, 8.0f, 78.0f}; versor b = {1.0f, 2.0f, 3.0f, 4.0f}; ASSERT(test_eq(GLM(quat_real)(a), 78.0f)) ASSERT(test_eq(GLM(quat_real)(b), 4.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_imag) { versor a = {10.0f, 9.0f, 8.0f, 78.0f}; versor b = {1.0f, 2.0f, 3.0f, 4.0f}; vec3 d, e; GLM(quat_imag)(a, d); GLM(quat_imag)(b, e); ASSERT(test_eq(d[0], a[0])) ASSERT(test_eq(d[1], a[1])) ASSERT(test_eq(d[2], a[2])) ASSERT(test_eq(e[0], b[0])) ASSERT(test_eq(e[1], b[1])) ASSERT(test_eq(e[2], b[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_imagn) { versor a = {10.0f, 9.0f, 8.0f, 78.0f}; versor b = {1.0f, 2.0f, 3.0f, 4.0f}; vec3 d, e; GLM(quat_imagn)(a, d); GLM(quat_imagn)(b, e); glm_vec3_normalize(a); glm_vec3_normalize(b); glm_vec3_normalize(d); glm_vec3_normalize(e); ASSERT(test_eq(d[0], a[0])) ASSERT(test_eq(d[1], a[1])) ASSERT(test_eq(d[2], a[2])) ASSERT(test_eq(e[0], b[0])) ASSERT(test_eq(e[1], b[1])) ASSERT(test_eq(e[2], b[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_imaglen) { versor a = {10.0f, 9.0f, 8.0f, 78.0f}; versor b = {1.0f, 2.0f, 3.0f, 4.0f}; ASSERT(test_eq(GLM(quat_imaglen)(a), glm_vec3_norm(a))); ASSERT(test_eq(GLM(quat_imaglen)(b), glm_vec3_norm(b))); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_angle) { versor q1 = {1.0f, 2.0f, 3.0f, 4.0f}, q2, q3; vec3 v1; float a1, a2, a3; test_rand_vec3(v1); GLM(quatv)(q1, glm_rad(60.140f), v1); GLM(quatv)(q2, glm_rad(160.04f), v1); GLM(quatv)(q3, glm_rad(20.350f), v1); a1 = GLM(quat_angle)(q1); a2 = GLM(quat_angle)(q2); a3 = GLM(quat_angle)(q3); ASSERT(test_eq(a1, glm_rad(60.140f))) ASSERT(test_eq(a2, glm_rad(160.04f))) ASSERT(test_eq(a3, glm_rad(20.350f))) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_axis) { versor q1 = {1.0f, 2.0f, 3.0f, 4.0f}, q2, q3; vec3 v1, v2; test_rand_vec3(v1); GLM(quatv)(q1, glm_rad(60.0f), v1); glm_quat_axis(q1, v2); glm_vec3_normalize(v1); ASSERTIFY(test_assert_vec3_eq(v1, v2)) test_rand_vec3(v1); GLM(quatv)(q2, glm_rad(60.0f), v1); glm_quat_axis(q2, v2); glm_vec3_normalize(v1); ASSERTIFY(test_assert_vec3_eq(v1, v2)) test_rand_vec3(v1); GLM(quatv)(q3, glm_rad(60.0f), v1); glm_quat_axis(q3, v2); glm_vec3_normalize(v1); ASSERTIFY(test_assert_vec3_eq(v1, v2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_mul) { versor q1 = {2.0f, 3.0f, 4.0f, 5.0f}; versor q2 = {6.0f, 7.0f, 8.0f, 9.0f}; versor q3; versor q4; vec3 v1 = {1.5f, 2.5f, 3.5f}; GLM(quat_mul)(q1, q2, q3); ASSERT(test_eq(q3[0], q1[3] * q2[0] + q1[0] * q2[3] + q1[1] * q2[2] - q1[2] * q2[1])) ASSERT(test_eq(q3[1], q1[3] * q2[1] - q1[0] * q2[2] + q1[1] * q2[3] + q1[2] * q2[0])) ASSERT(test_eq(q3[2], q1[3] * q2[2] + q1[0] * q2[1] - q1[1] * q2[0] + q1[2] * q2[3])) ASSERT(test_eq(q3[3], q1[3] * q2[3] - q1[0] * q2[0] - q1[1] * q2[1] - q1[2] * q2[2])) glm_quatv(q1, glm_rad(30.0f), v1); glm_quatv(q2, glm_rad(20.0f), v1); glm_quatv(q3, glm_rad(50.0f), v1); GLM(quat_mul)(q1, q2, q4); ASSERTIFY(test_assert_quat_eq(q3, q4)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_mat4) { mat4 m1, m2; versor q1, q2, q3, scaled, original; vec3 axis1; vec3 axis2 = {1.9f, 2.3f, 4.5f}; float scales[] = {2.0f, 0.5f, -2.0f, -0.5f, 1e-10f, 1e10f}; int i; GLM(quat)(q1, GLM_PI_4f, 1.9f, 2.3f, 4.5f); GLM(quat_mat4)(q1, m1); GLM(mat4_quat)(m1, q2); GLM(rotate_make)(m2, GLM_PI_4f, axis2); GLM(mat4_quat)(m1, q3); GLM(quat_axis)(q3, axis1); GLM(vec3_normalize)(axis1); GLM(vec3_normalize)(axis2); ASSERT(test_eq(glm_quat_angle(q3), GLM_PI_4f)) ASSERTIFY(test_assert_vec3_eq(axis1, axis2)) ASSERTIFY(test_assert_vec4_eq(q1, q2)) ASSERTIFY(test_assert_mat4_eq(m1, m2)) ASSERTIFY(test_assert_vec4_eq(q1, q3)) /* 1. test quat to mat and mat to quat */ for (i = 0; i < 1000; i++) { test_rand_quat(q1); GLM(quat_mat4)(q1, m1); GLM(mat4_quat)(m1, q2); GLM(quat_mat4)(q2, m2); /* 2. test first quat and generated one equality */ ASSERTIFY(test_assert_quat_eq_abs(q1, q2)); /* 3. test first rot and second rotation */ /* almost equal */ ASSERTIFY(test_assert_mat4_eq2(m1, m2, 0.000009f)); } /* Scaling a quaternion must not change its rotation or mutate it. */ GLM(quat)(q1, GLM_PI_4f, 1.9f, 2.3f, 4.5f); GLM(rotate_make)(m2, GLM_PI_4f, axis2); for (i = 0; i < (int)(sizeof(scales) / sizeof(scales[0])); i++) { glm_vec4_scale(q1, scales[i], scaled); glm_vec4_copy(scaled, original); GLM(quat_mat4)(scaled, m1); ASSERTIFY(test_assert_mat4_eq(m1, m2)); ASSERT(scaled[0] == original[0] && scaled[1] == original[1]); ASSERT(scaled[2] == original[2] && scaled[3] == original[3]); } /* Issue #503: a non-unit half-turn about Z. */ glm_vec4_zero(scaled); scaled[2] = 2.0f; GLM(quat_mat4)(scaled, m1); glm_mat4_identity(m2); m2[0][0] = m2[1][1] = -1.0f; ASSERTIFY(test_assert_mat4_eq(m1, m2)); /* Normalizing first avoids overflowing 2 / dot for tiny inputs. */ scaled[2] = 1e-20f; GLM(quat_mat4)(scaled, m1); ASSERTIFY(test_assert_mat4_eq2(m1, m2, 0.00002f)); /* Keep the existing identity fallback for a zero quaternion. */ glm_vec4_zero(scaled); GLM(quat_mat4)(scaled, m1); glm_mat4_identity(m2); ASSERTIFY(test_assert_mat4_eq(m1, m2)); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_mat4t) { mat4 m1, m2; versor q1, q2, q3, scaled, original; vec3 axis1; vec3 axis2 = {1.9f, 2.3f, 4.5f}; float scales[] = {2.0f, 0.5f, -2.0f, -0.5f, 1e-10f, 1e10f}; int i; GLM(quat)(q1, GLM_PI_4f, 1.9f, 2.3f, 4.5f); GLM(quat_mat4t)(q1, m1); glm_mat4_transpose(m1); GLM(mat4_quat)(m1, q2); GLM(rotate_make)(m2, GLM_PI_4f, axis2); GLM(mat4_quat)(m1, q3); GLM(quat_axis)(q3, axis1); GLM(vec3_normalize)(axis1); GLM(vec3_normalize)(axis2); ASSERT(test_eq(glm_quat_angle(q3), GLM_PI_4f)) ASSERTIFY(test_assert_vec3_eq(axis1, axis2)) ASSERTIFY(test_assert_vec4_eq(q1, q2)) ASSERTIFY(test_assert_mat4_eq(m1, m2)) ASSERTIFY(test_assert_vec4_eq(q1, q3)) /* 1. test quat to mat and mat to quat */ for (i = 0; i < 1000; i++) { test_rand_quat(q1); GLM(quat_mat4t)(q1, m1); glm_mat4_transpose(m1); GLM(mat4_quat)(m1, q2); GLM(quat_mat4t)(q2, m2); glm_mat4_transpose(m2); /* 2. test first quat and generated one equality */ ASSERTIFY(test_assert_quat_eq_abs(q1, q2)); /* 3. test first rot and second rotation */ /* almost equal */ ASSERTIFY(test_assert_mat4_eq2(m1, m2, 0.000009f)); } /* Scaling a quaternion must not change its rotation or mutate it. */ GLM(quat)(q1, GLM_PI_4f, 1.9f, 2.3f, 4.5f); GLM(rotate_make)(m2, GLM_PI_4f, axis2); for (i = 0; i < (int)(sizeof(scales) / sizeof(scales[0])); i++) { glm_vec4_scale(q1, scales[i], scaled); glm_vec4_copy(scaled, original); GLM(quat_mat4t)(scaled, m1); glm_mat4_transpose(m1); ASSERTIFY(test_assert_mat4_eq(m1, m2)); ASSERT(scaled[0] == original[0] && scaled[1] == original[1]); ASSERT(scaled[2] == original[2] && scaled[3] == original[3]); } /* Issue #503: a non-unit half-turn about Z. */ glm_vec4_zero(scaled); scaled[2] = 2.0f; GLM(quat_mat4t)(scaled, m1); glm_mat4_transpose(m1); glm_mat4_identity(m2); m2[0][0] = m2[1][1] = -1.0f; ASSERTIFY(test_assert_mat4_eq(m1, m2)); /* Normalizing first avoids overflowing 2 / dot for tiny inputs. */ scaled[2] = 1e-20f; GLM(quat_mat4t)(scaled, m1); glm_mat4_transpose(m1); ASSERTIFY(test_assert_mat4_eq2(m1, m2, 0.00002f)); /* Keep the existing identity fallback for a zero quaternion. */ glm_vec4_zero(scaled); GLM(quat_mat4t)(scaled, m1); glm_mat4_transpose(m1); glm_mat4_identity(m2); ASSERTIFY(test_assert_mat4_eq(m1, m2)); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_mat3) { mat4 m1, m2; mat3 m3; versor q1, q2, q3, scaled, original; vec3 axis1; vec3 axis2 = {1.9f, 2.3f, 4.5f}; float scales[] = {2.0f, 0.5f, -2.0f, -0.5f, 1e-10f, 1e10f}; int i; GLM(quat)(q1, GLM_PI_4f, 1.9f, 2.3f, 4.5f); GLM(quat_mat3)(q1, m3); glm_mat4_identity(m1); glm_mat4_ins3(m3, m1); GLM(mat4_quat)(m1, q2); GLM(rotate_make)(m2, GLM_PI_4f, axis2); GLM(mat4_quat)(m1, q3); GLM(quat_axis)(q3, axis1); GLM(vec3_normalize)(axis1); GLM(vec3_normalize)(axis2); ASSERT(test_eq(glm_quat_angle(q3), GLM_PI_4f)) ASSERTIFY(test_assert_vec3_eq(axis1, axis2)) ASSERTIFY(test_assert_vec4_eq(q1, q2)) ASSERTIFY(test_assert_mat4_eq(m1, m2)) ASSERTIFY(test_assert_vec4_eq(q1, q3)) /* 1. test quat to mat and mat to quat */ for (i = 0; i < 1000; i++) { test_rand_quat(q1); GLM(quat_mat3)(q1, m3); glm_mat4_identity(m1); glm_mat4_ins3(m3, m1); GLM(mat4_quat)(m1, q2); GLM(quat_mat3)(q2, m3); glm_mat4_identity(m2); glm_mat4_ins3(m3, m2); /* 2. test first quat and generated one equality */ ASSERTIFY(test_assert_quat_eq_abs(q1, q2)); /* 3. test first rot and second rotation */ /* almost equal */ ASSERTIFY(test_assert_mat4_eq2(m1, m2, 0.000009f)); } /* Scaling a quaternion must not change its rotation or mutate it. */ GLM(quat)(q1, GLM_PI_4f, 1.9f, 2.3f, 4.5f); GLM(rotate_make)(m2, GLM_PI_4f, axis2); for (i = 0; i < (int)(sizeof(scales) / sizeof(scales[0])); i++) { glm_vec4_scale(q1, scales[i], scaled); glm_vec4_copy(scaled, original); GLM(quat_mat3)(scaled, m3); glm_mat4_identity(m1); glm_mat4_ins3(m3, m1); ASSERTIFY(test_assert_mat4_eq(m1, m2)); ASSERT(scaled[0] == original[0] && scaled[1] == original[1]); ASSERT(scaled[2] == original[2] && scaled[3] == original[3]); } /* Issue #503: a non-unit half-turn about Z. */ glm_vec4_zero(scaled); scaled[2] = 2.0f; GLM(quat_mat3)(scaled, m3); glm_mat4_identity(m1); glm_mat4_ins3(m3, m1); glm_mat4_identity(m2); m2[0][0] = m2[1][1] = -1.0f; ASSERTIFY(test_assert_mat4_eq(m1, m2)); /* Normalizing first avoids overflowing 2 / dot for tiny inputs. */ scaled[2] = 1e-20f; GLM(quat_mat3)(scaled, m3); glm_mat4_identity(m1); glm_mat4_ins3(m3, m1); ASSERTIFY(test_assert_mat4_eq2(m1, m2, 0.00002f)); /* Keep the existing identity fallback for a zero quaternion. */ glm_vec4_zero(scaled); GLM(quat_mat3)(scaled, m3); glm_mat4_identity(m1); glm_mat4_ins3(m3, m1); glm_mat4_identity(m2); ASSERTIFY(test_assert_mat4_eq(m1, m2)); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_mat3t) { mat4 m1, m2; mat3 m3; versor q1, q2, q3, scaled, original; vec3 axis1; vec3 axis2 = {1.9f, 2.3f, 4.5f}; float scales[] = {2.0f, 0.5f, -2.0f, -0.5f, 1e-10f, 1e10f}; int i; GLM(quat)(q1, GLM_PI_4f, 1.9f, 2.3f, 4.5f); GLM(quat_mat3t)(q1, m3); glm_mat3_transpose(m3); glm_mat4_identity(m1); glm_mat4_ins3(m3, m1); GLM(mat4_quat)(m1, q2); GLM(rotate_make)(m2, GLM_PI_4f, axis2); GLM(mat4_quat)(m1, q3); GLM(quat_axis)(q3, axis1); GLM(vec3_normalize)(axis1); GLM(vec3_normalize)(axis2); ASSERT(test_eq(glm_quat_angle(q3), GLM_PI_4f)) ASSERTIFY(test_assert_vec3_eq(axis1, axis2)) ASSERTIFY(test_assert_vec4_eq(q1, q2)) ASSERTIFY(test_assert_mat4_eq(m1, m2)) ASSERTIFY(test_assert_vec4_eq(q1, q3)) /* 1. test quat to mat and mat to quat */ for (i = 0; i < 1000; i++) { test_rand_quat(q1); GLM(quat_mat3t)(q1, m3); glm_mat3_transpose(m3); glm_mat4_identity(m1); glm_mat4_ins3(m3, m1); GLM(mat4_quat)(m1, q2); GLM(quat_mat3t)(q2, m3); glm_mat3_transpose(m3); glm_mat4_identity(m2); glm_mat4_ins3(m3, m2); /* 2. test first quat and generated one equality */ ASSERTIFY(test_assert_quat_eq_abs(q1, q2)); /* 3. test first rot and second rotation */ /* almost equal */ ASSERTIFY(test_assert_mat4_eq2(m1, m2, 0.000009f)); } /* Scaling a quaternion must not change its rotation or mutate it. */ GLM(quat)(q1, GLM_PI_4f, 1.9f, 2.3f, 4.5f); GLM(rotate_make)(m2, GLM_PI_4f, axis2); for (i = 0; i < (int)(sizeof(scales) / sizeof(scales[0])); i++) { glm_vec4_scale(q1, scales[i], scaled); glm_vec4_copy(scaled, original); GLM(quat_mat3t)(scaled, m3); glm_mat3_transpose(m3); glm_mat4_identity(m1); glm_mat4_ins3(m3, m1); ASSERTIFY(test_assert_mat4_eq(m1, m2)); ASSERT(scaled[0] == original[0] && scaled[1] == original[1]); ASSERT(scaled[2] == original[2] && scaled[3] == original[3]); } /* Issue #503: a non-unit half-turn about Z. */ glm_vec4_zero(scaled); scaled[2] = 2.0f; GLM(quat_mat3t)(scaled, m3); glm_mat3_transpose(m3); glm_mat4_identity(m1); glm_mat4_ins3(m3, m1); glm_mat4_identity(m2); m2[0][0] = m2[1][1] = -1.0f; ASSERTIFY(test_assert_mat4_eq(m1, m2)); /* Normalizing first avoids overflowing 2 / dot for tiny inputs. */ scaled[2] = 1e-20f; GLM(quat_mat3t)(scaled, m3); glm_mat3_transpose(m3); glm_mat4_identity(m1); glm_mat4_ins3(m3, m1); ASSERTIFY(test_assert_mat4_eq2(m1, m2, 0.00002f)); /* Keep the existing identity fallback for a zero quaternion. */ glm_vec4_zero(scaled); GLM(quat_mat3t)(scaled, m3); glm_mat3_transpose(m3); glm_mat4_identity(m1); glm_mat4_ins3(m3, m1); glm_mat4_identity(m2); ASSERTIFY(test_assert_mat4_eq(m1, m2)); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_lerp) { versor v1 = {-100.0f, -200.0f, -10.0f, -10.0f}; versor v2 = {100.0f, 200.0f, 10.0f, 10.0f}; versor v3; GLM(quat_lerp)(v1, v2, 0.5f, v3); ASSERT(test_eq(v3[0], 0.0f)) ASSERT(test_eq(v3[1], 0.0f)) ASSERT(test_eq(v3[2], 0.0f)) ASSERT(test_eq(v3[3], 0.0f)) GLM(quat_lerp)(v1, v2, 0.75f, v3); ASSERT(test_eq(v3[0], 50.0f)) ASSERT(test_eq(v3[1], 100.0f)) ASSERT(test_eq(v3[2], 5.0f)) ASSERT(test_eq(v3[3], 5.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_lerpc) { versor v1 = {-100.0f, -200.0f, -10.0f, -10.0f}; versor v2 = {100.0f, 200.0f, 10.0f, 10.0f}; versor v3; GLM(quat_lerpc)(v1, v2, 0.5f, v3); ASSERT(test_eq(v3[0], 0.0f)) ASSERT(test_eq(v3[1], 0.0f)) ASSERT(test_eq(v3[2], 0.0f)) ASSERT(test_eq(v3[3], 0.0f)) GLM(quat_lerpc)(v1, v2, 0.75f, v3); ASSERT(test_eq(v3[0], 50.0f)) ASSERT(test_eq(v3[1], 100.0f)) ASSERT(test_eq(v3[2], 5.0f)) ASSERT(test_eq(v3[3], 5.0f)) GLM(quat_lerpc)(v1, v2, -1.75f, v3); ASSERT(test_eq(v3[0], -100.0f)) ASSERT(test_eq(v3[1], -200.0f)) ASSERT(test_eq(v3[2], -10.0f)) ASSERT(test_eq(v3[3], -10.0f)) GLM(quat_lerpc)(v1, v2, 1.75f, v3); ASSERT(test_eq(v3[0], 100.0f)) ASSERT(test_eq(v3[1], 200.0f)) ASSERT(test_eq(v3[2], 10.0f)) ASSERT(test_eq(v3[3], 10.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_nlerp) { versor q1, q2, q3, q4; vec3 v1 = {10.0f, 0.0f, 0.0f}, v2; glm_quatv(q1, glm_rad(30.0f), v1); glm_quatv(q2, glm_rad(90.0f), v1); GLM(quat_nlerp)(q1, q2, 1.0f, q3); glm_quat_normalize(q2); ASSERTIFY(test_assert_quat_eq(q2, q3)); glm_quatv(q1, glm_rad(30.001f), v1); glm_quatv(q2, glm_rad(30.002f), v1); GLM(quat_nlerp)(q1, q2, 0.7f, q3); glm_quat_lerp(q1, q2, 0.7f, q4); ASSERTIFY(test_assert_quat_eq(q3, q4)); glm_quatv(q1, glm_rad(30.0f), v1); glm_quatv(q2, glm_rad(90.0f), v1); GLM(quat_nlerp)(q1, q2, 0.5f, q3); glm_quat_axis(q3, v2); glm_vec3_normalize(v1); glm_vec3_normalize(v2); ASSERT(glm_quat_angle(q3) > glm_rad(30.0f)); ASSERT(glm_quat_angle(q3) < glm_rad(90.0f)); ASSERTIFY(test_assert_vec3_eq(v1, v2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_slerp) { versor q1, q2, q3, q4; vec3 v1 = {10.0f, 0.0f, 0.0f}, v2; glm_quatv(q1, glm_rad(30.0f), v1); glm_quatv(q2, glm_rad(90.0f), v1); q1[0] = 10.0f; GLM(quat_slerp)(q1, q2, 1.0f, q3); ASSERTIFY(test_assert_quat_eq(q1, q3)); glm_quatv(q1, glm_rad(30.001f), v1); glm_quatv(q2, glm_rad(30.002f), v1); GLM(quat_slerp)(q1, q2, 0.7f, q3); glm_quat_lerp(q1, q2, 0.7f, q4); ASSERTIFY(test_assert_quat_eq(q3, q4)); glm_quatv(q1, glm_rad(30.0f), v1); glm_quatv(q2, glm_rad(90.0f), v1); GLM(quat_slerp)(q1, q2, 0.5f, q3); glm_quat_axis(q3, v2); glm_vec3_normalize(v1); glm_vec3_normalize(v2); ASSERT(glm_quat_angle(q3) > glm_rad(30.0f)); ASSERT(glm_quat_angle(q3) < glm_rad(90.0f)); ASSERTIFY(test_assert_vec3_eq(v1, v2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_look) { versor q1; vec3 v1 = {0.0f, 1.0f, 0.0f}; mat4 m1, m2; glm_quat(q1, glm_rad(90.0f), 0.0f, 1.0f, 0.0f); GLM(quat_look)(v1, q1, m1); glm_look(v1, (vec3){-1.0f, 0.0f, 0.0f}, GLM_YUP, m2); ASSERTIFY(test_assert_mat4_eq(m1, m2)); glm_quat(q1, glm_rad(180.0f), 1.0f, 0.0f, 0.0f); GLM(quat_look)(v1, q1, m1); glm_look(v1, (vec3){0.0f, 0.0f, 1.0f}, (vec3){0.0f, -1.0f, 0.0f}, m2); ASSERTIFY(test_assert_mat4_eq(m1, m2)); /* A scaled orientation must yield the same camera view. */ glm_vec4_scale(q1, -2.0f, q1); GLM(quat_look)(v1, q1, m1); ASSERTIFY(test_assert_mat4_eq(m1, m2)); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_for) { versor q1, q2; glm_quat(q1, glm_rad(90.0f), 0.0f, 1.0f, 0.0f); GLM(quat_for)((vec3){-1.0f, 0.0f, 0.0f}, (vec3){0.0f, 1.0f, 0.0f}, q2); ASSERTIFY(test_assert_quat_eq(q1, q2)); glm_quat(q2, glm_rad(90.0f), 1.0f, 0.0f, 0.0f); GLM(quat_for)((vec3){0.0f, 1.0f, 0.0f}, (vec3){0.0f, 0.0f, 1.0f}, q1); ASSERTIFY(test_assert_quat_eq(q1, q2)); glm_quat(q2, glm_rad(180.0f), 1.0f, 0.0f, 0.0f); GLM(quat_for)((vec3){0.0f, 0.0f, 1.0f}, (vec3){0.0f, -1.0f, 0.0f}, q1); ASSERTIFY(test_assert_quat_eq(q1, q2)); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_forp) { versor q1, q2; glm_quat(q1, glm_rad(90.0f), 0.0f, 1.0f, 0.0f); GLM(quat_forp)((vec3){2.0f, 0.0f, 0.0f}, (vec3){1.0f, 0.0f, 0.0f}, (vec3){0.0f, 1.0f, 0.0f}, q2); ASSERTIFY(test_assert_quat_eq(q1, q2)); glm_quat(q2, glm_rad(90.0f), 1.0f, 0.0f, 0.0f); GLM(quat_forp)((vec3){0.0f, 1.0f, 0.0f}, (vec3){0.0f, 2.0f, 0.0f}, (vec3){0.0f, 0.0f, 1.0f}, q1); ASSERTIFY(test_assert_quat_eq(q1, q2)); glm_quat(q2, glm_rad(180.0f), 1.0f, 0.0f, 0.0f); GLM(quat_forp)((vec3){0.0f, 1.0f, 1.0f}, (vec3){0.0f, 1.0f, 2.0f}, (vec3){0.0f, -1.0f, 0.0f}, q1); ASSERTIFY(test_assert_quat_eq(q1, q2)); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_rotatev) { vec3 v1 = {1.0f, 0.0f, 0.0f}, v2 = {1.0f, 1.0f, 1.0f}; versor q; /* rotate X around Y = -Z */ glm_quatv(q, GLM_PI_2f, GLM_YUP); GLM(quat_rotatev)(q, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], -1.0f)) /* rotate -Z around X = Y */ glm_quatv(q, GLM_PI_2f, GLM_XUP); GLM(quat_rotatev)(q, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 1.0f)) ASSERT(test_eq(v1[2], 0.0f)) /* rotate Y around Z = -X */ glm_quatv(q, GLM_PI_2f, GLM_ZUP); GLM(quat_rotatev)(q, v1, v1); ASSERT(test_eq(v1[0], -1.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 0.0f)) /* rotate v2 around Y by 90deg */ glm_quatv(q, GLM_PI_2f, GLM_YUP); GLM(quat_rotatev)(q, v2, v2); ASSERT(test_eq(v2[0], 1.0f)) ASSERT(test_eq(v2[1], 1.0f)) ASSERT(test_eq(v2[2], -1.0f)) /* rotate v2 around Y by 90deg */ glm_quatv(q, GLM_PI_2f, GLM_YUP); GLM(quat_rotatev)(q, v2, v2); ASSERT(test_eq(v2[0], -1.0f)) ASSERT(test_eq(v2[1], 1.0f)) ASSERT(test_eq(v2[2], -1.0f)) /* rotate v2 around Y by 90deg */ glm_quatv(q, GLM_PI_2f, GLM_YUP); GLM(quat_rotatev)(q, v2, v2); ASSERT(test_eq(v2[0], -1.0f)) ASSERT(test_eq(v2[1], 1.0f)) ASSERT(test_eq(v2[2], 1.0f)) /* rotate v2 around X by 90deg */ glm_quatv(q, GLM_PI_2f, GLM_XUP); GLM(quat_rotatev)(q, v2, v2); ASSERT(test_eq(v2[0], -1.0f)) ASSERT(test_eq(v2[1], -1.0f)) ASSERT(test_eq(v2[2], 1.0f)) /* rotate v2 around Z by 90deg */ glm_quatv(q, GLM_PI_2f, GLM_ZUP); GLM(quat_rotatev)(q, v2, v2); ASSERT(test_eq(v2[0], 1.0f)) ASSERT(test_eq(v2[1], -1.0f)) ASSERT(test_eq(v2[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_rotate) { mat4 m1 = GLM_MAT4_IDENTITY_INIT, m2; versor q1; vec4 v1 = {1.0f, 0.0f, 0.0f, 1.0f}; /* rotate X around Y = -Z */ glm_quatv(q1, GLM_PI_2f, GLM_YUP); GLM(quat_rotate)(m1, q1, m1); glm_rotate_make(m2, GLM_PI_2f, GLM_YUP); ASSERTIFY(test_assert_mat4_eq(m1, m2)) glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], -1.0f)) glm_mat4_identity(m1); glm_mat4_identity(m2); /* rotate -Z around X = Y */ glm_quatv(q1, GLM_PI_2f, GLM_XUP); GLM(quat_rotate)(m1, q1, m1); glm_rotate(m2, GLM_PI_2f, GLM_XUP); ASSERTIFY(test_assert_mat4_eq(m1, m2)) glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 1.0f)) ASSERT(test_eq(v1[2], 0.0f)) glm_mat4_identity(m1); glm_mat4_identity(m2); /* rotate Y around X = +Z */ glm_quatv(q1, GLM_PI_2f, GLM_XUP); GLM(quat_rotate)(m1, q1, m1); glm_rotate(m2, GLM_PI_2f, GLM_XUP); ASSERTIFY(test_assert_mat4_eq(m1, m2)) glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 1.0f)) /* Non-unit orientation must not add scaling to the transform. */ glm_mat4_identity(m1); glm_mat4_identity(m2); glm_quatv(q1, GLM_PI_2f, GLM_YUP); glm_vec4_scale(q1, 2.0f, q1); GLM(quat_rotate)(m1, q1, m1); glm_rotate(m2, GLM_PI_2f, GLM_YUP); ASSERTIFY(test_assert_mat4_eq(m1, m2)); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_rotate_at) { mat4 m1 = GLM_MAT4_IDENTITY_INIT; versor q1; vec4 v1 = {1.0f, 0.0f, 0.0f, 1.0f}; glm_quatv(q1, GLM_PI_2f, GLM_YUP); GLM(quat_rotate_at)(m1, q1, (vec3){0.5f, 0.0f, 0.0f}); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.5f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], -0.5f)) glm_mat4_identity(m1); glm_quatv(q1, GLM_PI_2f, GLM_ZUP); GLM(quat_rotate_at)(m1, q1, (vec3){0.0f, 0.0f, 0.0f}); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.5f)) ASSERT(test_eq(v1[2], -0.5f)) glm_mat4_identity(m1); v1[0] = 1.0f; v1[1] = 1.0f; v1[2] = 1.0f; glm_quatv(q1, GLM_PI_2f, GLM_XUP); GLM(quat_rotate_at)(m1, q1, GLM_VEC3_ZERO); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 1.0f)) ASSERT(test_eq(v1[1], -1.0f)) ASSERT(test_eq(v1[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_rotate_atm) { mat4 m1 = GLM_MAT4_IDENTITY_INIT; versor q1; vec4 v1 = {1.0f, 0.0f, 0.0f, 1.0f}; glm_quatv(q1, GLM_PI_2f, GLM_YUP); GLM(quat_rotate_atm)(m1, q1, (vec3){0.5f, 0.0f, 0.0f}); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.5f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], -0.5f)) glm_quatv(q1, GLM_PI_2f, GLM_ZUP); GLM(quat_rotate_atm)(m1, q1, (vec3){0.0f, 0.0f, 0.0f}); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.5f)) ASSERT(test_eq(v1[2], -0.5f)) v1[0] = 1.0f; v1[1] = 1.0f; v1[2] = 1.0f; glm_quatv(q1, GLM_PI_2f, GLM_XUP); GLM(quat_rotate_atm)(m1, q1, GLM_VEC3_ZERO); glm_mat4_mulv(m1, v1, v1); ASSERT(test_eq(v1[0], 1.0f)) ASSERT(test_eq(v1[1], -1.0f)) ASSERT(test_eq(v1[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, quat_make) { versor dest[3]; float src[12] = { 7.2f, 1.0f, 2.5f, 6.1f, 0.2f, 2.8f, 17.3f, 5.1f, 4.2f, 7.3f, 6.6f, 8.8f }; float *srcp = src; unsigned int i, j; for (i = 0, j = 0; i < sizeof(src) / sizeof(float); i+=4,j++) { GLM(quat_make)(srcp + i, dest[j]); ASSERT(test_eq(src[ i ], dest[j][0])); ASSERT(test_eq(src[i+1], dest[j][1])); ASSERT(test_eq(src[i+2], dest[j][2])); ASSERT(test_eq(src[i+3], dest[j][3])); } TEST_SUCCESS } cglm-0.9.7/test/src/test_ray.h000066400000000000000000000050121526744317200162330ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" TEST_IMPL(GLM_PREFIX, ray_triangle) { /* Check whether a simple hit is recognized with the right distance */ vec3 origin = { 0.0f, 0.0f, 0.0f}; vec3 direction = { 1.0f, 0.0f, 0.0f}; vec3 opposite = {-1.0f, 0.0f, 0.0f}; vec3 v0 = { 5.0f, -1.0f, 1.0f}; vec3 v1 = { 5.0f, -1.0f, -1.0f}; vec3 v2 = { 5.0f, 1.0f, 0.0f}; float d; bool hit; hit = GLM(ray_triangle)(origin, direction, v0, v1, v2, &d); ASSERT(hit); ASSERT(fabsf(d - 5.0f) <= 0.0000009f); /* Check whether a simple miss works */ hit = GLM(ray_triangle)(origin, opposite, v0, v1, v2, &d); ASSERT(!hit); /* Check that we can disregard distance and pass NULL pointer instead */ hit = GLM(ray_triangle)(origin, direction, v0, v1, v2, NULL); ASSERT(hit); TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ray_sphere) { vec4 sphere = {5.0f, 0.0f, 0.0f, 1.0f}; /* Sphere: center at (5, 0, 0) with radius 1 */ float t1, t2; bool hit; /* Case 1: Ray misses the sphere */ hit = GLM(ray_sphere)((vec3){10.0f, 3.0f, 0.0f}, (vec3){1.0f, 0.0f, 0.0f}, sphere, &t1, &t2); ASSERT(!hit); /* Expect no intersection */ /* Case 2: Ray starts inside the sphere */ hit = GLM(ray_sphere)((vec3){5.0f, 0.5f, 0.0f}, (vec3){1.0f, 0.0f, 0.0f}, sphere, &t1, &t2); ASSERT(hit); /* Expect an intersection */ ASSERT(t1 < 0 && t2 > 0); /* Ray exits at t2 */ /* Case 3: Ray intersects the sphere from outside */ hit = GLM(ray_sphere)((vec3){0.0f, 0.0f, 0.0f}, (vec3){1.0f, 0.0f, 0.0f}, sphere, &t1, &t2); ASSERT(hit); /* Expect an intersection */ ASSERT(t1 > 0 && t2 > 0); /* Intersections at t1 and t2 */ TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, ray_at) { vec3 origin = {0.0f, 0.0f, 0.0f}; vec3 direction = {1.0f, 1.0f, 1.0f}; /* Diagonal direction */ float distance = sqrtf(3.0f); /* Distance along the ray; sqrt(3) for unit length due to direction normalization */ vec3 result; /* Normalize the direction to ensure accurate distance measurement */ glm_vec3_normalize(direction); GLM(ray_at)(origin, direction, distance, result); ASSERT(fabsf(result[0] - 1.0f) <= 0.0000009f); /* Expecting to be 1 unit along the x-axis */ ASSERT(fabsf(result[1] - 1.0f) <= 0.0000009f); /* Expecting to be 1 unit along the y-axis */ ASSERT(fabsf(result[2] - 1.0f) <= 0.0000009f); /* Expecting to be 1 unit along the z-axis */ TEST_SUCCESS } cglm-0.9.7/test/src/test_struct.c000066400000000000000000000117341526744317200167670ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" TEST_IMPL(mat2x3s_zero_init) { mat2x3s mat2x3_zero = GLMS_MAT2X3_ZERO_INIT; test_assert_mat2x3_eq_zero(mat2x3_zero.raw); TEST_SUCCESS } TEST_IMPL(mat2x3s_zero) { mat2x3s mat2x3_zero = GLMS_MAT2X3_ZERO; test_assert_mat2x3_eq_zero(mat2x3_zero.raw); TEST_SUCCESS } TEST_IMPL(mat2x4s_zero_init) { mat2x4s mat2x4_zero = GLMS_MAT2X4_ZERO_INIT; test_assert_mat2x4_eq_zero(mat2x4_zero.raw); TEST_SUCCESS } TEST_IMPL(mat2x4s_zero) { mat2x4s mat2x4_zero = GLMS_MAT2X4_ZERO; test_assert_mat2x4_eq_zero(mat2x4_zero.raw); TEST_SUCCESS } TEST_IMPL(mat3s_identity_init) { mat3s mat3_identity = GLMS_MAT3_IDENTITY_INIT; mat3 mat3_identity_a = GLM_MAT3_IDENTITY_INIT; test_assert_mat3_eq(mat3_identity.raw, mat3_identity_a); TEST_SUCCESS } TEST_IMPL(mat3s_zero_init) { mat3s mat3_zero = GLMS_MAT3_ZERO_INIT; mat3 mat3_zero_a = GLM_MAT3_ZERO_INIT; test_assert_mat3_eq(mat3_zero.raw, mat3_zero_a); TEST_SUCCESS } TEST_IMPL(mat3x2s_zero_init) { mat3x2s mat3x2_zero = GLMS_MAT3X2_ZERO_INIT; test_assert_mat3x2_eq_zero(mat3x2_zero.raw); TEST_SUCCESS } TEST_IMPL(mat3x2s_zero) { mat3x2s mat3x2_zero = GLMS_MAT3X2_ZERO; test_assert_mat3x2_eq_zero(mat3x2_zero.raw); TEST_SUCCESS } TEST_IMPL(mat3x4s_zero_init) { mat3x4s mat3x4_zero = GLMS_MAT3X4_ZERO_INIT; test_assert_mat3x4_eq_zero(mat3x4_zero.raw); TEST_SUCCESS } TEST_IMPL(mat3x4s_zero) { mat3x4s mat3x4_zero = GLMS_MAT3X4_ZERO; test_assert_mat3x4_eq_zero(mat3x4_zero.raw); TEST_SUCCESS } TEST_IMPL(mat4s_identity_init) { mat4s mat4_identity = GLMS_MAT4_IDENTITY_INIT; mat4 mat4_identity_a = GLM_MAT4_IDENTITY_INIT; test_assert_mat4_eq(mat4_identity.raw, mat4_identity_a); TEST_SUCCESS } TEST_IMPL(mat4s_zero_init) { mat4s mat4_zero = GLMS_MAT4_ZERO_INIT; mat4 mat4_zero_a = GLM_MAT4_ZERO_INIT; test_assert_mat4_eq(mat4_zero.raw, mat4_zero_a); TEST_SUCCESS } TEST_IMPL(mat4x2s_zero_init) { mat4x2s mat4x2_zero = GLMS_MAT4X2_ZERO_INIT; test_assert_mat4x2_eq_zero(mat4x2_zero.raw); TEST_SUCCESS } TEST_IMPL(mat4x2s_zero) { mat4x2s mat4x2_zero = GLMS_MAT4X2_ZERO; test_assert_mat4x2_eq_zero(mat4x2_zero.raw); TEST_SUCCESS } TEST_IMPL(mat4x3s_zero_init) { mat4x3s mat4x3_zero = GLMS_MAT4X3_ZERO_INIT; test_assert_mat4x3_eq_zero(mat4x3_zero.raw); TEST_SUCCESS } TEST_IMPL(mat4x3s_zero) { mat4x3s mat4x3_zero = GLMS_MAT4X3_ZERO; test_assert_mat4x3_eq_zero(mat4x3_zero.raw); TEST_SUCCESS } TEST_IMPL(quats_zero_init) { versors quat_zero = GLMS_QUAT_IDENTITY_INIT; versor quat_zero_a = GLM_QUAT_IDENTITY_INIT; test_assert_quat_eq(quat_zero.raw, quat_zero_a); TEST_SUCCESS } TEST_IMPL(quats_mat_nonunit) { versors q = {{0.0f, 0.0f, 2.0f, 0.0f}}; mat4s m4; mat3s m3; mat4 expected4 = GLM_MAT4_IDENTITY_INIT; mat3 expected3 = GLM_MAT3_IDENTITY_INIT; expected4[0][0] = expected4[1][1] = -1.0f; expected3[0][0] = expected3[1][1] = -1.0f; m4 = glms_quat_mat4(q); ASSERTIFY(test_assert_mat4_eq(m4.raw, expected4)); m4 = glms_quat_mat4t(q); ASSERTIFY(test_assert_mat4_eq(m4.raw, expected4)); m3 = glms_quat_mat3(q); ASSERTIFY(test_assert_mat3_eq(m3.raw, expected3)); m3 = glms_quat_mat3t(q); ASSERTIFY(test_assert_mat3_eq(m3.raw, expected3)); TEST_SUCCESS } TEST_IMPL(vec3s_one_init) { vec3s vec3_one = GLMS_VEC3_ONE_INIT; vec3 vec3_one_a = GLM_VEC3_ONE_INIT; test_assert_vec3_eq(vec3_one.raw, vec3_one_a); TEST_SUCCESS } TEST_IMPL(vec3s_zero_init) { vec3s vec3_zero = GLMS_VEC3_ZERO_INIT; vec3 vec3_zero_a = GLM_VEC3_ZERO_INIT; test_assert_vec3_eq(vec3_zero.raw, vec3_zero_a); TEST_SUCCESS } TEST_IMPL(vec4s_black_init) { vec4s vec4_black = GLMS_VEC4_BLACK_INIT; vec4 vec4_black_a = GLM_VEC4_BLACK_INIT; test_assert_vec4_eq(vec4_black.raw, vec4_black_a); TEST_SUCCESS } TEST_IMPL(vec4s_one_init) { vec4s vec4_one = GLMS_VEC4_ONE_INIT; vec4 vec4_one_a = GLM_VEC4_ONE_INIT; test_assert_vec4_eq(vec4_one.raw, vec4_one_a); TEST_SUCCESS } TEST_IMPL(vec4s_zero_init) { vec4s vec4_zero = GLMS_VEC4_ZERO_INIT; vec4 vec4_zero_a = GLM_VEC4_ZERO_INIT; test_assert_vec4_eq(vec4_zero.raw, vec4_zero_a); TEST_SUCCESS } TEST_IMPL(mat4s_spin) { mat4s m, result; mat4 expected = {{ 0.0f, 1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, 1.0f, 0.0f}, { 5.0f, 0.0f, 0.0f, 1.0f}}; glm_translate_make(m.raw, (vec3){5.0f, 0.0f, 0.0f}); result = glms_spin(m, GLM_PI_2f, (vec3s){{0.0f, 0.0f, 1.0f}}); ASSERTIFY(test_assert_mat4_eq(result.raw, expected)); ASSERTIFY(test_assert_mat4_eq(m.raw, (mat4){{1.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f, 0.0f}, {5.0f, 0.0f, 0.0f, 1.0f}})); TEST_SUCCESS } cglm-0.9.7/test/src/test_vec2.h000066400000000000000000000475061526744317200163150ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" #ifndef CGLM_TEST_VEC2_ONCE #define CGLM_TEST_VEC2_ONCE /* Macros */ TEST_IMPL(MACRO_GLM_VEC2_ONE_INIT) { vec2 v = GLM_VEC2_ONE_INIT; ASSERT(test_eq(v[0], 1.0f)) ASSERT(test_eq(v[1], 1.0f)) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_VEC2_ZERO_INIT) { vec2 v = GLM_VEC2_ZERO_INIT; ASSERT(test_eq(v[0], 0.0f)) ASSERT(test_eq(v[1], 0.0f)) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_VEC2_ONE) { ASSERT(test_eq(GLM_VEC2_ONE[0], 1.0f)) ASSERT(test_eq(GLM_VEC2_ONE[1], 1.0f)) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_VEC2_ZERO) { ASSERT(test_eq(GLM_VEC2_ZERO[0], 0.0f)) ASSERT(test_eq(GLM_VEC2_ZERO[0], 0.0f)) TEST_SUCCESS } #endif /* CGLM_TEST_VEC2_ONCE */ TEST_IMPL(GLM_PREFIX, vec2) { vec4 v4 = {10.0f, 9.0f, 8.0f, 7.0f}; vec3 v3 = {11.0f, 12.0f, 13.0f}; vec2 v2; GLM(vec2)(v4, v2); ASSERT(test_eq(v2[0], v4[0])) ASSERT(test_eq(v2[1], v4[1])) GLM(vec2)(v3, v2); ASSERT(test_eq(v2[0], v3[0])) ASSERT(test_eq(v2[1], v3[1])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_copy) { vec2 v1 = {10.0f, 9.0f}; vec2 v2 = {1.0f, 2.0f}; GLM(vec2_copy)(v1, v2); ASSERTIFY(test_assert_vec2_eq(v1, v2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_zero) { vec2 v1 = {10.0f, 9.0f}; vec2 v2 = {1.0f, 2.0f}; GLM(vec2_zero)(v1); GLM(vec2_zero)(v2); ASSERTIFY(test_assert_vec2_eq(v1, GLM_VEC2_ZERO)) ASSERTIFY(test_assert_vec2_eq(v2, GLM_VEC2_ZERO)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_one) { vec2 v1 = {10.0f, 9.0f}; vec2 v2 = {1.0f, 2.0f}; GLM(vec2_one)(v1); GLM(vec2_one)(v2); ASSERTIFY(test_assert_vec2_eq(v1, GLM_VEC2_ONE)) ASSERTIFY(test_assert_vec2_eq(v2, GLM_VEC2_ONE)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_dot) { vec2 a = {10.0f, 9.0f}; vec2 b = {1.0f, 2.0f}; float dot1, dot2; dot1 = GLM(vec2_dot)(a, b); dot2 = a[0] * b[0] + a[1] * b[1]; ASSERT(test_eq(dot1, dot2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_cross) { vec2 a = {10.0f, 9.0f}; vec2 b = {1.0f, 2.0f}; float cprod; cprod = a[0] * b[1] - a[1] * b[0]; ASSERT(test_eq(glm_vec2_cross(a, b), cprod)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_norm2) { vec2 a = {10.0f, 9.0f}; float n1, n2; n1 = GLM(vec2_norm2)(a); n2 = a[0] * a[0] + a[1] * a[1]; ASSERT(test_eq(n1, n2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_norm) { vec2 a = {10.0f, 9.0f}; float n1, n2; n1 = GLM(vec2_norm)(a); n2 = sqrtf(a[0] * a[0] + a[1] * a[1]); ASSERT(test_eq(n1, n2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_add) { vec2 a = {-10.0f, 9.0f}; vec2 b = {12.0f, 19.0f}; vec2 c, d; c[0] = a[0] + b[0]; c[1] = a[1] + b[1]; GLM(vec2_add)(a, b, d); ASSERTIFY(test_assert_vec2_eq(c, d)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_adds) { vec4 a = {-10.0f, 9.0f}; vec4 c, d; float s = 7.0f; c[0] = a[0] + s; c[1] = a[1] + s; GLM(vec2_adds)(a, s, d); ASSERTIFY(test_assert_vec2_eq(c, d)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_sub) { vec2 a = {-10.0f, 9.0f}; vec2 b = {12.0f, 19.0f}; vec2 c, d; c[0] = a[0] - b[0]; c[1] = a[1] - b[1]; GLM(vec2_sub)(a, b, d); ASSERTIFY(test_assert_vec2_eq(c, d)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_subs) { vec2 a = {-10.0f, 9.0f}; vec2 c, d; float s = 7.0f; c[0] = a[0] - s; c[1] = a[1] - s; GLM(vec2_subs)(a, s, d); ASSERTIFY(test_assert_vec2_eq(c, d)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_mul) { vec2 v1 = {2.0f, -3.0f}, v2 = {-3.0f, 4.0f}, v3; GLM(vec2_mul)(v1, v2, v3); ASSERT(test_eq(v1[0] * v2[0], v3[0])) ASSERT(test_eq(v1[1] * v2[1], v3[1])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_scale) { vec2 v1 = {2.0f, -3.0f}, v2; float s = 7.0f; GLM(vec2_scale)(v1, s, v2); ASSERT(test_eq(v1[0] * s, v2[0])) ASSERT(test_eq(v1[1] * s, v2[1])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_scale_as) { vec2 v1 = {2.0f, -3.0f}, v2; float s = 7.0f; float norm; GLM(vec2_scale_as)(v1, s, v2); norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1]); if (norm < FLT_EPSILON) { ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) TEST_SUCCESS } norm = s / norm; ASSERT(test_eq(v1[0] * norm, v2[0])) ASSERT(test_eq(v1[1] * norm, v2[1])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_div) { vec2 v1 = {2.0f, -3.0f}, v2 = {-3.0f, 4.0f}, v3; GLM(vec2_div)(v1, v2, v3); ASSERT(test_eq(v1[0] / v2[0], v3[0])) ASSERT(test_eq(v1[1] / v2[1], v3[1])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_divs) { vec2 v1 = {2.0f, -3.0f}, v2; float s = 7.0f; GLM(vec2_divs)(v1, s, v2); ASSERT(test_eq(v1[0] / s, v2[0])) ASSERT(test_eq(v1[1] / s, v2[1])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_addadd) { vec2 v1 = {2.0f, -3.0f}, v2 = {-3.0f, 4.0f}, v3 = {1.0f, 2.0f}, v4 = {1.0f, 2.0f}; GLM(vec2_addadd)(v1, v2, v4); ASSERT(test_eq(v3[0] + v1[0] + v2[0], v4[0])) ASSERT(test_eq(v3[1] + v1[1] + v2[1], v4[1])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_subadd) { vec2 v1 = {2.0f, -3.0f}, v2 = {-3.0f, 4.0f}, v3 = {1.0f, 2.0f}, v4 = {1.0f, 2.0f}; GLM(vec2_subadd)(v1, v2, v4); ASSERT(test_eq(v3[0] + v1[0] - v2[0], v4[0])) ASSERT(test_eq(v3[1] + v1[1] - v2[1], v4[1])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_muladd) { vec2 v1 = {2.0f, -3.0f}, v2 = {-3.0f, 4.0f}, v3 = {1.0f, 2.0f}, v4 = {1.0f, 2.0f}; GLM(vec2_muladd)(v1, v2, v4); ASSERT(test_eq(v3[0] + v1[0] * v2[0], v4[0])) ASSERT(test_eq(v3[1] + v1[1] * v2[1], v4[1])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_muladds) { vec2 v1 = {2.0f, -3.0f}, v2 = {1.0f, 2.0f}, v3 = {1.0f, 2.0f}; float s = 9.0f; GLM(vec2_muladds)(v1, s, v3); ASSERT(test_eq(v2[0] + v1[0] * s, v3[0])) ASSERT(test_eq(v2[1] + v1[1] * s, v3[1])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_maxadd) { vec2 v1 = {2.0f, -3.0f}, v2 = {-3.0f, 4.0f}, v3 = {1.0f, 2.0f}, v4 = {1.0f, 2.0f}; GLM(vec2_maxadd)(v1, v2, v4); ASSERT(test_eq(v3[0] + glm_max(v1[0], v2[0]), v4[0])) ASSERT(test_eq(v3[1] + glm_max(v1[1], v2[1]), v4[1])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_minadd) { vec2 v1 = {2.0f, -3.0f}, v2 = {-3.0f, 4.0f}, v3 = {1.0f, 2.0f}, v4 = {1.0f, 2.0f}; GLM(vec2_minadd)(v1, v2, v4); ASSERT(test_eq(v3[0] + glm_min(v1[0], v2[0]), v4[0])) ASSERT(test_eq(v3[1] + glm_min(v1[1], v2[1]), v4[1])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_subsub) { vec2 v1 = {2.0f, -3.0f}, v2 = {-3.0f, 4.0f}, v3 = {1.0f, 2.0f}, v4 = {1.0f, 2.0f}; GLM(vec2_subsub)(v1, v2, v4); ASSERT(test_eq(v3[0] - (v1[0] - v2[0]), v4[0])) ASSERT(test_eq(v3[1] - (v1[1] - v2[1]), v4[1])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_addsub) { vec2 v1 = {2.0f, -3.0f}, v2 = {-3.0f, 4.0f}, v3 = {1.0f, 2.0f}, v4 = {1.0f, 2.0f}; GLM(vec2_addsub)(v1, v2, v4); ASSERT(test_eq(v3[0] - (v1[0] + v2[0]), v4[0])) ASSERT(test_eq(v3[1] - (v1[1] + v2[1]), v4[1])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_mulsub) { vec2 v1 = {2.0f, -3.0f}, v2 = {-3.0f, 4.0f}, v3 = {1.0f, 2.0f}, v4 = {1.0f, 2.0f}; GLM(vec2_mulsub)(v1, v2, v4); ASSERT(test_eq(v3[0] - v1[0] * v2[0], v4[0])) ASSERT(test_eq(v3[1] - v1[1] * v2[1], v4[1])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_mulsubs) { vec2 v1 = {2.0f, -3.0f}, v2 = {1.0f, 2.0f}, v3 = {1.0f, 2.0f}; float s = 9.0f; GLM(vec2_mulsubs)(v1, s, v3); ASSERT(test_eq(v2[0] - v1[0] * s, v3[0])) ASSERT(test_eq(v2[1] - v1[1] * s, v3[1])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_maxsub) { vec2 v1 = {2.0f, -3.0f}, v2 = {-3.0f, 4.0f}, v3 = {1.0f, 2.0f}, v4 = {1.0f, 2.0f}; GLM(vec2_maxsub)(v1, v2, v4); ASSERT(test_eq(v3[0] - glm_max(v1[0], v2[0]), v4[0])) ASSERT(test_eq(v3[1] - glm_max(v1[1], v2[1]), v4[1])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_minsub) { vec2 v1 = {2.0f, -3.0f}, v2 = {-3.0f, 4.0f}, v3 = {1.0f, 2.0f}, v4 = {1.0f, 2.0f}; GLM(vec2_minsub)(v1, v2, v4); ASSERT(test_eq(v3[0] - glm_min(v1[0], v2[0]), v4[0])) ASSERT(test_eq(v3[1] - glm_min(v1[1], v2[1]), v4[1])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_negate_to) { vec2 v1 = {2.0f, -3.0f}, v2 = {-3.0f, 4.0f}, v3, v4; GLM(vec2_negate_to)(v1, v3); GLM(vec2_negate_to)(v2, v4); ASSERT(test_eq(-v1[0], v3[0])) ASSERT(test_eq(-v1[1], v3[1])) ASSERT(test_eq(-v2[0], v4[0])) ASSERT(test_eq(-v2[1], v4[1])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_negate) { vec2 v1 = {2.0f, -3.0f}, v2 = {-3.0f, 4.0f}, v3 = {2.0f, -3.0f}, v4 = {-3.0f, 4.0f}; GLM(vec2_negate)(v1); GLM(vec2_negate)(v2); ASSERT(test_eq(-v1[0], v3[0])) ASSERT(test_eq(-v1[1], v3[1])) ASSERT(test_eq(-v2[0], v4[0])) ASSERT(test_eq(-v2[1], v4[1])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_normalize) { vec2 v1 = {2.0f, -3.0f}, v2 = {2.0f, -3.0f}; float s = 1.0f; float norm; GLM(vec2_normalize)(v2); norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1]); if (norm < FLT_EPSILON) { ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) TEST_SUCCESS } norm = s / norm; ASSERT(test_eq(v1[0] * norm, v2[0])) ASSERT(test_eq(v1[1] * norm, v2[1])) glm_vec2_zero(v1); GLM(vec2_normalize)(v1); ASSERTIFY(test_assert_vec2_eq(v1, GLM_VEC2_ZERO)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_normalize_to) { vec2 v1 = {2.0f, -3.0f}, v2; float s = 1.0f; float norm; GLM(vec2_normalize_to)(v1, v2); norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1]); if (norm < FLT_EPSILON) { ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) TEST_SUCCESS } norm = s / norm; ASSERT(test_eq(v1[0] * norm, v2[0])) ASSERT(test_eq(v1[1] * norm, v2[1])) glm_vec2_zero(v1); GLM(vec2_normalize_to)(v1, v2); ASSERTIFY(test_assert_vec2_eq(v2, GLM_VEC2_ZERO)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_rotate) { vec2 v1 = {1.0f, 0.0f}; GLM(vec2_rotate)(v1, GLM_PI_2f, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 1.0f)) GLM(vec2_rotate)(v1, GLM_PI_2f, v1); ASSERT(test_eq(v1[0], -1.0f)) ASSERT(test_eq(v1[1], 0.0f)) GLM(vec2_rotate)(v1, GLM_PI_2f, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], -1.0f)) GLM(vec2_rotate)(v1, GLM_PI_2f, v1); ASSERT(test_eq(v1[0], 1.0f)) ASSERT(test_eq(v1[1], 0.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_center) { vec2 v1 = {1.0f, 1.0f}, v2 = {0.0f, 0.0f}; vec2 dest; GLM(vec2_center)(v1, v2, dest); ASSERTIFY(test_assert_vec2_eq(dest, (vec2){ 0.5f, 0.5f })) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_distance2) { vec2 v1 = {30.0f, 0.0f}, v2 = {0.0f, 0.0f}, v3 = {3.0f, 10.0f}, v4 = {0.46f, 4.0f}; float d; d = GLM(vec2_distance2)(v1, v2); ASSERT(test_eq(d, 30.0f * 30.0f)) d = GLM(vec2_distance2)(v3, v4); ASSERT(test_eq(powf(v3[0] - v4[0], 2.0f) + powf(v3[1] - v4[1], 2.0f), d)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_distance) { vec2 v1 = {30.0f, 0.0f}, v2 = {0.0f, 0.0f}, v3 = {3.0f, 10.0f}, v4 = {0.46f, 4.0f}; float d; d = GLM(vec2_distance)(v1, v2); ASSERT(test_eq(d, 30.0f)) d = GLM(vec2_distance)(v3, v4); ASSERT(test_eq(sqrtf(powf(v3[0] - v4[0], 2.0f) + powf(v3[1] - v4[1], 2.0f)), d)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_maxv) { vec2 v1, v2, v3; vec2 v5 = {-1.456f, -1.456f}; vec2 v6 = {11.0f, 11.0f}; vec2 v7 = {78.0f, -78.0f}; GLM(vec2_maxv)(v5, v6, v1); GLM(vec2_maxv)(v5, v7, v2); GLM(vec2_maxv)(v6, v7, v3); ASSERT(test_eq(v1[0], 11.0f)) ASSERT(test_eq(v1[1], 11.0f)) ASSERT(test_eq(v2[0], 78.0f)) ASSERT(test_eq(v2[1], -1.456f)) ASSERT(test_eq(v3[0], 78.0f)) ASSERT(test_eq(v3[1], 11.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_minv) { vec2 v1, v2, v3; vec2 v5 = {-1.456f, -1.456f}; vec2 v6 = {11.0f, 11.0f}; vec2 v7 = {78.0f, -78.0f}; GLM(vec2_minv)(v5, v6, v1); GLM(vec2_minv)(v5, v7, v2); GLM(vec2_minv)(v6, v7, v3); ASSERT(test_eq(v1[0], -1.456f)) ASSERT(test_eq(v1[1], -1.456f)) ASSERT(test_eq(v2[0], -1.456f)) ASSERT(test_eq(v2[1], -78.0f)) ASSERT(test_eq(v3[0], 11.0f)) ASSERT(test_eq(v3[1], -78.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_clamp) { vec2 v1 = {-1.456f, -11.456f}; vec2 v2 = {0.110f, 111.0f}; vec2 v3 = {78.0f, 32.0f}; GLM(vec2_clamp)(v1, -1.03f, 30.0f); GLM(vec2_clamp)(v2, 0.11f, 111.0f); GLM(vec2_clamp)(v3, -88.0f, 70.0f); ASSERT(test_eq(v1[0], -1.03f)) ASSERT(test_eq(v1[1], -1.03f)) ASSERT(test_eq(v2[0], 0.11f)) ASSERT(test_eq(v2[1], 111.0f)) ASSERT(test_eq(v3[0], 70.0f)) ASSERT(test_eq(v3[1], 32.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_abs) { vec2 v1 = {2, -3}, v2 = {-12, -31}; vec2 v3, v4; vec2 v5 = {2, 3}, v6 = {12, 31}; GLM(vec2_abs)(v1, v3); GLM(vec2_abs)(v2, v4); ASSERTIFY(test_assert_vec2_eq(v3, v5)) ASSERTIFY(test_assert_vec2_eq(v4, v6)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_fract) { vec2 v1 = {2.104f, 3.012f}, v2 = {12.35f, 31.140f}, v3, v4; vec2 v5 = {0.104f, 0.012f}, v6 = {0.35f, 0.140f}; GLM(vec2_fract)(v1, v3); GLM(vec2_fract)(v2, v4); ASSERTIFY(test_assert_vec2_eq(v3, v5)) ASSERTIFY(test_assert_vec2_eq(v4, v6)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_floor) { vec2 v1 = {2.104f, 3.012f}, v2 = {12.35f, 31.140f}, v3, v4; vec2 v5 = {2.0f, 3.0f}, v6 = {12.0f, 31.0f}; GLM(vec2_floor)(v1, v3); GLM(vec2_floor)(v2, v4); ASSERTIFY(test_assert_vec2_eq(v3, v5)) ASSERTIFY(test_assert_vec2_eq(v4, v6)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_mods) { vec2 v1 = {2.104f, 3.012f}, v2 = {12.35f, 31.140f}, v3, v4; vec2 v5 = {0.104f, 0.012f}, v6 = {0.35f, 0.140f}; /* Mod 1 - leaves just the fractional part */ GLM(vec2_mods)(v1, 1.0f, v3); GLM(vec2_mods)(v2, 1.0f, v4); ASSERTIFY(test_assert_vec2_eq(v3, v5)) ASSERTIFY(test_assert_vec2_eq(v4, v6)) /* Mod 2 - parity + fractional part */ GLM(vec2_mods)(v1, 2.0f, v3); GLM(vec2_mods)(v2, 2.0f, v4); vec2 v7 = {0.104f, 1.012f}, v8 = {0.35f, 1.140f}; ASSERTIFY(test_assert_vec2_eq(v3, v7)) ASSERTIFY(test_assert_vec2_eq(v4, v8)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_swizzle) { vec2 v; v[0] = 1; v[1] = 2; GLM(vec2_swizzle)(v, GLM_SHUFFLE2(1, 0), v); ASSERTIFY(test_assert_vec2_eq(v, (vec2){2, 1})) GLM(vec2_swizzle)(v, GLM_SHUFFLE2(0, 0), v); ASSERTIFY(test_assert_vec2_eq(v, (vec2){1, 1})) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_lerp) { vec2 v1 = {-100.0f, -200.0f}; vec2 v2 = {100.0f, 200.0f}; vec2 v3; GLM(vec2_lerp)(v1, v2, 0.5f, v3); ASSERT(test_eq(v3[0], 0.0f)) ASSERT(test_eq(v3[1], 0.0f)) GLM(vec2_lerp)(v1, v2, 0.75f, v3); ASSERT(test_eq(v3[0], 50.0f)) ASSERT(test_eq(v3[1], 100.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_steps) { vec2 v1 = {-100.0f, -200.0f}; vec2 v2; GLM(vec2_steps)(-2.5f, v1, v2); ASSERT(test_eq(v2[0], 0.0f)) ASSERT(test_eq(v2[1], 0.0f)) GLM(vec2_steps)(-150.0f, v1, v2); ASSERT(test_eq(v2[0], 1.0f)) ASSERT(test_eq(v2[1], 0.0f)) GLM(vec2_steps)(-300.0f, v1, v2); ASSERT(test_eq(v2[0], 1.0f)) ASSERT(test_eq(v2[1], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_stepr) { vec2 v1 = {-2.5f, -150.0f}; vec2 v2; GLM(vec2_stepr)(v1, -200.0f, v2); ASSERT(test_eq(v2[0], 0.0f)) ASSERT(test_eq(v2[1], 0.0f)) GLM(vec2_stepr)(v1, -150.0f, v2); ASSERT(test_eq(v2[0], 0.0f)) ASSERT(test_eq(v2[1], 1.0f)) GLM(vec2_stepr)(v1, 0.0f, v2); ASSERT(test_eq(v2[0], 1.0f)) ASSERT(test_eq(v2[1], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_step) { vec2 v1 = {-100.0f, -200.0f}; vec2 s1 = {-100.0f, 0.0f}; vec2 s2 = {100.0f, -220.0f}; vec2 s3 = {100.0f, 200.0f}; vec2 v2; GLM(vec2_step)(s1, v1, v2); ASSERT(test_eq(v2[0], 1.0f)) ASSERT(test_eq(v2[1], 0.0f)) GLM(vec2_step)(s2, v1, v2); ASSERT(test_eq(v2[0], 0.0f)) ASSERT(test_eq(v2[1], 1.0f)) GLM(vec2_step)(s3, v1, v2); ASSERT(test_eq(v2[0], 0.0f)) ASSERT(test_eq(v2[1], 0.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_complex_mul) { vec2 v1 = { 3.0f, 5.0f }, v2 = { 7.0f, 11.0f }, v3 = { cosf(GLM_PIf/4.0f), sinf(GLM_PIf/4.0f) }; GLM(vec2_complex_mul)(v1, v2, v2); ASSERTIFY(test_assert_vec2_eq(v2, (vec2){ -34, 68 })) GLM(vec2_complex_mul)(v3, v3, v3); ASSERTIFY(test_assert_vec2_eq(v3, (vec2){ 0.0f, 1.0f })) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_complex_div) { vec2 v1 = { -34.0f, 68.0f }, v2 = { 3.0f, 5.0f }, v3 = { cosf(GLM_PIf/4.0f), sinf(GLM_PIf/4.0f) }, v4 = { cosf(GLM_PIf/4.0f), -sinf(GLM_PIf/4.0f) }; GLM(vec2_complex_div)(v1, v2, v2); ASSERTIFY(test_assert_vec2_eq(v2, (vec2){ 7.0f, 11.0f })) GLM(vec2_complex_div)(v3, v4, v4); ASSERTIFY(test_assert_vec2_eq(v4, (vec2){ 0.0f, 1.0f })) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_make) { float src[6] = { 7.2f, 1.0f, 2.5f, 6.1f, 17.7f, 4.3f }; vec2 dest[3]; float *srcp = src; unsigned int i, j; for (i = 0, j = 0; i < sizeof(src) / sizeof(float); i+=2,j++) { GLM(vec2_make)(srcp + i, dest[j]); ASSERT(test_eq(src[ i ], dest[j][0])); ASSERT(test_eq(src[i+1], dest[j][1])); } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_reflect) { vec2 dest; /* Reflecting off a "horizontal" surface in 2D */ vec2 I1 = {1.0f, -1.0f}; /* Incoming vector */ vec2 N1 = {0.0f, 1.0f}; /* Normal vector */ GLM(vec2_reflect)(I1, N1, dest); ASSERT(fabsf(dest[0] - 1.0f) < 0.00001f && fabsf(dest[1] - 1.0f) < 0.00001f); /* Expect reflection upwards */ /* Reflecting at an angle in 2D */ vec2 I2 = {sqrtf(2)/2, -sqrtf(2)/2}; /* Incoming vector at 45 degrees */ vec2 N2 = {0.0f, 1.0f}; /* Upwards normal vector */ GLM(vec2_reflect)(I2, N2, dest); ASSERT(fabsf(dest[0] - sqrtf(2)/2) < 0.00001f && fabsf(dest[1] - sqrtf(2)/2) < 0.00001f); /* Expect reflection upwards */ /* Reflecting off a line in 2D representing a "vertical" surface analogy */ vec2 I3 = {1.0f, 0.0f}; /* Incoming vector */ vec2 N3 = {-1.0f, 0.0f}; /* Normal vector representing a "vertical" line */ GLM(vec2_reflect)(I3, N3, dest); ASSERT(fabsf(dest[0] + 1.0f) < 0.00001f && fabsf(dest[1]) < 0.00001f); /* Expect reflection to the left */ TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec2_refract) { vec2 v = {sqrtf(0.5f), -sqrtf(0.5f)}; /* Incoming vector at 45 degrees to normal */ vec2 N = {0.0f, 1.0f}; /* Surface normal */ vec2 dest; float eta; float r; /* Water to Air (eta = 1.33/1.0) */ eta = 1.33f / 1.0f; r = GLM(vec2_refract)(v, N, eta, dest); // In 2D, we expect a similar bending behavior as in 3D, so we check dest[1] if (!(dest[0] == 0.0f && dest[1] == 0.0f)) { ASSERT(dest[1] < -0.3f); // Refracted ray bends away from the normal ASSERT(r == true); } else { ASSERT(dest[0] == 0.0f && dest[1] == 0.0f); // Total internal reflection ASSERT(r == false); } /* Air to Glass (eta = 1.0 / 1.5) */ eta = 1.0f / 1.5f; r = GLM(vec2_refract)(v, N, eta, dest); ASSERT(r == true); ASSERT(dest[1] < -sqrtf(0.5f)); // Expect bending towards the normal /* Glass to Water (eta = 1.5 / 1.33) */ eta = 1.5f / 1.33f; r = GLM(vec2_refract)(v, N, eta, dest); ASSERT(r == true); ASSERT(dest[1] < -0.6f); // Expect bending towards the normal, less bending than air to glass /* Diamond to Air (eta = 2.42 / 1.0) */ eta = 2.42f / 1.0f; r = GLM(vec2_refract)(v, N, eta, dest); if (!(dest[0] == 0.0f && dest[1] == 0.0f)) { /* High potential for total internal reflection, but if it occurs, expect significant bending */ ASSERT(dest[1] < -sqrtf(0.5f)); ASSERT(r == true); } else { ASSERT(dest[0] == 0.0f && dest[1] == 0.0f); // Total internal reflection ASSERT(r == false); } TEST_SUCCESS } cglm-0.9.7/test/src/test_vec3.h000066400000000000000000001341101526744317200163020ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" #define TEST_GLM_SHUFFLE3(z, y, x) (((z) << 4) | ((y) << 2) | (x)) #ifndef CGLM_TEST_VEC3_ONCE #define CGLM_TEST_VEC3_ONCE /* Macros */ TEST_IMPL(MACRO_GLM_VEC3_ONE_INIT) { vec3 v = GLM_VEC3_ONE_INIT; ASSERT(test_eq(v[0], 1.0f)) ASSERT(test_eq(v[1], 1.0f)) ASSERT(test_eq(v[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_VEC3_ZERO_INIT) { vec3 v = GLM_VEC3_ZERO_INIT; ASSERT(test_eq(v[0], 0.0f)) ASSERT(test_eq(v[1], 0.0f)) ASSERT(test_eq(v[2], 0.0f)) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_VEC3_ONE) { ASSERT(test_eq(GLM_VEC3_ONE[0], 1.0f)) ASSERT(test_eq(GLM_VEC3_ONE[1], 1.0f)) ASSERT(test_eq(GLM_VEC3_ONE[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_VEC3_ZERO) { ASSERT(test_eq(GLM_VEC3_ZERO[0], 0.0f)) ASSERT(test_eq(GLM_VEC3_ZERO[1], 0.0f)) ASSERT(test_eq(GLM_VEC3_ZERO[2], 0.0f)) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_YUP) { ASSERT(test_eq(GLM_YUP[0], 0.0f)) ASSERT(test_eq(GLM_YUP[1], 1.0f)) ASSERT(test_eq(GLM_YUP[2], 0.0f)) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_ZUP) { ASSERT(test_eq(GLM_ZUP[0], 0.0f)) ASSERT(test_eq(GLM_ZUP[1], 0.0f)) ASSERT(test_eq(GLM_ZUP[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_XUP) { ASSERT(test_eq(GLM_XUP[0], 1.0f)) ASSERT(test_eq(GLM_XUP[1], 0.0f)) ASSERT(test_eq(GLM_XUP[2], 0.0f)) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_FORWARD_RH) { ASSERT(test_eq(GLM_FORWARD[0], 0.0f)) ASSERT(test_eq(GLM_FORWARD[1], 0.0f)) ASSERT(test_eq(GLM_FORWARD[2], -1.0f)) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_SHUFFLE3) { ASSERT(TEST_GLM_SHUFFLE3(1, 0, 0) == GLM_SHUFFLE3(1, 0, 0)) ASSERT(TEST_GLM_SHUFFLE3(0, 1, 0) == GLM_SHUFFLE3(0, 1, 0)) ASSERT(TEST_GLM_SHUFFLE3(0, 0, 1) == GLM_SHUFFLE3(0, 0, 1)) ASSERT(TEST_GLM_SHUFFLE3(1, 0, 0) == GLM_SHUFFLE3(1, 0, 0)) ASSERT(TEST_GLM_SHUFFLE3(1, 0, 1) == GLM_SHUFFLE3(1, 0, 1)) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_XXX) { ASSERT(TEST_GLM_SHUFFLE3(0, 0, 0) == GLM_XXX) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_YYY) { ASSERT(TEST_GLM_SHUFFLE3(1, 1, 1) == GLM_YYY) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_ZZZ) { ASSERT(TEST_GLM_SHUFFLE3(2, 2, 2) == GLM_ZZZ) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_ZYX) { ASSERT(TEST_GLM_SHUFFLE3(0, 1, 2) == GLM_ZYX) TEST_SUCCESS } /* Deprecated */ TEST_IMPL(MACRO_glm_vec3_dup) { vec3 v1 = {13.0f, 12.0f, 11.0f}, v2; glm_vec3_dup(v1, v2); ASSERTIFY(test_assert_vec3_eq(v1, v2)) TEST_SUCCESS } TEST_IMPL(MACRO_glm_vec3_flipsign) { vec3 v1 = {13.0f, -12.0f, 11.0f}, v2 = {13.0f, -12.0f, 11.0f}, v3 = {-13.0f, 12.0f, -11.0f}; glm_vec3_flipsign(v1); glmc_vec3_flipsign(v2); ASSERTIFY(test_assert_vec3_eq(v1, v3)) ASSERTIFY(test_assert_vec3_eq(v2, v3)) TEST_SUCCESS } TEST_IMPL(MACRO_glm_vec3_flipsign_to) { vec3 v1 = {13.0f, -12.0f, 11.0f}, v2 = {-13.0f, 12.0f, -11.0f}, v3, v4; glm_vec3_flipsign_to(v1, v3); glmc_vec3_flipsign_to(v1, v4); ASSERTIFY(test_assert_vec3_eq(v2, v3)) ASSERTIFY(test_assert_vec3_eq(v2, v4)) TEST_SUCCESS } TEST_IMPL(MACRO_glm_vec3_inv) { vec3 v1 = {13.0f, -12.0f, 11.0f}, v2 = {13.0f, -12.0f, 11.0f}, v3 = {-13.0f, 12.0f, -11.0f}; glm_vec3_inv(v1); glmc_vec3_inv(v2); ASSERTIFY(test_assert_vec3_eq(v1, v3)) ASSERTIFY(test_assert_vec3_eq(v2, v3)) TEST_SUCCESS } TEST_IMPL(MACRO_glm_vec3_inv_to) { vec3 v1 = {13.0f, -12.0f, 11.0f}, v2 = {-13.0f, 12.0f, -11.0f}, v3, v4; glm_vec3_inv_to(v1, v3); glmc_vec3_inv_to(v1, v4); ASSERTIFY(test_assert_vec3_eq(v3, v4)) ASSERTIFY(test_assert_vec3_eq(v2, v3)) TEST_SUCCESS } TEST_IMPL(MACRO_glm_vec3_mulv) { vec3 v1 = {2.0f, -3.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f}, v3, v4; glm_vec3_mulv(v1, v2, v3); glmc_vec3_mulv(v1, v2, v4); ASSERTIFY(test_assert_vec3_eq(v3, v4)) ASSERT(test_eq(v1[0] * v2[0], v3[0])) ASSERT(test_eq(v1[1] * v2[1], v3[1])) ASSERT(test_eq(v1[2] * v2[2], v3[2])) TEST_SUCCESS } #endif /* CGLM_TEST_VEC3_ONCE */ /* --- */ TEST_IMPL(GLM_PREFIX, vec3) { vec4 v4 = {10.0f, 9.0f, 8.0f, 7.0f}; vec3 v3; GLM(vec3)(v4, v3); ASSERT(test_eq(v3[0], v4[0])) ASSERT(test_eq(v3[1], v4[1])) ASSERT(test_eq(v3[2], v4[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_copy) { vec3 v1 = {10.0f, 9.0f, 8.0f}; vec3 v2 = {1.0f, 2.0f, 3.0f}; GLM(vec3_copy)(v1, v2); ASSERTIFY(test_assert_vec3_eq(v1, v2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_zero) { vec3 v1 = {10.0f, 9.0f, 8.0f}; vec3 v2 = {1.0f, 2.0f, 3.0f}; GLM(vec3_zero)(v1); GLM(vec3_zero)(v2); ASSERTIFY(test_assert_vec3_eq(v1, GLM_VEC3_ZERO)) ASSERTIFY(test_assert_vec3_eq(v2, GLM_VEC3_ZERO)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_one) { vec3 v1 = {10.0f, 9.0f, 8.0f}; vec3 v2 = {1.0f, 2.0f, 3.0f}; GLM(vec3_one)(v1); GLM(vec3_one)(v2); ASSERTIFY(test_assert_vec3_eq(v1, GLM_VEC3_ONE)) ASSERTIFY(test_assert_vec3_eq(v1, GLM_VEC3_ONE)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_dot) { vec3 a = {10.0f, 9.0f, 8.0f}; vec3 b = {1.0f, 2.0f, 3.0f}; float dot1, dot2; dot1 = GLM(vec3_dot)(a, b); dot2 = a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; ASSERT(test_eq(dot1, dot2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, dot) { /* SAME AS VEC3_DOT */ vec3 a = {10.0f, 9.0f, 8.0f}; vec3 b = {1.0f, 2.0f, 3.0f}; float dot1, dot2; dot1 = GLM(vec3_dot)(a, b); dot2 = a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; ASSERT(test_eq(dot1, dot2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_norm2) { vec3 a = {10.0f, 9.0f, 8.0f}; float n1, n2; n1 = GLM(vec3_norm2)(a); n2 = a[0] * a[0] + a[1] * a[1] + a[2] * a[2]; ASSERT(test_eq(n1, n2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_norm) { vec3 a = {10.0f, 9.0f, 8.0f}; float n1, n2; n1 = GLM(vec3_norm)(a); n2 = sqrtf(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]); ASSERT(test_eq(n1, n2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_norm_one) { vec3 a = {-10.0f, 9.0f, -8.0f}; float n1, n2; n1 = GLM(vec3_norm_one)(a); n2 = fabsf(a[0]) + fabsf(a[1]) + fabsf(a[2]); ASSERT(test_eq(n1, n2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_norm_inf) { vec3 a = {-10.0f, 9.0f, -8.0f}; float n1, n2; n1 = GLM(vec3_norm_inf)(a); n2 = fabsf(a[0]); if (n2 < fabsf(a[1])) n2 = fabsf(a[1]); if (n2 < fabsf(a[2])) n2 = fabsf(a[2]); ASSERT(test_eq(n1, n2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_add) { vec3 a = {-10.0f, 9.0f, -8.0f}; vec3 b = {12.0f, 19.0f, -18.0f}; vec3 c, d; c[0] = a[0] + b[0]; c[1] = a[1] + b[1]; c[2] = a[2] + b[2]; GLM(vec3_add)(a, b, d); ASSERTIFY(test_assert_vec3_eq(c, d)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_adds) { vec3 a = {-10.0f, 9.0f, -8.0f}; vec3 c, d; float s = 7.0f; c[0] = a[0] + s; c[1] = a[1] + s; c[2] = a[2] + s; GLM(vec3_adds)(a, s, d); ASSERTIFY(test_assert_vec3_eq(c, d)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_sub) { vec3 a = {-10.0f, 9.0f, -8.0f}; vec3 b = {12.0f, 19.0f, -18.0f}; vec3 c, d; c[0] = a[0] - b[0]; c[1] = a[1] - b[1]; c[2] = a[2] - b[2]; GLM(vec3_sub)(a, b, d); ASSERTIFY(test_assert_vec3_eq(c, d)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_subs) { vec3 a = {-10.0f, 9.0f, -8.0f}; vec3 c, d; float s = 7.0f; c[0] = a[0] - s; c[1] = a[1] - s; c[2] = a[2] - s; GLM(vec3_subs)(a, s, d); ASSERTIFY(test_assert_vec3_eq(c, d)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_mul) { vec3 v1 = {2.0f, -3.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f}, v3; GLM(vec3_mul)(v1, v2, v3); ASSERT(test_eq(v1[0] * v2[0], v3[0])) ASSERT(test_eq(v1[1] * v2[1], v3[1])) ASSERT(test_eq(v1[2] * v2[2], v3[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_scale) { vec3 v1 = {2.0f, -3.0f, 4.0f}, v2; float s = 7.0f; GLM(vec3_scale)(v1, s, v2); ASSERT(test_eq(v1[0] * s, v2[0])) ASSERT(test_eq(v1[1] * s, v2[1])) ASSERT(test_eq(v1[2] * s, v2[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_scale_as) { vec3 v1 = {2.0f, -3.0f, 4.0f}, v2; float s = 7.0f; float norm; GLM(vec3_scale_as)(v1, s, v2); norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]); if (norm < FLT_EPSILON) { ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 0.0f)) TEST_SUCCESS } norm = s / norm; ASSERT(test_eq(v1[0] * norm, v2[0])) ASSERT(test_eq(v1[1] * norm, v2[1])) ASSERT(test_eq(v1[2] * norm, v2[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_div) { vec3 v1 = {2.0f, -3.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f}, v3; GLM(vec3_div)(v1, v2, v3); ASSERT(test_eq(v1[0] / v2[0], v3[0])) ASSERT(test_eq(v1[1] / v2[1], v3[1])) ASSERT(test_eq(v1[2] / v2[2], v3[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_divs) { vec3 v1 = {2.0f, -3.0f, 4.0f}, v2; float s = 7.0f; GLM(vec3_divs)(v1, s, v2); ASSERT(test_eq(v1[0] / s, v2[0])) ASSERT(test_eq(v1[1] / s, v2[1])) ASSERT(test_eq(v1[2] / s, v2[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_addadd) { vec3 v1 = {2.0f, -3.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f}, v3 = {1.0f, 2.0f, 3.0f}, v4 = {1.0f, 2.0f, 3.0f}; GLM(vec3_addadd)(v1, v2, v4); ASSERT(test_eq(v3[0] + v1[0] + v2[0], v4[0])) ASSERT(test_eq(v3[1] + v1[1] + v2[1], v4[1])) ASSERT(test_eq(v3[2] + v1[2] + v2[2], v4[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_subadd) { vec3 v1 = {2.0f, -3.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f}, v3 = {1.0f, 2.0f, 3.0f}, v4 = {1.0f, 2.0f, 3.0f}; GLM(vec3_subadd)(v1, v2, v4); ASSERT(test_eq(v3[0] + v1[0] - v2[0], v4[0])) ASSERT(test_eq(v3[1] + v1[1] - v2[1], v4[1])) ASSERT(test_eq(v3[2] + v1[2] - v2[2], v4[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_muladd) { vec3 v1 = {2.0f, -3.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f}, v3 = {1.0f, 2.0f, 3.0f}, v4 = {1.0f, 2.0f, 3.0f}; GLM(vec3_muladd)(v1, v2, v4); ASSERT(test_eq(v3[0] + v1[0] * v2[0], v4[0])) ASSERT(test_eq(v3[1] + v1[1] * v2[1], v4[1])) ASSERT(test_eq(v3[2] + v1[2] * v2[2], v4[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_muladds) { vec3 v1 = {2.0f, -3.0f, 4.0f}, v2 = {1.0f, 2.0f, 3.0f}, v3 = {1.0f, 2.0f, 3.0f}; float s = 9.0f; GLM(vec3_muladds)(v1, s, v3); ASSERT(test_eq(v2[0] + v1[0] * s, v3[0])) ASSERT(test_eq(v2[1] + v1[1] * s, v3[1])) ASSERT(test_eq(v2[2] + v1[2] * s, v3[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_maxadd) { vec3 v1 = {2.0f, -3.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f}, v3 = {1.0f, 2.0f, 3.0f}, v4 = {1.0f, 2.0f, 3.0f}; GLM(vec3_maxadd)(v1, v2, v4); ASSERT(test_eq(v3[0] + glm_max(v1[0], v2[0]), v4[0])) ASSERT(test_eq(v3[1] + glm_max(v1[1], v2[1]), v4[1])) ASSERT(test_eq(v3[2] + glm_max(v1[2], v2[2]), v4[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_minadd) { vec3 v1 = {2.0f, -3.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f}, v3 = {1.0f, 2.0f, 3.0f}, v4 = {1.0f, 2.0f, 3.0f}; GLM(vec3_minadd)(v1, v2, v4); ASSERT(test_eq(v3[0] + glm_min(v1[0], v2[0]), v4[0])) ASSERT(test_eq(v3[1] + glm_min(v1[1], v2[1]), v4[1])) ASSERT(test_eq(v3[2] + glm_min(v1[2], v2[2]), v4[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_subsub) { vec3 v1 = {2.0f, -3.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f}, v3 = {1.0f, 2.0f, 3.0f}, v4 = {1.0f, 2.0f, 3.0f}; GLM(vec3_subsub)(v1, v2, v4); ASSERT(test_eq(v3[0] - (v1[0] - v2[0]), v4[0])) ASSERT(test_eq(v3[1] - (v1[1] - v2[1]), v4[1])) ASSERT(test_eq(v3[2] - (v1[2] - v2[2]), v4[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_addsub) { vec3 v1 = {2.0f, -3.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f}, v3 = {1.0f, 2.0f, 3.0f}, v4 = {1.0f, 2.0f, 3.0f}; GLM(vec3_addsub)(v1, v2, v4); ASSERT(test_eq(v3[0] - (v1[0] + v2[0]), v4[0])) ASSERT(test_eq(v3[1] - (v1[1] + v2[1]), v4[1])) ASSERT(test_eq(v3[2] - (v1[2] + v2[2]), v4[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_mulsub) { vec3 v1 = {2.0f, -3.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f}, v3 = {1.0f, 2.0f, 3.0f}, v4 = {1.0f, 2.0f, 3.0f}; GLM(vec3_mulsub)(v1, v2, v4); ASSERT(test_eq(v3[0] - v1[0] * v2[0], v4[0])) ASSERT(test_eq(v3[1] - v1[1] * v2[1], v4[1])) ASSERT(test_eq(v3[2] - v1[2] * v2[2], v4[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_mulsubs) { vec3 v1 = {2.0f, -3.0f, 4.0f}, v2 = {1.0f, 2.0f, 3.0f}, v3 = {1.0f, 2.0f, 3.0f}; float s = 9.0f; GLM(vec3_mulsubs)(v1, s, v3); ASSERT(test_eq(v2[0] - v1[0] * s, v3[0])) ASSERT(test_eq(v2[1] - v1[1] * s, v3[1])) ASSERT(test_eq(v2[2] - v1[2] * s, v3[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_maxsub) { vec3 v1 = {2.0f, -3.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f}, v3 = {1.0f, 2.0f, 3.0f}, v4 = {1.0f, 2.0f, 3.0f}; GLM(vec3_maxsub)(v1, v2, v4); ASSERT(test_eq(v3[0] - glm_max(v1[0], v2[0]), v4[0])) ASSERT(test_eq(v3[1] - glm_max(v1[1], v2[1]), v4[1])) ASSERT(test_eq(v3[2] - glm_max(v1[2], v2[2]), v4[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_minsub) { vec3 v1 = {2.0f, -3.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f}, v3 = {1.0f, 2.0f, 3.0f}, v4 = {1.0f, 2.0f, 3.0f}; GLM(vec3_minsub)(v1, v2, v4); ASSERT(test_eq(v3[0] - glm_min(v1[0], v2[0]), v4[0])) ASSERT(test_eq(v3[1] - glm_min(v1[1], v2[1]), v4[1])) ASSERT(test_eq(v3[2] - glm_min(v1[2], v2[2]), v4[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_negate_to) { vec3 v1 = {2.0f, -3.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f}, v3, v4; GLM(vec3_negate_to)(v1, v3); GLM(vec3_negate_to)(v2, v4); ASSERT(test_eq(-v1[0], v3[0])) ASSERT(test_eq(-v1[1], v3[1])) ASSERT(test_eq(-v1[2], v3[2])) ASSERT(test_eq(-v2[0], v4[0])) ASSERT(test_eq(-v2[1], v4[1])) ASSERT(test_eq(-v2[2], v4[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_negate) { vec3 v1 = {2.0f, -3.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f}, v3 = {2.0f, -3.0f, 4.0f}, v4 = {-3.0f, 4.0f, -5.0f}; GLM(vec3_negate)(v1); GLM(vec3_negate)(v2); ASSERT(test_eq(-v1[0], v3[0])) ASSERT(test_eq(-v1[1], v3[1])) ASSERT(test_eq(-v1[2], v3[2])) ASSERT(test_eq(-v2[0], v4[0])) ASSERT(test_eq(-v2[1], v4[1])) ASSERT(test_eq(-v2[2], v4[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_normalize) { vec3 v1 = {2.0f, -3.0f, 4.0f}, v2 = {2.0f, -3.0f, 4.0f}; float s = 1.0f; float norm; GLM(vec3_normalize)(v2); norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]); if (norm < FLT_EPSILON) { ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 0.0f)) TEST_SUCCESS } norm = s / norm; ASSERT(test_eq(v1[0] * norm, v2[0])) ASSERT(test_eq(v1[1] * norm, v2[1])) ASSERT(test_eq(v1[2] * norm, v2[2])) glm_vec3_zero(v1); GLM(vec3_normalize)(v1); ASSERTIFY(test_assert_vec3_eq(v1, GLM_VEC3_ZERO)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_normalize_to) { vec3 v1 = {2.0f, -3.0f, 4.0f}, v2; float s = 1.0f; float norm; GLM(vec3_normalize_to)(v1, v2); norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]); if (norm < FLT_EPSILON) { ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 0.0f)) TEST_SUCCESS } norm = s / norm; ASSERT(test_eq(v1[0] * norm, v2[0])) ASSERT(test_eq(v1[1] * norm, v2[1])) ASSERT(test_eq(v1[2] * norm, v2[2])) glm_vec3_zero(v1); GLM(vec3_normalize_to)(v1, v2); ASSERTIFY(test_assert_vec3_eq(v2, GLM_VEC3_ZERO)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, normalize) { /* SAME AS VEC3_NORMALIZE */ vec3 v1 = {2.0f, -3.0f, 4.0f}, v2 = {2.0f, -3.0f, 4.0f}; float s = 1.0f; float norm; GLM(vec3_normalize)(v2); norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]); if (norm < FLT_EPSILON) { ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 0.0f)) TEST_SUCCESS } norm = s / norm; ASSERT(test_eq(v1[0] * norm, v2[0])) ASSERT(test_eq(v1[1] * norm, v2[1])) ASSERT(test_eq(v1[2] * norm, v2[2])) glm_vec3_zero(v1); GLM(vec3_normalize)(v1); ASSERTIFY(test_assert_vec3_eq(v1, GLM_VEC3_ZERO)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, normalize_to) { /* SAME AS VEC3_NORMALIZE_TO */ vec3 v1 = {2.0f, -3.0f, 4.0f}, v2; float s = 1.0f; float norm; GLM(vec3_normalize_to)(v1, v2); norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]); if (norm < FLT_EPSILON) { ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 0.0f)) TEST_SUCCESS } norm = s / norm; ASSERT(test_eq(v1[0] * norm, v2[0])) ASSERT(test_eq(v1[1] * norm, v2[1])) ASSERT(test_eq(v1[2] * norm, v2[2])) glm_vec3_zero(v1); GLM(vec3_normalize_to)(v1, v2); ASSERTIFY(test_assert_vec3_eq(v2, GLM_VEC3_ZERO)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_cross) { /* (u2.v3 - u3.v2, u3.v1 - u1.v3, u1.v2 - u2.v1) */ vec3 v1 = {2.0f, -3.0f, 4.0f}, v2 = {12.0f, -31.0f, 43.0f}, v3, v4; GLM(vec3_cross)(v1, v2, v3); v4[0] = v1[1] * v2[2] - v1[2] * v2[1]; v4[1] = v1[2] * v2[0] - v1[0] * v2[2]; v4[2] = v1[0] * v2[1] - v1[1] * v2[0]; ASSERTIFY(test_assert_vec3_eq(v3, v4)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_crossn) { /* (u2.v3 - u3.v2, u3.v1 - u1.v3, u1.v2 - u2.v1) */ vec3 v1 = {2.0f, -3.0f, 4.0f}, v2 = {12.0f, -31.0f, 43.0f}, v3, v4; GLM(vec3_crossn)(v1, v2, v3); v4[0] = v1[1] * v2[2] - v1[2] * v2[1]; v4[1] = v1[2] * v2[0] - v1[0] * v2[2]; v4[2] = v1[0] * v2[1] - v1[1] * v2[0]; glm_normalize(v4); ASSERTIFY(test_assert_vec3_eq(v3, v4)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, cross) { /* SAME AS VEC3_CROSS */ /* (u2.v3 - u3.v2, u3.v1 - u1.v3, u1.v2 - u2.v1) */ vec3 v1 = {2.0f, -3.0f, 4.0f}, v2 = {12.0f, -31.0f, 43.0f}, v3, v4; GLM(vec3_cross)(v1, v2, v3); v4[0] = v1[1] * v2[2] - v1[2] * v2[1]; v4[1] = v1[2] * v2[0] - v1[0] * v2[2]; v4[2] = v1[0] * v2[1] - v1[1] * v2[0]; ASSERTIFY(test_assert_vec3_eq(v3, v4)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_angle) { vec3 v1 = {1.0f, 0.0f, 0.0f}, v2 = {1.0f, 0.0f, 1.0f}, v3 = {0.0f, 1.0f, 0.0f}; float a; a = GLM(vec3_angle)(v1, v1); #ifndef CGLM_FAST_MATH ASSERT(!isinf(a)) ASSERT(!isnan(a)) #endif ASSERT(test_eq(a, 0.0f)) a = GLM(vec3_angle)(v1, v2); #ifndef CGLM_FAST_MATH ASSERT(!isinf(a)) ASSERT(!isnan(a)) #endif ASSERT(test_eq(a, GLM_PI_4f)) a = GLM(vec3_angle)(v1, v3); #ifndef CGLM_FAST_MATH ASSERT(!isinf(a)) ASSERT(!isnan(a)) #endif ASSERT(test_eq(a, GLM_PI_2f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_rotate) { vec3 v1 = {1.0f, 0.0f, 0.0f}, v2 = {1.0f, 1.0f, 1.0f}; /* rotate X around Y = -Z */ GLM(vec3_rotate)(v1, GLM_PI_2f, GLM_YUP); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], -1.0f)) /* rotate -Z around X = Y */ GLM(vec3_rotate)(v1, GLM_PI_2f, GLM_XUP); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 1.0f)) ASSERT(test_eq(v1[2], 0.0f)) /* rotate Y around Z = -X */ GLM(vec3_rotate)(v1, GLM_PI_2f, GLM_ZUP); ASSERT(test_eq(v1[0], -1.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 0.0f)) /* rotate v2 around Y by 90deg */ GLM(vec3_rotate)(v2, GLM_PI_2f, GLM_YUP); ASSERT(test_eq(v2[0], 1.0f)) ASSERT(test_eq(v2[1], 1.0f)) ASSERT(test_eq(v2[2], -1.0f)) /* rotate v2 around Y by 90deg */ GLM(vec3_rotate)(v2, GLM_PI_2f, GLM_YUP); ASSERT(test_eq(v2[0], -1.0f)) ASSERT(test_eq(v2[1], 1.0f)) ASSERT(test_eq(v2[2], -1.0f)) /* rotate v2 around Y by 90deg */ GLM(vec3_rotate)(v2, GLM_PI_2f, GLM_YUP); ASSERT(test_eq(v2[0], -1.0f)) ASSERT(test_eq(v2[1], 1.0f)) ASSERT(test_eq(v2[2], 1.0f)) /* rotate v2 around X by 90deg */ GLM(vec3_rotate)(v2, GLM_PI_2f, GLM_XUP); ASSERT(test_eq(v2[0], -1.0f)) ASSERT(test_eq(v2[1], -1.0f)) ASSERT(test_eq(v2[2], 1.0f)) /* rotate v2 around Z by 90deg */ GLM(vec3_rotate)(v2, GLM_PI_2f, GLM_ZUP); ASSERT(test_eq(v2[0], 1.0f)) ASSERT(test_eq(v2[1], -1.0f)) ASSERT(test_eq(v2[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_rotate_m4) { vec3 v1 = {1.0f, 0.0f, 0.0f}, v2 = {1.0f, 1.0f, 1.0f}; mat4 x, y, z; glm_rotate_make(x, GLM_PI_2f, GLM_XUP); glm_rotate_make(y, GLM_PI_2f, GLM_YUP); glm_rotate_make(z, GLM_PI_2f, GLM_ZUP); /* rotate X around Y = -Z */ GLM(vec3_rotate_m4)(y, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], -1.0f)) /* rotate -Z around X = Y */ GLM(vec3_rotate_m4)(x, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 1.0f)) ASSERT(test_eq(v1[2], 0.0f)) /* rotate Y around X = -X */ GLM(vec3_rotate_m4)(z, v1, v1); ASSERT(test_eq(v1[0], -1.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 0.0f)) /* rotate v2 around Y by 90deg */ GLM(vec3_rotate_m4)(y, v2, v2); ASSERT(test_eq(v2[0], 1.0f)) ASSERT(test_eq(v2[1], 1.0f)) ASSERT(test_eq(v2[2], -1.0f)) /* rotate v2 around Y by 90deg */ GLM(vec3_rotate_m4)(y, v2, v2); ASSERT(test_eq(v2[0], -1.0f)) ASSERT(test_eq(v2[1], 1.0f)) ASSERT(test_eq(v2[2], -1.0f)) /* rotate v2 around Y by 90deg */ GLM(vec3_rotate_m4)(y, v2, v2); ASSERT(test_eq(v2[0], -1.0f)) ASSERT(test_eq(v2[1], 1.0f)) ASSERT(test_eq(v2[2], 1.0f)) /* rotate v2 around X by 90deg */ GLM(vec3_rotate_m4)(x, v2, v2); ASSERT(test_eq(v2[0], -1.0f)) ASSERT(test_eq(v2[1], -1.0f)) ASSERT(test_eq(v2[2], 1.0f)) /* rotate v2 around Z by 90deg */ GLM(vec3_rotate_m4)(z, v2, v2); ASSERT(test_eq(v2[0], 1.0f)) ASSERT(test_eq(v2[1], -1.0f)) ASSERT(test_eq(v2[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_rotate_m3) { vec3 v1 = {1.0f, 0.0f, 0.0f}, v2 = {1.0f, 1.0f, 1.0f}; mat4 x0, y0, z0; mat3 x, y, z; glm_rotate_make(x0, GLM_PI_2f, GLM_XUP); glm_rotate_make(y0, GLM_PI_2f, GLM_YUP); glm_rotate_make(z0, GLM_PI_2f, GLM_ZUP); glm_mat4_pick3(x0, x); glm_mat4_pick3(y0, y); glm_mat4_pick3(z0, z); /* rotate X around Y = -Z */ GLM(vec3_rotate_m3)(y, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], -1.0f)) /* rotate -Z around X = Y */ GLM(vec3_rotate_m3)(x, v1, v1); ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 1.0f)) ASSERT(test_eq(v1[2], 0.0f)) /* rotate Y around Z = -X */ GLM(vec3_rotate_m3)(z, v1, v1); ASSERT(test_eq(v1[0], -1.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 0.0f)) /* rotate v2 around Y by 90deg */ GLM(vec3_rotate_m3)(y, v2, v2); ASSERT(test_eq(v2[0], 1.0f)) ASSERT(test_eq(v2[1], 1.0f)) ASSERT(test_eq(v2[2], -1.0f)) /* rotate v2 around Y by 90deg */ GLM(vec3_rotate_m3)(y, v2, v2); ASSERT(test_eq(v2[0], -1.0f)) ASSERT(test_eq(v2[1], 1.0f)) ASSERT(test_eq(v2[2], -1.0f)) /* rotate v2 around Y by 90deg */ GLM(vec3_rotate_m3)(y, v2, v2); ASSERT(test_eq(v2[0], -1.0f)) ASSERT(test_eq(v2[1], 1.0f)) ASSERT(test_eq(v2[2], 1.0f)) /* rotate v2 around X by 90deg */ GLM(vec3_rotate_m3)(x, v2, v2); ASSERT(test_eq(v2[0], -1.0f)) ASSERT(test_eq(v2[1], -1.0f)) ASSERT(test_eq(v2[2], 1.0f)) /* rotate v2 around Z by 90deg */ GLM(vec3_rotate_m3)(z, v2, v2); ASSERT(test_eq(v2[0], 1.0f)) ASSERT(test_eq(v2[1], -1.0f)) ASSERT(test_eq(v2[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_proj) { vec3 v1 = {3.0f, 4.0f, 0.0f}, v2 = {10.0f, 0.0f, 0.0f}, v3 = {0.0f, 10.0f, 0.0f}, v4 = {3.0f, 0.0f, 0.0f}, v5 = {0.0f, 4.0f, 0.0f}, v6; GLM(vec3_proj)(v1, v2, v6); ASSERTIFY(test_assert_vec3_eq(v4, v6)) GLM(vec3_proj)(v1, v3, v6); ASSERTIFY(test_assert_vec3_eq(v5, v6)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_center) { vec3 v1 = {30.0f, 0.0f, 0.0f}, v2 = {0.0f, 0.0f, 0.0f}, v3 = {15.0f, 0.0f, 0.0f}, v4 = {3.0f, 10.0f, 120.0f}, v5 = {0.46f, 4.0f, 14.0f}, v6; GLM(vec3_center)(v1, v2, v6); ASSERTIFY(test_assert_vec3_eq(v3, v6)) GLM(vec3_center)(v4, v5, v6); ASSERT(test_eq((v4[0] + v5[0]) * 0.5f, v6[0])) ASSERT(test_eq((v4[1] + v5[1]) * 0.5f, v6[1])) ASSERT(test_eq((v4[2] + v5[2]) * 0.5f, v6[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_distance2) { vec3 v1 = {30.0f, 0.0f, 0.0f}, v2 = {0.0f, 0.0f, 0.0f}, v3 = {3.0f, 10.0f, 120.0f}, v4 = {0.46f, 4.0f, 14.0f}; float d; d = GLM(vec3_distance2)(v1, v2); ASSERT(test_eq(d, 30.0f * 30.0f)) d = GLM(vec3_distance2)(v3, v4); ASSERT(test_eq(powf(v3[0] - v4[0], 2.0f) + powf(v3[1] - v4[1], 2.0f) + powf(v3[2] - v4[2], 2.0f), d)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_distance) { vec3 v1 = {30.0f, 0.0f, 0.0f}, v2 = {0.0f, 0.0f, 0.0f}, v3 = {3.0f, 10.0f, 120.0f}, v4 = {0.46f, 4.0f, 14.0f}; float d; d = GLM(vec3_distance)(v1, v2); ASSERT(test_eq(d, 30.0f)) d = GLM(vec3_distance)(v3, v4); ASSERT(test_eq(sqrtf(powf(v3[0] - v4[0], 2.0f) + powf(v3[1] - v4[1], 2.0f) + powf(v3[2] - v4[2], 2.0f)), d)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_maxv) { vec3 v1, v2, v3; vec3 v5 = {-1.456f, -1.456f, 241.456f}; vec3 v6 = {11.0f, 11.0f, 11.0f}; vec3 v7 = {78.0f, -78.0f, 7.0f}; GLM(vec3_maxv)(v5, v6, v1); GLM(vec3_maxv)(v5, v7, v2); GLM(vec3_maxv)(v6, v7, v3); ASSERT(test_eq(v1[0], 11.0f)) ASSERT(test_eq(v1[1], 11.0f)) ASSERT(test_eq(v1[2], 241.456f)) ASSERT(test_eq(v2[0], 78.0f)) ASSERT(test_eq(v2[1], -1.456f)) ASSERT(test_eq(v2[2], 241.456f)) ASSERT(test_eq(v3[0], 78.0f)) ASSERT(test_eq(v3[1], 11.0f)) ASSERT(test_eq(v3[2], 11.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_minv) { vec3 v1, v2, v3; vec3 v5 = {-1.456f, -1.456f, 241.456f}; vec3 v6 = {11.0f, 11.0f, 11.0f}; vec3 v7 = {78.0f, -78.0f, 7.0f}; GLM(vec3_minv)(v5, v6, v1); GLM(vec3_minv)(v5, v7, v2); GLM(vec3_minv)(v6, v7, v3); ASSERT(test_eq(v1[0], -1.456f)) ASSERT(test_eq(v1[1], -1.456f)) ASSERT(test_eq(v1[2], 11.0f)) ASSERT(test_eq(v2[0], -1.456f)) ASSERT(test_eq(v2[1], -78.0f)) ASSERT(test_eq(v2[2], 7.0f)) ASSERT(test_eq(v3[0], 11.0f)) ASSERT(test_eq(v3[1], -78.0f)) ASSERT(test_eq(v3[2], 7.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_ortho) { vec3 v1, v2, v3, v4 = {1.f, 1.f, 1.f}; vec3 v5, v6, v7, v8; float a; test_rand_vec3(v1); test_rand_vec3(v2); test_rand_vec3(v3); GLM(vec3_ortho)(v1, v5); GLM(vec3_ortho)(v2, v6); GLM(vec3_ortho)(v3, v7); GLM(vec3_ortho)(v4, v8); a = glm_vec3_angle(v1, v5); #ifndef CGLM_FAST_MATH ASSERT(!isinf(a)) ASSERT(!isnan(a)) #endif ASSERT(test_eq(a, GLM_PI_2f)) a = glm_vec3_angle(v2, v6); #ifndef CGLM_FAST_MATH ASSERT(!isinf(a)) ASSERT(!isnan(a)) #endif ASSERT(test_eq(a, GLM_PI_2f)) a = glm_vec3_angle(v3, v7); #ifndef CGLM_FAST_MATH ASSERT(!isinf(a)) ASSERT(!isnan(a)) #endif ASSERT(test_eq(a, GLM_PI_2f)) a = glm_vec3_angle(v4, v8); #ifndef CGLM_FAST_MATH ASSERT(!isinf(a)) ASSERT(!isnan(a)) #endif ASSERT(test_eq(a, GLM_PI_2f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_clamp) { vec3 v1 = {-1.456f, -11.456f, 31.456f}; vec3 v2 = {0.110f, 111.0f, 11.0f}; vec3 v3 = {78.0f, 32.0f, -78.0f}; GLM(vec3_clamp)(v1, -1.03f, 30.0f); GLM(vec3_clamp)(v2, 0.11f, 111.0f); GLM(vec3_clamp)(v3, -88.0f, 70.0f); ASSERT(test_eq(v1[0], -1.03f)) ASSERT(test_eq(v1[1], -1.03f)) ASSERT(test_eq(v1[2], 30.0f)) ASSERT(test_eq(v2[0], 0.11f)) ASSERT(test_eq(v2[1], 111.0f)) ASSERT(test_eq(v2[2], 11.0f)) ASSERT(test_eq(v3[0], 70.0f)) ASSERT(test_eq(v3[1], 32.0f)) ASSERT(test_eq(v3[2], -78.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_lerp) { vec3 v1 = {-100.0f, -200.0f, -10.0f}; vec3 v2 = {100.0f, 200.0f, 10.0f}; vec3 v3; GLM(vec3_lerp)(v1, v2, 0.5f, v3); ASSERT(test_eq(v3[0], 0.0f)) ASSERT(test_eq(v3[1], 0.0f)) ASSERT(test_eq(v3[2], 0.0f)) GLM(vec3_lerp)(v1, v2, 0.75f, v3); ASSERT(test_eq(v3[0], 50.0f)) ASSERT(test_eq(v3[1], 100.0f)) ASSERT(test_eq(v3[2], 5.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_lerpc) { vec3 v1 = {-100.0f, -200.0f, -10.0f}; vec3 v2 = {100.0f, 200.0f, 10.0f}; vec3 v3; GLM(vec3_lerpc)(v1, v2, 0.5f, v3); ASSERT(test_eq(v3[0], 0.0f)) ASSERT(test_eq(v3[1], 0.0f)) ASSERT(test_eq(v3[2], 0.0f)) GLM(vec3_lerpc)(v1, v2, 0.75f, v3); ASSERT(test_eq(v3[0], 50.0f)) ASSERT(test_eq(v3[1], 100.0f)) ASSERT(test_eq(v3[2], 5.0f)) GLM(vec3_lerpc)(v1, v2, -1.75f, v3); ASSERT(test_eq(v3[0], -100.0f)) ASSERT(test_eq(v3[1], -200.0f)) ASSERT(test_eq(v3[2], -10.0f)) GLM(vec3_lerpc)(v1, v2, 1.75f, v3); ASSERT(test_eq(v3[0], 100.0f)) ASSERT(test_eq(v3[1], 200.0f)) ASSERT(test_eq(v3[2], 10.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_mix) { vec3 v1 = {-100.0f, -200.0f, -10.0f}; vec3 v2 = {100.0f, 200.0f, 10.0f}; vec3 v3; GLM(vec3_mix)(v1, v2, 0.5f, v3); ASSERT(test_eq(v3[0], 0.0f)) ASSERT(test_eq(v3[1], 0.0f)) ASSERT(test_eq(v3[2], 0.0f)) GLM(vec3_mix)(v1, v2, 0.75f, v3); ASSERT(test_eq(v3[0], 50.0f)) ASSERT(test_eq(v3[1], 100.0f)) ASSERT(test_eq(v3[2], 5.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_mixc) { vec3 v1 = {-100.0f, -200.0f, -10.0f}; vec3 v2 = {100.0f, 200.0f, 10.0f}; vec3 v3; GLM(vec3_mixc)(v1, v2, 0.5f, v3); ASSERT(test_eq(v3[0], 0.0f)) ASSERT(test_eq(v3[1], 0.0f)) ASSERT(test_eq(v3[2], 0.0f)) GLM(vec3_mixc)(v1, v2, 0.75f, v3); ASSERT(test_eq(v3[0], 50.0f)) ASSERT(test_eq(v3[1], 100.0f)) ASSERT(test_eq(v3[2], 5.0f)) GLM(vec3_mixc)(v1, v2, -1.75f, v3); ASSERT(test_eq(v3[0], -100.0f)) ASSERT(test_eq(v3[1], -200.0f)) ASSERT(test_eq(v3[2], -10.0f)) GLM(vec3_mixc)(v1, v2, 1.75f, v3); ASSERT(test_eq(v3[0], 100.0f)) ASSERT(test_eq(v3[1], 200.0f)) ASSERT(test_eq(v3[2], 10.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_steps) { vec3 v1 = {-100.0f, -200.0f, -10.0f}; vec3 v2; GLM(vec3_steps)(-2.5f, v1, v2); ASSERT(test_eq(v2[0], 0.0f)) ASSERT(test_eq(v2[1], 0.0f)) ASSERT(test_eq(v2[2], 0.0f)) GLM(vec3_steps)(-10.0f, v1, v2); ASSERT(test_eq(v2[0], 0.0f)) ASSERT(test_eq(v2[1], 0.0f)) ASSERT(test_eq(v2[2], 1.0f)) GLM(vec3_steps)(-1000.0f, v1, v2); ASSERT(test_eq(v2[0], 1.0f)) ASSERT(test_eq(v2[1], 1.0f)) ASSERT(test_eq(v2[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_stepr) { vec3 v1 = {-2.5f, -10.0f, -1000.0f}; vec3 v2; GLM(vec3_stepr)(v1, -100.0f, v2); ASSERT(test_eq(v2[0], 0.0f)) ASSERT(test_eq(v2[1], 0.0f)) ASSERT(test_eq(v2[2], 1.0f)) GLM(vec3_stepr)(v1, -5.0f, v2); ASSERT(test_eq(v2[0], 0.0f)) ASSERT(test_eq(v2[1], 1.0f)) ASSERT(test_eq(v2[2], 1.0f)) GLM(vec3_stepr)(v1, -1.0f, v2); ASSERT(test_eq(v2[0], 1.0f)) ASSERT(test_eq(v2[1], 1.0f)) ASSERT(test_eq(v2[2], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_step) { vec3 v1 = {-100.0f, -200.0f, -10.0f}; vec3 s1 = {-100.0f, 0.0f, 10.0f}; vec3 s2 = {100.0f, -220.0f, -10.0f}; vec3 s3 = {100.0f, 200.0f, 10.0f}; vec3 v2; GLM(vec3_step)(s1, v1, v2); ASSERT(test_eq(v2[0], 1.0f)) ASSERT(test_eq(v2[1], 0.0f)) ASSERT(test_eq(v2[2], 0.0f)) GLM(vec3_step)(s2, v1, v2); ASSERT(test_eq(v2[0], 0.0f)) ASSERT(test_eq(v2[1], 1.0f)) ASSERT(test_eq(v2[2], 1.0f)) GLM(vec3_step)(s3, v1, v2); ASSERT(test_eq(v2[0], 0.0f)) ASSERT(test_eq(v2[1], 0.0f)) ASSERT(test_eq(v2[2], 0.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_smoothstep_uni) { vec3 v1 = {-100.0f, -200.0f, -10.0f}; vec3 v2; GLM(vec3_smoothstep_uni)(-200.0f, -100.0f, v1, v2); ASSERT(test_eq_th(v2[0], 1.0f, 1e-5f)) ASSERT(test_eq_th(v2[1], 0.0f, 1e-5f)) ASSERT(test_eq_th(v2[2], 1.0f, 1e-5f)) GLM(vec3_smoothstep_uni)(-250.0f, -200.0f, v1, v2); ASSERT(test_eq_th(v2[0], 1.0f, 1e-5f)) ASSERT(test_eq_th(v2[1], 1.0f, 1e-5f)) ASSERT(test_eq_th(v2[2], 1.0f, 1e-5f)) GLM(vec3_smoothstep_uni)(-200.0f, 200, v1, v2); ASSERT(v2[0] > 0.0f && v2[0] < 0.25f) ASSERT(test_eq(v2[1], 0.0f)) ASSERT(v2[2] > 0.0f && v2[2] < 0.5f) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_smoothstep) { vec3 v1 = {-100.0f, -200.0f, -10.0f}; vec3 e1_0 = {-100.0f, 0.0f, -11.0f}; vec3 e1_1 = {50.0f, 10.0f, 20.0f}; vec3 e2_0 = {-180.0f, -300.0f, -93.0f}; vec3 e2_1 = {100.0f, 120.0f, -10.0f}; vec3 e3_0 = {-12.0f, 100.0f, 0.0f}; vec3 e3_1 = {100.0f, 200.0f, 10.0f}; vec3 v2; GLM(vec3_smoothstep)(e1_0, e1_1, v1, v2); ASSERT(test_eq_th(v2[0], 0.0f, 1e-5f)) ASSERT(test_eq_th(v2[1], 0.0f, 1e-5f)) ASSERT(v2[2] > 0.0f && v2[2] < 0.1f) GLM(vec3_smoothstep)(e2_0, e2_1, v1, v2); ASSERT(v2[0] > 0.0f && v2[0] < 0.25f) ASSERT(v2[1] > 0.0f && v2[1] < 0.15f) ASSERT(test_eq_th(v2[2], 1.0f, 1e-5f)) GLM(vec3_smoothstep)(e3_0, e3_1, v1, v2); ASSERT(test_eq_th(v2[0], 0.0f, 1e-5f)) ASSERT(test_eq_th(v2[1], 0.0f, 1e-5f)) ASSERT(test_eq_th(v2[2], 0.0f, 1e-5f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_smoothinterp) { vec3 e1_0 = {-100.0f, 0.0f, -11.0f}; vec3 e1_1 = {50.0f, 10.0f, 20.0f}; vec3 e2_0 = {80.0f, -220.0f, -19.0f}; vec3 e2_1 = {100.0f, -200.0f, -10.0f}; vec3 e3_0 = {-12.0f, 100.0f, 0.0f}; vec3 e3_1 = {100.0f, 200.0f, 10.0f}; vec3 v2; GLM(vec3_smoothinterp)(e1_0, e1_1, 0.5f, v2); ASSERT(v2[0] >= e1_0[0] && v2[0] <= e1_1[0]) ASSERT(v2[1] >= e1_0[1] && v2[1] <= e1_1[1]) ASSERT(v2[2] >= e1_0[2] && v2[2] <= e1_1[2]) GLM(vec3_smoothinterp)(e2_0, e2_1, 0.5, v2); ASSERT(v2[0] >= e2_0[0] && v2[0] <= e2_1[0]) ASSERT(v2[1] >= e2_0[1] && v2[1] <= e2_1[1]) ASSERT(v2[2] >= e2_0[2] && v2[2] <= e2_1[2]) GLM(vec3_smoothinterp)(e3_0, e3_1, 1.0, v2); ASSERT(v2[0] >= e3_0[0] && v2[0] <= e3_1[0]) ASSERT(v2[1] >= e3_0[1] && v2[1] <= e3_1[1]) ASSERT(v2[2] >= e3_0[2] && v2[2] <= e3_1[2]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_smoothinterpc) { vec3 e1_0 = {-100.0f, 0.0f, -11.0f}; vec3 e1_1 = {50.0f, 10.0f, 20.0f}; vec3 e2_0 = {80.0f, -220.0f, -19.0f}; vec3 e2_1 = {100.0f, -200.0f, -10.0f}; vec3 e3_0 = {-12.0f, 100.0f, 0.0f}; vec3 e3_1 = {100.0f, 200.0f, 10.0f}; vec3 v2; GLM(vec3_smoothinterpc)(e1_0, e1_1, -0.5f, v2); ASSERT(v2[0] >= e1_0[0] && v2[0] <= e1_1[0]) ASSERT(v2[1] >= e1_0[1] && v2[1] <= e1_1[1]) ASSERT(v2[2] >= e1_0[2] && v2[2] <= e1_1[2]) GLM(vec3_smoothinterpc)(e2_0, e2_1, 0.5f, v2); ASSERT(v2[0] >= e2_0[0] && v2[0] <= e2_1[0]) ASSERT(v2[1] >= e2_0[1] && v2[1] <= e2_1[1]) ASSERT(v2[2] >= e2_0[2] && v2[2] <= e2_1[2]) GLM(vec3_smoothinterpc)(e3_0, e3_1, 2.0f, v2); ASSERT(v2[0] >= e3_0[0] && v2[0] <= e3_1[0]) ASSERT(v2[1] >= e3_0[1] && v2[1] <= e3_1[1]) ASSERT(v2[2] >= e3_0[2] && v2[2] <= e3_1[2]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_swizzle) { vec3 v; /* ZYX */ v[0] = 1; v[1] = 2; v[2] = 3; GLM(vec3_swizzle)(v, GLM_ZYX, v); ASSERTIFY(test_assert_vec3_eq(v, (vec3){3, 2, 1})) GLM(vec3_swizzle)(v, GLM_XXX, v); ASSERTIFY(test_assert_vec3_eq(v, (vec3){3, 3, 3})) v[0] = 1; v[1] = 2; v[2] = 3; GLM(vec3_swizzle)(v, GLM_YYY, v); ASSERTIFY(test_assert_vec3_eq(v, (vec3){2, 2, 2})) v[0] = 1; v[1] = 2; v[2] = 3; GLM(vec3_swizzle)(v, GLM_ZZZ, v); ASSERTIFY(test_assert_vec3_eq(v, (vec3){3, 3, 3})) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_broadcast) { vec3 v1, v2, v3; vec3 v5 = {-1.456f, -1.456f, -1.456f}; vec3 v6 = {11.0f, 11.0f, 11.0f}; vec3 v7 = {78.0f, 78.0f, 78.0f}; GLM(vec3_broadcast)(-1.456f, v1); GLM(vec3_broadcast)(11.0f, v2); GLM(vec3_broadcast)(78.0f, v3); ASSERTIFY(test_assert_vec3_eq(v1, v5)) ASSERTIFY(test_assert_vec3_eq(v2, v6)) ASSERTIFY(test_assert_vec3_eq(v3, v7)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_fill) { vec3 v1, v2, v3; vec3 v5 = {-1.456f, -1.456f, -1.456f}; vec3 v6 = {11.0f, 11.0f, 11.0f}; vec3 v7 = {78.0f, 78.0f, 78.0f}; GLM(vec3_fill)(v1, -1.456f); GLM(vec3_fill)(v2, 11.0f); GLM(vec3_fill)(v3, 78.0f); ASSERTIFY(test_assert_vec3_eq(v1, v5)) ASSERTIFY(test_assert_vec3_eq(v2, v6)) ASSERTIFY(test_assert_vec3_eq(v3, v7)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_eq) { vec3 v1, v2, v3; GLM(vec3_fill)(v1, -1.456f); GLM(vec3_fill)(v2, 11.0f); GLM(vec3_fill)(v3, 78.1f); ASSERT(GLM(vec3_eq)(v1, -1.456f)) ASSERT(GLM(vec3_eq)(v2, 11.0f)) ASSERT(!GLM(vec3_eq)(v3, 78.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_eq_eps) { vec3 v1, v2, v3; GLM(vec3_fill)(v1, -1.456f); GLM(vec3_fill)(v2, 11.0f); GLM(vec3_fill)(v3, 78.1f); ASSERT(GLM(vec3_eq_eps)(v1, -1.456f)) ASSERT(GLM(vec3_eq_eps)(v2, 11.0f)) ASSERT(!GLM(vec3_eq_eps)(v3, 78.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_eq_all) { vec3 v1, v2, v3; vec3 v4 = {2.104f, -3.012f, -4.10f}; vec3 v5 = {-12.35f, -31.140f, -43.502f}; GLM(vec3_fill)(v1, -1.456f); GLM(vec3_fill)(v2, 11.0f); GLM(vec3_fill)(v3, 78.0f); ASSERT(GLM(vec3_eq_all)(v1)) ASSERT(GLM(vec3_eq_all)(v2)) ASSERT(GLM(vec3_eq_all)(v3)) ASSERT(!GLM(vec3_eq_all)(v4)) ASSERT(!GLM(vec3_eq_all)(v5)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_eqv) { vec3 v1, v2, v3, v4, v5; vec3 v6 = {-1.456f, -1.456f, -1.456f}; vec3 v7 = {11.0f, 11.0f, 11.0f}; vec3 v8 = {78.0f, 78.0f, -43.502f}; GLM(vec3_fill)(v1, -1.456f); GLM(vec3_fill)(v2, 11.0f); GLM(vec3_fill)(v3, 78.0f); test_rand_vec3(v4); test_rand_vec3(v5); ASSERT(GLM(vec3_eqv)(v1, v6)) ASSERT(GLM(vec3_eqv)(v2, v7)) ASSERT(!GLM(vec3_eqv)(v3, v8)) ASSERT(!GLM(vec3_eqv)(v4, v5)) ASSERT(GLM(vec3_eqv)(v5, v5)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_eqv_eps) { vec3 v1, v2, v3, v4, v5; vec3 v6 = {-1.456f, -1.456f, -1.456f}; vec3 v7 = {11.0f, 11.0f, 11.0f}; vec3 v8 = {78.0f, 78.0f, -43.502f}; GLM(vec3_fill)(v1, -1.456f); GLM(vec3_fill)(v2, 11.0f); GLM(vec3_fill)(v3, 78.0f); test_rand_vec3(v4); test_rand_vec3(v5); ASSERT(GLM(vec3_eqv_eps)(v1, v6)) ASSERT(GLM(vec3_eqv_eps)(v2, v7)) ASSERT(!GLM(vec3_eqv_eps)(v3, v8)) ASSERT(!GLM(vec3_eqv_eps)(v4, v5)) ASSERT(GLM(vec3_eqv_eps)(v5, v5)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_max) { vec3 v1 = {2.104f, -3.012f, -4.10f}, v2 = {-12.35f, -31.140f, -43.502f}; #ifndef CGLM_FAST_MATH vec3 v3 = {INFINITY, 0.0f, 0.0f}/*, v4 = {NAN, INFINITY, 2.0f}*/; #endif vec3 /*v5 = {NAN, -1.0f, -1.0f}, */v6 = {-1.0f, -11.0f, 11.0f}; ASSERT(test_eq(GLM(vec3_max)(v1), 2.104f)) ASSERT(test_eq(GLM(vec3_max)(v2), -12.35f)) #ifndef CGLM_FAST_MATH ASSERT(isinf(GLM(vec3_max)(v3))) #endif // ASSERT(isnan(GLM(vec3_max)(v4))) // ASSERT(isnan(GLM(vec3_max)(v5))) ASSERT(test_eq(GLM(vec3_max)(v6), 11.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_min) { vec3 v1 = {2.104f, -3.012f, -4.10f}, v2 = {-12.35f, -31.140f, -43.502f}; #ifndef CGLM_FAST_MATH vec3 v3 = {INFINITY, 0.0f, 0.0f}/*, v4 = {NAN, INFINITY, 2.0f}*/; #endif vec3 /*v5 = {NAN, -1.0f, -1.0f},*/ v6 = {-1.0f, -11.0f, 11.0f}; ASSERT(test_eq(GLM(vec3_min)(v1), -4.10f)) ASSERT(test_eq(GLM(vec3_min)(v2), -43.502f)) #ifndef CGLM_FAST_MATH ASSERT(test_eq(GLM(vec3_min)(v3), 0.0f)) #endif // ASSERT(isnan(GLM(vec3_min)(v4))) // ASSERT(isnan(GLM(vec3_min)(v5))) ASSERT(test_eq(GLM(vec3_min)(v6), -11.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_isnan) { #ifndef CGLM_FAST_MATH vec3 v1 = {2.104f, -3.012f, -4.10f}, v2 = {-12.35f, -31.140f, -43.502f}; vec3 v3 = {INFINITY, 0.0f, 0.0f}, v4 = {NAN, INFINITY, 2.0f}; vec3 v5 = {NAN, -1.0f, -1.0f}, v6 = {-1.0f, -1.0f, 11.0f}; ASSERT(!GLM(vec3_isnan)(v1)) ASSERT(!GLM(vec3_isnan)(v2)) ASSERT(!GLM(vec3_isnan)(v3)) ASSERT(GLM(vec3_isnan)(v4)) ASSERT(GLM(vec3_isnan)(v5)) ASSERT(!GLM(vec3_isnan)(v6)) #endif TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_isinf) { #ifndef CGLM_FAST_MATH vec3 v1 = {2.104f, -3.012f, -4.10f}, v2 = {-12.35f, -31.140f, -43.502f}; vec3 v3 = {INFINITY, 0.0f, 0.0f}, v4 = {NAN, INFINITY, 2.0f}; vec3 v5 = {NAN, -1.0f, -1.0f}, v6 = {-1.0f, -1.0f, 11.0f}; ASSERT(!GLM(vec3_isinf)(v1)) ASSERT(!GLM(vec3_isinf)(v2)) ASSERT(GLM(vec3_isinf)(v3)) ASSERT(GLM(vec3_isinf)(v4)) ASSERT(!GLM(vec3_isinf)(v5)) ASSERT(!GLM(vec3_isinf)(v6)) #endif TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_isvalid) { #ifndef CGLM_FAST_MATH vec3 v1 = {2.104f, -3.012f, -4.10f}, v2 = {-12.35f, -31.140f, -43.502f}; vec3 v3 = {INFINITY, 0.0f, 0.0f}, v4 = {NAN, INFINITY, 2.0f}; vec3 v5 = {NAN, -1.0f, -1.0f}, v6 = {-1.0f, -1.0f, 11.0f}; ASSERT(GLM(vec3_isvalid)(v1)) ASSERT(GLM(vec3_isvalid)(v2)) ASSERT(!GLM(vec3_isvalid)(v3)) ASSERT(!GLM(vec3_isvalid)(v4)) ASSERT(!GLM(vec3_isvalid)(v5)) ASSERT(GLM(vec3_isvalid)(v6)) #endif TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_sign) { vec3 v1 = {2.104f, -3.012f, -4.10f}, v2 = {-12.35f, -31.140f, -43.502f}; vec3 v3, v4; vec3 v5 = {1.0f, -1.0f, -1.0f}, v6 = {-1.0f, -1.0f, -1.0f}; GLM(vec3_sign)(v1, v3); GLM(vec3_sign)(v2, v4); ASSERTIFY(test_assert_vec3_eq(v3, v5)) ASSERTIFY(test_assert_vec3_eq(v4, v6)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_abs) { vec3 v1 = {2.104f, -3.012f, -4.10f}, v2 = {-12.35f, -31.140f, -43.502f}; vec3 v3, v4; vec3 v5 = {2.104f, 3.012f, 4.10f}, v6 = {12.35f, 31.140f, 43.502f}; GLM(vec3_abs)(v1, v3); GLM(vec3_abs)(v2, v4); ASSERTIFY(test_assert_vec3_eq(v3, v5)) ASSERTIFY(test_assert_vec3_eq(v4, v6)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_fract) { vec3 v1 = {2.104f, 3.012f, 4.10f}, v2 = {12.35f, 31.140f, 43.502f}, v3, v4; vec3 v5 = {0.104f, 0.012f, 0.10f}, v6 = {0.35f, 0.140f, 0.502f}; GLM(vec3_fract)(v1, v3); GLM(vec3_fract)(v2, v4); ASSERTIFY(test_assert_vec3_eq(v3, v5)) ASSERTIFY(test_assert_vec3_eq(v4, v6)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_floor) { vec3 v1 = {2.104f, 3.012f, 4.10f}, v2 = {12.35f, 31.140f, 43.502f}, v3, v4; vec3 v5 = {2.0f, 3.0f, 4.0f}, v6 = {12.0f, 31.0f, 43.0f}; GLM(vec3_floor)(v1, v3); GLM(vec3_floor)(v2, v4); ASSERTIFY(test_assert_vec3_eq(v3, v5)) ASSERTIFY(test_assert_vec3_eq(v4, v6)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_mods) { vec3 v1 = {2.104f, 3.012f, 4.10f}, v2 = {12.35f, 31.140f, 43.502f}, v3, v4; vec3 v5 = {0.104f, 0.012f, 0.10f}, v6 = {0.35f, 0.140f, 0.502f}; /* Mod 1 - leaves just the fractional part */ GLM(vec3_mods)(v1, 1.0f, v3); GLM(vec3_mods)(v2, 1.0f, v4); ASSERTIFY(test_assert_vec3_eq(v3, v5)) ASSERTIFY(test_assert_vec3_eq(v4, v6)) /* Mod 2 - parity + fractional part */ GLM(vec3_mods)(v1, 2.0f, v3); GLM(vec3_mods)(v2, 2.0f, v4); vec3 v7 = {0.104f, 1.012f, 0.10f}, v8 = {0.35f, 1.140f, 1.502f}; ASSERTIFY(test_assert_vec3_eq(v3, v7)) ASSERTIFY(test_assert_vec3_eq(v4, v8)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_hadd) { vec3 v1 = {2.0f, 3.0f, 4.0f}, v2 = {12.0f, 31.0f, 43.0f}; float r1, r2, r3, r4; r1 = GLM(vec3_hadd)(v1); r2 = GLM(vec3_hadd)(v2); r3 = v1[0] + v1[1] + v1[2]; r4 = v2[0] + v2[1] + v2[2]; ASSERT(test_eq(r1, r3)) ASSERT(test_eq(r2, r4)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_sqrt) { vec3 v1 = {2.0f, 3.0f, 4.0f}, v2 = {12.0f, 31.0f, 43.0f}, v3, v4; GLM(vec3_sqrt)(v1, v3); GLM(vec3_sqrt)(v2, v4); ASSERT(test_eq(sqrtf(v1[0]), v3[0])) ASSERT(test_eq(sqrtf(v1[1]), v3[1])) ASSERT(test_eq(sqrtf(v1[2]), v3[2])) ASSERT(test_eq(sqrtf(v2[0]), v4[0])) ASSERT(test_eq(sqrtf(v2[1]), v4[1])) ASSERT(test_eq(sqrtf(v2[2]), v4[2])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_make) { float src[9] = { 7.2f, 1.0f, 5.8f, 2.5f, 6.1f, 9.9f, 17.7f, 4.3f, 3.2f }; vec3 dest[3]; float *srcp = src; unsigned int i, j; for (i = 0, j = 0; i < sizeof(src) / sizeof(float); i+=3,j++) { GLM(vec3_make)(srcp + i, dest[j]); ASSERT(test_eq(src[ i ], dest[j][0])); ASSERT(test_eq(src[i+1], dest[j][1])); ASSERT(test_eq(src[i+2], dest[j][2])); } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_faceforward) { vec3 N = {0.0f, 1.0f, 0.0f}; vec3 v = {1.0f, -1.0f, 0.0f}; vec3 Nref = {0.0f, -1.0f, 0.0f}; vec3 dest; GLM(vec3_faceforward)(N, v, Nref, dest); ASSERT(dest[0] == 0.0f && dest[1] == -1.0f && dest[2] == 0.0f); /* Expect N flipped */ TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_reflect) { vec3 dest; /* Original test: Reflecting off a horizontal surface */ vec3 I1 = {1.0f, -1.0f, 0.0f}; /* Incoming vector */ vec3 N1 = {0.0f, 1.0f, 0.0f}; /* Normal vector */ GLM(vec3_reflect)(I1, N1, dest); ASSERT(fabsf(dest[0] - 1.0f) < 0.00001f && fabsf(dest[1] - 1.0f) < 0.00001f && fabsf(dest[2] - 0.0f) < 0.00001f); /* Expect reflection */ /* Scenario 2: Reflecting off a vertical surface */ vec3 I2 = {1.0f, 0.0f, 0.0f}; /* Incoming vector */ vec3 N2 = {-1.0f, 0.0f, 0.0f}; /* Normal vector */ GLM(vec3_reflect)(I2, N2, dest); ASSERT(fabsf(dest[0] + 1.0f) < 0.00001f && fabsf(dest[1]) < 0.00001f && fabsf(dest[2]) < 0.00001f); /* Expect reflection to the left */ /* Scenario 3: Reflecting at an angle */ vec3 I3 = {sqrtf(2)/2, -sqrtf(2)/2, 0.0f}; /* Incoming vector at 45 degrees */ vec3 N3 = {0.0f, 1.0f, 0.0f}; /* Upwards normal vector */ GLM(vec3_reflect)(I3, N3, dest); ASSERT(fabsf(dest[0] - sqrtf(2)/2) < 0.00001f && fabsf(dest[1] - sqrtf(2)/2) < 0.00001f && fabsf(dest[2]) < 0.00001f); /* Expect reflection upwards */ TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec3_refract) { vec3 v = {sqrtf(0.5f), -sqrtf(0.5f), 0.0f}; /* Incoming vector at 45 degrees to normal */ vec3 N = {0.0f, 1.0f, 0.0f}; /* Surface normal */ vec3 dest; float eta; bool r; /* Water to Air (eta = 1.33/1.0) */ eta = 1.33f / 1.0f; r = GLM(vec3_refract)(v, N, eta, dest); if (!(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f)) { ASSERT(dest[1] < -0.3f); ASSERT(r == true); } else { ASSERT(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f); ASSERT(r == false); } /* Air to Glass (eta = 1.0 / 1.5) */ eta = 1.0f / 1.5f; r = GLM(vec3_refract)(v, N, eta, dest); /* Expect bending towards the normal */ ASSERT(r == true); ASSERT(dest[1] < -sqrtf(0.5f)); /* Glass to Water (eta = 1.5 / 1.33) */ eta = 1.5f / 1.33f; r = GLM(vec3_refract)(v, N, eta, dest); /* Expect bending towards the normal, less bending than air to glass */ ASSERT(r == true); ASSERT(dest[1] < -0.6f); /* Diamond to Air (eta = 2.42 / 1.0) */ eta = 2.42f / 1.0f; r = GLM(vec3_refract)(v, N, eta, dest); if (!(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f)) { /* High potential for total internal reflection, but if it occurs, expect significant bending */ ASSERT(dest[1] < -sqrtf(0.5f)); ASSERT(r == true); } else { ASSERT(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f); ASSERT(r == false); } TEST_SUCCESS } cglm-0.9.7/test/src/test_vec4.h000066400000000000000000001235071526744317200163130ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #include "test_common.h" #define TEST_GLM_SHUFFLE4(z, y, x, w) (((z) << 6) | ((y) << 4) | ((x) << 2)|(w)) #ifndef CGLM_TEST_VEC4_ONCE #define CGLM_TEST_VEC4_ONCE /* Macros */ TEST_IMPL(MACRO_GLM_VEC4_ONE_INIT) { vec4 v = GLM_VEC4_ONE_INIT; ASSERT(test_eq(v[0], 1.0f)) ASSERT(test_eq(v[1], 1.0f)) ASSERT(test_eq(v[2], 1.0f)) ASSERT(test_eq(v[3], 1.0f)) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_VEC4_ZERO_INIT) { vec4 v = GLM_VEC4_ZERO_INIT; ASSERT(test_eq(v[0], 0.0f)) ASSERT(test_eq(v[1], 0.0f)) ASSERT(test_eq(v[2], 0.0f)) ASSERT(test_eq(v[3], 0.0f)) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_VEC4_ONE) { ASSERT(test_eq(GLM_VEC4_ONE[0], 1.0f)) ASSERT(test_eq(GLM_VEC4_ONE[1], 1.0f)) ASSERT(test_eq(GLM_VEC4_ONE[2], 1.0f)) ASSERT(test_eq(GLM_VEC4_ONE[3], 1.0f)) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_VEC4_ZERO) { ASSERT(test_eq(GLM_VEC4_ZERO[0], 0.0f)) ASSERT(test_eq(GLM_VEC4_ZERO[1], 0.0f)) ASSERT(test_eq(GLM_VEC4_ZERO[2], 0.0f)) ASSERT(test_eq(GLM_VEC4_ZERO[3], 0.0f)) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_XXXX) { ASSERT(TEST_GLM_SHUFFLE4(0, 0, 0, 0) == GLM_XXXX) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_YYYY) { ASSERT(TEST_GLM_SHUFFLE4(1, 1, 1, 1) == GLM_YYYY) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_ZZZZ) { ASSERT(TEST_GLM_SHUFFLE4(2, 2, 2, 2) == GLM_ZZZZ) TEST_SUCCESS } TEST_IMPL(MACRO_GLM_WZYX) { ASSERT(TEST_GLM_SHUFFLE4(0, 1, 2, 3) == GLM_WZYX) TEST_SUCCESS } /* Deprecated */ TEST_IMPL(MACRO_glm_vec4_dup) { vec4 v1 = {13.0f, 12.0f, 11.0f, 56.0f}, v2; glm_vec4_dup(v1, v2); ASSERTIFY(test_assert_vec4_eq(v1, v2)) TEST_SUCCESS } TEST_IMPL(MACRO_glm_vec4_flipsign) { vec4 v1 = {13.0f, -12.0f, 11.0f, 56.0f}, v2 = {13.0f, -12.0f, 11.0f, 56.0f}, v3 = {-13.0f, 12.0f, -11.0f, -56.0f}; glm_vec4_flipsign(v1); glmc_vec4_flipsign(v2); ASSERTIFY(test_assert_vec4_eq(v1, v3)) ASSERTIFY(test_assert_vec4_eq(v2, v3)) TEST_SUCCESS } TEST_IMPL(MACRO_glm_vec4_flipsign_to) { vec4 v1 = {13.0f, -12.0f, 11.0f, 56.0f}, v2 = {-13.0f, 12.0f, -11.0f, -56.0f}, v3, v4; glm_vec4_flipsign_to(v1, v3); glmc_vec4_flipsign_to(v1, v4); ASSERTIFY(test_assert_vec4_eq(v2, v3)) ASSERTIFY(test_assert_vec4_eq(v2, v4)) TEST_SUCCESS } TEST_IMPL(MACRO_glm_vec4_inv) { vec4 v1 = {13.0f, -12.0f, 11.0f, 56.0f}, v2 = {13.0f, -12.0f, 11.0f, 56.0f}, v3 = {-13.0f, 12.0f, -11.0f, -56.0f}; glm_vec4_inv(v1); glmc_vec4_inv(v2); ASSERTIFY(test_assert_vec4_eq(v1, v3)) ASSERTIFY(test_assert_vec4_eq(v2, v3)) TEST_SUCCESS } TEST_IMPL(MACRO_glm_vec4_inv_to) { vec4 v1 = {13.0f, -12.0f, 11.0f, 56.0f}, v2 = {-13.0f, 12.0f, -11.0f, -56.0f}, v3, v4; glm_vec4_inv_to(v1, v3); glmc_vec4_inv_to(v1, v4); ASSERTIFY(test_assert_vec4_eq(v3, v4)) ASSERTIFY(test_assert_vec4_eq(v2, v3)) TEST_SUCCESS } TEST_IMPL(MACRO_glm_vec4_mulv) { vec4 v1 = {2.0f, -3.0f, 4.0f, 56.0f}, v2 = {-3.0f, 4.0f, -5.0f, 56.0f}, v3, v4; glm_vec4_mulv(v1, v2, v3); glmc_vec4_mulv(v1, v2, v4); ASSERTIFY(test_assert_vec4_eq(v3, v4)) ASSERT(test_eq(v1[0] * v2[0], v3[0])) ASSERT(test_eq(v1[1] * v2[1], v3[1])) ASSERT(test_eq(v1[2] * v2[2], v3[2])) ASSERT(test_eq(v1[3] * v2[3], v3[3])) TEST_SUCCESS } #endif /* CGLM_TEST_VEC4_ONCE */ /* --- */ TEST_IMPL(GLM_PREFIX, vec4) { vec4 v1 = {10.0f, 9.0f, 8.0f}; vec4 v2 = {10.0f, 9.0f, 8.0f, 7.0f}; vec4 v3; GLM(vec4)(v1, 7.0f, v3); ASSERTIFY(test_assert_vec4_eq(v2, v3)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_copy3) { vec4 v4 = {10.0f, 9.0f, 8.0f, 7.0f}; vec3 v3; GLM(vec4_copy3)(v4, v3); ASSERTIFY(test_assert_vec3_eq(v3, v4)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_copy) { vec4 v1 = {10.0f, 9.0f, 8.0f, 78.0f}; vec4 v2 = {1.0f, 2.0f, 3.0f, 4.0f}; GLM(vec4_copy)(v1, v2); ASSERTIFY(test_assert_vec4_eq(v1, v2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_ucopy) { vec4 v1 = {10.0f, 9.0f, 8.0f, 78.0f}; vec4 v2 = {1.0f, 2.0f, 3.0f, 4.0f}; GLM(vec4_ucopy)(v1, v2); ASSERTIFY(test_assert_vec4_eq(v1, v2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_zero) { vec4 v1 = {10.0f, 9.0f, 8.0f, 78.0f}; vec4 v2 = {1.0f, 2.0f, 3.0f, 4.0f}; GLM(vec4_zero)(v1); GLM(vec4_zero)(v2); ASSERTIFY(test_assert_vec4_eq(v1, GLM_VEC4_ZERO)) ASSERTIFY(test_assert_vec4_eq(v2, GLM_VEC4_ZERO)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_one) { vec4 v1 = {10.0f, 9.0f, 8.0f, 78.0f}; vec4 v2 = {1.0f, 2.0f, 3.0f, 4.0f}; GLM(vec4_one)(v1); GLM(vec4_one)(v2); ASSERTIFY(test_assert_vec4_eq(v1, GLM_VEC4_ONE)) ASSERTIFY(test_assert_vec4_eq(v2, GLM_VEC4_ONE)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_dot) { vec4 a = {10.0f, 9.0f, 8.0f, 78.0f}; vec4 b = {1.0f, 2.0f, 3.0f, 4.0f}; float dot1, dot2; dot1 = GLM(vec4_dot)(a, b); dot2 = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; ASSERT(test_eq(dot1, dot2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_norm2) { vec4 a = {10.0f, 9.0f, 8.0f, 78.0f}; float n1, n2; n1 = GLM(vec4_norm2)(a); n2 = a[0] * a[0] + a[1] * a[1] + a[2] * a[2] + a[3] * a[3]; ASSERT(test_eq(n1, n2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_norm) { vec4 a = {10.0f, 9.0f, 8.0f, 78.0f}; float n1, n2; n1 = GLM(vec4_norm)(a); n2 = sqrtf(a[0] * a[0] + a[1] * a[1] + a[2] * a[2] + a[3] * a[3]); ASSERT(test_eq(n1, n2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_norm_one) { vec4 a = {-10.0f, 9.0f, -8.0f, 78.0f}; float n1, n2; n1 = GLM(vec4_norm_one)(a); n2 = fabsf(a[0]) + fabsf(a[1]) + fabsf(a[2]) + fabsf(a[3]); ASSERT(test_eq(n1, n2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_norm_inf) { vec4 a = {-10.0f, 9.0f, -8.0f, 78.0f}; float n1, n2; n1 = GLM(vec4_norm_inf)(a); n2 = fabsf(a[0]); if (n2 < fabsf(a[1])) n2 = fabsf(a[1]); if (n2 < fabsf(a[2])) n2 = fabsf(a[2]); if (n2 < fabsf(a[3])) n2 = fabsf(a[3]); ASSERT(test_eq(n1, n2)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_add) { vec4 a = {-10.0f, 9.0f, -8.0f, 56.0f}; vec4 b = {12.0f, 19.0f, -18.0f, 1.0f}; vec4 c, d; c[0] = a[0] + b[0]; c[1] = a[1] + b[1]; c[2] = a[2] + b[2]; c[3] = a[3] + b[3]; GLM(vec4_add)(a, b, d); ASSERTIFY(test_assert_vec4_eq(c, d)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_adds) { vec4 a = {-10.0f, 9.0f, -8.0f, 56.0f}; vec4 c, d; float s = 7.0f; c[0] = a[0] + s; c[1] = a[1] + s; c[2] = a[2] + s; c[3] = a[3] + s; GLM(vec4_adds)(a, s, d); ASSERTIFY(test_assert_vec4_eq(c, d)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_sub) { vec4 a = {-10.0f, 9.0f, -8.0f, 56.0f}; vec4 b = {12.0f, 19.0f, -18.0f, 1.0f}; vec4 c, d; c[0] = a[0] - b[0]; c[1] = a[1] - b[1]; c[2] = a[2] - b[2]; c[3] = a[3] - b[3]; GLM(vec4_sub)(a, b, d); ASSERTIFY(test_assert_vec4_eq(c, d)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_subs) { vec4 a = {-10.0f, 9.0f, -8.0f, 74.0f}; vec4 c, d; float s = 7.0f; c[0] = a[0] - s; c[1] = a[1] - s; c[2] = a[2] - s; c[3] = a[3] - s; GLM(vec4_subs)(a, s, d); ASSERTIFY(test_assert_vec4_eq(c, d)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_mul) { vec4 v1 = {2.0f, -3.0f, 4.0f, 56.0f}, v2 = {-3.0f, 4.0f, -5.0f, 46.0f}, v3; GLM(vec4_mul)(v1, v2, v3); ASSERT(test_eq(v1[0] * v2[0], v3[0])) ASSERT(test_eq(v1[1] * v2[1], v3[1])) ASSERT(test_eq(v1[2] * v2[2], v3[2])) ASSERT(test_eq(v1[3] * v2[3], v3[3])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_scale) { vec4 v1 = {2.0f, -3.0f, 4.0f, 5.0f}, v2; float s = 7.0f; GLM(vec4_scale)(v1, s, v2); ASSERT(test_eq(v1[0] * s, v2[0])) ASSERT(test_eq(v1[1] * s, v2[1])) ASSERT(test_eq(v1[2] * s, v2[2])) ASSERT(test_eq(v1[3] * s, v2[3])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_scale_as) { vec4 v1 = {2.0f, -3.0f, 4.0f, 5.0f}, v2; float s = 7.0f; float norm; GLM(vec4_scale_as)(v1, s, v2); norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2] + v1[3] * v1[3]); if (norm < FLT_EPSILON) { ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 0.0f)) ASSERT(test_eq(v1[3], 0.0f)) TEST_SUCCESS } norm = s / norm; ASSERT(test_eq(v1[0] * norm, v2[0])) ASSERT(test_eq(v1[1] * norm, v2[1])) ASSERT(test_eq(v1[2] * norm, v2[2])) ASSERT(test_eq(v1[3] * norm, v2[3])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_div) { vec4 v1 = {2.0f, -3.0f, 4.0f, 40.0f}, v2 = {-3.0f, 4.0f, -5.0f, 2.0f}, v3; GLM(vec4_div)(v1, v2, v3); ASSERT(test_eq(v1[0] / v2[0], v3[0])) ASSERT(test_eq(v1[1] / v2[1], v3[1])) ASSERT(test_eq(v1[2] / v2[2], v3[2])) ASSERT(test_eq(v1[3] / v2[3], v3[3])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_divs) { vec4 v1 = {2.0f, -3.0f, 4.0f, 40.0f}, v2; float s = 7.0f; GLM(vec4_divs)(v1, s, v2); ASSERT(test_eq(v1[0] / s, v2[0])) ASSERT(test_eq(v1[1] / s, v2[1])) ASSERT(test_eq(v1[2] / s, v2[2])) ASSERT(test_eq(v1[3] / s, v2[3])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_addadd) { vec4 v1 = {2.0f, -3.0f, 4.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f, 20.0f}, v3 = {1.0f, 2.0f, 3.0f, 130.0f}, v4 = {1.0f, 2.0f, 3.0f, 130.0f}; GLM(vec4_addadd)(v1, v2, v4); ASSERT(test_eq(v3[0] + v1[0] + v2[0], v4[0])) ASSERT(test_eq(v3[1] + v1[1] + v2[1], v4[1])) ASSERT(test_eq(v3[2] + v1[2] + v2[2], v4[2])) ASSERT(test_eq(v3[3] + v1[3] + v2[3], v4[3])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_subadd) { vec4 v1 = {2.0f, -3.0f, 4.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f, 20.0f}, v3 = {1.0f, 2.0f, 3.0f, 130.0f}, v4 = {1.0f, 2.0f, 3.0f, 130.0f}; GLM(vec4_subadd)(v1, v2, v4); ASSERT(test_eq(v3[0] + v1[0] - v2[0], v4[0])) ASSERT(test_eq(v3[1] + v1[1] - v2[1], v4[1])) ASSERT(test_eq(v3[2] + v1[2] - v2[2], v4[2])) ASSERT(test_eq(v3[3] + v1[3] - v2[3], v4[3])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_muladd) { vec4 v1 = {2.0f, -3.0f, 4.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f, 20.0f}, v3 = {1.0f, 2.0f, 3.0f, 130.0f}, v4 = {1.0f, 2.0f, 3.0f, 130.0f}; GLM(vec4_muladd)(v1, v2, v4); ASSERT(test_eq(v3[0] + v1[0] * v2[0], v4[0])) ASSERT(test_eq(v3[1] + v1[1] * v2[1], v4[1])) ASSERT(test_eq(v3[2] + v1[2] * v2[2], v4[2])) ASSERT(test_eq(v3[3] + v1[3] * v2[3], v4[3])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_muladds) { vec4 v1 = {2.0f, -3.0f, 4.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f, 20.0f}, v3 = {-3.0f, 4.0f, -5.0f, 20.0f}; float s = 9.0f; GLM(vec4_muladds)(v1, s, v3); ASSERT(test_eq(v2[0] + v1[0] * s, v3[0])) ASSERT(test_eq(v2[1] + v1[1] * s, v3[1])) ASSERT(test_eq(v2[2] + v1[2] * s, v3[2])) ASSERT(test_eq(v2[3] + v1[3] * s, v3[3])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_maxadd) { vec4 v1 = {2.0f, -3.0f, 4.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f, 20.0f}, v3 = {1.0f, 2.0f, 3.0f, 130.0f}, v4 = {1.0f, 2.0f, 3.0f, 130.0f}; GLM(vec4_maxadd)(v1, v2, v4); ASSERT(test_eq(v3[0] + glm_max(v1[0], v2[0]), v4[0])) ASSERT(test_eq(v3[1] + glm_max(v1[1], v2[1]), v4[1])) ASSERT(test_eq(v3[2] + glm_max(v1[2], v2[2]), v4[2])) ASSERT(test_eq(v3[3] + glm_max(v1[3], v2[3]), v4[3])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_minadd) { vec4 v1 = {2.0f, -3.0f, 4.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f, 20.0f}, v3 = {1.0f, 2.0f, 3.0f, 130.0f}, v4 = {1.0f, 2.0f, 3.0f, 130.0f}; GLM(vec4_minadd)(v1, v2, v4); ASSERT(test_eq(v3[0] + glm_min(v1[0], v2[0]), v4[0])) ASSERT(test_eq(v3[1] + glm_min(v1[1], v2[1]), v4[1])) ASSERT(test_eq(v3[2] + glm_min(v1[2], v2[2]), v4[2])) ASSERT(test_eq(v3[3] + glm_min(v1[3], v2[3]), v4[3])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_subsub) { vec4 v1 = {2.0f, -3.0f, 4.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f, 20.0f}, v3 = {1.0f, 2.0f, 3.0f, 130.0f}, v4 = {1.0f, 2.0f, 3.0f, 130.0f}; GLM(vec4_subsub)(v1, v2, v4); ASSERT(test_eq(v3[0] - (v1[0] - v2[0]), v4[0])) ASSERT(test_eq(v3[1] - (v1[1] - v2[1]), v4[1])) ASSERT(test_eq(v3[2] - (v1[2] - v2[2]), v4[2])) ASSERT(test_eq(v3[3] - (v1[3] - v2[3]), v4[3])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_addsub) { vec4 v1 = {2.0f, -3.0f, 4.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f, 20.0f}, v3 = {1.0f, 2.0f, 3.0f, 130.0f}, v4 = {1.0f, 2.0f, 3.0f, 130.0f}; GLM(vec4_addsub)(v1, v2, v4); ASSERT(test_eq(v3[0] - (v1[0] + v2[0]), v4[0])) ASSERT(test_eq(v3[1] - (v1[1] + v2[1]), v4[1])) ASSERT(test_eq(v3[2] - (v1[2] + v2[2]), v4[2])) ASSERT(test_eq(v3[3] - (v1[3] + v2[3]), v4[3])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_mulsub) { vec4 v1 = {2.0f, -3.0f, 4.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f, 20.0f}, v3 = {1.0f, 2.0f, 3.0f, 130.0f}, v4 = {1.0f, 2.0f, 3.0f, 130.0f}; GLM(vec4_mulsub)(v1, v2, v4); ASSERT(test_eq(v3[0] - (v1[0] * v2[0]), v4[0])) ASSERT(test_eq(v3[1] - (v1[1] * v2[1]), v4[1])) ASSERT(test_eq(v3[2] - (v1[2] * v2[2]), v4[2])) ASSERT(test_eq(v3[3] - (v1[3] * v2[3]), v4[3])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_mulsubs) { vec4 v1 = {2.0f, -3.0f, 4.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f, 20.0f}, v3 = {-3.0f, 4.0f, -5.0f, 20.0f}; float s = 9.0f; GLM(vec4_mulsubs)(v1, s, v3); ASSERT(test_eq(v2[0] - (v1[0] * s), v3[0])) ASSERT(test_eq(v2[1] - (v1[1] * s), v3[1])) ASSERT(test_eq(v2[2] - (v1[2] * s), v3[2])) ASSERT(test_eq(v2[3] - (v1[3] * s), v3[3])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_maxsub) { vec4 v1 = {2.0f, -3.0f, 4.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f, 20.0f}, v3 = {1.0f, 2.0f, 3.0f, 130.0f}, v4 = {1.0f, 2.0f, 3.0f, 130.0f}; GLM(vec4_maxsub)(v1, v2, v4); ASSERT(test_eq(v3[0] - glm_max(v1[0], v2[0]), v4[0])) ASSERT(test_eq(v3[1] - glm_max(v1[1], v2[1]), v4[1])) ASSERT(test_eq(v3[2] - glm_max(v1[2], v2[2]), v4[2])) ASSERT(test_eq(v3[3] - glm_max(v1[3], v2[3]), v4[3])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_minsub) { vec4 v1 = {2.0f, -3.0f, 4.0f, 4.0f}, v2 = {-3.0f, 4.0f, -5.0f, 20.0f}, v3 = {1.0f, 2.0f, 3.0f, 130.0f}, v4 = {1.0f, 2.0f, 3.0f, 130.0f}; GLM(vec4_minsub)(v1, v2, v4); ASSERT(test_eq(v3[0] - glm_min(v1[0], v2[0]), v4[0])) ASSERT(test_eq(v3[1] - glm_min(v1[1], v2[1]), v4[1])) ASSERT(test_eq(v3[2] - glm_min(v1[2], v2[2]), v4[2])) ASSERT(test_eq(v3[3] - glm_min(v1[3], v2[3]), v4[3])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_negate_to) { vec4 v1 = {2.0f, -3.0f, 4.0f, 60.0f}, v2 = {-3.0f, 4.0f, -5.0f, 34.0f}, v3, v4; GLM(vec4_negate_to)(v1, v3); GLM(vec4_negate_to)(v2, v4); ASSERT(test_eq(-v1[0], v3[0])) ASSERT(test_eq(-v1[1], v3[1])) ASSERT(test_eq(-v1[2], v3[2])) ASSERT(test_eq(-v1[3], v3[3])) ASSERT(test_eq(-v2[0], v4[0])) ASSERT(test_eq(-v2[1], v4[1])) ASSERT(test_eq(-v2[2], v4[2])) ASSERT(test_eq(-v2[3], v4[3])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_negate) { vec4 v1 = {2.0f, -3.0f, 4.0f, 60.0f}, v2 = {-3.0f, 4.0f, -5.0f, 34.0f}, v3 = {2.0f, -3.0f, 4.0f, 60.0f}, v4 = {-3.0f, 4.0f, -5.0f, 34.0f}; GLM(vec4_negate)(v1); GLM(vec4_negate)(v2); ASSERT(test_eq(-v1[0], v3[0])) ASSERT(test_eq(-v1[1], v3[1])) ASSERT(test_eq(-v1[2], v3[2])) ASSERT(test_eq(-v1[3], v3[3])) ASSERT(test_eq(-v2[0], v4[0])) ASSERT(test_eq(-v2[1], v4[1])) ASSERT(test_eq(-v2[2], v4[2])) ASSERT(test_eq(-v2[3], v4[3])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_normalize) { vec4 v1 = {2.0f, -3.0f, 4.0f, 5.0f}, v2 = {2.0f, -3.0f, 4.0f, 5.0f}; float s = 1.0f; float norm; GLM(vec4_normalize)(v2); norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2] + v1[3] * v1[3]); if (norm < FLT_EPSILON) { ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 0.0f)) ASSERT(test_eq(v1[3], 0.0f)) TEST_SUCCESS } norm = s / norm; ASSERT(test_eq(v1[0] * norm, v2[0])) ASSERT(test_eq(v1[1] * norm, v2[1])) ASSERT(test_eq(v1[2] * norm, v2[2])) ASSERT(test_eq(v1[3] * norm, v2[3])) glm_vec4_zero(v1); GLM(vec4_normalize)(v1); ASSERTIFY(test_assert_vec4_eq(v1, GLM_VEC4_ZERO)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_normalize_to) { vec4 v1 = {2.0f, -3.0f, 4.0f, 5.0f}, v2; float s = 1.0f; float norm; GLM(vec4_normalize_to)(v1, v2); norm = sqrtf(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2] + v1[3] * v1[3]); if (norm < FLT_EPSILON) { ASSERT(test_eq(v1[0], 0.0f)) ASSERT(test_eq(v1[1], 0.0f)) ASSERT(test_eq(v1[2], 0.0f)) ASSERT(test_eq(v1[3], 0.0f)) TEST_SUCCESS } norm = s / norm; ASSERT(test_eq(v1[0] * norm, v2[0])) ASSERT(test_eq(v1[1] * norm, v2[1])) ASSERT(test_eq(v1[2] * norm, v2[2])) ASSERT(test_eq(v1[3] * norm, v2[3])) glm_vec4_zero(v1); GLM(vec4_normalize_to)(v1, v2); ASSERTIFY(test_assert_vec4_eq(v2, GLM_VEC4_ZERO)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_distance2) { vec4 v1 = {30.0f, 0.0f, 0.0f, 0.0f}, v2 = {0.0f, 0.0f, 0.0f, 0.0f}, v3 = {3.0f, 10.0f, 120.0f, 140.0f}, v4 = {0.46f, 4.0f, 14.0f, 10.0f}; float d; d = GLM(vec4_distance2)(v1, v2); ASSERT(test_eq(d, 30.0f * 30.0f)) d = GLM(vec4_distance2)(v3, v4); ASSERT(test_eq(powf(v3[0] - v4[0], 2.0f) + powf(v3[1] - v4[1], 2.0f) + powf(v3[2] - v4[2], 2.0f) + powf(v3[3] - v4[3], 2.0f), d)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_distance) { vec4 v1 = {30.0f, 0.0f, 0.0f, 0.0f}, v2 = {0.0f, 0.0f, 0.0f, 0.0f}, v3 = {3.0f, 10.0f, 120.0f, 140.0f}, v4 = {0.46f, 4.0f, 14.0f, 10.0f}; float d; d = GLM(vec4_distance)(v1, v2); ASSERT(test_eq(d, 30.0f)) d = GLM(vec4_distance)(v3, v4); ASSERT(test_eq(sqrtf(powf(v3[0] - v4[0], 2.0f) + powf(v3[1] - v4[1], 2.0f) + powf(v3[2] - v4[2], 2.0f) + powf(v3[3] - v4[3], 2.0f)), d)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_maxv) { vec4 v1, v2, v3; vec4 v5 = {-1.456f, -1.456f, 241.456f, 10.0f}; vec4 v6 = {11.0f, 11.0f, 11.0f, 90.0f}; vec4 v7 = {78.0f, -78.0f, 7.0f, 5.0f}; GLM(vec4_maxv)(v5, v6, v1); GLM(vec4_maxv)(v5, v7, v2); GLM(vec4_maxv)(v6, v7, v3); ASSERT(test_eq(v1[0], 11.0f)) ASSERT(test_eq(v1[1], 11.0f)) ASSERT(test_eq(v1[2], 241.456f)) ASSERT(test_eq(v1[3], 90.0f)) ASSERT(test_eq(v2[0], 78.0f)) ASSERT(test_eq(v2[1], -1.456f)) ASSERT(test_eq(v2[2], 241.456f)) ASSERT(test_eq(v2[3], 10.0f)) ASSERT(test_eq(v3[0], 78.0f)) ASSERT(test_eq(v3[1], 11.0f)) ASSERT(test_eq(v3[2], 11.0f)) ASSERT(test_eq(v3[3], 90.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_minv) { vec4 v1, v2, v3; vec4 v5 = {-1.456f, -1.456f, 241.456f, 10.0f}; vec4 v6 = {11.0f, 11.0f, 11.0f, 90.0f}; vec4 v7 = {78.0f, -78.0f, 7.0f, 5.0f}; GLM(vec4_minv)(v5, v6, v1); GLM(vec4_minv)(v5, v7, v2); GLM(vec4_minv)(v6, v7, v3); ASSERT(test_eq(v1[0], -1.456f)) ASSERT(test_eq(v1[1], -1.456f)) ASSERT(test_eq(v1[2], 11.0f)) ASSERT(test_eq(v1[3], 10.0f)) ASSERT(test_eq(v2[0], -1.456f)) ASSERT(test_eq(v2[1], -78.0f)) ASSERT(test_eq(v2[2], 7.0f)) ASSERT(test_eq(v2[3], 5.0f)) ASSERT(test_eq(v3[0], 11.0f)) ASSERT(test_eq(v3[1], -78.0f)) ASSERT(test_eq(v3[2], 7.0f)) ASSERT(test_eq(v3[3], 5.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_clamp) { vec4 v1 = {-1.456f, -11.456f, 31.456f, 67.04f}; vec4 v2 = {0.110f, 111.0f, 11.0f, 90.0f}; vec4 v3 = {78.0f, 32.0f, -78.0f, 3.0f}; GLM(vec4_clamp)(v1, -1.03f, 30.0f); GLM(vec4_clamp)(v2, 0.11f, 111.0f); GLM(vec4_clamp)(v3, -88.0f, 70.0f); ASSERT(test_eq(v1[0], -1.03f)) ASSERT(test_eq(v1[1], -1.03f)) ASSERT(test_eq(v1[2], 30.0f)) ASSERT(test_eq(v1[3], 30.0f)) ASSERT(test_eq(v2[0], 0.11f)) ASSERT(test_eq(v2[1], 111.0f)) ASSERT(test_eq(v2[2], 11.0f)) ASSERT(test_eq(v2[3], 90.0f)) ASSERT(test_eq(v3[0], 70.0f)) ASSERT(test_eq(v3[1], 32.0f)) ASSERT(test_eq(v3[2], -78.0f)) ASSERT(test_eq(v3[3], 3.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_lerp) { vec4 v1 = {-100.0f, -200.0f, -10.0f, -10.0f}; vec4 v2 = {100.0f, 200.0f, 10.0f, 10.0f}; vec4 v3; GLM(vec4_lerp)(v1, v2, 0.5f, v3); ASSERT(test_eq(v3[0], 0.0f)) ASSERT(test_eq(v3[1], 0.0f)) ASSERT(test_eq(v3[2], 0.0f)) ASSERT(test_eq(v3[3], 0.0f)) GLM(vec4_lerp)(v1, v2, 0.75f, v3); ASSERT(test_eq(v3[0], 50.0f)) ASSERT(test_eq(v3[1], 100.0f)) ASSERT(test_eq(v3[2], 5.0f)) ASSERT(test_eq(v3[3], 5.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_lerpc) { vec4 v1 = {-100.0f, -200.0f, -10.0f, -10.0f}; vec4 v2 = {100.0f, 200.0f, 10.0f, 10.0f}; vec4 v3; GLM(vec4_lerpc)(v1, v2, 0.5f, v3); ASSERT(test_eq(v3[0], 0.0f)) ASSERT(test_eq(v3[1], 0.0f)) ASSERT(test_eq(v3[2], 0.0f)) ASSERT(test_eq(v3[3], 0.0f)) GLM(vec4_lerpc)(v1, v2, 0.75f, v3); ASSERT(test_eq(v3[0], 50.0f)) ASSERT(test_eq(v3[1], 100.0f)) ASSERT(test_eq(v3[2], 5.0f)) ASSERT(test_eq(v3[3], 5.0f)) GLM(vec4_lerpc)(v1, v2, -1.75f, v3); ASSERT(test_eq(v3[0], -100.0f)) ASSERT(test_eq(v3[1], -200.0f)) ASSERT(test_eq(v3[2], -10.0f)) ASSERT(test_eq(v3[3], -10.0f)) GLM(vec4_lerpc)(v1, v2, 1.75f, v3); ASSERT(test_eq(v3[0], 100.0f)) ASSERT(test_eq(v3[1], 200.0f)) ASSERT(test_eq(v3[2], 10.0f)) ASSERT(test_eq(v3[3], 10.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_mix) { vec4 v1 = {-100.0f, -200.0f, -10.0f, -10.0f}; vec4 v2 = {100.0f, 200.0f, 10.0f, 10.0f}; vec4 v3; GLM(vec4_mix)(v1, v2, 0.5f, v3); ASSERT(test_eq(v3[0], 0.0f)) ASSERT(test_eq(v3[1], 0.0f)) ASSERT(test_eq(v3[2], 0.0f)) ASSERT(test_eq(v3[3], 0.0f)) GLM(vec4_mix)(v1, v2, 0.75f, v3); ASSERT(test_eq(v3[0], 50.0f)) ASSERT(test_eq(v3[1], 100.0f)) ASSERT(test_eq(v3[2], 5.0f)) ASSERT(test_eq(v3[3], 5.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_mixc) { vec4 v1 = {-100.0f, -200.0f, -10.0f, -10.0f}; vec4 v2 = {100.0f, 200.0f, 10.0f, 10.0f}; vec4 v3; GLM(vec4_mixc)(v1, v2, 0.5f, v3); ASSERT(test_eq(v3[0], 0.0f)) ASSERT(test_eq(v3[1], 0.0f)) ASSERT(test_eq(v3[2], 0.0f)) ASSERT(test_eq(v3[3], 0.0f)) GLM(vec4_mixc)(v1, v2, 0.75f, v3); ASSERT(test_eq(v3[0], 50.0f)) ASSERT(test_eq(v3[1], 100.0f)) ASSERT(test_eq(v3[2], 5.0f)) ASSERT(test_eq(v3[3], 5.0f)) GLM(vec4_mixc)(v1, v2, -1.75f, v3); ASSERT(test_eq(v3[0], -100.0f)) ASSERT(test_eq(v3[1], -200.0f)) ASSERT(test_eq(v3[2], -10.0f)) ASSERT(test_eq(v3[3], -10.0f)) GLM(vec4_mixc)(v1, v2, 1.75f, v3); ASSERT(test_eq(v3[0], 100.0f)) ASSERT(test_eq(v3[1], 200.0f)) ASSERT(test_eq(v3[2], 10.0f)) ASSERT(test_eq(v3[3], 10.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_steps) { vec4 v1 = {-100.0f, -200.0f, -10.0f, -10.0f}; vec4 v2; GLM(vec4_steps)(-2.5f, v1, v2); ASSERT(test_eq(v2[0], 0.0f)) ASSERT(test_eq(v2[1], 0.0f)) ASSERT(test_eq(v2[2], 0.0f)) ASSERT(test_eq(v2[3], 0.0f)) GLM(vec4_steps)(-10.0f, v1, v2); ASSERT(test_eq(v2[0], 0.0f)) ASSERT(test_eq(v2[1], 0.0f)) ASSERT(test_eq(v2[2], 1.0f)) ASSERT(test_eq(v2[3], 1.0f)) GLM(vec4_steps)(-1000.0f, v1, v2); ASSERT(test_eq(v2[0], 1.0f)) ASSERT(test_eq(v2[1], 1.0f)) ASSERT(test_eq(v2[2], 1.0f)) ASSERT(test_eq(v2[3], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_stepr) { vec4 v1 = {-2.5f, -100.0f, -200.0f, -300.0f}; vec4 v2; GLM(vec4_stepr)(v1, -1000.0f, v2); ASSERT(test_eq(v2[0], 0.0f)) ASSERT(test_eq(v2[1], 0.0f)) ASSERT(test_eq(v2[2], 0.0f)) ASSERT(test_eq(v2[3], 0.0f)) GLM(vec4_stepr)(v1, -250.0f, v2); ASSERT(test_eq(v2[0], 0.0f)) ASSERT(test_eq(v2[1], 0.0f)) ASSERT(test_eq(v2[2], 0.0f)) ASSERT(test_eq(v2[3], 1.0f)) GLM(vec4_stepr)(v1, -150.0f, v2); ASSERT(test_eq(v2[0], 0.0f)) ASSERT(test_eq(v2[1], 0.0f)) ASSERT(test_eq(v2[2], 1.0f)) ASSERT(test_eq(v2[3], 1.0f)) GLM(vec4_stepr)(v1, -10.0f, v2); ASSERT(test_eq(v2[0], 0.0f)) ASSERT(test_eq(v2[1], 1.0f)) ASSERT(test_eq(v2[2], 1.0f)) ASSERT(test_eq(v2[3], 1.0f)) GLM(vec4_stepr)(v1, 0.0f, v2); ASSERT(test_eq(v2[0], 1.0f)) ASSERT(test_eq(v2[1], 1.0f)) ASSERT(test_eq(v2[2], 1.0f)) ASSERT(test_eq(v2[3], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_step) { vec4 v1 = {-100.0f, -200.0f, -10.0f, -10.0f}; vec4 s1 = {-100.0f, 0.0f, 10.0f, 10.0f}; vec4 s2 = {100.0f, -220.0f, -10.0f, -10.0f}; vec4 s3 = {100.0f, 200.0f, 10.0f, 10.0f}; vec4 v2; GLM(vec4_step)(s1, v1, v2); ASSERT(test_eq(v2[0], 1.0f)) ASSERT(test_eq(v2[1], 0.0f)) ASSERT(test_eq(v2[2], 0.0f)) ASSERT(test_eq(v2[3], 0.0f)) GLM(vec4_step)(s2, v1, v2); ASSERT(test_eq(v2[0], 0.0f)) ASSERT(test_eq(v2[1], 1.0f)) ASSERT(test_eq(v2[2], 1.0f)) ASSERT(test_eq(v2[3], 1.0f)) GLM(vec4_step)(s3, v1, v2); ASSERT(test_eq(v2[0], 0.0f)) ASSERT(test_eq(v2[1], 0.0f)) ASSERT(test_eq(v2[2], 0.0f)) ASSERT(test_eq(v2[3], 0.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_smoothstep_uni) { vec4 v1 = {-100.0f, -200.0f, -10.0f, -10.0f}; vec4 v2; GLM(vec4_smoothstep_uni)(-200.0f, -100.0f, v1, v2); ASSERT(test_eq_th(v2[0], 1.0f, 1e-5f)) ASSERT(test_eq_th(v2[1], 0.0f, 1e-5f)) ASSERT(test_eq_th(v2[2], 1.0f, 1e-5f)) ASSERT(test_eq_th(v2[3], 1.0f, 1e-5f)) GLM(vec4_smoothstep_uni)(-250.0f, -200.0f, v1, v2); ASSERT(test_eq_th(v2[0], 1.0f, 1e-5f)) ASSERT(test_eq_th(v2[1], 1.0f, 1e-5f)) ASSERT(test_eq_th(v2[2], 1.0f, 1e-5f)) ASSERT(test_eq_th(v2[3], 1.0f, 1e-5f)) GLM(vec4_smoothstep_uni)(-200.0f, 200.0f, v1, v2); ASSERT(v2[0] > 0.0f && v2[0] < 0.25f) ASSERT(test_eq(v2[1], 0.0f)) ASSERT(v2[2] > 0.0f && v2[2] < 0.5f) ASSERT(v2[3] > 0.0f && v2[3] < 0.5f) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_smoothstep) { vec4 v1 = {-100.0f, -200.0f, -10.0f, -10.0f}; vec4 e1_0 = {-100.0f, 0.0f, -11.0f, -11.0f}; vec4 e1_1 = {50.0f, 10.0f, 20.0f, 20.0f}; vec4 e2_0 = {-180.0f, -300.0f, -93.0f, -93.0f}; vec4 e2_1 = {100.0f, 120.0f, -10.0f, -10.0f}; vec4 e3_0 = {-12.0f, 100.0f, 0.0f, 0.0f}; vec4 e3_1 = {100.0f, 200.0f, 10.0f, 10.0f}; vec4 v2; GLM(vec4_smoothstep)(e1_0, e1_1, v1, v2); ASSERT(test_eq_th(v2[0], 0.0f, 1e-5f)) ASSERT(test_eq_th(v2[1], 0.0f, 1e-5f)) ASSERT(v2[2] > 0.0f && v2[2] < 0.1f) ASSERT(v2[3] > 0.0f && v2[3] < 0.1f) GLM(vec4_smoothstep)(e2_0, e2_1, v1, v2); ASSERT(v2[0] > 0.0f && v2[0] < 0.25f) ASSERT(v2[1] > 0.0f && v2[1] < 0.15f) ASSERT(test_eq_th(v2[2], 1.0f, 1e-5f)) ASSERT(test_eq_th(v2[3], 1.0f, 1e-5f)) GLM(vec4_smoothstep)(e3_0, e3_1, v1, v2); ASSERT(test_eq_th(v2[0], 0.0f, 1e-5f)) ASSERT(test_eq_th(v2[1], 0.0f, 1e-5f)) ASSERT(test_eq_th(v2[2], 0.0f, 1e-5f)) ASSERT(test_eq_th(v2[3], 0.0f, 1e-5f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_smoothinterp) { vec4 e1_0 = {-100.0f, 0.0f, -11.0f, -11.0f}; vec4 e1_1 = {50.0f, 10.0f, 20.0f, 20.0f}; vec4 e2_0 = {80.0f, -220.0f, -19.0f, -19.0f}; vec4 e2_1 = {100.0f, -200.0f, -10.0f, -10.0f}; vec4 e3_0 = {-12.0f, 100.0f, 0.0f, 0.0f}; vec4 e3_1 = {100.0f, 200.0f, 10.0f, 10.0f}; vec4 v2; GLM(vec4_smoothinterp)(e1_0, e1_1, 0.5f, v2); ASSERT(v2[0] >= e1_0[0] && v2[0] <= e1_1[0]) ASSERT(v2[1] >= e1_0[1] && v2[1] <= e1_1[1]) ASSERT(v2[2] >= e1_0[2] && v2[2] <= e1_1[2]) ASSERT(v2[3] >= e1_0[3] && v2[3] <= e1_1[3]) GLM(vec4_smoothinterp)(e2_0, e2_1, 0.5f, v2); ASSERT(v2[0] >= e2_0[0] && v2[0] <= e2_1[0]) ASSERT(v2[1] >= e2_0[1] && v2[1] <= e2_1[1]) ASSERT(v2[2] >= e2_0[2] && v2[2] <= e2_1[2]) ASSERT(v2[3] >= e2_0[3] && v2[3] <= e2_1[3]) GLM(vec4_smoothinterp)(e3_0, e3_1, 1.0f, v2); ASSERT(v2[0] >= e3_0[0] && v2[0] <= e3_1[0]) ASSERT(v2[1] >= e3_0[1] && v2[1] <= e3_1[1]) ASSERT(v2[2] >= e3_0[2] && v2[2] <= e3_1[2]) ASSERT(v2[3] >= e3_0[3] && v2[3] <= e3_1[3]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_smoothinterpc) { vec4 e1_0 = {-100.0f, 0.0f, -11.0f, -11.0f}; vec4 e1_1 = {50.0f, 10.0f, 20.0f, 20.0f}; vec4 e2_0 = {80.0f, -220.0f, -19.0f, -19.0f}; vec4 e2_1 = {100.0f, -200.0f, -10.0f, -10.0f}; vec4 e3_0 = {-12.0f, 100.0f, 0.0f, 0.0f}; vec4 e3_1 = {100.0f, 200.0f, 10.0f, 10.0f}; vec4 v2; GLM(vec4_smoothinterpc)(e1_0, e1_1, -0.5f, v2); ASSERT(v2[0] >= e1_0[0] && v2[0] <= e1_1[0]) ASSERT(v2[1] >= e1_0[1] && v2[1] <= e1_1[1]) ASSERT(v2[2] >= e1_0[2] && v2[2] <= e1_1[2]) ASSERT(v2[3] >= e1_0[3] && v2[3] <= e1_1[3]) GLM(vec4_smoothinterpc)(e2_0, e2_1, 0.5f, v2); ASSERT(v2[0] >= e2_0[0] && v2[0] <= e2_1[0]) ASSERT(v2[1] >= e2_0[1] && v2[1] <= e2_1[1]) ASSERT(v2[2] >= e2_0[2] && v2[2] <= e2_1[2]) ASSERT(v2[3] >= e2_0[3] && v2[3] <= e2_1[3]) GLM(vec4_smoothinterpc)(e3_0, e3_1, 2.0f, v2); ASSERT(v2[0] >= e3_0[0] && v2[0] <= e3_1[0]) ASSERT(v2[1] >= e3_0[1] && v2[1] <= e3_1[1]) ASSERT(v2[2] >= e3_0[2] && v2[2] <= e3_1[2]) ASSERT(v2[3] >= e3_0[3] && v2[3] <= e3_1[3]) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_cubic) { vec4 v1 = {125.0f, 25.0f, 5.0f, 1.0f}; vec4 v2 = {216.0f, 36.0f, 6.0f, 1.0f}; vec4 v3, v4; ASSERT(test_eq(v1[0], v1[2] * v1[2] * v1[2])) ASSERT(test_eq(v1[1], v1[2] * v1[2])) ASSERT(test_eq(v1[3], 1.0f)) ASSERT(test_eq(v2[0], v2[2] * v2[2] * v2[2])) ASSERT(test_eq(v2[1], v2[2] * v2[2])) ASSERT(test_eq(v2[3], 1.0f)) GLM(vec4_cubic)(test_rand(), v3); ASSERT(test_eq(v3[0], v3[2] * v3[2] * v3[2])) ASSERT(test_eq(v3[1], v3[2] * v3[2])) ASSERT(test_eq(v3[3], 1.0f)) GLM(vec4_cubic)(test_rand(), v4); ASSERT(test_eq(v4[0], v4[2] * v4[2] * v4[2])) ASSERT(test_eq(v4[1], v4[2] * v4[2])) ASSERT(test_eq(v4[3], 1.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_swizzle) { vec4 v; /* ZYX */ v[0] = 1; v[1] = 2; v[2] = 3; v[3] = 4; GLM(vec4_swizzle)(v, GLM_WZYX, v); ASSERTIFY(test_assert_vec4_eq(v, (vec4){4, 3, 2, 1})) GLM(vec4_swizzle)(v, GLM_XXXX, v); ASSERTIFY(test_assert_vec4_eq(v, (vec4){4, 4, 4, 4})) v[0] = 1; v[1] = 2; v[2] = 3; v[3] = 4; GLM(vec4_swizzle)(v, GLM_YYYY, v); ASSERTIFY(test_assert_vec4_eq(v, (vec4){2, 2, 2, 2})) v[0] = 1; v[1] = 2; v[2] = 3; v[3] = 4; GLM(vec4_swizzle)(v, GLM_ZZZZ, v); ASSERTIFY(test_assert_vec4_eq(v, (vec4){3, 3, 3, 3})) v[0] = 1; v[1] = 2; v[2] = 3; v[3] = 4; GLM(vec4_swizzle)(v, GLM_WWWW, v); ASSERTIFY(test_assert_vec4_eq(v, (vec4){4, 4, 4, 4})) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_broadcast) { vec4 v1, v2, v3; vec4 v5 = {-1.456f, -1.456f, -1.456f, -1.456f}; vec4 v6 = {11.0f, 11.0f, 11.0f, 11.0f}; vec4 v7 = {78.0f, 78.0f, 78.0f, 78.0f}; GLM(vec4_broadcast)(-1.456f, v1); GLM(vec4_broadcast)(11.0f, v2); GLM(vec4_broadcast)(78.0f, v3); ASSERTIFY(test_assert_vec4_eq(v1, v5)) ASSERTIFY(test_assert_vec4_eq(v2, v6)) ASSERTIFY(test_assert_vec4_eq(v3, v7)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_fill) { vec4 v1, v2, v3; vec4 v5 = {-1.456f, -1.456f, -1.456f, -1.456f}; vec4 v6 = {11.0f, 11.0f, 11.0f, 11.0f}; vec4 v7 = {78.0f, 78.0f, 78.0f, 78.0f}; GLM(vec4_fill)(v1, -1.456f); GLM(vec4_fill)(v2, 11.0f); GLM(vec4_fill)(v3, 78.0f); ASSERTIFY(test_assert_vec4_eq(v1, v5)) ASSERTIFY(test_assert_vec4_eq(v2, v6)) ASSERTIFY(test_assert_vec4_eq(v3, v7)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_eq) { vec4 v1, v2, v3; GLM(vec4_fill)(v1, -1.456f); GLM(vec4_fill)(v2, 11.0f); GLM(vec4_fill)(v3, 78.1f); ASSERT(GLM(vec4_eq)(v1, -1.456f)) ASSERT(GLM(vec4_eq)(v2, 11.0f)) ASSERT(!GLM(vec4_eq)(v3, 78.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_eq_eps) { vec4 v1, v2, v3; GLM(vec4_fill)(v1, -1.456f); GLM(vec4_fill)(v2, 11.0f); GLM(vec4_fill)(v3, 78.1f); ASSERT(GLM(vec4_eq_eps)(v1, -1.456f)) ASSERT(GLM(vec4_eq_eps)(v2, 11.0f)) ASSERT(!GLM(vec4_eq_eps)(v3, 78.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_eq_all) { vec4 v1, v2, v3; vec4 v4 = {2.104f, -3.012f, -4.10f, -4.10f}; vec4 v5 = {-12.35f, -31.140f, -43.502f, -43.502f}; GLM(vec4_fill)(v1, -1.456f); GLM(vec4_fill)(v2, 11.0f); GLM(vec4_fill)(v3, 78.0f); ASSERT(GLM(vec4_eq_all)(v1)) ASSERT(GLM(vec4_eq_all)(v2)) ASSERT(GLM(vec4_eq_all)(v3)) ASSERT(!GLM(vec4_eq_all)(v4)) ASSERT(!GLM(vec4_eq_all)(v5)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_eqv) { vec4 v1, v2, v3, v4, v5; vec4 v6 = {-1.456f, -1.456f, -1.456f, -1.456f}; vec4 v7 = {11.0f, 11.0f, 11.0f, 11.0f}; vec4 v8 = {78.0f, 78.0f, -43.502f, -43.502f}; GLM(vec4_fill)(v1, -1.456f); GLM(vec4_fill)(v2, 11.0f); GLM(vec4_fill)(v3, 78.0f); test_rand_vec4(v4); test_rand_vec4(v5); ASSERT(GLM(vec4_eqv)(v1, v6)) ASSERT(GLM(vec4_eqv)(v2, v7)) ASSERT(!GLM(vec4_eqv)(v3, v8)) ASSERT(!GLM(vec4_eqv)(v4, v5)) ASSERT(GLM(vec4_eqv)(v5, v5)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_eqv_eps) { vec4 v1, v2, v3, v4, v5; vec4 v6 = {-1.456f, -1.456f, -1.456f, -1.456f}; vec4 v7 = {11.0f, 11.0f, 11.0f, 11.0f}; vec4 v8 = {78.0f, 78.0f, -43.502f, -43.502f}; GLM(vec4_fill)(v1, -1.456f); GLM(vec4_fill)(v2, 11.0f); GLM(vec4_fill)(v3, 78.0f); test_rand_vec4(v4); test_rand_vec4(v5); ASSERT(GLM(vec4_eqv_eps)(v1, v6)) ASSERT(GLM(vec4_eqv_eps)(v2, v7)) ASSERT(!GLM(vec4_eqv_eps)(v3, v8)) ASSERT(!GLM(vec4_eqv_eps)(v4, v5)) ASSERT(GLM(vec4_eqv_eps)(v5, v5)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_max) { vec4 v1 = {2.104f, -3.012f, -4.10f, -4.10f}; vec4 v2 = {-12.35f, -31.140f, -43.502f, -43.502f}; #ifndef CGLM_FAST_MATH vec4 v3 = {INFINITY, 0.0f, 0.0f, 0.0f}; #endif // vec4 v4 = {NAN, INFINITY, 2.0f, 2.0f}; // vec4 v5 = {NAN, -1.0f, -1.0f, -1.0f}; vec4 v6 = {-1.0f, -11.0f, 11.0f, 11.0f}; ASSERT(test_eq(GLM(vec4_max)(v1), 2.104f)) ASSERT(test_eq(GLM(vec4_max)(v2), -12.35f)) #ifndef CGLM_FAST_MATH ASSERT(isinf(GLM(vec4_max)(v3))) #endif // ASSERT(isnan(GLM(vec4_max)(v4))) // ASSERT(isnan(GLM(vec4_max)(v5))) ASSERT(test_eq(GLM(vec4_max)(v6), 11.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_min) { vec4 v1 = {2.104f, -3.012f, -4.10f, -4.10f}; vec4 v2 = {-12.35f, -31.140f, -43.502f, -43.502f}; #ifndef CGLM_FAST_MATH vec4 v3 = {INFINITY, 0.0f, 0.0f, 0.0f}; #endif // vec4 v4 = {NAN, INFINITY, 2.0f, 2.0f}; // vec4 v5 = {NAN, -1.0f, -1.0f, -1.0f}; vec4 v6 = {-1.0f, -11.0f, 11.0f, 11.0f}; ASSERT(test_eq(GLM(vec4_min)(v1), -4.10f)) ASSERT(test_eq(GLM(vec4_min)(v2), -43.502f)) #ifndef CGLM_FAST_MATH ASSERT(test_eq(GLM(vec4_min)(v3), 0.0f)) #endif // ASSERT(isnan(GLM(vec4_min)(v4))) // ASSERT(isnan(GLM(vec4_min)(v5))) ASSERT(test_eq(GLM(vec4_min)(v6), -11.0f)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_isnan) { #ifndef CGLM_FAST_MATH vec4 v1 = {2.104f, -3.012f, -4.10f, -4.10f}; vec4 v2 = {-12.35f, -31.140f, -43.502f, -43.502f}; vec4 v3 = {INFINITY, 0.0f, 0.0f, 0.0f}; vec4 v4 = {NAN, INFINITY, 2.0f, 2.0f}; vec4 v5 = {NAN, -1.0f, -1.0f, -1.0f}; vec4 v6 = {-1.0f, -1.0f, 11.0f, 11.0f}; ASSERT(!GLM(vec4_isnan)(v1)) ASSERT(!GLM(vec4_isnan)(v2)) ASSERT(!GLM(vec4_isnan)(v3)) ASSERT(GLM(vec4_isnan)(v4)) ASSERT(GLM(vec4_isnan)(v5)) ASSERT(!GLM(vec4_isnan)(v6)) #endif TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_isinf) { #ifndef CGLM_FAST_MATH vec4 v1 = {2.104f, -3.012f, -4.10f, -4.10f}; vec4 v2 = {-12.35f, -31.140f, -43.502f, -43.502f}; vec4 v3 = {INFINITY, 0.0f, 0.0f, 0.0f}; vec4 v4 = {NAN, INFINITY, 2.0f, 2.0f}; vec4 v5 = {NAN, -1.0f, -1.0f, -1.0f}; vec4 v6 = {-1.0f, -1.0f, 11.0f, 11.0f}; ASSERT(!GLM(vec4_isinf)(v1)) ASSERT(!GLM(vec4_isinf)(v2)) ASSERT(GLM(vec4_isinf)(v3)) ASSERT(GLM(vec4_isinf)(v4)) ASSERT(!GLM(vec4_isinf)(v5)) ASSERT(!GLM(vec4_isinf)(v6)) #endif TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_isvalid) { #ifndef CGLM_FAST_MATH vec4 v1 = {2.104f, -3.012f, -4.10f, -4.10f}; vec4 v2 = {-12.35f, -31.140f, -43.502f, -43.502f}; vec4 v3 = {INFINITY, 0.0f, 0.0f, 0.0f}; vec4 v4 = {NAN, INFINITY, 2.0f, 2.0f}; vec4 v5 = {NAN, -1.0f, -1.0f, -1.0f}; vec4 v6 = {-1.0f, -1.0f, 11.0f, 11.0f}; ASSERT(GLM(vec4_isvalid)(v1)) ASSERT(GLM(vec4_isvalid)(v2)) ASSERT(!GLM(vec4_isvalid)(v3)) ASSERT(!GLM(vec4_isvalid)(v4)) ASSERT(!GLM(vec4_isvalid)(v5)) ASSERT(GLM(vec4_isvalid)(v6)) #endif TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_sign) { vec4 v1 = {2.104f, -3.012f, -4.10f, -4.10f}; vec4 v2 = {-12.35f, -31.140f, -43.502f, -43.502f}; vec4 v3, v4; vec4 v5 = {1.0f, -1.0f, -1.0f, -1.0f}; vec4 v6 = {-1.0f, -1.0f, -1.0f, -1.0f}; GLM(vec4_sign)(v1, v3); GLM(vec4_sign)(v2, v4); ASSERTIFY(test_assert_vec4_eq(v3, v5)) ASSERTIFY(test_assert_vec4_eq(v4, v6)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_abs) { vec4 v1 = {2.104f, -3.012f, -4.10f, -4.10f}; vec4 v2 = {-12.35f, -31.140f, -43.502f, -43.502f}; vec4 v3, v4; vec4 v5 = {2.104f, 3.012f, 4.10f, 4.10f}; vec4 v6 = {12.35f, 31.140f, 43.502f, 43.502f}; GLM(vec4_abs)(v1, v3); GLM(vec4_abs)(v2, v4); ASSERTIFY(test_assert_vec4_eq(v3, v5)) ASSERTIFY(test_assert_vec4_eq(v4, v6)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_fract) { vec4 v1 = {2.104f, 3.012f, 4.10f, 4.10f}; vec4 v2 = {12.35f, 31.140f, 43.502f, 43.502f}; vec4 v3, v4; vec4 v5 = {0.104f, 0.012f, 0.10f, 0.10f}; vec4 v6 = {0.35f, 0.140f, 0.502f, 0.502f}; GLM(vec4_fract)(v1, v3); GLM(vec4_fract)(v2, v4); ASSERTIFY(test_assert_vec4_eq(v3, v5)) ASSERTIFY(test_assert_vec4_eq(v4, v6)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_floor) { vec4 v1 = {2.104f, 3.012f, 4.10f, 4.10f}; vec4 v2 = {12.35f, 31.140f, 43.502f, 43.502f}; vec4 v3, v4; vec4 v5 = {2.0f, 3.0f, 4.0f, 4.0f}; vec4 v6 = {12.0f, 31.0f, 43.0f, 43.0f}; GLM(vec4_floor)(v1, v3); GLM(vec4_floor)(v2, v4); ASSERTIFY(test_assert_vec4_eq(v3, v5)) ASSERTIFY(test_assert_vec4_eq(v4, v6)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_mods) { vec4 v1 = {2.104f, 3.012f, 4.10f, 5.78f}, v2 = {12.35f, 31.140f, 43.502f, 198.999f}; vec4 v3, v4; vec4 v5 = {0.104f, 0.012f, 0.10f, 0.78f}, v6 = {0.35f, 0.140f, 0.502f, 0.999f}; /* Mod 1 - leaves just the fractional part */ GLM(vec4_mods)(v1, 1.0f, v3); GLM(vec4_mods)(v2, 1.0f, v4); ASSERTIFY(test_assert_vec4_eq(v3, v5)) ASSERTIFY(test_assert_vec4_eq(v4, v6)) /* Mod 2 - parity + fractional part */ GLM(vec4_mods)(v1, 2.0f, v3); GLM(vec4_mods)(v2, 2.0f, v4); vec4 v7 = {0.104f, 1.012f, 0.10f, 1.78f}, v8 = {0.35f, 1.140f, 1.502f, 0.999f}; ASSERTIFY(test_assert_vec4_eq(v3, v7)) ASSERTIFY(test_assert_vec4_eq(v4, v8)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_hadd) { vec4 v1 = {2.0f, 3.0f, 4.0f, 4.0f}, v2 = {12.0f, 31.0f, 43.0f, 43.0f}; float r1, r2, r3, r4; r1 = GLM(vec4_hadd)(v1); r2 = GLM(vec4_hadd)(v2); r3 = v1[0] + v1[1] + v1[2] + v1[3]; r4 = v2[0] + v2[1] + v2[2] + v2[3]; ASSERT(test_eq(r1, r3)) ASSERT(test_eq(r2, r4)) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_sqrt) { vec4 v1 = {2.0f, 3.0f, 4.0f, 4.0f}, v2 = {12.0f, 31.0f, 43.0f, 43.0f}; vec4 v3, v4; GLM(vec4_sqrt)(v1, v3); GLM(vec4_sqrt)(v2, v4); ASSERT(test_eq(sqrtf(v1[0]), v3[0])) ASSERT(test_eq(sqrtf(v1[1]), v3[1])) ASSERT(test_eq(sqrtf(v1[2]), v3[2])) ASSERT(test_eq(sqrtf(v1[3]), v3[3])) ASSERT(test_eq(sqrtf(v2[0]), v4[0])) ASSERT(test_eq(sqrtf(v2[1]), v4[1])) ASSERT(test_eq(sqrtf(v2[2]), v4[2])) ASSERT(test_eq(sqrtf(v2[3]), v4[3])) TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_make) { float src[12] = { 7.2f, 1.0f, 5.8f, 0.0f, 2.5f, 6.1f, 9.9f, 1.0f, 17.7f, 4.3f, 3.2f, 1.0f }; vec4 dest[3]; float *srcp = src; unsigned int i, j; for (i = 0, j = 0; i < sizeof(src) / sizeof(float); i+=4,j++) { GLM(vec4_make)(srcp + i, dest[j]); ASSERT(test_eq(src[ i ], dest[j][0])); ASSERT(test_eq(src[i+1], dest[j][1])); ASSERT(test_eq(src[i+2], dest[j][2])); ASSERT(test_eq(src[i+3], dest[j][3])); } TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_reflect) { vec4 dest; /* Original test: Reflecting off a horizontal surface */ vec4 I1 = {1.0f, -1.0f, 0.0f, 0.0f}; /* Incoming vector */ vec4 N1 = {0.0f, 1.0f, 0.0f, 0.0f}; /* Normal vector */ GLM(vec4_reflect)(I1, N1, dest); ASSERT(fabsf(dest[0] - 1.0f) < 0.00001f && fabsf(dest[1] - 1.0f) < 0.00001f && fabsf(dest[2] - 0.0f) < 0.00001f && fabsf(dest[3] - 0.0f) < 0.00001f); /* Expect reflection */ /* Scenario 2: Reflecting off a vertical surface */ vec4 I2 = {1.0f, 0.0f, 0.0f, 0.0f}; /* Incoming vector */ vec4 N2 = {-1.0f, 0.0f, 0.0f, 0.0f}; /* Normal vector */ GLM(vec4_reflect)(I2, N2, dest); ASSERT(fabsf(dest[0] + 1.0f) < 0.00001f && fabsf(dest[1]) < 0.00001f && fabsf(dest[2]) < 0.00001f && fabsf(dest[3] - 0.0f) < 0.00001f); /* Expect reflection to the left */ /* Scenario 3: Reflecting at an angle */ vec4 I3 = {sqrtf(2)/2, -sqrtf(2)/2, 0.0f, 0.0f}; /* Incoming vector at 45 degrees */ vec4 N3 = {0.0f, 1.0f, 0.0f, 0.0f}; /* Upwards normal vector */ GLM(vec4_reflect)(I3, N3, dest); ASSERT(fabsf(dest[0] - sqrtf(2)/2) < 0.00001f && fabsf(dest[1] - sqrtf(2)/2) < 0.00001f && fabsf(dest[2]) < 0.00001f && fabsf(dest[3] - 0.0f) < 0.00001f); /* Expect reflection upwards */ TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, vec4_refract) { vec4 v = {sqrtf(0.5f), -sqrtf(0.5f), 0.0f, 0.0f}; /* Incoming vector */ vec4 N = {0.0f, 1.0f, 0.0f, 0.0f}; /* Surface normal */ vec4 dest; float eta; float r; /* Water to Air (eta = 1.33/1.0) */ eta = 1.33f / 1.0f; r = GLM(vec4_refract)(v, N, eta, dest); if (!(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f && dest[3] == 0.0f)) { ASSERT(dest[1] < -0.3f); ASSERT(r == true); } else { ASSERT(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f && dest[3] == 0.0f); ASSERT(r == false); } /* Air to Glass (eta = 1.0 / 1.5) */ eta = 1.0f / 1.5f; r = GLM(vec4_refract)(v, N, eta, dest); ASSERT(r == true); ASSERT(dest[1] < -sqrtf(0.5f)); // Expect bending towards the normal /* Glass to Water (eta = 1.5 / 1.33) */ eta = 1.5f / 1.33f; r = GLM(vec4_refract)(v, N, eta, dest); ASSERT(r == true); ASSERT(dest[1] < -0.6f); // Expect bending towards the normal, less bending than air to glass /* Diamond to Air (eta = 2.42 / 1.0) */ eta = 2.42f / 1.0f; r = GLM(vec4_refract)(v, N, eta, dest); if (!(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f && dest[3] == 0.0f)) { /* High potential for total internal reflection, but if it occurs, expect significant bending */ ASSERT(dest[1] < -sqrtf(0.5f)); ASSERT(r == true); } else { ASSERT(dest[0] == 0.0f && dest[1] == 0.0f && dest[2] == 0.0f && dest[3] == 0.0f); ASSERT(r == false); } TEST_SUCCESS } cglm-0.9.7/test/src/tests.c000066400000000000000000000042501526744317200155410ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ /* test inline */ /*---------------------------------------------------------------------------*/ #define GLM_PREFIX glm_ #define GLM(X) (glm_ ## X) #include "test_vec2.h" #include "test_vec3.h" #include "test_vec4.h" #include "test_ivec2.h" #include "test_ivec3.h" #include "test_ivec4.h" #include "test_mat2.h" #include "test_mat2x3.h" #include "test_mat2x4.h" #include "test_mat3.h" #include "test_mat3x2.h" #include "test_mat3x4.h" #include "test_mat4.h" #include "test_mat4x2.h" #include "test_mat4x3.h" #include "test_quat.h" #include "test_project.h" #include "test_plane.h" #include "test_noise.h" #include "test_affine.h" #include "test_affine2d.h" #include "test_affine2d_post.h" #include "test_affine_mat.h" #include "test_aabb2d.h" #include "test_ray.h" #include "test_cam.h" #include "test_cam_lh_no.h" #include "test_cam_lh_zo.h" #include "test_cam_rh_no.h" #include "test_cam_rh_zo.h" #include "test_euler_to_quat_rh.h" #include "test_euler_to_quat_lh.h" #undef GLM #undef GLM_PREFIX /* test pre-compiled */ /*---------------------------------------------------------------------------*/ #define GLM_PREFIX glmc_ #define GLM(X) (glmc_ ## X) #include "test_vec2.h" #include "test_vec3.h" #include "test_vec4.h" #include "test_ivec2.h" #include "test_ivec3.h" #include "test_ivec4.h" #include "test_mat2.h" #include "test_mat2x3.h" #include "test_mat2x4.h" #include "test_mat3.h" #include "test_mat3x2.h" #include "test_mat3x4.h" #include "test_mat4.h" #include "test_mat4x2.h" #include "test_mat4x3.h" #include "test_quat.h" #include "test_project.h" #include "test_plane.h" #include "test_noise.h" #include "test_affine.h" #include "test_affine2d.h" #include "test_affine_mat.h" #include "test_aabb2d.h" #include "test_ray.h" #include "test_cam.h" #include "test_cam_lh_no.h" #include "test_cam_lh_zo.h" #include "test_cam_rh_no.h" #include "test_cam_rh_zo.h" #include "test_euler_to_quat_rh.h" #include "test_euler_to_quat_lh.h" #undef GLM #undef GLM_PREFIX /*---------------------------------------------------------------------------*/ cglm-0.9.7/test/tests.h000066400000000000000000002124201526744317200147570ustar00rootroot00000000000000/* * Copyright (c), Recep Aslantas. * * MIT License (MIT), http://opensource.org/licenses/MIT * Full license can be found in the LICENSE file */ #ifndef tests_h #define tests_h #include "include/common.h" /* * To register a test: * 1. use TEST_DECLARE() to forward declare test * 2. use TEST_ENTRY() to add test to list */ /* affine mat */ TEST_DECLARE(glm_mul) TEST_DECLARE(glm_mul) TEST_DECLARE(glm_inv_tr) TEST_DECLARE(glmc_mul) TEST_DECLARE(glmc_mul_rot) TEST_DECLARE(glmc_inv_tr) /* affine */ TEST_DECLARE(glm_translate) TEST_DECLARE(glm_translate_to) TEST_DECLARE(glm_translate_x) TEST_DECLARE(glm_translate_y) TEST_DECLARE(glm_translate_z) TEST_DECLARE(glm_translate_make) TEST_DECLARE(glm_scale_to) TEST_DECLARE(glm_scale_make) TEST_DECLARE(glm_scale) TEST_DECLARE(glm_scale_uni) TEST_DECLARE(glm_rotate_x) TEST_DECLARE(glm_rotate_y) TEST_DECLARE(glm_rotate_z) TEST_DECLARE(glm_rotate_make) TEST_DECLARE(glm_rotate) TEST_DECLARE(glm_rotate_at) TEST_DECLARE(glm_rotate_atm) TEST_DECLARE(glm_spin) TEST_DECLARE(glm_spin_affine) TEST_DECLARE(glm_decompose_scalev) TEST_DECLARE(glm_uniscaled) TEST_DECLARE(glm_decompose_rs) TEST_DECLARE(glm_decompose) TEST_DECLARE(glmc_translate) TEST_DECLARE(glmc_translate_to) TEST_DECLARE(glmc_translate_x) TEST_DECLARE(glmc_translate_y) TEST_DECLARE(glmc_translate_z) TEST_DECLARE(glmc_translate_make) TEST_DECLARE(glmc_scale_to) TEST_DECLARE(glmc_scale_make) TEST_DECLARE(glmc_scale) TEST_DECLARE(glmc_scale_uni) TEST_DECLARE(glmc_rotate_x) TEST_DECLARE(glmc_rotate_y) TEST_DECLARE(glmc_rotate_z) TEST_DECLARE(glmc_rotate_make) TEST_DECLARE(glmc_rotate) TEST_DECLARE(glmc_rotate_at) TEST_DECLARE(glmc_rotate_atm) TEST_DECLARE(glmc_spin) TEST_DECLARE(glmc_spin_affine) TEST_DECLARE(glmc_decompose_scalev) TEST_DECLARE(glmc_uniscaled) TEST_DECLARE(glmc_decompose_rs) TEST_DECLARE(glmc_decompose) /* affine 2d */ TEST_DECLARE(glm_translate2d) TEST_DECLARE(glm_translate2d_to) TEST_DECLARE(glm_translate2d_x) TEST_DECLARE(glm_translate2d_y) TEST_DECLARE(glm_translate2d_make) TEST_DECLARE(glm_scale2d_to) TEST_DECLARE(glm_scale2d_make) TEST_DECLARE(glm_scale2d) TEST_DECLARE(glm_scale2d_uni) TEST_DECLARE(glm_rotate2d_make) TEST_DECLARE(glm_rotate2d) TEST_DECLARE(glm_rotate2d_to) TEST_DECLARE(glmc_translate2d) TEST_DECLARE(glmc_translate2d_to) TEST_DECLARE(glmc_translate2d_x) TEST_DECLARE(glmc_translate2d_y) TEST_DECLARE(glmc_translate2d_make) TEST_DECLARE(glmc_scale2d_to) TEST_DECLARE(glmc_scale2d_make) TEST_DECLARE(glmc_scale2d) TEST_DECLARE(glmc_scale2d_uni) TEST_DECLARE(glmc_rotate2d_make) TEST_DECLARE(glmc_rotate2d) TEST_DECLARE(glmc_rotate2d_to) /* affine 2d post */ TEST_DECLARE(glm_translated2d) TEST_DECLARE(glm_translated2d_x) TEST_DECLARE(glm_translated2d_y) TEST_DECLARE(glm_rotated2d) TEST_DECLARE(glm_scaled2d) TEST_DECLARE(glm_scaled2d_uni) /* aabb2d */ TEST_DECLARE(glm_aabb2d_sizev) /* mat4 */ TEST_DECLARE(glm_mat4_ucopy) TEST_DECLARE(glm_mat4_copy) TEST_DECLARE(glm_mat4_identity) TEST_DECLARE(glm_mat4_identity_array) TEST_DECLARE(glm_mat4_zero) TEST_DECLARE(glm_mat4_pick3) TEST_DECLARE(glm_mat4_pick3t) TEST_DECLARE(glm_mat4_ins3) TEST_DECLARE(glm_mat4_mul) TEST_DECLARE(glm_mat4_mulN) TEST_DECLARE(glm_mat4_mulv) TEST_DECLARE(glm_mat4_mulv3) TEST_DECLARE(glm_mat4_trace) TEST_DECLARE(glm_mat4_trace3) TEST_DECLARE(glm_mat4_quat) TEST_DECLARE(glm_mat4_transpose_to) TEST_DECLARE(glm_mat4_transpose) TEST_DECLARE(glm_mat4_scale_p) TEST_DECLARE(glm_mat4_scale) TEST_DECLARE(glm_mat4_det) TEST_DECLARE(glm_mat4_inv) TEST_DECLARE(glm_mat4_inv_fast) TEST_DECLARE(glm_mat4_inv_precise) TEST_DECLARE(glm_mat4_swap_col) TEST_DECLARE(glm_mat4_swap_row) TEST_DECLARE(glm_mat4_rmc) TEST_DECLARE(glm_mat4_make) TEST_DECLARE(glm_mat4_textrans) TEST_DECLARE(glmc_mat4_ucopy) TEST_DECLARE(glmc_mat4_copy) TEST_DECLARE(glmc_mat4_identity) TEST_DECLARE(glmc_mat4_identity_array) TEST_DECLARE(glmc_mat4_zero) TEST_DECLARE(glmc_mat4_pick3) TEST_DECLARE(glmc_mat4_pick3t) TEST_DECLARE(glmc_mat4_ins3) TEST_DECLARE(glmc_mat4_mul) TEST_DECLARE(glmc_mat4_mulN) TEST_DECLARE(glmc_mat4_mulv) TEST_DECLARE(glmc_mat4_mulv3) TEST_DECLARE(glmc_mat4_trace) TEST_DECLARE(glmc_mat4_trace3) TEST_DECLARE(glmc_mat4_quat) TEST_DECLARE(glmc_mat4_transpose_to) TEST_DECLARE(glmc_mat4_transpose) TEST_DECLARE(glmc_mat4_scale_p) TEST_DECLARE(glmc_mat4_scale) TEST_DECLARE(glmc_mat4_det) TEST_DECLARE(glmc_mat4_inv) TEST_DECLARE(glmc_mat4_inv_fast) TEST_DECLARE(glmc_mat4_swap_col) TEST_DECLARE(glmc_mat4_swap_row) TEST_DECLARE(glmc_mat4_rmc) TEST_DECLARE(glmc_mat4_make) TEST_DECLARE(MACRO_GLM_MAT4X2_ZERO_INIT) TEST_DECLARE(MACRO_GLM_MAT4X2_ZERO) TEST_DECLARE(glm_mat4x2_copy) TEST_DECLARE(glm_mat4x2_zero) TEST_DECLARE(glm_mat4x2_make) TEST_DECLARE(glm_mat4x2_mul) TEST_DECLARE(glm_mat4x2_mulv) TEST_DECLARE(glm_mat4x2_transpose) TEST_DECLARE(glm_mat4x2_scale) TEST_DECLARE(glmc_mat4x2_copy) TEST_DECLARE(glmc_mat4x2_zero) TEST_DECLARE(glmc_mat4x2_make) TEST_DECLARE(glmc_mat4x2_mul) TEST_DECLARE(glmc_mat4x2_mulv) TEST_DECLARE(glmc_mat4x2_transpose) TEST_DECLARE(glmc_mat4x2_scale) TEST_DECLARE(MACRO_GLM_MAT4X3_ZERO_INIT) TEST_DECLARE(MACRO_GLM_MAT4X3_ZERO) TEST_DECLARE(glm_mat4x3_copy) TEST_DECLARE(glm_mat4x3_zero) TEST_DECLARE(glm_mat4x3_make) TEST_DECLARE(glm_mat4x3_mul) TEST_DECLARE(glm_mat4x3_mulv) TEST_DECLARE(glm_mat4x3_transpose) TEST_DECLARE(glm_mat4x3_scale) TEST_DECLARE(glmc_mat4x3_copy) TEST_DECLARE(glmc_mat4x3_zero) TEST_DECLARE(glmc_mat4x3_make) TEST_DECLARE(glmc_mat4x3_mul) TEST_DECLARE(glmc_mat4x3_mulv) TEST_DECLARE(glmc_mat4x3_transpose) TEST_DECLARE(glmc_mat4x3_scale) /* mat3 */ TEST_DECLARE(glm_mat3_copy) TEST_DECLARE(glm_mat3_identity) TEST_DECLARE(glm_mat3_identity_array) TEST_DECLARE(glm_mat3_zero) TEST_DECLARE(glm_mat3_mul) TEST_DECLARE(glm_mat3_mulv) TEST_DECLARE(glm_mat3_trace) TEST_DECLARE(glm_mat3_quat) TEST_DECLARE(glm_mat3_transpose_to) TEST_DECLARE(glm_mat3_transpose) TEST_DECLARE(glm_mat3_scale) TEST_DECLARE(glm_mat3_det) TEST_DECLARE(glm_mat3_inv) TEST_DECLARE(glm_mat3_swap_col) TEST_DECLARE(glm_mat3_swap_row) TEST_DECLARE(glm_mat3_rmc) TEST_DECLARE(glm_mat3_make) TEST_DECLARE(glm_mat3_textrans) TEST_DECLARE(glmc_mat3_copy) TEST_DECLARE(glmc_mat3_identity) TEST_DECLARE(glmc_mat3_identity_array) TEST_DECLARE(glmc_mat3_zero) TEST_DECLARE(glmc_mat3_mul) TEST_DECLARE(glmc_mat3_mulv) TEST_DECLARE(glmc_mat3_trace) TEST_DECLARE(glmc_mat3_quat) TEST_DECLARE(glmc_mat3_transpose_to) TEST_DECLARE(glmc_mat3_transpose) TEST_DECLARE(glmc_mat3_scale) TEST_DECLARE(glmc_mat3_det) TEST_DECLARE(glmc_mat3_inv) TEST_DECLARE(glmc_mat3_swap_col) TEST_DECLARE(glmc_mat3_swap_row) TEST_DECLARE(glmc_mat3_rmc) TEST_DECLARE(glmc_mat3_make) TEST_DECLARE(MACRO_GLM_MAT3X2_ZERO_INIT) TEST_DECLARE(MACRO_GLM_MAT3X2_ZERO) TEST_DECLARE(glm_mat3x2_copy) TEST_DECLARE(glm_mat3x2_zero) TEST_DECLARE(glm_mat3x2_make) TEST_DECLARE(glm_mat3x2_mul) TEST_DECLARE(glm_mat3x2_mulv) TEST_DECLARE(glm_mat3x2_transpose) TEST_DECLARE(glm_mat3x2_scale) TEST_DECLARE(glmc_mat3x2_copy) TEST_DECLARE(glmc_mat3x2_zero) TEST_DECLARE(glmc_mat3x2_make) TEST_DECLARE(glmc_mat3x2_mul) TEST_DECLARE(glmc_mat3x2_mulv) TEST_DECLARE(glmc_mat3x2_transpose) TEST_DECLARE(glmc_mat3x2_scale) TEST_DECLARE(MACRO_GLM_MAT3X4_ZERO_INIT) TEST_DECLARE(MACRO_GLM_MAT3X4_ZERO) TEST_DECLARE(glm_mat3x4_make) TEST_DECLARE(glmc_mat3x4_make) TEST_DECLARE(MACRO_GLM_MAT2_IDENTITY_INIT) TEST_DECLARE(MACRO_GLM_MAT2_ZERO_INIT) TEST_DECLARE(MACRO_GLM_MAT2_IDENTITY) TEST_DECLARE(MACRO_GLM_MAT2_ZERO) TEST_DECLARE(glm_mat2_copy) TEST_DECLARE(glm_mat2_identity) TEST_DECLARE(glm_mat2_identity_array) TEST_DECLARE(glm_mat2_zero) TEST_DECLARE(glm_mat2_mul) TEST_DECLARE(glm_mat2_transpose_to) TEST_DECLARE(glm_mat2_transpose) TEST_DECLARE(glm_mat2_mulv) TEST_DECLARE(glm_mat2_trace) TEST_DECLARE(glm_mat2_scale) TEST_DECLARE(glm_mat2_det) TEST_DECLARE(glm_mat2_inv) TEST_DECLARE(glm_mat2_swap_col) TEST_DECLARE(glm_mat2_swap_row) TEST_DECLARE(glm_mat2_rmc) TEST_DECLARE(glm_mat2_make) TEST_DECLARE(glmc_mat2_copy) TEST_DECLARE(glmc_mat2_identity) TEST_DECLARE(glmc_mat2_identity_array) TEST_DECLARE(glmc_mat2_zero) TEST_DECLARE(glmc_mat2_mul) TEST_DECLARE(glmc_mat2_transpose_to) TEST_DECLARE(glmc_mat2_transpose) TEST_DECLARE(glmc_mat2_mulv) TEST_DECLARE(glmc_mat2_trace) TEST_DECLARE(glmc_mat2_scale) TEST_DECLARE(glmc_mat2_det) TEST_DECLARE(glmc_mat2_inv) TEST_DECLARE(glmc_mat2_swap_col) TEST_DECLARE(glmc_mat2_swap_row) TEST_DECLARE(glmc_mat2_rmc) TEST_DECLARE(glmc_mat2_make) TEST_DECLARE(MACRO_GLM_MAT2X3_ZERO_INIT) TEST_DECLARE(MACRO_GLM_MAT2X3_ZERO) TEST_DECLARE(glm_mat2x3_copy) TEST_DECLARE(glm_mat2x3_zero) TEST_DECLARE(glm_mat2x3_make) TEST_DECLARE(glm_mat2x3_mul) TEST_DECLARE(glm_mat2x3_mulv) TEST_DECLARE(glm_mat2x3_transpose) TEST_DECLARE(glm_mat2x3_scale) TEST_DECLARE(glmc_mat2x3_copy) TEST_DECLARE(glmc_mat2x3_zero) TEST_DECLARE(glmc_mat2x3_make) TEST_DECLARE(glmc_mat2x3_mul) TEST_DECLARE(glmc_mat2x3_mulv) TEST_DECLARE(glmc_mat2x3_transpose) TEST_DECLARE(glmc_mat2x3_scale) TEST_DECLARE(MACRO_GLM_MAT2X4_ZERO_INIT) TEST_DECLARE(MACRO_GLM_MAT2X4_ZERO) TEST_DECLARE(glm_mat2x4_copy) TEST_DECLARE(glm_mat2x4_zero) TEST_DECLARE(glm_mat2x4_make) TEST_DECLARE(glm_mat2x4_mul) TEST_DECLARE(glm_mat2x4_mulv) TEST_DECLARE(glm_mat2x4_transpose) TEST_DECLARE(glm_mat2x4_scale) TEST_DECLARE(glmc_mat2x4_copy) TEST_DECLARE(glmc_mat2x4_zero) TEST_DECLARE(glmc_mat2x4_make) TEST_DECLARE(glmc_mat2x4_mul) TEST_DECLARE(glmc_mat2x4_mulv) TEST_DECLARE(glmc_mat2x4_transpose) TEST_DECLARE(glmc_mat2x4_scale) /* camera (incl [LR]H cross [NZ]O) */ TEST_DECLARE(glm_perspective_lh_zo) TEST_DECLARE(glm_perspective_rh_zo) TEST_DECLARE(glm_perspective_lh_no) TEST_DECLARE(glm_perspective_rh_no) TEST_DECLARE(glm_camera_lookat) TEST_DECLARE(glm_camera_decomp) TEST_DECLARE(glmc_perspective_lh_zo) TEST_DECLARE(glmc_perspective_rh_zo) TEST_DECLARE(glmc_perspective_lh_no) TEST_DECLARE(glmc_perspective_rh_no) TEST_DECLARE(glmc_camera_lookat) TEST_DECLARE(glmc_camera_decomp) TEST_DECLARE(glm_frustum) TEST_DECLARE(glmc_frustum) /* project */ TEST_DECLARE(glm_unprojecti) TEST_DECLARE(glm_unproject) TEST_DECLARE(glm_project) TEST_DECLARE(glmc_unprojecti) TEST_DECLARE(glmc_unproject) TEST_DECLARE(glmc_project) /* plane */ TEST_DECLARE(glm_plane_normalize) TEST_DECLARE(glmc_plane_normalize) /* noise */ TEST_DECLARE(glm_perlin_vec4) TEST_DECLARE(glmc_perlin_vec4) TEST_DECLARE(glm_perlin_vec3) TEST_DECLARE(glmc_perlin_vec3) TEST_DECLARE(glm_perlin_vec2) TEST_DECLARE(glmc_perlin_vec2) /* utils */ TEST_DECLARE(clamp) /* euler */ TEST_DECLARE(glm_euler_xyz_quat_rh) TEST_DECLARE(glm_euler_xzy_quat_rh) TEST_DECLARE(glm_euler_yxz_quat_rh) TEST_DECLARE(glm_euler_yzx_quat_rh) TEST_DECLARE(glm_euler_zxy_quat_rh) TEST_DECLARE(glm_euler_zyx_quat_rh) TEST_DECLARE(glm_euler_xyz_quat_lh) TEST_DECLARE(glm_euler_xzy_quat_lh) TEST_DECLARE(glm_euler_yxz_quat_lh) TEST_DECLARE(glm_euler_yzx_quat_lh) TEST_DECLARE(glm_euler_zxy_quat_lh) TEST_DECLARE(glm_euler_zyx_quat_lh) TEST_DECLARE(glmc_euler_xyz_quat_rh) TEST_DECLARE(glmc_euler_xzy_quat_rh) TEST_DECLARE(glmc_euler_yxz_quat_rh) TEST_DECLARE(glmc_euler_yzx_quat_rh) TEST_DECLARE(glmc_euler_zxy_quat_rh) TEST_DECLARE(glmc_euler_zyx_quat_rh) TEST_DECLARE(glmc_euler_xyz_quat_lh) TEST_DECLARE(glmc_euler_xzy_quat_lh) TEST_DECLARE(glmc_euler_yxz_quat_lh) TEST_DECLARE(glmc_euler_yzx_quat_lh) TEST_DECLARE(glmc_euler_zxy_quat_lh) TEST_DECLARE(glmc_euler_zyx_quat_lh) TEST_DECLARE(euler) /* ray */ TEST_DECLARE(glm_ray_triangle) TEST_DECLARE(glm_ray_sphere) TEST_DECLARE(glm_ray_at) TEST_DECLARE(glmc_ray_triangle) TEST_DECLARE(glmc_ray_sphere) TEST_DECLARE(glmc_ray_at) /* quat */ TEST_DECLARE(MACRO_GLM_QUAT_IDENTITY_INIT) TEST_DECLARE(MACRO_GLM_QUAT_IDENTITY) TEST_DECLARE(glm_quat_identity) TEST_DECLARE(glm_quat_identity_array) TEST_DECLARE(glm_quat_init) TEST_DECLARE(glm_quatv) TEST_DECLARE(glm_quat) TEST_DECLARE(glm_quat_copy) TEST_DECLARE(glm_quat_norm) TEST_DECLARE(glm_quat_normalize_to) TEST_DECLARE(glm_quat_normalize) TEST_DECLARE(glm_quat_dot) TEST_DECLARE(glm_quat_conjugate) TEST_DECLARE(glm_quat_inv) TEST_DECLARE(glm_quat_add) TEST_DECLARE(glm_quat_sub) TEST_DECLARE(glm_quat_real) TEST_DECLARE(glm_quat_imag) TEST_DECLARE(glm_quat_imagn) TEST_DECLARE(glm_quat_imaglen) TEST_DECLARE(glm_quat_angle) TEST_DECLARE(glm_quat_axis) TEST_DECLARE(glm_quat_mul) TEST_DECLARE(glm_quat_mat4) TEST_DECLARE(glm_quat_mat4t) TEST_DECLARE(glm_quat_mat3) TEST_DECLARE(glm_quat_mat3t) TEST_DECLARE(glm_quat_lerp) TEST_DECLARE(glm_quat_lerpc) TEST_DECLARE(glm_quat_nlerp) TEST_DECLARE(glm_quat_slerp) TEST_DECLARE(glm_quat_look) TEST_DECLARE(glm_quat_for) TEST_DECLARE(glm_quat_forp) TEST_DECLARE(glm_quat_rotatev) TEST_DECLARE(glm_quat_rotate) TEST_DECLARE(glm_quat_rotate_at) TEST_DECLARE(glm_quat_rotate_atm) TEST_DECLARE(glm_quat_from_vecs) TEST_DECLARE(glm_quat_make) TEST_DECLARE(glmc_quat_identity) TEST_DECLARE(glmc_quat_identity_array) TEST_DECLARE(glmc_quat_init) TEST_DECLARE(glmc_quatv) TEST_DECLARE(glmc_quat) TEST_DECLARE(glmc_quat_copy) TEST_DECLARE(glmc_quat_norm) TEST_DECLARE(glmc_quat_normalize_to) TEST_DECLARE(glmc_quat_normalize) TEST_DECLARE(glmc_quat_dot) TEST_DECLARE(glmc_quat_conjugate) TEST_DECLARE(glmc_quat_inv) TEST_DECLARE(glmc_quat_add) TEST_DECLARE(glmc_quat_sub) TEST_DECLARE(glmc_quat_real) TEST_DECLARE(glmc_quat_imag) TEST_DECLARE(glmc_quat_imagn) TEST_DECLARE(glmc_quat_imaglen) TEST_DECLARE(glmc_quat_angle) TEST_DECLARE(glmc_quat_axis) TEST_DECLARE(glmc_quat_mul) TEST_DECLARE(glmc_quat_mat4) TEST_DECLARE(glmc_quat_mat4t) TEST_DECLARE(glmc_quat_mat3) TEST_DECLARE(glmc_quat_mat3t) TEST_DECLARE(glmc_quat_lerp) TEST_DECLARE(glmc_quat_lerpc) TEST_DECLARE(glmc_quat_nlerp) TEST_DECLARE(glmc_quat_slerp) TEST_DECLARE(glmc_quat_look) TEST_DECLARE(glmc_quat_for) TEST_DECLARE(glmc_quat_forp) TEST_DECLARE(glmc_quat_rotatev) TEST_DECLARE(glmc_quat_rotate) TEST_DECLARE(glmc_quat_rotate_at) TEST_DECLARE(glmc_quat_rotate_atm) TEST_DECLARE(glmc_quat_from_vecs) TEST_DECLARE(glmc_quat_make) /* bezier */ TEST_DECLARE(bezier) /* vec2 */ TEST_DECLARE(MACRO_GLM_VEC2_ONE_INIT) TEST_DECLARE(MACRO_GLM_VEC2_ZERO_INIT) TEST_DECLARE(MACRO_GLM_VEC2_ONE) TEST_DECLARE(MACRO_GLM_VEC2_ZERO) TEST_DECLARE(glm_vec2) TEST_DECLARE(glm_vec2_copy) TEST_DECLARE(glm_vec2_zero) TEST_DECLARE(glm_vec2_one) TEST_DECLARE(glm_vec2_dot) TEST_DECLARE(glm_vec2_cross) TEST_DECLARE(glm_vec2_norm2) TEST_DECLARE(glm_vec2_norm) TEST_DECLARE(glm_vec2_add) TEST_DECLARE(glm_vec2_adds) TEST_DECLARE(glm_vec2_sub) TEST_DECLARE(glm_vec2_subs) TEST_DECLARE(glm_vec2_mul) TEST_DECLARE(glm_vec2_scale) TEST_DECLARE(glm_vec2_scale_as) TEST_DECLARE(glm_vec2_div) TEST_DECLARE(glm_vec2_divs) TEST_DECLARE(glm_vec2_addadd) TEST_DECLARE(glm_vec2_subadd) TEST_DECLARE(glm_vec2_muladd) TEST_DECLARE(glm_vec2_muladds) TEST_DECLARE(glm_vec2_maxadd) TEST_DECLARE(glm_vec2_minadd) TEST_DECLARE(glm_vec2_subsub) TEST_DECLARE(glm_vec2_addsub) TEST_DECLARE(glm_vec2_mulsub) TEST_DECLARE(glm_vec2_mulsubs) TEST_DECLARE(glm_vec2_maxsub) TEST_DECLARE(glm_vec2_minsub) TEST_DECLARE(glm_vec2_negate_to) TEST_DECLARE(glm_vec2_negate) TEST_DECLARE(glm_vec2_normalize) TEST_DECLARE(glm_vec2_normalize_to) TEST_DECLARE(glm_vec2_rotate) TEST_DECLARE(glm_vec2_center) TEST_DECLARE(glm_vec2_distance2) TEST_DECLARE(glm_vec2_distance) TEST_DECLARE(glm_vec2_maxv) TEST_DECLARE(glm_vec2_minv) TEST_DECLARE(glm_vec2_clamp) TEST_DECLARE(glm_vec2_abs) TEST_DECLARE(glm_vec2_fract) TEST_DECLARE(glm_vec2_floor) TEST_DECLARE(glm_vec2_mods) TEST_DECLARE(glm_vec2_steps) TEST_DECLARE(glm_vec2_stepr) TEST_DECLARE(glm_vec2_lerp) TEST_DECLARE(glm_vec2_complex_mul) TEST_DECLARE(glm_vec2_complex_div) TEST_DECLARE(glm_vec2_make) TEST_DECLARE(glm_vec2_reflect) TEST_DECLARE(glm_vec2_refract) TEST_DECLARE(glmc_vec2) TEST_DECLARE(glmc_vec2_copy) TEST_DECLARE(glmc_vec2_zero) TEST_DECLARE(glmc_vec2_one) TEST_DECLARE(glmc_vec2_dot) TEST_DECLARE(glmc_vec2_cross) TEST_DECLARE(glmc_vec2_norm2) TEST_DECLARE(glmc_vec2_norm) TEST_DECLARE(glmc_vec2_add) TEST_DECLARE(glmc_vec2_adds) TEST_DECLARE(glmc_vec2_sub) TEST_DECLARE(glmc_vec2_subs) TEST_DECLARE(glmc_vec2_mul) TEST_DECLARE(glmc_vec2_scale) TEST_DECLARE(glmc_vec2_scale_as) TEST_DECLARE(glmc_vec2_div) TEST_DECLARE(glmc_vec2_divs) TEST_DECLARE(glmc_vec2_addadd) TEST_DECLARE(glmc_vec2_subadd) TEST_DECLARE(glmc_vec2_muladd) TEST_DECLARE(glmc_vec2_muladds) TEST_DECLARE(glmc_vec2_maxadd) TEST_DECLARE(glmc_vec2_minadd) TEST_DECLARE(glmc_vec2_subsub) TEST_DECLARE(glmc_vec2_addsub) TEST_DECLARE(glmc_vec2_mulsub) TEST_DECLARE(glmc_vec2_mulsubs) TEST_DECLARE(glmc_vec2_maxsub) TEST_DECLARE(glmc_vec2_minsub) TEST_DECLARE(glmc_vec2_negate_to) TEST_DECLARE(glmc_vec2_negate) TEST_DECLARE(glmc_vec2_normalize) TEST_DECLARE(glmc_vec2_normalize_to) TEST_DECLARE(glmc_vec2_rotate) TEST_DECLARE(glmc_vec2_center) TEST_DECLARE(glmc_vec2_distance2) TEST_DECLARE(glmc_vec2_distance) TEST_DECLARE(glmc_vec2_maxv) TEST_DECLARE(glmc_vec2_minv) TEST_DECLARE(glmc_vec2_clamp) TEST_DECLARE(glmc_vec2_abs) TEST_DECLARE(glmc_vec2_fract) TEST_DECLARE(glmc_vec2_floor) TEST_DECLARE(glmc_vec2_mods) TEST_DECLARE(glmc_vec2_steps) TEST_DECLARE(glmc_vec2_stepr) TEST_DECLARE(glmc_vec2_lerp) TEST_DECLARE(glmc_vec2_complex_mul) TEST_DECLARE(glmc_vec2_complex_div) TEST_DECLARE(glmc_vec2_make) TEST_DECLARE(glmc_vec2_reflect) TEST_DECLARE(glmc_vec2_refract) /* vec3 */ TEST_DECLARE(MACRO_GLM_VEC3_ONE_INIT) TEST_DECLARE(MACRO_GLM_VEC3_ZERO_INIT) TEST_DECLARE(MACRO_GLM_VEC3_ONE) TEST_DECLARE(MACRO_GLM_VEC3_ZERO) TEST_DECLARE(MACRO_GLM_YUP) TEST_DECLARE(MACRO_GLM_ZUP) TEST_DECLARE(MACRO_GLM_XUP) TEST_DECLARE(MACRO_GLM_FORWARD_RH) TEST_DECLARE(MACRO_GLM_SHUFFLE3) TEST_DECLARE(MACRO_GLM_XXX) TEST_DECLARE(MACRO_GLM_YYY) TEST_DECLARE(MACRO_GLM_ZZZ) TEST_DECLARE(MACRO_GLM_ZYX) TEST_DECLARE(MACRO_glm_vec3_dup) TEST_DECLARE(MACRO_glm_vec3_flipsign) TEST_DECLARE(MACRO_glm_vec3_flipsign_to) TEST_DECLARE(MACRO_glm_vec3_inv) TEST_DECLARE(MACRO_glm_vec3_inv_to) TEST_DECLARE(MACRO_glm_vec3_mulv) TEST_DECLARE(glm_vec3) TEST_DECLARE(glm_vec3_copy) TEST_DECLARE(glm_vec3_zero) TEST_DECLARE(glm_vec3_one) TEST_DECLARE(glm_vec3_dot) TEST_DECLARE(glm_dot) TEST_DECLARE(glm_vec3_norm2) TEST_DECLARE(glm_vec3_norm) TEST_DECLARE(glm_vec3_norm_one) TEST_DECLARE(glm_vec3_norm_inf) TEST_DECLARE(glm_vec3_add) TEST_DECLARE(glm_vec3_adds) TEST_DECLARE(glm_vec3_sub) TEST_DECLARE(glm_vec3_subs) TEST_DECLARE(glm_vec3_mul) TEST_DECLARE(glm_vec3_scale) TEST_DECLARE(glm_vec3_scale_as) TEST_DECLARE(glm_vec3_div) TEST_DECLARE(glm_vec3_divs) TEST_DECLARE(glm_vec3_addadd) TEST_DECLARE(glm_vec3_subadd) TEST_DECLARE(glm_vec3_muladd) TEST_DECLARE(glm_vec3_muladds) TEST_DECLARE(glm_vec3_maxadd) TEST_DECLARE(glm_vec3_minadd) TEST_DECLARE(glm_vec3_subsub) TEST_DECLARE(glm_vec3_addsub) TEST_DECLARE(glm_vec3_mulsub) TEST_DECLARE(glm_vec3_mulsubs) TEST_DECLARE(glm_vec3_maxsub) TEST_DECLARE(glm_vec3_minsub) TEST_DECLARE(glm_vec3_negate_to) TEST_DECLARE(glm_vec3_negate) TEST_DECLARE(glm_vec3_normalize) TEST_DECLARE(glm_vec3_normalize_to) TEST_DECLARE(glm_normalize) TEST_DECLARE(glm_normalize_to) TEST_DECLARE(glm_vec3_cross) TEST_DECLARE(glm_vec3_crossn) TEST_DECLARE(glm_cross) TEST_DECLARE(glm_vec3_angle) TEST_DECLARE(glm_vec3_rotate) TEST_DECLARE(glm_vec3_rotate_m4) TEST_DECLARE(glm_vec3_rotate_m3) TEST_DECLARE(glm_vec3_proj) TEST_DECLARE(glm_vec3_center) TEST_DECLARE(glm_vec3_distance2) TEST_DECLARE(glm_vec3_distance) TEST_DECLARE(glm_vec3_maxv) TEST_DECLARE(glm_vec3_minv) TEST_DECLARE(glm_vec3_ortho) TEST_DECLARE(glm_vec3_clamp) TEST_DECLARE(glm_vec3_mix) TEST_DECLARE(glm_vec3_mixc) TEST_DECLARE(glm_vec3_step) TEST_DECLARE(glm_vec3_smoothstep_uni) TEST_DECLARE(glm_vec3_smoothstep) TEST_DECLARE(glm_vec3_smoothinterp) TEST_DECLARE(glm_vec3_smoothinterpc) TEST_DECLARE(glm_vec3_swizzle) TEST_DECLARE(glm_vec3_broadcast) TEST_DECLARE(glm_vec3_fill) TEST_DECLARE(glm_vec3_eq) TEST_DECLARE(glm_vec3_eq_eps) TEST_DECLARE(glm_vec3_eq_all) TEST_DECLARE(glm_vec3_eqv) TEST_DECLARE(glm_vec3_eqv_eps) TEST_DECLARE(glm_vec3_max) TEST_DECLARE(glm_vec3_min) TEST_DECLARE(glm_vec3_isnan) TEST_DECLARE(glm_vec3_isinf) TEST_DECLARE(glm_vec3_isvalid) TEST_DECLARE(glm_vec3_sign) TEST_DECLARE(glm_vec3_abs) TEST_DECLARE(glm_vec3_fract) TEST_DECLARE(glm_vec3_floor) TEST_DECLARE(glm_vec3_mods) TEST_DECLARE(glm_vec3_steps) TEST_DECLARE(glm_vec3_stepr) TEST_DECLARE(glm_vec3_hadd) TEST_DECLARE(glm_vec3_sqrt) TEST_DECLARE(glm_vec3_make) TEST_DECLARE(glm_vec3_faceforward) TEST_DECLARE(glm_vec3_reflect) TEST_DECLARE(glm_vec3_refract) TEST_DECLARE(glmc_vec3) TEST_DECLARE(glmc_vec3_copy) TEST_DECLARE(glmc_vec3_zero) TEST_DECLARE(glmc_vec3_one) TEST_DECLARE(glmc_vec3_dot) TEST_DECLARE(glmc_vec3_norm2) TEST_DECLARE(glmc_vec3_norm) TEST_DECLARE(glmc_vec3_norm_one) TEST_DECLARE(glmc_vec3_norm_inf) TEST_DECLARE(glmc_vec3_add) TEST_DECLARE(glmc_vec3_adds) TEST_DECLARE(glmc_vec3_sub) TEST_DECLARE(glmc_vec3_subs) TEST_DECLARE(glmc_vec3_mul) TEST_DECLARE(glmc_vec3_scale) TEST_DECLARE(glmc_vec3_scale_as) TEST_DECLARE(glmc_vec3_div) TEST_DECLARE(glmc_vec3_divs) TEST_DECLARE(glmc_vec3_addadd) TEST_DECLARE(glmc_vec3_subadd) TEST_DECLARE(glmc_vec3_muladd) TEST_DECLARE(glmc_vec3_muladds) TEST_DECLARE(glmc_vec3_maxadd) TEST_DECLARE(glmc_vec3_minadd) TEST_DECLARE(glmc_vec3_subsub) TEST_DECLARE(glmc_vec3_addsub) TEST_DECLARE(glmc_vec3_mulsub) TEST_DECLARE(glmc_vec3_mulsubs) TEST_DECLARE(glmc_vec3_maxsub) TEST_DECLARE(glmc_vec3_minsub) TEST_DECLARE(glmc_vec3_negate_to) TEST_DECLARE(glmc_vec3_negate) TEST_DECLARE(glmc_vec3_normalize) TEST_DECLARE(glmc_vec3_normalize_to) TEST_DECLARE(glmc_vec3_cross) TEST_DECLARE(glmc_vec3_crossn) TEST_DECLARE(glmc_vec3_angle) TEST_DECLARE(glmc_vec3_rotate) TEST_DECLARE(glmc_vec3_rotate_m4) TEST_DECLARE(glmc_vec3_rotate_m3) TEST_DECLARE(glmc_vec3_proj) TEST_DECLARE(glmc_vec3_center) TEST_DECLARE(glmc_vec3_distance2) TEST_DECLARE(glmc_vec3_distance) TEST_DECLARE(glmc_vec3_maxv) TEST_DECLARE(glmc_vec3_minv) TEST_DECLARE(glmc_vec3_ortho) TEST_DECLARE(glmc_vec3_clamp) TEST_DECLARE(glmc_vec3_mix) TEST_DECLARE(glmc_vec3_mixc) TEST_DECLARE(glmc_vec3_step) TEST_DECLARE(glmc_vec3_smoothstep_uni) TEST_DECLARE(glmc_vec3_smoothstep) TEST_DECLARE(glmc_vec3_smoothinterp) TEST_DECLARE(glmc_vec3_smoothinterpc) TEST_DECLARE(glmc_vec3_swizzle) TEST_DECLARE(glmc_vec3_broadcast) TEST_DECLARE(glmc_vec3_fill) TEST_DECLARE(glmc_vec3_eq) TEST_DECLARE(glmc_vec3_eq_eps) TEST_DECLARE(glmc_vec3_eq_all) TEST_DECLARE(glmc_vec3_eqv) TEST_DECLARE(glmc_vec3_eqv_eps) TEST_DECLARE(glmc_vec3_max) TEST_DECLARE(glmc_vec3_min) TEST_DECLARE(glmc_vec3_isnan) TEST_DECLARE(glmc_vec3_isinf) TEST_DECLARE(glmc_vec3_isvalid) TEST_DECLARE(glmc_vec3_sign) TEST_DECLARE(glmc_vec3_abs) TEST_DECLARE(glmc_vec3_fract) TEST_DECLARE(glmc_vec3_floor) TEST_DECLARE(glmc_vec3_mods) TEST_DECLARE(glmc_vec3_steps) TEST_DECLARE(glmc_vec3_stepr) TEST_DECLARE(glmc_vec3_hadd) TEST_DECLARE(glmc_vec3_sqrt) TEST_DECLARE(glmc_vec3_make) TEST_DECLARE(glmc_vec3_faceforward) TEST_DECLARE(glmc_vec3_reflect) TEST_DECLARE(glmc_vec3_refract) /* vec4 */ TEST_DECLARE(MACRO_GLM_VEC4_ONE_INIT) TEST_DECLARE(MACRO_GLM_VEC4_ZERO_INIT) TEST_DECLARE(MACRO_GLM_VEC4_ONE) TEST_DECLARE(MACRO_GLM_VEC4_ZERO) TEST_DECLARE(MACRO_GLM_XXXX) TEST_DECLARE(MACRO_GLM_YYYY) TEST_DECLARE(MACRO_GLM_ZZZZ) TEST_DECLARE(MACRO_GLM_WZYX) TEST_DECLARE(MACRO_glm_vec4_dup) TEST_DECLARE(MACRO_glm_vec4_flipsign) TEST_DECLARE(MACRO_glm_vec4_flipsign_to) TEST_DECLARE(MACRO_glm_vec4_inv) TEST_DECLARE(MACRO_glm_vec4_inv_to) TEST_DECLARE(MACRO_glm_vec4_mulv) TEST_DECLARE(glm_vec4) TEST_DECLARE(glm_vec4_copy3) TEST_DECLARE(glm_vec4_copy) TEST_DECLARE(glm_vec4_ucopy) TEST_DECLARE(glm_vec4_zero) TEST_DECLARE(glm_vec4_one) TEST_DECLARE(glm_vec4_dot) TEST_DECLARE(glm_vec4_norm2) TEST_DECLARE(glm_vec4_norm) TEST_DECLARE(glm_vec4_norm_one) TEST_DECLARE(glm_vec4_norm_inf) TEST_DECLARE(glm_vec4_add) TEST_DECLARE(glm_vec4_adds) TEST_DECLARE(glm_vec4_sub) TEST_DECLARE(glm_vec4_subs) TEST_DECLARE(glm_vec4_mul) TEST_DECLARE(glm_vec4_scale) TEST_DECLARE(glm_vec4_scale_as) TEST_DECLARE(glm_vec4_div) TEST_DECLARE(glm_vec4_divs) TEST_DECLARE(glm_vec4_addadd) TEST_DECLARE(glm_vec4_subadd) TEST_DECLARE(glm_vec4_muladd) TEST_DECLARE(glm_vec4_muladds) TEST_DECLARE(glm_vec4_maxadd) TEST_DECLARE(glm_vec4_minadd) TEST_DECLARE(glm_vec4_subsub) TEST_DECLARE(glm_vec4_addsub) TEST_DECLARE(glm_vec4_mulsub) TEST_DECLARE(glm_vec4_mulsubs) TEST_DECLARE(glm_vec4_maxsub) TEST_DECLARE(glm_vec4_minsub) TEST_DECLARE(glm_vec4_negate_to) TEST_DECLARE(glm_vec4_negate) TEST_DECLARE(glm_vec4_normalize) TEST_DECLARE(glm_vec4_normalize_to) TEST_DECLARE(glm_vec4_distance2) TEST_DECLARE(glm_vec4_distance) TEST_DECLARE(glm_vec4_maxv) TEST_DECLARE(glm_vec4_minv) TEST_DECLARE(glm_vec4_clamp) TEST_DECLARE(glm_vec4_lerp) TEST_DECLARE(glm_vec4_lerpc) TEST_DECLARE(glm_vec4_mix) TEST_DECLARE(glm_vec4_mixc) TEST_DECLARE(glm_vec4_step) TEST_DECLARE(glm_vec4_smoothstep_uni) TEST_DECLARE(glm_vec4_smoothstep) TEST_DECLARE(glm_vec4_smoothinterp) TEST_DECLARE(glm_vec4_smoothinterpc) TEST_DECLARE(glm_vec4_cubic) TEST_DECLARE(glm_vec4_swizzle) TEST_DECLARE(glm_vec4_broadcast) TEST_DECLARE(glm_vec4_fill) TEST_DECLARE(glm_vec4_eq) TEST_DECLARE(glm_vec4_eq_eps) TEST_DECLARE(glm_vec4_eq_all) TEST_DECLARE(glm_vec4_eqv) TEST_DECLARE(glm_vec4_eqv_eps) TEST_DECLARE(glm_vec4_max) TEST_DECLARE(glm_vec4_min) TEST_DECLARE(glm_vec4_isnan) TEST_DECLARE(glm_vec4_isinf) TEST_DECLARE(glm_vec4_isvalid) TEST_DECLARE(glm_vec4_sign) TEST_DECLARE(glm_vec4_abs) TEST_DECLARE(glm_vec4_fract) TEST_DECLARE(glm_vec4_floor) TEST_DECLARE(glm_vec4_mods) TEST_DECLARE(glm_vec4_steps) TEST_DECLARE(glm_vec4_stepr) TEST_DECLARE(glm_vec4_hadd) TEST_DECLARE(glm_vec4_sqrt) TEST_DECLARE(glm_vec4_make) TEST_DECLARE(glm_vec4_reflect) TEST_DECLARE(glm_vec4_refract) TEST_DECLARE(glmc_vec4) TEST_DECLARE(glmc_vec4_copy3) TEST_DECLARE(glmc_vec4_copy) TEST_DECLARE(glmc_vec4_ucopy) TEST_DECLARE(glmc_vec4_zero) TEST_DECLARE(glmc_vec4_one) TEST_DECLARE(glmc_vec4_dot) TEST_DECLARE(glmc_vec4_norm2) TEST_DECLARE(glmc_vec4_norm) TEST_DECLARE(glmc_vec4_norm_one) TEST_DECLARE(glmc_vec4_norm_inf) TEST_DECLARE(glmc_vec4_add) TEST_DECLARE(glmc_vec4_adds) TEST_DECLARE(glmc_vec4_sub) TEST_DECLARE(glmc_vec4_subs) TEST_DECLARE(glmc_vec4_mul) TEST_DECLARE(glmc_vec4_scale) TEST_DECLARE(glmc_vec4_scale_as) TEST_DECLARE(glmc_vec4_div) TEST_DECLARE(glmc_vec4_divs) TEST_DECLARE(glmc_vec4_addadd) TEST_DECLARE(glmc_vec4_subadd) TEST_DECLARE(glmc_vec4_muladd) TEST_DECLARE(glmc_vec4_muladds) TEST_DECLARE(glmc_vec4_maxadd) TEST_DECLARE(glmc_vec4_minadd) TEST_DECLARE(glmc_vec4_subsub) TEST_DECLARE(glmc_vec4_addsub) TEST_DECLARE(glmc_vec4_mulsub) TEST_DECLARE(glmc_vec4_mulsubs) TEST_DECLARE(glmc_vec4_maxsub) TEST_DECLARE(glmc_vec4_minsub) TEST_DECLARE(glmc_vec4_negate_to) TEST_DECLARE(glmc_vec4_negate) TEST_DECLARE(glmc_vec4_normalize) TEST_DECLARE(glmc_vec4_normalize_to) TEST_DECLARE(glmc_vec4_distance2) TEST_DECLARE(glmc_vec4_distance) TEST_DECLARE(glmc_vec4_maxv) TEST_DECLARE(glmc_vec4_minv) TEST_DECLARE(glmc_vec4_clamp) TEST_DECLARE(glmc_vec4_lerp) TEST_DECLARE(glmc_vec4_lerpc) TEST_DECLARE(glmc_vec4_mix) TEST_DECLARE(glmc_vec4_mixc) TEST_DECLARE(glmc_vec4_step) TEST_DECLARE(glmc_vec4_smoothstep_uni) TEST_DECLARE(glmc_vec4_smoothstep) TEST_DECLARE(glmc_vec4_smoothinterp) TEST_DECLARE(glmc_vec4_smoothinterpc) TEST_DECLARE(glmc_vec4_cubic) TEST_DECLARE(glmc_vec4_swizzle) TEST_DECLARE(glmc_vec4_broadcast) TEST_DECLARE(glmc_vec4_fill) TEST_DECLARE(glmc_vec4_eq) TEST_DECLARE(glmc_vec4_eq_eps) TEST_DECLARE(glmc_vec4_eq_all) TEST_DECLARE(glmc_vec4_eqv) TEST_DECLARE(glmc_vec4_eqv_eps) TEST_DECLARE(glmc_vec4_max) TEST_DECLARE(glmc_vec4_min) TEST_DECLARE(glmc_vec4_isnan) TEST_DECLARE(glmc_vec4_isinf) TEST_DECLARE(glmc_vec4_isvalid) TEST_DECLARE(glmc_vec4_sign) TEST_DECLARE(glmc_vec4_abs) TEST_DECLARE(glmc_vec4_fract) TEST_DECLARE(glmc_vec4_floor) TEST_DECLARE(glmc_vec4_mods) TEST_DECLARE(glmc_vec4_steps) TEST_DECLARE(glmc_vec4_stepr) TEST_DECLARE(glmc_vec4_hadd) TEST_DECLARE(glmc_vec4_sqrt) TEST_DECLARE(glmc_vec4_make) TEST_DECLARE(glmc_vec4_reflect) TEST_DECLARE(glmc_vec4_refract) /* ivec2 */ TEST_DECLARE(glm_ivec2) TEST_DECLARE(glm_ivec2_copy) TEST_DECLARE(glm_ivec2_zero) TEST_DECLARE(glm_ivec2_one) TEST_DECLARE(glm_ivec2_dot) TEST_DECLARE(glm_ivec2_cross) TEST_DECLARE(glm_ivec2_add) TEST_DECLARE(glm_ivec2_adds) TEST_DECLARE(glm_ivec2_sub) TEST_DECLARE(glm_ivec2_subs) TEST_DECLARE(glm_ivec2_mul) TEST_DECLARE(glm_ivec2_scale) TEST_DECLARE(glm_ivec2_div) TEST_DECLARE(glm_ivec2_divs) TEST_DECLARE(glm_ivec2_mod) TEST_DECLARE(glm_ivec2_addadd) TEST_DECLARE(glm_ivec2_addadds) TEST_DECLARE(glm_ivec2_subadd) TEST_DECLARE(glm_ivec2_subadds) TEST_DECLARE(glm_ivec2_muladd) TEST_DECLARE(glm_ivec2_muladds) TEST_DECLARE(glm_ivec2_maxadd) TEST_DECLARE(glm_ivec2_minadd) TEST_DECLARE(glm_ivec2_subsub) TEST_DECLARE(glm_ivec2_subsubs) TEST_DECLARE(glm_ivec2_addsub) TEST_DECLARE(glm_ivec2_addsubs) TEST_DECLARE(glm_ivec2_mulsub) TEST_DECLARE(glm_ivec2_mulsubs) TEST_DECLARE(glm_ivec2_maxsub) TEST_DECLARE(glm_ivec2_minsub) TEST_DECLARE(glm_ivec2_distance2) TEST_DECLARE(glm_ivec2_distance) TEST_DECLARE(glm_ivec2_fill) TEST_DECLARE(glm_ivec2_eq) TEST_DECLARE(glm_ivec2_eqv) TEST_DECLARE(glm_ivec2_maxv) TEST_DECLARE(glm_ivec2_minv) TEST_DECLARE(glm_ivec2_clamp) TEST_DECLARE(glm_ivec2_abs) TEST_DECLARE(glmc_ivec2) TEST_DECLARE(glmc_ivec2_copy) TEST_DECLARE(glmc_ivec2_zero) TEST_DECLARE(glmc_ivec2_one) TEST_DECLARE(glmc_ivec2_dot) TEST_DECLARE(glmc_ivec2_cross) TEST_DECLARE(glmc_ivec2_add) TEST_DECLARE(glmc_ivec2_adds) TEST_DECLARE(glmc_ivec2_sub) TEST_DECLARE(glmc_ivec2_subs) TEST_DECLARE(glmc_ivec2_mul) TEST_DECLARE(glmc_ivec2_scale) TEST_DECLARE(glmc_ivec2_div) TEST_DECLARE(glmc_ivec2_divs) TEST_DECLARE(glmc_ivec2_mod) TEST_DECLARE(glmc_ivec2_addadd) TEST_DECLARE(glmc_ivec2_addadds) TEST_DECLARE(glmc_ivec2_subadd) TEST_DECLARE(glmc_ivec2_subadds) TEST_DECLARE(glmc_ivec2_muladd) TEST_DECLARE(glmc_ivec2_muladds) TEST_DECLARE(glmc_ivec2_maxadd) TEST_DECLARE(glmc_ivec2_minadd) TEST_DECLARE(glmc_ivec2_subsub) TEST_DECLARE(glmc_ivec2_subsubs) TEST_DECLARE(glmc_ivec2_addsub) TEST_DECLARE(glmc_ivec2_addsubs) TEST_DECLARE(glmc_ivec2_mulsub) TEST_DECLARE(glmc_ivec2_mulsubs) TEST_DECLARE(glmc_ivec2_maxsub) TEST_DECLARE(glmc_ivec2_minsub) TEST_DECLARE(glmc_ivec2_distance2) TEST_DECLARE(glmc_ivec2_distance) TEST_DECLARE(glmc_ivec2_fill) TEST_DECLARE(glmc_ivec2_eq) TEST_DECLARE(glmc_ivec2_eqv) TEST_DECLARE(glmc_ivec2_maxv) TEST_DECLARE(glmc_ivec2_minv) TEST_DECLARE(glmc_ivec2_clamp) TEST_DECLARE(glmc_ivec2_abs) /* ivec3 */ TEST_DECLARE(glm_ivec3) TEST_DECLARE(glm_ivec3_copy) TEST_DECLARE(glm_ivec3_zero) TEST_DECLARE(glm_ivec3_one) TEST_DECLARE(glm_ivec3_dot) TEST_DECLARE(glm_ivec3_norm2) TEST_DECLARE(glm_ivec3_norm) TEST_DECLARE(glm_ivec3_add) TEST_DECLARE(glm_ivec3_adds) TEST_DECLARE(glm_ivec3_sub) TEST_DECLARE(glm_ivec3_subs) TEST_DECLARE(glm_ivec3_mul) TEST_DECLARE(glm_ivec3_scale) TEST_DECLARE(glm_ivec3_div) TEST_DECLARE(glm_ivec3_divs) TEST_DECLARE(glm_ivec3_mod) TEST_DECLARE(glm_ivec3_addadd) TEST_DECLARE(glm_ivec3_addadds) TEST_DECLARE(glm_ivec3_subadd) TEST_DECLARE(glm_ivec3_subadds) TEST_DECLARE(glm_ivec3_muladd) TEST_DECLARE(glm_ivec3_muladds) TEST_DECLARE(glm_ivec3_maxadd) TEST_DECLARE(glm_ivec3_minadd) TEST_DECLARE(glm_ivec3_subsub) TEST_DECLARE(glm_ivec3_subsubs) TEST_DECLARE(glm_ivec3_addsub) TEST_DECLARE(glm_ivec3_addsubs) TEST_DECLARE(glm_ivec3_mulsub) TEST_DECLARE(glm_ivec3_mulsubs) TEST_DECLARE(glm_ivec3_maxsub) TEST_DECLARE(glm_ivec3_minsub) TEST_DECLARE(glm_ivec3_distance2) TEST_DECLARE(glm_ivec3_distance) TEST_DECLARE(glm_ivec3_fill) TEST_DECLARE(glm_ivec3_eq) TEST_DECLARE(glm_ivec3_eqv) TEST_DECLARE(glm_ivec3_maxv) TEST_DECLARE(glm_ivec3_minv) TEST_DECLARE(glm_ivec3_clamp) TEST_DECLARE(glmc_ivec3) TEST_DECLARE(glmc_ivec3_copy) TEST_DECLARE(glmc_ivec3_zero) TEST_DECLARE(glmc_ivec3_one) TEST_DECLARE(glmc_ivec3_dot) TEST_DECLARE(glmc_ivec3_norm2) TEST_DECLARE(glmc_ivec3_norm) TEST_DECLARE(glmc_ivec3_add) TEST_DECLARE(glmc_ivec3_adds) TEST_DECLARE(glmc_ivec3_sub) TEST_DECLARE(glmc_ivec3_subs) TEST_DECLARE(glmc_ivec3_mul) TEST_DECLARE(glmc_ivec3_scale) TEST_DECLARE(glmc_ivec3_div) TEST_DECLARE(glmc_ivec3_divs) TEST_DECLARE(glmc_ivec3_mod) TEST_DECLARE(glmc_ivec3_addadd) TEST_DECLARE(glmc_ivec3_addadds) TEST_DECLARE(glmc_ivec3_subadd) TEST_DECLARE(glmc_ivec3_subadds) TEST_DECLARE(glmc_ivec3_muladd) TEST_DECLARE(glmc_ivec3_muladds) TEST_DECLARE(glmc_ivec3_maxadd) TEST_DECLARE(glmc_ivec3_minadd) TEST_DECLARE(glmc_ivec3_subsub) TEST_DECLARE(glmc_ivec3_subsubs) TEST_DECLARE(glmc_ivec3_addsub) TEST_DECLARE(glmc_ivec3_addsubs) TEST_DECLARE(glmc_ivec3_mulsub) TEST_DECLARE(glmc_ivec3_mulsubs) TEST_DECLARE(glmc_ivec3_maxsub) TEST_DECLARE(glmc_ivec3_minsub) TEST_DECLARE(glmc_ivec3_distance2) TEST_DECLARE(glmc_ivec3_distance) TEST_DECLARE(glmc_ivec3_fill) TEST_DECLARE(glmc_ivec3_eq) TEST_DECLARE(glmc_ivec3_eqv) TEST_DECLARE(glmc_ivec3_maxv) TEST_DECLARE(glmc_ivec3_minv) TEST_DECLARE(glmc_ivec3_clamp) /* ivec4 */ TEST_DECLARE(glm_ivec4) TEST_DECLARE(glm_ivec4_copy) TEST_DECLARE(glm_ivec4_zero) TEST_DECLARE(glm_ivec4_one) TEST_DECLARE(glm_ivec4_add) TEST_DECLARE(glm_ivec4_adds) TEST_DECLARE(glm_ivec4_sub) TEST_DECLARE(glm_ivec4_subs) TEST_DECLARE(glm_ivec4_mul) TEST_DECLARE(glm_ivec4_scale) TEST_DECLARE(glm_ivec4_addadd) TEST_DECLARE(glm_ivec4_addadds) TEST_DECLARE(glm_ivec4_subadd) TEST_DECLARE(glm_ivec4_subadds) TEST_DECLARE(glm_ivec4_muladd) TEST_DECLARE(glm_ivec4_muladds) TEST_DECLARE(glm_ivec4_maxadd) TEST_DECLARE(glm_ivec4_minadd) TEST_DECLARE(glm_ivec4_subsub) TEST_DECLARE(glm_ivec4_subsubs) TEST_DECLARE(glm_ivec4_addsub) TEST_DECLARE(glm_ivec4_addsubs) TEST_DECLARE(glm_ivec4_mulsub) TEST_DECLARE(glm_ivec4_mulsubs) TEST_DECLARE(glm_ivec4_maxsub) TEST_DECLARE(glm_ivec4_minsub) TEST_DECLARE(glm_ivec4_distance2) TEST_DECLARE(glm_ivec4_distance) TEST_DECLARE(glm_ivec4_maxv) TEST_DECLARE(glm_ivec4_minv) TEST_DECLARE(glm_ivec4_clamp) TEST_DECLARE(glm_ivec4_abs) TEST_DECLARE(glmc_ivec4) TEST_DECLARE(glmc_ivec4_copy) TEST_DECLARE(glmc_ivec4_zero) TEST_DECLARE(glmc_ivec4_one) TEST_DECLARE(glmc_ivec4_add) TEST_DECLARE(glmc_ivec4_adds) TEST_DECLARE(glmc_ivec4_sub) TEST_DECLARE(glmc_ivec4_subs) TEST_DECLARE(glmc_ivec4_mul) TEST_DECLARE(glmc_ivec4_scale) TEST_DECLARE(glmc_ivec4_addadd) TEST_DECLARE(glmc_ivec4_addadds) TEST_DECLARE(glmc_ivec4_subadd) TEST_DECLARE(glmc_ivec4_subadds) TEST_DECLARE(glmc_ivec4_muladd) TEST_DECLARE(glmc_ivec4_muladds) TEST_DECLARE(glmc_ivec4_maxadd) TEST_DECLARE(glmc_ivec4_minadd) TEST_DECLARE(glmc_ivec4_subsub) TEST_DECLARE(glmc_ivec4_subsubs) TEST_DECLARE(glmc_ivec4_addsub) TEST_DECLARE(glmc_ivec4_addsubs) TEST_DECLARE(glmc_ivec4_mulsub) TEST_DECLARE(glmc_ivec4_mulsubs) TEST_DECLARE(glmc_ivec4_maxsub) TEST_DECLARE(glmc_ivec4_minsub) TEST_DECLARE(glmc_ivec4_distance2) TEST_DECLARE(glmc_ivec4_distance) TEST_DECLARE(glmc_ivec4_maxv) TEST_DECLARE(glmc_ivec4_minv) TEST_DECLARE(glmc_ivec4_clamp) TEST_DECLARE(glmc_ivec4_abs) /* structs */ TEST_DECLARE(mat2x3s_zero_init) TEST_DECLARE(mat2x3s_zero) TEST_DECLARE(mat2x4s_zero_init) TEST_DECLARE(mat2x4s_zero) TEST_DECLARE(mat3s_identity_init) TEST_DECLARE(mat3s_zero_init) TEST_DECLARE(mat3x2s_zero_init) TEST_DECLARE(mat3x2s_zero) TEST_DECLARE(mat3x4s_zero_init) TEST_DECLARE(mat3x4s_zero) TEST_DECLARE(mat4s_spin) TEST_DECLARE(mat4s_identity_init) TEST_DECLARE(mat4s_zero_init) TEST_DECLARE(mat4x2s_zero_init) TEST_DECLARE(mat4x2s_zero) TEST_DECLARE(mat4x3s_zero_init) TEST_DECLARE(mat4x3s_zero) TEST_DECLARE(quats_zero_init) TEST_DECLARE(quats_mat_nonunit) TEST_DECLARE(vec3s_one_init) TEST_DECLARE(vec3s_zero_init) TEST_DECLARE(vec4s_black_init) TEST_DECLARE(vec4s_one_init) TEST_DECLARE(vec4s_zero_init) /*****************************************************************************/ TEST_LIST { /* affine mat */ TEST_ENTRY(glm_mul) TEST_ENTRY(glm_mul) TEST_ENTRY(glm_inv_tr) TEST_ENTRY(glmc_mul) TEST_ENTRY(glmc_mul_rot) TEST_ENTRY(glmc_inv_tr) /* affine */ TEST_ENTRY(glm_translate) TEST_ENTRY(glm_translate_to) TEST_ENTRY(glm_translate_x) TEST_ENTRY(glm_translate_y) TEST_ENTRY(glm_translate_z) TEST_ENTRY(glm_translate_make) TEST_ENTRY(glm_scale_to) TEST_ENTRY(glm_scale_make) TEST_ENTRY(glm_scale) TEST_ENTRY(glm_scale_uni) TEST_ENTRY(glm_rotate_x) TEST_ENTRY(glm_rotate_y) TEST_ENTRY(glm_rotate_z) TEST_ENTRY(glm_rotate_make) TEST_ENTRY(glm_rotate) TEST_ENTRY(glm_rotate_at) TEST_ENTRY(glm_rotate_atm) TEST_ENTRY(glm_spin) TEST_ENTRY(glm_spin_affine) TEST_ENTRY(glm_decompose_scalev) TEST_ENTRY(glm_uniscaled) TEST_ENTRY(glm_decompose_rs) TEST_ENTRY(glm_decompose) TEST_ENTRY(glmc_translate) TEST_ENTRY(glmc_translate_to) TEST_ENTRY(glmc_translate_x) TEST_ENTRY(glmc_translate_y) TEST_ENTRY(glmc_translate_z) TEST_ENTRY(glmc_translate_make) TEST_ENTRY(glmc_scale_to) TEST_ENTRY(glmc_scale_make) TEST_ENTRY(glmc_scale) TEST_ENTRY(glmc_scale_uni) TEST_ENTRY(glmc_rotate_x) TEST_ENTRY(glmc_rotate_y) TEST_ENTRY(glmc_rotate_z) TEST_ENTRY(glmc_rotate_make) TEST_ENTRY(glmc_rotate) TEST_ENTRY(glmc_rotate_at) TEST_ENTRY(glmc_rotate_atm) TEST_ENTRY(glmc_spin) TEST_ENTRY(glmc_spin_affine) TEST_ENTRY(glmc_decompose_scalev) TEST_ENTRY(glmc_uniscaled) TEST_ENTRY(glmc_decompose_rs) TEST_ENTRY(glmc_decompose) /* affine 2d */ TEST_ENTRY(glm_translate2d) TEST_ENTRY(glm_translate2d_to) TEST_ENTRY(glm_translate2d_x) TEST_ENTRY(glm_translate2d_y) TEST_ENTRY(glm_translate2d_make) TEST_ENTRY(glm_scale2d_to) TEST_ENTRY(glm_scale2d_make) TEST_ENTRY(glm_scale2d) TEST_ENTRY(glm_scale2d_uni) TEST_ENTRY(glm_rotate2d_make) TEST_ENTRY(glm_rotate2d) TEST_ENTRY(glm_rotate2d_to) TEST_ENTRY(glmc_translate2d) TEST_ENTRY(glmc_translate2d_to) TEST_ENTRY(glmc_translate2d_x) TEST_ENTRY(glmc_translate2d_y) TEST_ENTRY(glmc_translate2d_make) TEST_ENTRY(glmc_scale2d_to) TEST_ENTRY(glmc_scale2d_make) TEST_ENTRY(glmc_scale2d) TEST_ENTRY(glmc_scale2d_uni) TEST_ENTRY(glmc_rotate2d_make) TEST_ENTRY(glmc_rotate2d) TEST_ENTRY(glmc_rotate2d_to) /* affine 2d post */ TEST_ENTRY(glm_translated2d) TEST_ENTRY(glm_translated2d_x) TEST_ENTRY(glm_translated2d_y) TEST_ENTRY(glm_rotated2d) TEST_ENTRY(glm_scaled2d) TEST_ENTRY(glm_scaled2d_uni) /* aabb2d */ TEST_ENTRY(glm_aabb2d_sizev) /* mat4 */ TEST_ENTRY(glm_mat4_ucopy) TEST_ENTRY(glm_mat4_copy) TEST_ENTRY(glm_mat4_identity) TEST_ENTRY(glm_mat4_identity_array) TEST_ENTRY(glm_mat4_zero) TEST_ENTRY(glm_mat4_pick3) TEST_ENTRY(glm_mat4_pick3t) TEST_ENTRY(glm_mat4_ins3) TEST_ENTRY(glm_mat4_mul) TEST_ENTRY(glm_mat4_mulN) TEST_ENTRY(glm_mat4_mulv) TEST_ENTRY(glm_mat4_mulv3) TEST_ENTRY(glm_mat4_trace) TEST_ENTRY(glm_mat4_trace3) TEST_ENTRY(glm_mat4_quat) TEST_ENTRY(glm_mat4_transpose_to) TEST_ENTRY(glm_mat4_transpose) TEST_ENTRY(glm_mat4_scale_p) TEST_ENTRY(glm_mat4_scale) TEST_ENTRY(glm_mat4_det) TEST_ENTRY(glm_mat4_inv) TEST_ENTRY(glm_mat4_inv_fast) TEST_ENTRY(glm_mat4_inv_precise) TEST_ENTRY(glm_mat4_swap_col) TEST_ENTRY(glm_mat4_swap_row) TEST_ENTRY(glm_mat4_rmc) TEST_ENTRY(glm_mat4_make) TEST_ENTRY(glm_mat4_textrans) TEST_ENTRY(glmc_mat4_ucopy) TEST_ENTRY(glmc_mat4_copy) TEST_ENTRY(glmc_mat4_identity) TEST_ENTRY(glmc_mat4_identity_array) TEST_ENTRY(glmc_mat4_zero) TEST_ENTRY(glmc_mat4_pick3) TEST_ENTRY(glmc_mat4_pick3t) TEST_ENTRY(glmc_mat4_ins3) TEST_ENTRY(glmc_mat4_mul) TEST_ENTRY(glmc_mat4_mulN) TEST_ENTRY(glmc_mat4_mulv) TEST_ENTRY(glmc_mat4_mulv3) TEST_ENTRY(glmc_mat4_trace) TEST_ENTRY(glmc_mat4_trace3) TEST_ENTRY(glmc_mat4_quat) TEST_ENTRY(glmc_mat4_transpose_to) TEST_ENTRY(glmc_mat4_transpose) TEST_ENTRY(glmc_mat4_scale_p) TEST_ENTRY(glmc_mat4_scale) TEST_ENTRY(glmc_mat4_det) TEST_ENTRY(glmc_mat4_inv) TEST_ENTRY(glmc_mat4_inv_fast) TEST_ENTRY(glmc_mat4_swap_col) TEST_ENTRY(glmc_mat4_swap_row) TEST_ENTRY(glmc_mat4_rmc) TEST_ENTRY(glmc_mat4_make) TEST_ENTRY(MACRO_GLM_MAT4X2_ZERO_INIT) TEST_ENTRY(MACRO_GLM_MAT4X2_ZERO) TEST_ENTRY(glm_mat4x2_copy) TEST_ENTRY(glm_mat4x2_zero) TEST_ENTRY(glm_mat4x2_make) TEST_ENTRY(glm_mat4x2_mul) TEST_ENTRY(glm_mat4x2_mulv) TEST_ENTRY(glm_mat4x2_transpose) TEST_ENTRY(glm_mat4x2_scale) TEST_ENTRY(glmc_mat4x2_copy) TEST_ENTRY(glmc_mat4x2_zero) TEST_ENTRY(glmc_mat4x2_make) TEST_ENTRY(glmc_mat4x2_mul) TEST_ENTRY(glmc_mat4x2_mulv) TEST_ENTRY(glmc_mat4x2_transpose) TEST_ENTRY(glmc_mat4x2_scale) TEST_ENTRY(MACRO_GLM_MAT4X3_ZERO_INIT) TEST_ENTRY(MACRO_GLM_MAT4X3_ZERO) TEST_ENTRY(glm_mat4x3_copy) TEST_ENTRY(glm_mat4x3_zero) TEST_ENTRY(glm_mat4x3_make) TEST_ENTRY(glm_mat4x3_mul) TEST_ENTRY(glm_mat4x3_mulv) TEST_ENTRY(glm_mat4x3_transpose) TEST_ENTRY(glm_mat4x3_scale) TEST_ENTRY(glmc_mat4x3_copy) TEST_ENTRY(glmc_mat4x3_zero) TEST_ENTRY(glmc_mat4x3_make) TEST_ENTRY(glmc_mat4x3_mul) TEST_ENTRY(glmc_mat4x3_mulv) TEST_ENTRY(glmc_mat4x3_transpose) TEST_ENTRY(glmc_mat4x3_scale) /* mat3 */ TEST_ENTRY(glm_mat3_copy) TEST_ENTRY(glm_mat3_identity) TEST_ENTRY(glm_mat3_identity_array) TEST_ENTRY(glm_mat3_zero) TEST_ENTRY(glm_mat3_mul) TEST_ENTRY(glm_mat3_mulv) TEST_ENTRY(glm_mat3_trace) TEST_ENTRY(glm_mat3_quat) TEST_ENTRY(glm_mat3_transpose_to) TEST_ENTRY(glm_mat3_transpose) TEST_ENTRY(glm_mat3_scale) TEST_ENTRY(glm_mat3_det) TEST_ENTRY(glm_mat3_inv) TEST_ENTRY(glm_mat3_swap_col) TEST_ENTRY(glm_mat3_swap_row) TEST_ENTRY(glm_mat3_rmc) TEST_ENTRY(glm_mat3_make) TEST_ENTRY(glm_mat3_textrans) TEST_ENTRY(glmc_mat3_copy) TEST_ENTRY(glmc_mat3_identity) TEST_ENTRY(glmc_mat3_identity_array) TEST_ENTRY(glmc_mat3_zero) TEST_ENTRY(glmc_mat3_mul) TEST_ENTRY(glmc_mat3_mulv) TEST_ENTRY(glmc_mat3_trace) TEST_ENTRY(glmc_mat3_quat) TEST_ENTRY(glmc_mat3_transpose_to) TEST_ENTRY(glmc_mat3_transpose) TEST_ENTRY(glmc_mat3_scale) TEST_ENTRY(glmc_mat3_det) TEST_ENTRY(glmc_mat3_inv) TEST_ENTRY(glmc_mat3_swap_col) TEST_ENTRY(glmc_mat3_swap_row) TEST_ENTRY(glmc_mat3_rmc) TEST_ENTRY(glmc_mat3_make) TEST_ENTRY(MACRO_GLM_MAT3X2_ZERO_INIT) TEST_ENTRY(MACRO_GLM_MAT3X2_ZERO) TEST_ENTRY(glm_mat3x2_copy) TEST_ENTRY(glm_mat3x2_zero) TEST_ENTRY(glm_mat3x2_make) TEST_ENTRY(glm_mat3x2_mul) TEST_ENTRY(glm_mat3x2_mulv) TEST_ENTRY(glm_mat3x2_transpose) TEST_ENTRY(glm_mat3x2_scale) TEST_ENTRY(glmc_mat3x2_copy) TEST_ENTRY(glmc_mat3x2_zero) TEST_ENTRY(glmc_mat3x2_make) TEST_ENTRY(glmc_mat3x2_mul) TEST_ENTRY(glmc_mat3x2_mulv) TEST_ENTRY(glmc_mat3x2_transpose) TEST_ENTRY(glmc_mat3x2_scale) TEST_ENTRY(MACRO_GLM_MAT3X4_ZERO_INIT) TEST_ENTRY(MACRO_GLM_MAT3X4_ZERO) TEST_ENTRY(glm_mat3x4_make) TEST_ENTRY(glmc_mat3x4_make) TEST_ENTRY(MACRO_GLM_MAT2_IDENTITY_INIT) TEST_ENTRY(MACRO_GLM_MAT2_ZERO_INIT) TEST_ENTRY(MACRO_GLM_MAT2_IDENTITY) TEST_ENTRY(MACRO_GLM_MAT2_ZERO) TEST_ENTRY(glm_mat2_copy) TEST_ENTRY(glm_mat2_identity) TEST_ENTRY(glm_mat2_identity_array) TEST_ENTRY(glm_mat2_zero) TEST_ENTRY(glm_mat2_mul) TEST_ENTRY(glm_mat2_transpose_to) TEST_ENTRY(glm_mat2_transpose) TEST_ENTRY(glm_mat2_mulv) TEST_ENTRY(glm_mat2_trace) TEST_ENTRY(glm_mat2_scale) TEST_ENTRY(glm_mat2_det) TEST_ENTRY(glm_mat2_inv) TEST_ENTRY(glm_mat2_swap_col) TEST_ENTRY(glm_mat2_swap_row) TEST_ENTRY(glm_mat2_rmc) TEST_ENTRY(glm_mat2_make) TEST_ENTRY(glmc_mat2_copy) TEST_ENTRY(glmc_mat2_identity) TEST_ENTRY(glmc_mat2_identity_array) TEST_ENTRY(glmc_mat2_zero) TEST_ENTRY(glmc_mat2_mul) TEST_ENTRY(glmc_mat2_transpose_to) TEST_ENTRY(glmc_mat2_transpose) TEST_ENTRY(glmc_mat2_mulv) TEST_ENTRY(glmc_mat2_trace) TEST_ENTRY(glmc_mat2_scale) TEST_ENTRY(glmc_mat2_det) TEST_ENTRY(glmc_mat2_inv) TEST_ENTRY(glmc_mat2_swap_col) TEST_ENTRY(glmc_mat2_swap_row) TEST_ENTRY(glmc_mat2_rmc) TEST_ENTRY(glmc_mat2_make) TEST_ENTRY(MACRO_GLM_MAT2X3_ZERO_INIT) TEST_ENTRY(MACRO_GLM_MAT2X3_ZERO) TEST_ENTRY(glm_mat2x3_copy) TEST_ENTRY(glm_mat2x3_zero) TEST_ENTRY(glm_mat2x3_make) TEST_ENTRY(glm_mat2x3_mul) TEST_ENTRY(glm_mat2x3_mulv) TEST_ENTRY(glm_mat2x3_transpose) TEST_ENTRY(glm_mat2x3_scale) TEST_ENTRY(glmc_mat2x3_copy) TEST_ENTRY(glmc_mat2x3_zero) TEST_ENTRY(glmc_mat2x3_make) TEST_ENTRY(glmc_mat2x3_mul) TEST_ENTRY(glmc_mat2x3_mulv) TEST_ENTRY(glmc_mat2x3_transpose) TEST_ENTRY(glmc_mat2x3_scale) TEST_ENTRY(MACRO_GLM_MAT2X4_ZERO_INIT) TEST_ENTRY(MACRO_GLM_MAT2X4_ZERO) TEST_ENTRY(glm_mat2x4_copy) TEST_ENTRY(glm_mat2x4_zero) TEST_ENTRY(glm_mat2x4_make) TEST_ENTRY(glm_mat2x4_mul) TEST_ENTRY(glm_mat2x4_mulv) TEST_ENTRY(glm_mat2x4_transpose) TEST_ENTRY(glm_mat2x4_scale) TEST_ENTRY(glmc_mat2x4_copy) TEST_ENTRY(glmc_mat2x4_zero) TEST_ENTRY(glmc_mat2x4_make) TEST_ENTRY(glmc_mat2x4_mul) TEST_ENTRY(glmc_mat2x4_mulv) TEST_ENTRY(glmc_mat2x4_transpose) TEST_ENTRY(glmc_mat2x4_scale) /* camera (incl [LR]H cross [NZ]O) */ TEST_ENTRY(glm_perspective_lh_zo) TEST_ENTRY(glm_perspective_rh_zo) TEST_ENTRY(glm_perspective_lh_no) TEST_ENTRY(glm_perspective_rh_no) TEST_ENTRY(glm_camera_lookat) TEST_ENTRY(glm_camera_decomp) TEST_ENTRY(glmc_perspective_lh_zo) TEST_ENTRY(glmc_perspective_rh_zo) TEST_ENTRY(glmc_perspective_lh_no) TEST_ENTRY(glmc_perspective_rh_no) TEST_ENTRY(glmc_camera_lookat) TEST_ENTRY(glmc_camera_decomp) TEST_ENTRY(glm_frustum) TEST_ENTRY(glmc_frustum) /* project */ TEST_ENTRY(glm_unprojecti) TEST_ENTRY(glm_unproject) TEST_ENTRY(glm_project) TEST_ENTRY(glmc_unprojecti) TEST_ENTRY(glmc_unproject) TEST_ENTRY(glmc_project) /* plane */ TEST_ENTRY(glm_plane_normalize) TEST_ENTRY(glmc_plane_normalize) /* noise */ TEST_ENTRY(glm_perlin_vec4) TEST_ENTRY(glmc_perlin_vec4) TEST_ENTRY(glm_perlin_vec3) TEST_ENTRY(glmc_perlin_vec3) TEST_ENTRY(glm_perlin_vec2) TEST_ENTRY(glmc_perlin_vec2) /* utils */ TEST_ENTRY(clamp) /* euler */ TEST_ENTRY(glm_euler_xyz_quat_rh) TEST_ENTRY(glm_euler_xzy_quat_rh) TEST_ENTRY(glm_euler_yxz_quat_rh) TEST_ENTRY(glm_euler_yzx_quat_rh) TEST_ENTRY(glm_euler_zxy_quat_rh) TEST_ENTRY(glm_euler_zyx_quat_rh) TEST_ENTRY(glm_euler_xyz_quat_lh) TEST_ENTRY(glm_euler_xzy_quat_lh) TEST_ENTRY(glm_euler_yxz_quat_lh) TEST_ENTRY(glm_euler_yzx_quat_lh) TEST_ENTRY(glm_euler_zxy_quat_lh) TEST_ENTRY(glm_euler_zyx_quat_lh) TEST_ENTRY(glmc_euler_xyz_quat_rh) TEST_ENTRY(glmc_euler_xzy_quat_rh) TEST_ENTRY(glmc_euler_yxz_quat_rh) TEST_ENTRY(glmc_euler_yzx_quat_rh) TEST_ENTRY(glmc_euler_zxy_quat_rh) TEST_ENTRY(glmc_euler_zyx_quat_rh) TEST_ENTRY(glmc_euler_xyz_quat_lh) TEST_ENTRY(glmc_euler_xzy_quat_lh) TEST_ENTRY(glmc_euler_yxz_quat_lh) TEST_ENTRY(glmc_euler_yzx_quat_lh) TEST_ENTRY(glmc_euler_zxy_quat_lh) TEST_ENTRY(glmc_euler_zyx_quat_lh) TEST_ENTRY(euler) /* ray */ TEST_ENTRY(glm_ray_triangle) TEST_ENTRY(glm_ray_sphere) TEST_ENTRY(glm_ray_at) TEST_ENTRY(glmc_ray_triangle) TEST_ENTRY(glmc_ray_sphere) TEST_ENTRY(glmc_ray_at) /* quat */ TEST_ENTRY(MACRO_GLM_QUAT_IDENTITY_INIT) TEST_ENTRY(MACRO_GLM_QUAT_IDENTITY) TEST_ENTRY(glm_quat_identity) TEST_ENTRY(glm_quat_identity_array) TEST_ENTRY(glm_quat_init) TEST_ENTRY(glm_quatv) TEST_ENTRY(glm_quat) TEST_ENTRY(glm_quat_copy) TEST_ENTRY(glm_quat_norm) TEST_ENTRY(glm_quat_normalize_to) TEST_ENTRY(glm_quat_normalize) TEST_ENTRY(glm_quat_dot) TEST_ENTRY(glm_quat_conjugate) TEST_ENTRY(glm_quat_inv) TEST_ENTRY(glm_quat_add) TEST_ENTRY(glm_quat_sub) TEST_ENTRY(glm_quat_real) TEST_ENTRY(glm_quat_imag) TEST_ENTRY(glm_quat_imagn) TEST_ENTRY(glm_quat_imaglen) TEST_ENTRY(glm_quat_angle) TEST_ENTRY(glm_quat_axis) TEST_ENTRY(glm_quat_mul) TEST_ENTRY(glm_quat_mat4) TEST_ENTRY(glm_quat_mat4t) TEST_ENTRY(glm_quat_mat3) TEST_ENTRY(glm_quat_mat3t) TEST_ENTRY(glm_quat_lerp) TEST_ENTRY(glm_quat_lerpc) TEST_ENTRY(glm_quat_nlerp) TEST_ENTRY(glm_quat_slerp) TEST_ENTRY(glm_quat_look) TEST_ENTRY(glm_quat_for) TEST_ENTRY(glm_quat_forp) TEST_ENTRY(glm_quat_rotatev) TEST_ENTRY(glm_quat_rotate) TEST_ENTRY(glm_quat_rotate_at) TEST_ENTRY(glm_quat_rotate_atm) TEST_ENTRY(glm_quat_from_vecs) TEST_ENTRY(glm_quat_make) TEST_ENTRY(glmc_quat_identity) TEST_ENTRY(glmc_quat_identity_array) TEST_ENTRY(glmc_quat_init) TEST_ENTRY(glmc_quatv) TEST_ENTRY(glmc_quat) TEST_ENTRY(glmc_quat_copy) TEST_ENTRY(glmc_quat_norm) TEST_ENTRY(glmc_quat_normalize_to) TEST_ENTRY(glmc_quat_normalize) TEST_ENTRY(glmc_quat_dot) TEST_ENTRY(glmc_quat_conjugate) TEST_ENTRY(glmc_quat_inv) TEST_ENTRY(glmc_quat_add) TEST_ENTRY(glmc_quat_sub) TEST_ENTRY(glmc_quat_real) TEST_ENTRY(glmc_quat_imag) TEST_ENTRY(glmc_quat_imagn) TEST_ENTRY(glmc_quat_imaglen) TEST_ENTRY(glmc_quat_angle) TEST_ENTRY(glmc_quat_axis) TEST_ENTRY(glmc_quat_mul) TEST_ENTRY(glmc_quat_mat4) TEST_ENTRY(glmc_quat_mat4t) TEST_ENTRY(glmc_quat_mat3) TEST_ENTRY(glmc_quat_mat3t) TEST_ENTRY(glmc_quat_lerp) TEST_ENTRY(glmc_quat_lerpc) TEST_ENTRY(glmc_quat_nlerp) TEST_ENTRY(glmc_quat_slerp) TEST_ENTRY(glmc_quat_look) TEST_ENTRY(glmc_quat_for) TEST_ENTRY(glmc_quat_forp) TEST_ENTRY(glmc_quat_rotatev) TEST_ENTRY(glmc_quat_rotate) TEST_ENTRY(glmc_quat_rotate_at) TEST_ENTRY(glmc_quat_rotate_atm) TEST_ENTRY(glmc_quat_from_vecs) TEST_ENTRY(glmc_quat_make) /* bezier */ TEST_ENTRY(bezier) /* vec2 */ TEST_ENTRY(MACRO_GLM_VEC2_ONE_INIT) TEST_ENTRY(MACRO_GLM_VEC2_ZERO_INIT) TEST_ENTRY(MACRO_GLM_VEC2_ONE) TEST_ENTRY(MACRO_GLM_VEC2_ZERO) TEST_ENTRY(glm_vec2) TEST_ENTRY(glm_vec2_copy) TEST_ENTRY(glm_vec2_zero) TEST_ENTRY(glm_vec2_one) TEST_ENTRY(glm_vec2_dot) TEST_ENTRY(glm_vec2_cross) TEST_ENTRY(glm_vec2_norm2) TEST_ENTRY(glm_vec2_norm) TEST_ENTRY(glm_vec2_add) TEST_ENTRY(glm_vec2_adds) TEST_ENTRY(glm_vec2_sub) TEST_ENTRY(glm_vec2_subs) TEST_ENTRY(glm_vec2_mul) TEST_ENTRY(glm_vec2_scale) TEST_ENTRY(glm_vec2_scale_as) TEST_ENTRY(glm_vec2_div) TEST_ENTRY(glm_vec2_divs) TEST_ENTRY(glm_vec2_addadd) TEST_ENTRY(glm_vec2_subadd) TEST_ENTRY(glm_vec2_muladd) TEST_ENTRY(glm_vec2_muladds) TEST_ENTRY(glm_vec2_maxadd) TEST_ENTRY(glm_vec2_minadd) TEST_ENTRY(glm_vec2_subsub) TEST_ENTRY(glm_vec2_addsub) TEST_ENTRY(glm_vec2_mulsub) TEST_ENTRY(glm_vec2_mulsubs) TEST_ENTRY(glm_vec2_maxsub) TEST_ENTRY(glm_vec2_minsub) TEST_ENTRY(glm_vec2_negate_to) TEST_ENTRY(glm_vec2_negate) TEST_ENTRY(glm_vec2_normalize) TEST_ENTRY(glm_vec2_normalize_to) TEST_ENTRY(glm_vec2_rotate) TEST_ENTRY(glm_vec2_center) TEST_ENTRY(glm_vec2_distance2) TEST_ENTRY(glm_vec2_distance) TEST_ENTRY(glm_vec2_maxv) TEST_ENTRY(glm_vec2_minv) TEST_ENTRY(glm_vec2_clamp) TEST_ENTRY(glm_vec2_abs) TEST_ENTRY(glm_vec2_fract) TEST_ENTRY(glm_vec2_floor) TEST_ENTRY(glm_vec2_mods) TEST_ENTRY(glm_vec2_steps) TEST_ENTRY(glm_vec2_stepr) TEST_ENTRY(glm_vec2_lerp) TEST_ENTRY(glm_vec2_complex_mul) TEST_ENTRY(glm_vec2_complex_div) TEST_ENTRY(glm_vec2_make) TEST_ENTRY(glm_vec2_reflect) TEST_ENTRY(glm_vec2_refract) TEST_ENTRY(glmc_vec2) TEST_ENTRY(glmc_vec2_copy) TEST_ENTRY(glmc_vec2_zero) TEST_ENTRY(glmc_vec2_one) TEST_ENTRY(glmc_vec2_dot) TEST_ENTRY(glmc_vec2_cross) TEST_ENTRY(glmc_vec2_norm2) TEST_ENTRY(glmc_vec2_norm) TEST_ENTRY(glmc_vec2_add) TEST_ENTRY(glmc_vec2_adds) TEST_ENTRY(glmc_vec2_sub) TEST_ENTRY(glmc_vec2_subs) TEST_ENTRY(glmc_vec2_mul) TEST_ENTRY(glmc_vec2_scale) TEST_ENTRY(glmc_vec2_scale_as) TEST_ENTRY(glmc_vec2_div) TEST_ENTRY(glmc_vec2_divs) TEST_ENTRY(glmc_vec2_addadd) TEST_ENTRY(glmc_vec2_subadd) TEST_ENTRY(glmc_vec2_muladd) TEST_ENTRY(glmc_vec2_muladds) TEST_ENTRY(glmc_vec2_maxadd) TEST_ENTRY(glmc_vec2_minadd) TEST_ENTRY(glmc_vec2_subsub) TEST_ENTRY(glmc_vec2_addsub) TEST_ENTRY(glmc_vec2_mulsub) TEST_ENTRY(glmc_vec2_mulsubs) TEST_ENTRY(glmc_vec2_maxsub) TEST_ENTRY(glmc_vec2_minsub) TEST_ENTRY(glmc_vec2_negate_to) TEST_ENTRY(glmc_vec2_negate) TEST_ENTRY(glmc_vec2_normalize) TEST_ENTRY(glmc_vec2_normalize_to) TEST_ENTRY(glmc_vec2_rotate) TEST_ENTRY(glmc_vec2_center) TEST_ENTRY(glmc_vec2_distance2) TEST_ENTRY(glmc_vec2_distance) TEST_ENTRY(glmc_vec2_maxv) TEST_ENTRY(glmc_vec2_minv) TEST_ENTRY(glmc_vec2_clamp) TEST_ENTRY(glmc_vec2_abs) TEST_ENTRY(glmc_vec2_fract) TEST_ENTRY(glmc_vec2_floor) TEST_ENTRY(glmc_vec2_mods) TEST_ENTRY(glmc_vec2_steps) TEST_ENTRY(glmc_vec2_stepr) TEST_ENTRY(glmc_vec2_lerp) TEST_ENTRY(glmc_vec2_complex_mul) TEST_ENTRY(glmc_vec2_complex_div) TEST_ENTRY(glmc_vec2_make) TEST_ENTRY(glmc_vec2_reflect) TEST_ENTRY(glmc_vec2_refract) /* vec3 */ TEST_ENTRY(MACRO_GLM_VEC3_ONE_INIT) TEST_ENTRY(MACRO_GLM_VEC3_ZERO_INIT) TEST_ENTRY(MACRO_GLM_VEC3_ONE) TEST_ENTRY(MACRO_GLM_VEC3_ZERO) TEST_ENTRY(MACRO_GLM_YUP) TEST_ENTRY(MACRO_GLM_ZUP) TEST_ENTRY(MACRO_GLM_XUP) TEST_ENTRY(MACRO_GLM_FORWARD_RH) TEST_ENTRY(MACRO_GLM_SHUFFLE3) TEST_ENTRY(MACRO_GLM_XXX) TEST_ENTRY(MACRO_GLM_YYY) TEST_ENTRY(MACRO_GLM_ZZZ) TEST_ENTRY(MACRO_GLM_ZYX) TEST_ENTRY(MACRO_glm_vec3_dup) TEST_ENTRY(MACRO_glm_vec3_flipsign) TEST_ENTRY(MACRO_glm_vec3_flipsign_to) TEST_ENTRY(MACRO_glm_vec3_inv) TEST_ENTRY(MACRO_glm_vec3_inv_to) TEST_ENTRY(MACRO_glm_vec3_mulv) TEST_ENTRY(glm_vec3) TEST_ENTRY(glm_vec3_copy) TEST_ENTRY(glm_vec3_zero) TEST_ENTRY(glm_vec3_one) TEST_ENTRY(glm_vec3_dot) TEST_ENTRY(glm_dot) TEST_ENTRY(glm_vec3_norm2) TEST_ENTRY(glm_vec3_norm) TEST_ENTRY(glm_vec3_norm_one) TEST_ENTRY(glm_vec3_norm_inf) TEST_ENTRY(glm_vec3_add) TEST_ENTRY(glm_vec3_adds) TEST_ENTRY(glm_vec3_sub) TEST_ENTRY(glm_vec3_subs) TEST_ENTRY(glm_vec3_mul) TEST_ENTRY(glm_vec3_scale) TEST_ENTRY(glm_vec3_scale_as) TEST_ENTRY(glm_vec3_div) TEST_ENTRY(glm_vec3_divs) TEST_ENTRY(glm_vec3_addadd) TEST_ENTRY(glm_vec3_subadd) TEST_ENTRY(glm_vec3_muladd) TEST_ENTRY(glm_vec3_muladds) TEST_ENTRY(glm_vec3_maxadd) TEST_ENTRY(glm_vec3_minadd) TEST_ENTRY(glm_vec3_subsub) TEST_ENTRY(glm_vec3_addsub) TEST_ENTRY(glm_vec3_mulsub) TEST_ENTRY(glm_vec3_mulsubs) TEST_ENTRY(glm_vec3_maxsub) TEST_ENTRY(glm_vec3_minsub) TEST_ENTRY(glm_vec3_negate_to) TEST_ENTRY(glm_vec3_negate) TEST_ENTRY(glm_vec3_normalize) TEST_ENTRY(glm_vec3_normalize_to) TEST_ENTRY(glm_normalize) TEST_ENTRY(glm_normalize_to) TEST_ENTRY(glm_vec3_cross) TEST_ENTRY(glm_vec3_crossn) TEST_ENTRY(glm_cross) TEST_ENTRY(glm_vec3_angle) TEST_ENTRY(glm_vec3_rotate) TEST_ENTRY(glm_vec3_rotate_m4) TEST_ENTRY(glm_vec3_rotate_m3) TEST_ENTRY(glm_vec3_proj) TEST_ENTRY(glm_vec3_center) TEST_ENTRY(glmc_vec3_distance2) TEST_ENTRY(glmc_vec3_distance) TEST_ENTRY(glm_vec3_maxv) TEST_ENTRY(glm_vec3_minv) TEST_ENTRY(glm_vec3_ortho) TEST_ENTRY(glm_vec3_clamp) TEST_ENTRY(glm_vec3_mix) TEST_ENTRY(glm_vec3_mixc) TEST_ENTRY(glm_vec3_step) TEST_ENTRY(glm_vec3_smoothstep_uni) TEST_ENTRY(glm_vec3_smoothstep) TEST_ENTRY(glm_vec3_smoothinterp) TEST_ENTRY(glm_vec3_smoothinterpc) TEST_ENTRY(glm_vec3_swizzle) TEST_ENTRY(glm_vec3_broadcast) TEST_ENTRY(glm_vec3_fill) TEST_ENTRY(glm_vec3_eq) TEST_ENTRY(glm_vec3_eq_eps) TEST_ENTRY(glm_vec3_eq_all) TEST_ENTRY(glm_vec3_eqv) TEST_ENTRY(glm_vec3_eqv_eps) TEST_ENTRY(glm_vec3_max) TEST_ENTRY(glm_vec3_min) TEST_ENTRY(glm_vec3_isnan) TEST_ENTRY(glm_vec3_isinf) TEST_ENTRY(glm_vec3_isvalid) TEST_ENTRY(glm_vec3_sign) TEST_ENTRY(glm_vec3_abs) TEST_ENTRY(glm_vec3_fract) TEST_ENTRY(glm_vec3_floor) TEST_ENTRY(glm_vec3_mods) TEST_ENTRY(glm_vec3_steps) TEST_ENTRY(glm_vec3_stepr) TEST_ENTRY(glm_vec3_hadd) TEST_ENTRY(glm_vec3_sqrt) TEST_ENTRY(glm_vec3_make) TEST_ENTRY(glm_vec3_faceforward) TEST_ENTRY(glm_vec3_reflect) TEST_ENTRY(glm_vec3_refract) TEST_ENTRY(glmc_vec3) TEST_ENTRY(glmc_vec3_copy) TEST_ENTRY(glmc_vec3_zero) TEST_ENTRY(glmc_vec3_one) TEST_ENTRY(glmc_vec3_dot) TEST_ENTRY(glmc_vec3_norm2) TEST_ENTRY(glmc_vec3_norm) TEST_ENTRY(glmc_vec3_norm_one) TEST_ENTRY(glmc_vec3_norm_inf) TEST_ENTRY(glmc_vec3_add) TEST_ENTRY(glmc_vec3_adds) TEST_ENTRY(glmc_vec3_sub) TEST_ENTRY(glmc_vec3_subs) TEST_ENTRY(glmc_vec3_mul) TEST_ENTRY(glmc_vec3_scale) TEST_ENTRY(glmc_vec3_scale_as) TEST_ENTRY(glmc_vec3_div) TEST_ENTRY(glmc_vec3_divs) TEST_ENTRY(glmc_vec3_addadd) TEST_ENTRY(glmc_vec3_subadd) TEST_ENTRY(glmc_vec3_muladd) TEST_ENTRY(glmc_vec3_muladds) TEST_ENTRY(glmc_vec3_maxadd) TEST_ENTRY(glmc_vec3_minadd) TEST_ENTRY(glmc_vec3_subsub) TEST_ENTRY(glmc_vec3_addsub) TEST_ENTRY(glmc_vec3_mulsub) TEST_ENTRY(glmc_vec3_mulsubs) TEST_ENTRY(glmc_vec3_maxsub) TEST_ENTRY(glmc_vec3_minsub) TEST_ENTRY(glmc_vec3_negate_to) TEST_ENTRY(glmc_vec3_negate) TEST_ENTRY(glmc_vec3_normalize) TEST_ENTRY(glmc_vec3_normalize_to) TEST_ENTRY(glmc_vec3_cross) TEST_ENTRY(glmc_vec3_crossn) TEST_ENTRY(glmc_vec3_angle) TEST_ENTRY(glmc_vec3_rotate) TEST_ENTRY(glmc_vec3_rotate_m4) TEST_ENTRY(glmc_vec3_rotate_m3) TEST_ENTRY(glmc_vec3_proj) TEST_ENTRY(glmc_vec3_center) TEST_ENTRY(glmc_vec3_distance2) TEST_ENTRY(glmc_vec3_distance) TEST_ENTRY(glmc_vec3_maxv) TEST_ENTRY(glmc_vec3_minv) TEST_ENTRY(glmc_vec3_ortho) TEST_ENTRY(glmc_vec3_clamp) TEST_ENTRY(glmc_vec3_mix) TEST_ENTRY(glmc_vec3_mixc) TEST_ENTRY(glmc_vec3_step) TEST_ENTRY(glmc_vec3_smoothstep_uni) TEST_ENTRY(glmc_vec3_smoothstep) TEST_ENTRY(glmc_vec3_smoothinterp) TEST_ENTRY(glmc_vec3_smoothinterpc) TEST_ENTRY(glmc_vec3_swizzle) TEST_ENTRY(glmc_vec3_broadcast) TEST_ENTRY(glmc_vec3_fill) TEST_ENTRY(glmc_vec3_eq) TEST_ENTRY(glmc_vec3_eq_eps) TEST_ENTRY(glmc_vec3_eq_all) TEST_ENTRY(glmc_vec3_eqv) TEST_ENTRY(glmc_vec3_eqv_eps) TEST_ENTRY(glmc_vec3_max) TEST_ENTRY(glmc_vec3_min) TEST_ENTRY(glmc_vec3_isnan) TEST_ENTRY(glmc_vec3_isinf) TEST_ENTRY(glmc_vec3_isvalid) TEST_ENTRY(glmc_vec3_sign) TEST_ENTRY(glmc_vec3_abs) TEST_ENTRY(glmc_vec3_fract) TEST_ENTRY(glmc_vec3_floor) TEST_ENTRY(glmc_vec3_mods) TEST_ENTRY(glmc_vec3_steps) TEST_ENTRY(glmc_vec3_stepr) TEST_ENTRY(glmc_vec3_hadd) TEST_ENTRY(glmc_vec3_sqrt) TEST_ENTRY(glmc_vec3_make) TEST_ENTRY(glmc_vec3_faceforward) TEST_ENTRY(glmc_vec3_reflect) TEST_ENTRY(glmc_vec3_refract) /* vec4 */ TEST_ENTRY(MACRO_GLM_VEC4_ONE_INIT) TEST_ENTRY(MACRO_GLM_VEC4_ZERO_INIT) TEST_ENTRY(MACRO_GLM_VEC4_ONE) TEST_ENTRY(MACRO_GLM_VEC4_ZERO) TEST_ENTRY(MACRO_GLM_XXXX) TEST_ENTRY(MACRO_GLM_YYYY) TEST_ENTRY(MACRO_GLM_ZZZZ) TEST_ENTRY(MACRO_GLM_WZYX) TEST_ENTRY(MACRO_glm_vec4_dup) TEST_ENTRY(MACRO_glm_vec4_flipsign) TEST_ENTRY(MACRO_glm_vec4_flipsign_to) TEST_ENTRY(MACRO_glm_vec4_inv) TEST_ENTRY(MACRO_glm_vec4_inv_to) TEST_ENTRY(MACRO_glm_vec4_mulv) TEST_ENTRY(glm_vec4) TEST_ENTRY(glm_vec4_copy3) TEST_ENTRY(glm_vec4_copy) TEST_ENTRY(glm_vec4_ucopy) TEST_ENTRY(glm_vec4_zero) TEST_ENTRY(glm_vec4_one) TEST_ENTRY(glm_vec4_dot) TEST_ENTRY(glm_vec4_norm2) TEST_ENTRY(glm_vec4_norm) TEST_ENTRY(glm_vec4_norm_one) TEST_ENTRY(glm_vec4_norm_inf) TEST_ENTRY(glm_vec4_add) TEST_ENTRY(glm_vec4_adds) TEST_ENTRY(glm_vec4_sub) TEST_ENTRY(glm_vec4_subs) TEST_ENTRY(glm_vec4_mul) TEST_ENTRY(glm_vec4_scale) TEST_ENTRY(glm_vec4_scale_as) TEST_ENTRY(glm_vec4_div) TEST_ENTRY(glm_vec4_divs) TEST_ENTRY(glm_vec4_addadd) TEST_ENTRY(glm_vec4_subadd) TEST_ENTRY(glm_vec4_muladd) TEST_ENTRY(glm_vec4_muladds) TEST_ENTRY(glm_vec4_maxadd) TEST_ENTRY(glm_vec4_minadd) TEST_ENTRY(glm_vec4_subsub) TEST_ENTRY(glm_vec4_addsub) TEST_ENTRY(glm_vec4_mulsub) TEST_ENTRY(glm_vec4_mulsubs) TEST_ENTRY(glm_vec4_maxsub) TEST_ENTRY(glm_vec4_minsub) TEST_ENTRY(glm_vec4_negate_to) TEST_ENTRY(glm_vec4_negate) TEST_ENTRY(glm_vec4_normalize) TEST_ENTRY(glm_vec4_normalize_to) TEST_ENTRY(glm_vec4_distance2) TEST_ENTRY(glm_vec4_distance) TEST_ENTRY(glm_vec4_maxv) TEST_ENTRY(glm_vec4_minv) TEST_ENTRY(glm_vec4_clamp) TEST_ENTRY(glm_vec4_lerp) TEST_ENTRY(glm_vec4_lerpc) TEST_ENTRY(glm_vec4_mix) TEST_ENTRY(glm_vec4_mixc) TEST_ENTRY(glm_vec4_step) TEST_ENTRY(glm_vec4_smoothstep_uni) TEST_ENTRY(glm_vec4_smoothstep) TEST_ENTRY(glm_vec4_smoothinterp) TEST_ENTRY(glm_vec4_smoothinterpc) TEST_ENTRY(glm_vec4_cubic) TEST_ENTRY(glm_vec4_swizzle) TEST_ENTRY(glm_vec4_broadcast) TEST_ENTRY(glm_vec4_fill) TEST_ENTRY(glm_vec4_eq) TEST_ENTRY(glm_vec4_eq_eps) TEST_ENTRY(glm_vec4_eq_all) TEST_ENTRY(glm_vec4_eqv) TEST_ENTRY(glm_vec4_eqv_eps) TEST_ENTRY(glm_vec4_max) TEST_ENTRY(glm_vec4_min) TEST_ENTRY(glm_vec4_isnan) TEST_ENTRY(glm_vec4_isinf) TEST_ENTRY(glm_vec4_isvalid) TEST_ENTRY(glm_vec4_sign) TEST_ENTRY(glm_vec4_abs) TEST_ENTRY(glm_vec4_fract) TEST_ENTRY(glm_vec4_floor) TEST_ENTRY(glm_vec4_mods) TEST_ENTRY(glm_vec4_steps) TEST_ENTRY(glm_vec4_stepr) TEST_ENTRY(glm_vec4_hadd) TEST_ENTRY(glm_vec4_sqrt) TEST_ENTRY(glm_vec4_make) TEST_ENTRY(glm_vec4_reflect) TEST_ENTRY(glm_vec4_refract) TEST_ENTRY(glmc_vec4) TEST_ENTRY(glmc_vec4_copy3) TEST_ENTRY(glmc_vec4_copy) TEST_ENTRY(glmc_vec4_ucopy) TEST_ENTRY(glmc_vec4_zero) TEST_ENTRY(glmc_vec4_one) TEST_ENTRY(glmc_vec4_dot) TEST_ENTRY(glmc_vec4_norm2) TEST_ENTRY(glmc_vec4_norm) TEST_ENTRY(glmc_vec4_norm_one) TEST_ENTRY(glmc_vec4_norm_inf) TEST_ENTRY(glmc_vec4_add) TEST_ENTRY(glmc_vec4_adds) TEST_ENTRY(glmc_vec4_sub) TEST_ENTRY(glmc_vec4_subs) TEST_ENTRY(glmc_vec4_mul) TEST_ENTRY(glmc_vec4_scale) TEST_ENTRY(glmc_vec4_scale_as) TEST_ENTRY(glmc_vec4_div) TEST_ENTRY(glmc_vec4_divs) TEST_ENTRY(glmc_vec4_addadd) TEST_ENTRY(glmc_vec4_subadd) TEST_ENTRY(glmc_vec4_muladd) TEST_ENTRY(glmc_vec4_muladds) TEST_ENTRY(glmc_vec4_maxadd) TEST_ENTRY(glmc_vec4_minadd) TEST_ENTRY(glmc_vec4_subsub) TEST_ENTRY(glmc_vec4_addsub) TEST_ENTRY(glmc_vec4_mulsub) TEST_ENTRY(glmc_vec4_mulsubs) TEST_ENTRY(glmc_vec4_maxsub) TEST_ENTRY(glmc_vec4_minsub) TEST_ENTRY(glmc_vec4_negate_to) TEST_ENTRY(glmc_vec4_negate) TEST_ENTRY(glmc_vec4_normalize) TEST_ENTRY(glmc_vec4_normalize_to) TEST_ENTRY(glmc_vec4_distance2) TEST_ENTRY(glmc_vec4_distance) TEST_ENTRY(glmc_vec4_maxv) TEST_ENTRY(glmc_vec4_minv) TEST_ENTRY(glmc_vec4_clamp) TEST_ENTRY(glmc_vec4_lerp) TEST_ENTRY(glmc_vec4_lerpc) TEST_ENTRY(glmc_vec4_mix) TEST_ENTRY(glmc_vec4_mixc) TEST_ENTRY(glmc_vec4_step) TEST_ENTRY(glmc_vec4_smoothstep_uni) TEST_ENTRY(glmc_vec4_smoothstep) TEST_ENTRY(glmc_vec4_smoothinterp) TEST_ENTRY(glmc_vec4_smoothinterpc) TEST_ENTRY(glmc_vec4_cubic) TEST_ENTRY(glmc_vec4_swizzle) TEST_ENTRY(glmc_vec4_broadcast) TEST_ENTRY(glmc_vec4_fill) TEST_ENTRY(glmc_vec4_eq) TEST_ENTRY(glmc_vec4_eq_eps) TEST_ENTRY(glmc_vec4_eq_all) TEST_ENTRY(glmc_vec4_eqv) TEST_ENTRY(glmc_vec4_eqv_eps) TEST_ENTRY(glmc_vec4_max) TEST_ENTRY(glmc_vec4_min) TEST_ENTRY(glmc_vec4_isnan) TEST_ENTRY(glmc_vec4_isinf) TEST_ENTRY(glmc_vec4_isvalid) TEST_ENTRY(glmc_vec4_sign) TEST_ENTRY(glmc_vec4_abs) TEST_ENTRY(glmc_vec4_fract) TEST_ENTRY(glmc_vec4_floor) TEST_ENTRY(glmc_vec4_mods) TEST_ENTRY(glmc_vec4_steps) TEST_ENTRY(glmc_vec4_stepr) TEST_ENTRY(glmc_vec4_hadd) TEST_ENTRY(glmc_vec4_sqrt) TEST_ENTRY(glmc_vec4_make) TEST_ENTRY(glmc_vec4_reflect) TEST_ENTRY(glmc_vec4_refract) /* ivec2 */ TEST_ENTRY(glm_ivec2) TEST_ENTRY(glm_ivec2_copy) TEST_ENTRY(glm_ivec2_zero) TEST_ENTRY(glm_ivec2_one) TEST_ENTRY(glm_ivec2_dot) TEST_ENTRY(glm_ivec2_cross) TEST_ENTRY(glm_ivec2_add) TEST_ENTRY(glm_ivec2_adds) TEST_ENTRY(glm_ivec2_sub) TEST_ENTRY(glm_ivec2_subs) TEST_ENTRY(glm_ivec2_mul) TEST_ENTRY(glm_ivec2_scale) TEST_ENTRY(glm_ivec2_div) TEST_ENTRY(glm_ivec2_divs) TEST_ENTRY(glm_ivec2_mod) TEST_ENTRY(glm_ivec2_addadd) TEST_ENTRY(glm_ivec2_addadds) TEST_ENTRY(glm_ivec2_subadd) TEST_ENTRY(glm_ivec2_subadds) TEST_ENTRY(glm_ivec2_muladd) TEST_ENTRY(glm_ivec2_muladds) TEST_ENTRY(glm_ivec2_maxadd) TEST_ENTRY(glm_ivec2_minadd) TEST_ENTRY(glm_ivec2_subsub) TEST_ENTRY(glm_ivec2_subsubs) TEST_ENTRY(glm_ivec2_addsub) TEST_ENTRY(glm_ivec2_addsubs) TEST_ENTRY(glm_ivec2_mulsub) TEST_ENTRY(glm_ivec2_mulsubs) TEST_ENTRY(glm_ivec2_maxsub) TEST_ENTRY(glm_ivec2_minsub) TEST_ENTRY(glm_ivec2_distance2) TEST_ENTRY(glm_ivec2_distance) TEST_ENTRY(glm_ivec2_fill) TEST_ENTRY(glm_ivec2_eq) TEST_ENTRY(glm_ivec2_eqv) TEST_ENTRY(glm_ivec2_maxv) TEST_ENTRY(glm_ivec2_minv) TEST_ENTRY(glm_ivec2_clamp) TEST_ENTRY(glm_ivec2_abs) TEST_ENTRY(glmc_ivec2) TEST_ENTRY(glmc_ivec2_copy) TEST_ENTRY(glmc_ivec2_zero) TEST_ENTRY(glmc_ivec2_one) TEST_ENTRY(glmc_ivec2_dot) TEST_ENTRY(glmc_ivec2_cross) TEST_ENTRY(glmc_ivec2_add) TEST_ENTRY(glmc_ivec2_adds) TEST_ENTRY(glmc_ivec2_sub) TEST_ENTRY(glmc_ivec2_subs) TEST_ENTRY(glmc_ivec2_mul) TEST_ENTRY(glmc_ivec2_scale) TEST_ENTRY(glmc_ivec2_div) TEST_ENTRY(glmc_ivec2_divs) TEST_ENTRY(glmc_ivec2_mod) TEST_ENTRY(glmc_ivec2_addadd) TEST_ENTRY(glmc_ivec2_addadds) TEST_ENTRY(glmc_ivec2_subadd) TEST_ENTRY(glmc_ivec2_subadds) TEST_ENTRY(glmc_ivec2_muladd) TEST_ENTRY(glmc_ivec2_muladds) TEST_ENTRY(glmc_ivec2_maxadd) TEST_ENTRY(glmc_ivec2_minadd) TEST_ENTRY(glmc_ivec2_subsub) TEST_ENTRY(glmc_ivec2_subsubs) TEST_ENTRY(glmc_ivec2_addsub) TEST_ENTRY(glmc_ivec2_addsubs) TEST_ENTRY(glmc_ivec2_mulsub) TEST_ENTRY(glmc_ivec2_mulsubs) TEST_ENTRY(glmc_ivec2_maxsub) TEST_ENTRY(glmc_ivec2_minsub) TEST_ENTRY(glmc_ivec2_distance2) TEST_ENTRY(glmc_ivec2_distance) TEST_ENTRY(glmc_ivec2_fill) TEST_ENTRY(glmc_ivec2_eq) TEST_ENTRY(glmc_ivec2_eqv) TEST_ENTRY(glmc_ivec2_maxv) TEST_ENTRY(glmc_ivec2_minv) TEST_ENTRY(glmc_ivec2_clamp) TEST_ENTRY(glmc_ivec2_abs) /* ivec3 */ TEST_ENTRY(glm_ivec3) TEST_ENTRY(glm_ivec3_copy) TEST_ENTRY(glm_ivec3_zero) TEST_ENTRY(glm_ivec3_one) TEST_ENTRY(glm_ivec3_dot) TEST_ENTRY(glm_ivec3_norm2) TEST_ENTRY(glm_ivec3_norm) TEST_ENTRY(glm_ivec3_add) TEST_ENTRY(glm_ivec3_adds) TEST_ENTRY(glm_ivec3_sub) TEST_ENTRY(glm_ivec3_subs) TEST_ENTRY(glm_ivec3_mul) TEST_ENTRY(glm_ivec3_scale) TEST_ENTRY(glm_ivec3_div) TEST_ENTRY(glm_ivec3_divs) TEST_ENTRY(glm_ivec3_mod) TEST_ENTRY(glm_ivec3_addadd) TEST_ENTRY(glm_ivec3_addadds) TEST_ENTRY(glm_ivec3_subadd) TEST_ENTRY(glm_ivec3_subadds) TEST_ENTRY(glm_ivec3_muladd) TEST_ENTRY(glm_ivec3_muladds) TEST_ENTRY(glm_ivec3_maxadd) TEST_ENTRY(glm_ivec3_minadd) TEST_ENTRY(glm_ivec3_subsub) TEST_ENTRY(glm_ivec3_subsubs) TEST_ENTRY(glm_ivec3_addsub) TEST_ENTRY(glm_ivec3_addsubs) TEST_ENTRY(glm_ivec3_mulsub) TEST_ENTRY(glm_ivec3_mulsubs) TEST_ENTRY(glm_ivec3_maxsub) TEST_ENTRY(glm_ivec3_minsub) TEST_ENTRY(glm_ivec3_distance2) TEST_ENTRY(glm_ivec3_distance) TEST_ENTRY(glm_ivec3_fill) TEST_ENTRY(glm_ivec3_eq) TEST_ENTRY(glm_ivec3_eqv) TEST_ENTRY(glm_ivec3_maxv) TEST_ENTRY(glm_ivec3_minv) TEST_ENTRY(glm_ivec3_clamp) TEST_ENTRY(glmc_ivec3) TEST_ENTRY(glmc_ivec3_copy) TEST_ENTRY(glmc_ivec3_zero) TEST_ENTRY(glmc_ivec3_one) TEST_ENTRY(glmc_ivec3_dot) TEST_ENTRY(glmc_ivec3_norm2) TEST_ENTRY(glmc_ivec3_norm) TEST_ENTRY(glmc_ivec3_add) TEST_ENTRY(glmc_ivec3_adds) TEST_ENTRY(glmc_ivec3_sub) TEST_ENTRY(glmc_ivec3_subs) TEST_ENTRY(glmc_ivec3_mul) TEST_ENTRY(glmc_ivec3_scale) TEST_ENTRY(glmc_ivec3_div) TEST_ENTRY(glmc_ivec3_divs) TEST_ENTRY(glmc_ivec3_mod) TEST_ENTRY(glmc_ivec3_addadd) TEST_ENTRY(glmc_ivec3_addadds) TEST_ENTRY(glmc_ivec3_subadd) TEST_ENTRY(glmc_ivec3_subadds) TEST_ENTRY(glmc_ivec3_muladd) TEST_ENTRY(glmc_ivec3_muladds) TEST_ENTRY(glmc_ivec3_maxadd) TEST_ENTRY(glmc_ivec3_minadd) TEST_ENTRY(glmc_ivec3_subsub) TEST_ENTRY(glmc_ivec3_subsubs) TEST_ENTRY(glmc_ivec3_addsub) TEST_ENTRY(glmc_ivec3_addsubs) TEST_ENTRY(glmc_ivec3_mulsub) TEST_ENTRY(glmc_ivec3_mulsubs) TEST_ENTRY(glmc_ivec3_maxsub) TEST_ENTRY(glmc_ivec3_minsub) TEST_ENTRY(glmc_ivec3_distance2) TEST_ENTRY(glmc_ivec3_distance) TEST_ENTRY(glmc_ivec3_fill) TEST_ENTRY(glmc_ivec3_eq) TEST_ENTRY(glmc_ivec3_eqv) TEST_ENTRY(glmc_ivec3_maxv) TEST_ENTRY(glmc_ivec3_minv) TEST_ENTRY(glmc_ivec3_clamp) /* ivec4 */ TEST_ENTRY(glm_ivec4) TEST_ENTRY(glm_ivec4_copy) TEST_ENTRY(glm_ivec4_zero) TEST_ENTRY(glm_ivec4_one) TEST_ENTRY(glm_ivec4_add) TEST_ENTRY(glm_ivec4_adds) TEST_ENTRY(glm_ivec4_sub) TEST_ENTRY(glm_ivec4_subs) TEST_ENTRY(glm_ivec4_mul) TEST_ENTRY(glm_ivec4_scale) TEST_ENTRY(glm_ivec4_addadd) TEST_ENTRY(glm_ivec4_addadds) TEST_ENTRY(glm_ivec4_subadd) TEST_ENTRY(glm_ivec4_subadds) TEST_ENTRY(glm_ivec4_muladd) TEST_ENTRY(glm_ivec4_muladds) TEST_ENTRY(glm_ivec4_maxadd) TEST_ENTRY(glm_ivec4_minadd) TEST_ENTRY(glm_ivec4_subsub) TEST_ENTRY(glm_ivec4_subsubs) TEST_ENTRY(glm_ivec4_addsub) TEST_ENTRY(glm_ivec4_addsubs) TEST_ENTRY(glm_ivec4_mulsub) TEST_ENTRY(glm_ivec4_mulsubs) TEST_ENTRY(glm_ivec4_maxsub) TEST_ENTRY(glm_ivec4_minsub) TEST_ENTRY(glm_ivec4_distance2) TEST_ENTRY(glm_ivec4_distance) TEST_ENTRY(glm_ivec4_maxv) TEST_ENTRY(glm_ivec4_minv) TEST_ENTRY(glm_ivec4_clamp) TEST_ENTRY(glmc_ivec4) TEST_ENTRY(glmc_ivec4_copy) TEST_ENTRY(glmc_ivec4_zero) TEST_ENTRY(glmc_ivec4_one) TEST_ENTRY(glmc_ivec4_add) TEST_ENTRY(glmc_ivec4_adds) TEST_ENTRY(glmc_ivec4_sub) TEST_ENTRY(glmc_ivec4_subs) TEST_ENTRY(glmc_ivec4_mul) TEST_ENTRY(glmc_ivec4_scale) TEST_ENTRY(glmc_ivec4_addadd) TEST_ENTRY(glmc_ivec4_addadds) TEST_ENTRY(glmc_ivec4_subadd) TEST_ENTRY(glmc_ivec4_subadds) TEST_ENTRY(glmc_ivec4_muladd) TEST_ENTRY(glmc_ivec4_muladds) TEST_ENTRY(glmc_ivec4_maxadd) TEST_ENTRY(glmc_ivec4_minadd) TEST_ENTRY(glmc_ivec4_subsub) TEST_ENTRY(glmc_ivec4_subsubs) TEST_ENTRY(glmc_ivec4_addsub) TEST_ENTRY(glmc_ivec4_addsubs) TEST_ENTRY(glmc_ivec4_mulsub) TEST_ENTRY(glmc_ivec4_mulsubs) TEST_ENTRY(glmc_ivec4_maxsub) TEST_ENTRY(glmc_ivec4_minsub) TEST_ENTRY(glmc_ivec4_distance2) TEST_ENTRY(glmc_ivec4_distance) TEST_ENTRY(glmc_ivec4_maxv) TEST_ENTRY(glmc_ivec4_minv) TEST_ENTRY(glmc_ivec4_clamp) TEST_ENTRY(glmc_ivec4_abs) /* structs */ TEST_ENTRY(mat2x3s_zero_init) TEST_ENTRY(mat2x3s_zero) TEST_ENTRY(mat2x4s_zero_init) TEST_ENTRY(mat2x4s_zero) TEST_ENTRY(mat3s_identity_init) TEST_ENTRY(mat3s_zero_init) TEST_ENTRY(mat3x2s_zero_init) TEST_ENTRY(mat3x2s_zero) TEST_ENTRY(mat3x4s_zero_init) TEST_ENTRY(mat3x4s_zero) TEST_ENTRY(mat4s_spin) TEST_ENTRY(mat4s_identity_init) TEST_ENTRY(mat4s_zero_init) TEST_ENTRY(mat4x2s_zero_init) TEST_ENTRY(mat4x2s_zero) TEST_ENTRY(mat4x3s_zero_init) TEST_ENTRY(mat4x3s_zero) TEST_ENTRY(quats_zero_init) TEST_ENTRY(quats_mat_nonunit) TEST_ENTRY(vec3s_one_init) TEST_ENTRY(vec3s_zero_init) TEST_ENTRY(vec4s_black_init) TEST_ENTRY(vec4s_one_init) TEST_ENTRY(vec4s_zero_init) }; #endif /* tests_h */ cglm-0.9.7/win/000077500000000000000000000000001526744317200132615ustar00rootroot00000000000000cglm-0.9.7/win/.gitignore000066400000000000000000000001601526744317200152460ustar00rootroot00000000000000!cglm.sln !cglm.vcxproj !cglm.vcxproj.filters !cglm-test.vcxproj !cglm-test.vcxproj.filters !packages.config cglm-0.9.7/win/build.bat000077500000000000000000000000561526744317200150540ustar00rootroot00000000000000msbuild cglm.vcxproj /p:Configuration=Release cglm-0.9.7/win/cglm-test.vcxproj000066400000000000000000000532321526744317200166020ustar00rootroot00000000000000 Debug ARM Debug ARM64 Debug ARM64EC Debug Win32 Release ARM Release ARM64 Release ARM64EC Release Win32 Debug x64 Release x64 {ca8bcaf9-cd25-4133-8f62-3d1449b5d2fc} 16.0 {200E0DF1-7532-44E6-8273-84FB92C5557E} Win32Proj cglmtest 10.0 Application true v142 Unicode Application false v142 true Unicode Application true v142 Unicode Application true v142 Unicode Application true v142 Unicode Application true v142 Unicode Application false v142 true Unicode Application false v142 true Unicode Application false v142 true Unicode Application false v142 true Unicode false false false false true true true true true false Level3 MaxSpeed true true true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true ../include;%(AdditionalIncludeDirectories) Console true true true %(AdditionalDependencies) Level3 MaxSpeed true true true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true ../include;%(AdditionalIncludeDirectories) Console true true true %(AdditionalDependencies) Level3 MaxSpeed true true true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true ../include;%(AdditionalIncludeDirectories) Console true true true %(AdditionalDependencies) Level3 MaxSpeed true true true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true ../include;%(AdditionalIncludeDirectories) Console true true true %(AdditionalDependencies) Level3 Disabled true WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true ../include;%(AdditionalIncludeDirectories) Default Console true %(AdditionalDependencies) Level3 Disabled true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true ../include;%(AdditionalIncludeDirectories) Default Console true %(AdditionalDependencies) Level3 Disabled true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true ../include;%(AdditionalIncludeDirectories) Default Console true %(AdditionalDependencies) Level3 Disabled true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true ../include;%(AdditionalIncludeDirectories) Default Console true %(AdditionalDependencies) Level3 Disabled true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true ../include;%(AdditionalIncludeDirectories) Default Console true %(AdditionalDependencies) Level3 MaxSpeed true true true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true ../include;%(AdditionalIncludeDirectories) Console true true true %(AdditionalDependencies) cglm-0.9.7/win/cglm-test.vcxproj.filters000066400000000000000000000112711526744317200202460ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;ipp;xsd src src src src src src src include include include src src src src src src src src src src src src src src src src src src src src src src src src src src src src src src src src cglm-0.9.7/win/cglm.sln000066400000000000000000000102411526744317200147170ustar00rootroot00000000000000 Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.29123.88 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cglm", "cglm.vcxproj", "{CA8BCAF9-CD25-4133-8F62-3D1449B5D2FC}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cglm-test", "cglm-test.vcxproj", "{200E0DF1-7532-44E6-8273-84FB92C5557E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM = Debug|ARM Debug|ARM64 = Debug|ARM64 Debug|ARM64EC = Debug|ARM64EC Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|ARM = Release|ARM Release|ARM64 = Release|ARM64 Release|ARM64EC = Release|ARM64EC Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {CA8BCAF9-CD25-4133-8F62-3D1449B5D2FC}.Debug|ARM.ActiveCfg = Debug|ARM {CA8BCAF9-CD25-4133-8F62-3D1449B5D2FC}.Debug|ARM.Build.0 = Debug|ARM {CA8BCAF9-CD25-4133-8F62-3D1449B5D2FC}.Debug|ARM64.ActiveCfg = Debug|ARM64 {CA8BCAF9-CD25-4133-8F62-3D1449B5D2FC}.Debug|ARM64.Build.0 = Debug|ARM64 {CA8BCAF9-CD25-4133-8F62-3D1449B5D2FC}.Debug|ARM64EC.ActiveCfg = Debug|ARM64EC {CA8BCAF9-CD25-4133-8F62-3D1449B5D2FC}.Debug|ARM64EC.Build.0 = Debug|ARM64EC {CA8BCAF9-CD25-4133-8F62-3D1449B5D2FC}.Debug|x64.ActiveCfg = Debug|x64 {CA8BCAF9-CD25-4133-8F62-3D1449B5D2FC}.Debug|x64.Build.0 = Debug|x64 {CA8BCAF9-CD25-4133-8F62-3D1449B5D2FC}.Debug|x86.ActiveCfg = Debug|Win32 {CA8BCAF9-CD25-4133-8F62-3D1449B5D2FC}.Debug|x86.Build.0 = Debug|Win32 {CA8BCAF9-CD25-4133-8F62-3D1449B5D2FC}.Release|ARM.ActiveCfg = Release|ARM {CA8BCAF9-CD25-4133-8F62-3D1449B5D2FC}.Release|ARM.Build.0 = Release|ARM {CA8BCAF9-CD25-4133-8F62-3D1449B5D2FC}.Release|ARM64.ActiveCfg = Release|ARM64 {CA8BCAF9-CD25-4133-8F62-3D1449B5D2FC}.Release|ARM64.Build.0 = Release|ARM64 {CA8BCAF9-CD25-4133-8F62-3D1449B5D2FC}.Release|ARM64EC.ActiveCfg = Release|ARM64EC {CA8BCAF9-CD25-4133-8F62-3D1449B5D2FC}.Release|ARM64EC.Build.0 = Release|ARM64EC {CA8BCAF9-CD25-4133-8F62-3D1449B5D2FC}.Release|x64.ActiveCfg = Release|x64 {CA8BCAF9-CD25-4133-8F62-3D1449B5D2FC}.Release|x64.Build.0 = Release|x64 {CA8BCAF9-CD25-4133-8F62-3D1449B5D2FC}.Release|x86.ActiveCfg = Release|Win32 {CA8BCAF9-CD25-4133-8F62-3D1449B5D2FC}.Release|x86.Build.0 = Release|Win32 {200E0DF1-7532-44E6-8273-84FB92C5557E}.Debug|ARM.ActiveCfg = Debug|ARM {200E0DF1-7532-44E6-8273-84FB92C5557E}.Debug|ARM.Build.0 = Debug|ARM {200E0DF1-7532-44E6-8273-84FB92C5557E}.Debug|ARM64.ActiveCfg = Debug|ARM64 {200E0DF1-7532-44E6-8273-84FB92C5557E}.Debug|ARM64.Build.0 = Debug|ARM64 {200E0DF1-7532-44E6-8273-84FB92C5557E}.Debug|ARM64EC.ActiveCfg = Debug|ARM64EC {200E0DF1-7532-44E6-8273-84FB92C5557E}.Debug|ARM64EC.Build.0 = Debug|ARM64EC {200E0DF1-7532-44E6-8273-84FB92C5557E}.Debug|x64.ActiveCfg = Debug|x64 {200E0DF1-7532-44E6-8273-84FB92C5557E}.Debug|x64.Build.0 = Debug|x64 {200E0DF1-7532-44E6-8273-84FB92C5557E}.Debug|x86.ActiveCfg = Debug|Win32 {200E0DF1-7532-44E6-8273-84FB92C5557E}.Debug|x86.Build.0 = Debug|Win32 {200E0DF1-7532-44E6-8273-84FB92C5557E}.Release|ARM.ActiveCfg = Release|ARM {200E0DF1-7532-44E6-8273-84FB92C5557E}.Release|ARM.Build.0 = Release|ARM {200E0DF1-7532-44E6-8273-84FB92C5557E}.Release|ARM64.ActiveCfg = Release|ARM64 {200E0DF1-7532-44E6-8273-84FB92C5557E}.Release|ARM64.Build.0 = Release|ARM64 {200E0DF1-7532-44E6-8273-84FB92C5557E}.Release|ARM64EC.ActiveCfg = Release|ARM64EC {200E0DF1-7532-44E6-8273-84FB92C5557E}.Release|ARM64EC.Build.0 = Release|ARM64EC {200E0DF1-7532-44E6-8273-84FB92C5557E}.Release|x64.ActiveCfg = Release|x64 {200E0DF1-7532-44E6-8273-84FB92C5557E}.Release|x64.Build.0 = Release|x64 {200E0DF1-7532-44E6-8273-84FB92C5557E}.Release|x86.ActiveCfg = Release|Win32 {200E0DF1-7532-44E6-8273-84FB92C5557E}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {2AEF23C9-433B-428B-BEBC-068BF3AC9A65} EndGlobalSection EndGlobal cglm-0.9.7/win/cglm.vcxproj000066400000000000000000001027331526744317200156260ustar00rootroot00000000000000 Debug ARM Debug ARM64 Debug ARM64EC Debug Win32 Release ARM Release ARM64 Release ARM64EC Release Win32 Debug x64 Release x64 15.0 {CA8BCAF9-CD25-4133-8F62-3D1449B5D2FC} Win32Proj cglm 10.0 DynamicLibrary true v141 Unicode DynamicLibrary false v141 true Unicode DynamicLibrary true v141 Unicode DynamicLibrary true v141 Unicode DynamicLibrary true v141 Unicode DynamicLibrary true v141 Unicode DynamicLibrary false v141 true Unicode DynamicLibrary false v141 true Unicode DynamicLibrary false v141 true Unicode DynamicLibrary false v141 true Unicode true NativeRecommendedRules.ruleset true NativeRecommendedRules.ruleset true NativeRecommendedRules.ruleset true NativeRecommendedRules.ruleset true NativeRecommendedRules.ruleset true false NativeRecommendedRules.ruleset true false NativeRecommendedRules.ruleset true false NativeRecommendedRules.ruleset true false NativeRecommendedRules.ruleset true false NativeRecommendedRules.ruleset true NotUsing Level3 MaxSpeed WIN32;_DEBUG;_WINDOWS;_USRDLL;CGLM_EXPORTS;%(PreprocessorDefinitions) None Default CompileAsC true true Windows Level3 MaxSpeed _DEBUG;_WINDOWS;_USRDLL;CGLM_EXPORTS;%(PreprocessorDefinitions) AnySuitable true true CompileAsC None Default true Windows Level3 MaxSpeed _DEBUG;_WINDOWS;_USRDLL;CGLM_EXPORTS;%(PreprocessorDefinitions) AnySuitable true true CompileAsC None Default true Windows Level3 MaxSpeed _DEBUG;_WINDOWS;_USRDLL;CGLM_EXPORTS;%(PreprocessorDefinitions) AnySuitable true true CompileAsC None Default true Windows Level3 MaxSpeed _DEBUG;_WINDOWS;_USRDLL;CGLM_EXPORTS;%(PreprocessorDefinitions) AnySuitable true true CompileAsC None Default true Windows Level3 NotUsing MaxSpeed true true WIN32;NDEBUG;_WINDOWS;_USRDLL;CGLM_EXPORTS;%(PreprocessorDefinitions) None CompileAsC true Default Windows true true Level3 NotUsing MaxSpeed true true NDEBUG;_WINDOWS;_USRDLL;CGLM_EXPORTS;%(PreprocessorDefinitions) None CompileAsC true Default Windows true true Level3 NotUsing MaxSpeed true true NDEBUG;_WINDOWS;_USRDLL;CGLM_EXPORTS;%(PreprocessorDefinitions) None CompileAsC true Default Windows true true Level3 NotUsing MaxSpeed true true NDEBUG;_WINDOWS;_USRDLL;CGLM_EXPORTS;%(PreprocessorDefinitions) None CompileAsC true Default Windows true true Level3 NotUsing MaxSpeed true true NDEBUG;_WINDOWS;_USRDLL;CGLM_EXPORTS;%(PreprocessorDefinitions) None CompileAsC true Default Windows true true cglm-0.9.7/win/cglm.vcxproj.filters000066400000000000000000000720601526744317200172740ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {f46634e5-c098-41a0-afb3-45afb6a53593} {b982cbd3-03d9-4557-bed8-8224e4d95945} {6a2a4ebb-ac68-4ed6-a4a1-f6d2243814e9} {4bcb64d3-e522-48f7-85ef-3ddfacf50874} {ccf6244c-614c-4016-a5d9-8a78ffc7765a} {8607b04c-6eb6-49af-8ac2-e534ba78bf76} {fb97f276-fe14-47ba-8a9f-01032f065a19} {0b5febe7-a88d-4330-94ae-305897a5e957} {8044a657-123d-4a0e-8de1-f348fad7dadb} {842a48fc-5c7e-4951-9623-64af96dfb95a} {86101de1-0722-4c88-92a0-e6d71158354e} {98a166bb-ba2d-4649-a20f-ba6bf4ce6383} {24571788-2e78-4969-b66f-065aea5489be} {e6a410e7-83db-41a5-b9fc-34bbfcf46ae5} {BA6FE2A0-1E8D-4FBA-A272-8C0989F28E0D} src src src src src src src src src src src src src src src src src src src src src src src src src src src src\clipspace src\clipspace src\clipspace src\clipspace src\clipspace src\clipspace src\clipspace src\clipspace src\clipspace src\clipspace src\clipspace src\clipspace src\clipspace src\clipspace src src src src src src include\cglm\call include\cglm\call include\cglm\call include\cglm\call include\cglm\call include\cglm\call include\cglm\call include\cglm\call include\cglm\call include\cglm\call include\cglm\call include\cglm\call include\cglm\call include\cglm\call include\cglm\simd\avx include\cglm\simd\avx include\cglm\simd\neon include\cglm\simd\sse2 include\cglm\simd\sse2 include\cglm\simd\sse2 include\cglm\simd\sse2 include\cglm\simd include\cglm include\cglm include\cglm include\cglm include\cglm include\cglm include\cglm include\cglm include\cglm include\cglm include\cglm include\cglm include\cglm include\cglm include\cglm include\cglm include\cglm include\cglm include\cglm include\cglm include\cglm include\cglm include\cglm\call include\cglm\call include\cglm include\cglm include\cglm\call include\cglm include\cglm include\cglm include\cglm\call include\cglm\call include\cglm include\cglm\call include\cglm include\cglm include\cglm\simd include\cglm\simd include\cglm\call include\cglm include\cglm include\cglm\call include\cglm include\cglm\struct include\cglm\struct include\cglm\struct include\cglm\struct include\cglm\struct include\cglm\struct include\cglm\struct include\cglm\struct include\cglm\struct include\cglm\struct include\cglm\struct include\cglm\struct include\cglm\struct include\cglm\struct include\cglm\struct include\cglm\struct include\cglm\struct include\cglm\struct include\cglm\struct include\cglm\struct include\cglm\struct include\cglm\struct include\cglm include\cglm include\cglm\call include\cglm\call include\cglm\call include\cglm\call include\cglm\struct include\cglm\struct include\cglm\struct include\cglm include\cglm include\cglm include\cglm include\cglm include\cglm\struct include\cglm\struct include\cglm\simd\sse2 include\cglm\call include\cglm include\cglm\struct include\cglm\simd\neon include\cglm\simd\neon include\cglm\simd\neon include\cglm\clipspace include\cglm\clipspace include\cglm\clipspace include\cglm\clipspace include\cglm\clipspace include\cglm\clipspace include\cglm\clipspace include\cglm\clipspace include\cglm\clipspace include\cglm\clipspace include\cglm\clipspace include\cglm\clipspace include\cglm\clipspace include\cglm\clipspace include\cglm\clipspace include\cglm\call\clipspace include\cglm\call\clipspace include\cglm\call\clipspace include\cglm\call\clipspace include\cglm\call\clipspace include\cglm\call\clipspace include\cglm\call\clipspace include\cglm\call\clipspace include\cglm\call\clipspace include\cglm\call\clipspace include\cglm\call\clipspace include\cglm\call\clipspace include\cglm\struct\clipspace include\cglm\struct\clipspace include\cglm\struct\clipspace include\cglm\struct\clipspace include\cglm\struct\clipspace include\cglm\struct\clipspace include\cglm\struct\clipspace include\cglm\struct\clipspace include\cglm\struct\clipspace include\cglm\struct\clipspace include\cglm\struct\clipspace include\cglm\struct\clipspace include\cglm\clipspace include\cglm\clipspace include\cglm\call\clipspace include\cglm\call\clipspace include\cglm\call include\cglm\call include\cglm\call include\cglm\struct\clipspace include\cglm\struct\clipspace include\cglm include\cglm include\cglm include\cglm include\cglm include\cglm\struct include\cglm\struct include\cglm\struct include\cglm include\cglm\call include\cglm\simd\wasm include\cglm\simd\wasm include\cglm\simd\wasm include\cglm\simd\wasm include\cglm\simd\wasm include\cglm\simd include\cglm\struct include\cglm\struct\handed include\cglm\struct\handed include\cglm\struct include\cglm\struct include\cglm\struct include\cglm\struct include\cglm include\cglm\call include\cglm\struct include\cglm include\cglm\handed include\cglm\handed