comparison README.md @ 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 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