Mercurial > games > semicongine
comparison README.md @ 1266:9e4dc93d4fa9
did: completely rewrite readme
| author | sam <sam@basx.dev> |
|---|---|
| date | Sun, 28 Jul 2024 22:50:22 +0700 |
| parents | f8974736e446 |
| children | 4cf9872f7bb6 |
comparison
equal
deleted
inserted
replaced
| 1265:51348a4abefc | 1266:9e4dc93d4fa9 |
|---|---|
| 1 Note: If you are reading this on Github, please not that this is only a mirror | 1 Note: If you are reading this on Github, please not that this is only a mirror |
| 2 repository and the default branch is ```hg```. | 2 repository and the newest code is hosted on my mercurial repository at |
| 3 | 3 https://hg.basx.dev/games/semicongine/. |
| 4 Also, some of the README is a bit out of date, as I am now focusing mostly on | |
| 5 writing my first game. However, developement ist onging and the documentation | |
| 6 will be overhauled once I start working on my next game. | |
| 7 | 4 |
| 8 # Semicongine | 5 # Semicongine |
| 9 | 6 |
| 10 Hi there | 7 Hi there |
| 11 | 8 |
| 12 This is a little game engine, mainly trying to wrap around vulkan and the | 9 This is a little game engine, mainly trying to wrap around vulkan and the |
| 13 operating system's windowing, input and audio system. I am using the last | 10 operating system's windowing, input and audio system. I am using the last |
| 14 programming language you will ever need, [Nim](https://nim-lang.org/) | 11 programming language you will ever need, [Nim](https://nim-lang.org/) |
| 15 | 12 |
| 13 ## Features | |
| 14 | |
| 15 The engine currently features the following: | |
| 16 | |
| 17 - No dependencies outside of this repo (except zip/unzip on Linux). All | |
| 18 dependencies are included. | |
| 19 - Low-level, Vulkan-base rendering system | |
| 20 - All vertex/uniform/descriptors/shader-formats, shaders can and must be | |
| 21 defined "freely". The only restriction that we currently have, is that vertex | |
| 22 data is non-interleaved. | |
| 23 - A ton of compiletime checks to ensure the defined mesh-data and shaders are | |
| 24 compatible for rendering | |
| 25 - Simple audio mixer, should suffice for most things | |
| 26 - Simple input-system, no controller support at this time | |
| 27 - Resource packaging of images, audio and 3D files. | |
| 28 - A few additional utils like a simple storage API, a few algorithms for | |
| 29 collision detection, noise generation and texture packing, and a simple | |
| 30 settings API with hot-reloading | |
| 31 | |
| 32 ## Hello world example | |
| 33 | |
| 34 Attention, this project is not optimized for "hello world"-scenarios, so you | |
| 35 have quite a few lines to get something to display: | |
| 36 | |
| 37 ``` | |
| 38 | |
| 39 import semicongine | |
| 40 | |
| 41 # required | |
| 42 InitVulkan() | |
| 43 | |
| 44 # set up a simple render pass to render the displayed frame | |
| 45 var renderpass = CreateDirectPresentationRenderPass(depthBuffer = false, samples = VK_SAMPLE_COUNT_1_BIT) | |
| 46 | |
| 47 # the swapchain, needs to be attached to the main renderpass | |
| 48 SetupSwapchain(renderpass = renderpass) | |
| 49 | |
| 50 # render data is used for memory management on the GPU | |
| 51 var renderdata = InitRenderData() | |
| 52 | |
| 53 type | |
| 54 # define a push constant, to have something moving | |
| 55 PushConstant = object | |
| 56 scale: float32 | |
| 57 # This is how we define shaders: the interface needs to be "typed" | |
| 58 # but the shader code itself can freely be written in glsl | |
| 59 Shader = object | |
| 60 position {.VertexAttribute.}: Vec3f | |
| 61 color {.VertexAttribute.}: Vec3f | |
| 62 pushConstant {.PushConstantAttribute.}: PushConstant | |
| 63 fragmentColor {.Pass.}: Vec3f | |
| 64 outColor {.ShaderOutput.}: Vec4f | |
| 65 # code | |
| 66 vertexCode: string = """void main() { | |
| 67 fragmentColor = color; | |
| 68 gl_Position = vec4(position * pushConstant.scale, 1);}""" | |
| 69 fragmentCode: string = """void main() { | |
| 70 outColor = vec4(fragmentColor, 1);}""" | |
| 71 # And we also need to define our Mesh, which does describe the vertex layout | |
| 72 TriangleMesh = object | |
| 73 position: GPUArray[Vec3f, VertexBuffer] | |
| 74 color: GPUArray[Vec3f, VertexBuffer] | |
| 75 | |
| 76 # instantiate the mesh and fill with data | |
| 77 var mesh = TriangleMesh( | |
| 78 position: asGPUArray([NewVec3f(-0.5, -0.5), NewVec3f(0, 0.5), NewVec3f(0.5, -0.5)], VertexBuffer), | |
| 79 color: asGPUArray([NewVec3f(0, 0, 1), NewVec3f(0, 1, 0), NewVec3f(1, 0, 0)], VertexBuffer), | |
| 80 ) | |
| 81 | |
| 82 # this allocates GPU data, uploads the data to the GPU and flushes any thing that is host-cached | |
| 83 # this is a shortcut version, more fine-grained control is possible | |
| 84 AssignBuffers(renderdata, mesh) | |
| 85 renderdata.FlushAllMemory() | |
| 86 | |
| 87 # Now we need to instantiate the shader as a pipeline object that is attached to a renderpass | |
| 88 var pipeline = CreatePipeline[Shader](renderPass = vulkan.swapchain.renderPass) | |
| 89 | |
| 90 # the main render-loop will exit if we get a kill-signal from the OS | |
| 91 while UpdateInputs(): | |
| 92 | |
| 93 # starts the drawing for the next frame and provides us necesseary framebuffer and commandbuffer objects in this scope | |
| 94 WithNextFrame(framebuffer, commandbuffer): | |
| 95 | |
| 96 # start the main (and only) renderpass we have, needs to know the target framebuffer and a commandbuffer | |
| 97 WithRenderPass(vulkan.swapchain.renderPass, framebuffer, commandbuffer, vulkan.swapchain.width, vulkan.swapchain.height, NewVec4f(0, 0, 0, 0)): | |
| 98 | |
| 99 # now activate our shader-pipeline | |
| 100 WithPipeline(commandbuffer, pipeline): | |
| 101 | |
| 102 # and finally, draw the mesh and set a single parameter | |
| 103 # more complicated setups with descriptors/uniforms are of course possible | |
| 104 RenderWithPushConstant(commandbuffer = commandbuffer, pipeline = pipeline, mesh = mesh, pushConstant = PushConstant(scale: 0.3)) | |
| 105 | |
| 106 # cleanup | |
| 107 checkVkResult vkDeviceWaitIdle(vulkan.device) | |
| 108 DestroyPipeline(pipeline) | |
| 109 DestroyRenderData(renderdata) | |
| 110 vkDestroyRenderPass(vulkan.device, renderpass.vk, nil) | |
| 111 DestroyVulkan() | |
| 112 | |
| 113 ``` | |
| 114 | |
| 16 ## Roadmap | 115 ## Roadmap |
| 17 | 116 |
| 18 Here a bit to see what has been planed and what is done already. Is being | 117 For now all features that I need are implemented. I will gradually add more |
| 19 updated frequently (marking those checkboxes just feels to good to stop working). | 118 stuff that I need, based on the games that I am developing. Here are a few |
| 119 things that I consider integrating at a later point, once I have gather some | |
| 120 more experience what can/should be used across different projects: | |
| 20 | 121 |
| 21 Rendering: | 122 [ ] More support for glTF format (JPEG textures, animations, morphing) |
| 22 | 123 [ ] Maybe some often used utils like camera-controllers, offscreen-rendering, shadow-map rendering, etc. |
| 23 - [x] Vertex attributes, vertex data | 124 [ ] Maybe some UI-stuff |
| 24 - [x] Shaders (allow for predefined and custom shaders) | 125 [ ] Controller support |
| 25 - [x] Uniforms | |
| 26 - [x] Per-instance vertex attributes (required to be able to draw scene graph) | |
| 27 - [x] Fixed framerate | |
| 28 - [x] Instanced drawing (currently can use instance attributes, but we only support a single instance per draw call) | |
| 29 - [x] Textures | |
| 30 - [x] Materials (vertices with material indices) | |
| 31 - [x] Allow different shaders (ie pipelines) for different meshes | |
| 32 | |
| 33 Required for 3D rendering: | |
| 34 | |
| 35 - [ ] Depth buffering | |
| 36 - [ ] Mipmaps | |
| 37 | |
| 38 Asset handling: | |
| 39 | |
| 40 - [x] Resource loading - [x] Mod/resource-pack concept - [x] Load from directory - [x] Load from zip - [x] Load from exe-embeded | |
| 41 - [x] Mesh/material files (glTF, but incomplete, not all features supported) | |
| 42 - [x] Image files (BMP RGBA) | |
| 43 - [x] Audio files (AU) | |
| 44 - [x] API to transform/recalculate mesh data | |
| 45 | |
| 46 Other (required for alpha release): | |
| 47 | |
| 48 - [x] Config files ala \*.ini files (use std/parsecfg) | |
| 49 - [x] Mouse/Keyboard input handling | |
| 50 - [x] X11 | |
| 51 - [x] Win32 | |
| 52 - [x] Enable/disable hardware cursor | |
| 53 - [x] Fullscreen mode + switch between modes - [x] Linux - [x] Window | |
| 54 - [x] Audio playing - [x] Linux - [x] Windows Waveform API | |
| 55 - [ ] Generic configuration concept (engine defaults, per-user, etc) | |
| 56 - [ ] Input-mapping configuration | |
| 57 - [ ] Telemetry | |
| 58 - [x] Add simple event logging service | |
| 59 - [ ] Add exception reporting | |
| 60 | |
| 61 Other important features: | |
| 62 | |
| 63 - [ ] Multisampling | |
| 64 - [x] Text rendering | |
| 65 - [x] Animation system | |
| 66 - [ ] Sprite system | |
| 67 - [ ] Particle system | |
| 68 - [ ] Sound-animation | |
| 69 - [ ] Paletton-export-loader | |
| 70 - [ ] Arrange buffer memory types based on per-mesh-attribute type instead of per-shader-attribute type (possible?) | |
| 71 | |
| 72 Other less important features: | |
| 73 | |
| 74 - [ ] Viewport scaling (e.g. framebuffer resolution != window resolution) | |
| 75 - [ ] Query and display rendering information from Vulkan? | |
| 76 - [ ] Game controller input handling | |
| 77 - [ ] Allow multipel Uniform blocks | |
| 78 - [ ] Documentation | |
| 79 | |
| 80 Quality improvments: | |
| 81 | |
| 82 - [x] Better scenegraph API | |
| 83 - [x] Better rendering pipeline API | |
| 84 | |
| 85 Build-system: | |
| 86 | |
| 87 - [x] move all of Makefile to config.nims | |
| 88 | |
| 89 # Documentation | |
| 90 | |
| 91 Okay, here is first quick-n-dirty documentation, the only purpose to organize my thoughts a bit. | |
| 92 | |
| 93 ## Engine parts | |
| 94 | |
| 95 Currently we have at least the following: | |
| 96 | |
| 97 - Rendering: rendering.nim vulkan/\* | |
| 98 - Scene graph: entity.nim | |
| 99 - Audio: audio.nim audiotypes.nim | |
| 100 - Input: events.nim | |
| 101 - Settings: settings.nim | |
| 102 - Meshes: mesh.nim | |
| 103 - Math: math/\* | |
| 104 - Telemetry: telemetry.nim (wip) | |
| 105 - Resources (loading, mods): resources.nim | |
| 106 | |
| 107 Got you: Everything is wip, but (wip) here means work has not started yet. | |
| 108 | |
| 109 ## Handling of assets | |
| 110 | |
| 111 A short description how I want to handle assets. | |
| 112 | |
| 113 Support for file formats (super limited, no external dependencies, uses quite a bit of space, hoping for zip): | |
| 114 | |
| 115 - Images: BMP | |
| 116 - Audio: AU | |
| 117 - Mesh: glTF (\*.gld) | |
| 118 | |
| 119 In-memory layout of assets (everything needs to be converted to those while loading): | |
| 120 | |
| 121 - Images: 4 channel with each uint8 = 32 bit RGBA, little endian (R is low bits, A is high bits) | |
| 122 - Audio: 2 Channel 16 bit signed little endian, 44100Hz | |
| 123 - Meshes: non-interleaved, lists of values for each vertex, one list per attribute | |
| 124 | |
| 125 ## Configuration | |
| 126 | |
| 127 Or: How to organize s\*\*t that is not code | |
| 128 | |
| 129 Not sure why, but this feels super important to get done right. The engine is | |
| 130 being designed with a library-mindset, not a framework mindset. And with that, | |
| 131 ensuring the configuration of the build, runtime and settings in general | |
| 132 becomes a bit less straight-forward. | |
| 133 | |
| 134 So here is the idea: There are three to four different kinds of configurations | |
| 135 that the engine should be able to handle: | |
| 136 | |
| 137 1. Build configuration: Engine version, project name, log level, etc. | |
| 138 2. Runtime engine/project settings: Video/audio settings, telemetry, log-output, etc. | |
| 139 3. Mods: Different sets of assets and configuration to allow easy testing of different scenarios | |
| 140 4. Save data: Saving world state of the game | |
| 141 | |
| 142 Okay, let's look at each of those and how I plan to implement them: | |
| 143 | |
| 144 **1. Build configuration** | |
| 145 | |
| 146 **2. Runtime settings** | |
| 147 | |
| 148 This is mostly implemented already. I am using the Nim module std/parsecfg. | |
| 149 There is also the option to watch the filesystem and update values at runtime, | |
| 150 mostly usefull for development. | |
| 151 | |
| 152 The engine scans all files in the settings-root directory and builds a | |
| 153 settings tree that can be access via a setting-hierarchy like this: | |
| 154 | |
| 155 setting("a.b.c.d.e") | |
| 156 | |
| 157 `a.b` refers to the settings directory `./a/b/` (from the settings-root) | |
| 158 `c` refers to the file `c.ini` inside `./a/b/` | |
| 159 `d` refers to the ini-section inside the file `./a/b/c.ini` | |
| 160 `e` refers to the key inside section `d` inside the file `./a/b/c.ini` | |
| 161 | |
| 162 `a.b` are optional, they just allow larger configuration trees. | |
| 163 `d` is optional, if it is not give, `e` refers to the top-level section | |
| 164 of the ini-file. | |
| 165 | |
| 166 **3. Mods** | |
| 167 | |
| 168 A mod is just a collection of resources for a game. Can maybe switched from | |
| 169 inside a game. Current mod can be defined via "2. Runtime settings" | |
| 170 | |
| 171 I want to support mods from: | |
| 172 | |
| 173 a) a directory on the filesystem | |
| 174 b) a zip-file on the filesystem | |
| 175 c) a zip-file that is embeded in the executable | |
| 176 | |
| 177 The reasoning is simple: a) is helpfull for development, testing of | |
| 178 new/replaced assets, b) is the default deployment with mod-support and c) is | |
| 179 deployment without mod-support, demo-versions and similar. | |
| 180 | |
| 181 Should not be that difficult but give us everything we ever need in terms of | |
| 182 resource packaging. | |
| 183 | |
| 184 **4. Save data** | |
| 185 | |
| 186 Not too much thought here yet. Maybe we can use Nim's std/marshal module. It | |
| 187 produces JSON from nim objects. Pretty dope, but maybe pretty slow. However, we | |
| 188 are indie-JSON here, not 10M of GTA Online JSON: | |
| 189 https://nee.lv/2021/02/28/How-I-cut-GTA-Online-loading-times-by-70/ |
