1 //------------------------------------------------------------------------------ 2 // vertexpull.d 3 // 4 // Pull vertices from a storage buffer instead of using fixed-function 5 // vertex input. 6 //------------------------------------------------------------------------------ 7 module examples.vertexpull; 8 9 private: 10 11 import sg = sokol.gfx; 12 import app = sokol.app; 13 import log = sokol.log; 14 import handmade.math : Mat4, Vec3; 15 import sglue = sokol.glue; 16 import shd = shaders.vertexpull; 17 18 extern (C): 19 @safe: 20 21 struct State 22 { 23 float rx = 0; 24 float ry = 0; 25 26 sg.Pipeline pip; 27 sg.Bindings bind; 28 sg.PassAction passAction = {}; 29 30 Mat4 view() 31 { 32 return Mat4.lookAt(Vec3(0.0, 1.5, 6.0), Vec3.zero(), Vec3.up()); 33 } 34 } 35 36 static State state; 37 38 void init() 39 { 40 sg.Desc gfxd = {environment: sglue.environment, 41 logger: {func: &log.func}}; 42 sg.setup(gfxd); 43 44 // if storage buffers are not supported on the current backend, just render a red screen 45 if (!sg.queryFeatures.compute) 46 { 47 state.passAction.colors[0].load_action = sg.LoadAction.Clear; 48 state.passAction.colors[0].clear_value.r = 1.0; 49 state.passAction.colors[0].clear_value.g = 0.0; 50 state.passAction.colors[0].clear_value.b = 0.0; 51 state.passAction.colors[0].clear_value.a = 1.0; 52 return; 53 } 54 // otherwise set regular clear color 55 state.passAction.colors[0].load_action = sg.LoadAction.Clear; 56 state.passAction.colors[0].clear_value.r = 0.75; 57 state.passAction.colors[0].clear_value.g = 0.5; 58 state.passAction.colors[0].clear_value.b = 0.25; 59 state.passAction.colors[0].clear_value.a = 1.0; 60 61 shd.SbVertex[24] vertices = [ 62 {pos: [-1.0, -1.0, -1.0], color: [1.0, 0.0, 0.0, 1.0]}, 63 {pos: [1.0, -1.0, -1.0], color: [1.0, 0.0, 0.0, 1.0]}, 64 {pos: [1.0, 1.0, -1.0], color: [1.0, 0.0, 0.0, 1.0]}, 65 {pos: [-1.0, 1.0, -1.0], color: [1.0, 0.0, 0.0, 1.0]}, 66 {pos: [-1.0, -1.0, 1.0], color: [0.0, 1.0, 0.0, 1.0]}, 67 {pos: [1.0, -1.0, 1.0], color: [0.0, 1.0, 0.0, 1.0]}, 68 {pos: [1.0, 1.0, 1.0], color: [0.0, 1.0, 0.0, 1.0]}, 69 {pos: [-1.0, 1.0, 1.0], color: [0.0, 1.0, 0.0, 1.0]}, 70 {pos: [-1.0, -1.0, -1.0], color: [0.0, 0.0, 1.0, 1.0]}, 71 {pos: [-1.0, 1.0, -1.0], color: [0.0, 0.0, 1.0, 1.0]}, 72 {pos: [-1.0, 1.0, 1.0], color: [0.0, 0.0, 1.0, 1.0]}, 73 {pos: [-1.0, -1.0, 1.0], color: [0.0, 0.0, 1.0, 1.0]}, 74 {pos: [1.0, -1.0, -1.0], color: [1.0, 0.5, 0.0, 1.0]}, 75 {pos: [1.0, 1.0, -1.0], color: [1.0, 0.5, 0.0, 1.0]}, 76 {pos: [1.0, 1.0, 1.0], color: [1.0, 0.5, 0.0, 1.0]}, 77 {pos: [1.0, -1.0, 1.0], color: [1.0, 0.5, 0.0, 1.0]}, 78 {pos: [-1.0, -1.0, -1.0], color: [0.0, 0.5, 1.0, 1.0]}, 79 {pos: [-1.0, -1.0, 1.0], color: [0.0, 0.5, 1.0, 1.0]}, 80 {pos: [1.0, -1.0, 1.0], color: [0.0, 0.5, 1.0, 1.0]}, 81 {pos: [1.0, -1.0, -1.0], color: [0.0, 0.5, 1.0, 1.0]}, 82 {pos: [-1.0, 1.0, -1.0], color: [1.0, 0.0, 0.5, 1.0]}, 83 {pos: [-1.0, 1.0, 1.0], color: [1.0, 0.0, 0.5, 1.0]}, 84 {pos: [1.0, 1.0, 1.0], color: [1.0, 0.0, 0.5, 1.0]}, 85 {pos: [1.0, 1.0, -1.0], color: [1.0, 0.0, 0.5, 1.0]}, 86 ]; 87 88 // dfmt off 89 sg.BufferDesc sbuf_desc = { 90 usage: { storage_buffer: true }, 91 data: 92 { 93 ptr: vertices.ptr, 94 size: vertices.sizeof 95 }, 96 label: "vertices", 97 }; 98 // dfmt on 99 auto sbuf = sg.makeBuffer(sbuf_desc); 100 sg.ViewDesc sbuf_view_desc = { 101 storage_buffer: { buffer: sbuf }, 102 }; 103 state.bind.views[shd.VIEW_SSBO] = sg.makeView(sbuf_view_desc); 104 105 ushort[36] indices = [ 106 0, 1, 2, 0, 2, 3, 107 6, 5, 4, 7, 6, 4, 108 8, 9, 10, 8, 10, 11, 109 14, 13, 12, 15, 14, 12, 110 16, 17, 18, 16, 18, 19, 111 22, 21, 20, 23, 22, 20, 112 ]; 113 114 // dfmt off 115 sg.BufferDesc ibufd = { 116 usage: { index_buffer: true }, 117 data: {ptr: indices.ptr, size: indices.sizeof}, 118 }; 119 state.bind.index_buffer = sg.makeBuffer(ibufd); 120 121 sg.PipelineDesc pld = { 122 shader: sg.makeShader(shd.vertexpullShaderDesc(sg.queryBackend())), 123 index_type: sg.IndexType.Uint16, 124 cull_mode: sg.CullMode.Back, 125 depth: { 126 write_enabled: true, 127 compare: sg.CompareFunc.Less_equal 128 }, 129 label: "pipeline" 130 }; 131 // dfmt on 132 state.pip = sg.makePipeline(pld); 133 } 134 135 void frame() 136 { 137 immutable float t = cast(float)(app.frameDuration() * 60.0); 138 139 state.rx += 1.0 * t; 140 state.ry += 2.0 * t; 141 142 shd.VsParams vsParams = {mvp: computeMvp(state.rx, state.ry)}; 143 144 sg.Pass pass = {action: state.passAction, swapchain: sglue.swapchain()}; 145 sg.beginPass(pass); 146 sg.applyPipeline(state.pip); 147 sg.applyBindings(state.bind); 148 sg.Range r = {ptr: &vsParams, size: vsParams.sizeof}; 149 sg.applyUniforms(shd.UB_VS_PARAMS, r); 150 sg.draw(0, 36, 1); 151 sg.endPass(); 152 sg.commit(); 153 } 154 155 void cleanup() 156 { 157 sg.shutdown(); 158 } 159 160 Mat4 computeMvp(float rx, float ry) 161 { 162 immutable proj = Mat4.perspective(60.0, app.widthf() / app.heightf(), 0.01, 10.0); 163 immutable rxm = Mat4.rotate(rx, Vec3(1.0, 0.0, 0.0)); 164 immutable rym = Mat4.rotate(ry, Vec3(0.0, 1.0, 0.0)); 165 immutable model = Mat4.mul(rxm, rym); 166 immutable view_proj = Mat4.mul(proj, state.view()); 167 return Mat4.mul(view_proj, model); 168 } 169 170 // dfmt off 171 void main() 172 { 173 app.Desc runner = { 174 window_title: "vertexpull.d", 175 init_cb: &init, 176 frame_cb: &frame, 177 cleanup_cb: &cleanup, 178 width: 800, 179 height: 600, 180 sample_count: 4, 181 icon: {sokol_default: true}, 182 logger: {func: &log.func} 183 }; 184 app.run(runner); 185 } 186 // dfmt on 187 188 version (WebAssembly) 189 { 190 debug 191 { 192 import emscripten.assertd; 193 } 194 }