/// _ _ /// __ _(_)___(_) ___ _ __ /// \ \/ / / __| |/ _ \| '_ \ /// > <| \__ \ | (_) | | | | /// /_/\_\_|___/_|\___/|_| |_| /// /// 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 #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; boolean signal [signal_count]; boolean cursor [cursor_count]; integer cursor_x; integer cursor_y; boolean using_precomputed_spritesheet; caliber spritesheet_size; caliber vertex_limit; caliber index_limit; natural gameplay_framerate; natural animation_framerate; natural tab_width; natural default_font; boolean active; natural window_width; natural window_height; real pixel_width; real pixel_height; natural framerate; natural_64 frame_time; natural_64 frame_begin; natural_64 frame_end; natural global_tick; natural gameplay_tick; natural animation_tick; boolean freeze_cursor; boolean freeze_signal; natural vertex_object; natural vertex_buffer; natural index_buffer; natural vertex_shader; natural fragment_shader; natural shader_program; natural spritesheet; natural vertex_count; natural index_count; real * vertex_array; natural * index_array; natural sprite_count; natural font_count; natural * spritesheet_data; natural * * sprite_data; natural * sprite_width; natural * sprite_height; real * sprite_u; real * sprite_v; natural * * font_index; natural * * font_width; natural * * font_height; character * font_begin; character * font_end; real projection_matrix [16]; real movement_matrix [16]; real rotation_matrix [16]; real aspect_ratio; real field_of_view; real far_plane; real near_plane; real camera_x; real camera_y; real sensitivity; } vision_structure; static natural vision_sprite_raw_import (vision_structure * vision, natural * data, natural width, natural 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 natural vision_font_raw_import (vision_structure * vision, natural * data, natural image_width, character begin, character end, natural empty) { natural pointer = 0; natural width = 0; natural 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 ((caliber) (end - begin + 1) * sizeof (* * vision->font_index)); vision->font_width [vision->font_count - 1] = allocate ((caliber) (end - begin + 1) * sizeof (* * vision->font_width)); vision->font_height [vision->font_count - 1] = allocate ((caliber) (end - begin + 1) * sizeof (* * vision->font_height)); for (character 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); natural * buffer = allocate (width * height * sizeof (* buffer)); for (natural y = 0; y < height; ++y) { for (natural x = 0; x < width; ++x) { buffer [y * width + x] = data [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 natural vision_sprite_import (vision_structure * vision, character * path) { natural width = 0; natural height = 0; natural * data = null; data = format_image_import (path, & width, & height); return (vision_sprite_raw_import (vision, data, width, height)); } static natural vision_font_import (vision_structure * vision, character * path, character begin, character end, natural colour) { natural width = 0; natural height = 0; natural result = 0; natural * 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 natural vision_sprite_width (vision_structure * vision, natural sprite) { return (vision->sprite_width [sprite]); } static natural vision_sprite_height (vision_structure * vision, natural sprite) { return (vision->sprite_height [sprite]); } static natural vision_center_x (vision_structure * vision, natural size) { return ((vision->window_width - size) / 2); } static natural vision_center_y (vision_structure * vision, natural size) { return ((vision->window_height - size) / 2); } static boolean vision_cursor_inside (vision_structure * vision, integer x, integer y, natural width, natural height) { return ((vision->cursor_x > x) && (vision->cursor_y > y) && (vision->cursor_x < x + (integer) width) && (vision->cursor_y < y + (integer) height)); } static boolean vision_cursor_left_click (vision_structure * vision, integer x, integer y, natural width, natural height) { if (vision->cursor [cursor_left] == true) { vision->freeze_cursor = true; return (vision_cursor_inside (vision, x, y, width, height) == true); } return (false); } static boolean vision_cursor_right_click (vision_structure * vision, integer x, integer y, natural width, natural height) { if (vision->cursor [cursor_right]) { vision->freeze_cursor = true; return (vision_cursor_inside (vision, x, y, width, height)); } return (false); } static procedure vision_import_spritesheet (vision_structure * vision, character * data_file) { integer 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 (natural index = 0; index < vision->font_count; ++index) { natural range = (natural) (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 (natural 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 procedure vision_export_spritesheet (vision_structure * vision, character * data_file) { integer 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 (natural index = 0; index < vision->font_count; ++index) { for (natural subindex = 0; subindex < (natural) (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 (natural gameplay_framerate, natural animation_framerate, boolean use_precomputed_spritesheet, natural vertex_limit, natural index_limit, natural 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 ("/s Initialized OpenGL renderer.\n"); return (vision); } static vision_structure * vision_deinitialize (vision_structure * vision) { vision->active = false; for (natural 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 ("/s Deinitialized OpenGL renderer.\n"); return (deallocate (vision)); } static procedure vision_configure (vision_structure * vision, natural window_width, natural window_height, character * window_title) { natural_64 font_bitmap [190] = { 0x0000000000000000, 0x0000000000000000, 0x0000101010101010, 0x1000101000000000, 0x0024242400000000, 0x0000000000000000, 0x00002424247e2424, 0x7e24242400000000, 0x0010107c9290907c, 0x1212927c10100000, 0x0000649468081010, 0x202c524c00000000, 0x000018242418304a, 0x4444443a00000000, 0x0010101000000000, 0x0000000000000000, 0x0000081020202020, 0x2020100800000000, 0x0000201008080808, 0x0808102000000000, 0x000000000024187e, 0x1824000000000000, 0x000000000010107c, 0x1010000000000000, 0x0000000000000000, 0x0000101020000000, 0x000000000000007e, 0x0000000000000000, 0x0000000000000000, 0x0000101000000000, 0x0000040408081010, 0x2020404000000000, 0x00003c4242464a52, 0x6242423c00000000, 0x0000081828080808, 0x0808083e00000000, 0x00003c4242020408, 0x1020407e00000000, 0x00003c4242021c02, 0x0242423c00000000, 0x000002060a122242, 0x7e02020200000000, 0x00007e4040407c02, 0x0202423c00000000, 0x00001c2040407c42, 0x4242423c00000000, 0x00007e0202040408, 0x0810101000000000, 0x00003c4242423c42, 0x4242423c00000000, 0x00003c424242423e, 0x0202043800000000, 0x0000000000101000, 0x0000101000000000, 0x0000000000101000, 0x0000101020000000, 0x0000000408102040, 0x2010080400000000, 0x00000000007e0000, 0x7e00000000000000, 0x0000004020100804, 0x0810204000000000, 0x00003c4242420408, 0x0800080800000000, 0x00007c829ea2a2a2, 0xa69a807e00000000, 0x00003c424242427e, 0x4242424200000000, 0x00007c4242427c42, 0x4242427c00000000, 0x00003c4242404040, 0x4042423c00000000, 0x0000784442424242, 0x4242447800000000, 0x00007e4040407840, 0x4040407e00000000, 0x00007e4040407840, 0x4040404000000000, 0x00003c424240404e, 0x4242423c00000000, 0x0000424242427e42, 0x4242424200000000, 0x0000381010101010, 0x1010103800000000, 0x00000e0404040404, 0x0444443800000000, 0x0000424448506060, 0x5048444200000000, 0x0000404040404040, 0x4040407e00000000, 0x000082c6aa929282, 0x8282828200000000, 0x000042424262524a, 0x4642424200000000, 0x00003c4242424242, 0x4242423c00000000, 0x00007c424242427c, 0x4040404000000000, 0x00003c4242424242, 0x42424a3c02000000, 0x00007c424242427c, 0x5048444200000000, 0x00003c4240403c02, 0x0242423c00000000, 0x0000fe1010101010, 0x1010101000000000, 0x0000424242424242, 0x4242423c00000000, 0x0000424242424224, 0x2424181800000000, 0x0000828282828292, 0x92aac68200000000, 0x0000424224241818, 0x2424424200000000, 0x0000828244442810, 0x1010101000000000, 0x00007e0202040810, 0x2040407e00000000, 0x0000382020202020, 0x2020203800000000, 0x0000404020201010, 0x0808040400000000, 0x0000380808080808, 0x0808083800000000, 0x0000102844000000, 0x0000000000000000, 0x0000000000000000, 0x0000007e00000000, 0x1008000000000000, 0x0000000000000000, 0x00000000003c023e, 0x4242423e00000000, 0x00004040407c4242, 0x4242427c00000000, 0x00000000003c4240, 0x4040423c00000000, 0x00000202023e4242, 0x4242423e00000000, 0x00000000003c4242, 0x7e40403c00000000, 0x00000e10107c1010, 0x1010101000000000, 0x00000000003e4242, 0x4242423e02023c00, 0x00004040407c4242, 0x4242424200000000, 0x0000101000301010, 0x1010103800000000, 0x00000404000c0404, 0x0404040444443800, 0x0000404040424448, 0x7048444200000000, 0x0000301010101010, 0x1010103800000000, 0x0000000000fc9292, 0x9292929200000000, 0x00000000007c4242, 0x4242424200000000, 0x00000000003c4242, 0x4242423c00000000, 0x00000000007c4242, 0x4242427c40404000, 0x00000000003e4242, 0x4242423e02020200, 0x00000000005e6040, 0x4040404000000000, 0x00000000003e4040, 0x3c02027c00000000, 0x00001010107c1010, 0x1010100e00000000, 0x0000000000424242, 0x4242423e00000000, 0x0000000000424242, 0x2424181800000000, 0x0000000000828292, 0x9292927c00000000, 0x0000000000424224, 0x1824424200000000, 0x0000000000424242, 0x4242423e02023c00, 0x00000000007e0408, 0x1020407e00000000, 0x00000c1010102010, 0x1010100c00000000, 0x0000101010101010, 0x1010101000000000, 0x0000300808080408, 0x0808083000000000, 0x000000000062928c, 0x0000000000000000 }; character * 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" "procedure 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"; character * fragment_shader = "#version 330 core\n" "uniform sampler2D texture_p;\n" "in vec2 fragment_uv;\n" "in vec4 fragment_rgba;\n" "out vec4 data;\n" "procedure main () {\n" " data = texture (texture_p, fragment_uv) * fragment_rgba;\n" "}\n"; natural * dumb_buffer = null; natural * order = null; natural xyz_attribute = 0; natural uv_attribute = 0; natural rgba_attribute = 0; natural u = 0; natural v = 0; if (vision->using_precomputed_spritesheet == true) { for (natural 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 (natural index = 0; index < 256; ++index) { dumb_buffer [index] = 0xffffffff; } ++vision->font_count; natural 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 (natural index = 0; index < 95; ++index) { natural * buffer = allocate (vision_font_width * vision_font_height * sizeof (* buffer)); for (natural value = 0; value < 2; ++value) { for (natural bit = 64; bit > 0; --bit) { natural destination = ((value << 3) - ((bit - 1) >> 3) + 7) * vision_font_width - ((bit - 1) & 7) + 7; natural 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 (natural index = 0; index < vision->sprite_count; ++index) { order [index] = index; } for (natural index = 0; index < vision->sprite_count; ++index) { for (natural subindex = 0; subindex < vision->sprite_count; ++subindex) { if (vision->sprite_height [order [index]] < vision->sprite_height [order [subindex]]) { natural temporary = order [index]; order [index] = order [subindex]; order [subindex] = temporary; } } } for (natural 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]] = (real) u / (real) vision->spritesheet_size; vision->sprite_v [order [index]] = (real) v / (real) vision->spritesheet_size; for (natural y = 0; y < vision->sprite_height [order [index]]; ++y) { for (natural x = 0; x < vision->sprite_width [order [index]]; ++x) { natural destination = (v + y) * vision->spritesheet_size + (u + x); natural 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 = (real) window_height / (real) window_width; vision->pixel_width = 2.0f / (real) window_width; vision->pixel_height = 2.0f / (real) window_height; glfwInit (); glfwWindowHinteger (GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHinteger (GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHinteger (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHinteger (GLFW_OPENGL_FORWARD_COMPAT, 1); vision->window = glfwCreateWindow ((integer) window_width, (integer) 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, (integer) window_width, (integer) 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 = (natural) vision->glGetAttribLocation (vision->shader_program, "vertex_xyz"); vision->glEnableVertexAttribArray (xyz_attribute); vision->glVertexAttribPointer (xyz_attribute, 3, GL_FLOAT, GL_FALSE, 9 * sizeof (real), (procedure *) 0); uv_attribute = (natural) vision->glGetAttribLocation (vision->shader_program, "vertex_uv"); vision->glEnableVertexAttribArray (uv_attribute); vision->glVertexAttribPointer (uv_attribute, 2, GL_FLOAT, GL_FALSE, 9 * sizeof (real), (procedure *) (3 * sizeof (real))); rgba_attribute = (natural) vision->glGetAttribLocation (vision->shader_program, "vertex_rgba"); vision->glEnableVertexAttribArray (rgba_attribute); vision->glVertexAttribPointer (rgba_attribute, 4, GL_FLOAT, GL_FALSE, 9 * sizeof (real), (procedure *) (5 * sizeof (real))); vision->vertex_array = allocate (vision->vertex_limit * sizeof (vision->vertex_array)); vision->index_array = allocate (vision->index_limit * sizeof (vision->index_array)); for (natural 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 ("/s Configured OpenGL renderer.\n"); } static procedure vision_synchronize (vision_structure * vision, natural colour) { integer signal_code [signal_count] = { 0, GLFW_KEY_A, GLFW_KEY_B, GLFW_KEY_C, GLFW_KEY_D, GLFW_KEY_E, GLFW_KEY_F, GLFW_KEY_G, GLFW_KEY_H, GLFW_KEY_I, GLFW_KEY_J, GLFW_KEY_K, GLFW_KEY_L, GLFW_KEY_M, GLFW_KEY_N, GLFW_KEY_O, GLFW_KEY_P, GLFW_KEY_Q, GLFW_KEY_R, GLFW_KEY_S, GLFW_KEY_T, GLFW_KEY_U, GLFW_KEY_V, GLFW_KEY_W, GLFW_KEY_X, GLFW_KEY_Y, GLFW_KEY_Z, GLFW_KEY_0, GLFW_KEY_1, GLFW_KEY_2, GLFW_KEY_3, GLFW_KEY_4, GLFW_KEY_5, GLFW_KEY_6, GLFW_KEY_7, GLFW_KEY_8, GLFW_KEY_9, GLFW_KEY_ESCAPE, GLFW_KEY_TAB, GLFW_KEY_ENTER, GLFW_KEY_ENTER, GLFW_KEY_SLASH, GLFW_KEY_BACKSLASH, GLFW_KEY_SEMICOLON, GLFW_KEY_GRAVE_ACCENT, GLFW_KEY_SPACE, GLFW_KEY_BACKSPACE, GLFW_KEY_PERIOD, GLFW_KEY_COMMA, GLFW_KEY_APOSTROPHE, GLFW_KEY_CAPS_LOCK, GLFW_KEY_MINUS, GLFW_KEY_EQUAL, GLFW_KEY_LEFT_BRACKET, GLFW_KEY_RIGHT_BRACKET, GLFW_KEY_LEFT_CONTROL, GLFW_KEY_RIGHT_CONTROL, GLFW_KEY_LEFT_SHIFT, GLFW_KEY_RIGHT_SHIFT, GLFW_KEY_LEFT_ALT, GLFW_KEY_RIGHT_ALT, GLFW_KEY_F1, GLFW_KEY_F2, GLFW_KEY_F3, GLFW_KEY_F4, GLFW_KEY_F5, GLFW_KEY_F6, GLFW_KEY_F7, GLFW_KEY_F8, GLFW_KEY_F9, GLFW_KEY_F10, GLFW_KEY_F11, GLFW_KEY_F12, GLFW_KEY_UP, GLFW_KEY_DOWN, GLFW_KEY_LEFT, GLFW_KEY_RIGHT, GLFW_KEY_NUM_LOCK, GLFW_KEY_PAUSE, GLFW_KEY_INSERT, GLFW_KEY_HOME, GLFW_KEY_PAGE_UP, GLFW_KEY_DELETE, GLFW_KEY_END, GLFW_KEY_PAGE_DOWN, GLFW_KEY_KP_ADD, GLFW_KEY_KP_SUBTRACT, GLFW_KEY_KP_MULTIPLY, GLFW_KEY_KP_DIVIDE, GLFW_KEY_KP_ENTER, GLFW_KEY_KP_DECIMAL, GLFW_KEY_KP_0, GLFW_KEY_KP_1, GLFW_KEY_KP_2, GLFW_KEY_KP_3, GLFW_KEY_KP_4, GLFW_KEY_KP_5, GLFW_KEY_KP_6, GLFW_KEY_KP_7, GLFW_KEY_KP_8, GLFW_KEY_KP_9 }; integer new_window_width = 0; integer new_window_height = 0; 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 != (natural) new_window_width) || (vision->window_height != (natural) new_window_height)) { if ((new_window_width <= 0) || (new_window_height <= 0)) return; glViewport (0, 0, new_window_width, new_window_height); vision->window_width = (natural) new_window_width; vision->window_height = (natural) new_window_height; vision->pixel_width = 2.0f / (real) new_window_width; vision->pixel_height = 2.0f / (real) new_window_height; } vision->cursor [cursor_left] = (boolean) (glfwGetMouseButton (vision->window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS); vision->cursor [cursor_middle] = (boolean) (glfwGetMouseButton (vision->window, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS); vision->cursor [cursor_right] = (boolean) (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) { real_64 x = 0.0; real_64 y = 0.0; glfwGetCursorPos (vision->window, & x, & y); vision->cursor_x = (integer) x; vision->cursor_y = (integer) y; //~real offset_x = vision->camera_x - x; //~for (natural 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 (natural index = 0; index < signal_count; ++index) { vision->signal [index] = (boolean) (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, (integer) 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 = (natural) (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 procedure vision_render_base (vision_structure * vision, natural vertex_count, real * vertex_array, natural index_count, natural * index_array, natural sprite, natural 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; real unwrap_x = (real) vision->sprite_u [sprite] / (real) vision->spritesheet_size; real unwrap_y = (real) vision->sprite_v [sprite] / (real) vision->spritesheet_size; real unwrap_width = (real) vision->sprite_width [sprite] / (real) vision->spritesheet_size; real unwrap_height = (real) vision->sprite_height [sprite] / (real) vision->spritesheet_size; //~for (natural vertex = 0; vertex < vertex_count; ++vertex) { //~natural destination = 9 * vertex + vision->vertex_count; //~natural 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 (natural 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 (natural 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 procedure vision_render_triangle (vision_structure * vision, real * vertex_array, natural colour) { //~if (vision->vertex_count + 3 * 36 >= vision->vertex_limit) return; //~if (vision->index_count + 3 >= vision->index_limit) return; //~for (natural vertex = 0; vertex < 3; ++vertex) { //~natural destination = 9 * vertex + vision->vertex_count; //~natural 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 (natural 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 procedure vision_change_field_of_view (vision_structure * vision, real 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 procedure vision_change_translation (vision_structure * vision, real x, real y, real 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 procedure vision_change_rotation (vision_structure * vision, real vertical, real horizontal) { for (natural 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