revolver

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

util_idraw2d.c (14835B)


      1 //////////////////////////////////////////////////////////////////
      2 // util_idraw2d.c
      3 
      4 //////////////////////////////////////////////////////////////////
      5 // data
      6 
      7 RV_INTERNAL rv_str8 rv_idraw2d_v_src = S("#version 330 core\n" rv_strify(
      8     layout(location = 0) in vec2 a_pos;
      9     layout(location = 1) in vec2 a_uv;
     10     layout(location = 2) in vec4 a_color;
     11     precision mediump float;
     12 
     13     uniform vec2 u_resolution;
     14 
     15     out vec4 f_color;
     16     out vec2 f_uv;
     17 
     18     void main()
     19     {
     20         vec2 xy_pos = a_pos/u_resolution * 2.0;
     21         xy_pos.y = -xy_pos.y;
     22         xy_pos += vec2(-1.0, 1.0);
     23         gl_Position = vec4(xy_pos, 0.0, 1.0);
     24         f_color = a_color;
     25         f_uv = a_uv;
     26     }
     27 ));
     28 
     29 RV_INTERNAL rv_str8 rv_idraw2d_f_src = S("#version 330 core\n" rv_strify(
     30     precision mediump float;
     31     in vec4 f_color;
     32     in vec2 f_uv;
     33     out vec4 frag_color;
     34     uniform sampler2D u_tex;
     35     uniform float u_omit_tex;
     36     void main()
     37     {
     38         vec4 color = f_color;
     39         if (u_omit_tex < 0.0) {
     40             color.a *= texture(u_tex, f_uv).r;
     41         } else if (u_omit_tex < 1.0) {
     42             color *= texture(u_tex, f_uv);
     43         }
     44         frag_color = color;
     45     }
     46 ));
     47 
     48 //////////////////////////////////////////////////////////////////
     49 // init
     50 
     51 RV_GLOBAL void rvi2d_create(rv_idraw2d_ctx* ctx, rv_arena* arena, rv_command_list_t* create_commands)
     52 {
     53     rvi2d_destroy(ctx, arena, create_commands);
     54 
     55     ctx->arena = rv_arena_alloc();
     56     ctx->permanent_arena = rv_arena_alloc(.commit_size = KB(4), .reserve_size = KB(4));
     57 
     58     // make render objects
     59     ctx->vbo          = rv_push_compound(ctx->permanent_arena, rv_vbo_t,     {.usage = RV_BUFFER_USAGE_DYNAMIC});
     60     ctx->ibo          = rv_push_compound(ctx->permanent_arena, rv_ibo_t,     {.usage = RV_BUFFER_USAGE_DYNAMIC, .elem_size = sizeof(u32)});
     61     rv_shader_t* vert = rv_push_compound(ctx->permanent_arena, rv_shader_t,  {.source = rv_idraw2d_v_src,      .type = RV_SHADER_TYPE_VERTEX});
     62     rv_shader_t* frag = rv_push_compound(ctx->permanent_arena, rv_shader_t,  {.source = rv_idraw2d_f_src,      .type = RV_SHADER_TYPE_FRAGMENT});
     63     ctx->pip          = rv_push(ctx->permanent_arena, rv_pipeline_t);
     64 
     65     // construct pipeline
     66     rv_pipeline_push_shader(arena, ctx->pip, vert);
     67     rv_pipeline_push_shader(arena, ctx->pip, frag);
     68     rv_pipeline_push_vattr(arena,  ctx->pip, RV_VATTR_TYPE_FLOAT2, 0, 0);
     69     rv_pipeline_push_vattr(arena,  ctx->pip, RV_VATTR_TYPE_FLOAT2, 0, 0);
     70     rv_pipeline_push_vattr(arena,  ctx->pip, RV_VATTR_TYPE_FLOAT4, 0, 0);
     71     ctx->u_tex        = rv_pipeline_push_uniform(ctx->permanent_arena, ctx->pip, S("u_tex"),        RV_UNIFORM_TEX);
     72     ctx->u_omit_tex   = rv_pipeline_push_uniform(ctx->permanent_arena, ctx->pip, S("u_omit_tex"),   RV_UNIFORM_F32);
     73     ctx->u_resolution = rv_pipeline_push_uniform(ctx->permanent_arena, ctx->pip, S("u_resolution"), RV_UNIFORM_VEC2);
     74 
     75     // add creation commands
     76     rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_VERTEX,   RV_RENDER_OBJ_OP_CREATE,  ctx->vbo);
     77     rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_INDEX,    RV_RENDER_OBJ_OP_CREATE,  ctx->ibo);
     78     rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_SHADER,   RV_RENDER_OBJ_OP_CREATE,  vert);
     79     rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_SHADER,   RV_RENDER_OBJ_OP_CREATE,  frag);
     80     rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_CREATE,  ctx->pip);
     81     rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_SHADER,   RV_RENDER_OBJ_OP_DESTROY, frag); // don't need anymore
     82     rv_cmd_push_obj(arena, create_commands, RV_COMMAND_OBJ_SHADER,   RV_RENDER_OBJ_OP_DESTROY, vert); // don't need anymore
     83     { // set default uniforms
     84         rv_cmd_push_obj(arena,            create_commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, ctx->pip);
     85         rv_cmd_push_uniform_update(arena, create_commands, ctx->u_omit_tex,   {.v_f32 = 1.0f});
     86         ctx->u_omit_tex_last = 1.0f;
     87         rv_cmd_push_uniform_update(arena, create_commands, ctx->u_resolution, {.v_vec2 = rv_v2(1,1)});
     88         ctx->u_resolution_last = rv_v2(1,1);
     89         rv_cmd_push_obj(arena,            create_commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, NULL);
     90     }
     91 
     92     rv_bump_cache_create(&ctx->vertex, sizeof(rv_vec2) + sizeof(rv_vec2) + sizeof(rv_vec4));
     93     rv_bump_cache_create(&ctx->index, sizeof(u32));
     94 
     95     ctx->default_binds = rv_push(ctx->permanent_arena, rv_command_list_node_t);
     96     rv_cmd_push_obj(ctx->permanent_arena, &ctx->default_binds->commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_BIND, ctx->pip);
     97 
     98     rv_llist_stack_push(ctx->custom_binds_stack, ctx->default_binds);
     99 }
    100 
    101 RV_GLOBAL void rvi2d_destroy(rv_idraw2d_ctx* ctx, rv_arena* arena, rv_command_list_t* destroy_commands)
    102 {
    103     // just use something to check if we're already destroyed
    104     if (ctx->pip) {
    105         // make copies, the memory will be invalid otherwise
    106         rv_vbo_t*      vbo_vertex_copy = rv_push_copy(arena, rv_vbo_t,      ctx->vbo);
    107         rv_ibo_t*      ibo_copy        = rv_push_copy(arena, rv_ibo_t,      ctx->ibo);
    108         rv_pipeline_t* pip_copy        = rv_push_copy(arena, rv_pipeline_t, ctx->ibo);
    109 
    110         rv_cmd_push_obj(arena, destroy_commands, RV_COMMAND_OBJ_VERTEX,   RV_RENDER_OBJ_OP_DESTROY, vbo_vertex_copy);
    111         rv_cmd_push_obj(arena, destroy_commands, RV_COMMAND_OBJ_INDEX,    RV_RENDER_OBJ_OP_DESTROY, ibo_copy);
    112         rv_cmd_push_obj(arena, destroy_commands, RV_COMMAND_OBJ_PIPELINE, RV_RENDER_OBJ_OP_DESTROY, pip_copy);
    113 
    114         rv_arena_release(ctx->arena);
    115         rv_arena_release(ctx->permanent_arena);
    116         rv_bump_cache_destroy(&ctx->vertex);
    117         rv_bump_cache_destroy(&ctx->index);
    118 
    119         *ctx = (rv_idraw2d_ctx){0};
    120     }
    121 }
    122 
    123 //////////////////////////////////////////////////////////////////
    124 // draw
    125 
    126 RV_GLOBAL rv_command_t* rvi2d_draw_and_reset(rv_idraw2d_ctx* ctx, rv_arena* arena, rv_command_list_t* render_commands)
    127 {
    128     rv_command_t* res = rvi2d_break(ctx);
    129 
    130     { // update vbo
    131         rv_command_t update_vbo_cmd = rv_cmd_obj(RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_UPDATE, ctx->vbo);
    132         rv_bump_cache_upload_and_reset(&ctx->vertex, arena, &update_vbo_cmd.obj.vbo_update.data, &update_vbo_cmd.obj.vbo_update.size);
    133         rv_cmd_push_copy(arena, render_commands, update_vbo_cmd);
    134     }
    135 
    136     { // update ibo
    137         rv_command_t update_ibo_cmd = rv_cmd_obj(RV_COMMAND_OBJ_INDEX, RV_RENDER_OBJ_OP_UPDATE, ctx->ibo);
    138         rv_bump_cache_upload_and_reset(&ctx->index, arena, &update_ibo_cmd.obj.ibo_update.data, &update_ibo_cmd.obj.ibo_update.size);
    139         rv_cmd_push_copy(arena, render_commands, update_ibo_cmd);
    140     }
    141 
    142     // push draw commands
    143     rv_render_copy_commands(arena, render_commands, &ctx->commands);
    144 
    145     // check that custom binds steck is where it started
    146     if (ctx->custom_binds_stack->next) {
    147         rv_unreachable();
    148         ctx->custom_binds_stack = NULL;
    149         rv_llist_stack_push(ctx->custom_binds_stack, ctx->default_binds);
    150     }
    151 
    152     ctx->commands = (rv_command_list_t){0};
    153     ctx->last_commited_command = NULL;
    154     ctx->last_bind = NULL;
    155     rv_arena_clear(ctx->arena);
    156 
    157     return res;
    158 }
    159 
    160 //////////////////////////////////////////////////////////////////
    161 // core update functions
    162 
    163 
    164 RV_GLOBAL rv_command_t* rvi2d_break(rv_idraw2d_ctx* ctx)
    165 {
    166     if (ctx->last_bind != ctx->custom_binds_stack) {
    167         rv_render_copy_commands(ctx->arena, &ctx->commands, &ctx->custom_binds_stack->commands);
    168 
    169         // force rebind vbo and ibo
    170         rv_cmd_push_obj(ctx->arena, &ctx->commands, RV_COMMAND_OBJ_VERTEX, RV_RENDER_OBJ_OP_BIND, ctx->vbo);
    171         rv_cmd_push_obj(ctx->arena, &ctx->commands, RV_COMMAND_OBJ_INDEX, RV_RENDER_OBJ_OP_BIND, ctx->ibo);
    172         // force update all uniforms
    173         rv_cmd_push_uniform_update(ctx->arena, &ctx->commands, ctx->u_resolution, {.v_vec2 = ctx->u_resolution_last});
    174         rv_cmd_push_uniform_update(ctx->arena, &ctx->commands, ctx->u_tex,        {.v_tex  = ctx->u_tex_last});
    175         rv_cmd_push_uniform_update(ctx->arena, &ctx->commands, ctx->u_omit_tex,   {.v_f32  = ctx->u_omit_tex_last});
    176 
    177         ctx->last_bind = ctx->custom_binds_stack;
    178     }
    179 
    180     s64 first, count;
    181     rv_bump_cache_break(&ctx->vertex, NULL, NULL);
    182     rv_bump_cache_break(&ctx->index, &first, &count);
    183 
    184     if (count > 0) {
    185         rv_command_t draw_cmd = {
    186             .type = RV_COMMAND_DRAW,
    187             .draw = {
    188                 .first = first,
    189                 .count = count,
    190             }};
    191         rv_cmd_push_copy(ctx->arena, &ctx->commands, draw_cmd);
    192     }
    193 
    194     rv_command_t* first_cmd;
    195     if (ctx->last_commited_command == NULL) {
    196         first_cmd = ctx->commands.first;
    197     } else {
    198         first_cmd = ctx->last_commited_command->next;
    199     }
    200     ctx->last_commited_command = ctx->commands.last;
    201 
    202     return first_cmd;
    203 }
    204 
    205 RV_GLOBAL rv_command_t* rvi2d_camera(rv_idraw2d_ctx* ctx, rv_vec2 screen_size)
    206 {
    207     rv_command_t* res = rvi2d_break(ctx);
    208     rv_cmd_push_uniform_update(ctx->arena, &ctx->commands, ctx->u_resolution, {.v_vec2 = screen_size});
    209     ctx->u_resolution_last = screen_size;
    210 
    211     return res;
    212 }
    213 
    214 RV_GLOBAL rv_command_t* rvi2d_tex(rv_idraw2d_ctx* ctx, rv_texture_t* tex)
    215 {
    216     return rvi2d_tex_ex(ctx, tex, false);
    217 }
    218 
    219 RV_GLOBAL rv_command_t* rvi2d_tex_ex(rv_idraw2d_ctx* ctx, rv_texture_t* tex, bool32 is_red_channel)
    220 {
    221     rv_command_t* res = NULL;
    222     if (ctx->last_tex == tex) {
    223         // nothing to change
    224     } else {
    225         res = rvi2d_break(ctx);
    226 
    227         rv_cmd_push_uniform_update(ctx->arena, &ctx->commands, ctx->u_tex, {.v_tex = tex});
    228         ctx->u_tex_last = tex;
    229 
    230         if (tex) {
    231             rv_cmd_push_uniform_update(ctx->arena, &ctx->commands, ctx->u_omit_tex, {.v_f32 = is_red_channel ? -1.0f : 0.0f});
    232             ctx->u_omit_tex_last = is_red_channel ? -1.0f : 0.0f;
    233         } else {
    234             rv_cmd_push_uniform_update(ctx->arena, &ctx->commands, ctx->u_omit_tex, {.v_f32 = 1.0f});
    235             ctx->u_omit_tex_last = 1.0f;
    236         }
    237 
    238         ctx->last_tex = tex;
    239     }
    240 
    241     return res;
    242 }
    243 
    244 RV_GLOBAL rv_command_t* rvi2d_custom_binds_push(rv_idraw2d_ctx* ctx, rv_command_list_t* copy_binds)
    245 {
    246     rv_command_t* res = rvi2d_break(ctx);
    247 
    248     rv_command_list_node_t* n = rv_push(ctx->arena, rv_command_list_node_t);
    249     rv_render_copy_commands(ctx->arena, &ctx->commands, copy_binds);
    250     rv_llist_stack_push(ctx->custom_binds_stack, n);
    251 
    252     return res;
    253 
    254 }
    255 
    256 RV_GLOBAL rv_command_t* rvi2d_custom_binds_pop(rv_idraw2d_ctx* ctx)
    257 {
    258     rv_command_t* res = rvi2d_break(ctx);
    259 
    260     rv_command_list_node_t* tmp = ctx->custom_binds_stack;
    261     rv_llist_stack_pop(ctx->custom_binds_stack);
    262     tmp->next = NULL;
    263 
    264     if (!ctx->custom_binds_stack) {
    265         rv_unreachable();
    266         rv_llist_stack_push(ctx->custom_binds_stack, ctx->default_binds);
    267     }
    268 
    269     return res;
    270 }
    271 
    272 RV_GLOBAL void rvi2d_triangle(rv_idraw2d_ctx* ctx,
    273                               rv_vec2 pos_a, rv_vec2 pos_b, rv_vec2 pos_c,
    274                               rv_vec2  uv_a,  rv_vec2 uv_b,  rv_vec2 uv_c,
    275                               rv_color_t color)
    276 {
    277     u32 last_index = ctx->vertex.total_count;
    278 
    279     rv_vec4 c = rv_vec4_from_color(color);
    280     struct {
    281         rv_vec2 pos, uv;
    282         rv_vec4 color;
    283     } copy_from[3] = {
    284         {.pos = pos_a, .uv = uv_a, .color = c},
    285         {.pos = pos_b, .uv = uv_b, .color = c},
    286         {.pos = pos_c, .uv = uv_c, .color = c},
    287     };
    288     rv_bump_cache_push_many(&ctx->vertex, &copy_from, 3);
    289 
    290     u32 indices[3] = {last_index + 0, last_index + 1, last_index + 2};
    291     rv_bump_cache_push_many(&ctx->index, &indices, 3);
    292 }
    293 
    294 RV_GLOBAL void rvi2d_quad(rv_idraw2d_ctx* ctx,
    295                           rv_vec2 pos_tl, rv_vec2 pos_tr, rv_vec2 pos_bl, rv_vec2 pos_br,
    296                           rv_vec2  uv_tl, rv_vec2  uv_tr,  rv_vec2 uv_bl,  rv_vec2 uv_br,
    297                           rv_color_t color)
    298 {
    299     u32 index_begin = ctx->vertex.total_count;
    300 
    301     rv_vec4 c = rv_vec4_from_color(color);
    302     struct {
    303         rv_vec2 pos, uv;
    304         rv_vec4 color;
    305     } copy_from[4] = {
    306         {.pos = pos_tl, .uv = uv_tl, .color = c},
    307         {.pos = pos_tr, .uv = uv_tr, .color = c},
    308         {.pos = pos_bl, .uv = uv_bl, .color = c},
    309         {.pos = pos_br, .uv = uv_br, .color = c},
    310     };
    311     rv_bump_cache_push_many(&ctx->vertex, &copy_from, 4);
    312 
    313     u32 indices[6] = {
    314         index_begin + 0, // tl     +--+
    315         index_begin + 1, // tr     | /
    316         index_begin + 2, // bl     +/
    317         index_begin + 1, // tr       /+
    318         index_begin + 2, // bl      / |
    319         index_begin + 3, // br     +--+
    320     };
    321     rv_bump_cache_push_many(&ctx->index, &indices, 6);
    322 }
    323 
    324 //////////////////////////////////////////////////////////////////
    325 // helpers functions
    326 
    327 RV_GLOBAL void rvi2d_rect(rv_idraw2d_ctx* ctx, rv_rect rect, rv_color_t color)
    328 {
    329     rvi2d_quad(ctx,
    330                rv_vec2_add(rect.xy, rv_v2(0,      0)),
    331                rv_vec2_add(rect.xy, rv_v2(rect.w, 0)),
    332                rv_vec2_add(rect.xy, rv_v2(0,      rect.h)),
    333                rv_vec2_add(rect.xy, rv_v2(rect.w, rect.h)),
    334                rv_v2(0,0), rv_v2(1,0), rv_v2(0,1), rv_v2(1,1), color);
    335 }
    336 RV_GLOBAL void rvi2d_line(rv_idraw2d_ctx* ctx, rv_vec2 a, rv_vec2 b, f32 thickness, rv_color_t color)
    337 {
    338     rv_unreachable(); // not implemented
    339 }
    340 RV_GLOBAL void rvi2d_circle(rv_idraw2d_ctx* ctx, rv_vec2 center, f32 radius, s32 segments)
    341 {
    342     rv_unreachable(); // not implemented
    343 }
    344 
    345 RV_GLOBAL rv_command_t* rvi2d_text(rv_idraw2d_ctx* ctx, rv_ascii_font_t* font, rv_vec2 bl_first, rv_str8 str, rv_color_t color)
    346 {
    347     rv_command_t* res = rvi2d_tex_ex(ctx, font->tex, true);
    348 
    349     rv_vec2 cursor = bl_first;
    350     for (s32 i = 0; i < str.len; i++) {
    351         if (str.str[i] == '\n') {
    352             cursor.x = bl_first.x;
    353             cursor.y += font->linedist;
    354             continue;
    355         }
    356 
    357         if (str.str[i] < 32 || str.str[i] > 128) continue;
    358 
    359         stbtt_packedchar c = font->cdata[str.str[i] - 32];
    360 
    361         rv_vec2 off1 = rv_v2(c.xoff, c.yoff);
    362         rv_vec2 off2 = rv_v2(c.xoff2, c.yoff2);
    363 
    364         rv_rect r = {0};
    365         r.x = rv_min(off1.x, off2.x);
    366         r.y = rv_min(off1.y, off2.y);
    367         r.w = fabsf(off1.x - off2.x);
    368         r.h = fabsf(off1.y - off2.y);
    369         r.xy = rv_vec2_add(r.xy, cursor);
    370 
    371         rv_vec2 uv_tr = rv_vec2_div(rv_v2(c.x1, c.y1), font->tex->size);
    372         rv_vec2 uv_bl = rv_vec2_div(rv_v2(c.x0, c.y0), font->tex->size);
    373         rv_vec2 uv_tl = rv_v2(uv_bl.x, uv_tr.y);
    374         rv_vec2 uv_br = rv_v2(uv_tr.x, uv_bl.y);
    375 
    376         rvi2d_quad(ctx,
    377                    rv_vec2_add(r.xy, rv_v2(0,   0)),
    378                    rv_vec2_add(r.xy, rv_v2(r.w, 0)),
    379                    rv_vec2_add(r.xy, rv_v2(0,   r.h)),
    380                    rv_vec2_add(r.xy, rv_v2(r.w, r.h)),
    381                    uv_bl, uv_br, uv_tl, uv_tr,
    382                    color);
    383 
    384         cursor.x += c.xadvance;
    385     }
    386 
    387     return res;
    388 }