v2 / examples / sokol / 07_simple_shader_glsl / simple_shader.v
156 lines · 133 sloc · 4.89 KB · 12c7816c5844852e71628b0360ffec8d6d731545
Raw
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`
4module main
5
6// Example shader triangle adapted to V from https://github.com/floooh/sokol-samples/blob/1f2ad36/sapp/triangle-sapp.c
7import sokol.sapp
8import 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.
20fn 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
24struct 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
36fn 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
45struct App {
46 pass_action gfx.PassAction
47mut:
48 width int
49 height int
50 shader_pipeline gfx.Pipeline
51 bind gfx.Bindings
52}
53
54fn (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
69fn 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
139fn cleanup(user_data voidptr) {
140 gfx.shutdown()
141}
142
143fn 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