xolatilization/xpengl.h
2025-04-14 19:49:49 +02:00

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