#include "renderer.h" #include "bitmaps.h" static SDL_Window *window; static renderer_state renderer; void r_resize(int width, int height) { glViewport(0, 0, width, height); } v4 extract_color_v4_from_u32(uint32_t in) { v4 result; result.x = ((in >> 24) & 0xFF) / 255.0f; result.y = ((in >> 16) & 0xFF) / 255.0f; result.z = ((in >> 8) & 0xFF) / 255.0f; result.w = ((in >> 0) & 0xFF) / 255.0f; return result; } void r_make_draw_call(int num_of_elements, uint32_t color) { v4 uniform_color = extract_color_v4_from_u32(color); GLint texture_location = glGetUniformLocation(renderer.shader_program, "texture1"); glUniform1i(texture_location, 0); GLint color_location = glGetUniformLocation(renderer.shader_program, "color"); glUniform4f(color_location, uniform_color.x, uniform_color.y, uniform_color.z, uniform_color.w); glBindVertexArray(renderer.vao); glBindBuffer(GL_ARRAY_BUFFER, renderer.vbo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, renderer.ebo); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(render_target), (void *)(0)); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(render_target), (void *)(sizeof(v2))); glEnableVertexAttribArray(1); glUseProgram(renderer.shader_program); glBindVertexArray(renderer.vao); //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glDrawElements(GL_TRIANGLES, num_of_elements, GL_UNSIGNED_INT, 0); } void r_draw_text(char *text, float x, float y, uint32_t color, float scaler) { v2 pos = { .x = x, .y = y }; size_t size = strlen(text); size_t vert_memory_size = sizeof(render_target) * size * 4; size_t indx_memory_size = sizeof(int) * size * 6; render_target *verts = alloca( vert_memory_size ); unsigned int *indexes = alloca( indx_memory_size ); int last_vert = 0; int last_index = 0; for (int index = 0; index < size; ++index) { char c = text[index]; if(c == '\n') { pos.x = x; pos.y -= (25 * scaler) / ASCII_HEIGHT; continue; } font_info char_info = base_font_info[c - ' ']; float c_width = char_info.width * scaler; float c_height = char_info.height * scaler; v2 t1 = { .x = char_info.pos.x, .y = 1 - char_info.pos.y }; v2 t2 = { .x = t1.x + char_info.width, .y = t1.y - char_info.height }; v2 p1 = { .x = pos.x, .y = pos.y }; v2 p2 = { .x = p1.x + c_width, .y = p1.y + c_height }; p1.y += ((25*scaler) / ASCII_HEIGHT) - (c_height + char_info.y_offset * scaler); p2.y += ((25*scaler) / ASCII_HEIGHT) - (c_height + char_info.y_offset * scaler); int vert_offset = last_vert; verts[last_vert++] = (render_target){ p1.x, p1.y, t1.x, t2.y }; verts[last_vert++] = (render_target){ p2.x, p1.y, t2.x, t2.y }; verts[last_vert++] = (render_target){ p2.x, p2.y, t2.x, t1.y }; verts[last_vert++] = (render_target){ p1.x, p2.y, t1.x, t1.y }; indexes[last_index++] = 0 + vert_offset; indexes[last_index++] = 1 + vert_offset; indexes[last_index++] = 2 + vert_offset; indexes[last_index++] = 0 + vert_offset; indexes[last_index++] = 2 + vert_offset; indexes[last_index++] = 3 + vert_offset; pos.x += c_width + 15 / ASCII_WIDTH; } glBindBuffer(GL_ARRAY_BUFFER, renderer.vbo); glBufferSubData(GL_ARRAY_BUFFER, 0, last_vert * sizeof(render_target), verts); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, renderer.ebo); glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, last_index * sizeof(int), indexes); r_make_draw_call(last_index, color); } void r_present(void) { SDL_GL_SwapWindow(window); } void r_compile_shaders(void) { GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER); GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(vertex_shader, 1, &vertex_shader_src, 0); glShaderSource(fragment_shader, 1, &fragment_shader_src, 0); glCompileShader(vertex_shader); glCompileShader(fragment_shader); int success; char info_log[512] = {0}; glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success); if(!success) { glGetShaderInfoLog(vertex_shader, 512, NULL, info_log); fprintf(stderr, info_log); exit(1); } glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success); if(!success) { glGetShaderInfoLog(fragment_shader, 512, NULL, info_log); fprintf(stderr, info_log); exit(1); } renderer.shader_program = glCreateProgram(); glAttachShader(renderer.shader_program, vertex_shader); glAttachShader(renderer.shader_program, fragment_shader); glLinkProgram(renderer.shader_program); glUseProgram(renderer.shader_program); glGetProgramiv(renderer.shader_program, GL_LINK_STATUS, &success); if(!success) { glGetProgramInfoLog(renderer.shader_program, 512, NULL, info_log); fprintf(stderr, info_log); exit(1); } } void r_init(init_info info) { /* Create window and context */ window = SDL_CreateWindow("Template Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, info.width, info.height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); SDL_GL_CreateContext(window); assert(gladLoadGLLoader(SDL_GL_GetProcAddress)); /* Initialize OpenGL */ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); glEnable(GL_SCISSOR_TEST); glEnable(GL_TEXTURE_2D); r_compile_shaders(); /* Set-up GL buffers */ glGenVertexArrays(1, &renderer.vao); glGenBuffers(1, &renderer.vbo); glGenBuffers(1, &renderer.ebo); glBindVertexArray(renderer.vao); // 10 MB glBindBuffer(GL_ARRAY_BUFFER, renderer.vbo); glBufferData(GL_ARRAY_BUFFER, 10*1024*1024, NULL, GL_STREAM_DRAW); // 10 MB glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, renderer.ebo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, 10*1024*1024, NULL, GL_STREAM_DRAW); GLuint id; glGenTextures(1, &id); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, id); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ASCII_WIDTH, ASCII_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, ascii_characters); assert(glGetError() == 0); r_resize(info.width, info.height); }