diff --git a/include/drawglx_internal.h b/include/drawglx_internal.h index ce4409d..f62bce1 100644 --- a/include/drawglx_internal.h +++ b/include/drawglx_internal.h @@ -8,51 +8,112 @@ #pragma once #include "drawglx.h" +#include "programs.h" #include "vector.h" #include "vec234.h" #include "mat4.h" -enum -{ - PROGRAM_TRIANGLES_PLAIN, - PROGRAM_TRIANGLES_TEXTURED, - PROGRAM_FREETYPE, - PROGRAM_COUNT -}; - -typedef void(*program_callback_fn)(struct draw_cmd *); -typedef void(*program_callback_empty_fn)(); - -struct program_t -{ - vertex_buffer_t *vertex; - GLuint shader; - - program_callback_empty_fn init; - program_callback_empty_fn load; - program_callback_fn render; - program_callback_empty_fn unload; - program_callback_empty_fn destroy; -}; - -void -program_init_inplace(struct program_t *program, const char *vertex_format, const char *shader_frag, const char *shader_vert, program_callback_empty_fn init, program_callback_empty_fn load, program_callback_fn render, program_callback_empty_fn unload, program_callback_empty_fn destroy); - -struct program_t programs[PROGRAM_COUNT]; - int drawglx_internal_init(); +enum +{ + DI_INVALID_INSTRUCTION, + DI_SWITCH_PROGRAM, + DI_PUSH_VERTICES, + DI_PUSH_INDICES, + DI_PROGRAM_SWITCH_TEXTURE, + DI_PROGRAM_SWITCH_FONT, + DI_TERMINATE +}; + +struct draw_instruction_t +{ + int type; + union + { + /* DI_SWITCH_PROGRAM */ + int program; + /* DI_PUSH_VERTICES / DI_PUSH_INDICES */ + size_t count; + /* DI_PROGRAM_SWITCH_TEXTURE */ + GLuint texture; + /* DI_PROGRAM_SWITCH_FONT */ + texture_font_t *font; + }; +}; + +struct draw_instruction_stream_t +{ + void *memory; + size_t capacity; + size_t write_ptr; + size_t read_ptr; + size_t last_draw_instruction_offset; +}; + +struct draw_instruction_stream_t dstream; + +void +dis_init(); + +void +dis_destroy(); + +void +dis_reset(); + +void +dis_reserve(size_t bytes); + +struct draw_instruction_t* +dis_last_pushed_instruction(); + +void +dis_push_data(size_t bytes, void *data); + +void +dis_push_instruction(struct draw_instruction_t instr); + +size_t +dis_fetch_data(size_t bytes, void *data); + +void +dis_switch_program(int program); + +void +dis_push_vertices(size_t count, size_t vertex_size, void *vertex_data); + +void +dis_push_indices(size_t count, GLuint *index_data); + +void +dis_program_switch_texture(GLuint texture); + +void +dis_program_switch_font(texture_font_t *font); + +void +dis_finish(); + +struct draw_instruction_t* +dis_fetch_instruction(); + struct draw_cmd { vector_t *vertices; + vector_t *indices; + int program; - GLuint texture; + struct program_data_t data; }; struct draw_cmd* -draw_cmd_new(); +draw_cmd_new(int program); + +void +draw_cmd_delete(struct draw_cmd *cmd); struct draw_state { @@ -67,28 +128,48 @@ struct draw_state struct size_t current_command; }; -struct draw_state drawstate; +struct draw_state ds; void -draw_state_init(); +ds_init(); void -draw_state_next_command(); +ds_destroy(); void -draw_state_free(); +ds_alloc_next_command(int program); void -draw_state_clear(); +ds_next_frame(); void -draw_state_render(); +ds_render(); void -draw_set_texture(GLuint texture); +ds_prepare_command(int program); + +/* Primitive Internal Drawing API */ void -draw_line(float x, float y, float x2, float y2); +draw_line(vec2 xy, vec2 delta, vec4 color); void -draw_rect(float x, float y, float w, float h); +draw_rect(vec2 xy, vec2 hw, vec4 color); + +void +draw_rect_outline(vec2 xy, vec2 hw, vec4 color); + +void +draw_rect_textured(vec2 xy, vec2 hw, vec4 color, int texture, vec2 uv, vec2 st); + +void +draw_string(vec2 xy, const char *string, texture_font_t *font, vec4 color); + +void +draw_string_outline(vec2 xy, const char *string, texture_font_t *font, vec4 color); + +void +draw_string_with_outline(vec2 xy, const char *string, texture_font_t *font, vec4 color, vec4 outline_color); + +void +get_string_size(const char *string, texture_font_t *font, vec2 *out); diff --git a/include/programs.h b/include/programs.h index c36384e..3234aa7 100644 --- a/include/programs.h +++ b/include/programs.h @@ -7,27 +7,81 @@ #pragma once +#include "freetype-gl.h" + +struct draw_cmd; + #define PROGRAM_INIT(name) program_##name##_init #define PROGRAM_LOAD(name) program_##name##_load #define PROGRAM_RENDER(name) program_##name##_render #define PROGRAM_UNLOAD(name) program_##name##_unload #define PROGRAM_DESTROY(name) program_##name##_destroy +#define PROGRAM_CHECK(name) program_##name##_check #define DECL_PROGRAM_INIT(name) void program_##name##_init() #define DECL_PROGRAM_LOAD(name) void program_##name##_load() #define DECL_PROGRAM_RENDER(name) void program_##name##_render(struct draw_cmd *cmd) #define DECL_PROGRAM_UNLOAD(name) void program_##name##_unload() #define DECL_PROGRAM_DESTROY(name) void program_##name##_destroy() +#define DECL_PROGRAM_CHECK(name) int program_##name##_check(struct draw_cmd *cmd, void *data) #define DECL_PROGRAM(name) \ DECL_PROGRAM_INIT(name); \ DECL_PROGRAM_LOAD(name); \ DECL_PROGRAM_RENDER(name); \ DECL_PROGRAM_UNLOAD(name); \ - DECL_PROGRAM_DESTROY(name) + DECL_PROGRAM_DESTROY(name); \ + DECL_PROGRAM_CHECK(name) + +enum +{ + PROGRAM_TRIANGLES_PLAIN, + PROGRAM_TRIANGLES_TEXTURED, + PROGRAM_FREETYPE, + PROGRAM_COUNT +}; + +typedef void(*program_callback_fn)(struct draw_cmd *); +typedef void(*program_callback_empty_fn)(); +typedef int(*program_callback_check_command_fn)(struct draw_cmd *cmd, void *data); + +struct program_t +{ + vertex_buffer_t *vertex; + GLuint shader; + + program_callback_empty_fn init; + program_callback_empty_fn load; + program_callback_fn render; + program_callback_empty_fn unload; + program_callback_empty_fn destroy; + program_callback_check_command_fn check; +}; + +void +program_init_inplace(struct program_t *program, const char *vertex_format, const char *shader_frag, const char *shader_vert, program_callback_empty_fn init, program_callback_empty_fn load, program_callback_fn render, program_callback_empty_fn unload, program_callback_empty_fn destroy, program_callback_check_command_fn check); + +struct program_t programs[PROGRAM_COUNT]; + +struct program_data_t +{ + union + { + struct + { + int pad; + } triangles_plain; + struct + { + GLuint texture; + } triangles_textured; + struct + { + texture_font_t *font; + } freetype; + }; +}; DECL_PROGRAM(triangles_plain); DECL_PROGRAM(triangles_textured); DECL_PROGRAM(freetype); - -void program_noop() {}; diff --git a/include/vertex_structs.h b/include/vertex_structs.h new file mode 100644 index 0000000..df049ca --- /dev/null +++ b/include/vertex_structs.h @@ -0,0 +1,37 @@ +/* + * vertex_structs.h + * + * Created on: Nov 10, 2017 + * Author: nullifiedcat + */ + +#pragma once + +/* Used for drawing primitives */ +struct vertex_v2fc4f +{ + float x; + float y; + + float r; + float g; + float b; + float a; +}; + +/* Used for drawing textured primitives and freetype-gl fonts */ +struct vertex_v2ft2fc4f +{ + float x; + float y; + + float s; + float t; + + float r; + float g; + float b; + float a; +}; + + diff --git a/src/drawglx_internal.c b/src/drawglx_internal.c index fe28671..a6bb438 100644 --- a/src/drawglx_internal.c +++ b/src/drawglx_internal.c @@ -7,38 +7,274 @@ #include "drawglx_internal.h" -struct draw_state* -draw_state_init(size_t vertex_size) +#include +#include + +int +drawglx_internal_init() { - struct draw_state *result = calloc(1, sizeof(struct draw_state)); - result->commands = vector_new(sizeof(struct draw_cmd)); - result->current_command = -1; - return result; + return 0; } void -draw_state_next_command(struct draw_state *state) +dis_init() { - + dstream.capacity = 128; + dstream.memory = malloc(dstream.capacity); + struct draw_instruction_t *instr = dstream.memory; + instr->type = DI_INVALID_INSTRUCTION; } void -draw_state_free(struct draw_state *state) +dis_destroy() { - + free(dstream.memory); } void -draw_state_clear(struct draw_state *state) +dis_reset() { - for (int i = 0; i < vector_size(state->commands); ++i) + dstream.write_ptr = 0; + dstream.read_ptr = 0; +} + +void +dis_reserve(size_t bytes) +{ + while (dstream.write_ptr + bytes > dstream.capacity) { - struct draw_cmd *current = vector_get(state->commands, i); + dstream.capacity *= 2; + dstream.memory = realloc(dstream.memory, dstream.capacity); + } +} + +struct draw_instruction_t* +dis_last_pushed_instruction() +{ + if (dstream.write_ptr == 0) + { + return NULL; + } + return (struct draw_instruction_t *)(dstream.memory + dstream.last_draw_instruction_offset); +} + +void +dis_push_data(size_t bytes, void *data) +{ + dis_reserve(bytes); + memcpy(dstream.memory + dstream.write_ptr, data, bytes); + dstream.write_ptr += bytes; +} + +void +dis_push_instruction(struct draw_instruction_t instr) +{ + dstream.last_draw_instruction_offset = dstream.write_ptr; + dis_push_data(sizeof(struct draw_instruction_t), &instr); +} + +size_t +dis_fetch_data(size_t bytes, void *data) +{ + size_t read_count = bytes; + if (dstream.read_ptr + bytes < dstream.capacity) + read_count = dstream.capacity - dstream.read_ptr; + memcpy(data, dstream.memory + dstream.read_ptr, bytes); + dstream.read_ptr += bytes; + return read_count; +} + +void +dis_switch_program(int program) +{ + struct draw_instruction_t *last = dis_last_pushed_instruction(); + + if (last && last->type == DI_SWITCH_PROGRAM) + { + last->program = program; + return; + } + else + { + struct draw_instruction_t instr; + + instr.type = DI_SWITCH_PROGRAM; + instr.program = program; + dis_push_instruction(instr); } } void -draw_state_render(struct draw_state *state) +dis_push_vertices(size_t count, size_t vertex_size, void *vertex_data) +{ + struct draw_instruction_t *last = dis_last_pushed_instruction(); + + if (last && (last->type == DI_PUSH_VERTICES)) + { + dis_push_data(count * vertex_size, vertex_data); + last->count += count; + return; + } + else + { + struct draw_instruction_t instr; + + instr.type = DI_PUSH_VERTICES; + instr.count = count; + dis_push_instruction(instr); + dis_push_data(count * vertex_size, vertex_data); + } +} + +void +dis_push_indices(size_t count, GLuint *index_data) +{ + struct draw_instruction_t *last = dis_last_pushed_instruction(); + + if (last && (last->type == DI_PUSH_INDICES)) + { + dis_push_data(count * sizeof(GLuint), index_data); + last->count += count; + return; + } + else + { + struct draw_instruction_t instr; + + instr.type = DI_PUSH_INDICES; + instr.count = count; + dis_push_instruction(instr); + dis_push_data(count * sizeof(GLuint), index_data); + } +} + +void +dis_program_switch_texture(GLuint texture) +{ + struct draw_instruction_t *last = dis_last_pushed_instruction(); + + if (last && last->type == DI_PROGRAM_SWITCH_TEXTURE) + { + last->texture = texture; + return; + } + else + { + struct draw_instruction_t instr; + + instr.type = DI_PROGRAM_SWITCH_TEXTURE; + instr.texture = texture; + dis_push_instruction(instr); + } +} + +void +dis_program_switch_font(texture_font_t *font) +{ + struct draw_instruction_t *last = dis_last_pushed_instruction(); + + if (last && last->type == DI_PROGRAM_SWITCH_FONT) + { + last->font = font; + return; + } + else + { + struct draw_instruction_t instr; + + instr.type = DI_PROGRAM_SWITCH_FONT; + instr.font = font; + dis_push_instruction(instr); + } +} + +struct draw_instruction_t terminate = { .type = DI_TERMINATE }; + +void +dis_finish() +{ + dis_push_instruction(terminate); +} + +struct draw_instruction_t* +dis_fetch_instruction() +{ + if (dstream.read_ptr + sizeof(struct draw_instruction_t) > dstream.capacity) + return NULL; + struct draw_instruction_t *result; + result = (struct draw_instruction_t *)(dstream.memory + dstream.read_ptr); + dstream.read_ptr += sizeof(struct draw_instruction_t); + return result; +} + +struct draw_cmd* +draw_cmd_new(int program) +{ + struct draw_cmd *result = calloc(1, sizeof(struct draw_cmd)); + result->program = program; + result->vertices = vector_new(programs[program]->vertex->vertices->item_size); + result->indices = vector_new(programs[program]->vertex->indices->item_size); + return result; +} + +void +draw_cmd_delete(struct draw_cmd *cmd) +{ + vector_delete(cmd->vertices); + vector_delete(cmd->indices); + free(cmd); +} + +void +ds_init() +{ + memset(&ds, 0, sizeof(struct draw_state)); + ds.commands = vector_new(sizeof(struct draw_cmd)); + vector_push_back(ds.commands, calloc(1, sizeof(struct draw_cmd))); + ds.current_command = 0; +} + +void +ds_destroy() +{ + for (int i = 0; i < ds.commands->size; ++i) + { + struct draw_cmd *cmd = vector_get(ds.commands, i); + draw_cmd_delete(cmd); + } + vector_delete(ds.commands); +} + +void +ds_alloc_next_command(int program) +{ + struct draw_cmd *result = calloc(1, sizeof(struct draw_cmd)); + result->program = program; + vector_push_back(ds.commands, result); + ds.current_command++; +} + +void +ds_next_frame() +{ + for (int i = 0; i < ds.commands->size; ++i) + { + struct draw_cmd *cmd = vector_get(ds.commands, i); + draw_cmd_delete(cmd); + } + vector_resize(ds.commands, 1); + memset(vector_get(ds.commands, 0), 0, sizeof(struct draw_cmd)); + ds.current_command = 0; +} + +void +ds_render() +{ + +} + +void +ds_render() { for (int i = 0; i < vector_size(state->commands); ++i) { @@ -69,19 +305,70 @@ draw_state_render(struct draw_state *state) } void -draw_set_texture(struct draw_state *state, GLuint texture) +ds_prepare_command(int program) { + int should_alloc_command = 0; + struct draw_cmd *current = vector_get(ds.commands, ds.current_command); + + if (current == NULL) + should_alloc_command = 1; + else if (program != current->program) + should_alloc_command = 1; + else if (programs[program].check && !programs[program].check(current)) + should_alloc_command = 1; + + if (should_alloc_command) + { + ds_alloc_next_command(); + } +} + +void +draw_line(vec2 xy, vec2 delta, vec4 color) +{ + ds_prepare_command(PROGRAM_TRIANGLES_PLAIN); + vertex_buffer_delete(); +} + +void +draw_rect(vec2 xy, vec2 hw, vec4 color) +{ + ds_prepare_command(PROGRAM_TRIANGLES_PLAIN); } void -draw_line(struct draw_state *state, float x, float y, float x2, float y2) +draw_rect_outline(vec2 xy, vec2 hw, vec4 color) { - + ds_prepare_command(PROGRAM_TRIANGLES_PLAIN); } void -draw_rect(struct draw_state *state, float x, float y, float w, float h) +draw_rect_textured(vec2 xy, vec2 hw, vec4 color, int texture, vec2 uv, vec2 st) +{ + ds_prepare_command(PROGRAM_TRIANGLES_TEXTURED); +} + +void +draw_string(vec2 xy, const char *string, texture_font_t *font, vec4 color) +{ + ds_prepare_command(PROGRAM_FREETYPE); +} + +void +draw_string_outline(vec2 xy, const char *string, texture_font_t *font, vec4 color) +{ + ds_prepare_command(PROGRAM_FREETYPE); +} + +void +draw_string_with_outline(vec2 xy, const char *string, texture_font_t *font, vec4 color, vec4 outline_color) +{ + ds_prepare_command(PROGRAM_FREETYPE); +} + +void +get_string_size(const char *string, texture_font_t *font, vec2 *out) { }