1 //------------------------------------------------------------------------------ 2 // noninterleaved.d 3 // 4 // How to use non-interleaved vertex data (vertex components in 5 // separate non-interleaved chunks in the same vertex buffers). Note 6 // that only 4 separate chunks are currently possible because there 7 // are 4 vertex buffer bind slots in sg_bindings, but you can keep 8 // several related vertex components interleaved in the same chunk. 9 //------------------------------------------------------------------------------ 10 module examples.noninterleaved; 11 12 private: 13 14 import sg = sokol.gfx; 15 import app = sokol.app; 16 import log = sokol.log; 17 import handmade.math : Mat4, Vec3; 18 import sglue = sokol.glue; 19 import shd = examples.shaders.noninterleaved; 20 21 extern (C): 22 @safe: 23 24 struct State 25 { 26 float rx = 0; 27 float ry = 0; 28 29 sg.Pipeline pip; 30 sg.Bindings bind; 31 sg.PassAction passAction = {}; 32 33 Mat4 view() 34 { 35 return Mat4.lookAt(Vec3(0.0, 1.5, 6.0), Vec3.zero(), Vec3.up()); 36 } 37 } 38 39 static State state; 40 41 void init() 42 { 43 sg.Desc gfxd = {environment: sglue.environment, 44 logger: {func: &log.func}}; 45 sg.setup(gfxd); 46 47 float[168] vertices = [ 48 // positions 49 -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 50 -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 51 -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 52 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 53 -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 54 -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 55 // colors 56 1.0, 0.5, 0.0, 1.0, 1.0, 0.5, 0.0, 1.0, 1.0, 0.5, 0.0, 1.0, 57 1.0, 0.5, 0.0, 1.0, 0.5, 1.0, 0.0, 1.0, 0.5, 1.0, 0.0, 1.0, 58 0.5, 1.0, 0.0, 1.0, 0.5, 1.0, 0.0, 1.0, 0.5, 0.0, 1.0, 1.0, 59 0.5, 0.0, 1.0, 1.0, 0.5, 0.0, 1.0, 1.0, 0.5, 0.0, 1.0, 1.0, 60 1.0, 0.5, 1.0, 1.0, 1.0, 0.5, 1.0, 1.0, 1.0, 0.5, 1.0, 1.0, 61 1.0, 0.5, 1.0, 1.0, 0.5, 1.0, 1.0, 1.0, 0.5, 1.0, 1.0, 1.0, 62 0.5, 1.0, 1.0, 1.0, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 0.5, 1.0, 63 1.0, 1.0, 0.5, 1.0, 1.0, 1.0, 0.5, 1.0, 1.0, 1.0, 0.5, 1.0, 64 ]; 65 66 // dfmt off 67 sg.BufferDesc vbufd = { 68 data: 69 { 70 ptr: vertices.ptr, 71 size: vertices.sizeof 72 }, 73 label: "vertices", 74 }; 75 // dfmt on 76 77 ushort[36] indices = [ 78 0, 1, 2, 0, 2, 3, 79 6, 5, 4, 7, 6, 4, 80 8, 9, 10, 8, 10, 11, 81 14, 13, 12, 15, 14, 12, 82 16, 17, 18, 16, 18, 19, 83 22, 21, 20, 23, 22, 20, 84 ]; 85 86 // dfmt off 87 sg.BufferDesc ibufd = { 88 type: sg.BufferType.Indexbuffer, 89 data: {ptr: indices.ptr, size: indices.sizeof}, 90 }; 91 92 sg.PipelineDesc pld = { 93 layout: { 94 attrs: [ 95 shd.ATTR_NONINTERLEAVED_POSITION: { 96 format: sg.VertexFormat.Float3, 97 buffer_index: 0 98 }, 99 shd.ATTR_NONINTERLEAVED_COLOR0: { 100 format: sg.VertexFormat.Float4, 101 buffer_index: 1 102 }, 103 ], 104 }, 105 shader: sg.makeShader(shd.noninterleavedShaderDesc(sg.queryBackend())), 106 index_type: sg.IndexType.Uint16, 107 cull_mode: sg.CullMode.Back, 108 depth: { 109 write_enabled: true, 110 compare: sg.CompareFunc.Less_equal 111 }, 112 label: "pipeline" 113 }; 114 // dfmt on 115 state.pip = sg.makePipeline(pld); 116 117 // fill the resource bindings, note how the same vertex 118 // buffer is bound to the first two slots, and the vertex-buffer-offsets 119 // are used to point to the position- and color-components. 120 state.bind.vertex_buffers[0] = sg.makeBuffer(vbufd); 121 state.bind.vertex_buffers[1] = sg.makeBuffer(vbufd); 122 // position vertex components are at the start of the buffer 123 state.bind.vertex_buffer_offsets[0] = 0; 124 // color vertex components follow after the positions 125 state.bind.vertex_buffer_offsets[1] = 24 * 3 * float.sizeof; 126 state.bind.index_buffer = sg.makeBuffer(ibufd); 127 } 128 129 void frame() 130 { 131 immutable float t = cast(float)(app.frameDuration() * 60.0); 132 133 state.rx += 1.0 * t; 134 state.ry += 2.0 * t; 135 136 shd.VsParams vsParams = {mvp: computeMvp(state.rx, state.ry)}; 137 138 sg.Pass pass = {action: state.passAction, swapchain: sglue.swapchain()}; 139 sg.beginPass(pass); 140 sg.applyPipeline(state.pip); 141 sg.applyBindings(state.bind); 142 sg.Range r = {ptr: &vsParams, size: vsParams.sizeof}; 143 sg.applyUniforms(shd.UB_VS_PARAMS, r); 144 sg.draw(0, 36, 1); 145 sg.endPass(); 146 sg.commit(); 147 } 148 149 void cleanup() 150 { 151 sg.shutdown(); 152 } 153 154 Mat4 computeMvp(float rx, float ry) 155 { 156 immutable proj = Mat4.perspective(60.0, app.widthf() / app.heightf(), 0.01, 10.0); 157 immutable rxm = Mat4.rotate(rx, Vec3(1.0, 0.0, 0.0)); 158 immutable rym = Mat4.rotate(ry, Vec3(0.0, 1.0, 0.0)); 159 immutable model = Mat4.mul(rxm, rym); 160 immutable view_proj = Mat4.mul(proj, state.view()); 161 return Mat4.mul(view_proj, model); 162 } 163 164 // dfmt off 165 void main() 166 { 167 app.Desc runner = { 168 window_title: "noninterleaved.d", 169 init_cb: &init, 170 frame_cb: &frame, 171 cleanup_cb: &cleanup, 172 width: 800, 173 height: 600, 174 sample_count: 4, 175 icon: {sokol_default: true}, 176 logger: {func: &log.func} 177 }; 178 app.run(runner); 179 } 180 // dfmt on