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 sg.Attachments attachments; 24 sg.Image img; 25 sgl.Context sgl_ctx; 26 sg.PassAction pass_action = { 27 colors: [ 28 { 29 load_action: sg.LoadAction.Clear, clear_value: { 30 r: 0, g: 0, b: 0, a: 1 31 } 32 }, 33 ] 34 }; 35 } 36 37 struct Display 38 { 39 sg.Sampler smp; 40 sgl.Pipeline sgl_pip; 41 sg.PassAction pass_action = { 42 colors: [ 43 { 44 load_action: sg.LoadAction.Clear, clear_value: { 45 r: 0.5, g: 0.7, b: 1.0, a: 1.0 46 } 47 }, 48 ], 49 }; 50 } 51 52 struct State 53 { 54 Display display; 55 Offscreen offscreen; 56 } 57 58 static State state; 59 60 enum offscreen_pixel_format = sg.PixelFormat.Rgba8; 61 enum offscreen_sample_count = 1; 62 enum offscreen_width = 32; 63 enum offscreen_height = 32; 64 65 void init() 66 { 67 sg.Desc gfxd = { 68 environment: sglue.environment(), 69 logger: {func: &slog.func} 70 }; 71 sg.setup(gfxd); 72 73 // setup sokol-gl with the default context compatible with the default 74 // render pass (which means just keep pixelformats and sample count at defaults) 75 // 76 // reduce the vertex- and command-count though, otherwise we just waste memory 77 sgl.Desc gld = { 78 max_vertices: 64, 79 max_commands: 16, 80 logger: {func: &slog.func}, 81 }; 82 sgl.setup(gld); 83 84 // create a sokol-gl pipeline object for 3D rendering into the default pass 85 sg.PipelineDesc pld = { 86 cull_mode: sg.CullMode.Back, 87 depth: {write_enabled: true, 88 compare: sg.CompareFunc.Less_equal}, 89 }; 90 state.display.sgl_pip = sgl.contextMakePipeline(sgl.defaultContext, pld); 91 92 // create a sokol-gl context compatible with the offscreen render pass 93 // (specific color pixel format, no depth-stencil-surface, no MSAA) 94 sgl.ContextDesc ctd = { 95 max_vertices: 8, 96 max_commands: 4, 97 color_format: offscreen_pixel_format, 98 depth_format: sg.PixelFormat.None, 99 sample_count: offscreen_sample_count 100 }; 101 state.offscreen.sgl_ctx = sgl.makeContext(ctd); 102 103 // create an offscreen render target texture, pass-attachments object and pass-action 104 sg.ImageDesc imgd = { 105 render_target: true, 106 width: offscreen_width, 107 height: offscreen_height, 108 pixel_format: offscreen_pixel_format, 109 sample_count: offscreen_sample_count 110 }; 111 state.offscreen.img = sg.makeImage(imgd); 112 113 sg.AttachmentsDesc attd = {colors: [ 114 {image: state.offscreen.img} 115 ]}; 116 state.offscreen.attachments = sg.makeAttachments(attd); 117 118 // sampler for sampling the offscreen render target 119 sg.SamplerDesc smd = { 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(smd); 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.offscreen.img, 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.Pass offscreen_pass = { 154 action: state.offscreen.pass_action, 155 attachments: state.offscreen.attachments 156 }; 157 sg.beginPass(offscreen_pass); 158 sgl.contextDraw(state.offscreen.sgl_ctx); 159 sg.endPass(); 160 sg.Pass display_pass = { 161 action: state.display.pass_action, 162 swapchain: sglue.swapchain 163 }; 164 sg.beginPass(display_pass); 165 sgl.contextDraw(sgl.defaultContext()); 166 sg.endPass(); 167 sg.commit(); 168 } 169 170 void cleanup() 171 { 172 sgl.shutdown(); 173 sg.shutdown(); 174 } 175 176 void main() 177 { 178 sapp.Desc runner = { 179 window_title: "sgl-context.d", 180 init_cb: &init, 181 frame_cb: &frame, 182 cleanup_cb: &cleanup, 183 width: 800, 184 height: 600, 185 sample_count: 4, 186 logger: {func: &slog.func}, 187 icon: {sokol_default: true} 188 }; 189 sapp.run(runner); 190 } 191 192 void draw_quad() 193 { 194 sgl.beginQuads(); 195 sgl.v2fC3b(0.0, -1.0, 255, 0, 0); 196 sgl.v2fC3b(1.0, 0.0, 0, 0, 255); 197 sgl.v2fC3b(0.0, 1.0, 0, 255, 255); 198 sgl.v2fC3b(-1.0, 0.0, 0, 255, 0); 199 sgl.end(); 200 } 201 202 void draw_cube() 203 { 204 sgl.beginQuads(); 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.v3fT2f(-1.0, 1.0, -1.0, 0.0, 1.0); 226 sgl.v3fT2f(-1.0, 1.0, 1.0, 1.0, 1.0); 227 sgl.v3fT2f(1.0, 1.0, 1.0, 1.0, 0.0); 228 sgl.v3fT2f(1.0, 1.0, -1.0, 0.0, 0.0); 229 sgl.end(); 230 }