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

998 lines
45 KiB
C

/// _ _
/// __ _(_)___(_) ___ _ __
/// \ \/ / / __| |/ _ \| '_ \
/// > <| \__ \ | (_) | | | |
/// /_/\_\_|___/_|\___/|_| |_|
///
/// Copyright (c) 1997 - Ognjen 'xolatile' Milan Robovic
///
/// xolatile@chud.cyou - xision - General 3D GLFW, OpenGL and OpenAL wrapper library.
///
/// 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 vision_font_width (8)
#define vision_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;
PFNGLUNIFORM1FPROC glUniform1f;
PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
PFNGLDELETEBUFFERSPROC glDeleteBuffers;
PFNGLDELETESHADERPROC glDeleteShader;
PFNGLDELETEPROGRAMPROC glDeleteProgram;
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
PFNGLBUFFERDATAPROC glBufferData;
PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv;
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;
float projection_matrix [16];
float movement_matrix [16];
float rotation_matrix [16];
float aspect_ratio;
float field_of_view;
float far_plane;
float near_plane;
float camera_x;
float camera_y;
float sensitivity;
} vision_structure;
static uint vision_sprite_raw_import (vision_structure * vision, uint * data, uint width, uint height) {
fatal_failure (vision->active == true, "vision_sprite_raw_import: OpenGL renderer is already initialized.");
fatal_failure (data == null, "vision_sprite_raw_import: Data is null pointer.");
fatal_failure (width == 0, "vision_sprite_raw_import: Font image width is zero.");
fatal_failure (height == 0, "vision_sprite_raw_import: Font image height is zero.");
++vision->sprite_count;
vision->sprite_data = reallocate (vision->sprite_data, vision->sprite_count * sizeof (* vision->sprite_data));
vision->sprite_width = reallocate (vision->sprite_width, vision->sprite_count * sizeof (* vision->sprite_width));
vision->sprite_height = reallocate (vision->sprite_height, vision->sprite_count * sizeof (* vision->sprite_height));
vision->sprite_u = reallocate (vision->sprite_u, vision->sprite_count * sizeof (* vision->sprite_u));
vision->sprite_v = reallocate (vision->sprite_v, vision->sprite_count * sizeof (* vision->sprite_v));
vision->sprite_data [vision->sprite_count - 1] = data;
vision->sprite_width [vision->sprite_count - 1] = width;
vision->sprite_height [vision->sprite_count - 1] = height;
vision->sprite_u [vision->sprite_count - 1] = 0;
vision->sprite_v [vision->sprite_count - 1] = 0;
return (vision->sprite_count - 1);
}
static uint vision_font_raw_import (vision_structure * vision, uint * data, uint image_width, char begin, char end, uint empty) {
uint pointer = 0;
uint width = 0;
uint height = 0;
fatal_failure (vision->active == true, "vision_font_raw_import: OpenGL renderer is already initialized.");
fatal_failure (data == null, "vision_font_raw_import: Data is null pointer.");
fatal_failure (image_width == 0, "vision_font_raw_import: Font image width is zero.");
fatal_failure (begin >= end, "vision_font_raw_import: Font character range is inverted.");
++vision->font_count;
vision->font_index = reallocate (vision->font_index, vision->font_count * sizeof (* vision->font_index));
vision->font_width = reallocate (vision->font_width, vision->font_count * sizeof (* vision->font_width));
vision->font_height = reallocate (vision->font_height, vision->font_count * sizeof (* vision->font_height));
vision->font_begin = reallocate (vision->font_begin, vision->font_count * sizeof (* vision->font_begin));
vision->font_end = reallocate (vision->font_end, vision->font_count * sizeof (* vision->font_end));
vision->font_begin [vision->font_count - 1] = begin;
vision->font_end [vision->font_count - 1] = end;
vision->font_index [vision->font_count - 1] = allocate ((ulong) (end - begin + 1) * sizeof (* * vision->font_index));
vision->font_width [vision->font_count - 1] = allocate ((ulong) (end - begin + 1) * sizeof (* * vision->font_width));
vision->font_height [vision->font_count - 1] = allocate ((ulong) (end - begin + 1) * sizeof (* * vision->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];
}
}
vision->font_index [vision->font_count - 1] [index - begin] = vision_sprite_raw_import (vision, buffer, width, height);
vision->font_width [vision->font_count - 1] [index - begin] = width;
vision->font_height [vision->font_count - 1] [index - begin] = height;
pointer += width;
for (; data [pointer] == empty; ++pointer);
if (pointer % image_width == 2) {
pointer += height * image_width;
}
}
return (vision->font_count - 1);
}
static uint vision_sprite_import (vision_structure * vision, char * path) {
uint width = 0;
uint height = 0;
uint * data = null;
data = format_image_import (path, & width, & height);
return (vision_sprite_raw_import (vision, data, width, height));
}
static uint vision_font_import (vision_structure * vision, char * path, char begin, char end, uint colour) {
uint width = 0;
uint height = 0;
uint result = 0;
uint * data = null;
data = format_image_import (path, & width, & height);
result = vision_font_raw_import (vision, data, width, begin, end, colour);
data = deallocate (data);
return (result);
}
static uint vision_sprite_width (vision_structure * vision, uint sprite) {
return (vision->sprite_width [sprite]);
}
static uint vision_sprite_height (vision_structure * vision, uint sprite) {
return (vision->sprite_height [sprite]);
}
static uint vision_center_x (vision_structure * vision, uint size) {
return ((vision->window_width - size) / 2);
}
static uint vision_center_y (vision_structure * vision, uint size) {
return ((vision->window_height - size) / 2);
}
static bool vision_cursor_inside (vision_structure * vision, int x, int y, uint width, uint height) {
return ((vision->cursor_x > x) &&
(vision->cursor_y > y) &&
(vision->cursor_x < x + (int) width) &&
(vision->cursor_y < y + (int) height));
}
static bool vision_cursor_left_click (vision_structure * vision, int x, int y, uint width, uint height) {
if (vision->cursor [cursor_left] == true) {
vision->freeze_cursor = true;
return (vision_cursor_inside (vision, x, y, width, height) == true);
}
return (false);
}
static bool vision_cursor_right_click (vision_structure * vision, int x, int y, uint width, uint height) {
if (vision->cursor [cursor_right]) {
vision->freeze_cursor = true;
return (vision_cursor_inside (vision, x, y, width, height));
}
return (false);
}
static void vision_import_spritesheet (vision_structure * vision, char * data_file) {
int file = file_open (data_file, file_flag_read);
fatal_failure (vision->active == true, "vision_import_spritesheet: OpenGL renderer is already initialized.");
file_read (file, & vision->spritesheet_size, sizeof (vision->spritesheet_size));
file_read (file, & vision->sprite_count, sizeof (vision->sprite_count));
vision->sprite_width = allocate (vision->sprite_count * sizeof (* vision->sprite_width));
vision->sprite_height = allocate (vision->sprite_count * sizeof (* vision->sprite_height));
vision->sprite_u = allocate (vision->sprite_count * sizeof (* vision->sprite_u));
vision->sprite_v = allocate (vision->sprite_count * sizeof (* vision->sprite_v));
file_read (file, vision->sprite_width, vision->sprite_count * sizeof (* vision->sprite_width));
file_read (file, vision->sprite_height, vision->sprite_count * sizeof (* vision->sprite_height));
file_read (file, vision->sprite_u, vision->sprite_count * sizeof (* vision->sprite_u));
file_read (file, vision->sprite_v, vision->sprite_count * sizeof (* vision->sprite_v));
file_read (file, & vision->font_count, sizeof (vision->font_count));
vision->font_index = allocate (vision->font_count * sizeof (* vision->font_index));
vision->font_width = allocate (vision->font_count * sizeof (* vision->font_width));
vision->font_height = allocate (vision->font_count * sizeof (* vision->font_height));
vision->font_begin = allocate (vision->font_count * sizeof (* vision->font_begin));
vision->font_end = allocate (vision->font_count * sizeof (* vision->font_end));
file_read (file, vision->font_begin, vision->font_count * sizeof (* vision->font_begin));
file_read (file, vision->font_end, vision->font_count * sizeof (* vision->font_end));
for (uint index = 0; index < vision->font_count; ++index) {
uint range = (uint) (vision->font_end [index] - vision->font_begin [index]) + 1;
vision->font_index [index] = allocate (range * sizeof (* * vision->font_index));
vision->font_width [index] = allocate (range * sizeof (* * vision->font_width));
vision->font_height [index] = allocate (range * sizeof (* * vision->font_height));
for (uint subindex = 0; subindex < range; ++subindex) {
file_read (file, & vision->font_index [index] [subindex], sizeof (* * vision->font_index));
file_read (file, & vision->font_width [index] [subindex], sizeof (* * vision->font_width));
file_read (file, & vision->font_height [index] [subindex], sizeof (* * vision->font_height));
}
}
file = file_close (file);
vision->sprite_count = 0;
vision->font_count = 0;
}
static void vision_export_spritesheet (vision_structure * vision, char * data_file) {
int file = file_open (data_file, file_flag_write | file_flag_create | file_flag_truncate);
fatal_failure (vision->spritesheet_data == null, "vision_export_spritesheet: OpenGL renderer can't access spritesheet data.");
file_write (file, & vision->spritesheet_size, sizeof (vision->spritesheet_size));
file_write (file, & vision->sprite_count, sizeof (vision->sprite_count));
file_write (file, vision->sprite_width, vision->sprite_count * sizeof (* vision->sprite_width));
file_write (file, vision->sprite_height, vision->sprite_count * sizeof (* vision->sprite_height));
file_write (file, vision->sprite_u, vision->sprite_count * sizeof (* vision->sprite_u));
file_write (file, vision->sprite_v, vision->sprite_count * sizeof (* vision->sprite_v));
file_write (file, & vision->font_count, sizeof (vision->font_count));
file_write (file, vision->font_begin, vision->font_count * sizeof (* vision->font_begin));
file_write (file, vision->font_end, vision->font_count * sizeof (* vision->font_end));
for (uint index = 0; index < vision->font_count; ++index) {
for (uint subindex = 0; subindex < (uint) (vision->font_end [index] - vision->font_begin [index]) + 1; ++subindex) {
file_write (file, & vision->font_index [index] [subindex], sizeof (* * vision->font_index));
file_write (file, & vision->font_width [index] [subindex], sizeof (* * vision->font_width));
file_write (file, & vision->font_height [index] [subindex], sizeof (* * vision->font_height));
}
}
file = file_close (file);
print ("/c Exported internal binary data of OpenGL spritesheet.");
}
static vision_structure * vision_initialize (uint gameplay_framerate, uint animation_framerate, bool use_precomputed_spritesheet,
uint vertex_limit, uint index_limit, uint spritesheet_side) {
vision_structure * vision = allocate (sizeof (* vision));
vision->using_precomputed_spritesheet = use_precomputed_spritesheet;
vision->spritesheet_size = spritesheet_side;
vision->gameplay_framerate = gameplay_framerate;
vision->animation_framerate = animation_framerate;
vision->vertex_limit = vertex_limit;
vision->index_limit = index_limit;
vision->tab_width = 4;
vision->default_font = ~0u;
vision->field_of_view = 2.0f;
vision->far_plane = 100.0f;
vision->near_plane = 0.1f;
vision->sensitivity = 0.1f;
if (use_precomputed_spritesheet == true) {
print ("[/0Comment/-] Importing spritesheet image and information...\n");
vision_import_spritesheet (vision, "binary/spritesheet.bin");
}
print ("[/2Success/-] Initialized OpenGL renderer.\n");
return (vision);
}
static vision_structure * vision_deinitialize (vision_structure * vision) {
vision->active = false;
for (uint index = 0; index < vision->font_count; ++index) {
vision->font_index [index] = deallocate (vision->font_index [index]);
vision->font_width [index] = deallocate (vision->font_width [index]);
vision->font_height [index] = deallocate (vision->font_height [index]);
}
vision->font_index = deallocate (vision->font_index);
vision->font_width = deallocate (vision->font_width);
vision->font_height = deallocate (vision->font_height);
vision->font_begin = deallocate (vision->font_begin);
vision->font_end = deallocate (vision->font_end);
vision->sprite_width = deallocate (vision->sprite_width);
vision->sprite_height = deallocate (vision->sprite_height);
vision->sprite_u = deallocate (vision->sprite_u);
vision->sprite_v = deallocate (vision->sprite_v);
if (vision->using_precomputed_spritesheet == false) {
vision->spritesheet_data = deallocate (vision->spritesheet_data);
}
vision->vertex_array = deallocate (vision->vertex_array);
vision->index_array = deallocate (vision->index_array);
glDeleteTextures (1, & vision->spritesheet);
vision->glDeleteProgram (vision->shader_program);
vision->glDeleteShader (vision->fragment_shader);
vision->glDeleteShader (vision->vertex_shader);
vision->glDeleteBuffers (1, & vision->index_buffer);
vision->glDeleteBuffers (1, & vision->vertex_buffer);
vision->glDeleteVertexArrays (1, & vision->vertex_object);
glfwDestroyWindow (vision->window);
glfwTerminate ();
print ("[/2Success/-] Deinitialized OpenGL renderer.\n");
return (deallocate (vision));
}
static void vision_configure (vision_structure * vision, 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 vec3 vertex_xyz;\n"
"in vec2 vertex_uv;\n"
"in vec4 vertex_rgba;\n"
"out vec2 fragment_uv;\n"
"out vec4 fragment_rgba;\n"
"uniform mat4 projection_matrix;\n"
"uniform mat4 movement_matrix;\n"
"uniform mat4 rotation_matrix;\n"
"void main () {\n"
" gl_Position = movement_matrix * rotation_matrix * projection_matrix * vec4 (vertex_xyz, 1.0);\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 xyz_attribute = 0;
uint uv_attribute = 0;
uint rgba_attribute = 0;
uint u = 0;
uint v = 0;
if (vision->using_precomputed_spritesheet == true) {
for (uint index = 0; index < 95; ++index) {
vision->font_index [vision->font_count] [index] = ++vision->sprite_count - 1;
}
++vision->sprite_count;
++vision->font_count;
goto ignore_import;
}
dumb_buffer = allocate (256 * sizeof (* dumb_buffer));
for (uint index = 0; index < 256; ++index) {
dumb_buffer [index] = 0xffffffff;
}
++vision->font_count;
uint current = vision->font_count - 1;
vision->font_index = reallocate (vision->font_index, vision->font_count * sizeof (* vision->font_index));
vision->font_width = reallocate (vision->font_width, vision->font_count * sizeof (* vision->font_width));
vision->font_height = reallocate (vision->font_height, vision->font_count * sizeof (* vision->font_height));
vision->font_begin = reallocate (vision->font_begin, vision->font_count * sizeof (* vision->font_begin));
vision->font_end = reallocate (vision->font_end, vision->font_count * sizeof (* vision->font_end));
vision->font_begin [vision->font_count - 1] = ' ';
vision->font_end [vision->font_count - 1] = '~';
vision->font_index [vision->font_count - 1] = allocate (95 * sizeof (* * vision->font_index));
vision->font_width [vision->font_count - 1] = allocate (95 * sizeof (* * vision->font_width));
vision->font_height [vision->font_count - 1] = allocate (95 * sizeof (* * vision->font_height));
for (uint index = 0; index < 95; ++index) {
uint * buffer = allocate (vision_font_width * vision_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) * vision_font_width - ((bit - 1) & 7) + 7;
uint source = (font_bitmap [2 * index + value] >> (bit - 1)) & 1;
buffer [destination] = (source) ? 0xffffffff : 0x00000000;
}
}
vision->font_index [current] [index] = vision_sprite_raw_import (vision, buffer, vision_font_width, vision_font_height);
vision->font_width [current] [index] = vision_font_width;
vision->font_height [current] [index] = vision_font_height;
}
vision_sprite_raw_import (vision, dumb_buffer, 16, 16);
vision->spritesheet_data = allocate (vision->spritesheet_size * vision->spritesheet_size * sizeof (* vision->spritesheet_data));
order = allocate (vision->sprite_count * sizeof (* order));
for (uint index = 0; index < vision->sprite_count; ++index) {
order [index] = index;
}
for (uint index = 0; index < vision->sprite_count; ++index) {
for (uint subindex = 0; subindex < vision->sprite_count; ++subindex) {
if (vision->sprite_height [order [index]] < vision->sprite_height [order [subindex]]) {
uint temporary = order [index];
order [index] = order [subindex];
order [subindex] = temporary;
}
}
}
for (uint index = 0; index < vision->sprite_count; ++index) {
if (u + vision->sprite_width [order [index]] >= vision->spritesheet_size) {
u *= 0;
v += vision->sprite_height [order [index]];
}
vision->sprite_u [order [index]] = (float) u / (float) vision->spritesheet_size;
vision->sprite_v [order [index]] = (float) v / (float) vision->spritesheet_size;
for (uint y = 0; y < vision->sprite_height [order [index]]; ++y) {
for (uint x = 0; x < vision->sprite_width [order [index]]; ++x) {
uint destination = (v + y) * vision->spritesheet_size + (u + x);
uint source = y * vision->sprite_width [order [index]] + x;
vision->spritesheet_data [destination] = vision->sprite_data [order [index]] [source];
}
}
u += vision->sprite_width [order [index]];
vision->sprite_data [order [index]] = deallocate (vision->sprite_data [order [index]]);
}
vision->sprite_data = deallocate (vision->sprite_data);
order = deallocate (order);
ignore_import:
vision->window_width = window_width;
vision->window_height = window_height;
vision->aspect_ratio = (float) window_height / (float) window_width;
vision->pixel_width = 2.0f / (float) window_width;
vision->pixel_height = 2.0f / (float) 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);
vision->window = glfwCreateWindow ((int) window_width, (int) window_height, window_title, null, null);
fatal_failure (vision->window == null, "Failed to create GLFW window.\n");
glfwSetWindowSizeLimits (vision->window, 320, 240, 1920, 1080);
//~glfwSetInputMode (vision->window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
//~glfwSetInputMode (vision->window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
glfwSetCursorPos (vision->window, (double) vision->window_width / 2.0, (double) vision->window_height / 2.0);
glfwMakeContextCurrent (vision->window);
vision->glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC) glfwGetProcAddress ("glGenVertexArrays");
vision->glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC) glfwGetProcAddress ("glBindVertexArray");
vision->glGenBuffers = (PFNGLGENBUFFERSPROC) glfwGetProcAddress ("glGenBuffers");
vision->glBindBuffer = (PFNGLBINDBUFFERPROC) glfwGetProcAddress ("glBindBuffer");
vision->glCreateShader = (PFNGLCREATESHADERPROC) glfwGetProcAddress ("glCreateShader");
vision->glShaderSource = (PFNGLSHADERSOURCEPROC) glfwGetProcAddress ("glShaderSource");
vision->glCompileShader = (PFNGLCOMPILESHADERPROC) glfwGetProcAddress ("glCompileShader");
vision->glCreateProgram = (PFNGLCREATEPROGRAMPROC) glfwGetProcAddress ("glCreateProgram");
vision->glAttachShader = (PFNGLATTACHSHADERPROC) glfwGetProcAddress ("glAttachShader");
vision->glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC) glfwGetProcAddress ("glBindFragDataLocation");
vision->glLinkProgram = (PFNGLLINKPROGRAMPROC) glfwGetProcAddress ("glLinkProgram");
vision->glUseProgram = (PFNGLUSEPROGRAMPROC) glfwGetProcAddress ("glUseProgram");
vision->glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) glfwGetProcAddress ("glGetAttribLocation");
vision->glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC) glfwGetProcAddress ("glEnableVertexAttribArray");
vision->glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC) glfwGetProcAddress ("glVertexAttribPointer");
vision->glUniform1i = (PFNGLUNIFORM1IPROC) glfwGetProcAddress ("glUniform1i");
vision->glUniform1f = (PFNGLUNIFORM1FPROC) glfwGetProcAddress ("glUniform1f");
vision->glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC) glfwGetProcAddress ("glDeleteVertexArrays");
vision->glDeleteBuffers = (PFNGLDELETEBUFFERSPROC) glfwGetProcAddress ("glDeleteBuffers");
vision->glDeleteShader = (PFNGLDELETESHADERPROC) glfwGetProcAddress ("glDeleteShader");
vision->glDeleteProgram = (PFNGLDELETEPROGRAMPROC) glfwGetProcAddress ("glDeleteProgram");
vision->glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) glfwGetProcAddress ("glGetUniformLocation");
vision->glBufferData = (PFNGLBUFFERDATAPROC) glfwGetProcAddress ("glBufferData");
vision->glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) glfwGetProcAddress ("glUniformMatrix4fv");
glViewport (0, 0, (int) window_width, (int) window_height);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthFunc (GL_LESS);
glEnable (GL_DEPTH_TEST);
glEnable (GL_CULL_FACE);
glEnable (GL_BLEND);
vision->glGenVertexArrays (1, & vision->vertex_object);
vision->glBindVertexArray (vision->vertex_object);
vision->glGenBuffers (1, & vision->vertex_buffer);
vision->glBindBuffer (GL_ARRAY_BUFFER, vision->vertex_buffer);
vision->glGenBuffers (1, & vision->index_buffer);
vision->glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, vision->index_buffer);
vision->vertex_shader = vision->glCreateShader (GL_VERTEX_SHADER);
vision->glShaderSource (vision->vertex_shader, 1, & vertex_shader, null);
vision->glCompileShader (vision->vertex_shader);
vision->fragment_shader = vision->glCreateShader (GL_FRAGMENT_SHADER);
vision->glShaderSource (vision->fragment_shader, 1, & fragment_shader, null);
vision->glCompileShader (vision->fragment_shader);
vision->shader_program = vision->glCreateProgram ();
vision->glAttachShader (vision->shader_program, vision->vertex_shader);
vision->glAttachShader (vision->shader_program, vision->fragment_shader);
vision->glBindFragDataLocation (vision->shader_program, 0, "data");
vision->glLinkProgram (vision->shader_program);
vision->glUseProgram (vision->shader_program);
xyz_attribute = (uint) vision->glGetAttribLocation (vision->shader_program, "vertex_xyz");
vision->glEnableVertexAttribArray (xyz_attribute);
vision->glVertexAttribPointer (xyz_attribute, 3, GL_FLOAT, GL_FALSE, 9 * sizeof (float), (void *) 0);
uv_attribute = (uint) vision->glGetAttribLocation (vision->shader_program, "vertex_uv");
vision->glEnableVertexAttribArray (uv_attribute);
vision->glVertexAttribPointer (uv_attribute, 2, GL_FLOAT, GL_FALSE, 9 * sizeof (float), (void *) (3 * sizeof (float)));
rgba_attribute = (uint) vision->glGetAttribLocation (vision->shader_program, "vertex_rgba");
vision->glEnableVertexAttribArray (rgba_attribute);
vision->glVertexAttribPointer (rgba_attribute, 4, GL_FLOAT, GL_FALSE, 9 * sizeof (float), (void *) (5 * sizeof (float)));
vision->vertex_array = allocate (vision->vertex_limit * sizeof (vision->vertex_array));
vision->index_array = allocate (vision->index_limit * sizeof (vision->index_array));
for (uint index = 0; index < 16; ++index) {
vision->projection_matrix [index] = 0.0f;
vision->movement_matrix [index] = 0.0f;
vision->rotation_matrix [index] = 0.0f;
}
vision->movement_matrix [0] = vision->movement_matrix [5] = vision->movement_matrix [10] = vision->movement_matrix [15] = 1.0f;
vision->rotation_matrix [0] = vision->rotation_matrix [5] = vision->rotation_matrix [10] = vision->rotation_matrix [15] = 1.0f;
vision->projection_matrix [ 0] = vision->aspect_ratio / tangent (vision->field_of_view / 2.0f);
vision->projection_matrix [ 5] = 1.0f / tangent (vision->field_of_view / 2.0f);
vision->projection_matrix [10] = vision->far_plane / (vision->far_plane - vision->near_plane);
vision->projection_matrix [11] = 1.0f;
vision->projection_matrix [14] = (- vision->far_plane * vision->near_plane) / (vision->far_plane - vision->near_plane);
vision->glUniformMatrix4fv (vision->glGetUniformLocation (vision->shader_program, "projection_matrix"), 1, GL_FALSE,
vision->projection_matrix);
vision->glUniformMatrix4fv (vision->glGetUniformLocation (vision->shader_program, "movement_matrix"), 1, GL_FALSE,
vision->movement_matrix);
vision->glUniformMatrix4fv (vision->glGetUniformLocation (vision->shader_program, "rotation_matrix"), 1, GL_FALSE,
vision->rotation_matrix);
glGenTextures (1, & vision->spritesheet);
glBindTexture (GL_TEXTURE_2D, vision->spritesheet);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, vision->spritesheet_size, vision->spritesheet_size, 0, GL_RGBA, GL_UNSIGNED_BYTE,
vision->spritesheet_data);
vision->glUniform1i (vision->glGetUniformLocation (vision->shader_program, "texture_p"), 0);
//~vision->glUniform1f (vision->glGetUniformLocation (vision->shader_program, "aspect_ratio"), vision->aspect_ratio);
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 (vision->using_precomputed_spritesheet == true) {
vision->spritesheet_data = deallocate (vision->spritesheet_data);
}
vision->active = true;
vision->frame_begin = nano_time ();
glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
print ("[/2Success/-] Configured OpenGL renderer.\n");
}
static void vision_synchronize (vision_structure * vision, 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
};
int new_window_width = 0;
int new_window_height = 0;
glClearColor (normal_r (colour), normal_g (colour), normal_b (colour), normal_a (colour));
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glfwPollEvents ();
glfwSetWindowShouldClose (vision->window, vision->active == false);
glfwGetWindowSize (vision->window, & new_window_width, & new_window_height);
if ((vision->window_width != (uint) new_window_width) || (vision->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);
vision->window_width = (uint) new_window_width;
vision->window_height = (uint) new_window_height;
vision->pixel_width = 2.0f / (float) new_window_width;
vision->pixel_height = 2.0f / (float) new_window_height;
}
vision->cursor [cursor_left] = (bool) (glfwGetMouseButton (vision->window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);
vision->cursor [cursor_middle] = (bool) (glfwGetMouseButton (vision->window, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);
vision->cursor [cursor_right] = (bool) (glfwGetMouseButton (vision->window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);
glfwSetCursorPos (vision->window, (double) vision->window_width / 2.0, (double) vision->window_height / 2.0);
if (vision->freeze_cursor == false) {
double x = 0.0;
double y = 0.0;
glfwGetCursorPos (vision->window, & x, & y);
vision->cursor_x = (int) x;
vision->cursor_y = (int) y;
//~float offset_x = vision->camera_x - x;
//~for (uint index = 0; index < 16; ++index) {
//~vision->rotation_matrix [index] = 0.0f;
//~}
//~offset_x *= vision->sensitivity;
//~vision->rotation_matrix [0] = vision->rotation_matrix [5] = vision->rotation_matrix [10] = vision->rotation_matrix [15] = 1.0f;
//~vision->rotation_matrix [5] = vision->rotation_matrix [10] = cosine (offset_x);
//~vision->rotation_matrix [6] = vision->rotation_matrix [ 9] = sine (offset_x);
//~vision->rotation_matrix [6] *= - 1.0f;
//~vision->glUniformMatrix4fv (vision->glGetUniformLocation (vision->shader_program, "rotation_matrix"), 1, GL_FALSE,
//~vision->rotation_matrix);
//~vision->camera_x = x;
} else {
if ((vision->cursor [cursor_left] == false)
&& (vision->cursor [cursor_middle] == false)
&& (vision->cursor [cursor_right] == false)) {
vision->freeze_cursor = false;
}
}
if (vision->freeze_signal == false) {
for (uint index = 0; index < signal_count; ++index) {
vision->signal [index] = (bool) (glfwGetKey (vision->window, signal_code [index]) == GLFW_PRESS);
}
}
vision->glBufferData (GL_ARRAY_BUFFER, vision->vertex_count * 4, vision->vertex_array, GL_DYNAMIC_DRAW);
vision->glBufferData (GL_ELEMENT_ARRAY_BUFFER, vision->index_count * 4, vision->index_array, GL_DYNAMIC_DRAW);
vision->glBindBuffer (GL_ARRAY_BUFFER, vision->vertex_buffer);
glDrawElements (GL_TRIANGLES, (int) vision->index_count * 4, GL_UNSIGNED_INT, null);
glfwSwapBuffers (vision->window);
vision->vertex_count = 0;
vision->index_count = 0;
vision->frame_end = nano_time ();
vision->frame_time = vision->frame_end - vision->frame_begin;
if (vision->frame_time < 1000000000ul / vision->gameplay_framerate) {
nano_wait (1000000000ul / vision->gameplay_framerate - vision->frame_time);
}
if (vision->global_tick % vision->gameplay_framerate == 0) {
vision->framerate = (uint) (1000000000ul / vision->frame_time);
}
++vision->global_tick;
vision->global_tick = vision->global_tick % (vision->gameplay_framerate * vision->animation_framerate);
vision->gameplay_tick = vision->global_tick % (vision->gameplay_framerate);
vision->animation_tick = vision->global_tick / (vision->gameplay_framerate / vision->animation_framerate);
vision->frame_begin = nano_time ();
}
static void vision_render_base (vision_structure * vision, uint vertex_count, float * vertex_array, uint index_count,
uint * index_array, uint sprite, uint colour) {
if (sprite >= vision->sprite_count) return;
if (vision->vertex_count + vertex_count >= vision->vertex_limit) return;
if (vision->index_count + index_count >= vision->index_limit) return;
float unwrap_x = (float) vision->sprite_u [sprite] / (float) vision->spritesheet_size;
float unwrap_y = (float) vision->sprite_v [sprite] / (float) vision->spritesheet_size;
float unwrap_width = (float) vision->sprite_width [sprite] / (float) vision->spritesheet_size;
float unwrap_height = (float) vision->sprite_height [sprite] / (float) vision->spritesheet_size;
//~for (uint vertex = 0; vertex < vertex_count; ++vertex) {
//~uint destination = 9 * vertex + vision->vertex_count;
//~uint source = 5 * vertex;
//~vision->vertex_array [destination + 0] = vertex_array [source + 0];
//~vision->vertex_array [destination + 1] = vertex_array [source + 1];
//~vision->vertex_array [destination + 2] = vertex_array [source + 2];
//~vision->vertex_array [destination + 3] = vertex_array [source + 3] * unwrap_width + unwrap_x;
//~vision->vertex_array [destination + 4] = vertex_array [source + 4] * unwrap_height + unwrap_y;
//~vision->vertex_array [destination + 5] = normal_r (colour);
//~vision->vertex_array [destination + 6] = normal_g (colour);
//~vision->vertex_array [destination + 7] = normal_b (colour);
//~vision->vertex_array [destination + 8] = normal_a (colour);
//~}
for (uint vertex = 0; vertex < vertex_count; ++vertex) {
vision->vertex_array [vision->vertex_count + vertex] = vertex_array [vertex];
}
//~vision->vertex_array [destination + 3] = vertex_array [source + 3] * unwrap_width + unwrap_x;
//~vision->vertex_array [destination + 4] = vertex_array [source + 4] * unwrap_height + unwrap_y;
for (uint index = 0; index < index_count; ++index) {
vision->index_array [vision->index_count + index] = index_array [index];
}
//~vision->vertex_count += 36 * vertex_count;
//~vision->index_count += 3 * index_count;
vision->vertex_count += vertex_count;
vision->index_count += index_count;
}
//~static void vision_render_triangle (vision_structure * vision, float * vertex_array, uint colour) {
//~if (vision->vertex_count + 3 * 36 >= vision->vertex_limit) return;
//~if (vision->index_count + 3 >= vision->index_limit) return;
//~for (uint vertex = 0; vertex < 3; ++vertex) {
//~uint destination = 9 * vertex + vision->vertex_count;
//~uint source = 5 * vertex;
//~vision->vertex_array [destination + 0] = vertex_array [source + 0];
//~vision->vertex_array [destination + 1] = vertex_array [source + 1];
//~vision->vertex_array [destination + 2] = vertex_array [source + 2];
//~vision->vertex_array [destination + 3] = (binary_sign (vertex >> 0) + 1.0f) / 2.0f;
//~vision->vertex_array [destination + 4] = (binary_sign (vertex >> 1) + 1.0f) / 2.0f;
//~vision->vertex_array [destination + 5] = normal_r (colour);
//~vision->vertex_array [destination + 6] = normal_g (colour);
//~vision->vertex_array [destination + 7] = normal_b (colour);
//~vision->vertex_array [destination + 8] = normal_a (colour);
//~}
//~for (uint index = 0; index < 3; ++index) {
//~vision->index_array [vision->index_count + index] = vision->vertex_array [vision->vertex_count / 9 + index];
//~}
//~vision->vertex_count += 108;
//~vision->index_count += 3;
//~}
static void vision_change_field_of_view (vision_structure * vision, float change) {
vision->field_of_view += change;
vision->projection_matrix [ 0] = vision->aspect_ratio / tangent (vision->field_of_view / 2.0f);
vision->projection_matrix [ 5] = 1.0f / tangent (vision->field_of_view / 2.0f);
vision->glUniformMatrix4fv (vision->glGetUniformLocation (vision->shader_program, "projection_matrix"), 1, GL_FALSE,
vision->projection_matrix);
}
static void vision_change_translation (vision_structure * vision, float x, float y, float z) {
vision->movement_matrix [ 3] += x;
vision->movement_matrix [ 7] += y;
vision->movement_matrix [11] += z;
vision->glUniformMatrix4fv (vision->glGetUniformLocation (vision->shader_program, "movement_matrix"), 1, GL_FALSE,
vision->movement_matrix);
}
static void vision_change_rotation (vision_structure * vision, float vertical, float horizontal) {
for (uint index = 0; index < 16; ++index) {
vision->rotation_matrix [index] = 0.0f;
}
vision->rotation_matrix [0] = vision->rotation_matrix [5] = vision->rotation_matrix [10] = vision->rotation_matrix [15] = 1.0f;
vision->rotation_matrix [5] = vision->rotation_matrix [10] = cosine (vertical);
vision->rotation_matrix [6] = vision->rotation_matrix [ 9] = sine (vertical);
vision->rotation_matrix [6] *= - 1.0f;
vision->glUniformMatrix4fv (vision->glGetUniformLocation (vision->shader_program, "rotation_matrix"), 1, GL_FALSE,
vision->rotation_matrix);
}
#undef vision_font_width
#undef vision_font_height