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 = examples.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.storage_buffer) 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 vbufd = { 90 type: sg.BufferType.Storagebuffer, 91 data: 92 { 93 ptr: vertices.ptr, 94 size: vertices.sizeof 95 }, 96 label: "vertices", 97 }; 98 // dfmt on 99 100 state.bind.storage_buffers[shd.SBUF_SSBO] = sg.makeBuffer(vbufd); 101 102 ushort[36] indices = [ 103 0, 1, 2, 0, 2, 3, 104 6, 5, 4, 7, 6, 4, 105 8, 9, 10, 8, 10, 11, 106 14, 13, 12, 15, 14, 12, 107 16, 17, 18, 16, 18, 19, 108 22, 21, 20, 23, 22, 20, 109 ]; 110 111 // dfmt off 112 sg.BufferDesc ibufd = { 113 type: sg.BufferType.Indexbuffer, 114 data: {ptr: indices.ptr, size: indices.sizeof}, 115 }; 116 state.bind.index_buffer = sg.makeBuffer(ibufd); 117 118 sg.PipelineDesc pld = { 119 shader: sg.makeShader(shd.vertexpullShaderDesc(sg.queryBackend())), 120 index_type: sg.IndexType.Uint16, 121 cull_mode: sg.CullMode.Back, 122 depth: { 123 write_enabled: true, 124 compare: sg.CompareFunc.Less_equal 125 }, 126 label: "pipeline" 127 }; 128 // dfmt on 129 state.pip = sg.makePipeline(pld); 130 } 131 132 void frame() 133 { 134 immutable float t = cast(float)(app.frameDuration() * 60.0); 135 136 state.rx += 1.0 * t; 137 state.ry += 2.0 * t; 138 139 shd.VsParams vsParams = {mvp: computeMvp(state.rx, state.ry)}; 140 141 sg.Pass pass = {action: state.passAction, swapchain: sglue.swapchain()}; 142 sg.beginPass(pass); 143 sg.applyPipeline(state.pip); 144 sg.applyBindings(state.bind); 145 sg.Range r = {ptr: &vsParams, size: vsParams.sizeof}; 146 sg.applyUniforms(shd.UB_VS_PARAMS, r); 147 sg.draw(0, 36, 1); 148 sg.endPass(); 149 sg.commit(); 150 } 151 152 void cleanup() 153 { 154 sg.shutdown(); 155 } 156 157 Mat4 computeMvp(float rx, float ry) 158 { 159 immutable proj = Mat4.perspective(60.0, app.widthf() / app.heightf(), 0.01, 10.0); 160 immutable rxm = Mat4.rotate(rx, Vec3(1.0, 0.0, 0.0)); 161 immutable rym = Mat4.rotate(ry, Vec3(0.0, 1.0, 0.0)); 162 immutable model = Mat4.mul(rxm, rym); 163 immutable view_proj = Mat4.mul(proj, state.view()); 164 return Mat4.mul(view_proj, model); 165 } 166 167 // dfmt off 168 void main() 169 { 170 app.Desc runner = { 171 window_title: "vertexpull.d", 172 init_cb: &init, 173 frame_cb: &frame, 174 cleanup_cb: &cleanup, 175 width: 800, 176 height: 600, 177 sample_count: 4, 178 icon: {sokol_default: true}, 179 logger: {func: &log.func} 180 }; 181 app.run(runner); 182 } 183 // dfmt on