1 //------------------------------------------------------------------------------ 2 // sgl-context.d 3 // 4 // Demonstrates how to render into different render passes with sokol-gl. 5 // using contexts. 6 //------------------------------------------------------------------------------ 7 module examples.sgl_context; 8 9 private: 10 11 import sg = sokol.gfx; 12 import sglue = sokol.glue; 13 import sapp = sokol.app; 14 import slog = sokol.log; 15 import sgl = sokol.gl; 16 import handmade.math : sin, cos; 17 18 extern (C): 19 @safe: 20 21 struct Offscreen 22 { 23 sgl.Context sgl_ctx; 24 sg.Pass pass = { 25 action: { 26 colors: [ 27 { 28 load_action: sg.LoadAction.Clear, clear_value: { 29 r: 0, g: 0, b: 0, a: 1 30 } 31 }, 32 ], 33 }, 34 }; 35 } 36 37 struct Display 38 { 39 sg.Sampler smp; 40 sg.View tex_view; 41 sgl.Pipeline sgl_pip; 42 sg.PassAction pass_action = { 43 colors: [ 44 { 45 load_action: sg.LoadAction.Clear, clear_value: { 46 r: 0.5, g: 0.7, b: 1.0, a: 1.0 47 } 48 }, 49 ], 50 }; 51 } 52 53 struct State 54 { 55 Display display; 56 Offscreen offscreen; 57 } 58 59 static State state; 60 61 enum offscreen_pixel_format = sg.PixelFormat.Rgba8; 62 enum offscreen_sample_count = 1; 63 enum offscreen_width = 32; 64 enum offscreen_height = 32; 65 66 void init() 67 { 68 sg.Desc gfxd = { 69 environment: sglue.environment(), 70 logger: {func: &slog.func} 71 }; 72 sg.setup(gfxd); 73 74 // setup sokol-gl with the default context compatible with the default 75 // render pass (which means just keep pixelformats and sample count at defaults) 76 // 77 // reduce the vertex- and command-count though, otherwise we just waste memory 78 sgl.Desc gld = { 79 max_vertices: 64, 80 max_commands: 16, 81 logger: {func: &slog.func}, 82 }; 83 sgl.setup(gld); 84 85 // create a sokol-gl pipeline object for 3D rendering into the default pass 86 sg.PipelineDesc pld = { 87 cull_mode: sg.CullMode.Back, 88 depth: {write_enabled: true, 89 compare: sg.CompareFunc.Less_equal}, 90 }; 91 state.display.sgl_pip = sgl.contextMakePipeline(sgl.defaultContext, pld); 92 93 // create a sokol-gl context compatible with the offscreen render pass 94 // (specific color pixel format, no depth-stencil-surface, no MSAA) 95 sgl.ContextDesc ctd = { 96 max_vertices: 8, 97 max_commands: 4, 98 color_format: offscreen_pixel_format, 99 depth_format: sg.PixelFormat.None, 100 sample_count: offscreen_sample_count 101 }; 102 state.offscreen.sgl_ctx = sgl.makeContext(ctd); 103 104 // setup offscreen render pass attachment image and view objects 105 sg.ImageDesc img_desc = { 106 usage: { color_attachment: true }, 107 width: offscreen_width, 108 height: offscreen_height, 109 pixel_format: offscreen_pixel_format, 110 sample_count: offscreen_sample_count 111 }; 112 auto img = sg.makeImage(img_desc); 113 sg.ViewDesc att_view_desc = { color_attachment: { image: img } }; 114 state.offscreen.pass.attachments.colors[0] = sg.makeView(att_view_desc); 115 sg.ViewDesc tex_view_desc = { texture: { image: img } }; 116 state.display.tex_view = sg.makeView(tex_view_desc); 117 118 // sampler for sampling the offscreen render target 119 sg.SamplerDesc smp_desc = { 120 wrap_u: sg.Wrap.Clamp_to_edge, 121 wrap_v: sg.Wrap.Clamp_to_edge, 122 min_filter: sg.Filter.Nearest, 123 mag_filter: sg.Filter.Nearest 124 }; 125 state.display.smp = sg.makeSampler(smp_desc); 126 } 127 128 void frame() 129 { 130 immutable float a = sgl.asRadians(sapp.frameCount()); 131 132 // draw a rotating quad into the offscreen render target texture 133 sgl.setContext(state.offscreen.sgl_ctx); 134 sgl.defaults(); 135 sgl.matrixModeModelview(); 136 sgl.rotate(a, 0.0, 0.0, 1.0); 137 draw_quad(); 138 139 // draw a rotating 3D cube, using the offscreen render target as texture 140 sgl.setContext(sgl.defaultContext()); 141 sgl.defaults(); 142 sgl.enableTexture(); 143 sgl.texture(state.display.tex_view, state.display.smp); 144 sgl.loadPipeline(state.display.sgl_pip); 145 sgl.matrixModeProjection(); 146 sgl.perspective(sgl.asRadians(45.0), sapp.widthf() / sapp.heightf(), 0.1, 100.0); 147 immutable(float)[3] eye = [sin(a) * 6.0, sin(a) * 3.0, cos(a) * 6.0]; 148 sgl.matrixModeModelview(); 149 sgl.lookat(eye[0], eye[1], eye[2], 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); 150 draw_cube(); 151 152 // do the actual offscreen and display rendering in sokol-gfx passes 153 sg.beginPass(state.offscreen.pass); 154 sgl.contextDraw(state.offscreen.sgl_ctx); 155 sg.endPass(); 156 sg.Pass display_pass = { 157 action: state.display.pass_action, 158 swapchain: sglue.swapchain 159 }; 160 sg.beginPass(display_pass); 161 sgl.contextDraw(sgl.defaultContext()); 162 sg.endPass(); 163 sg.commit(); 164 } 165 166 void cleanup() 167 { 168 sgl.shutdown(); 169 sg.shutdown(); 170 } 171 172 void main() 173 { 174 sapp.Desc runner = { 175 window_title: "sgl-context.d", 176 init_cb: &init, 177 frame_cb: &frame, 178 cleanup_cb: &cleanup, 179 width: 800, 180 height: 600, 181 sample_count: 4, 182 logger: {func: &slog.func}, 183 icon: {sokol_default: true} 184 }; 185 sapp.run(runner); 186 } 187 188 void draw_quad() 189 { 190 sgl.beginQuads(); 191 sgl.v2fC3b(0.0, -1.0, 255, 0, 0); 192 sgl.v2fC3b(1.0, 0.0, 0, 0, 255); 193 sgl.v2fC3b(0.0, 1.0, 0, 255, 255); 194 sgl.v2fC3b(-1.0, 0.0, 0, 255, 0); 195 sgl.end(); 196 } 197 198 void draw_cube() 199 { 200 sgl.beginQuads(); 201 sgl.v3fT2f(-1.0, 1.0, -1.0, 0.0, 1.0); 202 sgl.v3fT2f(1.0, 1.0, -1.0, 1.0, 1.0); 203 sgl.v3fT2f(1.0, -1.0, -1.0, 1.0, 0.0); 204 sgl.v3fT2f(-1.0, -1.0, -1.0, 0.0, 0.0); 205 sgl.v3fT2f(-1.0, -1.0, 1.0, 0.0, 1.0); 206 sgl.v3fT2f(1.0, -1.0, 1.0, 1.0, 1.0); 207 sgl.v3fT2f(1.0, 1.0, 1.0, 1.0, 0.0); 208 sgl.v3fT2f(-1.0, 1.0, 1.0, 0.0, 0.0); 209 sgl.v3fT2f(-1.0, -1.0, 1.0, 0.0, 1.0); 210 sgl.v3fT2f(-1.0, 1.0, 1.0, 1.0, 1.0); 211 sgl.v3fT2f(-1.0, 1.0, -1.0, 1.0, 0.0); 212 sgl.v3fT2f(-1.0, -1.0, -1.0, 0.0, 0.0); 213 sgl.v3fT2f(1.0, -1.0, 1.0, 0.0, 1.0); 214 sgl.v3fT2f(1.0, -1.0, -1.0, 1.0, 1.0); 215 sgl.v3fT2f(1.0, 1.0, -1.0, 1.0, 0.0); 216 sgl.v3fT2f(1.0, 1.0, 1.0, 0.0, 0.0); 217 sgl.v3fT2f(1.0, -1.0, -1.0, 0.0, 1.0); 218 sgl.v3fT2f(1.0, -1.0, 1.0, 1.0, 1.0); 219 sgl.v3fT2f(-1.0, -1.0, 1.0, 1.0, 0.0); 220 sgl.v3fT2f(-1.0, -1.0, -1.0, 0.0, 0.0); 221 sgl.v3fT2f(-1.0, 1.0, -1.0, 0.0, 1.0); 222 sgl.v3fT2f(-1.0, 1.0, 1.0, 1.0, 1.0); 223 sgl.v3fT2f(1.0, 1.0, 1.0, 1.0, 0.0); 224 sgl.v3fT2f(1.0, 1.0, -1.0, 0.0, 0.0); 225 sgl.end(); 226 } 227 228 version (WebAssembly) 229 { 230 debug 231 { 232 import emscripten.assertd; 233 } 234 }