//------------------------------------------------------------------------------
//  blend/module.jai
//
//  Test/demonstrate blend modes.
//------------------------------------------------------------------------------
#import "Basic";
#import,dir "../../sokol/log"(USE_GL=USE_GL);
#import,dir "../../sokol/gfx"(USE_GL=USE_GL);
#import,dir "../../sokol/app"(USE_GL=USE_GL);
#import,dir "../../sokol/glue"(USE_GL=USE_GL);
#load "../math.jai";
#load "./shader.jai";

NUM_BLEND_FACTORS :: 15;

state: struct {
    pass_action:    sg_pass_action;
    bind:           sg_bindings;
    pips:           [NUM_BLEND_FACTORS][NUM_BLEND_FACTORS]sg_pipeline;
    bg_pip:         sg_pipeline;
    r:              float;
    quad_vs_params: Quad_Vs_Params;
    bg_fs_params:   Bg_Fs_Params;
}

init :: () #c_call {
    push_context,defer_pop;
    sg_setup(*(sg_desc.{
        pipeline_pool_size = NUM_BLEND_FACTORS * NUM_BLEND_FACTORS + 1,
        environment = xx,force sglue_environment(),
        logger = .{ func = slog_func },
    }));

    // a quad vertex buffer
    vertices := float.[
        // pos            color
        -1.0, -1.0, 0.0,  1.0, 0.0, 0.0, 0.5,
        +1.0, -1.0, 0.0,  0.0, 1.0, 0.0, 0.5,
        -1.0, +1.0, 0.0,  0.0, 0.0, 1.0, 0.5,
        +1.0, +1.0, 0.0,  1.0, 1.0, 0.0, 0.5,
    ];
    buffer := sg_buffer_desc.{ data = .{ ptr = *vertices, size = size_of(type_of(vertices)) } };
    state.bind.vertex_buffers[0] = sg_make_buffer(*buffer);

    // shader and pipeline object for rendering the background quad
    bg_pip_desc: sg_pipeline_desc;
    bg_pip_desc.shader = sg_make_shader(*bg_shader_desc(sg_query_backend()));
    // we use the same vertex buffer as for the colored 3D quads,
    // but only the first two floats from the position, need to
    // provide a stride to skip the gap to the next vertex
    bg_pip_desc.layout.buffers[0] = .{ stride = 28 };
    bg_pip_desc.layout.attrs[ATTR_bg_position] = .{ format = .FLOAT2 };
    bg_pip_desc.primitive_type = .TRIANGLE_STRIP;
    state.bg_pip = sg_make_pipeline(*bg_pip_desc);

    // a shader for the blended quads
    quad_shd := sg_make_shader(*quad_shader_desc(sg_query_backend()));

    // one pipeline object per blend-factor combination
    pip_desc := sg_pipeline_desc.{
        shader = quad_shd,
        primitive_type = .TRIANGLE_STRIP,
        blend_color = .{ 1.0, 0.0, 0.0, 1.0 },
    };
    pip_desc.layout.attrs[ATTR_quad_position] = .{ format = .FLOAT3 };
    pip_desc.layout.attrs[ATTR_quad_color0]   = .{ format = .FLOAT4 };
    for src : 0 .. NUM_BLEND_FACTORS-1 {
        for dst : 0 .. NUM_BLEND_FACTORS-1 {
            pip_desc.colors[0].blend = .{
                enabled = true,
                src_factor_rgb = cast(sg_blend_factor) (src + 1),
                dst_factor_rgb = cast(sg_blend_factor) (dst + 1),
                src_factor_alpha = .ONE,
                dst_factor_alpha = .ZERO,
            };
            state.pips[src][dst] = sg_make_pipeline(*pip_desc);
        }
    }
}

frame :: () #c_call {
    push_context,defer_pop;
    t := cast(float) (sapp_frame_duration() * 60.0);
    state.r += 0.6 * t;
    state.bg_fs_params.tick += 1.0 * t;

    // view-projection matrix
    proj := persp_mat4(fov = 90.0, aspect = sapp_widthf() / sapp_heightf(), near = 0.01, far = 100.0);
    view := lookat_mat4(eye = .{ 0.0, 0.0, 25.0 }, center = .{}, up = .{ 0.0, 1.0, 0.0 });
    view_proj := multiply_mat4(proj, view);

    // start rendering
    sg_begin_pass(*(sg_pass.{ action = state.pass_action, swapchain = xx,force sglue_swapchain() }));

    // draw a background quad
    sg_apply_pipeline(state.bg_pip);
    sg_apply_bindings(*state.bind);
    sg_apply_uniforms(UB_bg_fs_params, *(sg_range.{ ptr = *state.bg_fs_params, size = size_of(Bg_Fs_Params) }));
    sg_draw(0, 4, 1);

    // draw the blended quads
    r0 := state.r;
    for src : 0 .. NUM_BLEND_FACTORS - 1 {
        for dst : 0 .. NUM_BLEND_FACTORS - 1 {
            // compute model-view-proj matrix
            rm := rotate_mat4(r0, .{ 0.0, 1.0, 0.0 });
            x := cast(float) (dst - NUM_BLEND_FACTORS/2) * 3.0;
            y := cast(float) (src - NUM_BLEND_FACTORS/2) * 2.2;
            model := multiply_mat4(translate_mat4(.{ x, y, 0.0 }), rm);
            state.quad_vs_params.mvp = multiply_mat4(view_proj, model);

            sg_apply_pipeline(state.pips[src][dst]);
            sg_apply_bindings(*state.bind);
            sg_apply_uniforms(UB_quad_vs_params, *(sg_range.{ ptr = *state.quad_vs_params, size = size_of(Quad_Vs_Params) }));
            sg_draw(0, 4, 1);
        }
    }
    sg_end_pass();
    sg_commit();
}

cleanup :: () #c_call {
    sg_shutdown();
}

main :: () {
    sapp_run(*(sapp_desc.{
        init_cb = init,
        frame_cb = frame,
        cleanup_cb = cleanup,
        width = 800,
        height = 600,
        sample_count = 4,
        window_title = "blend",
        icon = .{ sokol_default = true },
        logger = .{ func = slog_func },
    }));
}
