├── .gitignore
├── CMakeLists.txt
├── LICENSE
├── README.md
├── SlimRaster_logo.png
└── src
├── SlimRaster.h
├── SlimRaster
├── app.h
├── core
│ ├── base.h
│ ├── init.h
│ ├── string.h
│ ├── text.h
│ ├── time.h
│ └── types.h
├── math
│ ├── mat2.h
│ ├── mat3.h
│ ├── mat4.h
│ ├── quat.h
│ ├── vec2.h
│ ├── vec3.h
│ └── vec4.h
├── platforms
│ └── win32.h
├── renderer
│ ├── common.h
│ ├── mesh_shaders.h
│ ├── pixel_shaders.h
│ └── rasterizer.h
├── scene
│ ├── box.h
│ ├── cube.h
│ ├── curve.h
│ ├── grid.h
│ ├── io.h
│ ├── mesh.h
│ ├── primitive.h
│ ├── texture.h
│ └── xform.h
├── shapes
│ ├── circle.h
│ ├── edge.h
│ ├── line.h
│ ├── rect.h
│ └── triangle.h
└── viewport
│ ├── hud.h
│ ├── manipulation.h
│ ├── navigation.h
│ └── viewport.h
├── bmp2texture.c
├── examples
├── 1_clipping_interpolation.c
├── 1_clipping_interpolation.gif
├── 2_normal_maps.c
├── 2_normal_maps.gif
├── 3_anti_aliasing.c
├── SlimRaster.gif
├── dog.mesh
├── dog.obj
├── dog_albedo.texture
├── dog_normal.texture
├── dragon.mesh
├── floor_albedo.texture
├── floor_normal.texture
├── suzanne.mesh
└── suzanne.obj
└── obj2mesh.c
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Object files
5 | *.o
6 | *.ko
7 | *.obj
8 | *.elf
9 |
10 | # Linker output
11 | *.ilk
12 | *.map
13 | *.exp
14 |
15 | # Precompiled Headers
16 | *.gch
17 | *.pch
18 |
19 | # Libraries
20 | *.lib
21 | *.a
22 | *.la
23 | *.lo
24 |
25 | # Shared objects (inc. Windows DLLs)
26 | *.dll
27 | *.so
28 | *.so.*
29 | *.dylib
30 |
31 | # Executables
32 | *.exe
33 | *.out
34 | *.app
35 | *.i*86
36 | *.x86_64
37 | *.hex
38 |
39 | # Debug files
40 | *.dSYM/
41 | *.su
42 | *.idb
43 | *.pdb
44 |
45 | # Kernel Module Compile Results
46 | *.mod*
47 | *.cmd
48 | .tmp_versions/
49 | modules.order
50 | Module.symvers
51 | Mkfile.old
52 | dkms.conf
53 |
54 | /cmake-build-debug/
55 | /cmake-build-release/
56 | /bin/
57 | /x64/
58 | /out/
59 | /build/
60 | /.idea/
61 | /.vs/
62 | /.vscode/
63 | /SlimRaster.sln
64 | /SlimRaster.vcxproj
65 | /SlimRaster.vcxproj.user
66 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.8)
2 |
3 | project(SlimRaster_1_clipping_interpolatio)
4 | add_executable(SlimRaster_1_clipping_interpolatio WIN32 src/examples/1_clipping_interpolation.c)
5 | project(SlimRaster_2_normal_maps)
6 | add_executable(SlimRaster_2_normal_maps WIN32 src/examples/2_normal_maps.c)
7 | #project(SlimRaster_3_debug_shaders)
8 | #add_executable(SlimRaster_3_debug_shaders WIN32 src/examples/1_clipping_interpolation.c)
9 |
10 | project(obj2mesh)
11 | add_executable(obj2mesh src/obj2mesh.c)
12 |
13 | project(bmp2texture)
14 | add_executable(bmp2texture src/bmp2texture.c)
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Arnon Marcus
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 | 
4 |
5 | A minimalist, platform agnostic interactive real time rasterizer.
6 | Strong emphasis on simplicity, ease of use and almost no setup to get started with
7 | Written in plain C and can be complied in either C or C++
8 |
9 | This project extends [SlimEngine](https://github.com/HardCoreCodin/SlimEngine).
10 |
11 | Features:
12 | -
13 | All features of SlimEngine are available here as well.
14 | Additional features include rasterization facilities:
15 | - Pixel Shaders that feed interpolated vertex attributes
16 | - Mesh shaders for object culling using axis-aligned bounding boxes
17 | - Perspective corrected barycentric coordinates
18 | - Tangent space derivatives for adaptive texture mip-level selection
19 | - Bi-linear filtered texture sampling with auto-selected mip levels
20 | - Anti aliasing (optional SSAA)
21 | - Frustum and back face triangle culling
22 | - Frustum triangle clipping with interpolates vertex attributes
23 | 
24 | - Normal maps with controllable strength
25 | 
26 |
27 | * obj2mesh: Also privided is a separate CLI tool for converting `.obj` files to `.mesh` files.
28 | It is also written in plain C (so is compatible with C++)
29 | Usage: `./obj2mesh src.obj trg.mesh`
30 | - invert_winding_order : Reverses the vertex ordering (for objs exported with clockwise order)
31 |
32 | * bmp2texture: Also provided is a separate CLI tool for converting `.bmp` files to `.texture` files.
33 | It is also written in plain C (so is compatible with C++)
34 | Usage: `./bmp2texture src.bmp trg.texture`
35 | - m : Generate mip-maps
36 | - w : Wrap-around
37 | - f : Filter
38 |
39 | Architecture:
40 | -
41 | The platform layer only uses operating-system headers (no standard library used).
42 | The application layer itself has no dependencies, apart from the standard math header.
43 | It is just a library that the platform layer uses - it has no knowledge of the platform.
44 |
45 | More details on this architecture [here](https://youtu.be/Ev_TeQmus68).
46 |
47 |
48 | Usage:
49 | -
50 | The single header file variant includes everything.
51 | Otherwise, specific headers can be included from the directory of headers.
52 | The main entry point for the app needs to be defined explicitly (see [SlimApp](https://github.com/HardCoreCodin/SlimApp)).
53 |
54 | SlimRaster comes with pre-configured CMake targets for all examples.
55 | For manual builds on Windows, the typical system libraries need to be linked
56 | (winmm.lib, gdi32.lib, shell32.lib, user32.lib) and the SUBSYSTEM needs to be set to WINDOWS
57 |
58 | SlimRaster does not come with any GUI functionality at this point.
59 | Some example apps have an optional HUD (heads up display) that shows additional information.
60 | It can be toggled on or off using the`tab` key.
61 |
62 | All examples are interactive using SlimRaster's facilities having 2 interaction modes:
63 | 1. FPS navigation (WASD + mouse look + zooming)
64 | 2. DCC application (default)
65 |
66 | Double clicking the `left mouse button` anywhere within the window toggles between these 2 modes.
67 |
68 | Entering FPS mode captures the mouse movement for the window and hides the cursor.
69 | Navigation is then as in a typical first-person game (plus lateral movement and zooming):
70 |
71 | Move the `mouse` to freely look around (even if the cursor would leave the window border)
72 | Scroll the `mouse wheel` to zoom in and out (changes the field of view of the perspective)
73 | Hold `W` to move forward
74 | Hold `S` to move backward
75 | Hold `A` to move left
76 | Hold `D` to move right
77 | Hold `R` to move up
78 | Hold `F` to move down
79 |
80 | Exit this mode by double clicking the `left mouse button`.
81 |
82 | The default interaction mode is similar to a typical DCC application (i.e: Maya):
83 | The mouse is not captured to the window and the cursor is visible.
84 | Holding the `right mouse button` and dragging the mouse orbits the camera around a target.
85 | Holding the `middle mouse button` and dragging the mouse pans the camera (left, right, up and down).
86 | Scrolling the `mouse wheel` dollys the camera forward and backward.
87 |
88 | Clicking the `left mouse button` selects an object in the scene that is under the cursor.
89 | Holding the `left mouse button` while hovering an object and then dragging the mouse,
90 | moves the object parallel to the screen.
91 |
92 | Holding `alt` highlights the currently selecte object by drawing a bounding box around it.
93 | While `alt` is still held, if the cursor hovers the selected object's bounding box,
94 | mouse interaction transforms the object along the plane of the bounding box that the cursor hovers on:
95 | Holding the `left mouse button` and dragging the mouse moves the object.
96 | Holding the `right mouse button` and dragging the mouse rotates the object.
97 | Holding the `middle mouse button` and dragging the mouse scales the object.
98 | (`mouse wheel` interaction is disabled while `alt` is held)
--------------------------------------------------------------------------------
/SlimRaster_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HardCoreCodin/SlimRaster/3718a02b52844f5a66376314ff63b76eff886e56/SlimRaster_logo.png
--------------------------------------------------------------------------------
/src/SlimRaster/app.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "./core/init.h"
4 | #include "./scene/io.h"
5 |
6 | App *app;
7 |
8 | void initApp(Defaults *defaults);
9 |
10 | void _windowRedraw() {
11 | if (!app->is_running) return;
12 | if (app->on.windowRedraw) app->on.windowRedraw();
13 | }
14 |
15 | void _windowResize(u16 width, u16 height) {
16 | if (!app->is_running) return;
17 | updateDimensions(&app->viewport.dimensions, width, height, width);
18 |
19 | if (app->on.windowResize) app->on.windowResize(width, height);
20 | if (app->on.windowRedraw) app->on.windowRedraw();
21 | }
22 |
23 | void _keyChanged(u8 key, bool pressed) {
24 | if (key == app->controls.key_map.ctrl) app->controls.is_pressed.ctrl = pressed;
25 | else if (key == app->controls.key_map.alt) app->controls.is_pressed.alt = pressed;
26 | else if (key == app->controls.key_map.shift) app->controls.is_pressed.shift = pressed;
27 | else if (key == app->controls.key_map.space) app->controls.is_pressed.space = pressed;
28 | else if (key == app->controls.key_map.tab) app->controls.is_pressed.tab = pressed;
29 |
30 | if (app->on.keyChanged) app->on.keyChanged(key, pressed);
31 | }
32 |
33 | void _mouseButtonDown(MouseButton *mouse_button, i32 x, i32 y) {
34 | mouse_button->is_pressed = true;
35 | mouse_button->is_handled = false;
36 |
37 | mouse_button->down_pos.x = x;
38 | mouse_button->down_pos.y = y;
39 |
40 | if (app->on.mouseButtonDown) app->on.mouseButtonDown(mouse_button);
41 | }
42 |
43 | void _mouseButtonUp(MouseButton *mouse_button, i32 x, i32 y) {
44 | mouse_button->is_pressed = false;
45 | mouse_button->is_handled = false;
46 |
47 | mouse_button->up_pos.x = x;
48 | mouse_button->up_pos.y = y;
49 |
50 | if (app->on.mouseButtonUp) app->on.mouseButtonUp(mouse_button);
51 | }
52 |
53 | void _mouseButtonDoubleClicked(MouseButton *mouse_button, i32 x, i32 y) {
54 | app->controls.mouse.double_clicked = true;
55 | mouse_button->double_click_pos.x = x;
56 | mouse_button->double_click_pos.y = y;
57 | if (app->on.mouseButtonDoubleClicked) app->on.mouseButtonDoubleClicked(mouse_button);
58 | }
59 |
60 | void _mouseWheelScrolled(f32 amount) {
61 | app->controls.mouse.wheel_scroll_amount += amount * 100;
62 | app->controls.mouse.wheel_scrolled = true;
63 |
64 | if (app->on.mouseWheelScrolled) app->on.mouseWheelScrolled(amount);
65 | }
66 |
67 | void _mousePositionSet(i32 x, i32 y) {
68 | app->controls.mouse.pos.x = x;
69 | app->controls.mouse.pos.y = y;
70 |
71 | if (app->on.mousePositionSet) app->on.mousePositionSet(x, y);
72 | }
73 |
74 | void _mouseMovementSet(i32 x, i32 y) {
75 | app->controls.mouse.movement.x = x - app->controls.mouse.pos.x;
76 | app->controls.mouse.movement.y = y - app->controls.mouse.pos.y;
77 | app->controls.mouse.moved = true;
78 |
79 | if (app->on.mouseMovementSet) app->on.mouseMovementSet(x, y);
80 | }
81 |
82 | void _mouseRawMovementSet(i32 x, i32 y) {
83 | app->controls.mouse.pos_raw_diff.x += x;
84 | app->controls.mouse.pos_raw_diff.y += y;
85 | app->controls.mouse.moved = true;
86 |
87 | if (app->on.mouseRawMovementSet) app->on.mouseRawMovementSet(x, y);
88 | }
89 |
90 | bool initAppMemory(u64 size) {
91 | if (app->memory.address) return false;
92 |
93 | void* memory_address = app->platform.getMemory(size);
94 | if (!memory_address) {
95 | app->is_running = false;
96 | return false;
97 | }
98 |
99 | initMemory(&app->memory, (u8*)memory_address, size);
100 | return true;
101 | }
102 |
103 | void* allocateAppMemory(u64 size) {
104 | void *new_memory = allocateMemory(&app->memory, size);
105 | if (new_memory) return new_memory;
106 |
107 | app->is_running = false;
108 | return null;
109 | }
110 |
111 | void initScene(Scene *scene, SceneSettings *settings, Memory *memory, Platform *platform) {
112 | scene->settings = *settings;
113 | scene->primitives = null;
114 | scene->cameras = null;
115 | scene->curves = null;
116 | scene->boxes = null;
117 | scene->grids = null;
118 | scene->meshes = null;
119 | scene->textures = null;
120 |
121 | scene->selection = (Selection*)allocateMemory(memory, sizeof(Selection));
122 | scene->selection->object_type = scene->selection->object_id = 0;
123 | scene->selection->changed = false;
124 |
125 | if (settings->meshes && settings->mesh_files) {
126 | scene->meshes = (Mesh*)allocateMemory(memory, sizeof(Mesh) * settings->meshes);
127 | for (u32 i = 0; i < settings->meshes; i++)
128 | loadMeshFromFile(&scene->meshes[i], settings->mesh_files[i].char_ptr, platform, memory);
129 | }
130 |
131 | if (settings->cameras) {
132 | scene->cameras = (Camera*)allocateMemory(memory, sizeof(Camera) * settings->cameras);
133 | if (scene->cameras)
134 | for (u32 i = 0; i < settings->cameras; i++)
135 | initCamera(scene->cameras + i);
136 | }
137 |
138 | if (settings->primitives) {
139 | scene->primitives = (Primitive*)allocateMemory(memory, sizeof(Primitive) * settings->primitives);
140 | if (scene->primitives)
141 | for (u32 i = 0; i < settings->primitives; i++) {
142 | initPrimitive(scene->primitives + i);
143 | scene->primitives[i].id = i;
144 | }
145 | }
146 |
147 | if (settings->curves) {
148 | scene->curves = (Curve*)allocateMemory(memory, sizeof(Curve) * settings->curves);
149 | if (scene->curves)
150 | for (u32 i = 0; i < settings->curves; i++)
151 | initCurve(scene->curves + i);
152 | }
153 |
154 | if (settings->boxes) {
155 | scene->boxes = (Box*)allocateMemory(memory, sizeof(Box) * settings->boxes);
156 | if (scene->boxes)
157 | for (u32 i = 0; i < settings->boxes; i++)
158 | initBox(scene->boxes + i);
159 | }
160 |
161 | if (settings->grids) {
162 | scene->grids = (Grid*)allocateMemory(memory, sizeof(Grid) * settings->grids);
163 | if (scene->grids)
164 | for (u32 i = 0; i < settings->grids; i++)
165 | initGrid(scene->grids + i, 3, 3);
166 | }
167 |
168 | if (settings->lights) {
169 | Light *light = scene->lights = (Light*)allocateMemory(memory, sizeof(Light) * settings->lights);
170 | for (u32 i = 0; i < settings->lights; i++, light++) {
171 | for (u8 c = 0; c < 3; c++) {
172 | light->position_or_direction.components[c] = 0;
173 | light->color.components[c] = 1;
174 | light->attenuation.components[c] = 1;
175 | }
176 | light->intensity = 1;
177 | light->is_directional = false;
178 | }
179 | }
180 |
181 | if (settings->materials) {
182 | Material *material = scene->materials = (Material*)allocateMemory(memory, sizeof(Material) * settings->materials);
183 | for (u32 i = 0; i < settings->materials; i++, material++)
184 | initMaterial(material);
185 | }
186 |
187 | if (settings->textures && settings->texture_files) {
188 | scene->textures = (Texture*)allocateMemory(memory, sizeof(Texture) * settings->textures);
189 | for (u32 i = 0; i < settings->textures; i++)
190 | loadTextureFromFile(&scene->textures[i], settings->texture_files[i].char_ptr, platform, memory);
191 | }
192 |
193 | scene->last_io_ticks = 0;
194 | scene->last_io_is_save = false;
195 | }
196 |
197 |
198 | void _initApp(Defaults *defaults, u32* window_content) {
199 | app->window_content = window_content;
200 |
201 | app->is_running = true;
202 | app->user_data = null;
203 | app->memory.address = null;
204 |
205 | app->on.sceneReady = null;
206 | app->on.viewportReady = null;
207 | app->on.windowRedraw = null;
208 | app->on.keyChanged = null;
209 | app->on.mouseButtonUp = null;
210 | app->on.mouseButtonDown = null;
211 | app->on.mouseButtonDoubleClicked = null;
212 | app->on.mouseWheelScrolled = null;
213 | app->on.mousePositionSet = null;
214 | app->on.mouseMovementSet = null;
215 | app->on.mouseRawMovementSet = null;
216 |
217 | defaults->title = (char*)"";
218 | defaults->width = 480;
219 | defaults->height = 360;
220 | defaults->additional_memory_size = 0;
221 |
222 | SceneSettings *scene_settings = &defaults->settings.scene;
223 | ViewportSettings *viewport_settings = &defaults->settings.viewport;
224 | NavigationSettings *navigation_settings = &defaults->settings.navigation;
225 |
226 | setDefaultSceneSettings(scene_settings);
227 | setDefaultViewportSettings(viewport_settings);
228 | setDefaultNavigationSettings(navigation_settings);
229 |
230 | initTime(&app->time, app->platform.getTicks, app->platform.ticks_per_second);
231 | initMouse(&app->controls.mouse);
232 | initApp(defaults);
233 |
234 | u64 memory_size = sizeof(Selection) + defaults->additional_memory_size;
235 | memory_size += scene_settings->primitives * sizeof(Primitive);
236 | memory_size += scene_settings->textures * sizeof(Texture);
237 | memory_size += scene_settings->meshes * sizeof(Mesh);
238 | memory_size += scene_settings->curves * sizeof(Curve);
239 | memory_size += scene_settings->boxes * sizeof(Box);
240 | memory_size += scene_settings->grids * sizeof(Grid);
241 | memory_size += scene_settings->cameras * sizeof(Camera);
242 | memory_size += scene_settings->materials * sizeof(Material);
243 | memory_size += scene_settings->lights * sizeof(Light);
244 | memory_size += viewport_settings->hud_line_count * sizeof(HUDLine);
245 |
246 | if (scene_settings->textures &&
247 | scene_settings->texture_files)
248 | for (u32 i = 0; i < scene_settings->textures; i++)
249 | memory_size += getTextureMemorySize(scene_settings->texture_files[i].char_ptr, &app->platform);
250 |
251 | u32 max_triangle_count = CUBE__TRIANGLE_COUNT;
252 | u32 max_vertex_count = CUBE__VERTEX_COUNT;
253 | u32 max_normal_count = CUBE__NORMAL_COUNT;
254 | if (scene_settings->meshes && scene_settings->mesh_files) {
255 | Mesh mesh;
256 | for (u32 i = 0; i < scene_settings->meshes; i++) {
257 | memory_size += getMeshMemorySize(&mesh, scene_settings->mesh_files[i].char_ptr, &app->platform);
258 | if (mesh.triangle_count > max_triangle_count) max_triangle_count = mesh.triangle_count;
259 | if (mesh.vertex_count > max_vertex_count) max_vertex_count = mesh.vertex_count;
260 | if (mesh.normals_count > max_normal_count) max_normal_count = mesh.normals_count;
261 | }
262 | }
263 |
264 | memory_size += max_vertex_count * (sizeof(vec3) + sizeof(vec4) + 1);
265 | memory_size += max_normal_count * sizeof(vec3);
266 | memory_size += FRAME_BUFFER_MEMORY_SIZE;
267 |
268 | initAppMemory(memory_size);
269 |
270 | PixelQuad *pixels = (PixelQuad*)allocateAppMemory(FRAME_BUFFER_MEMORY_SIZE);
271 | initRasterizer(&app->rasterizer, max_vertex_count, max_normal_count, &app->memory);
272 | initScene(&app->scene, scene_settings, &app->memory, &app->platform);
273 | if (app->on.sceneReady) app->on.sceneReady(&app->scene);
274 |
275 | if (viewport_settings->hud_line_count)
276 | viewport_settings->hud_lines = (HUDLine*)allocateAppMemory(viewport_settings->hud_line_count * sizeof(HUDLine));
277 |
278 | initViewport(&app->viewport, viewport_settings, navigation_settings, app->scene.cameras, pixels);
279 | if (app->on.viewportReady) app->on.viewportReady(&app->viewport);
280 | }
281 |
282 | #ifdef __linux__
283 | //linux code goes here
284 | #elif _WIN32
285 | #include "./platforms/win32.h"
286 | #endif
--------------------------------------------------------------------------------
/src/SlimRaster/core/init.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "./types.h"
4 | #include "../renderer/mesh_shaders.h"
5 | #include "../renderer/pixel_shaders.h"
6 | #include "../scene/cube.h"
7 |
8 | void initNumberString(NumberString *number_string) {
9 | number_string->string.char_ptr = number_string->_buffer;
10 | number_string->string.length = 1;
11 | number_string->_buffer[12] = 0;
12 | for (u8 i = 0; i < 12; i++)
13 | number_string->_buffer[i] = ' ';
14 | }
15 |
16 | void initMouse(Mouse *mouse) {
17 | mouse->is_captured = false;
18 |
19 | mouse->moved = false;
20 | mouse->move_handled = false;
21 |
22 | mouse->double_clicked = false;
23 | mouse->double_clicked_handled = false;
24 |
25 | mouse->wheel_scrolled = false;
26 | mouse->wheel_scroll_amount = 0;
27 | mouse->wheel_scroll_handled = false;
28 |
29 | mouse->pos.x = 0;
30 | mouse->pos.y = 0;
31 | mouse->pos_raw_diff.x = 0;
32 | mouse->pos_raw_diff.y = 0;
33 | mouse->raw_movement_handled = false;
34 |
35 | mouse->middle_button.is_pressed = false;
36 | mouse->middle_button.is_handled = false;
37 | mouse->middle_button.up_pos.x = 0;
38 | mouse->middle_button.down_pos.x = 0;
39 |
40 | mouse->right_button.is_pressed = false;
41 | mouse->right_button.is_handled = false;
42 | mouse->right_button.up_pos.x = 0;
43 | mouse->right_button.down_pos.x = 0;
44 |
45 | mouse->left_button.is_pressed = false;
46 | mouse->left_button.is_handled = false;
47 | mouse->left_button.up_pos.x = 0;
48 | mouse->left_button.down_pos.x = 0;
49 | }
50 |
51 | void initTimer(Timer *timer, GetTicks getTicks, Ticks *ticks) {
52 | timer->getTicks = getTicks;
53 | timer->ticks = ticks;
54 |
55 | timer->delta_time = 0;
56 | timer->ticks_before = 0;
57 | timer->ticks_after = 0;
58 | timer->ticks_diff = 0;
59 |
60 | timer->accumulated_ticks = 0;
61 | timer->accumulated_frame_count = 0;
62 |
63 | timer->ticks_of_last_report = 0;
64 |
65 | timer->seconds = 0;
66 | timer->milliseconds = 0;
67 | timer->microseconds = 0;
68 | timer->nanoseconds = 0;
69 |
70 | timer->average_frames_per_tick = 0;
71 | timer->average_ticks_per_frame = 0;
72 | timer->average_frames_per_second = 0;
73 | timer->average_milliseconds_per_frame = 0;
74 | timer->average_microseconds_per_frame = 0;
75 | timer->average_nanoseconds_per_frame = 0;
76 | }
77 |
78 | void initTime(Time *time, GetTicks getTicks, u64 ticks_per_second) {
79 | time->getTicks = getTicks;
80 | time->ticks.per_second = ticks_per_second;
81 |
82 | time->ticks.per_tick.seconds = 1 / (f64)(time->ticks.per_second);
83 | time->ticks.per_tick.milliseconds = 1000 / (f64)(time->ticks.per_second);
84 | time->ticks.per_tick.microseconds = 1000000 / (f64)(time->ticks.per_second);
85 | time->ticks.per_tick.nanoseconds = 1000000000 / (f64)(time->ticks.per_second);
86 |
87 | initTimer(&time->timers.update, getTicks, &time->ticks);
88 | initTimer(&time->timers.render, getTicks, &time->ticks);
89 | initTimer(&time->timers.aux, getTicks, &time->ticks);
90 |
91 | time->timers.update.ticks_before = time->timers.update.ticks_of_last_report = getTicks();
92 | }
93 |
94 | void initXform3(xform3 *xform) {
95 | mat3 I;
96 | I.X.x = 1; I.Y.x = 0; I.Z.x = 0;
97 | I.X.y = 0; I.Y.y = 1; I.Z.y = 0;
98 | I.X.z = 0; I.Y.z = 0; I.Z.z = 1;
99 | xform->matrix = xform->yaw_matrix = xform->pitch_matrix = xform->roll_matrix = xform->rotation_matrix = xform->rotation_matrix_inverted = I;
100 | xform->right_direction = &xform->rotation_matrix.X;
101 | xform->up_direction = &xform->rotation_matrix.Y;
102 | xform->forward_direction = &xform->rotation_matrix.Z;
103 | xform->scale.x = 1;
104 | xform->scale.y = 1;
105 | xform->scale.z = 1;
106 | xform->position.x = 0;
107 | xform->position.y = 0;
108 | xform->position.z = 0;
109 | xform->rotation.axis.x = 0;
110 | xform->rotation.axis.y = 0;
111 | xform->rotation.axis.z = 0;
112 | xform->rotation.amount = 1;
113 | xform->rotation_inverted = xform->rotation;
114 | }
115 |
116 | void initCamera(Camera* camera) {
117 | camera->focal_length = camera->zoom = CAMERA_DEFAULT__FOCAL_LENGTH;
118 | camera->target_distance = CAMERA_DEFAULT__TARGET_DISTANCE;
119 | camera->dolly = 0;
120 | camera->current_velocity.x = 0;
121 | camera->current_velocity.y = 0;
122 | camera->current_velocity.z = 0;
123 | initXform3(&camera->transform);
124 | }
125 |
126 | void initBox(Box *box) {
127 | box->vertices.corners.front_top_left.x = -1;
128 | box->vertices.corners.back_top_left.x = -1;
129 | box->vertices.corners.front_bottom_left.x = -1;
130 | box->vertices.corners.back_bottom_left.x = -1;
131 |
132 | box->vertices.corners.front_top_right.x = 1;
133 | box->vertices.corners.back_top_right.x = 1;
134 | box->vertices.corners.front_bottom_right.x = 1;
135 | box->vertices.corners.back_bottom_right.x = 1;
136 |
137 |
138 | box->vertices.corners.front_bottom_left.y = -1;
139 | box->vertices.corners.front_bottom_right.y = -1;
140 | box->vertices.corners.back_bottom_left.y = -1;
141 | box->vertices.corners.back_bottom_right.y = -1;
142 |
143 | box->vertices.corners.front_top_left.y = 1;
144 | box->vertices.corners.front_top_right.y = 1;
145 | box->vertices.corners.back_top_left.y = 1;
146 | box->vertices.corners.back_top_right.y = 1;
147 |
148 |
149 | box->vertices.corners.front_top_left.z = 1;
150 | box->vertices.corners.front_top_right.z = 1;
151 | box->vertices.corners.front_bottom_left.z = 1;
152 | box->vertices.corners.front_bottom_right.z = 1;
153 |
154 | box->vertices.corners.back_top_left.z = -1;
155 | box->vertices.corners.back_top_right.z = -1;
156 | box->vertices.corners.back_bottom_left.z = -1;
157 | box->vertices.corners.back_bottom_right.z = -1;
158 |
159 | setBoxEdgesFromVertices(&box->edges, &box->vertices);
160 | }
161 |
162 | void initHUD(HUD *hud, HUDLine *lines, u32 line_count, f32 line_height, enum ColorID default_color, i32 position_x, i32 position_y) {
163 | hud->lines = lines;
164 | hud->line_count = line_count;
165 | hud->line_height = line_height;
166 | hud->position.x = position_x;
167 | hud->position.y = position_y;
168 |
169 | if (lines) {
170 | HUDLine *line = lines;
171 | for (u32 i = 0; i < line_count; i++, line++) {
172 | line->use_alternate = null;
173 | line->invert_alternate_use = false;
174 | line->title_color = line->value_color = line->alternate_value_color = default_color;
175 | initNumberString(&line->value);
176 | line->title.char_ptr = line->alternate_value.char_ptr = (char*)("");
177 | line->title.length = line->alternate_value.length = 0;
178 | }
179 | }
180 | }
181 |
182 | void setDefaultNavigationSettings(NavigationSettings *settings) {
183 | settings->max_velocity = NAVIGATION_DEFAULT__MAX_VELOCITY;
184 | settings->acceleration = NAVIGATION_DEFAULT__ACCELERATION;
185 | settings->speeds.turn = NAVIGATION_SPEED_DEFAULT__TURN;
186 | settings->speeds.orient = NAVIGATION_SPEED_DEFAULT__ORIENT;
187 | settings->speeds.orbit = NAVIGATION_SPEED_DEFAULT__ORBIT;
188 | settings->speeds.zoom = NAVIGATION_SPEED_DEFAULT__ZOOM;
189 | settings->speeds.dolly = NAVIGATION_SPEED_DEFAULT__DOLLY;
190 | settings->speeds.pan = NAVIGATION_SPEED_DEFAULT__PAN;
191 | }
192 |
193 | void initNavigation(Navigation *navigation, NavigationSettings *navigation_settings) {
194 | navigation->settings = *navigation_settings;
195 |
196 | navigation->turned = false;
197 | navigation->moved = false;
198 | navigation->zoomed = false;
199 |
200 | navigation->move.right = false;
201 | navigation->move.left = false;
202 | navigation->move.up = false;
203 | navigation->move.down = false;
204 | navigation->move.forward = false;
205 | navigation->move.backward = false;
206 |
207 | navigation->turn.right = false;
208 | navigation->turn.left = false;
209 | }
210 | void setDefaultViewportSettings(ViewportSettings *settings) {
211 | settings->near_clipping_plane_distance = VIEWPORT_DEFAULT__NEAR_CLIPPING_PLANE_DISTANCE;
212 | settings->far_clipping_plane_distance = VIEWPORT_DEFAULT__FAR_CLIPPING_PLANE_DISTANCE;
213 | settings->hud_default_color = White;
214 | settings->hud_line_count = 0;
215 | settings->hud_lines = null;
216 | settings->show_hud = false;
217 | settings->use_cube_NDC = false;
218 | settings->flip_z = false;
219 | settings->antialias = false;
220 | settings->cull_back_faces = true;
221 | settings->show_wire_frame = false;
222 | settings->background.color = Color(Black);
223 | settings->background.opacity = 0;
224 | settings->background.depth = INFINITY;
225 | }
226 |
227 | void setProjectionMatrix(Viewport *viewport) {
228 | const f32 n = viewport->settings.near_clipping_plane_distance;
229 | const f32 f = viewport->settings.far_clipping_plane_distance;
230 | const f32 fl = viewport->camera->focal_length;
231 | const f32 ar = viewport->dimensions.height_over_width;
232 | const f32 gl = viewport->settings.use_cube_NDC;
233 | mat4 M;
234 |
235 | M.X.y = M.X.z = M.X.w = M.Y.x = M.Y.z = M.Y.w = M.W.x = M.W.y = M.W.w = M.Z.x = M.Z.y = 0;
236 | M.Z.w = 1.0f;
237 | M.X.x = fl * ar;
238 | M.Y.y = fl;
239 | M.Z.z = M.W.z = 1.0f / (f - n);
240 | M.Z.z *= gl ? (f + n) : f;
241 | M.W.z *= gl ? (-2 * f * n) : (-n * f);
242 |
243 | viewport->projection_matrix = M;
244 | }
245 |
246 | void initViewport(Viewport *viewport, ViewportSettings *viewport_settings, NavigationSettings *navigation_settings, Camera *camera, PixelQuad *pixels) {
247 | viewport->pixels = pixels;
248 | viewport->camera = camera;
249 | viewport->settings = *viewport_settings;
250 | viewport->position.x = 0;
251 | viewport->position.y = 0;
252 | initBox(&viewport->default_box);
253 | initHUD(&viewport->hud, viewport_settings->hud_lines, viewport_settings->hud_line_count, 1, viewport_settings->hud_default_color, 0, 0);
254 | initNavigation(&viewport->navigation, navigation_settings);
255 | setProjectionMatrix(viewport);
256 | updateDimensions(&viewport->dimensions, MAX_WIDTH, MAX_HEIGHT, MAX_WIDTH);
257 | }
258 |
259 | void setDefaultSceneSettings(SceneSettings *settings) {
260 | settings->cameras = 1;
261 | settings->primitives = 0;
262 | settings->materials = 0;
263 | settings->lights = 0;
264 | settings->curves = 0;
265 | settings->boxes = 0;
266 | settings->grids = 0;
267 | settings->textures = 0;
268 | settings->meshes = 0;
269 | settings->mesh_files = null;
270 | settings->texture_files = null;
271 | settings->file.char_ptr = null;
272 | settings->file.length = 0;
273 | }
274 | void initCurve(Curve *curve) {
275 | curve->thickness = 0.1f;
276 | curve->revolution_count = 1;
277 | }
278 |
279 | void initPrimitive(Primitive *primitive) {
280 | primitive->id = 0;
281 | primitive->type = PrimitiveType_None;
282 | primitive->color = White;
283 | primitive->flags = ALL_FLAGS;
284 | primitive->scale.x = 1;
285 | primitive->scale.y = 1;
286 | primitive->scale.z = 1;
287 | primitive->position.x = 0;
288 | primitive->position.y = 0;
289 | primitive->position.z = 0;
290 | primitive->rotation.axis.x = 0;
291 | primitive->rotation.axis.y = 0;
292 | primitive->rotation.axis.z = 0;
293 | primitive->rotation.amount = 1;
294 | }
295 |
296 | bool initGrid(Grid *grid, u8 u_segments, u8 v_segments) {
297 | if (!u_segments || u_segments > GRID__MAX_SEGMENTS ||
298 | !v_segments || v_segments > GRID__MAX_SEGMENTS)
299 | return false;
300 |
301 | grid->u_segments = u_segments;
302 | grid->v_segments = v_segments;
303 |
304 | f32 u_step = u_segments > 1 ? (2.0f / (u_segments - 1)) : 0;
305 | f32 v_step = v_segments > 1 ? (2.0f / (v_segments - 1)) : 0;
306 |
307 | for (u8 u = 0; u < grid->u_segments; u++) {
308 | grid->vertices.uv.u.from[u].y = grid->vertices.uv.u.to[u].y = 0;
309 | grid->vertices.uv.u.from[u].x = grid->vertices.uv.u.to[u].x = -1 + u * u_step;
310 | grid->vertices.uv.u.from[u].z = -1;
311 | grid->vertices.uv.u.to[ u].z = +1;
312 | }
313 | for (u8 v = 0; v < grid->v_segments; v++) {
314 | grid->vertices.uv.v.from[v].y = grid->vertices.uv.v.to[v].y = 0;
315 | grid->vertices.uv.v.from[v].z = grid->vertices.uv.v.to[v].z = -1 + v * v_step;
316 | grid->vertices.uv.v.from[v].x = -1;
317 | grid->vertices.uv.v.to[ v].x = +1;
318 | }
319 |
320 | setGridEdgesFromVertices(grid->edges.uv.u, grid->u_segments, grid->vertices.uv.u.from, grid->vertices.uv.u.to);
321 | setGridEdgesFromVertices(grid->edges.uv.v, grid->v_segments, grid->vertices.uv.v.from, grid->vertices.uv.v.to);
322 |
323 | return true;
324 | }
325 |
326 | void initMaterial(Material *material) {
327 | for (u8 i = 0; i < 3; i++) {
328 | material->specular.components[i] = 1;
329 | material->diffuse.components[i] = 1;
330 | material->ambient.components[i] = 1;
331 | }
332 | material->brdf = phong;
333 | material->flags = LAMBERT;
334 | material->pixel_shader = shadePixelDepth;
335 | material->mesh_shader = shadeMesh;
336 | material->roughness = 1;
337 | material->shininess = 1;
338 | material->normal_magnitude = 1;
339 | material->texture_count = 0;
340 | for (u8 i = 0; i < 16; i++) material->texture_ids[i] = 0;
341 | }
342 |
343 | void initRasterizer(Rasterizer *rasterizer, u32 max_vertex_count, u32 max_normal_count, Memory *memory) {
344 | rasterizer->vertex_flags = (u8*)allocateMemory(memory, max_vertex_count);
345 | rasterizer->clip_space_vertex_positions = (vec4*)allocateMemory(memory, sizeof(vec4) * max_vertex_count);
346 | rasterizer->world_space_vertex_positions = (vec3*)allocateMemory(memory, sizeof(vec3) * max_vertex_count);
347 | rasterizer->world_space_vertex_normals = (vec3*)allocateMemory(memory, sizeof(vec3) * max_normal_count);
348 | setMeshToCube(&rasterizer->default_cube_mesh);
349 | }
--------------------------------------------------------------------------------
/src/SlimRaster/core/string.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | void setString(String *string, char *char_ptr) {
4 | string->char_ptr = char_ptr;
5 | string->length = 0;
6 | if (char_ptr)
7 | while (char_ptr[string->length])
8 | string->length++;
9 | }
10 |
11 | u32 getStringLength(char *string) {
12 | char *char_ptr = string;
13 | u32 length = 0;
14 | if (char_ptr) while (char_ptr[length]) length++;
15 | return length;
16 | }
17 |
18 | u32 getDirectoryLength(char *path) {
19 | u32 path_len = getStringLength(path);
20 | u32 dir_len = path_len;
21 | while (path[dir_len] != '/' && path[dir_len] != '\\') dir_len--;
22 | return dir_len + 1;
23 | }
24 |
25 | void copyToString(String *string, char* char_ptr, u32 offset) {
26 | string->length = offset;
27 | char *source_char = char_ptr;
28 | char *string_char = string->char_ptr + offset;
29 | while (source_char[0]) {
30 | *string_char = *source_char;
31 | string_char++;
32 | source_char++;
33 | string->length++;
34 | }
35 | *string_char = 0;
36 | }
37 |
38 | void mergeString(String *string, char* first, char* second, u32 offset) {
39 | copyToString(string, first, 0);
40 | copyToString(string, second, offset);
41 | }
42 |
43 | void printNumberIntoString(i32 number, NumberString *number_string) {
44 | initNumberString(number_string);
45 | char *buffer = number_string->_buffer;
46 | buffer[12] = 0;
47 |
48 | bool is_negative = number < 0;
49 | if (is_negative) number = -number;
50 |
51 | if (number) {
52 | u32 temp;
53 | buffer += 11;
54 | number_string->string.char_ptr = buffer;
55 | number_string->string.length = 0;
56 |
57 | for (u8 i = 0; i < 11; i++) {
58 | temp = number;
59 | number /= 10;
60 | number_string->string.length++;
61 | *buffer-- = (char)('0' + temp - number * 10);
62 | if (!number) {
63 | if (is_negative) {
64 | *buffer = '-';
65 | number_string->string.char_ptr--;
66 | number_string->string.length++;
67 | }
68 |
69 | break;
70 | }
71 | number_string->string.char_ptr--;
72 | }
73 | } else {
74 | buffer[11] = '0';
75 | number_string->string.length = 1;
76 | number_string->string.char_ptr = buffer + 11;
77 | }
78 | }
79 |
80 | void printFloatIntoString(f32 number, NumberString *number_string, u8 float_digits_count) {
81 | f32 factor = 1;
82 | for (u8 i = 0; i < float_digits_count; i++) factor *= 10;
83 | i32 int_num = (i32)(number * factor);
84 | if (int_num == 0) {
85 | printNumberIntoString((i32)factor, number_string);
86 | number_string->string.length++;
87 | number_string->string.char_ptr[0] = '.';
88 | number_string->string.char_ptr--;
89 | number_string->string.char_ptr[0] = '0';
90 | return;
91 | }
92 |
93 | bool is_negative = number < 0;
94 | bool is_fraction = is_negative ? number > -1 : number < 1;
95 |
96 | printNumberIntoString(int_num, number_string);
97 |
98 | if (is_fraction) {
99 | u32 len = number_string->string.length;
100 | number_string->string.length++;
101 | number_string->string.char_ptr--;
102 | if (is_negative) {
103 | number_string->string.char_ptr[0] = '-';
104 | number_string->string.char_ptr[1] = '0';
105 | } else {
106 | number_string->string.char_ptr[0] = '0';
107 | }
108 | if (len < float_digits_count) {
109 | for (u32 i = 0; i < (float_digits_count - len); i++) {
110 | number_string->string.length++;
111 | number_string->string.char_ptr--;
112 | number_string->string.char_ptr[0] = '0';
113 | }
114 | }
115 | }
116 |
117 | static char tmp[13];
118 | tmp[number_string->string.length + 1] = 0;
119 | for (u8 i = 0; i < (u8)number_string->string.length; i++) {
120 | u8 char_count_from_right_to_left = (u8)number_string->string.length - i - 1;
121 | if (char_count_from_right_to_left >= float_digits_count) tmp[i] = number_string->string.char_ptr[i];
122 | else tmp[i + 1] = number_string->string.char_ptr[i];
123 | }
124 | tmp[number_string->string.length - float_digits_count] = '.';
125 | copyToString(&number_string->string, tmp, 0);
126 | if (is_negative) number_string->string.length++;
127 | }
--------------------------------------------------------------------------------
/src/SlimRaster/core/time.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "./base.h"
4 |
5 | void accumulateTimer(Timer* timer) {
6 | timer->ticks_diff = timer->ticks_after - timer->ticks_before;
7 | timer->accumulated_ticks += timer->ticks_diff;
8 | timer->accumulated_frame_count++;
9 |
10 | timer->seconds = (u64)(timer->ticks->per_tick.seconds * (f64)(timer->ticks_diff));
11 | timer->milliseconds = (u64)(timer->ticks->per_tick.milliseconds * (f64)(timer->ticks_diff));
12 | timer->microseconds = (u64)(timer->ticks->per_tick.microseconds * (f64)(timer->ticks_diff));
13 | timer->nanoseconds = (u64)(timer->ticks->per_tick.nanoseconds * (f64)(timer->ticks_diff));
14 | }
15 |
16 | void averageTimer(Timer *timer) {
17 | timer->average_frames_per_tick = (f64)timer->accumulated_frame_count / (f64)timer->accumulated_ticks;
18 | timer->average_ticks_per_frame = (f64)timer->accumulated_ticks / (f64)timer->accumulated_frame_count;
19 | timer->average_frames_per_second = (u16)(timer->average_frames_per_tick * (f64)timer->ticks->per_second);
20 | timer->average_milliseconds_per_frame = (u16)(timer->average_ticks_per_frame * timer->ticks->per_tick.milliseconds);
21 | timer->average_microseconds_per_frame = (u16)(timer->average_ticks_per_frame * timer->ticks->per_tick.microseconds);
22 | timer->average_nanoseconds_per_frame = (u16)(timer->average_ticks_per_frame * timer->ticks->per_tick.nanoseconds);
23 | timer->accumulated_ticks = timer->accumulated_frame_count = 0;
24 | }
25 |
26 | INLINE void beginFrameTimer(Timer *timer) {
27 | timer->ticks_after = timer->ticks_before;
28 | timer->ticks_before = timer->getTicks();
29 | timer->ticks_diff = timer->ticks_before - timer->ticks_after;
30 | timer->delta_time = (f32)((f64)timer->ticks_diff * timer->ticks->per_tick.seconds);
31 | }
32 |
33 | INLINE void endFrameTimer(Timer *timer) {
34 | timer->ticks_after = timer->getTicks();
35 | accumulateTimer(timer);
36 | if (timer->accumulated_ticks >= timer->ticks->per_second / 4)
37 | averageTimer(timer);
38 | }
39 |
40 | void beginFrame(Timer *timer) {
41 | beginFrameTimer(timer);
42 | }
43 |
44 | void endFrame(Timer *timer, Mouse *mouse) {
45 | resetMouseChanges(mouse);
46 | endFrameTimer(timer);
47 | }
--------------------------------------------------------------------------------
/src/SlimRaster/math/mat2.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../core/base.h"
4 |
5 | INLINE mat2 getMat2Identity() {
6 | mat2 out;
7 |
8 | out.X.x = 1; out.X.y = 0;
9 | out.Y.x = 0; out.Y.y = 1;
10 |
11 | return out;
12 | }
13 |
14 | INLINE mat2 addMat2(mat2 a, mat2 b) {
15 | mat2 out;
16 |
17 | out.X.x = a.X.x + b.X.x;
18 | out.X.y = a.X.y + b.X.y;
19 |
20 | out.Y.x = a.Y.x + b.Y.x;
21 | out.Y.y = a.Y.y + b.Y.y;
22 |
23 | return out;
24 | }
25 |
26 | INLINE mat2 subMat2(mat2 a, mat2 b) {
27 | mat2 out;
28 |
29 | out.X.x = a.X.x - b.X.x;
30 | out.X.y = a.X.y - b.X.y;
31 |
32 | out.Y.x = a.Y.x - b.Y.x;
33 | out.Y.y = a.Y.y - b.Y.y;
34 |
35 | return out;
36 | }
37 |
38 | INLINE mat2 scaleMat2(mat2 m, f32 factor) {
39 | mat2 out;
40 |
41 | out.X.x = m.X.x * factor;
42 | out.X.y = m.X.y * factor;
43 |
44 | out.Y.x = m.Y.x * factor;
45 | out.Y.y = m.Y.y * factor;
46 |
47 | return out;
48 | }
49 |
50 | INLINE mat2 transposedMat2(mat2 m) {
51 | mat2 out;
52 |
53 | out.X.x = m.X.x; out.X.y = m.Y.x;
54 | out.Y.x = m.X.y; out.Y.y = m.Y.y;
55 |
56 | return out;
57 | }
58 |
59 | INLINE mat2 mulMat2(mat2 a, mat2 b) {
60 | mat2 out;
61 |
62 | out.X.x = a.X.x*b.X.x + a.X.y*b.Y.x; // Row 1 | Column 1
63 | out.X.y = a.X.x*b.X.y + a.X.y*b.Y.y; // Row 1 | Column 2
64 |
65 | out.Y.x = a.Y.x*b.X.x + a.Y.y*b.Y.x; // Row 2 | Column 1
66 | out.Y.y = a.Y.x*b.X.y + a.Y.y*b.Y.y; // Row 2 | Column 2
67 |
68 | return out;
69 | }
70 |
71 | INLINE mat2 invMat2(mat2 m) {
72 | mat2 out;
73 |
74 | f32 a = m.X.x, b = m.X.y,
75 | c = m.Y.x, d = m.Y.y;
76 |
77 | f32 det = a*d - b*c;
78 | f32 one_over_det = 1.0f / det;
79 |
80 | out.X.x = +d * one_over_det;
81 | out.X.y = -b * one_over_det;
82 | out.Y.x = -c * one_over_det;
83 | out.Y.y = +a * one_over_det;
84 |
85 | return out;
86 | }
87 |
88 | INLINE bool safeInvertMat2(mat2 *m) {
89 | f32 a = m->X.x, b = m->X.y,
90 | c = m->Y.x, d = m->Y.y;
91 |
92 | f32 det = a*d - b*c;
93 | if (!det) return false;
94 | f32 one_over_det = 1.0f / det;
95 |
96 | m->X.x = +d * one_over_det;
97 | m->X.y = -b * one_over_det;
98 | m->Y.x = -c * one_over_det;
99 | m->Y.y = +a * one_over_det;
100 |
101 | return true;
102 | }
103 |
104 | INLINE void rotateMat2(f32 amount, mat2* out) {
105 | vec2 xy = getPointOnUnitCircle(amount);
106 |
107 | vec2 X = out->X;
108 | vec2 Y = out->Y;
109 |
110 | out->X.x = xy.x * X.x + xy.y * X.y;
111 | out->Y.x = xy.x * Y.x + xy.y * Y.y;
112 |
113 | out->X.y = xy.x * X.y - xy.y * X.x;
114 | out->Y.y = xy.x * Y.y - xy.y * Y.x;
115 | }
116 |
117 | INLINE void setRotationMat2(f32 roll, mat2* roll_matrix) {
118 | vec2 xy = getPointOnUnitCircle(roll);
119 |
120 | roll_matrix->X.x = roll_matrix->Y.y = xy.x;
121 | roll_matrix->X.y = -xy.y;
122 | roll_matrix->Y.x = +xy.y;
123 | }
--------------------------------------------------------------------------------
/src/SlimRaster/math/mat3.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../core/base.h"
4 |
5 | INLINE mat3 getMat3Identity() {
6 | mat3 out;
7 |
8 | out.X.x = 1; out.X.y = 0; out.X.z = 0;
9 | out.Y.x = 0; out.Y.y = 1; out.Y.z = 0;
10 | out.Z.x = 0; out.Z.y = 0; out.Z.z = 1;
11 |
12 | return out;
13 | }
14 |
15 | INLINE mat3 addMat3(mat3 a, mat3 b) {
16 | mat3 out;
17 |
18 | out.X.x = a.X.x + b.X.x;
19 | out.X.y = a.X.y + b.X.y;
20 | out.X.z = a.X.z + b.X.z;
21 |
22 | out.Y.x = a.Y.x + b.Y.x;
23 | out.Y.y = a.Y.y + b.Y.y;
24 | out.Y.z = a.Y.z + b.Y.z;
25 |
26 | out.Z.x = a.Z.x + b.Z.x;
27 | out.Z.y = a.Z.y + b.Z.y;
28 | out.Z.z = a.Z.x + b.Z.x;
29 |
30 | return out;
31 | }
32 |
33 | INLINE mat3 subMat3(mat3 a, mat3 b) {
34 | mat3 out;
35 |
36 | out.X.x = a.X.x - b.X.x;
37 | out.X.y = a.X.y - b.X.y;
38 | out.X.z = a.X.z - b.X.z;
39 |
40 | out.Y.x = a.Y.x - b.Y.x;
41 | out.Y.y = a.Y.y - b.Y.y;
42 | out.Y.z = a.Y.z - b.Y.z;
43 |
44 | out.Z.x = a.Z.x - b.Z.x;
45 | out.Z.y = a.Z.y - b.Z.y;
46 | out.Z.z = a.Z.x - b.Z.x;
47 |
48 | return out;
49 | }
50 |
51 | INLINE mat3 scaleMat3(mat3 m, f32 factor) {
52 | mat3 out;
53 |
54 | out.X.x = m.X.x * factor;
55 | out.X.y = m.X.y * factor;
56 | out.X.z = m.X.z * factor;
57 |
58 | out.Y.x = m.Y.x * factor;
59 | out.Y.y = m.Y.y * factor;
60 | out.Y.z = m.Y.z * factor;
61 |
62 | out.Z.x = m.Z.x * factor;
63 | out.Z.y = m.Z.y * factor;
64 | out.Z.z = m.Z.z * factor;
65 |
66 | return out;
67 | }
68 |
69 | INLINE mat3 transposedMat3(mat3 m) {
70 | mat3 out;
71 |
72 | out.X.x = m.X.x; out.X.y = m.Y.x; out.X.z = m.Z.x;
73 | out.Y.x = m.X.y; out.Y.y = m.Y.y; out.Y.z = m.Z.y;
74 | out.Z.x = m.X.z; out.Z.y = m.Y.z; out.Z.z = m.Z.z;
75 |
76 | return out;
77 | }
78 |
79 | INLINE mat3 mulMat3(mat3 a, mat3 b) {
80 | mat3 out;
81 |
82 | out.X.x = a.X.x*b.X.x + a.X.y*b.Y.x + a.X.z*b.Z.x; // Row 1 | Column 1
83 | out.X.y = a.X.x*b.X.y + a.X.y*b.Y.y + a.X.z*b.Z.y; // Row 1 | Column 2
84 | out.X.z = a.X.x*b.X.z + a.X.y*b.Y.z + a.X.z*b.Z.z; // Row 1 | Column 3
85 |
86 | out.Y.x = a.Y.x*b.X.x + a.Y.y*b.Y.x + a.Y.z*b.Z.x; // Row 2 | Column 1
87 | out.Y.y = a.Y.x*b.X.y + a.Y.y*b.Y.y + a.Y.z*b.Z.y; // Row 2 | Column 2
88 | out.Y.z = a.Y.x*b.X.z + a.Y.y*b.Y.z + a.Y.z*b.Z.z; // Row 2 | Column 3
89 |
90 | out.Z.x = a.Z.x*b.X.x + a.Z.y*b.Y.x + a.Z.z*b.Z.x; // Row 3 | Column 1
91 | out.Z.y = a.Z.x*b.X.y + a.Z.y*b.Y.y + a.Z.z*b.Z.y; // Row 3 | Column 2
92 | out.Z.z = a.Z.x*b.X.z + a.Z.y*b.Y.z + a.Z.z*b.Z.z; // Row 3 | Column 3
93 |
94 | return out;
95 | }
96 |
97 | INLINE mat3 invMat3(mat3 m) {
98 | mat3 out;
99 |
100 | f32 one_over_determinant = 1.0f / (
101 | + m.X.x * (m.Y.y * m.Z.z - m.Z.y * m.Y.z)
102 | - m.Y.x * (m.X.y * m.Z.z - m.Z.y * m.X.z)
103 | + m.Z.x * (m.X.y * m.Y.z - m.Y.y * m.X.z)
104 | );
105 |
106 | out.X.x = + (m.Y.y * m.Z.z - m.Z.y * m.Y.z) * one_over_determinant;
107 | out.Y.x = - (m.Y.x * m.Z.z - m.Z.x * m.Y.z) * one_over_determinant;
108 | out.Z.x = + (m.Y.x * m.Z.y - m.Z.x * m.Y.y) * one_over_determinant;
109 | out.X.y = - (m.X.y * m.Z.z - m.Z.y * m.X.z) * one_over_determinant;
110 | out.Y.y = + (m.X.x * m.Z.z - m.Z.x * m.X.z) * one_over_determinant;
111 | out.Z.y = - (m.X.x * m.Z.y - m.Z.x * m.X.y) * one_over_determinant;
112 | out.X.z = + (m.X.y * m.Y.z - m.Y.y * m.X.z) * one_over_determinant;
113 | out.Y.z = - (m.X.x * m.Y.z - m.Y.x * m.X.z) * one_over_determinant;
114 | out.Z.z = + (m.X.x * m.Y.y - m.Y.x * m.X.y) * one_over_determinant;
115 |
116 | return out;
117 | }
118 |
119 | INLINE bool safeInvertMat3(mat3 *m) {
120 | f32 m11 = m->X.x, m12 = m->X.y, m13 = m->X.z,
121 | m21 = m->Y.x, m22 = m->Y.y, m23 = m->Y.z,
122 | m31 = m->Z.x, m32 = m->Z.y, m33 = m->Z.z,
123 |
124 | c11 = m22*m33 -
125 | m23*m32,
126 |
127 | c12 = m13*m32 -
128 | m12*m33,
129 |
130 | c13 = m12*m23 -
131 | m13*m22,
132 |
133 |
134 | c21 = m23*m31 -
135 | m21*m33,
136 |
137 | c22 = m11*m33 -
138 | m13*m31,
139 |
140 | c23 = m13*m21 -
141 | m11*m23,
142 |
143 |
144 | c31 = m21*m32 -
145 | m22*m31,
146 |
147 | c32 = m12*m31 -
148 | m11*m32,
149 |
150 | c33 = m11*m22 -
151 | m12*m21,
152 |
153 | d = c11 + c12 + c13 +
154 | c21 + c22 + c23 +
155 | c31 + c32 + c33;
156 |
157 | if (!d) return false;
158 |
159 | d = 1 / d;
160 |
161 | m->X.x = d * c11; m->X.y = d * c12; m->X.z = d * c13;
162 | m->Y.x = d * c21; m->Y.y = d * c22; m->Y.z = d * c23;
163 | m->Z.x = d * c31; m->Z.y = d * c32; m->Z.z = d * c33;
164 |
165 | return true;
166 | }
167 |
168 | INLINE void yawMat3(f32 amount, mat3* out) {
169 | vec2 xy = getPointOnUnitCircle(amount);
170 |
171 | vec3 X = out->X;
172 | vec3 Y = out->Y;
173 | vec3 Z = out->Z;
174 |
175 | out->X.x = xy.x * X.x - xy.y * X.z;
176 | out->Y.x = xy.x * Y.x - xy.y * Y.z;
177 | out->Z.x = xy.x * Z.x - xy.y * Z.z;
178 |
179 | out->X.z = xy.x * X.z + xy.y * X.x;
180 | out->Y.z = xy.x * Y.z + xy.y * Y.x;
181 | out->Z.z = xy.x * Z.z + xy.y * Z.x;
182 | }
183 |
184 | INLINE void pitchMat3(f32 amount, mat3* out) {
185 | vec2 xy = getPointOnUnitCircle(amount);
186 |
187 | vec3 X = out->X;
188 | vec3 Y = out->Y;
189 | vec3 Z = out->Z;
190 |
191 | out->X.y = xy.x * X.y + xy.y * X.z;
192 | out->Y.y = xy.x * Y.y + xy.y * Y.z;
193 | out->Z.y = xy.x * Z.y + xy.y * Z.z;
194 |
195 | out->X.z = xy.x * X.z - xy.y * X.y;
196 | out->Y.z = xy.x * Y.z - xy.y * Y.y;
197 | out->Z.z = xy.x * Z.z - xy.y * Z.y;
198 | }
199 |
200 | INLINE void rollMat3(f32 amount, mat3* out) {
201 | vec2 xy = getPointOnUnitCircle(amount);
202 |
203 | vec3 X = out->X;
204 | vec3 Y = out->Y;
205 | vec3 Z = out->Z;
206 |
207 | out->X.x = xy.x * X.x + xy.y * X.y;
208 | out->Y.x = xy.x * Y.x + xy.y * Y.y;
209 | out->Z.x = xy.x * Z.x + xy.y * Z.y;
210 |
211 | out->X.y = xy.x * X.y - xy.y * X.x;
212 | out->Y.y = xy.x * Y.y - xy.y * Y.x;
213 | out->Z.y = xy.x * Z.y - xy.y * Z.x;
214 | }
215 |
216 | INLINE void setYawMat3(f32 yaw, mat3* yaw_matrix) {
217 | vec2 xy = getPointOnUnitCircle(yaw);
218 |
219 | yaw_matrix->X.x = yaw_matrix->Z.z = xy.x;
220 | yaw_matrix->X.z = +xy.y;
221 | yaw_matrix->Z.x = -xy.y;
222 | }
223 |
224 | INLINE void setPitchMat3(f32 pitch, mat3* pitch_matrix) {
225 | vec2 xy = getPointOnUnitCircle(pitch);
226 |
227 | pitch_matrix->Z.z = pitch_matrix->Y.y = xy.x;
228 | pitch_matrix->Y.z = -xy.y;
229 | pitch_matrix->Z.y = +xy.y;
230 | }
231 |
232 | INLINE void setRollMat3(f32 roll, mat3* roll_matrix) {
233 | vec2 xy = getPointOnUnitCircle(roll);
234 |
235 | roll_matrix->X.x = roll_matrix->Y.y = xy.x;
236 | roll_matrix->X.y = -xy.y;
237 | roll_matrix->Y.x = +xy.y;
238 | }
--------------------------------------------------------------------------------
/src/SlimRaster/math/mat4.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../core/base.h"
4 |
5 | INLINE mat4 getMat4Identity() {
6 | mat4 out;
7 |
8 | out.X.x = 1; out.X.y = 0; out.X.z = 0; out.X.w = 0;
9 | out.Y.x = 0; out.Y.y = 1; out.Y.z = 0; out.Y.w = 0;
10 | out.Z.x = 0; out.Z.y = 0; out.Z.z = 1; out.Z.w = 0;
11 | out.W.x = 0; out.W.y = 0; out.W.z = 0; out.W.w = 1;
12 |
13 | return out;
14 | }
15 |
16 | INLINE mat4 transposeMat4(mat4 m) {
17 | mat4 out;
18 |
19 | out.X.x = m.X.x; out.X.y = m.Y.x; out.X.z = m.Z.x; out.X.w = m.W.x;
20 | out.Y.x = m.X.y; out.Y.y = m.Y.y; out.Y.z = m.Z.y; out.Y.w = m.W.y;
21 | out.Z.x = m.X.z; out.Z.y = m.Y.z; out.Z.z = m.Z.z; out.Z.w = m.W.z;
22 | out.W.x = m.X.w; out.W.y = m.Y.w; out.W.z = m.Z.w; out.W.w = m.W.w;
23 |
24 | return out;
25 | }
26 |
27 | INLINE mat4 addMat4(mat4 a, mat4 b) {
28 | mat4 out;
29 |
30 | out.X.x = a.X.x + b.X.x;
31 | out.X.y = a.X.y + b.X.y;
32 | out.X.z = a.X.z + b.X.z;
33 | out.X.w = a.X.w + b.X.w;
34 |
35 | out.Y.x = a.Y.x + b.Y.x;
36 | out.Y.y = a.Y.y + b.Y.y;
37 | out.Y.z = a.Y.z + b.Y.z;
38 | out.Y.w = a.Y.w + b.Y.w;
39 |
40 | out.Z.x = a.Z.x + b.Z.x;
41 | out.Z.y = a.Z.y + b.Z.y;
42 | out.Z.z = a.Z.x + b.Z.x;
43 | out.Z.w = a.Z.w + b.Z.w;
44 |
45 | out.W.x = a.W.x + b.W.x;
46 | out.W.y = a.W.y + b.W.y;
47 | out.W.z = a.W.x + b.W.x;
48 | out.W.w = a.W.w + b.W.w;
49 |
50 | return out;
51 | }
52 |
53 | INLINE mat4 subMat4(mat4 a, mat4 b) {
54 | mat4 out;
55 |
56 | out.X.x = a.X.x - b.X.x;
57 | out.X.y = a.X.y - b.X.y;
58 | out.X.z = a.X.z - b.X.z;
59 | out.X.w = a.X.w - b.X.w;
60 |
61 | out.Y.x = a.Y.x - b.Y.x;
62 | out.Y.y = a.Y.y - b.Y.y;
63 | out.Y.z = a.Y.z - b.Y.z;
64 | out.Y.w = a.Y.w - b.Y.w;
65 |
66 | out.Z.x = a.Z.x - b.Z.x;
67 | out.Z.y = a.Z.y - b.Z.y;
68 | out.Z.z = a.Z.x - b.Z.x;
69 | out.Z.w = a.Z.w - b.Z.w;
70 |
71 | out.W.x = a.W.x - b.W.x;
72 | out.W.y = a.W.y - b.W.y;
73 | out.W.z = a.W.x - b.W.x;
74 | out.W.w = a.W.w - b.W.w;
75 |
76 | return out;
77 | }
78 |
79 | INLINE mat4 scaleMat4(mat4 m, f32 factor) {
80 | mat4 out;
81 |
82 | out.X.x = m.X.x * factor;
83 | out.X.y = m.X.y * factor;
84 | out.X.z = m.X.z * factor;
85 | out.X.w = m.X.w * factor;
86 |
87 | out.Y.x = m.Y.x * factor;
88 | out.Y.y = m.Y.y * factor;
89 | out.Y.z = m.Y.z * factor;
90 | out.Y.w = m.Y.w * factor;
91 |
92 | out.Z.x = m.Z.x * factor;
93 | out.Z.y = m.Z.y * factor;
94 | out.Z.z = m.Z.z * factor;
95 | out.Z.w = m.Z.w * factor;
96 |
97 | out.W.x = m.W.x * factor;
98 | out.W.y = m.W.y * factor;
99 | out.W.z = m.W.z * factor;
100 | out.W.w = m.W.w * factor;
101 |
102 | return out;
103 | }
104 |
105 | INLINE mat4 mulMat4(mat4 a, mat4 b) {
106 | mat4 out;
107 |
108 | out.X.x = a.X.x*b.X.x + a.X.y*b.Y.x + a.X.z*b.Z.x + a.X.w*b.W.x; // Row 1 | Column 1
109 | out.X.y = a.X.x*b.X.y + a.X.y*b.Y.y + a.X.z*b.Z.y + a.X.w*b.W.y; // Row 1 | Column 2
110 | out.X.z = a.X.x*b.X.z + a.X.y*b.Y.z + a.X.z*b.Z.z + a.X.w*b.W.z; // Row 1 | Column 3
111 | out.X.w = a.X.x*b.X.w + a.X.y*b.Y.w + a.X.z*b.Z.w + a.X.w*b.W.w; // Row 1 | Column 4
112 |
113 | out.Y.x = a.Y.x*b.X.x + a.Y.y*b.Y.x + a.Y.z*b.Z.x + a.Y.w*b.W.x; // Row 2 | Column 1
114 | out.Y.y = a.Y.x*b.X.y + a.Y.y*b.Y.y + a.Y.z*b.Z.y + a.Y.w*b.W.y; // Row 2 | Column 2
115 | out.Y.z = a.Y.x*b.X.z + a.Y.y*b.Y.z + a.Y.z*b.Z.z + a.Y.w*b.W.z; // Row 2 | Column 3
116 | out.Y.w = a.Y.x*b.X.w + a.Y.y*b.Y.w + a.Y.z*b.Z.w + a.Y.w*b.W.w; // Row 2 | Column 4
117 |
118 | out.Z.x = a.Z.x*b.X.x + a.Z.y*b.Y.x + a.Z.z*b.Z.x + a.Z.w*b.W.x; // Row 3 | Column 1
119 | out.Z.y = a.Z.x*b.X.y + a.Z.y*b.Y.y + a.Z.z*b.Z.y + a.Z.w*b.W.y; // Row 3 | Column 2
120 | out.Z.z = a.Z.x*b.X.z + a.Z.y*b.Y.z + a.Z.z*b.Z.z + a.Z.w*b.W.z; // Row 3 | Column 3
121 | out.Z.w = a.Z.x*b.X.w + a.Z.y*b.Y.w + a.Z.z*b.Z.w + a.Z.w*b.W.w; // Row 3 | Column 4
122 |
123 | out.W.x = a.W.x*b.X.x + a.W.y*b.Y.x + a.W.z*b.Z.x + a.W.w*b.W.x; // Row 4 | Column 1
124 | out.W.y = a.W.x*b.X.y + a.W.y*b.Y.y + a.W.z*b.Z.y + a.W.w*b.W.y; // Row 4 | Column 2
125 | out.W.z = a.W.x*b.X.z + a.W.y*b.Y.z + a.W.z*b.Z.z + a.W.w*b.W.z; // Row 4 | Column 3
126 | out.W.w = a.W.x*b.X.w + a.W.y*b.Y.w + a.W.z*b.Z.w + a.W.w*b.W.w; // Row 4 | Column 4
127 |
128 | return out;
129 | }
130 |
131 | INLINE mat4 invMat4(mat4 m) {
132 | mat4 out;
133 |
134 | f32 m11 = m.X.x, m12 = m.X.y, m13 = m.X.z, m14 = m.X.w,
135 | m21 = m.Y.x, m22 = m.Y.y, m23 = m.Y.z, m24 = m.Y.w,
136 | m31 = m.Z.x, m32 = m.Z.y, m33 = m.Z.z, m34 = m.Z.w,
137 | m41 = m.W.x, m42 = m.W.y, m43 = m.W.z, m44 = m.W.w;
138 |
139 | out.X.x = +m22*m33*m44 - m22*m34*m43 - m32*m23*m44 + m32*m24*m43 + m42*m23*m34 - m42*m24*m33;
140 | out.X.y = -m12*m33*m44 + m12*m34*m43 + m32*m13*m44 - m32*m14*m43 - m42*m13*m34 + m42*m14*m33;
141 | out.X.z = +m12*m23*m44 - m12*m24*m43 - m22*m13*m44 + m22*m14*m43 + m42*m13*m24 - m42*m14*m23;
142 | out.X.w = -m12*m23*m34 + m12*m24*m33 + m22*m13*m34 - m22*m14*m33 - m32*m13*m24 + m32*m14*m23;
143 |
144 | out.Y.x = -m21*m33*m44 + m21*m34*m43 + m31*m23*m44 - m31*m24*m43 - m41*m23*m34 + m41*m24*m33;
145 | out.Y.y = +m11*m33*m44 - m11*m34*m43 - m31*m13*m44 + m31*m14*m43 + m41*m13*m34 - m41*m14*m33;
146 | out.Y.z = -m11*m23*m44 + m11*m24*m43 + m21*m13*m44 - m21*m14*m43 - m41*m13*m24 + m41*m14*m23;
147 | out.Y.w = +m11*m23*m34 - m11*m24*m33 - m21*m13*m34 + m21*m14*m33 + m31*m13*m24 - m31*m14*m23;
148 |
149 | out.Z.x = +m21*m32*m44 - m21*m34*m42 - m31*m22*m44 + m31*m24*m42 + m41*m22*m34 - m41*m24*m32;
150 | out.Z.y = -m11*m32*m44 + m11*m34*m42 + m31*m12*m44 - m31*m14*m42 - m41*m12*m34 + m41*m14*m32;
151 | out.Z.z = +m11*m22*m44 - m11*m24*m42 - m21*m12*m44 + m21*m14*m42 + m41*m12*m24 - m41*m14*m22;
152 | out.Z.w = -m11*m22*m34 + m11*m24*m32 + m21*m12*m34 - m21*m14*m32 - m31*m12*m24 + m31*m14*m22;
153 |
154 | out.W.x = -m21*m32*m43 + m21*m33*m42 + m31*m22*m43 - m31*m23*m42 - m41*m22*m33 + m41*m23*m32;
155 | out.W.y = +m11*m32*m43 - m11*m33*m42 - m31*m12*m43 + m31*m13*m42 + m41*m12*m33 - m41*m13*m32;
156 | out.W.z = -m11*m22*m43 + m11*m23*m42 + m21*m12*m43 - m21*m13*m42 - m41*m12*m23 + m41*m13*m22;
157 | out.W.w = +m11*m22*m33 - m11*m23*m32 - m21*m12*m33 + m21*m13*m32 + m31*m12*m23 - m31*m13*m22;
158 |
159 | f32 det = m11*out.X.x + m12*out.Y.x + m13*out.Z.x + m14*out.W.x;
160 | if (!det) return m;
161 |
162 | out = scaleMat4(out, 1.0f / det);
163 |
164 | return out;
165 | }
166 |
167 | INLINE void yawMat4(f32 amount, mat4 *out) {
168 | vec2 xy = getPointOnUnitCircle(amount);
169 |
170 | vec4 X = out->X;
171 | vec4 Y = out->Y;
172 | vec4 Z = out->Z;
173 |
174 | out->X.x = xy.x * X.x - xy.y * X.z;
175 | out->Y.x = xy.x * Y.x - xy.y * Y.z;
176 | out->Z.x = xy.x * Z.x - xy.y * Z.z;
177 |
178 | out->X.z = xy.x * X.z + xy.y * X.x;
179 | out->Y.z = xy.x * Y.z + xy.y * Y.x;
180 | out->Z.z = xy.x * Z.z + xy.y * Z.x;
181 | }
182 |
183 | INLINE void pitchMat4(f32 amount, mat4 *out) {
184 | vec2 xy = getPointOnUnitCircle(amount);
185 |
186 | vec4 X = out->X;
187 | vec4 Y = out->Y;
188 | vec4 Z = out->Z;
189 |
190 | out->X.y = xy.x * X.y + xy.y * X.z;
191 | out->Y.y = xy.x * Y.y + xy.y * Y.z;
192 | out->Z.y = xy.x * Z.y + xy.y * Z.z;
193 |
194 | out->X.z = xy.x * X.z - xy.y * X.y;
195 | out->Y.z = xy.x * Y.z - xy.y * Y.y;
196 | out->Z.z = xy.x * Z.z - xy.y * Z.y;
197 | }
198 |
199 | INLINE void rollMat4(f32 amount, mat4 *out) {
200 | vec2 xy = getPointOnUnitCircle(amount);
201 |
202 | vec4 X = out->X;
203 | vec4 Y = out->Y;
204 | vec4 Z = out->Z;
205 |
206 | out->X.x = xy.x * X.x + xy.y * X.y;
207 | out->Y.x = xy.x * Y.x + xy.y * Y.y;
208 | out->Z.x = xy.x * Z.x + xy.y * Z.y;
209 |
210 | out->X.y = xy.x * X.y - xy.y * X.x;
211 | out->Y.y = xy.x * Y.y - xy.y * Y.x;
212 | out->Z.y = xy.x * Z.y - xy.y * Z.x;
213 | }
214 |
215 | INLINE void setYawMat4(f32 yaw, mat4 *yaw_matrix) {
216 | vec2 xy = getPointOnUnitCircle(yaw);
217 |
218 | yaw_matrix->X.x = yaw_matrix->Z.z = xy.x;
219 | yaw_matrix->X.z = +xy.y;
220 | yaw_matrix->Z.x = -xy.y;
221 | }
222 |
223 | INLINE void setPitchMat4(f32 pitch, mat4 *pitch_matrix) {
224 | vec2 xy = getPointOnUnitCircle(pitch);
225 |
226 | pitch_matrix->Z.z = pitch_matrix->Y.y = xy.x;
227 | pitch_matrix->Y.z = -xy.y;
228 | pitch_matrix->Z.y = +xy.y;
229 | }
230 |
231 | INLINE void setRollMat4(f32 roll, mat4 *roll_matrix) {
232 | vec2 xy = getPointOnUnitCircle(roll);
233 |
234 | roll_matrix->X.x = roll_matrix->Y.y = xy.x;
235 | roll_matrix->X.y = -xy.y;
236 | roll_matrix->Y.x = +xy.y;
237 | }
238 |
239 | INLINE mat4 mat4fromMat3(mat3 m3) {
240 | mat4 out = getMat4Identity();
241 | for (u8 row = 0; row < 3; row++)
242 | for (u8 col = 0; col < 3; col++)
243 | out.axis[row].components[col] = m3.axis[row].components[col];
244 |
245 | return out;
246 | }
--------------------------------------------------------------------------------
/src/SlimRaster/math/quat.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../core/base.h"
4 | #include "./vec3.h"
5 |
6 | INLINE quat getIdentityQuaternion() {
7 | quat out;
8 |
9 | out.axis = getVec3Of(0);
10 | out.amount = 1;
11 |
12 | return out;
13 | }
14 |
15 | INLINE quat normQuat(quat q) {
16 | quat out;
17 |
18 | f32 factor = 1.0f / sqrtf(q.axis.x * q.axis.x + q.axis.y * q.axis.y + q.axis.z * q.axis.z + q.amount * q.amount);
19 | out.axis = scaleVec3(q.axis, factor);
20 | out.amount = q.amount * factor;
21 |
22 | return out;
23 | }
24 |
25 | INLINE vec3 mulVec3Quat(const vec3 v, quat q) {
26 | vec3 out = crossVec3(q.axis, v);
27 | vec3 qqv = crossVec3(q.axis, out);
28 | out = scaleAddVec3(out, q.amount, qqv);
29 | out = scaleAddVec3(out, 2, v);
30 | return out;
31 | }
32 |
33 | INLINE quat mulQuat(quat a, quat b) {
34 | quat out;
35 |
36 | out.amount = a.amount * b.amount - a.axis.x * b.axis.x - a.axis.y * b.axis.y - a.axis.z * b.axis.z;
37 | out.axis.x = a.amount * b.axis.x + a.axis.x * b.amount + a.axis.y * b.axis.z - a.axis.z * b.axis.y;
38 | out.axis.y = a.amount * b.axis.y - a.axis.x * b.axis.z + a.axis.y * b.amount + a.axis.z * b.axis.x;
39 | out.axis.z = a.amount * b.axis.z + a.axis.x * b.axis.y - a.axis.y * b.axis.x + a.axis.z * b.amount;
40 |
41 | return out;
42 | }
43 |
44 | INLINE quat conjugate(quat q) {
45 | quat out;
46 |
47 | out.amount = q.amount;
48 | out.axis = invertedVec3(q.axis);
49 |
50 | return out;
51 | }
52 |
53 | INLINE quat convertRotationMatrixToQuaternion(mat3 rotation_matrix) {
54 | quat out;
55 |
56 | f32 fourXSquaredMinus1 = rotation_matrix.X.x - rotation_matrix.Y.y - rotation_matrix.Z.z;
57 | f32 fourYSquaredMinus1 = rotation_matrix.Y.y - rotation_matrix.X.x - rotation_matrix.Z.z;
58 | f32 fourZSquaredMinus1 = rotation_matrix.Z.z - rotation_matrix.X.x - rotation_matrix.Y.y;
59 | f32 fourWSquaredMinus1 = rotation_matrix.X.x + rotation_matrix.Y.y + rotation_matrix.Z.z;
60 |
61 | int biggestIndex = 0;
62 | f32 fourBiggestSquaredMinus1 = fourWSquaredMinus1;
63 | if (fourXSquaredMinus1 > fourBiggestSquaredMinus1) {
64 | fourBiggestSquaredMinus1 = fourXSquaredMinus1;
65 | biggestIndex = 1;
66 | }
67 | if (fourYSquaredMinus1 > fourBiggestSquaredMinus1) {
68 | fourBiggestSquaredMinus1 = fourYSquaredMinus1;
69 | biggestIndex = 2;
70 | }
71 | if (fourZSquaredMinus1 > fourBiggestSquaredMinus1) {
72 | fourBiggestSquaredMinus1 = fourZSquaredMinus1;
73 | biggestIndex = 3;
74 | }
75 |
76 | f32 biggestVal = sqrtf(fourBiggestSquaredMinus1 + 1.0f) * 0.5f;
77 | f32 mult = 0.25f / biggestVal;
78 |
79 | switch(biggestIndex) {
80 | case 0:
81 | out.amount = biggestVal;
82 | out.axis.x = (rotation_matrix.Y.z - rotation_matrix.Z.y) * mult;
83 | out.axis.y = (rotation_matrix.Z.x - rotation_matrix.X.z) * mult;
84 | out.axis.z = (rotation_matrix.X.y - rotation_matrix.Y.x) * mult;
85 | break;
86 | case 1:
87 | out.amount = (rotation_matrix.Y.z - rotation_matrix.Z.y) * mult;
88 | out.axis.x = biggestVal;
89 | out.axis.y = (rotation_matrix.X.y + rotation_matrix.Y.x) * mult;
90 | out.axis.z = (rotation_matrix.Z.x + rotation_matrix.X.z) * mult;
91 | break;
92 | case 2:
93 | out.amount = (rotation_matrix.Z.x - rotation_matrix.X.z) * mult;
94 | out.axis.x = (rotation_matrix.X.y + rotation_matrix.Y.x) * mult;
95 | out.axis.y = biggestVal;
96 | out.axis.z = (rotation_matrix.Y.z + rotation_matrix.Z.y) * mult;
97 | break;
98 | case 3:
99 | out.amount = (rotation_matrix.X.y - rotation_matrix.Y.x) * mult;
100 | out.axis.x = (rotation_matrix.Z.x + rotation_matrix.X.z) * mult;
101 | out.axis.y = (rotation_matrix.Y.z + rotation_matrix.Z.y) * mult;
102 | out.axis.z = biggestVal;
103 | break;
104 | }
105 |
106 | return out;
107 | }
108 |
109 | INLINE mat3 convertQuaternionToRotationMatrix(quat q) {
110 | mat3 out;
111 |
112 | f32 q0 = q.amount;
113 | f32 q1 = q.axis.x;
114 | f32 q2 = q.axis.y;
115 | f32 q3 = q.axis.z;
116 |
117 | out.X.x = 2 * (q0 * q0 + q1 * q1) - 1;
118 | out.X.y = 2 * (q1 * q2 - q0 * q3);
119 | out.X.z = 2 * (q1 * q3 + q0 * q2);
120 |
121 | out.Y.x = 2 * (q1 * q2 + q0 * q3);
122 | out.Y.y = 2 * (q0 * q0 + q2 * q2) - 1;
123 | out.Y.z = 2 * (q2 * q3 - q0 * q1);
124 |
125 | out.Z.x = 2 * (q1 * q3 - q0 * q2);
126 | out.Z.y = 2 * (q2 * q3 + q0 * q1);
127 | out.Z.z = 2 * (q0 * q0 + q3 * q3) - 1;
128 |
129 | return out;
130 | }
131 |
132 | INLINE quat getRotationAroundAxis(vec3 axis, f32 amount) {
133 | vec2 sin_cos = getPointOnUnitCircle(amount);
134 | quat out;
135 | out.axis = scaleVec3(axis, sin_cos.y);
136 | out.amount = sin_cos.x;
137 |
138 | return normQuat(out);
139 | }
140 |
141 | INLINE quat getRotationAroundAxisBySinCon(vec3 axis, vec2 sin_cos) {
142 | quat out;
143 | out.axis = scaleVec3(axis, sin_cos.y);
144 | out.amount = sin_cos.x;
145 |
146 | return normQuat(out);
147 | }
148 |
149 | INLINE quat rotateAroundAxisBySinCos(quat q, vec3 axis, vec2 sin_cos) {
150 | quat rotation = getRotationAroundAxisBySinCon(axis, sin_cos);
151 | return mulQuat(q, rotation);
152 | }
153 |
154 | INLINE quat rotateAroundAxis(quat q, vec3 axis, f32 amount) {
155 | quat rotation = getRotationAroundAxis(axis, amount);
156 | return mulQuat(q, rotation);
157 | }
--------------------------------------------------------------------------------
/src/SlimRaster/math/vec2.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../core/base.h"
4 |
5 | INLINE vec2 getVec2Of(f32 value) {
6 | vec2 out;
7 |
8 | out.x = out.y = value;
9 |
10 | return out;
11 | }
12 | INLINE bool isEqualVec2(vec2 a, vec2 b) {
13 | return a.x == b.x && a.y == b.y;
14 | }
15 |
16 | INLINE vec2 clampVec2ToZero(vec2 v) {
17 | v.x = v.x > 0.0f ? v.x : 0.0f;
18 | v.y = v.y > 0.0f ? v.y : 0.0f;
19 | return v;
20 | }
21 |
22 | INLINE vec2 clampVec2ToUpper(vec2 v, vec2 upper) {
23 | v.x = v.x < upper.x ? v.x : upper.x;
24 | v.y = v.y < upper.y ? v.y : upper.y;
25 | return v;
26 | }
27 |
28 | INLINE vec2 clampVec2(vec2 v) {
29 | v.x = v.x > 0.0f ? v.x : 0.0f;
30 | v.y = v.y > 0.0f ? v.y : 0.0f;
31 |
32 | v.x = v.x < 1.0f ? v.x : 1.0f;
33 | v.y = v.y < 1.0f ? v.y : 1.0f;
34 |
35 | return v;
36 | }
37 |
38 | INLINE vec2 clampVec2To(vec2 v, const f32 min_value, const f32 max_value) {
39 | v.x = v.x > min_value ? v.x : min_value;
40 | v.y = v.y > min_value ? v.y : min_value;
41 |
42 | v.x = v.x < max_value ? v.x : max_value;
43 | v.y = v.y < max_value ? v.y : max_value;
44 |
45 | return v;
46 | }
47 |
48 | INLINE vec2 invertedVec2(vec2 in) {
49 | vec2 out;
50 |
51 | out.x = -in.x;
52 | out.y = -in.y;
53 |
54 | return out;
55 | }
56 |
57 | INLINE vec2 oneOverVec2(vec2 v) {
58 | vec2 out;
59 |
60 | out.x = 1.0f / v.x;
61 | out.y = 1.0f / v.y;
62 |
63 | return out;
64 | }
65 |
66 | INLINE vec2 approachVec2(vec2 src, vec2 trg, f32 diff) {
67 | vec2 out;
68 |
69 | out.x = approach(src.x, trg.x, diff);
70 | out.y = approach(src.y, trg.y, diff);
71 |
72 | return out;
73 | }
74 |
75 | INLINE bool nonZeroVec2(vec2 v) {
76 | return v.x != 0 ||
77 | v.y != 0;
78 | }
79 |
80 | INLINE vec2 minVec2(vec2 a, vec2 b) {
81 | vec2 out;
82 |
83 | out.x = a.x < b.x ? a.x : b.x;
84 | out.y = a.y < b.y ? a.y : b.y;
85 |
86 | return out;
87 | }
88 |
89 | INLINE vec2 maxVec2(vec2 a, vec2 b) {
90 | vec2 out;
91 |
92 | out.x = a.x > b.x ? a.x : b.x;
93 | out.y = a.y > b.y ? a.y : b.y;
94 |
95 | return out;
96 | }
97 |
98 | INLINE f32 minCoordVec2(vec2 v) {
99 | f32 out = v.x;
100 | if (v.y < out) out = v.y;
101 | return out;
102 | }
103 |
104 | INLINE f32 maxCoordVec2(vec2 v) {
105 | f32 out = v.x;
106 | if (v.y > out) out = v.y;
107 | return out;
108 | }
109 |
110 | INLINE vec2 subVec2(vec2 a, vec2 b) {
111 | vec2 out;
112 |
113 | out.x = a.x - b.x;
114 | out.y = a.y - b.y;
115 |
116 | return out;
117 | }
118 |
119 | INLINE vec2 addVec2(vec2 a, vec2 b) {
120 | vec2 out;
121 |
122 | out.x = a.x + b.x;
123 | out.y = a.y + b.y;
124 |
125 | return out;
126 | }
127 |
128 | INLINE vec2 mulVec2(vec2 a, vec2 b) {
129 | vec2 out;
130 |
131 | out.x = a.x * b.x;
132 | out.y = a.y * b.y;
133 |
134 | return out;
135 | }
136 |
137 | INLINE vec2 mulAddVec2(vec2 v, vec2 factors, vec2 to_be_added) {
138 | vec2 out;
139 |
140 | out.x = fast_mul_add(v.x, factors.x, to_be_added.x);
141 | out.y = fast_mul_add(v.y, factors.y, to_be_added.y);
142 |
143 | return out;
144 | }
145 |
146 | INLINE vec2 scaleAddVec2(vec2 v, f32 factor, vec2 to_be_added) {
147 | vec2 out;
148 |
149 | out.x = fast_mul_add(v.x, factor, to_be_added.x);
150 | out.y = fast_mul_add(v.y, factor, to_be_added.y);
151 |
152 | return out;
153 | }
154 |
155 | INLINE vec2 scaleVec2(vec2 a, f32 factor) {
156 | vec2 out;
157 |
158 | out.x = a.x * factor;
159 | out.y = a.y * factor;
160 |
161 | return out;
162 | }
163 |
164 | INLINE vec2 mulVec2Mat2(vec2 in, mat2 m) {
165 | vec2 out;
166 |
167 | out.x = in.x * m.X.x + in.y * m.Y.x;
168 | out.y = in.x * m.X.y + in.y * m.Y.y;
169 |
170 | return out;
171 | }
172 |
173 | INLINE f32 dotVec2(vec2 a, vec2 b) {
174 | return (
175 | (a.x * b.x) +
176 | (a.y * b.y)
177 | );
178 | }
179 |
180 | INLINE f32 squaredLengthVec2(vec2 v) {
181 | return (
182 | (v.x * v.x) +
183 | (v.y * v.y)
184 | );
185 | }
186 |
187 | INLINE f32 lengthVec2(vec2 v) {
188 | return sqrtf(squaredLengthVec2(v));
189 | }
190 |
191 | INLINE vec2 normVec2(vec2 v) {
192 | return scaleVec2(v, 1.0f / lengthVec2(v));
193 | }
194 |
195 | INLINE f32 DotVec2(vec2 a, vec2 b) { return clampValue(dotVec2(a, b)); }
196 |
197 | INLINE mat2 outerVec2(vec2 a, vec2 b) {
198 | mat2 out;
199 |
200 | out.X = scaleVec2(a, b.x);
201 | out.Y = scaleVec2(a, b.y);
202 |
203 | return out;
204 | }
205 |
206 | INLINE vec2 reflectVec2(vec2 V, vec2 N) {
207 | vec2 out = scaleVec2(N, -2 * dotVec2(N, V));
208 | out = addVec2(out, V);
209 | return out;
210 | }
--------------------------------------------------------------------------------
/src/SlimRaster/math/vec3.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../core/base.h"
4 |
5 | INLINE bool isEqualVec3(vec3 a, vec3 b) {
6 | return a.x == b.x && a.y == b.y && a.z == b.z;
7 | }
8 |
9 | INLINE vec3 clampVec3ToZero(vec3 v) {
10 | v.x = v.x > 0.0f ? v.x : 0.0f;
11 | v.y = v.y > 0.0f ? v.y : 0.0f;
12 | v.z = v.z > 0.0f ? v.z : 0.0f;
13 | return v;
14 | }
15 |
16 | INLINE vec3 clampVec3ToUpper(vec3 v, vec3 upper) {
17 | v.x = v.x < upper.x ? v.x : upper.x;
18 | v.y = v.y < upper.y ? v.y : upper.y;
19 | v.z = v.z < upper.z ? v.z : upper.z;
20 | return v;
21 | }
22 |
23 | INLINE vec3 clampVec3(vec3 v) {
24 | v.x = v.x > 0.0f ? v.x : 0.0f;
25 | v.y = v.y > 0.0f ? v.y : 0.0f;
26 | v.z = v.z > 0.0f ? v.z : 0.0f;
27 |
28 | v.x = v.x < 1.0f ? v.x : 1.0f;
29 | v.y = v.y < 1.0f ? v.y : 1.0f;
30 | v.z = v.z < 1.0f ? v.z : 1.0f;
31 |
32 | return v;
33 | }
34 |
35 | INLINE vec3 clampVec3To(vec3 v, const f32 min_value, const f32 max_value) {
36 | v.x = v.x > min_value ? v.x : min_value;
37 | v.y = v.y > min_value ? v.y : min_value;
38 | v.z = v.z > min_value ? v.z : min_value;
39 |
40 | v.x = v.x < max_value ? v.x : max_value;
41 | v.y = v.y < max_value ? v.y : max_value;
42 | v.z = v.z < max_value ? v.z : max_value;
43 |
44 | return v;
45 | }
46 |
47 | INLINE vec3 getVec3Of(f32 value) {
48 | vec3 out;
49 |
50 | out.x = out.y = out.z = value;
51 |
52 | return out;
53 | }
54 |
55 | INLINE vec3 invertedVec3(vec3 in) {
56 | vec3 out;
57 |
58 | out.x = -in.x;
59 | out.y = -in.y;
60 | out.z = -in.z;
61 |
62 | return out;
63 | }
64 |
65 | INLINE vec3 oneOverVec3(vec3 v) {
66 | vec3 out;
67 |
68 | out.x = 1.0f / v.x;
69 | out.y = 1.0f / v.y;
70 | out.z = 1.0f / v.z;
71 |
72 | return out;
73 | }
74 |
75 | INLINE vec3 approachVec3(vec3 src, vec3 trg, f32 diff) {
76 | vec3 out;
77 |
78 | out.x = approach(src.x, trg.x, diff);
79 | out.y = approach(src.y, trg.y, diff);
80 | out.z = approach(src.z, trg.z, diff);
81 |
82 | return out;
83 | }
84 |
85 | INLINE bool nonZeroVec3(vec3 v) {
86 | return v.x != 0 ||
87 | v.y != 0 ||
88 | v.z != 0;
89 | }
90 |
91 | INLINE vec3 minVec3(vec3 a, vec3 b) {
92 | vec3 out;
93 |
94 | out.x = a.x < b.x ? a.x : b.x;
95 | out.y = a.y < b.y ? a.y : b.y;
96 | out.z = a.z < b.z ? a.z : b.z;
97 |
98 | return out;
99 | }
100 |
101 | INLINE vec3 maxVec3(vec3 a, vec3 b) {
102 | vec3 out;
103 |
104 | out.x = a.x > b.x ? a.x : b.x;
105 | out.y = a.y > b.y ? a.y : b.y;
106 | out.z = a.z > b.z ? a.z : b.z;
107 |
108 | return out;
109 | }
110 |
111 | INLINE f32 minCoordVec3(vec3 v) {
112 | f32 out = v.x;
113 | if (v.y < out) out = v.y;
114 | if (v.z < out) out = v.z;
115 | return out;
116 | }
117 |
118 | INLINE f32 maxCoordVec3(vec3 v) {
119 | f32 out = v.x;
120 | if (v.y > out) out = v.y;
121 | if (v.z > out) out = v.z;
122 | return out;
123 | }
124 |
125 | INLINE vec3 setPointOnUnitSphere(f32 s, f32 t) {
126 | vec3 out;
127 |
128 | f32 t_squared = t * t;
129 | f32 s_squared = s * s;
130 | f32 factor = 1 / ( t_squared + s_squared + 1);
131 |
132 | out.x = 2*s * factor;
133 | out.y = 2*t * factor;
134 | out.z = (t_squared + s_squared - 1) * t_squared;
135 |
136 | return out;
137 | }
138 |
139 | INLINE vec3 subVec3(vec3 a, vec3 b) {
140 | vec3 out;
141 |
142 | out.x = a.x - b.x;
143 | out.y = a.y - b.y;
144 | out.z = a.z - b.z;
145 |
146 | return out;
147 | }
148 |
149 | INLINE vec3 addVec3(vec3 a, vec3 b) {
150 | vec3 out;
151 |
152 | out.x = a.x + b.x;
153 | out.y = a.y + b.y;
154 | out.z = a.z + b.z;
155 |
156 | return out;
157 | }
158 |
159 | INLINE vec3 mulVec3(vec3 a, vec3 b) {
160 | vec3 out;
161 |
162 | out.x = a.x * b.x;
163 | out.y = a.y * b.y;
164 | out.z = a.z * b.z;
165 |
166 | return out;
167 | }
168 |
169 | INLINE vec3 mulAddVec3(vec3 v, vec3 factors, vec3 to_be_added) {
170 | vec3 out;
171 |
172 | out.x = fast_mul_add(v.x, factors.x, to_be_added.x);
173 | out.y = fast_mul_add(v.y, factors.y, to_be_added.y);
174 | out.z = fast_mul_add(v.z, factors.z, to_be_added.z);
175 |
176 | return out;
177 | }
178 |
179 | INLINE vec3 scaleAddVec3(vec3 v, f32 factor, vec3 to_be_added) {
180 | vec3 out;
181 |
182 | out.x = fast_mul_add(v.x, factor, to_be_added.x);
183 | out.y = fast_mul_add(v.y, factor, to_be_added.y);
184 | out.z = fast_mul_add(v.z, factor, to_be_added.z);
185 |
186 | return out;
187 | }
188 |
189 | INLINE vec3 scaleVec3(vec3 a, f32 factor) {
190 | vec3 out;
191 |
192 | out.x = a.x * factor;
193 | out.y = a.y * factor;
194 | out.z = a.z * factor;
195 |
196 | return out;
197 | }
198 |
199 | INLINE vec3 mulVec3Mat3(vec3 in, mat3 m) {
200 | vec3 out;
201 |
202 | out.x = in.x * m.X.x + in.y * m.Y.x + in.z * m.Z.x;
203 | out.y = in.x * m.X.y + in.y * m.Y.y + in.z * m.Z.y;
204 | out.z = in.x * m.X.z + in.y * m.Y.z + in.z * m.Z.z;
205 |
206 | return out;
207 | }
208 |
209 | INLINE f32 dotVec3(vec3 a, vec3 b) {
210 | return (
211 | (a.x * b.x) +
212 | (a.y * b.y) +
213 | (a.z * b.z)
214 | );
215 | }
216 |
217 | INLINE vec3 crossVec3(vec3 a, vec3 b) {
218 | vec3 out;
219 |
220 | out.x = (a.y * b.z) - (a.z * b.y);
221 | out.y = (a.z * b.x) - (a.x * b.z);
222 | out.z = (a.x * b.y) - (a.y * b.x);
223 |
224 | return out;
225 | }
226 |
227 | INLINE f32 squaredLengthVec3(vec3 v) {
228 | return (
229 | (v.x * v.x) +
230 | (v.y * v.y) +
231 | (v.z * v.z)
232 | );
233 | }
234 |
235 | INLINE f32 lengthVec3(vec3 v) {
236 | return sqrtf(squaredLengthVec3(v));
237 | }
238 |
239 | INLINE vec3 normVec3(vec3 v) {
240 | return scaleVec3(v, 1.0f / lengthVec3(v));
241 | }
242 |
243 | INLINE f32 DotVec3(vec3 a, vec3 b) { return clampValue(dotVec3(a, b)); }
244 |
245 | INLINE mat3 outerVec3(vec3 a, vec3 b) {
246 | mat3 out;
247 |
248 | out.X = scaleVec3(a, b.x);
249 | out.Y = scaleVec3(a, b.y);
250 | out.Z = scaleVec3(a, b.z);
251 |
252 | return out;
253 | }
254 |
255 | INLINE vec3 reflectVec3(vec3 V, vec3 N) {
256 | vec3 out = scaleVec3(N, -2 * dotVec3(N, V));
257 | out = addVec3(out, V);
258 | return out;
259 | }
260 |
261 | INLINE vec3 lerpVec3(vec3 from, vec3 to, f32 by) {
262 | return scaleAddVec3(subVec3(to, from), by, from);
263 | }
--------------------------------------------------------------------------------
/src/SlimRaster/math/vec4.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../core/base.h"
4 |
5 | INLINE vec4 getVec4Of(f32 value) {
6 | vec4 out;
7 |
8 | out.x = out.y = out.z = out.w = value;
9 |
10 | return out;
11 | }
12 |
13 | INLINE vec4 invertedVec4(vec4 in) {
14 | vec4 out;
15 |
16 | out.x = -in.x;
17 | out.y = -in.y;
18 | out.z = -in.z;
19 | out.w = -in.w;
20 |
21 | return out;
22 | }
23 |
24 | INLINE vec4 approachVec4(vec4 src, vec4 trg, f32 diff) {
25 | vec4 out;
26 |
27 | out.x = approach(src.x, trg.x, diff);
28 | out.y = approach(src.y, trg.y, diff);
29 | out.z = approach(src.z, trg.z, diff);
30 | out.w = approach(src.w, trg.w, diff);
31 |
32 | return out;
33 | }
34 |
35 | INLINE bool nonZeroVec4(vec4 v) {
36 | return v.x != 0 ||
37 | v.y != 0 ||
38 | v.z != 0 ||
39 | v.w != 0;
40 | }
41 |
42 | INLINE vec4 subVec4(vec4 a, vec4 b) {
43 | vec4 out;
44 |
45 | out.x = a.x - b.x;
46 | out.y = a.y - b.y;
47 | out.z = a.z - b.z;
48 | out.w = a.w - b.w;
49 |
50 | return out;
51 | }
52 |
53 | INLINE vec4 addVec4(vec4 a, vec4 b) {
54 | vec4 out;
55 |
56 | out.x = a.x + b.x;
57 | out.y = a.y + b.y;
58 | out.z = a.z + b.z;
59 | out.w = a.w + b.w;
60 |
61 | return out;
62 | }
63 |
64 | INLINE vec4 mulVec4(vec4 a, vec4 b) {
65 | vec4 out;
66 |
67 | out.x = a.x * b.x;
68 | out.y = a.y * b.y;
69 | out.z = a.z * b.z;
70 | out.w = a.w * b.w;
71 |
72 | return out;
73 | }
74 |
75 | INLINE vec4 scaleVec4(vec4 a, f32 factor) {
76 | vec4 out;
77 |
78 | out.x = a.x * factor;
79 | out.y = a.y * factor;
80 | out.z = a.z * factor;
81 | out.w = a.w * factor;
82 |
83 | return out;
84 | }
85 | INLINE vec4 scaleAddVec4(vec4 v, f32 factor, vec4 to_be_added) {
86 | vec4 out;
87 |
88 | out.x = fast_mul_add(v.x, factor, to_be_added.x);
89 | out.y = fast_mul_add(v.y, factor, to_be_added.y);
90 | out.z = fast_mul_add(v.z, factor, to_be_added.z);
91 | out.w = fast_mul_add(v.w, factor, to_be_added.w);
92 |
93 | return out;
94 | }
95 |
96 | INLINE vec4 mulVec4Mat4(vec4 in, mat4 m) {
97 | vec4 out;
98 |
99 | out.x = in.x * m.X.x + in.y * m.Y.x + in.z * m.Z.x + in.w * m.W.x;
100 | out.y = in.x * m.X.y + in.y * m.Y.y + in.z * m.Z.y + in.w * m.W.y;
101 | out.z = in.x * m.X.z + in.y * m.Y.z + in.z * m.Z.z + in.w * m.W.z;
102 | out.w = in.x * m.X.w + in.y * m.Y.w + in.z * m.Z.w + in.w * m.W.w;
103 |
104 | return out;
105 | }
106 |
107 | INLINE f32 dotVec4(vec4 a, vec4 b) {
108 | return (
109 | (a.x * b.x) +
110 | (a.y * b.y) +
111 | (a.z * b.z) +
112 | (a.w * b.w)
113 | );
114 | }
115 |
116 | INLINE f32 squaredLengthVec4(vec4 v) {
117 | return (
118 | (v.x * v.x) +
119 | (v.y * v.y) +
120 | (v.z * v.z) +
121 | (v.w * v.w)
122 | );
123 | }
124 |
125 | INLINE f32 lengthVec4(vec4 v) {
126 | return sqrtf(squaredLengthVec4(v));
127 | }
128 |
129 | INLINE vec4 norm4(vec4 v) {
130 | return scaleVec4(v, 1.0f / lengthVec4(v));
131 | }
132 |
133 | INLINE f32 mulVec3Mat4(vec3 in, f32 w, mat4 M, vec3 *out) {
134 | vec4 v4 = mulVec4Mat4(Vec4fromVec3(in, w), M);
135 | *out = Vec3fromVec4(v4);
136 | return v4.w;
137 | }
138 |
139 | INLINE vec4 lerpVec4(vec4 from, vec4 to, f32 by) {
140 | return scaleAddVec4(subVec4(to, from), by, from);
141 | }
--------------------------------------------------------------------------------
/src/SlimRaster/platforms/win32.h:
--------------------------------------------------------------------------------
1 | #define WIN32_LEAN_AND_MEAN
2 | #include
3 |
4 | #ifndef NDEBUG
5 | #include
6 | #include
7 | #include
8 |
9 | void DisplayError(LPTSTR lpszFunction) {
10 | LPVOID lpMsgBuf;
11 | LPVOID lpDisplayBuf;
12 | unsigned int last_error = GetLastError();
13 |
14 | FormatMessage(
15 | FORMAT_MESSAGE_ALLOCATE_BUFFER |
16 | FORMAT_MESSAGE_FROM_SYSTEM |
17 | FORMAT_MESSAGE_IGNORE_INSERTS,
18 | null, last_error,
19 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
20 | (LPTSTR) &lpMsgBuf, 0, null);
21 |
22 | lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
23 |
24 | if (FAILED( StringCchPrintf((LPTSTR)lpDisplayBuf, LocalSize(lpDisplayBuf) / sizeof(TCHAR),
25 | TEXT("%s failed with error code %d as follows:\n%s"), lpszFunction, last_error, lpMsgBuf)))
26 | printf("FATAL ERROR: Unable to output error code.\n");
27 |
28 | _tprintf(TEXT((LPTSTR)"ERROR: %s\n"), (LPCTSTR)lpDisplayBuf);
29 |
30 | LocalFree(lpMsgBuf);
31 | LocalFree(lpDisplayBuf);
32 | }
33 | #endif
34 |
35 | #define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
36 | #define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
37 |
38 | WNDCLASSA window_class;
39 | HWND window;
40 | HDC win_dc;
41 | BITMAPINFO info;
42 | RECT win_rect;
43 | RAWINPUT raw_inputs;
44 | HRAWINPUT raw_input_handle;
45 | RAWINPUTDEVICE raw_input_device;
46 | UINT raw_input_size;
47 | PUINT raw_input_size_ptr = (PUINT)(&raw_input_size);
48 | UINT raw_input_header_size = sizeof(RAWINPUTHEADER);
49 |
50 | u64 Win32_ticksPerSecond;
51 | LARGE_INTEGER performance_counter;
52 |
53 | void Win32_setWindowTitle(char* str) { SetWindowTextA(window, str); }
54 | void Win32_setCursorVisibility(bool on) { ShowCursor(on); }
55 | void Win32_setWindowCapture(bool on) { if (on) SetCapture(window); else ReleaseCapture(); }
56 | u64 Win32_getTicks() {
57 | QueryPerformanceCounter(&performance_counter);
58 | return (u64)performance_counter.QuadPart;
59 | }
60 | void* Win32_getMemory(u64 size) {
61 | return VirtualAlloc((LPVOID)MEMORY_BASE, (SIZE_T)size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
62 | }
63 |
64 | inline UINT getRawInput(LPVOID data) {
65 | return GetRawInputData(raw_input_handle, RID_INPUT, data, raw_input_size_ptr, raw_input_header_size);
66 | }
67 | inline bool hasRawInput() {
68 | return getRawInput(0) == 0 && raw_input_size != 0;
69 | }
70 | inline bool hasRawMouseInput(LPARAM lParam) {
71 | raw_input_handle = (HRAWINPUT)(lParam);
72 | return (
73 | hasRawInput() &&
74 | getRawInput((LPVOID)&raw_inputs) == raw_input_size &&
75 | raw_inputs.header.dwType == RIM_TYPEMOUSE
76 | );
77 | }
78 |
79 | void Win32_closeFile(void *handle) { CloseHandle(handle); }
80 | void* Win32_openFileForReading(const char* path) {
81 | HANDLE handle = CreateFile(path, // file to open
82 | GENERIC_READ, // open for reading
83 | FILE_SHARE_READ, // share for reading
84 | null, // default security
85 | OPEN_EXISTING, // existing file only
86 | FILE_ATTRIBUTE_NORMAL, // normal file
87 | null); // no attr. template
88 | #ifndef NDEBUG
89 | if (handle == INVALID_HANDLE_VALUE) {
90 | DisplayError(TEXT((LPTSTR)"CreateFile"));
91 | _tprintf(TEXT("Terminal failure: unable to open file \"%s\" for read.\n"), path);
92 | return null;
93 | }
94 | #endif
95 | return handle;
96 | }
97 | void* Win32_openFileForWriting(const char* path) {
98 | HANDLE handle = CreateFile(path, // file to open
99 | GENERIC_WRITE, // open for writing
100 | 0, // do not share
101 | null, // default security
102 | OPEN_ALWAYS, // create new or open existing
103 | FILE_ATTRIBUTE_NORMAL, // normal file
104 | null);
105 | #ifndef NDEBUG
106 | if (handle == INVALID_HANDLE_VALUE) {
107 | DisplayError(TEXT((LPTSTR)"CreateFile"));
108 | _tprintf(TEXT("Terminal failure: unable to open file \"%s\" for write.\n"), path);
109 | return null;
110 | }
111 | #endif
112 | return handle;
113 | }
114 | bool Win32_readFromFile(LPVOID out, DWORD size, HANDLE handle) {
115 | DWORD bytes_read = 0;
116 | BOOL result = ReadFile(handle, out, size, &bytes_read, null);
117 | #ifndef NDEBUG
118 | if (result == FALSE) {
119 | DisplayError(TEXT((LPTSTR)"ReadFile"));
120 | printf("Terminal failure: Unable to read from file.\n GetLastError=%08x\n", (unsigned int)GetLastError());
121 | CloseHandle(handle);
122 | }
123 | #endif
124 | return result != FALSE;
125 | }
126 |
127 | bool Win32_writeToFile(LPVOID out, DWORD size, HANDLE handle) {
128 | DWORD bytes_written = 0;
129 | BOOL result = WriteFile(handle, out, size, &bytes_written, null);
130 | #ifndef NDEBUG
131 | if (result == FALSE) {
132 | DisplayError(TEXT((LPTSTR)"WriteFile"));
133 | printf("Terminal failure: Unable to write from file.\n GetLastError=%08x\n", (unsigned int)GetLastError());
134 | CloseHandle(handle);
135 | }
136 | #endif
137 | return result != FALSE;
138 | }
139 |
140 | LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
141 | switch (message) {
142 | case WM_DESTROY:
143 | app->is_running = false;
144 | PostQuitMessage(0);
145 | break;
146 |
147 | case WM_SIZE:
148 | GetClientRect(window, &win_rect);
149 |
150 | info.bmiHeader.biWidth = win_rect.right - win_rect.left;
151 | info.bmiHeader.biHeight = win_rect.top - win_rect.bottom;
152 |
153 | _windowResize((u16)info.bmiHeader.biWidth, (u16)-info.bmiHeader.biHeight);
154 |
155 | break;
156 |
157 | case WM_PAINT:
158 | SetDIBitsToDevice(win_dc,
159 | 0, 0, app->viewport.dimensions.width, app->viewport.dimensions.height,
160 | 0, 0, 0, app->viewport.dimensions.height,
161 | app->window_content, &info, DIB_RGB_COLORS);
162 |
163 | ValidateRgn(window, null);
164 | break;
165 |
166 | case WM_SYSKEYDOWN:
167 | case WM_KEYDOWN:
168 | _keyChanged((u8)wParam, true);
169 | break;
170 |
171 | case WM_SYSKEYUP:
172 | case WM_KEYUP: _keyChanged((u8)wParam, false); break;
173 |
174 | case WM_MBUTTONUP: _mouseButtonUp( &app->controls.mouse.middle_button, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); break;
175 | case WM_MBUTTONDOWN: _mouseButtonDown(&app->controls.mouse.middle_button, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); break;
176 | case WM_LBUTTONDOWN: _mouseButtonDown(&app->controls.mouse.left_button, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); break;
177 | case WM_LBUTTONUP : _mouseButtonUp( &app->controls.mouse.left_button, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); break;
178 | case WM_RBUTTONDOWN: _mouseButtonDown(&app->controls.mouse.right_button, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); break;
179 | case WM_RBUTTONUP: _mouseButtonUp( &app->controls.mouse.right_button, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); break;
180 | case WM_LBUTTONDBLCLK: _mouseButtonDoubleClicked(&app->controls.mouse.left_button, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); break;
181 | case WM_RBUTTONDBLCLK: _mouseButtonDoubleClicked(&app->controls.mouse.right_button, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); break;
182 | case WM_MBUTTONDBLCLK: _mouseButtonDoubleClicked(&app->controls.mouse.middle_button, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); break;
183 | case WM_MOUSEWHEEL: _mouseWheelScrolled((f32)(GET_WHEEL_DELTA_WPARAM(wParam)) / (f32)(WHEEL_DELTA)); break;
184 | case WM_MOUSEMOVE:
185 | _mouseMovementSet(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
186 | _mousePositionSet(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
187 | break;
188 |
189 | case WM_INPUT:
190 | if ((hasRawMouseInput(lParam)) && (
191 | raw_inputs.data.mouse.lLastX != 0 ||
192 | raw_inputs.data.mouse.lLastY != 0))
193 | _mouseRawMovementSet(
194 | raw_inputs.data.mouse.lLastX,
195 | raw_inputs.data.mouse.lLastY
196 | );
197 |
198 | default:
199 | return DefWindowProc(hWnd, message, wParam, lParam);
200 | }
201 |
202 | return 0;
203 | }
204 |
205 | int APIENTRY WinMain(HINSTANCE hInstance,
206 | HINSTANCE hPrevInstance,
207 | LPSTR lpCmdLine,
208 | int nCmdShow) {
209 |
210 | void* app_memory = GlobalAlloc(GPTR, sizeof(App));
211 | if (!app_memory)
212 | return -1;
213 |
214 | app = (App*)app_memory;
215 |
216 | void* window_content_memory = GlobalAlloc(GPTR, sizeof(u32) * MAX_WIDTH * MAX_HEIGHT);
217 | if (!window_content_memory)
218 | return -1;
219 |
220 | LARGE_INTEGER performance_frequency;
221 | QueryPerformanceFrequency(&performance_frequency);
222 | Win32_ticksPerSecond = (u64)performance_frequency.QuadPart;
223 |
224 | app->controls.key_map.space = VK_SPACE;
225 | app->controls.key_map.shift = VK_SHIFT;
226 | app->controls.key_map.ctrl = VK_CONTROL;
227 | app->controls.key_map.alt = VK_MENU;
228 | app->controls.key_map.tab = VK_TAB;
229 |
230 | app->platform.ticks_per_second = Win32_ticksPerSecond;
231 | app->platform.getTicks = Win32_getTicks;
232 | app->platform.getMemory = Win32_getMemory;
233 | app->platform.setWindowTitle = Win32_setWindowTitle;
234 | app->platform.setWindowCapture = Win32_setWindowCapture;
235 | app->platform.setCursorVisibility = Win32_setCursorVisibility;
236 | app->platform.closeFile = Win32_closeFile;
237 | app->platform.openFileForReading = Win32_openFileForReading;
238 | app->platform.openFileForWriting = Win32_openFileForWriting;
239 | app->platform.readFromFile = Win32_readFromFile;
240 | app->platform.writeToFile = Win32_writeToFile;
241 |
242 | Defaults defaults;
243 | _initApp(&defaults, (u32*)window_content_memory);
244 |
245 | info.bmiHeader.biSize = sizeof(info.bmiHeader);
246 | info.bmiHeader.biCompression = BI_RGB;
247 | info.bmiHeader.biBitCount = 32;
248 | info.bmiHeader.biPlanes = 1;
249 |
250 | window_class.lpszClassName = "RnDer";
251 | window_class.hInstance = hInstance;
252 | window_class.lpfnWndProc = WndProc;
253 | window_class.style = CS_OWNDC|CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
254 | window_class.hCursor = LoadCursorA(null, IDC_ARROW);
255 |
256 | if (!RegisterClassA(&window_class)) return -1;
257 |
258 | win_rect.top = 0;
259 | win_rect.left = 0;
260 | win_rect.right = defaults.width;
261 | win_rect.bottom = defaults.height;
262 | AdjustWindowRect(&win_rect, WS_OVERLAPPEDWINDOW, false);
263 |
264 | window = CreateWindowA(
265 | window_class.lpszClassName,
266 | defaults.title,
267 | WS_OVERLAPPEDWINDOW,
268 |
269 | CW_USEDEFAULT,
270 | CW_USEDEFAULT,
271 | win_rect.right - win_rect.left,
272 | win_rect.bottom - win_rect.top,
273 |
274 | null,
275 | null,
276 | hInstance,
277 | null
278 | );
279 | if (!window)
280 | return -1;
281 |
282 | raw_input_device.usUsagePage = 0x01;
283 | raw_input_device.usUsage = 0x02;
284 | if (!RegisterRawInputDevices(&raw_input_device, 1, sizeof(raw_input_device)))
285 | return -1;
286 |
287 | win_dc = GetDC(window);
288 |
289 | SetICMMode(win_dc, ICM_OFF);
290 |
291 |
292 |
293 | ShowWindow(window, nCmdShow);
294 |
295 | MSG message;
296 | while (app->is_running) {
297 | while (PeekMessageA(&message, null, 0, 0, PM_REMOVE)) {
298 | TranslateMessage(&message);
299 | DispatchMessageA(&message);
300 | }
301 | _windowRedraw();
302 | InvalidateRgn(window, null, false);
303 | }
304 |
305 | return 0;
306 | }
--------------------------------------------------------------------------------
/src/SlimRaster/renderer/common.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../math/vec3.h"
4 | #include "../math/quat.h"
5 |
6 | INLINE f32 toneMappedBaked(f32 LinearColor) {
7 | f32 x = LinearColor - 0.004f;
8 | if (x < 0.0f) x = 0.0f;
9 | f32 x2_times_sholder_strength = x * x * 6.2f;
10 | return (x2_times_sholder_strength + x*0.5f)/(x2_times_sholder_strength + x*1.7f + 0.06f);
11 | }
12 |
13 | INLINE vec3 reflectWithDot(vec3 V, vec3 N, f32 NdotV) {
14 | return scaleAddVec3(N, -2 * NdotV, V);
15 | }
16 |
17 | INLINE vec3 shadePointOnSurface(Shaded *shaded, f32 NdotL) {
18 | if (shaded->has.specular) {
19 | vec3 half_vector, color;
20 | if (shaded->uses.blinn) {
21 | half_vector = normVec3(subVec3(shaded->light_direction, shaded->viewing_direction));
22 | color = scaleVec3(shaded->material->specular, powf(DotVec3(shaded->normal, half_vector), 16.0f * shaded->material->shininess));
23 | } else
24 | color = scaleVec3(shaded->material->specular, powf(DotVec3(shaded->reflected_direction, shaded->light_direction), 4.0f * shaded->material->shininess));
25 |
26 | if (shaded->has.diffuse)
27 | return scaleAddVec3(shaded->diffuse, clampValue(NdotL), color);
28 | else
29 | return color;
30 | } else
31 | return scaleVec3(shaded->diffuse, clampValue(NdotL));
32 | }
--------------------------------------------------------------------------------
/src/SlimRaster/renderer/mesh_shaders.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../math/vec4.h"
4 |
5 |
6 | u8 shadeMesh(Mesh *mesh, Rasterizer *rasterizer) {
7 |
8 | // Transform the mesh's vertex positions into clip space and world space:
9 | vec4 world_space;
10 | for (u32 i = 0; i < mesh->vertex_count; i++) {
11 | world_space = Vec4fromVec3(mesh->vertex_positions[i], 1.0f);
12 | world_space = mulVec4Mat4(world_space, rasterizer->model_to_world);
13 | rasterizer->clip_space_vertex_positions[i] = mulVec4Mat4(world_space, rasterizer->world_to_clip);
14 | rasterizer->world_space_vertex_positions[i] = world_space.v3;
15 | }
16 |
17 | // Transform the mesh's vertex normals into world space:
18 | for (u32 i = 0; i < mesh->normals_count; i++) {
19 | world_space = Vec4fromVec3(mesh->vertex_normals[i], 0.0f);
20 | world_space = mulVec4Mat4(world_space, rasterizer->model_to_world_inverted_transposed);
21 | rasterizer->world_space_vertex_normals[i] = world_space.v3;
22 | }
23 |
24 | return INSIDE;
25 | }
26 |
27 |
--------------------------------------------------------------------------------
/src/SlimRaster/renderer/pixel_shaders.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../math/vec3.h"
4 | #include "../scene/texture.h"
5 | #include "./common.h"
6 |
7 |
8 | INLINE vec3 sampleNormal(Texture *texture, vec2 uv, vec2 dUV) {
9 | vec3 normal = sampleTexture(texture, uv, dUV).v3;
10 | f32 y = normal.z;
11 | normal.z = normal.y;
12 | normal.y = y;
13 | return normVec3(scaleAddVec3(normal, 2.0f, getVec3Of(-1.0f)));
14 | }
15 | INLINE quat getNormalRotation(vec3 normal, f32 magnitude) {
16 | quat q;
17 | normal = scaleVec3(normal, 0.25f);
18 | q.axis.x = normal.z;
19 | q.axis.y = 0;
20 | q.axis.z = normal.x;
21 | q.amount = normal.y / magnitude;
22 | return normQuat(q);
23 | }
24 |
25 | INLINE u8 getCheckerBoardPixelValueByUV(vec2 UV, f32 half_step_count) {
26 | f32 s = UV.u * half_step_count;
27 | f32 t = UV.v * half_step_count;
28 | s -= floorf(s);
29 | t -= floorf(t);
30 | return (s > 0.5f ? (u8)1 : (u8)0) ^ (t < 0.5f ? (u8)1 : (u8)0);
31 | }
32 |
33 | void shadePixelTextured(PixelShaderInputs *inputs, Scene *scene, Shaded *shaded, PixelShaderOutputs *outputs) {
34 | outputs->color = sampleTexture(scene->textures + shaded->material->texture_ids[0], inputs->UV, inputs->dUV).v3;
35 | }
36 |
37 | void shadePixelDepth(PixelShaderInputs *inputs, Scene *scene, Shaded *shaded, PixelShaderOutputs *outputs) {
38 | outputs->color = getVec3Of(inputs->depth > 10 ? 1 : inputs->depth * 0.1f);
39 | }
40 |
41 | void shadePixelUV(PixelShaderInputs *inputs, Scene *scene, Shaded *shaded, PixelShaderOutputs *outputs) {
42 | outputs->color.v2 = inputs->UV;
43 | }
44 |
45 | void shadePixelPosition(PixelShaderInputs *inputs, Scene *scene, Shaded *shaded, PixelShaderOutputs *outputs) {
46 | outputs->color = scaleVec3(addVec3(shaded->position, getVec3Of(2.0f)), 0.5f);
47 | }
48 |
49 | void shadePixelNormal(PixelShaderInputs *inputs, Scene *scene, Shaded *shaded, PixelShaderOutputs *outputs) {
50 | outputs->color = scaleAddVec3(shaded->normal, 0.5f, getVec3Of(0.5f));
51 | }
52 |
53 | void shadePixelCheckerboard(PixelShaderInputs *inputs, Scene *scene, Shaded *shaded, PixelShaderOutputs *outputs) {
54 | outputs->color = getVec3Of(getCheckerBoardPixelValueByUV(inputs->UV, 4));
55 | }
56 |
57 | void shadePixelClassic(PixelShaderInputs *inputs, Scene *scene, Shaded *shaded, PixelShaderOutputs *outputs) {
58 | f32 NdotL, NdotRd, squared_distance;
59 | decodeMaterialSpec(shaded->material->flags, &shaded->has, &shaded->uses);
60 |
61 | shaded->diffuse = shaded->material->diffuse;
62 |
63 | if (shaded->material->texture_count) {
64 | Texture *texture = &scene->textures[shaded->material->texture_ids[0]];
65 | vec4 texture_sample = sampleTexture(texture, inputs->UV, inputs->dUV);
66 | shaded->diffuse = mulVec3(shaded->diffuse, texture_sample.v3);
67 | if (shaded->material->texture_count > 1) {
68 | texture = &scene->textures[shaded->material->texture_ids[1]];
69 | texture_sample.v3 = sampleNormal(texture, inputs->UV, inputs->dUV);
70 | if (shaded->material->normal_magnitude) {
71 | quat normal_rotation = getNormalRotation(texture_sample.v3, shaded->material->normal_magnitude);
72 | shaded->normal = mulVec3Quat(shaded->normal, normal_rotation);
73 | }
74 | }
75 | }
76 |
77 | outputs->color = scene->ambient_light.color;
78 | shaded->viewing_direction = normVec3(subVec3(shaded->position, shaded->viewing_origin));
79 | if (shaded->uses.phong) {
80 | NdotRd = DotVec3(shaded->normal, shaded->viewing_direction);
81 | shaded->reflected_direction = reflectWithDot(shaded->viewing_direction, shaded->normal, NdotRd);
82 | }
83 |
84 | Light *light = scene->lights;
85 | for (u32 i = 0; i < scene->settings.lights; i++, light++) {
86 | shaded->light_direction = subVec3(light->position_or_direction, shaded->position);
87 | squared_distance = squaredLengthVec3(shaded->light_direction);
88 | shaded->light_direction = scaleVec3(shaded->light_direction, 1.0f / sqrtf(squared_distance));
89 | NdotL = dotVec3(shaded->normal, shaded->light_direction);
90 | if (NdotL > 0)
91 | outputs->color = mulAddVec3(
92 | shadePointOnSurface(shaded, NdotL),
93 | scaleVec3(light->color, light->intensity / squared_distance),
94 | outputs->color);
95 | }
96 |
97 | outputs->color.x = toneMappedBaked(outputs->color.x);
98 | outputs->color.y = toneMappedBaked(outputs->color.y);
99 | outputs->color.z = toneMappedBaked(outputs->color.z);
100 | }
101 |
102 | void shadePixelClassicCheckerboard(PixelShaderInputs *inputs, Scene *scene, Shaded *shaded, PixelShaderOutputs *outputs) {
103 | shadePixelClassic(inputs, scene, shaded, outputs);
104 |
105 | if (!getCheckerBoardPixelValueByUV(inputs->UV, 4))
106 | outputs->color = scaleVec3(outputs->color, 0.5f);
107 | }
--------------------------------------------------------------------------------
/src/SlimRaster/scene/box.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../core/init.h"
4 | #include "../math/quat.h"
5 | #include "../math/vec3.h"
6 | #include "../shapes/edge.h"
7 | #include "./primitive.h"
8 |
9 | void transformBoxVerticesFromObjectToViewSpace(BoxVertices *vertices, BoxVertices *transformed_vertices, Primitive *primitive, Viewport *viewport) {
10 | vec3 position;
11 | for (u8 i = 0; i < BOX__VERTEX_COUNT; i++) {
12 | position = vertices->buffer[i];
13 | position = convertPositionToWorldSpace(position, primitive);
14 | position = subVec3( position, viewport->camera->transform.position);
15 | position = mulVec3Quat(position, viewport->camera->transform.rotation_inverted);
16 | transformed_vertices->buffer[i] = position;
17 | }
18 | }
19 |
20 | void drawBox(Box *box, u8 sides, Primitive *primitive, vec3 color, f32 opacity, u8 line_width, Viewport *viewport) {
21 | // Transform vertices positions from local-space to world-space and then to view-space:
22 | static BoxVertices vertices;
23 | transformBoxVerticesFromObjectToViewSpace(&box->vertices, &vertices, primitive, viewport);
24 |
25 | // Distribute transformed vertices positions to edges:
26 | static BoxEdges edges;
27 | setBoxEdgesFromVertices(&edges, &vertices);
28 |
29 | if (sides == BOX__ALL_SIDES) {
30 | for (u8 i = 0; i < BOX__EDGE_COUNT; i++)
31 | drawEdge(edges.buffer + i, color, opacity, line_width, viewport);
32 | } else {
33 | if (sides & Front | sides & Top ) drawEdge(&edges.sides.front_top, color, opacity, line_width, viewport);
34 | if (sides & Front | sides & Bottom) drawEdge(&edges.sides.front_bottom, color, opacity, line_width, viewport);
35 | if (sides & Front | sides & Left ) drawEdge(&edges.sides.front_left, color, opacity, line_width, viewport);
36 | if (sides & Front | sides & Right ) drawEdge(&edges.sides.front_right, color, opacity, line_width, viewport);
37 | if (sides & Back | sides & Top ) drawEdge(&edges.sides.back_top, color, opacity, line_width, viewport);
38 | if (sides & Back | sides & Bottom) drawEdge(&edges.sides.back_bottom, color, opacity, line_width, viewport);
39 | if (sides & Back | sides & Left ) drawEdge(&edges.sides.back_left, color, opacity, line_width, viewport);
40 | if (sides & Back | sides & Right ) drawEdge(&edges.sides.back_right, color, opacity, line_width, viewport);
41 | if (sides & Left | sides & Top ) drawEdge(&edges.sides.left_top, color, opacity, line_width, viewport);
42 | if (sides & Left | sides & Bottom) drawEdge(&edges.sides.left_bottom, color, opacity, line_width, viewport);
43 | if (sides & Right | sides & Top ) drawEdge(&edges.sides.right_top, color, opacity, line_width, viewport);
44 | if (sides & Right | sides & Bottom) drawEdge(&edges.sides.right_bottom, color, opacity, line_width, viewport);
45 | }
46 | }
47 |
48 | void drawCamera(Camera *camera, vec3 color, f32 opacity, u8 line_width, Viewport *viewport) {
49 | static Box box;
50 | static Primitive primitive;
51 | initBox(&box);
52 | primitive.flags = ALL_FLAGS;
53 | primitive.rotation = camera->transform.rotation;
54 | primitive.position = camera->transform.position;
55 | primitive.scale.x = primitive.scale.y = primitive.scale.z = 1;
56 | drawBox(&box, BOX__ALL_SIDES, &primitive, color, opacity, line_width, viewport);
57 | box.vertices.corners.back_bottom_left = scaleVec3(box.vertices.corners.back_bottom_left, 0.5f);
58 | box.vertices.corners.back_bottom_right = scaleVec3(box.vertices.corners.back_bottom_right, 0.5f);
59 | box.vertices.corners.back_top_left = scaleVec3(box.vertices.corners.back_top_left, 0.5f);
60 | box.vertices.corners.back_top_right = scaleVec3(box.vertices.corners.back_top_right, 0.5f);
61 | box.vertices.corners.front_bottom_left = scaleVec3(box.vertices.corners.front_bottom_left, 2);
62 | box.vertices.corners.front_bottom_right = scaleVec3(box.vertices.corners.front_bottom_right, 2);
63 | box.vertices.corners.front_top_left = scaleVec3(box.vertices.corners.front_top_left, 2);
64 | box.vertices.corners.front_top_right = scaleVec3(box.vertices.corners.front_top_right, 2);
65 | for (u8 i = 0; i < BOX__VERTEX_COUNT; i++)
66 | box.vertices.buffer[i].z += 1.5f;
67 | drawBox(&box, BOX__ALL_SIDES, &primitive, color, opacity, line_width, viewport);
68 | }
--------------------------------------------------------------------------------
/src/SlimRaster/scene/cube.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../core/base.h"
4 |
5 |
6 | #define CUBE__UV_COUNT 4
7 | #define CUBE__NORMAL_COUNT 6
8 | #define CUBE__VERTEX_COUNT 8
9 | #define CUBE__TRIANGLE_COUNT 12
10 |
11 | static const vec3 CUBE__VERTEX_POSITIONS[CUBE__VERTEX_COUNT] = {
12 | {-1, -1, -1},
13 | {1, -1, -1},
14 | {1, 1, -1},
15 | {-1, 1, -1},
16 | {-1, -1, 1},
17 | {1, -1, 1},
18 | {1, 1, 1},
19 | {-1, 1, 1}
20 | };
21 |
22 | static const TriangleVertexIndices CUBE__VERTEX_POSITION_INDICES[CUBE__TRIANGLE_COUNT] = {
23 | {0, 1, 2},
24 | {1, 5, 6},
25 | {5, 4, 7},
26 | {4, 0, 3},
27 | {3, 2, 6},
28 | {1, 0, 4},
29 | {0, 2, 3},
30 | {1, 6, 2},
31 | {5, 7, 6},
32 | {4, 3, 7},
33 | {3, 6, 7},
34 | {1, 4, 5}
35 | };
36 |
37 | static const vec3 CUBE__VERTEX_NORMALS[CUBE__NORMAL_COUNT] = {
38 | {0, 0, -1},
39 | {1, 0, 0},
40 | {0, 0, 1},
41 | {-1, 0, 0},
42 | {0, 1, 0},
43 | {0, -1, 0}
44 | };
45 | static const TriangleVertexIndices CUBE__VERTEX_NORMAL_INDICES[CUBE__TRIANGLE_COUNT] = {
46 | {0, 0, 0},
47 | {1, 1, 1},
48 | {2, 2, 2},
49 | {3, 3, 3},
50 | {4, 4, 4},
51 | {5, 5, 5},
52 | {0, 0, 0},
53 | {1, 1, 1},
54 | {2, 2, 2},
55 | {3, 3, 3},
56 | {4, 4, 4},
57 | {5, 5, 5}
58 | };
59 |
60 | static const vec2 CUBE__VERTEX_UVS[CUBE__UV_COUNT] = {
61 | {0, 0},
62 | {0, 1},
63 | {1, 1},
64 | {1, 0},
65 | };
66 | static const TriangleVertexIndices CUBE__VERTEX_UV_INDICES[CUBE__TRIANGLE_COUNT] = {
67 | {0, 1, 2},
68 | {0, 1, 2},
69 | {0, 1, 2},
70 | {0, 1, 2},
71 | {0, 1, 2},
72 | {0, 1, 2},
73 | {0, 2, 3},
74 | {0, 2, 3},
75 | {0, 2, 3},
76 | {0, 2, 3},
77 | {0, 2, 3},
78 | {0, 2, 3}
79 | };
80 |
81 | void setMeshToCube(Mesh *mesh) {
82 | mesh->triangle_count = CUBE__TRIANGLE_COUNT;
83 | mesh->vertex_count = CUBE__VERTEX_COUNT;
84 | mesh->normals_count = CUBE__NORMAL_COUNT;
85 | mesh->uvs_count = CUBE__UV_COUNT;
86 |
87 | mesh->vertex_uvs = (vec2*)CUBE__VERTEX_UVS;
88 | mesh->vertex_normals = (vec3*)CUBE__VERTEX_NORMALS;
89 | mesh->vertex_positions = (vec3*)CUBE__VERTEX_POSITIONS;
90 |
91 | mesh->vertex_uvs_indices = (TriangleVertexIndices*)CUBE__VERTEX_UV_INDICES;
92 | mesh->vertex_normal_indices = (TriangleVertexIndices*)CUBE__VERTEX_NORMAL_INDICES;
93 | mesh->vertex_position_indices = (TriangleVertexIndices*)CUBE__VERTEX_POSITION_INDICES;
94 | }
--------------------------------------------------------------------------------
/src/SlimRaster/scene/curve.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../core/types.h"
4 | #include "../math/vec3.h"
5 | #include "../math/mat3.h"
6 | #include "../math/quat.h"
7 | #include "../shapes/edge.h"
8 | #include "./primitive.h"
9 |
10 | #define CURVE_STEPS 3600
11 |
12 | void drawCurve(Curve *curve, u32 step_count, Primitive *primitive, vec3 color, f32 opacity, u8 line_width, Viewport *viewport) {
13 | f32 one_over_step_count = 1.0f / (f32)step_count;
14 | f32 rotation_step = one_over_step_count * TAU;
15 | f32 rotation_step_times_rev_count = rotation_step * (f32)curve->revolution_count;
16 |
17 | if (primitive->type == PrimitiveType_Helix)
18 | rotation_step = rotation_step_times_rev_count;
19 |
20 | vec3 center_to_orbit;
21 | center_to_orbit.x = 1;
22 | center_to_orbit.y = center_to_orbit.z = 0;
23 |
24 | vec3 orbit_to_curve;
25 | orbit_to_curve.x = curve->thickness;
26 | orbit_to_curve.y = orbit_to_curve.z = 0;
27 |
28 | mat3 rotation;
29 | rotation.X.x = rotation.Z.z = cosf(rotation_step);
30 | rotation.X.z = sinf(rotation_step);
31 | rotation.Z.x = -rotation.X.z;
32 | rotation.X.y = rotation.Z.y = rotation.Y.x = rotation.Y.z = 0;
33 | rotation.Y.y = 1;
34 |
35 | mat3 orbit_to_curve_rotation;
36 | if (primitive->type == PrimitiveType_Coil) {
37 | orbit_to_curve_rotation.X.x = orbit_to_curve_rotation.Y.y = cosf(rotation_step_times_rev_count);
38 | orbit_to_curve_rotation.X.y = sinf(rotation_step_times_rev_count);
39 | orbit_to_curve_rotation.Y.x = -orbit_to_curve_rotation.X.y;
40 | orbit_to_curve_rotation.X.z = orbit_to_curve_rotation.Y.z = orbit_to_curve_rotation.Z.x = orbit_to_curve_rotation.Z.y = 0;
41 | orbit_to_curve_rotation.Z.z = 1;
42 | }
43 |
44 | // Transform vertices positions of edges from view-space to screen-space (w/ culling and clipping):
45 | mat3 accumulated_orbit_rotation = rotation;
46 | vec3 current_position, previous_position;
47 | Edge edge;
48 |
49 | for (u32 i = 0; i < step_count; i++) {
50 | center_to_orbit = mulVec3Mat3(center_to_orbit, rotation);
51 |
52 | switch (primitive->type) {
53 | case PrimitiveType_Helix:
54 | current_position = center_to_orbit;
55 | current_position.y -= 1;
56 | break;
57 | case PrimitiveType_Coil:
58 | orbit_to_curve = mulVec3Mat3(orbit_to_curve, orbit_to_curve_rotation);
59 | current_position = mulVec3Mat3(orbit_to_curve, accumulated_orbit_rotation);
60 | current_position = addVec3(center_to_orbit, current_position);
61 | break;
62 | default:
63 | break;
64 | }
65 |
66 | current_position = convertPositionToWorldSpace(current_position, primitive);
67 | current_position = subVec3( current_position, viewport->camera->transform.position);
68 | current_position = mulVec3Quat(current_position, viewport->camera->transform.rotation_inverted);
69 |
70 | if (i) {
71 | edge.from = previous_position;
72 | edge.to = current_position;
73 | drawEdge(&edge, color, opacity, line_width, viewport);
74 | }
75 |
76 | switch (primitive->type) {
77 | case PrimitiveType_Helix:
78 | center_to_orbit.y += 2 * one_over_step_count;
79 | break;
80 | case PrimitiveType_Coil:
81 | accumulated_orbit_rotation = mulMat3(accumulated_orbit_rotation, rotation);
82 | break;
83 | default:
84 | break;
85 | }
86 |
87 | previous_position = current_position;
88 | }
89 | }
--------------------------------------------------------------------------------
/src/SlimRaster/scene/grid.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../core/types.h"
4 | #include "../math/vec3.h"
5 | #include "../shapes/edge.h"
6 | #include "./primitive.h"
7 |
8 | void transformGridVerticesFromObjectToViewSpace(Grid *grid, GridVertices *transformed_vertices, Primitive *primitive, Viewport *viewport) {
9 | vec3 position;
10 | for (u8 side = 0; side < 2; side++) {
11 | for (u8 axis = 0; axis < 2; axis++) {
12 | u8 segment_count = axis ? grid->v_segments : grid->u_segments;
13 | for (u8 segment = 0; segment < segment_count; segment++) {
14 | position = grid->vertices.buffer[axis][side][segment];
15 | position = convertPositionToWorldSpace(position, primitive);
16 | position = subVec3( position, viewport->camera->transform.position);
17 | position = mulVec3Quat(position, viewport->camera->transform.rotation_inverted);
18 | transformed_vertices->buffer[axis][side][segment] = position;
19 | }
20 | }
21 | }
22 | }
23 |
24 | void drawGrid(Grid *grid, Primitive *primitive, vec3 color, f32 opacity, u8 line_width, Viewport *viewport) {
25 | // Transform vertices positions from local-space to world-space and then to view-space:
26 | static GridVertices vertices;
27 |
28 | transformGridVerticesFromObjectToViewSpace(grid, &vertices, primitive, viewport);
29 |
30 | // Distribute transformed vertices positions to edges:
31 | static GridEdges edges;
32 | setGridEdgesFromVertices(edges.uv.u, grid->u_segments, vertices.uv.u.from, vertices.uv.u.to);
33 | setGridEdgesFromVertices(edges.uv.v, grid->v_segments, vertices.uv.v.from, vertices.uv.v.to);
34 |
35 | for (u8 u = 0; u < grid->u_segments; u++) drawEdge(edges.uv.u + u, color, opacity, line_width, viewport);
36 | for (u8 v = 0; v < grid->v_segments; v++) drawEdge(edges.uv.v + v, color, opacity, line_width, viewport);
37 | }
--------------------------------------------------------------------------------
/src/SlimRaster/scene/mesh.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../core/base.h"
4 | #include "../core/types.h"
5 | #include "../shapes/edge.h"
6 | #include "./primitive.h"
7 |
8 | void drawMesh(Mesh *mesh, bool draw_normals, Primitive *primitive, vec3 color, f32 opacity, u8 line_width, Viewport *viewport) {
9 | EdgeVertexIndices *edge_vertex_indices = mesh->edge_vertex_indices;
10 | quat cam_rot = viewport->camera->transform.rotation_inverted;
11 | vec3 cam_pos = viewport->camera->transform.position;
12 | vec3 *positions = mesh->vertex_positions;
13 | vec3 position;
14 | Edge edge;
15 | for (u32 i = 0; i < mesh->edge_count; i++, edge_vertex_indices++) {
16 | position = positions[edge_vertex_indices->from];
17 | position = convertPositionToWorldSpace(position, primitive);
18 | position = subVec3(position, cam_pos);
19 | position = mulVec3Quat(position, cam_rot);
20 | edge.from = position;
21 |
22 | position = positions[edge_vertex_indices->to];
23 | position = convertPositionToWorldSpace(position, primitive);
24 | position = subVec3(position, cam_pos);
25 | position = mulVec3Quat(position, cam_rot);
26 | edge.to = position;
27 |
28 | drawEdge(&edge, color, opacity, line_width, viewport);
29 | }
30 |
31 | if (draw_normals && mesh->normals_count && mesh->vertex_normals && mesh->vertex_normal_indices) {
32 | TriangleVertexIndices *vertex_normal_indices = mesh->vertex_normal_indices;
33 | TriangleVertexIndices *vertex_position_indices = mesh->vertex_position_indices;
34 | vec3 *normals = mesh->vertex_normals;
35 | for (u32 t = 0; t < mesh->triangle_count; t++, vertex_normal_indices++, vertex_position_indices++) {
36 | for (u8 i = 0; i < 3; i++) {
37 | position = positions[vertex_position_indices->ids[i]];
38 | edge.from = convertPositionToWorldSpace(position, primitive);
39 | edge.from = subVec3(edge.from, cam_pos);
40 | edge.from = mulVec3Quat(edge.from, cam_rot);
41 |
42 | edge.to = addVec3(position, scaleVec3(normals[vertex_normal_indices->ids[i]], 0.1f));
43 | edge.to = convertPositionToWorldSpace(edge.to, primitive);
44 | edge.to = subVec3(edge.to, cam_pos);
45 | edge.to = mulVec3Quat(edge.to, cam_rot);
46 |
47 | drawEdge(&edge, Color(Red), opacity * 0.5f, line_width, viewport);
48 | }
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/src/SlimRaster/scene/primitive.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../core/types.h"
4 | #include "../math/vec3.h"
5 | #include "../math/mat3.h"
6 | #include "../math/mat4.h"
7 | #include "../math/quat.h"
8 |
9 | INLINE void convertPositionAndDirectionToObjectSpace(
10 | vec3 position,
11 | vec3 dir,
12 | Primitive *primitive,
13 | vec3 *out_position,
14 | vec3 *out_direction
15 | ) {
16 | *out_position = primitive->flags & IS_TRANSLATED ?
17 | subVec3(position, primitive->position) :
18 | position;
19 |
20 | if (primitive->flags & IS_ROTATED) {
21 | quat inv_rotation = conjugate(primitive->rotation);
22 | *out_position = mulVec3Quat(*out_position, inv_rotation);
23 | *out_direction = mulVec3Quat(dir, inv_rotation);
24 | } else
25 | *out_direction = dir;
26 |
27 | if (primitive->flags & IS_SCALED) {
28 | vec3 inv_scale = oneOverVec3(primitive->scale);
29 | *out_position = mulVec3(*out_position, inv_scale);
30 | if (primitive->flags & IS_SCALED_NON_UNIFORMLY)
31 | *out_direction = normVec3(mulVec3(*out_direction, inv_scale));
32 | }
33 | }
34 | INLINE mat4 getPrimitiveTransformationMatrix(Primitive *primitive) {
35 | mat3 rotation_matrix = transposedMat3(convertQuaternionToRotationMatrix(primitive->rotation));
36 |
37 | rotation_matrix.X = scaleVec3(rotation_matrix.X, primitive->scale.x);
38 | rotation_matrix.Y = scaleVec3(rotation_matrix.Y, primitive->scale.y);
39 | rotation_matrix.Z = scaleVec3(rotation_matrix.Z, primitive->scale.z);
40 |
41 | mat4 matrix = mat4fromMat3(rotation_matrix);
42 | matrix.W = Vec4fromVec3(primitive->position, 1);
43 |
44 | return matrix;
45 | }
46 |
47 | INLINE vec3 convertPositionToWorldSpace(vec3 position, Primitive *primitive) {
48 | if (primitive->flags & IS_SCALED) position = mulVec3( position, primitive->scale);
49 | if (primitive->flags & IS_ROTATED) position = mulVec3Quat(position, primitive->rotation);
50 | if (primitive->flags & IS_TRANSLATED) position = addVec3( position, primitive->position);
51 | return position;
52 | }
53 | INLINE vec3 convertPositionToObjectSpace(vec3 position, Primitive *primitive) {
54 | if (primitive->flags & IS_TRANSLATED) position = subVec3( position, primitive->position);
55 | if (primitive->flags & IS_ROTATED) position = mulVec3Quat(position, conjugate(primitive->rotation));
56 | if (primitive->flags & IS_SCALED) position = mulVec3(position, oneOverVec3(primitive->scale));
57 | return position;
58 | }
59 |
60 | INLINE vec3 convertDirectionToWorldSpace(vec3 direction, Primitive *primitive) {
61 | if (primitive->flags & IS_SCALED_NON_UNIFORMLY) direction = mulVec3(direction, oneOverVec3(primitive->scale));
62 | if (primitive->flags & IS_ROTATED) direction = mulVec3Quat(direction, primitive->rotation);
63 | return direction;
64 | }
--------------------------------------------------------------------------------
/src/SlimRaster/scene/texture.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../core/types.h"
4 |
5 | INLINE vec4 sampleTextureMip(TextureMip *mip, vec2 UV) {
6 | f32 u = UV.u;
7 | f32 v = UV.v;
8 | if (u > 1) u -= (f32)((u32)u);
9 | if (v > 1) v -= (f32)((u32)v);
10 |
11 | const f32 U = u * (f32)mip->width + 0.5f;
12 | const f32 V = v * (f32)mip->height + 0.5f;
13 | const u32 x = (u32)U;
14 | const u32 y = (u32)V;
15 | const f32 r = U - (f32)x;
16 | const f32 b = V - (f32)y;
17 | const f32 l = 1 - r;
18 | const f32 t = 1 - b;
19 | const f32 tl = t * l * COLOR_COMPONENT_TO_FLOAT;
20 | const f32 tr = t * r * COLOR_COMPONENT_TO_FLOAT;
21 | const f32 bl = b * l * COLOR_COMPONENT_TO_FLOAT;
22 | const f32 br = b * r * COLOR_COMPONENT_TO_FLOAT;
23 |
24 | const TexelQuad texel_quad = mip->texel_quads[y * (mip->width + 1) + x];
25 | return Vec4(
26 | fast_mul_add((f32)texel_quad.R.BR, br, fast_mul_add((f32)texel_quad.R.BL, bl, fast_mul_add((f32)texel_quad.R.TR, tr, (f32)texel_quad.R.TL * tl))),
27 | fast_mul_add((f32)texel_quad.G.BR, br, fast_mul_add((f32)texel_quad.G.BL, bl, fast_mul_add((f32)texel_quad.G.TR, tr, (f32)texel_quad.G.TL * tl))),
28 | fast_mul_add((f32)texel_quad.B.BR, br, fast_mul_add((f32)texel_quad.B.BL, bl, fast_mul_add((f32)texel_quad.B.TR, tr, (f32)texel_quad.B.TL * tl))),
29 | 1.0f);
30 | }
31 |
32 | INLINE vec4 sampleTexture(Texture *texture, vec2 UV, vec2 dUV) {
33 | u8 mip_level = 0;
34 | if (texture->mipmap) {
35 | const f32 pixel_width = dUV.u * (f32)texture->width;
36 | const f32 pixel_height = dUV.v * (f32)texture->height;
37 | f32 pixel_size = (f32)(pixel_width + pixel_height) * 0.5f;
38 | const u8 last_mip = texture->mip_count - 1;
39 |
40 | while (pixel_size > 1 && mip_level < last_mip) {
41 | pixel_size /= 2;
42 | mip_level += 1;
43 | }
44 | }
45 |
46 | return sampleTextureMip(texture->mips + mip_level, UV);
47 | }
--------------------------------------------------------------------------------
/src/SlimRaster/scene/xform.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../core/base.h"
4 | #include "../math/vec3.h"
5 | #include "../math/mat3.h"
6 | #include "../math/quat.h"
7 |
8 | INLINE void rotateXform3(xform3 *xform, f32 yaw, f32 pitch, f32 roll) {
9 | if (yaw) yawMat3( yaw, &xform->yaw_matrix);
10 | if (pitch) pitchMat3(pitch, &xform->pitch_matrix);
11 | if (roll) rollMat3( roll, &xform->roll_matrix);
12 |
13 | xform->rotation_matrix = mulMat3(mulMat3(xform->pitch_matrix, xform->yaw_matrix), xform->roll_matrix);
14 | xform->rotation_matrix_inverted = transposedMat3(xform->rotation_matrix);
15 |
16 | xform->rotation = convertRotationMatrixToQuaternion(xform->rotation_matrix);
17 | xform->rotation_inverted = convertRotationMatrixToQuaternion(xform->rotation_matrix_inverted);
18 |
19 | xform->matrix = mulMat3(xform->matrix, xform->rotation_matrix);
20 | }
--------------------------------------------------------------------------------
/src/SlimRaster/shapes/circle.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../core/base.h"
4 | //
5 | //void drawCircle(Viewport *viewport, vec3 color, f32 opacity, i32 center_x, i32 center_y, i32 radius) {
6 | // if (radius <= 1) {
7 | // if (inRange(0, center_x, viewport->dimensions.width - 1) &&
8 | // inRange(0, center_y, viewport->dimensions.height - 1))
9 | // setPixel(viewport, center_y, center_x, color, opacity, 0);
10 | //
11 | // return;
12 | // }
13 | //
14 | // i32 width = viewport->dimensions.width;
15 | // i32 size = viewport->dimensions.width_times_height;
16 | //
17 | // i32 x = radius, y = 0, y2 = 0;
18 | // i32 r2 = radius * radius;
19 | // i32 x2 = r2;
20 | //
21 | // i32 Sx1 = center_x - radius;
22 | // i32 Ex1 = center_x + radius;
23 | // i32 Sy1 = center_y * width;
24 | // i32 Ey1 = Sy1;
25 | //
26 | // i32 Sx2 = center_x;
27 | // i32 Ex2 = center_x;
28 | // i32 Sy2 = (center_y - radius) * width;
29 | // i32 Ey2 = (center_y + radius) * width;
30 | //
31 | // while (y <= x) {
32 | // if (Sy1 >= 0 && Sy1 < size) {
33 | // if (Sx1 >= 0 && Sx1 < width) setPixel(canvas->float_pixels + (Sy1 + Sx1), color, opacity, 0);
34 | // if (Ex1 >= 0 && Ex1 < width) setPixel(canvas->float_pixels + (Sy1 + Ex1), color, opacity, 0);
35 | // }
36 | // if (Ey1 >= 0 && Ey1 < size) {
37 | // if (Sx1 >= 0 && Sx1 < width) setPixel(canvas->float_pixels + (Ey1 + Sx1), color, opacity, 0);
38 | // if (Ex1 >= 0 && Ex1 < width) setPixel(canvas->float_pixels + (Ey1 + Ex1), color, opacity, 0);
39 | // }
40 | //
41 | // if (Sy2 >= 0 && Sy2 < size) {
42 | // if (Sx2 >= 0 && Sx2 < width) setPixel(canvas->float_pixels + (Sy2 + Sx2), color, opacity, 0);
43 | // if (Ex2 >= 0 && Ex2 < width) setPixel(canvas->float_pixels + (Sy2 + Ex2), color, opacity, 0);
44 | // }
45 | // if (Ey2 >= 0 && Ey2 < size) {
46 | // if (Sx2 >= 0 && Sx2 < width) setPixel(canvas->float_pixels + (Ey2 + Sx2), color, opacity, 0);
47 | // if (Ex2 >= 0 && Ex2 < width) setPixel(canvas->float_pixels + (Ey2 + Ex2), color, opacity, 0);
48 | // }
49 | //
50 | // if ((x2 + y2) > r2) {
51 | // x -= 1;
52 | // x2 = x * x;
53 | //
54 | // Sx1 += 1;
55 | // Ex1 -= 1;
56 | //
57 | // Sy2 += width;
58 | // Ey2 -= width;
59 | // }
60 | //
61 | // y += 1;
62 | // y2 = y * y;
63 | //
64 | // Sy1 -= width;
65 | // Ey1 += width;
66 | //
67 | // Sx2 -= 1;
68 | // Ex2 += 1;
69 | // }
70 | //}
71 | //
72 | //void fillCircle2D(PixelGrid *canvas, RGBA color, i32 center_x, i32 center_y, i32 radius) {
73 | // if (radius <= 1) {
74 | // if (inRange(0, center_x, canvas->dimensions.width - 1) &&
75 | // inRange(0, center_y, canvas->dimensions.height - 1))
76 | // setPixel(canvas->float_pixels + (canvas->dimensions.width * center_y + center_x), color, opacity, 0);
77 | //
78 | // return;
79 | // }
80 | //
81 | // i32 width = canvas->dimensions.width;
82 | // i32 size = canvas->dimensions.width_times_height;
83 | //
84 | // i32 x = radius, y = 0, y2 = 0;
85 | // i32 r2 = radius * radius;
86 | // i32 x2 = r2;
87 | //
88 | // i32 Sx1 = center_x - radius;
89 | // i32 Ex1 = center_x + radius;
90 | // i32 Sy1 = center_y * width;
91 | // i32 Ey1 = Sy1;
92 | //
93 | // i32 Sx2 = center_x;
94 | // i32 Ex2 = center_x;
95 | // i32 Sy2 = (center_y - radius) * width;
96 | // i32 Ey2 = (center_y + radius) * width;
97 | //
98 | // i32 i, start, end;
99 | //
100 | // while (y <= x) {
101 | // start = Sx1 > 0 ? Sx1 : 0;
102 | // end = Ex1 < (width - 1) ? Ex1 : (width - 1);
103 | // if (Sy1 >= 0 && Sy1 < size) for (i = start; i <= end; i++) setPixel(canvas->float_pixels + (Sy1 + i), color, opacity, 0);
104 | // if (Ey1 >= 0 && Ey1 < size) for (i = start; i <= end; i++) setPixel(canvas->float_pixels + (Ey1 + i), color, opacity, 0);
105 | //
106 | // start = Sx2 > 0 ? Sx2 : 0;
107 | // end = Ex2 < (width - 1) ? Ex2 : (width - 1);
108 | // if (Sy2 >= 0 && Sy2 < size) for (i = start; i <= end; i++) setPixel(canvas->float_pixels + (Sy2 + i), color, opacity, 0);
109 | // if (Ey2 >= 0 && Ey2 < size) for (i = start; i <= end; i++) setPixel(canvas->float_pixels + (Ey2 + i), color, opacity, 0);
110 | //
111 | // if ((x2 + y2) > r2) {
112 | // x -= 1;
113 | // x2 = x * x;
114 | //
115 | // Sx1 += 1;
116 | // Ex1 -= 1;
117 | //
118 | // Sy2 += width;
119 | // Ey2 -= width;
120 | // }
121 | //
122 | // y += 1;
123 | // y2 = y * y;
124 | //
125 | // Sy1 -= width;
126 | // Ey1 += width;
127 | //
128 | // Sx2 -= 1;
129 | // Ex2 += 1;
130 | // }
131 | //}
--------------------------------------------------------------------------------
/src/SlimRaster/shapes/edge.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../core/types.h"
4 | #include "../math/vec3.h"
5 | #include "../math/vec4.h"
6 | #include "./line.h"
7 |
8 | bool cullAndClipEdge(Edge *edge, Viewport *viewport) {
9 | f32 distance = viewport->settings.near_clipping_plane_distance;
10 | vec3 A = edge->from;
11 | vec3 B = edge->to;
12 |
13 | u8 out = (A.z < distance) | ((B.z < distance) << 1);
14 | if (out) {
15 | if (out == 3) return false;
16 | if (out & 1) A = lerpVec3(A, B, (distance - A.z) / (B.z - A.z));
17 | else B = lerpVec3(B, A, (distance - B.z) / (A.z - B.z));
18 | }
19 |
20 | distance = viewport->settings.far_clipping_plane_distance;
21 | out = (A.z > distance) | ((B.z > distance) << 1);
22 | if (out) {
23 | if (out == 3) return false;
24 | if (out & 1) A = lerpVec3(A, B, (A.z - distance) / (A.z - B.z));
25 | else B = lerpVec3(B, A, (B.z - distance) / (B.z - A.z));
26 | }
27 |
28 | // Left plane (facing to the right):
29 | vec3 N = Vec3(viewport->camera->focal_length, 0, viewport->dimensions.width_over_height);
30 | f32 NdotA = dotVec3(N, A);
31 | f32 NdotB = dotVec3(N, B);
32 |
33 | out = (NdotA < 0) | ((NdotB < 0) << 1);
34 | if (out) {
35 | if (out == 3) return false;
36 | if (out & 1) A = lerpVec3(A, B, NdotA / (NdotA - NdotB));
37 | else B = lerpVec3(B, A, NdotB / (NdotB - NdotA));
38 | }
39 |
40 | // Right plane (facing to the left):
41 | N.x = -N.x;
42 | NdotA = dotVec3(N, A);
43 | NdotB = dotVec3(N, B);
44 |
45 | out = (NdotA < 0) | ((NdotB < 0) << 1);
46 | if (out) {
47 | if (out == 3) return false;
48 | if (out & 1) A = lerpVec3(A, B, NdotA / (NdotA - NdotB));
49 | else B = lerpVec3(B, A, NdotB / (NdotB - NdotA));
50 | }
51 |
52 | // Bottom plane (facing up):
53 | N = Vec3(0, viewport->camera->focal_length, 1);
54 | NdotA = dotVec3(N, A);
55 | NdotB = dotVec3(N, B);
56 |
57 | out = (NdotA < 0) | ((NdotB < 0) << 1);
58 | if (out) {
59 | if (out == 3) return false;
60 | if (out & 1) A = lerpVec3(A, B, NdotA / (NdotA - NdotB));
61 | else B = lerpVec3(B, A, NdotB / (NdotB - NdotA));
62 | }
63 |
64 | // Top plane (facing down):
65 | N.y = -N.y;
66 | NdotA = dotVec3(N, A);
67 | NdotB = dotVec3(N, B);
68 |
69 | out = (NdotA < 0) | ((NdotB < 0) << 1);
70 | if (out) {
71 | if (out == 3) return false;
72 | if (out & 1) A = lerpVec3(A, B, NdotA / (NdotA - NdotB));
73 | else B = lerpVec3(B, A, NdotB / (NdotB - NdotA));
74 | }
75 |
76 | edge->from = A;
77 | edge->to = B;
78 |
79 | return true;
80 | }
81 |
82 | INLINE bool projectEdge(Edge *edge, Viewport *viewport) {
83 | if (!cullAndClipEdge(edge, viewport))
84 | return false;
85 |
86 | vec4 A = mulVec4Mat4(Vec4fromVec3(edge->from, 1.0f), viewport->projection_matrix);
87 | vec4 B = mulVec4Mat4(Vec4fromVec3(edge->to, 1.0f), viewport->projection_matrix);
88 |
89 | // Project:
90 | edge->from = scaleVec3(Vec3fromVec4(A), 1.0f / A.w);
91 | edge->to = scaleVec3(Vec3fromVec4(B), 1.0f / B.w);
92 |
93 | // NDC->screen:
94 | edge->from.x += 1; edge->from.x *= viewport->dimensions.h_width;
95 | edge->to.x += 1; edge->to.x *= viewport->dimensions.h_width;
96 | edge->from.y += 1; edge->from.y *= viewport->dimensions.h_height;
97 | edge->to.y += 1; edge->to.y *= viewport->dimensions.h_height;
98 |
99 | // Flip Y:
100 | edge->from.y = viewport->dimensions.f_height - edge->from.y;
101 | edge->to.y = viewport->dimensions.f_height - edge->to.y;
102 |
103 | return true;
104 | }
105 |
106 | INLINE void drawEdge(Edge *edge, vec3 color, f32 opacity, u8 line_width, Viewport *viewport) {
107 | if (projectEdge(edge, viewport))
108 | drawLine(edge->from.x, edge->from.y, edge->from.z,
109 | edge->to.x, edge->to.y, edge->to.z,
110 | color, opacity, line_width, viewport);
111 | }
112 |
113 | //
114 | //INLINE f32 clipFactor(f32 Aw, f32 Bw, f32 a, f32 b, bool negative_w) {
115 | // if (negative_w)
116 | // b = -b;
117 | // else
118 | // a = -a;
119 | //
120 | // f32 numerator = Aw + a;
121 | // return numerator / (numerator - Bw + b);
122 | //}
123 | //
124 | //INLINE bool cullAndClipEdgeInClipSpace(vec4 *A, vec4 *B) {
125 | // u8 A_flags = (A->x > A->w) | ((A->x < -A->w) * 2) | ((A->y > A->w) * 4) | ((A->y < -A->w) * 8) | ((A->z > A->w) * 16) | ((A->z < -A->w) * 32);
126 | // u8 B_flags = (B->x > B->w) | ((B->x < -B->w) * 2) | ((B->y > B->w) * 4) | ((B->y < -B->w) * 8) | ((B->z > B->w) * 16) | ((B->z < -B->w) * 32);
127 | //
128 | // // Cull:
129 | // if (A_flags & B_flags)
130 | // return false;
131 | //
132 | // // Clip:
133 | // if (A_flags | B_flags) {
134 | // if ( A_flags & 3) *A = lerpVec4(*B, *A, clipFactor(B->w, A->w, B->x, A->x, A_flags & 2));
135 | // else if (B_flags & 3) *B = lerpVec4(*A, *B, clipFactor(A->w, B->w, A->x, B->x, B_flags & 2));
136 | //
137 | // if ( A_flags & 12) *A = lerpVec4(*B, *A, clipFactor(B->w, A->w, B->y, A->y, A_flags & 8));
138 | // else if (B_flags & 12) *B = lerpVec4(*A, *B, clipFactor(A->w, B->w, A->y, B->y, B_flags & 8));
139 | //
140 | // if ( A_flags & 48) *A = lerpVec4(*B, *A, clipFactor(B->w, A->w, B->z, A->z, A_flags & 32));
141 | // else if (B_flags & 48) *B = lerpVec4(*A, *B, clipFactor(A->w, B->w, A->z, B->z, B_flags & 32));
142 | // }
143 | //
144 | // return true;
145 | //}
146 | //
147 | //INLINE bool cullAndClipEdge2(Edge *edge, Viewport *viewport) {
148 | // vec4 A = mulVec4Mat4(Vec4fromVec3(edge->from, 1.0f), viewport->projection_matrix);
149 | // vec4 B = mulVec4Mat4(Vec4fromVec3(edge->to, 1.0f), viewport->projection_matrix);
150 | //
151 | // if (cullAndClipEdgeInClipSpace(&A, &B)) {
152 | // edge->from = Vec3fromVec4(mulVec4Mat4(A, viewport->pre_projection_matrix_inverted));
153 | // edge->to = Vec3fromVec4(mulVec4Mat4(B, viewport->pre_projection_matrix_inverted));
154 | // return true;
155 | // } else
156 | // return false;
157 | //}
--------------------------------------------------------------------------------
/src/SlimRaster/shapes/line.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../math/vec3.h"
4 |
5 | void drawHLine(i32 x_start, i32 x_end, i32 y, vec3 color, f32 opacity, Viewport *viewport) {
6 | x_start += viewport->position.x;
7 | x_end += viewport->position.x;
8 | y += viewport->position.y;
9 |
10 | if (!inRange(y, viewport->dimensions.height + viewport->position.y, viewport->position.y)) return;
11 |
12 | i32 first, last, step = 1;
13 | subRange(x_start, x_end, viewport->dimensions.width + viewport->position.x, viewport->position.x, &first, &last);
14 |
15 | color = mulVec3(color, color);
16 | if (viewport->settings.antialias) {
17 | y <<= 1;
18 | first <<= 1;
19 | last <<= 1;
20 | step = 2;
21 | for (i32 x = first; x <= last; x += step) {
22 | setPixel(x+0, y+0, 0, color, opacity, viewport);
23 | setPixel(x+1, y+0, 0, color, opacity, viewport);
24 | setPixel(x+0, y+1, 0, color, opacity, viewport);
25 | setPixel(x+1, y+1, 0, color, opacity, viewport);
26 | }
27 | } else
28 | for (i32 x = first; x <= last; x += step)
29 | setPixel(x, y, 0, color, opacity, viewport);
30 | }
31 |
32 | void drawVLine(i32 y_start, i32 y_end, i32 x, vec3 color, f32 opacity, Viewport *viewport) {
33 | y_start += viewport->position.y;
34 | y_end += viewport->position.y;
35 | x += viewport->position.x;
36 |
37 | if (!inRange(x, viewport->dimensions.width + viewport->position.x, viewport->position.x)) return;
38 | i32 first, last, step = 1;
39 |
40 | subRange(y_start, y_end, viewport->dimensions.height + viewport->position.y, viewport->position.y, &first, &last);
41 | color = mulVec3(color, color);
42 | if (viewport->settings.antialias) {
43 | x <<= 1;
44 | first <<= 1;
45 | last <<= 1;
46 | step = 2;
47 | for (i32 y = first; y <= last; y += step) {
48 | setPixel(x+0, y+0, 0, color, opacity, viewport);
49 | setPixel(x+1, y+0, 0, color, opacity, viewport);
50 | setPixel(x+0, y+1, 0, color, opacity, viewport);
51 | setPixel(x+1, y+1, 0, color, opacity, viewport);
52 | }
53 | } else
54 | for (i32 y = first; y <= last; y += step)
55 | setPixel(x, y, 0, color, opacity, viewport);
56 | }
57 |
58 | INLINE f32 fractionOf(f32 x) {
59 | return x - floorf(x);
60 | }
61 |
62 | INLINE f32 oneMinusFractionOf(f32 x) {
63 | return 1 - fractionOf(x);
64 | }
65 |
66 | INLINE void drawLine(f32 x1, f32 y1, f64 z1,
67 | f32 x2, f32 y2, f64 z2,
68 | vec3 color, f32 opacity, u8 line_width, Viewport *viewport) {
69 | if (x1 < 0 &&
70 | y1 < 0 &&
71 | x2 < 0 &&
72 | y2 < 0)
73 | return;
74 |
75 | i32 x_left = viewport->position.x;
76 | i32 y_top = viewport->position.y;
77 | x1 += (f32)x_left;
78 | x2 += (f32)x_left;
79 | y1 += (f32)y_top;
80 | y2 += (f32)y_top;
81 |
82 | i32 w = viewport->dimensions.width + x_left;
83 | i32 h = viewport->dimensions.height + y_top;
84 |
85 | color = mulVec3(color, color);
86 | i32 x, y;
87 | if (viewport->settings.antialias) {
88 | x1 += x1;
89 | x2 += x2;
90 | y1 += y1;
91 | y2 += y2;
92 | w <<= 1;
93 | h <<= 1;
94 | line_width <<= 1;
95 | line_width++;
96 | }
97 | f64 tmp, z_range, range_remap;
98 | f32 dx = x2 - x1;
99 | f32 dy = y2 - y1;
100 | f32 gap, grad, first_offset, last_offset;
101 | f64 z, z_curr, z_step;
102 | vec3 first, last;
103 | vec2i start, end;
104 | bool has_depth = z1 || z2;
105 | if (fabsf(dx) > fabsf(dy)) { // Shallow:
106 | if (x2 < x1) { // Left to right:
107 | tmp = x2; x2 = x1; x1 = (f32)tmp;
108 | tmp = y2; y2 = y1; y1 = (f32)tmp;
109 | tmp = z2; z2 = z1; z1 = tmp;
110 | }
111 |
112 | grad = dy / dx;
113 |
114 | first.x = roundf(x1);
115 | last.x = roundf(x2);
116 | first_offset = first.x - x1;
117 | last_offset = last.x - x2;
118 |
119 | first.y = y1 + grad * first_offset;
120 | last.y = y2 + grad * last_offset;
121 |
122 | start.x = (i32)first.x;
123 | start.y = (i32)first.y;
124 | end.x = (i32)last.x;
125 | end.y = (i32)last.y;
126 |
127 | x = start.x;
128 | y = start.y;
129 | gap = oneMinusFractionOf(x1 + 0.5f);
130 |
131 | if (inRange(x, w, x_left)) {
132 | if (inRange(y, h, y_top)) setPixel(x, y, z1, color, oneMinusFractionOf(first.y) * gap * opacity, viewport);
133 |
134 | for (u8 i = 0; i < line_width; i++) {
135 | y++;
136 | if (inRange(y, h, y_top)) setPixel(x, y, z1, color, opacity, viewport);
137 | }
138 |
139 | y++;
140 | if (inRange(y, h, y_top)) setPixel(x, y, z1, color, fractionOf(first.y) * gap * opacity, viewport);
141 | }
142 |
143 | x = end.x;
144 | y = end.y;
145 | gap = fractionOf(x2 + 0.5f);
146 |
147 | if (inRange(x, w, x_left)) {
148 | if (inRange(y, h, y_top)) setPixel(x, y, z2, color, oneMinusFractionOf(last.y) * gap * opacity, viewport);
149 |
150 | for (u8 i = 0; i < line_width; i++) {
151 | y++;
152 | if (inRange(y, h, y_top)) setPixel(x, y, z2, color, opacity, viewport);
153 | }
154 |
155 | y++;
156 | if (inRange(y, h, y_top)) setPixel(x, y, z2, color, fractionOf(last.y) * gap * opacity, viewport);
157 | }
158 |
159 | if (has_depth) { // Compute one-over-z start and step
160 | z1 = 1.0 / z1;
161 | z2 = 1.0 / z2;
162 | z_range = z2 - z1;
163 | range_remap = z_range / (f64)(x2 - x1);
164 | z1 += range_remap * (f64)(first_offset + 1);
165 | z2 += range_remap * (f64)(last_offset - 1);
166 | z_range = z2 - z1;
167 | z_step = z_range / (f64)(last.x - first.x - 1);
168 | z_curr = z1;
169 | } else z = 0;
170 |
171 | gap = first.y + grad;
172 | for (x = start.x + 1; x < end.x; x++) {
173 | if (inRange(x, w, x_left)) {
174 | if (has_depth) z = 1.0 / z_curr;
175 | y = (i32) gap;
176 | if (inRange(y, h, y_top)) setPixel(x, y, z, color, oneMinusFractionOf(gap) * opacity, viewport);
177 |
178 | for (u8 i = 0; i < line_width; i++) {
179 | y++;
180 | if (inRange(y, h, y_top)) setPixel(x, y, z, color, opacity, viewport);
181 | }
182 |
183 | y++;
184 | if (inRange(y, h, y_top)) setPixel(x, y, z, color, fractionOf(gap) * opacity, viewport);
185 | }
186 |
187 | gap += grad;
188 | if (has_depth) z_curr += z_step;
189 | }
190 | } else { // Steep:
191 | if (y2 < y1) { // Bottom up:
192 | tmp = x2; x2 = x1; x1 = (f32)tmp;
193 | tmp = y2; y2 = y1; y1 = (f32)tmp;
194 | tmp = z2; z2 = z1; z1 = tmp;
195 | }
196 |
197 | grad = dx / dy;
198 |
199 | first.y = roundf(y1);
200 | last.y = roundf(y2);
201 |
202 | first_offset = y1 - first.y;
203 | last_offset = last.y - y2;
204 |
205 | first.x = x1 + grad * first_offset;
206 | last.x = x2 + grad * last_offset;
207 |
208 | start.y = (i32)first.y;
209 | start.x = (i32)first.x;
210 |
211 | end.y = (i32)last.y;
212 | end.x = (i32)last.x;
213 |
214 | x = start.x;
215 | y = start.y;
216 | gap = oneMinusFractionOf(y1 + 0.5f);
217 |
218 | if (inRange(y, h, y_top)) {
219 | if (inRange(x, w, x_left)) setPixel(x, y, z1, color, oneMinusFractionOf(first.x) * gap * opacity, viewport);
220 |
221 | for (u8 i = 0; i < line_width; i++) {
222 | x++;
223 | if (inRange(x, w, x_left)) setPixel(x, y, z1, color, opacity, viewport);
224 | }
225 |
226 | x++;
227 | if (inRange(x, w, x_left)) setPixel(x, y, z1, color, fractionOf(first.x) * gap * opacity, viewport);
228 | }
229 |
230 | x = end.x;
231 | y = end.y;
232 | gap = fractionOf(y2 + 0.5f);
233 |
234 | if (inRange(y, h, y_top)) {
235 | if (inRange(x, w, x_left)) setPixel(x, y, z2, color, oneMinusFractionOf(last.x) * gap * opacity, viewport);
236 |
237 | for (u8 i = 0; i < line_width; i++) {
238 | x++;
239 | if (inRange(x, w, x_left)) setPixel(x, y, z2, color, opacity, viewport);
240 | }
241 |
242 | x++;
243 | if (inRange(x, w, x_left)) setPixel(x, y, z2, color, fractionOf(last.x) * gap * opacity, viewport);
244 | }
245 |
246 | if (has_depth) { // Compute one-over-z start and step
247 | z1 = 1.0 / z1;
248 | z2 = 1.0 / z2;
249 | z_range = z2 - z1;
250 | range_remap = z_range / (f64)(y2 - y1);
251 | z1 += range_remap * (f64)(first_offset + 1);
252 | z2 += range_remap * (f64)(last_offset - 1);
253 | z_range = z2 - z1;
254 | z_step = z_range / (f64)(last.y - first.y - 1);
255 | z_curr = z1;
256 | } else z = 0;
257 |
258 | gap = first.x + grad;
259 | for (y = start.y + 1; y < end.y; y++) {
260 | if (inRange(y, h, y_top)) {
261 | if (has_depth) z = 1.0 / z_curr;
262 | x = (i32)gap;
263 |
264 | if (inRange(x, w, x_left)) setPixel(x, y, z, color, oneMinusFractionOf(gap) * opacity, viewport);
265 |
266 | for (u8 i = 0; i < line_width; i++) {
267 | x++;
268 | if (inRange(x, w, x_left)) setPixel(x, y, z, color, opacity, viewport);
269 | }
270 |
271 | x++;
272 | if (inRange(x, w, x_left)) setPixel(x, y, z, color, fractionOf(gap) * opacity, viewport);
273 | }
274 |
275 | gap += grad;
276 | if (has_depth) z_curr += z_step;
277 | }
278 | }
279 | }
280 |
281 | //INLINE void swapf(f32 *a, f32 *b) {
282 | // f32 t = *a;
283 | // *a = *b;
284 | // *b = t;
285 | //}
286 | //
287 | //f32 fpart(f32 x) {
288 | // return x - floorf(x);
289 | //}
290 | //
291 | //f32 rfpart(f32 x) {
292 | // return 1.0f - fpart(x);
293 | //}
294 | //
295 | //#define getPixel(x, y, canvas) ((canvas)->pixels + (canvas)->dimensions.width * (y) + (x))
296 | //#define plot(x, y, opacity, color, canvas) (setPixel(getPixel(x, y, canvas), (color), opacity, 0, (canvas)->settings.gamma_corrected_blending))
297 | //
298 | //
299 | //INLINE void drawLinehh(PixelGrid *canvas, vec3 color, f32 opacity,
300 | // f32 x1, f32 y1, f64 z1,
301 | // f32 x2, f32 y2, f64 z2,
302 | // u8 line_width) {
303 | // bool steep = fabsf(y2 - y1) > fabsf(x2 - x1);
304 | //
305 | // if (steep) {
306 | // swapf(&x1, &y1);
307 | // swapf(&x2, &y2);
308 | // }
309 | //
310 | // if (x1 > x2) {
311 | // swapf(&x1, &x2);
312 | // swapf(&y1, &y2);
313 | // }
314 | //
315 | // f32 dx = x2 - x1;
316 | // f32 dy = y2 - y1;
317 | // f32 gradient = dx ? (dy / dx) : 1.0f;
318 | //
319 | // // handle first endpoint
320 | // f32 xend = roundf(x1);
321 | // f32 yend = y1 + gradient * (xend - x1);
322 | // f32 xgap = rfpart(x1 + 0.5f);
323 | // i32 xpxl1 = (i32)xend; // this will be used in the main loop
324 | // i32 ypxl1 = (i32)yend;
325 | // if (steep) {
326 | // plot( ypxl1 , xpxl1, rfpart(yend) * xgap, color, canvas);
327 | // plot(ypxl1 + 1, xpxl1, fpart(yend) * xgap, color, canvas);
328 | // } else {
329 | // plot(xpxl1, ypxl1 , rfpart(yend) * xgap, color, canvas);
330 | // plot(xpxl1, ypxl1 + 1, fpart(yend) * xgap, color, canvas);
331 | // }
332 | //
333 | // f32 intery = yend + gradient; // first y-intersection for the main loop
334 | //
335 | // // handle second endpoint
336 | // xend = roundf(x2);
337 | // yend = y2 + gradient * (xend - x2);
338 | // xgap = fpart(x2 + 0.5f);
339 | // i32 xpxl2 = (i32)xend; //this will be used in the main loop
340 | // i32 ypxl2 = (i32)yend;
341 | // if (steep) {
342 | // plot( ypxl2 , xpxl2, rfpart(yend) * xgap, color, canvas);
343 | // plot(ypxl2 + 1, xpxl2, fpart(yend) * xgap, color, canvas);
344 | // } else {
345 | // plot(xpxl2, ypxl2 , rfpart(yend) * xgap, color, canvas);
346 | // plot(xpxl2, ypxl2 + 1, fpart(yend) * xgap, color, canvas);
347 | // }
348 | //
349 | // // main loop
350 | // if (steep) {
351 | // for (i32 x = xpxl1 + 1; x < xpxl2 - 1; x++, intery += gradient) {
352 | // plot((i32)intery , x, rfpart(intery), color, canvas);
353 | // plot((i32)intery + 1, x, fpart(intery), color, canvas);
354 | // }
355 | // } else {
356 | // for (i32 x = xpxl1 + 1; x < xpxl2 - 1; x++, intery += gradient) {
357 | // plot(x, (i32)intery , rfpart(intery), color, canvas);
358 | // plot(x, (i32)intery + 1, fpart(intery), color, canvas);
359 | // }
360 | // }
361 | //}
--------------------------------------------------------------------------------
/src/SlimRaster/shapes/rect.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../core/base.h"
4 | #include "./line.h"
5 |
6 | INLINE void drawRect(Rect rect, vec3 color, f32 opacity, Viewport *viewport) {
7 | if (rect.max.x < 0 || rect.min.x >= viewport->dimensions.width ||
8 | rect.max.y < 0 || rect.min.y >= viewport->dimensions.height)
9 | return;
10 |
11 | drawHLine(rect.min.x, rect.max.x, rect.min.y, color, opacity, viewport);
12 | drawHLine(rect.min.x, rect.max.x, rect.max.y, color, opacity, viewport);
13 | drawVLine(rect.min.y, rect.max.y, rect.min.x, color, opacity, viewport);
14 | drawVLine(rect.min.y, rect.max.y, rect.max.x, color, opacity, viewport);
15 | }
16 |
17 | INLINE void fillRect(Rect rect, vec3 color, f32 opacity, Viewport *viewport) {
18 | if (rect.max.x < 0 || rect.min.x >= viewport->dimensions.width ||
19 | rect.max.y < 0 || rect.min.y >= viewport->dimensions.height)
20 | return;
21 |
22 | i32 min_x, min_y, max_x, max_y;
23 | subRange(rect.min.x, rect.max.x, viewport->dimensions.width, 0, &min_x, &max_x);
24 | subRange(rect.min.y, rect.max.y, viewport->dimensions.height, 0, &min_y, &max_y);
25 | for (i32 y = min_y; y <= max_y; y++)
26 | drawHLine(min_x, max_x, y, color, opacity, viewport);
27 | }
--------------------------------------------------------------------------------
/src/SlimRaster/shapes/triangle.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../core/base.h"
4 | //
5 | //void fillTriangle(PixelGrid *canvas, vec3 color, f32 opacity, f32 *X, f32 *Y) {
6 | // u16 W = canvas->dimensions.width;
7 | // u16 H = canvas->dimensions.height;
8 | // f32 dx1, x1, y1, xs,
9 | // dx2, x2, y2, xe,
10 | // dx3, x3, y3, dy;
11 | // i32 offset,
12 | // x, x1i, y1i, x2i, xsi, ysi = 0,
13 | // y, y2i, x3i, y3i, xei, yei = 0;
14 | // for (u8 i = 1; i <= 2; i++) {
15 | // if (Y[i] < Y[ysi]) ysi = i;
16 | // if (Y[i] > Y[yei]) yei = i;
17 | // }
18 | // u8 id[3];
19 | // if (ysi) {
20 | // if (ysi == 1) {
21 | // id[0] = 1;
22 | // id[1] = 2;
23 | // id[2] = 0;
24 | // } else {
25 | // id[0] = 2;
26 | // id[1] = 0;
27 | // id[2] = 1;
28 | // }
29 | // } else {
30 | // id[0] = 0;
31 | // id[1] = 1;
32 | // id[2] = 2;
33 | // }
34 | // x1 = X[id[0]]; y1 = Y[id[0]]; x1i = (i32)x1; y1i = (i32)y1;
35 | // x2 = X[id[1]]; y2 = Y[id[1]]; x2i = (i32)x2; y2i = (i32)y2;
36 | // x3 = X[id[2]]; y3 = Y[id[2]]; x3i = (i32)x3; y3i = (i32)y3;
37 | // dx1 = x1i == x2i || y1i == y2i ? 0 : (x2 - x1) / (y2 - y1);
38 | // dx2 = x2i == x3i || y2i == y3i ? 0 : (x3 - x2) / (y3 - y2);
39 | // dx3 = x1i == x3i || y1i == y3i ? 0 : (x3 - x1) / (y3 - y1);
40 | // dy = 1 - (y1 - (f32)y1);
41 | // xs = dx3 ? x1 + dx3 * dy : x1; ysi = (i32)Y[ysi];
42 | // xe = dx1 ? x1 + dx1 * dy : x1; yei = (i32)Y[yei];
43 | // offset = W * y1i;
44 | // for (y = ysi; y < yei; y++) {
45 | // if (y == y3i) xs = dx2 ? (x3 + dx2 * (1 - (y3 - (f32)y3i))) : x3;
46 | // if (y == y2i) xe = dx2 ? (x2 + dx2 * (1 - (y2 - (f32)y2i))) : x2;
47 | // xsi = (i32)xs;
48 | // xei = (i32)xe;
49 | // for (x = xsi; x < xei; x++) {
50 | // if (x > 0 && x < W && y > 0 && y < H)
51 | // setPixel(canvas->float_pixels + (offset + x), color, opacity, 0);
52 | // }
53 | // offset += W;
54 | // xs += y < y3i ? dx3 : dx2;
55 | // xe += y < y2i ? dx1 : dx2;
56 | // }
57 | //}
--------------------------------------------------------------------------------
/src/SlimRaster/viewport/hud.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../core/base.h"
4 | #include "../core/text.h"
5 |
6 | void drawHUD(Viewport *viewport, HUD *hud) {
7 | u16 x = (u16)hud->position.x;
8 | u16 y = (u16)hud->position.y;
9 |
10 | HUDLine *line = hud->lines;
11 | bool alt;
12 | for (u32 i = 0; i < hud->line_count; i++, line++) {
13 | if (line->use_alternate) {
14 | alt = *line->use_alternate;
15 | if (line->invert_alternate_use)
16 | alt = !alt;
17 | } else
18 | alt = false;
19 |
20 | drawText(line->title.char_ptr, x, y, Color(line->title_color), 1, viewport);
21 | drawText(alt ? line->alternate_value.char_ptr : line->value.string.char_ptr,
22 | x + (u16)line->title.length * FONT_WIDTH, y,
23 | Color(alt ? line->alternate_value_color : line->value_color), 1, viewport);
24 | y += (u16)(hud->line_height * (f32)FONT_HEIGHT);
25 | }
26 | }
--------------------------------------------------------------------------------
/src/SlimRaster/viewport/manipulation.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../core/types.h"
4 | #include "../math/vec3.h"
5 | #include "../math/quat.h"
6 | #include "../scene/primitive.h"
7 | #include "../scene/box.h"
8 |
9 | void setViewportProjectionPlane(Viewport *viewport) {
10 | Camera *camera = viewport->camera;
11 | ProjectionPlane *projection_plane = &viewport->projection_plane;
12 | Dimensions *dimensions = &viewport->dimensions;
13 |
14 | projection_plane->start = scaleVec3(*camera->transform.forward_direction, dimensions->f_height * camera->focal_length);
15 | projection_plane->right = scaleVec3(*camera->transform.right_direction, 1.0f - (f32)dimensions->width);
16 | projection_plane->down = scaleVec3(*camera->transform.up_direction, dimensions->f_height - 1.0f);
17 | projection_plane->start = addVec3(projection_plane->start, projection_plane->right);
18 | projection_plane->start = addVec3(projection_plane->start, projection_plane->down);
19 |
20 | projection_plane->right = scaleVec3(*camera->transform.right_direction, 2);
21 | projection_plane->down = scaleVec3(*camera->transform.up_direction, -2);
22 | }
23 |
24 | INLINE void setRayFromCoords(Ray *ray, vec2i coords, Viewport *viewport) {
25 | ray->origin = viewport->camera->transform.position;
26 | ray->direction = scaleAddVec3(viewport->projection_plane.right, (f32)coords.x, viewport->projection_plane.start);
27 | ray->direction = scaleAddVec3(viewport->projection_plane.down, (f32)coords.y, ray->direction);
28 | ray->direction = normVec3(ray->direction);
29 | }
30 |
31 | INLINE bool hitPlane(vec3 plane_origin, vec3 plane_normal, vec3 *ray_origin, vec3 *ray_direction, RayHit *hit) {
32 | f32 Rd_dot_n = dotVec3(*ray_direction, plane_normal);
33 | if (Rd_dot_n == 0) // The ray is parallel to the plane
34 | return false;
35 |
36 | bool ray_is_facing_the_plane = Rd_dot_n < 0;
37 |
38 | vec3 RtoP = subVec3(*ray_origin, plane_origin);
39 | f32 Po_to_Ro_dot_n = dotVec3(RtoP, plane_normal);
40 | hit->from_behind = Po_to_Ro_dot_n < 0;
41 | if (hit->from_behind == ray_is_facing_the_plane) // The ray can't hit the plane
42 | return false;
43 |
44 | hit->distance = fabsf(Po_to_Ro_dot_n / Rd_dot_n);
45 | hit->position = scaleVec3(*ray_direction, hit->distance);
46 | hit->position = addVec3(*ray_origin, hit->position);
47 | hit->normal = plane_normal;
48 |
49 | return true;
50 | }
51 |
52 | INLINE BoxSide getBoxSide(vec3 octant, u8 axis) {
53 | switch (axis) {
54 | case 0 : return octant.x > 0 ? Right : Left;
55 | case 3 : return octant.x > 0 ? Left : Right;
56 | case 1 : return octant.y > 0 ? Top : Bottom;
57 | case 4 : return octant.y > 0 ? Bottom : Top;
58 | case 2 : return octant.z > 0 ? Front : Back;
59 | default: return octant.z > 0 ? Back : Front;
60 | }
61 | }
62 |
63 | INLINE BoxSide hitCube(RayHit *hit, vec3 *Ro, vec3 *Rd) {
64 | vec3 octant, RD_rcp = oneOverVec3(*Rd);
65 | octant.x = signbit(Rd->x) ? 1.0f : -1.0f;
66 | octant.y = signbit(Rd->y) ? 1.0f : -1.0f;
67 | octant.z = signbit(Rd->z) ? 1.0f : -1.0f;
68 |
69 | f32 t[6];
70 | t[0] = ( octant.x - Ro->x) * RD_rcp.x;
71 | t[1] = ( octant.y - Ro->y) * RD_rcp.y;
72 | t[2] = ( octant.z - Ro->z) * RD_rcp.z;
73 | t[3] = (-octant.x - Ro->x) * RD_rcp.x;
74 | t[4] = (-octant.y - Ro->y) * RD_rcp.y;
75 | t[5] = (-octant.z - Ro->z) * RD_rcp.z;
76 |
77 | u8 max_axis = t[3] < t[4] ? 3 : 4; if (t[5] < t[max_axis]) max_axis = 5;
78 | f32 maxt = t[max_axis];
79 | if (maxt < 0) // Further-away hit is behind the ray - intersection can not occur.
80 | return NoSide;
81 |
82 | u8 min_axis = t[0] > t[1] ? 0 : 1; if (t[2] > t[min_axis]) min_axis = 2;
83 | f32 mint = t[min_axis];
84 | if (maxt < (mint > 0 ? mint : 0))
85 | return NoSide;
86 |
87 | hit->from_behind = mint < 0; // Further-away hit is in front of the ray, closer one is behind it.
88 | if (hit->from_behind) {
89 | mint = maxt;
90 | min_axis = max_axis;
91 | }
92 |
93 | BoxSide side = getBoxSide(octant, min_axis);
94 | hit->position = scaleAddVec3(*Rd, mint, *Ro);
95 | hit->normal = getVec3Of(0);
96 | switch (side) {
97 | case Left: hit->normal.x = hit->from_behind ? +1.0f : -1.0f; break;
98 | case Right: hit->normal.x = hit->from_behind ? -1.0f : +1.0f; break;
99 | case Bottom: hit->normal.y = hit->from_behind ? +1.0f : -1.0f; break;
100 | case Top: hit->normal.y = hit->from_behind ? -1.0f : +1.0f; break;
101 | case Back: hit->normal.z = hit->from_behind ? +1.0f : -1.0f; break;
102 | case Front: hit->normal.z = hit->from_behind ? -1.0f : +1.0f; break;
103 | default: return NoSide;
104 | }
105 |
106 | return side;
107 | }
108 |
109 | INLINE bool rayHitScene(Ray *ray, RayHit *local_hit, RayHit *hit, Scene *scene) {
110 | bool current_found, found = false;
111 | vec3 Ro, Rd;
112 | Primitive hit_primitive, primitive;
113 | for (u32 i = 0; i < scene->settings.primitives; i++) {
114 | primitive = scene->primitives[i];
115 | if (primitive.type == PrimitiveType_Mesh)
116 | primitive.scale = mulVec3(primitive.scale, scene->meshes[primitive.id].aabb.max);
117 |
118 | convertPositionAndDirectionToObjectSpace(ray->origin, ray->direction, &primitive, &Ro, &Rd);
119 |
120 | current_found = hitCube(local_hit, &Ro, &Rd);
121 | if (current_found) {
122 | local_hit->position = convertPositionToWorldSpace(local_hit->position, &primitive);
123 | local_hit->distance_squared = squaredLengthVec3(subVec3(local_hit->position, ray->origin));
124 | if (local_hit->distance_squared < hit->distance_squared) {
125 | *hit = *local_hit;
126 | hit->object_type = primitive.type;
127 | hit->object_id = i;
128 |
129 | hit_primitive = primitive;
130 | found = true;
131 | }
132 | }
133 | }
134 |
135 | if (found) {
136 | hit->distance = sqrtf(hit->distance_squared);
137 | hit->normal = normVec3(convertDirectionToWorldSpace(hit->normal, &hit_primitive));
138 | }
139 |
140 | return found;
141 | }
142 |
143 | void manipulateSelection(Scene *scene, Viewport *viewport, Controls *controls) {
144 | Mouse *mouse = &controls->mouse;
145 | Camera *camera = viewport->camera;
146 | Dimensions *dimensions = &viewport->dimensions;
147 | Selection *selection = scene->selection;
148 |
149 | setProjectionMatrix(viewport);
150 | setViewportProjectionPlane(viewport);
151 |
152 | vec3 position;
153 | vec3 *cam_pos = &camera->transform.position;
154 | mat3 *rot = &camera->transform.rotation_matrix;
155 | mat3 *inv_rot = &camera->transform.rotation_matrix_inverted;
156 | RayHit *hit = &selection->hit;
157 | Ray ray, *local_ray = &selection->local_ray;
158 | Primitive primitive;
159 | vec2i mouse_pos = Vec2i(mouse->pos.x - viewport->position.x,
160 | mouse->pos.y - viewport->position.y);
161 |
162 | if (mouse->left_button.is_pressed) {
163 | if (!mouse->left_button.is_handled) { // This is the first frame after the left mouse button went down:
164 | mouse->left_button.is_handled = true;
165 |
166 | // Cast a ray onto the scene to find the closest object behind the hovered pixel:
167 | setRayFromCoords(&ray, mouse_pos, viewport);
168 |
169 | hit->distance_squared = INFINITY;
170 | if (rayHitScene(&ray, &selection->local_hit, hit, scene)) {
171 | // Detect if object scene->selection has changed:
172 | selection->changed = (
173 | selection->object_type != hit->object_type ||
174 | selection->object_id != hit->object_id
175 | );
176 |
177 | // Track the object that is now selected:
178 | selection->object_type = hit->object_type;
179 | selection->object_id = hit->object_id;
180 | selection->primitive = null;
181 |
182 | // Capture a pointer to the selected object's position for later use in transformations:
183 | selection->primitive = scene->primitives + selection->object_id;
184 | selection->world_position = &selection->primitive->position;
185 | selection->transformation_plane_origin = hit->position;
186 |
187 | selection->world_offset = subVec3(hit->position, *selection->world_position);
188 |
189 | // Track how far away the hit position is from the camera along the z axis:
190 | position = mulVec3Mat3(subVec3(hit->position, ray.origin), *inv_rot);
191 | selection->object_distance = position.z;
192 | } else {
193 | if (selection->object_type)
194 | selection->changed = true;
195 | selection->object_type = 0;
196 | }
197 | }
198 | }
199 |
200 | if (selection->object_type) {
201 | if (controls->is_pressed.alt) {
202 | bool any_mouse_button_is_pressed = (
203 | mouse->left_button.is_pressed ||
204 | mouse->middle_button.is_pressed ||
205 | mouse->right_button.is_pressed);
206 | if (selection->primitive && !any_mouse_button_is_pressed) {
207 | // Cast a ray onto the bounding box of the currently selected object:
208 | setRayFromCoords(&ray, mouse_pos, viewport);
209 | primitive = *selection->primitive;
210 | if (primitive.type == PrimitiveType_Mesh)
211 | primitive.scale = mulVec3(primitive.scale, scene->meshes[primitive.id].aabb.max);
212 |
213 | convertPositionAndDirectionToObjectSpace(ray.origin, ray.direction, &primitive, &local_ray->origin, &local_ray->direction);
214 |
215 | selection->box_side = hitCube(hit, &local_ray->origin, &local_ray->direction);
216 | if (selection->box_side) {
217 | selection->transformation_plane_center = convertPositionToWorldSpace(hit->normal, &primitive);
218 | selection->transformation_plane_origin = convertPositionToWorldSpace(hit->position, &primitive);
219 | selection->transformation_plane_normal = convertDirectionToWorldSpace(hit->normal, &primitive);
220 | selection->transformation_plane_normal = normVec3(selection->transformation_plane_normal);
221 | selection->world_offset = subVec3(selection->transformation_plane_origin, *selection->world_position);
222 | selection->object_scale = selection->primitive->scale;
223 | selection->object_rotation = selection->primitive->rotation;
224 | }
225 | }
226 |
227 | if (selection->box_side) {
228 | if (selection->primitive) {
229 | if (any_mouse_button_is_pressed) {
230 | setRayFromCoords(&ray, mouse_pos, viewport);
231 | if (hitPlane(selection->transformation_plane_origin,
232 | selection->transformation_plane_normal,
233 | &ray.origin,
234 | &ray.direction,
235 | hit)) {
236 |
237 | primitive = *selection->primitive;
238 | if (primitive.type == PrimitiveType_Mesh)
239 | primitive.scale = mulVec3(primitive.scale, scene->meshes[primitive.id].aabb.max);
240 | if (mouse->left_button.is_pressed) {
241 | position = subVec3(hit->position, selection->world_offset);
242 | *selection->world_position = position;
243 | if (selection->primitive)
244 | selection->primitive->flags |= IS_TRANSLATED;
245 | } else if (mouse->middle_button.is_pressed) {
246 | position = selection->transformation_plane_origin;
247 | position = convertPositionToObjectSpace( position, &primitive);
248 | hit->position = convertPositionToObjectSpace(hit->position, &primitive);
249 |
250 | selection->primitive->scale = mulVec3(selection->object_scale,
251 | mulVec3(hit->position, oneOverVec3(position)));
252 | selection->primitive->flags |= IS_SCALED | IS_SCALED_NON_UNIFORMLY;
253 | } else if (mouse->right_button.is_pressed) {
254 | vec3 v1 = subVec3(hit->position,
255 | selection->transformation_plane_center);
256 | vec3 v2 = subVec3(selection->transformation_plane_origin,
257 | selection->transformation_plane_center);
258 | quat q;
259 | q.axis = crossVec3(v2, v1);
260 | q.amount = sqrtf(squaredLengthVec3(v1) * squaredLengthVec3(v2)) + dotVec3(v1, v2);
261 | q = normQuat(q);
262 | selection->primitive->rotation = mulQuat(q, selection->object_rotation);
263 | selection->primitive->rotation = normQuat(selection->primitive->rotation);
264 | selection->primitive->flags |= IS_ROTATED;
265 | }
266 | }
267 | }
268 | }
269 | }
270 | } else {
271 | selection->box_side = NoSide;
272 | if (mouse->left_button.is_pressed && mouse->moved) {
273 | // Back-project the new mouse position onto a quad at a distance of the selected-object away from the camera
274 | position.z = selection->object_distance;
275 |
276 | // Screen -> NDC:
277 | position.x = ((f32)mouse_pos.x + 0.5f) / dimensions->h_width - 1;
278 | position.y = ((f32)mouse_pos.y + 0.5f) / dimensions->h_height - 1;
279 | position.y = -position.y;
280 |
281 | // NDC -> View:
282 | position.x *= position.z / (camera->focal_length * dimensions->height_over_width);
283 | position.y *= position.z / camera->focal_length;
284 |
285 | // View -> World:
286 | position = addVec3(mulVec3Mat3(position, *rot), *cam_pos);
287 |
288 | // Back-track by the world offset (from the hit position back to the selected-object's center):
289 | position = subVec3(position, selection->world_offset);
290 | *selection->world_position = position;
291 | if (selection->primitive)
292 | selection->primitive->flags |= IS_TRANSLATED;
293 | }
294 | }
295 | }
296 | }
297 |
298 | void drawSelection(Scene *scene, Viewport *viewport, Controls *controls) {
299 | Mouse *mouse = &controls->mouse;
300 | Selection *selection = scene->selection;
301 | Box *box = &selection->box;
302 |
303 | if (controls->is_pressed.alt &&
304 | !mouse->is_captured &&
305 | selection->object_type &&
306 | selection->primitive) {
307 | Primitive primitive = *selection->primitive;
308 | if (primitive.type == PrimitiveType_Mesh)
309 | primitive.scale = mulVec3(primitive.scale, scene->meshes[primitive.id].aabb.max);
310 |
311 | initBox(box);
312 | drawBox(box, BOX__ALL_SIDES, &primitive, Color(Yellow), 0.5f, 0, viewport);
313 | if (selection->box_side) {
314 | vec3 color = Color(White);
315 | switch (selection->box_side) {
316 | case Left: case Right: color = Color(Red); break;
317 | case Top: case Bottom: color = Color(Green); break;
318 | case Front: case Back: color = Color(Blue); break;
319 | case NoSide: break;
320 | }
321 | drawBox(box, selection->box_side, &primitive, color, 0.5f, 1, viewport);
322 | }
323 | }
324 | }
--------------------------------------------------------------------------------
/src/SlimRaster/viewport/navigation.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../core/types.h"
4 | #include "../math/vec3.h"
5 | #include "../scene/xform.h"
6 |
7 | void zoomCamera(Camera *camera, f32 zoom) {
8 | f32 new_zoom = camera->zoom + zoom;
9 | camera->focal_length = new_zoom > 1 ? new_zoom : (new_zoom < -1 ? (-1 / new_zoom) : 1);
10 | camera->zoom = new_zoom;
11 | }
12 |
13 | void dollyCamera(Camera *camera, f32 dolly) {
14 | vec3 target_position = scaleVec3(*camera->transform.forward_direction, camera->target_distance);
15 | target_position = addVec3(camera->transform.position, target_position);
16 |
17 | // Compute new target distance:
18 | camera->dolly += dolly;
19 | camera->target_distance = powf(2, camera->dolly / -200) * CAMERA_DEFAULT__TARGET_DISTANCE;
20 |
21 | // Back-track from target position to new current position:
22 | camera->transform.position = scaleVec3(*camera->transform.forward_direction, camera->target_distance);
23 | camera->transform.position = subVec3(target_position,camera->transform.position);
24 | }
25 |
26 | void orbitCamera(Camera *camera, f32 azimuth, f32 altitude) {
27 | // Move the camera forward to the position of it's target:
28 | vec3 movement = scaleVec3(*camera->transform.forward_direction, camera->target_distance);
29 | camera->transform.position = addVec3(camera->transform.position, movement);
30 |
31 | // Reorient the camera while it is at the position of it's target:
32 | rotateXform3(&camera->transform, azimuth, altitude, 0);
33 |
34 | // Back the camera away from it's target position using the updated forward direction:
35 | movement = scaleVec3(*camera->transform.forward_direction, camera->target_distance);
36 | camera->transform.position = subVec3(camera->transform.position, movement);
37 | }
38 |
39 | void panCamera(Camera *camera, f32 right, f32 up) {
40 | vec3 up_movement = scaleVec3(*camera->transform.up_direction, up);
41 | vec3 right_movement = scaleVec3(*camera->transform.right_direction, right);
42 | camera->transform.position = addVec3(camera->transform.position, up_movement);
43 | camera->transform.position = addVec3(camera->transform.position, right_movement);
44 | }
45 |
46 | void panViewport(Viewport *viewport, Mouse *mouse) {
47 | f32 x = viewport->navigation.settings.speeds.pan * -(f32)mouse->pos_raw_diff.x;
48 | f32 y = viewport->navigation.settings.speeds.pan * +(f32)mouse->pos_raw_diff.y;
49 | panCamera(viewport->camera, x, y);
50 |
51 | viewport->navigation.moved = true;
52 | mouse->raw_movement_handled = true;
53 | mouse->moved = false;
54 | }
55 |
56 | void zoomViewport(Viewport *viewport, Mouse *mouse) {
57 | f32 z = viewport->navigation.settings.speeds.zoom * mouse->wheel_scroll_amount;
58 | zoomCamera(viewport->camera, z);
59 |
60 | viewport->navigation.zoomed = true;
61 | mouse->wheel_scroll_handled = true;
62 | }
63 |
64 | void dollyViewport(Viewport *viewport, Mouse *mouse) {
65 | f32 z = viewport->navigation.settings.speeds.dolly * mouse->wheel_scroll_amount;
66 | dollyCamera(viewport->camera, z);
67 | viewport->navigation.moved = true;
68 | mouse->wheel_scroll_handled = true;
69 | }
70 |
71 | void orientViewport(Viewport *viewport, Mouse *mouse) {
72 | f32 x = viewport->navigation.settings.speeds.orient * -(f32)mouse->pos_raw_diff.x;
73 | f32 y = viewport->navigation.settings.speeds.orient * -(f32)mouse->pos_raw_diff.y;
74 | rotateXform3(&viewport->camera->transform, x, y, 0);
75 |
76 | mouse->moved = false;
77 | mouse->raw_movement_handled = true;
78 | viewport->navigation.turned = true;
79 | }
80 |
81 | void orbitViewport(Viewport *viewport, Mouse *mouse) {
82 | f32 x = viewport->navigation.settings.speeds.orbit * -(f32)mouse->pos_raw_diff.x;
83 | f32 y = viewport->navigation.settings.speeds.orbit * -(f32)mouse->pos_raw_diff.y;
84 | orbitCamera(viewport->camera, x, y);
85 |
86 | viewport->navigation.turned = true;
87 | viewport->navigation.moved = true;
88 | mouse->raw_movement_handled = true;
89 | mouse->moved = false;
90 | }
91 |
92 | void navigateViewport(Viewport *viewport, f32 delta_time) {
93 | vec3 target_velocity = getVec3Of(0);
94 | Navigation *navigation = &viewport->navigation;
95 | Camera *camera = viewport->camera;
96 |
97 | if (navigation->move.right) target_velocity.x += navigation->settings.max_velocity;
98 | if (navigation->move.left) target_velocity.x -= navigation->settings.max_velocity;
99 | if (navigation->move.up) target_velocity.y += navigation->settings.max_velocity;
100 | if (navigation->move.down) target_velocity.y -= navigation->settings.max_velocity;
101 | if (navigation->move.forward) target_velocity.z += navigation->settings.max_velocity;
102 | if (navigation->move.backward) target_velocity.z -= navigation->settings.max_velocity;
103 | if (navigation->turn.left) {
104 | rotateXform3(&camera->transform, delta_time * +navigation->settings.speeds.turn, 0, 0);
105 | navigation->turned = true;
106 | }
107 | if (navigation->turn.right) {
108 | rotateXform3(&camera->transform, delta_time * -navigation->settings.speeds.turn, 0, 0);
109 | navigation->turned = true;
110 | }
111 |
112 | // Update the current velocity:
113 | f32 velocity_difference = navigation->settings.acceleration * delta_time;
114 | camera->current_velocity = approachVec3(camera->current_velocity, target_velocity, velocity_difference);
115 |
116 | navigation->moved = nonZeroVec3(camera->current_velocity);
117 | if (navigation->moved) { // Update the current position:
118 | vec3 movement = scaleVec3(camera->current_velocity, delta_time);
119 | movement = mulVec3Mat3(movement, camera->transform.rotation_matrix);
120 | camera->transform.position = addVec3(camera->transform.position, movement);
121 | }
122 | }
--------------------------------------------------------------------------------
/src/SlimRaster/viewport/viewport.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../math/vec3.h"
4 | #include "./hud.h"
5 |
6 | typedef union RGBA2u32 {
7 | RGBA rgba;
8 | u32 value;
9 | } RGBA2u32;
10 |
11 | void drawViewportToWindowContent(Viewport *viewport) {
12 | PixelQuad *src_pixel = viewport->pixels;
13 | u32 *trg_value = app->window_content;
14 | vec3 color;
15 | RGBA2u32 background, trg_pixel;
16 | background.rgba.R = (u8)(viewport->settings.background.color.r * FLOAT_TO_COLOR_COMPONENT);
17 | background.rgba.G = (u8)(viewport->settings.background.color.g * FLOAT_TO_COLOR_COMPONENT);
18 | background.rgba.B = (u8)(viewport->settings.background.color.b * FLOAT_TO_COLOR_COMPONENT);
19 | background.rgba.A = (u8)(viewport->settings.background.opacity * FLOAT_TO_COLOR_COMPONENT);
20 | if (viewport->settings.antialias) {
21 | for (u16 y = 0; y < viewport->dimensions.height; y++) {
22 | for (u16 x = 0; x < viewport->dimensions.width; x++, src_pixel++, trg_value++) {
23 | if (src_pixel->TL.opacity || src_pixel->TR.opacity || src_pixel->BL.opacity || src_pixel->BR.opacity) {
24 | color = scaleVec3(src_pixel->TL.color, src_pixel->TL.opacity * 0.25f);
25 | color = scaleAddVec3(src_pixel->TR.color, src_pixel->TR.opacity * 0.25f, color);
26 | color = scaleAddVec3(src_pixel->BL.color, src_pixel->BL.opacity * 0.25f, color);
27 | color = scaleAddVec3(src_pixel->BR.color, src_pixel->BR.opacity * 0.25f, color);
28 | trg_pixel.rgba.R = (u8)(color.r > (MAX_COLOR_VALUE * MAX_COLOR_VALUE) ? MAX_COLOR_VALUE : sqrt(color.r));
29 | trg_pixel.rgba.G = (u8)(color.g > (MAX_COLOR_VALUE * MAX_COLOR_VALUE) ? MAX_COLOR_VALUE : sqrt(color.g));
30 | trg_pixel.rgba.B = (u8)(color.b > (MAX_COLOR_VALUE * MAX_COLOR_VALUE) ? MAX_COLOR_VALUE : sqrt(color.b));
31 | trg_pixel.rgba.A = (u8)(clampValue(src_pixel->TL.opacity) * FLOAT_TO_COLOR_COMPONENT);
32 | } else trg_pixel = background;
33 | *trg_value = trg_pixel.value;
34 | }
35 | }
36 | } else {
37 | for (u16 y = 0; y < viewport->dimensions.height; y++) {
38 | for (u16 x = 0; x < viewport->dimensions.width; x++, src_pixel++, trg_value++) {
39 | if (src_pixel->TL.depth == INFINITY)
40 | trg_pixel = background;
41 | else {
42 | color = scaleVec3(src_pixel->TL.color, src_pixel->TL.opacity);
43 | trg_pixel.rgba.R = (u8)(color.r > (MAX_COLOR_VALUE * MAX_COLOR_VALUE) ? MAX_COLOR_VALUE : sqrt(color.r));
44 | trg_pixel.rgba.G = (u8)(color.g > (MAX_COLOR_VALUE * MAX_COLOR_VALUE) ? MAX_COLOR_VALUE : sqrt(color.g));
45 | trg_pixel.rgba.B = (u8)(color.b > (MAX_COLOR_VALUE * MAX_COLOR_VALUE) ? MAX_COLOR_VALUE : sqrt(color.b));
46 | trg_pixel.rgba.A = (u8)(clampValue(src_pixel->TL.opacity) * FLOAT_TO_COLOR_COMPONENT);
47 | }
48 | *trg_value = trg_pixel.value;
49 | }
50 | }
51 | }
52 | }
53 |
54 | void fillViewport(Viewport *viewport, vec3 color, f32 opacity, f64 depth) {
55 | PixelQuad fill_pixel;
56 | Pixel fill_sub_pixel;
57 | fill_sub_pixel.color = color;
58 | fill_sub_pixel.opacity = opacity;
59 | fill_sub_pixel.depth = depth;
60 | fill_pixel.TL = fill_pixel.TR = fill_pixel.BL = fill_pixel.BR = fill_sub_pixel;
61 | for (i32 y = viewport->position.y; y < (viewport->position.y + viewport->dimensions.height); y++)
62 | for (i32 x = viewport->position.x; x < (viewport->position.x + viewport->dimensions.width); x++)
63 | viewport->pixels[viewport->dimensions.stride * y + x] = fill_pixel;
64 | }
65 |
66 | void clearViewportToBackground(Viewport *viewport) {
67 | fillViewport(viewport,
68 | viewport->settings.background.color,
69 | viewport->settings.background.opacity,
70 | viewport->settings.background.depth);
71 | }
72 |
73 | void beginDrawing(Viewport *viewport) {
74 | clearViewportToBackground(viewport);
75 | setProjectionMatrix(viewport);
76 | }
77 |
78 | void endDrawing(Viewport *viewport) {
79 | if (viewport->settings.show_hud)
80 | drawHUD(viewport, &viewport->hud);
81 | drawViewportToWindowContent(viewport);
82 | }
--------------------------------------------------------------------------------
/src/examples/1_clipping_interpolation.c:
--------------------------------------------------------------------------------
1 | #include "../SlimRaster/app.h"
2 | #include "../SlimRaster/core/time.h"
3 | #include "../SlimRaster/viewport/viewport.h"
4 | #include "../SlimRaster/viewport/navigation.h"
5 | #include "../SlimRaster/viewport/manipulation.h"
6 | #include "../SlimRaster/renderer/rasterizer.h"
7 | // Or using the single-header file:
8 | // #include "../SlimRaster.h"
9 |
10 |
11 | void onMouseButtonDown(MouseButton *mouse_button) {
12 | app->controls.mouse.pos_raw_diff = Vec2i(0, 0);
13 | }
14 | void onMouseDoubleClicked(MouseButton *mouse_button) {
15 | if (mouse_button == &app->controls.mouse.left_button) {
16 | app->controls.mouse.is_captured = !app->controls.mouse.is_captured;
17 | app->platform.setCursorVisibility(!app->controls.mouse.is_captured);
18 | app->platform.setWindowCapture( app->controls.mouse.is_captured);
19 | onMouseButtonDown(mouse_button);
20 | }
21 | }
22 | void onKeyChanged(u8 key, bool is_pressed) {
23 | if (!is_pressed) {
24 | Viewport *viewport = &app->viewport;
25 | ViewportSettings *settings = &viewport->settings;
26 | u8 tab = app->controls.key_map.tab;
27 | if (key == tab) settings->show_hud = !settings->show_hud;
28 | if (key == '1') {
29 | settings->show_wire_frame = !settings->show_wire_frame;
30 | setString(&viewport->hud.lines[1].value.string,settings->show_wire_frame ? (char*)"On" : (char*)"Off");
31 | viewport->hud.lines[1].value_color = settings->show_wire_frame ? White : Grey;
32 | }
33 | if (key == '2') {
34 | settings->antialias = !settings->antialias;
35 | setString(&viewport->hud.lines[2].value.string,settings->antialias ? (char*)"On" : (char*)"Off");
36 | viewport->hud.lines[2].value_color = settings->antialias ? White : Grey;
37 | }
38 | }
39 |
40 | NavigationMove *move = &app->viewport.navigation.move;
41 | if (key == 'R') move->up = is_pressed;
42 | if (key == 'F') move->down = is_pressed;
43 | if (key == 'W') move->forward = is_pressed;
44 | if (key == 'A') move->left = is_pressed;
45 | if (key == 'S') move->backward = is_pressed;
46 | if (key == 'D') move->right = is_pressed;
47 | }
48 | void updateViewport(Viewport *viewport, Mouse *mouse) {
49 | if (mouse->is_captured) {
50 | navigateViewport(viewport, app->time.timers.update.delta_time);
51 | if (mouse->moved) orientViewport(viewport, mouse);
52 | if (mouse->wheel_scrolled) zoomViewport(viewport, mouse);
53 | } else {
54 | if (mouse->wheel_scrolled) dollyViewport(viewport, mouse);
55 | if (mouse->moved) {
56 | if (mouse->middle_button.is_pressed) panViewport(viewport, mouse);
57 | if (mouse->right_button.is_pressed) orbitViewport(viewport, mouse);
58 | }
59 | }
60 | }
61 | void updateAndRender() {
62 | Timer *timer = &app->time.timers.update;
63 | Controls *controls = &app->controls;
64 | Viewport *viewport = &app->viewport;
65 | Mouse *mouse = &controls->mouse;
66 | Scene *scene = &app->scene;
67 |
68 | beginFrame(timer);
69 | if (!mouse->is_captured) manipulateSelection(scene, viewport, controls);
70 | if (!controls->is_pressed.alt) updateViewport(viewport, mouse);
71 | beginDrawing(viewport);
72 | rasterize(scene, viewport, &app->rasterizer);
73 | drawSelection(scene, viewport, controls);
74 | printNumberIntoString((i16)app->time.timers.update.average_frames_per_second, &viewport->hud.lines->value);
75 | endDrawing(viewport);
76 | endFrame(timer, mouse);
77 | }
78 | void setupViewport(Viewport *viewport) {
79 | xform3 *cam_xform = &viewport->camera->transform;
80 | cam_xform->position = Vec3(0, 15, -15);
81 | rotateXform3(cam_xform, 0, -0.25f, 0);
82 |
83 | i32 average_fps = app->time.timers.update.average_frames_per_second;
84 |
85 | HUDLine *fps = viewport->hud.lines;
86 | HUDLine *wireframe = fps + 1;
87 | HUDLine *msaa = wireframe + 1;
88 | HUDLine *mode = msaa + 1;
89 | wireframe->value_color = msaa->value_color = mode->value_color = Grey;
90 |
91 | printNumberIntoString(average_fps, &fps->value);
92 |
93 | setString(&fps->title, (char*)"Fps: ");
94 | setString(&wireframe->title, (char*)"Wireframe: ");
95 | setString(&wireframe->value.string, (char*)"Off");
96 | setString(&msaa->title, (char*)"MSAA: ");
97 | setString(&msaa->value.string, (char*)"Off");
98 | setString(&mode->title, (char*)"Mode: ");
99 | setString(&mode->value.string, (char*)"Beauty");
100 | }
101 | void setupScene(Scene *scene) {
102 | Material *floor_material = scene->materials + 0;
103 | Material *monkey_material1 = scene->materials + 1;
104 | Material *monkey_material2 = scene->materials + 2;
105 | Material *monkey_material3 = scene->materials + 3;
106 | Primitive *floor = scene->primitives + 0;
107 | Primitive *monkey1 = scene->primitives + 1;
108 | Primitive *monkey2 = scene->primitives + 2;
109 | Primitive *monkey3 = scene->primitives + 3;
110 |
111 | monkey_material1->pixel_shader = shadePixelPosition;
112 | monkey_material2->pixel_shader = shadePixelUV;
113 | monkey_material3->pixel_shader = shadePixelNormal;
114 | floor_material->pixel_shader = shadePixelCheckerboard;
115 |
116 | floor->type = PrimitiveType_Box;
117 | floor->scale = Vec3(16, 1, 16);
118 | floor->position = Vec3(-6, -3, 0);
119 | floor->material_id = 0;
120 |
121 | monkey1->type = monkey2->type = monkey3->type = PrimitiveType_Mesh;
122 | monkey1->id = monkey2->id = monkey3->id = 0;
123 | monkey1->material_id = 1;
124 | monkey2->material_id = 2;
125 | monkey3->material_id = 3;
126 | monkey2->position = Vec3(2, 2, 3);
127 | monkey3->position = Vec3(-2, 2, -3);
128 | monkey1->rotation = getRotationAroundAxisBySinCon(Vec3(0, 1, 0), Vec2(sinf(0.5f), cosf(0.5f)));
129 |
130 | floor_material->texture_count = 2;
131 | floor_material->texture_ids[0] = 0;
132 | floor_material->texture_ids[1] = 1;
133 | floor_material->normal_magnitude = 0.4f;
134 | }
135 |
136 | void initApp(Defaults *defaults) {
137 | static char string_buffer[100];
138 | static String file;
139 | file.char_ptr = string_buffer;
140 | char* this_file = __FILE__;
141 | char* monkey_mesh = "suzanne.mesh";
142 | u32 dir_len = getDirectoryLength(this_file);
143 | mergeString(&file, this_file, monkey_mesh, dir_len);
144 | defaults->settings.scene.meshes = 1;
145 | defaults->settings.scene.mesh_files = &file;
146 | defaults->settings.scene.primitives = 4;
147 | defaults->settings.scene.materials = 4;
148 | defaults->settings.viewport.near_clipping_plane_distance = 1;
149 | defaults->settings.viewport.hud_line_count = 4;
150 | app->on.sceneReady = setupScene;
151 | app->on.viewportReady = setupViewport;
152 | app->on.windowRedraw = updateAndRender;
153 | app->on.keyChanged = onKeyChanged;
154 | app->on.mouseButtonDown = onMouseButtonDown;
155 | app->on.mouseButtonDoubleClicked = onMouseDoubleClicked;
156 | }
--------------------------------------------------------------------------------
/src/examples/1_clipping_interpolation.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HardCoreCodin/SlimRaster/3718a02b52844f5a66376314ff63b76eff886e56/src/examples/1_clipping_interpolation.gif
--------------------------------------------------------------------------------
/src/examples/2_normal_maps.c:
--------------------------------------------------------------------------------
1 | #include "../SlimRaster/app.h"
2 | #include "../SlimRaster/core/time.h"
3 | #include "../SlimRaster/viewport/viewport.h"
4 | #include "../SlimRaster/viewport/navigation.h"
5 | #include "../SlimRaster/viewport/manipulation.h"
6 | #include "../SlimRaster/renderer/rasterizer.h"
7 | // Or using the single-header file:
8 | // #include "../SlimRaster.h"
9 |
10 |
11 | void onMouseButtonDown(MouseButton *mouse_button) {
12 | app->controls.mouse.pos_raw_diff = Vec2i(0, 0);
13 | }
14 | void onMouseDoubleClicked(MouseButton *mouse_button) {
15 | if (mouse_button == &app->controls.mouse.left_button) {
16 | app->controls.mouse.is_captured = !app->controls.mouse.is_captured;
17 | app->platform.setCursorVisibility(!app->controls.mouse.is_captured);
18 | app->platform.setWindowCapture( app->controls.mouse.is_captured);
19 | onMouseButtonDown(mouse_button);
20 | }
21 | }
22 | void onKeyChanged(u8 key, bool is_pressed) {
23 | if (!is_pressed) {
24 | Viewport *viewport = &app->viewport;
25 | ViewportSettings *settings = &viewport->settings;
26 | u8 tab = app->controls.key_map.tab;
27 | if (key == tab) settings->show_hud = !settings->show_hud;
28 | }
29 |
30 | NavigationMove *move = &app->viewport.navigation.move;
31 | if (key == 'R') move->up = is_pressed;
32 | if (key == 'F') move->down = is_pressed;
33 | if (key == 'W') move->forward = is_pressed;
34 | if (key == 'A') move->left = is_pressed;
35 | if (key == 'S') move->backward = is_pressed;
36 | if (key == 'D') move->right = is_pressed;
37 | }
38 | void updateViewport(Viewport *viewport, Mouse *mouse) {
39 | if (mouse->is_captured) {
40 | navigateViewport(viewport, app->time.timers.update.delta_time);
41 | if (mouse->moved) orientViewport(viewport, mouse);
42 | if (mouse->wheel_scrolled) zoomViewport(viewport, mouse);
43 | } else {
44 | if (mouse->wheel_scrolled) dollyViewport(viewport, mouse);
45 | if (mouse->moved) {
46 | if (mouse->middle_button.is_pressed) panViewport(viewport, mouse);
47 | if (mouse->right_button.is_pressed) orbitViewport(viewport, mouse);
48 | }
49 | }
50 | }
51 | void updateAndRender() {
52 | Timer *timer = &app->time.timers.update;
53 | Controls *controls = &app->controls;
54 | Viewport *viewport = &app->viewport;
55 | Mouse *mouse = &controls->mouse;
56 | Scene *scene = &app->scene;
57 | f32 dt = app->time.timers.update.delta_time;
58 | static float elapsed = 0;
59 | elapsed += dt;
60 |
61 | vec2 sincos = Vec2(sinf(elapsed), cosf(elapsed));
62 | vec3 *prim_pos = &scene->primitives[0].position;
63 | vec3 *light_pos = &scene->lights[0].position_or_direction;
64 |
65 | light_pos->x = prim_pos->x - 3.0f + sincos.x * 0.6f;
66 | light_pos->z = prim_pos->z + 3.0f + sincos.y * 0.6f;
67 | light_pos->y = 2 + sinf(elapsed * 2.0f);
68 |
69 | prim_pos = &scene->primitives[1].position;
70 | light_pos = &scene->lights[2].position_or_direction;
71 | light_pos->x = prim_pos->x + 3.0f + sinf(elapsed * 0.5f) * 0.6f;
72 | light_pos->z = prim_pos->z + 3.0f + cosf(elapsed * 0.5f) * 0.6f;
73 | light_pos->y = 2 + cosf(elapsed * 2.0f);
74 |
75 | beginFrame(timer);
76 | if (!mouse->is_captured) manipulateSelection(scene, viewport, controls);
77 | Material *material = scene->materials + scene->selection->object_id;
78 | if (controls->is_pressed.ctrl) {
79 | if (mouse->wheel_scrolled) {
80 | mouse->wheel_scrolled = false;
81 | mouse->wheel_scroll_handled = true;
82 | material->normal_magnitude += mouse->wheel_scroll_amount * 0.001f;
83 | material->normal_magnitude = clampValueToBetween(material->normal_magnitude, 0, 4);
84 | printFloatIntoString(material->normal_magnitude, &viewport->hud.lines->value, 1);
85 | }
86 | } else if (!controls->is_pressed.alt) updateViewport(viewport, mouse);
87 | if (scene->selection->changed) {
88 | scene->selection->changed = false;
89 | if (!mouse->wheel_scroll_handled)
90 | printFloatIntoString(material->normal_magnitude, &viewport->hud.lines->value, 1);
91 | }
92 | beginDrawing(viewport);
93 | rasterize(scene, viewport, &app->rasterizer);
94 | drawSelection(scene, viewport, controls);
95 | endDrawing(viewport);
96 | endFrame(timer, mouse);
97 | }
98 | void setupViewport(Viewport *viewport) {
99 | xform3 *cam_xform = &viewport->camera->transform;
100 | cam_xform->position = Vec3(0, 15, -15);
101 | rotateXform3(cam_xform, 0, -0.25f, 0);
102 | setString(&viewport->hud.lines->title, (char*)"Normal Magnitude: ");
103 | }
104 | void setupScene(Scene *scene) {
105 | scene->ambient_light.color = Vec3(0.008f, 0.008f, 0.014f);
106 |
107 | Light *light1 = scene->lights + 0;
108 | Light *light2 = scene->lights + 1;
109 | Light *light3 = scene->lights + 2;
110 | Material *floor_material = scene->materials + 0;
111 | Material *dog_material = scene->materials + 1;
112 | Primitive *floor = scene->primitives + 0;
113 | Primitive *dog = scene->primitives + 1;
114 |
115 | floor_material->flags |= PHONG;
116 | floor_material->diffuse = Vec3(0.7f, 0.7f, 0.7f);
117 | floor_material->pixel_shader = shadePixelClassic;
118 | floor_material->texture_count = 2;
119 | floor_material->texture_ids[0] = 0;
120 | floor_material->texture_ids[1] = 1;
121 | floor_material->normal_magnitude = 0.4f;
122 |
123 | dog_material->flags |= PHONG;
124 | dog_material->diffuse = Vec3(0.4f, 0.4f, 0.4f);
125 | dog_material->pixel_shader = shadePixelClassic;
126 | dog_material->texture_count = 2;
127 | dog_material->texture_ids[0] = 2;
128 | dog_material->texture_ids[1] = 3;
129 | dog_material->normal_magnitude = 3.0f;
130 |
131 | floor->type = PrimitiveType_Box;
132 | floor->scale = Vec3(16, 1, 16);
133 | floor->position = Vec3(-6, -3, 0);
134 | floor->material_id = 0;
135 |
136 | dog->type = PrimitiveType_Mesh;
137 | dog->id = 0;
138 | dog->material_id = 1;
139 | dog->position = Vec3(2, 2, 9);
140 | dog->rotation = getRotationAroundAxisBySinCon(Vec3(0, 1, 0), Vec2(sinf(0.5f), cosf(0.5f)));
141 |
142 | vec3 mesh1_position = Vec3(0, 0, 5);
143 | vec3 mesh2_position = Vec3(5, 0, 5);
144 |
145 | light1->intensity = 20;
146 | light1->color.r = 0.8f;
147 | light1->color.g = 0.3f;
148 | light1->color.b = 0.2f;
149 | light1->position_or_direction.x = mesh1_position.x - 3;
150 | light1->position_or_direction.z = mesh1_position.z + 3;
151 | light1->position_or_direction.y = 5;
152 |
153 | light2->intensity = 20;
154 | light2->color.r = 0.2f;
155 | light2->color.g = 0.3f;
156 | light2->color.b = 0.8f;
157 | light2->position_or_direction.x = mesh2_position.x + 3;
158 | light2->position_or_direction.z = mesh2_position.z + 3;
159 | light2->position_or_direction.y = 4;
160 |
161 | light3->intensity = 16;
162 | light3->color.r = 0.2f;
163 | light3->color.g = 0.9f;
164 | light3->color.b = 0.3f;
165 | light3->position_or_direction.x = (mesh1_position.x + mesh2_position.x) / 2;
166 | light3->position_or_direction.z = -1;
167 | light3->position_or_direction.y = 3;
168 | }
169 |
170 | void initApp(Defaults *defaults) {
171 | static char string_buffers[5][100];
172 | static String files[5];
173 | files[0].char_ptr = string_buffers[0];
174 | files[1].char_ptr = string_buffers[1];
175 | files[2].char_ptr = string_buffers[2];
176 | files[3].char_ptr = string_buffers[3];
177 | files[4].char_ptr = string_buffers[4];
178 |
179 | char* this_file = __FILE__;
180 | char* dog_mesh = "dog.mesh";
181 | char* dog_albedo = "dog_albedo.texture";
182 | char* dog_normal = "dog_normal.texture";
183 | char* floor_albedo = "floor_albedo.texture";
184 | char* floor_normal = "floor_normal.texture";
185 | u32 dir_len = getDirectoryLength(this_file);
186 | mergeString(files, this_file, dog_mesh, dir_len);
187 | mergeString(files + 1, this_file, floor_albedo, dir_len);
188 | mergeString(files + 2, this_file, floor_normal, dir_len);
189 | mergeString(files + 3, this_file, dog_albedo, dir_len);
190 | mergeString(files + 4, this_file, dog_normal, dir_len);
191 | defaults->settings.scene.textures = 4;
192 | defaults->settings.scene.meshes = 1;
193 | defaults->settings.scene.mesh_files = files;
194 | defaults->settings.scene.texture_files = files + 1;
195 | defaults->settings.scene.lights = 3;
196 | defaults->settings.scene.primitives = 2;
197 | defaults->settings.scene.materials = 2;
198 | defaults->settings.viewport.near_clipping_plane_distance = 1;
199 | defaults->settings.viewport.hud_line_count = 1;
200 | app->on.sceneReady = setupScene;
201 | app->on.viewportReady = setupViewport;
202 | app->on.windowRedraw = updateAndRender;
203 | app->on.keyChanged = onKeyChanged;
204 | app->on.mouseButtonDown = onMouseButtonDown;
205 | app->on.mouseButtonDoubleClicked = onMouseDoubleClicked;
206 | }
--------------------------------------------------------------------------------
/src/examples/2_normal_maps.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HardCoreCodin/SlimRaster/3718a02b52844f5a66376314ff63b76eff886e56/src/examples/2_normal_maps.gif
--------------------------------------------------------------------------------
/src/examples/3_anti_aliasing.c:
--------------------------------------------------------------------------------
1 | #include "../SlimRaster/app.h"
2 | #include "../SlimRaster/core/time.h"
3 | #include "../SlimRaster/viewport/viewport.h"
4 | #include "../SlimRaster/viewport/navigation.h"
5 | #include "../SlimRaster/viewport/manipulation.h"
6 | #include "../SlimRaster/renderer/rasterizer.h"
7 | // Or using the single-header file:
8 | // #include "../SlimRaster.h"
9 |
10 |
11 | void onMouseButtonDown(MouseButton *mouse_button) {
12 | app->controls.mouse.pos_raw_diff = Vec2i(0, 0);
13 | }
14 | void onMouseDoubleClicked(MouseButton *mouse_button) {
15 | if (mouse_button == &app->controls.mouse.left_button) {
16 | app->controls.mouse.is_captured = !app->controls.mouse.is_captured;
17 | app->platform.setCursorVisibility(!app->controls.mouse.is_captured);
18 | app->platform.setWindowCapture( app->controls.mouse.is_captured);
19 | onMouseButtonDown(mouse_button);
20 | }
21 | }
22 | void onKeyChanged(u8 key, bool is_pressed) {
23 | if (!is_pressed) {
24 | Viewport *viewport = &app->viewport;
25 | ViewportSettings *settings = &viewport->settings;
26 | u8 tab = app->controls.key_map.tab;
27 | if (key == tab) settings->show_hud = !settings->show_hud;
28 | if (key == '1') {
29 | settings->show_wire_frame = !settings->show_wire_frame;
30 | setString(&viewport->hud.lines[1].value.string,settings->show_wire_frame ? (char*)"On" : (char*)"Off");
31 | viewport->hud.lines[1].value_color = settings->show_wire_frame ? White : Grey;
32 | }
33 | if (key == '2') {
34 | settings->antialias = !settings->antialias;
35 | setString(&viewport->hud.lines[2].value.string,settings->antialias ? (char*)"On" : (char*)"Off");
36 | viewport->hud.lines[2].value_color = settings->antialias ? White : Grey;
37 | }
38 | }
39 |
40 | NavigationMove *move = &app->viewport.navigation.move;
41 | if (key == 'R') move->up = is_pressed;
42 | if (key == 'F') move->down = is_pressed;
43 | if (key == 'W') move->forward = is_pressed;
44 | if (key == 'A') move->left = is_pressed;
45 | if (key == 'S') move->backward = is_pressed;
46 | if (key == 'D') move->right = is_pressed;
47 | }
48 | void updateViewport(Viewport *viewport, Mouse *mouse) {
49 | if (mouse->is_captured) {
50 | navigateViewport(viewport, app->time.timers.update.delta_time);
51 | if (mouse->moved) orientViewport(viewport, mouse);
52 | if (mouse->wheel_scrolled) zoomViewport(viewport, mouse);
53 | } else {
54 | if (mouse->wheel_scrolled) dollyViewport(viewport, mouse);
55 | if (mouse->moved) {
56 | if (mouse->middle_button.is_pressed) panViewport(viewport, mouse);
57 | if (mouse->right_button.is_pressed) orbitViewport(viewport, mouse);
58 | }
59 | }
60 | }
61 | void updateAndRender() {
62 | Timer *timer = &app->time.timers.update;
63 | Controls *controls = &app->controls;
64 | Viewport *viewport = &app->viewport;
65 | Mouse *mouse = &controls->mouse;
66 | Scene *scene = &app->scene;
67 | f32 dt = app->time.timers.update.delta_time;
68 | static float elapsed = 0;
69 | elapsed += dt;
70 |
71 | vec2 sincos = Vec2(sinf(elapsed), cosf(elapsed));
72 | vec3 *prim_pos = &scene->primitives[0].position;
73 | vec3 *light_pos = &scene->lights[0].position_or_direction;
74 |
75 | light_pos->x = prim_pos->x - 3.0f + sincos.x * 0.6f;
76 | light_pos->z = prim_pos->z + 3.0f + sincos.y * 0.6f;
77 | light_pos->y = 2 + sinf(elapsed * 2.0f);
78 |
79 | prim_pos = &scene->primitives[1].position;
80 | light_pos = &scene->lights[2].position_or_direction;
81 | light_pos->x = prim_pos->x + 3.0f + sinf(elapsed * 0.5f) * 0.6f;
82 | light_pos->z = prim_pos->z + 3.0f + cosf(elapsed * 0.5f) * 0.6f;
83 | light_pos->y = 2 + cosf(elapsed * 2.0f);
84 |
85 | beginFrame(timer);
86 | if (!mouse->is_captured) manipulateSelection(scene, viewport, controls);
87 | if (!controls->is_pressed.alt) updateViewport(viewport, mouse);
88 | beginDrawing(viewport);
89 | rasterize(scene, viewport, &app->rasterizer);
90 | drawSelection(scene, viewport, controls);
91 | printNumberIntoString((i16)app->time.timers.update.average_frames_per_second, &viewport->hud.lines->value);
92 | endDrawing(viewport);
93 | endFrame(timer, mouse);
94 | }
95 | void setupViewport(Viewport *viewport) {
96 | xform3 *cam_xform = &viewport->camera->transform;
97 | cam_xform->position = Vec3(0, 15, -15);
98 | rotateXform3(cam_xform, 0, -0.25f, 0);
99 |
100 | Mesh *mesh = app->scene.meshes;
101 | i32 triangle_count = (i32)mesh->triangle_count + 12;
102 | i32 average_fps = app->time.timers.update.average_frames_per_second;
103 |
104 | HUDLine *fps = viewport->hud.lines;
105 | HUDLine *wireframe = fps + 1;
106 | HUDLine *msaa = wireframe + 1;
107 | HUDLine *triangles = msaa + 1;
108 | wireframe->value_color = msaa->value_color = triangles->value_color = Grey;
109 |
110 | printNumberIntoString(average_fps, &fps->value);
111 | printNumberIntoString(triangle_count, &triangles->value);
112 |
113 | setString(&fps->title, (char*)"Fps: ");
114 | setString(&wireframe->title, (char*)"Wireframe: ");
115 | setString(&wireframe->value.string, (char*)"Off");
116 | setString(&msaa->title, (char*)"MSAA: ");
117 | setString(&msaa->value.string, (char*)"Off");
118 | setString(&triangles->title, (char*)"Triangles: ");
119 | }
120 | void setupScene(Scene *scene) {
121 | Light *light1 = scene->lights + 0;
122 | Light *light2 = scene->lights + 1;
123 | Light *light3 = scene->lights + 2;
124 | Material *dog_material = scene->materials + 0;
125 | Material *floor_material = scene->materials + 1;
126 | Primitive *floor = scene->primitives + 0;
127 | Primitive *dog = scene->primitives + 1;
128 |
129 | dog_material->flags |= BLINN;
130 | dog_material->diffuse = Vec3(0.4f, 0.4f, 0.4f);
131 | floor_material->diffuse = Vec3(0.7f, 0.7f, 0.7f);
132 |
133 | dog_material->pixel_shader = floor_material->pixel_shader = shadePixelClassic;
134 |
135 | floor->type = PrimitiveType_Box;
136 | floor->scale = Vec3(16, 1, 16);
137 | floor->position = Vec3(-6, -3, 0);
138 | floor->material_id = 0;
139 |
140 | dog->type = PrimitiveType_Mesh;
141 | dog->id = 0;
142 | dog->material_id = 1;
143 | dog->position = Vec3(2, 2, 9);
144 | dog->rotation = getRotationAroundAxisBySinCon(Vec3(0, 1, 0), Vec2(sinf(0.5f), cosf(0.5f)));
145 |
146 | scene->ambient_light.color = Vec3(0.008f, 0.008f, 0.014f);
147 |
148 | vec3 mesh1_position = Vec3(0, 0, 5);
149 | vec3 mesh2_position = Vec3(5, 0, 5);
150 |
151 | light1->intensity = 20;
152 | light1->color.r = 0.8f;
153 | light1->color.g = 0.3f;
154 | light1->color.b = 0.2f;
155 | light1->position_or_direction.x = mesh1_position.x - 3;
156 | light1->position_or_direction.z = mesh1_position.z + 3;
157 | light1->position_or_direction.y = 5;
158 |
159 | light2->intensity = 20;
160 | light2->color.r = 0.2f;
161 | light2->color.g = 0.3f;
162 | light2->color.b = 0.8f;
163 | light2->position_or_direction.x = mesh2_position.x + 3;
164 | light2->position_or_direction.z = mesh2_position.z + 3;
165 | light2->position_or_direction.y = 4;
166 |
167 | light3->intensity = 16;
168 | light3->color.r = 0.2f;
169 | light3->color.g = 0.9f;
170 | light3->color.b = 0.3f;
171 | light3->position_or_direction.x = (mesh1_position.x + mesh2_position.x) / 2;
172 | light3->position_or_direction.z = -1;
173 | light3->position_or_direction.y = 3;
174 |
175 | dog_material->texture_count = 2;
176 | dog_material->texture_ids[0] = 0;
177 | dog_material->texture_ids[1] = 1;
178 | dog_material->normal_magnitude = 4.0f;
179 |
180 | floor_material->texture_count = 2;
181 | floor_material->texture_ids[0] = 2;
182 | floor_material->texture_ids[1] = 3;
183 | floor_material->normal_magnitude = 0.4f;
184 | }
185 |
186 | void initApp(Defaults *defaults) {
187 | static char string_buffers[5][100];
188 | static String files[5];
189 | files[0].char_ptr = string_buffers[0];
190 | files[1].char_ptr = string_buffers[1];
191 | files[2].char_ptr = string_buffers[2];
192 | files[3].char_ptr = string_buffers[3];
193 | files[4].char_ptr = string_buffers[4];
194 |
195 | char* this_file = __FILE__;
196 | char* dog_mesh = "dog.mesh";
197 | char* dog_texture = "dog_albedo.texture";
198 | char* dog_normal = "dog_normal.texture";
199 | char* rock_texture = "floor_albedo.texture";
200 | char* rock_normal = "floor_normal.texture";
201 | u32 dir_len = getDirectoryLength(this_file);
202 | mergeString(files, this_file, dog_mesh, dir_len);
203 | mergeString(files + 1, this_file, rock_texture, dir_len);
204 | mergeString(files + 2, this_file, rock_normal, dir_len);
205 | mergeString(files + 3, this_file, dog_texture, dir_len);
206 | mergeString(files + 4, this_file, dog_normal, dir_len);
207 | defaults->settings.scene.textures = 4;
208 | defaults->settings.scene.meshes = 1;
209 | defaults->settings.scene.mesh_files = files;
210 | defaults->settings.scene.texture_files = files + 1;
211 | defaults->settings.scene.lights = 3;
212 | defaults->settings.scene.primitives = 2;
213 | defaults->settings.scene.materials = 2;
214 | defaults->settings.viewport.near_clipping_plane_distance = 1;
215 | defaults->settings.viewport.hud_line_count = 4;
216 | app->on.sceneReady = setupScene;
217 | app->on.viewportReady = setupViewport;
218 | app->on.windowRedraw = updateAndRender;
219 | app->on.keyChanged = onKeyChanged;
220 | app->on.mouseButtonDown = onMouseButtonDown;
221 | app->on.mouseButtonDoubleClicked = onMouseDoubleClicked;
222 | }
--------------------------------------------------------------------------------
/src/examples/SlimRaster.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HardCoreCodin/SlimRaster/3718a02b52844f5a66376314ff63b76eff886e56/src/examples/SlimRaster.gif
--------------------------------------------------------------------------------
/src/examples/dog.mesh:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HardCoreCodin/SlimRaster/3718a02b52844f5a66376314ff63b76eff886e56/src/examples/dog.mesh
--------------------------------------------------------------------------------
/src/examples/dog_albedo.texture:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HardCoreCodin/SlimRaster/3718a02b52844f5a66376314ff63b76eff886e56/src/examples/dog_albedo.texture
--------------------------------------------------------------------------------
/src/examples/dog_normal.texture:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HardCoreCodin/SlimRaster/3718a02b52844f5a66376314ff63b76eff886e56/src/examples/dog_normal.texture
--------------------------------------------------------------------------------
/src/examples/dragon.mesh:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HardCoreCodin/SlimRaster/3718a02b52844f5a66376314ff63b76eff886e56/src/examples/dragon.mesh
--------------------------------------------------------------------------------
/src/examples/floor_albedo.texture:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HardCoreCodin/SlimRaster/3718a02b52844f5a66376314ff63b76eff886e56/src/examples/floor_albedo.texture
--------------------------------------------------------------------------------
/src/examples/floor_normal.texture:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HardCoreCodin/SlimRaster/3718a02b52844f5a66376314ff63b76eff886e56/src/examples/floor_normal.texture
--------------------------------------------------------------------------------
/src/examples/suzanne.mesh:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HardCoreCodin/SlimRaster/3718a02b52844f5a66376314ff63b76eff886e56/src/examples/suzanne.mesh
--------------------------------------------------------------------------------
/src/obj2mesh.c:
--------------------------------------------------------------------------------
1 | #ifdef COMPILER_CLANG
2 | #pragma clang diagnostic push
3 | #pragma clang diagnostic ignored "-Wdeprecated-declarations"
4 | #else
5 | #define _CRT_SECURE_NO_DEPRECATE
6 | #define _CRT_SECURE_NO_WARNINGS
7 | #endif
8 |
9 | #include
10 | #include
11 | #include
12 |
13 | #include "./SlimRaster/core/types.h"
14 | #include "./SlimRaster/math/vec3.h"
15 | #include "./SlimRaster/math/mat3.h"
16 |
17 | enum VertexAttributes {
18 | VertexAttributes_None,
19 | VertexAttributes_Positions,
20 | VertexAttributes_PositionsAndUVs,
21 | VertexAttributes_PositionsUVsAndNormals
22 | };
23 |
24 | int obj2mesh(char* obj_file_path, char* mesh_file_path, bool invert_winding_order) {
25 | Mesh mesh;
26 | mesh.aabb.min.x = mesh.aabb.min.y = mesh.aabb.min.z = 0;
27 | mesh.aabb.max.x = mesh.aabb.max.y = mesh.aabb.max.z = 0;
28 | mesh.triangle_count = 0;
29 | mesh.normals_count = 0;
30 | mesh.vertex_count = 0;
31 | mesh.edge_count = 0;
32 | mesh.uvs_count = 0;
33 | mesh.vertex_normals = null;
34 | mesh.vertex_normal_indices = null;
35 | mesh.vertex_uvs = null;
36 | mesh.vertex_uvs_indices = null;
37 |
38 | FILE* file;
39 | file = fopen(obj_file_path, "r");
40 | char line[1024];
41 |
42 | enum VertexAttributes vertex_attributes = VertexAttributes_None;
43 | while (fgets(line, 1024, file)) {
44 | if (strncmp(line, (char*)"vn ", 2) == 0) mesh.normals_count++;
45 | if (strncmp(line, (char*)"vt ", 2) == 0) mesh.uvs_count++;
46 | if (strncmp(line, (char*)"v ", 2) == 0) mesh.vertex_count++;
47 | if (strncmp(line, (char*)"f ", 2) == 0) {
48 | mesh.triangle_count++;
49 | if (vertex_attributes == VertexAttributes_None) {
50 | int forward_slash_count = 0;
51 | char *character = line;
52 | while (*character) {
53 | if ((*character) == '/') forward_slash_count++;
54 | character++;
55 | }
56 | switch (forward_slash_count) {
57 | case 0: vertex_attributes = VertexAttributes_Positions; break;
58 | case 3: vertex_attributes = VertexAttributes_PositionsAndUVs; break;
59 | case 6: vertex_attributes = VertexAttributes_PositionsUVsAndNormals; break;
60 | default: break;
61 | }
62 | }
63 | }
64 | }
65 | fclose(file);
66 |
67 | mesh.vertex_position_indices = (TriangleVertexIndices*)malloc(sizeof(TriangleVertexIndices) * mesh.triangle_count);
68 | mesh.vertex_positions = ( vec3*)malloc(sizeof(vec3 ) * mesh.vertex_count);
69 | mesh.edge_vertex_indices = ( EdgeVertexIndices*)malloc(sizeof(EdgeVertexIndices ) * mesh.triangle_count * 3);
70 |
71 | if (vertex_attributes == VertexAttributes_PositionsUVsAndNormals) {
72 | mesh.vertex_normals = ( vec3*)malloc(sizeof(vec3 ) * mesh.normals_count);
73 | mesh.vertex_normal_indices = (TriangleVertexIndices*)malloc(sizeof(TriangleVertexIndices) * mesh.triangle_count);
74 | mesh.vertex_uvs = ( vec2*)malloc(sizeof(vec2 ) * mesh.uvs_count);
75 | mesh.vertex_uvs_indices = (TriangleVertexIndices*)malloc(sizeof(TriangleVertexIndices) * mesh.triangle_count);
76 | } else if (vertex_attributes == VertexAttributes_PositionsAndUVs) {
77 | mesh.vertex_uvs = ( vec2*)malloc(sizeof(vec2 ) * mesh.uvs_count);
78 | mesh.vertex_uvs_indices = (TriangleVertexIndices*)malloc(sizeof(TriangleVertexIndices) * mesh.triangle_count);
79 | }
80 |
81 | vec3 *vertex_position = mesh.vertex_positions;
82 | vec3 *vertex_normal = mesh.vertex_normals;
83 | vec2 *vertex_uvs = mesh.vertex_uvs;
84 | TriangleVertexIndices *vertex_position_indices = mesh.vertex_position_indices;
85 | TriangleVertexIndices *vertex_normal_indices = mesh.vertex_normal_indices;
86 | TriangleVertexIndices *vertex_uvs_indices = mesh.vertex_uvs_indices;
87 |
88 | u8 v1_id = 0;
89 | u8 v2_id = invert_winding_order ? 2 : 1;
90 | u8 v3_id = invert_winding_order ? 1 : 2;
91 |
92 | file = fopen(obj_file_path, (char*)"r");
93 | while (fgets(line, 1024, file)) {
94 | // Vertex information
95 | if (strncmp(line, (char*)"v ", 2) == 0) {
96 | sscanf(line, (char*)"v %f %f %f", &vertex_position->x, &vertex_position->y, &vertex_position->z);
97 | vertex_position++;
98 | } else if (strncmp(line, (char*)"vn ", 2) == 0) {
99 | sscanf(line, (char*)"vn %f %f %f", &vertex_normal->x, &vertex_normal->y, &vertex_normal->z);
100 | vertex_normal++;
101 | } else if (strncmp(line, (char*)"vt ", 2) == 0) {
102 | sscanf(line, (char*)"vt %f %f", &vertex_uvs->x, &vertex_uvs->y);
103 | vertex_uvs++;
104 | } else if (strncmp(line, (char*)"f ", 2) == 0) {
105 | int vertex_indices[3];
106 | int uvs_indices[3];
107 | int normal_indices[3];
108 |
109 | switch (vertex_attributes) {
110 | case VertexAttributes_Positions:
111 | sscanf(
112 | line, (char*)"f %d %d %d",
113 | &vertex_indices[v1_id],
114 | &vertex_indices[v2_id],
115 | &vertex_indices[v3_id]
116 | );
117 | break;
118 | case VertexAttributes_PositionsAndUVs:
119 | sscanf(
120 | line, (char*)"f %d/%d %d/%d %d/%d",
121 | &vertex_indices[v1_id], &uvs_indices[v1_id],
122 | &vertex_indices[v2_id], &uvs_indices[v2_id],
123 | &vertex_indices[v3_id], &uvs_indices[v3_id]
124 | );
125 | vertex_uvs_indices->ids[0] = uvs_indices[0] - 1;
126 | vertex_uvs_indices->ids[1] = uvs_indices[1] - 1;
127 | vertex_uvs_indices->ids[2] = uvs_indices[2] - 1;
128 | vertex_uvs_indices++;
129 | break;
130 | case VertexAttributes_PositionsUVsAndNormals:
131 | sscanf(
132 | line, (char*)"f %d/%d/%d %d/%d/%d %d/%d/%d",
133 | &vertex_indices[v1_id], &uvs_indices[v1_id], &normal_indices[v1_id],
134 | &vertex_indices[v2_id], &uvs_indices[v2_id], &normal_indices[v2_id],
135 | &vertex_indices[v3_id], &uvs_indices[v3_id], &normal_indices[v3_id]
136 | );
137 | vertex_uvs_indices->ids[0] = uvs_indices[0] - 1;
138 | vertex_uvs_indices->ids[1] = uvs_indices[1] - 1;
139 | vertex_uvs_indices->ids[2] = uvs_indices[2] - 1;
140 | vertex_normal_indices->ids[0] = normal_indices[0] - 1;
141 | vertex_normal_indices->ids[1] = normal_indices[1] - 1;
142 | vertex_normal_indices->ids[2] = normal_indices[2] - 1;
143 | vertex_normal_indices++;
144 | vertex_uvs_indices++;
145 | break;
146 | default:
147 | return 1;
148 | }
149 | vertex_position_indices->ids[0] = vertex_indices[0] - 1;
150 | vertex_position_indices->ids[1] = vertex_indices[1] - 1;
151 | vertex_position_indices->ids[2] = vertex_indices[2] - 1;
152 | vertex_position_indices++;
153 | }
154 | }
155 | fclose(file);
156 |
157 | // Dog/Monkey >
158 | // mat3 rot45 = getMat3Identity();
159 | // rot45.X.x = 0.70710678118f;
160 | // rot45.X.z = 0.70710678118f;
161 | // rot45.Z.x = -0.70710678118f;
162 | // rot45.Z.z = 0.70710678118f;
163 | // mat3 rot90 = mulMat3(rot45, rot45);
164 | // mat3 rot = mulMat3(rot45, rot90); // Dog
165 | // mat3 rot = rot90; // Monkey
166 | //
167 | // vertex_position = mesh.vertex_normals;
168 | // for (u32 i = 0; i < mesh.normals_count; i++, vertex_position++)
169 | // *vertex_position = mulVec3Mat3(*vertex_position, rot);
170 | // Dog/Monkey <
171 |
172 | vertex_position = mesh.vertex_positions;
173 | for (u32 i = 0; i < mesh.vertex_count; i++, vertex_position++) {
174 | // *vertex_position = mulVec3Mat3(*vertex_position, rot); // Dog/Monkey
175 | mesh.aabb.min.x = mesh.aabb.min.x < vertex_position->x ? mesh.aabb.min.x : vertex_position->x;
176 | mesh.aabb.min.y = mesh.aabb.min.y < vertex_position->y ? mesh.aabb.min.y : vertex_position->y;
177 | mesh.aabb.min.z = mesh.aabb.min.z < vertex_position->z ? mesh.aabb.min.z : vertex_position->z;
178 | mesh.aabb.max.x = mesh.aabb.max.x > vertex_position->x ? mesh.aabb.max.x : vertex_position->x;
179 | mesh.aabb.max.y = mesh.aabb.max.y > vertex_position->y ? mesh.aabb.max.y : vertex_position->y;
180 | mesh.aabb.max.z = mesh.aabb.max.z > vertex_position->z ? mesh.aabb.max.z : vertex_position->z;
181 | }
182 |
183 | vec3 centroid = scaleVec3(addVec3(mesh.aabb.min, mesh.aabb.max), 0.5f);
184 | if (nonZeroVec3(centroid)) {
185 | mesh.aabb.min = subVec3(mesh.aabb.min, centroid);
186 | mesh.aabb.max = subVec3(mesh.aabb.max, centroid);
187 | vertex_position = mesh.vertex_positions;
188 | for (u32 i = 0; i < mesh.vertex_count; i++, vertex_position++)
189 | *vertex_position = subVec3(*vertex_position, centroid);
190 | }
191 |
192 | // Dog/Monkey >
193 | // f32 scale = 0.1f; // dog
194 | // f32 scale = 4.0f; // dog
195 | // vertex_position = mesh.vertex_positions;
196 | // for (u32 i = 0; i < mesh.vertex_count; i++, vertex_position++)
197 | // *vertex_position = scaleVec3(*vertex_position, scale);
198 | // mesh.aabb.min = scaleVec3(mesh.aabb.min, scale);
199 | // mesh.aabb.max = scaleVec3(mesh.aabb.max, scale);
200 | // Dog/Monkey <
201 |
202 | EdgeVertexIndices current_edge_vertex_indices, *edge_vertex_indices;
203 | vertex_position_indices = mesh.vertex_position_indices;
204 | for (u32 i = 0; i < mesh.triangle_count; i++, vertex_position_indices++) {
205 | for (u8 from = 0, to = 1; from < 3; from++, to = (to + 1) % 3) {
206 | current_edge_vertex_indices.from = vertex_position_indices->ids[from];
207 | current_edge_vertex_indices.to = vertex_position_indices->ids[to];
208 | if (current_edge_vertex_indices.from > current_edge_vertex_indices.to) {
209 | u32 temp = current_edge_vertex_indices.from;
210 | current_edge_vertex_indices.from = current_edge_vertex_indices.to;
211 | current_edge_vertex_indices.to = temp;
212 | }
213 |
214 | bool found = false;
215 | edge_vertex_indices = mesh.edge_vertex_indices;
216 | for (u32 e = 0; e < mesh.edge_count; e++, edge_vertex_indices++) {
217 | if (edge_vertex_indices->from == current_edge_vertex_indices.from &&
218 | edge_vertex_indices->to == current_edge_vertex_indices.to) {
219 | found = true;
220 | break;
221 | }
222 | }
223 |
224 | if (!found) {
225 | mesh.edge_vertex_indices[mesh.edge_count] = current_edge_vertex_indices;
226 | mesh.edge_count++;
227 | }
228 | }
229 | }
230 |
231 | file = fopen(mesh_file_path, (char*)"wb");
232 |
233 | fwrite(&mesh.aabb, sizeof(AABB), 1, file);
234 | fwrite(&mesh.vertex_count, sizeof(u32), 1, file);
235 | fwrite(&mesh.triangle_count, sizeof(u32), 1, file);
236 | fwrite(&mesh.edge_count, sizeof(u32), 1, file);
237 | fwrite(&mesh.uvs_count, sizeof(u32), 1, file);
238 | fwrite(&mesh.normals_count, sizeof(u32), 1, file);
239 | fwrite( mesh.vertex_positions, sizeof(vec3) , mesh.vertex_count, file);
240 | fwrite( mesh.vertex_position_indices, sizeof(TriangleVertexIndices), mesh.triangle_count, file);
241 | fwrite( mesh.edge_vertex_indices, sizeof(EdgeVertexIndices) , mesh.edge_count, file);
242 | if (mesh.uvs_count) {
243 | fwrite(mesh.vertex_uvs, sizeof(vec2) , mesh.uvs_count, file);
244 | fwrite(mesh.vertex_uvs_indices, sizeof(TriangleVertexIndices) , mesh.triangle_count, file);
245 | }
246 | if (mesh.normals_count) {
247 | fwrite(mesh.vertex_normals, sizeof(vec3) , mesh.normals_count, file);
248 | fwrite(mesh.vertex_normal_indices, sizeof(TriangleVertexIndices) , mesh.triangle_count, file);
249 | }
250 |
251 | fclose(file);
252 |
253 | return 0;
254 | }
255 |
256 | int main(int argc, char *argv[]) {
257 | if (argc == 2 && !strcmp(argv[1], (char*)"--help")) {
258 | printf((char*)("Exactly 2 file paths need to be provided: "
259 | "An '.obj' file (input) then a '.mesh' file (output), "
260 | "and an optional flag '-invert_winding_order' for inverting winding order"));
261 | return 0;
262 | } else if (argc == 3 || // 2 arguments
263 | argc == 4 // 3 arguments
264 | ) {
265 | char *obj_file_path = argv[1];
266 | char *mesh_file_path = argv[2];
267 | bool invert_winding_order = argc == 4 ? !strcmp(argv[3], (char*)"-invert_winding_order") : false;
268 | return obj2mesh(obj_file_path, mesh_file_path, invert_winding_order);
269 | }
270 |
271 | printf((char*)("Exactly 2 file paths need to be provided: "
272 | "An '.obj' file (input) then a '.mesh' file (output), "
273 | "and an optional flag '-invert_winding_order' for inverting winding order"));
274 | return 1;
275 | }
--------------------------------------------------------------------------------