584 lines
15 KiB
C
584 lines
15 KiB
C
|
// Release target will include shaders into the binary
|
||
|
#ifdef BUILD_RELEASE
|
||
|
#include "glsl.inc"
|
||
|
#endif
|
||
|
|
||
|
enum { MAX_TEXT_LENGTH = 128 };
|
||
|
|
||
|
typedef struct render_mgr {
|
||
|
struct {
|
||
|
GLuint shader;
|
||
|
GLuint u_proj;
|
||
|
GLuint u_view;
|
||
|
GLuint u_model;
|
||
|
GLuint u_texture;
|
||
|
GLuint u_texture_alpha;
|
||
|
GLuint u_light_count;
|
||
|
GLuint u_lights;
|
||
|
GLuint u_is_emitter;
|
||
|
GLuint u_uv_scale;
|
||
|
GLuint u_uv_translation;
|
||
|
GLuint u_powerup_timer;
|
||
|
GLuint u_ambient_adjust;
|
||
|
mat4 proj_mat;
|
||
|
} geo;
|
||
|
|
||
|
struct {
|
||
|
GLuint shader;
|
||
|
GLuint vao;
|
||
|
GLuint vbo;
|
||
|
GLuint texture;
|
||
|
GLuint u_proj;
|
||
|
GLuint u_model;
|
||
|
GLuint u_texture;
|
||
|
GLuint u_color;
|
||
|
mat4 proj_mat;
|
||
|
} text;
|
||
|
|
||
|
struct {
|
||
|
GLuint shader;
|
||
|
GLuint texture;
|
||
|
GLuint vao;
|
||
|
GLuint vbo;
|
||
|
GLuint fbo;
|
||
|
GLuint rbo;
|
||
|
GLuint u_texture;
|
||
|
GLuint u_powerup_timer;
|
||
|
} screen;
|
||
|
|
||
|
#ifdef BUILD_DEBUG
|
||
|
struct {
|
||
|
time_t geo;
|
||
|
time_t screen;
|
||
|
time_t text;
|
||
|
} debug;
|
||
|
#endif
|
||
|
} render_mgr_t;
|
||
|
|
||
|
GLuint
|
||
|
compile_shader(char* contents, size_t size, unsigned int type)
|
||
|
{
|
||
|
const char* sources[3];
|
||
|
sources[0] = "#version 400 core\n";
|
||
|
sources[1] = (type == GL_VERTEX_SHADER) ? "#define VERTEX\n" : "#define FRAGMENT\n";
|
||
|
sources[2] = contents;
|
||
|
|
||
|
int lengths[3];
|
||
|
lengths[0] = strlen(sources[0]);
|
||
|
lengths[1] = strlen(sources[1]);
|
||
|
lengths[2] = size;
|
||
|
|
||
|
GLuint id = glCreateShader(type);
|
||
|
glShaderSource(id, 3, sources, lengths);
|
||
|
glCompileShader(id);
|
||
|
|
||
|
char log[512];
|
||
|
int success;
|
||
|
glGetShaderiv(id, GL_COMPILE_STATUS, &success);
|
||
|
if (!success)
|
||
|
{
|
||
|
glGetShaderInfoLog(id, sizeof(log), NULL, log);
|
||
|
|
||
|
LOG_ERROR("Failed to compile shader:");
|
||
|
LOG_ERROR(" %s", log);
|
||
|
|
||
|
#ifdef BUILD_RELEASE
|
||
|
exit(EXIT_FAILURE);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
return id;
|
||
|
}
|
||
|
|
||
|
#ifdef BUILD_DEBUG
|
||
|
char*
|
||
|
load_shader(const char* path, size_t* size)
|
||
|
{
|
||
|
SDL_RWops* ops = SDL_RWFromFile(path, "r");
|
||
|
if (ops == NULL)
|
||
|
{
|
||
|
LOG_ERROR("Error opening file %s: %s", path, SDL_GetError());
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
|
||
|
Sint64 file_size = SDL_RWsize(ops);
|
||
|
if (size < 0) {
|
||
|
LOG_ERROR("Error getting size of file %s: %s", path, SDL_GetError());
|
||
|
}
|
||
|
|
||
|
char* buf = scratch_mem_alloc(1, file_size);
|
||
|
|
||
|
size_t items_read = SDL_RWread(ops, buf, file_size, 1);
|
||
|
if (items_read != 1) {
|
||
|
LOG_ERROR("Error reading file %s: %s", path, SDL_GetError());
|
||
|
}
|
||
|
|
||
|
int ret = SDL_RWclose(ops);
|
||
|
if (ret != 0) {
|
||
|
LOG_ERROR("Error closing file %s: %s", path, SDL_GetError());
|
||
|
}
|
||
|
|
||
|
*size = (size_t)file_size;
|
||
|
|
||
|
return buf;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
GLuint
|
||
|
create_shader(char* buf, size_t size)
|
||
|
{
|
||
|
size_t vertex_size;
|
||
|
{
|
||
|
char* substring = strstr(buf, "#ifdef FRAGMENT");
|
||
|
LOG_ASSERT(substring != NULL, "Error parsing vertex shader");
|
||
|
|
||
|
vertex_size = substring - buf;
|
||
|
}
|
||
|
|
||
|
size_t fragment_size;
|
||
|
{
|
||
|
fragment_size = size - vertex_size;
|
||
|
}
|
||
|
|
||
|
GLuint vertex = compile_shader(buf, vertex_size, GL_VERTEX_SHADER);
|
||
|
GLuint fragment = compile_shader(buf+vertex_size, fragment_size, GL_FRAGMENT_SHADER);
|
||
|
|
||
|
GLuint shader = glCreateProgram();
|
||
|
{
|
||
|
char log[512];
|
||
|
int success;
|
||
|
|
||
|
glAttachShader(shader, vertex);
|
||
|
glAttachShader(shader, fragment);
|
||
|
glLinkProgram(shader);
|
||
|
glGetProgramiv(shader, GL_LINK_STATUS, &success);
|
||
|
if (!success)
|
||
|
{
|
||
|
glGetProgramInfoLog(shader, sizeof(log), NULL, log);
|
||
|
|
||
|
LOG_ERROR("Failed to link shader program:");
|
||
|
LOG_ERROR(" %s", log);
|
||
|
|
||
|
#ifdef BUILD_RELEASE
|
||
|
exit(EXIT_FAILURE);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
glDeleteShader(vertex);
|
||
|
glDeleteShader(fragment);
|
||
|
}
|
||
|
|
||
|
return shader;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
render_mgr_startup(void)
|
||
|
{
|
||
|
// Geometry rendering
|
||
|
{
|
||
|
#ifdef BUILD_RELEASE
|
||
|
size_t size = strlen(geo_glsl);
|
||
|
char* buf = (char*)geo_glsl;
|
||
|
#else
|
||
|
size_t size;
|
||
|
char* buf = load_shader("shaders/geo.glsl", &size);
|
||
|
|
||
|
struct stat attrib;
|
||
|
stat("shaders/geo.glsl", &attrib);
|
||
|
g_render_mgr->debug.geo = attrib.st_mtime;
|
||
|
#endif
|
||
|
|
||
|
GLuint shader = create_shader(buf, size);
|
||
|
|
||
|
GLuint u_model = glGetUniformLocation(shader, "u_model");
|
||
|
GLuint u_view = glGetUniformLocation(shader, "u_view");
|
||
|
GLuint u_proj = glGetUniformLocation(shader, "u_proj");
|
||
|
GLuint u_texture = glGetUniformLocation(shader, "u_texture");
|
||
|
GLuint u_texture_alpha = glGetUniformLocation(shader, "u_texture_alpha");
|
||
|
GLuint u_light_count = glGetUniformLocation(shader, "u_light_count");
|
||
|
GLuint u_lights = glGetUniformLocation(shader, "u_lights[0].position");
|
||
|
GLuint u_is_emitter = glGetUniformLocation(shader, "u_is_emitter");
|
||
|
GLuint u_uv_scale = glGetUniformLocation(shader, "u_uv_scale");
|
||
|
GLuint u_uv_translation = glGetUniformLocation(shader, "u_uv_translation");
|
||
|
GLuint u_powerup_timer = glGetUniformLocation(shader, "u_powerup_timer");
|
||
|
GLuint u_ambient_adjust = glGetUniformLocation(shader, "u_ambient_adjust");
|
||
|
|
||
|
const float n = 0.1f;
|
||
|
const float f = 100.0f;
|
||
|
const float fov = 75.0f;
|
||
|
const float d = 1.0f / tanf(DEG_TO_RAD(fov*0.5f));
|
||
|
const float a = (float)RENDER_WIDTH / (float)RENDER_HEIGHT;
|
||
|
|
||
|
mat4 proj_mat = {
|
||
|
d/a, 0.0f, 0.0f, 0.0f,
|
||
|
0.0f, d, 0.0f, 0.0f,
|
||
|
0.0f, 0.0f, f/(f-n), (-f*n)/(f-n),
|
||
|
0.0f, 0.0f, 1.0f, 0.0f
|
||
|
};
|
||
|
|
||
|
g_render_mgr->geo.shader = shader;
|
||
|
g_render_mgr->geo.u_model = u_model;
|
||
|
g_render_mgr->geo.u_proj = u_proj;
|
||
|
g_render_mgr->geo.u_view= u_view;
|
||
|
g_render_mgr->geo.u_texture = u_texture;
|
||
|
g_render_mgr->geo.u_texture_alpha = u_texture_alpha;
|
||
|
g_render_mgr->geo.u_light_count = u_light_count;
|
||
|
g_render_mgr->geo.u_lights = u_lights;
|
||
|
g_render_mgr->geo.u_is_emitter = u_is_emitter;
|
||
|
g_render_mgr->geo.u_uv_scale = u_uv_scale;
|
||
|
g_render_mgr->geo.u_uv_translation = u_uv_translation;
|
||
|
g_render_mgr->geo.u_powerup_timer = u_powerup_timer;
|
||
|
g_render_mgr->geo.u_ambient_adjust = u_ambient_adjust;
|
||
|
g_render_mgr->geo.proj_mat = proj_mat;
|
||
|
}
|
||
|
|
||
|
// Text rendering
|
||
|
{
|
||
|
#ifdef BUILD_RELEASE
|
||
|
size_t size = strlen(text_glsl);
|
||
|
char* buf = (char*)text_glsl;
|
||
|
#else
|
||
|
size_t size;
|
||
|
char* buf = load_shader("shaders/text.glsl", &size);
|
||
|
|
||
|
struct stat attrib;
|
||
|
stat("shaders/text.glsl", &attrib);
|
||
|
g_render_mgr->debug.text = attrib.st_mtime;
|
||
|
#endif
|
||
|
|
||
|
GLuint shader = create_shader(buf, size);
|
||
|
|
||
|
GLuint vao;
|
||
|
glGenVertexArrays(1, &vao);
|
||
|
glBindVertexArray(vao);
|
||
|
|
||
|
GLuint vbo;
|
||
|
glGenBuffers(1, &vbo);
|
||
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||
|
|
||
|
glEnableVertexAttribArray(0);
|
||
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
|
||
|
|
||
|
glEnableVertexAttribArray(1);
|
||
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
|
||
|
|
||
|
GLuint texture;
|
||
|
glGenTextures(1, &texture);
|
||
|
glBindTexture(GL_TEXTURE_2D, texture);
|
||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, g_font.width, g_font.height, 0, GL_RED, GL_UNSIGNED_BYTE, g_font.bitmap);
|
||
|
|
||
|
GLuint u_proj = glGetUniformLocation(shader, "u_proj");
|
||
|
GLuint u_model = glGetUniformLocation(shader, "u_model");
|
||
|
GLuint u_texture = glGetUniformLocation(shader, "u_texture");
|
||
|
GLuint u_color = glGetUniformLocation(shader, "u_color");
|
||
|
|
||
|
mat4 proj_mat =
|
||
|
{
|
||
|
2.0f/WINDOW_WIDTH, 0.0f, 0.0f, -1.0f,
|
||
|
0.0f, 2.0f/WINDOW_HEIGHT, 0.0f, -1.0f,
|
||
|
0.0f, 0.0f, -1.0f, -1.0f,
|
||
|
0.0f, 0.0f, 0.0f, 1.0f
|
||
|
};
|
||
|
|
||
|
g_render_mgr->text.shader = shader;
|
||
|
g_render_mgr->text.vao = vao;
|
||
|
g_render_mgr->text.vbo = vbo;
|
||
|
g_render_mgr->text.texture = texture;
|
||
|
g_render_mgr->text.u_proj = u_proj;
|
||
|
g_render_mgr->text.u_model = u_model;
|
||
|
g_render_mgr->text.u_texture = u_texture;
|
||
|
g_render_mgr->text.u_color = u_color;
|
||
|
g_render_mgr->text.proj_mat = proj_mat;
|
||
|
}
|
||
|
|
||
|
// Screen rendering
|
||
|
{
|
||
|
#ifdef BUILD_RELEASE
|
||
|
size_t size = strlen(screen_glsl);
|
||
|
char* buf = (char*)screen_glsl;
|
||
|
#else
|
||
|
size_t size;
|
||
|
char* buf = load_shader("shaders/screen.glsl", &size);
|
||
|
|
||
|
struct stat attrib;
|
||
|
stat("shaders/screen.glsl", &attrib);
|
||
|
g_render_mgr->debug.screen= attrib.st_mtime;
|
||
|
#endif
|
||
|
|
||
|
GLuint shader = create_shader(buf, size);
|
||
|
|
||
|
// Low-resolution texture that will be rendered into
|
||
|
GLuint texture;
|
||
|
glGenTextures(1, &texture);
|
||
|
glBindTexture(GL_TEXTURE_2D, texture);
|
||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, RENDER_WIDTH, RENDER_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||
|
|
||
|
// Render buffer object required for the framebuffer
|
||
|
GLuint rbo;
|
||
|
glGenRenderbuffers(1, &rbo);
|
||
|
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
|
||
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, RENDER_WIDTH, RENDER_HEIGHT);
|
||
|
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||
|
|
||
|
// Framebuffer attached to texture and RBO
|
||
|
GLuint fbo;
|
||
|
glGenFramebuffers(1, &fbo);
|
||
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
|
||
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo);
|
||
|
|
||
|
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||
|
LOG_ERROR("Unable to create render-to-texture framebuffer.");
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
|
||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||
|
|
||
|
float vertices[] =
|
||
|
{
|
||
|
// Position Texcoord
|
||
|
-1.0f, 1.0f, 0.0f, 1.0f, // upper left
|
||
|
-1.0f, -1.0f, 0.0f, 0.0f, // lower left
|
||
|
1.0f, -1.0f, 1.0f, 0.0f, // lower right
|
||
|
1.0f, -1.0f, 1.0f, 0.0f, // lower right
|
||
|
1.0f, 1.0f, 1.0f, 1.0f, // upper right
|
||
|
-1.0f, 1.0f, 0.0f, 1.0f, // upper left
|
||
|
};
|
||
|
|
||
|
GLuint vao;
|
||
|
glGenVertexArrays(1, &vao);
|
||
|
glBindVertexArray(vao);
|
||
|
|
||
|
GLuint vbo;
|
||
|
glGenBuffers(1, &vbo);
|
||
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||
|
|
||
|
glEnableVertexAttribArray(0);
|
||
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(vertices[0]), (void*)0);
|
||
|
|
||
|
glEnableVertexAttribArray(1);
|
||
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(vertices[0]), (void*)(2 * sizeof(vertices[0])));
|
||
|
|
||
|
glBindVertexArray(0);
|
||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||
|
|
||
|
GLuint u_texture = glGetUniformLocation(shader, "u_texture");
|
||
|
GLuint u_powerup_timer = glGetUniformLocation(shader, "u_powerup_timer");
|
||
|
|
||
|
g_render_mgr->screen.shader = shader;
|
||
|
g_render_mgr->screen.vao = vao;
|
||
|
g_render_mgr->screen.vbo = vbo;
|
||
|
g_render_mgr->screen.fbo = fbo;
|
||
|
g_render_mgr->screen.rbo = rbo;
|
||
|
g_render_mgr->screen.texture = texture;
|
||
|
g_render_mgr->screen.u_texture = u_texture;
|
||
|
g_render_mgr->screen.u_powerup_timer = u_powerup_timer;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const char*
|
||
|
format_text(const char* format, ...)
|
||
|
{
|
||
|
static char buf[MAX_TEXT_LENGTH] = {};
|
||
|
|
||
|
va_list args;
|
||
|
va_start(args, format);
|
||
|
vsprintf(buf, format, args);
|
||
|
va_end(args);
|
||
|
|
||
|
return buf;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
render_geo_begin(camera_t* camera)
|
||
|
{
|
||
|
glBindFramebuffer(GL_FRAMEBUFFER, g_render_mgr->screen.fbo);
|
||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||
|
glEnable(GL_DEPTH_TEST);
|
||
|
glEnable(GL_BLEND);
|
||
|
|
||
|
glUseProgram(g_render_mgr->geo.shader);
|
||
|
glViewport(0, 0, RENDER_WIDTH, RENDER_HEIGHT);
|
||
|
glUniformMatrix4fv(g_render_mgr->geo.u_proj, 1, GL_TRUE, (float*)&g_render_mgr->geo.proj_mat);
|
||
|
glUniformMatrix4fv(g_render_mgr->geo.u_view, 1, GL_TRUE, (float*)&camera->view_mat);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
render_geo_end(void)
|
||
|
{
|
||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||
|
glViewport(VIEWPORT_X, VIEWPORT_Y, VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
render_screen_begin(void)
|
||
|
{
|
||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||
|
glEnable(GL_BLEND);
|
||
|
|
||
|
glUseProgram(g_render_mgr->screen.shader);
|
||
|
glBindVertexArray(g_render_mgr->screen.vao);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
render_screen_end(void)
|
||
|
{
|
||
|
glDisable(GL_DEPTH_TEST);
|
||
|
|
||
|
glBindTexture(GL_TEXTURE_2D, g_render_mgr->screen.texture);
|
||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||
|
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
render_text(const char* text, vec2 position, vec3 color, float size)
|
||
|
{
|
||
|
typedef struct vertex {
|
||
|
vec2 position;
|
||
|
vec2 texcoord;
|
||
|
} vertex_t;
|
||
|
|
||
|
vertex_t vertices[6 * MAX_TEXT_LENGTH];
|
||
|
|
||
|
int text_length = strlen(text);
|
||
|
LOG_ASSERT(text_length < MAX_TEXT_LENGTH,
|
||
|
"Text length (%d) exceeds allowed maximum (%d)", text_length, MAX_TEXT_LENGTH);
|
||
|
|
||
|
float atlas_width_recip = 1.0f / g_font.width;
|
||
|
float atlas_height_recip = 1.0f / g_font.height;
|
||
|
int cursor = 0;
|
||
|
|
||
|
for (int i = 0; i < text_length; i++)
|
||
|
{
|
||
|
// Indices start with space character (ASCII 0x20 / 32)
|
||
|
int idx = text[i] - ' ';
|
||
|
glyph_t glyph = g_font.glyphs[idx];
|
||
|
|
||
|
// Set up the four vertices required for the glyph's quad (texcoord.y is flipped to account for flipped texture)
|
||
|
vertex_t upper_left = {
|
||
|
.position.x = cursor - glyph.origin_x,
|
||
|
.position.y = glyph.origin_y,
|
||
|
.texcoord.x = glyph.x * atlas_width_recip,
|
||
|
.texcoord.y = 1.0f - (glyph.y * atlas_height_recip)};
|
||
|
|
||
|
vertex_t upper_right = {
|
||
|
.position.x = upper_left.position.x + glyph.width,
|
||
|
.position.y = upper_left.position.y,
|
||
|
.texcoord.x = (glyph.x + glyph.width) * atlas_width_recip,
|
||
|
.texcoord.y = upper_left.texcoord.y};
|
||
|
|
||
|
vertex_t bottom_right = {
|
||
|
.position.x = upper_right.position.x,
|
||
|
.position.y = upper_left.position.y - glyph.height,
|
||
|
.texcoord.x = upper_right.texcoord.x,
|
||
|
.texcoord.y = 1.0f - ((glyph.y + glyph.height) * atlas_height_recip)};
|
||
|
|
||
|
vertex_t bottom_left = {
|
||
|
.position.x = upper_left.position.x,
|
||
|
.position.y = bottom_right.position.y,
|
||
|
.texcoord.x = upper_left.texcoord.x,
|
||
|
.texcoord.y = bottom_right.texcoord.y};
|
||
|
|
||
|
// o-----o
|
||
|
// | \ |
|
||
|
// | \ |
|
||
|
// | \ |
|
||
|
// o-----o
|
||
|
|
||
|
vertices[6*i + 0] = upper_left;
|
||
|
vertices[6*i + 1] = upper_right;
|
||
|
vertices[6*i + 2] = bottom_right;
|
||
|
vertices[6*i + 3] = bottom_right;
|
||
|
vertices[6*i + 4] = bottom_left;
|
||
|
vertices[6*i + 5] = upper_left;
|
||
|
|
||
|
cursor += g_font.advance;
|
||
|
}
|
||
|
|
||
|
mat4 model_mat = mat4_identity();
|
||
|
model_mat.e00 = size;
|
||
|
model_mat.e11 = size;
|
||
|
model_mat.e03 = position.x;
|
||
|
model_mat.e13 = position.y;
|
||
|
|
||
|
glUseProgram(g_render_mgr->text.shader);
|
||
|
glUniformMatrix4fv(g_render_mgr->text.u_proj, 1, GL_TRUE, (float*)&g_render_mgr->text.proj_mat);
|
||
|
glUniformMatrix4fv(g_render_mgr->text.u_model, 1, GL_TRUE, (float*)&model_mat);
|
||
|
glUniform1i(g_render_mgr->text.u_texture, 0);
|
||
|
glUniform3fv(g_render_mgr->text.u_color, 1, (float*)&color);
|
||
|
|
||
|
glBindVertexArray(g_render_mgr->text.vao);
|
||
|
glActiveTexture(GL_TEXTURE0);
|
||
|
glBindTexture(GL_TEXTURE_2D, g_render_mgr->text.texture);
|
||
|
glBindBuffer(GL_ARRAY_BUFFER, g_render_mgr->text.vbo);
|
||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * 6 * text_length, vertices, GL_DYNAMIC_DRAW);
|
||
|
|
||
|
glDrawArrays(GL_TRIANGLES, 0, 6 * text_length);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
reload_shaders(void)
|
||
|
{
|
||
|
#ifdef BUILD_DEBUG
|
||
|
glUseProgram(0);
|
||
|
|
||
|
{
|
||
|
struct stat attrib;
|
||
|
stat("shaders/geo.glsl", &attrib);
|
||
|
time_t mod_time = attrib.st_mtime;
|
||
|
if (mod_time != g_render_mgr->debug.geo)
|
||
|
{
|
||
|
glDeleteProgram(g_render_mgr->geo.shader);
|
||
|
|
||
|
size_t size;
|
||
|
char* buf = load_shader("shaders/geo.glsl", &size);
|
||
|
|
||
|
g_render_mgr->geo.shader = create_shader(buf, size);
|
||
|
g_render_mgr->debug.geo = mod_time;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
{
|
||
|
struct stat attrib;
|
||
|
stat("shaders/screen.glsl", &attrib);
|
||
|
time_t mod_time = attrib.st_mtime;
|
||
|
if (mod_time != g_render_mgr->debug.screen)
|
||
|
{
|
||
|
glDeleteProgram(g_render_mgr->screen.shader);
|
||
|
|
||
|
size_t size;
|
||
|
char* buf = load_shader("shaders/screen.glsl", &size);
|
||
|
|
||
|
g_render_mgr->screen.shader = create_shader(buf, size);
|
||
|
g_render_mgr->debug.screen = mod_time;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
{
|
||
|
struct stat attrib;
|
||
|
stat("shaders/text.glsl", &attrib);
|
||
|
time_t mod_time = attrib.st_mtime;
|
||
|
if (mod_time != g_render_mgr->debug.text)
|
||
|
{
|
||
|
glDeleteProgram(g_render_mgr->text.shader);
|
||
|
|
||
|
size_t size;
|
||
|
char* buf = load_shader("shaders/text.glsl", &size);
|
||
|
|
||
|
g_render_mgr->text.shader = create_shader(buf, size);
|
||
|
g_render_mgr->debug.text = mod_time;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|