| 1 | // Copyright(C) 2022 Lars Pontoppidan. All rights reserved. |
| 2 | // Use of this source code is governed by an MIT license file distributed with this software package |
| 3 | // vtest build: misc-tooling // needs .h files that are produced by `v shader` |
| 4 | module main |
| 5 | |
| 6 | // Example shader triangle adapted to V from https://github.com/floooh/sokol-samples/blob/1f2ad36/sapp/triangle-sapp.c |
| 7 | import sokol.sapp |
| 8 | import sokol.gfx |
| 9 | |
| 10 | // Use `v shader` or `sokol-shdc` to generate the necessary `.h` file |
| 11 | // Using `v shader -v .` in this directory will show some additional |
| 12 | // info - and what you should include to make things work. |
| 13 | #include "@VMODROOT/simple_shader.h" # It should be generated with `v shader .` |
| 14 | |
| 15 | // simple_shader_desc is a C function declaration defined by |
| 16 | // the `@program` entry in the `simple_shader.glsl` shader file. |
| 17 | // When the shader is compiled this function name is generated |
| 18 | // by the shader compiler for easier inclusion of universal shader code |
| 19 | // in C (and V) code. |
| 20 | fn C.simple_shader_desc(gfx.Backend) &gfx.ShaderDesc |
| 21 | |
| 22 | // Vertex_t makes it possible to model vertex buffer data |
| 23 | // for use with the shader system |
| 24 | struct Vertex_t { |
| 25 | // Position |
| 26 | x f32 |
| 27 | y f32 |
| 28 | z f32 |
| 29 | // Color |
| 30 | r f32 |
| 31 | g f32 |
| 32 | b f32 |
| 33 | a f32 |
| 34 | } |
| 35 | |
| 36 | fn main() { |
| 37 | mut app := &App{ |
| 38 | width: 800 |
| 39 | height: 400 |
| 40 | pass_action: gfx.create_clear_pass_action(0.0, 0.0, 0.0, 1.0) // This will create a black color as a default pass (window background color) |
| 41 | } |
| 42 | app.run() |
| 43 | } |
| 44 | |
| 45 | struct App { |
| 46 | pass_action gfx.PassAction |
| 47 | mut: |
| 48 | width int |
| 49 | height int |
| 50 | shader_pipeline gfx.Pipeline |
| 51 | bind gfx.Bindings |
| 52 | } |
| 53 | |
| 54 | fn (mut a App) run() { |
| 55 | title := 'V Simple Shader Example' |
| 56 | desc := sapp.Desc{ |
| 57 | width: a.width |
| 58 | height: a.height |
| 59 | user_data: a |
| 60 | init_userdata_cb: init |
| 61 | frame_userdata_cb: frame |
| 62 | window_title: &char(title.str) |
| 63 | cleanup_userdata_cb: cleanup |
| 64 | sample_count: 4 // Enables MSAA (Multisample anti-aliasing) x4 on rendered output, this can be omitted. |
| 65 | } |
| 66 | sapp.run(&desc) |
| 67 | } |
| 68 | |
| 69 | fn init(user_data voidptr) { |
| 70 | mut app := unsafe { &App(user_data) } |
| 71 | mut desc := sapp.create_desc() |
| 72 | |
| 73 | gfx.setup(&desc) |
| 74 | |
| 75 | // `vertices` defines a vertex buffer with 3 vertices |
| 76 | // with 3 position fields XYZ and 4 color components RGBA - |
| 77 | // for drawing a multi-colored triangle. |
| 78 | // |
| 79 | // C code: |
| 80 | // float vertices[] = { |
| 81 | // // Positions // Colors |
| 82 | // 0.0, 0.5, 0.5, 1.0, 0.0, 0.0, 1.0, |
| 83 | // 0.5, -0.5, 0.5, 0.0, 1.0, 0.0, 1.0, |
| 84 | // -0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 1.0 |
| 85 | // }; |
| 86 | // |
| 87 | // Array entries in the following V code is the equivalent |
| 88 | // of the C code entry described above: |
| 89 | vertices := [ |
| 90 | Vertex_t{0.0, 0.5, 0.5, 1.0, 0.0, 0.0, 1.0}, |
| 91 | Vertex_t{0.5, -0.5, 0.5, 0.0, 1.0, 0.0, 1.0}, |
| 92 | Vertex_t{-0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 1.0}, |
| 93 | ] |
| 94 | |
| 95 | // Create a vertex buffer with the 3 vertices defined above. |
| 96 | mut vertex_buffer_desc := gfx.BufferDesc{ |
| 97 | label: c'triangle-vertices' |
| 98 | } |
| 99 | unsafe { vmemset(&vertex_buffer_desc, 0, int(sizeof(vertex_buffer_desc))) } |
| 100 | |
| 101 | vertex_buffer_desc.size = usize(vertices.len * int(sizeof(Vertex_t))) |
| 102 | vertex_buffer_desc.data = gfx.Range{ |
| 103 | ptr: vertices.data |
| 104 | size: vertex_buffer_desc.size |
| 105 | } |
| 106 | |
| 107 | app.bind.vertex_buffers[0] = gfx.make_buffer(&vertex_buffer_desc) |
| 108 | |
| 109 | // Create shader from the code-generated sg_shader_desc (gfx.ShaderDesc in V). |
| 110 | // Note the function `C.simple_shader_desc()` (also defined above) - this is |
| 111 | // the function that returns the compiled shader code/desciption we have |
| 112 | // written in `simple_shader.glsl` and compiled with `v shader .` (`sokol-shdc`). |
| 113 | shader := gfx.make_shader(voidptr(C.simple_shader_desc(gfx.query_backend()))) |
| 114 | |
| 115 | // Create a pipeline object (default render states are fine for triangle) |
| 116 | mut pipeline_desc := gfx.PipelineDesc{} |
| 117 | // This will zero the memory used to store the pipeline in. |
| 118 | unsafe { vmemset(&pipeline_desc, 0, int(sizeof(pipeline_desc))) } |
| 119 | |
| 120 | // Populate the essential struct fields |
| 121 | pipeline_desc.shader = shader |
| 122 | // The vertex shader (`simple_shader.glsl`) takes 2 inputs: |
| 123 | // ```glsl |
| 124 | // in vec4 position; |
| 125 | // in vec4 color0; |
| 126 | // ``` |
| 127 | // Also note the naming of the C.ATTR_* used as indices. |
| 128 | // They are the prefixed versions of the names of the input variables in the shader code. |
| 129 | // If they change in the shader code they will also change here. |
| 130 | pipeline_desc.layout.attrs[C.ATTR_vs_position].format = .float3 // x,y,z as f32 |
| 131 | pipeline_desc.layout.attrs[C.ATTR_vs_color0].format = .float4 // r, g, b, a as f32 |
| 132 | // The .label is optional but can aid debugging sokol shader related issues |
| 133 | // When things get complex - and you get tired :) |
| 134 | pipeline_desc.label = c'triangle-pipeline' |
| 135 | |
| 136 | app.shader_pipeline = gfx.make_pipeline(&pipeline_desc) |
| 137 | } |
| 138 | |
| 139 | fn cleanup(user_data voidptr) { |
| 140 | gfx.shutdown() |
| 141 | } |
| 142 | |
| 143 | fn frame(user_data voidptr) { |
| 144 | mut app := unsafe { &App(user_data) } |
| 145 | |
| 146 | pass := sapp.create_default_pass(app.pass_action) |
| 147 | gfx.begin_pass(&pass) |
| 148 | |
| 149 | gfx.apply_pipeline(app.shader_pipeline) |
| 150 | gfx.apply_bindings(&app.bind) |
| 151 | |
| 152 | gfx.draw(0, 3, 1) |
| 153 | |
| 154 | gfx.end_pass() |
| 155 | gfx.commit() |
| 156 | } |
| 157 | |