├── .github ├── ISSUE_TEMPLATE │ ├── bug-error-report.md │ └── new-feature-request.md └── workflows │ └── tests.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── examples └── readme.md ├── hapticx.nimble ├── src ├── app │ ├── app.nim │ └── environment.nim ├── core │ ├── animatable.nim │ ├── basis.nim │ ├── color.nim │ ├── core.nim │ ├── enums.nim │ ├── exceptions.nim │ ├── glmanager.nim │ ├── hmacros.nim │ ├── hmath.nim │ ├── input.nim │ ├── mat4.nim │ ├── material.nim │ ├── rect.nim │ ├── vec2.nim │ ├── vec3.nim │ └── vkmanager.nim ├── hapticx.nim ├── nodes │ ├── canvas.nim │ ├── node.nim │ └── scene.nim ├── private │ └── templates.nim └── thirdparty │ ├── opengl.nim │ ├── opengl │ ├── glu.nim │ ├── glut.nim │ ├── glx.nim │ ├── private │ │ ├── constants.nim │ │ ├── errors.nim │ │ ├── prelude.nim │ │ ├── procs.nim │ │ └── types.nim │ └── wingl.nim │ ├── sdl2.nim │ ├── sdl2 │ ├── audio.nim │ ├── gamecontroller.nim │ ├── gfx.nim │ ├── haptic.nim │ ├── image.nim │ ├── joystick.nim │ ├── mixer.nim │ ├── net.nim │ ├── private │ │ └── keycodes.nim │ └── ttf.nim │ ├── vulkan.nim │ ├── webgl.nim │ └── webgl │ ├── consts.nim │ └── enums.nim └── tests ├── assets └── hapticX.png ├── glew ├── include │ └── GL │ │ ├── eglew.h │ │ ├── glew.h │ │ ├── glxew.h │ │ └── wglew.h └── lib │ └── Release │ ├── Win32 │ ├── glew32.lib │ └── glew32s.lib │ └── x64 │ ├── glew32.lib │ └── glew32s.lib ├── min_js.html ├── test1.nim ├── test2.nim ├── test3.nim └── test4.nim /.github/ISSUE_TEMPLATE/bug-error-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug/Error report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. :bug: 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Write '...' :pencil2: 16 | 2. Import '....' :inbox_tray: 17 | 3. Input '....' :black_nib: 18 | 4. See error :boom: 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. :mag: 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. :eyes: 25 | 26 | **Desktop (please complete the following information):** :computer: 27 | - OS [e.g. Linux, Ubuntu] 28 | - Version [e.g. 0.1.5] 29 | 30 | **Smartphone (please complete the following information):** :iphone: 31 | - Device [e.g. Realme] 32 | - OS [e.g. Android 13] 33 | - Version [e.g. 0.1.5] 34 | 35 | **Additional context** 36 | Add any other context about the problem here. :speech_balloon: 37 | 38 | Help us to improve engine :smiley: 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/new-feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: New feature request 3 | about: Suggest an idea for engine 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. :smiley: 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. :question: 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. :bulb: 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. :eyes: 21 | 22 | P.S.: 23 | You can send PR if you want :v: 24 | 25 | Help us to improve engine ^^ 26 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Testing 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'master' 7 | paths-ignore: 8 | - 'docs/**' 9 | - '.github/ISSUE_TEMPLATE/*' 10 | - '*.md' 11 | - '*.nimble' 12 | - '.gitignore' 13 | - 'LICENSE' 14 | 15 | jobs: 16 | before: 17 | runs-on: ubuntu-latest 18 | if: "! contains(github.event.head_commit.message, '[skip ci]')" 19 | steps: 20 | - run: echo "not contains '[skip ci]'" 21 | 22 | UbuntuBuild: 23 | runs-on: ${{ matrix.os }} 24 | strategy: 25 | matrix: 26 | os: 27 | - ubuntu-latest 28 | nim_version: 29 | - '1.0.0' 30 | - '1.2.18' 31 | - '1.4.8' 32 | - 'stable' 33 | needs: before 34 | env: 35 | TIMEOUT_EXIT_STATUS: 124 36 | steps: 37 | - uses: actions/checkout@v3 38 | - name: Cache nimble 39 | id: cache-nimble 40 | uses: actions/cache@v3 41 | with: 42 | path: ~/.nimble 43 | key: ${{ runner.os }}-nimble-${{ hashFiles('*.nimble') }} 44 | - uses: jiro4989/setup-nim-action@v1 45 | with: 46 | nim-version: ${{ matrix.nim_version }} 47 | 48 | - name: Fix apt packages 49 | run: | 50 | # see. https://github.com/actions/virtual-environments/issues/675 51 | sudo sed -i 's/azure\.//' /etc/apt/sources.list 52 | sudo apt update -yqq 53 | 54 | - name: Install xvfb 55 | run: sudo apt install -y xvfb 56 | 57 | - name: Install mingw and objective C 58 | run: sudo apt install -y mingw-w64 gobjc gnustep gnustep-devel 59 | 60 | - name: Install sdl2 61 | run: sudo apt install --fix-missing -y libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev 62 | 63 | - name: Download GLEW 64 | run: | 65 | sudo apt-get install -y libglew-dev 66 | 67 | - name: Install Vulkan API 68 | run: | 69 | wget -qO- https://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo tee /etc/apt/trusted.gpg.d/lunarg.asc 70 | sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-1.3.239-jammy.list https://packages.lunarg.com/vulkan/1.3.239/lunarg-vulkan-1.3.239-jammy.list 71 | sudo apt update 72 | sudo apt install -y vulkan-sdk 73 | 74 | - name: Build tests 75 | run: | 76 | cd tests 77 | for file in $(ls -v test*.nim); do 78 | echo "# ---=== Testing via C backend [$file] ===--- #" 79 | nim c -d:useGlew --passC:"-Iglew\include" --passL:"-Lglew\lib\Release\x64" $file 80 | echo "# ---=== Testing via C++ backend [$file] ===--- #" 81 | nim cpp -d:useGlew --passC:"-Iglew\include" --passL:"-Lglew\lib\Release\x64" $file 82 | echo "# ---=== Testing via ObjC backend [$file] ===--- #" 83 | nim objc -d:useGlew --passC:"-Iglew\include" --passL:"-Lglew\lib\Release\x64" $file 84 | echo "# ---=== Testing via JS backend [$file] ===--- #" 85 | nim js --noMain --app:lib $file 86 | done 87 | shell: bash 88 | 89 | - name: Build tests via Vulkan 90 | run: | 91 | cd tests 92 | for file in $(ls -v test*.nim); do 93 | echo "# ---=== Testing via C backend [$file] ===--- #" 94 | nim c -d:vulkan $file 95 | echo "# ---=== Testing via C++ backend [$file] ===--- #" 96 | nim cpp -d:vulkan $file 97 | echo "# ---=== Testing via ObjC backend [$file] ===--- #" 98 | nim objc -d:vulkan $file 99 | done 100 | shell: bash 101 | 102 | - name: Cross build tests 103 | run: | 104 | cd tests 105 | for file in $(ls -v test*.nim); do 106 | echo "# ---=== Compile for Win AMD64 [$file] ===--- #" 107 | nim c -d:mingw --cpu:amd64 $file 108 | echo "# ---=== Compile for Win i386 [$file] ===--- #" 109 | nim c -d:mingw --cpu:i386 $file 110 | echo "# ---=== Compile for Android [$file] ===--- #" 111 | nim c -c --cpu:arm --os:android -d:androidNDK --noMain:on $file 112 | echo "# ---=== Compile for iOS [$file] ===--- #" 113 | nim c -c --os:ios --noMain:on $file 114 | echo "# ---=== Compile for Nintendo Switch [$file] ===--- #" 115 | nim c -c --os:nintendoswitch $file 116 | done 117 | shell: bash 118 | 119 | WinBuild: 120 | runs-on: ${{ matrix.os }} 121 | strategy: 122 | matrix: 123 | os: 124 | - windows-latest 125 | nim_version: 126 | - '1.0.0' 127 | - '1.2.18' 128 | - '1.4.8' 129 | - 'stable' 130 | needs: before 131 | env: 132 | TIMEOUT_EXIT_STATUS: 124 133 | steps: 134 | - uses: actions/checkout@v3 135 | - name: Cache nimble 136 | id: cache-nimble 137 | uses: actions/cache@v3 138 | with: 139 | path: ~/.nimble 140 | key: ${{ runner.os }}-nimble-${{ hashFiles('*.nimble') }} 141 | - uses: jiro4989/setup-nim-action@v1 142 | with: 143 | nim-version: ${{ matrix.nim_version }} 144 | 145 | - name: Download GLEW 146 | shell: bash 147 | run: | 148 | curl -L https://sourceforge.net/projects/glew/files/glew/2.1.0/glew-2.1.0-win32.zip -o glew.zip 149 | unzip -q glew.zip 150 | mkdir -p glew/include 151 | mkdir -p glew/lib/Release/x64 152 | cp -f -rp glew-2.1.0/include/* glew/include 153 | cp -f -rp glew-2.1.0/lib/Release/x64/glew32.lib glew/lib/Release/x64 154 | 155 | - name: Download SDL2 156 | shell: bash 157 | run: | 158 | mkdir -p sdl2 159 | cd sdl2 160 | curl -L https://github.com/libsdl-org/SDL/releases/download/release-2.26.4/SDL2-2.26.4-win32-x64.zip -o SDL2.zip 161 | unzip -q SDL2.zip 162 | cp -f -rp *.dll ~/.nimble/bin 163 | cd .. 164 | 165 | - name: Download SDL2-ttf 166 | shell: bash 167 | run: | 168 | mkdir -p sdl2_ttf 169 | cd sdl2_ttf 170 | curl -L https://github.com/libsdl-org/SDL_ttf/releases/download/release-2.20.2/SDL2_ttf-2.20.2-win32-x64.zip -o SDL2_ttf.zip 171 | unzip -q SDL2_ttf.zip 172 | cp -f -rp *.dll ~/.nimble/bin 173 | cd .. 174 | 175 | - name: Download SDL2-image 176 | shell: bash 177 | run: | 178 | mkdir -p sdl2_image 179 | cd sdl2_image 180 | curl -L https://github.com/libsdl-org/SDL_image/releases/download/release-2.6.3/SDL2_image-2.6.3-win32-x64.zip -o SDL2_image.zip 181 | unzip -q SDL2_image.zip 182 | cp -f -rp *.dll ~/.nimble/bin 183 | cp -f -rp optional/*.dll ~/.nimble/bin 184 | cd .. 185 | 186 | - name: Download SDL2-mixer 187 | shell: bash 188 | run: | 189 | mkdir -p sdl2_mixer 190 | cd sdl2_mixer 191 | curl -L https://github.com/libsdl-org/SDL_mixer/releases/download/release-2.6.3/SDL2_mixer-2.6.3-win32-x64.zip -o SDL2_mixer.zip 192 | unzip -q SDL2_mixer.zip 193 | cp -f -rp *.dll ~/.nimble/bin 194 | cp -f -rp optional/*.dll ~/.nimble/bin 195 | cd .. 196 | 197 | - name: Install Vulkan SDK 198 | uses: jakoch/install-vulkan-sdk-action@main 199 | with: 200 | # You can set the Vulkan SDK version to download. 201 | # Defaults to latest version, if version not set. 202 | version: 1.3.231.1 203 | 204 | - name: Set up MinGW 205 | uses: egor-tensin/setup-mingw@v2 206 | with: 207 | platform: x64 208 | 209 | - name: Build tests 210 | run: | 211 | cd tests 212 | for file in $(ls -v test*.nim); do 213 | echo "# ---=== Testing via C backend [$file] ===--- #" 214 | nim c -d:useGlew --passC:"-Iglew\include" --passL:"-Lglew\lib\Release\x64" $file 215 | echo "# ---=== Testing via C++ backend [$file] ===--- #" 216 | nim cpp -d:useGlew --passC:"-Iglew\include" --passL:"-Lglew\lib\Release\x64" $file 217 | echo "# ---=== Testing via JS backend [$file] ===--- #" 218 | nim js --noMain --app:lib $file 219 | done 220 | shell: bash 221 | 222 | - name: Build tests via Vulkan 223 | run: | 224 | cd tests 225 | for file in $(ls -v test*.nim); do 226 | echo "# ---=== Testing via C backend [$file] ===--- #" 227 | nim c -d:vulkan $file 228 | echo "# ---=== Testing via C++ backend [$file] ===--- #" 229 | nim cpp -d:vulkan $file 230 | done 231 | shell: bash -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | nimcache/ 2 | nimblecache/ 3 | htmldocs/ 4 | .idea/ 5 | 6 | # Android 7 | .gradle 8 | .DS_Store 9 | build/ 10 | captures/ 11 | .externalNativeBuild 12 | .cxx 13 | local.properties 14 | 15 | 16 | docs/ 17 | 18 | *.log 19 | *.lg 20 | *.crashlog 21 | *.crash 22 | *.iml 23 | 24 | # Binaries 25 | *.exe 26 | *.x86 27 | *.x64 28 | *.x32_86 29 | *.zip 30 | *.7z 31 | 32 | # Cache 33 | *.js 34 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Before starting writing the **PR** please, open issue and describe **PR**. It's removes us from writing dublicated code :smiley: 2 | 3 | Please, describe every `func`, `method` and `proc` with docstrings :book: 4 | 5 | If you need help with PR - send PR and ask to help :slightly_smiling_face: 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 HapticX 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | ## ` N X p r e s s i v e ` 4 | experimental UI/2D engine written in Nim with :heart: 5 | 6 | ![Nim language](https://img.shields.io/badge/>=1.0.0-1b1e2b?style=for-the-badge&logo=nim&logoColor=f1fa8c&label=Nim&labelColor=2b2e3b) 7 | ![Open GL](https://img.shields.io/badge/Open%20GL-2b2e3b?style=for-the-badge&logo=opengl&logoColor=f1fa8c) 8 | ![Vulkan](https://img.shields.io/badge/Vulkan-2b2e3b?style=for-the-badge&logo=vulkan&logoColor=f1fa8c) 9 | ![SDL2](https://img.shields.io/badge/SDL2-2b2e3b?style=for-the-badge&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAAo5JREFUeF7tmDtOAzEQhj2AuAAlDT0H4A40AZpUSBSUBIkuEURECa+aINEg0dCkikjDHag5AAWXiBTWaBErHOPHeB2HeD0po/HY/uaf8cwCS/wHid+fEQBSQOIEKAUSFwAVQUoBSoHECVAKJC4AegUoBSgFKkCg/rzL82sMakNnRTsvWEReBCB1BeSqlFVQH+08Mg4HtrSoRArIAAoYRbqaIFQOgFyjZqqAVq//XW1Vv+t2YwqmyTZfL9urfMo+xDVilAHgkHP+4Hr53B6tANuFxEthbMXDqmCofOgAqODZIl+sQQHAXqg4INbeBMEHAPbyKAW4XMYHgJwWNgBTUecc6qO9TPwPC8GqgCgACM+gK4TSAORoi/npAk08MGfs6abd2M//c1HA1LPH+TsD2Pjx+zmoDVdM3aszgDLVW1X1dZBMaaTb+08T9NMZYuaDfwNgi3IZBYh5j50PKgsAO7Q5A8A0MS7R0zU7WB/YSOuAlAJQONPlJPbwqjQoUwOw0VbZeQHQqaFSAHTFyqeLE9f6poBP9FGdYG50enG/nvHJh2kzWx+ATZeFS4Hi0q3eXcYY16ZM5QH8grCPxJWrAbL0Z9nFRVEDVLnf7PbfANimqhhiFWCyw/qYSxHUbeIbvaQBNLu3RwDQl+Eu3CuQR8n1k1XZcVhsrFx9YKbUIJ0gtgZgctX2lGL7EMxehY2xFe50Oqvj5bUx1mHoT2JzB+AiQ5/oqWYKl70xE2qpadDlED4AsDVm7grADEI+0YNssn11fvKCfWZ1dkvAty7Pjl+xqSraWcfhMk5jWkMAYopWiLOSAkJQjcknKSCmaIU4KykgBNWYfJICYopWiLOSAkJQjcknKSCmaIU4a/IK+AKpP99QxkaIhgAAAABJRU5ErkJggg==&logoColor=f1fa8c) 10 | 11 | [![wakatime](https://wakatime.com/badge/user/eaf11f95-5e2a-4b60-ae6a-38cd01ed317b/project/2c4b13a1-b570-4d8a-81a4-272e5773f087.svg?style=for-the-badge)](https://wakatime.com/badge/user/eaf11f95-5e2a-4b60-ae6a-38cd01ed317b/project/2c4b13a1-b570-4d8a-81a4-272e5773f087) 12 | 13 | [![Testing](https://github.com/HapticX/engine/actions/workflows/tests.yml/badge.svg?style=for-the-badge)](https://github.com/HapticX/engine/actions/workflows/tests.yml) 14 | 15 |
16 | 17 | ## Why HapticX? :new_moon_with_face: 18 | It's simple to use and have a lot of sugar in syntax :eyes:. 19 | 20 | ### Features :sparkles: 21 | - Support `C`/`Cpp`/`ObjC`/`JS` backends; 22 | - Support earlier versions (`1.0.0` and above); 23 | - Support graphics backends: 24 | - `OpenGL`/`Vulkan` for `C`/`Cpp`/`ObjC`; 25 | - `WebGl` for `JS`. 26 | - Event handling via `@` macro; 27 | 28 | ## Why Nim? :crown: 29 | It's simple to use and has flexible syntax :smiley: 30 | 31 | 32 | ## Install :inbox_tray: 33 | ### Dependencies 34 | - Win/MacOS 35 | Put all of these libraries in `./nimble/bin/` folder: 36 | - [SDL2](https://github.com/libsdl-org/SDL) 37 | - [SDL2-ttf](https://github.com/libsdl-org/SDL_ttf/) 38 | - [SDL2-mixer](https://github.com/libsdl-org/SDL_mixer) 39 | - [SDL2-image](https://github.com/libsdl-org/SDL_image) 40 | 41 | Also Install [GLEW library](https://glew.sourceforge.net/) 42 | And [Vulkan SDK](https://vulkan.lunarg.com/sdk/home#windows) 43 | 44 | - Unix 45 | - SDL2 46 | ```bash 47 | sudo apt install --fix-missing -y libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev 48 | ``` 49 | - [Vulkan SDK](https://vulkan.lunarg.com/sdk/home#linux) 50 | ```bash 51 | wget -qO- https://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo tee /etc/apt/trusted.gpg.d/lunarg.asc 52 | sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-1.3.239-jammy.list https://packages.lunarg.com/vul1.3.239/lunarg-vulkan-1.3.239-jammy.list 53 | sudo apt update 54 | sudo apt install -y vulkan-sdk 55 | ``` 56 | - [GLEW library](https://glew.sourceforge.net/) 57 | ```bash 58 | sudo apt install -y libglew-dev 59 | ``` 60 | ### Engine 61 | ```bash 62 | nimble install https://github.com/HapticX/engine 63 | ``` 64 | 65 | ## What's Next? :bulb: 66 | Even more features! and bugs :bug: 67 | 68 | ## Contributing :dizzy: 69 | You can help to fix bugs and errors if you want :v: 70 | -------------------------------------------------------------------------------- /examples/readme.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # HapticX engine Examples 4 | 5 |
-------------------------------------------------------------------------------- /hapticx.nimble: -------------------------------------------------------------------------------- 1 | [Package] 2 | name = "hapticx" 3 | description = "2D/UI Engine written with love" 4 | author = "HapticX" 5 | version = "0.2.0" 6 | license = "GNU GPLv3" 7 | srcDir = "src" 8 | 9 | [Deps] 10 | Requires: "nim >= 1.6.0" 11 | -------------------------------------------------------------------------------- /src/app/app.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Provides window behavior 3 | ]# 4 | import 5 | os, 6 | unicode, 7 | strutils, 8 | ../core/core, 9 | ../core/vec2, 10 | ../core/input, 11 | ../core/exceptions, 12 | ../nodes/scene, 13 | ./environment 14 | 15 | when not defined(js): 16 | import 17 | ../thirdparty/sdl2/image, 18 | ../thirdparty/sdl2/joystick, 19 | ../thirdparty/sdl2 20 | else: 21 | import 22 | dom 23 | 24 | when defined(vulkan): 25 | import 26 | ../thirdparty/vulkan, 27 | ../core/vkmanager 28 | elif not defined(js): 29 | import 30 | ../thirdparty/opengl, 31 | ../thirdparty/opengl/glu 32 | else: 33 | import 34 | ../thirdparty/webgl, 35 | ../thirdparty/webgl/consts 36 | 37 | 38 | 39 | type 40 | App* = object 41 | when defined(vulkan): 42 | vkmanager: VulkanManager 43 | elif not defined(js): 44 | context: GlContextPtr 45 | when not defined(js): 46 | window: WindowPtr 47 | current, main*: HSceneRef 48 | paused*: bool 49 | running: bool 50 | title: string 51 | w, h: float 52 | env*: Environment 53 | scenes, scene_stack: seq[HSceneRef] 54 | 55 | 56 | when defined(js): 57 | var 58 | canvas* = dom.document.getElementById("app").Canvas 59 | gl* = canvas.getContext("webgl") 60 | if gl.isNil: 61 | gl = canvas.getContext("experimental-webgl") 62 | 63 | 64 | proc newApp*(title: string = "App", width: cint = 720, height: cint = 480): App = 65 | ## Initializes the new app with specified title and size 66 | once: 67 | # Set up SDL 2 68 | when not defined(js): 69 | discard captureMouse(True32) 70 | discard sdl2.init(INIT_EVERYTHING) 71 | 72 | when defined(vulkan): 73 | # Initialize Vulkan 74 | if not defined(android) and not defined(ios) and not defined(js): 75 | vkPreload() 76 | elif not defined(android) and not defined(ios) and not defined(js) and not defined(useGlew): 77 | # Initialize OpenGL 78 | loadExtensions() 79 | when not defined(vulkan) and not defined(js): 80 | # Set up GL attrs 81 | discard glSetAttribute(SDL_GL_DOUBLEBUFFER, 1) 82 | discard glSetAttribute(SDL_GL_GREEN_SIZE, 6) 83 | discard glSetAttribute(SDL_GL_RED_SIZE, 5) 84 | discard glSetAttribute(SDL_GL_BLUE_SIZE, 5) 85 | result = App( 86 | title: title, 87 | w: width.float, 88 | h: height.float, 89 | running: false, 90 | paused: false, 91 | env: newEnvironment(), 92 | scenes: @[], 93 | scene_stack: @[], 94 | current: nil, 95 | main: nil 96 | ) 97 | when not defined(js): 98 | let backend_flag = 99 | when defined(vulkan): 100 | SDL_WINDOW_VULKAN 101 | else: 102 | SDL_WINDOW_OPENGL 103 | let window = createWindow( 104 | title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, 105 | SDL_WINDOW_SHOWN or backend_flag or SDL_WINDOW_RESIZABLE or SDL_WINDOW_ALLOW_HIGHDPI or 106 | SDL_WINDOW_FOREIGN or SDL_WINDOW_INPUT_FOCUS or SDL_WINDOW_MOUSE_FOCUS 107 | ) 108 | result.window = window 109 | else: 110 | document.title = title 111 | 112 | when defined(vulkan): 113 | # Initializes Vulkan API 114 | result.vkmanager = initVulkan() 115 | elif not defined(js): 116 | # Initializes OpenGL 117 | result.context = window.glCreateContext() 118 | when defined(useGlew): 119 | assert glewInit().uint32 == 0 120 | glShadeModel(GL_SMOOTH) 121 | glClear(GL_COLOR_BUFFER_BIT) 122 | glEnable(GL_COLOR_MATERIAL) 123 | glMaterialf(GL_FRONT, GL_SHININESS, 15) 124 | else: 125 | gl.enable(SCISSOR_TEST) 126 | gl.clear(bbCOLOR.uint or bbDEPTH.uint) 127 | 128 | 129 | when not defined(js): 130 | proc reshape*(width, height: cint) = 131 | ## Computes an aspect ratio of the new window size 132 | ## `width` and `height` of current window 133 | when defined(vulkan): 134 | discard 135 | elif not defined(js): 136 | glViewport(0, 0, width, height) 137 | 138 | glMatrixMode(GL_PROJECTION) 139 | glLoadIdentity() 140 | glOrtho(0f, width.float, height.float, 0f, 0f, 1000f) 141 | glMatrixMode(GL_MODELVIEW) 142 | else: 143 | proc reshape*() = 144 | ## Computes an aspect ratio of the new window size 145 | ## `width` and `height` of current window 146 | var 147 | w = canvas.clientwidth 148 | h = canvas.clientHeight 149 | if canvas.width != w or canvas.height != h: 150 | canvas.width = w 151 | canvas.height = h 152 | gl.viewport(0, 0, w, h) 153 | reshape() 154 | 155 | func title*(app: App): string = 156 | ## Returns app title 157 | app.title 158 | 159 | proc `title=`*(app: var App, new_title: string) = 160 | ## Changes app title 161 | app.title = new_title 162 | when not defined(js): 163 | app.window.setTitle(new_title) 164 | else: 165 | document.title = new_title 166 | 167 | proc `icon=`*(app: var App, icon_path: cstring) = 168 | ## Changes app icon if available 169 | ## `icon_path` is path to icon 170 | when not defined(js): 171 | let icon = cast[SurfacePtr](image.load(icon_path)) 172 | app.window.setIcon(icon) 173 | else: 174 | var favicon = document.getElementById("dyn-favicon") 175 | if isNil(favicon): 176 | favicon = document.createElement("link") 177 | favicon.id = "dyn-favicon" 178 | else: 179 | document.head.removeChild(favicon) 180 | favicon.setAttr("rel", "shortcut icon") 181 | favicon.setAttr("href", icon_path) 182 | document.head.appendChild(favicon) 183 | 184 | 185 | 186 | func hasScene*(app: App, tag: string): bool = 187 | ## Returns true when app contains scene with `tag` 188 | for scene in app.scenes: 189 | if scene.tag == tag: 190 | return true 191 | false 192 | 193 | 194 | proc goTo*(app: var App, tag: string) = 195 | ## Goes to available scene 196 | for s in app.scenes: 197 | if s.tag == tag: 198 | app.scene_stack.add(s) 199 | app.current.exit() 200 | app.current = s 201 | app.current.enter() 202 | break 203 | 204 | 205 | proc goBack*(app: var App) = 206 | ## Goes back in scene stack 207 | assert app.scene_stack.len > 0 208 | discard app.scene_stack.pop() 209 | app.current.exit() 210 | app.current = app.scene_stack[^1] 211 | app.current.enter() 212 | 213 | 214 | func clearSceneStack*(app: var App) = 215 | ## Clears scene stack and puts current scene into stack 216 | app.scene_stack = @[app.current] 217 | 218 | 219 | func size*(app: App): Vec2 = 220 | ## Returns current window size 221 | Vec2(x: app.w.float, y: app.h.float) 222 | 223 | 224 | proc resize*(app: var App, w: cint, h: cint) = 225 | ## Resizes window 226 | ## `w` - new width 227 | ## `h` - new height 228 | when not defined(js): 229 | app.window.setSize(w, h) 230 | else: 231 | window.innerWidth = w 232 | window.innerHeight = h 233 | app.w = w.float 234 | app.h = h.float 235 | when not defined(js): 236 | reshape(w, h) 237 | else: 238 | reshape() 239 | 240 | 241 | proc resize*(app: var App, new_size: Vec2) = 242 | ## Resizes window 243 | ## `new_size` - Vec2 size repr 244 | when not defined(js): 245 | app.window.setSize(new_size.x.cint, new_size.y.cint) 246 | else: 247 | window.innerWidth = new_size.x.cint 248 | window.innerHeight = new_size.y.cint 249 | app.w = new_size.x 250 | app.h = new_size.y 251 | when not defined(js): 252 | reshape(app.w.cint, app.h.cint) 253 | else: 254 | reshape() 255 | 256 | 257 | func quit*(app: var App) = 258 | ## Quits from app 259 | app.running = false 260 | 261 | 262 | template check(event, condition, conditionelif: untyped): untyped = 263 | ## Checks input event and changes press state 264 | ## `event` - InputEventType 265 | ## `condition` - condition when press state should be 2 266 | ## `conditionelif` - condition when press state should be 1 267 | press_state = 268 | if last_event.kind == `event` and `condition`: 269 | 2 270 | elif `conditionelif`: 271 | 1 272 | else: 273 | 0 274 | 275 | when not defined(js): 276 | {.push cdecl.} 277 | proc keyboard(app: App, key: cint, pressed: bool) = 278 | ## Notify input system about keyboard event 279 | ## `key` - key code 280 | check(InputEventType.Keyboard, last_event.pressed, true) 281 | let k = $Rune(key) 282 | if pressed: 283 | pressed_keys.add(key) 284 | else: 285 | for i in pressed_keys.low..pressed_keys.high: 286 | if pressed_keys[i] == key: 287 | pressed_keys.del(i) 288 | break 289 | last_event.kind = InputEventType.Keyboard 290 | last_event.key = k 291 | last_event.key_int = key 292 | last_event.pressed = pressed 293 | current_event = last_event 294 | 295 | proc textinput(app: App, ev: TextInputEventPtr) = 296 | ## Notify input system about keyboard event 297 | last_event.kind = InputEventType.Text 298 | last_event.key = toRunes(join(ev.text))[0].toUTF8() 299 | current_event = last_event 300 | 301 | proc mousebutton(app: App, btn, x, y: cint, pressed: bool) = 302 | ## Notify input system about mouse button event 303 | check(InputEventType.Mouse, last_event.pressed and pressed, pressed) 304 | last_event.kind = InputEventType.Mouse 305 | last_event.pressed = pressed 306 | last_event.x = x.float 307 | last_event.y = y.float 308 | current_event = last_event 309 | 310 | proc wheel(app: App, x, y: cint) = 311 | ## Notify input system about mouse wheel event 312 | check(InputEventType.Wheel, false, false) 313 | last_event.kind = InputEventType.Wheel 314 | last_event.xrel = x.float 315 | last_event.yrel = y.float 316 | current_event = last_event 317 | 318 | proc motion(app: App, x, y, xrel, yrel: cint) = 319 | ## Notify input system about mouse motion event 320 | last_event.kind = InputEventType.Motion 321 | last_event.x = x.float 322 | last_event.y = y.float 323 | last_event.xrel = xrel.float 324 | last_event.yrel = yrel.float 325 | current_event = last_event 326 | 327 | proc joyaxismotion(app: App, axis: uint8, which: int, val: int16) = 328 | ## Notify input system about joystick event 329 | last_event.kind = InputEventType.JAxisMotion 330 | last_event.axis = axis 331 | last_event.val = val.float 332 | current_event = last_event 333 | 334 | proc joyhatmotion(app: App, axis: uint8, which: int) = 335 | ## Notify input system about joystick event 336 | last_event.kind = InputEventType.JHatMotion 337 | last_event.axis = axis 338 | current_event = last_event 339 | 340 | proc joybutton(app: App, button_index: cint, pressed: bool) = 341 | ## Notify input system about joystick event 342 | check(InputEventType.JButton, last_event.pressed and pressed, pressed) 343 | last_event.kind = InputEventType.JButton 344 | last_event.button_index = button_index 345 | last_event.pressed = pressed 346 | current_event = last_event 347 | 348 | proc touch(x, y: float, pressed: bool) = 349 | ## Notify input system about finger touch 350 | last_event.kind = InputEventType.Touch 351 | last_event.x = x 352 | last_event.y = y 353 | current_event = last_event 354 | 355 | proc onReshape(userdata: pointer, event: ptr Event): Bool32 = 356 | var 357 | app = (cast[ptr App](userdata))[] 358 | width: cint 359 | height: cint 360 | if event.kind == WindowEvent: 361 | case evWindow(event[]).event 362 | of WindowEvent_Resized, WindowEvent_SizeChanged, WindowEvent_Minimized, WindowEvent_Maximized, WindowEvent_Restored: 363 | app.window.getSize(width, height) 364 | app.w = width.float 365 | app.h = height.float 366 | reshape(width, height) 367 | else: 368 | discard 369 | False32 370 | {.pop.} 371 | else: 372 | proc mousemotion(x, y, xrel, yrel: float) = 373 | last_event.kind = InputEventType.Motion 374 | last_event.x = x 375 | last_event.y = y 376 | last_event.xrel = xrel 377 | last_event.yrel = yrel 378 | current_event = last_event 379 | 380 | proc mouseclick(x, y: float, pressed: bool) = 381 | check(InputEventType.Mouse, last_event.pressed and pressed, pressed) 382 | last_event.kind = InputEventType.Mouse 383 | last_event.pressed = pressed 384 | last_event.x = x 385 | last_event.y = y 386 | current_event = last_event 387 | 388 | proc wheel(x, y: float) = 389 | ## Notify input system about mouse wheel event 390 | check(InputEventType.Wheel, false, false) 391 | last_event.kind = InputEventType.Wheel 392 | last_event.xrel = x 393 | last_event.yrel = y 394 | current_event = last_event 395 | proc touch(x, y: float, pressed: bool) = 396 | ## Notify input system about finger touch 397 | last_event.kind = InputEventType.Touch 398 | last_event.x = x 399 | last_event.y = y 400 | current_event = last_event 401 | proc keyboard(code: cint, pressed: bool) = 402 | ## Notify input system about keyboard event 403 | ## `key` - key code 404 | check(InputEventType.Keyboard, last_event.pressed, true) 405 | let key = $Rune(code) 406 | if pressed: 407 | pressed_keys.add(code) 408 | else: 409 | for i in pressed_keys.low..pressed_keys.high: 410 | if pressed_keys[i] == code: 411 | pressed_keys.del(i) 412 | break 413 | last_event.kind = InputEventType.Keyboard 414 | last_event.key = key 415 | last_event.key_int = code 416 | last_event.pressed = pressed 417 | current_event = last_event 418 | 419 | proc handleEvent(app: var App) = 420 | ## Handles events 421 | when not defined(js): 422 | # Handle joysticks 423 | var joystick: JoystickPtr 424 | discard joystickEventState(SDL_ENABLE) 425 | joystick = joystickOpen(0) 426 | # Handle events 427 | var event = defaultEvent 428 | while sdl2.pollEvent(event): 429 | case event.kind 430 | of QuitEvent: 431 | app.running = false 432 | of KeyDown: 433 | keyboard(app, evKeyboard(event).keysym.sym, true) 434 | of KeyUp: 435 | keyboard(app, evKeyboard(event).keysym.sym, false) 436 | of TextInput: 437 | textinput(app, evTextInput(event)) 438 | of MouseButtonDown: 439 | let ev = evMouseButton(event) 440 | mousebutton(app, ev.button.cint, ev.x, ev.y, true) 441 | of MouseButtonUp: 442 | let ev = evMouseButton(event) 443 | mousebutton(app, ev.button.cint, ev.x, ev.y, false) 444 | of MouseWheel: 445 | let ev = evMouseWheel(event) 446 | wheel(app, ev.x, ev.y) 447 | of MouseMotion: 448 | let ev = evMouseMotion(event) 449 | motion(app, ev.x, ev.y, ev.xrel, ev.yrel) 450 | of JoyAxisMotion: 451 | let ev = EvJoyAxis(event) 452 | joyaxismotion(app, ev.axis, ev.which, ev.value) 453 | of JoyButtonDown: 454 | let ev = EvJoyButton(event) 455 | joybutton(app, ev.button.cint, true) 456 | of JoyButtonUp: 457 | let ev = EvJoyButton(event) 458 | joybutton(app, ev.button.cint, false) 459 | of JoyHatMotion: 460 | let ev = EvJoyHat(event) 461 | joyhatmotion(app, ev.hat, ev.which) 462 | of FingerDown, FingerUp, FingerMotion: 463 | let 464 | ev = EvTouchFinger(event) 465 | finger = getTouchFinger(ev.touchID, ev.fingerID.cint)[] 466 | touch(finger.x, finger.y, finger.pressure > 0f) 467 | else: 468 | discard 469 | if current_event == last_event: 470 | app.current.handleEvent(last_event) 471 | current_event = default_input_event 472 | 473 | 474 | proc display(app: App) = 475 | ## Displays current scene 476 | let bg = app.env.background_color 477 | when defined(vulkan): 478 | app.vkmanager.display() 479 | elif not defined(js): 480 | # Default color 481 | glClearColor(bg.r, bg.g, bg.b, bg.a) 482 | glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) 483 | glEnable(GL_BLEND) 484 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 485 | else: 486 | gl.clearColor(bg.r, bg.g, bg.b, bg.a) 487 | gl.clear(COLOR_BUFFER_BIT or DEPTH_BUFFER_BIT) 488 | gl.enable(BLEND) 489 | gl.blendFunc(SRC_ALPHA, ONE_MINUS_SRC_ALPHA) 490 | gl.scissor(0, 0, gl.canvas.width, gl.canvas.height) 491 | 492 | # Draw current scene 493 | app.current.draw(app.w, app.h) 494 | 495 | when defined(vulkan): 496 | discard 497 | elif not defined(js): 498 | glFlush() 499 | app.window.glSwapWindow() 500 | else: 501 | gl.flush() 502 | when not defined(js): 503 | # Framerate 504 | os.sleep(app.env.delay.int) 505 | 506 | 507 | proc run*(app: var App) = 508 | ## Runs app and launches the main scene 509 | if isNil(app.main): 510 | raise newException(MainSceneNotDefinedDefect, "Main scene not defined!") 511 | app.current = app.main 512 | app.running = true 513 | app.scene_stack.add(app.current) 514 | app.current.enter() 515 | when not defined(js): 516 | reshape(app.w.cint, app.h.cint) 517 | else: 518 | reshape() 519 | 520 | when defined(debug): 521 | echo "App started" 522 | 523 | when not defined(js): 524 | # handle window resize 525 | addEventWatch(onReshape, addr app) 526 | 527 | # Main app loop 528 | while app.running: 529 | app.handleEvent() 530 | app.display() 531 | 532 | app.current.exit() 533 | 534 | when defined(vulkan): 535 | app.vkmanager.cleanUp() 536 | else: 537 | glDeleteContext(app.context) 538 | destroy(app.window) 539 | sdl2.quit() 540 | else: 541 | reshape() 542 | {.emit: """ 543 | window.addEventListener('resize', `reshape`); 544 | window.addEventListener('mousemove', (ev) => { 545 | `mousemotion`(ev.clientX, ev.clientY, ev.movementX, ev.movementY); 546 | }); 547 | window.addEventListener('mousedown', (ev) => { 548 | `mouseclick`(ev.clientX, ev.clientY, true); 549 | }); 550 | window.addEventListener('mouseup', (ev) => { 551 | `mouseclick`(ev.clientX, ev.clientY, false); 552 | }); 553 | window.addEventListener('wheel', (ev) => { 554 | `wheel`(ev.deltaX, ev.deltaY); 555 | }); 556 | window.addEventListener('touchstart', (ev) => { 557 | `touch`(ev.touchles[0].clientX, ev.touchles[0].clientY, true); 558 | }); 559 | window.addEventListener('touchend', (ev) => { 560 | `touch`(ev.touchles[0].clientX, ev.touchles[0].clientY, false); 561 | }); 562 | window.addEventListener('keydown', (ev) => { 563 | `keyboard`(ev.keyCode, true); 564 | }); 565 | window.addEventListener('keyup', (ev) => { 566 | `keyboard`(ev.keyCode, false); 567 | }); 568 | window.addEventListener('load', `reshape`); 569 | 570 | function mainLoop(time) { 571 | `display`(`app`); 572 | `handleEvent`(`app`); 573 | requestAnimationFrame(mainLoop); 574 | } 575 | requestAnimationFrame(mainLoop); 576 | """.} 577 | -------------------------------------------------------------------------------- /src/app/environment.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Provides environment 3 | ]# 4 | import 5 | ../core/color 6 | 7 | 8 | type 9 | Environment* = ref object 10 | brightness*: float 11 | delay*: float 12 | background_color*: Color 13 | fullscreen*: bool 14 | 15 | 16 | func newEnvironment*: Environment = 17 | ## Creates a new environment 18 | Environment( 19 | brightness: 1f, 20 | delay: 16f, 21 | background_color: newColor("#212121"), 22 | fullscreen: false 23 | ) 24 | -------------------------------------------------------------------------------- /src/core/animatable.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Provides low-level animatable objects 3 | ]# 4 | import 5 | strformat, 6 | math 7 | 8 | 9 | type 10 | Animatable*[T] = object 11 | value*: T 12 | Easing* {.pure, size: sizeof(int8).} = enum 13 | Linear 14 | EaseIn 15 | EaseOut 16 | EaseInOut 17 | QuadIn 18 | QuadOut 19 | QuadInOut 20 | CubicIn 21 | CubicOut 22 | CubicInOut 23 | QuartIn 24 | QuartOut 25 | QuartInOut 26 | QuintIn 27 | QuintOut 28 | QuintInOut 29 | ExpoIn 30 | ExpoOut 31 | ExpoInOut 32 | CircIn 33 | CircOut 34 | CircInOut 35 | BackIn 36 | BackOut 37 | BackInOut 38 | ElasticIn 39 | ElasticOut 40 | ElasticInOut 41 | 42 | 43 | func animatable*[T](val: T): Animatable[T] = 44 | ## Creates a new Animatable value 45 | Animatable[T](value: val) 46 | 47 | 48 | func tween*[T](a, b: Animatable[T], t: float, easing: Easing): Animatable[T] = 49 | ## Returns animatable value at `t` position between `a` and `b`. 50 | ## 51 | ## Arguments: 52 | ## - `a` - start position; 53 | ## - `b` - end position; 54 | ## - `t` - number between 0 and 1, where 0 is start and 1 is end; 55 | ## - `easing` - easing mode 56 | let val = 57 | case easing: 58 | of Easing.Linear: 59 | t 60 | of Easing.EaseIn: 61 | 1f - cos((t * PI) / 2f) 62 | of Easing.EaseOut: 63 | cos((t * PI) / 2f) 64 | of Easing.EaseInOut: 65 | -(cos(PI * t) - 1f) / 2f 66 | of Easing.QuadIn: 67 | t * t 68 | of Easing.QuadOut: 69 | 1f - (1f - t) * (1f - t) 70 | of Easing.QuadInOut: 71 | if t < 0.5f: 72 | 2 * t * t 73 | else: 74 | 1f - pow(-2f * t + 2f, 2f) / 2f 75 | of Easing.CubicIn: 76 | t * t * t 77 | of Easing.CubicOut: 78 | 1 - pow(1f - t, 3f) 79 | of Easing.CubicInOut: 80 | if t < 0.5f: 81 | 4f * t * t * t 82 | else: 83 | 1f - pow(-2f * t + 2f, 3f) / 2f 84 | of Easing.QuartIn: 85 | t * t * t * t * t 86 | of Easing.QuartOut: 87 | 1 - pow(1f - t, 5f) 88 | of Easing.QuartInOut: 89 | if t < 0.5f: 90 | 16f * t * t * t * t * t 91 | else: 92 | 1f - pow(-2f * t + 2f, 5f) / 2f 93 | of Easing.QuintIn: 94 | t * t * t * t 95 | of Easing.QuintOut: 96 | 1 - pow(1f - t, 4f) 97 | of Easing.QuintInOut: 98 | if t < 0.5f: 99 | 8f * t * t * t * t 100 | else: 101 | 1f - pow(-2f * t + 2f, 4f) / 2f 102 | of Easing.ExpoIn: 103 | if t == 0f: 104 | 0f 105 | else: 106 | pow(2f, 10f * t - 10f) 107 | of Easing.ExpoOut: 108 | if t == 1f: 109 | 1f 110 | else: 111 | 1f - pow(2f, -10f * t) 112 | of Easing.ExpoInOut: 113 | if t == 0f: 114 | 0f 115 | elif t == 1f: 116 | 1f 117 | elif t < 0.5f: 118 | pow(2f, -20f * t + 10f) / 2f 119 | else: 120 | (2f - pow(2f, -20f * t + 10f)) / 2f 121 | of Easing.CircIn: 122 | 1f - sqrt(1f - pow(t, 2f)) 123 | of Easing.CircOut: 124 | sqrt(1f - pow(t - 1f, 2f)) 125 | of Easing.CircInOut: 126 | if t < 0.5f: 127 | (1f - sqrt(1f - pow(2f * t, 2f))) / 2f 128 | else: 129 | (sqrt(1f - pow(-2f * t + 2f, 2f)) + 1f) / 2f 130 | of Easing.BackIn: 131 | const 132 | c1 = 1.70158f 133 | c2 = c1 + 1f 134 | c2 * t * t * t - c1 * t * t 135 | of Easing.BackOut: 136 | const 137 | c1 = 1.70158f 138 | c2 = c1 + 1f 139 | 1f + c2 * pow(t - 1f, 3f) - c1 * pow(t - 1f, 2f) 140 | of Easing.BackInOut: 141 | const 142 | c1 = 1.70158f 143 | c2 = c1 * 1.525 144 | if t < 0.5: 145 | (pow(2f * t, 2f) * ((c2 + 1f) * 2f * t - c2)) / 2f 146 | else: 147 | (pow(2f * t - 2f, 2f) * ((c2 + 1f) * (t * 2f - 2f) + c2) + 2) / 2f 148 | of Easing.ElasticIn: 149 | const c = (2f * PI) / 3f 150 | if t == 0f: 151 | 0f 152 | elif t == 1f: 153 | 1f 154 | else: 155 | -pow(2f, 10f * t - 10f) * sin((t * 10f - 10.75f) * c) 156 | of Easing.ElasticOut: 157 | const c = (2f * PI) / 3f 158 | if t == 0f: 159 | 0f 160 | elif t == 1f: 161 | 1f 162 | else: 163 | pow(2f, -10f * t) * sin((t * 10f - 0.75f) * c) + 1f 164 | of Easing.ElasticInOut: 165 | const c = (2f * PI) / 4.5f 166 | if t == 0f: 167 | 0f 168 | elif t == 1f: 169 | 1f 170 | elif t < 0.5: 171 | -pow(2f, 20f * t - 10f) * sin((20f * t - 11.125f) * c) / 2f 172 | else: 173 | pow(2f, -20f * t + 10f) * sin((20f * t - 11.125f) * c) / 2f + 1f 174 | Animatable[T](value: a.value + ((b.value - a.value) * val)) 175 | 176 | 177 | func tween*[T](a: Animatable[T], b: T, t: float, easing: Easing): Animatable[T] = 178 | ## Returns animatable value at `t` position between `a` and `b`. 179 | tween(a, animatable(b), t, easing) 180 | 181 | 182 | func `$`*[T](a: Animatable[T]): string = 183 | ## Returns string representation 184 | fmt"animatable[{a.value}]" 185 | -------------------------------------------------------------------------------- /src/core/basis.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Provides working with Basis 3 | ]# 4 | import 5 | strformat, 6 | vec3, 7 | ./exceptions 8 | 9 | 10 | type 11 | Basis* = object 12 | x*, y*, z*: Vec3 13 | 14 | 15 | const 16 | BasisZero* = Basis( 17 | x: Vec3(x: 0f, y: 0f, z: 0f), 18 | y: Vec3(x: 0f, y: 0f, z: 0f), 19 | z: Vec3(x: 0f, y: 0f, z: 0f) 20 | ) 21 | BasisOne* = Basis( 22 | x: Vec3(x: 1f, y: 1f, z: 1f), 23 | y: Vec3(x: 1f, y: 1f, z: 1f), 24 | z: Vec3(x: 1f, y: 1f, z: 1f) 25 | ) 26 | BasisDiagonal* = Basis( 27 | x: Vec3(x: 1f, y: 0f, z: 0f), 28 | y: Vec3(x: 0f, y: 1f, z: 0f), 29 | z: Vec3(x: 0f, y: 0f, z: 1f) 30 | ) 31 | BasisSecondDiagonal* = Basis( 32 | x: Vec3(x: 0f, y: 0f, z: 1f), 33 | y: Vec3(x: 0f, y: 1f, z: 0f), 34 | z: Vec3(x: 1f, y: 0f, z: 0f) 35 | ) 36 | 37 | 38 | func newBasis*: Basis = 39 | ## Creates a new zero basis 40 | Basis( 41 | x: Vec3(x: 0f, y: 0f, z: 0f), 42 | y: Vec3(x: 0f, y: 0f, z: 0f), 43 | z: Vec3(x: 0f, y: 0f, z: 0f) 44 | ) 45 | 46 | func newBasis*(val: float): Basis = 47 | ## Creates a new basis with val 48 | Basis( 49 | x: Vec3(x: val, y: val, z: val), 50 | y: Vec3(x: val, y: val, z: val), 51 | z: Vec3(x: val, y: val, z: val) 52 | ) 53 | 54 | func newBasis*(x, y, z: float): Basis = 55 | ## Creates a new basis with xyz values 56 | Basis( 57 | x: Vec3(x: x, y: y, z: z), 58 | y: Vec3(x: x, y: y, z: z), 59 | z: Vec3(x: x, y: y, z: z) 60 | ) 61 | 62 | func newBasis*(x1, y1, z1, x2, y2, z2, x3, y3, z3: float): Basis = 63 | ## Creates a new basis 64 | Basis( 65 | x: Vec3(x: x1, y: y1, z: z1), 66 | y: Vec3(x: x2, y: y2, z: z2), 67 | z: Vec3(x: x3, y: y3, z: z3) 68 | ) 69 | 70 | func newBasis*(a: Basis): Basis = 71 | ## Creates a new basis from other basis. 72 | Basis( 73 | x: newVec3(a.x), 74 | y: newVec3(a.y), 75 | z: newVec3(a.z), 76 | ) 77 | 78 | 79 | 80 | # ---=== Operators ===--- # 81 | func `$`*(a: Basis): string = 82 | fmt"basis({a.x}, {a.y}, {a.z})" 83 | 84 | func pretty*(a: Basis): string = 85 | fmt"""basis( 86 | {a.x.x}, {a.x.y}, {a.x.z} 87 | {a.y.x}, {a.y.y}, {a.y.z} 88 | {a.z.x}, {a.z.y}, {a.z.z} 89 | )""" 90 | 91 | func `[]`*(a: Basis, index: int): Vec3 = 92 | ## Returns basis `x`, `y` or `z` by `index` 93 | if index == 0: 94 | a.x 95 | elif index == 1: 96 | a.y 97 | elif index == 2: 98 | a.z 99 | else: 100 | raise newException(OutOfIndexDefect, fmt"{index} is out of bounds") 101 | 102 | func `[]=`*(a: var Basis, index: int, val: Vec3): float = 103 | ## Changes basis `x`, `y` or `z` by `index` to `val` 104 | if index == 0: 105 | a.x = val 106 | elif index == 1: 107 | a.y = val 108 | elif index == 2: 109 | a.z = val 110 | else: 111 | raise newException(OutOfIndexDefect, fmt"{index} is out of bounds") 112 | 113 | 114 | template provideOperator(operatorFunc, op: untyped): untyped = 115 | func `operatorFunc`*(a, b: Basis): Basis {.inline.} = 116 | Basis(x: `op`(a.x, b.x), y: `op`(a.y, b.y), z: `op`(a.z, b.z)) 117 | func `operatorFunc`*(a: float, b: Basis): Basis {.inline.} = 118 | Basis(x: `op`(a, b.x), y: `op`(a, b.y), z: `op`(a, b.z)) 119 | func `operatorFunc`*(a: Basis, b: float): Basis {.inline.} = 120 | Basis(x: `op`(a.x, b), y: `op`(a.y, b), z: `op`(a.z, b)) 121 | func `operatorFunc`*(a: Vec3, b: Basis): Basis {.inline.} = 122 | Basis(x: `op`(a.x, b.x), y: `op`(a.y, b.y), z: `op`(a.z, b.z)) 123 | func `operatorFunc`*(a: Basis, b: Vec3): Basis {.inline.} = 124 | Basis(x: `op`(a.x, b.x), y: `op`(a.y, b.y), z: `op`(a.z, b.z)) 125 | 126 | 127 | template provideOperatorVar(operatorFunc, op: untyped): untyped = 128 | func `operatorFunc`*(a: var Basis, b: Basis) = 129 | `op`(a.x, b.x) 130 | `op`(a.y, b.y) 131 | `op`(a.z, b.z) 132 | func `operatorFunc`*(a: var Basis, b: float) = 133 | `op`(a.x, b) 134 | `op`(a.y, b) 135 | `op`(a.z, b) 136 | func `operatorFunc`*(a: var Basis, b: Vec3) = 137 | `op`(a.x, b.x) 138 | `op`(a.y, b.y) 139 | `op`(a.z, b.z) 140 | 141 | template provideBinOperator(operatorFunc, op: untyped): untyped = 142 | func `operatorFunc`*(a, b: Basis): bool {.inline.} = 143 | `op`(a.x, b.x) and `op`(a.y, b.y) and `op`(a.z, b.z) 144 | 145 | 146 | provideOperator(`+`, `+`) 147 | provideOperator(`-`, `-`) 148 | provideOperator(`/`, `/`) 149 | provideOperator(`*`, `*`) 150 | 151 | provideOperatorVar(`+=`, `+=`) 152 | provideOperatorVar(`-=`, `-=`) 153 | provideOperatorVar(`/=`, `/=`) 154 | provideOperatorVar(`*=`, `*=`) 155 | 156 | provideBinOperator(`==`, `==`) 157 | provideBinOperator(`!=`, `!=`) 158 | provideBinOperator(`>`, `>`) 159 | provideBinOperator(`<`, `<`) 160 | 161 | 162 | # ---=== Methods ===--- # 163 | func determinant*(a: Basis): float = 164 | ## Calculates Basis determinant 165 | ( 166 | a[0][0]*a[1][1]*a[2][2] + a[1][0]*a[2][1]*a[0][2] + a[0][1]*a[1][2]*a[2][0] - 167 | a[0][2]*a[1][1]*a[2][0] - a[0][0]*a[1][2]*a[2][1] - a[1][0]*a[0][1]*a[2][2] 168 | ) 169 | 170 | func transpose*(a: Basis): Basis = 171 | ## Transposes basis 172 | Basis( 173 | x: Vec3(x: a[0][0], y: a[1][0], z: a[2][0]), 174 | y: Vec3(x: a[0][1], y: a[1][1], z: a[2][1]), 175 | z: Vec3(x: a[0][2], y: a[1][2], z: a[2][2]) 176 | ) 177 | 178 | func minor*(a: Basis, x, y: int): float = 179 | ## Calculates minor of Basis. 180 | assert x >= 0 and x <= 2 and y >= 0 and y <= 2 181 | var row1, row2: Vec3 182 | 183 | case x: 184 | of 0: 185 | (row1, row2) = (a.y, a.z) 186 | of 1: 187 | (row1, row2) = (a.x, a.z) 188 | else: 189 | (row1, row2) = (a.x, a.y) 190 | 191 | case y: 192 | of 0: 193 | row1.y*row2.z - row1.z*row2.y 194 | of 1: 195 | row1.x*row2.z - row1.z*row2.x 196 | else: 197 | row1.x*row2.y - row1.y*row2.x 198 | 199 | func normalized*(a: Basis): Basis {.inline.} = 200 | ## Normalizes every vector of basis 201 | Basis( 202 | x: a.x.normalized(), 203 | y: a.y.normalized(), 204 | z: a.z.normalized() 205 | ) 206 | 207 | func normalize*(a: var Basis) = 208 | ## Normalizes every vector of basis 209 | a.x.normalize() 210 | a.y.normalize() 211 | a.z.normalize() 212 | 213 | 214 | func inverse*(a: Basis): Basis = 215 | ## Calculates inverse basis 216 | let det = a.determinant() 217 | assert det != 0 218 | let invDet = 1f/det 219 | Basis( 220 | x: Vec3(x: (a.y.y*a.z.z - a.z.y*a.y.z) * invDet, y: (a.z.x*a.y.z - a.y.x*a.z.z) * invDet, z: (a.y.x*a.z.y - a.z.x*a.y.y) * invDet), 221 | y: Vec3(x: (a.z.x*a.x.z - a.x.y*a.z.z) * invDet, y: (a.x.x*a.z.z - a.x.z*a.z.x) * invDet, z: (a.z.x*a.x.y - a.x.x*a.z.y) * invDet), 222 | z: Vec3(x: (a.x.y*a.y.z - a.y.y*a.x.z) * invDet, y: (a.y.x*a.x.z - a.x.x*a.y.z) * invDet, z: (a.x.x*a.y.y - a.y.x*a.x.y) * invDet), 223 | ) 224 | 225 | func isOrthogonal*(a: Basis): bool {.inline.} = 226 | ## Returns `true` if the basis vectors of `b` are mutually orthogonal. 227 | a.x.dot(a.y) == 0f and a.x.dot(a.z) == 0f and a.y.dot(a.z) == 0f 228 | 229 | func isOrthonormal*(a: Basis): bool {.inline.} = 230 | ## Returns true when basis vectors of `a` are mutually ortogonal and each has unit length 231 | a.isOrthogonal() and a.x.isNorm and a.y.isNorm and a.z.isNorm 232 | -------------------------------------------------------------------------------- /src/core/color.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Provides working with color 3 | ]# 4 | import 5 | strformat, 6 | strutils, 7 | math, 8 | ./hmath 9 | 10 | 11 | type 12 | Color* = object 13 | r*, g*, b*, a*: float 14 | BlendMode* {.pure, size: sizeof(int8).} = enum 15 | Normal, 16 | Screen, 17 | Multiply, 18 | Overlay, 19 | Addition, 20 | Substract, 21 | Divide, 22 | Diffirence, 23 | Darken, 24 | Lighten, 25 | SoftLight 26 | 27 | 28 | const 29 | TransparentClr* = Color(r: 0f, g: 0f, b: 0f, a: 0f) 30 | WhiteClr* = Color(r: 1f, g: 1f, b: 1f, a: 1f) 31 | BlackClr* = Color(r: 0f, g: 0f, b: 0f, a: 1f) 32 | RedClr* = Color(r: 1f, g: 0f, b: 0f, a: 1f) 33 | GreenClr* = Color(r: 0f, g: 1f, b: 0f, a: 1f) 34 | BlueClr* = Color(r: 0f, g: 0f, b: 1f, a: 1f) 35 | CyanClr* = Color(r: 0f, g: 1f, b: 1f, a: 1f) 36 | GrayClr* = Color(r: 0.75f, g: 0.75f, b: 0.75f, a: 1f) 37 | PurpleClr* = Color(r: 0.63f, g: 0.13f, b: 0.94f, a: 1f) 38 | RebeccaPurpleClr* = Color(r: 0.4f, g: 0.2f, b: 0.6f, a: 1f) 39 | MaroonClr* = Color(r: 0.69f, g: 0.19f, b: 0.38f, a: 1f) 40 | OrangeClr* = Color(r: 1f, g: 0.65, b: 0f, a: 1f) 41 | 42 | 43 | func newColor*: Color = 44 | ## Creates a new color object with default values. 45 | ## Color(1f, 1f, 1f, 1f) 46 | Color(r: 1f, g: 1f, b: 1f, a: 1f) 47 | func newColor*(r, g, b: float): Color = 48 | ## Creates a new color object with default alpha value. 49 | ## Color(`r`, `g`, `b`, 1f) 50 | Color(r: r, g: g, b: b, a: 1) 51 | func newColor*(r, g, b, a: float): Color = 52 | ## Creates a new color. 53 | ## Color(`r`, `g`, `b`, `a`) 54 | Color(r: r, g: g, b: b, a: a) 55 | func newColor*(brightness: float): Color = 56 | ## Creates a new color. 57 | ## Color(`brightness`, `brightness`, `brightness`, 1f) 58 | Color(r: brightness, g: brightness, b: brightness, a: 1f) 59 | func newColor*(a: Color): Color = 60 | ## Creates a new color from other color. 61 | ## Color(`brightness`, `brightness`, `brightness`, 1f) 62 | Color(r: a.r, g: a.g, b: a.b, a: a.a) 63 | 64 | 65 | func newColor*(r, g, b: uint): Color = 66 | ## Creates a new color from unsigned integer with default alpha value (1f). 67 | Color( 68 | r: r.float / 255f, 69 | g: g.float / 255f, 70 | b: b.float / 255f, 71 | a: 1f 72 | ) 73 | func newColor*(r, g, b, a: uint): Color = 74 | ## Creates a new color from unsigned integers. 75 | Color( 76 | r: r.float / 255f, 77 | g: g.float / 255f, 78 | b: b.float / 255f, 79 | a: a.float / 255f 80 | ) 81 | 82 | 83 | when not defined(js): 84 | func newColor*(hexInteger: int64): Color = 85 | ## Creates a new color from one HEX 0xRRGGBBAA unsigned integer. 86 | Color( 87 | r: ((hexInteger and 0xFF000000) shr 24).float / 255f, 88 | g: ((hexInteger and 0x00FF0000) shr 16).float / 255f, 89 | b: ((hexInteger and 0x0000FF00) shr 8).float / 255f, 90 | a: (hexInteger and 0x000000FF).float / 255f 91 | ) 92 | 93 | func newColor*(hexInteger: int): Color = 94 | ## Creates a new color from one HEX 0xRRGGBB unsigned integer. 95 | Color( 96 | r: ((hexInteger and 0xFF0000) shr 16).float / 255f, 97 | g: ((hexInteger and 0x00FF00) shr 8).float / 255f, 98 | b: (hexInteger and 0x0000FF).float / 255f, 99 | a: 1f 100 | ) 101 | 102 | 103 | func newColor*(hexString: string): Color = 104 | ## Creates a new color from HEX string that starts with `0x`, `0X` or `#`. 105 | newColor(parseHexInt(hexString)) 106 | 107 | 108 | # --== Operators ==-- # 109 | func `$`*(clr: Color): string = 110 | ## Casts color into string 111 | fmt"clr({clr.r}, {clr.g}, {clr.b}, {clr.a})" 112 | 113 | template provideOperator(funcname, op: untyped): untyped = 114 | func `funcname`*(a, b: Color): Color = 115 | Color( 116 | r: `op`(a.r, b.r), 117 | g: `op`(a.g, b.g), 118 | b: `op`(a.b, b.b), 119 | a: `op`(a.a, b.a) 120 | ) 121 | func `funcname`*(a: float32, b: Color): Color = 122 | Color( 123 | r: `op`(a, b.r), 124 | g: `op`(a, b.g), 125 | b: `op`(a, b.b), 126 | a: `op`(a, b.a) 127 | ) 128 | func `funcname`*(a: Color, b: float32): Color = 129 | Color( 130 | r: `op`(a.r, b), 131 | g: `op`(a.g, b), 132 | b: `op`(a.b, b), 133 | a: `op`(a.a, b) 134 | ) 135 | 136 | template provideOperatorVar(operatorFunc, op: untyped): untyped = 137 | func `operatorFunc`*(a: var Color, b: Color) = 138 | `op`(a.r, b.r) 139 | `op`(a.g, b.g) 140 | `op`(a.b, b.b) 141 | `op`(a.a, b.a) 142 | func `operatorFunc`*(a: var Color, b: float) = 143 | `op`(a.r, b) 144 | `op`(a.g, b) 145 | `op`(a.b, b) 146 | `op`(a.a, b) 147 | 148 | template provideBinOperator(funcname, op: untyped): untyped = 149 | func `funcname`*(a, b: Color): bool = 150 | `op`(a.r, b.r) and 151 | `op`(a.g, b.g) and 152 | `op`(a.b, b.b) and 153 | `op`(a.a, b.a) 154 | func `funcname`*(a: float32, b: Color): bool = 155 | `op`(a, b.r) and 156 | `op`(a, b.g) and 157 | `op`(a, b.b) and 158 | `op`(a, b.a) 159 | func `funcname`*(a: Color, b: float32): bool = 160 | `op`(a.r, b) and 161 | `op`(a.g, b) and 162 | `op`(a.b, b) and 163 | `op`(a.a, b) 164 | 165 | provideOperator(`*`, `*`) 166 | provideOperator(`-`, `-`) 167 | provideOperator(`+`, `+`) 168 | provideOperator(`/`, `/`) 169 | 170 | provideOperatorVar(`*=`, `*=`) 171 | provideOperatorVar(`-=`, `-=`) 172 | provideOperatorVar(`+=`, `+=`) 173 | provideOperatorVar(`/=`, `/=`) 174 | 175 | provideBinOperator(`>`, `>`) 176 | provideBinOperator(`<`, `<`) 177 | provideBinOperator(`==`, `==`) 178 | provideBinOperator(`!=`, `!=`) 179 | 180 | 181 | # --== Methods ==-- # 182 | template provideFunc4Colors(funcname: untyped): untyped = 183 | func `funcname`*(a, b: Color): Color = 184 | Color( 185 | r: `funcname`(a.r, b.r), 186 | g: `funcname`(a.g, b.g), 187 | b: `funcname`(a.b, b.b), 188 | a: `funcname`(a.a, b.a) 189 | ) 190 | template provideFunc4Color(funcname: untyped): untyped = 191 | func `funcname`*(a: Color): Color = 192 | Color( 193 | r: `funcname`(a.r), 194 | g: `funcname`(a.g), 195 | b: `funcname`(a.b), 196 | a: `funcname`(a.a) 197 | ) 198 | 199 | provideFunc4Colors(min) 200 | provideFunc4Colors(max) 201 | provideFunc4Color(sqrt) 202 | provideFunc4Color(abs) 203 | 204 | 205 | func blend*(a, b: Color, blendMode: BlendMode = BlendMode.Normal): Color = 206 | ## Blends two colors 207 | case blendMode 208 | of BlendMode.Normal: 209 | b 210 | of BlendMode.Multiply: 211 | a*b 212 | of BlendMode.Screen: 213 | 1 - (1 - a)*(1 - b) 214 | of BlendMode.Overlay: 215 | if a < 0.5: 216 | 2*a*b 217 | else: 218 | 1 - 2*(1 - a)*(1 - b) 219 | of BlendMode.Addition: 220 | a+b 221 | of BlendMode.Substract: 222 | a-b 223 | of BlendMode.Divide: 224 | a/b 225 | of BlendMode.Diffirence: 226 | if a > b: 227 | a - b 228 | else: 229 | b - a 230 | of BlendMode.Darken: 231 | min(a, b) 232 | of BlendMode.Lighten: 233 | max(a, b) 234 | of BlendMode.SoftLight: 235 | if b < 0.5: 236 | 2*a*b + a*a*(1 - 2*b) 237 | else: 238 | 2*a*(1 - b) + sqrt(a)*(2*b - 1) 239 | 240 | 241 | # --== Other color systems ==-- # 242 | func `hue`*(a: Color): float32 = 243 | ## Calculates hue value and returns it 244 | let 245 | maxValue = max(a.r, max(a.g, a.b)) 246 | minValue = min(a.r, min(a.g, a.b)) 247 | delta = maxValue - minValue 248 | 249 | if delta != 0f: 250 | if a.r == maxValue: 251 | result = (a.g - a.b) / delta 252 | elif a.g == maxValue: 253 | result = 2f + (a.b - a.r) / delta 254 | else: 255 | result = 4f + (a.r - a.g) / delta 256 | result *= 60f 257 | if result < 0f: 258 | result += 360f 259 | result = result / 360f 260 | 261 | func `saturation`*(a: Color): float32 = 262 | ## Calculates saturation and returns it 263 | let 264 | maxValue = max(a.r, max(a.g, a.b)) 265 | minValue = min(a.r, min(a.g, a.b)) 266 | delta = maxValue - minValue 267 | 268 | if maxValue == 0: 269 | 0f 270 | else: 271 | (delta / maxValue) 272 | 273 | func `brightness`*(a: Color): float32 {.inline.} = 274 | ## Calculates color brightness 275 | max(a.r, max(a.g, a.b)) 276 | 277 | when not defined(js): 278 | func `hex`*(a: Color): int64 = 279 | ## Returns HEX integer 280 | ( 281 | ((a.r * 255f).int64 shl 24) or 282 | ((a.g * 255f).int64 shl 16) or 283 | ((a.b * 255f).int64 shl 8) or 284 | (a.a * 255f).int64 285 | ) 286 | else: 287 | func `hex`*(a: Color): int = 288 | ## Returns HEX integer 289 | ( 290 | ((a.r * 255f).int shl 16) or 291 | ((a.g * 255f).int shl 8) or 292 | ((a.b * 255f).int) 293 | ) 294 | 295 | func interpolate*(a, b: Color, t: float): Color {.inline.} = 296 | ## Returns linear interpolated color between `a` and `b` by `t`. 297 | a + (b-a)*t 298 | 299 | func cubic_interpolate*(a, b, ca, cb: Color, t: float): Color = 300 | ## Returns cubic interpolated color between `a` and `b`. 301 | Color( 302 | r: cubic_interpolate(a.r, b.r, ca.r, cb.r, t), 303 | g: cubic_interpolate(a.g, b.g, ca.g, cb.g, t), 304 | b: cubic_interpolate(a.b, b.b, ca.b, cb.b, t), 305 | a: cubic_interpolate(a.a, b.a, ca.a, cb.a, t) 306 | ) 307 | -------------------------------------------------------------------------------- /src/core/core.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Provides cross-backend support 3 | ]# 4 | # Adaptive some functions for JS 5 | when defined(js): 6 | # os.sleep(milliseconds) 7 | {.emit: "function jsSleep(ms){const d=Date.now();let c=null;do{c=Date.now()}while(c-d on_ready 24 | var evname = event_name.toLower() 25 | if not evname.startsWith("on_"): 26 | evname = "on_" & evname 27 | elif evname.startsWith("on"): 28 | evname = "on_" & evname[2..^1] 29 | # ident 30 | let ev = ident(evname) 31 | 32 | case evname: 33 | of "on_ready", "on_destroy", "on_enter", "on_exit", "on_process": 34 | result = quote do: 35 | `node`.`ev` = proc(): void = 36 | `code` 37 | of "on_input": 38 | let arg = event[1] 39 | result = quote do: 40 | `node`.`ev` = proc(`arg`: InputEvent): void = 41 | `code` 42 | 43 | 44 | macro defineNode*(nodes: untyped): untyped = 45 | ## Provides custom node definition via specified syntax: 46 | ## ```nim 47 | ## defineNode: 48 | ## MyNode(RootNode): 49 | ## - x float 50 | ## - y float 51 | ## - my_event proc(): void 52 | ## ``` 53 | # nodes - nnkStmtList 54 | result = newNimNode(nnkTypeSection) 55 | for i in nodes.children: 56 | # i - nnkCall 57 | let 58 | new_type = newNimNode(nnkTypeDef) 59 | obj_ty = newNimNode(nnkObjectTy) 60 | rec_list = newNimNode(nnkRecList) 61 | inherit_from = newNimNode(nnkOfInherit) 62 | if len(i) > 2: 63 | for param in i[2]: 64 | # - NAME TYPE 65 | rec_list.add(newIdentDefs( 66 | postfix(param[1][0], "*"), param[1][1] 67 | )) 68 | new_type.add(postfix(i[0], "*")) 69 | new_type.add(newEmptyNode()) 70 | new_type.add(obj_ty) 71 | 72 | obj_ty.add(newEmptyNode()) 73 | obj_ty.add(inherit_from) 74 | obj_ty.add(rec_list) 75 | inherit_from.add(i[1]) 76 | 77 | # Ref 78 | let 79 | ref_type = newNimNode(nnkTypeDef) 80 | ref_obj_ty = newNimNode(nnkObjectTy) 81 | ref_ty = newNimNode(nnkRefTy) 82 | ref_type.add(postfix(ident($i[0] & "Ref"), "*")) 83 | ref_type.add(newEmptyNode()) 84 | ref_type.add(ref_obj_ty) 85 | 86 | ref_ty.add(i[0]) 87 | 88 | ref_obj_ty.add(newEmptyNode()) 89 | ref_obj_ty.add(ref_ty) 90 | ref_obj_ty.add(newEmptyNode()) 91 | 92 | result.add(new_type) 93 | result.add(ref_type) 94 | -------------------------------------------------------------------------------- /src/core/hmath.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Provides helpful math functions 3 | ]# 4 | {.push inline.} 5 | func interpolate*(a, b, t: float): float = 6 | ## Returns linear interpolation 7 | ## `a` - start 8 | ## `b` - end 9 | ## `t` interpolate value between 0 and 1 10 | a + t*(b-a) 11 | 12 | func cubic_interpolate*(a, b, ca, cb, t: float): float = 13 | ## Returns cubic interpolation 14 | ## `a` - start 15 | ## `ca` - helps for `a` 16 | ## `b` - end 17 | ## `cb` - helps for `b` 18 | ## `t` interpolate value between 0 and 1 19 | a + t*(b - a + t*t*(1-t)*(ca - a + t*t*t*(b - a + cb - ca))) 20 | {.pop.} 21 | -------------------------------------------------------------------------------- /src/core/input.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Provides input events 3 | ]# 4 | import unicode 5 | 6 | 7 | type 8 | InputEventType* {.pure, size: sizeof(int8).} = enum 9 | Mouse, 10 | Touch, 11 | Motion, 12 | Wheel, 13 | Keyboard, 14 | Text, 15 | JAxisMotion, 16 | JButton, 17 | JHatMotion, 18 | Unknown 19 | 20 | InputEvent* = object 21 | kind*: InputEventType 22 | x*, y*, xrel*, yrel*, val*: float 23 | axis*: uint8 24 | key_int*, button_index*: cint 25 | key*: string 26 | pressed*: bool 27 | 28 | InputAction* = object 29 | kind*: InputEventType 30 | axis*: uint8 31 | key_int*, button_index*: cint 32 | name*, key*: string 33 | 34 | 35 | const default_input_event* = InputEvent() 36 | 37 | var 38 | actions: seq[InputAction] = @[] 39 | pressed_keys*: seq[cint] = @[] 40 | press_state*: cint = 0 41 | last_event* = InputEvent() 42 | current_event* = InputEvent() 43 | 44 | 45 | {.push inline.} 46 | func isInputEventUnknown*(a: InputEvent): bool = a.kind == InputEventType.Unknown 47 | func isInputEventKeyboard*(a: InputEvent): bool = a.kind == InputEventType.Keyboard 48 | func isInputEventJoyAxisMotion*(a: InputEvent): bool = a.kind == InputEventType.JAxisMotion 49 | func isInputEventJoyHatMotion*(a: InputEvent): bool = a.kind == InputEventType.JHatMotion 50 | func isInputEventJoyButton*(a: InputEvent): bool = a.kind == InputEventType.JButton 51 | func isInputEventMouse*(a: InputEvent): bool = a.kind == InputEventType.Mouse 52 | func isInputEventTouch*(a: InputEvent): bool = a.kind == InputEventType.Touch 53 | func isInputEventMotion*(a: InputEvent): bool = a.kind == InputEventType.Motion 54 | func isInputEventText*(a: InputEvent): bool = a.kind == InputEventType.Text 55 | func isInputEventWheel*(a: InputEvent): bool = a.kind == InputEventType.Wheel 56 | 57 | proc regButtonAction*(name: string, button: cint | uint8) = 58 | ## Register mouse button action 59 | actions.add(InputAction(kind: InputEventType.Mouse, name: name, button_index: button.cint)) 60 | proc regKeyAction*(name, key: string) = 61 | ## Register keyboard action 62 | actions.add(InputAction(kind: InputEventType.Keyboard, name: name, key: key)) 63 | proc regKeyAction*(name: string, key: cint) = 64 | ## Register keyboard action, but for keycode 65 | actions.add(InputAction(kind: InputEventType.Keyboard, name: name, key_int: key)) 66 | proc regTouchAction*(name: string) = 67 | ## Register touch action 68 | actions.add(InputAction(kind: InputEventType.Touch, name: name)) 69 | proc regJoyAxisMotion*(name: string, axis: uint8) = 70 | ## Register joystick axis motion action 71 | actions.add(InputAction(kind: InputEventType.JAxisMotion, name: name, axis: axis)) 72 | proc regJoyHatMotion*(name: string, axis: uint8) = 73 | ## Reguster joystick hat motion action 74 | actions.add(InputAction(kind: InputEventType.JHatMotion, name: name, axis: axis)) 75 | proc regJoyButton*(name: string, button_index: cint) = 76 | ## Register joystick button action 77 | actions.add(InputAction(kind: InputEventType.JButton, name: name, button_index: button_index)) 78 | {.pop.} 79 | 80 | 81 | proc isActionJustPressed*(name: string): bool = 82 | ## Returns true when action with `name` is pressed only one times 83 | for action in actions: 84 | if action.name == name and press_state == 0: 85 | if action.kind == InputEventType.Mouse and 86 | action.button_index == last_event.button_index and press_state == 0: 87 | return true 88 | elif action.kind == InputEventType.JButton and 89 | action.button_index == last_event.button_index and press_state == 0: 90 | return true 91 | elif action.kind == InputEventType.Touch and action.kind == last_event.kind: 92 | return true 93 | elif action.kind == InputEventType.Keyboard and last_event.kind == action.kind: 94 | if action.key_int == last_event.key_int or action.key == last_event.key or 95 | action.key == $Rune(last_event.key_int): 96 | return true 97 | return false 98 | 99 | 100 | proc isActionPressed*(name: string): bool = 101 | ## Returns true when action with `name` is pressed more times 102 | for action in actions: 103 | if action.name == name: 104 | if action.kind == InputEventType.Mouse and 105 | action.button_index == last_event.button_index: 106 | return true 107 | elif action.kind == InputEventType.JButton and 108 | action.button_index == last_event.button_index: 109 | return true 110 | elif action.kind == InputEventType.Touch and press_state > 0: 111 | return true 112 | elif action.kind == InputEventType.Keyboard and action.key_int in pressed_keys: 113 | return true 114 | return false 115 | 116 | 117 | proc isActionReleased*(name: string): bool = 118 | ## Returns true when action was released 119 | for action in actions: 120 | if action.name == name: 121 | if action.kind == InputEventType.Mouse and last_event.kind in [InputEventType.Mouse, InputEventType.Motion] and 122 | action.button_index == last_event.button_index and press_state == 0: 123 | return true 124 | elif action.kind == InputEventType.JButton and last_event.kind == InputEventType.JButton and 125 | action.button_index == last_event.button_index and press_state == 0: 126 | return true 127 | elif action.kind == InputEventType.Keyboard and last_event.kind == action.kind and press_state == 0: 128 | if action.key == $Rune(last_event.key_int) or action.key == last_event.key or action.key_int == last_event.key_int: 129 | return true 130 | return false 131 | -------------------------------------------------------------------------------- /src/core/mat4.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Provides Matrix4 behavior 3 | ]# 4 | 5 | type 6 | Mat4* = array[16, float32] 7 | 8 | 9 | func newMat4*: Mat4 = 10 | let x: Mat4 = [0f,0,0,0, 11 | 0,0,0,0, 12 | 0,0,0,0, 13 | 0,0,0,0] 14 | x 15 | 16 | 17 | func `[][]`*(self: Mat4, x, y: int): float = 18 | self[y*4 + x] 19 | 20 | 21 | func `[][]=`*(self: var Mat4, x, y: int, val: float) = 22 | self[y*4 + x] = val 23 | -------------------------------------------------------------------------------- /src/core/material.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Provides shader materials 3 | ]# 4 | when defined(vulkan): 5 | import 6 | ../thirdparty/vulkan 7 | 8 | const 9 | DefaultVertexCode* = "" 10 | DefaultFragmentCode* = "" 11 | DefaultTextureVertexCode* = """""" 12 | DefaultTextureFragmentCode* = """""" 13 | elif not defined(js): 14 | import 15 | ../thirdparty/opengl 16 | 17 | const 18 | DefaultVertexCode* = """ 19 | void main() 20 | { 21 | gl_Position = ftransform(); 22 | }""" 23 | DefaultFragmentCode* = """ 24 | void main() 25 | { 26 | gl_FragColor = vec4(1,1,1,1); 27 | }""" 28 | DefaultTextureVertexCode* = """""" 29 | DefaultTextureFragmentCode* = """""" 30 | else: 31 | import 32 | ../app/app, 33 | ../thirdparty/webgl, 34 | ../thirdparty/webgl/consts 35 | 36 | const 37 | DefaultVertexCode* = """ 38 | precision mediump float; 39 | 40 | attribute vec2 pos; 41 | attribute vec4 clr; 42 | uniform vec2 u_res; 43 | 44 | varying vec4 v_color; 45 | 46 | void main() { 47 | vec2 position = ((pos / u_res) * 2.0 - 1.0) * vec2(1, -1); 48 | gl_Position = vec4(position, 0, 1); 49 | v_color = clr; 50 | }""" 51 | DefaultFragmentCode* = """ 52 | precision mediump float; 53 | 54 | varying vec4 v_color; 55 | 56 | void main() { 57 | gl_FragColor = v_color; 58 | }""" 59 | DefaultTextureVertexCode* = """ 60 | precision mediump float; 61 | 62 | attribute vec2 uv; 63 | attribute vec2 pos; 64 | attribute vec4 clr; 65 | uniform vec2 u_res; 66 | 67 | varying vec2 v_tex_coords; 68 | varying vec4 v_color; 69 | varying vec2 v_res; 70 | 71 | void main() { 72 | vec2 position = ((pos / u_res) * 2.0 - 1.0) * vec2(1, -1); 73 | gl_Position = vec4(position, 0, 1); 74 | v_color = clr; 75 | v_res = u_res; 76 | v_tex_coords = uv; 77 | }""" 78 | DefaultTextureFragmentCode* = """ 79 | precision mediump float; 80 | 81 | varying vec4 v_color; 82 | varying vec2 v_res; 83 | varying vec2 v_tex_coords; 84 | uniform sampler2D u_texture; 85 | 86 | void main() { 87 | gl_FragColor = texture2D(u_texture, v_tex_coords) * v_color; 88 | }""" 89 | 90 | 91 | type 92 | ShaderMaterial* = ref object 93 | when defined(js): 94 | vertexCode*: cstring 95 | fragmentCode*: cstring 96 | else: 97 | vertexCode*: string 98 | fragmentCode*: string 99 | when defined(vulkan): 100 | discard 101 | elif not defined(js): 102 | program*: GLuint 103 | vertexShader: GLuint 104 | fragmentShader: GLuint 105 | else: 106 | program*: WebGLProgram 107 | vertexShader: WebGLShader 108 | fragmentShader: WebGLShader 109 | isCompiled: bool 110 | 111 | 112 | proc newShaderMaterial*: ShaderMaterial = 113 | ## Creates a new shader material 114 | result = ShaderMaterial(vertexCode: DefaultVertexCode, fragmentCode: DefaultFragmentCode) 115 | when defined(vulkan): 116 | discard 117 | elif not defined(js): 118 | result.program = glCreateProgram() 119 | result.vertexShader = glCreateShader(GL_VERTEX_SHADER) 120 | result.fragmentShader = glCreateShader(GL_FRAGMENT_SHADER) 121 | else: 122 | result.program = gl.createProgram() 123 | result.vertexShader = gl.createShader(VERTEX_SHADER) 124 | result.fragmentShader = gl.createShader(FRAGMENT_SHADER) 125 | 126 | 127 | func isCompiled*(self: ShaderMaterial): bool = self.isCompiled 128 | 129 | 130 | proc compile*(self: ShaderMaterial) = 131 | ## Compiles shaders 132 | when defined(vulkan): 133 | discard 134 | elif not defined(js): 135 | var 136 | vertexSource = allocCStringArray([self.vertexCode]) 137 | fragmentSource = allocCStringArray([self.fragmentCode]) 138 | glShaderSource(self.vertexShader, 1, vertexSource, nil) 139 | glShaderSource(self.fragmentShader, 1, fragmentSource, nil) 140 | 141 | glCompileShader(self.vertexShader) 142 | glCompileShader(self.fragmentShader) 143 | # free memory 144 | deallocCStringArray(vertexSource) 145 | deallocCStringArray(fragmentSource) 146 | 147 | glAttachShader(self.program, self.vertexShader) 148 | glAttachShader(self.program, self.fragmentShader) 149 | glLinkProgram(self.program) 150 | else: 151 | gl.shaderSource(self.vertexShader, self.vertexCode) 152 | gl.shaderSource(self.fragmentShader, self.fragmentCode) 153 | 154 | gl.compileShader(self.vertexShader) 155 | if not gl.getStatus(self.vertexShader): 156 | echo gl.getShaderInfoLog(self.vertexShader) 157 | echo self.vertexCode 158 | gl.compileShader(self.fragmentShader) 159 | if not gl.getStatus(self.fragmentShader): 160 | echo gl.getShaderInfoLog(self.fragmentShader) 161 | echo self.fragmentCode 162 | 163 | when defined(debug): 164 | {.emit: """ 165 | let src = `gl`.getExtension('WEBGL_debug_shaders').getTranslatedShaderSource(`self`.`vertexShader`); 166 | console.log(src); 167 | src = `gl`.getExtension('WEBGL_debug_shaders').getTranslatedShaderSource(`self`.`fragmentShader`); 168 | console.log(src); 169 | """.} 170 | 171 | gl.attachShader(self.program, self.vertexShader) 172 | gl.attachShader(self.program, self.fragmentShader) 173 | 174 | gl.linkProgram(self.program) 175 | if not gl.getStatus(self.program): 176 | echo gl.getProgramInfoLog(self.program) 177 | self.isCompiled = true 178 | 179 | 180 | proc destroy*(self: ShaderMaterial) = 181 | ## Destroys shader program 182 | when defined(vulkan): 183 | discard 184 | elif not defined(js): 185 | glDeleteProgram(self.program) 186 | else: 187 | gl.deleteProgram(self.program) 188 | 189 | 190 | proc use*(self: ShaderMaterial) = 191 | ## Use current program 192 | when defined(vulkan): 193 | discard 194 | elif not defined(js): 195 | glUseProgram(self.program) 196 | else: 197 | gl.useProgram(self.program) 198 | 199 | 200 | proc unuse*(self: ShaderMaterial) = 201 | ## Use current program 202 | when defined(vulkan): 203 | discard 204 | elif not defined(js): 205 | glUseProgram(0) 206 | else: 207 | gl.useProgram(nil) 208 | -------------------------------------------------------------------------------- /src/core/rect.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Provides Rect behavior 3 | ]# 4 | import 5 | ./vec2 6 | 7 | 8 | type 9 | Rect* = object 10 | x*, y*, w*, h*: float 11 | 12 | 13 | func newRect*: Rect = 14 | Rect(x: 0f, y: 0f, w: 1f, h: 1f) 15 | 16 | func newRect*(w, h: float): Rect = 17 | Rect(x: 0f, y: 0f, w: w, h: h) 18 | 19 | func newRect*(x, y, w, h: float): Rect = 20 | Rect(x: x, y: y, w: w, h: h) 21 | 22 | func newRect*(wh: Vec2): Rect = 23 | Rect(x: 0f, y: 0f, w: wh.x, h: wh.y) 24 | 25 | func newRect*(xy, wh: Vec2): Rect = 26 | Rect(x: xy.x, y: xy.y, w: wh.x, h: wh.y) 27 | 28 | 29 | func left*(a: Rect): float = a.x 30 | func right*(a: Rect): float = a.x+a.w 31 | func top*(a: Rect): float = a.y 32 | func bottom*(a: Rect): float = a.y+a.h 33 | 34 | 35 | func contains*(a, b: Rect): bool = 36 | ## Returns true when rect `a` contains rect `b` 37 | a.x <= b.x and a.y <= b.y and a.w >= b.w and a.h >= b.h 38 | 39 | 40 | func contains*(a: Rect, b: Vec2): bool = 41 | ## Returns true when rect `a` contains point `b` 42 | a.x <= b.x and a.x+a.w >= b.x and a.y <= b.y and a.y+a.h >= b.y 43 | 44 | 45 | func contains*(a: Rect, b, c: Vec2): bool = 46 | ## Returns true when rect `a` contains segment `b`, `c` 47 | a.contains(b) and a.contains(b) 48 | 49 | 50 | func intersects*(a: Rect, b, c: Vec2): bool = 51 | ## Returns true when rect `a` intersects with segment `b`,`c` 52 | a.contains(b, c) or 53 | intersects(newVec2(a.left, a.top), newVec2(a.right, a.top), b, c) or 54 | intersects(newVec2(a.left, a.top), newVec2(a.left, a.bottom), b, c) or 55 | intersects(newVec2(a.left, a.bottom), newVec2(a.right, a.bottom), b, c) or 56 | intersects(newVec2(a.right, a.top), newVec2(a.right, a.bottom), b, c) 57 | -------------------------------------------------------------------------------- /src/core/vec2.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Provides working with Vec2 3 | ]# 4 | import 5 | strformat, 6 | math, 7 | ./hmath, 8 | ./exceptions 9 | 10 | type 11 | Vec2* = object 12 | x*, y*: float 13 | 14 | const 15 | Vec2Up* = Vec2(x: 0f, y: 1f) 16 | Vec2Down* = Vec2(x: 0f, y: -1f) 17 | Vec2Right* = Vec2(x: 1f, y: 0f) 18 | Vec2Left* = Vec2(x: -1f, y: 0f) 19 | 20 | func newVec2*(x, y: float32): Vec2 = Vec2(x: x, y: y) 21 | func newVec2*(xy: float32): Vec2 = Vec2(x: xy, y: xy) 22 | func newVec2*(a: Vec2): Vec2 = Vec2(x: a.x, y: a.y) 23 | func newVec2*: Vec2 = Vec2(x: 0f, y: 0f) 24 | 25 | 26 | # --== Operators ==-- # 27 | template provideOperator(operatorFunc, op: untyped): untyped = 28 | func `operatorFunc`*(a, b: Vec2): Vec2 {.inline.} = 29 | Vec2(x: `op`(a.x, b.x), y: `op`(a.y, b.y)) 30 | func `operatorFunc`*(a: float, b: Vec2): Vec2 {.inline.} = 31 | Vec2(x: `op`(a, b.x), y: `op`(a, b.y)) 32 | func `operatorFunc`*(a: Vec2, b: float): Vec2 {.inline.} = 33 | Vec2(x: `op`(a.x, b), y: `op`(a.y, b)) 34 | 35 | template provideOperatorVar(operatorFunc, op: untyped): untyped = 36 | func `operatorFunc`*(a: var Vec2, b: Vec2) = 37 | `op`(a.x, b.x) 38 | `op`(a.y, b.y) 39 | func `operatorFunc`*(a: var Vec2, b: float) = 40 | `op`(a.x, b) 41 | `op`(a.y, b) 42 | 43 | template provideBinOperator(operatorFunc, op: untyped): untyped = 44 | func `operatorFunc`*(a, b: Vec2): bool {.inline.} = 45 | `op`(a.x, b.x) and `op`(a.y, b.y) 46 | 47 | func `$`*(a: Vec2): string = fmt"vec2({a.x}, {a.y})" 48 | 49 | func `[]`*(a: Vec2, index: int): float = 50 | if index == 0: 51 | a.x 52 | elif index == 1: 53 | a.y 54 | else: 55 | raise newException(OutOfIndexDefect, fmt"{index} is out of bounds") 56 | 57 | func `[]=`*(a: var Vec2, index: int, val: float): float = 58 | if index == 0: 59 | a.x = val 60 | elif index == 1: 61 | a.y = val 62 | else: 63 | raise newException(OutOfIndexDefect, fmt"{index} is out of bounds") 64 | 65 | provideOperator(`+`, `+`) 66 | provideOperator(`-`, `-`) 67 | provideOperator(`*`, `*`) 68 | provideOperator(`/`, `/`) 69 | 70 | provideOperatorVar(`+=`, `+=`) 71 | provideOperatorVar(`-=`, `-=`) 72 | provideOperatorVar(`*=`, `*=`) 73 | provideOperatorVar(`/=`, `/=`) 74 | 75 | provideBinOperator(`==`, `==`) 76 | provideBinOperator(`!=`, `!=`) 77 | provideBinOperator(`>`, `>`) 78 | provideBinOperator(`<`, `<`) 79 | 80 | # --== Methods ==-- # 81 | template provideAnyFunc(funcname: untyped, oneArg: bool = false): untyped = 82 | when oneArg: 83 | func `funcname`*(a: Vec2): Vec2 = 84 | Vec2( 85 | x: `funcname`(a.x), 86 | y: `funcname`(a.y) 87 | ) 88 | else: 89 | func `funcname`*(a, b: Vec2): Vec2 = 90 | Vec2( 91 | x: `funcname`(a.x, b.x), 92 | y: `funcname`(a.y, b.y) 93 | ) 94 | 95 | provideAnyFunc(min) 96 | provideAnyFunc(max) 97 | provideAnyFunc(sqrt, true) 98 | provideAnyFunc(abs, true) 99 | 100 | func aspect*(a: Vec2): float {.inline.} = 101 | ## Returns ratio of X to Y 102 | a.x / a.y 103 | 104 | func scalar*(a, b: Vec2): float {.inline.} = 105 | ## Scalar product of a and b 106 | a.x*b.x + a.y*b.y 107 | 108 | func len*(a: Vec2): float {.inline.} = 109 | ## Returns length of `a` vector. 110 | sqrt(a.x*a.x + a.y*a.y) 111 | 112 | func lenSquared*(a: Vec2): float {.inline.} = 113 | ## Returns squared vector length 114 | a.x*a.x + a.y*a.y 115 | 116 | func interpolate*(a, b: Vec2, t: 0f..1f): Vec2 {.inline.} = 117 | ## Returns linear interpolated vector 118 | a + (b - a)*t 119 | 120 | func cubic_interpolate*(a, b, ca, cb: Vec2, t: float): Vec2 = 121 | ## Returns cubic interpolated vector between `a` and `b`. 122 | Vec2( 123 | x: cubic_interpolate(a.x, b.x, ca.x, cb.x, t), 124 | y: cubic_interpolate(a.y, b.y, ca.y, cb.y, t) 125 | ) 126 | 127 | func angle*(a: Vec2): float = 128 | ## Vector angle 129 | arctan2(a.x, a.y) 130 | 131 | func angle2*(a, b: Vec2): float = 132 | ## Angle between a and b vectors 133 | let length = a.len 134 | if length != 0: 135 | arccos(a.scalar(b) / length) 136 | else: 137 | 0f 138 | 139 | func dot*(a, b: Vec2): float = 140 | ## Dot product 141 | a.len * b.len * cos(a.angle2(b)) 142 | 143 | func dist2*(a, b: Vec2): float {.inline.} = 144 | ## Distance from a to b 145 | (b - a).len 146 | 147 | func normalized*(a: Vec2): Vec2 {.inline.} = 148 | ## Normalized vector 149 | a / a.len 150 | 151 | func isNorm*(a: Vec2): bool {.inline.} = 152 | ## Returns true if a is normailized 153 | a.x <= 1f and a.y <= 1f 154 | 155 | func rotated*(a: Vec2, b: float): Vec2 = 156 | ## Rotate vector by angle 157 | Vec2( 158 | x: a.x*cos(b) - a.y*sin(b), 159 | y: a.x*sin(b) + a.y*cos(b) 160 | ) 161 | 162 | func tangent*(a: Vec2): Vec2 {.inline.} = 163 | ## Returns perpendicular vector 164 | a.rotated(PI/2) 165 | 166 | func snapped*(a, s: Vec2): Vec2 = 167 | ## Rounds `a` by `s` step 168 | Vec2( 169 | x: s.x * floor(a.x / s.x), 170 | y: s.y * floor(a.y / s.y) 171 | ) 172 | 173 | func bounce*(a, b: Vec2): Vec2 {.inline.} = 174 | ## Returns vector "bounced off" from the plane, specified by `b` normal vector. 175 | a - 2*dot(a, b)*b 176 | 177 | func clamped*(a: Vec2, length: float): Vec2 {.inline.} = 178 | ## Returns vector with maximum length 179 | a * (length / a.len) 180 | 181 | func intersects*(a, b, c, d: Vec2): bool = 182 | ## Returns true when line `a`,`b` intersects with line `c`,`d`. 183 | let t = (b.x - a.x)*(d.y - c.y) - (b.y - a.y)*(d.x - c.x) 184 | if t != 0: 185 | let 186 | r = ((a.y - c.y)*(d.x - c.x) - (a.x - c.x)*(d.y - c.y)) / t 187 | s = ((a.y - c.y)*(b.x - a.x) - (a.x - c.x)*(b.y - a.y)) / t 188 | if r >= 0 and r <= 1 and s >= 0 and s <= 1: 189 | return true 190 | false 191 | -------------------------------------------------------------------------------- /src/core/vec3.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Provides working with Vec3 3 | ]# 4 | import 5 | strformat, 6 | math, 7 | ./hmath, 8 | ./exceptions 9 | 10 | 11 | type 12 | Vec3* = object 13 | x*, y*, z*: float 14 | Axis* {.pure, size: sizeof(int8).} = enum 15 | X = 0 16 | Y = 1 17 | Z = 2 18 | 19 | 20 | const 21 | Vec3Up* = Vec3(x: 0f, y: 1f, z: 0f) 22 | Vec3Down* = Vec3(x: 0f, y: -1f, z: 0f) 23 | Vec3Right* = Vec3(x: 1f, y: 0f, z: 0f) 24 | Vec3Left* = Vec3(x: -1f, y: 0f, z: 0f) 25 | Vec3Toward* = Vec3(x: 0f, y: 0f, z: 1f) 26 | Vec3Backward* = Vec3(x: 0f, y: 0f, z: -1f) 27 | 28 | 29 | func newVec3*(x, y, z: float): Vec3 = Vec3(x: x, y: y, z: z) 30 | func newVec3*(xyz: float): Vec3 = Vec3(x: xyz, y: xyz, z: xyz) 31 | func newVec3*(a: Vec3): Vec3 = Vec3(x: a.x, y: a.y, z: a.z) 32 | func newVec3*: Vec3 = Vec3(x: 0f, y: 0f, z: 0f) 33 | 34 | 35 | # --== Operators ==-- # 36 | template provideOperator(operatorFunc, op: untyped): untyped = 37 | func `operatorFunc`*(a, b: Vec3): Vec3 {.inline.} = 38 | Vec3(x: `op`(a.x, b.x), y: `op`(a.y, b.y), z: `op`(a.z, b.z)) 39 | func `operatorFunc`*(a: float, b: Vec3): Vec3 {.inline.} = 40 | Vec3(x: `op`(a, b.x), y: `op`(a, b.y), z: `op`(a, b.z)) 41 | func `operatorFunc`*(a: Vec3, b: float): Vec3 {.inline.} = 42 | Vec3(x: `op`(a.x, b), y: `op`(a.y, b), z: `op`(a.z, b)) 43 | 44 | template provideOperatorVar(operatorFunc, op: untyped): untyped = 45 | func `operatorFunc`*(a: var Vec3, b: Vec3) = 46 | `op`(a.x, b.x) 47 | `op`(a.y, b.y) 48 | `op`(a.z, b.z) 49 | func `operatorFunc`*(a: var Vec3, b: float) = 50 | `op`(a.x, b) 51 | `op`(a.y, b) 52 | `op`(a.z, b) 53 | 54 | template provideBinOperator(operatorFunc, op: untyped): untyped = 55 | func `operatorFunc`*(a, b: Vec3): bool {.inline.} = 56 | `op`(a.x, b.x) and `op`(a.y, b.y) and `op`(a.z, b.z) 57 | 58 | func `$`*(a: Vec3): string = fmt"Vec3({a.x}, {a.y}, {a.z})" 59 | 60 | func `[]`*(a: Vec3, index: int): float = 61 | if index == 0: 62 | a.x 63 | elif index == 1: 64 | a.y 65 | elif index == 2: 66 | a.z 67 | else: 68 | raise newException(OutOfIndexDefect, fmt"{index} is out of bounds") 69 | 70 | func `[]=`*(a: var Vec3, index: int, val: float): float = 71 | if index == 0: 72 | a.x = val 73 | elif index == 1: 74 | a.y = val 75 | elif index == 2: 76 | a.z = val 77 | else: 78 | raise newException(OutOfIndexDefect, fmt"{index} is out of bounds") 79 | 80 | provideOperator(`+`, `+`) 81 | provideOperator(`-`, `-`) 82 | provideOperator(`*`, `*`) 83 | provideOperator(`/`, `/`) 84 | 85 | provideOperatorVar(`+=`, `+=`) 86 | provideOperatorVar(`-=`, `-=`) 87 | provideOperatorVar(`*=`, `*=`) 88 | provideOperatorVar(`/=`, `/=`) 89 | 90 | provideBinOperator(`==`, `==`) 91 | provideBinOperator(`!=`, `!=`) 92 | provideBinOperator(`>`, `>`) 93 | provideBinOperator(`<`, `<`) 94 | 95 | # --== Methods ==-- # 96 | template provideAnyFunc(funcname: untyped, oneArg: bool = false): untyped = 97 | when oneArg: 98 | func `funcname`*(a: Vec3): Vec3 = 99 | Vec3( 100 | x: `funcname`(a.x), 101 | y: `funcname`(a.y), 102 | z: `funcname`(a.y) 103 | ) 104 | else: 105 | func `funcname`*(a, b: Vec3): Vec3 = 106 | Vec3( 107 | x: `funcname`(a.x, b.x), 108 | y: `funcname`(a.y, b.y), 109 | z: `funcname`(a.z, b.z) 110 | ) 111 | 112 | provideAnyFunc(min) 113 | provideAnyFunc(max) 114 | provideAnyFunc(sqrt, true) 115 | provideAnyFunc(abs, true) 116 | 117 | func max_axis*(a: Vec3): Axis = 118 | ## Returns largest axis 119 | let m = max(a.x, max(a.y, a.z)) 120 | if m == a.x: 121 | Axis.X 122 | elif m == a.y: 123 | Axis.Y 124 | else: 125 | Axis.Z 126 | 127 | func min_axis*(a: Vec3): Axis = 128 | ## Returns smallest axis 129 | let m = min(a.x, min(a.y, a.z)) 130 | if m == a.x: 131 | Axis.X 132 | elif m == a.y: 133 | Axis.Y 134 | else: 135 | Axis.Z 136 | 137 | func inversed*(a: Vec3): Vec3 = 138 | ## Returns inversed vector 139 | Vec3(x: 1f / a.x, y: 1f / a.y, z: 1f / a.z) 140 | 141 | func cross*(a, b: Vec3): Vec3 = 142 | ## Calculates the cross product of `a` and `b` 143 | Vec3( 144 | x: a.y * b.z - a.z * b.y, 145 | y: a.z * b.x - a.x * b.z, 146 | z: a.x * b.y - a.y * b.x 147 | ) 148 | 149 | func dot*(a, b: Vec3): float {.inline.} = 150 | ## dot product of a and b 151 | a.x*b.x + a.y*b.y + a.z*b.z 152 | 153 | func len*(a: Vec3): float {.inline.} = 154 | ## Vector length 155 | sqrt(a.x*a.x + a.y*a.y + a.z*a.z) 156 | 157 | func lenSquared*(a: Vec3): float {.inline.} = 158 | ## Returns squared vector length 159 | a.x*a.x + a.y*a.y + a.z*a.z 160 | 161 | func interpolate*(a, b: Vec3, t: 0f..1f): Vec3 {.inline.} = 162 | ## Returns linear interpolated vector 163 | a + (b - a)*t 164 | 165 | func cubic_interpolate*(a, b, ca, cb: Vec3, t: float): Vec3 = 166 | ## Returns cubic interpolated vector between `a` and `b`. 167 | Vec3( 168 | x: cubic_interpolate(a.x, b.x, ca.x, cb.x, t), 169 | y: cubic_interpolate(a.y, b.y, ca.y, cb.y, t), 170 | z: cubic_interpolate(a.z, b.z, ca.z, cb.z, t) 171 | ) 172 | 173 | func rotated*(a, axis: Vec3, angle: float): Vec3 = 174 | ## Rotates a vector `a` around an `axis` by `angle` 175 | ## 176 | ## Arguments: 177 | ## - `a` the vector to be rotated 178 | ## - `axis` the axis of rotation, represent as `Vec3` object 179 | ## - `angle` the angle in radians. 180 | let 181 | c = cos(angle) 182 | s = sin(angle) 183 | t = 1f - c 184 | (x, y, z) = (a.x, a.y, a.z) 185 | (u, v, w) = (axis.x, axis.y, axis.z) 186 | Vec3( 187 | x: x * (c + u * u * t) + y * (u * v * t - w * s) + z * (u * w * t + v * s), 188 | y: x * (v * u * t + w * s) + y * (c * v * v * t) + z * (v * w * t - u * s), 189 | z: x * (w * u * t - v * s) + y * (w * v * t + u * s) + z * (c + w * w * t) 190 | ) 191 | 192 | func rotatedX*(a: Vec3, angle: float): Vec3 {.inline.} = 193 | ## Rotates vector `a` around x-axis by `angle`. 194 | rotated(a, Vec3Right, angle) 195 | 196 | func rotatedY*(a: Vec3, angle: float): Vec3 {.inline.} = 197 | ## Rotates vector `a` around y-axis by `angle`. 198 | rotated(a, Vec3Up, angle) 199 | 200 | func rotatedZ*(a: Vec3, angle: float): Vec3 {.inline.} = 201 | ## Rotates vector `a` around z-axis by `angle`. 202 | rotated(a, Vec3Toward, angle) 203 | 204 | func rotated*(a: Vec3, axis: Axis, angle: float): Vec3 {.inline.} = 205 | ## Rotates vector `a` around axis by `angle`. 206 | case axis 207 | of Axis.X: 208 | a.rotatedX(angle) 209 | of Axis.Y: 210 | a.rotatedY(angle) 211 | of Axis.Z: 212 | a.rotatedZ(angle) 213 | 214 | func angle2*(a, b: Vec3): float = 215 | ## Calculates the angle between `a` and `b` in radians 216 | let m = a.len * b.len 217 | if m == 0: 218 | 0f 219 | else: 220 | arccos(dot(a, b) / m) 221 | 222 | func dist2*(a, b: Vec3): float {.inline.} = 223 | ## Distance from a to b 224 | (b - a).len 225 | 226 | func normalized*(a: Vec3): Vec3 {.inline.} = 227 | ## Normalized vector 228 | a / a.len 229 | 230 | func normalize*(a: var Vec3) = 231 | ## Normalizes var vector 232 | a = a / a.len 233 | 234 | func isNorm*(a: Vec3): bool {.inline.} = 235 | ## Returns true if a is normailized 236 | a.x <= 1f and a.y <= 1f 237 | 238 | func snapped*(a, s: Vec3): Vec3 = 239 | ## Rounds `a` by `s` step 240 | Vec3( 241 | x: s.x * floor(a.x / s.x), 242 | y: s.y * floor(a.y / s.y), 243 | z: s.z * floor(a.z / s.z) 244 | ) 245 | 246 | func snap*(a: var Vec3, s: Vec3) = 247 | ## Rounds `a` by `s` step. 248 | a.x = s.x * floor(a.x / s.x) 249 | a.y = s.y * floor(a.y / s.y) 250 | a.z = s.z * floor(a.z / s.z) 251 | 252 | func bounce*(a, b: Vec3): Vec3 {.inline.} = 253 | ## Returns vector "bounced off" from the plane, specified by `b` normal vector. 254 | a - 2*dot(a, b)*b 255 | 256 | func clamped*(a: Vec3, length: float): Vec3 {.inline.} = 257 | ## Returns vector with maximum length 258 | a * (length / a.len) 259 | 260 | 261 | func reflect*(a, plane: Vec3): Vec3 {.inline.} = 262 | ## Reflects the vector `a` along the given plane by its normal vector `plane` 263 | a - plane * 2 * dot(a, plane) 264 | 265 | func intersects*(a, b, c, d: Vec3): bool = 266 | ## Returns true when line `a`,`b` intersects with line `c`,`d`. 267 | let t = (b.x - a.x)*(d.y - c.y) - (b.y - a.y)*(d.x - c.x) - (b.z - a.z)*(d.z - c.z) 268 | if t != 0: 269 | let 270 | r = ((a.y - c.y)*(d.x - c.x) - (a.x - c.x)*(d.y - c.y) - (a.z - c.z)*(d.z - c.z)) / t 271 | s = ((a.y - c.y)*(b.x - a.x) - (a.x - c.x)*(b.y - a.y) - (a.z - c.z)*(d.z - a.z)) / t 272 | if r >= 0 and r <= 1 and s >= 0 and s <= 1: 273 | return true 274 | false 275 | -------------------------------------------------------------------------------- /src/core/vkmanager.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Provides vulkan wrapper 3 | ]# 4 | import 5 | strutils, 6 | strformat, 7 | unicode, 8 | options, 9 | ./exceptions, 10 | ../thirdparty/vulkan 11 | 12 | 13 | once: 14 | # Load vulkan library 15 | vkPreload() 16 | 17 | 18 | type 19 | VulkanManager* = object 20 | instance: VkInstance 21 | create_info: VkInstanceCreateInfo 22 | app_info: VkApplicationInfo 23 | when defined(debug): 24 | debugger: VkDebugUtilsMessengerEXT 25 | debugger_create_info: VkDebugUtilsMessengerCreateInfoEXT 26 | QueueFamilyIndices* = object 27 | graphicsFamily*: Option[uint32] 28 | presentFamily*: Option[uint32] 29 | 30 | 31 | func isComplete*(a: QueueFamilyIndices): bool = 32 | a.graphicsFamily.isSome and a.presentFamily.isSome 33 | 34 | 35 | proc checkExtensionLayers*: tuple[count: uint32, arr: array[32, VkExtensionProperties]] {.discardable.} = 36 | ## Checks available vulkan extensions 37 | var 38 | extCount: uint32 39 | extensions: array[32, VkExtensionProperties] 40 | discard vkEnumerateInstanceExtensionProperties(nil, addr extCount, nil) 41 | discard vkEnumerateInstanceExtensionProperties(nil, addr extCount, cast[ptr VkExtensionProperties](addr extensions)) 42 | 43 | when defined(debug): 44 | echo "Available extension layers" 45 | for ext in extensions: 46 | echo $(join(ext.extensionName).toRunes()) 47 | (extCount, extensions) 48 | 49 | 50 | proc checkInstanceLayers*(): tuple[count: uint32, arr: array[32, VkLayerProperties]] {.discardable.} = 51 | ## Checks available vulkan instance layers 52 | var 53 | layerCount: uint32 54 | availableLayers: array[32, VkLayerProperties] 55 | discard vkEnumerateInstanceLayerProperties(addr layerCount, nil) 56 | discard vkEnumerateInstanceLayerProperties(addr layerCount, cast[ptr VkLayerProperties](addr availableLayers)) 57 | 58 | when defined(debug): 59 | echo "Available instance layers" 60 | for layerProperties in availableLayers: 61 | echo $(join(layerProperties.layerName).toRunes()) 62 | (layerCount, availableLayers) 63 | 64 | 65 | proc checkValidationLayersSupport*(validationLayers: openArray[string] | seq[string]): bool = 66 | ## Returns true when validation layers is supported 67 | let layers = checkInstanceLayers() 68 | 69 | for layerName in validationLayers: 70 | var layerFound = false 71 | 72 | for layer in layers.arr: 73 | var name = "" 74 | for c in layer.layerName: 75 | if c != '\x00': 76 | name &= c 77 | if name == layerName: 78 | layerFound = true 79 | break 80 | 81 | if not layerFound: 82 | return false 83 | true 84 | 85 | 86 | proc isDeviceSuitable*(device: VkPhysicalDevice): bool = 87 | ## Check for extension support 88 | var indices: QueueFamilyIndices 89 | 90 | 91 | proc initVulkan*(): VulkanManager = 92 | ## Initializes and returns vk instance 93 | result = VulkanManager() 94 | let version: uint32 = vkMakeVersion(0, 1, 5) 95 | # Register Application info 96 | result.app_info = newVkApplicationInfo( 97 | pApplicationName = "HapticX engine", 98 | pEngineName = "HapticX", 99 | applicationVersion = 1, 100 | engineVersion = version, 101 | apiVersion = vkApiVersion1_2 102 | ) 103 | when defined(debug): 104 | ## Adds validation layers in VkInstanceCreateInfo 105 | var 106 | # Get all layers 107 | (extCount, extArr) = checkExtensionLayers() 108 | (layersCount, layersArr) = checkInstanceLayers() 109 | # layer name 110 | name: string 111 | ppLayers: seq[string] = @[] 112 | ppExtensions: seq[string] = @[] 113 | # Extension names handler 114 | for i in extArr.low..extArr.high: 115 | name = "" 116 | for j in extArr[i].extensionName: 117 | if j != '\x00': 118 | name &= j 119 | if name.len > 0: 120 | ppExtensions.add(name) 121 | # Instance layer names handler 122 | for i in layersArr.low..layersArr.high: 123 | name = "" 124 | for j in layersArr[i].layerName: 125 | if j != '\x00': 126 | name &= j 127 | if name.len > 0: 128 | ppLayers.add(name) 129 | # Add layers into VkInstanceCreateInfo 130 | result.create_info = newVkInstanceCreateInfo( 131 | pApplicationInfo = addr result.app_info, 132 | enabledLayerCount = layersCount, 133 | ppEnabledLayerNames = allocCStringArray(ppLayers.toOpenArray(ppLayers.low, ppLayers.high)), 134 | enabledExtensionCount = extCount, 135 | ppEnabledExtensionNames = allocCStringArray(ppExtensions.toOpenArray(ppExtensions.low, ppExtensions.high)) 136 | ) 137 | else: 138 | # Without debug mode validation layers is not added 139 | result.create_info = newVkInstanceCreateInfo( 140 | pApplicationInfo = addr result.app_info, 141 | enabledLayerCount = 0, 142 | ppEnabledLayerNames = nil, 143 | enabledExtensionCount = 0, 144 | ppEnabledExtensionNames = nil 145 | ) 146 | let res = vkCreateInstance(addr result.create_info, nil, addr result.instance) 147 | # Check for errors 148 | if res != VK_SUCCESS or not vkInit(result.instance): 149 | raise newException(VkInitDefect, fmt"Error when trying to initialize vulkan - {res}") 150 | echo checkValidationLayersSupport(@["VK_LAYER_AMD_switchable_graphics"]) 151 | 152 | 153 | proc display*(m: VulkanManager) = 154 | ## Displays via Vulkan API 155 | discard 156 | 157 | 158 | proc cleanUp*(m: VulkanManager) = 159 | ## Cleans up vulkan 160 | vkDestroyInstance(m.instance, nil) 161 | -------------------------------------------------------------------------------- /src/hapticx.nim: -------------------------------------------------------------------------------- 1 | import 2 | core/[ 3 | color, vec2, vec3, animatable, basis, 4 | hmacros, exceptions, rect, input, material, 5 | mat4 6 | ], 7 | nodes/[node, scene, canvas], 8 | app/[app, environment] 9 | 10 | export 11 | # core 12 | color, vec2, vec3, animatable, basis, 13 | hmacros, exceptions, rect, input, material, 14 | mat4, 15 | # nodes 16 | node, scene, canvas, 17 | # application 18 | app, environment 19 | -------------------------------------------------------------------------------- /src/nodes/canvas.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Provides Canvas behavior 3 | ]# 4 | import 5 | ./node, 6 | ../private/templates, 7 | ../core/enums, 8 | ../core/color, 9 | ../core/input, 10 | ../core/material 11 | 12 | 13 | when defined(vulkan): 14 | import 15 | ../thirdparty/vulkan, 16 | ../core/vkmanager 17 | elif not defined(js): 18 | import 19 | ../thirdparty/opengl, 20 | ../core/glmanager 21 | else: 22 | import 23 | ../thirdparty/webgl, 24 | ../thirdparty/webgl/consts, 25 | ../core/glmanager, 26 | ../app/app 27 | 28 | 29 | type 30 | HCanvasRef* = ref HCanvas 31 | HCanvas* = object of HNode 32 | x*, y*: float 33 | w*, h*: float 34 | screenw*, screenh*: float 35 | material*: ShaderMaterial 36 | when defined(vulkan): 37 | discard 38 | elif not defined(js): 39 | fbo: GLuint # Framebuffer object 40 | rbo: GLuint # Renderbuffer object 41 | tex: GLuint # color texture 42 | else: 43 | fbo: WebGLFramebuffer 44 | rbo: WebGLRenderbuffer 45 | tex: WebGLTexture 46 | 47 | 48 | proc newHCanvas*(tag: string = "HCanvas"): HCanvasRef = 49 | ## Creates a new HCanvas 50 | defaultNode(HCanvasRef) 51 | result.x = 0f 52 | result.y = 0f 53 | result.w = 512f 54 | result.h = 512f 55 | result.material = newShaderMaterial() 56 | result.material.fragmentCode = DefaultTextureFragmentCode 57 | result.material.vertexCode = DefaultTextureVertexCode 58 | when defined(vulkan): 59 | discard 60 | elif not defined(js): 61 | ## Generates framebuffers and textures 62 | result.tex = emptyTexture2D(GL_RGBA, GL_RGBA, result.w.Glsizei, result.h.Glsizei) 63 | result.fbo = initFramebuffers(result.tex, result.rbo, result.w, result.h) 64 | else: 65 | result.tex = emptyTexture2D(RGBA.int, RGBA.uint, result.w.int, result.h.int) 66 | result.fbo = initFramebuffers(result.tex, result.rbo, result.w, result.h) 67 | 68 | 69 | method destroy*(self: HCanvasRef) = 70 | ## Destroys canvas 71 | self.material.destroy() 72 | when defined(vulkan): 73 | discard 74 | elif not defined(js): 75 | ## Deletes framebuffer and texture 76 | glDeleteFramebuffers(1, addr self.fbo) 77 | glDeleteRenderbuffers(1, addr self.rbo) 78 | glDeleteTextures(1, addr self.tex) 79 | else: 80 | gl.deleteFramebuffer(self.fbo) 81 | gl.deleteRenderbuffer(self.rbo) 82 | gl.deleteTexture(self.tex) 83 | procCall self.HNodeRef.destroy() 84 | 85 | 86 | method draw*(self: HCanvasRef, w, h: float) = 87 | ## Draws canvas 88 | procCall self.HNodeRef.draw(w, h) 89 | self.screenh = h 90 | self.screenw = w 91 | when defined(vulkan): 92 | discard 93 | elif not defined(js): 94 | ## Bind framebuffer and texture 95 | glBindTexture(GL_TEXTURE_2D, self.tex) 96 | glPushMatrix() 97 | glTranslatef(self.x, self.y, 0f) 98 | 99 | glEnable(GL_TEXTURE_2D) 100 | glBegin(GL_QUADS) 101 | glColor4f(1f, 1f, 1f, 1f) 102 | glTexCoord2f(0f, 0f) 103 | glVertex2f(0, 0) 104 | glTexCoord2f(1f, 0f) 105 | glVertex2f(self.w, 0) 106 | glTexCoord2f(1f, 1f) 107 | glVertex2f(self.w, self.h) 108 | glTexCoord2f(0f, 1f) 109 | glVertex2f(0, self.h) 110 | glEnd() 111 | glDisable(GL_TEXTURE_2D) 112 | else: 113 | drawTexQuad(self.material, self.tex, self.x, self.y, self.w, self.h, WhiteClr) 114 | # drawQuad(self.material, self.x, self.y, self.w, self.h, WhiteClr) 115 | 116 | when defined(vulkan): 117 | discard 118 | elif not defined(js): 119 | ## Unbind framebuffer and texture 120 | glBindTexture(GL_TEXTURE_2D, 0) 121 | glPopMatrix() 122 | else: 123 | discard 124 | 125 | 126 | proc drawRect*(self: HCanvasRef, x, y, w, h: float, clr: Color) = 127 | ## Draws rect at `x`,`y` with size `w`,`h`. 128 | when defined(vulkan): 129 | discard 130 | elif not defined(js): 131 | glBindFramebuffer(GL_FRAMEBUFFER, self.fbo) 132 | glColor4f(clr.r, clr.g, clr.b, clr.a) 133 | glRectf(x, y, x+w, y+h) 134 | glBindFramebuffer(GL_FRAMEBUFFER, 0) 135 | else: 136 | gl.bindFramebuffer(FRAMEBUFFER, self.fbo) 137 | gl.viewport(x.int, y.int, self.w.int, self.h.int) 138 | gl.scissor(x.int, y.int, self.w.int, self.h.int) 139 | drawQuad(newShaderMaterial(), x, y, w, h, clr) 140 | gl.bindFramebuffer(FRAMEBUFFER, nil) 141 | gl.viewport(0, 0, gl.canvas.width, gl.canvas.height) 142 | gl.scissor(0, 0, gl.canvas.width, gl.canvas.height) 143 | 144 | 145 | proc fill*(self: HCanvasRef, clr: Color) = 146 | ## Fills canvas by color 147 | when defined(vulkan): 148 | discard 149 | elif not defined(js): 150 | glBindFramebuffer(GL_FRAMEBUFFER, self.fbo) 151 | glClearColor(clr.r, clr.g, clr.b, clr.a) 152 | glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) 153 | glBindFramebuffer(GL_FRAMEBUFFER, 0) 154 | else: 155 | gl.bindFramebuffer(FRAMEBUFFER, self.fbo) 156 | gl.clearColor(clr.r, clr.g, clr.b, clr.a) 157 | gl.clear(COLOR_BUFFER_BIT or DEPTH_BUFFER_BIT) 158 | gl.bindFramebuffer(FRAMEBUFFER, nil) 159 | -------------------------------------------------------------------------------- /src/nodes/node.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Provides HNode behavior 3 | ]# 4 | import 5 | strformat, 6 | strutils, 7 | ../core/input, 8 | ../core/exceptions, 9 | ../core/enums, 10 | ../core/input, 11 | ../private/templates 12 | 13 | 14 | type 15 | HNodeEvent* = proc(): void 16 | HNodeInputEvent* = proc(event: InputEvent): void 17 | HNode* = object of RootObj 18 | is_ready*: bool 19 | pause_behavior*: PauseBehavior 20 | tag*: string 21 | parent*: HNodeRef 22 | children*: seq[HNodeRef] 23 | # events 24 | on_ready*: HNodeEvent ## Calls when node is entered and ready 25 | on_destroy*: HNodeEvent ## Calls when node is destroyed 26 | on_enter*: HNodeEvent ## Calls when entered into scene 27 | on_exit*: HNodeEvent ## Calls when exited from scene 28 | on_process*: HNodeEvent ## Calls every frame 29 | on_input*: HNodeInputEvent ## Calls on input 30 | HNodeRef* = ref HNode 31 | 32 | 33 | let 34 | default_event_handler* = proc(): void = discard 35 | default_input_event_handler* = proc(event: InputEvent): void = discard 36 | 37 | 38 | proc newHNode*(tag: string = "HNode"): HNodeRef = 39 | ## Creates a new HNode with tag 40 | defaultNode(HNodeRef) 41 | 42 | 43 | func childIndex*(self, node: HNodeRef): int = 44 | ## Search node in `self` children and returns its index. 45 | ## Returns -1, when not found 46 | for (index, child) in self.children.pairs: 47 | if child == node: 48 | return index 49 | -1 50 | 51 | 52 | method addChild*(self: HNodeRef, nodes: varargs[HNodeRef]) {.base, noSideEffect.} = 53 | ## Adds child `node` into `self` 54 | ## 55 | ## Swaps/moves nodes in tree, if parent of `self` is `node`. 56 | for node in nodes: 57 | if node == self: 58 | raise newException(SelfAdditionDefect, "Can not add node to self.") 59 | 60 | # Self parent is node 61 | if self.parent == node: 62 | node.parent.children.add(self) 63 | self.children.add(node) 64 | node.parent.children.delete(node.parent.childIndex(node)) 65 | node.children.delete(node.childIndex(self)) 66 | self.parent = node.parent 67 | node.parent = self 68 | # Node has not parent 69 | elif isNil(node.parent): 70 | self.children.add(node) 71 | node.parent = self 72 | # Node already has other parent 73 | elif node.parent != self: 74 | node.parent.children.delete(node.parent.childIndex(node)) 75 | self.children.add(node) 76 | node.parent = self 77 | # Self already has node child 78 | else: 79 | raise newException(AlreadyHasNodeDefect, fmt"{self.tag} already has {node.tag} in children.") 80 | 81 | 82 | method insertChild*(self, other: HNodeRef, idx: int) {.base, noSideEffect.} = 83 | ## Inserts new child at `idx` position 84 | if self == other: 85 | raise newException(SelfAdditionDefect, "Can not insert self to self node") 86 | 87 | if self.parent == other: 88 | other.parent.children.delete(other.parent.childIndex(other)) 89 | other.parent.children.add(self) 90 | self.parent = other.parent 91 | other.parent = self 92 | elif not isNil(other.parent): 93 | other.parent.children.delete(other.parent.childIndex(other)) 94 | other.parent = self 95 | self.children.insert(other, idx) 96 | 97 | 98 | # ---=== Abstract method ===--- # 99 | method draw*(self: HNodeRef, w, h: float) {.base.} = 100 | ## Abstract method for drawing 101 | if self.is_ready: 102 | self.on_ready() 103 | self.is_ready = false 104 | 105 | method handleEvent*(self: HNodeRef, event: InputEvent) {.base.} = 106 | ## Abstract method for handling events 107 | discard 108 | 109 | method destroy*(self: HNodeRef) {.base.} = 110 | ## Destroys node. 111 | ## This calls `destroyed` callback. 112 | self.on_destroy() 113 | for node in self.children: 114 | node.destroy() 115 | if not isNil(self.parent): 116 | self.parent.children.del(self.parent.childIndex(self)) 117 | self.parent = nil 118 | 119 | 120 | # ---=== Base functions ===--- # 121 | func iter*(self: HNodeRef): seq[HNodeRef] = 122 | ## Iterate all children of children 123 | result = @[] 124 | for i in self.children: 125 | result.add(i) 126 | for j in i.iter(): 127 | result.add(j) 128 | 129 | 130 | func iterLvl*(self: HNodeRef, lvl: int = 1): seq[tuple[lvl: int, node: HNodeRef]] = 131 | ## Iterate all children of children with their levels 132 | result = @[] 133 | for i in self.children: 134 | result.add((lvl, i)) 135 | for (jl, jn) in i.iterLvl(lvl+1): 136 | result.add((jl, jn)) 137 | 138 | 139 | func getByTag*(self: HNodeRef, tag: string): HNodeRef = 140 | ## Returns first node by tag 141 | for node in self.iter(): 142 | if node.tag == tag: 143 | return node 144 | return nil 145 | 146 | 147 | func getRootNode*(self: HNodeRef): HNodeRef = 148 | ## Returns root node 149 | result = self 150 | while not isNil(result.parent): 151 | result = result.parent 152 | 153 | 154 | func hasChild*(self, other: HNodeRef): bool = 155 | ## Returns true when `self` contains `other` 156 | other.parent == self and other in self.children 157 | 158 | 159 | func hasParent*(self: HNodeRef): bool = 160 | ## Returns true when has parent 161 | not isNil(self.parent) 162 | 163 | 164 | func delChild*(self, child: HNodeRef) = 165 | ## Deletes child and moves last child to deleted child postition. 166 | ## It's O(1) operation 167 | let idx = self.childIndex(child) 168 | if idx < 0: 169 | raise newException(OutOfIndexDefect, "Index out of bounds") 170 | self.children.del(idx) 171 | 172 | 173 | func delChild*(self: HNodeRef, idx: int) = 174 | ## Deletes child and moves last child to deleted child postition. 175 | ## It's O(1) operation 176 | if idx < 0: 177 | raise newException(OutOfIndexDefect, "Index out of bounds") 178 | self.children.del(idx) 179 | 180 | 181 | func deleteChild*(self, child: HNodeRef) = 182 | ## Deletes child and moves all next children by one pos. 183 | ## It's O(n) operation 184 | let idx = self.childIndex(child) 185 | if idx < 0: 186 | raise newException(OutOfIndexDefect, "Index out of bounds") 187 | self.children.delete(idx) 188 | 189 | 190 | func deleteChild*(self: HNodeRef, idx: int) = 191 | ## Deletes child and moves all next children by one pos. 192 | ## It's O(n) operation 193 | if idx < 0: 194 | raise newException(OutOfIndexDefect, "Index out of bounds") 195 | self.children.delete(idx) 196 | 197 | 198 | # ---=== Operators ===--- # 199 | func `[]`*(self: HNodeRef, idx: int | BackwardsIndex | range): HNodeRef = 200 | ## Returns child at `idx` position. 201 | self.children[idx] 202 | 203 | func `$`*(self: HNodeRef): string = 204 | ## Returns string representation of HNode 205 | fmt"HNode({self.tag})" 206 | 207 | func `~`*(self: HNodeRef): string = 208 | ## Returns tree representation of node. 209 | result = $self & "\n" 210 | for (lvl, node) in self.iterLvl(): 211 | let padding = " ".repeat(lvl) 212 | result &= fmt"{padding}{node}" & "\n" 213 | 214 | 215 | func treeRepr*(self: HNodeRef): string = 216 | ## Alias for `~` func 217 | ~self 218 | -------------------------------------------------------------------------------- /src/nodes/scene.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Provides Scene behavior 3 | ]# 4 | import 5 | ./node, 6 | ../core/hmacros, 7 | ../core/input, 8 | ../core/enums, 9 | ../core/rect, 10 | ../private/templates 11 | 12 | 13 | type 14 | HSceneRef* = ref HScene 15 | HScene* = object of HNode 16 | 17 | 18 | proc newHScene*(tag: string = "HScene"): HSceneRef = 19 | ## Creates a new HScene 20 | defaultNode(HSceneRef) 21 | 22 | 23 | method draw*(self: HSceneRef, w, h: float) = 24 | ## Draws all children 25 | procCall self.HNodeRef.draw(w, h) 26 | self.on_process() 27 | for node in self.iter(): 28 | node.draw(w, h) 29 | 30 | 31 | method handleEvent*(self: HSceneRef, event: InputEvent) = 32 | ## Handles event 33 | self.on_input(event) 34 | for node in self.iter(): 35 | node.on_input(event) 36 | node.handleEvent(event) 37 | 38 | 39 | proc enter*(scene: HSceneRef) = 40 | ## Enters in scene and calls `on_enter` callback 41 | scene.on_enter() 42 | for node in scene.iter(): 43 | node.on_enter() 44 | node.is_ready = true 45 | scene.is_ready = true 46 | 47 | 48 | proc exit*(scene: HSceneRef) = 49 | ## Exit from scene and calls `on_exit` callback 50 | scene.on_exit() 51 | for node in scene.iter(): 52 | node.is_ready = false 53 | scene.is_ready = false 54 | -------------------------------------------------------------------------------- /src/private/templates.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Provides all private templates 3 | ]# 4 | 5 | template defaultNode*(node_type: untyped): untyped = 6 | ## Initializes default fields 7 | result = `node_type`( 8 | children: @[], 9 | tag: tag, 10 | is_ready: false, 11 | on_ready: default_event_handler, 12 | on_destroy: default_event_handler, 13 | on_enter: default_event_handler, 14 | on_exit: default_event_handler, 15 | on_process: default_event_handler, 16 | on_input: default_input_event_handler, 17 | parent: nil, 18 | pause_behavior: PauseBehavior.Inherit 19 | ) 20 | -------------------------------------------------------------------------------- /src/thirdparty/opengl.nim: -------------------------------------------------------------------------------- 1 | # 2 | # 3 | # Nim's Runtime Library 4 | # (c) Copyright 2012-2017 Andreas Rumpf 5 | # 6 | # See the file "copying.txt", included in this 7 | # distribution, for details about the copyright. 8 | # 9 | 10 | ## This module is a wrapper around `opengl`:idx:. If you define the symbol 11 | ## ``useGlew`` this wrapper does not use Nim's ``dynlib`` mechanism, 12 | ## but `glew`:idx: instead. However, this shouldn't be necessary anymore; even 13 | ## extension loading for the different operating systems is handled here. 14 | ## 15 | ## You need to call ``loadExtensions`` after a rendering context has been 16 | ## created to load any extension proc that your code uses. 17 | 18 | include opengl/private/prelude, opengl/private/types, 19 | opengl/private/errors, opengl/private/procs, opengl/private/constants -------------------------------------------------------------------------------- /src/thirdparty/opengl/glu.nim: -------------------------------------------------------------------------------- 1 | # 2 | # 3 | # Adaption of the delphi3d.net OpenGL units to FreePascal 4 | # Sebastian Guenther (sg@freepascal.org) in 2002 5 | # These units are free to use 6 | #****************************************************************************** 7 | # Converted to Delphi by Tom Nuydens (tom@delphi3d.net) 8 | # For the latest updates, visit Delphi3D: http://www.delphi3d.net 9 | #****************************************************************************** 10 | 11 | import ../opengl 12 | 13 | {.deadCodeElim: on.} 14 | 15 | when defined(windows): 16 | {.push, callconv: stdcall.} 17 | else: 18 | {.push, callconv: cdecl.} 19 | 20 | when defined(windows): 21 | const 22 | dllname = "glu32.dll" 23 | elif defined(macosx): 24 | const 25 | dllname = "/System/Library/Frameworks/OpenGL.framework/Libraries/libGLU.dylib" 26 | else: 27 | const 28 | dllname = "libGLU.so.1" 29 | 30 | type 31 | ViewPortArray* = array[0..3, GLint] 32 | T16dArray* = array[0..15, GLdouble] 33 | CallBack* = proc () {.cdecl.} 34 | T3dArray* = array[0..2, GLdouble] 35 | T4pArray* = array[0..3, pointer] 36 | T4fArray* = array[0..3, GLfloat] 37 | 38 | {.deprecated: [ 39 | TViewPortArray: ViewPortArray, 40 | TCallBack: CallBack, 41 | ].} 42 | 43 | type 44 | GLUnurbs*{.final.} = ptr object 45 | GLUquadric*{.final.} = ptr object 46 | GLUtesselator*{.final.} = ptr object 47 | GLUnurbsObj* = GLUnurbs 48 | GLUquadricObj* = GLUquadric 49 | GLUtesselatorObj* = GLUtesselator 50 | GLUtriangulatorObj* = GLUtesselator 51 | 52 | proc gluErrorString*(errCode: GLenum): cstring{.dynlib: dllname, 53 | importc: "gluErrorString".} 54 | when defined(Windows): 55 | proc gluErrorUnicodeStringEXT*(errCode: GLenum): ptr int16{.dynlib: dllname, 56 | importc: "gluErrorUnicodeStringEXT".} 57 | proc gluGetString*(name: GLenum): cstring{.dynlib: dllname, 58 | importc: "gluGetString".} 59 | proc gluOrtho2D*(left, right, bottom, top: GLdouble){.dynlib: dllname, 60 | importc: "gluOrtho2D".} 61 | proc gluPerspective*(fovy, aspect, zNear, zFar: GLdouble){.dynlib: dllname, 62 | importc: "gluPerspective".} 63 | proc gluPickMatrix*(x, y, width, height: GLdouble, viewport: var ViewPortArray){. 64 | dynlib: dllname, importc: "gluPickMatrix".} 65 | proc gluLookAt*(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz: GLdouble){. 66 | dynlib: dllname, importc: "gluLookAt".} 67 | proc gluProject*(objx, objy, objz: GLdouble, 68 | modelMatrix, projMatrix: var T16dArray, 69 | viewport: var ViewPortArray, winx, winy, winz: ptr GLdouble): int{. 70 | dynlib: dllname, importc: "gluProject".} 71 | proc gluUnProject*(winx, winy, winz: GLdouble, 72 | modelMatrix, projMatrix: var T16dArray, 73 | viewport: var ViewPortArray, objx, objy, objz: ptr GLdouble): int{. 74 | dynlib: dllname, importc: "gluUnProject".} 75 | proc gluScaleImage*(format: GLenum, widthin, heightin: GLint, typein: GLenum, 76 | datain: pointer, widthout, heightout: GLint, 77 | typeout: GLenum, dataout: pointer): int{.dynlib: dllname, 78 | importc: "gluScaleImage".} 79 | proc gluBuild1DMipmaps*(target: GLenum, components, width: GLint, 80 | format, atype: GLenum, data: pointer): int{. 81 | dynlib: dllname, importc: "gluBuild1DMipmaps".} 82 | proc gluBuild2DMipmaps*(target: GLenum, components, width, height: GLint, 83 | format, atype: GLenum, data: pointer): int{. 84 | dynlib: dllname, importc: "gluBuild2DMipmaps".} 85 | proc gluNewQuadric*(): GLUquadric{.dynlib: dllname, importc: "gluNewQuadric".} 86 | proc gluDeleteQuadric*(state: GLUquadric){.dynlib: dllname, 87 | importc: "gluDeleteQuadric".} 88 | proc gluQuadricNormals*(quadObject: GLUquadric, normals: GLenum){. 89 | dynlib: dllname, importc: "gluQuadricNormals".} 90 | proc gluQuadricTexture*(quadObject: GLUquadric, textureCoords: GLboolean){. 91 | dynlib: dllname, importc: "gluQuadricTexture".} 92 | proc gluQuadricOrientation*(quadObject: GLUquadric, orientation: GLenum){. 93 | dynlib: dllname, importc: "gluQuadricOrientation".} 94 | proc gluQuadricDrawStyle*(quadObject: GLUquadric, drawStyle: GLenum){. 95 | dynlib: dllname, importc: "gluQuadricDrawStyle".} 96 | proc gluCylinder*(qobj: GLUquadric, baseRadius, topRadius, height: GLdouble, 97 | slices, stacks: GLint){.dynlib: dllname, 98 | importc: "gluCylinder".} 99 | proc gluDisk*(qobj: GLUquadric, innerRadius, outerRadius: GLdouble, 100 | slices, loops: GLint){.dynlib: dllname, importc: "gluDisk".} 101 | proc gluPartialDisk*(qobj: GLUquadric, innerRadius, outerRadius: GLdouble, 102 | slices, loops: GLint, startAngle, sweepAngle: GLdouble){. 103 | dynlib: dllname, importc: "gluPartialDisk".} 104 | proc gluSphere*(qobj: GLuquadric, radius: GLdouble, slices, stacks: GLint){. 105 | dynlib: dllname, importc: "gluSphere".} 106 | proc gluQuadricCallback*(qobj: GLUquadric, which: GLenum, fn: CallBack){. 107 | dynlib: dllname, importc: "gluQuadricCallback".} 108 | proc gluNewTess*(): GLUtesselator{.dynlib: dllname, importc: "gluNewTess".} 109 | proc gluDeleteTess*(tess: GLUtesselator){.dynlib: dllname, 110 | importc: "gluDeleteTess".} 111 | proc gluTessBeginPolygon*(tess: GLUtesselator, polygon_data: pointer){. 112 | dynlib: dllname, importc: "gluTessBeginPolygon".} 113 | proc gluTessBeginContour*(tess: GLUtesselator){.dynlib: dllname, 114 | importc: "gluTessBeginContour".} 115 | proc gluTessVertex*(tess: GLUtesselator, coords: var T3dArray, data: pointer){. 116 | dynlib: dllname, importc: "gluTessVertex".} 117 | proc gluTessEndContour*(tess: GLUtesselator){.dynlib: dllname, 118 | importc: "gluTessEndContour".} 119 | proc gluTessEndPolygon*(tess: GLUtesselator){.dynlib: dllname, 120 | importc: "gluTessEndPolygon".} 121 | proc gluTessProperty*(tess: GLUtesselator, which: GLenum, value: GLdouble){. 122 | dynlib: dllname, importc: "gluTessProperty".} 123 | proc gluTessNormal*(tess: GLUtesselator, x, y, z: GLdouble){.dynlib: dllname, 124 | importc: "gluTessNormal".} 125 | proc gluTessCallback*(tess: GLUtesselator, which: GLenum, fn: CallBack){. 126 | dynlib: dllname, importc: "gluTessCallback".} 127 | proc gluGetTessProperty*(tess: GLUtesselator, which: GLenum, value: ptr GLdouble){. 128 | dynlib: dllname, importc: "gluGetTessProperty".} 129 | proc gluNewNurbsRenderer*(): GLUnurbs{.dynlib: dllname, 130 | importc: "gluNewNurbsRenderer".} 131 | proc gluDeleteNurbsRenderer*(nobj: GLUnurbs){.dynlib: dllname, 132 | importc: "gluDeleteNurbsRenderer".} 133 | proc gluBeginSurface*(nobj: GLUnurbs){.dynlib: dllname, 134 | importc: "gluBeginSurface".} 135 | proc gluBeginCurve*(nobj: GLUnurbs){.dynlib: dllname, importc: "gluBeginCurve".} 136 | proc gluEndCurve*(nobj: GLUnurbs){.dynlib: dllname, importc: "gluEndCurve".} 137 | proc gluEndSurface*(nobj: GLUnurbs){.dynlib: dllname, importc: "gluEndSurface".} 138 | proc gluBeginTrim*(nobj: GLUnurbs){.dynlib: dllname, importc: "gluBeginTrim".} 139 | proc gluEndTrim*(nobj: GLUnurbs){.dynlib: dllname, importc: "gluEndTrim".} 140 | proc gluPwlCurve*(nobj: GLUnurbs, count: GLint, aarray: ptr GLfloat, 141 | stride: GLint, atype: GLenum){.dynlib: dllname, 142 | importc: "gluPwlCurve".} 143 | proc gluNurbsCurve*(nobj: GLUnurbs, nknots: GLint, knot: ptr GLfloat, 144 | stride: GLint, ctlarray: ptr GLfloat, order: GLint, 145 | atype: GLenum){.dynlib: dllname, importc: "gluNurbsCurve".} 146 | proc gluNurbsSurface*(nobj: GLUnurbs, sknot_count: GLint, sknot: ptr GLfloat, 147 | tknot_count: GLint, tknot: ptr GLfloat, 148 | s_stride, t_stride: GLint, ctlarray: ptr GLfloat, 149 | sorder, torder: GLint, atype: GLenum){.dynlib: dllname, 150 | importc: "gluNurbsSurface".} 151 | proc gluLoadSamplingMatrices*(nobj: GLUnurbs, 152 | modelMatrix, projMatrix: var T16dArray, 153 | viewport: var ViewPortArray){.dynlib: dllname, 154 | importc: "gluLoadSamplingMatrices".} 155 | proc gluNurbsProperty*(nobj: GLUnurbs, aproperty: GLenum, value: GLfloat){. 156 | dynlib: dllname, importc: "gluNurbsProperty".} 157 | proc gluGetNurbsProperty*(nobj: GLUnurbs, aproperty: GLenum, value: ptr GLfloat){. 158 | dynlib: dllname, importc: "gluGetNurbsProperty".} 159 | proc gluNurbsCallback*(nobj: GLUnurbs, which: GLenum, fn: CallBack){. 160 | dynlib: dllname, importc: "gluNurbsCallback".} 161 | #*** Callback function prototypes *** 162 | type # gluQuadricCallback 163 | GLUquadricErrorProc* = proc (p: GLenum) # gluTessCallback 164 | GLUtessBeginProc* = proc (p: GLenum) 165 | GLUtessEdgeFlagProc* = proc (p: GLboolean) 166 | GLUtessVertexProc* = proc (p: pointer) 167 | GLUtessEndProc* = proc () 168 | GLUtessErrorProc* = proc (p: GLenum) 169 | GLUtessCombineProc* = proc (p1: var T3dArray, p2: T4pArray, p3: T4fArray, 170 | p4: ptr pointer) 171 | GLUtessBeginDataProc* = proc (p1: GLenum, p2: pointer) 172 | GLUtessEdgeFlagDataProc* = proc (p1: GLboolean, p2: pointer) 173 | GLUtessVertexDataProc* = proc (p1, p2: pointer) 174 | GLUtessEndDataProc* = proc (p: pointer) 175 | GLUtessErrorDataProc* = proc (p1: GLenum, p2: pointer) 176 | GLUtessCombineDataProc* = proc (p1: var T3dArray, p2: var T4pArray, 177 | p3: var T4fArray, p4: ptr pointer, p5: pointer) # 178 | GLUnurbsErrorProc* = proc (p: GLenum) #*** Generic constants ****/ 179 | 180 | const # Version 181 | GLU_VERSION_1_1* = 1 182 | GLU_VERSION_1_2* = 1 # Errors: (return value 0 = no error) 183 | GLU_INVALID_ENUM* = 100900 184 | GLU_INVALID_VALUE* = 100901 185 | GLU_OUT_OF_MEMORY* = 100902 186 | GLU_INCOMPATIBLE_GL_VERSION* = 100903 # StringName 187 | GLU_VERSION* = 100800 188 | GLU_EXTENSIONS* = 100801 # Boolean 189 | GLU_TRUE* = GL_TRUE 190 | GLU_FALSE* = GL_FALSE #*** Quadric constants ****/ 191 | # QuadricNormal 192 | GLU_SMOOTH* = 100000 193 | GLU_FLAT* = 100001 194 | GLU_NONE* = 100002 # QuadricDrawStyle 195 | GLU_POINT* = 100010 196 | GLU_LINE* = 100011 197 | GLU_FILL* = 100012 198 | GLU_SILHOUETTE* = 100013 # QuadricOrientation 199 | GLU_OUTSIDE* = 100020 200 | GLU_INSIDE* = 100021 # Callback types: 201 | # GLU_ERROR = 100103; 202 | #*** Tesselation constants ****/ 203 | GLU_TESS_MAX_COORD* = 1.00000e+150 # TessProperty 204 | GLU_TESS_WINDING_RULE* = 100140 205 | GLU_TESS_BOUNDARY_ONLY* = 100141 206 | GLU_TESS_TOLERANCE* = 100142 # TessWinding 207 | GLU_TESS_WINDING_ODD* = 100130 208 | GLU_TESS_WINDING_NONZERO* = 100131 209 | GLU_TESS_WINDING_POSITIVE* = 100132 210 | GLU_TESS_WINDING_NEGATIVE* = 100133 211 | GLU_TESS_WINDING_ABS_GEQ_TWO* = 100134 # TessCallback 212 | GLU_TESS_BEGIN* = 100100 # void (CALLBACK*)(GLenum type) 213 | constGLU_TESS_VERTEX* = 100101 # void (CALLBACK*)(void *data) 214 | GLU_TESS_END* = 100102 # void (CALLBACK*)(void) 215 | GLU_TESS_ERROR* = 100103 # void (CALLBACK*)(GLenum errno) 216 | GLU_TESS_EDGE_FLAG* = 100104 # void (CALLBACK*)(GLboolean boundaryEdge) 217 | GLU_TESS_COMBINE* = 100105 # void (CALLBACK*)(GLdouble coords[3], 218 | # void *data[4], 219 | # GLfloat weight[4], 220 | # void **dataOut) 221 | GLU_TESS_BEGIN_DATA* = 100106 # void (CALLBACK*)(GLenum type, 222 | # void *polygon_data) 223 | GLU_TESS_VERTEX_DATA* = 100107 # void (CALLBACK*)(void *data, 224 | # void *polygon_data) 225 | GLU_TESS_END_DATA* = 100108 # void (CALLBACK*)(void *polygon_data) 226 | GLU_TESS_ERROR_DATA* = 100109 # void (CALLBACK*)(GLenum errno, 227 | # void *polygon_data) 228 | GLU_TESS_EDGE_FLAG_DATA* = 100110 # void (CALLBACK*)(GLboolean boundaryEdge, 229 | # void *polygon_data) 230 | GLU_TESS_COMBINE_DATA* = 100111 # void (CALLBACK*)(GLdouble coords[3], 231 | # void *data[4], 232 | # GLfloat weight[4], 233 | # void **dataOut, 234 | # void *polygon_data) 235 | # TessError 236 | GLU_TESS_ERROR1* = 100151 237 | GLU_TESS_ERROR2* = 100152 238 | GLU_TESS_ERROR3* = 100153 239 | GLU_TESS_ERROR4* = 100154 240 | GLU_TESS_ERROR5* = 100155 241 | GLU_TESS_ERROR6* = 100156 242 | GLU_TESS_ERROR7* = 100157 243 | GLU_TESS_ERROR8* = 100158 244 | GLU_TESS_MISSING_BEGIN_POLYGON* = GLU_TESS_ERROR1 245 | GLU_TESS_MISSING_BEGIN_CONTOUR* = GLU_TESS_ERROR2 246 | GLU_TESS_MISSING_END_POLYGON* = GLU_TESS_ERROR3 247 | GLU_TESS_MISSING_END_CONTOUR* = GLU_TESS_ERROR4 248 | GLU_TESS_COORD_TOO_LARGE* = GLU_TESS_ERROR5 249 | GLU_TESS_NEED_COMBINE_CALLBACK* = GLU_TESS_ERROR6 #*** NURBS constants ****/ 250 | # NurbsProperty 251 | GLU_AUTO_LOAD_MATRIX* = 100200 252 | GLU_CULLING* = 100201 253 | GLU_SAMPLING_TOLERANCE* = 100203 254 | GLU_DISPLAY_MODE* = 100204 255 | GLU_PARAMETRIC_TOLERANCE* = 100202 256 | GLU_SAMPLING_METHOD* = 100205 257 | GLU_U_STEP* = 100206 258 | GLU_V_STEP* = 100207 # NurbsSampling 259 | GLU_PATH_LENGTH* = 100215 260 | GLU_PARAMETRIC_ERROR* = 100216 261 | GLU_DOMAIN_DISTANCE* = 100217 # NurbsTrim 262 | GLU_MAP1_TRIM_2* = 100210 263 | GLU_MAP1_TRIM_3* = 100211 # NurbsDisplay 264 | # GLU_FILL = 100012; 265 | GLU_OUTLINE_POLYGON* = 100240 266 | GLU_OUTLINE_PATCH* = 100241 # NurbsCallback 267 | # GLU_ERROR = 100103; 268 | # NurbsErrors 269 | GLU_NURBS_ERROR1* = 100251 270 | GLU_NURBS_ERROR2* = 100252 271 | GLU_NURBS_ERROR3* = 100253 272 | GLU_NURBS_ERROR4* = 100254 273 | GLU_NURBS_ERROR5* = 100255 274 | GLU_NURBS_ERROR6* = 100256 275 | GLU_NURBS_ERROR7* = 100257 276 | GLU_NURBS_ERROR8* = 100258 277 | GLU_NURBS_ERROR9* = 100259 278 | GLU_NURBS_ERROR10* = 100260 279 | GLU_NURBS_ERROR11* = 100261 280 | GLU_NURBS_ERROR12* = 100262 281 | GLU_NURBS_ERROR13* = 100263 282 | GLU_NURBS_ERROR14* = 100264 283 | GLU_NURBS_ERROR15* = 100265 284 | GLU_NURBS_ERROR16* = 100266 285 | GLU_NURBS_ERROR17* = 100267 286 | GLU_NURBS_ERROR18* = 100268 287 | GLU_NURBS_ERROR19* = 100269 288 | GLU_NURBS_ERROR20* = 100270 289 | GLU_NURBS_ERROR21* = 100271 290 | GLU_NURBS_ERROR22* = 100272 291 | GLU_NURBS_ERROR23* = 100273 292 | GLU_NURBS_ERROR24* = 100274 293 | GLU_NURBS_ERROR25* = 100275 294 | GLU_NURBS_ERROR26* = 100276 295 | GLU_NURBS_ERROR27* = 100277 296 | GLU_NURBS_ERROR28* = 100278 297 | GLU_NURBS_ERROR29* = 100279 298 | GLU_NURBS_ERROR30* = 100280 299 | GLU_NURBS_ERROR31* = 100281 300 | GLU_NURBS_ERROR32* = 100282 301 | GLU_NURBS_ERROR33* = 100283 302 | GLU_NURBS_ERROR34* = 100284 303 | GLU_NURBS_ERROR35* = 100285 304 | GLU_NURBS_ERROR36* = 100286 305 | GLU_NURBS_ERROR37* = 100287 #*** Backwards compatibility for old tesselator ****/ 306 | 307 | proc gluBeginPolygon*(tess: GLUtesselator){.dynlib: dllname, 308 | importc: "gluBeginPolygon".} 309 | proc gluNextContour*(tess: GLUtesselator, atype: GLenum){.dynlib: dllname, 310 | importc: "gluNextContour".} 311 | proc gluEndPolygon*(tess: GLUtesselator){.dynlib: dllname, 312 | importc: "gluEndPolygon".} 313 | const # Contours types -- obsolete! 314 | GLU_CW* = 100120 315 | GLU_CCW* = 100121 316 | GLU_INTERIOR* = 100122 317 | GLU_EXTERIOR* = 100123 318 | GLU_UNKNOWN* = 100124 # Names without "TESS_" prefix 319 | GLU_BEGIN* = GLU_TESS_BEGIN 320 | GLU_VERTEX* = constGLU_TESS_VERTEX 321 | GLU_END* = GLU_TESS_END 322 | GLU_ERROR* = GLU_TESS_ERROR 323 | GLU_EDGE_FLAG* = GLU_TESS_EDGE_FLAG 324 | 325 | {.pop.} 326 | # implementation 327 | -------------------------------------------------------------------------------- /src/thirdparty/opengl/glut.nim: -------------------------------------------------------------------------------- 1 | # 2 | # 3 | # Adaption of the delphi3d.net OpenGL units to FreePascal 4 | # Sebastian Guenther (sg@freepascal.org) in 2002 5 | # These units are free to use 6 | # 7 | 8 | # Copyright (c) Mark J. Kilgard, 1994, 1995, 1996. 9 | # This program is freely distributable without licensing fees and is 10 | # provided without guarantee or warrantee expressed or implied. This 11 | # program is -not- in the public domain. 12 | #****************************************************************************** 13 | # Converted to Delphi by Tom Nuydens (tom@delphi3d.net) 14 | # Contributions by Igor Karpov (glygrik@hotbox.ru) 15 | # For the latest updates, visit Delphi3D: http://www.delphi3d.net 16 | #****************************************************************************** 17 | 18 | import ../opengl 19 | 20 | {.deadCodeElim: on.} 21 | 22 | when defined(windows): 23 | const 24 | dllname = "(freeglut.dll|glut32.dll)" 25 | elif defined(macosx): 26 | const 27 | dllname = "/System/Library/Frameworks/GLUT.framework/GLUT" 28 | else: 29 | const 30 | dllname = "libglut.so.3" 31 | type 32 | TGlutVoidCallback* = proc (){.cdecl.} 33 | TGlut1IntCallback* = proc (value: cint){.cdecl.} 34 | TGlut2IntCallback* = proc (v1, v2: cint){.cdecl.} 35 | TGlut3IntCallback* = proc (v1, v2, v3: cint){.cdecl.} 36 | TGlut4IntCallback* = proc (v1, v2, v3, v4: cint){.cdecl.} 37 | TGlut1Char2IntCallback* = proc (c: int8, v1, v2: cint){.cdecl.} 38 | TGlut1UInt3IntCallback* = proc (u, v1, v2, v3: cint){.cdecl.} 39 | 40 | {.deprecated: [Pointer: pointer].} 41 | 42 | const 43 | GLUT_API_VERSION* = 3 44 | GLUT_XLIB_IMPLEMENTATION* = 12 # Display mode bit masks. 45 | GLUT_RGB* = 0 46 | GLUT_RGBA* = GLUT_RGB 47 | GLUT_INDEX* = 1 48 | GLUT_SINGLE* = 0 49 | GLUT_DOUBLE* = 2 50 | GLUT_ACCUM* = 4 51 | GLUT_ALPHA* = 8 52 | GLUT_DEPTH* = 16 53 | GLUT_STENCIL* = 32 54 | GLUT_MULTISAMPLE* = 128 55 | GLUT_STEREO* = 256 56 | GLUT_LUMINANCE* = 512 # Mouse buttons. 57 | GLUT_LEFT_BUTTON* = 0 58 | GLUT_MIDDLE_BUTTON* = 1 59 | GLUT_RIGHT_BUTTON* = 2 # Mouse button state. 60 | GLUT_DOWN* = 0 61 | GLUT_UP* = 1 # function keys 62 | GLUT_KEY_F1* = 1 63 | GLUT_KEY_F2* = 2 64 | GLUT_KEY_F3* = 3 65 | GLUT_KEY_F4* = 4 66 | GLUT_KEY_F5* = 5 67 | GLUT_KEY_F6* = 6 68 | GLUT_KEY_F7* = 7 69 | GLUT_KEY_F8* = 8 70 | GLUT_KEY_F9* = 9 71 | GLUT_KEY_F10* = 10 72 | GLUT_KEY_F11* = 11 73 | GLUT_KEY_F12* = 12 # directional keys 74 | GLUT_KEY_LEFT* = 100 75 | GLUT_KEY_UP* = 101 76 | GLUT_KEY_RIGHT* = 102 77 | GLUT_KEY_DOWN* = 103 78 | GLUT_KEY_PAGE_UP* = 104 79 | GLUT_KEY_PAGE_DOWN* = 105 80 | GLUT_KEY_HOME* = 106 81 | GLUT_KEY_END* = 107 82 | GLUT_KEY_INSERT* = 108 # Entry/exit state. 83 | GLUT_LEFT* = 0 84 | GLUT_ENTERED* = 1 # Menu usage state. 85 | GLUT_MENU_NOT_IN_USE* = 0 86 | GLUT_MENU_IN_USE* = 1 # Visibility state. 87 | GLUT_NOT_VISIBLE* = 0 88 | GLUT_VISIBLE* = 1 # Window status state. 89 | GLUT_HIDDEN* = 0 90 | GLUT_FULLY_RETAINED* = 1 91 | GLUT_PARTIALLY_RETAINED* = 2 92 | GLUT_FULLY_COVERED* = 3 # Color index component selection values. 93 | GLUT_RED* = 0 94 | GLUT_GREEN* = 1 95 | GLUT_BLUE* = 2 # Layers for use. 96 | GLUT_NORMAL* = 0 97 | GLUT_OVERLAY* = 1 98 | 99 | {.push dynlib: dllname, importc.} 100 | 101 | when defined(Windows): 102 | const # Stroke font constants (use these in GLUT program). 103 | GLUT_STROKE_ROMAN* = cast[pointer](0) 104 | GLUT_STROKE_MONO_ROMAN* = cast[pointer](1) # Bitmap font constants (use these in GLUT program). 105 | GLUT_BITMAP_9_BY_15* = cast[pointer](2) 106 | GLUT_BITMAP_8_BY_13* = cast[pointer](3) 107 | GLUT_BITMAP_TIMES_ROMAN_10* = cast[pointer](4) 108 | GLUT_BITMAP_TIMES_ROMAN_24* = cast[pointer](5) 109 | GLUT_BITMAP_HELVETICA_10* = cast[pointer](6) 110 | GLUT_BITMAP_HELVETICA_12* = cast[pointer](7) 111 | GLUT_BITMAP_HELVETICA_18* = cast[pointer](8) 112 | else: 113 | var # Stroke font constants (use these in GLUT program). 114 | glutStrokeRoman {.importc: "glutStrokeRoman".}: pointer 115 | glutStrokeMonoRoman {.importc: "glutStrokeMonoRoman".}: pointer # Bitmap font constants (use these in GLUT program). 116 | glutBitmap9By15 {.importc: "glutBitmap9By15".}: pointer 117 | glutBitmap8By13 {.importc: "glutBitmap8By13".}: pointer 118 | glutBitmapTimesRoman10 {.importc: "glutBitmapTimesRoman10".}: pointer 119 | glutBitmapTimesRoman24 {.importc: "glutBitmapTimesRoman24".}: pointer 120 | glutBitmapHelvetica10 {.importc: "glutBitmapHelvetica10".}: pointer 121 | glutBitmapHelvetica12 {.importc: "glutBitmapHelvetica12".}: pointer 122 | glutBitmapHelvetica18 {.importc: "glutBitmapHelvetica18".}: pointer 123 | 124 | let 125 | GLUT_STROKE_ROMAN* = cast[pointer](addr glutStrokeRoman) 126 | GLUT_STROKE_MONO_ROMAN* = cast[pointer](addr glutStrokeMonoRoman) 127 | GLUT_BITMAP_9_BY_15* = cast[pointer](addr glutBitmap9By15) 128 | GLUT_BITMAP_8_BY_13* = cast[pointer](addr glutBitmap8By13) 129 | GLUT_BITMAP_TIMES_ROMAN_10* = cast[pointer](addr glutBitmapTimesRoman10) 130 | GLUT_BITMAP_TIMES_ROMAN_24* = cast[pointer](addr glutBitmapTimesRoman24) 131 | GLUT_BITMAP_HELVETICA_10* = cast[pointer](addr glutBitmapHelvetica10) 132 | GLUT_BITMAP_HELVETICA_12* = cast[pointer](addr glutBitmapHelvetica12) 133 | GLUT_BITMAP_HELVETICA_18* = cast[pointer](addr glutBitmapHelvetica18) 134 | 135 | const # glutGet parameters. 136 | GLUT_WINDOW_X* = 100 137 | GLUT_WINDOW_Y* = 101 138 | GLUT_WINDOW_WIDTH* = 102 139 | GLUT_WINDOW_HEIGHT* = 103 140 | GLUT_WINDOW_BUFFER_SIZE* = 104 141 | GLUT_WINDOW_STENCIL_SIZE* = 105 142 | GLUT_WINDOW_DEPTH_SIZE* = 106 143 | GLUT_WINDOW_RED_SIZE* = 107 144 | GLUT_WINDOW_GREEN_SIZE* = 108 145 | GLUT_WINDOW_BLUE_SIZE* = 109 146 | GLUT_WINDOW_ALPHA_SIZE* = 110 147 | GLUT_WINDOW_ACCUM_RED_SIZE* = 111 148 | GLUT_WINDOW_ACCUM_GREEN_SIZE* = 112 149 | GLUT_WINDOW_ACCUM_BLUE_SIZE* = 113 150 | GLUT_WINDOW_ACCUM_ALPHA_SIZE* = 114 151 | GLUT_WINDOW_DOUBLEBUFFER* = 115 152 | GLUT_WINDOW_RGBA* = 116 153 | GLUT_WINDOW_PARENT* = 117 154 | GLUT_WINDOW_NUM_CHILDREN* = 118 155 | GLUT_WINDOW_COLORMAP_SIZE* = 119 156 | GLUT_WINDOW_NUM_SAMPLES* = 120 157 | GLUT_WINDOW_STEREO* = 121 158 | GLUT_WINDOW_CURSOR* = 122 159 | GLUT_SCREEN_WIDTH* = 200 160 | GLUT_SCREEN_HEIGHT* = 201 161 | GLUT_SCREEN_WIDTH_MM* = 202 162 | GLUT_SCREEN_HEIGHT_MM* = 203 163 | GLUT_MENU_NUM_ITEMS* = 300 164 | GLUT_DISPLAY_MODE_POSSIBLE* = 400 165 | GLUT_INIT_WINDOW_X* = 500 166 | GLUT_INIT_WINDOW_Y* = 501 167 | GLUT_INIT_WINDOW_WIDTH* = 502 168 | GLUT_INIT_WINDOW_HEIGHT* = 503 169 | constGLUT_INIT_DISPLAY_MODE* = 504 170 | GLUT_ELAPSED_TIME* = 700 171 | GLUT_WINDOW_FORMAT_ID* = 123 # glutDeviceGet parameters. 172 | GLUT_HAS_KEYBOARD* = 600 173 | GLUT_HAS_MOUSE* = 601 174 | GLUT_HAS_SPACEBALL* = 602 175 | GLUT_HAS_DIAL_AND_BUTTON_BOX* = 603 176 | GLUT_HAS_TABLET* = 604 177 | GLUT_NUM_MOUSE_BUTTONS* = 605 178 | GLUT_NUM_SPACEBALL_BUTTONS* = 606 179 | GLUT_NUM_BUTTON_BOX_BUTTONS* = 607 180 | GLUT_NUM_DIALS* = 608 181 | GLUT_NUM_TABLET_BUTTONS* = 609 182 | GLUT_DEVICE_IGNORE_KEY_REPEAT* = 610 183 | GLUT_DEVICE_KEY_REPEAT* = 611 184 | GLUT_HAS_JOYSTICK* = 612 185 | GLUT_OWNS_JOYSTICK* = 613 186 | GLUT_JOYSTICK_BUTTONS* = 614 187 | GLUT_JOYSTICK_AXES* = 615 188 | GLUT_JOYSTICK_POLL_RATE* = 616 # glutLayerGet parameters. 189 | GLUT_OVERLAY_POSSIBLE* = 800 190 | GLUT_LAYER_IN_USE* = 801 191 | GLUT_HAS_OVERLAY* = 802 192 | GLUT_TRANSPARENT_INDEX* = 803 193 | GLUT_NORMAL_DAMAGED* = 804 194 | GLUT_OVERLAY_DAMAGED* = 805 # glutVideoResizeGet parameters. 195 | GLUT_VIDEO_RESIZE_POSSIBLE* = 900 196 | GLUT_VIDEO_RESIZE_IN_USE* = 901 197 | GLUT_VIDEO_RESIZE_X_DELTA* = 902 198 | GLUT_VIDEO_RESIZE_Y_DELTA* = 903 199 | GLUT_VIDEO_RESIZE_WIDTH_DELTA* = 904 200 | GLUT_VIDEO_RESIZE_HEIGHT_DELTA* = 905 201 | GLUT_VIDEO_RESIZE_X* = 906 202 | GLUT_VIDEO_RESIZE_Y* = 907 203 | GLUT_VIDEO_RESIZE_WIDTH* = 908 204 | GLUT_VIDEO_RESIZE_HEIGHT* = 909 # glutGetModifiers return mask. 205 | GLUT_ACTIVE_SHIFT* = 1 206 | GLUT_ACTIVE_CTRL* = 2 207 | GLUT_ACTIVE_ALT* = 4 # glutSetCursor parameters. 208 | # Basic arrows. 209 | GLUT_CURSOR_RIGHT_ARROW* = 0 210 | GLUT_CURSOR_LEFT_ARROW* = 1 # Symbolic cursor shapes. 211 | GLUT_CURSOR_INFO* = 2 212 | GLUT_CURSOR_DESTROY* = 3 213 | GLUT_CURSOR_HELP* = 4 214 | GLUT_CURSOR_CYCLE* = 5 215 | GLUT_CURSOR_SPRAY* = 6 216 | GLUT_CURSOR_WAIT* = 7 217 | GLUT_CURSOR_TEXT* = 8 218 | GLUT_CURSOR_CROSSHAIR* = 9 # Directional cursors. 219 | GLUT_CURSOR_UP_DOWN* = 10 220 | GLUT_CURSOR_LEFT_RIGHT* = 11 # Sizing cursors. 221 | GLUT_CURSOR_TOP_SIDE* = 12 222 | GLUT_CURSOR_BOTTOM_SIDE* = 13 223 | GLUT_CURSOR_LEFT_SIDE* = 14 224 | GLUT_CURSOR_RIGHT_SIDE* = 15 225 | GLUT_CURSOR_TOP_LEFT_CORNER* = 16 226 | GLUT_CURSOR_TOP_RIGHT_CORNER* = 17 227 | GLUT_CURSOR_BOTTOM_RIGHT_CORNER* = 18 228 | GLUT_CURSOR_BOTTOM_LEFT_CORNER* = 19 # Inherit from parent window. 229 | GLUT_CURSOR_INHERIT* = 100 # Blank cursor. 230 | GLUT_CURSOR_NONE* = 101 # Fullscreen crosshair (if available). 231 | GLUT_CURSOR_FULL_CROSSHAIR* = 102 # GLUT device control sub-API. 232 | # glutSetKeyRepeat modes. 233 | GLUT_KEY_REPEAT_OFF* = 0 234 | GLUT_KEY_REPEAT_ON* = 1 235 | GLUT_KEY_REPEAT_DEFAULT* = 2 # Joystick button masks. 236 | GLUT_JOYSTICK_BUTTON_A* = 1 237 | GLUT_JOYSTICK_BUTTON_B* = 2 238 | GLUT_JOYSTICK_BUTTON_C* = 4 239 | GLUT_JOYSTICK_BUTTON_D* = 8 # GLUT game mode sub-API. 240 | # glutGameModeGet. 241 | GLUT_GAME_MODE_ACTIVE* = 0 242 | GLUT_GAME_MODE_POSSIBLE* = 1 243 | GLUT_GAME_MODE_WIDTH* = 2 244 | GLUT_GAME_MODE_HEIGHT* = 3 245 | GLUT_GAME_MODE_PIXEL_DEPTH* = 4 246 | GLUT_GAME_MODE_REFRESH_RATE* = 5 247 | GLUT_GAME_MODE_DISPLAY_CHANGED* = 6 # GLUT initialization sub-API. 248 | 249 | proc glutInit*(argcp: ptr cint, argv: pointer) 250 | proc glutInitDisplayMode*(mode: int16) 251 | proc glutInitDisplayString*(str: cstring) 252 | proc glutInitWindowPosition*(x, y: int) 253 | proc glutInitWindowSize*(width, height: int) 254 | proc glutMainLoop*() 255 | # GLUT window sub-API. 256 | proc glutCreateWindow*(title: cstring): int 257 | proc glutCreateSubWindow*(win, x, y, width, height: int): int 258 | proc glutDestroyWindow*(win: int) 259 | proc glutPostRedisplay*() 260 | proc glutPostWindowRedisplay*(win: int) 261 | proc glutSwapBuffers*() 262 | proc glutSetWindow*(win: int) 263 | proc glutSetWindowTitle*(title: cstring) 264 | proc glutSetIconTitle*(title: cstring) 265 | proc glutPositionWindow*(x, y: int) 266 | proc glutReshapeWindow*(width, height: int) 267 | proc glutPopWindow*() 268 | proc glutPushWindow*() 269 | proc glutIconifyWindow*() 270 | proc glutShowWindow*() 271 | proc glutHideWindow*() 272 | proc glutFullScreen*() 273 | proc glutSetCursor*(cursor: int) 274 | proc glutWarpPointer*(x, y: int) 275 | # GLUT overlay sub-API. 276 | proc glutEstablishOverlay*() 277 | proc glutRemoveOverlay*() 278 | proc glutUseLayer*(layer: GLenum) 279 | proc glutPostOverlayRedisplay*() 280 | proc glutPostWindowOverlayRedisplay*(win: int) 281 | proc glutShowOverlay*() 282 | proc glutHideOverlay*() 283 | # GLUT menu sub-API. 284 | proc glutCreateMenu*(callback: TGlut1IntCallback): int 285 | proc glutDestroyMenu*(menu: int) 286 | proc glutSetMenu*(menu: int) 287 | proc glutAddMenuEntry*(caption: cstring, value: int) 288 | proc glutAddSubMenu*(caption: cstring, submenu: int) 289 | proc glutChangeToMenuEntry*(item: int, caption: cstring, value: int) 290 | proc glutChangeToSubMenu*(item: int, caption: cstring, submenu: int) 291 | proc glutRemoveMenuItem*(item: int) 292 | proc glutAttachMenu*(button: int) 293 | proc glutDetachMenu*(button: int) 294 | # GLUT window callback sub-API. 295 | proc glutDisplayFunc*(f: TGlutVoidCallback) 296 | proc glutReshapeFunc*(f: TGlut2IntCallback) 297 | proc glutKeyboardFunc*(f: TGlut1Char2IntCallback) 298 | proc glutMouseFunc*(f: TGlut4IntCallback) 299 | proc glutMotionFunc*(f: TGlut2IntCallback) 300 | proc glutPassiveMotionFunc*(f: TGlut2IntCallback) 301 | proc glutEntryFunc*(f: TGlut1IntCallback) 302 | proc glutVisibilityFunc*(f: TGlut1IntCallback) 303 | proc glutIdleFunc*(f: TGlutVoidCallback) 304 | proc glutTimerFunc*(millis: int16, f: TGlut1IntCallback, value: int) 305 | proc glutMenuStateFunc*(f: TGlut1IntCallback) 306 | proc glutSpecialFunc*(f: TGlut3IntCallback) 307 | proc glutSpaceballMotionFunc*(f: TGlut3IntCallback) 308 | proc glutSpaceballRotateFunc*(f: TGlut3IntCallback) 309 | proc glutSpaceballButtonFunc*(f: TGlut2IntCallback) 310 | proc glutButtonBoxFunc*(f: TGlut2IntCallback) 311 | proc glutDialsFunc*(f: TGlut2IntCallback) 312 | proc glutTabletMotionFunc*(f: TGlut2IntCallback) 313 | proc glutTabletButtonFunc*(f: TGlut4IntCallback) 314 | proc glutMenuStatusFunc*(f: TGlut3IntCallback) 315 | proc glutOverlayDisplayFunc*(f: TGlutVoidCallback) 316 | proc glutWindowStatusFunc*(f: TGlut1IntCallback) 317 | proc glutKeyboardUpFunc*(f: TGlut1Char2IntCallback) 318 | proc glutSpecialUpFunc*(f: TGlut3IntCallback) 319 | proc glutJoystickFunc*(f: TGlut1UInt3IntCallback, pollInterval: int) 320 | # GLUT color index sub-API. 321 | proc glutSetColor*(cell: int, red, green, blue: GLfloat) 322 | proc glutGetColor*(ndx, component: int): GLfloat 323 | proc glutCopyColormap*(win: int) 324 | # GLUT state retrieval sub-API. 325 | # GLUT extension support sub-API 326 | proc glutExtensionSupported*(name: cstring): int 327 | # GLUT font sub-API 328 | proc glutBitmapCharacter*(font: pointer, character: int) 329 | proc glutBitmapWidth*(font: pointer, character: int): int 330 | proc glutBitmapHeight*(font: pointer): int 331 | proc glutStrokeCharacter*(font: pointer, character: int) 332 | proc glutStrokeWidth*(font: pointer, character: int): int 333 | proc glutBitmapLength*(font: pointer, str: cstring): int 334 | proc glutStrokeLength*(font: pointer, str: cstring): int 335 | # GLUT pre-built models sub-API 336 | proc glutWireSphere*(radius: GLdouble, slices, stacks: GLint) 337 | proc glutSolidSphere*(radius: GLdouble, slices, stacks: GLint) 338 | proc glutWireCone*(base, height: GLdouble, slices, stacks: GLint) 339 | proc glutSolidCone*(base, height: GLdouble, slices, stacks: GLint) 340 | proc glutWireCube*(size: GLdouble) 341 | proc glutSolidCube*(size: GLdouble) 342 | proc glutWireTorus*(innerRadius, outerRadius: GLdouble, sides, rings: GLint) 343 | proc glutSolidTorus*(innerRadius, outerRadius: GLdouble, sides, rings: GLint) 344 | proc glutWireDodecahedron*() 345 | proc glutSolidDodecahedron*() 346 | proc glutWireTeapot*(size: GLdouble) 347 | proc glutSolidTeapot*(size: GLdouble) 348 | proc glutWireOctahedron*() 349 | proc glutSolidOctahedron*() 350 | proc glutWireTetrahedron*() 351 | proc glutSolidTetrahedron*() 352 | proc glutWireIcosahedron*() 353 | proc glutSolidIcosahedron*() 354 | # GLUT video resize sub-API. 355 | proc glutVideoResizeGet*(param: GLenum): int 356 | proc glutSetupVideoResizing*() 357 | proc glutStopVideoResizing*() 358 | proc glutVideoResize*(x, y, width, height: int) 359 | proc glutVideoPan*(x, y, width, height: int) 360 | # GLUT debugging sub-API. 361 | proc glutReportErrors*() 362 | # GLUT device control sub-API. 363 | proc glutIgnoreKeyRepeat*(ignore: int) 364 | proc glutSetKeyRepeat*(repeatMode: int) 365 | proc glutForceJoystickFunc*() 366 | # GLUT game mode sub-API. 367 | #example glutGameModeString('1280x1024:32@75'); 368 | proc glutGameModeString*(AString: cstring) 369 | proc glutLeaveGameMode*() 370 | proc glutGameModeGet*(mode: GLenum): int 371 | # implementation 372 | {.pop.} # dynlib: dllname, importc 373 | 374 | # Convenience procs 375 | proc glutInit*() = 376 | ## version that passes `argc` and `argc` implicitely. 377 | var 378 | cmdLine {.importc: "cmdLine".}: array[0..255, cstring] 379 | cmdCount {.importc: "cmdCount".}: cint 380 | glutInit(addr(cmdCount), addr(cmdLine)) 381 | -------------------------------------------------------------------------------- /src/thirdparty/opengl/glx.nim: -------------------------------------------------------------------------------- 1 | # 2 | # 3 | # Translation of the Mesa GLX headers for FreePascal 4 | # Copyright (C) 1999 Sebastian Guenther 5 | # 6 | # 7 | # Mesa 3-D graphics library 8 | # Version: 3.0 9 | # Copyright (C) 1995-1998 Brian Paul 10 | # 11 | 12 | import x11/x, x11/xlib, x11/xutil, ../opengl 13 | 14 | {.deadCodeElim: on.} 15 | 16 | when defined(windows): 17 | const 18 | dllname = "GL.dll" 19 | elif defined(macosx): 20 | const 21 | dllname = "/usr/X11R6/lib/libGL.dylib" 22 | elif defined(linux): 23 | const 24 | dllname = "libGL.so.1" 25 | else: 26 | const 27 | dllname = "libGL.so" 28 | const 29 | GLX_USE_GL* = 1'i32 30 | GLX_BUFFER_SIZE* = 2'i32 31 | GLX_LEVEL* = 3'i32 32 | GLX_RGBA* = 4'i32 33 | GLX_DOUBLEBUFFER* = 5'i32 34 | GLX_STEREO* = 6'i32 35 | GLX_AUX_BUFFERS* = 7'i32 36 | GLX_RED_SIZE* = 8'i32 37 | GLX_GREEN_SIZE* = 9'i32 38 | GLX_BLUE_SIZE* = 10'i32 39 | GLX_ALPHA_SIZE* = 11'i32 40 | GLX_DEPTH_SIZE* = 12'i32 41 | GLX_STENCIL_SIZE* = 13'i32 42 | GLX_ACCUM_RED_SIZE* = 14'i32 43 | GLX_ACCUM_GREEN_SIZE* = 15'i32 44 | GLX_ACCUM_BLUE_SIZE* = 16'i32 45 | GLX_ACCUM_ALPHA_SIZE* = 17'i32 # GLX_EXT_visual_info extension 46 | GLX_X_VISUAL_TYPE_EXT* = 0x00000022 47 | GLX_TRANSPARENT_TYPE_EXT* = 0x00000023 48 | GLX_TRANSPARENT_INDEX_VALUE_EXT* = 0x00000024 49 | GLX_TRANSPARENT_RED_VALUE_EXT* = 0x00000025 50 | GLX_TRANSPARENT_GREEN_VALUE_EXT* = 0x00000026 51 | GLX_TRANSPARENT_BLUE_VALUE_EXT* = 0x00000027 52 | GLX_TRANSPARENT_ALPHA_VALUE_EXT* = 0x00000028 # Error codes returned by glXGetConfig: 53 | GLX_BAD_SCREEN* = 1 54 | GLX_BAD_ATTRIBUTE* = 2 55 | GLX_NO_EXTENSION* = 3 56 | GLX_BAD_VISUAL* = 4 57 | GLX_BAD_CONTEXT* = 5 58 | GLX_BAD_VALUE* = 6 59 | GLX_BAD_ENUM* = 7 # GLX 1.1 and later: 60 | GLX_VENDOR* = 1 61 | GLX_VERSION* = 2 62 | GLX_EXTENSIONS* = 3 # GLX_visual_info extension 63 | GLX_TRUE_COLOR_EXT* = 0x00008002 64 | GLX_DIRECT_COLOR_EXT* = 0x00008003 65 | GLX_PSEUDO_COLOR_EXT* = 0x00008004 66 | GLX_STATIC_COLOR_EXT* = 0x00008005 67 | GLX_GRAY_SCALE_EXT* = 0x00008006 68 | GLX_STATIC_GRAY_EXT* = 0x00008007 69 | GLX_NONE_EXT* = 0x00008000 70 | GLX_TRANSPARENT_RGB_EXT* = 0x00008008 71 | GLX_TRANSPARENT_INDEX_EXT* = 0x00008009 72 | 73 | type # From XLib: 74 | XPixmap* = TXID 75 | XFont* = TXID 76 | XColormap* = TXID 77 | GLXContext* = pointer 78 | GLXPixmap* = TXID 79 | GLXDrawable* = TXID 80 | GLXContextID* = TXID 81 | TXPixmap* = XPixmap 82 | TXFont* = XFont 83 | TXColormap* = XColormap 84 | TGLXContext* = GLXContext 85 | TGLXPixmap* = GLXPixmap 86 | TGLXDrawable* = GLXDrawable 87 | TGLXContextID* = GLXContextID 88 | 89 | GLXBool = cint 90 | 91 | proc glXChooseVisual*(dpy: PDisplay, screen: cint, attribList: ptr int32): PXVisualInfo{. 92 | cdecl, dynlib: dllname, importc: "glXChooseVisual".} 93 | proc glXCreateContext*(dpy: PDisplay, vis: PXVisualInfo, shareList: GLXContext, 94 | direct: GLXBool): GLXContext{.cdecl, dynlib: dllname, 95 | importc: "glXCreateContext".} 96 | proc glXDestroyContext*(dpy: PDisplay, ctx: GLXContext){.cdecl, dynlib: dllname, 97 | importc: "glXDestroyContext".} 98 | proc glXMakeCurrent*(dpy: PDisplay, drawable: GLXDrawable, ctx: GLXContext): GLXBool{. 99 | cdecl, dynlib: dllname, importc: "glXMakeCurrent".} 100 | proc glXCopyContext*(dpy: PDisplay, src, dst: GLXContext, mask: int32){.cdecl, 101 | dynlib: dllname, importc: "glXCopyContext".} 102 | proc glXSwapBuffers*(dpy: PDisplay, drawable: GLXDrawable){.cdecl, 103 | dynlib: dllname, importc: "glXSwapBuffers".} 104 | proc glXCreateGLXPixmap*(dpy: PDisplay, visual: PXVisualInfo, pixmap: XPixmap): GLXPixmap{. 105 | cdecl, dynlib: dllname, importc: "glXCreateGLXPixmap".} 106 | proc glXDestroyGLXPixmap*(dpy: PDisplay, pixmap: GLXPixmap){.cdecl, 107 | dynlib: dllname, importc: "glXDestroyGLXPixmap".} 108 | proc glXQueryExtension*(dpy: PDisplay, errorb, event: var cint): GLXBool{.cdecl, 109 | dynlib: dllname, importc: "glXQueryExtension".} 110 | proc glXQueryVersion*(dpy: PDisplay, maj, min: var cint): GLXBool{.cdecl, 111 | dynlib: dllname, importc: "glXQueryVersion".} 112 | proc glXIsDirect*(dpy: PDisplay, ctx: GLXContext): GLXBool{.cdecl, dynlib: dllname, 113 | importc: "glXIsDirect".} 114 | proc glXGetConfig*(dpy: PDisplay, visual: PXVisualInfo, attrib: cint, 115 | value: var cint): cint{.cdecl, dynlib: dllname, 116 | importc: "glXGetConfig".} 117 | proc glXGetCurrentContext*(): GLXContext{.cdecl, dynlib: dllname, 118 | importc: "glXGetCurrentContext".} 119 | proc glXGetCurrentDrawable*(): GLXDrawable{.cdecl, dynlib: dllname, 120 | importc: "glXGetCurrentDrawable".} 121 | proc glXWaitGL*(){.cdecl, dynlib: dllname, importc: "glXWaitGL".} 122 | proc glXWaitX*(){.cdecl, dynlib: dllname, importc: "glXWaitX".} 123 | proc glXUseXFont*(font: XFont, first, count, list: cint){.cdecl, dynlib: dllname, 124 | importc: "glXUseXFont".} 125 | # GLX 1.1 and later 126 | proc glXQueryExtensionsString*(dpy: PDisplay, screen: cint): cstring{.cdecl, 127 | dynlib: dllname, importc: "glXQueryExtensionsString".} 128 | proc glXQueryServerString*(dpy: PDisplay, screen, name: cint): cstring{.cdecl, 129 | dynlib: dllname, importc: "glXQueryServerString".} 130 | proc glXGetClientString*(dpy: PDisplay, name: cint): cstring{.cdecl, 131 | dynlib: dllname, importc: "glXGetClientString".} 132 | # Mesa GLX Extensions 133 | proc glXCreateGLXPixmapMESA*(dpy: PDisplay, visual: PXVisualInfo, 134 | pixmap: XPixmap, cmap: XColormap): GLXPixmap{. 135 | cdecl, dynlib: dllname, importc: "glXCreateGLXPixmapMESA".} 136 | proc glXReleaseBufferMESA*(dpy: PDisplay, d: GLXDrawable): GLXBool{.cdecl, 137 | dynlib: dllname, importc: "glXReleaseBufferMESA".} 138 | proc glXCopySubBufferMESA*(dpy: PDisplay, drawbale: GLXDrawable, 139 | x, y, width, height: cint){.cdecl, dynlib: dllname, 140 | importc: "glXCopySubBufferMESA".} 141 | proc glXGetVideoSyncSGI*(counter: var int32): cint{.cdecl, dynlib: dllname, 142 | importc: "glXGetVideoSyncSGI".} 143 | proc glXWaitVideoSyncSGI*(divisor, remainder: cint, count: var int32): cint{. 144 | cdecl, dynlib: dllname, importc: "glXWaitVideoSyncSGI".} 145 | # implementation 146 | -------------------------------------------------------------------------------- /src/thirdparty/opengl/private/errors.nim: -------------------------------------------------------------------------------- 1 | import macros, sequtils 2 | 3 | proc glGetError*(): GLenum {.stdcall, importc, ogl.} 4 | 5 | macro wrapErrorChecking*(f: untyped): typed = 6 | f.expectKind nnkStmtList 7 | result = newStmtList() 8 | 9 | for child in f.children: 10 | if child.kind == nnkCommentStmt: 11 | continue 12 | child.expectKind nnkProcDef 13 | 14 | let params = toSeq(child.params.children) 15 | var glProc = copy child 16 | glProc.pragma = newTree(nnkPragma, 17 | newTree(nnkExprColonExpr, 18 | ident"importc" , newLit($child.name)), 19 | ident"ogl") 20 | 21 | let rawGLprocName = $glProc.name 22 | glProc.name = ident(rawGLprocName & "Impl") 23 | var 24 | body = newStmtList glProc 25 | returnsSomething = child.params[0].kind != nnkEmpty 26 | callParams = newSeq[NimNode]() 27 | for param in params[1 ..< params.len]: 28 | callParams.add param[0] 29 | 30 | let glCall = newCall(glProc.name, callParams) 31 | body.add if returnsSomething: 32 | newAssignment(ident"result", glCall) 33 | else: 34 | glCall 35 | 36 | if rawGLprocName == "glBegin": 37 | body.add newAssignment(ident"gInsideBeginEnd", ident"true") 38 | if rawGLprocName == "glEnd": 39 | body.add newAssignment(ident"gInsideBeginEnd", ident"false") 40 | 41 | template errCheck: untyped = 42 | when not (NoAutoGLerrorCheck): 43 | if gAutoGLerrorCheck and not gInsideBeginEnd: 44 | checkGLerror() 45 | 46 | body.add getAst(errCheck()) 47 | 48 | var procc = newProc(child.name, params, body) 49 | procc.pragma = newTree(nnkPragma, ident"inline") 50 | procc.name = postfix(procc.name, "*") 51 | result.add procc 52 | 53 | type 54 | GLerrorCode* {.size: GLenum.sizeof.} = enum 55 | glErrNoError = (0, "no error") 56 | glErrInvalidEnum = (0x0500, "invalid enum") 57 | glErrInvalidValue = (0x0501, "invalid value") 58 | glErrInvalidOperation = (0x0502, "invalid operation") 59 | glErrStackOverflow = (0x0503, "stack overflow") 60 | glErrStackUnderflow = (0x0504, "stack underflow") 61 | glErrOutOfMem = (0x0505, "out of memory") 62 | glErrInvalidFramebufferOperation = (0x0506, "invalid framebuffer operation") 63 | glErrTableTooLarge = (0x8031, "table too large") 64 | 65 | const AllErrorCodes = [ 66 | glErrNoError, 67 | glErrInvalidEnum, 68 | glErrInvalidValue, 69 | glErrInvalidOperation, 70 | glErrStackOverflow, 71 | glErrStackUnderflow, 72 | glErrOutOfMem, 73 | glErrInvalidFramebufferOperation, 74 | glErrTableTooLarge, 75 | ] 76 | 77 | proc getGLerrorCode*: GLerrorCode = glGetError().GLerrorCode 78 | ## Like ``glGetError`` but returns an enumerator instead. 79 | 80 | type 81 | GLerror* = object of Exception 82 | ## An exception for OpenGL errors. 83 | code*: GLerrorCode ## The error code. This might be invalid for two reasons: 84 | ## an outdated list of errors or a bad driver. 85 | 86 | proc checkGLerror* = 87 | ## Raise ``GLerror`` if the last call to an OpenGL function generated an error. 88 | ## You might want to call this once every frame for example if automatic 89 | ## error checking has been disabled. 90 | let error = getGLerrorCode() 91 | if error == glErrNoError: 92 | return 93 | 94 | var 95 | exc = new(GLerror) 96 | for e in AllErrorCodes: 97 | if e == error: 98 | exc.msg = "OpenGL error: " & $e 99 | raise exc 100 | 101 | exc.code = error 102 | exc.msg = "OpenGL error: unknown (" & $error & ")" 103 | raise exc 104 | 105 | {.push warning[User]: off.} 106 | 107 | const 108 | NoAutoGLerrorCheck* = defined(noAutoGLerrorCheck) ##\ 109 | ## This determines (at compile time) whether an exception should be raised 110 | ## if an OpenGL call generates an error. No additional code will be generated 111 | ## and ``enableAutoGLerrorCheck(bool)`` will have no effect when 112 | ## ``noAutoGLerrorCheck`` is defined. 113 | 114 | {.pop.} # warning[User]: off 115 | 116 | var 117 | gAutoGLerrorCheck = true 118 | gInsideBeginEnd* = false # do not change manually. 119 | 120 | proc enableAutoGLerrorCheck*(yes: bool) = 121 | ## This determines (at run time) whether an exception should be raised if an 122 | ## OpenGL call generates an error. This has no effect when 123 | ## ``noAutoGLerrorCheck`` is defined. 124 | gAutoGLerrorCheck = yes 125 | -------------------------------------------------------------------------------- /src/thirdparty/opengl/private/prelude.nim: -------------------------------------------------------------------------------- 1 | {.deadCodeElim: on.} 2 | {.push warning[User]: off.} 3 | 4 | when defined(windows): 5 | const 6 | ogldll* = "OpenGL32.dll" 7 | gludll* = "GLU32.dll" 8 | elif defined(macosx): 9 | #macosx has this notion of a framework, thus the path to the openGL dylib files 10 | #is absolute 11 | const 12 | ogldll* = "/System/Library/Frameworks/OpenGL.framework/Versions/Current/Libraries/libGL.dylib" 13 | gludll* = "/System/Library/Frameworks/OpenGL.framework/Versions/Current/Libraries/libGLU.dylib" 14 | else: 15 | const 16 | ogldll* = "libGL.so.1" 17 | gludll* = "libGLU.so.1" 18 | 19 | when defined(useGlew): 20 | {.pragma: ogl, header: "".} 21 | {.pragma: oglx, header: "".} 22 | {.pragma: wgl, header: "".} 23 | {.pragma: glu, dynlib: gludll.} 24 | 25 | when defined(linux) or defined(windows): 26 | {.passC: "-flto -useGlew".} 27 | when defined(windows): 28 | {.passL: "-lglew32 -lopengl32".} 29 | elif defined(linux): 30 | {.passL: "-lGLEW -lGL".} 31 | elif defined(ios): 32 | {.pragma: ogl.} 33 | {.pragma: oglx.} 34 | {.passC: "-framework OpenGLES", passL: "-framework OpenGLES".} 35 | elif defined(android) or defined(js) or defined(emscripten) or defined(wasm): 36 | {.pragma: ogl.} 37 | {.pragma: oglx.} 38 | else: 39 | # quite complex ... thanks to extension support for various platforms: 40 | import dynlib 41 | 42 | let oglHandle = loadLib(ogldll) 43 | if isNil(oglHandle): quit("could not load: " & ogldll) 44 | 45 | when defined(windows): 46 | var wglGetProcAddress = cast[proc (s: cstring): pointer {.stdcall.}]( 47 | symAddr(oglHandle, "wglGetProcAddress")) 48 | elif defined(linux): 49 | var glxGetProcAddress = cast[proc (s: cstring): pointer {.cdecl.}]( 50 | symAddr(oglHandle, "glXGetProcAddress")) 51 | var glxGetProcAddressArb = cast[proc (s: cstring): pointer {.cdecl.}]( 52 | symAddr(oglHandle, "glXGetProcAddressARB")) 53 | 54 | proc glGetProc(h: LibHandle; procName: cstring): pointer = 55 | when defined(windows): 56 | result = symAddr(h, procname) 57 | if result != nil: return 58 | if not isNil(wglGetProcAddress): result = wglGetProcAddress(procName) 59 | elif defined(linux): 60 | if not isNil(glxGetProcAddress): result = glxGetProcAddress(procName) 61 | if result != nil: return 62 | if not isNil(glxGetProcAddressArb): 63 | result = glxGetProcAddressArb(procName) 64 | if result != nil: return 65 | result = symAddr(h, procname) 66 | else: 67 | result = symAddr(h, procName) 68 | if result == nil: raiseInvalidLibrary(procName) 69 | 70 | proc glGetProc*(name: cstring): pointer {.inline.} = 71 | glGetProc(oglHandle, name) 72 | 73 | var gluHandle: LibHandle 74 | 75 | proc gluGetProc(procname: cstring): pointer = 76 | if gluHandle == nil: 77 | gluHandle = loadLib(gludll) 78 | if gluHandle == nil: quit("could not load: " & gludll) 79 | result = glGetProc(gluHandle, procname) 80 | 81 | # undocumented 'dynlib' feature: the string literal is replaced by 82 | # the imported proc name: 83 | {.pragma: ogl, dynlib: glGetProc("0").} 84 | {.pragma: oglx, dynlib: glGetProc("0").} 85 | {.pragma: wgl, dynlib: glGetProc("0").} 86 | {.pragma: glu, dynlib: gluGetProc("").} 87 | 88 | proc nimLoadProcs0() {.importc.} 89 | 90 | template loadExtensions*() = 91 | ## call this after your rendering context has been setup if you use 92 | ## extensions. 93 | bind nimLoadProcs0 94 | nimLoadProcs0() 95 | 96 | {.pop.} # warning[User]: off -------------------------------------------------------------------------------- /src/thirdparty/opengl/private/types.nim: -------------------------------------------------------------------------------- 1 | type 2 | GLenum* = distinct uint32 3 | GLboolean* = bool 4 | GLbitfield* = distinct uint32 5 | GLvoid* = pointer 6 | GLbyte* = int8 7 | GLshort* = int16 8 | GLint* = int32 9 | GLclampx* = int32 10 | GLubyte* = uint8 11 | GLushort* = uint16 12 | GLuint* = uint32 13 | GLhandle* = GLuint 14 | GLsizei* = int32 15 | GLfloat* = float32 16 | GLclampf* = float32 17 | GLdouble* = float64 18 | GLclampd* = float64 19 | GLeglImageOES* = distinct pointer 20 | GLchar* = char 21 | GLcharArb* = char 22 | GLfixed* = int32 23 | GLhalfNv* = uint16 24 | GLvdpauSurfaceNv* = uint 25 | GLintptr* = int 26 | GLintptrArb* = int 27 | GLint64EXT* = int64 28 | GLuint64EXT* = uint64 29 | GLint64* = int64 30 | GLsizeiptrArb* = int 31 | GLsizeiptr* = int 32 | GLsync* = distinct pointer 33 | GLuint64* = uint64 34 | GLvectorub2* = array[0..1, GLubyte] 35 | GLvectori2* = array[0..1, GLint] 36 | GLvectorf2* = array[0..1, GLfloat] 37 | GLvectord2* = array[0..1, GLdouble] 38 | GLvectorp2* = array[0..1, pointer] 39 | GLvectorb3* = array[0..2, GLbyte] 40 | GLvectorub3* = array[0..2, GLubyte] 41 | GLvectori3* = array[0..2, GLint] 42 | GLvectorui3* = array[0..2, GLuint] 43 | GLvectorf3* = array[0..2, GLfloat] 44 | GLvectord3* = array[0..2, GLdouble] 45 | GLvectorp3* = array[0..2, pointer] 46 | GLvectors3* = array[0..2, GLshort] 47 | GLvectorus3* = array[0..2, GLushort] 48 | GLvectorb4* = array[0..3, GLbyte] 49 | GLvectorub4* = array[0..3, GLubyte] 50 | GLvectori4* = array[0..3, GLint] 51 | GLvectorui4* = array[0..3, GLuint] 52 | GLvectorf4* = array[0..3, GLfloat] 53 | GLvectord4* = array[0..3, GLdouble] 54 | GLvectorp4* = array[0..3, pointer] 55 | GLvectors4* = array[0..3, GLshort] 56 | GLvectorus4* = array[0..3, GLshort] 57 | GLarray4f* = GLvectorf4 58 | GLarrayf3* = GLvectorf3 59 | GLarrayd3* = GLvectord3 60 | GLarrayi4* = GLvectori4 61 | GLarrayp4* = GLvectorp4 62 | GLmatrixub3* = array[0..2, array[0..2, GLubyte]] 63 | GLmatrixi3* = array[0..2, array[0..2, GLint]] 64 | GLmatrixf3* = array[0..2, array[0..2, GLfloat]] 65 | GLmatrixd3* = array[0..2, array[0..2, GLdouble]] 66 | GLmatrixub4* = array[0..3, array[0..3, GLubyte]] 67 | GLmatrixi4* = array[0..3, array[0..3, GLint]] 68 | GLmatrixf4* = array[0..3, array[0..3, GLfloat]] 69 | GLmatrixd4* = array[0..3, array[0..3, GLdouble]] 70 | ClContext* = distinct pointer 71 | ClEvent* = distinct pointer 72 | GLdebugProc* = proc ( 73 | source: GLenum, 74 | typ: GLenum, 75 | id: GLuint, 76 | severity: GLenum, 77 | length: GLsizei, 78 | message: ptr GLchar, 79 | userParam: pointer) {.stdcall.} 80 | GLdebugProcArb* = proc ( 81 | source: GLenum, 82 | typ: GLenum, 83 | id: GLuint, 84 | severity: GLenum, 85 | len: GLsizei, 86 | message: ptr GLchar, 87 | userParam: pointer) {.stdcall.} 88 | GLdebugProcAmd* = proc ( 89 | id: GLuint, 90 | category: GLenum, 91 | severity: GLenum, 92 | len: GLsizei, 93 | message: ptr GLchar, 94 | userParam: pointer) {.stdcall.} 95 | GLdebugProcKhr* = proc ( 96 | source, typ: GLenum, 97 | id: GLuint, 98 | severity: GLenum, 99 | length: GLsizei, 100 | message: ptr GLchar, 101 | userParam: pointer) {.stdcall.} 102 | 103 | when defined(macosx): 104 | type 105 | GLhandleArb = pointer 106 | else: 107 | type 108 | GLhandleArb = uint32 109 | 110 | proc `==`*(a, b: GLenum): bool {.borrow.} 111 | proc `==`*(a, b: GLbitfield): bool {.borrow.} 112 | proc `or`*(a, b: GLbitfield): GLbitfield {.borrow.} 113 | proc hash*(x: GLenum): int = x.int 114 | 115 | when defined(useGlew): 116 | proc glewInit*(): GLenum {.importc, used.} 117 | -------------------------------------------------------------------------------- /src/thirdparty/sdl2/gamecontroller.nim: -------------------------------------------------------------------------------- 1 | discard """ 2 | Simple DirectMedia Layer 3 | Copyright (C) 1997-2014 Sam Lantinga 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 3. This notice may not be removed or altered from any source distribution. 20 | """ 21 | 22 | 23 | ## SDL game controller event handling 24 | ## 25 | ## In order to use these functions, `sdl.init()` must have been called 26 | ## with the `SDL_INIT_JOYSTICK` flag. This causes SDL to scan the system 27 | ## for game controllers, and load appropriate drivers. 28 | ## 29 | ## If you would like to receive controller updates while the application 30 | ## is in the background, you should set the following hint before calling 31 | ## init(): SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS 32 | 33 | import 34 | ../sdl2, 35 | ./joystick 36 | 37 | 38 | type 39 | GameController* = object 40 | ## The gamecontroller structure used to identify an SDL game controller. 41 | 42 | GameControllerPtr* = ptr GameController 43 | 44 | GameControllerBindType* {.size: sizeof(cint).} = enum 45 | SDL_CONTROLLER_BINDTYPE_NONE, 46 | SDL_CONTROLLER_BINDTYPE_BUTTON, 47 | SDL_CONTROLLER_BINDTYPE_AXIS, 48 | SDL_CONTROLLER_BINDTYPE_HAT 49 | 50 | # Get the SDL joystick layer binding for this controller button/axis mapping 51 | 52 | type 53 | GameControllerButtonBind* = object 54 | ## Get the SDL joystick layer binding 55 | ## for this controller button/axis mapping 56 | case bindType*: GameControllerBindType 57 | of SDL_CONTROLLER_BINDTYPE_NONE: 58 | nil 59 | of SDL_CONTROLLER_BINDTYPE_BUTTON: 60 | button*: cint 61 | of SDL_CONTROLLER_BINDTYPE_AXIS: 62 | axis*: cint 63 | of SDL_CONTROLLER_BINDTYPE_HAT: 64 | hat*, hatMask*: cint 65 | 66 | when defined(SDL_Static): 67 | static: echo "SDL_Static option is deprecated and will soon be removed. Instead please use --dynlibOverride:SDL2." 68 | else: 69 | {.push callConv: cdecl, dynlib: LibName.} 70 | 71 | proc gameControllerAddMapping*(mappingString: cstring): cint {. 72 | importc: "SDL_GameControllerAddMapping".} 73 | ## Add or update an existing mapping configuration. 74 | ## 75 | ## `Return` `1` if mapping is added, `0` if updated, `-1` on error. 76 | 77 | proc gameControllerMappingForGUID*(guid: JoystickGuid): cstring {. 78 | importc: "SDL_GameControllerMappingForGUID".} 79 | ## Get a mapping string for a GUID. 80 | ## 81 | ## `Return` the mapping string. Must be freed with `sdl.free()`. 82 | ## Returns `nil` if no mapping is available 83 | 84 | proc mapping*(gameController: GameControllerPtr): cstring {. 85 | importc: "SDL_GameControllerMapping".} 86 | ## Get a mapping string for an open GameController. 87 | ## 88 | ## `Return` the mapping string. Must be freed with `sdl.free()`. 89 | ## Returns `nil` if no mapping is available 90 | 91 | proc isGameController*(joystickIndex: cint): Bool32 {. 92 | importc: "SDL_IsGameController".} 93 | ## Is the joystick on this index supported by the game controller interface? 94 | 95 | proc gameControllerNameForIndex*(joystickIndex: cint): cstring {. 96 | importc: "SDL_GameControllerNameForIndex".} 97 | ## Get the implementation dependent name of a game controller. 98 | ## 99 | ## This can be called before any controllers are opened. 100 | ## If no name can be found, this procedure returns `nil`. 101 | 102 | proc gameControllerOpen*(joystickIndex: cint): GameControllerPtr {. 103 | importc: "SDL_GameControllerOpen".} 104 | ## Open a game controller for use. 105 | ## 106 | ## The index passed as an argument refers to the N'th game controller 107 | ## on the system. 108 | ## 109 | ## This index is not the value which will identify this controller in future 110 | ## controller events. The joystick's instance id (`JoystickID`) will be 111 | ## used there instead. 112 | ## 113 | ## `Return` a controller identifier, or `nil` if an error occurred. 114 | 115 | proc name*(gameController: GameControllerPtr): cstring {. 116 | importc: "SDL_GameControllerName".} 117 | ## `Return` the name for this currently opened controller. 118 | 119 | proc getAttached*(gameController: GameControllerPtr): Bool32 {. 120 | importc: "SDL_GameControllerGetAttached".} 121 | ## `Returns` `true` if the controller has been opened and currently 122 | ## connected, or `false` if it has not. 123 | 124 | proc getJoystick*(gameController: GameControllerPtr): JoystickPtr {. 125 | importc: "SDL_GameControllerGetJoystick".} 126 | ## Get the underlying joystick object used by a controller. 127 | 128 | proc gameControllerEventState*(state: cint): cint {. 129 | importc: "SDL_GameControllerEventState".} 130 | ## Enable/disable controller event polling. 131 | ## 132 | ## If controller events are disabled, you must call 133 | ## `gameControllerUpdate()` yourself and check the state of the 134 | ## controller when you want controller information. 135 | ## 136 | ## The state can be one of `SDL_QUERY`, `SDL_ENABLE` or `SDL_IGNORE`. 137 | 138 | 139 | proc gameControllerUpdate*() {.importc: "SDL_GameControllerUpdate".} 140 | ## Update the current state of the open game controllers. 141 | ## 142 | ## This is called automatically by the event loop if any game controller 143 | ## events are enabled. 144 | 145 | type 146 | GameControllerAxis* {.size: sizeof(cint).} = enum 147 | ## The list of axes available from a controller. 148 | ## 149 | ## Thumbstick axis values range 150 | ## from `JOYSTICK_AXIS_MIN` to `JOYSTICK_AXIS_MAX`, 151 | ## and are centered within ~8000 of zero, 152 | ## though advanced UI will allow users to set 153 | ## or autodetect the dead zone, which varies between controllers. 154 | ## 155 | ## Trigger axis values range from `0` to `JOYSTICK_AXIS_MAX`. 156 | SDL_CONTROLLER_AXIS_INVALID = -1, 157 | SDL_CONTROLLER_AXIS_LEFTX, 158 | SDL_CONTROLLER_AXIS_LEFTY, 159 | SDL_CONTROLLER_AXIS_RIGHTX, 160 | SDL_CONTROLLER_AXIS_RIGHTY, 161 | SDL_CONTROLLER_AXIS_TRIGGERLEFT, 162 | SDL_CONTROLLER_AXIS_TRIGGERRIGHT, 163 | SDL_CONTROLLER_AXIS_MAX 164 | 165 | converter toInt*(some: GameControllerAxis): uint8 = uint8(some) 166 | 167 | proc gameControllerGetAxisFromString*(pchString: cstring): GameControllerAxis {. 168 | importc: "SDL_GameControllerGetAxisFromString".} 169 | ## Turn this string into a axis mapping. 170 | 171 | proc gameControllerGetStringForAxis*(axis: GameControllerAxis): cstring {. 172 | importc: "SDL_GameControllerGetStringForAxis".} 173 | ## Turn this axis enum into a string mapping. 174 | 175 | proc getBindForAxis*(gameController: GameControllerPtr, 176 | axis: GameControllerAxis): GameControllerButtonBind {. 177 | importc: "SDL_GameControllerGetBindForAxis".} 178 | ## Get the SDL joystick layer binding for this controller button mapping. 179 | 180 | proc getAxis*(gameController: GameControllerPtr, 181 | axis: GameControllerAxis): int16 {. 182 | importc: "SDL_GameControllerGetAxis".} 183 | ## Get the current state of an axis control on a game controller. 184 | ## 185 | ## The state is a value ranging from `-32768` to `32767` 186 | ## (except for the triggers, which range from `0` to `32767`. 187 | ## 188 | ## The axis indices start at index `0`. 189 | 190 | type 191 | GameControllerButton* {.size: sizeof(cint).} = enum 192 | ## The list of buttons available from a controller 193 | SDL_CONTROLLER_BUTTON_INVALID = -1, 194 | SDL_CONTROLLER_BUTTON_A, 195 | SDL_CONTROLLER_BUTTON_B, 196 | SDL_CONTROLLER_BUTTON_X, 197 | SDL_CONTROLLER_BUTTON_Y, 198 | SDL_CONTROLLER_BUTTON_BACK, 199 | SDL_CONTROLLER_BUTTON_GUIDE, 200 | SDL_CONTROLLER_BUTTON_START, 201 | SDL_CONTROLLER_BUTTON_LEFTSTICK, 202 | SDL_CONTROLLER_BUTTON_RIGHTSTICK, 203 | SDL_CONTROLLER_BUTTON_LEFTSHOULDER, 204 | SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, 205 | SDL_CONTROLLER_BUTTON_DPAD_UP, 206 | SDL_CONTROLLER_BUTTON_DPAD_DOWN, 207 | SDL_CONTROLLER_BUTTON_DPAD_LEFT, 208 | SDL_CONTROLLER_BUTTON_DPAD_RIGHT, 209 | SDL_CONTROLLER_BUTTON_MAX 210 | 211 | converter toInt*(some: GameControllerButton): uint8 = uint8(some) 212 | 213 | proc gameControllerGetButtonFromString*( 214 | pchString: cstring): GameControllerButton {. 215 | importc: "SDL_GameControllerGetButtonFromString".} 216 | ## Turn this string into a button mapping. 217 | 218 | proc gameControllerGetStringForButton*( 219 | button: GameControllerButton): cstring {. 220 | importc: "SDL_GameControllerGetStringForButton".} 221 | ## Turn this button enum into a string mapping. 222 | 223 | proc getBindForButton*( 224 | gameController: GameControllerPtr, 225 | button: GameControllerButton): GameControllerButtonBind {. 226 | importc: "SDL_GameControllerGetBindForButton".} 227 | ## Get the SDL joystick layer binding for this controller button mapping. 228 | 229 | proc getButton*( 230 | gameController: GameControllerPtr, 231 | button: GameControllerButton): uint8 {. 232 | importc: "SDL_GameControllerGetButton".} 233 | ## Get the current state of a button on a game controller. 234 | ## 235 | ## The button indices start at index `0`. 236 | 237 | proc close*(gameController: GameControllerPtr) {. 238 | importc: "SDL_GameControllerClose".} 239 | ## Close a controller previously opened with `gameControllerOpen()`. 240 | 241 | 242 | when not defined(SDL_Static): 243 | {.pop.} 244 | -------------------------------------------------------------------------------- /src/thirdparty/sdl2/image.nim: -------------------------------------------------------------------------------- 1 | ## A simple library to load images of various formats as SDL surfaces. 2 | 3 | 4 | import ../sdl2 5 | 6 | when not defined(SDL_Static): 7 | when defined(windows): 8 | const LibName = "SDL2_image.dll" 9 | elif defined(macosx): 10 | const LibName = "libSDL2_image.dylib" 11 | else: 12 | const LibName = "libSDL2_image(|-2.0).so(|.0)" 13 | else: 14 | static: echo "SDL_Static option is deprecated and will soon be removed. Instead please use --dynlibOverride:SDL2." 15 | 16 | const 17 | IMG_INIT_JPG* = 0x00000001 18 | IMG_INIT_PNG* = 0x00000002 19 | IMG_INIT_TIF* = 0x00000004 20 | IMG_INIT_WEBP* = 0x00000008 21 | 22 | when not defined(SDL_Static): 23 | {.push callConv: cdecl, dynlib: LibName.} 24 | 25 | proc linkedVersion*(): ptr SDL_version {.importc: "IMG_Linked_Version".} 26 | ## Gets the version of the dynamically linked image library. 27 | 28 | proc init*(flags: cint = IMG_INIT_JPG or IMG_INIT_PNG): cint {.importc: "IMG_Init".} 29 | ## It returns the flags successfully initialized, or 0 on failure. 30 | ## This is completely different than sdl2.init() -_- 31 | 32 | proc quit*() {.importc: "IMG_Quit".} 33 | ## Unloads libraries loaded with `init()`. 34 | 35 | proc loadTyped_RW*(src: RWopsPtr; freesrc: cint; 36 | `type`: cstring): SurfacePtr {.importc: "IMG_LoadTyped_RW".} 37 | ## Load an image from an SDL data source. 38 | ## 39 | ## `kind` may be one of: `"BMP"`, `"GIF"`, `"PNG"`, etc. 40 | ## 41 | ## If the image format supports a transparent pixel, SDL will set the 42 | ## colorkey for the surface. You can enable RLE acceleration on the 43 | ## surface afterwards by calling: 44 | ## 45 | ## .. code-block:: nim 46 | ## setColorKey(image, SDL_RLEACCEL, image.format.colorkey) 47 | 48 | # Convenience functions 49 | proc load*(file: cstring): SurfacePtr {.importc: "IMG_Load".} 50 | proc load_RW*(src: RWopsPtr; 51 | freesrc: cint): SurfacePtr {.importc: "IMG_Load_RW".} 52 | ## Load an image directly into a render texture. 53 | 54 | proc loadTexture*(renderer: RendererPtr; 55 | file: cstring): TexturePtr {.importc: "IMG_LoadTexture".} 56 | proc loadTexture_RW*(renderer: RendererPtr; src: RWopsPtr; 57 | freesrc: cint): TexturePtr {. 58 | importc: "IMG_LoadTexture_RW".} 59 | proc loadTextureTyped_RW*(renderer: RendererPtr; 60 | src: RWopsPtr; 61 | freesrc: cint; 62 | `type`: cstring): TexturePtr {. 63 | importc: "IMG_LoadTextureTyped_RW".} 64 | 65 | # Functions to detect a file type, given a seekable source 66 | proc isICO*(src: RWopsPtr): cint {.importc: "IMG_isICO".} 67 | proc isCUR*(src: RWopsPtr): cint {.importc: "IMG_isCUR".} 68 | proc isBMP*(src: RWopsPtr): cint {.importc: "IMG_isBMP".} 69 | proc isGIF*(src: RWopsPtr): cint {.importc: "IMG_isGIF".} 70 | proc isJPG*(src: RWopsPtr): cint {.importc: "IMG_isJPG".} 71 | proc isLBM*(src: RWopsPtr): cint {.importc: "IMG_isLBM".} 72 | proc isPCX*(src: RWopsPtr): cint {.importc: "IMG_isPCX".} 73 | proc isPNG*(src: RWopsPtr): cint {.importc: "IMG_isPNG".} 74 | proc isPNM*(src: RWopsPtr): cint {.importc: "IMG_isPNM".} 75 | proc isTIF*(src: RWopsPtr): cint {.importc: "IMG_isTIF".} 76 | proc isXCF*(src: RWopsPtr): cint {.importc: "IMG_isXCF".} 77 | proc isXPM*(src: RWopsPtr): cint {.importc: "IMG_isXPM".} 78 | proc isXV*(src: RWopsPtr): cint {.importc: "IMG_isXV".} 79 | proc isWEBP*(src: RWopsPtr): cint {.importc: "IMG_isWEBP".} 80 | # Individual loading functions 81 | proc loadICO_RW*(src: RWopsPtr): SurfacePtr {.importc: "IMG_LoadICO_RW".} 82 | proc loadCUR_RW*(src: RWopsPtr): SurfacePtr {.importc: "IMG_LoadCUR_RW".} 83 | proc loadBMP_RW*(src: RWopsPtr): SurfacePtr {.importc: "IMG_LoadBMP_RW".} 84 | proc loadGIF_RW*(src: RWopsPtr): SurfacePtr {.importc: "IMG_LoadGIF_RW".} 85 | proc loadJPG_RW*(src: RWopsPtr): SurfacePtr {.importc: "IMG_LoadJPG_RW".} 86 | proc loadLBM_RW*(src: RWopsPtr): SurfacePtr {.importc: "IMG_LoadLBM_RW".} 87 | proc loadPCX_RW*(src: RWopsPtr): SurfacePtr {.importc: "IMG_LoadPCX_RW".} 88 | proc loadPNG_RW*(src: RWopsPtr): SurfacePtr {.importc: "IMG_LoadPNG_RW".} 89 | proc loadPNM_RW*(src: RWopsPtr): SurfacePtr {.importc: "IMG_LoadPNM_RW".} 90 | proc loadTGA_RW*(src: RWopsPtr): SurfacePtr {.importc: "IMG_LoadTGA_RW".} 91 | proc loadTIF_RW*(src: RWopsPtr): SurfacePtr {.importc: "IMG_LoadTIF_RW".} 92 | proc loadXCF_RW*(src: RWopsPtr): SurfacePtr {.importc: "IMG_LoadXCF_RW".} 93 | proc loadXPM_RW*(src: RWopsPtr): SurfacePtr {.importc: "IMG_LoadXPM_RW".} 94 | proc loadXV_RW*(src: RWopsPtr): SurfacePtr {.importc: "IMG_LoadXV_RW".} 95 | proc loadWEBP_RW*(src: RWopsPtr): SurfacePtr {.importc: "IMG_LoadWEBP_RW".} 96 | proc readXPMFromArray*(xpm: cstringArray): SurfacePtr {.importc: "IMG_ReadXPMFromArray".} 97 | # Saving functions 98 | proc savePNG*(surface: SurfacePtr, file: cstring): cint {.importc: "IMG_SavePNG".} 99 | 100 | when not defined(SDL_Static): 101 | {.pop.} 102 | -------------------------------------------------------------------------------- /src/thirdparty/sdl2/joystick.nim: -------------------------------------------------------------------------------- 1 | discard """ Simple DirectMedia Layer 2 | Copyright (C) 1997-2014 Sam Lantinga 3 | 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any damages 6 | arising from the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any purpose, 9 | including commercial applications, and to alter it and redistribute it 10 | freely, subject to the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; you must not 13 | claim that you wrote the original software. If you use this software 14 | in a product, an acknowledgment in the product documentation would be 15 | appreciated but is not required. 16 | 2. Altered source versions must be plainly marked as such, and must not be 17 | misrepresented as being the original software. 18 | 3. This notice may not be removed or altered from any source distribution. 19 | 20 | """ 21 | 22 | ## Include file for SDL joystick event handling 23 | ## 24 | ## The term "device_index" identifies currently plugged in joystick devices 25 | ## between 0 and SDL_NumJoysticks, with the exact joystick behind a 26 | ## device_index changing as joysticks are plugged and unplugged. 27 | ## 28 | ## The term "instance_id" is the current instantiation of a joystick device in 29 | ## the system, if the joystick is removed and then re-inserted then it will get 30 | ## a new instance_id, instance_id's are monotonically increasing identifiers of 31 | ## a joystick plugged in. 32 | ## 33 | ## The term JoystickGUID is a stable 128-bit identifier for a joystick device 34 | ## that does not change over time, it identifies class of the device 35 | ## (a X360 wired controller for example). This identifier is platform dependent. 36 | ## 37 | ## In order to use these functions, `init()` must have been called with 38 | ## the `INIT_JOYSTICK` flag. This causes SDL to scan the system for joysticks, 39 | ## and load appropriate drivers. 40 | ## 41 | ## If you would like to receive joystick updates while the application 42 | ## is in the background, you should set the following hint before calling 43 | ## `init()`: `SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS` 44 | import ../sdl2 45 | 46 | 47 | # The joystick structure used to identify an SDL joystick 48 | type 49 | Joystick* = object 50 | JoystickPtr* = ptr Joystick 51 | 52 | # A structure that encodes the stable unique id for a joystick device# 53 | type 54 | JoystickGuid* = object 55 | data: array[16, uint8] 56 | JoystickID* = int32 57 | ## This is a unique ID for a joystick for the time it is connected to the 58 | ## system, and is never reused for the lifetime of the application. If the 59 | ## joystick is disconnected and reconnected, it will get a new ID. 60 | ## 61 | ## The ID value starts at `0` and increments from there. 62 | ## The value `-1` is an invalid ID. 63 | 64 | when defined(SDL_Static): 65 | static: echo "SDL_Static option is deprecated and will soon be removed. Instead please use --dynlibOverride:SDL2." 66 | else: 67 | {.push callConv: cdecl, dynlib: LibName.} 68 | 69 | 70 | proc numJoysticks*(): cint {.importc: "SDL_NumJoysticks".} 71 | ## Count the number of joysticks attached to the system right now. 72 | 73 | proc joystickNameForIndex*(device_index: cint): cstring {. 74 | importc: "SDL_JoystickNameForIndex".} 75 | ## Get the implementation dependent name of a joystick. 76 | ## 77 | ## This can be called before any joysticks are opened. 78 | ## If no name can be found, this procedure returns `nil`. 79 | 80 | proc joystickOpen*(device_index: cint): JoystickPtr {. 81 | importc: "SDL_JoystickOpen".} 82 | ## Open a joystick for use. 83 | ## 84 | ## The index passed as an argument refers to the N'th joystick on the system. 85 | ## This index is not the value which will identify this joystick in future 86 | ## joystick events. The joystick's instance id (`JoystickID`) will be used 87 | ## there instead. 88 | ## 89 | ## `Return` a joystick identifier, or `nil` if an error occurred. 90 | 91 | proc joystickName*(joystick: ptr Joystick): cstring {.importc: "SDL_JoystickName".} 92 | ## `Return` the name for this currently opened joystick. 93 | ## If no name can be found, this procedure returns `nil`. 94 | 95 | proc name*(joystick: ptr Joystick): cstring {.inline.} = 96 | ## `Return` the name for this currently opened joystick. 97 | ## If no name can be found, this procedure returns `nil`. 98 | joystick.joystickName 99 | 100 | proc joystickGetDeviceGUID*(device_index: cint): JoystickGUID {. 101 | importc: "SDL_JoystickGetDeviceGUID".} 102 | ## Return the GUID for the joystick at this index. 103 | ## 104 | ## This can be called before any joysticks are opened. 105 | 106 | proc joystickGetGUID*(joystick: JoystickPtr): JoystickGUID {. 107 | importc: "SDL_JoystickGetGUID".} 108 | ## `Return` the GUID for this opened joystick. 109 | 110 | proc getGUID*(joystick: JoystickPtr): JoystickGUID {.inline.} = 111 | ## `Return` the GUID for this opened joystick. 112 | joystick.joystickGetGUID 113 | 114 | proc joystickGetGUIDString*(guid: JoystickGUID, pszGUID: cstring, cbGUID: cint) {. 115 | importc: "SDL_JoystickGetGUIDString".} 116 | ## `Return` a string representation for this guid. 117 | ## 118 | ## `pszGUID` must point to at least 33 bytes 119 | ## (32 for the string plus a `nil` terminator). 120 | 121 | proc joystickGetGUIDFromString*(pchGUID: cstring): JoystickGUID {. 122 | importc: "SDL_JoystickGetGUIDFromString".} 123 | ## Convert a string into a joystick GUID. 124 | 125 | proc joystickGetAttached*(joystick: JoystickPtr): Bool32 {. 126 | importc: "SDL_JoystickGetAttached".} 127 | ## `Return` `true` if the joystick has been opened and currently 128 | ## connected, or `false` if it has not. 129 | 130 | proc getAttached* (joystick: JoystickPtr): Bool32 {.inline.} = 131 | ## `Return` `true` if the joystick has been opened and currently 132 | ## connected, or `false` if it has not. 133 | joystick.joystickGetAttached 134 | 135 | proc joystickInstanceID*(joystick: JoystickPtr): JoystickID {. 136 | importc: "SDL_JoystickInstanceID".} 137 | ## Get the instance ID of an opened joystick, 138 | ## or `-1` if the joystick is invalid. 139 | 140 | proc instanceID*(joystick: JoystickPtr): JoystickID {.inline.} = 141 | ## Get the instance ID of an opened joystick, 142 | ## or `-1` if the joystick is invalid. 143 | joystick.joystickInstanceID 144 | 145 | proc joystickNumAxes*(joystick: JoystickPtr): cint {. 146 | importc: "SDL_JoystickNumAxes".} 147 | ## Get the number of general axis controls on a joystick. 148 | 149 | proc numAxes* (joystick: JoystickPtr): cint {.inline.} = 150 | ## Get the number of general axis controls on a joystick. 151 | joystick.joystickNumAxes 152 | 153 | proc joystickNumBalls*(joystick: JoystickPtr): cint {. 154 | importc: "SDL_JoystickNumBalls".} 155 | ## Get the number of trackballs on a joystick. 156 | ## 157 | ## Joystick trackballs have only relative motion events associated 158 | ## with them and their state cannot be polled. 159 | 160 | proc numBalls*(joystick: JoystickPtr): cint {.inline.} = 161 | ## Get the number of trackballs on a joystick. 162 | ## 163 | ## Joystick trackballs have only relative motion events associated 164 | ## with them and their state cannot be polled. 165 | joystick.joystickNumBalls 166 | 167 | proc joystickNumHats*(joystick: JoystickPtr): cint {. 168 | importc: "SDL_JoystickNumHats".} 169 | ## Get the number of POV hats on a joystick. 170 | 171 | proc numHats*(joystick: JoystickPtr): cint {.inline.} = 172 | ## Get the number of POV hats on a joystick. 173 | joystick.joystickNumHats 174 | 175 | proc joystickNumButtons*(joystick: JoystickPtr): cint {. 176 | importc: "SDL_JoystickNumButtons".} 177 | ## Get the number of buttons on a joystick. 178 | 179 | proc numButtons*(joystick: JoystickPtr): cint {.inline.} = 180 | ## Get the number of buttons on a joystick. 181 | joystick.joystickNumButtons 182 | 183 | proc joystickUpdate*() {.importc: "SDL_JoystickUpdate".} 184 | ## Update the current state of the open joysticks. 185 | ## 186 | ## This is called automatically by the event loop if any joystick 187 | ## events are enabled. 188 | 189 | proc joystickEventState*(state: cint): cint {. 190 | importc: "SDL_JoystickEventState".} 191 | ## Enable/disable joystick event polling. 192 | ## 193 | ## If joystick events are disabled, you must call `joystickUpdate()` 194 | ## yourself and check the state of the joystick when you want joystick 195 | ## information. 196 | ## 197 | ## The `state` can be one of `SDL_QUERY`, `SDL_ENABLE` or `SDL_IGNORE`. 198 | 199 | proc joystickGetAxis*(joystick: JoystickPtr, axis: cint): int16 {. 200 | importc: "SDL_JoystickGetAxis".} 201 | ## Get the current state of an axis control on a joystick. 202 | ## 203 | ## The state is a value ranging from `-32768` to `32767`. 204 | ## 205 | ## The axis indices start at index `0`. 206 | 207 | proc getAxis*(joystick: JoystickPtr, axis: cint): int16 {.inline.} = 208 | ## Get the current state of an axis control on a joystick. 209 | ## 210 | ## The state is a value ranging from `-32768` to `32767`. 211 | ## 212 | ## The axis indices start at index `0`. 213 | joystick.joystickGetAxis(axis) 214 | 215 | const 216 | SDL_HAT_CENTERED*: cint = 0x00000000 217 | SDL_HAT_UP*: cint = 0x00000001 218 | SDL_HAT_RIGHT*: cint = 0x00000002 219 | SDL_HAT_DOWN*: cint = 0x00000004 220 | SDL_HAT_LEFT*: cint = 0x00000008 221 | SDL_HAT_RIGHTUP*: cint = SDL_HAT_RIGHT or SDL_HAT_UP 222 | SDL_HAT_RIGHTDOWN*: cint = SDL_HAT_RIGHT or SDL_HAT_DOWN 223 | SDL_HAT_LEFTUP*: cint = SDL_HAT_LEFT or SDL_HAT_UP 224 | SDL_HAT_LEFTDOWN*: cint = SDL_HAT_LEFT or SDL_HAT_DOWN 225 | 226 | 227 | proc joystickGetHat*(joystick: JoystickPtr, hat: cint): uint8 {. 228 | importc: "SDL_JoystickGetHat".} 229 | ## Get the current state of a POV hat on a joystick. 230 | ## 231 | ## The hat indices start at index `0`. 232 | ## 233 | ## `Return` The return value is one of the following positions: 234 | ## * SDL_HAT_CENTERED 235 | ## * SDL_HAT_UP 236 | ## * SDL_HAT_RIGHT 237 | ## * SDL_HAT_DOWN 238 | ## * SDL_HAT_LEFT 239 | ## * SDL_HAT_RIGHTUP 240 | ## * SDL_HAT_RIGHTDOWN 241 | ## * SDL_HAT_LEFTUP 242 | ## * SDL_HAT_LEFTDOWN 243 | 244 | proc getHat*(joystick: JoystickPtr, hat: cint): uint8 {.inline.} = 245 | ## Get the current state of a POV hat on a joystick. 246 | ## 247 | ## The hat indices start at index `0`. 248 | ## 249 | ## `Return` The return value is one of the following positions: 250 | ## * SDL_HAT_CENTERED 251 | ## * SDL_HAT_UP 252 | ## * SDL_HAT_RIGHT 253 | ## * SDL_HAT_DOWN 254 | ## * SDL_HAT_LEFT 255 | ## * SDL_HAT_RIGHTUP 256 | ## * SDL_HAT_RIGHTDOWN 257 | ## * SDL_HAT_LEFTUP 258 | ## * SDL_HAT_LEFTDOWN 259 | joystick.joystickGetHat(hat) 260 | 261 | proc joystickGetBall*(joystick: JoystickPtr, ball: cint, dx: ptr cint, dy: ptr cint): cint {. 262 | importc: "SDL_JoystickGetBall".} 263 | ## Get the ball axis change since the last poll. 264 | ## 265 | ## `Return` `0`, or `-1` if you passed it invalid parameters. 266 | ## 267 | ## The ball indices start at index `0`. 268 | 269 | proc getBall*(joystick: JoystickPtr, ball: cint, dx: ptr cint, dy: ptr cint): cint {.inline.} = 270 | ## Get the ball axis change since the last poll. 271 | ## 272 | ## `Return` `0`, or `-1` if you passed it invalid parameters. 273 | ## 274 | ## The ball indices start at index `0`. 275 | joystick.joystickGetBall(ball, dx, dy) 276 | 277 | proc joystickGetButton*(joystick: JoystickPtr, button: cint): uint8 {. 278 | importc: "SDL_JoystickGetButton".} 279 | ## Get the current state of a button on a joystick. 280 | ## 281 | ## The button indices start at index `0`. 282 | 283 | proc getButton* (joystick: JoystickPtr, button: cint): uint8 {.inline.} = 284 | ## Get the current state of a button on a joystick. 285 | ## 286 | ## The button indices start at index `0`. 287 | joystick.joystickGetButton(button) 288 | 289 | proc joystickClose*(joystick: JoystickPtr) {.importc: "SDL_JoystickClose".} 290 | ## Close a joystick previously opened with `joystickOpen()`. 291 | 292 | proc close* (joystick: JoystickPtr) {.inline.} = 293 | ## Close a joystick previously opened with `joystickOpen()`. 294 | joystick.joystickClose() 295 | 296 | when not defined(SDL_Static): 297 | {.pop.} 298 | -------------------------------------------------------------------------------- /src/thirdparty/sdl2/ttf.nim: -------------------------------------------------------------------------------- 1 | ## TrueType font rendering library. 2 | ## 3 | ## **Note:** 4 | ## In many places, ttf will say "glyph" when it means "code point." 5 | ## Unicode is hard, we learn as we go, and we apologize for adding to the 6 | ## confusion. 7 | 8 | {.deadCodeElim: on.} 9 | 10 | when not defined(SDL_Static): 11 | when defined(windows): 12 | const LibName* = "SDL2_ttf.dll" 13 | elif defined(macosx): 14 | const LibName = "libSDL2_ttf.dylib" 15 | else: 16 | const LibName = "libSDL2_ttf(|-2.0).so(|.0)" 17 | else: 18 | static: echo "SDL_Static option is deprecated and will soon be removed. Instead please use --dynlibOverride:SDL2." 19 | 20 | import ../sdl2 21 | 22 | type 23 | FontPtr* {.pure.} = ptr object 24 | ## The internal structure containing font information 25 | 26 | when not defined(SDL_Static): 27 | {.push callConv:cdecl, dynlib:LibName.} 28 | 29 | proc ttfLinkedVersion*(): ptr SDL_version {.importc: "TTF_Linked_Version".} 30 | ## This procedure gets the version of the dynamically linked ttf library. 31 | # TODO Add an equivalent of the `TTF_VERSION` macro (version template ?) 32 | # and this comment: 33 | # It should NOT be used to fill a version structure, instead you should 34 | # use the `version()` template. 35 | 36 | # ZERO WIDTH NO-BREAKSPACE (Unicode byte order mark) 37 | const 38 | UNICODE_BOM_NATIVE* = 0x0000FEFF 39 | UNICODE_BOM_SWAPPED* = 0x0000FFFE 40 | 41 | proc ttfByteSwappedUnicode*(swapped: cint) {.importc: "TTF_ByteSwappedUNICODE".} 42 | ## This procedure tells the library whether UNICODE text is generally 43 | ## byteswapped. A UNICODE BOM character in a string will override 44 | ## this setting for the remainder of that string. 45 | 46 | proc ttfInit*(): SDL_Return {.importc: "TTF_Init", discardable.} 47 | ## Initialize the TTF engine. 48 | ## 49 | ## `Return` `0` if successful, `-1` on error. 50 | 51 | proc openFont*(file: cstring; ptsize: cint): FontPtr {.importc: "TTF_OpenFont".} 52 | ## Open a font file and create a font of the specified point size. 53 | ## Some .fon fonts will have several sizes embedded in the file, so the 54 | ## point size becomes the index of choosing which size. If the value 55 | ## is too high, the last indexed size will be the default. 56 | ## 57 | ## **See also:** 58 | ## * `openFontIndex proc<#openFontIndex,cstring,cint,clong>`_ 59 | ## * `openFontRW proc<#openFontRW,ptr.RWops,cint,cint>`_ 60 | ## * `openFontIndexRW proc<#openFontIndexRW,ptr.RWops,cint,cint,clong>`_ 61 | 62 | proc openFontIndex*(file: cstring; ptsize: cint; index: clong): FontPtr {. 63 | importc: "TTF_OpenFontIndex".} 64 | proc openFontRW*(src: ptr RWops; freesrc: cint; ptsize: cint): FontPtr {. 65 | importc: "TTF_OpenFontRW".} 66 | proc openFontIndexRW*(src: ptr RWops; freesrc: cint; ptsize: cint; 67 | index: clong): FontPtr {.importc: "TTF_OpenFontIndexRW".} 68 | # Set and retrieve the font style 69 | const 70 | TTF_STYLE_NORMAL* = 0x00000000 71 | TTF_STYLE_BOLD* = 0x00000001 72 | TTF_STYLE_ITALIC* = 0x00000002 73 | TTF_STYLE_UNDERLINE* = 0x00000004 74 | TTF_STYLE_STRIKETHROUGH* = 0x00000008 75 | 76 | proc getFontStyle*(font: FontPtr): cint {.importc: "TTF_GetFontStyle".} 77 | proc setFontStyle*(font: FontPtr; style: cint) {.importc: "TTF_SetFontStyle".} 78 | proc getFontOutline*(font: FontPtr): cint {.importc: "TTF_GetFontOutline".} 79 | proc setFontOutline*(font: FontPtr; outline: cint) {.importc: "TTF_SetFontOutline".} 80 | 81 | # Set and retrieve FreeType hinter settings 82 | const 83 | TTF_HINTING_NORMAL* = 0 84 | TTF_HINTING_LIGHT* = 1 85 | TTF_HINTING_MONO* = 2 86 | TTF_HINTING_NONE* = 3 87 | proc getFontHinting*(font: FontPtr): cint {.importc: "TTF_GetFontHinting".} 88 | 89 | proc setFontHinting*(font: FontPtr; hinting: cint) {.importc: "TTF_SetFontHinting".} 90 | 91 | proc fontHeight*(font: FontPtr): cint {.importc: "TTF_FontHeight".} 92 | ## Get the total height of the font - usually equal to point size. 93 | 94 | proc fontAscent*(font: FontPtr): cint {.importc: "TTF_FontAscent".} 95 | ## Get the offset from the baseline to the top of the font. 96 | ## 97 | ## This is a positive value, relative to the baseline. 98 | 99 | proc fontDescent*(font: FontPtr): cint {.importc: "TTF_FontDescent".} 100 | ## Get the offset from the baseline to the bottom of the font. 101 | ## 102 | ## This is a negative value, relative to the baseline. 103 | 104 | proc fontLineSkip*(font: FontPtr): cint {.importc: "TTF_FontLineSkip".} 105 | ## Get the recommended spacing between lines of text for this font. 106 | 107 | proc getFontKerning*(font: FontPtr): cint {.importc: "TTF_GetFontKerning".} 108 | ## Get whether or not kerning is allowed for this font. 109 | 110 | proc setFontKerning*(font: FontPtr; allowed: cint) {.importc: "TTF_SetFontKerning".} 111 | ## Set whether or not kerning is allowed for this font. 112 | 113 | proc fontFaces*(font: FontPtr): clong {.importc: "TTF_FontFaces".} 114 | ## Get the number of faces of the font. 115 | 116 | proc fontFaceIsFixedWidth*(font: FontPtr): cint {. 117 | importc: "TTF_FontFaceIsFixedWidth".} 118 | ## Get the font face attributes, if any. 119 | 120 | proc fontFaceFamilyName*(font: FontPtr): cstring {.importc: "TTF_FontFaceFamilyName".} 121 | proc fontFaceStyleName*(font: FontPtr): cstring {.importc: "TTF_FontFaceStyleName".} 122 | 123 | proc glyphIsProvided*(font: FontPtr; ch: uint16): cint {. 124 | importc: "TTF_GlyphIsProvided".} 125 | ## Check wether a glyph is provided by the font or not. 126 | 127 | proc glyphMetrics*(font: FontPtr; ch: uint16; minx: ptr cint; 128 | maxx: ptr cint; miny: ptr cint; maxy: ptr cint; 129 | advance: ptr cint): cint {.importc: "TTF_GlyphMetrics".} 130 | ## Get the metrics (dimensions) of a glyph. 131 | ## 132 | ## To understand what these metrics mean, here is a useful link: 133 | ## 134 | ## http://freetype.sourceforge.net/freetype2/docs/tutorial/step2.html 135 | 136 | proc sizeText*(font: FontPtr; text: cstring; w: ptr cint; h: ptr cint): cint{. 137 | importc: "TTF_SizeText".} 138 | ## Get the dimensions of a rendered string of text. 139 | ## 140 | ## **See also:** 141 | ## * `sizeUtf8 proc<#sizeUtf8,FontPtr,cstring,ptr.cint,ptr.cint>`_ 142 | ## * `sizeUnicode proc<#sizeUnicode,FontPtr,ptr.uint16,ptr.cint,ptr.cint>`_ 143 | 144 | proc sizeUtf8*(font: FontPtr; text: cstring; w: ptr cint; h: ptr cint): cint{. 145 | importc: "TTF_SizeUTF8".} 146 | proc sizeUnicode*(font: FontPtr; text: ptr uint16; w, h: ptr cint): cint{. 147 | importc: "TTF_SizeUNICODE".} 148 | # Create an 8-bit palettized surface and render the given text at 149 | # fast quality with the given font and color. The 0 pixel is the 150 | # colorkey, giving a transparent background, and the 1 pixel is set 151 | # to the text color. 152 | # This function returns the new surface, or NULL if there was an error. 153 | # 154 | proc renderTextSolid*(font: FontPtr; text: cstring; fg: Color): SurfacePtr{. 155 | importc: "TTF_RenderText_Solid".} 156 | ## Create an 8-bit palettized surface and render the given text at 157 | ## fast quality with the given font and color. The 0 pixel is the 158 | ## colorkey, giving a transparent background, and the 1 pixel is set 159 | ## to the text color. 160 | ## 161 | ## `Return` the new surface, or `nil` if there was an error. 162 | ## 163 | ## **See also:** 164 | ## * `renderUtf8Solid proc<#renderUtf8Solid,FontPtr,cstring,Color>`_ 165 | ## * `renderUnicodeSolid proc<#renderUnicodeSolid,FontPtr,ptr.uint16,Color>`_ 166 | 167 | proc renderUtf8Solid*(font: FontPtr; text: cstring; fg: Color): SurfacePtr{. 168 | importc: "TTF_RenderUTF8_Solid".} 169 | proc renderUnicodeSolid*(font: FontPtr; text: ptr uint16; 170 | fg: Color): SurfacePtr {.importc: "TTF_RenderUNICODE_Solid".} 171 | 172 | proc renderGlyphSolid*(font: FontPtr; ch: uint16; fg: Color): SurfacePtr {. 173 | importc: "TTF_RenderGlyph_Solid".} 174 | ## Create an 8-bit palettized surface and render the given glyph at 175 | ## fast quality with the given font and color. The 0 pixel is the 176 | ## colorkey, giving a transparent background, and the 1 pixel is set 177 | ## to the text color. 178 | ## 179 | ## The glyph is rendered without any padding or centering in the X 180 | ## direction, and aligned normally in the Y direction. 181 | ## 182 | ## `Return` the new surface, or `nil` if there was an error. 183 | 184 | proc renderTextShaded*(font: FontPtr; text: cstring; 185 | fg, bg: Color): SurfacePtr {.importc: "TTF_RenderText_Shaded".} 186 | ## Create an 8-bit palettized surface and render the given text at 187 | ## high quality with the given font and colors. The 0 pixel is background, 188 | ## while other pixels have varying degrees of the foreground color. 189 | ## 190 | ## `Return` the new surface, or `nil` if there was an error. 191 | ## 192 | ## **See also:** 193 | ## * `renderUtf8Shaded proc<#renderUtf8Shaded,FontPtr,cstring,Color,Color>`_ 194 | ## * `renderUnicodeShaded proc<#renderUnicodeShaded,FontPtr,ptr.uint16,Color,Color>`_ 195 | 196 | proc renderUtf8Shaded*(font: FontPtr; text: cstring; fg, bg: Color): SurfacePtr {. 197 | importc: "TTF_RenderUTF8_Shaded".} 198 | proc renderUnicodeShaded*(font: FontPtr; text: ptr uint16; 199 | fg, bg: Color): SurfacePtr {.importc: "TTF_RenderUNICODE_Shaded".} 200 | 201 | proc renderGlyphShaded*(font: FontPtr; ch: uint16; fg, bg: Color): SurfacePtr {. 202 | importc: "TTF_RenderGlyph_Shaded".} 203 | ## Create an 8-bit palettized surface and render the given glyph at 204 | ## high quality with the given font and colors. The 0 pixel is background, 205 | ## while other pixels have varying degrees of the foreground color. 206 | ## 207 | ## The glyph is rendered without any padding or centering in the X 208 | ## direction, and aligned normally in the Y direction. 209 | ## 210 | ## `Return` the new surface, or `nil` if there was an error. 211 | 212 | proc renderTextBlended*(font: FontPtr; text: cstring; fg: Color): SurfacePtr {. 213 | importc: "TTF_RenderText_Blended".} 214 | ## Create a 32-bit ARGB surface and render the given text at high quality, 215 | ## using alpha blending to dither the font with the given color. 216 | ## 217 | ## `Return` the new surface, or `nil` if there was an error. 218 | ## 219 | ## **See also:** 220 | ## * `renderUtf8Blended proc<#renderUtf8Blended,FontPtr,cstring,Color>`_ 221 | ## * `renderUnicodeBlended proc<#renderUnicodeBlended,FontPtr,ptr.uint16,Color>`_ 222 | 223 | proc renderUtf8Blended*(font: FontPtr; text: cstring; fg: Color): SurfacePtr {. 224 | importc: "TTF_RenderUTF8_Blended".} 225 | proc renderUnicodeBlended*(font: FontPtr; text: ptr uint16; 226 | fg: Color): SurfacePtr {.importc: "TTF_RenderUNICODE_Blended".} 227 | 228 | proc renderTextBlendedWrapped*(font: FontPtr; text: cstring; fg: Color; 229 | wrapLength: uint32): SurfacePtr {.importc: "TTF_RenderText_Blended_Wrapped".} 230 | ## Create a 32-bit ARGB surface and render the given text at high quality, 231 | ## using alpha blending to dither the font with the given color. 232 | ## Text is wrapped to multiple lines on line endings and on word boundaries 233 | ## if it extends beyond wrapLength in pixels. 234 | ## 235 | ## `Return` the new surface, or `nil` if there was an error. 236 | ## 237 | ## **See also:** 238 | ## * `renderUtf8BlendedWrapped proc<#renderUtf8BlendedWrapped,FontPtr,cstring,Color,uint32>`_ 239 | ## * `renderUnicodeBlendedWrapped proc<#renderUnicodeBlendedWrapped,FontPtr,ptr.uint16,Color,uint32>`_ 240 | 241 | proc renderUtf8BlendedWrapped*(font: FontPtr; text: cstring; fg: Color; 242 | wrapLength: uint32): SurfacePtr {.importc: "TTF_RenderUTF8_Blended_Wrapped".} 243 | proc renderUnicodeBlendedWrapped*(font: FontPtr; text: ptr uint16; fg: Color; 244 | wrapLength: uint32): SurfacePtr {.importc: "TTF_RenderUNICODE_Blended_Wrapped".} 245 | 246 | proc renderGlyphBlended*(font: FontPtr; ch: uint16; fg: Color): SurfacePtr {. 247 | importc: "TTF_RenderGlyph_Blended".} 248 | ## Create a 32-bit ARGB surface and render the given glyph at high quality, 249 | ## using alpha blending to dither the font with the given color. 250 | ## The glyph is rendered without any padding or centering in the X 251 | ## direction, and aligned normally in the Y direction. 252 | ## 253 | ## `Return` the new surface, or `nil` if there was an error. 254 | 255 | 256 | proc close*(font: FontPtr) {.importc: "TTF_CloseFont".} 257 | ## Close an opened font file. 258 | 259 | proc ttfQuit*() {.importc: "TTF_Quit".} 260 | ## De-initialize the TTF engine. 261 | 262 | proc ttfWasInit*(): bool {.importc: "TTF_WasInit".} 263 | ## Check if the TTF engine is initialized. 264 | 265 | proc getFontKerningSize*(font: FontPtr; prev_index, indx: cint): cint {. 266 | importc: "TTF_GetFontKerningSize".} 267 | ## Get the kerning size of two glyphs indices. 268 | 269 | when not defined(SDL_Static): 270 | {.pop.} 271 | 272 | 273 | proc renderText*(font: FontPtr; text: cstring; fg, bg: Color): SurfacePtr = 274 | renderTextShaded(font, text, fg, bg) 275 | -------------------------------------------------------------------------------- /src/thirdparty/webgl/enums.nim: -------------------------------------------------------------------------------- 1 | type BufferBit* = enum 2 | bbDepth = 0x00000100 # Passed to clear to clear the current depth buffer. 3 | bbStencil = 0x00000400 # Passed to clear to clear the current stencil buffer. 4 | bbColor = 0x00004000 # Passed to clear to clear the current color buffer. 5 | 6 | type PrimitiveMode* = enum 7 | ## Constants passed to WebGLRenderingContext.drawElements() or 8 | ## WebGLRenderingContext.drawArrays() to specify what kind of primitive to render. 9 | pmPoints = 0x0000 # Passed to drawElements or drawArrays to draw single points. 10 | pmLines = 0x0001 # Passed to drawElements or drawArrays to draw lines. Each vertex connects to the one after it. 11 | pmLineLoop = 0x0002 # Passed to drawElements or drawArrays to draw lines. Each set of two vertices is treated as a separate line segment. 12 | pmLineStrip = 0x0003 # Passed to drawElements or drawArrays to draw a connected group of line segments from the first vertex to the last. 13 | pmTriangles = 0x0004 # Passed to drawElements or drawArrays to draw triangles. Each set of three vertices creates a separate triangle. 14 | pmTriangleStrip = 0x0005 # Passed to drawElements or drawArrays to draw a connected group of triangles. 15 | pmTriangleFan = 0x0006 # Passed to drawElements or drawArrays to draw a connected group of triangles. Each vertex connects to the previous and the first vertex in the fan. 16 | 17 | type BlendingMode* = enum 18 | #Constants passed to WebGLRenderingContext.blendFunc() or WebGLRenderingContext.blendFuncSeparate() to specify the blending mode (for both, RBG and alpha, or separately). 19 | bmZERO = 0 # Passed to blendFunc or blendFuncSeparate to turn off a component. 20 | bmONE = 1 # Passed to blendFunc or blendFuncSeparate to turn on a component. 21 | bmSRC_COLOR = 0x0300 # Passed to blendFunc or blendFuncSeparate to multiply a component by the source elements color. 22 | bmONE_MINUS_SRC_COLOR = 0x0301 # Passed to blendFunc or blendFuncSeparate to multiply a component by one minus the source elements color. 23 | bmSRC_ALPHA = 0x0302 # Passed to blendFunc or blendFuncSeparate to multiply a component by the source's alpha. 24 | bmONE_MINUS_SRC_ALPHA = 0x0303 # Passed to blendFunc or blendFuncSeparate to multiply a component by one minus the source's alpha. 25 | bmDST_ALPHA = 0x0304 # Passed to blendFunc or blendFuncSeparate to multiply a component by the destination's alpha. 26 | bmONE_MINUS_DST_ALPHA = 0x0305 # Passed to blendFunc or blendFuncSeparate to multiply a component by one minus the destination's alpha. 27 | bmDST_COLOR = 0x0306 # Passed to blendFunc or blendFuncSeparate to multiply a component by the destination's color. 28 | bmONE_MINUS_DST_COLOR = 0x0307 # Passed to blendFunc or blendFuncSeparate to multiply a component by one minus the destination's color. 29 | bmSRC_ALPHA_SATURATE = 0x0308 # Passed to blendFunc or blendFuncSeparate to multiply a component by the minimum of source's alpha or one minus the destination's alpha. 30 | bmCONSTANT_COLOR = 0x8001 # Passed to blendFunc or blendFuncSeparate to specify a constant color blend function. 31 | bmONE_MINUS_CONSTANT_COLOR = 0x8002 # Passed to blendFunc or blendFuncSeparate to specify one minus a constant color blend function. 32 | bmCONSTANT_ALPHA = 0x8003 # Passed to blendFunc or blendFuncSeparate to specify a constant alpha blend function. 33 | bmONE_MINUS_CONSTANT_ALPHA = 0x8004 # Passed to blendFunc or blendFuncSeparate to specify one minus a constant alpha blend function. 34 | 35 | type BlendingEq* = enum 36 | #Constants passed to WebGLRenderingContext.blendEquation() or WebGLRenderingContext.blendEquationSeparate() to control how the blending is calculated (for both, RBG and alpha, or separately). 37 | beFUNC_ADD = 0x8006 # Passed to blendEquation or blendEquationSeparate to set an addition blend function. 38 | beFUNC_SUBSTRACT = 0x800A # Passed to blendEquation or blendEquationSeparate to specify a subtraction blend function (source - destination). 39 | beFUNC_REVERSE_SUBTRACT = 0x800B # Passed to blendEquation or blendEquationSeparate to specify a reverse subtraction blend function (destination - source). 40 | 41 | type BufferEnum* = enum 42 | #Constants passed to WebGLRenderingContext.bufferData(), WebGLRenderingContext.bufferSubData(), WebGLRenderingContext.bindBuffer(), or WebGLRenderingContext.getBufferParameter(). 43 | beBUFFER_SIZE = 0x8764 # Passed to getBufferParameter to get a buffer's size. 44 | beBUFFER_USAGE = 0x8765 # Passed to getBufferParameter to get the hint for the buffer passed in when it was created. 45 | beARRAY_BUFFER = 0x8892 # Passed to bindBuffer or bufferData to specify the type of buffer being used. 46 | beELEMENT_ARRAY_BUFFER = 0x8893 # Passed to bindBuffer or bufferData to specify the type of buffer being used. 47 | beSTREAM_DRAW = 0x88E0 # Passed to bufferData as a hint about whether the contents of the buffer are likely to not be used often. 48 | beSTATIC_DRAW = 0x88E4 # Passed to bufferData as a hint about whether the contents of the buffer are likely to be used often and not change often. 49 | beDYNAMIC_DRAW = 0x88E8 # Passed to bufferData as a hint about whether the contents of the buffer are likely to be used often and change often. 50 | 51 | type DataType* = enum 52 | dtBYTE = 0x1400 # 53 | dtUNSIGNED_BYTE = 0x1401 # 54 | dtSHORT = 0x1402 # 55 | dtUNSIGNED_SHORT = 0x1403 # 56 | dtINT = 0x1404 # 57 | dtUNSIGNED_INT = 0x1405 # 58 | dtFLOAT = 0x1406 # 59 | 60 | type ShaderEnum* = enum 61 | #Constants passed to WebGLRenderingContext.createShader() or WebGLRenderingContext.getShaderParameter() 62 | seMAX_VERTEX_ATTRIBS = 0x8869 # 63 | seMAX_TEXTURE_IMAGE_UNITS = 0x8872 # Implementation dependent number of maximum texture units. At least 8. 64 | seFRAGMENT_SHADER = 0x8B30 # Passed to createShader to define a fragment shader. 65 | seVERTEX_SHADER = 0x8B31 # Passed to createShader to define a vertex shader 66 | seMAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C # 67 | seMAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D # 68 | seSHADER_TYPE = 0x8B4F # 69 | seDELETE_STATUS = 0x8B80 # Passed to getShaderParamter to determine if a shader was deleted via deleteShader. Returns true if it was, false otherwise. 70 | seCOMPILE_STATUS = 0x8B81 # Passed to getShaderParamter to get the status of the compilation. Returns false if the shader was not compiled. You can then query getShaderInfoLog to find the exact error 71 | seLINK_STATUS = 0x8B82 # Passed to getProgramParameter after calling linkProgram to determine if a program was linked correctly. Returns false if there were errors. Use getProgramInfoLog to find the exact error. 72 | seVALIDATE_STATUS = 0x8B83 # Passed to getProgramParameter after calling validateProgram to determine if it is valid. Returns false if errors were found. 73 | seATTACHED_SHADERS = 0x8B85 # Passed to getProgramParameter after calling attachShader to determine if the shader was attached correctly. Returns false if errors occurred. 74 | seACTIVE_UNIFORMS = 0x8B86 # Passed to getProgramParamter to get the number of uniforms active in a program. 75 | seACTIVE_ATTRIBUTES = 0x8B89 # Passed to getProgramParameter to get the number of attributes active in a program. 76 | seSHADING_LANGUAGE_VERSION = 0x8B8C # 77 | seCURRENT_PROGRAM = 0x8B8D # 78 | seMAX_VERTEX_UNIFORM_VECTORS = 0x8DFB # 79 | seMAX_VARYING_VECTORS = 0x8DFC # 80 | seMAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD # 81 | -------------------------------------------------------------------------------- /tests/assets/hapticX.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HapticX/nxpressive/3c51398ed3c91f6d47b3259e07c36b89388ef148/tests/assets/hapticX.png -------------------------------------------------------------------------------- /tests/glew/lib/Release/Win32/glew32.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HapticX/nxpressive/3c51398ed3c91f6d47b3259e07c36b89388ef148/tests/glew/lib/Release/Win32/glew32.lib -------------------------------------------------------------------------------- /tests/glew/lib/Release/Win32/glew32s.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HapticX/nxpressive/3c51398ed3c91f6d47b3259e07c36b89388ef148/tests/glew/lib/Release/Win32/glew32s.lib -------------------------------------------------------------------------------- /tests/glew/lib/Release/x64/glew32.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HapticX/nxpressive/3c51398ed3c91f6d47b3259e07c36b89388ef148/tests/glew/lib/Release/x64/glew32.lib -------------------------------------------------------------------------------- /tests/glew/lib/Release/x64/glew32s.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HapticX/nxpressive/3c51398ed3c91f6d47b3259e07c36b89388ef148/tests/glew/lib/Release/x64/glew32s.lib -------------------------------------------------------------------------------- /tests/min_js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 21 | -------------------------------------------------------------------------------- /tests/test1.nim: -------------------------------------------------------------------------------- 1 | import 2 | unittest, 3 | math, 4 | ../src/hapticx 5 | 6 | 7 | suite "Core": 8 | test "Color": 9 | let clr = newColor(255, 100, 0) 10 | echo clr 11 | 12 | when not defined(js): 13 | let rgbaHex = newColor(0xFFAA9944) 14 | echo rgbaHex 15 | 16 | let rgbHex = newColor(0xFFAA99) 17 | echo rgbHex 18 | 19 | let rgbStrHex = newColor("#FFAA99") 20 | echo rgbStrHex 21 | assert rgbHex == rgbStrHex 22 | 23 | test "Color blending": 24 | let rgbaHex = newColor(0xFFBB99) 25 | let rgbHex = newColor(0x227722) 26 | 27 | echo rgbaHex.blend(rgbHex, BlendMode.Normal) 28 | echo rgbaHex.blend(rgbHex, BlendMode.Multiply) 29 | echo rgbaHex.blend(rgbHex, BlendMode.Screen) 30 | echo rgbaHex.blend(rgbHex, BlendMode.Overlay) 31 | echo rgbaHex.blend(rgbHex, BlendMode.Addition) 32 | echo rgbaHex.blend(rgbHex, BlendMode.Divide) 33 | echo rgbaHex.blend(rgbHex, BlendMode.Substract) 34 | echo rgbaHex.blend(rgbHex, BlendMode.Diffirence) 35 | echo rgbaHex.blend(rgbHex, BlendMode.SoftLight) 36 | echo rgbaHex.blend(rgbHex, BlendMode.Darken) 37 | echo rgbaHex.blend(rgbHex, BlendMode.Lighten) 38 | 39 | test "hue": 40 | let rgb = newColor(50, 100, 200) 41 | echo rgb 42 | echo rgb.hue 43 | echo rgb.saturation 44 | echo rgb.brightness 45 | echo newColor(rgb.hex) 46 | 47 | test "Vec2": 48 | let vec2 = newVec2(0.5f, 1f) 49 | echo vec2 50 | 51 | assert radToDeg(Vec2Right.angle2(Vec2Up)) == 90f 52 | assert radToDeg(Vec2Up.angle2(Vec2Down)) == 180f 53 | 54 | test "interpolation": 55 | let 56 | vec1 = newVec2(0.25f, 0.75f) 57 | vec2 = newVec2(0.5f, 0f) 58 | 59 | echo vec1.interpolate(vec2, 0f) 60 | echo vec1.interpolate(vec2, 0.25f) 61 | echo vec1.interpolate(vec2, 0.5f) 62 | echo vec1.interpolate(vec2, 0.75f) 63 | echo vec1.interpolate(vec2, 1f) 64 | 65 | test "snap": 66 | let 67 | vec = newVec2(37f, 12f) 68 | snap = newVec2(5f, 5f) 69 | echo vec.snapped(snap) 70 | 71 | test "bounce": 72 | let 73 | vec1 = newVec2(1f, 2f) 74 | vec2 = newVec2(0.5f, 0.5f) 75 | 76 | echo vec1.bounce(vec2) 77 | 78 | test "Animatable": 79 | let 80 | x = animatable(0f) 81 | y = animatable(newColor(0xFF99FF)) 82 | z = animatable(newVec2(1f, 5f)) 83 | 84 | echo tween(x, 10f, 0.5f, Easing.Linear) 85 | echo tween(x, 10f, 0.5f, Easing.CubicIn) 86 | echo tween(x, 10f, 0.5f, Easing.CubicInOut) 87 | echo tween(x, 10f, 0.5f, Easing.CubicOut) 88 | echo tween(x, 10f, 0.5f, Easing.ElasticIn) 89 | echo tween(x, 10f, 0.5f, Easing.ElasticOut) 90 | echo tween(x, 10f, 0.5f, Easing.ElasticInOut) 91 | echo tween(x, 10f, 0.5f, Easing.ExpoIn) 92 | echo tween(x, 10f, 0.5f, Easing.ExpoInOut) 93 | echo tween(x, 10f, 0.5f, Easing.BackOut) 94 | echo tween(x, 10f, 0.5f, Easing.EaseIn) 95 | 96 | echo tween(y, newColor(0x999fff), 0f, Easing.CubicIn) 97 | echo tween(y, newColor(0x999fff), 0.5f, Easing.CubicIn) 98 | echo tween(y, newColor(0x999fff), 1f, Easing.CubicIn) 99 | 100 | echo tween(z, newVec2(78f, -0.125f), 0.5f, Easing.CubicIn) 101 | echo tween(z, newVec2(78f, -0.125f), 0.5f, Easing.BackIn) 102 | 103 | test "Vec3": 104 | let 105 | v1 = newVec3() 106 | v2 = newVec3(10f) 107 | v3 = newVec3(1f, 2f, 4f) 108 | 109 | echo v1 110 | echo v2 111 | echo v3 112 | 113 | echo v2.dot(v3) 114 | echo v2.cross(v3) 115 | 116 | echo v2.rotatedX(90) 117 | echo v2.rotatedY(90) 118 | echo v2.rotatedZ(90) 119 | 120 | test "Basis": 121 | let 122 | b1 = newBasis() 123 | b2 = newBasis(5f) 124 | b3 = newBasis(5f, 4f, 2f) 125 | b4 = newBasis(5f, 4f, 2f, 2f, 4f, 5f, 1f, 2f, 3f) 126 | echo b1 127 | echo b1.pretty() 128 | 129 | echo b2.pretty() 130 | echo (b2 * BasisDiagonal).pretty() 131 | 132 | echo BasisDiagonal.determinant 133 | 134 | echo b3.pretty() 135 | echo b3.transpose().pretty() 136 | echo b3.transpose().transpose() == b3 137 | 138 | echo b4.pretty() 139 | echo b4.minor(1, 1) 140 | -------------------------------------------------------------------------------- /tests/test2.nim: -------------------------------------------------------------------------------- 1 | import 2 | unittest, 3 | ../src/hapticx 4 | 5 | 6 | suite "Node": 7 | test "Init and free": 8 | let 9 | a = newHNode("Root") 10 | b = newHNode("Child1") 11 | c = newHNode("Child2") 12 | 13 | a.addChild(b, c) 14 | echo a 15 | echo ~a 16 | 17 | b.destroy() 18 | echo ~a 19 | 20 | a.addChild(b) 21 | echo ~a 22 | 23 | c.addChild(b) 24 | echo ~a 25 | 26 | b.addChild(c) 27 | echo ~a 28 | 29 | test "event syntax": 30 | let a = newHNode() 31 | 32 | a@ready(): 33 | echo 1 34 | -------------------------------------------------------------------------------- /tests/test3.nim: -------------------------------------------------------------------------------- 1 | import 2 | unittest, 3 | ../src/hapticx 4 | 5 | 6 | suite "App": 7 | test "Initialize": 8 | var 9 | app = newApp("HapticX") 10 | scene = newHScene() 11 | 12 | # Sets main scene 13 | app.main = scene 14 | # Changes app icon 15 | app.icon = "./assets/hapticX.png" 16 | 17 | scene@ready(): 18 | echo "ready" 19 | scene@enter(): 20 | echo "enter" 21 | scene@exit(): 22 | echo "exit" 23 | 24 | app.run() 25 | -------------------------------------------------------------------------------- /tests/test4.nim: -------------------------------------------------------------------------------- 1 | import 2 | unittest, 3 | ../src/hapticx 4 | 5 | 6 | suite "Drawing": 7 | test "Draw": 8 | var 9 | app = newApp("HapticX") 10 | scene = newHScene() 11 | 12 | # Sets main scene 13 | app.main = scene 14 | # Changes app icon 15 | app.icon = "./assets/hapticX.png" 16 | 17 | scene@ready(): 18 | echo "ready" 19 | scene@enter(): 20 | echo "enter" 21 | scene@exit(): 22 | echo "exit" 23 | 24 | var i = 0 25 | scene@process(): 26 | if i < 10: 27 | inc i 28 | else: 29 | i = 0 30 | app.title = app.title[1..^1] & app.title[0] 31 | 32 | var canvas = newHCanvas() 33 | scene.addChild(canvas) 34 | canvas.fill(newColor(1, 0.75, 1)) 35 | canvas.drawRect(32, 32, 480, 480, BlackClr) 36 | canvas.drawRect(128, 256, 16, 96, RedClr) 37 | canvas.drawRect(111, 111, 160, 160, BlueClr) 38 | canvas.drawRect(130, 64, 128, 256, newColor(0, 1, 0, 0.5)) 39 | 40 | app.run() 41 | --------------------------------------------------------------------------------