├── .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 | 
7 | 
8 | 
9 | 
10 |
11 | [](https://wakatime.com/badge/user/eaf11f95-5e2a-4b60-ae6a-38cd01ed317b/project/2c4b13a1-b570-4d8a-81a4-272e5773f087)
12 |
13 | [](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 |
--------------------------------------------------------------------------------