From a0b18d01dda31290eb39e5bf5844b726fb1badd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matheus=20Catarino=20Fran=C3=A7a?= Date: Sun, 17 Dec 2023 15:53:02 -0300 Subject: [PATCH] sgl_context and some fixes --- .github/workflows/build.yml | 2 +- build.zig | 15 +-- src/examples/clear.d | 18 +-- src/examples/sgl_context.d | 213 ++++++++++++++++++++++++++++++++++++ src/sokol/gl.d | 2 +- 5 files changed, 233 insertions(+), 17 deletions(-) create mode 100644 src/examples/sgl_context.d diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1d2984d..009d191 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,4 +26,4 @@ jobs: run: | zig build debugtext_print --summary all zig build clear --summary all - # zig build cube --summary all + zig build sgl_context --summary all diff --git a/build.zig b/build.zig index d84d269..d6d0b96 100644 --- a/build.zig +++ b/build.zig @@ -198,14 +198,14 @@ pub fn build(b: *Builder) !void { // "mrt", // "saudio", // "sgl", - // "sgl-context", + "sgl_context", // "sgl-points", // "debugtext", "debugtext_print", // "debugtext-userfont", // "shapes", }; - b.getInstallStep().name = "sokol-d-examples"; + b.getInstallStep().name = "sokol library"; inline for (examples) |example| { const ldc = try buildLDC(b, sokol, .{ .name = example, @@ -214,7 +214,13 @@ pub fn build(b: *Builder) !void { // handmade math rootPath() ++ fmt.comptimePrint("/src/examples/math.d", .{}), }, + .dflags = &.{ + "--wi", // warnings only (no error) + // "-w", // warnings as error + "--wo", // warning of deprecated features + }, }); + ldc.setName("ldc2"); ldc.step.dependOn(b.getInstallStep()); const run = b.step(b.fmt("{s}", .{example}), b.fmt("Build example {s}", .{example})); run.dependOn(&ldc.step); @@ -328,11 +334,6 @@ fn buildLDC(b: *Builder, lib: *Builder.CompileStep, comptime config: ldcConfig) try cmds.append("--boundscheck=off"); }, } - // warnings - try cmds.append("-w"); - - // warning obsolete features - try cmds.append("--wo"); // Print character (column) numbers in diagnostics try cmds.append("--vcolumns"); diff --git a/src/examples/clear.d b/src/examples/clear.d index 12a8c37..f058cd6 100644 --- a/src/examples/clear.d +++ b/src/examples/clear.d @@ -46,14 +46,16 @@ void cleanup() void main() { sapp.IconDesc icon = {sokol_default: true}; - sapp.Desc runner = {window_title: "clear.d"}; - runner.init_cb = &init; - runner.frame_cb = &frame; - runner.cleanup_cb = &cleanup; - runner.width = 640; - runner.height = 480; + sapp.Desc runner = { + window_title: "clear.d", + init_cb: &init, + frame_cb: &frame, + cleanup_cb: &cleanup, + width: 640, + height: 480, + win32_console_attach: true + }; runner.icon = icon; - runner.win32_console_attach = true; - runner.logger.func = &log.slog_func; + runner.logger.func = &log.func; sapp.run(runner); } diff --git a/src/examples/sgl_context.d b/src/examples/sgl_context.d new file mode 100644 index 0000000..544d8aa --- /dev/null +++ b/src/examples/sgl_context.d @@ -0,0 +1,213 @@ +//------------------------------------------------------------------------------ +// sgl-context.d +// +// Demonstrates how to render into different render passes with sokol-gl. +// using contexts. +//------------------------------------------------------------------------------ +module examples.sgl_context; + +import std.stdio; +import sg = sokol.gfx; +import sgapp = sokol.glue; +import sapp = sokol.app; +import log = sokol.log; +import sgl = sokol.gl; +import std.math : sin, cos; + +struct State +{ + struct Offscreen + { + sg.PassAction pass_action; + sg.Pass pass; + sg.Image img; + sgl.Context sgl_ctx; + } + + struct Display + { + sg.PassAction pass_action; + sg.Sampler smp; + sgl.Pipeline sgl_pip; + } +} + +enum offscreen_pixel_format = sg.PixelFormat.RGBA8; +enum offscreen_sample_count = 1; +enum offscreen_width = 32; +enum offscreen_height = 32; + +State.Offscreen offscreen; +State.Display display; + +void init() +{ + sg.Desc gfxd; + gfxd.context = sgapp.context(); + gfxd.logger.func = &log.func; + sg.setup(gfxd); + + // setup sokol-gl with the default context compatible with the default + // render pass (which means just keep pixelformats and sample count at defaults) + // + // reduce the vertex- and command-count though, otherwise we just waste memory + sgl.Desc gld; + gld.max_vertices = 64; + gld.max_commands = 16; + gld.logger.func = &log.func; + sgl.setup(gld); + + // initialize a pass action struct for the default pass to clear to a light-blue color + display.pass_action.colors[0].load_action = sg.LoadAction.CLEAR; + display.pass_action.colors[0].clear_value.r = 0.5; + display.pass_action.colors[0].clear_value.g = 0.7; + display.pass_action.colors[0].clear_value.b = 1; + display.pass_action.colors[0].clear_value.a = 1; + + // create a sokol-gl pipeline object for 3D rendering into the default pass + sg.PipelineDesc pld; + pld.cull_mode = sg.CullMode.BACK; + pld.depth.write_enabled = true; + pld.depth.compare = sg.CompareFunc.LESS_EQUAL; + display.sgl_pip = sgl.contextMakePipeline(sgl.defaultContext, pld); + + // create a sokol-gl context compatible with the offscreen render pass + // (specific color pixel format, no depth-stencil-surface, no MSAA) + sgl.ContextDesc ctd; + ctd.max_vertices = 8; + ctd.max_commands = 4; + ctd.color_format = offscreen_pixel_format, + ctd.depth_format = sg.PixelFormat.NONE, + ctd.sample_count = offscreen_sample_count, + + offscreen.sgl_ctx = sgl.makeContext(ctd); + + // create an offscreen render target texture, pass and pass-action + sg.ImageDesc imgd; + imgd.render_target = true, + imgd.width = offscreen_width, + imgd.height = offscreen_height, + imgd.pixel_format = offscreen_pixel_format, + imgd.sample_count = offscreen_sample_count, + + offscreen.img = sg.makeImage(imgd); + + sg.PassDesc pass_desc; + pass_desc.color_attachments[0].image = offscreen.img; + offscreen.pass = sg.makePass(pass_desc); + + offscreen.pass_action.colors[0].load_action = sg.LoadAction.CLEAR; + offscreen.pass_action.colors[0].clear_value.r = 0; + offscreen.pass_action.colors[0].clear_value.g = 0; + offscreen.pass_action.colors[0].clear_value.b = 0; + offscreen.pass_action.colors[0].clear_value.a = 1; + + // sampler for sampling the offscreen render target + sg.SamplerDesc smd; + smd.wrap_u = sg.Wrap.CLAMP_TO_EDGE, + smd.wrap_v = sg.Wrap.CLAMP_TO_EDGE, + smd.min_filter = sg.Filter.NEAREST, + smd.mag_filter = sg.Filter.NEAREST, + display.smp = sg.makeSampler(smd); +} + +void frame() +{ + const a = sgl.asRadians(sapp.frameCount()); + + // draw a rotating quad into the offscreen render target texture + sgl.setContext(offscreen.sgl_ctx); + sgl.defaults(); + sgl.matrixModeModelview(); + sgl.rotate(a, 0, 0, 1); + draw_quad(); + + // draw a rotating 3D cube, using the offscreen render target as texture + sgl.setContext(sgl.defaultContext()); + sgl.defaults(); + sgl.enableTexture(); + sgl.texture(offscreen.img, display.smp); + sgl.loadPipeline(display.sgl_pip); + sgl.matrixModeProjection(); + sgl.perspective(sgl.asRadians(45.0), sapp.widthf() / sapp.heightf(), 0.1, 100.0); + const(float)[3] eye = [ + sin(a) * 6.0, + sin(a) * 3.0, + cos(a) * 6.0, + ]; + sgl.matrixModeModelview(); + sgl.lookat(eye[0], eye[1], eye[2], 0, 0, 0, 0, 1, 0); + draw_cube(); + + // do the actual offscreen and display rendering in sokol-gfx passes + sg.beginPass(offscreen.pass, offscreen.pass_action); + sgl.contextDraw(offscreen.sgl_ctx); + sg.endPass(); + sg.beginDefaultPass(display.pass_action, sapp.width(), sapp.height()); + sgl.contextDraw(sgl.defaultContext()); + sg.endPass(); + sg.commit(); +} + +void cleanup() +{ + sgl.shutdown(); + sg.shutdown(); +} + +void main() +{ + sapp.IconDesc icon = {sokol_default: true}; + sapp.Desc runner = { + window_title: "sgl_context.d", + init_cb: &init, + frame_cb: &frame, + cleanup_cb: &cleanup, + width: 800, + height: 600, + sample_count: 4, + }; + runner.icon = icon; + runner.logger.func = &log.func; + sapp.run(runner); +} + +void draw_quad() +{ + sgl.beginQuads(); + sgl.v2fC3b(0.0, -1.0, 255, 0, 0); + sgl.v2fC3b(1.0, 0.0, 0, 0, 255); + sgl.v2fC3b(0.0, 1.0, 0, 255, 255); + sgl.v2fC3b(-1.0, 0.0, 0, 255, 0); + sgl.end(); +} + +void draw_cube() +{ + sgl.beginQuads(); + sgl.v3fT2f(-1.0, 1.0, -1.0, 0.0, 1.0); + sgl.v3fT2f(1.0, 1.0, -1.0, 1.0, 1.0); + sgl.v3fT2f(1.0, -1.0, -1.0, 1.0, 0.0); + sgl.v3fT2f(-1.0, -1.0, -1.0, 0.0, 0.0); + sgl.v3fT2f(-1.0, -1.0, 1.0, 0.0, 1.0); + sgl.v3fT2f(1.0, -1.0, 1.0, 1.0, 1.0); + sgl.v3fT2f(1.0, 1.0, 1.0, 1.0, 0.0); + sgl.v3fT2f(-1.0, 1.0, 1.0, 0.0, 0.0); + sgl.v3fT2f(-1.0, -1.0, 1.0, 0.0, 1.0); + sgl.v3fT2f(-1.0, 1.0, 1.0, 1.0, 1.0); + sgl.v3fT2f(-1.0, 1.0, -1.0, 1.0, 0.0); + sgl.v3fT2f(-1.0, -1.0, -1.0, 0.0, 0.0); + sgl.v3fT2f(1.0, -1.0, 1.0, 0.0, 1.0); + sgl.v3fT2f(1.0, -1.0, -1.0, 1.0, 1.0); + sgl.v3fT2f(1.0, 1.0, -1.0, 1.0, 0.0); + sgl.v3fT2f(1.0, 1.0, 1.0, 0.0, 0.0); + sgl.v3fT2f(1.0, -1.0, -1.0, 0.0, 1.0); + sgl.v3fT2f(1.0, -1.0, 1.0, 1.0, 1.0); + sgl.v3fT2f(-1.0, -1.0, 1.0, 1.0, 0.0); + sgl.v3fT2f(-1.0, -1.0, -1.0, 0.0, 0.0); + sgl.v3fT2f(-1.0, 1.0, -1.0, 0.0, 1.0); + sgl.v3fT2f(-1.0, 1.0, 1.0, 1.0, 1.0); + sgl.v3fT2f(1.0, 1.0, 1.0, 1.0, 0.0); + sgl.v3fT2f(1.0, 1.0, -1.0, 0.0, 0.0); + sgl.end(); +} diff --git a/src/sokol/gl.d b/src/sokol/gl.d index b5c43c7..676891f 100644 --- a/src/sokol/gl.d +++ b/src/sokol/gl.d @@ -18,7 +18,7 @@ enum LogItem { CANNOT_DESTROY_DEFAULT_CONTEXT, } struct Logger { - void function(const (char*), uint, uint, const (char*), uint, const (char*), void*) func; + extern(C) void function(const (char*), uint, uint, const (char*), uint, const (char*), void*) func; void* user_data; } struct Pipeline {