Mercurial > games > semicongine
comparison README.md @ 1443:768bf1a8407b
add: hello-triangle example, did: update according readme parts
| author | sam <sam@basx.dev> |
|---|---|
| date | Mon, 24 Feb 2025 10:09:41 +0700 |
| parents | 0f3f2017b054 |
| children |
comparison
equal
deleted
inserted
replaced
| 1442:8d26eb12f6e8 | 1443:768bf1a8407b |
|---|---|
| 33 collision detection, noise generation and texture packing, and a simple | 33 collision detection, noise generation and texture packing, and a simple |
| 34 settings API with hot-reloading | 34 settings API with hot-reloading |
| 35 | 35 |
| 36 ## Wishlist | 36 ## Wishlist |
| 37 | 37 |
| 38 [ ] Macro-based internal DSL to convert Nim code into GLSL/slang at compile time | 38 - Macro-based internal DSL to convert Nim code into GLSL/slang at compile time |
| 39 [ ] Better memory management | 39 - Better memory management |
| 40 - Simple buffer resizing | 40 - Simple buffer resizing |
| 41 - Mechanism to mark unused buffers | 41 - Mechanism to mark unused buffers |
| 42 - Use mapped GPU buffers without copying (implement seq with pointers to GPU memory) | 42 - Use mapped GPU buffers without copying (implement seq with pointers to GPU memory) |
| 43 - Do not keep copy of content for un-mapped buffers around (only pass data on creating or update) | 43 - Do not keep copy of content for un-mapped buffers around (only pass data on creating or update) |
| 44 | 44 |
| 45 ## Hello world example | 45 ## Hello world example |
| 46 | 46 |
| 47 Attention, this project is not optimized for "hello world"-scenarios, so you | 47 Attention, this project is not optimized for "hello world"-scenarios, so you |
| 48 have to write quite a few lines to get something to display: | 48 have to write quite a few lines to get something to display: |
| 49 | 49 |
| 50 ```nim | 50 ```nim |
| 51 | 51 |
| 52 import semicongine | 52 import ../semicongine |
| 53 import ../semicongine/rendering | |
| 54 import ../semicongine/input | |
| 53 | 55 |
| 54 # required | 56 # required |
| 55 InitVulkan() | 57 initEngine("Hello triangle") |
| 56 | 58 |
| 57 # set up a simple render pass to render the displayed frame | 59 # set up a simple render pass to render the displayed frame |
| 58 var renderpass = CreateDirectPresentationRenderPass(depthBuffer = false, samples = VK_SAMPLE_COUNT_1_BIT) | 60 var renderpass = createDirectPresentationRenderPass( |
| 61 depthBuffer = false, samples = VK_SAMPLE_COUNT_1_BIT | |
| 62 ) | |
| 59 | 63 |
| 60 # the swapchain, needs to be attached to the main renderpass | 64 # the swapchain, needs to be attached to the main renderpass |
| 61 SetupSwapchain(renderpass = renderpass) | 65 setupSwapchain(renderpass = renderpass) |
| 62 | 66 |
| 63 # render data is used for memory management on the GPU | 67 # render data is used for memory management on the GPU |
| 64 var renderdata = InitRenderData() | 68 var renderdata = initRenderData() |
| 65 | 69 |
| 66 type | 70 type |
| 67 # define a push constant, to have something moving | 71 # define a push constant, to have something moving |
| 68 PushConstant = object | 72 PushConstant = object |
| 69 scale: float32 | 73 scale: float32 |
| 74 | |
| 70 # This is how we define shaders: the interface needs to be "typed" | 75 # This is how we define shaders: the interface needs to be "typed" |
| 71 # but the shader code itself can freely be written in glsl | 76 # but the shader code itself can freely be written in glsl |
| 72 Shader = object | 77 Shader = object |
| 73 position {.VertexAttribute.}: Vec3f | 78 position {.VertexAttribute.}: Vec3f |
| 74 color {.VertexAttribute.}: Vec3f | 79 color {.VertexAttribute.}: Vec3f |
| 75 pushConstant {.PushConstantAttribute.}: PushConstant | 80 pushConstant {.PushConstant.}: PushConstant |
| 76 fragmentColor {.Pass.}: Vec3f | 81 fragmentColor {.Pass.}: Vec3f |
| 77 outColor {.ShaderOutput.}: Vec4f | 82 outColor {.ShaderOutput.}: Vec4f |
| 78 # code | 83 # code |
| 79 vertexCode: string = """void main() { | 84 vertexCode: string = |
| 85 """void main() { | |
| 80 fragmentColor = color; | 86 fragmentColor = color; |
| 81 gl_Position = vec4(position * pushConstant.scale, 1);}""" | 87 gl_Position = vec4(position * pushConstant.scale, 1);}""" |
| 82 fragmentCode: string = """void main() { | 88 fragmentCode: string = |
| 89 """void main() { | |
| 83 outColor = vec4(fragmentColor, 1);}""" | 90 outColor = vec4(fragmentColor, 1);}""" |
| 91 | |
| 84 # And we also need to define our Mesh, which does describe the vertex layout | 92 # And we also need to define our Mesh, which does describe the vertex layout |
| 85 TriangleMesh = object | 93 TriangleMesh = object |
| 86 position: GPUArray[Vec3f, VertexBuffer] | 94 position: GPUArray[Vec3f, VertexBuffer] |
| 87 color: GPUArray[Vec3f, VertexBuffer] | 95 color: GPUArray[Vec3f, VertexBuffer] |
| 88 | 96 |
| 89 # instantiate the mesh and fill with data | 97 # instantiate the mesh and fill with data |
| 90 var mesh = TriangleMesh( | 98 var mesh = TriangleMesh( |
| 91 position: asGPUArray([NewVec3f(-0.5, -0.5), NewVec3f(0, 0.5), NewVec3f(0.5, -0.5)], VertexBuffer), | 99 position: asGPUArray([vec3(-0.5, -0.5), vec3(0, 0.5), vec3(0.5, -0.5)], VertexBuffer), |
| 92 color: asGPUArray([NewVec3f(0, 0, 1), NewVec3f(0, 1, 0), NewVec3f(1, 0, 0)], VertexBuffer), | 100 color: asGPUArray([vec3(0, 0, 1), vec3(0, 1, 0), vec3(1, 0, 0)], VertexBuffer), |
| 93 ) | 101 ) |
| 94 | 102 |
| 95 # this allocates GPU data, uploads the data to the GPU and flushes any thing that is host-cached | 103 # this allocates GPU data, uploads the data to the GPU and flushes any thing that is host-cached |
| 96 # this is a shortcut version, more fine-grained control is possible | 104 # this is a shortcut version, more fine-grained control is possible |
| 97 AssignBuffers(renderdata, mesh) | 105 assignBuffers(renderdata, mesh) |
| 98 renderdata.FlushAllMemory() | 106 renderdata.flushAllMemory() |
| 99 | 107 |
| 100 # Now we need to instantiate the shader as a pipeline object that is attached to a renderpass | 108 # Now we need to instantiate the shader as a pipeline object that is attached to a renderpass |
| 101 var pipeline = CreatePipeline[Shader](renderPass = vulkan.swapchain.renderPass) | 109 var pipeline = createPipeline(Shader(), renderPass = renderPass) |
| 102 | 110 |
| 103 # the main render-loop will exit if we get a kill-signal from the OS | 111 # the main render-loop will exit if we get a kill-signal from the OS |
| 104 while UpdateInputs(): | 112 while updateInputs(): |
| 105 | |
| 106 # starts the drawing for the next frame and provides us necesseary framebuffer and commandbuffer objects in this scope | 113 # starts the drawing for the next frame and provides us necesseary framebuffer and commandbuffer objects in this scope |
| 107 WithNextFrame(framebuffer, commandbuffer): | 114 withNextFrame(framebuffer, commandbuffer): |
| 108 | |
| 109 # start the main (and only) renderpass we have, needs to know the target framebuffer and a commandbuffer | 115 # start the main (and only) renderpass we have, needs to know the target framebuffer and a commandbuffer |
| 110 WithRenderPass(vulkan.swapchain.renderPass, framebuffer, commandbuffer, vulkan.swapchain.width, vulkan.swapchain.height, NewVec4f(0, 0, 0, 0)): | 116 withRenderPass( |
| 111 | 117 renderPass, |
| 118 framebuffer, | |
| 119 commandbuffer, | |
| 120 frameWidth(), | |
| 121 frameHeight(), | |
| 122 vec4(0, 0, 0, 0), | |
| 123 ): | |
| 112 # now activate our shader-pipeline | 124 # now activate our shader-pipeline |
| 113 WithPipeline(commandbuffer, pipeline): | 125 withPipeline(commandbuffer, pipeline): |
| 114 | |
| 115 # and finally, draw the mesh and set a single parameter | 126 # and finally, draw the mesh and set a single parameter |
| 116 # more complicated setups with descriptors/uniforms are of course possible | 127 # more complicated setups with descriptors/uniforms are of course possible |
| 117 RenderWithPushConstant(commandbuffer = commandbuffer, pipeline = pipeline, mesh = mesh, pushConstant = PushConstant(scale: 0.3)) | 128 renderWithPushConstant( |
| 129 commandbuffer = commandbuffer, | |
| 130 pipeline = pipeline, | |
| 131 mesh = mesh, | |
| 132 pushConstant = PushConstant(scale: 0.3), | |
| 133 ) | |
| 118 | 134 |
| 119 # cleanup | 135 # cleanup |
| 120 checkVkResult vkDeviceWaitIdle(vulkan.device) | 136 checkVkResult vkDeviceWaitIdle(engine().vulkan.device) |
| 121 DestroyPipeline(pipeline) | 137 destroyPipeline(pipeline) |
| 122 DestroyRenderData(renderdata) | 138 destroyRenderData(renderdata) |
| 123 vkDestroyRenderPass(vulkan.device, renderpass.vk, nil) | 139 destroyRenderPass(renderpass) |
| 124 DestroyVulkan() | 140 destroyVulkan() |
| 125 | 141 |
| 126 ``` | 142 ``` |
| 127 | 143 |
| 128 ## Future development | 144 ## Future development |
| 129 | 145 |
