/// _ /// __ ___ __ ___ _ __ __ _| | /// \ \/ / '_ \ / _ \ '_ \ / _` | | /// > <| |_) | __/ | | | (_| | | /// /_/\_\ .__/ \___|_| |_|\__, |_| /// |_| |___/ /// /// Copyright (c) 1997 - Ognjen 'xolatile' Milan Robovic /// /// xolatile@chud.cyou - xpengl - Tiny and elegant OpenGL + GLFW wrapper library so I don't go insane because of Khronos. /// /// This program is free software, free as in freedom and as in free beer, you can redistribute it and/or modify it under the terms of the GNU /// General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version if you wish... /// /// This program is distributed in the hope that it will be useful, but it is probably not, and without any warranty, without even the implied /// warranty of merchantability or fitness for a particular purpose, because it is pointless. Please see the GNU (Geenoo) General Public License /// for more details, if you dare, it is a lot of text that nobody wants to read... #include #define opengl_font_width (8) #define opengl_font_height (16) //~typedef enum { //~opengl_window_fullscreen = 0x1, //~opengl_window_transparent = 0x2, //~opengl_window_resizable = 0x4, //~opengl_window_decorated = 0x8 //~} opengl_window_flag; typedef struct { GLFWwindow * window; PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; PFNGLBINDVERTEXARRAYPROC glBindVertexArray; PFNGLGENBUFFERSPROC glGenBuffers; PFNGLBINDBUFFERPROC glBindBuffer; PFNGLCREATESHADERPROC glCreateShader; PFNGLSHADERSOURCEPROC glShaderSource; PFNGLCOMPILESHADERPROC glCompileShader; PFNGLCREATEPROGRAMPROC glCreateProgram; PFNGLATTACHSHADERPROC glAttachShader; PFNGLBINDFRAGDATALOCATIONPROC glBindFragDataLocation; PFNGLLINKPROGRAMPROC glLinkProgram; PFNGLUSEPROGRAMPROC glUseProgram; PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation; PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; PFNGLUNIFORM1IPROC glUniform1i; PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays; PFNGLDELETEBUFFERSPROC glDeleteBuffers; PFNGLDELETESHADERPROC glDeleteShader; PFNGLDELETEPROGRAMPROC glDeleteProgram; PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; PFNGLBUFFERDATAPROC glBufferData; bool signal [signal_count]; bool cursor [cursor_count]; int cursor_x; int cursor_y; bool using_precomputed_spritesheet; ulong spritesheet_size; ulong vertex_limit; ulong index_limit; uint gameplay_framerate; uint animation_framerate; uint tab_width; uint default_font; bool active; uint window_width; uint window_height; float pixel_width; float pixel_height; uint framerate; ulong frame_time; ulong frame_begin; ulong frame_end; uint global_tick; uint gameplay_tick; uint animation_tick; bool freeze_cursor; bool freeze_signal; uint vertex_object; uint vertex_buffer; uint index_buffer; uint vertex_shader; uint fragment_shader; uint shader_program; uint spritesheet; uint vertex_count; uint index_count; float * vertex_array; uint * index_array; uint sprite_count; uint font_count; uint * spritesheet_data; uint * * sprite_data; uint * sprite_width; uint * sprite_height; float * sprite_u; float * sprite_v; uint * * font_index; uint * * font_width; uint * * font_height; char * font_begin; char * font_end; } opengl_structure; static uint opengl_sprite_raw_import (opengl_structure * opengl, uint * data, uint width, uint height) { fatal_failure (opengl->active == true, "opengl_sprite_raw_import: OpenGL renderer is already initialized."); fatal_failure (data == null, "opengl_sprite_raw_import: Data is null pointer."); fatal_failure (width == 0, "opengl_sprite_raw_import: Font image width is zero."); fatal_failure (height == 0, "opengl_sprite_raw_import: Font image height is zero."); ++opengl->sprite_count; opengl->sprite_data = reallocate (opengl->sprite_data, opengl->sprite_count * sizeof (* opengl->sprite_data)); opengl->sprite_width = reallocate (opengl->sprite_width, opengl->sprite_count * sizeof (* opengl->sprite_width)); opengl->sprite_height = reallocate (opengl->sprite_height, opengl->sprite_count * sizeof (* opengl->sprite_height)); opengl->sprite_u = reallocate (opengl->sprite_u, opengl->sprite_count * sizeof (* opengl->sprite_u)); opengl->sprite_v = reallocate (opengl->sprite_v, opengl->sprite_count * sizeof (* opengl->sprite_v)); opengl->sprite_data [opengl->sprite_count - 1] = data; opengl->sprite_width [opengl->sprite_count - 1] = width; opengl->sprite_height [opengl->sprite_count - 1] = height; opengl->sprite_u [opengl->sprite_count - 1] = 0; opengl->sprite_v [opengl->sprite_count - 1] = 0; return (opengl->sprite_count - 1); } static uint opengl_font_raw_import (opengl_structure * opengl, uint * data, uint image_width, char begin, char end, uint empty) { uint pointer = 0; uint width = 0; uint height = 0; fatal_failure (opengl->active == true, "opengl_font_raw_import: OpenGL renderer is already initialized."); fatal_failure (data == null, "opengl_font_raw_import: Data is null pointer."); fatal_failure (image_width == 0, "opengl_font_raw_import: Font image width is zero."); fatal_failure (begin >= end, "opengl_font_raw_import: Font character range is inverted."); ++opengl->font_count; opengl->font_index = reallocate (opengl->font_index, opengl->font_count * sizeof (* opengl->font_index)); opengl->font_width = reallocate (opengl->font_width, opengl->font_count * sizeof (* opengl->font_width)); opengl->font_height = reallocate (opengl->font_height, opengl->font_count * sizeof (* opengl->font_height)); opengl->font_begin = reallocate (opengl->font_begin, opengl->font_count * sizeof (* opengl->font_begin)); opengl->font_end = reallocate (opengl->font_end, opengl->font_count * sizeof (* opengl->font_end)); opengl->font_begin [opengl->font_count - 1] = begin; opengl->font_end [opengl->font_count - 1] = end; opengl->font_index [opengl->font_count - 1] = allocate ((ulong) (end - begin + 1) * sizeof (* * opengl->font_index)); opengl->font_width [opengl->font_count - 1] = allocate ((ulong) (end - begin + 1) * sizeof (* * opengl->font_width)); opengl->font_height [opengl->font_count - 1] = allocate ((ulong) (end - begin + 1) * sizeof (* * opengl->font_height)); for (char index = begin; index <= end; ++index) { for ( ; data [pointer] == empty; ++pointer); for (width = 0; data [pointer + width] != empty; ++width); for (height = 0; data [pointer + height * image_width] != empty; ++height); uint * buffer = allocate (width * height * sizeof (* buffer)); for (uint y = 0; y < height; ++y) { for (uint x = 0; x < width; ++x) { buffer [y * width + x] = data [pointer + (y * image_width) + x]; } } opengl->font_index [opengl->font_count - 1] [index - begin] = opengl_sprite_raw_import (opengl, buffer, width, height); opengl->font_width [opengl->font_count - 1] [index - begin] = width; opengl->font_height [opengl->font_count - 1] [index - begin] = height; pointer += width; for (; data [pointer] == empty; ++pointer); if (pointer % image_width == 2) { pointer += height * image_width; } } return (opengl->font_count - 1); } static uint opengl_sprite_import (opengl_structure * opengl, char * path) { uint width = 0; uint height = 0; uint * data = null; char buffer [256] = ""; if (opengl->using_precomputed_spritesheet == true) { return (++opengl->sprite_count - 1); } #ifdef use_png_library if (file_exists (string_concatenate (string_copy (buffer, path), ".png")) == true) { data = png_image_import (buffer, & width, & height); } else { print ("/w File '/3%s/-' doesn't exist.\n", buffer); } #endif #ifdef use_jxl_library if ((data == null) && (file_exists (string_concatenate (string_copy (buffer, path), ".jxl")) == true)) { data = jxl_image_import (buffer, & width, & height); } #endif fatal_failure (data == null, "opengl_sprite_import: Unsupported image format."); return (opengl_sprite_raw_import (opengl, data, width, height)); } static uint opengl_font_import (opengl_structure * opengl, char * path, char begin, char end, uint colour) { uint width = 0; uint height = 0; uint result = 0; uint * data = null; char buffer [256] = ""; if (opengl->using_precomputed_spritesheet == true) { for (char index = begin; index <= end; ++index) { opengl->font_index [opengl->font_count] [index - begin] = ++opengl->sprite_count - 1; } return (++opengl->font_count - 1); } #ifdef use_png_library if (file_exists (string_concatenate (string_copy (buffer, path), ".png")) == true) { data = png_image_import (buffer, & width, & height); } else { print ("/w File '/3%s/-' doesn't exist.\n", buffer); } #endif #ifdef use_jxl_library if ((data == null) && (file_exists (string_concatenate (string_copy (buffer, path), ".jxl")) == true)) { data = jxl_image_import (buffer, & width, & height); } #endif fatal_failure (data == null, "opengl_font_import: Unsupported image format."); result = opengl_font_raw_import (opengl, data, width, begin, end, colour); data = deallocate (data); return (result); } static uint opengl_sprite_width (opengl_structure * opengl, uint sprite) { return (opengl->sprite_width [sprite]); } static uint opengl_sprite_height (opengl_structure * opengl, uint sprite) { return (opengl->sprite_height [sprite]); } static uint opengl_center_x (opengl_structure * opengl, uint size) { return ((opengl->window_width - size) / 2); } static uint opengl_center_y (opengl_structure * opengl, uint size) { return ((opengl->window_height - size) / 2); } static bool opengl_cursor_inside (opengl_structure * opengl, int x, int y, uint width, uint height) { return ((opengl->cursor_x > x) && (opengl->cursor_y > y) && (opengl->cursor_x < x + (int) width) && (opengl->cursor_y < y + (int) height)); } static bool opengl_cursor_left_click (opengl_structure * opengl, int x, int y, uint width, uint height) { if (opengl->cursor [cursor_left] == true) { opengl->freeze_cursor = true; return (opengl_cursor_inside (opengl, x, y, width, height) == true); } return (false); } static bool opengl_cursor_right_click (opengl_structure * opengl, int x, int y, uint width, uint height) { if (opengl->cursor [cursor_right]) { opengl->freeze_cursor = true; return (opengl_cursor_inside (opengl, x, y, width, height)); } return (false); } static void opengl_import_spritesheet (opengl_structure * opengl, char * data_file) { int file = file_open (data_file, file_flag_read); fatal_failure (opengl->active == true, "opengl_import_spritesheet: OpenGL renderer is already initialized."); file_read (file, & opengl->spritesheet_size, sizeof (opengl->spritesheet_size)); file_read (file, & opengl->sprite_count, sizeof (opengl->sprite_count)); opengl->sprite_width = allocate (opengl->sprite_count * sizeof (* opengl->sprite_width)); opengl->sprite_height = allocate (opengl->sprite_count * sizeof (* opengl->sprite_height)); opengl->sprite_u = allocate (opengl->sprite_count * sizeof (* opengl->sprite_u)); opengl->sprite_v = allocate (opengl->sprite_count * sizeof (* opengl->sprite_v)); file_read (file, opengl->sprite_width, opengl->sprite_count * sizeof (* opengl->sprite_width)); file_read (file, opengl->sprite_height, opengl->sprite_count * sizeof (* opengl->sprite_height)); file_read (file, opengl->sprite_u, opengl->sprite_count * sizeof (* opengl->sprite_u)); file_read (file, opengl->sprite_v, opengl->sprite_count * sizeof (* opengl->sprite_v)); file_read (file, & opengl->font_count, sizeof (opengl->font_count)); opengl->font_index = allocate (opengl->font_count * sizeof (* opengl->font_index)); opengl->font_width = allocate (opengl->font_count * sizeof (* opengl->font_width)); opengl->font_height = allocate (opengl->font_count * sizeof (* opengl->font_height)); opengl->font_begin = allocate (opengl->font_count * sizeof (* opengl->font_begin)); opengl->font_end = allocate (opengl->font_count * sizeof (* opengl->font_end)); file_read (file, opengl->font_begin, opengl->font_count * sizeof (* opengl->font_begin)); file_read (file, opengl->font_end, opengl->font_count * sizeof (* opengl->font_end)); for (uint index = 0; index < opengl->font_count; ++index) { uint range = (uint) (opengl->font_end [index] - opengl->font_begin [index]) + 1; opengl->font_index [index] = allocate (range * sizeof (* * opengl->font_index)); opengl->font_width [index] = allocate (range * sizeof (* * opengl->font_width)); opengl->font_height [index] = allocate (range * sizeof (* * opengl->font_height)); for (uint subindex = 0; subindex < range; ++subindex) { file_read (file, & opengl->font_index [index] [subindex], sizeof (* * opengl->font_index)); file_read (file, & opengl->font_width [index] [subindex], sizeof (* * opengl->font_width)); file_read (file, & opengl->font_height [index] [subindex], sizeof (* * opengl->font_height)); } } file = file_close (file); opengl->sprite_count = 0; opengl->font_count = 0; } static void opengl_export_spritesheet (opengl_structure * opengl, char * data_file) { int file = file_open (data_file, file_flag_write | file_flag_create | file_flag_truncate); fatal_failure (opengl->spritesheet_data == null, "opengl_export_spritesheet: OpenGL renderer can't access spritesheet data."); file_write (file, & opengl->spritesheet_size, sizeof (opengl->spritesheet_size)); file_write (file, & opengl->sprite_count, sizeof (opengl->sprite_count)); file_write (file, opengl->sprite_width, opengl->sprite_count * sizeof (* opengl->sprite_width)); file_write (file, opengl->sprite_height, opengl->sprite_count * sizeof (* opengl->sprite_height)); file_write (file, opengl->sprite_u, opengl->sprite_count * sizeof (* opengl->sprite_u)); file_write (file, opengl->sprite_v, opengl->sprite_count * sizeof (* opengl->sprite_v)); file_write (file, & opengl->font_count, sizeof (opengl->font_count)); file_write (file, opengl->font_begin, opengl->font_count * sizeof (* opengl->font_begin)); file_write (file, opengl->font_end, opengl->font_count * sizeof (* opengl->font_end)); for (uint index = 0; index < opengl->font_count; ++index) { for (uint subindex = 0; subindex < (uint) (opengl->font_end [index] - opengl->font_begin [index]) + 1; ++subindex) { file_write (file, & opengl->font_index [index] [subindex], sizeof (* * opengl->font_index)); file_write (file, & opengl->font_width [index] [subindex], sizeof (* * opengl->font_width)); file_write (file, & opengl->font_height [index] [subindex], sizeof (* * opengl->font_height)); } } file = file_close (file); print ("/c Exported internal binary data of OpenGL spritesheet."); } static opengl_structure * opengl_initialize (uint gameplay_framerate, uint animation_framerate, bool use_precomputed_spritesheet, uint maximum_quads_on_screen, uint spritesheet_side) { opengl_structure * opengl = allocate (sizeof (* opengl)); opengl->using_precomputed_spritesheet = use_precomputed_spritesheet; opengl->spritesheet_size = spritesheet_side; opengl->gameplay_framerate = gameplay_framerate; opengl->animation_framerate = animation_framerate; opengl->vertex_limit = maximum_quads_on_screen * 32; opengl->index_limit = maximum_quads_on_screen * 6; opengl->tab_width = 4; opengl->default_font = ~0u; if (use_precomputed_spritesheet == true) { print ("[/0Comment/-] Importing spritesheet image and information...\n"); opengl_import_spritesheet (opengl, "binary/spritesheet.bin"); } print ("[/2Success/-] Initialized OpenGL renderer.\n"); return (opengl); } static opengl_structure * opengl_deinitialize (opengl_structure * opengl) { opengl->active = false; for (uint index = 0; index < opengl->font_count; ++index) { opengl->font_index [index] = deallocate (opengl->font_index [index]); opengl->font_width [index] = deallocate (opengl->font_width [index]); opengl->font_height [index] = deallocate (opengl->font_height [index]); } opengl->font_index = deallocate (opengl->font_index); opengl->font_width = deallocate (opengl->font_width); opengl->font_height = deallocate (opengl->font_height); opengl->font_begin = deallocate (opengl->font_begin); opengl->font_end = deallocate (opengl->font_end); opengl->sprite_width = deallocate (opengl->sprite_width); opengl->sprite_height = deallocate (opengl->sprite_height); opengl->sprite_u = deallocate (opengl->sprite_u); opengl->sprite_v = deallocate (opengl->sprite_v); if (opengl->using_precomputed_spritesheet == false) { opengl->spritesheet_data = deallocate (opengl->spritesheet_data); } opengl->vertex_array = deallocate (opengl->vertex_array); opengl->index_array = deallocate (opengl->index_array); glDeleteTextures (1, & opengl->spritesheet); opengl->glDeleteProgram (opengl->shader_program); opengl->glDeleteShader (opengl->fragment_shader); opengl->glDeleteShader (opengl->vertex_shader); opengl->glDeleteBuffers (1, & opengl->index_buffer); opengl->glDeleteBuffers (1, & opengl->vertex_buffer); opengl->glDeleteVertexArrays (1, & opengl->vertex_object); glfwDestroyWindow (opengl->window); glfwTerminate (); print ("[/2Success/-] Deinitialized OpenGL renderer.\n"); return (deallocate (opengl)); } static void opengl_configure (opengl_structure * opengl, uint window_width, uint window_height, char * window_title) { ulong font_bitmap [190] = { 0x0000000000000000, 0x0000000000000000, 0x0000101010101010, 0x1000101000000000, 0x0024242400000000, 0x0000000000000000, 0x00002424247e2424, 0x7e24242400000000, 0x0010107c9290907c, 0x1212927c10100000, 0x0000649468081010, 0x202c524c00000000, 0x000018242418304a, 0x4444443a00000000, 0x0010101000000000, 0x0000000000000000, 0x0000081020202020, 0x2020100800000000, 0x0000201008080808, 0x0808102000000000, 0x000000000024187e, 0x1824000000000000, 0x000000000010107c, 0x1010000000000000, 0x0000000000000000, 0x0000101020000000, 0x000000000000007e, 0x0000000000000000, 0x0000000000000000, 0x0000101000000000, 0x0000040408081010, 0x2020404000000000, 0x00003c4242464a52, 0x6242423c00000000, 0x0000081828080808, 0x0808083e00000000, 0x00003c4242020408, 0x1020407e00000000, 0x00003c4242021c02, 0x0242423c00000000, 0x000002060a122242, 0x7e02020200000000, 0x00007e4040407c02, 0x0202423c00000000, 0x00001c2040407c42, 0x4242423c00000000, 0x00007e0202040408, 0x0810101000000000, 0x00003c4242423c42, 0x4242423c00000000, 0x00003c424242423e, 0x0202043800000000, 0x0000000000101000, 0x0000101000000000, 0x0000000000101000, 0x0000101020000000, 0x0000000408102040, 0x2010080400000000, 0x00000000007e0000, 0x7e00000000000000, 0x0000004020100804, 0x0810204000000000, 0x00003c4242420408, 0x0800080800000000, 0x00007c829ea2a2a2, 0xa69a807e00000000, 0x00003c424242427e, 0x4242424200000000, 0x00007c4242427c42, 0x4242427c00000000, 0x00003c4242404040, 0x4042423c00000000, 0x0000784442424242, 0x4242447800000000, 0x00007e4040407840, 0x4040407e00000000, 0x00007e4040407840, 0x4040404000000000, 0x00003c424240404e, 0x4242423c00000000, 0x0000424242427e42, 0x4242424200000000, 0x0000381010101010, 0x1010103800000000, 0x00000e0404040404, 0x0444443800000000, 0x0000424448506060, 0x5048444200000000, 0x0000404040404040, 0x4040407e00000000, 0x000082c6aa929282, 0x8282828200000000, 0x000042424262524a, 0x4642424200000000, 0x00003c4242424242, 0x4242423c00000000, 0x00007c424242427c, 0x4040404000000000, 0x00003c4242424242, 0x42424a3c02000000, 0x00007c424242427c, 0x5048444200000000, 0x00003c4240403c02, 0x0242423c00000000, 0x0000fe1010101010, 0x1010101000000000, 0x0000424242424242, 0x4242423c00000000, 0x0000424242424224, 0x2424181800000000, 0x0000828282828292, 0x92aac68200000000, 0x0000424224241818, 0x2424424200000000, 0x0000828244442810, 0x1010101000000000, 0x00007e0202040810, 0x2040407e00000000, 0x0000382020202020, 0x2020203800000000, 0x0000404020201010, 0x0808040400000000, 0x0000380808080808, 0x0808083800000000, 0x0000102844000000, 0x0000000000000000, 0x0000000000000000, 0x0000007e00000000, 0x1008000000000000, 0x0000000000000000, 0x00000000003c023e, 0x4242423e00000000, 0x00004040407c4242, 0x4242427c00000000, 0x00000000003c4240, 0x4040423c00000000, 0x00000202023e4242, 0x4242423e00000000, 0x00000000003c4242, 0x7e40403c00000000, 0x00000e10107c1010, 0x1010101000000000, 0x00000000003e4242, 0x4242423e02023c00, 0x00004040407c4242, 0x4242424200000000, 0x0000101000301010, 0x1010103800000000, 0x00000404000c0404, 0x0404040444443800, 0x0000404040424448, 0x7048444200000000, 0x0000301010101010, 0x1010103800000000, 0x0000000000fc9292, 0x9292929200000000, 0x00000000007c4242, 0x4242424200000000, 0x00000000003c4242, 0x4242423c00000000, 0x00000000007c4242, 0x4242427c40404000, 0x00000000003e4242, 0x4242423e02020200, 0x00000000005e6040, 0x4040404000000000, 0x00000000003e4040, 0x3c02027c00000000, 0x00001010107c1010, 0x1010100e00000000, 0x0000000000424242, 0x4242423e00000000, 0x0000000000424242, 0x2424181800000000, 0x0000000000828292, 0x9292927c00000000, 0x0000000000424224, 0x1824424200000000, 0x0000000000424242, 0x4242423e02023c00, 0x00000000007e0408, 0x1020407e00000000, 0x00000c1010102010, 0x1010100c00000000, 0x0000101010101010, 0x1010101000000000, 0x0000300808080408, 0x0808083000000000, 0x000000000062928c, 0x0000000000000000 }; char * vertex_shader = "# version 330 core\n" "in vec2 vertex_xy;\n" "in vec2 vertex_uv;\n" "in vec4 vertex_rgba;\n" "out vec2 fragment_uv;\n" "out vec4 fragment_rgba;\n" "void main () {\n" " gl_Position = vec4 (vertex_xy, 0, 1);\n" " fragment_uv = vertex_uv;\n" " fragment_rgba = vertex_rgba;\n" "}\n"; char * fragment_shader = "# version 330 core\n" "uniform sampler2D texture_p;\n" "in vec2 fragment_uv;\n" "in vec4 fragment_rgba;\n" "out vec4 data;\n" "void main () {\n" " data = texture (texture_p, fragment_uv) * fragment_rgba;\n" "}\n"; uint * dumb_buffer = null; uint * order = null; uint xy_attribute = 0; uint uv_attribute = 0; uint rgba_attribute = 0; //~uint flags = 0; uint u = 0; uint v = 0; if (opengl->using_precomputed_spritesheet == true) { for (uint index = 0; index < 95; ++index) { opengl->font_index [opengl->font_count] [index] = ++opengl->sprite_count - 1; } ++opengl->sprite_count; ++opengl->font_count; goto ignore_import; } dumb_buffer = allocate (256 * sizeof (* dumb_buffer)); for (uint index = 0; index < 256; ++index) { dumb_buffer [index] = 0xffffffff; } ++opengl->font_count; uint current = opengl->font_count - 1; opengl->font_index = reallocate (opengl->font_index, opengl->font_count * sizeof (* opengl->font_index)); opengl->font_width = reallocate (opengl->font_width, opengl->font_count * sizeof (* opengl->font_width)); opengl->font_height = reallocate (opengl->font_height, opengl->font_count * sizeof (* opengl->font_height)); opengl->font_begin = reallocate (opengl->font_begin, opengl->font_count * sizeof (* opengl->font_begin)); opengl->font_end = reallocate (opengl->font_end, opengl->font_count * sizeof (* opengl->font_end)); opengl->font_begin [opengl->font_count - 1] = ' '; opengl->font_end [opengl->font_count - 1] = '~'; opengl->font_index [opengl->font_count - 1] = allocate (95 * sizeof (* * opengl->font_index)); opengl->font_width [opengl->font_count - 1] = allocate (95 * sizeof (* * opengl->font_width)); opengl->font_height [opengl->font_count - 1] = allocate (95 * sizeof (* * opengl->font_height)); for (uint index = 0; index < 95; ++index) { uint * buffer = allocate (opengl_font_width * opengl_font_height * sizeof (* buffer)); for (uint value = 0; value < 2; ++value) { for (uint bit = 64; bit > 0; --bit) { uint destination = ((value << 3) - ((bit - 1) >> 3) + 7) * opengl_font_width - ((bit - 1) & 7) + 7; uint source = (font_bitmap [2 * index + value] >> (bit - 1)) & 1; buffer [destination] = (source) ? 0xffffffff : 0x00000000; } } opengl->font_index [current] [index] = opengl_sprite_raw_import (opengl, buffer, opengl_font_width, opengl_font_height); opengl->font_width [current] [index] = opengl_font_width; opengl->font_height [current] [index] = opengl_font_height; } opengl_sprite_raw_import (opengl, dumb_buffer, 16, 16); opengl->spritesheet_data = allocate (opengl->spritesheet_size * opengl->spritesheet_size * sizeof (* opengl->spritesheet_data)); order = allocate (opengl->sprite_count * sizeof (* order)); for (uint index = 0; index < opengl->sprite_count; ++index) { order [index] = index; } for (uint index = 0; index < opengl->sprite_count; ++index) { for (uint subindex = 0; subindex < opengl->sprite_count; ++subindex) { if (opengl->sprite_height [order [index]] < opengl->sprite_height [order [subindex]]) { uint temporary = order [index]; order [index] = order [subindex]; order [subindex] = temporary; } } } for (uint index = 0; index < opengl->sprite_count; ++index) { if (u + opengl->sprite_width [order [index]] >= opengl->spritesheet_size) { u *= 0; v += opengl->sprite_height [order [index]]; } opengl->sprite_u [order [index]] = (float) u / (float) opengl->spritesheet_size; opengl->sprite_v [order [index]] = (float) v / (float) opengl->spritesheet_size; for (uint y = 0; y < opengl->sprite_height [order [index]]; ++y) { for (uint x = 0; x < opengl->sprite_width [order [index]]; ++x) { uint destination = (v + y) * opengl->spritesheet_size + (u + x); uint source = y * opengl->sprite_width [order [index]] + x; opengl->spritesheet_data [destination] = opengl->sprite_data [order [index]] [source]; } } u += opengl->sprite_width [order [index]]; opengl->sprite_data [order [index]] = deallocate (opengl->sprite_data [order [index]]); } opengl->sprite_data = deallocate (opengl->sprite_data); order = deallocate (order); ignore_import: opengl->window_width = window_width; opengl->window_height = window_height; opengl->pixel_width = 2.0f / (float) window_width; opengl->pixel_height = 2.0f / (float) window_height; //~if (window_flags == 0) { //~flags = opengl_window_decorated | opengl_window_resizable; //~} else { //~flags = window_flags; //~} glfwInit (); glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint (GLFW_OPENGL_FORWARD_COMPAT, 1); opengl->window = glfwCreateWindow ((int) window_width, (int) window_height, window_title, null, null); glfwSetWindowSizeLimits (opengl->window, 320, 240, 1920, 1080); fatal_failure (opengl->window == null, "Failed to create GLFW window.\n"); glfwMakeContextCurrent (opengl->window); opengl->glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC) glfwGetProcAddress ("glGenVertexArrays"); opengl->glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC) glfwGetProcAddress ("glBindVertexArray"); opengl->glGenBuffers = (PFNGLGENBUFFERSPROC) glfwGetProcAddress ("glGenBuffers"); opengl->glBindBuffer = (PFNGLBINDBUFFERPROC) glfwGetProcAddress ("glBindBuffer"); opengl->glCreateShader = (PFNGLCREATESHADERPROC) glfwGetProcAddress ("glCreateShader"); opengl->glShaderSource = (PFNGLSHADERSOURCEPROC) glfwGetProcAddress ("glShaderSource"); opengl->glCompileShader = (PFNGLCOMPILESHADERPROC) glfwGetProcAddress ("glCompileShader"); opengl->glCreateProgram = (PFNGLCREATEPROGRAMPROC) glfwGetProcAddress ("glCreateProgram"); opengl->glAttachShader = (PFNGLATTACHSHADERPROC) glfwGetProcAddress ("glAttachShader"); opengl->glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC) glfwGetProcAddress ("glBindFragDataLocation"); opengl->glLinkProgram = (PFNGLLINKPROGRAMPROC) glfwGetProcAddress ("glLinkProgram"); opengl->glUseProgram = (PFNGLUSEPROGRAMPROC) glfwGetProcAddress ("glUseProgram"); opengl->glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) glfwGetProcAddress ("glGetAttribLocation"); opengl->glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC) glfwGetProcAddress ("glEnableVertexAttribArray"); opengl->glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC) glfwGetProcAddress ("glVertexAttribPointer"); opengl->glUniform1i = (PFNGLUNIFORM1IPROC) glfwGetProcAddress ("glUniform1i"); opengl->glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC) glfwGetProcAddress ("glDeleteVertexArrays"); opengl->glDeleteBuffers = (PFNGLDELETEBUFFERSPROC) glfwGetProcAddress ("glDeleteBuffers"); opengl->glDeleteShader = (PFNGLDELETESHADERPROC) glfwGetProcAddress ("glDeleteShader"); opengl->glDeleteProgram = (PFNGLDELETEPROGRAMPROC) glfwGetProcAddress ("glDeleteProgram"); opengl->glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) glfwGetProcAddress ("glGetUniformLocation"); opengl->glBufferData = (PFNGLBUFFERDATAPROC) glfwGetProcAddress ("glBufferData"); glViewport (0, 0, (int) window_width, (int) window_height); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable (GL_CULL_FACE); glEnable (GL_BLEND); opengl->glGenVertexArrays (1, & opengl->vertex_object); opengl->glBindVertexArray (opengl->vertex_object); opengl->glGenBuffers (1, & opengl->vertex_buffer); opengl->glBindBuffer (GL_ARRAY_BUFFER, opengl->vertex_buffer); opengl->glGenBuffers (1, & opengl->index_buffer); opengl->glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, opengl->index_buffer); opengl->vertex_shader = opengl->glCreateShader (GL_VERTEX_SHADER); opengl->glShaderSource (opengl->vertex_shader, 1, & vertex_shader, null); opengl->glCompileShader (opengl->vertex_shader); opengl->fragment_shader = opengl->glCreateShader (GL_FRAGMENT_SHADER); opengl->glShaderSource (opengl->fragment_shader, 1, & fragment_shader, null); opengl->glCompileShader (opengl->fragment_shader); opengl->shader_program = opengl->glCreateProgram (); opengl->glAttachShader (opengl->shader_program, opengl->vertex_shader); opengl->glAttachShader (opengl->shader_program, opengl->fragment_shader); opengl->glBindFragDataLocation (opengl->shader_program, 0, "data"); opengl->glLinkProgram (opengl->shader_program); opengl->glUseProgram (opengl->shader_program); xy_attribute = (uint) opengl->glGetAttribLocation (opengl->shader_program, "vertex_xy"); opengl->glEnableVertexAttribArray (xy_attribute); opengl->glVertexAttribPointer (xy_attribute, 2, GL_FLOAT, GL_FALSE, 8 * sizeof (float), (void *) 0); uv_attribute = (uint) opengl->glGetAttribLocation (opengl->shader_program, "vertex_uv"); opengl->glEnableVertexAttribArray (uv_attribute); opengl->glVertexAttribPointer (uv_attribute, 2, GL_FLOAT, GL_FALSE, 8 * sizeof (float), (void *) (2 * sizeof (float))); rgba_attribute = (uint) opengl->glGetAttribLocation (opengl->shader_program, "vertex_rgba"); opengl->glEnableVertexAttribArray (rgba_attribute); opengl->glVertexAttribPointer (rgba_attribute, 4, GL_FLOAT, GL_FALSE, 8 * sizeof (float), (void *) (4 * sizeof (float))); opengl->vertex_array = allocate (opengl->vertex_limit * sizeof (opengl->vertex_array)); opengl->index_array = allocate (opengl->index_limit * sizeof (opengl->index_array)); glGenTextures (1, & opengl->spritesheet); glBindTexture (GL_TEXTURE_2D, opengl->spritesheet); glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, opengl->spritesheet_size, opengl->spritesheet_size, 0, GL_RGBA, GL_UNSIGNED_BYTE, opengl->spritesheet_data); opengl->glUniform1i (opengl->glGetUniformLocation (opengl->shader_program, "texture_p"), 0); 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); if (opengl->using_precomputed_spritesheet == true) { opengl->spritesheet_data = deallocate (opengl->spritesheet_data); } opengl->active = true; opengl->frame_begin = nano_time (); glClearColor (0.0f, 0.0f, 0.0f, 1.0f); glClear (GL_COLOR_BUFFER_BIT); print ("[/2Success/-] Configured OpenGL renderer.\n"); } static void opengl_synchronize (opengl_structure * opengl, uint colour) { int signal_code [signal_count] = { 0, GLFW_KEY_A, GLFW_KEY_B, GLFW_KEY_C, GLFW_KEY_D, GLFW_KEY_E, GLFW_KEY_F, GLFW_KEY_G, GLFW_KEY_H, GLFW_KEY_I, GLFW_KEY_J, GLFW_KEY_K, GLFW_KEY_L, GLFW_KEY_M, GLFW_KEY_N, GLFW_KEY_O, GLFW_KEY_P, GLFW_KEY_Q, GLFW_KEY_R, GLFW_KEY_S, GLFW_KEY_T, GLFW_KEY_U, GLFW_KEY_V, GLFW_KEY_W, GLFW_KEY_X, GLFW_KEY_Y, GLFW_KEY_Z, GLFW_KEY_0, GLFW_KEY_1, GLFW_KEY_2, GLFW_KEY_3, GLFW_KEY_4, GLFW_KEY_5, GLFW_KEY_6, GLFW_KEY_7, GLFW_KEY_8, GLFW_KEY_9, GLFW_KEY_ESCAPE, GLFW_KEY_TAB, GLFW_KEY_ENTER, GLFW_KEY_ENTER, GLFW_KEY_SLASH, GLFW_KEY_BACKSLASH, GLFW_KEY_SEMICOLON, GLFW_KEY_GRAVE_ACCENT, GLFW_KEY_SPACE, GLFW_KEY_BACKSPACE, GLFW_KEY_PERIOD, GLFW_KEY_COMMA, GLFW_KEY_APOSTROPHE, GLFW_KEY_CAPS_LOCK, GLFW_KEY_MINUS, GLFW_KEY_EQUAL, GLFW_KEY_LEFT_BRACKET, GLFW_KEY_RIGHT_BRACKET, GLFW_KEY_LEFT_CONTROL, GLFW_KEY_RIGHT_CONTROL, GLFW_KEY_LEFT_SHIFT, GLFW_KEY_RIGHT_SHIFT, GLFW_KEY_LEFT_ALT, GLFW_KEY_RIGHT_ALT, GLFW_KEY_F1, GLFW_KEY_F2, GLFW_KEY_F3, GLFW_KEY_F4, GLFW_KEY_F5, GLFW_KEY_F6, GLFW_KEY_F7, GLFW_KEY_F8, GLFW_KEY_F9, GLFW_KEY_F10, GLFW_KEY_F11, GLFW_KEY_F12, GLFW_KEY_UP, GLFW_KEY_DOWN, GLFW_KEY_LEFT, GLFW_KEY_RIGHT, GLFW_KEY_NUM_LOCK, GLFW_KEY_PAUSE, GLFW_KEY_INSERT, GLFW_KEY_HOME, GLFW_KEY_PAGE_UP, GLFW_KEY_DELETE, GLFW_KEY_END, GLFW_KEY_PAGE_DOWN, GLFW_KEY_KP_ADD, GLFW_KEY_KP_SUBTRACT, GLFW_KEY_KP_MULTIPLY, GLFW_KEY_KP_DIVIDE, GLFW_KEY_KP_ENTER, GLFW_KEY_KP_DECIMAL, GLFW_KEY_KP_0, GLFW_KEY_KP_1, GLFW_KEY_KP_2, GLFW_KEY_KP_3, GLFW_KEY_KP_4, GLFW_KEY_KP_5, GLFW_KEY_KP_6, GLFW_KEY_KP_7, GLFW_KEY_KP_8, GLFW_KEY_KP_9 }; float r = (float) ((colour >> 24) & 0xff) / 255.0f; float g = (float) ((colour >> 16) & 0xff) / 255.0f; float b = (float) ((colour >> 8) & 0xff) / 255.0f; float a = (float) ((colour >> 0) & 0xff) / 255.0f; int new_window_width = 0; int new_window_height = 0; glClearColor (r, g, b, a); glClear (GL_COLOR_BUFFER_BIT); glfwPollEvents (); glfwSetWindowShouldClose (opengl->window, opengl->active == false); glfwGetWindowSize (opengl->window, & new_window_width, & new_window_height); if ((opengl->window_width != (uint) new_window_width) || (opengl->window_height != (uint) new_window_height)) { if ((new_window_width <= 0) || (new_window_height <= 0)) return; glViewport (0, 0, new_window_width, new_window_height); opengl->window_width = (uint) new_window_width; opengl->window_height = (uint) new_window_height; opengl->pixel_width = 2.0f / (float) new_window_width; opengl->pixel_height = 2.0f / (float) new_window_height; } opengl->cursor [cursor_left] = (bool) (glfwGetMouseButton (opengl->window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS); opengl->cursor [cursor_middle] = (bool) (glfwGetMouseButton (opengl->window, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS); opengl->cursor [cursor_right] = (bool) (glfwGetMouseButton (opengl->window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS); if (opengl->freeze_cursor == false) { double x = 0.0; double y = 0.0; glfwGetCursorPos (opengl->window, & x, & y); opengl->cursor_x = (int) x; opengl->cursor_y = (int) y; //~if ((opengl->cursor_x < 0) || (opengl->cursor_x > (int) opengl->window_width) || //~(opengl->cursor_y < 0) || (opengl->cursor_y > (int) opengl->window_height)) { //~opengl->cursor_x = 0; //~opengl->cursor_y = 0; //~} } else { if ((opengl->cursor [cursor_left] == false) && (opengl->cursor [cursor_middle] == false) && (opengl->cursor [cursor_right] == false)) { opengl->freeze_cursor = false; } } if (opengl->freeze_signal == false) { for (uint index = 0; index < signal_count; ++index) { opengl->signal [index] = (bool) (glfwGetKey (opengl->window, signal_code [index]) == GLFW_PRESS); } } opengl->glBufferData (GL_ARRAY_BUFFER, opengl->vertex_count * 4, opengl->vertex_array, GL_DYNAMIC_DRAW); opengl->glBufferData (GL_ELEMENT_ARRAY_BUFFER, opengl->index_count * 4, opengl->index_array, GL_DYNAMIC_DRAW); opengl->glBindBuffer (GL_ARRAY_BUFFER, opengl->vertex_buffer); glDrawElements (GL_TRIANGLES, (int) opengl->index_count * 4, GL_UNSIGNED_INT, null); glfwSwapBuffers (opengl->window); opengl->vertex_count = 0; opengl->index_count = 0; opengl->frame_end = nano_time (); opengl->frame_time = opengl->frame_end - opengl->frame_begin; if (opengl->frame_time < 1000000000ul / opengl->gameplay_framerate) { nano_wait (1000000000ul / opengl->gameplay_framerate - opengl->frame_time); } if (opengl->global_tick % opengl->gameplay_framerate == 0) { opengl->framerate = (uint) (1000000000ul / opengl->frame_time); } ++opengl->global_tick; opengl->global_tick = opengl->global_tick % (opengl->gameplay_framerate * opengl->animation_framerate); opengl->gameplay_tick = opengl->global_tick % (opengl->gameplay_framerate); opengl->animation_tick = opengl->global_tick / (opengl->gameplay_framerate / opengl->animation_framerate); opengl->frame_begin = nano_time (); } static void opengl_render_base (opengl_structure * opengl, uint sprite, int x, int y, uint u, uint v, uint width, uint height, float scale_x, float scale_y, int flip_x, int flip_y, uint colour_upper_left, uint colour_upper_right, uint colour_lower_left, uint colour_lower_right) { float screen_x = 0.0f; float screen_y = 0.0f; float unwrap_x = 0.0f; float unwrap_y = 0.0f; float screen_width = 0.0f; float screen_height = 0.0f; float unwrap_width = 0.0f; float unwrap_height = 0.0f; if ((x > (int) opengl->window_width) || (y > (int) opengl->window_height)) return; if ((x < (int) - ((float) width * scale_x)) || (y < (int) - ((float) height * scale_y))) return; if (sprite >= opengl->sprite_count) return; if (opengl->vertex_count + 32 >= opengl->vertex_limit) return; if (opengl->index_count + 6 >= opengl->index_limit) return; screen_x = + ((float) x * opengl->pixel_width - 1); screen_y = - ((float) y * opengl->pixel_height - 1); unwrap_x = opengl->sprite_u [sprite] + (float) u / (float) opengl->spritesheet_size; unwrap_y = opengl->sprite_v [sprite] + (float) v / (float) opengl->spritesheet_size; screen_width = +((float) width * opengl->pixel_width * scale_x); screen_height = -((float) height * opengl->pixel_height * scale_y); unwrap_width = (float) width / (float) opengl->spritesheet_size; unwrap_height = (float) height / (float) opengl->spritesheet_size; opengl->vertex_array [opengl->vertex_count + 0] = screen_x; opengl->vertex_array [opengl->vertex_count + 1] = screen_y; opengl->vertex_array [opengl->vertex_count + 2] = unwrap_x + unwrap_width * (float) (flip_y != 0); opengl->vertex_array [opengl->vertex_count + 3] = unwrap_y + unwrap_height * (float) (flip_x != 0); opengl->vertex_array [opengl->vertex_count + 4] = normal_r (colour_upper_left); opengl->vertex_array [opengl->vertex_count + 5] = normal_g (colour_upper_left); opengl->vertex_array [opengl->vertex_count + 6] = normal_b (colour_upper_left); opengl->vertex_array [opengl->vertex_count + 7] = normal_a (colour_upper_left); opengl->vertex_array [opengl->vertex_count + 8] = screen_x + screen_width; opengl->vertex_array [opengl->vertex_count + 9] = screen_y; opengl->vertex_array [opengl->vertex_count + 10] = unwrap_x + unwrap_width * (float) (flip_y == 0); opengl->vertex_array [opengl->vertex_count + 11] = unwrap_y + unwrap_height * (float) (flip_x != 0); opengl->vertex_array [opengl->vertex_count + 12] = normal_r (colour_upper_right); opengl->vertex_array [opengl->vertex_count + 13] = normal_g (colour_upper_right); opengl->vertex_array [opengl->vertex_count + 14] = normal_b (colour_upper_right); opengl->vertex_array [opengl->vertex_count + 15] = normal_a (colour_upper_right); opengl->vertex_array [opengl->vertex_count + 16] = screen_x; opengl->vertex_array [opengl->vertex_count + 17] = screen_y + screen_height; opengl->vertex_array [opengl->vertex_count + 18] = unwrap_x + unwrap_width * (float) (flip_y != 0); opengl->vertex_array [opengl->vertex_count + 19] = unwrap_y + unwrap_height * (float) (flip_x == 0); opengl->vertex_array [opengl->vertex_count + 20] = normal_r (colour_lower_left); opengl->vertex_array [opengl->vertex_count + 21] = normal_g (colour_lower_left); opengl->vertex_array [opengl->vertex_count + 22] = normal_b (colour_lower_left); opengl->vertex_array [opengl->vertex_count + 23] = normal_a (colour_lower_left); opengl->vertex_array [opengl->vertex_count + 24] = screen_x + screen_width; opengl->vertex_array [opengl->vertex_count + 25] = screen_y + screen_height; opengl->vertex_array [opengl->vertex_count + 26] = unwrap_x + unwrap_width * (float) (flip_y == 0); opengl->vertex_array [opengl->vertex_count + 27] = unwrap_y + unwrap_height * (float) (flip_x == 0); opengl->vertex_array [opengl->vertex_count + 28] = normal_r (colour_lower_right); opengl->vertex_array [opengl->vertex_count + 29] = normal_g (colour_lower_right); opengl->vertex_array [opengl->vertex_count + 30] = normal_b (colour_lower_right); opengl->vertex_array [opengl->vertex_count + 31] = normal_a (colour_lower_right); opengl->index_array [opengl->index_count + 0] = (opengl->vertex_count / 8) + 2; opengl->index_array [opengl->index_count + 1] = (opengl->vertex_count / 8) + 1; opengl->index_array [opengl->index_count + 2] = (opengl->vertex_count / 8) + 0; opengl->index_array [opengl->index_count + 3] = (opengl->vertex_count / 8) + 1; opengl->index_array [opengl->index_count + 4] = (opengl->vertex_count / 8) + 2; opengl->index_array [opengl->index_count + 5] = (opengl->vertex_count / 8) + 3; opengl->vertex_count += 32; opengl->index_count += 6; } static void opengl_render_rectangle (opengl_structure * opengl, int x, int y, uint width, uint height, uint colour) { opengl_render_base (opengl, opengl->sprite_count - 1, x, y, 0, 0, 16, 16, (float) width / 16.0f, (float) height / 16.0f, 0, 0, colour, colour, colour, colour); } static void opengl_render_rectangle_vertical_gradient (opengl_structure * opengl, int x, int y, uint width, uint height, uint colour_up, uint colour_down) { opengl_render_base (opengl, opengl->sprite_count - 1, x, y, 0, 0, 16, 16, (float) width / 16.0f, (float) height / 16.0f, 0, 0, colour_up, colour_up, colour_down, colour_down); } static void opengl_render_rectangle_horizontal_gradient (opengl_structure * opengl, int x, int y, uint width, uint height, uint colour_left, uint colour_right) { opengl_render_base (opengl, opengl->sprite_count - 1, x, y, 0, 0, 16, 16, (float) width / 16.0f, (float) height / 16.0f, 0, 0, colour_left, colour_right, colour_left, colour_right); } static void opengl_render_sprite (opengl_structure * opengl, uint sprite, int x, int y) { opengl_render_base (opengl, sprite, x, y, 0, 0, opengl->sprite_width [sprite], opengl->sprite_height [sprite], 1.0f, 1.0f, 0, 0, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu); } static void opengl_render_sprite_crop (opengl_structure * opengl, uint sprite, int x, int y, uint u, uint v, uint width, uint height) { opengl_render_base (opengl, sprite, x, y, u, v, width, height, 1.0f, 1.0f, 0, 0, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu); } static void opengl_render_sprite_flip (opengl_structure * opengl, uint sprite, int x, int y, int flip_x, int flip_y) { opengl_render_base (opengl, sprite, x, y, 0, 0, opengl->sprite_width [sprite], opengl->sprite_height [sprite], 1.0f, 1.0f, flip_x, flip_y, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu); } static void opengl_render_sprite_colour (opengl_structure * opengl, uint sprite, int x, int y, uint colour) { opengl_render_base (opengl, sprite, x, y, 0, 0, opengl->sprite_width [sprite], opengl->sprite_height [sprite], 1.0f, 1.0f, 0, 0, colour, colour, colour, colour); } static void opengl_render_sprite_control (opengl_structure * opengl, uint sprite, int x, int y, uint u, uint v, uint width, uint height, int flip_x, int flip_y) { opengl_render_base (opengl, sprite, x, y, u, v, width, height, 1.0f, 1.0f, flip_x, flip_y, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu); } static void opengl_render_sprite_crop_colour (opengl_structure * opengl, uint sprite, uint colour, int x, int y, uint u, uint v, uint width, uint height) { opengl_render_base (opengl, sprite, x, y, u, v, width, height, 1.0f, 1.0f, 0, 0, colour, colour, colour, colour); } static void opengl_render_sprite_animate (opengl_structure * opengl, uint sprite, int x, int y, uint frames, uint state, uint states) { uint width = opengl->sprite_width [sprite] / states; uint height = opengl->sprite_height [sprite] / frames; uint u = width * (state % states); uint v = height * (opengl->animation_tick % frames); opengl_render_sprite_crop (opengl, sprite, x, y, u, v, width, height); } static uint opengl_render_character_width (opengl_structure * opengl, char character, uint font, float scale) { if ((character < opengl->font_begin [font]) || (character > opengl->font_end [font])) { return (0); } else { uint index = opengl->font_index [font] [character - opengl->font_begin [font]]; return ((uint) (scale * (float) opengl->sprite_width [index])); } } static uint opengl_render_character_height (opengl_structure * opengl, char character, uint font, float scale) { if ((character < opengl->font_begin [font]) || (character > opengl->font_end [font])) { return (0); } else { uint index = opengl->font_index [font] [character - opengl->font_begin [font]]; return ((uint) (scale * (float) opengl->sprite_height [index])); } } static uint opengl_render_string_width (opengl_structure * opengl, char * string, uint font, float scale) { uint width = 0; uint match = 0; if (string == null) { return (0); } for (uint index = 0; string [index] != '\0'; ++index) { if (string [index] == '\t') { width += opengl->tab_width * opengl_render_character_width (opengl, ' ', font, scale); } else if (string [index] == '\n') { match = maximum (width, match); width = 0; } else { width += opengl_render_character_width (opengl, string [index], font, scale); } } return (maximum (width, match)); } static uint opengl_render_string_height (opengl_structure * opengl, char * string, uint font, float scale) { uint height = opengl_render_character_height (opengl, ' ', font, scale); if ((string == null) || (string [0] == '\0')) { return (0); } for (uint index = 0; string [index] != '\0'; ++index) { if (string [index] == '\n') { height += opengl_render_character_height (opengl, ' ', font, scale); } } return (height); } static void opengl_render_character_base (opengl_structure * opengl, char character, uint font, int x, int y, float scale, uint colour_upper_left, uint colour_upper_right, uint colour_lower_left, uint colour_lower_right) { if ((character < opengl->font_begin [font]) || (character > opengl->font_end [font])) return; if (font == opengl->default_font) { font = opengl->font_count - 1; } uint index = opengl->font_index [font] [character - opengl->font_begin [font]]; uint width = opengl->sprite_width [index]; uint height = opengl->sprite_height [index]; opengl_render_base (opengl, index, x, y, 0, 0, width, height, scale, scale, 0, 0, colour_upper_left, colour_upper_right, colour_lower_left, colour_lower_right); } static void opengl_render_character (opengl_structure * opengl, char character, uint font, int x, int y, float scale, uint colour) { opengl_render_character_base (opengl, character, font, x, y, scale, colour, colour, colour, colour); } static void opengl_render_character_vertical_gradient (opengl_structure * opengl, char character, uint font, int x, int y, float scale, uint colour_up, uint colour_down) { opengl_render_character_base (opengl, character, font, x, y, scale, colour_up, colour_up, colour_down, colour_down); } static void opengl_render_character_horizontal_gradient (opengl_structure * opengl, char character, uint font, int x, int y, float scale, uint colour_left, uint colour_right) { opengl_render_character_base (opengl, character, font, x, y, scale, colour_left, colour_right, colour_left, colour_right); } static void opengl_render_string_base (opengl_structure * opengl, char * string, uint font, int x, int y, float scale, uint colour_upper_left, uint colour_upper_right, uint colour_lower_left, uint colour_lower_right) { int offset = x; if (string == null) return; for (uint index = 0; string [index] != '\0'; ++index) { if (string [index] == '\t') { x += opengl->tab_width * opengl_render_character_width (opengl, ' ', font, scale); continue; } else if (string [index] == '\n') { x = offset; y += opengl_render_character_height (opengl, ' ', font, scale); continue; } else { opengl_render_character_base (opengl, string [index], font, x, y, scale, colour_upper_left, colour_upper_right, colour_lower_left, colour_lower_right); x += opengl_render_character_width (opengl, string [index], font, scale); } } } static void opengl_render_string (opengl_structure * opengl, char * string, uint font, int x, int y, float scale, uint colour) { opengl_render_string_base (opengl, string, font, x, y, scale, colour, colour, colour, colour); } static void opengl_render_string_vertical_gradient (opengl_structure * opengl, char * string, uint font, int x, int y, float scale, uint colour_up, uint colour_down) { opengl_render_string_base (opengl, string, font, x, y, scale, colour_up, colour_up, colour_down, colour_down); } static void opengl_render_string_horizontal_gradient (opengl_structure * opengl, char * string, uint font, int x, int y, float scale, uint colour_left, uint colour_right) { opengl_render_string_base (opengl, string, font, x, y, scale, colour_left, colour_right, colour_left, colour_right); } static void opengl_render_string_full_vertical_gradient (opengl_structure * opengl, char * string, uint font, int x, int y, float scale, uint colour_up, uint colour_down) { int offset = x; uint back = 0; uint up = 0; uint down = 0; float interpolator = 1.0f / (float) string_full_height (string); if (string == null) return; for (uint index = 0; string [index] != '\0'; ++index) { if (string [index] == '\t') { x += opengl->tab_width * opengl_render_character_width (opengl, ' ', font, scale); continue; } else if (string [index] == '\n') { back += 1; x = offset; y += opengl_render_character_height (opengl, ' ', font, scale); continue; } else { up = colour_linear_interpolation (colour_up, colour_down, (float) (back + 0) * interpolator); down = colour_linear_interpolation (colour_up, colour_down, (float) (back + 1) * interpolator); opengl_render_character_vertical_gradient (opengl, string [index], font, x, y, scale, up, down); x += opengl_render_character_width (opengl, string [index], font, scale); } } } static void opengl_render_string_full_horizontal_gradient (opengl_structure * opengl, char * string, uint font, int x, int y, float scale, uint colour_left, uint colour_right) { int offset = x; uint back = 0; uint left = 0; uint right = 0; float interpolator = 1.0f / (float) string_full_width (string, opengl->tab_width); if (string == null) return; for (uint index = 0; string [index] != '\0'; ++index) { if (string [index] == '\t') { x += opengl->tab_width * opengl_render_character_width (opengl, ' ', font, scale); continue; } else if (string [index] == '\n') { back = 0; x = offset; y += opengl_render_character_height (opengl, ' ', font, scale); continue; } else { back += 1; left = colour_linear_interpolation (colour_left, colour_right, (float) (back + 0) * interpolator); right = colour_linear_interpolation (colour_left, colour_right, (float) (back + 1) * interpolator); opengl_render_character_horizontal_gradient (opengl, string [index], font, x, y, scale, left, right); x += opengl_render_character_width (opengl, string [index], font, scale); } } } static void opengl_render_framerate (opengl_structure * opengl, uint font, int x, int y, float scale, uint colour) { opengl_render_string (opengl, number_to_string (opengl->framerate), font, x, y, scale, colour); } #undef opengl_font_width #undef opengl_font_height