diff --git a/examples/gg/additive.v b/examples/gg/additive.v new file mode 100644 index 0000000000..edae97635c --- /dev/null +++ b/examples/gg/additive.v @@ -0,0 +1,134 @@ +module main + +import os +import gg +import gx +import math + +[heap] +pub struct Window { +pub mut: + ctx &gg.Context = unsafe { 0 } + image gg.Image +} + +pub fn (mut window Window) init(_ voidptr) { + logo_path := os.resource_abs_path(os.join_path('..', 'assets', 'logo.png')) + window.image = window.ctx.create_image(logo_path) +} + +pub fn (mut window Window) draw(_ voidptr) { + window.ctx.begin() + + window.ctx.draw_image_with_config( + img: &window.image + img_id: window.image.id + img_rect: gg.Rect{ + x: 400 - window.image.width / 2 + y: 300 - window.image.height / 2 + width: window.image.width + height: window.image.height + } + // effect: .alpha <-- this can be omitted completely as it is alpha by default. + ) + + // Red + window.ctx.draw_image_with_config( + img: &window.image + img_id: window.image.id + img_rect: gg.Rect{ + x: (400 - window.image.width / 2) + f32(math.sin(f32(window.ctx.frame) / 10.0) * 60) + y: (300 - window.image.height / 2) + f32(math.cos(f32(window.ctx.frame) / 10.0) * 60) + width: window.image.width + height: window.image.height + } + color: gx.Color{255, 0, 0, 255} + effect: .add + ) + + // Green + window.ctx.draw_image_with_config( + img: &window.image + img_id: window.image.id + img_rect: gg.Rect{ + x: (400 - window.image.width / 2) + f32(math.sin(f32(window.ctx.frame) / 10.0) * 80) + y: (300 - window.image.height / 2) + f32(math.cos(f32(window.ctx.frame) / 10.0) * 80) + width: window.image.width + height: window.image.height + } + color: gx.Color{0, 255, 0, 255} + effect: .add + ) + + // Blue + window.ctx.draw_image_with_config( + img: &window.image + img_id: window.image.id + img_rect: gg.Rect{ + x: (400 - window.image.width / 2) + f32(math.sin(f32(window.ctx.frame) / 10.0) * 100) + y: (300 - window.image.height / 2) + f32(math.cos(f32(window.ctx.frame) / 10.0) * 100) + width: window.image.width + height: window.image.height + } + color: gx.Color{0, 0, 255, 255} + effect: .add + ) + + // More examples + window.ctx.draw_image_with_config( + img: &window.image + img_id: window.image.id + img_rect: gg.Rect{ + x: 50 + y: 0 + width: window.image.width + height: window.image.height + } + color: gx.Color{255, 0, 0, 255} + effect: .add + ) + + window.ctx.draw_image_with_config( + img: &window.image + img_id: window.image.id + img_rect: gg.Rect{ + x: 50 + y: 50 + width: window.image.width + height: window.image.height + } + color: gx.Color{0, 255, 0, 255} + effect: .add + ) + + window.ctx.draw_image_with_config( + img: &window.image + img_id: window.image.id + img_rect: gg.Rect{ + x: 50 + y: 100 + width: window.image.width + height: window.image.height + } + color: gx.Color{0, 0, 255, 255} + effect: .add + ) + + window.ctx.end() +} + +fn main() { + mut window := &Window{} + + window.ctx = gg.new_context( + width: 800 + height: 600 + user_data: window + bg_color: gx.gray + // FNs + init_fn: window.init + frame_fn: window.draw + ) + + window.ctx.run() +} diff --git a/examples/gg/rotating_textured_quad.v b/examples/gg/rotating_textured_quad.v index 1ffec3f80d..20c150e564 100644 --- a/examples/gg/rotating_textured_quad.v +++ b/examples/gg/rotating_textured_quad.v @@ -16,7 +16,7 @@ pub fn (mut window Window) init() { pub fn (mut window Window) draw() { angle := f32(window.ctx.frame) / 64 // since window.ctx.frame is increased by 1 on every frame -> the angle will be increasing too window.ctx.begin() - sgl.load_pipeline(window.ctx.timage_pip) + sgl.load_pipeline(window.ctx.pipeline.alpha) sgl.translate(400, 400, 0) // center of the screen sgl.rotate(angle, 0.0, 0.0, 1.0) // rotate around the Z axis pointing towards the camera diff --git a/vlib/gg/draw.c.v b/vlib/gg/draw.c.v index 4f0f8d2760..1218b2a2a5 100644 --- a/vlib/gg/draw.c.v +++ b/vlib/gg/draw.c.v @@ -15,7 +15,7 @@ import math [inline] pub fn (ctx &Context) draw_pixel(x f32, y f32, c gx.Color) { if c.a != 255 { - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) } sgl.c4b(c.r, c.g, c.b, c.a) @@ -37,7 +37,7 @@ pub fn (ctx &Context) draw_pixels(points []f32, c gx.Color) { len := points.len / 2 if c.a != 255 { - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) } sgl.c4b(c.r, c.g, c.b, c.a) @@ -67,7 +67,7 @@ pub fn (ctx &Context) draw_line(x f32, y f32, x2 f32, y2 f32, c gx.Color) { } if c.a != 255 { - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) } sgl.c4b(c.r, c.g, c.b, c.a) @@ -80,7 +80,7 @@ pub fn (ctx &Context) draw_line(x f32, y f32, x2 f32, y2 f32, c gx.Color) { // draw_line_with_config draws a line between the points `x,y` and `x2,y2` using `PenConfig`. pub fn (ctx &Context) draw_line_with_config(x f32, y f32, x2 f32, y2 f32, config PenConfig) { if config.color.a != 255 { - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) } if config.thickness <= 0 { @@ -137,7 +137,7 @@ pub fn (ctx &Context) draw_poly_empty(points []f32, c gx.Color) { } if c.a != 255 { - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) } sgl.c4b(c.r, c.g, c.b, c.a) @@ -159,7 +159,7 @@ pub fn (ctx &Context) draw_convex_poly(points []f32, c gx.Color) { } if c.a != 255 { - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) } sgl.c4b(c.r, c.g, c.b, c.a) @@ -182,7 +182,7 @@ pub fn (ctx &Context) draw_convex_poly(points []f32, c gx.Color) { // `w` is the width, `h` is the height and `c` is the color of the outline. pub fn (ctx &Context) draw_rect_empty(x f32, y f32, w f32, h f32, c gx.Color) { if c.a != 255 { - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) } sgl.c4b(c.r, c.g, c.b, c.a) @@ -207,7 +207,7 @@ pub fn (ctx &Context) draw_rect_filled(x f32, y f32, w f32, h f32, c gx.Color) { } if c.a != 255 { - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) } sgl.c4b(c.r, c.g, c.b, c.a) @@ -230,7 +230,7 @@ pub fn (ctx &Context) draw_rounded_rect_empty(x f32, y f32, w f32, h f32, radius } if c.a != 255 { - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) } sgl.c4b(c.r, c.g, c.b, c.a) @@ -329,7 +329,7 @@ pub fn (ctx &Context) draw_rounded_rect_filled(x f32, y f32, w f32, h f32, radiu } if c.a != 255 { - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) } sgl.c4b(c.r, c.g, c.b, c.a) @@ -435,7 +435,7 @@ pub fn (ctx &Context) draw_rounded_rect_filled(x f32, y f32, w f32, h f32, radiu // `c` is the color of the outline. pub fn (ctx &Context) draw_triangle_empty(x f32, y f32, x2 f32, y2 f32, x3 f32, y3 f32, c gx.Color) { if c.a != 255 { - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) } sgl.c4b(c.r, c.g, c.b, c.a) @@ -454,7 +454,7 @@ pub fn (ctx &Context) draw_triangle_empty(x f32, y f32, x2 f32, y2 f32, x3 f32, // `c` is the color of the outline. pub fn (ctx &Context) draw_triangle_filled(x f32, y f32, x2 f32, y2 f32, x3 f32, y3 f32, c gx.Color) { if c.a != 255 { - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) } sgl.c4b(c.r, c.g, c.b, c.a) @@ -505,7 +505,7 @@ fn radius_to_segments(r f32) int { // `c` is the color of the outline. pub fn (ctx &Context) draw_circle_empty(x f32, y f32, radius f32, c gx.Color) { if c.a != 255 { - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) } sgl.c4b(c.r, c.g, c.b, c.a) @@ -554,7 +554,7 @@ pub fn (ctx &Context) draw_polygon_filled(x f32, y f32, size f32, edges int, rot } if c.a != 255 { - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) } sgl.c4b(c.r, c.g, c.b, c.a) @@ -604,7 +604,7 @@ pub fn (ctx &Context) draw_circle_line(x f32, y f32, radius int, segments int, c } if c.a != 255 { - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) } sgl.c4b(c.r, c.g, c.b, c.a) @@ -631,7 +631,7 @@ pub fn (ctx &Context) draw_slice_empty(x f32, y f32, radius f32, start_angle f32 return } if c.a != 255 { - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) } sgl.c4b(c.r, c.g, c.b, c.a) @@ -672,7 +672,7 @@ pub fn (ctx &Context) draw_slice_filled(x f32, y f32, radius f32, start_angle f3 } if c.a != 255 { - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) } sgl.c4b(c.r, c.g, c.b, c.a) @@ -721,7 +721,7 @@ pub fn (ctx Context) draw_arc_line(x f32, y f32, radius f32, start_angle f32, en } if c.a != 255 { - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) } sgl.c4b(c.r, c.g, c.b, c.a) @@ -768,7 +768,7 @@ pub fn (ctx &Context) draw_arc_empty(x f32, y f32, inner_radius f32, thickness f } if c.a != 255 { - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) } sgl.c4b(c.r, c.g, c.b, c.a) @@ -835,7 +835,7 @@ pub fn (ctx &Context) draw_arc_filled(x f32, y f32, inner_radius f32, thickness } if c.a != 255 { - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) } sgl.c4b(c.r, c.g, c.b, c.a) @@ -874,7 +874,7 @@ pub fn (ctx &Context) draw_arc_filled(x f32, y f32, inner_radius f32, thickness // `c` is the color of the outline. pub fn (ctx &Context) draw_ellipse_empty(x f32, y f32, rw f32, rh f32, c gx.Color) { if c.a != 255 { - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) } sgl.c4b(c.r, c.g, c.b, c.a) @@ -894,7 +894,7 @@ pub fn (ctx &Context) draw_ellipse_empty(x f32, y f32, rw f32, rh f32, c gx.Colo // `c` is the fill color. pub fn (ctx &Context) draw_ellipse_filled(x f32, y f32, rw f32, rh f32, c gx.Color) { if c.a != 255 { - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) } sgl.c4b(c.r, c.g, c.b, c.a) @@ -926,7 +926,7 @@ pub fn (ctx &Context) draw_cubic_bezier_in_steps(points []f32, steps u32, c gx.C return } if c.a != 255 { - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) } sgl.c4b(c.r, c.g, c.b, c.a) diff --git a/vlib/gg/gg.c.v b/vlib/gg/gg.c.v index e963f2cd25..863ea0445b 100644 --- a/vlib/gg/gg.c.v +++ b/vlib/gg/gg.c.v @@ -103,6 +103,51 @@ pub: max_dropped_file_path_length int = 2048 // max length in bytes of a dropped UTF-8 file path (default: 2048) } +[heap] +pub struct PipelineContainer { +pub mut: + alpha sgl.Pipeline + add sgl.Pipeline +} + +fn (mut container PipelineContainer) init_pipeline() { + // FIXME(FireRedz): this looks kinda funny, find a better way to initialize pipeline. + + // Alpha + mut alpha_pipdesc := gfx.PipelineDesc{ + label: c'alpha-pipeline' + } + + unsafe { vmemset(&alpha_pipdesc, 0, int(sizeof(alpha_pipdesc))) } + + alpha_pipdesc.colors[0] = gfx.ColorState{ + blend: gfx.BlendState{ + enabled: true + src_factor_rgb: .src_alpha + dst_factor_rgb: .one_minus_src_alpha + } + } + + container.alpha = sgl.make_pipeline(&alpha_pipdesc) + + // Add + mut add_pipdesc := gfx.PipelineDesc{ + label: c'additive-pipeline' + } + + unsafe { vmemset(&add_pipdesc, 0, int(sizeof(add_pipdesc))) } + + add_pipdesc.colors[0] = gfx.ColorState{ + blend: gfx.BlendState{ + enabled: true + src_factor_rgb: .src_alpha + dst_factor_rgb: .one + } + } + + container.add = sgl.make_pipeline(&add_pipdesc) +} + [heap] pub struct Context { mut: @@ -120,7 +165,8 @@ pub mut: height int clear_pass gfx.PassAction window sapp.Desc - timage_pip sgl.Pipeline + timage_pip sgl.Pipeline [deprecated: 'Use `Context.pipeline.alpha` instead!'] + pipeline &PipelineContainer = unsafe { nil } config Config user_data voidptr ft &FT = unsafe { nil } @@ -205,22 +251,14 @@ fn gg_init_sokol_window(user_data voidptr) { ctx.font_inited = true } } - // - mut pipdesc := gfx.PipelineDesc{ - label: c'alpha_image' - } - unsafe { vmemset(&pipdesc, 0, int(sizeof(pipdesc))) } - color_state := gfx.ColorState{ - blend: gfx.BlendState{ - enabled: true - src_factor_rgb: .src_alpha - dst_factor_rgb: .one_minus_src_alpha - } - } - pipdesc.colors[0] = color_state + // Pipeline + ctx.pipeline = &PipelineContainer{} + ctx.pipeline.init_pipeline() + + // Keep the old pipeline for now, cuz v ui used it. + ctx.timage_pip = ctx.pipeline.alpha - ctx.timage_pip = sgl.make_pipeline(&pipdesc) // if ctx.config.init_fn != unsafe { nil } { $if android { diff --git a/vlib/gg/image.c.v b/vlib/gg/image.c.v index ec57680c50..a62e24310f 100644 --- a/vlib/gg/image.c.v +++ b/vlib/gg/image.c.v @@ -296,7 +296,12 @@ pub fn (ctx &Context) draw_image_with_config(config DrawImageConfig) { mut v0f := if !flip_y { v0 } else { v1 } mut v1f := if !flip_y { v1 } else { v0 } - sgl.load_pipeline(ctx.timage_pip) + // FIXME: is this okay? + match config.effect { + .alpha { sgl.load_pipeline(ctx.pipeline.alpha) } + .add { sgl.load_pipeline(ctx.pipeline.add) } + } + sgl.enable_texture() sgl.texture(img.simg) diff --git a/vlib/gg/image.v b/vlib/gg/image.v index 8e488b4701..e2aead62ce 100644 --- a/vlib/gg/image.v +++ b/vlib/gg/image.v @@ -16,7 +16,14 @@ pub: part_rect Rect // defines the size and position of part of the image to use when rendering rotate int // amount to rotate the image in degrees z f32 - color gx.Color = gx.white + color gx.Color = gx.white + effect ImageEffect = .alpha +} + +pub enum ImageEffect { + // TODO(FireRedz): Add more effects + alpha + add } // Rect represents a rectangular shape in `gg`. diff --git a/vlib/gg/text_rendering.c.v b/vlib/gg/text_rendering.c.v index 6c60983041..406f54bae6 100644 --- a/vlib/gg/text_rendering.c.v +++ b/vlib/gg/text_rendering.c.v @@ -138,7 +138,7 @@ pub fn (ctx &Context) set_text_cfg(cfg gx.TextCfg) { ctx.ft.fons.set_align(int(cfg.align) | int(cfg.vertical_align)) color := sfons.rgba(cfg.color.r, cfg.color.g, cfg.color.b, cfg.color.a) if cfg.color.a != 255 { - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) } ctx.ft.fons.set_color(color) ascender := f32(0.0) diff --git a/vlib/x/ttf/render_sokol_cpu.v b/vlib/x/ttf/render_sokol_cpu.v index a6052a3002..f921cbd6b4 100644 --- a/vlib/x/ttf/render_sokol_cpu.v +++ b/vlib/x/ttf/render_sokol_cpu.v @@ -196,7 +196,7 @@ pub fn (tf_skl TTF_render_Sokol) draw_text_bmp(ctx &gg.Context, x f32, y f32) { ] sgl.mult_matrix(m) // - sgl.load_pipeline(ctx.timage_pip) + sgl.load_pipeline(ctx.pipeline.alpha) sgl.enable_texture() sgl.texture(tf_skl.sg_img) sgl.begin_quads()