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