xolatilization/xpengl.h

1229 lines
58 KiB
C
Executable File

/// _
/// __ ___ __ ___ _ __ __ _| |
/// \ \/ / '_ \ / _ \ '_ \ / _` | |
/// > <| |_) | __/ | | | (_| | |
/// /_/\_\ .__/ \___|_| |_|\__, |_|
/// |_| |___/
///
/// 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 <GLFW/glfw3.h>
#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