struct ScreenVertex {
float xy[2];
float rgba[4];
float st[2];
};
enum Sampler { Sampler_NEAREST, Sampler_LINEAR, NUM_BACKEND_SAMPLERS };
ENGINE_ENUM(r_window_mode, 0, "",
(windowed, 0, ""),
(fullscreen, 1, ""),
(borderless, 2, "")
)
ENGINE_INTEGER(r_monitor, -1, "Chosen monitor index for fullscreen, -1 gets the primary monitor")
ENGINE_INTEGER(r_window_width, 0, "desired width of window")
ENGINE_INTEGER(r_window_height, 0, "desired height of window")
static uint32_t _r_width;
static uint32_t _r_height;
static GLFWwindow * _r_window;
static inline void prepare_model_view(void) {
alias_matrix_multiply(engine_r_view_matrix.uniform.data.mat, engine_r_model_matrix.uniform.data.mat,
engine_r_model_view_matrix.uniform.data.mat);
}
static inline void prepare_view_projection(void) {
alias_matrix_multiply(engine_r_projection_matrix.uniform.data.mat, engine_r_view_matrix.uniform.data.mat,
engine_r_view_projection_matrix.uniform.data.mat);
}
static inline void prepare_model_view_projection(void) {
alias_gl_ShaderResource_prepare(&engine_r_view_projection_matrix);
alias_matrix_multiply(engine_r_view_projection_matrix.uniform.data.mat, engine_r_model_matrix.uniform.data.mat,
engine_r_model_view_projection_matrix.uniform.data.mat);
}
struct alias_gl_ShaderResource engine_r_time = {.type = alias_gl_Type_float, .name = "time"};
struct alias_gl_ShaderResource engine_r_model_matrix = {.type = alias_gl_Type_float4x4, .name = "model_matrix"};
struct alias_gl_ShaderResource engine_r_view_matrix = {.type = alias_gl_Type_float4x4, .name = "view_matrix"};
struct alias_gl_ShaderResource engine_r_model_view_matrix = {
.type = alias_gl_Type_float4x4, .name = "model_view_matrix", .uniform.prepare = prepare_model_view};
struct alias_gl_ShaderResource engine_r_projection_matrix = {.type = alias_gl_Type_float4x4, .name = "projection_matrix"};
struct alias_gl_ShaderResource engine_r_view_projection_matrix = {
.type = alias_gl_Type_float4x4, .name = "view_projection_matrix", .uniform.prepare = prepare_view_projection};
struct alias_gl_ShaderResource engine_r_model_view_projection_matrix = {
.type = alias_gl_Type_float4x4, .name = "model_view_projection_matrix", .uniform.prepare = prepare_model_view_projection};
ALIAS_GL_SHADER(_ScreenVertex_vertex,
code(
layout(location = 0) out vec2 out_st;
layout(location = 1) out vec4 out_rgba;
),
main(
gl_Position = u_view_projection_matrix * vec4(in_xy, 0, 1);
out_st = in_st;
out_rgba = in_rgba;
)
)
ALIAS_GL_SHADER(_ScreenVertex_fragment,
code(
layout(location = 0) in vec2 in_st;
layout(location = 1) in vec4 in_rgba;
layout(location = 0) out vec4 out_color;
),
main(
out_color = texture(u_img, in_st) * in_rgba;
)
)
static struct alias_gl_Buffer _ScreenVertex_element_buffer;
static struct alias_gl_Buffer _ScreenVertex_vertexes_buffer;
static struct alias_gl_DrawState _ScreenVertex_draw_state = {
.primitive = GL_TRIANGLES,
.attribute[0] = {0, alias_memory_Format_Float32, 2, "xy", 0},
.attribute[1] = {0, alias_memory_Format_Float32, 4, "rgba", 8},
.attribute[2] = {0, alias_memory_Format_Float32, 2, "st", 24},
.binding[0] = {sizeof(struct ScreenVertex)},
.global[0] = {ALIAS_GL_VERTEX_BIT, &engine_r_view_projection_matrix},
.image[0] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_sampler2D, "img"},
.vertex_shader = &_ScreenVertex_vertex_shader,
.fragment_shader = &_ScreenVertex_fragment_shader,
.depth_range_min = 0,
.depth_range_max = 1,
.blend_enable = true,
.blend_src_factor = GL_SRC_ALPHA,
.blend_dst_factor = GL_ONE_MINUS_SRC_ALPHA};
static void _ScreenVertex_begin_draw(uint32_t num_indexes, uint32_t **indexes_ptr, uint32_t num_vertexes,
struct ScreenVertex **vertexes_ptr) {
_ScreenVertex_element_buffer =
alias_gl_allocateTemporaryBuffer(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * num_indexes);
_ScreenVertex_vertexes_buffer =
alias_gl_allocateTemporaryBuffer(GL_ARRAY_BUFFER, sizeof(struct ScreenVertex) * num_vertexes);
*indexes_ptr = _ScreenVertex_element_buffer.mapping;
*vertexes_ptr = _ScreenVertex_vertexes_buffer.mapping;
}
static uint32_t _render_white_image(void) {
static bool init = false;
static struct Image image;
if(!init) {
init = true;
uint8_t * data = alias_stack_allocation(16 * 16 * 3, 1);
alias_memory_set(data, 16 * 16 * 3, 255, 16 * 16 * 3);
_image_upload_2d(&image, 16, 16, 3, data, true);
}
return image.gl.image;
}
static void _ScreenVertex_draw(struct Image * image, uint32_t index_offset, uint32_t num_indexes) {
alias_gl_drawElements(&_ScreenVertex_draw_state, &(struct alias_gl_DrawAssets){
.image[0] = image ? image->gl.image : _render_white_image(),
.element_buffer = &_ScreenVertex_element_buffer,
.element_buffer_offset = index_offset,
.vertex_buffers[0] = &_ScreenVertex_vertexes_buffer
}, num_indexes, 1, 0, 0);
}
static void _ScreenVertex_end_draw(void) {
}
#define FONT_DRAW_CHARACTERS_PER_BATCH 1024
static void _font_draw(struct Font *font, const char *text, float x, float y, float size, float spacing, alias_Color color) {
struct ScreenVertex *vertexes = NULL;
uint32_t *indexes = NULL;
uint32_t i = 0;
size_t length = alias_str_length(text);
struct Image *image = &_resource_from_image(&font->atlas)->image;
float s_scale = alias_R_ONE / image->width;
float t_scale = alias_R_ONE / image->height;
while(*text) {
if(i == 0) {
_ScreenVertex_begin_draw(6 * alias_min(FONT_DRAW_CHARACTERS_PER_BATCH, length), &indexes,
4 * alias_min(FONT_DRAW_CHARACTERS_PER_BATCH, length), &vertexes);
}
const struct Font_Glyph *glyph = _font_findGlyph(font, text);
// TODO utf8 advance
text++;
#define EMIT(I, V, H) \
vertexes[i * 4 + I].xy[0] = x + glyph->plane_##H * size; \
vertexes[i * 4 + I].xy[1] = y + (1.0f - glyph->plane_##V) * size; \
vertexes[i * 4 + I].rgba[0] = color.r; \
vertexes[i * 4 + I].rgba[1] = color.g; \
vertexes[i * 4 + I].rgba[2] = color.b; \
vertexes[i * 4 + I].rgba[3] = color.a; \
vertexes[i * 4 + I].st[0] = glyph->atlas_##H * s_scale; \
vertexes[i * 4 + I].st[1] = 1.0f - (glyph->atlas_##V * t_scale);
EMIT(0, bottom, left)
EMIT(1, bottom, right)
EMIT(2, top, right)
EMIT(3, top, left)
#undef EMIT
indexes[i * 6 + 0] = i * 4 + 0;
indexes[i * 6 + 1] = i * 4 + 2;
indexes[i * 6 + 2] = i * 4 + 1;
indexes[i * 6 + 3] = i * 4 + 2;
indexes[i * 6 + 4] = i * 4 + 0;
indexes[i * 6 + 5] = i * 4 + 3;
x += glyph->advance * size + spacing;
i++;
length--;
if(i >= FONT_DRAW_CHARACTERS_PER_BATCH) {
_ScreenVertex_draw(image, 0, 6 * FONT_DRAW_CHARACTERS_PER_BATCH);
_ScreenVertex_end_draw();
i = 0;
}
}
if(i >= 0) {
_ScreenVertex_draw(image, 0, 6 * i);
_ScreenVertex_end_draw();
}
}