/* * Mr. 4th Dimention - Allen Webster * * 10.11.2017 * * Render target function implementations. * */ // TOP internal void draw__begin_new_group(Render_Target *target){ Render_Group *group = 0; if (target->group_last != 0){ if (target->group_last->vertex_list.vertex_count == 0){ group = target->group_last; } } if (group == 0){ group = push_array_zero(&target->arena, Render_Group, 1); sll_queue_push(target->group_first, target->group_last, group); } group->face_id = target->current_face_id; group->clip_box = target->current_clip_box; } internal Render_Vertex_Array_Node* draw__extend_group_vertex_memory(Arena *arena, Render_Vertex_List *list, i32 size){ Render_Vertex_Array_Node *node = push_array_zero(arena, Render_Vertex_Array_Node, 1); sll_queue_push(list->first, list->last, node); node->vertices = push_array(arena, Render_Vertex, size); node->vertex_max = size; return(node); } internal void draw__write_vertices_in_current_group(Render_Target *target, Render_Vertex *vertices, i32 count){ if (count > 0){ Render_Group *group = target->group_last; if (group == 0){ draw__begin_new_group(target); group = target->group_last; } Render_Vertex_List *list = &group->vertex_list; Render_Vertex_Array_Node *last = list->last; Render_Vertex *tail_vertex = 0; i32 tail_count = 0; if (last != 0){ tail_vertex = last->vertices + last->vertex_count; tail_count = last->vertex_max - last->vertex_count; } i32 base_vertex_max = 64; i32 transfer_count = clamp_top(count, tail_count); if (transfer_count > 0){ block_copy_dynamic_array(tail_vertex, vertices, transfer_count); last->vertex_count += transfer_count; list->vertex_count += transfer_count; base_vertex_max = last->vertex_max; } i32 count_left_over = count - transfer_count; if (count_left_over > 0){ Render_Vertex *vertices_left_over = vertices + transfer_count; i32 next_node_size = (base_vertex_max + count_left_over)*2; Render_Vertex_Array_Node *memory = draw__extend_group_vertex_memory(&target->arena, list, next_node_size); block_copy_dynamic_array(memory->vertices, vertices_left_over, count_left_over); memory->vertex_count += count_left_over; list->vertex_count += count_left_over; } } } internal void draw__set_clip_box(Render_Target *target, Rect_i32 clip_box){ if (target->current_clip_box != clip_box){ target->current_clip_box = clip_box; draw__begin_new_group(target); } } internal void draw__set_face_id(Render_Target *target, Face_ID face_id){ if (target->current_face_id != face_id){ if (target->current_face_id != 0){ target->current_face_id = face_id; draw__begin_new_group(target); } else{ target->current_face_id = face_id; for (Render_Group *group = target->group_first; group != 0; group = group->next){ group->face_id = face_id; } } } } //////////////////////////////// internal void draw_push_clip(Render_Target *target, Rect_i32 clip_box){ if (target->clip_top != -1){ clip_box = intersection_of(clip_box, target->clip_boxes[target->clip_top]); } Assert(target->clip_top + 1 < ArrayCount(target->clip_boxes)); target->clip_boxes[++target->clip_top] = clip_box; draw__set_clip_box(target, clip_box); } internal Rect_i32 draw_pop_clip(Render_Target *target){ Assert(target->clip_top > 0); i32_Rect result = target->clip_boxes[target->clip_top]; --target->clip_top; i32_Rect clip_box = target->clip_boxes[target->clip_top]; draw__set_clip_box(target, clip_box); return(result); } internal void draw_change_clip(Render_Target *target, Rect_i32 clip_box){ Assert(target->clip_top > -1); target->clip_boxes[target->clip_top] = clip_box; draw__set_clip_box(target, clip_box); } internal void begin_frame(Render_Target *target, void *font_set){ linalloc_clear(&target->arena); target->group_first = 0; target->group_last = 0; target->current_face_id = 0; target->current_clip_box = Ri32(0, 0, target->width, target->height); target->font_set = font_set; } internal void begin_render_section(Render_Target *target, System_Functions *system, i32 frame_index, f32 literal_dt, f32 animation_dt){ target->clip_top = -1; i32_Rect clip; clip.x0 = 0; clip.y0 = 0; clip.x1 = target->width; clip.y1 = target->height; draw_push_clip(target, clip); target->frame_index = frame_index; target->literal_dt = literal_dt; target->animation_dt = animation_dt; } internal void end_render_section(Render_Target *target, System_Functions *system){ Assert(target->clip_top == 0); } //////////////////////////////// internal void draw_rectangle(Render_Target *target, Rect_f32 rect, u32 color){ Render_Vertex vertices[6] = {}; vertices[0].xy = V2(rect.x0, rect.y0); vertices[1].xy = V2(rect.x1, rect.y0); vertices[2].xy = V2(rect.x0, rect.y1); vertices[3].xy = V2(rect.x1, rect.y0); vertices[4].xy = V2(rect.x0, rect.y1); vertices[5].xy = V2(rect.x1, rect.y1); Vec4 c = unpack_color4(color); for (i32 i = 0; i < 6; i += 1){ vertices[i].color = c; } draw__write_vertices_in_current_group(target, vertices, 6); } internal void draw_font_glyph(Render_Target *target, Face *face, u32 codepoint, f32 x, f32 y, u32 color, u32 flags){ draw__set_face_id(target, face->id); u16 glyph_index = 0; if (!codepoint_index_map_read(&face->codepoint_to_index_map, codepoint, &glyph_index)){ glyph_index = 0; } Glyph_Bounds bounds = face->bounds[glyph_index]; Vec3_f32 texture_dim = face->texture_dim; Rect_f32 uv = bounds.uv; Render_Vertex vertices[6] = {}; if (!HasFlag(flags, GlyphFlag_Rotate90)){ f32_Rect xy = Rf32(x + bounds.xy_off.x0, y + bounds.xy_off.y0, x + bounds.xy_off.x1, y + bounds.xy_off.y1); vertices[0].xy = V2(xy.x0, xy.y1); vertices[0].uvw = V3(uv.x0, uv.y1, bounds.w); vertices[1].xy = V2(xy.x1, xy.y1); vertices[1].uvw = V3(uv.x1, uv.y1, bounds.w); vertices[2].xy = V2(xy.x0, xy.y0); vertices[2].uvw = V3(uv.x0, uv.y0, bounds.w); vertices[5].xy = V2(xy.x1, xy.y0); vertices[5].uvw = V3(uv.x1, uv.y0, bounds.w); } else{ f32_Rect xy = Rf32(x - bounds.xy_off.y1, y + bounds.xy_off.x0, x - bounds.xy_off.y0, y + bounds.xy_off.x1); vertices[0].xy = V2(xy.x0, xy.y1); vertices[0].uvw = V3(uv.x1, uv.y1, bounds.w); vertices[1].xy = V2(xy.x1, xy.y1); vertices[1].uvw = V3(uv.x1, uv.y0, bounds.w); vertices[2].xy = V2(xy.x0, xy.y0); vertices[2].uvw = V3(uv.x0, uv.y1, bounds.w); vertices[5].xy = V2(xy.x1, xy.y0); vertices[5].uvw = V3(uv.x0, uv.y0, bounds.w); } vertices[3] = vertices[1]; vertices[4] = vertices[2]; Vec4 c = unpack_color4(color); for (i32 i = 0; i < 6; i += 1){ vertices[i].color = c; } draw__write_vertices_in_current_group(target, vertices, 6); } //////////////////////////////// internal void draw_rectangle_outline(Render_Target *target, f32_Rect rect, u32 color){ draw_rectangle(target, Rf32(rect.x0, rect.y0, rect.x1, rect.y0 + 1), color); draw_rectangle(target, Rf32(rect.x1 - 1, rect.y0, rect.x1, rect.y1), color); draw_rectangle(target, Rf32(rect.x0, rect.y1 - 1, rect.x1, rect.y1), color); draw_rectangle(target, Rf32(rect.x0, rect.y0, rect.x0 + 1, rect.y1), color); } //////////////////////////////// internal void draw_rectangle(Render_Target *target, i32_Rect rect, u32 color){ draw_rectangle(target, f32R(rect), color); } internal void draw_rectangle_outline(Render_Target *target, i32_Rect rect, u32 color){ draw_rectangle_outline(target, f32R(rect), color); } internal void draw_margin(Render_Target *target, f32_Rect outer, f32_Rect inner, u32 color){ draw_rectangle(target, f32R(outer.x0, outer.y0, outer.x1, inner.y0), color); draw_rectangle(target, f32R(outer.x0, inner.y1, outer.x1, outer.y1), color); draw_rectangle(target, f32R(outer.x0, inner.y0, inner.x0, inner.y1), color); draw_rectangle(target, f32R(inner.x1, inner.y0, outer.x1, inner.y1), color); } internal void draw_margin(Render_Target *target, f32_Rect outer, f32 width, u32 color){ f32_Rect inner = rect_inner(outer, width); draw_margin(target, outer, inner, color); } internal void draw_margin(Render_Target *target, i32_Rect outer, i32_Rect inner, u32 color){ draw_rectangle(target, i32R(outer.x0, outer.y0, outer.x1, inner.y0), color); draw_rectangle(target, i32R(outer.x0, inner.y1, outer.x1, outer.y1), color); draw_rectangle(target, i32R(outer.x0, inner.y0, inner.x0, inner.y1), color); draw_rectangle(target, i32R(inner.x1, inner.y0, outer.x1, inner.y1), color); } internal void draw_margin(Render_Target *target, i32_Rect outer, i32 width, u32 color){ i32_Rect inner = rect_inner(outer, width); draw_margin(target, outer, inner, color); } internal Vec2 snap_point_to_boundary(Vec2 point){ point.x = (f32)(floor32(point.x)); point.y = (f32)(floor32(point.y)); return(point); } internal f32 draw_string(Render_Target *target, Face *face, String_Const_u8 string, Vec2 point, u32 color, u32 flags, Vec2 delta){ f32 total_delta = 0.f; if (face != 0){ point = snap_point_to_boundary(point); f32 byte_advance = face->byte_advance; f32 *byte_sub_advances = face->byte_sub_advances; u8 *str = (u8*)string.str; u8 *str_end = str + string.size; Translation_State tran = {}; Translation_Emits emits = {}; for (u32 i = 0; str < str_end; ++str, ++i){ translating_fully_process_byte(&tran, *str, i, (i32)string.size, &emits); for (TRANSLATION_DECL_EMIT_LOOP(J, emits)){ TRANSLATION_DECL_GET_STEP(step, behavior, J, emits); if (behavior.do_codepoint_advance){ u32 codepoint = step.value; if (color != 0){ draw_font_glyph(target, face, codepoint, point.x, point.y, color, flags); } f32 d = font_get_glyph_advance(face, codepoint); point += d*delta; total_delta += d; } else if (behavior.do_number_advance){ u8 n = (u8)(step.value); if (color != 0){ u8 cs[3]; cs[0] = '\\'; byte_to_ascii(n, cs+1); Vec2 pp = point; for (u32 j = 0; j < 3; ++j){ draw_font_glyph(target, face, cs[j], pp.x, pp.y, color, flags); pp += delta*byte_sub_advances[j]; } } point += byte_advance*delta; total_delta += byte_advance; } } } } return(total_delta); } internal f32 draw_string(Render_Target *target, Face *face, String_Const_u8 string, Vec2 point, u32 color){ return(draw_string(target, face, string, point, color, 0, V2(1.f, 0.f))); } internal f32 draw_string(Render_Target *target, Face *face, u8 *str, Vec2 point, u32 color, u32 flags, Vec2 delta){ return(draw_string(target, face, SCu8(str), point, color, flags, delta)); } internal f32 draw_string(Render_Target *target, Face *face, u8 *str, Vec2 point, u32 color){ return(draw_string(target, face, SCu8(str), point, color, 0, V2(1.f, 0.f))); } internal f32 font_string_width(Render_Target *target, Face *face, String_Const_u8 str){ return(draw_string(target, face, str, V2(0, 0), 0, 0, V2(0, 0))); } internal f32 font_string_width(Render_Target *target, Face *face, u8 *str){ return(draw_string(target, face, SCu8(str), V2(0, 0), 0, 0, V2(0, 0))); } // BOTTOM