├── .clang-format ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── Untitled.ipynb ├── block.txt ├── examples └── rick │ ├── 01.png │ ├── 02.png │ ├── 03.png │ ├── 04.png │ ├── 05.png │ ├── 06.png │ ├── 07.png │ ├── 08.png │ ├── 09.png │ ├── 10.png │ ├── 11.png │ ├── 12.png │ ├── 13.png │ ├── 14.png │ ├── 15.png │ ├── 16.png │ ├── 17.png │ ├── 18.png │ ├── 19.png │ ├── 20.png │ ├── 21.png │ ├── 22.png │ ├── 23.png │ ├── 24.png │ ├── 25.png │ ├── 26.png │ ├── 27.png │ ├── 28.png │ ├── 29.png │ ├── 30.png │ ├── 31.png │ ├── rick.mp4 │ └── rick.webp ├── maki ├── CMakeLists.txt └── src │ └── maki.cpp ├── maki_core ├── CMakeLists.txt ├── include │ └── maki.h ├── res │ └── shaders │ │ ├── cuboid_frag.glsl │ │ ├── cuboid_vert.glsl │ │ ├── simple_fragment.glsl │ │ └── simple_vertex.glsl └── src │ ├── atom │ ├── atom.h │ ├── atom_chain.h │ ├── atom_diff.h │ ├── atom_diff_frame.h │ ├── atom_diff_lifetime.h │ ├── atom_dispenser.cpp │ ├── atom_dispenser.h │ ├── atom_renderer.h │ ├── atoms │ │ ├── cuboid_atom.cpp │ │ ├── cuboid_atom.h │ │ ├── quadrilateral_atom.cpp │ │ └── quadrilateral_atom.h │ └── renderers │ │ ├── batch_renderer.cpp │ │ ├── batch_renderer.h │ │ ├── cuboid_renderer.cpp │ │ ├── cuboid_renderer.h │ │ ├── quadrilateral_renderer.cpp │ │ └── quadrilateral_renderer.h │ ├── core │ ├── definitions.h │ ├── log.cpp │ ├── log.h │ ├── thread_safety.cpp │ └── thread_safety.h │ ├── driver │ ├── camera_driver.cpp │ ├── camera_driver.h │ ├── interface.h │ ├── render_driver.h │ ├── render_driver_control.cpp │ └── render_driver_render.cpp │ ├── pch.cpp │ ├── pch.h │ ├── platform │ ├── enums.h │ ├── event.h │ ├── glfw │ │ └── glfw_window.cpp │ ├── window.cpp │ └── window.h │ └── renderer │ ├── buffer.cpp │ ├── buffer.h │ ├── camera.cpp │ ├── camera.h │ ├── opengl │ ├── opengl_buffer.cpp │ ├── opengl_buffer.h │ ├── opengl_renderer.cpp │ ├── opengl_renderer.h │ ├── opengl_shader.cpp │ ├── opengl_shader.h │ ├── opengl_stringifier.cpp │ ├── opengl_stringifier.h │ ├── opengl_types.h │ ├── opengl_vertex_array.cpp │ └── opengl_vertex_array.h │ ├── renderer.cpp │ ├── renderer.h │ ├── shader.cpp │ ├── shader.h │ ├── types.h │ ├── vertex_array.cpp │ └── vertex_array.h ├── maki_showcase.ipynb ├── pretty_bugs ├── broken_cube.png ├── broken_cube2.png ├── broken_cube3.png ├── corrupted_atoms.png └── floating_boxes.png ├── stub ├── CMakeLists.txt └── src │ └── main.cpp └── vendor ├── CMakeLists.txt └── stb.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | AccessModifierOffset: '-4' 3 | AlignAfterOpenBracket: Align 4 | AlignConsecutiveMacros: 'true' 5 | AlignConsecutiveAssignments: 'true' 6 | AlignConsecutiveDeclarations: 'true' 7 | AlignEscapedNewlines: Left 8 | AlignOperands: 'true' 9 | AlignTrailingComments: 'true' 10 | AllowAllArgumentsOnNextLine: 'true' 11 | AllowAllConstructorInitializersOnNextLine: 'true' 12 | AllowAllParametersOfDeclarationOnNextLine: 'true' 13 | AllowShortBlocksOnASingleLine: 'false' 14 | AllowShortCaseLabelsOnASingleLine: 'false' 15 | AllowShortFunctionsOnASingleLine: Inline 16 | AllowShortIfStatementsOnASingleLine: Never 17 | AllowShortLambdasOnASingleLine: Inline 18 | AllowShortLoopsOnASingleLine: 'false' 19 | AlwaysBreakAfterDefinitionReturnType: None 20 | AlwaysBreakAfterReturnType: None 21 | AlwaysBreakBeforeMultilineStrings: 'false' 22 | AlwaysBreakTemplateDeclarations: 'Yes' 23 | BinPackArguments: 'true' 24 | BinPackParameters: 'true' 25 | BreakAfterJavaFieldAnnotations: 'true' 26 | BreakBeforeBinaryOperators: None 27 | BreakBeforeBraces: Stroustrup 28 | BreakBeforeTernaryOperators: 'false' 29 | BreakConstructorInitializers: BeforeColon 30 | BreakInheritanceList: BeforeColon 31 | BreakStringLiterals: 'false' 32 | ColumnLimit: '0' 33 | CommentPragmas: '^ todo:' 34 | CompactNamespaces: 'false' 35 | ConstructorInitializerAllOnOneLineOrOnePerLine: 'false' 36 | ConstructorInitializerIndentWidth: '4' 37 | ContinuationIndentWidth: '4' 38 | Cpp11BracedListStyle: 'true' 39 | DerivePointerAlignment: 'false' 40 | DisableFormat: 'false' 41 | ExperimentalAutoDetectBinPacking: 'false' 42 | FixNamespaceComments: 'true' 43 | IncludeBlocks: Preserve 44 | IndentCaseLabels: 'false' 45 | IndentPPDirectives: None 46 | IndentWidth: '4' 47 | IndentWrappedFunctionNames: 'true' 48 | KeepEmptyLinesAtTheStartOfBlocks: 'false' 49 | Language: Cpp 50 | MaxEmptyLinesToKeep: '1' 51 | NamespaceIndentation: None 52 | PointerAlignment: Left 53 | ReflowComments: 'false' 54 | SortIncludes: 'true' 55 | SortUsingDeclarations: 'true' 56 | SpaceAfterCStyleCast: 'false' 57 | SpaceAfterLogicalNot: 'false' 58 | SpaceAfterTemplateKeyword: 'false' 59 | SpaceBeforeAssignmentOperators: 'true' 60 | SpaceBeforeCpp11BracedList: 'true' 61 | SpaceBeforeCtorInitializerColon: 'false' 62 | SpaceBeforeInheritanceColon: 'false' 63 | SpaceBeforeParens: Never 64 | SpaceBeforeRangeBasedForLoopColon: 'false' 65 | SpaceInEmptyParentheses: 'false' 66 | SpacesBeforeTrailingComments: '1' 67 | SpacesInAngles: 'false' 68 | SpacesInCStyleCastParentheses: 'false' 69 | SpacesInContainerLiterals: 'false' 70 | SpacesInParentheses: 'false' 71 | SpacesInSquareBrackets: 'false' 72 | Standard: Cpp11 73 | TabWidth: '4' 74 | UseTab: Never 75 | 76 | ... 77 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | build 35 | 36 | vendor/glfw/ 37 | vendor/glm/ 38 | vendor/imgui/ 39 | vendor/pybind11/ 40 | vendor/spdlog/ 41 | vendor/stb/ 42 | 43 | # imgui safe state 44 | imgui.ini 45 | 46 | # development sym links 47 | compile_commands.json 48 | maki.cpython-310-x86_64-linux-gnu.so 49 | 50 | # Jupyter 51 | .ipynb_checkpoints/ 52 | 53 | .cache/ 54 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/glfw"] 2 | path = vendor/glfw 3 | url = https://github.com/glfw/glfw 4 | [submodule "vendor/glm"] 5 | path = vendor/glm 6 | url = https://github.com/g-truc/glm 7 | [submodule "vendor/stb"] 8 | path = vendor/stb 9 | url = https://github.com/nothings/stb 10 | [submodule "vendor/spdlog"] 11 | path = vendor/spdlog 12 | url = https://github.com/gabime/spdlog 13 | [submodule "vendor/pybind11"] 14 | path = vendor/pybind11 15 | url = https://github.com/pybind/pybind11 16 | [submodule "vendor/imgui"] 17 | path = vendor/imgui 18 | url = https://github.com/ocornut/imgui 19 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | project(maki) 4 | 5 | set(CMAKE_CXX_STANDARD 17) 6 | set(CMAKE_CXX_STANDARD_REQUIRED TRUE) 7 | # required for spdlog included in a shared lib 8 | set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) 9 | 10 | if(NOT CMAKE_BUILD_TYPE) 11 | set(CMAKE_BUILD_TYPE Release) 12 | endif() 13 | 14 | if(NOT CMAKE_EXPORT_COMPILE_COMMANDS) 15 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 16 | endif() 17 | 18 | # dependencies # 19 | # opengl 20 | set(OpenGL_GL_PREFERENCE "GLVND") 21 | find_package(OpenGL REQUIRED) 22 | 23 | # glew 24 | find_package(GLEW REQUIRED) 25 | 26 | add_subdirectory("${CMAKE_SOURCE_DIR}/vendor") 27 | 28 | # use warnings and multi threading 29 | if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") 30 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic") 31 | elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") 32 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic") 33 | elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") 34 | set( 35 | CMAKE_CXX_FLAGS 36 | "${CMAKE_CXX_FLAGS} /MP2 /DWIN32_LEAN_AND_MEAN /DNOMINMAX" 37 | ) 38 | endif() 39 | 40 | add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/maki_core") 41 | add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/maki") 42 | add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/stub") 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Christopher Besch 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 | # Maki 2 | 3 | **M**athematical **A**nimation and **K**nickknack **I**nscriber (Maki), a program for interactive and programmatic animation development. 4 | Or: **How to Time Travel.** 5 | 6 | ![image](https://user-images.githubusercontent.com/57909184/148649899-0a890deb-c435-493e-8a89-419e895296dd.png) 7 | 8 | This is a cross-platform project. 9 | But right now only Linux-builds have been tested. 10 | Though if you know what you're doing, this will compile and run everywhere. 11 | 12 | At the moment this project is under development, thus the documentation and volume of comments is left to be desired. 13 | 14 | Learn more in this article: [Maki, Atoms and Time Travel](https://chris-besch.com/articles/maki_atoms_and_time_travel) 15 | 16 | ## Requirements 17 | 18 | ### Debian/Ubuntu 19 | 20 | ``` 21 | sudo apt install build-essential cmake libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libglew-dev 22 | ``` 23 | 24 | ### Gentoo 25 | 26 | ``` 27 | sudo emerge --ask media-libs/glew 28 | ``` 29 | 30 | ## Compilation 31 | 32 | ``` 33 | git clone https://github.com/christopher-besch/maki --recurse 34 | cd maki 35 | mkdir build && cd build 36 | cmake .. -DCMAKE_BUILD_TYPE=Release -Dplatform=glfw 37 | cmake --build . -j4 38 | ``` 39 | 40 | ## Use 41 | 42 | You can take a look at `maki_showcase.ipynb`. 43 | It contains a few examples for Maki. 44 | For it to function correctly you have to copy (or symlink) the compiled shared object for Python (for example `maki.cpython-310-x86_64-linux-gnu.so`) into the root of this project. 45 | You can find that shared object in `build/maki` (if you called your build directory that). 46 | 47 | The examples work with both Debug and Release builds, but some are excruciatingly slow in the former. 48 | Please try both modes before reporting any bugs or performance problems. 49 | 50 | On a related note: 51 | Please do inform the author of any problems, bugs or feature requests. 52 | You can use the [issues](https://github.com/christopher-besch/maki/issues) for that. 53 | 54 | ## References 55 | 56 | - [opengl_reference](https://github.com/christopher-besch/opengl_reference) 57 | - [lynton_legacy](https://github.com/christopher-besch/lynton_legacy) 58 | - [lynton](https://github.com/christopher-besch/lynton) 59 | - [ray_tracer](https://github.com/christopher-besch/ray_tracer) 60 | - [Light](https://github.com/Light3039/Light) 61 | - [The Cherno OpenGL](https://www.youtube.com/watch?v=W3gAzLwfIP0&list=PLlrATfBNZ98foTJPJ_Ev03o2oq3-GGOS2) 62 | - [opengl-tutorial.org](http://www.opengl-tutorial.org) 63 | - [imgui-cmake](https://github.com/Pesc0/imgui-cmake) 64 | - [marshalling glm types](https://github.com/pybind/pybind11/issues/430) 65 | - [morphing in Blender](https://www.youtube.com/watch?v=SgDhzkv-p6s) 66 | - [morphing in babylon.js](https://doc.babylonjs.com/divingDeeper/mesh/dynamicMeshMorph) 67 | - [more morphing](http://web.mit.edu/manoli/morph/www/morph.html) 68 | - [Python WebAssembly](https://almarklein.org/python_and_webassembly.html) 69 | - [more morphing](https://www.geeks3d.com/20140205/glsl-simple-morph-target-animation-opengl-glslhacker-demo) 70 | - [lighting](https://www.lighthouse3d.com/tutorials/glsl-tutorial/lighting/) 71 | -------------------------------------------------------------------------------- /Untitled.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "de4c812f-9e4c-42b3-943f-51489dc8e5c6", 7 | "metadata": {}, 8 | "outputs": [ 9 | { 10 | "name": "stdout", 11 | "output_type": "stream", 12 | "text": [ 13 | "[13:08:15] Maki:\tInitializing GLFW.\n", 14 | "[13:08:15] Maki:\tCreating GLFW window 'Maki Showcase Window' (1280, 640).\n", 15 | "[13:08:15] Maki:\tCreating OpenGL Renderer.\n", 16 | "[13:08:15] Maki:\tInitializing GLEW.\n", 17 | "[13:08:15] Maki:\tShaders linked.\n", 18 | "[13:08:15] Maki:\tShaders linked.\n" 19 | ] 20 | } 21 | ], 22 | "source": [ 23 | "import maki\n", 24 | "# init\n", 25 | "maki.init(maki.RendererImplementation.opengl)\n", 26 | "render_driver = maki.RenderDriver(\"Maki Showcase Window\", 1280, 640, maki.vec4(0.20, 0.23, 0.25, 1.0))" 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": 3, 32 | "id": "00ba4ff2-89bc-4965-9552-f982eb38bb41", 33 | "metadata": {}, 34 | "outputs": [], 35 | "source": [ 36 | "cube = render_driver.add_cuboid_atom()" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": 4, 42 | "id": "bc92918d-c1aa-47e0-a3c4-037442277108", 43 | "metadata": {}, 44 | "outputs": [ 45 | { 46 | "name": "stdout", 47 | "output_type": "stream", 48 | "text": [ 49 | "[13:11:18] Maki:\tCuboidAtom Chrono Sync initiated.\n" 50 | ] 51 | } 52 | ], 53 | "source": [ 54 | "render_driver.show_cuboid_atom(cuboid, 1, True)" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": 5, 60 | "id": "e4fbde3f-2889-4cb2-aa7e-46507751c348", 61 | "metadata": {}, 62 | "outputs": [], 63 | "source": [ 64 | "render_driver.color_cuboid_atom(cuboid, 2, maki.vec4(1.0, 1.0, 0.0, 1.0))\n", 65 | "render_driver.color_cuboid_atom(cuboid, 3, maki.vec4(1.0, 0.0, 1.0, 1.0))\n", 66 | "render_driver.color_cuboid_atom(cuboid, 4, maki.vec4(0.5, 0.5, 0.5, 1.0))\n", 67 | "render_driver.color_cuboid_atom(cuboid, 5, maki.vec4(0.8, 0.0, 0.4, 1.0))" 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": 6, 73 | "id": "6aa86ad9-76dd-45df-a742-c68f89db017d", 74 | "metadata": {}, 75 | "outputs": [ 76 | { 77 | "name": "stdout", 78 | "output_type": "stream", 79 | "text": [ 80 | "[13:12:16] Maki:\tCuboidAtom Chrono Sync initiated.\n" 81 | ] 82 | } 83 | ], 84 | "source": [ 85 | "render_driver.translate_cuboid_atom(cuboid, 6, maki.vec3(0.0, 1.0, 0.0))" 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": 7, 91 | "id": "04165268-221f-4e33-a7e3-f72fd812bba2", 92 | "metadata": {}, 93 | "outputs": [], 94 | "source": [ 95 | "target_delta = maki.vec3(10.0, 10.0, 5.0)\n", 96 | "first_frame = 60 # alpha = 0.0\n", 97 | "after_last_frame = 200 # alpha = 1.0\n", 98 | "\n", 99 | "alpha_delta = 1 / (after_last_frame - first_frame)\n", 100 | "for frame in range(first_frame, after_last_frame):\n", 101 | " cur_delta = target_delta * alpha_delta\n", 102 | " render_driver.translate_cuboid_atom(cuboid, frame, cur_delta)" 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": 8, 108 | "id": "d1f48596-c5d7-4dad-9bb5-b11992b37540", 109 | "metadata": {}, 110 | "outputs": [ 111 | { 112 | "name": "stdout", 113 | "output_type": "stream", 114 | "text": [ 115 | "[13:13:33] Maki:\tCuboidAtom Chrono Sync initiated.\n", 116 | "[13:13:56] Maki:\tDestructing OpenGL Renderer.\n" 117 | ] 118 | } 119 | ], 120 | "source": [ 121 | "target_delta = maki.vec3(0.0, -5.0, 0.0)\n", 122 | "first_frame = 5 # alpha = 0.0\n", 123 | "after_last_frame = 50 # alpha = 1.0\n", 124 | "alpha_delta = 1 / (after_last_frame - first_frame)\n", 125 | "for frame in range(first_frame, after_last_frame):\n", 126 | " cur_delta = target_delta * alpha_delta\n", 127 | " render_driver.translate_cuboid_atom(cuboid, frame, cur_delta)" 128 | ] 129 | }, 130 | { 131 | "cell_type": "code", 132 | "execution_count": null, 133 | "id": "6832ed37-3f88-46ff-bab1-e085f195d115", 134 | "metadata": {}, 135 | "outputs": [], 136 | "source": [] 137 | } 138 | ], 139 | "metadata": { 140 | "kernelspec": { 141 | "display_name": "Python 3 (ipykernel)", 142 | "language": "python", 143 | "name": "python3" 144 | }, 145 | "language_info": { 146 | "codemirror_mode": { 147 | "name": "ipython", 148 | "version": 3 149 | }, 150 | "file_extension": ".py", 151 | "mimetype": "text/x-python", 152 | "name": "python", 153 | "nbconvert_exporter": "python", 154 | "pygments_lexer": "ipython3", 155 | "version": "3.10.1" 156 | } 157 | }, 158 | "nbformat": 4, 159 | "nbformat_minor": 5 160 | } 161 | -------------------------------------------------------------------------------- /block.txt: -------------------------------------------------------------------------------- 1 | // height: 8 2 | // spacing: 3 3 | // block from https://www.messletters.com/en/big-text/ 4 | -32 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -33 14 | 15 | _| 16 | _| 17 | _| 18 | 19 | _| 20 | 21 | 22 | -34 23 | _| _| 24 | _| _| 25 | 26 | 27 | 28 | 29 | 30 | 31 | -35 32 | 33 | _| _| 34 | _|_|_|_|_| 35 | _| _| 36 | _|_|_|_|_| 37 | _| _| 38 | 39 | 40 | -36 41 | 42 | _| 43 | _|_|_| 44 | _|_| 45 | _|_| 46 | _|_|_| 47 | _| 48 | 49 | -37 50 | 51 | _|_| _| 52 | _|_| _| 53 | _| 54 | _| _|_| 55 | _| _|_| 56 | 57 | 58 | -38 59 | 60 | _| 61 | _| _| 62 | _|_| _| 63 | _| _| 64 | _|_| _| 65 | 66 | 67 | -39 68 | _| 69 | _| 70 | 71 | 72 | 73 | 74 | 75 | 76 | -40 77 | _| 78 | _| 79 | _| 80 | _| 81 | _| 82 | _| 83 | _| 84 | 85 | -41 86 | _| 87 | _| 88 | _| 89 | _| 90 | _| 91 | _| 92 | _| 93 | 94 | -42 95 | 96 | _| _| _| 97 | _|_|_| 98 | _|_|_|_|_| 99 | _|_|_| 100 | _| _| _| 101 | 102 | 103 | -43 104 | 105 | _| 106 | _| 107 | _|_|_|_|_| 108 | _| 109 | _| 110 | 111 | 112 | -44 113 | 114 | 115 | 116 | 117 | 118 | _| 119 | _| 120 | 121 | -45 122 | 123 | 124 | 125 | _|_|_|_|_| 126 | 127 | 128 | 129 | 130 | -46 131 | 132 | 133 | 134 | 135 | 136 | _| 137 | 138 | 139 | -47 140 | 141 | _| 142 | _| 143 | _| 144 | _| 145 | _| 146 | 147 | 148 | -48 149 | 150 | _| 151 | _| _| 152 | _| _| 153 | _| _| 154 | _| 155 | 156 | 157 | -49 158 | 159 | _| 160 | _|_| 161 | _| 162 | _| 163 | _| 164 | 165 | 166 | -50 167 | 168 | _|_| 169 | _| _| 170 | _| 171 | _| 172 | _|_|_|_| 173 | 174 | 175 | -51 176 | 177 | _|_|_| 178 | _| 179 | _|_| 180 | _| 181 | _|_|_| 182 | 183 | 184 | -52 185 | 186 | _| _| 187 | _| _| 188 | _|_|_|_| 189 | _| 190 | _| 191 | 192 | 193 | -53 194 | 195 | _|_|_|_| 196 | _| 197 | _|_|_| 198 | _| 199 | _|_|_| 200 | 201 | 202 | -54 203 | 204 | _|_|_| 205 | _| 206 | _|_|_| 207 | _| _| 208 | _|_| 209 | 210 | 211 | -55 212 | 213 | _|_|_|_|_| 214 | _| 215 | _| 216 | _| 217 | _| 218 | 219 | 220 | -56 221 | 222 | _|_| 223 | _| _| 224 | _|_| 225 | _| _| 226 | _|_| 227 | 228 | 229 | -57 230 | 231 | _|_| 232 | _| _| 233 | _|_|_| 234 | _| 235 | _|_|_| 236 | 237 | 238 | -58 239 | 240 | 241 | _| 242 | 243 | 244 | _| 245 | 246 | 247 | -59 248 | 249 | 250 | _| 251 | 252 | 253 | _| 254 | _| 255 | 256 | -60 257 | 258 | _| 259 | _| 260 | _| 261 | _| 262 | _| 263 | 264 | 265 | -61 266 | 267 | 268 | _|_|_|_|_| 269 | 270 | _|_|_|_|_| 271 | 272 | 273 | 274 | -62 275 | 276 | _| 277 | _| 278 | _| 279 | _| 280 | _| 281 | 282 | 283 | -63 284 | 285 | _|_| 286 | _| 287 | _|_| 288 | 289 | _| 290 | 291 | 292 | -64 293 | _|_|_|_|_| 294 | _| _| 295 | _| _|_|_| _| 296 | _| _| _| _| 297 | _| _|_|_|_| 298 | _| 299 | _|_|_|_|_|_| 300 | 301 | -65 302 | 303 | _|_| 304 | _| _| 305 | _|_|_|_| 306 | _| _| 307 | _| _| 308 | 309 | 310 | -66 311 | 312 | _|_|_| 313 | _| _| 314 | _|_|_| 315 | _| _| 316 | _|_|_| 317 | 318 | 319 | -67 320 | 321 | _|_|_| 322 | _| 323 | _| 324 | _| 325 | _|_|_| 326 | 327 | 328 | -68 329 | 330 | _|_|_| 331 | _| _| 332 | _| _| 333 | _| _| 334 | _|_|_| 335 | 336 | 337 | -69 338 | 339 | _|_|_|_| 340 | _| 341 | _|_|_| 342 | _| 343 | _|_|_|_| 344 | 345 | 346 | -70 347 | 348 | _|_|_|_| 349 | _| 350 | _|_|_| 351 | _| 352 | _| 353 | 354 | 355 | -71 356 | 357 | _|_|_| 358 | _| 359 | _| _|_| 360 | _| _| 361 | _|_|_| 362 | 363 | 364 | -72 365 | 366 | _| _| 367 | _| _| 368 | _|_|_|_| 369 | _| _| 370 | _| _| 371 | 372 | 373 | -73 374 | 375 | _|_|_| 376 | _| 377 | _| 378 | _| 379 | _|_|_| 380 | 381 | 382 | -74 383 | 384 | _| 385 | _| 386 | _| 387 | _| _| 388 | _|_| 389 | 390 | 391 | -75 392 | 393 | _| _| 394 | _| _| 395 | _|_| 396 | _| _| 397 | _| _| 398 | 399 | 400 | -76 401 | 402 | _| 403 | _| 404 | _| 405 | _| 406 | _|_|_|_| 407 | 408 | 409 | -77 410 | 411 | _| _| 412 | _|_| _|_| 413 | _| _| _| 414 | _| _| 415 | _| _| 416 | 417 | 418 | -78 419 | 420 | _| _| 421 | _|_| _| 422 | _| _| _| 423 | _| _|_| 424 | _| _| 425 | 426 | 427 | -79 428 | 429 | _|_| 430 | _| _| 431 | _| _| 432 | _| _| 433 | _|_| 434 | 435 | 436 | -80 437 | 438 | _|_|_| 439 | _| _| 440 | _|_|_| 441 | _| 442 | _| 443 | 444 | 445 | -81 446 | 447 | _|_| 448 | _| _| 449 | _| _|_| 450 | _| _| 451 | _|_| _| 452 | 453 | 454 | -82 455 | 456 | _|_|_| 457 | _| _| 458 | _|_|_| 459 | _| _| 460 | _| _| 461 | 462 | 463 | -83 464 | 465 | _|_|_| 466 | _| 467 | _|_| 468 | _| 469 | _|_|_| 470 | 471 | 472 | -84 473 | 474 | _|_|_|_|_| 475 | _| 476 | _| 477 | _| 478 | _| 479 | 480 | 481 | -85 482 | 483 | _| _| 484 | _| _| 485 | _| _| 486 | _| _| 487 | _|_| 488 | 489 | 490 | -86 491 | 492 | _| _| 493 | _| _| 494 | _| _| 495 | _| _| 496 | _| 497 | 498 | 499 | -87 500 | 501 | _| _| 502 | _| _| 503 | _| _| _| 504 | _| _| _| 505 | _| _| 506 | 507 | 508 | -88 509 | 510 | _| _| 511 | _| _| 512 | _| 513 | _| _| 514 | _| _| 515 | 516 | 517 | -89 518 | 519 | _| _| 520 | _| _| 521 | _| 522 | _| 523 | _| 524 | 525 | 526 | -90 527 | 528 | _|_|_|_|_| 529 | _| 530 | _| 531 | _| 532 | _|_|_|_|_| 533 | 534 | 535 | -91 536 | _|_| 537 | _| 538 | _| 539 | _| 540 | _| 541 | _| 542 | _|_| 543 | 544 | -92 545 | 546 | _| 547 | _| 548 | _| 549 | _| 550 | _| 551 | 552 | 553 | -93 554 | _|_| 555 | _| 556 | _| 557 | _| 558 | _| 559 | _| 560 | _|_| 561 | 562 | -94 563 | _| 564 | _| _| 565 | 566 | 567 | 568 | 569 | 570 | 571 | -95 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | _|_|_|_|_| 580 | -96 581 | _| 582 | _| 583 | 584 | 585 | 586 | 587 | 588 | 589 | -97 590 | 591 | 592 | _|_|_| 593 | _| _| 594 | _| _| 595 | _|_|_| 596 | 597 | 598 | -98 599 | 600 | _| 601 | _|_|_| 602 | _| _| 603 | _| _| 604 | _|_|_| 605 | 606 | 607 | -99 608 | 609 | 610 | _|_|_| 611 | _| 612 | _| 613 | _|_|_| 614 | 615 | 616 | -100 617 | 618 | _| 619 | _|_|_| 620 | _| _| 621 | _| _| 622 | _|_|_| 623 | 624 | 625 | -101 626 | 627 | 628 | _|_| 629 | _|_|_|_| 630 | _| 631 | _|_|_| 632 | 633 | 634 | -102 635 | 636 | _|_| 637 | _| 638 | _|_|_|_| 639 | _| 640 | _| 641 | 642 | 643 | -103 644 | 645 | 646 | _|_|_| 647 | _| _| 648 | _| _| 649 | _|_|_| 650 | _| 651 | _|_| 652 | -104 653 | 654 | _| 655 | _|_|_| 656 | _| _| 657 | _| _| 658 | _| _| 659 | 660 | 661 | -105 662 | 663 | _| 664 | 665 | _| 666 | _| 667 | _| 668 | 669 | 670 | -106 671 | 672 | _| 673 | 674 | _| 675 | _| 676 | _| 677 | _| 678 | _| 679 | -107 680 | 681 | _| 682 | _| _| 683 | _|_| 684 | _| _| 685 | _| _| 686 | 687 | 688 | -108 689 | 690 | _| 691 | _| 692 | _| 693 | _| 694 | _| 695 | 696 | 697 | -109 698 | 699 | 700 | _|_|_| _|_| 701 | _| _| _| 702 | _| _| _| 703 | _| _| _| 704 | 705 | 706 | -110 707 | 708 | 709 | _|_|_| 710 | _| _| 711 | _| _| 712 | _| _| 713 | 714 | 715 | -111 716 | 717 | 718 | _|_| 719 | _| _| 720 | _| _| 721 | _|_| 722 | 723 | 724 | -112 725 | 726 | 727 | _|_|_| 728 | _| _| 729 | _| _| 730 | _|_|_| 731 | _| 732 | _| 733 | -113 734 | 735 | 736 | _|_|_| 737 | _| _| 738 | _| _| 739 | _|_|_| 740 | _| 741 | _| 742 | -114 743 | 744 | 745 | _| _|_| 746 | _|_| 747 | _| 748 | _| 749 | 750 | 751 | -115 752 | 753 | 754 | _|_|_| 755 | _|_| 756 | _|_| 757 | _|_|_| 758 | 759 | 760 | -116 761 | 762 | _| 763 | _|_|_|_| 764 | _| 765 | _| 766 | _|_| 767 | 768 | 769 | -117 770 | 771 | 772 | _| _| 773 | _| _| 774 | _| _| 775 | _|_|_| 776 | 777 | 778 | -118 779 | 780 | 781 | _| _| 782 | _| _| 783 | _| _| 784 | _| 785 | 786 | 787 | -119 788 | 789 | 790 | _| _| _| 791 | _| _| _| 792 | _| _| _| _| 793 | _| _| 794 | 795 | 796 | -120 797 | 798 | 799 | _| _| 800 | _|_| 801 | _| _| 802 | _| _| 803 | 804 | 805 | -121 806 | 807 | 808 | _| _| 809 | _| _| 810 | _| _| 811 | _|_|_| 812 | _| 813 | _|_| 814 | -122 815 | 816 | 817 | _|_|_|_| 818 | _| 819 | _| 820 | _|_|_|_| 821 | 822 | 823 | -123 824 | _| 825 | _| 826 | _| 827 | _| 828 | _| 829 | _| 830 | _| 831 | 832 | -124 833 | _| 834 | _| 835 | _| 836 | _| 837 | _| 838 | _| 839 | _| 840 | _| 841 | -125 842 | _| 843 | _| 844 | _| 845 | _| 846 | _| 847 | _| 848 | _| 849 | 850 | -126 851 | _| _| 852 | _| _| 853 | 854 | 855 | 856 | 857 | 858 | 859 | -------------------------------------------------------------------------------- /examples/rick/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/01.png -------------------------------------------------------------------------------- /examples/rick/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/02.png -------------------------------------------------------------------------------- /examples/rick/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/03.png -------------------------------------------------------------------------------- /examples/rick/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/04.png -------------------------------------------------------------------------------- /examples/rick/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/05.png -------------------------------------------------------------------------------- /examples/rick/06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/06.png -------------------------------------------------------------------------------- /examples/rick/07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/07.png -------------------------------------------------------------------------------- /examples/rick/08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/08.png -------------------------------------------------------------------------------- /examples/rick/09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/09.png -------------------------------------------------------------------------------- /examples/rick/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/10.png -------------------------------------------------------------------------------- /examples/rick/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/11.png -------------------------------------------------------------------------------- /examples/rick/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/12.png -------------------------------------------------------------------------------- /examples/rick/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/13.png -------------------------------------------------------------------------------- /examples/rick/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/14.png -------------------------------------------------------------------------------- /examples/rick/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/15.png -------------------------------------------------------------------------------- /examples/rick/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/16.png -------------------------------------------------------------------------------- /examples/rick/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/17.png -------------------------------------------------------------------------------- /examples/rick/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/18.png -------------------------------------------------------------------------------- /examples/rick/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/19.png -------------------------------------------------------------------------------- /examples/rick/20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/20.png -------------------------------------------------------------------------------- /examples/rick/21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/21.png -------------------------------------------------------------------------------- /examples/rick/22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/22.png -------------------------------------------------------------------------------- /examples/rick/23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/23.png -------------------------------------------------------------------------------- /examples/rick/24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/24.png -------------------------------------------------------------------------------- /examples/rick/25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/25.png -------------------------------------------------------------------------------- /examples/rick/26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/26.png -------------------------------------------------------------------------------- /examples/rick/27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/27.png -------------------------------------------------------------------------------- /examples/rick/28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/28.png -------------------------------------------------------------------------------- /examples/rick/29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/29.png -------------------------------------------------------------------------------- /examples/rick/30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/30.png -------------------------------------------------------------------------------- /examples/rick/31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/31.png -------------------------------------------------------------------------------- /examples/rick/rick.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/rick.mp4 -------------------------------------------------------------------------------- /examples/rick/rick.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/examples/rick/rick.webp -------------------------------------------------------------------------------- /maki/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | file(GLOB_RECURSE SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") 4 | pybind11_add_module(maki ${SOURCES}) 5 | target_include_directories(maki PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src") 6 | 7 | target_link_libraries(maki PRIVATE maki_core) 8 | -------------------------------------------------------------------------------- /maki/src/maki.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include "maki.h" 7 | 8 | namespace py = pybind11; 9 | 10 | void init_interface(py::module& m) 11 | { 12 | m.def("init", &Maki::init, "Initialize Maki; to be called once and only once"); 13 | py::enum_(m, "RendererImplementation") 14 | .value("none", Maki::Renderer::Implementation::none) 15 | .value("opengl", Maki::Renderer::Implementation::opengl) 16 | .export_values(); 17 | } 18 | void init_glm_types(py::module& m) 19 | { 20 | // TODO: remove these children's toys 21 | py::class_(m, "vec3") 22 | .def(py::init()) 23 | .def(py::self * float()); 24 | py::class_(m, "vec4") 25 | .def(py::init()) 26 | .def(py::self * float()); 27 | } 28 | py::class_ init_render_driver(py::module& m) 29 | { 30 | return py::class_(m, "RenderDriver") 31 | .def(py::init()) 32 | .def("await_termination", &Maki::RenderDriver::await_termination) 33 | .def("is_terminated", &Maki::RenderDriver::is_terminated) 34 | .def("set_target_frame", &Maki::RenderDriver::set_target_frame); 35 | } 36 | template 37 | void init_atom(py::class_& render_driver) 38 | { 39 | std::string type_name {AtomType::type_name}; 40 | std::transform(type_name.begin(), type_name.end(), type_name.begin(), [](unsigned char c) { return std::tolower(c); }); 41 | render_driver 42 | .def(("add_" + type_name + "_atom").c_str(), 43 | &Maki::RenderDriver::add_atom) 44 | .def(("show_" + type_name + "_atom").c_str(), 45 | &Maki::RenderDriver::show_atom) 46 | .def(("translate_" + type_name + "_atom").c_str(), 47 | &Maki::RenderDriver::translate_atom) 48 | .def(("color_" + type_name + "_atom").c_str(), 49 | &Maki::RenderDriver::color_atom); 50 | } 51 | 52 | PYBIND11_MODULE(maki, m) 53 | { 54 | m.doc() = "Experimental Rendering Backend for Manim."; 55 | init_interface(m); 56 | init_glm_types(m); 57 | auto render_driver = init_render_driver(m); 58 | init_atom(render_driver); 59 | init_atom(render_driver); 60 | } 61 | -------------------------------------------------------------------------------- /maki_core/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | file(GLOB_RECURSE SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") 4 | add_library(maki_core STATIC ${SOURCES}) 5 | target_include_directories(maki_core PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src") 6 | target_precompile_headers(maki_core PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/pch.h") 7 | target_include_directories(maki_core INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") 8 | 9 | # dependencies 10 | target_link_libraries(maki_core PUBLIC glfw) 11 | 12 | target_link_libraries(maki_core PUBLIC glm) 13 | 14 | target_link_libraries(maki_core PUBLIC ${OPENGL_LIBRARIES}) 15 | 16 | target_include_directories(maki_core PUBLIC ${GLEW_INCLUDE_DIRS}) 17 | target_link_libraries(maki_core PUBLIC ${GLEW_LIBRARIES}) 18 | 19 | target_link_libraries(maki_core PUBLIC stb) 20 | 21 | target_link_libraries(maki_core PUBLIC spdlog) 22 | 23 | target_link_libraries(maki_core PUBLIC imgui) 24 | 25 | # TODO: add only linux check 26 | option(ASAN "enable address and undefined behaviour sanitization" OFF) 27 | if(${ASAN}) 28 | message("-- Using ASan") 29 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined,address") 30 | set(CMAKE_LINKER_FLAGS "${CMAKE_LINKER_FLAGS} -fsanitize=undefined,address") 31 | endif() 32 | 33 | # copy resources in beginning 34 | message("-- Copying resources") 35 | file( 36 | COPY "${CMAKE_CURRENT_SOURCE_DIR}/res" 37 | DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/" 38 | ) 39 | # copy resources before each build 40 | add_custom_command( 41 | TARGET maki_core 42 | COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/res" 43 | "${CMAKE_CURRENT_BINARY_DIR}/res" 44 | ) 45 | message("-- Copying resources - OK") 46 | 47 | # platform config 48 | set(platforms "glfw") 49 | set(platform "none" CACHE STRING "Platform to be used, one of: ${platforms}") 50 | set_property(CACHE platform PROPERTY STRINGS ${platforms}) 51 | 52 | if(NOT platform IN_LIST platforms) 53 | message(FATAL_ERROR "The platform must be one of: ${platforms}") 54 | endif() 55 | add_compile_definitions(PLATFORM=${platform}) 56 | -------------------------------------------------------------------------------- /maki_core/include/maki.h: -------------------------------------------------------------------------------- 1 | // to be included from client program 2 | #pragma once 3 | 4 | #include "atom/atom.h" 5 | #include "core/log.h" 6 | #include "driver/interface.h" 7 | #include "driver/render_driver.h" 8 | -------------------------------------------------------------------------------- /maki_core/res/shaders/cuboid_frag.glsl: -------------------------------------------------------------------------------- 1 | #version 450 core 2 | 3 | in vec4 col; 4 | 5 | out vec4 color; 6 | 7 | void main() 8 | { 9 | color = col; 10 | } 11 | -------------------------------------------------------------------------------- /maki_core/res/shaders/cuboid_vert.glsl: -------------------------------------------------------------------------------- 1 | #version 450 core 2 | 3 | layout(location = 0) in vec3 a_pos; 4 | layout(location = 1) in vec4 a_col; 5 | 6 | uniform mat4 u_mvp; 7 | 8 | out vec4 col; 9 | 10 | void main() 11 | { 12 | gl_Position = u_mvp * vec4(a_pos, 1.0); 13 | col = a_col; 14 | } 15 | -------------------------------------------------------------------------------- /maki_core/res/shaders/simple_fragment.glsl: -------------------------------------------------------------------------------- 1 | #version 450 core 2 | 3 | /* // interpolated from vertex shader */ 4 | /* in vec2 uv; */ 5 | 6 | /* out vec3 color; */ 7 | 8 | /* // constant for whole mesh */ 9 | /* uniform sampler2D texture_sampler; */ 10 | 11 | /* void main() */ 12 | /* { */ 13 | /* color = texture(texture_sampler, uv).rgb; */ 14 | /* } */ 15 | 16 | in vec4 col; 17 | 18 | uniform vec3 u_color; 19 | 20 | out vec4 color; 21 | 22 | void main() 23 | { 24 | color = col; 25 | } 26 | -------------------------------------------------------------------------------- /maki_core/res/shaders/simple_vertex.glsl: -------------------------------------------------------------------------------- 1 | #version 450 core 2 | 3 | /* // load vec3 from buffer 0 for this vertex and store it as the position */ 4 | /* layout(location = 0) in vec3 vertex_position_modelspace; */ 5 | /* layout(location = 1) in vec2 vertex_uv; */ 6 | 7 | /* uniform mat4 mvp; */ 8 | 9 | /* out vec2 uv; */ 10 | 11 | /* void main() */ 12 | /* { */ 13 | /* gl_Position = mvp * vec4(vertex_position_modelspace, 1); */ 14 | /* uv = vertex_uv; */ 15 | /* } */ 16 | 17 | layout(location = 0) in vec3 a_position; 18 | layout(location = 1) in vec3 a_color; 19 | 20 | uniform mat4 u_mvp; 21 | 22 | out vec4 col; 23 | 24 | void main(){ 25 | gl_Position = u_mvp * vec4(a_position, 1.0); 26 | col = vec4(a_color, 1); 27 | } 28 | -------------------------------------------------------------------------------- /maki_core/src/atom/atom.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Maki { 4 | 5 | // smallest renderable unit 6 | // implementation inheritance -> Atom* never used <- using templated programming 7 | // abstract 8 | struct Atom { 9 | bool render {false}; 10 | 11 | // to be defined by implementation: 12 | // static constexpr const char* type_name {"Atom"}; 13 | }; 14 | 15 | } // namespace Maki 16 | -------------------------------------------------------------------------------- /maki_core/src/atom/atom_chain.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "atom/atom_diff_lifetime.h" 4 | #include "atom/atom_renderer.h" 5 | #include "core/definitions.h" 6 | 7 | namespace Maki { 8 | 9 | // representation of current frame (either for control or render thread) 10 | // thread safe; all member functions can be called from control and render thread (though they probably shouldn't) 11 | template 12 | class AtomChain { 13 | public: 14 | // returned atom shan't be used after destruction of lock 15 | std::pair get_locked_atom(size_t id) 16 | { 17 | lock lock {m_atoms_mutex}; 18 | return {std::move(lock), m_atoms[id]}; 19 | } 20 | 21 | uint32_t get_frame() { return m_frame; } 22 | size_t size() const 23 | { 24 | lock lock {m_atoms_mutex}; 25 | return m_atoms.size(); 26 | } 27 | uint32_t add() 28 | { 29 | // reason for locks everywhere -> only function called from control thread with render atom chain 30 | MAKI_ASSERT_CTRL_THREAD(); 31 | lock lock {m_atoms_mutex}; 32 | m_atoms.emplace_back(); 33 | return m_atoms.size() - 1; 34 | } 35 | 36 | void set_frame(uint32_t frame, const AtomDiffLifetime& atom_diff_lifetime) 37 | { 38 | lock lock {m_atoms_mutex}; 39 | MAKI_ASSERT_CRITICAL(atom_diff_lifetime.size() > frame, "Frame {} hasn't been created yet.", frame); 40 | while(m_frame < frame) 41 | next_frame(atom_diff_lifetime); 42 | while(m_frame > frame) 43 | prev_frame(atom_diff_lifetime); 44 | } 45 | void chrono_sync() 46 | { 47 | lock lock {m_atoms_mutex}; 48 | MAKI_LOG_EXTRA("{}Atom Chrono Sync initiated.", AtomType::type_name); 49 | // safe current state 50 | size_t target_atom_count = m_atoms.size(); 51 | 52 | // evict data 53 | m_atoms.resize(0); 54 | m_frame = 0; 55 | 56 | // sync 57 | m_atoms.resize(target_atom_count); 58 | } 59 | void render(typename AtomRendererRouter::type* renderer) 60 | { 61 | MAKI_ASSERT_RNDR_THREAD(); 62 | lock lock {m_atoms_mutex}; 63 | 64 | renderer->begin_scene(); 65 | for(size_t i {0}; i < m_atoms.size(); ++i) { 66 | renderer->draw_atom(m_atoms[i]); 67 | } 68 | renderer->end_scene(); 69 | } 70 | 71 | private: 72 | // expects m_atoms_mutex to already be locked 73 | void next_frame(const AtomDiffLifetime& atom_diff_lifetime) 74 | { 75 | atom_diff_lifetime.apply(m_frame + 1, m_atoms); 76 | ++m_frame; 77 | } 78 | void prev_frame(const AtomDiffLifetime& atom_diff_lifetime) 79 | { 80 | atom_diff_lifetime.reverse(m_frame, m_atoms); 81 | --m_frame; 82 | } 83 | 84 | private: 85 | // frame that has been applied last 86 | uint32_t m_frame {0}; 87 | std::vector m_atoms {}; 88 | mutable mutex m_atoms_mutex; 89 | }; 90 | 91 | } // namespace Maki 92 | -------------------------------------------------------------------------------- /maki_core/src/atom/atom_diff.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "atom/atom.h" 6 | #include "core/definitions.h" 7 | 8 | namespace Maki { 9 | 10 | // only to be created by control thread 11 | // immutable -> can't be changed by render thread -> no mutexes required 12 | 13 | // how to convert single atom "across" frame-border 14 | template 15 | class AtomDiff { 16 | public: 17 | explicit AtomDiff(uint32_t id) 18 | : m_id(id), m_priority(s_next_priority++) {} 19 | 20 | virtual ~AtomDiff() = default; 21 | 22 | uint32_t get_id() const { return m_id; } 23 | uint32_t get_priority() const { return m_priority; } 24 | 25 | virtual void apply(AtomType& atom) const = 0; 26 | virtual void reverse(AtomType& atom) const = 0; 27 | 28 | private: 29 | const uint32_t m_id; 30 | const uint32_t m_priority; 31 | 32 | private: 33 | static uint32_t s_next_priority; 34 | }; 35 | 36 | template 37 | uint32_t AtomDiff::s_next_priority {0}; 38 | 39 | // used for sorting containers 40 | template 41 | class CompareAtomDiff { 42 | public: 43 | bool operator()(const AtomDiff* a, const AtomDiff* b) const 44 | { 45 | if(a->get_id() < b->get_id()) 46 | return true; 47 | if(a->get_id() > b->get_id()) 48 | return false; 49 | // consult priority when id same 50 | if(a->get_priority() <= b->get_priority()) 51 | return true; 52 | return false; 53 | } 54 | }; 55 | 56 | template 57 | class ToggleRenderDiff: public AtomDiff { 58 | public: 59 | explicit ToggleRenderDiff(uint32_t id) 60 | : AtomDiff {id} {} 61 | 62 | virtual void apply(AtomType& atom) const override 63 | { 64 | atom.render = !atom.render; 65 | } 66 | virtual void reverse(AtomType& atom) const override 67 | { 68 | atom.render = !atom.render; 69 | } 70 | }; 71 | 72 | // template 73 | // class ReplacementDiff: public AtomDiff { 74 | // public: 75 | // ReplacementDiff(uint32_t id) 76 | // : AtomDiff(id) {} 77 | 78 | // virtual void apply(AtomType& atom) const override 79 | // { 80 | // atom += m_diff; 81 | // } 82 | // virtual void reverse(AtomType& atom) const override 83 | // { 84 | // atom -= m_diff; 85 | // } 86 | 87 | // private: 88 | // AtomType m_diff; 89 | // }; 90 | 91 | template 92 | class TransformDiff: public AtomDiff { 93 | public: 94 | TransformDiff(uint32_t id, mat4 mat) 95 | : AtomDiff {id}, m_mat(mat) 96 | { 97 | m_inv_mat = glm::inverse(mat); 98 | } 99 | 100 | virtual void apply(AtomType& atom) const override 101 | { 102 | for(vec3& pos: atom.ver_pos) { 103 | pos = m_mat * vec4(pos, 1.0f); 104 | } 105 | } 106 | virtual void reverse(AtomType& atom) const override 107 | { 108 | for(vec3& pos: atom.ver_pos) { 109 | pos = m_inv_mat * vec4(pos, 1.0f); 110 | } 111 | } 112 | 113 | private: 114 | mat4 m_mat; 115 | mat4 m_inv_mat; 116 | }; 117 | 118 | template 119 | class ReColorDiff: public AtomDiff { 120 | public: 121 | ReColorDiff(uint32_t id, std::array delta_col) 122 | : AtomDiff {id}, m_delta_col {delta_col} {} 123 | 124 | virtual void apply(AtomType& atom) const override 125 | { 126 | atom.add_col(m_delta_col); 127 | } 128 | virtual void reverse(AtomType& atom) const override 129 | { 130 | atom.sub_col(m_delta_col); 131 | } 132 | 133 | private: 134 | std::array m_delta_col; 135 | }; 136 | 137 | } // namespace Maki 138 | -------------------------------------------------------------------------------- /maki_core/src/atom/atom_diff_frame.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "atom/atom_diff.h" 6 | #include "core/log.h" 7 | 8 | namespace Maki { 9 | 10 | template 11 | class AtomChain; 12 | 13 | // all changes required to convert atoms of current frame into next or previous (apply or reverse) 14 | template 15 | class AtomDiffFrame { 16 | public: 17 | AtomDiffFrame() = default; 18 | // copy not allowed 19 | AtomDiffFrame(const AtomDiffFrame&) = delete; 20 | AtomDiffFrame& operator=(const AtomDiffFrame&) = delete; 21 | 22 | AtomDiffFrame(AtomDiffFrame&& other) 23 | : m_atom_diffs {std::move(other.m_atom_diffs)} 24 | { 25 | other.m_atom_diffs.clear(); 26 | } 27 | AtomDiffFrame& operator=(AtomDiffFrame&& other) 28 | { 29 | for(const AtomDiff* atom_diff: m_atom_diffs) 30 | delete atom_diff; 31 | m_atom_diffs = std::move(other.m_atom_diffs); 32 | other.m_atom_diffs.clear(); 33 | return *this; 34 | } 35 | ~AtomDiffFrame() 36 | { 37 | for(const AtomDiff* atom_diff: m_atom_diffs) 38 | delete atom_diff; 39 | } 40 | 41 | void add(const AtomDiff* new_atom_diff) 42 | { 43 | m_atom_diffs.insert(new_atom_diff); 44 | } 45 | 46 | void apply(std::vector& atoms) const 47 | { 48 | for(const AtomDiff* atom_diff: m_atom_diffs) { 49 | atom_diff->apply(atoms[atom_diff->get_id()]); 50 | } 51 | } 52 | void reverse(std::vector& atoms) const 53 | { 54 | for(const AtomDiff* atom_diff: m_atom_diffs) { 55 | atom_diff->reverse(atoms[atom_diff->get_id()]); 56 | } 57 | } 58 | 59 | private: 60 | // sorted by id, then priority -> cache locality + correct order 61 | std::set*, CompareAtomDiff> m_atom_diffs; 62 | }; 63 | 64 | } // namespace Maki 65 | -------------------------------------------------------------------------------- /maki_core/src/atom/atom_diff_lifetime.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "atom/atom_diff_frame.h" 6 | #include "core/definitions.h" 7 | #include "core/thread_safety.h" 8 | 9 | namespace Maki { 10 | 11 | // represent entire runtime of scene 12 | template 13 | class AtomDiffLifetime { 14 | public: 15 | // to be run from control thread // 16 | 17 | void ensure_frame_existence(uint32_t frame) 18 | { 19 | MAKI_ASSERT_CTRL_THREAD(); 20 | rec_lock lock {m_mutex}; 21 | if(frame >= m_atom_diff_frames.size()) 22 | m_atom_diff_frames.resize(frame + 1); 23 | } 24 | 25 | void add(uint32_t frame, const AtomDiff* diff) 26 | { 27 | MAKI_ASSERT_CTRL_THREAD(); 28 | rec_lock lock {m_mutex}; 29 | MAKI_ASSERT_CRITICAL(frame < m_atom_diff_frames.size(), "Frame {} hasn't been created yet for atom diff lifetime with {} frames.", frame, m_atom_diff_frames.size()); 30 | m_atom_diff_frames[frame].add(diff); 31 | // last frame outdated <- when currently currently going back with render thread would apply wrong reverse 32 | // TODO: actually verify that this fixes https://github.com/christopher-besch/maki/issues/16 33 | m_first_outdated_frame = frame - 1; 34 | } 35 | 36 | // to be run from render thread // 37 | 38 | bool is_outdated(uint32_t frame) 39 | { 40 | MAKI_ASSERT_RNDR_THREAD(); 41 | rec_lock lock {m_mutex}; 42 | if(frame >= m_first_outdated_frame) 43 | return true; 44 | // not outdated 45 | update(); 46 | return false; 47 | } 48 | void update() 49 | { 50 | MAKI_ASSERT_RNDR_THREAD(); 51 | rec_lock lock {m_mutex}; 52 | m_first_outdated_frame = m_atom_diff_frames.size(); 53 | } 54 | 55 | // can be run from either thread // 56 | 57 | size_t size() const 58 | { 59 | rec_lock lock {m_mutex}; 60 | return m_atom_diff_frames.size(); 61 | } 62 | 63 | // apply changes of requested frame to all atoms of an atom chain 64 | void apply(uint32_t frame, std::vector& atoms) const 65 | { 66 | rec_lock lock {m_mutex}; 67 | m_atom_diff_frames[frame].apply(atoms); 68 | } 69 | void reverse(uint32_t frame, std::vector& atoms) const 70 | { 71 | rec_lock lock {m_mutex}; 72 | m_atom_diff_frames[frame].reverse(atoms); 73 | } 74 | 75 | private: 76 | // one entry per frame 77 | // first frame stays empty 78 | std::vector> m_atom_diff_frames {std::vector>(1)}; 79 | // render thread has to reload when it's atom chain is at or after first outdated frame 80 | uint32_t m_first_outdated_frame {1}; 81 | // lock m_atom_diff_frames and m_first_outdated_frame 82 | mutable rec_mutex m_mutex; 83 | }; 84 | 85 | } // namespace Maki 86 | -------------------------------------------------------------------------------- /maki_core/src/atom/atom_dispenser.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "atom_dispenser.h" 4 | 5 | namespace Maki { 6 | 7 | AtomDispenser::~AtomDispenser() 8 | { 9 | MAKI_ASSERT_CTRL_THREAD(); 10 | MAKI_ASSERT_CRITICAL(!m_cuboid_renderer, "CuboidRenderer hasn't been deleted yet."); 11 | MAKI_ASSERT_CRITICAL(!m_quadrilateral_renderer, "QuadrilateralRenderer hasn't been deleted yet."); 12 | } 13 | 14 | uint32_t AtomDispenser::get_last_frame() 15 | { 16 | MAKI_ASSERT_RNDR_THREAD(); 17 | return std::max( 18 | m_cuboid_diff_lifetime.size(), 19 | m_quadrilateral_diff_lifetime.size()) - 20 | 1; 21 | } 22 | 23 | void AtomDispenser::create_all_atom_renderers(Renderer* renderer) 24 | { 25 | MAKI_ASSERT_RNDR_THREAD(); 26 | MAKI_ASSERT_CRITICAL(!m_cuboid_renderer, "Recreation of CuboidRenderer."); 27 | m_cuboid_renderer = new CuboidRenderer(renderer); 28 | 29 | MAKI_ASSERT_CRITICAL(!m_quadrilateral_renderer, "Recreation of QuadrilateralRenderer."); 30 | m_quadrilateral_renderer = new QuadrilateralRenderer(renderer); 31 | } 32 | 33 | void AtomDispenser::delete_all_renderers() 34 | { 35 | MAKI_ASSERT_RNDR_THREAD(); 36 | MAKI_ASSERT_CRITICAL(m_cuboid_renderer, "Redeletion of CuboidRenderer."); 37 | delete m_cuboid_renderer; 38 | m_cuboid_renderer = nullptr; 39 | 40 | MAKI_ASSERT_CRITICAL(m_quadrilateral_renderer, "Redeletion of QuadrilateralRenderer."); 41 | delete m_quadrilateral_renderer; 42 | m_quadrilateral_renderer = nullptr; 43 | } 44 | 45 | void AtomDispenser::render_all() 46 | { 47 | MAKI_ASSERT_RNDR_THREAD(); 48 | individual_render(); 49 | 50 | individual_render(); 51 | } 52 | 53 | void AtomDispenser::set_render_frame(uint32_t frame) 54 | { 55 | MAKI_ASSERT_RNDR_THREAD(); 56 | m_render_cuboid_chain.set_frame(frame, m_cuboid_diff_lifetime); 57 | 58 | m_render_quadrilateral_chain.set_frame(frame, m_quadrilateral_diff_lifetime); 59 | } 60 | void AtomDispenser::ensure_chrono_sync(bool force) 61 | { 62 | MAKI_ASSERT_RNDR_THREAD(); 63 | ensure_individual_chrono_sync(force); 64 | 65 | ensure_individual_chrono_sync(force); 66 | } 67 | 68 | void AtomDispenser::ensure_frame_existence(uint32_t frame) 69 | { 70 | m_cuboid_diff_lifetime.ensure_frame_existence(frame); 71 | 72 | m_quadrilateral_diff_lifetime.ensure_frame_existence(frame); 73 | } 74 | 75 | } // namespace Maki 76 | -------------------------------------------------------------------------------- /maki_core/src/atom/atom_dispenser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "atom/atom_chain.h" 4 | #include "atom/atom_renderer.h" 5 | #include "core/definitions.h" 6 | #include "core/thread_safety.h" 7 | 8 | #include 9 | 10 | namespace Maki { 11 | 12 | class AtomDispenser { 13 | public: 14 | // to be run from control thread // 15 | 16 | ~AtomDispenser(); 17 | 18 | // return id of created atom 19 | template 20 | uint32_t add_atom() 21 | { 22 | MAKI_ASSERT_CTRL_THREAD(); 23 | // reason for why chains can't be thread_local 24 | uint32_t control_id = get_control_chain().add(); 25 | uint32_t render_id = get_render_chain().add(); 26 | MAKI_ASSERT_CRITICAL(control_id == render_id, "Control (ID {}) and render (ID {}) {} chain out of sync.", control_id, render_id, AtomType::type_name); 27 | return control_id; 28 | } 29 | template 30 | void show_atom(uint32_t id, uint32_t frame, bool render) 31 | { 32 | MAKI_ASSERT_CTRL_THREAD(); 33 | // TODO: prepare_update locks m_atoms_mutex and get_locked_atom locks it again -> inefficient 34 | prepare_update(id, frame); 35 | auto [lock, atom] = get_control_chain().get_locked_atom(id); 36 | if(atom.render != render) { 37 | // ownsership is taken over by AtomDiffFrame 38 | const auto diff = new ToggleRenderDiff(id); 39 | finalize_update(frame, atom, diff); 40 | } 41 | } 42 | template 43 | void translate_atom(uint32_t id, uint32_t frame, vec3 delta) 44 | { 45 | MAKI_ASSERT_CTRL_THREAD(); 46 | prepare_update(id, frame); 47 | auto [lock, atom] = get_control_chain().get_locked_atom(id); 48 | auto diff = new TransformDiff(id, glm::translate(mat4 {1.0f}, delta)); 49 | finalize_update(frame, atom, diff); 50 | } 51 | template 52 | void color_atom(uint32_t id, uint32_t frame, vec4 col) 53 | { 54 | MAKI_ASSERT_CTRL_THREAD(); 55 | prepare_update(id, frame); 56 | auto [lock, atom] = get_control_chain().get_locked_atom(id); 57 | // calculate difference 58 | std::array delta_col; 59 | delta_col.fill(col); 60 | for(size_t i {0}; i != delta_col.size(); ++i) { 61 | delta_col[i] -= atom.ver_col[i]; 62 | } 63 | auto diff = new ReColorDiff(id, delta_col); 64 | finalize_update(frame, atom, diff); 65 | } 66 | 67 | // to be run from render thread // 68 | 69 | uint32_t get_last_frame(); 70 | 71 | // can't be performed in constructor <- constructed with main thread, renderer using OpenGL calls -> need to be called from render thread 72 | void create_all_atom_renderers(Renderer* renderer); 73 | // same with destructor 74 | void delete_all_renderers(); 75 | 76 | void render_all(); 77 | 78 | // update frame to target 79 | void set_render_frame(uint32_t frame); 80 | // update rendering thread atom chains if necessary 81 | void ensure_chrono_sync(bool force = false); 82 | 83 | // can ben run from both threads // 84 | 85 | void ensure_frame_existence(uint32_t frame); 86 | 87 | private: 88 | // atom dispensing -> return requested variable in template specialization // 89 | template 90 | AtomChain& get_control_chain(); 91 | template 92 | AtomChain& get_render_chain(); 93 | template 94 | AtomDiffLifetime& get_diff_lifetime(); 95 | // ::type notation required because renderers are implemented using OOP -> generic programming interface layer required 96 | template 97 | typename AtomRendererRouter::type* get_renderer(); 98 | 99 | // to be run from control thread 100 | 101 | // set control frame -> set AtomChain to frame that should be effected 102 | template 103 | void prepare_update(uint32_t id, uint32_t frame) 104 | { 105 | MAKI_ASSERT_CTRL_THREAD(); 106 | MAKI_ASSERT_CRITICAL(get_control_chain().size() > id, "ID {} hasn't been allocated yet for {} atoms.", id, AtomType::type_name); 107 | // first frame can't have any diffs <- first frame used as reference for others 108 | MAKI_ASSERT_CRITICAL(frame > 0, "Frame {} is invalid.", frame); 109 | 110 | ensure_frame_existence(frame); 111 | get_control_chain().set_frame(frame, get_diff_lifetime()); 112 | } 113 | // save new AtomDiff and apply it -> current AtomChain is correct 114 | template 115 | void finalize_update(uint32_t frame, AtomType& atom, const AtomDiff* diff) 116 | { 117 | MAKI_ASSERT_CTRL_THREAD(); 118 | get_diff_lifetime().add(frame, diff); 119 | diff->apply(atom); 120 | } 121 | 122 | // to be run from render thread // 123 | 124 | template 125 | void ensure_individual_chrono_sync(bool force) 126 | { 127 | MAKI_ASSERT_RNDR_THREAD(); 128 | if(force || get_diff_lifetime().is_outdated(get_render_chain().get_frame())) { 129 | get_render_chain().chrono_sync(); 130 | get_diff_lifetime().update(); 131 | } 132 | } 133 | 134 | template 135 | void individual_render() 136 | { 137 | MAKI_ASSERT_RNDR_THREAD(); 138 | get_render_chain().render(get_renderer()); 139 | } 140 | 141 | private: 142 | // CuboidAtom 143 | // used by control thread or render thread respectively 144 | AtomChain m_control_cuboid_chain {}; 145 | AtomChain m_render_cuboid_chain {}; 146 | AtomDiffLifetime m_cuboid_diff_lifetime {}; 147 | CuboidRenderer* m_cuboid_renderer {nullptr}; 148 | // QuadrilateralAtom 149 | AtomChain m_control_quadrilateral_chain {}; 150 | AtomChain m_render_quadrilateral_chain {}; 151 | AtomDiffLifetime m_quadrilateral_diff_lifetime {}; 152 | QuadrilateralRenderer* m_quadrilateral_renderer {nullptr}; 153 | }; 154 | 155 | // CuboidAtom 156 | template<> 157 | inline AtomChain& AtomDispenser::get_control_chain() 158 | { 159 | return m_control_cuboid_chain; 160 | } 161 | template<> 162 | inline AtomChain& AtomDispenser::get_render_chain() 163 | { 164 | return m_render_cuboid_chain; 165 | } 166 | template<> 167 | inline AtomDiffLifetime& AtomDispenser::get_diff_lifetime() 168 | { 169 | return m_cuboid_diff_lifetime; 170 | } 171 | template<> 172 | inline AtomRendererRouter::type* AtomDispenser::get_renderer() 173 | { 174 | return m_cuboid_renderer; 175 | } 176 | 177 | // QuadrilateralAtom 178 | template<> 179 | inline AtomChain& AtomDispenser::get_control_chain() 180 | { 181 | return m_control_quadrilateral_chain; 182 | } 183 | template<> 184 | inline AtomChain& AtomDispenser::get_render_chain() 185 | { 186 | return m_render_quadrilateral_chain; 187 | } 188 | template<> 189 | inline AtomDiffLifetime& AtomDispenser::get_diff_lifetime() 190 | { 191 | return m_quadrilateral_diff_lifetime; 192 | } 193 | template<> 194 | inline QuadrilateralRenderer* AtomDispenser::get_renderer() 195 | { 196 | return m_quadrilateral_renderer; 197 | } 198 | 199 | } // namespace Maki 200 | -------------------------------------------------------------------------------- /maki_core/src/atom/atom_renderer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "atom/renderers/cuboid_renderer.h" 4 | #include "atom/renderers/quadrilateral_renderer.h" 5 | 6 | namespace Maki { 7 | 8 | // used as an interface between OOP implementation of renderer and AtomDispenser using generic programming 9 | // can be used like: 10 | // typename AtomRendererRouter::type* m_cuboid_renderer {nullptr}; 11 | template 12 | struct AtomRendererRouter { 13 | // can't be used unspecialized 14 | typedef void type; 15 | }; 16 | 17 | template<> 18 | struct AtomRendererRouter { 19 | typedef CuboidRenderer type; 20 | }; 21 | 22 | template<> 23 | struct AtomRendererRouter { 24 | typedef QuadrilateralRenderer type; 25 | }; 26 | 27 | } // namespace Maki 28 | -------------------------------------------------------------------------------- /maki_core/src/atom/atoms/cuboid_atom.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "cuboid_atom.h" 4 | 5 | namespace Maki { 6 | 7 | // TODO: remove code duplication 8 | CuboidAtom& CuboidAtom::operator+=(const CuboidAtom& atom) 9 | { 10 | add_pos(atom.ver_pos); 11 | add_col(atom.ver_col); 12 | return *this; 13 | } 14 | CuboidAtom& CuboidAtom::operator-=(const CuboidAtom& atom) 15 | { 16 | sub_pos(atom.ver_pos); 17 | sub_col(atom.ver_col); 18 | return *this; 19 | } 20 | void CuboidAtom::add_pos(const std::array& delta_pos) 21 | { 22 | for(size_t i {0}; i != ver_pos.size(); ++i) { 23 | ver_pos[i] += delta_pos[i]; 24 | } 25 | } 26 | void CuboidAtom::sub_pos(const std::array& delta_pos) 27 | { 28 | for(size_t i {0}; i != ver_pos.size(); ++i) { 29 | ver_pos[i] -= delta_pos[i]; 30 | } 31 | } 32 | void CuboidAtom::add_col(const std::array& delta_col) 33 | { 34 | for(size_t i {0}; i != ver_col.size(); ++i) { 35 | ver_col[i] += delta_col[i]; 36 | } 37 | } 38 | void CuboidAtom::sub_col(const std::array& delta_col) 39 | { 40 | for(size_t i {0}; i != ver_col.size(); ++i) { 41 | ver_col[i] -= delta_col[i]; 42 | } 43 | } 44 | 45 | } // namespace Maki 46 | -------------------------------------------------------------------------------- /maki_core/src/atom/atoms/cuboid_atom.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "atom/atom.h" 6 | #include "core/definitions.h" 7 | 8 | namespace Maki { 9 | 10 | struct CuboidAtom: public Atom { 11 | std::array ver_pos { 12 | vec3 {-1.0f, -1.0f, +1.0f}, // 0 bottom front left 13 | vec3 {+1.0f, -1.0f, +1.0f}, // 1 bottom front right 14 | vec3 {-1.0f, -1.0f, -1.0f}, // 2 bottom back left 15 | vec3 {+1.0f, -1.0f, -1.0f}, // 3 bottom back right 16 | vec3 {-1.0f, +1.0f, +1.0f}, // 4 top front left 17 | vec3 {+1.0f, +1.0f, +1.0f}, // 5 top front right 18 | vec3 {-1.0f, +1.0f, -1.0f}, // 6 top back left 19 | vec3 {+1.0f, +1.0f, -1.0f}}; // 7 top back right 20 | std::array ver_col { 21 | vec4 {1.0f, 1.0f, 1.0f, 1.0f}, 22 | vec4 {1.0f, 1.0f, 1.0f, 1.0f}, 23 | vec4 {1.0f, 1.0f, 1.0f, 1.0f}, 24 | vec4 {1.0f, 1.0f, 1.0f, 1.0f}, 25 | vec4 {1.0f, 1.0f, 1.0f, 1.0f}, 26 | vec4 {1.0f, 1.0f, 1.0f, 1.0f}, 27 | vec4 {1.0f, 1.0f, 1.0f, 1.0f}, 28 | vec4 {1.0f, 1.0f, 1.0f, 1.0f}}; 29 | 30 | CuboidAtom& operator+=(const CuboidAtom& atom); 31 | CuboidAtom& operator-=(const CuboidAtom& atom); 32 | void add_pos(const std::array& delta_pos); 33 | void sub_pos(const std::array& delta_pos); 34 | void add_col(const std::array& delta_col); 35 | void sub_col(const std::array& delta_col); 36 | 37 | static constexpr uint32_t vertex_count {8}; 38 | static constexpr const char* type_name {"Cuboid"}; 39 | }; 40 | 41 | } // namespace Maki 42 | -------------------------------------------------------------------------------- /maki_core/src/atom/atoms/quadrilateral_atom.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "quadrilateral_atom.h" 4 | 5 | namespace Maki { 6 | 7 | // TODO: remove code duplication 8 | QuadrilateralAtom& QuadrilateralAtom::operator+=(const QuadrilateralAtom& atom) 9 | { 10 | add_pos(atom.ver_pos); 11 | add_col(atom.ver_col); 12 | return *this; 13 | } 14 | QuadrilateralAtom& QuadrilateralAtom::operator-=(const QuadrilateralAtom& atom) 15 | { 16 | sub_pos(atom.ver_pos); 17 | sub_col(atom.ver_col); 18 | return *this; 19 | } 20 | void QuadrilateralAtom::add_pos(const std::array& delta_pos) 21 | { 22 | for(size_t i {0}; i != ver_pos.size(); ++i) { 23 | ver_pos[i] += delta_pos[i]; 24 | } 25 | } 26 | void QuadrilateralAtom::sub_pos(const std::array& delta_pos) 27 | { 28 | for(size_t i {0}; i != ver_pos.size(); ++i) { 29 | ver_pos[i] -= delta_pos[i]; 30 | } 31 | } 32 | void QuadrilateralAtom::add_col(const std::array& delta_col) 33 | { 34 | for(size_t i {0}; i != ver_col.size(); ++i) { 35 | ver_col[i] += delta_col[i]; 36 | } 37 | } 38 | void QuadrilateralAtom::sub_col(const std::array& delta_col) 39 | { 40 | for(size_t i {0}; i != ver_col.size(); ++i) { 41 | ver_col[i] -= delta_col[i]; 42 | } 43 | } 44 | 45 | } // namespace Maki 46 | -------------------------------------------------------------------------------- /maki_core/src/atom/atoms/quadrilateral_atom.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "atom/atom.h" 6 | #include "core/definitions.h" 7 | 8 | namespace Maki { 9 | 10 | struct QuadrilateralAtom: public Atom { 11 | std::array ver_pos { 12 | vec3 {-1.0f, -1.0f, +0.0f}, // bottom left 13 | vec3 {+1.0f, -1.0f, +0.0f}, // bottom right 14 | vec3 {-1.0f, +1.0f, +0.0f}, // top left 15 | vec3 {+1.0f, +1.0f, +0.0f}}; // top right 16 | std::array ver_col { 17 | vec4 {1.0f, 1.0f, 1.0f, 1.0f}, 18 | vec4 {1.0f, 1.0f, 1.0f, 1.0f}, 19 | vec4 {1.0f, 1.0f, 1.0f, 1.0f}, 20 | vec4 {1.0f, 1.0f, 1.0f, 1.0f}}; 21 | 22 | QuadrilateralAtom& operator+=(const QuadrilateralAtom& atom); 23 | QuadrilateralAtom& operator-=(const QuadrilateralAtom& atom); 24 | void add_pos(const std::array& delta_pos); 25 | void sub_pos(const std::array& delta_pos); 26 | void add_col(const std::array& delta_col); 27 | void sub_col(const std::array& delta_col); 28 | 29 | static constexpr uint32_t vertex_count {4}; 30 | static constexpr const char* type_name {"Quadrilateral"}; 31 | }; 32 | 33 | } // namespace Maki 34 | -------------------------------------------------------------------------------- /maki_core/src/atom/renderers/batch_renderer.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "batch_renderer.h" 4 | 5 | namespace Maki { 6 | 7 | BatchRenderer::BatchRenderer(Renderer* renderer, VertexBuffer* vertex_buffer, IndexBuffer* index_buffer, Shader* shader) 8 | : m_renderer {renderer}, 9 | m_vertex_array {VertexArray::create()}, 10 | m_vertex_buffer {vertex_buffer}, 11 | m_index_buffer {index_buffer}, 12 | m_shader {shader} 13 | { 14 | m_vertex_array->add_vertex_buffer(m_vertex_buffer); 15 | m_vertex_array->set_index_buffer(m_index_buffer); 16 | m_vertex_array->unbind(); 17 | } 18 | 19 | BatchRenderer::~BatchRenderer() 20 | { 21 | delete m_vertex_array; 22 | delete m_vertex_buffer; 23 | delete m_index_buffer; 24 | delete m_shader; 25 | } 26 | 27 | void BatchRenderer::begin_scene() 28 | { 29 | m_shader->set_mat4("u_mvp", m_renderer->get_camera()->get_view_projection()); 30 | start_batch(); 31 | } 32 | void BatchRenderer::end_scene() 33 | { 34 | flush(); 35 | } 36 | void BatchRenderer::start_batch() 37 | { 38 | m_index_count = 0; 39 | reset_vertex_buffer_ptr(); 40 | } 41 | void BatchRenderer::next_batch() 42 | { 43 | flush(); 44 | start_batch(); 45 | } 46 | void BatchRenderer::flush() 47 | { 48 | m_shader->bind(); 49 | auto vao_bind = VertexArrayBind(m_vertex_array); 50 | 51 | if(!m_index_count) 52 | // nothing to draw 53 | return; 54 | // how much of vertex buffer base is actually used 55 | uint32_t data_size {static_cast( 56 | reinterpret_cast(get_vertex_buffer_ptr()) - 57 | reinterpret_cast(get_vertex_buffer_base()))}; 58 | m_vertex_buffer->set_data(get_vertex_buffer_base(), data_size); 59 | 60 | m_renderer->draw(m_index_count); 61 | 62 | m_shader->unbind(); 63 | } 64 | 65 | } // namespace Maki 66 | -------------------------------------------------------------------------------- /maki_core/src/atom/renderers/batch_renderer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "atom/atom.h" 4 | #include "renderer/renderer.h" 5 | 6 | namespace Maki { 7 | 8 | // implementation inheritance 9 | // abstract 10 | class BatchRenderer { 11 | public: 12 | BatchRenderer(Renderer* renderer, VertexBuffer* vertex_buffer, IndexBuffer* index_buffer, Shader* shader); 13 | virtual ~BatchRenderer(); 14 | 15 | // can be augmented by implementation 16 | virtual void begin_scene(); 17 | void end_scene(); 18 | 19 | // to be defined by implementation 20 | // void draw_atom(const AtomType& atom); 21 | 22 | protected: 23 | // reset buffer pointer 24 | void start_batch(); 25 | // flush and start new batch 26 | void next_batch(); 27 | // render call 28 | void flush(); 29 | 30 | virtual void reset_vertex_buffer_ptr() = 0; 31 | // void needed because size of a vertex varies from implementation to implementation -> vertex buffer data has to be owned by implementation 32 | virtual const void* get_vertex_buffer_base() const = 0; 33 | virtual const void* get_vertex_buffer_ptr() const = 0; 34 | 35 | protected: 36 | uint32_t m_index_count {0}; 37 | 38 | private: 39 | Renderer* m_renderer {nullptr}; 40 | VertexArray* m_vertex_array {nullptr}; 41 | VertexBuffer* m_vertex_buffer {nullptr}; 42 | IndexBuffer* m_index_buffer {nullptr}; 43 | Shader* m_shader {nullptr}; 44 | }; 45 | 46 | } // namespace Maki 47 | -------------------------------------------------------------------------------- /maki_core/src/atom/renderers/cuboid_renderer.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "cuboid_renderer.h" 4 | 5 | namespace Maki { 6 | 7 | CuboidRenderer::CuboidRenderer(Renderer* renderer) 8 | : BatchRenderer { 9 | renderer, 10 | VertexBuffer::create( 11 | {{"a_pos", DataType::float3}, 12 | {"a_col", DataType::float4}}, 13 | s_max_vertices * sizeof(Vertex)), 14 | create_index_buffer(), 15 | Shader::create("maki_core/res/shaders/cuboid_vert.glsl", "maki_core/res/shaders/cuboid_frag.glsl")}, 16 | m_vertex_buffer_base {new Vertex[s_max_vertices]} {} 17 | 18 | CuboidRenderer::~CuboidRenderer() 19 | { 20 | delete[] m_vertex_buffer_base; 21 | } 22 | 23 | void CuboidRenderer::draw_atom(const CuboidAtom& atom) 24 | { 25 | if(!atom.render) 26 | return; 27 | if(m_index_count >= s_max_indices) 28 | next_batch(); 29 | for(uint32_t i {0}; i < 8; ++i) { 30 | m_vertex_buffer_ptr->pos = atom.ver_pos[i]; 31 | m_vertex_buffer_ptr->col = atom.ver_col[i]; 32 | ++m_vertex_buffer_ptr; 33 | } 34 | m_index_count += 36; 35 | } 36 | 37 | // TODO: remove code duplication 38 | void CuboidRenderer::reset_vertex_buffer_ptr() 39 | { 40 | m_vertex_buffer_ptr = m_vertex_buffer_base; 41 | } 42 | 43 | IndexBuffer* CuboidRenderer::create_index_buffer() 44 | { 45 | uint32_t* indices {new uint32_t[s_max_indices]}; 46 | 47 | uint32_t offset {0}; 48 | for(uint32_t i {0}; i < s_max_indices; i += 36) { 49 | // bottom 50 | indices[i + 0] = offset + 2; 51 | indices[i + 1] = offset + 3; 52 | indices[i + 2] = offset + 0; 53 | 54 | indices[i + 3] = offset + 0; 55 | indices[i + 4] = offset + 3; 56 | indices[i + 5] = offset + 1; 57 | 58 | // front 59 | indices[i + 6] = offset + 0; 60 | indices[i + 7] = offset + 1; 61 | indices[i + 8] = offset + 5; 62 | 63 | indices[i + 9] = offset + 5; 64 | indices[i + 10] = offset + 4; 65 | indices[i + 11] = offset + 0; 66 | 67 | // left 68 | indices[i + 12] = offset + 2; 69 | indices[i + 13] = offset + 0; 70 | indices[i + 14] = offset + 4; 71 | 72 | indices[i + 15] = offset + 4; 73 | indices[i + 16] = offset + 6; 74 | indices[i + 17] = offset + 2; 75 | 76 | // right 77 | indices[i + 18] = offset + 1; 78 | indices[i + 19] = offset + 3; 79 | indices[i + 20] = offset + 7; 80 | 81 | indices[i + 21] = offset + 7; 82 | indices[i + 22] = offset + 5; 83 | indices[i + 23] = offset + 1; 84 | 85 | // back 86 | indices[i + 24] = offset + 3; 87 | indices[i + 25] = offset + 2; 88 | indices[i + 26] = offset + 6; 89 | 90 | indices[i + 27] = offset + 6; 91 | indices[i + 28] = offset + 7; 92 | indices[i + 29] = offset + 3; 93 | 94 | // top 95 | indices[i + 30] = offset + 7; 96 | indices[i + 31] = offset + 6; 97 | indices[i + 32] = offset + 4; 98 | 99 | indices[i + 33] = offset + 4; 100 | indices[i + 34] = offset + 5; 101 | indices[i + 35] = offset + 7; 102 | 103 | offset += 8; 104 | } 105 | IndexBuffer* index_buffer = IndexBuffer::create(s_max_indices, indices); 106 | delete[] indices; 107 | return index_buffer; 108 | } 109 | 110 | } // namespace Maki 111 | -------------------------------------------------------------------------------- /maki_core/src/atom/renderers/cuboid_renderer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "atom/atoms/cuboid_atom.h" 4 | #include "atom/renderers/batch_renderer.h" 5 | #include "renderer/renderer.h" 6 | 7 | namespace Maki { 8 | 9 | // batch renderer 10 | class CuboidRenderer: public BatchRenderer { 11 | public: 12 | CuboidRenderer(Renderer* renderer); 13 | ~CuboidRenderer(); 14 | 15 | void draw_atom(const CuboidAtom& atom); 16 | 17 | protected: 18 | virtual void reset_vertex_buffer_ptr() override; 19 | virtual const void* get_vertex_buffer_base() const override { return m_vertex_buffer_base; } 20 | virtual const void* get_vertex_buffer_ptr() const override { return m_vertex_buffer_ptr; } 21 | 22 | static IndexBuffer* create_index_buffer(); 23 | 24 | protected: 25 | struct Vertex { 26 | vec3 pos; 27 | vec4 col; 28 | }; 29 | 30 | Vertex* m_vertex_buffer_base {nullptr}; 31 | Vertex* m_vertex_buffer_ptr {nullptr}; 32 | 33 | protected: 34 | // how many cuboids in single render call / batch 35 | static constexpr uint32_t s_max_cuboids {3000}; 36 | // 8 corners 37 | static constexpr uint32_t s_max_vertices {s_max_cuboids * 8}; 38 | // 6 sides, 2 triangles per side, 3 vertices per triangle = 36 39 | static constexpr uint32_t s_max_indices {s_max_cuboids * 6 * 2 * 3}; 40 | }; 41 | 42 | } // namespace Maki 43 | -------------------------------------------------------------------------------- /maki_core/src/atom/renderers/quadrilateral_renderer.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "quadrilateral_renderer.h" 4 | 5 | namespace Maki { 6 | 7 | QuadrilateralRenderer::QuadrilateralRenderer(Renderer* renderer) 8 | : BatchRenderer { 9 | renderer, 10 | VertexBuffer::create( 11 | {{"a_pos", DataType::float3}, 12 | {"a_col", DataType::float4}}, 13 | s_max_vertices * sizeof(Vertex)), 14 | create_index_buffer(), 15 | // TODO: use shader that renders both sides 16 | Shader::create("maki_core/res/shaders/cuboid_vert.glsl", "maki_core/res/shaders/cuboid_frag.glsl")}, 17 | m_vertex_buffer_base {new Vertex[s_max_vertices]} 18 | { 19 | } 20 | 21 | QuadrilateralRenderer::~QuadrilateralRenderer() 22 | { 23 | delete[] m_vertex_buffer_base; 24 | } 25 | 26 | void QuadrilateralRenderer::draw_atom(const QuadrilateralAtom& atom) 27 | { 28 | if(!atom.render) 29 | return; 30 | if(m_index_count >= s_max_indices) 31 | next_batch(); 32 | for(uint32_t i {0}; i < 4; ++i) { 33 | m_vertex_buffer_ptr->pos = atom.ver_pos[i]; 34 | m_vertex_buffer_ptr->col = atom.ver_col[i]; 35 | ++m_vertex_buffer_ptr; 36 | } 37 | m_index_count += 6; 38 | } 39 | 40 | // TODO: remove code duplication 41 | void QuadrilateralRenderer::reset_vertex_buffer_ptr() 42 | { 43 | m_vertex_buffer_ptr = m_vertex_buffer_base; 44 | } 45 | 46 | IndexBuffer* QuadrilateralRenderer::create_index_buffer() 47 | { 48 | uint32_t* indices {new uint32_t[s_max_indices]}; 49 | 50 | uint32_t offset {0}; 51 | for(uint32_t i {0}; i < s_max_indices; i += 6) { 52 | indices[i + 0] = offset + 2; 53 | indices[i + 1] = offset + 0; 54 | indices[i + 2] = offset + 3; 55 | 56 | indices[i + 3] = offset + 3; 57 | indices[i + 4] = offset + 0; 58 | indices[i + 5] = offset + 1; 59 | 60 | offset += 4; 61 | } 62 | IndexBuffer* index_buffer = IndexBuffer::create(s_max_indices, indices); 63 | delete[] indices; 64 | return index_buffer; 65 | } 66 | 67 | } // namespace Maki 68 | -------------------------------------------------------------------------------- /maki_core/src/atom/renderers/quadrilateral_renderer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "atom/atoms/quadrilateral_atom.h" 4 | #include "atom/renderers/batch_renderer.h" 5 | #include "renderer/renderer.h" 6 | 7 | namespace Maki { 8 | 9 | // batch renderer 10 | class QuadrilateralRenderer: public BatchRenderer { 11 | public: 12 | QuadrilateralRenderer(Renderer* renderer); 13 | ~QuadrilateralRenderer(); 14 | 15 | void draw_atom(const QuadrilateralAtom& atom); 16 | 17 | protected: 18 | virtual void reset_vertex_buffer_ptr() override; 19 | virtual const void* get_vertex_buffer_base() const override { return m_vertex_buffer_base; } 20 | virtual const void* get_vertex_buffer_ptr() const override { return m_vertex_buffer_ptr; } 21 | 22 | static IndexBuffer* create_index_buffer(); 23 | 24 | protected: 25 | struct Vertex { 26 | vec3 pos; 27 | vec4 col; 28 | }; 29 | 30 | Vertex* m_vertex_buffer_base {nullptr}; 31 | Vertex* m_vertex_buffer_ptr {nullptr}; 32 | 33 | protected: 34 | // how many cuboids in single render call / batch 35 | static constexpr uint32_t s_max_quadrilaterals {12000}; 36 | // 4 corners 37 | static constexpr uint32_t s_max_vertices {s_max_quadrilaterals * 4}; 38 | // 1 side, 2 triangles per side, 3 vertices per triangle = 36 39 | static constexpr uint32_t s_max_indices {s_max_quadrilaterals * 1 * 2 * 3}; 40 | }; 41 | 42 | } // namespace Maki 43 | -------------------------------------------------------------------------------- /maki_core/src/core/definitions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace Maki { 10 | 11 | // definitions 12 | using vec2 = glm::vec2; 13 | using vec3 = glm::vec3; 14 | using vec4 = glm::vec4; 15 | 16 | using mat3 = glm::mat3; 17 | using mat4 = glm::mat4; 18 | 19 | using mutex = std::mutex; 20 | using rec_mutex = std::recursive_mutex; 21 | using lock = std::unique_lock; 22 | using rec_lock = std::unique_lock; 23 | 24 | using Clock = std::chrono::high_resolution_clock; 25 | using TimePoint = std::chrono::time_point>>; 26 | using Duration = std::chrono::duration>; 27 | 28 | // consts 29 | constexpr float PI {M_PI}; 30 | 31 | inline long get_mills(Duration duration) 32 | { 33 | return std::chrono::duration_cast(duration).count(); 34 | } 35 | 36 | } // namespace Maki 37 | -------------------------------------------------------------------------------- /maki_core/src/core/log.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "log.h" 4 | 5 | namespace Maki { 6 | 7 | std::shared_ptr Log::s_maki_logger; 8 | std::shared_ptr Log::s_client_logger; 9 | std::shared_ptr Log::s_error_logger; 10 | 11 | void Log::init() 12 | { 13 | try { 14 | // log to console and file 15 | std::vector default_log_sinks; 16 | default_log_sinks.emplace_back(std::make_shared()); 17 | default_log_sinks[0]->set_pattern("%^[%T] %n:\t%v%$"); 18 | // log to std error stream 19 | std::vector error_log_sinks; 20 | error_log_sinks.emplace_back(std::make_shared()); 21 | error_log_sinks[0]->set_pattern("%^[%T] %n:\t%v%$"); 22 | 23 | s_maki_logger = std::make_shared("Maki", default_log_sinks.begin(), default_log_sinks.end()); 24 | s_client_logger = std::make_shared("Client", default_log_sinks.begin(), default_log_sinks.end()); 25 | s_error_logger = std::make_shared("Error", error_log_sinks.begin(), error_log_sinks.end()); 26 | 27 | spdlog::register_logger(s_maki_logger); 28 | s_maki_logger->set_level(spdlog::level::trace); 29 | s_maki_logger->flush_on(spdlog::level::trace); 30 | 31 | spdlog::register_logger(s_client_logger); 32 | s_client_logger->set_level(spdlog::level::trace); 33 | s_client_logger->flush_on(spdlog::level::trace); 34 | 35 | spdlog::register_logger(s_error_logger); 36 | s_error_logger->set_level(spdlog::level::critical); 37 | s_error_logger->flush_on(spdlog::level::critical); 38 | } 39 | catch(const spdlog::spdlog_ex& ex) { 40 | std::cerr << "Log init failed: " << ex.what() << std::endl; 41 | std::exit(EXIT_FAILURE); 42 | } 43 | } 44 | 45 | } // namespace Maki 46 | -------------------------------------------------------------------------------- /maki_core/src/core/log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace Maki { 8 | 9 | // user can deside what loglevels to display 10 | enum class LogLevel { 11 | Extra = spdlog::level::trace, 12 | General = spdlog::level::debug, 13 | Warn = spdlog::level::warn, 14 | Error = spdlog::level::err 15 | }; 16 | 17 | class Log { 18 | public: 19 | static void init(); 20 | 21 | static std::shared_ptr& get_maki_logger() { return s_maki_logger; } 22 | static std::shared_ptr& get_client_logger() { return s_client_logger; } 23 | static std::shared_ptr& get_error_logger() { return s_error_logger; } 24 | 25 | static void set_maki_level(LogLevel log_level) 26 | { 27 | s_maki_logger->set_level(static_cast(log_level)); 28 | } 29 | static void set_client_level(LogLevel log_level) 30 | { 31 | s_client_logger->set_level(static_cast(log_level)); 32 | } 33 | 34 | private: 35 | // stdout and file 36 | static std::shared_ptr s_maki_logger; 37 | static std::shared_ptr s_client_logger; 38 | 39 | // stderr 40 | static std::shared_ptr s_error_logger; 41 | }; 42 | 43 | // asserts only in debug 44 | #ifdef NDEBUG 45 | #define MAKI_RAISE_CRITICAL(...) \ 46 | do { \ 47 | ::Maki::Log::get_error_logger()->critical(__VA_ARGS__); \ 48 | std::terminate(); \ 49 | } while(0) 50 | 51 | #define MAKI_ASSERT_WARN(x, ...) 52 | #define MAKI_ASSERT_CRITICAL(x, ...) 53 | 54 | #else 55 | // TODO: would be better in single log message 56 | #define MAKI_RAISE_CRITICAL(...) \ 57 | do { \ 58 | ::Maki::Log::get_error_logger()->critical(__VA_ARGS__); \ 59 | ::Maki::Log::get_error_logger()->critical("(in {}:{}; in function: {})", __FILE__, __LINE__, __func__); \ 60 | std::terminate(); \ 61 | } while(0) 62 | 63 | #define MAKI_ASSERT_WARN(x, ...) \ 64 | do { \ 65 | if(!(x)) \ 66 | MAKI_LOG_WARN(__VA_ARGS__); \ 67 | } while(0) 68 | #define MAKI_ASSERT_CRITICAL(x, ...) \ 69 | do { \ 70 | if(!(x)) \ 71 | MAKI_RAISE_CRITICAL(__VA_ARGS__); \ 72 | } while(0) 73 | #endif 74 | 75 | // Maki logger -> to be used by Maki internally 76 | #define MAKI_LOG_EXTRA(...) Log::get_maki_logger()->trace(__VA_ARGS__) 77 | #define MAKI_LOG_GENERAl(...) Log::get_maki_logger()->debug(__VA_ARGS__) 78 | #define MAKI_LOG_WARN(...) Log::get_maki_logger()->warn(__VA_ARGS__) 79 | 80 | #ifdef NDEBUG 81 | #define MAKI_LOG_ERROR(...) \ 82 | do { \ 83 | Log::get_maki_logger()->error(__VA_ARGS__); \ 84 | } while(0) 85 | #else 86 | // TODO: would be better in single log message 87 | #define MAKI_LOG_ERROR(...) \ 88 | do { \ 89 | Log::get_maki_logger()->error(__VA_ARGS__); \ 90 | Log::get_maki_logger()->error("(in {}:{}; in function: {})", __FILE__, __LINE__, __func__); \ 91 | } while(0) 92 | #endif 93 | 94 | // client logger -> can be used by the client 95 | #define MAKI_CLIENT_LOG_EXTRA(...) ::Maki::Log::get_client_logger()->trace(__VA_ARGS__) 96 | #define MAKI_CLIENT_LOG_GENERAL(...) ::Maki::Log::get_client_logger()->debug(__VA_ARGS__) 97 | #define MAKI_CLIENT_LOG_WARN(...) ::Maki::Log::get_client_logger()->warn(__VA_ARGS__) 98 | 99 | #ifdef NDEBUG 100 | #define MAKI_CLIENT_LOG_ERROR(...) \ 101 | do { \ 102 | ::Maki::Log::get_client_logger()->error(__VA_ARGS__); \ 103 | } while(0) 104 | #else 105 | #define MAKI_CLIENT_LOG_ERROR(...) \ 106 | do { \ 107 | ::Maki::Log::get_client_logger()->error(__VA_ARGS__); \ 108 | ::Maki::Log::get_client_logger()->error("(in {}:{}; in function: {})", __FILE__, __LINE__, __func__); \ 109 | } while(0) 110 | #endif 111 | 112 | } // namespace Maki 113 | -------------------------------------------------------------------------------- /maki_core/src/core/thread_safety.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "thread_safety.h" 4 | 5 | namespace Maki { 6 | 7 | #ifndef NDEBUG 8 | thread_local ThreadType g_thread_type {ThreadType::undefined}; 9 | #endif 10 | 11 | } // namespace Maki 12 | -------------------------------------------------------------------------------- /maki_core/src/core/thread_safety.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Maki { 4 | 5 | #ifndef NDEBUG 6 | 7 | enum class ThreadType { 8 | undefined = 0, 9 | control = 1, 10 | render = 2, 11 | }; 12 | 13 | extern thread_local ThreadType g_thread_type; 14 | 15 | #define SET_THREAD_TYPE_CONTROL() g_thread_type = ThreadType::control 16 | #define SET_THREAD_TYPE_RENDER() g_thread_type = ThreadType::render 17 | 18 | // have to be macros to get correct line number, function name, etc. in log 19 | #define MAKI_ASSERT_CTRL_THREAD() \ 20 | MAKI_ASSERT_CRITICAL(g_thread_type == ThreadType::control, \ 21 | "This function can only be called from the control thread.") 22 | #define MAKI_ASSERT_RNDR_THREAD() \ 23 | MAKI_ASSERT_CRITICAL(g_thread_type == ThreadType::render, \ 24 | "This function can only be called from the render thread.") 25 | 26 | #else 27 | 28 | // don't do anything in release mode 29 | #define SET_THREAD_TYPE_CONTROL() 30 | #define SET_THREAD_TYPE_RENDER() 31 | 32 | #define MAKI_ASSERT_CTRL_THREAD() 33 | #define MAKI_ASSERT_RNDR_THREAD() 34 | 35 | #endif 36 | 37 | } // namespace Maki 38 | -------------------------------------------------------------------------------- /maki_core/src/driver/camera_driver.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "camera_driver.h" 4 | 5 | namespace Maki { 6 | 7 | CameraDriver::CameraDriver(Renderer* renderer) 8 | : m_renderer {renderer} 9 | { 10 | set_event_handler(); 11 | } 12 | 13 | // TODO: broken when entering ImGui while pressing 14 | bool CameraDriver::on_key_press(Key key) 15 | { 16 | switch(key) { 17 | case Key::w: 18 | m_vel.z += m_speed; 19 | return true; 20 | case Key::s: 21 | m_vel.z -= m_speed; 22 | return true; 23 | case Key::a: 24 | m_vel.x -= m_speed; 25 | return true; 26 | case Key::d: 27 | m_vel.x += m_speed; 28 | return true; 29 | case Key::left_shift: 30 | m_vel.y += m_speed; 31 | return true; 32 | case Key::left_control: 33 | m_vel.y -= m_speed; 34 | return true; 35 | default: 36 | return false; 37 | } 38 | } 39 | bool CameraDriver::on_key_release(Key key) 40 | { 41 | switch(key) { 42 | case Key::w: 43 | m_vel.z -= m_speed; 44 | return true; 45 | case Key::s: 46 | m_vel.z += m_speed; 47 | return true; 48 | case Key::a: 49 | m_vel.x += m_speed; 50 | return true; 51 | case Key::d: 52 | m_vel.x -= m_speed; 53 | return true; 54 | case Key::left_shift: 55 | m_vel.y -= m_speed; 56 | return true; 57 | case Key::left_control: 58 | m_vel.y += m_speed; 59 | return true; 60 | default: 61 | return false; 62 | } 63 | } 64 | bool CameraDriver::on_mouse_btn_press(MouseBtn btn) 65 | { 66 | switch(btn) { 67 | case MouseBtn::button_left: 68 | m_capture_mouse = true; 69 | // hide cursor 70 | m_renderer->set_cursor_type(CursorType::disabled); 71 | return true; 72 | default: 73 | return false; 74 | } 75 | } 76 | bool CameraDriver::on_mouse_btn_release(MouseBtn btn) 77 | { 78 | switch(btn) { 79 | case MouseBtn::button_left: 80 | m_capture_mouse = false; 81 | m_renderer->set_cursor_type(CursorType::normal); 82 | return true; 83 | default: 84 | return false; 85 | } 86 | } 87 | bool CameraDriver::on_mouse_move(double pos_x, double pos_y) 88 | { 89 | m_cur_mouse_pos = {pos_x, pos_y}; 90 | if(m_capture_mouse) 91 | return true; 92 | m_last_mouse_pos = m_cur_mouse_pos; 93 | return false; 94 | } 95 | 96 | void CameraDriver::set_event_handler() 97 | { 98 | EventHandler& event_handler = m_renderer->get_driver_event_handler(); 99 | event_handler.on_key_press = [this](Key key) { 100 | return on_key_press(key); 101 | }; 102 | event_handler.on_key_release = [this](Key key) { 103 | return on_key_release(key); 104 | }; 105 | event_handler.on_mouse_btn_press = [this](MouseBtn btn) { 106 | return on_mouse_btn_press(btn); 107 | }; 108 | event_handler.on_mouse_btn_release = [this](MouseBtn btn) { 109 | return on_mouse_btn_release(btn); 110 | }; 111 | event_handler.on_mouse_move = [this](double pos_x, double pos_y) { 112 | return on_mouse_move(pos_x, pos_y); 113 | }; 114 | } 115 | 116 | void CameraDriver::update(long delta_time) 117 | { 118 | m_renderer->get_camera()->move(m_vel * float(delta_time) * m_speed); 119 | if(m_capture_mouse) { 120 | m_renderer->get_camera()->rotate((m_last_mouse_pos - m_cur_mouse_pos) * (delta_time * m_rotation_speed)); 121 | m_last_mouse_pos = m_cur_mouse_pos; 122 | } 123 | } 124 | 125 | } // namespace Maki 126 | -------------------------------------------------------------------------------- /maki_core/src/driver/camera_driver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "core/definitions.h" 4 | #include "platform/event.h" 5 | #include "renderer/renderer.h" 6 | 7 | namespace Maki { 8 | 9 | // control Camera with user input 10 | class CameraDriver { 11 | public: 12 | CameraDriver(Renderer* renderer); 13 | 14 | void update(long delta_time); 15 | void set_speed(float speed) { m_speed = speed; } 16 | float get_speed() { return m_speed; } 17 | 18 | private: 19 | void set_event_handler(); 20 | // return true when handled 21 | bool on_key_press(Key key); 22 | bool on_key_release(Key key); 23 | bool on_mouse_btn_press(MouseBtn btn); 24 | bool on_mouse_btn_release(MouseBtn btn); 25 | bool on_mouse_move(double pos_x, double pos_y); 26 | 27 | private: 28 | // borrowed from RenderDriver -> don't delete in destructor 29 | Renderer* m_renderer; 30 | 31 | vec3 m_vel {0.0f}; 32 | bool m_capture_mouse {false}; 33 | vec2 m_last_mouse_pos; 34 | vec2 m_cur_mouse_pos; 35 | 36 | // in units per millisecond 37 | float m_speed {0.05f}; 38 | // in radians per millisecond 39 | float m_rotation_speed {0.00003f}; 40 | }; 41 | 42 | } // namespace Maki 43 | -------------------------------------------------------------------------------- /maki_core/src/driver/interface.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "core/log.h" 4 | #include "core/thread_safety.h" 5 | #include "renderer/renderer.h" 6 | 7 | namespace Maki { 8 | 9 | // any client-facing functions outside of RenderDriver 10 | inline void init(Renderer::Implementation renderer_impl) 11 | { 12 | SET_THREAD_TYPE_CONTROL(); 13 | Log::init(); 14 | Renderer::set_renderer_impl(renderer_impl); 15 | } 16 | 17 | } // namespace Maki 18 | -------------------------------------------------------------------------------- /maki_core/src/driver/render_driver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "atom/atom_dispenser.h" 6 | #include "driver/camera_driver.h" 7 | #include "renderer/renderer.h" 8 | 9 | namespace Maki { 10 | 11 | // main interface to client program 12 | // creates atoms, applies diffs to atoms, starts/sops rendering (creates rendering thread) 13 | class RenderDriver { 14 | public: 15 | // to be run from control thread 16 | RenderDriver(const std::string& title, uint32_t width, uint32_t height, vec4 clear_color = {0.34f, 0.74f, 0.77f, 1.0f}); 17 | 18 | ~RenderDriver(); 19 | 20 | void await_termination(); 21 | bool is_terminated(); 22 | 23 | // return id of created atom 24 | template 25 | uint32_t add_atom() 26 | { 27 | MAKI_ASSERT_CTRL_THREAD(); 28 | return m_atom_dispenser.add_atom(); 29 | } 30 | 31 | template 32 | void show_atom(uint32_t id, uint32_t frame, bool show) 33 | { 34 | MAKI_ASSERT_CTRL_THREAD(); 35 | return m_atom_dispenser.show_atom(id, frame, show); 36 | } 37 | template 38 | void translate_atom(uint32_t id, uint32_t frame, vec3 delta) 39 | { 40 | MAKI_ASSERT_CTRL_THREAD(); 41 | m_atom_dispenser.translate_atom(id, frame, delta); 42 | } 43 | template 44 | void color_atom(uint32_t id, uint32_t frame, vec4 col) 45 | { 46 | MAKI_ASSERT_CTRL_THREAD(); 47 | m_atom_dispenser.color_atom(id, frame, col); 48 | } 49 | 50 | void set_target_frame(uint32_t frame); 51 | 52 | private: 53 | // to be run from render thread 54 | void render_thread_func(const std::string& title, uint32_t width, uint32_t height, vec4 clear_col); 55 | void setup(const std::string& title, uint32_t width, uint32_t height, vec4 clear_col); 56 | void cleanup(); 57 | void run(); 58 | void render_frame(); 59 | void render_imgui(); 60 | 61 | // update frame to match target 62 | void sync_frame_target(); 63 | 64 | private: 65 | std::thread m_render_thread; 66 | bool m_terminated; 67 | // owned by renderering thread <- OpenGL context can only be current for one thread 68 | Renderer* m_renderer {nullptr}; 69 | CameraDriver* m_camera_driver {nullptr}; 70 | 71 | AtomDispenser m_atom_dispenser {}; 72 | 73 | uint32_t m_target_frame {0}; 74 | mutex m_target_frame_mutex; 75 | 76 | private: 77 | static mutex s_setup_mutex; 78 | }; 79 | 80 | } // namespace Maki 81 | -------------------------------------------------------------------------------- /maki_core/src/driver/render_driver_control.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "render_driver.h" 4 | 5 | namespace Maki { 6 | 7 | // all functions to be run from control thread 8 | mutex RenderDriver::s_setup_mutex; 9 | 10 | RenderDriver::RenderDriver(const std::string& title, uint32_t width, uint32_t height, vec4 clear_color) 11 | { 12 | MAKI_ASSERT_CTRL_THREAD(); 13 | m_render_thread = std::thread([this, title, width, height, clear_color]() { 14 | SET_THREAD_TYPE_RENDER(); 15 | // only render thread code in this file 16 | render_thread_func(title, width, height, clear_color); 17 | }); 18 | } 19 | 20 | RenderDriver::~RenderDriver() 21 | { 22 | MAKI_ASSERT_CTRL_THREAD(); 23 | MAKI_ASSERT_WARN(m_render_thread.joinable(), "Attempting termination of unjoinable render thread."); 24 | if(!m_terminated) { 25 | m_renderer->terminate(); 26 | await_termination(); 27 | } 28 | 29 | // ensure cleanup has been called 30 | MAKI_ASSERT_CRITICAL(!m_renderer, "Renderer hasn't been deleted yet."); 31 | MAKI_ASSERT_CRITICAL(!m_camera_driver, "CameraDriver hasn't been deleted yet."); 32 | } 33 | 34 | void RenderDriver::await_termination() 35 | { 36 | MAKI_ASSERT_CTRL_THREAD(); 37 | // not even running? 38 | if(!m_render_thread.joinable()) 39 | return; 40 | m_render_thread.join(); 41 | } 42 | bool RenderDriver::is_terminated() 43 | { 44 | MAKI_ASSERT_CTRL_THREAD(); 45 | return m_terminated; 46 | } 47 | 48 | void RenderDriver::set_target_frame(uint32_t frame) 49 | { 50 | MAKI_ASSERT_CTRL_THREAD(); 51 | lock lock {m_target_frame_mutex}; 52 | m_atom_dispenser.ensure_frame_existence(frame); 53 | m_target_frame = frame; 54 | } 55 | 56 | } // namespace Maki 57 | -------------------------------------------------------------------------------- /maki_core/src/driver/render_driver_render.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "render_driver.h" 4 | 5 | namespace Maki { 6 | 7 | // all functions to be run from rendering thread 8 | void RenderDriver::render_thread_func(const std::string& title, uint32_t width, uint32_t height, vec4 clear_col) 9 | { 10 | MAKI_ASSERT_RNDR_THREAD(); 11 | setup(title, width, height, clear_col); 12 | run(); 13 | cleanup(); 14 | m_terminated = true; 15 | } 16 | 17 | void RenderDriver::setup(const std::string& title, uint32_t width, uint32_t height, vec4 clear_col) 18 | { 19 | MAKI_ASSERT_RNDR_THREAD(); 20 | // setup can't be performed twice at the same time 21 | lock lock {s_setup_mutex}; 22 | MAKI_ASSERT_CRITICAL(!m_renderer, "Recreation of Renderer."); 23 | m_renderer = Renderer::create(title, width, height, clear_col); 24 | MAKI_ASSERT_CRITICAL(!m_camera_driver, "Recreation of CameraDriver."); 25 | m_camera_driver = new CameraDriver(m_renderer); 26 | 27 | m_atom_dispenser.create_all_atom_renderers(m_renderer); 28 | } 29 | 30 | void RenderDriver::cleanup() 31 | { 32 | MAKI_ASSERT_RNDR_THREAD(); 33 | MAKI_ASSERT_CRITICAL(m_renderer, "Renderer has already been deleted."); 34 | delete m_renderer; 35 | m_renderer = nullptr; 36 | MAKI_ASSERT_CRITICAL(m_camera_driver, "CameraDriver has already been deleted."); 37 | delete m_camera_driver; 38 | m_camera_driver = nullptr; 39 | 40 | m_atom_dispenser.delete_all_renderers(); 41 | } 42 | 43 | void RenderDriver::run() 44 | { 45 | MAKI_ASSERT_RNDR_THREAD(); 46 | do { 47 | render_frame(); 48 | } while(!m_renderer->should_terminate()); 49 | } 50 | 51 | void RenderDriver::render_frame() 52 | { 53 | MAKI_ASSERT_RNDR_THREAD(); 54 | sync_frame_target(); 55 | m_camera_driver->update(m_renderer->get_last_frame_time()); 56 | 57 | m_renderer->start_frame(); 58 | m_atom_dispenser.render_all(); 59 | render_imgui(); 60 | m_renderer->end_frame(); 61 | } 62 | 63 | void RenderDriver::render_imgui() 64 | { 65 | MAKI_ASSERT_RNDR_THREAD(); 66 | if(!m_renderer->imgui_supported()) 67 | return; 68 | // ImGui not thread-safe -> extra variables and locks required 69 | int target_frame; 70 | float camera_speed {m_camera_driver->get_speed()}; 71 | { 72 | lock lock {m_target_frame_mutex}; 73 | target_frame = m_target_frame; 74 | } 75 | ImGui::Begin("Time Traveler's Toolkit"); 76 | ImGui::Text("fps: %f", 1000.0 / m_renderer->get_last_frame_time()); 77 | ImGui::SliderInt("Frame", &target_frame, 0, m_atom_dispenser.get_last_frame()); 78 | ImGui::SliderFloat("Camera speed (units/ms)", &camera_speed, 0.001f, 0.5f); 79 | if(ImGui::Button("Force Chrono Sync")) 80 | m_atom_dispenser.ensure_chrono_sync(true); 81 | ImGui::End(); 82 | { 83 | lock lock {m_target_frame_mutex}; 84 | m_target_frame = target_frame; 85 | } 86 | m_camera_driver->set_speed(camera_speed); 87 | } 88 | 89 | void RenderDriver::sync_frame_target() 90 | { 91 | MAKI_ASSERT_RNDR_THREAD(); 92 | m_atom_dispenser.ensure_chrono_sync(); 93 | lock lock {m_target_frame_mutex}; 94 | m_atom_dispenser.set_render_frame(m_target_frame); 95 | } 96 | 97 | } // namespace Maki 98 | -------------------------------------------------------------------------------- /maki_core/src/pch.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | -------------------------------------------------------------------------------- /maki_core/src/pch.h: -------------------------------------------------------------------------------- 1 | // include everything often used and rarely or never changed -> speeds up compilation 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | // has to be included before gl.h and glfw3.h 18 | #include 19 | 20 | #if PROJECT == glfw 21 | #include 22 | #endif 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | #include 31 | #if PROJECT == glfw 32 | #include 33 | #endif 34 | #include 35 | 36 | // often used, rarely changing custom declarations 37 | #include "core/definitions.h" 38 | #include "core/log.h" 39 | #include "core/thread_safety.h" 40 | -------------------------------------------------------------------------------- /maki_core/src/platform/enums.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace Maki { 6 | 7 | // platform-independent enums 8 | // actual value dependent on platform -> actual values of enums to be treated as undefined 9 | enum class MouseBtn { 10 | #if PROJECT == glfw 11 | button_1 = GLFW_MOUSE_BUTTON_1, 12 | button_2 = GLFW_MOUSE_BUTTON_2, 13 | button_3 = GLFW_MOUSE_BUTTON_3, 14 | button_4 = GLFW_MOUSE_BUTTON_4, 15 | button_5 = GLFW_MOUSE_BUTTON_5, 16 | button_6 = GLFW_MOUSE_BUTTON_6, 17 | button_7 = GLFW_MOUSE_BUTTON_7, 18 | button_8 = GLFW_MOUSE_BUTTON_8, 19 | button_last = GLFW_MOUSE_BUTTON_LAST, 20 | button_left = GLFW_MOUSE_BUTTON_LEFT, 21 | button_right = GLFW_MOUSE_BUTTON_RIGHT, 22 | button_middle = GLFW_MOUSE_BUTTON_MIDDLE, 23 | #endif 24 | }; 25 | 26 | enum class Key { 27 | #if PROJECT == glfw 28 | // keyboard 29 | space = GLFW_KEY_SPACE, 30 | apostrophe = GLFW_KEY_APOSTROPHE, 31 | comma = GLFW_KEY_COMMA, 32 | minus = GLFW_KEY_MINUS, 33 | period = GLFW_KEY_PERIOD, 34 | slash = GLFW_KEY_SLASH, 35 | zero = GLFW_KEY_0, 36 | one = GLFW_KEY_1, 37 | two = GLFW_KEY_2, 38 | three = GLFW_KEY_3, 39 | four = GLFW_KEY_4, 40 | five = GLFW_KEY_5, 41 | six = GLFW_KEY_6, 42 | seves = GLFW_KEY_7, 43 | eight = GLFW_KEY_8, 44 | nine = GLFW_KEY_9, 45 | semicolon = GLFW_KEY_SEMICOLON, 46 | equal = GLFW_KEY_EQUAL, 47 | a = GLFW_KEY_A, 48 | b = GLFW_KEY_B, 49 | c = GLFW_KEY_C, 50 | d = GLFW_KEY_D, 51 | e = GLFW_KEY_E, 52 | f = GLFW_KEY_F, 53 | g = GLFW_KEY_G, 54 | h = GLFW_KEY_H, 55 | i = GLFW_KEY_I, 56 | j = GLFW_KEY_J, 57 | k = GLFW_KEY_K, 58 | l = GLFW_KEY_L, 59 | m = GLFW_KEY_M, 60 | n = GLFW_KEY_N, 61 | o = GLFW_KEY_O, 62 | p = GLFW_KEY_P, 63 | q = GLFW_KEY_Q, 64 | r = GLFW_KEY_R, 65 | s = GLFW_KEY_S, 66 | t = GLFW_KEY_T, 67 | u = GLFW_KEY_U, 68 | v = GLFW_KEY_V, 69 | w = GLFW_KEY_W, 70 | x = GLFW_KEY_X, 71 | y = GLFW_KEY_Y, 72 | z = GLFW_KEY_Z, 73 | left_bracket = GLFW_KEY_LEFT_BRACKET, 74 | backslash = GLFW_KEY_BACKSLASH, 75 | right_bracket = GLFW_KEY_RIGHT_BRACKET, 76 | grave_accent = GLFW_KEY_GRAVE_ACCENT, 77 | world_1 = GLFW_KEY_WORLD_1, 78 | world_2 = GLFW_KEY_WORLD_2, 79 | escape = GLFW_KEY_ESCAPE, 80 | enter = GLFW_KEY_ENTER, 81 | tab = GLFW_KEY_TAB, 82 | backspace = GLFW_KEY_BACKSPACE, 83 | insert = GLFW_KEY_INSERT, 84 | del = GLFW_KEY_DELETE, 85 | right = GLFW_KEY_RIGHT, 86 | left = GLFW_KEY_LEFT, 87 | down = GLFW_KEY_DOWN, 88 | up = GLFW_KEY_UP, 89 | page_up = GLFW_KEY_PAGE_UP, 90 | page_down = GLFW_KEY_PAGE_DOWN, 91 | home = GLFW_KEY_HOME, 92 | end = GLFW_KEY_END, 93 | caps_lock = GLFW_KEY_CAPS_LOCK, 94 | scroll_lock = GLFW_KEY_SCROLL_LOCK, 95 | num_lock = GLFW_KEY_NUM_LOCK, 96 | print_screen = GLFW_KEY_PRINT_SCREEN, 97 | pause = GLFW_KEY_PAUSE, 98 | f1 = GLFW_KEY_F1, 99 | f2 = GLFW_KEY_F2, 100 | f3 = GLFW_KEY_F3, 101 | f4 = GLFW_KEY_F4, 102 | f5 = GLFW_KEY_F5, 103 | f6 = GLFW_KEY_F6, 104 | f7 = GLFW_KEY_F7, 105 | f8 = GLFW_KEY_F8, 106 | f9 = GLFW_KEY_F9, 107 | f10 = GLFW_KEY_F10, 108 | f11 = GLFW_KEY_F11, 109 | f12 = GLFW_KEY_F12, 110 | f13 = GLFW_KEY_F13, 111 | f14 = GLFW_KEY_F14, 112 | f15 = GLFW_KEY_F15, 113 | f16 = GLFW_KEY_F16, 114 | f17 = GLFW_KEY_F17, 115 | f18 = GLFW_KEY_F18, 116 | f19 = GLFW_KEY_F19, 117 | f20 = GLFW_KEY_F20, 118 | f21 = GLFW_KEY_F21, 119 | f22 = GLFW_KEY_F22, 120 | f23 = GLFW_KEY_F23, 121 | f24 = GLFW_KEY_F24, 122 | f25 = GLFW_KEY_F25, 123 | kp_0 = GLFW_KEY_KP_0, 124 | kp_1 = GLFW_KEY_KP_1, 125 | kp_2 = GLFW_KEY_KP_2, 126 | kp_3 = GLFW_KEY_KP_3, 127 | kp_4 = GLFW_KEY_KP_4, 128 | kp_5 = GLFW_KEY_KP_5, 129 | kp_6 = GLFW_KEY_KP_6, 130 | kp_7 = GLFW_KEY_KP_7, 131 | kp_8 = GLFW_KEY_KP_8, 132 | kp_9 = GLFW_KEY_KP_9, 133 | kp_decimal = GLFW_KEY_KP_DECIMAL, 134 | kp_divide = GLFW_KEY_KP_DIVIDE, 135 | kp_multiply = GLFW_KEY_KP_MULTIPLY, 136 | kp_subtract = GLFW_KEY_KP_SUBTRACT, 137 | kp_add = GLFW_KEY_KP_ADD, 138 | kp_enter = GLFW_KEY_KP_ENTER, 139 | kp_equal = GLFW_KEY_KP_EQUAL, 140 | left_shift = GLFW_KEY_LEFT_SHIFT, 141 | left_control = GLFW_KEY_LEFT_CONTROL, 142 | left_alt = GLFW_KEY_LEFT_ALT, 143 | left_super = GLFW_KEY_LEFT_SUPER, 144 | right_shift = GLFW_KEY_RIGHT_SHIFT, 145 | right_control = GLFW_KEY_RIGHT_CONTROL, 146 | right_alt = GLFW_KEY_RIGHT_ALT, 147 | right_super = GLFW_KEY_RIGHT_SUPER, 148 | menu = GLFW_KEY_MENU, 149 | #endif 150 | }; 151 | 152 | // states the cursor can be in 153 | enum class CursorType { 154 | #if PROJECT == glfw 155 | normal = GLFW_CURSOR_NORMAL, 156 | hidden = GLFW_CURSOR_HIDDEN, 157 | disabled = GLFW_CURSOR_DISABLED, 158 | #endif 159 | }; 160 | 161 | } // namespace Maki 162 | -------------------------------------------------------------------------------- /maki_core/src/platform/event.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "platform/enums.h" 6 | 7 | namespace Maki { 8 | 9 | // set of callbacks to run when something happens 10 | struct EventHandler { 11 | // return true when event handled and not to be passed to next layer 12 | std::function on_mouse_move {nullptr}; 13 | std::function on_scroll {nullptr}; 14 | std::function on_mouse_btn_press {nullptr}; 15 | std::function on_mouse_btn_release {nullptr}; 16 | std::function on_key_press {nullptr}; 17 | std::function on_key_repeat {nullptr}; 18 | std::function on_key_release {nullptr}; 19 | std::function on_window_resize {nullptr}; 20 | std::function on_window_close {nullptr}; 21 | // these might also be worth implementing: 22 | // on_window_lose_focus 23 | // on_window_gain_focus 24 | // on_window_minimize 25 | // on_window_unminimize 26 | }; 27 | 28 | } // namespace Maki 29 | -------------------------------------------------------------------------------- /maki_core/src/platform/glfw/glfw_window.cpp: -------------------------------------------------------------------------------- 1 | #if PROJECT == glfw 2 | #include "pch.h" 3 | 4 | #include "../window.h" 5 | #include "renderer/renderer.h" 6 | 7 | namespace Maki { 8 | 9 | Window::~Window() 10 | { 11 | if(imgui_supported()) { 12 | ImGui_ImplOpenGL3_Shutdown(); 13 | ImGui_ImplGlfw_Shutdown(); 14 | ImGui::DestroyContext(); 15 | } 16 | 17 | glfwDestroyWindow(m_handle); 18 | --s_window_count; 19 | if(s_window_count == 0) 20 | glfwTerminate(); 21 | } 22 | 23 | void Window::start_frame() 24 | { 25 | if(imgui_supported()) { 26 | ImGui_ImplOpenGL3_NewFrame(); 27 | ImGui_ImplGlfw_NewFrame(); 28 | ImGui::NewFrame(); 29 | } 30 | } 31 | void Window::end_frame() 32 | { 33 | if(imgui_supported()) { 34 | ImGui::Render(); 35 | ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); 36 | } 37 | 38 | glfwSwapBuffers(m_handle); 39 | glfwPollEvents(); 40 | } 41 | 42 | void Window::set_cursor_type(CursorType type) 43 | { 44 | glfwSetInputMode(m_handle, GLFW_CURSOR, static_cast(type)); 45 | } 46 | 47 | void Window::create() 48 | { 49 | MAKI_LOG_EXTRA("Creating GLFW window '{0}' ({1}, {2}).", m_title, m_width, m_height); 50 | 51 | // 4x antialiasing 52 | glfwWindowHint(GLFW_SAMPLES, 4); 53 | // TODO: differentiate between OpenGL and Vulkan 54 | // OpenGL version 55 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); 56 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5); 57 | // for macos 58 | glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 59 | // disable old OpenGL 60 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 61 | 62 | m_handle = glfwCreateWindow(m_width, m_height, m_title.c_str(), nullptr, nullptr); 63 | ++s_window_count; 64 | if(m_handle == nullptr) 65 | MAKI_RAISE_CRITICAL("Failed to create GLFW window."); 66 | glfwMakeContextCurrent(m_handle); 67 | 68 | // disable vsync 69 | // TODO: handle vsync 70 | // glfwSwapInterval(0); 71 | 72 | // used to access this instance in event callbacks 73 | glfwSetWindowUserPointer(m_handle, this); 74 | 75 | bind_event_callbacks(); 76 | 77 | // has been increased before 78 | if(s_window_count == 1) 79 | init_imgui(); 80 | } 81 | void Window::init_imgui() 82 | { 83 | IMGUI_CHECKVERSION(); 84 | ImGui::CreateContext(); 85 | m_imgui_io = &ImGui::GetIO(); 86 | 87 | ImGui::StyleColorsDark(); 88 | 89 | ImGui_ImplGlfw_InitForOpenGL(m_handle, true); 90 | ImGui_ImplOpenGL3_Init("#version 450 core"); 91 | } 92 | 93 | void Window::init() 94 | { 95 | MAKI_LOG_EXTRA("Initializing GLFW."); 96 | 97 | int success = glfwInit(); 98 | MAKI_ASSERT_CRITICAL(success, "Couldn't initialize GLFW."); 99 | glfwSetErrorCallback([](int error, const char* description) { 100 | MAKI_LOG_ERROR("GLFW Error ({0}): {1}", error, description); 101 | }); 102 | 103 | #ifndef NDEBUG 104 | if(Renderer::get_renderer_impl() == Renderer::Implementation::opengl) 105 | glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); 106 | #endif 107 | } 108 | 109 | void Window::bind_event_callbacks() 110 | { 111 | // TODO: make easier to understand 112 | glfwSetCursorPosCallback(m_handle, [](GLFWwindow* handle, double pos_x, double pos_y) { 113 | // get pointer to this window through glfw 114 | // set using glfwSetWindowUserPointer 115 | Window* window = reinterpret_cast(glfwGetWindowUserPointer(handle)); 116 | // check if imgui is capturing the mouse -> don't propagate to next layers 117 | (window->imgui_supported() && window->m_imgui_io->WantCaptureMouse) || 118 | // does the render event handler have a callback defined for this event? 119 | // if so, execute it 120 | (window->m_renderer_event_handler.on_mouse_move && window->m_renderer_event_handler.on_mouse_move(pos_x, pos_y)) || 121 | // if last layer's callback returned false -> event not handled yet -> propagate to next layer 122 | (window->m_driver_event_handler.on_mouse_move && window->m_driver_event_handler.on_mouse_move(pos_x, pos_y)); 123 | }); 124 | glfwSetScrollCallback(m_handle, [](GLFWwindow* handle, double offset_x, double offset_y) { 125 | Window* window = reinterpret_cast(glfwGetWindowUserPointer(handle)); 126 | (window->imgui_supported() && window->m_imgui_io->WantCaptureMouse) || 127 | (window->m_renderer_event_handler.on_scroll && window->m_renderer_event_handler.on_scroll(offset_x, offset_y)) || 128 | (window->m_driver_event_handler.on_scroll && window->m_driver_event_handler.on_scroll(offset_x, offset_y)); 129 | }); 130 | glfwSetMouseButtonCallback(m_handle, [](GLFWwindow* handle, int button, int action, int) { 131 | Window* window = reinterpret_cast(glfwGetWindowUserPointer(handle)); 132 | // split events into sub-categories 133 | switch(action) { 134 | case GLFW_PRESS: 135 | (window->imgui_supported() && window->m_imgui_io->WantCaptureMouse) || 136 | (window->m_renderer_event_handler.on_mouse_btn_press && window->m_renderer_event_handler.on_mouse_btn_press(static_cast(button))) || 137 | (window->m_driver_event_handler.on_mouse_btn_press && window->m_driver_event_handler.on_mouse_btn_press(static_cast(button))); 138 | return; 139 | case GLFW_RELEASE: 140 | (window->imgui_supported() && window->m_imgui_io->WantCaptureMouse) || 141 | (window->m_renderer_event_handler.on_mouse_btn_release && window->m_renderer_event_handler.on_mouse_btn_release(static_cast(button))) || 142 | (window->m_driver_event_handler.on_mouse_btn_release && window->m_driver_event_handler.on_mouse_btn_release(static_cast(button))); 143 | return; 144 | } 145 | }); 146 | glfwSetKeyCallback(m_handle, [](GLFWwindow* handle, int key, int, int action, int) { 147 | Window* window = reinterpret_cast(glfwGetWindowUserPointer(handle)); 148 | switch(action) { 149 | case GLFW_PRESS: 150 | (window->imgui_supported() && window->m_imgui_io->WantCaptureKeyboard) || 151 | (window->m_renderer_event_handler.on_key_press && window->m_renderer_event_handler.on_key_press(static_cast(key))) || 152 | (window->m_driver_event_handler.on_key_press && window->m_driver_event_handler.on_key_press(static_cast(key))); 153 | return; 154 | case GLFW_RELEASE: 155 | (window->imgui_supported() && window->m_imgui_io->WantCaptureKeyboard) || 156 | (window->m_renderer_event_handler.on_key_release && window->m_renderer_event_handler.on_key_release(static_cast(key))) || 157 | (window->m_driver_event_handler.on_key_release && window->m_driver_event_handler.on_key_release(static_cast(key))); 158 | return; 159 | case GLFW_REPEAT: 160 | (window->imgui_supported() && window->m_imgui_io->WantCaptureKeyboard) || 161 | (window->m_renderer_event_handler.on_key_repeat && window->m_renderer_event_handler.on_key_repeat(static_cast(key))) || 162 | (window->m_driver_event_handler.on_key_repeat && window->m_driver_event_handler.on_key_repeat(static_cast(key))); 163 | return; 164 | } 165 | }); 166 | glfwSetWindowSizeCallback(m_handle, [](GLFWwindow* handle, int width, int height) { 167 | Window* window = reinterpret_cast(glfwGetWindowUserPointer(handle)); 168 | // imgui doesn't use this event 169 | (window->m_renderer_event_handler.on_window_resize && window->m_renderer_event_handler.on_window_resize(width, height)) || 170 | (window->m_driver_event_handler.on_window_resize && window->m_driver_event_handler.on_window_resize(width, height)); 171 | }); 172 | glfwSetWindowCloseCallback(m_handle, [](GLFWwindow* handle) { 173 | Window* window = reinterpret_cast(glfwGetWindowUserPointer(handle)); 174 | (window->m_renderer_event_handler.on_window_close && window->m_renderer_event_handler.on_window_close()) || 175 | (window->m_driver_event_handler.on_window_close && window->m_driver_event_handler.on_window_close()); 176 | }); 177 | } 178 | 179 | } // namespace Maki 180 | #endif 181 | -------------------------------------------------------------------------------- /maki_core/src/platform/window.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "renderer/renderer.h" 4 | #include "window.h" 5 | 6 | namespace Maki { 7 | 8 | Window::Window(const std::string& title, uint32_t width, uint32_t height, EventHandler driver_event_handler, EventHandler renderer_event_handler) 9 | : m_title(title), m_width(width), m_height(height), m_driver_event_handler(driver_event_handler), m_renderer_event_handler(renderer_event_handler) 10 | { 11 | // check compatibility 12 | #if PROJECT == glfw 13 | MAKI_ASSERT_CRITICAL( 14 | Renderer::get_renderer_impl() == Renderer::Implementation::opengl, 15 | "Unsupported Implementation for a GLFW Window."); 16 | #endif 17 | if(s_window_count == 0) 18 | init(); 19 | create(); 20 | } 21 | 22 | } // namespace Maki 23 | -------------------------------------------------------------------------------- /maki_core/src/platform/window.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if PROJECT == glfw 4 | #include 5 | #endif 6 | #include 7 | #include 8 | 9 | #include "core/log.h" 10 | #include "platform/event.h" 11 | 12 | namespace Maki { 13 | 14 | // create window, handle events/inputs 15 | // implementation gets chosen at compile time with -Dplatform 16 | class Window { 17 | public: 18 | Window(const std::string& title, uint32_t width, uint32_t height, EventHandler driver_event_handler, EventHandler renderer_event_handler); 19 | ~Window(); 20 | 21 | // should be run before gl draws 22 | void start_frame(); 23 | // should be run after gl draws 24 | void end_frame(); 25 | 26 | void set_cursor_type(CursorType type); 27 | 28 | EventHandler& get_driver_event_handler() { return m_driver_event_handler; } 29 | 30 | bool imgui_supported() { return m_imgui_io; } 31 | 32 | private: 33 | void create(); 34 | // init performed at creation of first window 35 | void init(); 36 | void bind_event_callbacks(); 37 | // has to be called after bind_event_callbacks 38 | void init_imgui(); 39 | 40 | private: 41 | static inline int s_window_count {0}; 42 | 43 | private: 44 | std::string m_title; 45 | uint32_t m_width, m_height; 46 | 47 | // each layer can handle an event or pass it on to the next layer 48 | // only two layers supported 49 | // driver events -> camera movement, interactivity, ... 50 | // renderer events -> close Window, resize, ImGui, ... 51 | EventHandler m_driver_event_handler, m_renderer_event_handler; 52 | 53 | // nullptr when imgui not supported -> only supported with first window because of https://github.com/ocornut/imgui/issues/2117 54 | ImGuiIO* m_imgui_io {nullptr}; 55 | 56 | #if PROJECT == glfw 57 | GLFWwindow* m_handle {nullptr}; 58 | #endif 59 | }; 60 | 61 | } // namespace Maki 62 | -------------------------------------------------------------------------------- /maki_core/src/renderer/buffer.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "buffer.h" 4 | 5 | #include "renderer/opengl/opengl_buffer.h" 6 | #include "renderer/renderer.h" 7 | 8 | namespace Maki { 9 | 10 | VertexBuffer* VertexBuffer::create(const std::initializer_list& elements, size_t size) 11 | { 12 | switch(Renderer::get_renderer_impl()) { 13 | case Renderer::Implementation::none: 14 | MAKI_RAISE_CRITICAL("Renderer::Implementation::none is not supported."); 15 | return nullptr; 16 | case Renderer::Implementation::opengl: 17 | return new OpenGLVertexBuffer(elements, size); 18 | default: 19 | MAKI_RAISE_CRITICAL("The requested renderer implementation is not supported."); 20 | return nullptr; 21 | } 22 | } 23 | 24 | VertexBuffer* VertexBuffer::create(const std::initializer_list& elements, const void* data, size_t size) 25 | { 26 | switch(Renderer::get_renderer_impl()) { 27 | case Renderer::Implementation::none: 28 | MAKI_RAISE_CRITICAL("Renderer::Implementation::none is not supported."); 29 | return nullptr; 30 | case Renderer::Implementation::opengl: 31 | return new OpenGLVertexBuffer(elements, data, size); 32 | default: 33 | MAKI_RAISE_CRITICAL("The requested renderer implementation is not supported."); 34 | return nullptr; 35 | } 36 | } 37 | 38 | IndexBuffer* IndexBuffer::create(uint32_t count, const uint32_t* indices) 39 | { 40 | switch(Renderer::get_renderer_impl()) { 41 | case Renderer::Implementation::none: 42 | MAKI_RAISE_CRITICAL("Renderer::Implementation::none is not supported."); 43 | return nullptr; 44 | case Renderer::Implementation::opengl: 45 | return new OpenGLIndexBuffer(count, indices); 46 | default: 47 | MAKI_RAISE_CRITICAL("The requested renderer implementation is not supported."); 48 | return nullptr; 49 | } 50 | } 51 | 52 | } // namespace Maki 53 | -------------------------------------------------------------------------------- /maki_core/src/renderer/buffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "core/log.h" 4 | #include "renderer/types.h" 5 | 6 | namespace Maki { 7 | 8 | // one variable type in a buffer 9 | // a buffer can have multiple BufferElements 10 | struct BufferElement { 11 | std::string name; 12 | DataType type; 13 | size_t size; 14 | bool normalized; 15 | // to be calculated in VertexBuffer::calculate_offset_and_stride 16 | uint32_t offset {0}; 17 | 18 | BufferElement() = default; 19 | BufferElement(const std::string& name, DataType type, bool normalized = false) 20 | : name {name}, type {type}, size {data_type_size(type)}, normalized {normalized} {} 21 | }; 22 | 23 | // pass data to GPU, BufferElements define how that data looks like 24 | class VertexBuffer { 25 | public: 26 | // dynamic 27 | static VertexBuffer* create(const std::initializer_list& elements, size_t size); 28 | // static 29 | static VertexBuffer* create(const std::initializer_list& elements, const void* data, size_t size); 30 | 31 | public: 32 | VertexBuffer(const std::initializer_list& elements, bool dynamic) 33 | : m_elements {elements}, m_dynamic {dynamic} 34 | { 35 | calculate_offset_and_stride(); 36 | } 37 | 38 | virtual ~VertexBuffer() = default; 39 | 40 | // can only be used when not static 41 | // WARN: correct vao has to be bound prior to use 42 | virtual void set_data(const void* data, size_t size) = 0; 43 | 44 | virtual void bind() const = 0; 45 | virtual void unbind() const = 0; 46 | 47 | const std::vector& get_elements() { return m_elements; } 48 | uint32_t get_stride() { return m_stride; } 49 | 50 | protected: 51 | void calculate_offset_and_stride() 52 | { 53 | size_t offset {0}; 54 | m_stride = 0; 55 | for(BufferElement& element: m_elements) { 56 | element.offset = offset; 57 | offset += element.size; 58 | m_stride += element.size; 59 | } 60 | } 61 | 62 | protected: 63 | std::vector m_elements; 64 | uint32_t m_stride {0}; 65 | // true -> data can be updated 66 | // false -> data has to be set at creation 67 | bool m_dynamic; 68 | }; 69 | 70 | // what vertices should be rendered in what order 71 | class IndexBuffer { 72 | public: 73 | static IndexBuffer* create(uint32_t count, const uint32_t* indices); 74 | 75 | public: 76 | virtual ~IndexBuffer() = default; 77 | 78 | virtual void bind() const = 0; 79 | virtual void unbind() const = 0; 80 | 81 | virtual uint32_t get_count() const = 0; 82 | }; 83 | 84 | } // namespace Maki 85 | -------------------------------------------------------------------------------- /maki_core/src/renderer/camera.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "camera.h" 4 | 5 | namespace Maki { 6 | 7 | Camera::Camera(uint32_t width, uint32_t height, Camera::Type type) 8 | : m_type {type}, m_width {width}, m_height {height}, m_aspect_ratio {float(width) / float(height)} 9 | { 10 | calc_projection(); 11 | } 12 | 13 | void Camera::set_fov(float fov) 14 | { 15 | m_fov = fov; 16 | 17 | outdate_projetion(); 18 | } 19 | void Camera::set_type(Camera::Type type) 20 | { 21 | m_type = type; 22 | 23 | outdate_projetion(); 24 | } 25 | void Camera::set_window_size(uint32_t width, uint32_t height) 26 | { 27 | m_width = width; 28 | m_height = height; 29 | m_aspect_ratio = float(width) / float(height); 30 | 31 | outdate_projetion(); 32 | } 33 | void Camera::set_position(vec3 position) 34 | { 35 | m_position = position; 36 | 37 | outdate_view(); 38 | } 39 | void Camera::set_rotation(vec2 angle) 40 | { 41 | m_angle = angle; 42 | 43 | outdate_direction(); 44 | } 45 | void Camera::move(vec3 delta) 46 | { 47 | calc_direction(); 48 | m_position += delta.x * m_right; 49 | m_position += delta.y * m_up; 50 | m_position += delta.z * m_direction; 51 | 52 | outdate_view(); 53 | } 54 | void Camera::rotate(vec2 delta_angle) 55 | { 56 | m_angle += delta_angle; 57 | // can't break your ribs 58 | m_angle.y = std::clamp(m_angle.y, -PI / 2.0f, PI / 2.0f); 59 | 60 | outdate_direction(); 61 | } 62 | 63 | const mat4& Camera::get_view_projection() const 64 | { 65 | calc_view_projection(); 66 | return m_view_projection; 67 | } 68 | 69 | // calculate updates // 70 | 71 | void Camera::calc_view_projection() const 72 | { 73 | // cache still valid? 74 | if(!m_view_projection_outdated) 75 | return; 76 | 77 | calc_projection(); 78 | calc_view(); 79 | 80 | m_view_projection = m_projection * m_view; 81 | 82 | m_view_projection_outdated = false; 83 | } 84 | void Camera::calc_projection() const 85 | { 86 | if(!m_projection_outdated) 87 | return; 88 | 89 | switch(m_type) { 90 | case Camera::Type::perspective: 91 | m_projection = glm::perspective(m_fov, m_aspect_ratio, s_near_plane, s_far_plane); 92 | break; 93 | case Camera::Type::orthographic: 94 | MAKI_RAISE_CRITICAL("Orthographic camera isn't supported yet."); 95 | break; 96 | default: 97 | MAKI_RAISE_CRITICAL("Unsupported camera type."); 98 | break; 99 | } 100 | m_projection_outdated = false; 101 | } 102 | void Camera::calc_view() const 103 | { 104 | if(!m_view_outdated) 105 | return; 106 | 107 | calc_direction(); 108 | 109 | m_view = glm::lookAt(m_position, m_position + m_direction, m_up); 110 | 111 | m_view_outdated = false; 112 | } 113 | void Camera::calc_direction() const 114 | { 115 | if(!m_direction_outdated) 116 | return; 117 | 118 | m_direction = {cos(m_angle.y) * sin(m_angle.x), 119 | sin(m_angle.y), 120 | cos(m_angle.y) * cos(m_angle.x)}; 121 | 122 | m_right = {sin(m_angle.x - PI / 2.0f), 123 | 0.0f, 124 | cos(m_angle.x - PI / 2.0f)}; 125 | 126 | m_up = glm::cross(m_right, m_direction); 127 | 128 | m_direction_outdated = false; 129 | } 130 | 131 | void Camera::outdate_view_projection() const 132 | { 133 | m_view_projection_outdated = true; 134 | } 135 | void Camera::outdate_projetion() const 136 | { 137 | m_projection_outdated = true; 138 | outdate_view_projection(); 139 | } 140 | void Camera::outdate_view() const 141 | { 142 | m_view_outdated = true; 143 | outdate_view_projection(); 144 | } 145 | void Camera::outdate_direction() const 146 | { 147 | m_direction_outdated = true; 148 | outdate_view(); 149 | } 150 | 151 | } // namespace Maki 152 | -------------------------------------------------------------------------------- /maki_core/src/renderer/camera.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "core/definitions.h" 4 | 5 | namespace Maki { 6 | 7 | // handle view-projection matrix 8 | class Camera { 9 | public: 10 | enum class Type { 11 | perspective = 0, 12 | orthographic, 13 | }; 14 | 15 | Camera(uint32_t width, uint32_t height, Camera::Type type); 16 | 17 | void set_type(Camera::Type type); 18 | void set_window_size(uint32_t width, uint32_t height); 19 | void set_fov(float fov); 20 | void set_position(vec3 position); 21 | // horizontal, vertical 22 | void set_rotation(vec2 angel); 23 | // in camera coordinates 24 | void move(vec3 delta); 25 | // horizontal, vertical 26 | void rotate(vec2 angel); 27 | 28 | vec3 get_position() const { return m_position; } 29 | vec2 get_angle() const { return m_angle; } 30 | 31 | const mat4& get_view_projection() const; 32 | uint32_t get_width() const { return m_width; } 33 | uint32_t get_height() const { return m_height; } 34 | 35 | private: 36 | // only update what's necessary 37 | void calc_view_projection() const; // depends on projection and view 38 | void calc_projection() const; 39 | void calc_view() const; // depends on direction 40 | void calc_direction() const; 41 | 42 | // outdate specified and all depending on that 43 | void outdate_view_projection() const; 44 | void outdate_projetion() const; 45 | void outdate_view() const; 46 | void outdate_direction() const; 47 | 48 | private: 49 | Camera::Type m_type; 50 | uint32_t m_width, m_height; 51 | float m_aspect_ratio; 52 | 53 | vec3 m_position {0.0f, 0.0f, 10.0f}; 54 | // all angles in radians 55 | // horizontal, vertical 56 | // default: look into the screen (negative z) 57 | vec2 m_angle {PI, 0.0f}; 58 | float m_fov {PI / 4}; 59 | 60 | // mainly for caching 61 | // always normalized 62 | mutable vec3 m_direction; 63 | mutable vec3 m_right; 64 | mutable vec3 m_up; 65 | 66 | mutable mat4 m_projection; 67 | mutable mat4 m_view; 68 | mutable mat4 m_view_projection; 69 | 70 | // only update what's changed 71 | mutable bool m_view_projection_outdated {true}; 72 | mutable bool m_projection_outdated {true}; 73 | mutable bool m_view_outdated {true}; 74 | mutable bool m_direction_outdated {true}; 75 | 76 | private: 77 | static constexpr float s_near_plane {0.1f}; 78 | static constexpr float s_far_plane {1000.0f}; 79 | }; 80 | 81 | } // namespace Maki 82 | -------------------------------------------------------------------------------- /maki_core/src/renderer/opengl/opengl_buffer.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "opengl_buffer.h" 4 | 5 | namespace Maki { 6 | 7 | // VertexBuffer 8 | OpenGLVertexBuffer::OpenGLVertexBuffer(const std::initializer_list& elements, size_t size) 9 | : VertexBuffer(elements, true) 10 | { 11 | glCreateBuffers(1, &m_id); 12 | bind(); 13 | // GL_ARRAY_BUFFER allows data loading regardless of vao state 14 | glBufferData(GL_ARRAY_BUFFER, size, nullptr, GL_DYNAMIC_DRAW); 15 | } 16 | 17 | OpenGLVertexBuffer::OpenGLVertexBuffer(const std::initializer_list& elements, const void* data, size_t size) 18 | : VertexBuffer(elements, false) 19 | { 20 | glCreateBuffers(1, &m_id); 21 | bind(); 22 | glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW); 23 | } 24 | 25 | OpenGLVertexBuffer::~OpenGLVertexBuffer() 26 | { 27 | glDeleteBuffers(1, &m_id); 28 | } 29 | 30 | void OpenGLVertexBuffer::set_data(const void* data, size_t size) 31 | { 32 | MAKI_ASSERT_CRITICAL(m_dynamic, "OpenGLVertexBuffer::set_data can't be used with a static buffer."); 33 | bind(); 34 | // replace everything 35 | glBufferSubData(GL_ARRAY_BUFFER, 0, size, data); 36 | } 37 | 38 | void OpenGLVertexBuffer::bind() const 39 | { 40 | glBindBuffer(GL_ARRAY_BUFFER, m_id); 41 | } 42 | void OpenGLVertexBuffer::unbind() const 43 | { 44 | glBindBuffer(GL_ARRAY_BUFFER, 0); 45 | } 46 | 47 | // IndexBuffer 48 | OpenGLIndexBuffer::OpenGLIndexBuffer(uint32_t count, const uint32_t* indices) 49 | : m_count(count) 50 | { 51 | glCreateBuffers(1, &m_id); 52 | bind(); 53 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(uint32_t), indices, GL_STATIC_DRAW); 54 | } 55 | 56 | OpenGLIndexBuffer::~OpenGLIndexBuffer() 57 | { 58 | glDeleteBuffers(1, &m_id); 59 | } 60 | 61 | void OpenGLIndexBuffer::bind() const 62 | { 63 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_id); 64 | } 65 | void OpenGLIndexBuffer::unbind() const 66 | { 67 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 68 | } 69 | 70 | } // namespace Maki 71 | -------------------------------------------------------------------------------- /maki_core/src/renderer/opengl/opengl_buffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../buffer.h" 4 | 5 | namespace Maki { 6 | 7 | class OpenGLVertexBuffer: public VertexBuffer { 8 | public: 9 | // dynamic 10 | OpenGLVertexBuffer(const std::initializer_list& elements, size_t size); 11 | // static 12 | OpenGLVertexBuffer(const std::initializer_list& elements, const void* data, size_t size); 13 | 14 | ~OpenGLVertexBuffer(); 15 | 16 | virtual void set_data(const void* data, size_t size) override; 17 | 18 | virtual void bind() const override; 19 | virtual void unbind() const override; 20 | 21 | private: 22 | uint32_t m_id; 23 | }; 24 | 25 | class OpenGLIndexBuffer: public IndexBuffer { 26 | public: 27 | OpenGLIndexBuffer(uint32_t count, const uint32_t* indices); 28 | ~OpenGLIndexBuffer(); 29 | 30 | virtual void bind() const override; 31 | virtual void unbind() const override; 32 | 33 | virtual uint32_t get_count() const override { return m_count; }; 34 | 35 | private: 36 | uint32_t m_id; 37 | uint32_t m_count; 38 | }; 39 | 40 | } // namespace Maki 41 | -------------------------------------------------------------------------------- /maki_core/src/renderer/opengl/opengl_renderer.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "opengl_renderer.h" 4 | 5 | #include "renderer/opengl/opengl_stringifier.h" 6 | 7 | namespace Maki { 8 | 9 | inline void log_gl_extra(const std::string& source, const std::string& type, GLuint id, const std::string& severity, const char* message) 10 | { 11 | MAKI_LOG_EXTRA("OpenGL Message: Source: {0} Type: {1} ID: {2} Severity: {3}\n{4}", 12 | source, type, id, severity, message); 13 | } 14 | inline void log_gl_warn(const std::string& source, const std::string& type, GLuint id, const std::string& severity, const char* message) 15 | { 16 | MAKI_LOG_WARN("OpenGL Message: Source: {0} Type: {1} ID: {2} Severity: {3}\n{4}", 17 | source, type, id, severity, message); 18 | } 19 | inline void log_gl_error(const std::string& source, const std::string& type, GLuint id, const std::string& severity, const char* message) 20 | { 21 | MAKI_LOG_ERROR("OpenGL Message: Source: {0} Type: {1} ID: {2} Severity: {3}\n{4}", 22 | source, type, id, severity, message); 23 | } 24 | 25 | OpenGLRenderer::OpenGLRenderer(const std::string& title, uint32_t width, uint32_t height, vec4 clear_col, EventHandler driver_event_handler) 26 | : Renderer {title, width, height, driver_event_handler} 27 | { 28 | MAKI_LOG_EXTRA("Creating OpenGL Renderer."); 29 | MAKI_LOG_EXTRA("Initializing GLEW."); 30 | glewExperimental = true; 31 | if(glewInit() != GLEW_OK) 32 | MAKI_RAISE_CRITICAL("Failed to initialize GLEW."); 33 | 34 | #ifndef NDEBUG 35 | glDebugMessageCallback([](GLenum source, GLenum type, uint32_t id, GLenum severity, GLsizei, const char* message, const void*) { 36 | std::string source_str = Stringifier::gl_msg_source(source); 37 | std::string type_str = Stringifier::gl_msg_type(type); 38 | std::string severity_str = Stringifier::gl_msg_severity(severity); 39 | 40 | switch(severity) { 41 | case GL_DEBUG_SEVERITY_NOTIFICATION: 42 | log_gl_extra(source_str, type_str, id, severity_str, message); 43 | break; 44 | case GL_DEBUG_SEVERITY_LOW: 45 | log_gl_extra(source_str, type_str, id, severity_str, message); 46 | break; 47 | case GL_DEBUG_SEVERITY_MEDIUM: 48 | log_gl_warn(source_str, type_str, id, severity_str, message); 49 | break; 50 | case GL_DEBUG_SEVERITY_HIGH: 51 | log_gl_error(source_str, type_str, id, severity_str, message); 52 | break; 53 | default: 54 | log_gl_error(source_str, type_str, id, severity_str, message); 55 | break; 56 | } 57 | }, 58 | nullptr); 59 | #endif 60 | set_clear_col(clear_col); 61 | glEnable(GL_DEPTH_TEST); 62 | glEnable(GL_CULL_FACE); 63 | glDepthFunc(GL_LESS); 64 | } 65 | 66 | OpenGLRenderer::~OpenGLRenderer() 67 | { 68 | MAKI_LOG_EXTRA("Destructing OpenGL Renderer."); 69 | } 70 | 71 | void OpenGLRenderer::set_clear_col(vec4 color) 72 | { 73 | glClearColor(color.r, color.g, color.b, color.a); 74 | } 75 | 76 | void OpenGLRenderer::draw(uint32_t index_count) 77 | { 78 | glDrawElements(GL_TRIANGLES, index_count, GL_UNSIGNED_INT, nullptr); 79 | } 80 | 81 | void OpenGLRenderer::start_frame() 82 | { 83 | Renderer::start_frame(); 84 | // required by multiple windows 85 | glViewport(0, 0, m_camera->get_width(), m_camera->get_height()); 86 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 87 | } 88 | 89 | } // namespace Maki 90 | -------------------------------------------------------------------------------- /maki_core/src/renderer/opengl/opengl_renderer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "renderer/renderer.h" 4 | 5 | namespace Maki { 6 | 7 | class OpenGLRenderer: public Renderer { 8 | public: 9 | OpenGLRenderer(const std::string& title, uint32_t width, uint32_t height, vec4 clear_col, EventHandler driver_event_handler = EventHandler {}); 10 | ~OpenGLRenderer(); 11 | 12 | virtual void set_clear_col(vec4 color) override; 13 | 14 | virtual void draw(uint32_t index_count) override; 15 | virtual void start_frame() override; 16 | // to be defined when necessary 17 | // virtual void end_frame() override; 18 | }; 19 | 20 | } // namespace Maki 21 | -------------------------------------------------------------------------------- /maki_core/src/renderer/opengl/opengl_shader.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "opengl_shader.h" 4 | 5 | namespace Maki { 6 | 7 | OpenGLShader::OpenGLShader(const std::string& vert_path, const std::string& frag_path) 8 | { 9 | std::string vert_source = read_file(vert_path); 10 | std::string frag_source = read_file(frag_path); 11 | 12 | compile({{GL_VERTEX_SHADER, vert_source}, 13 | {GL_FRAGMENT_SHADER, frag_source}}); 14 | } 15 | 16 | OpenGLShader::~OpenGLShader() 17 | { 18 | glDeleteProgram(m_id); 19 | } 20 | 21 | void OpenGLShader::compile(const std::unordered_map& shader_sources) 22 | { 23 | m_id = glCreateProgram(); 24 | 25 | MAKI_ASSERT_CRITICAL(shader_sources.size() <= 16, "Only up to 16 shaders are supported."); 26 | // used to delete shaders once attached 27 | std::array shader_ids; 28 | int shader_id_idx {0}; 29 | 30 | for(auto& [type, source]: shader_sources) { 31 | uint32_t shader = glCreateShader(type); 32 | const char* source_c_str = source.c_str(); 33 | glShaderSource(shader, 1, &source_c_str, nullptr); 34 | glCompileShader(shader); 35 | 36 | GLint is_compiled {0}; 37 | glGetShaderiv(shader, GL_COMPILE_STATUS, &is_compiled); 38 | if(is_compiled == GL_FALSE) { 39 | int max_length {0}; 40 | glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &max_length); 41 | 42 | std::vector log(max_length); 43 | glGetShaderInfoLog(shader, max_length, &max_length, &log[0]); 44 | 45 | MAKI_RAISE_CRITICAL("Shader compilation failure: {0}", log.data()); 46 | } 47 | glAttachShader(m_id, shader); 48 | shader_ids[shader_id_idx++] = shader; 49 | } 50 | 51 | glLinkProgram(m_id); 52 | MAKI_LOG_EXTRA("Shaders linked."); 53 | 54 | GLint is_linked {0}; 55 | glGetProgramiv(m_id, GL_LINK_STATUS, &is_linked); 56 | if(is_linked == GL_FALSE) { 57 | int max_length {0}; 58 | glGetProgramiv(m_id, GL_INFO_LOG_LENGTH, &max_length); 59 | 60 | std::vector log(max_length); 61 | glGetProgramInfoLog(m_id, max_length, &max_length, &log[0]); 62 | 63 | MAKI_RAISE_CRITICAL("Shader linkage failure: {0}", log.data()); 64 | } 65 | 66 | for(int i {0}; i < shader_id_idx; ++i) { 67 | glDetachShader(m_id, shader_ids[i]); 68 | glDeleteShader(shader_ids[i]); 69 | } 70 | } 71 | 72 | std::string OpenGLShader::read_file(const std::string& path) 73 | { 74 | std::string out; 75 | std::ifstream stream(path, std::ios::in); 76 | if(stream.is_open()) { 77 | std::stringstream ss; 78 | ss << stream.rdbuf(); 79 | out = ss.str(); 80 | stream.close(); 81 | } 82 | else 83 | MAKI_RAISE_CRITICAL("Impossible to open '{0}'.", path); 84 | return out; 85 | } 86 | 87 | void OpenGLShader::set_float1(const std::string& name, float val) 88 | { 89 | bind(); 90 | int location = glGetUniformLocation(m_id, name.c_str()); 91 | MAKI_ASSERT_CRITICAL(location != -1, "Can't find Uniform '{0}'.", name); 92 | glUniform1f(location, val); 93 | } 94 | void OpenGLShader::set_float2(const std::string& name, const vec2& val) 95 | { 96 | bind(); 97 | int location = glGetUniformLocation(m_id, name.c_str()); 98 | MAKI_ASSERT_CRITICAL(location != -1, "Can't find Uniform '{0}'.", name); 99 | glUniform2f(location, val.x, val.y); 100 | } 101 | void OpenGLShader::set_float3(const std::string& name, const vec3& val) 102 | { 103 | bind(); 104 | int location = glGetUniformLocation(m_id, name.c_str()); 105 | MAKI_ASSERT_CRITICAL(location != -1, "Can't find Uniform '{0}'.", name); 106 | glUniform3f(location, val.x, val.y, val.z); 107 | } 108 | void OpenGLShader::set_float4(const std::string& name, const vec4& val) 109 | { 110 | bind(); 111 | int location = glGetUniformLocation(m_id, name.c_str()); 112 | MAKI_ASSERT_CRITICAL(location != -1, "Can't find Uniform '{0}'.", name); 113 | glUniform4f(location, val.x, val.y, val.z, val.w); 114 | } 115 | void OpenGLShader::set_mat3(const std::string& name, const mat3& val) 116 | { 117 | bind(); 118 | int location = glGetUniformLocation(m_id, name.c_str()); 119 | MAKI_ASSERT_CRITICAL(location != -1, "Can't find Uniform '{0}'.", name); 120 | glUniformMatrix3fv(location, 1, GL_FALSE, glm::value_ptr(val)); 121 | } 122 | void OpenGLShader::set_mat4(const std::string& name, const mat4& val) 123 | { 124 | bind(); 125 | int location = glGetUniformLocation(m_id, name.c_str()); 126 | MAKI_ASSERT_CRITICAL(location != -1, "Can't find Uniform '{0}'.", name); 127 | glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(val)); 128 | } 129 | void OpenGLShader::set_int1(const std::string& name, int val) 130 | { 131 | bind(); 132 | int location = glGetUniformLocation(m_id, name.c_str()); 133 | MAKI_ASSERT_CRITICAL(location != -1, "Can't find Uniform '{0}'.", name); 134 | glUniform1i(location, val); 135 | } 136 | 137 | void OpenGLShader::bind() const 138 | { 139 | glUseProgram(m_id); 140 | } 141 | void OpenGLShader::unbind() const 142 | { 143 | glUseProgram(0); 144 | } 145 | 146 | } // namespace Maki 147 | -------------------------------------------------------------------------------- /maki_core/src/renderer/opengl/opengl_shader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../shader.h" 4 | 5 | #include 6 | #include 7 | 8 | namespace Maki { 9 | 10 | class OpenGLShader: public Shader { 11 | public: 12 | OpenGLShader(const std::string& vert_path, const std::string& frag_path); 13 | ~OpenGLShader(); 14 | 15 | virtual void set_float1(const std::string& name, float val) override; 16 | virtual void set_float2(const std::string& name, const vec2& val) override; 17 | virtual void set_float3(const std::string& name, const vec3& val) override; 18 | virtual void set_float4(const std::string& name, const vec4& val) override; 19 | virtual void set_mat3(const std::string& name, const mat3& val) override; 20 | virtual void set_mat4(const std::string& name, const mat4& val) override; 21 | virtual void set_int1(const std::string& name, int val) override; 22 | 23 | virtual void bind() const override; 24 | virtual void unbind() const override; 25 | 26 | private: 27 | void compile(const std::unordered_map& shader_sources); 28 | std::string read_file(const std::string& path); 29 | 30 | private: 31 | uint32_t m_id; 32 | }; 33 | 34 | } // namespace Maki 35 | -------------------------------------------------------------------------------- /maki_core/src/renderer/opengl/opengl_stringifier.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "opengl_stringifier.h" 4 | 5 | namespace Maki { 6 | 7 | // Thanks to Light3039!!! ^^ 8 | std::string Stringifier::gl_msg_severity(GLenum val) 9 | { 10 | switch(val) { 11 | case GL_DEBUG_SEVERITY_NOTIFICATION: 12 | return "GL_DEBUG_SEVERITY_NOTIFICATION"; 13 | case GL_DEBUG_SEVERITY_LOW: 14 | return "GL_DEBUG_SEVERITY_LOW"; 15 | case GL_DEBUG_SEVERITY_MEDIUM: 16 | return "GL_DEBUG_SEVERITY_MEDIUM"; 17 | case GL_DEBUG_SEVERITY_HIGH: 18 | return "GL_DEBUG_SEVERITY_HIGH"; 19 | default: 20 | return "UNKNOWN"; 21 | } 22 | } 23 | std::string Stringifier::gl_msg_source(GLenum val) 24 | { 25 | switch(val) { 26 | case GL_DEBUG_SOURCE_API: 27 | return "GL_DEBUG_SOURCE_API"; 28 | case GL_DEBUG_SOURCE_WINDOW_SYSTEM: 29 | return "GL_DEBUG_SOURCE_WINDOW_SYSTEM"; 30 | case GL_DEBUG_SOURCE_SHADER_COMPILER: 31 | return "GL_DEBUG_SOURCE_SHADER_COMPILER"; 32 | case GL_DEBUG_SOURCE_THIRD_PARTY: 33 | return "GL_DEBUG_SOURCE_THIRD_PARTY"; 34 | case GL_DEBUG_SOURCE_APPLICATION: 35 | return "GL_DEBUG_SOURCE_APPLICATION"; 36 | case GL_DEBUG_SOURCE_OTHER: 37 | return "GL_DEBUG_SOURCE_OTHER"; 38 | default: 39 | return "UNKNOWN"; 40 | } 41 | } 42 | std::string Stringifier::gl_msg_type(GLenum val) 43 | { 44 | switch(val) { 45 | case GL_DEBUG_TYPE_ERROR: 46 | return "GL_DEBUG_TYPE_ERROR"; 47 | case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: 48 | return "GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR"; 49 | case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: 50 | return "GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR"; 51 | case GL_DEBUG_TYPE_PORTABILITY: 52 | return "GL_DEBUG_TYPE_PORTABILITY"; 53 | case GL_DEBUG_TYPE_PERFORMANCE: 54 | return "GL_DEBUG_TYPE_PERFORMANCE"; 55 | case GL_DEBUG_TYPE_MARKER: 56 | return "GL_DEBUG_TYPE_MARKER"; 57 | case GL_DEBUG_TYPE_PUSH_GROUP: 58 | return "GL_DEBUG_TYPE_PUSH_GROUP"; 59 | case GL_DEBUG_TYPE_POP_GROUP: 60 | return "GL_DEBUG_TYPE_POP_GROUP"; 61 | case GL_DEBUG_TYPE_OTHER: 62 | return "GL_DEBUG_TYPE_OTHER"; 63 | default: 64 | return "UNKNOWN"; 65 | } 66 | } 67 | 68 | } // namespace Maki 69 | -------------------------------------------------------------------------------- /maki_core/src/renderer/opengl/opengl_stringifier.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace Maki { 7 | 8 | // convert GLenums into legible output 9 | class Stringifier { 10 | public: 11 | static std::string gl_msg_severity(GLenum val); 12 | static std::string gl_msg_source(GLenum val); 13 | static std::string gl_msg_type(GLenum val); 14 | }; 15 | 16 | } // namespace Maki 17 | -------------------------------------------------------------------------------- /maki_core/src/renderer/opengl/opengl_types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../types.h" 4 | 5 | #include 6 | 7 | namespace Maki { 8 | 9 | inline GLenum data_type_to_gl_enum(DataType type) 10 | { 11 | switch(type) { 12 | case DataType::float1: 13 | return GL_FLOAT; 14 | case DataType::float2: 15 | return GL_FLOAT; 16 | case DataType::float3: 17 | return GL_FLOAT; 18 | case DataType::float4: 19 | return GL_FLOAT; 20 | case DataType::mat3: 21 | return GL_FLOAT; 22 | case DataType::mat4: 23 | return GL_FLOAT; 24 | case DataType::int1: 25 | return GL_INT; 26 | case DataType::int2: 27 | return GL_INT; 28 | case DataType::int3: 29 | return GL_INT; 30 | case DataType::int4: 31 | return GL_INT; 32 | case DataType::bool1: 33 | return GL_BOOL; 34 | default: 35 | MAKI_RAISE_CRITICAL("Unknown DataType."); 36 | return 0; 37 | } 38 | } 39 | 40 | } // namespace Maki 41 | -------------------------------------------------------------------------------- /maki_core/src/renderer/opengl/opengl_vertex_array.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "opengl_vertex_array.h" 4 | #include "renderer/opengl/opengl_types.h" 5 | 6 | namespace Maki { 7 | 8 | OpenGLVertexArray::OpenGLVertexArray() 9 | { 10 | glCreateVertexArrays(1, &m_id); 11 | } 12 | OpenGLVertexArray::~OpenGLVertexArray() 13 | { 14 | glDeleteVertexArrays(1, &m_id); 15 | } 16 | 17 | void OpenGLVertexArray::bind() const 18 | { 19 | glBindVertexArray(m_id); 20 | } 21 | void OpenGLVertexArray::unbind() const 22 | { 23 | glBindVertexArray(0); 24 | } 25 | 26 | void OpenGLVertexArray::add_vertex_buffer(VertexBuffer* vertex_buffer) 27 | { 28 | auto vao_bind = VertexArrayBind(this); 29 | vertex_buffer->bind(); 30 | 31 | for(const BufferElement& element: vertex_buffer->get_elements()) { 32 | glEnableVertexAttribArray(m_next_attrib_id); 33 | glVertexAttribPointer( 34 | m_next_attrib_id, 35 | data_type_components(element.type), 36 | data_type_to_gl_enum(element.type), 37 | element.normalized ? GL_TRUE : GL_FALSE, 38 | vertex_buffer->get_stride(), 39 | reinterpret_cast(element.offset)); 40 | ++m_next_attrib_id; 41 | } 42 | m_vertex_buffers.push_back(vertex_buffer); 43 | } 44 | 45 | void OpenGLVertexArray::set_index_buffer(IndexBuffer* index_buffer) 46 | { 47 | auto vao_bind = VertexArrayBind(this); 48 | index_buffer->bind(); 49 | m_index_buffer = index_buffer; 50 | } 51 | 52 | } // namespace Maki 53 | -------------------------------------------------------------------------------- /maki_core/src/renderer/opengl/opengl_vertex_array.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../vertex_array.h" 4 | 5 | namespace Maki { 6 | 7 | class OpenGLVertexArray: public VertexArray { 8 | public: 9 | OpenGLVertexArray(); 10 | ~OpenGLVertexArray(); 11 | 12 | virtual void bind() const override; 13 | virtual void unbind() const override; 14 | 15 | virtual void add_vertex_buffer(VertexBuffer* vertex_buffer) override; 16 | virtual void set_index_buffer(IndexBuffer* index_buffer) override; 17 | 18 | private: 19 | uint32_t m_id; 20 | uint32_t m_next_attrib_id {0}; 21 | std::vector m_vertex_buffers; 22 | IndexBuffer* m_index_buffer {nullptr}; 23 | }; 24 | 25 | } // namespace Maki 26 | -------------------------------------------------------------------------------- /maki_core/src/renderer/renderer.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "renderer.h" 4 | 5 | #include "renderer/opengl/opengl_renderer.h" 6 | 7 | namespace Maki { 8 | 9 | Renderer* Renderer::create(const std::string& title, uint32_t width, uint32_t height, vec4 clear_col, EventHandler driver_event_handler) 10 | { 11 | switch(s_renderer_impl) { 12 | case Implementation::none: 13 | MAKI_RAISE_CRITICAL("Renderer::Implementation::none is not supported."); 14 | return nullptr; 15 | case Implementation::opengl: 16 | return new OpenGLRenderer(title, width, height, clear_col, driver_event_handler); 17 | default: 18 | MAKI_RAISE_CRITICAL("The requested renderer implementation is not supported."); 19 | return nullptr; 20 | } 21 | } 22 | 23 | Renderer::Renderer(const std::string& title, uint32_t width, uint32_t height, EventHandler driver_event_handler) 24 | : m_camera {new Camera(width, height, Camera::Type::perspective)}, m_last_time {Clock::now()} 25 | { 26 | EventHandler renderer_event_handler; 27 | renderer_event_handler.on_window_resize = [this](int width, int height) { 28 | m_camera->set_window_size(width, height); 29 | return false; 30 | }; 31 | renderer_event_handler.on_window_close = [this]() { 32 | terminate(); 33 | return false; 34 | }; 35 | m_window = new Window(title, width, height, driver_event_handler, renderer_event_handler); 36 | } 37 | 38 | Renderer::~Renderer() 39 | { 40 | delete m_window; 41 | delete m_camera; 42 | } 43 | 44 | void Renderer::start_frame() 45 | { 46 | TimePoint current_time = Clock::now(); 47 | m_last_frame_time = current_time - m_last_time; 48 | m_last_time = current_time; 49 | m_window->start_frame(); 50 | } 51 | void Renderer::end_frame() 52 | { 53 | m_window->end_frame(); 54 | } 55 | 56 | // thread safe -> can be run from control thread // 57 | void Renderer::terminate() 58 | { 59 | lock lock {m_should_terminate_mutex}; 60 | m_should_terminate = true; 61 | } 62 | bool Renderer::should_terminate() 63 | { 64 | lock lock {m_should_terminate_mutex}; 65 | return m_should_terminate; 66 | } 67 | 68 | } // namespace Maki 69 | -------------------------------------------------------------------------------- /maki_core/src/renderer/renderer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "platform/event.h" 4 | #include "platform/window.h" 5 | #include "renderer/buffer.h" 6 | #include "renderer/camera.h" 7 | #include "renderer/shader.h" 8 | #include "renderer/vertex_array.h" 9 | 10 | namespace Maki { 11 | 12 | // TODO: MAKI_ASSERT_RNDR_THREADs should be added, but not so clean with inheritance 13 | // low-level abstraction for rendering api calls 14 | // implementation gets chosen at runtime -> inheritance 15 | class Renderer { 16 | public: 17 | enum class Implementation { 18 | none = 0, 19 | opengl = 1, 20 | }; 21 | 22 | public: 23 | // create renderer with implementation specified in s_renderer_impl 24 | // every implementation-specific class uses this concept 25 | static Renderer* create(const std::string& title, uint32_t width, uint32_t height, vec4 clear_col, EventHandler driver_event_handler = EventHandler {}); 26 | 27 | static Implementation get_renderer_impl() { return s_renderer_impl; } 28 | static void set_renderer_impl(Implementation renderer_impl) { s_renderer_impl = renderer_impl; } 29 | 30 | public: 31 | Renderer(const std::string& title, uint32_t width, uint32_t height, EventHandler driver_event_handler = EventHandler {}); 32 | virtual ~Renderer(); 33 | 34 | void set_cursor_type(CursorType type) { m_window->set_cursor_type(type); } 35 | EventHandler& get_driver_event_handler() { return m_window->get_driver_event_handler(); } 36 | Camera* get_camera() { return m_camera; } 37 | bool imgui_supported() { return m_window->imgui_supported(); } 38 | 39 | // in milliseconds 40 | long get_last_frame_time() { return get_mills(m_last_frame_time); } 41 | 42 | virtual void set_clear_col(vec4 color) = 0; 43 | 44 | // shader and vertex array object needs to be bound prior 45 | virtual void draw(uint32_t index_count) = 0; 46 | // to be augmented by implementation -> Renderer func has to be called from implementation prior to anything else 47 | virtual void start_frame(); 48 | virtual void end_frame(); 49 | 50 | // thread safe -> can be run from control thread // 51 | void terminate(); 52 | bool should_terminate(); 53 | 54 | protected: 55 | static inline Implementation s_renderer_impl {Renderer::Implementation::none}; 56 | 57 | protected: 58 | Window* m_window {nullptr}; 59 | Camera* m_camera {nullptr}; 60 | // single source of truth for termination status 61 | // needs to be in renderer <- window close handled by renderer, otherwise reference to RenderDriver or other required, would be unclean 62 | bool m_should_terminate {false}; 63 | mutex m_should_terminate_mutex; 64 | 65 | TimePoint m_last_time; 66 | Duration m_last_frame_time {0}; 67 | }; 68 | 69 | } // namespace Maki 70 | -------------------------------------------------------------------------------- /maki_core/src/renderer/shader.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "buffer.h" 4 | 5 | #include "renderer/opengl/opengl_shader.h" 6 | #include "renderer/renderer.h" 7 | 8 | namespace Maki { 9 | 10 | Shader* Shader::create(const std::string& vert_path, const std::string& frag_path) 11 | { 12 | switch(Renderer::get_renderer_impl()) { 13 | case Renderer::Implementation::none: 14 | MAKI_RAISE_CRITICAL("Renderer::Implementation::none is not supported."); 15 | return nullptr; 16 | case Renderer::Implementation::opengl: 17 | return new OpenGLShader(vert_path, frag_path); 18 | default: 19 | MAKI_RAISE_CRITICAL("The requested renderer implementation is not supported."); 20 | return nullptr; 21 | } 22 | } 23 | 24 | } // namespace Maki 25 | -------------------------------------------------------------------------------- /maki_core/src/renderer/shader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "core/definitions.h" 6 | 7 | namespace Maki { 8 | 9 | // store shader and uniform definitions 10 | class Shader { 11 | public: 12 | static Shader* create(const std::string& vert_path, const std::string& frag_path); 13 | 14 | public: 15 | virtual ~Shader() = default; 16 | 17 | virtual void bind() const = 0; 18 | virtual void unbind() const = 0; 19 | 20 | virtual void set_float1(const std::string& name, float val) = 0; 21 | virtual void set_float2(const std::string& name, const vec2& val) = 0; 22 | virtual void set_float3(const std::string& name, const vec3& val) = 0; 23 | virtual void set_float4(const std::string& name, const vec4& val) = 0; 24 | virtual void set_mat3(const std::string& name, const mat3& val) = 0; 25 | virtual void set_mat4(const std::string& name, const mat4& val) = 0; 26 | virtual void set_int1(const std::string& name, int val) = 0; 27 | }; 28 | 29 | } // namespace Maki 30 | -------------------------------------------------------------------------------- /maki_core/src/renderer/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "core/log.h" 4 | 5 | namespace Maki { 6 | 7 | enum class DataType { 8 | none = 0, 9 | float1, 10 | float2, 11 | float3, 12 | float4, 13 | mat3, 14 | mat4, 15 | int1, 16 | int2, 17 | int3, 18 | int4, 19 | bool1 20 | }; 21 | 22 | inline size_t data_type_size(DataType type) 23 | { 24 | switch(type) { 25 | case DataType::float1: 26 | return sizeof(float) * 1; 27 | case DataType::float2: 28 | return sizeof(float) * 2; 29 | case DataType::float3: 30 | return sizeof(float) * 3; 31 | case DataType::float4: 32 | return sizeof(float) * 4; 33 | case DataType::mat3: 34 | return sizeof(float) * 3 * 3; 35 | case DataType::mat4: 36 | return sizeof(float) * 4 * 4; 37 | case DataType::int1: 38 | return sizeof(int) * 1; 39 | case DataType::int2: 40 | return sizeof(int) * 2; 41 | case DataType::int3: 42 | return sizeof(int) * 3; 43 | case DataType::int4: 44 | return sizeof(int) * 4; 45 | case DataType::bool1: 46 | return sizeof(bool) * 1; 47 | default: 48 | MAKI_RAISE_CRITICAL("Unknown DataType."); 49 | return 0; 50 | } 51 | } 52 | 53 | inline uint32_t data_type_components(DataType type) 54 | { 55 | switch(type) { 56 | case DataType::float1: 57 | return 1; 58 | case DataType::float2: 59 | return 2; 60 | case DataType::float3: 61 | return 3; 62 | case DataType::float4: 63 | return 4; 64 | case DataType::mat3: 65 | return 3 * 3; 66 | case DataType::mat4: 67 | return 4 * 4; 68 | case DataType::int1: 69 | return 1; 70 | case DataType::int2: 71 | return 2; 72 | case DataType::int3: 73 | return 3; 74 | case DataType::int4: 75 | return 4; 76 | case DataType::bool1: 77 | return 1; 78 | default: 79 | MAKI_RAISE_CRITICAL("Unknown DataType."); 80 | return 0; 81 | } 82 | } 83 | 84 | } // namespace Maki 85 | -------------------------------------------------------------------------------- /maki_core/src/renderer/vertex_array.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "buffer.h" 4 | 5 | #include "renderer/opengl/opengl_vertex_array.h" 6 | #include "renderer/renderer.h" 7 | 8 | namespace Maki { 9 | 10 | VertexArray* VertexArray::create() 11 | { 12 | switch(Renderer::get_renderer_impl()) { 13 | case Renderer::Implementation::none: 14 | MAKI_RAISE_CRITICAL("Renderer::Implementation::none is not supported."); 15 | return nullptr; 16 | case Renderer::Implementation::opengl: 17 | return new OpenGLVertexArray(); 18 | default: 19 | MAKI_RAISE_CRITICAL("The requested renderer implementation is not supported."); 20 | return nullptr; 21 | } 22 | } 23 | 24 | } // namespace Maki 25 | -------------------------------------------------------------------------------- /maki_core/src/renderer/vertex_array.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "renderer/buffer.h" 4 | 5 | namespace Maki { 6 | 7 | // bind (multiple) vertex buffers and one index buffer together 8 | class VertexArray { 9 | public: 10 | static VertexArray* create(); 11 | 12 | public: 13 | virtual ~VertexArray() = default; 14 | 15 | // unbind has to be called after vertex array isn't being used anymore -> different vertex buffer creation would spoil this vao 16 | // use VertexArrayBind unless raw use of bind/unbind completely unavoidable 17 | virtual void bind() const = 0; 18 | virtual void unbind() const = 0; 19 | 20 | virtual void add_vertex_buffer(VertexBuffer* vertex_buffer) = 0; 21 | virtual void set_index_buffer(IndexBuffer* index_buffer) = 0; 22 | }; 23 | 24 | // RAII approach to binding/unbinding a vertex array 25 | class VertexArrayBind { 26 | public: 27 | VertexArrayBind(const VertexArray* vertex_array) 28 | : m_vertex_array(vertex_array) 29 | { 30 | m_vertex_array->bind(); 31 | } 32 | 33 | ~VertexArrayBind() 34 | { 35 | m_vertex_array->unbind(); 36 | } 37 | 38 | private: 39 | const VertexArray* m_vertex_array {nullptr}; 40 | }; 41 | 42 | } // namespace Maki 43 | -------------------------------------------------------------------------------- /maki_showcase.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "67880847-cf33-4257-87ed-fc67338474f4", 6 | "metadata": {}, 7 | "source": [ 8 | "# Maki or How to Teach Manim Time Travel" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "id": "90dbab12-cbdb-4d5a-91c9-0dae8901dab8", 14 | "metadata": {}, 15 | "source": [ 16 | "### Setup" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": 1, 22 | "id": "d4763229-66e7-4098-8b52-d67fe912d70c", 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "import maki" 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": 2, 32 | "id": "2041ec1f-4e48-48f2-82fa-c2dfe1e4efd0", 33 | "metadata": {}, 34 | "outputs": [], 35 | "source": [ 36 | "maki.init(maki.RendererImplementation.opengl)" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": 21, 42 | "id": "884bee7e-a512-4113-8a14-9abe72eef9f3", 43 | "metadata": {}, 44 | "outputs": [ 45 | { 46 | "name": "stdout", 47 | "output_type": "stream", 48 | "text": [ 49 | "[19:21:47] Maki:\tCreating GLFW window 'Maki Showcase Window' (1280, 640).\n", 50 | "[19:21:47] Maki:\tCreating OpenGL Renderer.\n", 51 | "[19:21:47] Maki:\tInitializing GLEW.\n", 52 | "[19:21:47] Maki:\tShaders linked.\n", 53 | "[19:21:47] Maki:\tShaders linked.\n" 54 | ] 55 | } 56 | ], 57 | "source": [ 58 | "render_driver = maki.RenderDriver(\"Maki Showcase Window\", 1280, 640, maki.vec4(0.20, 0.23, 0.25, 1.0))" 59 | ] 60 | }, 61 | { 62 | "cell_type": "markdown", 63 | "id": "11cd5843-42b4-43c2-82c6-d18ff8deb5ac", 64 | "metadata": {}, 65 | "source": [ 66 | "## Raw Cuboids" 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": 22, 72 | "id": "f2775c62-2b75-4425-8f89-48b97872e95e", 73 | "metadata": {}, 74 | "outputs": [], 75 | "source": [ 76 | "cuboid = render_driver.add_cuboid_atom()" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": 23, 82 | "id": "55df67af-1fc4-4d26-84b5-661cb3137b43", 83 | "metadata": {}, 84 | "outputs": [ 85 | { 86 | "name": "stdout", 87 | "output_type": "stream", 88 | "text": [ 89 | "[19:21:51] Maki:\tCuboidAtom Chrono Sync initiated.\n" 90 | ] 91 | } 92 | ], 93 | "source": [ 94 | "render_driver.show_cuboid_atom(cuboid, 1, True)" 95 | ] 96 | }, 97 | { 98 | "cell_type": "markdown", 99 | "id": "669a8e02-1232-40ae-9e35-bf18fe5ee490", 100 | "metadata": {}, 101 | "source": [ 102 | "### Colouring" 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": 24, 108 | "id": "228da863-5521-432f-9d80-29598b761a04", 109 | "metadata": {}, 110 | "outputs": [], 111 | "source": [ 112 | "render_driver.color_cuboid_atom(cuboid, 2, maki.vec4(1.0, 1.0, 0.0, 1.0))" 113 | ] 114 | }, 115 | { 116 | "cell_type": "code", 117 | "execution_count": 7, 118 | "id": "6d30c001-70bc-494f-8545-0cd6e1bc221b", 119 | "metadata": {}, 120 | "outputs": [], 121 | "source": [ 122 | "render_driver.color_cuboid_atom(cuboid, 3, maki.vec4(1.0, 0.0, 1.0, 1.0))\n", 123 | "render_driver.color_cuboid_atom(cuboid, 4, maki.vec4(0.5, 0.5, 0.5, 1.0))\n", 124 | "render_driver.color_cuboid_atom(cuboid, 5, maki.vec4(0.8, 0.0, 0.4, 1.0))" 125 | ] 126 | }, 127 | { 128 | "cell_type": "markdown", 129 | "id": "113fb580-0b55-40bd-97cf-f0ed14b907f8", 130 | "metadata": {}, 131 | "source": [ 132 | "### Translation" 133 | ] 134 | }, 135 | { 136 | "cell_type": "code", 137 | "execution_count": 8, 138 | "id": "57acd2b2-56f7-40d7-9820-aecd835d8ef8", 139 | "metadata": {}, 140 | "outputs": [], 141 | "source": [ 142 | "render_driver.translate_cuboid_atom(cuboid, 6, maki.vec3(0.0, 1.0, 0.0))" 143 | ] 144 | }, 145 | { 146 | "cell_type": "code", 147 | "execution_count": 9, 148 | "id": "36e2ad86-b7f7-4fc8-a223-a101f7964ef6", 149 | "metadata": {}, 150 | "outputs": [], 151 | "source": [ 152 | "target_delta = maki.vec3(10.0, 10.0, 5.0)\n", 153 | "first_frame = 60 # alpha = 0.0\n", 154 | "after_last_frame = 200 # alpha = 1.0\n", 155 | "\n", 156 | "alpha_delta = 1 / (after_last_frame - first_frame)\n", 157 | "for frame in range(first_frame, after_last_frame):\n", 158 | " cur_delta = target_delta * alpha_delta\n", 159 | " render_driver.translate_cuboid_atom(cuboid, frame, cur_delta)" 160 | ] 161 | }, 162 | { 163 | "cell_type": "markdown", 164 | "id": "780fb1a1-d1d8-4cf4-b153-9431598b5a1f", 165 | "metadata": {}, 166 | "source": [ 167 | "## Time Travel" 168 | ] 169 | }, 170 | { 171 | "cell_type": "code", 172 | "execution_count": 10, 173 | "id": "a6bfc44f-567b-4eeb-8e86-d6253ae85159", 174 | "metadata": {}, 175 | "outputs": [ 176 | { 177 | "name": "stdout", 178 | "output_type": "stream", 179 | "text": [ 180 | "[19:21:12] Maki:\tCreating GLFW window 'Maki Showcase Window' (1280, 640).\n" 181 | ] 182 | } 183 | ], 184 | "source": [ 185 | "target_delta = maki.vec3(0.0, -5.0, 0.0)\n", 186 | "first_frame = 5 # alpha = 0.0\n", 187 | "after_last_frame = 50 # alpha = 1.0\n", 188 | "alpha_delta = 1 / (after_last_frame - first_frame)\n", 189 | "for frame in range(first_frame, after_last_frame):\n", 190 | " cur_delta = target_delta * alpha_delta\n", 191 | " render_driver.translate_cuboid_atom(cuboid, frame, cur_delta)" 192 | ] 193 | }, 194 | { 195 | "cell_type": "markdown", 196 | "id": "96bbebe2-13d2-4abd-8c65-d43ca8405dd3", 197 | "metadata": {}, 198 | "source": [ 199 | "## Abstraction" 200 | ] 201 | }, 202 | { 203 | "cell_type": "code", 204 | "execution_count": 11, 205 | "id": "0d9b0b42-8031-4f68-8694-12f9ebb0bdc0", 206 | "metadata": {}, 207 | "outputs": [], 208 | "source": [ 209 | "from abc import abstractmethod\n", 210 | "\n", 211 | "# this is not clean code, it's just a showcase\n", 212 | "class Mobject:\n", 213 | " def __init__(self, render_driver: maki.RenderDriver):\n", 214 | " self.render_driver = render_driver\n", 215 | " \n", 216 | " @abstractmethod\n", 217 | " def show(self, frame: int):\n", 218 | " pass\n", 219 | " @abstractmethod\n", 220 | " def hide(self, frame: int):\n", 221 | " pass\n", 222 | " \n", 223 | " @abstractmethod\n", 224 | " def translate(self, delta: maki.vec3, first_frame: int, after_last_frame: int):\n", 225 | " pass\n", 226 | "\n", 227 | "\n", 228 | "class Cube(Mobject):\n", 229 | " def __init__(self, render_driver: maki.RenderDriver, first_frame: int):\n", 230 | " super().__init__(render_driver)\n", 231 | " self.cuboid_atom = render_driver.add_cuboid_atom()\n", 232 | " self.show(first_frame)\n", 233 | " \n", 234 | " def show(self, frame: int):\n", 235 | " self.render_driver.show_cuboid_atom(self.cuboid_atom, frame, True)\n", 236 | " def hide(self, frame: int):\n", 237 | " self.render_driver.show_cuboid_atom(self.cuboid_atom, frame, False)\n", 238 | " \n", 239 | " def translate(self, delta: maki.vec3, first_frame: int, after_last_frame: int):\n", 240 | " alpha_delta = 1 / (after_last_frame - first_frame)\n", 241 | " for frame in range(first_frame, after_last_frame):\n", 242 | " cur_delta = delta * alpha_delta\n", 243 | " self.render_driver.translate_cuboid_atom(self.cuboid_atom, frame, cur_delta)" 244 | ] 245 | }, 246 | { 247 | "cell_type": "code", 248 | "execution_count": 12, 249 | "id": "592dbd78-5a67-4c3c-a286-bbfbcc3528f5", 250 | "metadata": {}, 251 | "outputs": [], 252 | "source": [ 253 | "c = Cube(render_driver, 5)" 254 | ] 255 | }, 256 | { 257 | "cell_type": "code", 258 | "execution_count": 13, 259 | "id": "b73596a2-6569-46c1-bea9-5269893a7c9f", 260 | "metadata": {}, 261 | "outputs": [], 262 | "source": [ 263 | "c.translate(maki.vec3(0.0, 0.0, 20.0), 10, 300)" 264 | ] 265 | }, 266 | { 267 | "cell_type": "markdown", 268 | "id": "ce668c16-eecb-4561-9a44-2a15370b04b4", 269 | "metadata": {}, 270 | "source": [ 271 | "# Some more complicated Mobjects" 272 | ] 273 | }, 274 | { 275 | "cell_type": "markdown", 276 | "id": "14914b98-2ba5-4bce-8c69-8dae91a1da28", 277 | "metadata": {}, 278 | "source": [ 279 | "## Big Block of Cubes" 280 | ] 281 | }, 282 | { 283 | "cell_type": "code", 284 | "execution_count": 14, 285 | "id": "d8f40eeb-a18f-4d60-8677-7160d6e8c201", 286 | "metadata": {}, 287 | "outputs": [], 288 | "source": [ 289 | "import random\n", 290 | "\n", 291 | "\n", 292 | "# again, this is very unclean code\n", 293 | "def get_random_color():\n", 294 | " return maki.vec4(random.uniform(0.0, 1.0), random.uniform(0.0, 1.0), random.uniform(0.0, 1.0), 1.0)" 295 | ] 296 | }, 297 | { 298 | "cell_type": "code", 299 | "execution_count": 15, 300 | "id": "a6172d4f-bcf7-460a-a980-240fa3ac7df2", 301 | "metadata": {}, 302 | "outputs": [ 303 | { 304 | "name": "stdout", 305 | "output_type": "stream", 306 | "text": [ 307 | "[19:21:12] Maki:\tCreating OpenGL Renderer.\n", 308 | "[19:21:12] Maki:\tInitializing GLEW.\n", 309 | "[19:21:12] Maki:\tShaders linked.\n", 310 | "[19:21:12] Maki:\tShaders linked.\n" 311 | ] 312 | } 313 | ], 314 | "source": [ 315 | "space = 4\n", 316 | "frame = 1.0\n", 317 | "for x in range(0, 50 * space, space):\n", 318 | " for y in range(0, 50 * space, space):\n", 319 | " for z in range(0, 50 * space, space):\n", 320 | " cube = render_driver.add_cuboid_atom()\n", 321 | " render_driver.show_cuboid_atom(cube, int(frame), True)\n", 322 | " render_driver.translate_cuboid_atom(cube, int(frame), maki.vec3(x-300, y-200, z))\n", 323 | " render_driver.color_cuboid_atom(cube, int(frame), get_random_color())\n", 324 | " frame += 0.005" 325 | ] 326 | }, 327 | { 328 | "cell_type": "markdown", 329 | "id": "907824c5-4707-44d9-994c-e058f92d46ce", 330 | "metadata": {}, 331 | "source": [ 332 | "## Text" 333 | ] 334 | }, 335 | { 336 | "cell_type": "code", 337 | "execution_count": 16, 338 | "id": "f864d7f3-0396-432f-8bd2-51148899c298", 339 | "metadata": {}, 340 | "outputs": [], 341 | "source": [ 342 | "class TextCubes(Mobject):\n", 343 | " cubes = []\n", 344 | " \n", 345 | " def __init__(self, render_driver: maki.RenderDriver, first_frame: int, after_last_frame: int, text: str):\n", 346 | " super().__init__(render_driver)\n", 347 | " alpha_delta = 1 / (after_last_frame - first_frame)\n", 348 | " font = self.load_font()\n", 349 | " rendered_text = self.render_text(text, *font)\n", 350 | " y = 0.0\n", 351 | " spacing = 3.0\n", 352 | " for line in rendered_text:\n", 353 | " x = 0.0\n", 354 | " for char in line:\n", 355 | " if char == \"#\":\n", 356 | " self.cubes.append(self.render_driver.add_cuboid_atom())\n", 357 | " for frame in range(first_frame, after_last_frame):\n", 358 | " self.render_driver.translate_cuboid_atom(self.cubes[-1], frame, maki.vec3(x, -y, 0) * alpha_delta)\n", 359 | " self.render_driver.color_cuboid_atom(self.cubes[-1], random.randint(int(first_frame + (after_last_frame - first_frame) / 2), after_last_frame - 1), get_random_color())\n", 360 | " x += spacing\n", 361 | " y += spacing\n", 362 | " self.show(first_frame)\n", 363 | " \n", 364 | " def show(self, frame: int):\n", 365 | " for cube in self.cubes:\n", 366 | " self.render_driver.show_cuboid_atom(cube, frame, True)\n", 367 | " def hide(self, frame: int):\n", 368 | " for cube in self.cubes:\n", 369 | " self.render_driver.show_cuboid_atom(cube, frame, False)\n", 370 | " \n", 371 | " def translate(self, delta: maki.vec3, first_frame: int, after_last_frame: int):\n", 372 | " alpha_delta = 1 / (after_last_frame - first_frame)\n", 373 | " for frame in range(first_frame, after_last_frame):\n", 374 | " cur_delta = delta * alpha_delta\n", 375 | " for cube in self.cubes:\n", 376 | " self.render_driver.translate_cuboid_atom(cube, frame, cur_delta)\n", 377 | " \n", 378 | " def load_font(self):\n", 379 | " chars = {}\n", 380 | " with open(f\"block.txt\", \"r\", encoding=\"utf-8\") as file:\n", 381 | " height = int(file.readline().split(\":\")[-1])\n", 382 | " spacing = int(file.readline().split(\":\")[-1])\n", 383 | " while line := file.readline():\n", 384 | " if line[0] == \"-\":\n", 385 | " code = int(line[1:])\n", 386 | " char = []\n", 387 | " for _ in range(0, height):\n", 388 | " char.append(list(file.readline().strip(\"\\n\"))[::2])\n", 389 | " chars[code] = char\n", 390 | " return (chars, height, spacing)\n", 391 | "\n", 392 | "\n", 393 | " def render_text(self, text, font_chars, height, spacing):\n", 394 | " # rows to be printed\n", 395 | " output_lines = []\n", 396 | " for input_line in text.split(\"\\n\"):\n", 397 | " # filling lines with pixels of one char after another\n", 398 | " new_output_lines = [[] for _ in range(height)]\n", 399 | " for input_char in input_line:\n", 400 | " # convert input char into array of pixels\n", 401 | " output_char_rows = font_chars[ord(input_char)]\n", 402 | " for new_output_line, output_char_row in zip(new_output_lines, output_char_rows):\n", 403 | " new_output_line += output_char_row\n", 404 | " output_lines += new_output_lines\n", 405 | "\n", 406 | " output_strings = [\"\".join(line).replace(\"_\", \"#\").replace(\"|\", \"#\") for line in output_lines]\n", 407 | " return output_strings" 408 | ] 409 | }, 410 | { 411 | "cell_type": "code", 412 | "execution_count": 17, 413 | "id": "bd7f2850-1ce2-42de-8cc5-64e4f4837705", 414 | "metadata": {}, 415 | "outputs": [ 416 | { 417 | "name": "stdout", 418 | "output_type": "stream", 419 | "text": [ 420 | "[19:21:13] Maki:\tCuboidAtom Chrono Sync initiated.\n", 421 | "[19:21:13] Maki:\tCuboidAtom Chrono Sync initiated.\n", 422 | "[19:21:13] Maki:\tCuboidAtom Chrono Sync initiated.\n", 423 | "[19:21:13] Maki:\tCuboidAtom Chrono Sync initiated.\n", 424 | "[19:21:13] Maki:\tCuboidAtom Chrono Sync initiated.\n", 425 | "[19:21:13] Maki:\tCuboidAtom Chrono Sync initiated.\n", 426 | "[19:21:14] Maki:\tCuboidAtom Chrono Sync initiated.\n", 427 | "[19:21:14] Maki:\tCuboidAtom Chrono Sync initiated.\n", 428 | "[19:21:14] Maki:\tCuboidAtom Chrono Sync initiated.\n", 429 | "[19:21:14] Maki:\tCuboidAtom Chrono Sync initiated.\n", 430 | "[19:21:14] Maki:\tCuboidAtom Chrono Sync initiated.\n" 431 | ] 432 | } 433 | ], 434 | "source": [ 435 | "t = TextCubes(render_driver, 1, 200, \"Hello World\")" 436 | ] 437 | }, 438 | { 439 | "cell_type": "markdown", 440 | "id": "9615b638-c801-417b-9ae1-4116de301afd", 441 | "metadata": {}, 442 | "source": [ 443 | "## Images and Videos" 444 | ] 445 | }, 446 | { 447 | "cell_type": "code", 448 | "execution_count": 18, 449 | "id": "f1ca6d73-86c3-4030-833f-6b93013ecb84", 450 | "metadata": {}, 451 | "outputs": [], 452 | "source": [ 453 | "from PIL import Image\n", 454 | "import numpy as np\n", 455 | "import itertools\n", 456 | "import os\n", 457 | "\n", 458 | "# again, garbage code\n", 459 | "class ImageRects(Mobject):\n", 460 | " rects = []\n", 461 | " WIDTH = 96\n", 462 | " HEIGHT = 72\n", 463 | " SPACING = 3\n", 464 | " \n", 465 | " def __init__(self, render_driver: maki.RenderDriver, first_frame: int, after_last_frame: int, path: str, z: float):\n", 466 | " super().__init__(render_driver)\n", 467 | " \n", 468 | " image = Image.open(path)\n", 469 | " image = image.resize((self.WIDTH, self.HEIGHT), Image.ANTIALIAS)\n", 470 | " image_data = np.asarray(image)\n", 471 | " \n", 472 | " for (x, y), frame in zip(itertools.product(range(self.WIDTH), range(self.HEIGHT)), np.linspace(first_frame, after_last_frame, num=self.WIDTH*self.HEIGHT, endpoint=False)):\n", 473 | " # create rect\n", 474 | " self.rects.append(self.render_driver.add_quadrilateral_atom())\n", 475 | " # position rect\n", 476 | " self.render_driver.translate_quadrilateral_atom(self.rects[-1], int(frame), maki.vec3(x * self.SPACING, -y * self.SPACING, z))\n", 477 | " # set color\n", 478 | " self.render_driver.color_quadrilateral_atom(self.rects[-1], int(frame), maki.vec4(float(image_data[y][x][0]/256), float(image_data[y][x][1]/256), float(image_data[y][x][2]/256), 1.0))\n", 479 | " # show rect\n", 480 | " self.render_driver.show_quadrilateral_atom(self.rects[-1], int(frame), True)\n", 481 | " \n", 482 | " print(f\"created image for '{path}'\")\n", 483 | " \n", 484 | " def show(self, frame: int):\n", 485 | " for cube in self.cubes:\n", 486 | " self.render_driver.show_quadrilateral_atom(cube, frame, True)\n", 487 | " def hide(self, frame: int):\n", 488 | " for rect in self.rects:\n", 489 | " self.render_driver.show_quadrilateral_atom(rect, frame, False)\n", 490 | " \n", 491 | " def translate(self, delta: maki.vec3, first_frame: int, after_last_frame: int):\n", 492 | " alpha_delta = 1 / (after_last_frame - first_frame)\n", 493 | " for frame in range(first_frame, after_last_frame):\n", 494 | " cur_delta = delta * alpha_delta\n", 495 | " for rect in self.rects:\n", 496 | " self.render_driver.translate_quadrilateral_atom(rect, frame, cur_delta)\n", 497 | "\n", 498 | "class VideoRects(Mobject):\n", 499 | " images = []\n", 500 | " SPACING = 3\n", 501 | " \n", 502 | " def __init__(self, render_driver: maki.RenderDriver, first_frame: int, after_last_frame: int, path: str, frames):\n", 503 | " super().__init__(render_driver)\n", 504 | " \n", 505 | " frame_space = np.linspace(first_frame, after_last_frame, num=frames+1, endpoint=False)\n", 506 | " \n", 507 | " for frame in range(1, frames+1):\n", 508 | " self.images.append(ImageRects(self.render_driver, frame_space[frame-1], frame_space[frame], os.path.join(path, f\"{frame:02d}.png\"), frame * self.SPACING))\n", 509 | " \n", 510 | " def show(self, frame: int):\n", 511 | " for image in self.images:\n", 512 | " image.show(frame)\n", 513 | " def hide(self, frame: int):\n", 514 | " for image in self.images:\n", 515 | " image.hide(frame)\n", 516 | " def translate(self, delta: maki.vec3, first_frame: int, after_last_frame: int):\n", 517 | " for image in self.images:\n", 518 | " image.translate(delta, first_frame, after_last_frame)" 519 | ] 520 | }, 521 | { 522 | "cell_type": "code", 523 | "execution_count": 19, 524 | "id": "e2c88037-548b-430d-8bb8-b7188fdd5be3", 525 | "metadata": {}, 526 | "outputs": [ 527 | { 528 | "name": "stdout", 529 | "output_type": "stream", 530 | "text": [ 531 | "created image for 'examples/rick/01.png'\n", 532 | "created image for 'examples/rick/02.png'\n", 533 | "created image for 'examples/rick/03.png'\n", 534 | "created image for 'examples/rick/04.png'\n", 535 | "created image for 'examples/rick/05.png'\n", 536 | "created image for 'examples/rick/06.png'\n", 537 | "created image for 'examples/rick/07.png'\n", 538 | "created image for 'examples/rick/08.png'\n", 539 | "created image for 'examples/rick/09.png'\n", 540 | "created image for 'examples/rick/10.png'\n", 541 | "created image for 'examples/rick/11.png'\n", 542 | "created image for 'examples/rick/12.png'\n", 543 | "created image for 'examples/rick/13.png'\n", 544 | "created image for 'examples/rick/14.png'\n", 545 | "created image for 'examples/rick/15.png'\n", 546 | "created image for 'examples/rick/16.png'\n", 547 | "created image for 'examples/rick/17.png'\n", 548 | "created image for 'examples/rick/18.png'\n", 549 | "created image for 'examples/rick/19.png'\n", 550 | "created image for 'examples/rick/20.png'\n", 551 | "created image for 'examples/rick/21.png'\n", 552 | "created image for 'examples/rick/22.png'\n", 553 | "created image for 'examples/rick/23.png'\n", 554 | "created image for 'examples/rick/24.png'\n", 555 | "created image for 'examples/rick/25.png'\n", 556 | "created image for 'examples/rick/26.png'\n", 557 | "created image for 'examples/rick/27.png'\n", 558 | "created image for 'examples/rick/28.png'\n", 559 | "created image for 'examples/rick/29.png'\n", 560 | "created image for 'examples/rick/30.png'\n", 561 | "created image for 'examples/rick/31.png'\n" 562 | ] 563 | } 564 | ], 565 | "source": [ 566 | "t = VideoRects(render_driver, 500, 1000, \"examples/rick\", 31)" 567 | ] 568 | }, 569 | { 570 | "cell_type": "code", 571 | "execution_count": 25, 572 | "id": "8b5a99d5-8349-4d9d-ab8a-cbbd545940f5", 573 | "metadata": {}, 574 | "outputs": [ 575 | { 576 | "name": "stdout", 577 | "output_type": "stream", 578 | "text": [ 579 | "[19:23:42] Maki:\tCuboidAtom Chrono Sync initiated.\n", 580 | "[19:23:42] Maki:\tQuadrilateralAtom Chrono Sync initiated.\n", 581 | "[19:23:42] Maki:\tCuboidAtom Chrono Sync initiated.\n", 582 | "[19:23:42] Maki:\tQuadrilateralAtom Chrono Sync initiated.\n" 583 | ] 584 | } 585 | ], 586 | "source": [ 587 | "render_driver.set_target_frame(500)" 588 | ] 589 | }, 590 | { 591 | "cell_type": "code", 592 | "execution_count": null, 593 | "id": "1d39d559-6323-401b-bc4b-df83605cb95a", 594 | "metadata": {}, 595 | "outputs": [], 596 | "source": [] 597 | } 598 | ], 599 | "metadata": { 600 | "kernelspec": { 601 | "display_name": "Python 3 (ipykernel)", 602 | "language": "python", 603 | "name": "python3" 604 | }, 605 | "language_info": { 606 | "codemirror_mode": { 607 | "name": "ipython", 608 | "version": 3 609 | }, 610 | "file_extension": ".py", 611 | "mimetype": "text/x-python", 612 | "name": "python", 613 | "nbconvert_exporter": "python", 614 | "pygments_lexer": "ipython3", 615 | "version": "3.10.1" 616 | } 617 | }, 618 | "nbformat": 4, 619 | "nbformat_minor": 5 620 | } 621 | -------------------------------------------------------------------------------- /pretty_bugs/broken_cube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/pretty_bugs/broken_cube.png -------------------------------------------------------------------------------- /pretty_bugs/broken_cube2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/pretty_bugs/broken_cube2.png -------------------------------------------------------------------------------- /pretty_bugs/broken_cube3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/pretty_bugs/broken_cube3.png -------------------------------------------------------------------------------- /pretty_bugs/corrupted_atoms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/pretty_bugs/corrupted_atoms.png -------------------------------------------------------------------------------- /pretty_bugs/floating_boxes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-besch/maki/45323817461cbe69a9b99e50ffebbceb7fca823e/pretty_bugs/floating_boxes.png -------------------------------------------------------------------------------- /stub/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | file(GLOB_RECURSE SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") 4 | add_executable(stub ${SOURCES}) 5 | target_include_directories(stub PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") 6 | 7 | # dependencies 8 | target_link_libraries(stub PRIVATE maki_core) 9 | -------------------------------------------------------------------------------- /stub/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "maki.h" 2 | 3 | int main() 4 | { 5 | Maki::init(Maki::Renderer::Implementation::opengl); 6 | Maki::RenderDriver* render_driver = new Maki::RenderDriver("Maki Test", 1280, 720); 7 | MAKI_CLIENT_LOG_EXTRA("Before Render Loop"); 8 | // uint32_t cuboid = render_driver->add_cuboid_atom(); 9 | // render_driver->render_cuboid_atom(cuboid, 3, true); 10 | // render_driver->translate_cuboid_atom(cuboid, 4, {1.0f, 1.0f, 1.0f}); 11 | // render_driver->render_cuboid_atom(cuboid, 5, false); 12 | // render_driver->render_cuboid_atom(cuboid, 10, true); 13 | 14 | #if 1 15 | constexpr float space {4.0f}; 16 | uint32_t frame {1}; 17 | for(float x {0.0f}; x < 50.0f * space; x += space) { 18 | for(float y {0.0f}; y < 50.0f * space; y += space) { 19 | for(float z {0.0f}; z < 50.0f * space; z += space) { 20 | uint32_t cuboid = render_driver->add_atom(); 21 | render_driver->show_atom(cuboid, frame, true); 22 | render_driver->translate_atom(cuboid, frame, {x, y, z}); 23 | render_driver->color_atom(cuboid, frame, {0.8f, 0.8f, 0.0f, 0.1f}); 24 | // for(uint32_t anim_frame {101}; anim_frame < 200; ++anim_frame) 25 | // render_driver->translate_cuboid_atom(cuboid, anim_frame, {0.2f, 0.0f, 0.0f}); 26 | ++frame; 27 | // MAKI_CLIENT_LOG_EXTRA("new cube {} {} {}", x, y, z); 28 | } 29 | } 30 | } 31 | #endif 32 | #if 0 33 | uint32_t cuboid = render_driver->add_atom(); 34 | render_driver->show_atom(cuboid, 1, true); 35 | 36 | // uint32_t cuboid2 = render_driver->add_atom(); 37 | // render_driver->show_atom(cuboid2, 1, true); 38 | // render_driver->translate_atom(cuboid2, 1, {0.0f, 0.0f, 1.0f}); 39 | // render_driver->color_atom(cuboid2, 1, {1.0f, 1.0f, 0.0f, 1.0f}); 40 | 41 | uint32_t rect = render_driver->add_atom(); 42 | render_driver->show_atom(rect, 2, true); 43 | render_driver->translate_atom(rect, 2, {3.0f, 3.0f, 0.0f}); 44 | #endif 45 | MAKI_CLIENT_LOG_EXTRA("done creating"); 46 | // uint32_t cuboid = render_driver->add_cuboid_atom(); 47 | // render_driver->render_cuboid_atom(cuboid, 1, true); 48 | // render_driver->translate_cuboid_atom(cuboid, 1, {1, 1, 1}); 49 | // uint32_t cuboid1 = render_driver->add_cuboid_atom(); 50 | // render_driver->render_cuboid_atom(cuboid1, 2, true); 51 | // render_driver->translate_cuboid_atom(cuboid1, 2, {2, 2, 2}); 52 | 53 | // render_driver->color_cuboid_atom(cuboid, 11, {1.0f, 1.0f, 0.0f, 1.0f}); 54 | render_driver->await_termination(); 55 | MAKI_CLIENT_LOG_EXTRA("After Render Loop"); 56 | delete render_driver; 57 | } 58 | -------------------------------------------------------------------------------- /vendor/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # glfw 2 | add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/glfw") 3 | 4 | # glm 5 | add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/glm") 6 | 7 | # stb 8 | add_library(stb STATIC "${CMAKE_CURRENT_SOURCE_DIR}/stb.cpp") 9 | target_include_directories(stb PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/stb") 10 | 11 | # spdlog 12 | add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/spdlog") 13 | 14 | # pybind11 15 | add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/pybind11") 16 | 17 | # imgui 18 | set(IMGUI_DIR "${CMAKE_CURRENT_SOURCE_DIR}/imgui") 19 | add_library( 20 | imgui STATIC 21 | "${IMGUI_DIR}/imgui_demo.cpp" 22 | "${IMGUI_DIR}/imgui_draw.cpp" 23 | "${IMGUI_DIR}/imgui_tables.cpp" 24 | "${IMGUI_DIR}/imgui_widgets.cpp" 25 | "${IMGUI_DIR}/imgui.cpp" 26 | 27 | # backends 28 | "${IMGUI_DIR}/backends/imgui_impl_glfw.cpp" 29 | "${IMGUI_DIR}/backends/imgui_impl_opengl3.cpp" 30 | ) 31 | target_include_directories(imgui PUBLIC "${IMGUI_DIR}" "${IMGUI_DIR}/backends") 32 | target_include_directories(imgui INTERFACE "${IMGUI_DIR}/include") 33 | 34 | target_link_libraries(imgui PUBLIC glfw) 35 | target_link_libraries(imgui PUBLIC ${OPENGL_LIBRARIES}) 36 | -------------------------------------------------------------------------------- /vendor/stb.cpp: -------------------------------------------------------------------------------- 1 | #define STB_IMAGE_IMPLEMENTATION 2 | #include 3 | --------------------------------------------------------------------------------