/// _ /// __ ___ __ ___ _ __ __ _| | /// \ \/ / '_ \ / _ \ '_ \ / _` | | /// > <| |_) | __/ | | | (_| | | /// /_/\_\ .__/ \___|_| |_|\__, |_| /// |_| |___/ /// /// 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 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; PFNGLGETSHADERIVPROC glGetShaderiv; PFNGLGETPROGRAMIVPROC glGetProgramiv; boolean signal [signal_count]; boolean cursor [cursor_count]; integer cursor_x; integer cursor_y; boolean active; boolean very_verbose_spam; natural window_width; natural window_height; natural_64 frame_time; natural_64 frame_begin; natural_64 frame_end; natural framerate; natural global_tick; natural gameplay_tick; natural animation_tick; natural gameplay_framerate; natural animation_framerate; natural sprite_count; natural font_count; natural * * sprite_data; natural * sprite_width; natural * sprite_height; natural * * font_index; natural * * font_width; natural * * font_height; character * font_begin; character * font_end; natural tab_width; natural default_font; boolean using_precomputed_spritesheet; real pixel_width; real pixel_height; natural vertex_object; natural vertex_buffer; natural index_buffer; natural vertex_shader; natural fragment_shader; natural shader_program; natural spritesheet; caliber vertex_limit; caliber index_limit; natural vertex_count; natural index_count; real * vertex_array; natural * index_array; natural * spritesheet_data; real * sprite_u; real * sprite_v; caliber spritesheet_size; boolean freeze_cursor; boolean freeze_signal; } opengl_structure; static opengl_structure * opengl_initialize (natural gameplay_framerate, natural animation_framerate, boolean use_precomputed_spritesheet, natural maximum_quads_on_screen, natural 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; print ("/s Initialized OpenGL renderer.\n"); return (opengl); } static opengl_structure * opengl_deinitialize (opengl_structure * opengl) { opengl->active = false; for (natural 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 ("/s Deinitialized OpenGL renderer.\n"); return (deallocate (opengl)); } static natural opengl_sprite_raw_import (opengl_structure * opengl, natural * data, natural width, natural height) { natural current = ++opengl->sprite_count - 1; 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_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 [current] = data; opengl->sprite_width [current] = width; opengl->sprite_height [current] = height; opengl->sprite_u [current] = 0; opengl->sprite_v [current] = 0; return (current); } static natural opengl_font_raw_import (opengl_structure * opengl, natural * data, natural image_width, natural image_height, character begin, character end, natural separator_colour) { natural current = ++opengl->font_count - 1; natural pointer = 0; natural width = 0; natural height = 0; natural point_count = 0; natural * point_array = null; 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 (image_height == 0, "opengl_font_raw_import: Font image height is zero."); fatal_failure (begin >= end, "opengl_font_raw_import: Font character range is inverted."); 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 [current] = begin; opengl->font_end [current] = end; opengl->font_index [current] = allocate ((caliber) (end - begin + 1) * sizeof (* * opengl->font_index)); opengl->font_width [current] = allocate ((caliber) (end - begin + 1) * sizeof (* * opengl->font_width)); opengl->font_height [current] = allocate ((caliber) (end - begin + 1) * sizeof (* * opengl->font_height)); point_array = allocate ((caliber) (end - begin + 1) * sizeof (* point_array)); if (separator_colour == 0x00000000u) { separator_colour = data [0]; } for (natural y = 0; y < image_height - 1; ++y) { for (natural x = 0; x < image_width - 1; ++x) { if ((data [(y + 0) * image_width + (x + 0)] == separator_colour) && (data [(y + 1) * image_width + (x + 0)] == separator_colour) && (data [(y + 0) * image_width + (x + 1)] == separator_colour) && (data [(y + 1) * image_width + (x + 1)] == 0x00000000u)) { ++point_count; point_array [point_count - 1] = (y + 1) * image_width + (x + 1); } } } if (point_count != end - begin + 1) { print ("/w Mismatch between font character points:\n"); print ("/c --- Hardcoded expected number of character points: %i\n", end - begin + 1); print ("/c --- Algorithm found number of character points: %i\n", point_count); } for (natural index = 0; index < end - begin + 1; ++index) { for (width = 0; data [point_array [index] + width] != separator_colour; ++width); for (height = 0; data [point_array [index] + height * image_width] != separator_colour; ++height); fatal_failure (width == 0, "opengl_font_raw_import: Font width is zero."); fatal_failure (height == 0, "opengl_font_raw_import: Font height is zero."); natural * buffer = allocate (width * height * sizeof (* buffer)); for (natural y = 0; y < height; ++y) { for (natural x = 0; x < width; ++x) { buffer [y * width + x] = data [point_array [index] + y * image_width + x]; } } opengl->font_index [current] [index] = opengl_sprite_raw_import (opengl, buffer, width, height); opengl->font_width [current] [index] = width; opengl->font_height [current] [index] = height; } point_array = deallocate (point_array); return (current); } static natural opengl_sprite_import (opengl_structure * opengl, character * path) { natural width = 0; natural height = 0; natural * data = null; fatal_failure (opengl->active == true, "opengl_sprite_import: OpenGL renderer is already initialized."); if (opengl->using_precomputed_spritesheet == true) { return (++opengl->sprite_count - 1); } data = format_image_import (path, & width, & height); conditional_print ((data == null) || (width == 0) || (height == 0), "/f Failed to import sprite '%s'.", path); conditional_print (opengl->very_verbose_spam == true, "/c Importing sprite '/0/B%s/-' of size %i x %i.\n", path, width, height); return (opengl_sprite_raw_import (opengl, data, width, height)); } static natural opengl_font_import (opengl_structure * opengl, character * path, character begin, character end, natural colour) { natural width = 0; natural height = 0; natural result = 0; natural * data = null; character buffer [256] = ""; fatal_failure (opengl->active == true, "opengl_font_import: OpenGL renderer is already initialized."); if (opengl->using_precomputed_spritesheet == true) { for (character index = begin; index <= end; ++index) { opengl->font_index [opengl->font_count] [index - begin] = ++opengl->sprite_count - 1; } return (++opengl->font_count - 1); } data = format_image_import (path, & width, & height); conditional_print (opengl->very_verbose_spam == true, "/c Importing font '/0/B%s/-' of size %i x %i, in range from (%i) to (%i).\n", path, width, height, begin, end); result = opengl_font_raw_import (opengl, data, width, height, begin, end, colour); data = deallocate (data); return (result); } static natural opengl_sprite_width (opengl_structure * opengl, natural sprite) { return ((sprite >= opengl->sprite_count) ? 0 : opengl->sprite_width [sprite]); } static natural opengl_sprite_height (opengl_structure * opengl, natural sprite) { return ((sprite >= opengl->sprite_count) ? 0 : opengl->sprite_height [sprite]); } static natural opengl_character_width (opengl_structure * opengl, character data, natural font, real scale) { if (font == ~ 0u) { font = opengl->font_count - 1; } if ((data < opengl->font_begin [font]) || (data > opengl->font_end [font])) { return (0); } else { natural index = opengl->font_index [font] [data - opengl->font_begin [font]]; return ((natural) (scale * (real) opengl->sprite_width [index])); } } static natural opengl_character_height (opengl_structure * opengl, character data, natural font, real scale) { if (font == ~ 0u) { font = opengl->font_count - 1; } if ((data < opengl->font_begin [font]) || (data > opengl->font_end [font])) { return (0); } else { natural index = opengl->font_index [font] [data - opengl->font_begin [font]]; return ((natural) (scale * (real) opengl->sprite_height [index])); } } static natural opengl_string_width (opengl_structure * opengl, character * string, natural font, real scale) { natural width = 0; natural match = 0; if (string == null) { return (0); } for (natural index = 0; string [index] != '\0'; ++index) { if (string [index] == '\t') { width += opengl->tab_width * opengl_character_width (opengl, ' ', font, scale); } else if (string [index] == '\n') { match = maximum_macro (width, match); width = 0; } else { width += opengl_character_width (opengl, string [index], font, scale); } } return (maximum_macro (width, match)); } static natural opengl_string_height (opengl_structure * opengl, character * string, natural font, real scale) { natural height = opengl_character_height (opengl, ' ', font, scale); if ((string == null) || (string [0] == '\0')) { return (0); } for (natural index = 0; string [index] != '\0'; ++index) { if (string [index] == '\n') { height += opengl_character_height (opengl, ' ', font, scale); } } return (height); } static natural opengl_center_x (opengl_structure * opengl, natural size) { return ((opengl->window_width - size) / 2); } static natural opengl_center_y (opengl_structure * opengl, natural size) { return ((opengl->window_height - size) / 2); } static boolean opengl_cursor_inside (opengl_structure * opengl, integer x, integer y, natural width, natural height) { return ((opengl->cursor_x > x) && (opengl->cursor_y > y) && (opengl->cursor_x < x + (integer) width) && (opengl->cursor_y < y + (integer) height)); } static procedure opengl_import_spritesheet (opengl_structure * opengl, character * data_file) { integer 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 (natural index = 0; index < opengl->font_count; ++index) { natural range = (natural) (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 (natural 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; print ("/c Imported internal binary data of OpenGL spritesheet.\n"); } static procedure opengl_export_spritesheet (opengl_structure * opengl, character * data_file) { integer 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 (natural index = 0; index < opengl->font_count; ++index) { for (natural subindex = 0; subindex < (natural) (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.\n"); } static procedure opengl_configure (opengl_structure * opengl, natural window_width, natural window_height, character * window_title) { natural_64 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 }; const character * 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"; const character * 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"; natural * dumb_buffer = null; natural * order = null; natural xy_attribute = 0; natural uv_attribute = 0; natural rgba_attribute = 0; natural u = 0; natural v = 0; integer status = GL_NO_ERROR; if (opengl->using_precomputed_spritesheet == true) { for (natural index = 0; index < 95; ++index) { opengl->font_index [opengl->font_count] [index] = ++opengl->sprite_count - 1; } ++opengl->sprite_count; ++opengl->font_count; print ("[/0Comment/-] Importing spritesheet image and information...\n"); opengl_import_spritesheet (opengl, "binary/spritesheet.bin"); goto ignore_import; } dumb_buffer = allocate (256 * sizeof (* dumb_buffer)); for (natural index = 0; index < 256; ++index) { dumb_buffer [index] = 0xffffffff; } natural 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 [current] = ' '; opengl->font_end [current] = '~'; opengl->font_index [current] = allocate (95 * sizeof (* * opengl->font_index)); opengl->font_width [current] = allocate (95 * sizeof (* * opengl->font_width)); opengl->font_height [current] = allocate (95 * sizeof (* * opengl->font_height)); for (natural index = 0; index < 95; ++index) { natural * buffer = allocate (opengl_font_width * opengl_font_height * sizeof (* buffer)); for (natural value = 0; value < 2; ++value) { for (natural bit = 64; bit > 0; --bit) { natural destination = ((value << 3) - ((bit - 1) >> 3) + 7) * opengl_font_width - ((bit - 1) & 7) + 7; natural 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 (natural index = 0; index < opengl->sprite_count; ++index) { order [index] = index; } for (natural index = 0; index < opengl->sprite_count; ++index) { for (natural subindex = 0; subindex < opengl->sprite_count; ++subindex) { if (opengl->sprite_height [order [index]] < opengl->sprite_height [order [subindex]]) { exchange_natural (& order [index], & order [subindex]); } } } for (natural 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]] = (real) u / (real) opengl->spritesheet_size; opengl->sprite_v [order [index]] = (real) v / (real) opengl->spritesheet_size; for (natural y = 0; y < opengl->sprite_height [order [index]]; ++y) { for (natural x = 0; x < opengl->sprite_width [order [index]]; ++x) { natural destination = (v + y) * opengl->spritesheet_size + (u + x); natural 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 / (real) window_width; opengl->pixel_height = 2.0f / (real) window_height; 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 ((integer) window_width, (integer) window_height, window_title, null, null); fatal_failure (opengl->window == null, "Failed to create GLFW window.\n"); glfwSetWindowSizeLimits (opengl->window, 320, 240, 1920, 1080); /// REDO 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"); opengl->glGetShaderiv = (PFNGLGETSHADERIVPROC) glfwGetProcAddress ("glGetShaderiv"); opengl->glGetProgramiv = (PFNGLGETPROGRAMIVPROC) glfwGetProcAddress ("glGetProgramiv"); glViewport (0, 0, (integer) window_width, (integer) window_height); conditional_print ((status = glGetError ()) != GL_NO_ERROR, "/f Failed to set OpenGL viewport dimensions: %i\n", status); opengl->glGenVertexArrays (1, & opengl->vertex_object); opengl->glBindVertexArray (opengl->vertex_object); conditional_print ((status = glGetError ()) != GL_NO_ERROR, "/f Failed to generate and bind OpenGL vertex array object: %i\n", status); opengl->glGenBuffers (1, & opengl->vertex_buffer); opengl->glBindBuffer (GL_ARRAY_BUFFER, opengl->vertex_buffer); conditional_print ((status = glGetError ()) != GL_NO_ERROR, "/f Failed to generate and bind OpenGL vertex buffer object: %i\n", status); opengl->glGenBuffers (1, & opengl->index_buffer); opengl->glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, opengl->index_buffer); conditional_print ((status = glGetError ()) != GL_NO_ERROR, "/f Failed to generate and bind OpenGL index buffer object: %i\n", status); opengl->vertex_shader = opengl->glCreateShader (GL_VERTEX_SHADER); conditional_print (opengl->vertex_shader == 0, "/f Failed to create OpenGL vertex shader: %i\n", glGetError ()); opengl->glShaderSource (opengl->vertex_shader, 1, & vertex_shader, null); opengl->glCompileShader (opengl->vertex_shader); opengl->glGetShaderiv (opengl->vertex_shader, GL_COMPILE_STATUS, & status); conditional_print (status == GL_FALSE, "/f Failed to compile OpenGL vertex shader: %i\n", status); opengl->fragment_shader = opengl->glCreateShader (GL_FRAGMENT_SHADER); conditional_print (opengl->fragment_shader == 0, "/f Failed to create OpenGL fragment shader: %i\n", glGetError ()); opengl->glShaderSource (opengl->fragment_shader, 1, & fragment_shader, null); opengl->glCompileShader (opengl->fragment_shader); opengl->glGetShaderiv (opengl->fragment_shader, GL_COMPILE_STATUS, & status); conditional_print (status == GL_FALSE, "/f Failed to compile OpenGL fragment shader: %i\n", status); opengl->shader_program = opengl->glCreateProgram (); conditional_print (opengl->shader_program == 0, "/f Failed to create OpenGL shader program: /1%i/-.\n", glGetError ()); 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->glGetProgramiv (opengl->shader_program, GL_LINK_STATUS, & status); conditional_print (status == GL_FALSE, "/f Failed to link OpenGL shader program: %i\n", status); opengl->glUseProgram (opengl->shader_program); /////////////////// status = glGetError (); if (status != GL_NO_ERROR) printf (">>> using %i\n", status); xy_attribute = (natural) opengl->glGetAttribLocation (opengl->shader_program, "vertex_xy"); opengl->glEnableVertexAttribArray (xy_attribute); opengl->glVertexAttribPointer (xy_attribute, 2, GL_FLOAT, GL_FALSE, 8 * sizeof (real), (procedure *) 0); uv_attribute = (natural) opengl->glGetAttribLocation (opengl->shader_program, "vertex_uv"); opengl->glEnableVertexAttribArray (uv_attribute); opengl->glVertexAttribPointer (uv_attribute, 2, GL_FLOAT, GL_FALSE, 8 * sizeof (real), (procedure *) (2 * sizeof (real))); rgba_attribute = (natural) opengl->glGetAttribLocation (opengl->shader_program, "vertex_rgba"); opengl->glEnableVertexAttribArray (rgba_attribute); opengl->glVertexAttribPointer (rgba_attribute, 4, GL_FLOAT, GL_FALSE, 8 * sizeof (real), (procedure *) (4 * sizeof (real))); if (glGetError () != GL_NO_ERROR) printf (">>> texture+\n"); 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); if (glGetError () != GL_NO_ERROR) printf (">>> texture-\n"); 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); } glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable (GL_CULL_FACE); glEnable (GL_BLEND); opengl->active = true; opengl->frame_begin = nano_time (); glClearColor (0.0f, 0.0f, 0.0f, 1.0f); glClear (GL_COLOR_BUFFER_BIT); if (glGetError () != GL_NO_ERROR) printf (">>> done\n"); print ("/s Configured OpenGL renderer.\n"); } static procedure opengl_render_base (opengl_structure * opengl, natural sprite, integer x, integer y, natural u, natural v, natural width, natural height, real scale_x, real scale_y, integer flip_x, integer flip_y, natural colour_upper_left, natural colour_upper_right, natural colour_lower_left, natural colour_lower_right) { if ((x > (integer) opengl->window_width) || (x < (integer) - ((real) width * scale_x))) return; if ((y > (integer) opengl->window_height) || (y < (integer) - ((real) height * scale_y))) return; fatal_failure (sprite >= opengl->sprite_count, "Not rendering, sprite out of range."); fatal_failure (opengl->vertex_count + 32 >= opengl->vertex_limit, "Not rendering, not enough vertex space."); fatal_failure (opengl->index_count + 6 >= opengl->index_limit, "Not rendering, not enough index space."); real screen_x = + ((real) x * opengl->pixel_width - 1.0f); real screen_y = - ((real) y * opengl->pixel_height - 1.0f); real screen_width = + ((real) width * opengl->pixel_width * scale_x); real screen_height = - ((real) height * opengl->pixel_height * scale_y); real unwrap_x = opengl->sprite_u [sprite] + (real) u / (real) opengl->spritesheet_size; real unwrap_y = opengl->sprite_v [sprite] + (real) v / (real) opengl->spritesheet_size; real unwrap_width = (real) width / (real) opengl->spritesheet_size; real unwrap_height = (real) height / (real) 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 * (real) (flip_y != 0); opengl->vertex_array [opengl->vertex_count + 3] = unwrap_y + unwrap_height * (real) (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 * (real) (flip_y == 0); opengl->vertex_array [opengl->vertex_count + 11] = unwrap_y + unwrap_height * (real) (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 * (real) (flip_y != 0); opengl->vertex_array [opengl->vertex_count + 19] = unwrap_y + unwrap_height * (real) (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 * (real) (flip_y == 0); opengl->vertex_array [opengl->vertex_count + 27] = unwrap_y + unwrap_height * (real) (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 procedure opengl_render_rectangle (opengl_structure * opengl, integer x, integer y, natural width, natural height, natural colour) { opengl_render_base (opengl, opengl->sprite_count - 1, x, y, 0, 0, 16, 16, (real) width / 16.0f, (real) height / 16.0f, 0, 0, colour, colour, colour, colour); } static procedure opengl_render_rectangle_vertical_gradient (opengl_structure * opengl, integer x, integer y, natural width, natural height, natural colour_up, natural colour_down) { opengl_render_base (opengl, opengl->sprite_count - 1, x, y, 0, 0, 16, 16, (real) width / 16.0f, (real) height / 16.0f, 0, 0, colour_up, colour_up, colour_down, colour_down); } static procedure opengl_render_rectangle_horizontal_gradient (opengl_structure * opengl, integer x, integer y, natural width, natural height, natural colour_left, natural colour_right) { opengl_render_base (opengl, opengl->sprite_count - 1, x, y, 0, 0, 16, 16, (real) width / 16.0f, (real) height / 16.0f, 0, 0, colour_left, colour_right, colour_left, colour_right); } static procedure opengl_render_sprite (opengl_structure * opengl, natural sprite, integer x, integer 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 procedure opengl_render_sprite_scale (opengl_structure * opengl, natural sprite, integer x, integer y, real scale_x, real scale_y) { opengl_render_base (opengl, sprite, x, y, 0, 0, opengl->sprite_width [sprite], opengl->sprite_height [sprite], scale_x, scale_y, 0, 0, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu); } static procedure opengl_render_sprite_crop (opengl_structure * opengl, natural sprite, integer x, integer y, natural u, natural v, natural width, natural height) { opengl_render_base (opengl, sprite, x, y, u, v, width, height, 1.0f, 1.0f, 0, 0, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu); } static procedure opengl_render_sprite_colour (opengl_structure * opengl, natural sprite, integer x, integer y, natural 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 procedure opengl_render_sprite_flip (opengl_structure * opengl, natural sprite, integer x, integer y, integer flip_x, integer 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 procedure opengl_render_sprite_orient (opengl_structure * opengl, natural sprite, integer x, integer y, natural u, natural v, natural width, natural height, integer flip_x, integer 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 procedure opengl_render_sprite_animation (opengl_structure * opengl, natural sprite, integer x, integer y, natural frames, natural state, natural states) { natural width = opengl->sprite_width [sprite] / states; natural height = opengl->sprite_height [sprite] / frames; natural u = width * (state % states); natural v = height * (opengl->animation_tick % frames); opengl_render_sprite_crop (opengl, sprite, x, y, u, v, width, height); } static procedure opengl_render_sprite_crop_colour (opengl_structure * opengl, natural sprite, natural colour, integer x, integer y, natural u, natural v, natural width, natural height) { opengl_render_base (opengl, sprite, x, y, u, v, width, height, 1.0f, 1.0f, 0, 0, colour, colour, colour, colour); } static procedure opengl_render_character_base (opengl_structure * opengl, character data, natural font, integer x, integer y, real scale, natural colour_upper_left, natural colour_upper_right, natural colour_lower_left, natural colour_lower_right) { if ((font >= opengl->font_count) && (font != ~ 0u)) return; if (font == ~ 0u) { font = opengl->font_count - 1; } if ((data < opengl->font_begin [font]) || (data > opengl->font_end [font])) return; natural index = opengl->font_index [font] [data - opengl->font_begin [font]]; natural width = opengl->sprite_width [index]; natural 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 procedure opengl_render_character (opengl_structure * opengl, character data, natural font, integer x, integer y, real scale, natural colour) { opengl_render_character_base (opengl, data, font, x, y, scale, colour, colour, colour, colour); } static procedure opengl_render_character_vertical_gradient (opengl_structure * opengl, character data, natural font, integer x, integer y, real scale, natural colour_up, natural colour_down) { opengl_render_character_base (opengl, data, font, x, y, scale, colour_up, colour_up, colour_down, colour_down); } static procedure opengl_render_character_horizontal_gradient (opengl_structure * opengl, character data, natural font, integer x, integer y, real scale, natural colour_left, natural colour_right) { opengl_render_character_base (opengl, data, font, x, y, scale, colour_left, colour_right, colour_left, colour_right); } static procedure opengl_render_string_base (opengl_structure * opengl, character * string, natural font, integer x, integer y, real scale, natural colour_upper_left, natural colour_upper_right, natural colour_lower_left, natural colour_lower_right) { integer offset = x; if (string == null) return; for (natural index = 0; string [index] != '\0'; ++index) { if (string [index] == '\t') { x += opengl->tab_width * opengl_character_width (opengl, ' ', font, scale); continue; } else if (string [index] == '\n') { x = offset; y += opengl_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_character_width (opengl, string [index], font, scale); } } } static procedure opengl_render_string (opengl_structure * opengl, character * string, natural font, integer x, integer y, real scale, natural colour) { opengl_render_string_base (opengl, string, font, x, y, scale, colour, colour, colour, colour); } static procedure opengl_render_string_vertical_gradient (opengl_structure * opengl, character * string, natural font, integer x, integer y, real scale, natural colour_up, natural colour_down) { opengl_render_string_base (opengl, string, font, x, y, scale, colour_up, colour_up, colour_down, colour_down); } static procedure opengl_render_string_horizontal_gradient (opengl_structure * opengl, character * string, natural font, integer x, integer y, real scale, natural colour_left, natural colour_right) { opengl_render_string_base (opengl, string, font, x, y, scale, colour_left, colour_right, colour_left, colour_right); } static procedure opengl_render_string_full_vertical_gradient (opengl_structure * opengl, character * string, natural font, integer x, integer y, real scale, natural colour_up, natural colour_down) { integer offset = x; natural back = 0; natural up = 0; natural down = 0; real interpolator = 1.0f / (real) string_full_height (string); if (string == null) return; for (natural index = 0; string [index] != '\0'; ++index) { if (string [index] == '\t') { x += opengl->tab_width * opengl_character_width (opengl, ' ', font, scale); continue; } else if (string [index] == '\n') { back += 1; x = offset; y += opengl_character_height (opengl, ' ', font, scale); continue; } else { up = colour_linear_interpolation (colour_up, colour_down, (real) (back + 0) * interpolator); down = colour_linear_interpolation (colour_up, colour_down, (real) (back + 1) * interpolator); opengl_render_character_vertical_gradient (opengl, string [index], font, x, y, scale, up, down); x += opengl_character_width (opengl, string [index], font, scale); } } } static procedure opengl_render_string_full_horizontal_gradient (opengl_structure * opengl, character * string, natural font, integer x, integer y, real scale, natural colour_left, natural colour_right) { integer offset = x; natural back = 0; natural left = 0; natural right = 0; real interpolator = 1.0f / (real) string_full_width (string, opengl->tab_width); if (string == null) return; for (natural index = 0; string [index] != '\0'; ++index) { if (string [index] == '\t') { x += opengl->tab_width * opengl_character_width (opengl, ' ', font, scale); continue; } else if (string [index] == '\n') { back = 0; x = offset; y += opengl_character_height (opengl, ' ', font, scale); continue; } else { back += 1; left = colour_linear_interpolation (colour_left, colour_right, (real) (back + 0) * interpolator); right = colour_linear_interpolation (colour_left, colour_right, (real) (back + 1) * interpolator); opengl_render_character_horizontal_gradient (opengl, string [index], font, x, y, scale, left, right); x += opengl_character_width (opengl, string [index], font, scale); } } } static procedure opengl_render_framerate (opengl_structure * opengl, natural font, integer x, integer y, real scale, natural colour) { opengl_render_string (opengl, number_to_string (opengl->framerate), font, x, y, scale, colour); } static procedure opengl_synchronize (opengl_structure * opengl, natural colour) { integer 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 }; integer new_window_width = 0; integer new_window_height = 0; opengl->cursor [cursor_left] = false; opengl->cursor [cursor_middle] = false; opengl->cursor [cursor_right] = false; glClearColor (normal_r (colour), normal_g (colour), normal_b (colour), normal_a (colour)); 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 != (natural) new_window_width) || (opengl->window_height != (natural) 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 = (natural) new_window_width; opengl->window_height = (natural) new_window_height; opengl->pixel_width = 2.0f / (real) new_window_width; opengl->pixel_height = 2.0f / (real) new_window_height; } opengl->cursor [cursor_left] = (boolean) (glfwGetMouseButton (opengl->window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS); opengl->cursor [cursor_middle] = (boolean) (glfwGetMouseButton (opengl->window, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS); opengl->cursor [cursor_right] = (boolean) (glfwGetMouseButton (opengl->window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS); if (opengl->freeze_cursor == false) { real_64 x = 0.0; real_64 y = 0.0; glfwGetCursorPos (opengl->window, & x, & y); opengl->cursor_x = (integer) x; opengl->cursor_y = (integer) y; //~if ((opengl->cursor_x < 0) || (opengl->cursor_x > (integer) opengl->window_width) || //~(opengl->cursor_y < 0) || (opengl->cursor_y > (integer) 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 (natural index = 0; index < signal_count; ++index) { opengl->signal [index] = (boolean) (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, (integer) 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 = (natural) (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 (); } #undef opengl_font_width #undef opengl_font_height