diff 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
line wrap: on
line diff
--- a/README.md	Sun Jul 28 21:59:22 2024 +0700
+++ b/README.md	Sun Jul 28 22:50:22 2024 +0700
@@ -1,9 +1,6 @@
 Note: If you are reading this on Github, please not that this is only a mirror
-repository and the default branch is ```hg```.
-
-Also, some of the README is a bit out of date, as I am now focusing mostly on
-writing my first game. However, developement ist onging and the documentation
-will be overhauled once I start working on my next game.
+repository and the newest code is hosted on my mercurial repository at
+https://hg.basx.dev/games/semicongine/.
 
 # Semicongine
 
@@ -13,177 +10,116 @@
 operating system's windowing, input and audio system. I am using the last
 programming language you will ever need, [Nim](https://nim-lang.org/)
 
+## Features
+
+The engine currently features the following:
+
+- No dependencies outside of this repo (except zip/unzip on Linux). All
+  dependencies are included.
+- Low-level, Vulkan-base rendering system
+- All vertex/uniform/descriptors/shader-formats, shaders can and must be
+  defined "freely". The only restriction that we currently have, is that vertex
+  data is non-interleaved.
+- A ton of compiletime checks to ensure the defined mesh-data and shaders are
+  compatible for rendering
+- Simple audio mixer, should suffice for most things
+- Simple input-system, no controller support at this time
+- Resource packaging of images, audio and 3D files.
+- A few additional utils like a simple storage API, a few algorithms for
+  collision detection, noise generation and texture packing, and a simple
+  settings API with hot-reloading
+
+## Hello world example
+
+Attention, this project is not optimized for "hello world"-scenarios, so you
+have quite a few lines to get something to display:
+
+```
+
+import semicongine
+
+# required
+InitVulkan()
+
+# set up a simple render pass to render the displayed frame
+var renderpass = CreateDirectPresentationRenderPass(depthBuffer = false, samples = VK_SAMPLE_COUNT_1_BIT)
+
+# the swapchain, needs to be attached to the main renderpass
+SetupSwapchain(renderpass = renderpass)
+
+# render data is used for memory management on the GPU
+var renderdata = InitRenderData()
+
+type
+  # define a push constant, to have something moving
+  PushConstant = object
+    scale: float32
+  # This is how we define shaders: the interface needs to be "typed"
+  # but the shader code itself can freely be written in glsl
+  Shader = object
+    position {.VertexAttribute.}: Vec3f
+    color {.VertexAttribute.}: Vec3f
+    pushConstant {.PushConstantAttribute.}: PushConstant
+    fragmentColor {.Pass.}: Vec3f
+    outColor {.ShaderOutput.}: Vec4f
+    # code
+    vertexCode: string = """void main() {
+    fragmentColor = color;
+    gl_Position = vec4(position * pushConstant.scale, 1);}"""
+    fragmentCode: string = """void main() {
+    outColor = vec4(fragmentColor, 1);}"""
+  # And we also need to define our Mesh, which does describe the vertex layout
+  TriangleMesh = object
+    position: GPUArray[Vec3f, VertexBuffer]
+    color: GPUArray[Vec3f, VertexBuffer]
+
+# instantiate the mesh and fill with data
+var mesh = TriangleMesh(
+  position: asGPUArray([NewVec3f(-0.5, -0.5), NewVec3f(0, 0.5), NewVec3f(0.5, -0.5)], VertexBuffer),
+  color: asGPUArray([NewVec3f(0, 0, 1), NewVec3f(0, 1, 0), NewVec3f(1, 0, 0)], VertexBuffer),
+)
+
+# this allocates GPU data, uploads the data to the GPU and flushes any thing that is host-cached
+# this is a shortcut version, more fine-grained control is possible
+AssignBuffers(renderdata, mesh)
+renderdata.FlushAllMemory()
+
+# Now we need to instantiate the shader as a pipeline object that is attached to a renderpass
+var pipeline = CreatePipeline[Shader](renderPass = vulkan.swapchain.renderPass)
+
+# the main render-loop will exit if we get a kill-signal from the OS
+while UpdateInputs():
+
+  # starts the drawing for the next frame and provides us necesseary framebuffer and commandbuffer objects in this scope
+  WithNextFrame(framebuffer, commandbuffer):
+
+    # start the main (and only) renderpass we have, needs to know the target framebuffer and a commandbuffer
+    WithRenderPass(vulkan.swapchain.renderPass, framebuffer, commandbuffer, vulkan.swapchain.width, vulkan.swapchain.height, NewVec4f(0, 0, 0, 0)):
+
+      # now activate our shader-pipeline
+      WithPipeline(commandbuffer, pipeline):
+
+        # and finally, draw the mesh and set a single parameter
+        # more complicated setups with descriptors/uniforms are of course possible
+        RenderWithPushConstant(commandbuffer = commandbuffer, pipeline = pipeline, mesh = mesh, pushConstant = PushConstant(scale: 0.3))
+
+# cleanup
+checkVkResult vkDeviceWaitIdle(vulkan.device)
+DestroyPipeline(pipeline)
+DestroyRenderData(renderdata)
+vkDestroyRenderPass(vulkan.device, renderpass.vk, nil)
+DestroyVulkan()
+
+```
+
 ## Roadmap
 
-Here a bit to see what has been planed and what is done already. Is being
-updated frequently (marking those checkboxes just feels to good to stop working).
-
-Rendering:
-
-- [x] Vertex attributes, vertex data
-- [x] Shaders (allow for predefined and custom shaders)
-- [x] Uniforms
-- [x] Per-instance vertex attributes (required to be able to draw scene graph)
-- [x] Fixed framerate
-- [x] Instanced drawing (currently can use instance attributes, but we only support a single instance per draw call)
-- [x] Textures
-- [x] Materials (vertices with material indices)
-- [x] Allow different shaders (ie pipelines) for different meshes
-
-Required for 3D rendering:
-
-- [ ] Depth buffering
-- [ ] Mipmaps
-
-Asset handling:
-
-- [x] Resource loading - [x] Mod/resource-pack concept - [x] Load from directory - [x] Load from zip - [x] Load from exe-embeded
-- [x] Mesh/material files (glTF, but incomplete, not all features supported)
-- [x] Image files (BMP RGBA)
-- [x] Audio files (AU)
-- [x] API to transform/recalculate mesh data
-
-Other (required for alpha release):
-
-- [x] Config files ala \*.ini files (use std/parsecfg)
-- [x] Mouse/Keyboard input handling
-  - [x] X11
-  - [x] Win32
-- [x] Enable/disable hardware cursor
-- [x] Fullscreen mode + switch between modes - [x] Linux - [x] Window
-- [x] Audio playing - [x] Linux - [x] Windows Waveform API
-- [ ] Generic configuration concept (engine defaults, per-user, etc)
-- [ ] Input-mapping configuration
-- [ ] Telemetry
-  - [x] Add simple event logging service
-  - [ ] Add exception reporting
-
-Other important features:
-
-- [ ] Multisampling
-- [x] Text rendering
-- [x] Animation system
-- [ ] Sprite system
-- [ ] Particle system
-- [ ] Sound-animation
-- [ ] Paletton-export-loader
-- [ ] Arrange buffer memory types based on per-mesh-attribute type instead of per-shader-attribute type (possible?)
-
-Other less important features:
-
-- [ ] Viewport scaling (e.g. framebuffer resolution != window resolution)
-- [ ] Query and display rendering information from Vulkan?
-- [ ] Game controller input handling
-- [ ] Allow multipel Uniform blocks
-- [ ] Documentation
-
-Quality improvments:
-
-- [x] Better scenegraph API
-- [x] Better rendering pipeline API
-
-Build-system:
-
-- [x] move all of Makefile to config.nims
-
-# Documentation
-
-Okay, here is first quick-n-dirty documentation, the only purpose to organize my thoughts a bit.
-
-## Engine parts
-
-Currently we have at least the following:
+For now all features that I need are implemented. I will gradually add more
+stuff that I need, based on the games that I am developing. Here are a few
+things that I consider integrating at a later point, once I have gather some
+more experience what can/should be used across different projects:
 
-- Rendering: rendering.nim vulkan/\*
-- Scene graph: entity.nim
-- Audio: audio.nim audiotypes.nim
-- Input: events.nim
-- Settings: settings.nim
-- Meshes: mesh.nim
-- Math: math/\*
-- Telemetry: telemetry.nim (wip)
-- Resources (loading, mods): resources.nim
-
-Got you: Everything is wip, but (wip) here means work has not started yet.
-
-## Handling of assets
-
-A short description how I want to handle assets.
-
-Support for file formats (super limited, no external dependencies, uses quite a bit of space, hoping for zip):
-
-- Images: BMP
-- Audio: AU
-- Mesh: glTF (\*.gld)
-
-In-memory layout of assets (everything needs to be converted to those while loading):
-
-- Images: 4 channel with each uint8 = 32 bit RGBA, little endian (R is low bits, A is high bits)
-- Audio: 2 Channel 16 bit signed little endian, 44100Hz
-- Meshes: non-interleaved, lists of values for each vertex, one list per attribute
-
-## Configuration
-
-Or: How to organize s\*\*t that is not code
-
-Not sure why, but this feels super important to get done right. The engine is
-being designed with a library-mindset, not a framework mindset. And with that,
-ensuring the configuration of the build, runtime and settings in general
-becomes a bit less straight-forward.
-
-So here is the idea: There are three to four different kinds of configurations
-that the engine should be able to handle:
-
-1. Build configuration: Engine version, project name, log level, etc.
-2. Runtime engine/project settings: Video/audio settings, telemetry, log-output, etc.
-3. Mods: Different sets of assets and configuration to allow easy testing of different scenarios
-4. Save data: Saving world state of the game
-
-Okay, let's look at each of those and how I plan to implement them:
-
-**1. Build configuration**
-
-**2. Runtime settings**
-
-This is mostly implemented already. I am using the Nim module std/parsecfg.
-There is also the option to watch the filesystem and update values at runtime,
-mostly usefull for development.
-
-The engine scans all files in the settings-root directory and builds a
-settings tree that can be access via a setting-hierarchy like this:
-
-    setting("a.b.c.d.e")
-
-`a.b` refers to the settings directory `./a/b/` (from the settings-root)
-`c` refers to the file `c.ini` inside `./a/b/`
-`d` refers to the ini-section inside the file `./a/b/c.ini`
-`e` refers to the key inside section `d` inside the file `./a/b/c.ini`
-
-`a.b` are optional, they just allow larger configuration trees.
-`d` is optional, if it is not give, `e` refers to the top-level section
-of the ini-file.
-
-**3. Mods**
-
-A mod is just a collection of resources for a game. Can maybe switched from
-inside a game. Current mod can be defined via "2. Runtime settings"
-
-I want to support mods from:
-
-a) a directory on the filesystem
-b) a zip-file on the filesystem
-c) a zip-file that is embeded in the executable
-
-The reasoning is simple: a) is helpfull for development, testing of
-new/replaced assets, b) is the default deployment with mod-support and c) is
-deployment without mod-support, demo-versions and similar.
-
-Should not be that difficult but give us everything we ever need in terms of
-resource packaging.
-
-**4. Save data**
-
-Not too much thought here yet. Maybe we can use Nim's std/marshal module. It
-produces JSON from nim objects. Pretty dope, but maybe pretty slow. However, we
-are indie-JSON here, not 10M of GTA Online JSON:
-https://nee.lv/2021/02/28/How-I-cut-GTA-Online-loading-times-by-70/
+[ ] More support for glTF format (JPEG textures, animations, morphing)
+[ ] Maybe some often used utils like camera-controllers, offscreen-rendering, shadow-map rendering, etc.
+[ ] Maybe some UI-stuff
+[ ] Controller support