changeset 1443:768bf1a8407b default tip main

add: hello-triangle example, did: update according readme parts
author sam <sam@basx.dev>
date Mon, 24 Feb 2025 10:09:41 +0700
parents 8d26eb12f6e8
children
files README.md tests/hello_triangle.nim
diffstat 2 files changed, 138 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/README.md	Sun Feb 16 23:12:32 2025 +0700
+++ b/README.md	Mon Feb 24 10:09:41 2025 +0700
@@ -35,12 +35,12 @@
 
 ## Wishlist
 
-[ ] Macro-based internal DSL to convert Nim code into GLSL/slang at compile time
-[ ] Better memory management
-    - Simple buffer resizing
-    - Mechanism to mark unused buffers
-    - Use mapped GPU buffers without copying (implement seq with pointers to GPU memory)
-    - Do not keep copy of content for un-mapped buffers around (only pass data on creating or update)
+- Macro-based internal DSL to convert Nim code into GLSL/slang at compile time
+- Better memory management
+  - Simple buffer resizing
+  - Mechanism to mark unused buffers
+  - Use mapped GPU buffers without copying (implement seq with pointers to GPU memory)
+  - Do not keep copy of content for un-mapped buffers around (only pass data on creating or update)
 
 ## Hello world example
 
@@ -49,38 +49,46 @@
 
 ```nim
 
-import semicongine
+import ../semicongine
+import ../semicongine/rendering
+import ../semicongine/input
 
 # required
-InitVulkan()
+initEngine("Hello triangle")
 
 # set up a simple render pass to render the displayed frame
-var renderpass = CreateDirectPresentationRenderPass(depthBuffer = false, samples = VK_SAMPLE_COUNT_1_BIT)
+var renderpass = createDirectPresentationRenderPass(
+  depthBuffer = false, samples = VK_SAMPLE_COUNT_1_BIT
+)
 
 # the swapchain, needs to be attached to the main renderpass
-SetupSwapchain(renderpass = renderpass)
+setupSwapchain(renderpass = renderpass)
 
 # render data is used for memory management on the GPU
-var renderdata = InitRenderData()
+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
+    pushConstant {.PushConstant.}: PushConstant
     fragmentColor {.Pass.}: Vec3f
     outColor {.ShaderOutput.}: Vec4f
     # code
-    vertexCode: string = """void main() {
+    vertexCode: string =
+      """void main() {
     fragmentColor = color;
     gl_Position = vec4(position * pushConstant.scale, 1);}"""
-    fragmentCode: string = """void main() {
+    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]
@@ -88,40 +96,48 @@
 
 # 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),
+  position: asGPUArray([vec3(-0.5, -0.5), vec3(0, 0.5), vec3(0.5, -0.5)], VertexBuffer),
+  color: asGPUArray([vec3(0, 0, 1), vec3(0, 1, 0), vec3(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()
+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)
+var pipeline = createPipeline(Shader(), renderPass = renderPass)
 
 # the main render-loop will exit if we get a kill-signal from the OS
-while UpdateInputs():
-
+while updateInputs():
   # starts the drawing for the next frame and provides us necesseary framebuffer and commandbuffer objects in this scope
-  WithNextFrame(framebuffer, commandbuffer):
-
+  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)):
-
+    withRenderPass(
+      renderPass,
+      framebuffer,
+      commandbuffer,
+      frameWidth(),
+      frameHeight(),
+      vec4(0, 0, 0, 0),
+    ):
       # now activate our shader-pipeline
-      WithPipeline(commandbuffer, 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))
+        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()
+checkVkResult vkDeviceWaitIdle(engine().vulkan.device)
+destroyPipeline(pipeline)
+destroyRenderData(renderdata)
+destroyRenderPass(renderpass)
+destroyVulkan()
 
 ```
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/hello_triangle.nim	Mon Feb 24 10:09:41 2025 +0700
@@ -0,0 +1,89 @@
+import ../semicongine
+import ../semicongine/rendering
+import ../semicongine/input
+
+# required
+initEngine("Hello triangle")
+
+# 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 {.PushConstant.}: 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([vec3(-0.5, -0.5), vec3(0, 0.5), vec3(0.5, -0.5)], VertexBuffer),
+  color: asGPUArray([vec3(0, 0, 1), vec3(0, 1, 0), vec3(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 = 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(
+      renderPass,
+      framebuffer,
+      commandbuffer,
+      frameWidth(),
+      frameHeight(),
+      vec4(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(engine().vulkan.device)
+destroyPipeline(pipeline)
+destroyRenderData(renderdata)
+destroyRenderPass(renderpass)
+destroyVulkan()