From 3dcbd2e9032867a0aa1961a1016790dd61d424a0 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Fri, 4 Aug 2023 21:58:43 -0400 Subject: [PATCH] Initial Commit --- .gitignore | 1 + CMakeLists.txt | 13 ++ cmake/embed-resource.cmake | 12 ++ cmake/util.cmake | 15 ++ include/GLES/gl.h | 188 +++++++++++++++++++++ src/draw.c | 302 +++++++++++++++++++++++++++++++++ src/log.h | 22 +++ src/matrix.c | 131 +++++++++++++++ src/matrix.h | 9 + src/passthrough.c | 146 ++++++++++++++++ src/passthrough.h | 23 +++ src/shaders/main.fsh | 52 ++++++ src/shaders/main.vsh | 48 ++++++ src/state.c | 336 +++++++++++++++++++++++++++++++++++++ src/state.h | 81 +++++++++ 15 files changed, 1379 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 cmake/embed-resource.cmake create mode 100644 cmake/util.cmake create mode 100644 include/GLES/gl.h create mode 100644 src/draw.c create mode 100644 src/log.h create mode 100644 src/matrix.c create mode 100644 src/matrix.h create mode 100644 src/passthrough.c create mode 100644 src/passthrough.h create mode 100644 src/shaders/main.fsh create mode 100644 src/shaders/main.vsh create mode 100644 src/state.c create mode 100644 src/state.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/build diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..ac8883a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.16.0) +project(gles-compatibility-layer) + +# Build +add_library(gles-compatibility-layer STATIC src/state.c src/passthrough.c src/matrix.c src/draw.c) +target_link_libraries(gles-compatibility-layer m SDL) +target_include_directories(gles-compatibility-layer PUBLIC include) +# Shaders +include(cmake/util.cmake) +embed_resource(gles-compatibility-layer src/shaders/main.vsh) +embed_resource(gles-compatibility-layer src/shaders/main.fsh) +# Warnings +target_compile_options(gles-compatibility-layer PRIVATE -Wall -Wextra -Werror -Wpointer-arith -Wshadow -Wnull-dereference) diff --git a/cmake/embed-resource.cmake b/cmake/embed-resource.cmake new file mode 100644 index 0000000..63379f0 --- /dev/null +++ b/cmake/embed-resource.cmake @@ -0,0 +1,12 @@ +# Read Hex Data +file(READ "${EMBED_IN}" data HEX) + +# Convert Hex Data For C Compatibility +string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," data "${data}") + +# Get C Name +get_filename_component(name "${EMBED_IN}" NAME) +string(MAKE_C_IDENTIFIER "${name}" name) + +# Write Data +file(WRITE "${EMBED_OUT}" "#include \nconst unsigned char ${name}[] = {${data}};\nconst size_t ${name}_len = sizeof (${name});\n") diff --git a/cmake/util.cmake b/cmake/util.cmake new file mode 100644 index 0000000..66af3f0 --- /dev/null +++ b/cmake/util.cmake @@ -0,0 +1,15 @@ +# Embed Resources +set(util_list_dir "${CMAKE_CURRENT_LIST_DIR}") +function(embed_resource target file) + # Get C Name + get_filename_component(name "${file}" NAME) + string(MAKE_C_IDENTIFIER "${name}" name) + # Add Command + add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${name}.c" + COMMAND "${CMAKE_COMMAND}" + ARGS "-DEMBED_IN=${CMAKE_CURRENT_SOURCE_DIR}/${file}" "-DEMBED_OUT=${CMAKE_CURRENT_BINARY_DIR}/${name}.c" "-P" "${util_list_dir}/embed-resource.cmake" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${file}" "${util_list_dir}/embed-resource.cmake" + ) + # Add To Target + target_sources("${target}" PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/${name}.c") +endfunction() diff --git a/include/GLES/gl.h b/include/GLES/gl.h new file mode 100644 index 0000000..b1f67ab --- /dev/null +++ b/include/GLES/gl.h @@ -0,0 +1,188 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define GL_FALSE 0 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_FLOAT 0x1406 +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 +#define GL_MODELVIEW_MATRIX 0xba6 +#define GL_PROJECTION_MATRIX 0xba7 +#define GL_VIEWPORT 0xba2 +#define GL_DEPTH_TEST 0xb71 +#define GL_PACK_ALIGNMENT 0xd05 +#define GL_UNPACK_ALIGNMENT 0xcf5 +#define GL_SRC_ALPHA 0x302 +#define GL_DST_ALPHA 0x304 +#define GL_ONE_MINUS_SRC_ALPHA 0x303 +#define GL_MODELVIEW 0x1700 +#define GL_PROJECTION 0x1701 +#define GL_TEXTURE 0x1702 +#define GL_VERTEX_ARRAY 0x8074 +#define GL_COLOR_ARRAY 0x8076 +#define GL_TEXTURE_COORD_ARRAY 0x8078 +#define GL_GREATER 0x204 +#define GL_ALPHA_TEST 0xbc0 +#define GL_TEXTURE_2D 0xde1 +#define GL_COLOR_MATERIAL 0xb57 +#define GL_PERSPECTIVE_CORRECTION_HINT 0xc50 +#define GL_FOG 0xb60 +#define GL_LINEAR 0x2601 +#define GL_EXP 0x800 +#define GL_FOG_DENSITY 0xb62 +#define GL_FOG_START 0xb63 +#define GL_FOG_END 0xb64 +#define GL_FOG_MODE 0xb65 +#define GL_FOG_COLOR 0xb66 +#define GL_BLEND 0xbe2 +#define GL_TRIANGLES 0x4 +#define GL_TRIANGLE_STRIP 0x5 +#define GL_TRIANGLE_FAN 0x6 +#define GL_FASTEST 0x1101 +#define GL_BACK 0x405 +#define GL_CULL_FACE 0xb44 +#define GL_LEQUAL 0x203 +#define GL_EQUAL 0x202 +#define GL_ONE_MINUS_DST_COLOR 0x307 +#define GL_ONE_MINUS_SRC_COLOR 0x301 +#define GL_ZERO 0 +#define GL_FLAT 0x1d00 +#define GL_SMOOTH 0x1d01 +#define GL_SCISSOR_TEST 0xc11 +#define GL_TRUE 1 +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_SRC_COLOR 0x300 +#define GL_DST_COLOR 0x306 +#define GL_ONE 1 +#define GL_LINES 0x1 +#define GL_LINE_STRIP 0x3 +#define GL_STATIC_DRAW 0x88e4 +#define GL_DYNAMIC_DRAW 0x88e8 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_REPEAT 0x2901 +#define GL_CLAMP_TO_EDGE 0x812f +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_NEAREST 0x2600 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +#define GL_DEPTH_BUFFER_BIT 0x100 +#define GL_COLOR_BUFFER_BIT 0x4000 +#define GL_NO_ERROR 0 +#define GL_NORMAL_ARRAY 0x8075 +#define GL_LIGHTING 0xb50 +#define GL_LIGHT0 0x4000 +#define GL_LIGHT1 0x4001 +#define GL_RESCALE_NORMAL 0x803a +#define GL_AMBIENT 0x1200 +#define GL_DIFFUSE 0x1201 +#define GL_SPECULAR 0x1202 +#define GL_POSITION 0x1203 +#define GL_LIGHT_MODEL_AMBIENT 0xb53 +#define GL_BYTE 0x1400 +#define GL_ACCUM 0x100 +#define GL_ALPHA 0x1906 +#define GL_NONE 0 + +typedef float GLfloat; +typedef float GLclampf; +typedef int GLint; +typedef unsigned char GLboolean; +typedef int GLsizei; +typedef unsigned int GLuint; +typedef ssize_t GLsizeiptr; +typedef intptr_t GLintptr; +typedef int32_t GLfixed; +typedef unsigned int GLbitfield; +typedef unsigned int GLenum; +typedef char GLchar; +typedef void GLvoid; + +void glFogfv(GLenum pname, const GLfloat *params); +void glVertexPointer(GLint size, GLenum type, GLsizei stride, const void *pointer); +void glLineWidth(GLfloat width); +void glBlendFunc(GLenum sfactor, GLenum dfactor); +void glDrawArrays(GLenum mode, GLint first, GLsizei count); +void glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +void glClear(GLbitfield mask); +void glBufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage); +void glFogx(GLenum pname, GLfixed param); +#define glFogi glFogx +void glFogf(GLenum pname, GLfloat param); +void glMatrixMode(GLenum mode); +void glColorPointer(GLint size, GLenum type, GLsizei stride, const void *pointer); +void glScissor(GLint x, GLint y, GLsizei width, GLsizei height); +void glTexParameteri(GLenum target, GLenum pname, GLint param); +void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +void glEnable(GLenum cap); +void glEnableClientState(GLenum array); +void glPolygonOffset(GLfloat factor, GLfloat units); +void glDisableClientState(GLenum array); +void glDepthRangef(GLclampf near, GLclampf far); +void glDepthFunc(GLenum func); +void glBindBuffer(GLenum target, GLuint buffer); +void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +void glPopMatrix(); +void glLoadIdentity(); +void glScalef(GLfloat x, GLfloat y, GLfloat z); +void glPushMatrix(); +void glDepthMask(GLboolean flag); +void glHint(GLenum target, GLenum mode); +void glMultMatrixf(const GLfloat *m); +void glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const void *pointer); +void glDeleteBuffers(GLsizei n, const GLuint *buffers); +void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +void glGenTextures(GLsizei n, GLuint *textures); +void glDeleteTextures(GLsizei n, const GLuint *textures); +void glAlphaFunc(GLenum func, GLclampf ref); +void glGetFloatv(GLenum pname, GLfloat *params); +void glBindTexture(GLenum target, GLuint texture); +void glTranslatef(GLfloat x, GLfloat y, GLfloat z); +void glShadeModel(GLenum mode); +void glOrthof(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far); +void glDisable(GLenum cap); +void glCullFace(GLenum mode); +void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +void glViewport(GLint x, GLint y, GLsizei width, GLsizei height); +void glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz); +GLboolean glIsEnabled(GLenum cap); +void glGetIntegerv(GLenum pname, GLint *data); +void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *data); +void glGenBuffers(GLsizei n, GLuint *buffers); +GLenum glGetError(); +void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void *data); +void glNormalPointer(GLenum type, GLsizei stride, const void *pointer); +void glLightfv(GLenum light, GLenum pname, const GLfloat *params); +void glLightModelfv(GLenum pname, const GLfloat *params); +void glPixelStorei(GLenum pname, GLint param); + +// Not Part Of OpenGL ES 1.1 +#define GL_SAMPLES_PASSED_ARB 0x8c2f // GL_ANY_SAMPLES_PASSED +#define GL_QUERY_RESULT_AVAILABLE_ARB 0x8867 // GL_QUERY_RESULT_AVAILABLE +#define GL_QUERY_RESULT_ARB 0x8866 // GL_QUERY_RESULT +void glGenQueriesARB(GLsizei n, GLuint *ids); +void glDeleteQueriesARB(GLsizei n, const GLuint *ids); +void glBeginQueryARB(GLenum target, GLuint id); +void glEndQueryARB(GLenum target); +void glGetQueryObjectuivARB(GLuint id, GLenum pname, GLuint *params); +void extra_enable_highlight_mode(float red, float green, float blue, float alpha); +void extra_disable_highlight_mode(); + +void init_gles_compatibility_layer(); + +#ifdef __cplusplus +} +#endif diff --git a/src/draw.c b/src/draw.c new file mode 100644 index 0000000..4efb68f --- /dev/null +++ b/src/draw.c @@ -0,0 +1,302 @@ +#include + +#include "state.h" +#include "passthrough.h" +#include "log.h" + +#include + +// Shaders +#define REAL_GL_FRAGMENT_SHADER 0x8b30 +#define REAL_GL_VERTEX_SHADER 0x8b31 +#define REAL_GL_INFO_LOG_LENGTH 0x8b84 +#define REAL_GL_COMPILE_STATUS 0x8b81 +GL_FUNC(glUseProgram, void, (GLuint program)); +GL_FUNC(glGetUniformLocation, GLint, (GLuint program, const GLchar *name)); +GL_FUNC(glUniformMatrix4fv, void, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)); +GL_FUNC(glUniform1i, void, (GLint location, GLint v0)); +GL_FUNC(glUniform1f, void, (GLint location, GLfloat v0)); +GL_FUNC(glUniform3f, void, (GLint location, GLfloat v0, GLfloat v1, GLfloat v2)); +GL_FUNC(glUniform4f, void, (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)); +GL_FUNC(glGetAttribLocation, GLint, (GLuint program, const GLchar *name)); +GL_FUNC(glEnableVertexAttribArray, void, (GLuint index)); +GL_FUNC(glDisableVertexAttribArray, void, (GLuint index)); +GL_FUNC(glVertexAttribPointer, void, (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer)); +GL_FUNC(glVertexAttrib3f, void, (GLuint index, GLfloat v0, GLfloat v1, GLfloat v2)); +GL_FUNC(glVertexAttrib4f, void, (GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)); +GL_FUNC(glCreateShader, GLuint, (GLenum type)); +GL_FUNC(glShaderSource, void, (GLuint shader, GLsizei count, const GLchar *const *string, const GLint *length)); +GL_FUNC(glCompileShader, void, (GLuint shader)); +GL_FUNC(glCreateProgram, GLuint, ()); +GL_FUNC(glAttachShader, void, (GLuint program, GLuint shader)); +GL_FUNC(glLinkProgram, void, (GLuint program)); +GL_FUNC(glGetShaderiv, void, (GLuint shader, GLenum pname, GLint *params)); +GL_FUNC(glGetShaderInfoLog, void, (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog)); + +// Compile Shader +static void log_shader(GLuint shader, const char *name) { + // Log + GLint log_length = 0; + real_glGetShaderiv()(shader, REAL_GL_INFO_LOG_LENGTH, &log_length); + GLchar *log = malloc(log_length * sizeof (GLchar)); + ALLOC_CHECK(log); + real_glGetShaderInfoLog()(shader, log_length, &log_length, log); + if (log_length > 0) { + if (log_length > 1 && log[log_length - 1] == '\n') { + log[log_length - 1] = '\0'; + } + DEBUG("%s Shader Compile Log: %s", name, log); + } + free(log); + + // Check Status + GLint is_compiled = 0; + real_glGetShaderiv()(shader, REAL_GL_COMPILE_STATUS, &is_compiled); + if (!is_compiled) { + ERR("Failed To Compile %s Shader", name); + } +} +static GLuint compile_shader(const char *vertex_shader_text, const int vertex_shader_length, const char *fragment_shader_text, const int fragment_shader_length) { + // Vertex Shader + const GLuint vertex_shader = real_glCreateShader()(REAL_GL_VERTEX_SHADER); + real_glShaderSource()(vertex_shader, 1, &vertex_shader_text, &vertex_shader_length); + real_glCompileShader()(vertex_shader); + log_shader(vertex_shader, "Vertex"); + + // Fragment Shader + const GLuint fragment_shader = real_glCreateShader()(REAL_GL_FRAGMENT_SHADER); + real_glShaderSource()(fragment_shader, 1, &fragment_shader_text, &fragment_shader_length); + real_glCompileShader()(fragment_shader); + log_shader(fragment_shader, "Fragment"); + + // Link + GLuint program = real_glCreateProgram()(); + real_glAttachShader()(program, vertex_shader); + real_glAttachShader()(program, fragment_shader); + real_glLinkProgram()(program); + + // Return + return program; +} + +// Reset Static Variables +typedef struct { + GLint *variable; + GLint default_value; +} static_variable_t; +static static_variable_t variables_to_reset[64]; +static int variables_to_reset_size = 0; +static void mark_for_reset(GLint *variable) { + static_variable_t variable_obj; + variable_obj.variable = variable; + variable_obj.default_value = *variable; + variables_to_reset[variables_to_reset_size++] = variable_obj; +} +static void reset_variables() { + for (int i = 0; i < variables_to_reset_size; i++) { + static_variable_t variable_obj = variables_to_reset[i]; + *variable_obj.variable = variable_obj.default_value; + } + variables_to_reset_size = 0; +} + +// Shader +extern unsigned char main_vsh[]; +extern size_t main_vsh_len; +extern unsigned char main_fsh[]; +extern size_t main_fsh_len; +static GLuint get_shader() { + static GLuint program = 0; + if (program == 0) { + mark_for_reset((GLint *) &program); + program = compile_shader((const char *) main_vsh, main_vsh_len, (const char *) main_fsh, main_fsh_len); + } + return program; +} + +// Init +GL_FUNC(glGenVertexArrays, void, (GLsizei n, GLuint *arrays)); +GL_FUNC(glBindVertexArray, void, (GLuint array)); +GL_FUNC(glActiveTexture, void, (GLenum texture)); +void init_gles_compatibility_layer() { + // State + _init_gles_compatibility_layer_state(); + + // Reset Static Variables + reset_variables(); + + // Setup VAO + GLuint vao; + real_glGenVertexArrays()(1, &vao); + real_glBindVertexArray()(vao); + + // Load Shader + GLuint program = get_shader(); + real_glUseProgram()(program); +} + +// Array Pointer Drawing +GL_FUNC(glDrawArrays, void, (GLenum mode, GLint first, GLsizei count)); +#define lazy_handle(function, name) \ + static GLint name##_handle = -1; \ + if (name##_handle == -1) { \ + mark_for_reset(&name##_handle); \ + name##_handle = real_##function()(program, #name); \ + if (name##_handle == -1) { \ + ERR("Unable To Find: %s", #name); \ + } \ + } +#define lazy_uniform(name) lazy_handle(glGetUniformLocation, name) +#define lazy_attrib(name) lazy_handle(glGetAttribLocation, name) +void glDrawArrays(GLenum mode, GLint first, GLsizei count) { + // Verify + if (gl_state.array_pointers.vertex.size != 3 || !gl_state.array_pointers.vertex.enabled || gl_state.array_pointers.vertex.type != GL_FLOAT) { + ERR("Unsupported Vertex Conifguration"); + } + + // Check + GLint current_buffer; + glGetIntegerv(GL_ARRAY_BUFFER_BINDING, ¤t_buffer); + if (current_buffer == 0) { + return; + } + + // Check Mode + int use_color_pointer = gl_state.array_pointers.color.enabled; + if (use_color_pointer && (gl_state.array_pointers.color.size != 4 || gl_state.array_pointers.color.type != GL_UNSIGNED_BYTE)) { + ERR("Unsupported Color Conifguration"); + } + int use_normal_pointer = gl_state.lighting.enabled && gl_state.array_pointers.normal.enabled; + if (use_normal_pointer && gl_state.array_pointers.normal.type != GL_BYTE) { + ERR("Unsupported Normal Conifguration"); + } + int use_texture = gl_state.texture_2d && gl_state.array_pointers.tex_coord.enabled; + if (use_texture && (gl_state.array_pointers.tex_coord.size != 2 || gl_state.array_pointers.tex_coord.type != GL_FLOAT)) { + ERR("Unsupported Texture Conifguration"); + } + + // Get Shader + GLuint program = get_shader(); + + // Projection Matrix + lazy_uniform(u_projection); + matrix_t *projection = &gl_state.matrix_stacks.projection.stack[gl_state.matrix_stacks.projection.i]; + real_glUniformMatrix4fv()(u_projection_handle, 1, 0, (GLfloat *) &projection->data[0][0]); + + // Model View Matrix + lazy_uniform(u_model_view); + matrix_t *model_view = &gl_state.matrix_stacks.model_view.stack[gl_state.matrix_stacks.model_view.i]; + real_glUniformMatrix4fv()(u_model_view_handle, 1, 0, (GLfloat *) &model_view->data[0][0]); + + // Has Texture + lazy_uniform(u_has_texture); \ + real_glUniform1i()(u_has_texture_handle, use_texture); \ + + // Texture Matrix + lazy_uniform(u_texture); + matrix_t *texture = &gl_state.matrix_stacks.texture.stack[gl_state.matrix_stacks.texture.i]; + real_glUniformMatrix4fv()(u_texture_handle, 1, 0, (GLfloat *) &texture->data[0][0]); + + // Texture Unit + lazy_uniform(u_texture_unit); + real_glUniform1i()(u_texture_unit_handle, 0); + + // Alpha Test + lazy_uniform(u_alpha_test); + real_glUniform1i()(u_alpha_test_handle, gl_state.alpha_test); + + // Color + lazy_attrib(a_color); + if (use_color_pointer) { + real_glVertexAttribPointer()(a_color_handle, gl_state.array_pointers.color.size, gl_state.array_pointers.color.type, 1, gl_state.array_pointers.color.stride, gl_state.array_pointers.color.pointer); + real_glEnableVertexAttribArray()(a_color_handle); + } else { + real_glVertexAttrib4f()(a_color_handle, gl_state.color.red, gl_state.color.green, gl_state.color.blue, gl_state.color.alpha); + } + + // Highlight Mode + lazy_uniform(u_highlight_mode); + real_glUniform1i()(u_highlight_mode_handle, gl_state.highlight_mode.enabled); + if (gl_state.highlight_mode.enabled) { + lazy_uniform(u_highlight_mode_color); + real_glUniform4f()(u_highlight_mode_color_handle, gl_state.highlight_mode.color.red, gl_state.highlight_mode.color.green, gl_state.highlight_mode.color.blue, gl_state.highlight_mode.color.alpha); + } + + // Lighting + lazy_uniform(u_lighting); + real_glUniform1i()(u_lighting_handle, gl_state.lighting.enabled); + lazy_attrib(a_normal); + if (gl_state.lighting.enabled) { + lazy_uniform(u_lighting_ambient); + real_glUniform4f()(u_lighting_ambient_handle, gl_state.lighting.ambient.red, gl_state.lighting.ambient.green, gl_state.lighting.ambient.blue, gl_state.lighting.ambient.alpha); + light_source_t *light_source; +#define light_source_uniforms(number) \ + light_source = &gl_state.lighting.light_sources[number]; \ + lazy_uniform(u_lighting_light_source_##number); \ + real_glUniform1i()(u_lighting_light_source_##number##_handle, light_source->enabled); \ + lazy_uniform(u_lighting_light_source_##number##_position); \ + real_glUniform3f()(u_lighting_light_source_##number##_position_handle, light_source->position.x, light_source->position.y, light_source->position.z); \ + lazy_uniform(u_lighting_light_source_##number##_diffuse); \ + real_glUniform4f()(u_lighting_light_source_##number##_diffuse_handle, light_source->diffuse.red, light_source->diffuse.green, light_source->diffuse.blue, light_source->diffuse.alpha); + light_source_uniforms(0); + light_source_uniforms(1); + + // Normal + if (use_normal_pointer) { + real_glVertexAttribPointer()(a_normal_handle, 3, gl_state.array_pointers.normal.type, 1, gl_state.array_pointers.normal.stride, gl_state.array_pointers.normal.pointer); + real_glEnableVertexAttribArray()(a_normal_handle); + } else { + real_glVertexAttrib3f()(a_normal_handle, gl_state.normal.x, gl_state.normal.y, gl_state.normal.z); + } + // Normal Rescale Factor (See Pages 46-47 Of https://registry.khronos.org/OpenGL/specs/gl/glspec15.pdf) + float normal_rescale_factor = 1; + if (gl_state.rescale_normal) { + normal_rescale_factor = 1.0f / sqrtf(powf(model_view->data[0][2], 2) + powf(model_view->data[1][2], 2) + powf(model_view->data[2][2], 2)); + } + lazy_uniform(u_normal_rescale_factor); + real_glUniform1f()(u_normal_rescale_factor_handle, normal_rescale_factor); + } + + // Fog + lazy_uniform(u_fog); + real_glUniform1i()(u_fog_handle, gl_state.fog.enabled); + if (gl_state.fog.enabled) { + lazy_uniform(u_fog_color); + real_glUniform4f()(u_fog_color_handle, gl_state.fog.color.red, gl_state.fog.color.green, gl_state.fog.color.blue, gl_state.fog.color.alpha); + lazy_uniform(u_fog_is_linear); + real_glUniform1i()(u_fog_is_linear_handle, gl_state.fog.mode == GL_LINEAR); + lazy_uniform(u_fog_start); + real_glUniform1f()(u_fog_start_handle, gl_state.fog.start); + lazy_uniform(u_fog_end); + real_glUniform1f()(u_fog_end_handle, gl_state.fog.end); + } + + // Vertices + lazy_attrib(a_vertex_coords); + real_glVertexAttribPointer()(a_vertex_coords_handle, gl_state.array_pointers.vertex.size, gl_state.array_pointers.vertex.type, 0, gl_state.array_pointers.vertex.stride, gl_state.array_pointers.vertex.pointer); + real_glEnableVertexAttribArray()(a_vertex_coords_handle); + + // Texture Coordinates + lazy_attrib(a_texture_coords); + if (use_texture) { + real_glVertexAttribPointer()(a_texture_coords_handle, gl_state.array_pointers.tex_coord.size, gl_state.array_pointers.tex_coord.type, 0, gl_state.array_pointers.tex_coord.stride, gl_state.array_pointers.tex_coord.pointer); + real_glEnableVertexAttribArray()(a_texture_coords_handle); + } else { + real_glVertexAttrib3f()(a_texture_coords_handle, 0, 0, 0); + } + + // Draw + real_glDrawArrays()(mode, first, count); + + // Cleanup + if (use_color_pointer) { + real_glDisableVertexAttribArray()(a_color_handle); + } + if (use_normal_pointer) { + real_glDisableVertexAttribArray()(a_normal_handle); + } + real_glDisableVertexAttribArray()(a_vertex_coords_handle); + if (use_texture) { + real_glDisableVertexAttribArray()(a_texture_coords_handle); + } +} diff --git a/src/log.h b/src/log.h new file mode 100644 index 0000000..6f8d50d --- /dev/null +++ b/src/log.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +#ifdef ANDROID +#include + +#define DEBUG(...) { ((void) __android_log_print(ANDROID_LOG_VERBOSE, "GL DEBUG", __VA_ARGS__)); } +#define ERR(...) { ((void) __android_log_print(ANDROID_LOG_ERROR, "GL ERROR", __VA_ARGS__)); exit(EXIT_FAILURE); } +#else +#include + +#define DEBUG(format, ...) { printf("GL DEBUG: " format "\n", ##__VA_ARGS__); } +#define ERR(format, ...) { printf("GL ERROR: (%s:%i): " format "\n", __FILE__, __LINE__, ##__VA_ARGS__); exit(EXIT_FAILURE); } +#endif + +#define ALLOC_CHECK(obj) \ + { \ + if (obj == NULL) { \ + ERR("Memory Allocation Failed"); \ + } \ + } diff --git a/src/matrix.c b/src/matrix.c new file mode 100644 index 0000000..7cfdea9 --- /dev/null +++ b/src/matrix.c @@ -0,0 +1,131 @@ +#include +#include + +#include "log.h" + +#include "state.h" + +// Matrix Common +static void matrix_copy(matrix_t *src, matrix_t *dst) { + memcpy((void *) dst->data, (void *) src->data, MATRIX_DATA_SIZE); +} + +// Identity Matrix +static matrix_t identity_matrix = { + .data = { + {1, 0, 0, 0}, + {0, 1, 0, 0}, + {0, 0, 1, 0}, + {0, 0, 0, 1} + } +}; +static void init_matrix_stack(matrix_stack_t *stack) { + matrix_copy(&identity_matrix, &stack->stack[0]); +} +void _init_gles_compatibility_matrix_stacks() { + init_matrix_stack(&gl_state.matrix_stacks.model_view); + init_matrix_stack(&gl_state.matrix_stacks.projection); + init_matrix_stack(&gl_state.matrix_stacks.texture); +} + +// Matrix Mode +static matrix_stack_t *get_matrix_stack() { + switch (gl_state.matrix_stacks.mode) { + case GL_MODELVIEW: { + return &gl_state.matrix_stacks.model_view; + } + case GL_PROJECTION: { + return &gl_state.matrix_stacks.projection; + } + case GL_TEXTURE: { + return &gl_state.matrix_stacks.texture; + } + default: { + ERR("Unsupported Matrix Mode: %i", gl_state.matrix_stacks.mode); + } + } +} + +// Matrix Functions +void glMatrixMode(GLenum mode) { + gl_state.matrix_stacks.mode = mode; +} +void glPopMatrix() { + get_matrix_stack()->i--; +} +void glLoadIdentity() { + matrix_stack_t *stack = get_matrix_stack(); + matrix_copy(&identity_matrix, &stack->stack[stack->i]); +} +void glPushMatrix() { + matrix_stack_t *stack = get_matrix_stack(); + matrix_copy(&stack->stack[stack->i], &stack->stack[stack->i + 1]); + stack->i++; +} +void glMultMatrixf(const GLfloat *m) { + matrix_t new_matrix; + matrix_stack_t *stack = get_matrix_stack(); + matrix_t *current_matrix = &stack->stack[stack->i]; + for (int x = 0; x < MATRIX_SIZE; x++) { + for (int y = 0; y < MATRIX_SIZE; y++) { + GLfloat result = 0; + for (int i = 0; i < MATRIX_SIZE; i++) { + result += (current_matrix->data[i][y] * m[(x * MATRIX_SIZE) + i]); + } + new_matrix.data[x][y] = result; + } + } + matrix_copy(&new_matrix, current_matrix); +} +void glScalef(GLfloat x, GLfloat y, GLfloat z) { + GLfloat m[] = { + x, 0, 0, 0, + 0, y, 0, 0, + 0, 0, z, 0, + 0, 0, 0, 1 + }; + glMultMatrixf(m); +} +void glTranslatef(GLfloat x, GLfloat y, GLfloat z) { + GLfloat m[] = { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + x, y, z, 1 + }; + glMultMatrixf(m); +} +void glOrthof(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far) { + GLfloat m[] = { + (2.f / (right - left)), 0, 0, 0, + 0, (2.f / (top - bottom)), 0, 0, + 0, 0, (-2.f / (far - near)), 0, + -((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -((far + near) / (far - near)), 1 + }; + glMultMatrixf(m); +} +#define DEG2RAD (M_PI / 180.f) +void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) { + // Normalize + GLfloat length = sqrtf((x * x) + (y * y) + (z * z)); + x /= length; + y /= length; + z /= length; + + // Values + GLfloat angle_radians = angle * DEG2RAD; + GLfloat c = cosf(angle_radians); + GLfloat s = sinf(angle_radians); + GLfloat x2 = x * x; + GLfloat y2 = y * y; + GLfloat z2 = z * z; + + // Multiply + GLfloat m[] = { + x2 * (1.f - c) + c, (x * y) * (1.f - c) + (z * s), (x * z) * (1.f - c) - (y * s), 0, + (x * y) * (1.f - c) - (z * s), y2 * (1.f - c) + c, (y * z) * (1.f - c) + (x * s), 0, + (x * z) * (1.f - c) + (y * s), (y * z) * (1.f - c) - (x * s), z2 * (1.f - c) + c, 0, + 0, 0, 0, 1.f + }; + glMultMatrixf(m); +} diff --git a/src/matrix.h b/src/matrix.h new file mode 100644 index 0000000..e4a8f9b --- /dev/null +++ b/src/matrix.h @@ -0,0 +1,9 @@ +#include + +// Matrix Common +#define MATRIX_SIZE 4 +#define MATRIX_DATA_SIZE (sizeof (GLfloat) * MATRIX_SIZE * MATRIX_SIZE) +// OpenGL Matrices Are Column-Major +typedef struct { + GLfloat data[MATRIX_SIZE][MATRIX_SIZE]; +} matrix_t; diff --git a/src/passthrough.c b/src/passthrough.c new file mode 100644 index 0000000..fdaee30 --- /dev/null +++ b/src/passthrough.c @@ -0,0 +1,146 @@ +#include + +#include "passthrough.h" + +// Simple v1.1 -> v2.0 Passthrough Functions +GL_FUNC(glLineWidth, void, (GLfloat width)); +void glLineWidth(GLfloat width) { + real_glLineWidth()(width); +} +GL_FUNC(glBlendFunc, void, (GLenum sfactor, GLenum dfactor)); +void glBlendFunc(GLenum sfactor, GLenum dfactor) { + real_glBlendFunc()(sfactor, dfactor); +} +GL_FUNC(glClear, void, (GLbitfield mask)); +void glClear(GLbitfield mask) { + real_glClear()(mask); +} +GL_FUNC(glBufferData, void, (GLenum target, GLsizeiptr size, const void *data, GLenum usage)); +void glBufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage) { + real_glBufferData()(target, size, data, usage); +} +GL_FUNC(glScissor, void, (GLint x, GLint y, GLsizei width, GLsizei height)); +void glScissor(GLint x, GLint y, GLsizei width, GLsizei height) { + real_glScissor()(x, y, width, height); +} +GL_FUNC(glTexParameteri, void, (GLenum target, GLenum pname, GLint param)); +void glTexParameteri(GLenum target, GLenum pname, GLint param) { + real_glTexParameteri()(target, pname, param); +} +GL_FUNC(glTexImage2D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels)); +void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) { + real_glTexImage2D()(target, level, internalformat, width, height, border, format, type, pixels); +} +GL_FUNC(glPolygonOffset, void, (GLfloat factor, GLfloat units)); +void glPolygonOffset(GLfloat factor, GLfloat units) { + real_glPolygonOffset()(factor, units); +} +GL_FUNC(glDepthRangef, void, (GLclampf near, GLclampf far)); +void glDepthRangef(GLclampf near, GLclampf far) { + real_glDepthRangef()(near, far); +} +GL_FUNC(glBindBuffer, void, (GLenum target, GLuint buffer)); +void glBindBuffer(GLenum target, GLuint buffer) { + real_glBindBuffer()(target, buffer); +} +GL_FUNC(glDepthFunc, void, (GLenum func)); +void glDepthFunc(GLenum func) { + real_glDepthFunc()(func); +} +GL_FUNC(glClearColor, void, (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)); +void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { + real_glClearColor()(red, green, blue, alpha); +} +GL_FUNC(glDepthMask, void, (GLboolean flag)); +void glDepthMask(GLboolean flag) { + real_glDepthMask()(flag); +} +GL_FUNC(glHint, void, (GLenum target, GLenum mode)); +void glHint(GLenum target, GLenum mode) { + if (target != GL_PERSPECTIVE_CORRECTION_HINT) { + real_glHint()(target, mode); + } +} +GL_FUNC(glDeleteBuffers, void, (GLsizei n, const GLuint *buffers)); +void glDeleteBuffers(GLsizei n, const GLuint *buffers) { + real_glDeleteBuffers()(n, buffers); +} +GL_FUNC(glColorMask, void, (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)); +void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) { + real_glColorMask()(red, green, blue, alpha); +} +GL_FUNC(glTexSubImage2D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)); +void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) { + real_glTexSubImage2D()(target, level, xoffset, yoffset, width, height, format, type, pixels); +} +GL_FUNC(glGenTextures, void, (GLsizei n, GLuint *textures)); +void glGenTextures(GLsizei n, GLuint *textures) { + real_glGenTextures()(n, textures); +} +GL_FUNC(glDeleteTextures, void, (GLsizei n, const GLuint *textures)); +void glDeleteTextures(GLsizei n, const GLuint *textures) { + real_glDeleteTextures()(n, textures); +} +GL_FUNC(glBindTexture, void, (GLenum target, GLuint texture)); +void glBindTexture(GLenum target, GLuint texture) { + real_glBindTexture()(target, texture); +} +GL_FUNC(glCullFace, void, (GLenum mode)); +void glCullFace(GLenum mode) { + real_glCullFace()(mode); +} +GL_FUNC(glViewport, void, (GLint x, GLint y, GLsizei width, GLsizei height)); +void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) { + real_glViewport()(x, y, width, height); +} +GL_FUNC(glIsEnabled, GLboolean, (GLenum cap)); +GLboolean glIsEnabled(GLenum cap) { + return real_glIsEnabled()(cap); +} +GL_FUNC(glGetIntegerv, void, (GLenum pname, GLint *data)); +void glGetIntegerv(GLenum pname, GLint *data) { + real_glGetIntegerv()(pname, data); +} +GL_FUNC(glReadPixels, void, (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *data)); +void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *data) { + real_glReadPixels()(x, y, width, height, format, type, data); +} +void glShadeModel(__attribute__((unused)) GLenum mode) { + // Do Nothing +} +GL_FUNC(glGenBuffers, void, (GLsizei n, GLuint *buffers)); +void glGenBuffers(GLsizei n, GLuint *buffers) { + real_glGenBuffers()(n, buffers); +} +GL_FUNC(glGetError, GLenum, ()); +GLenum glGetError() { + return real_glGetError()(); +} +GL_FUNC(glBufferSubData, void, (GLenum target, GLintptr offset, GLsizeiptr size, const void *data)); +void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void *data) { + real_glBufferSubData()(target, offset, size, data); +} +GL_FUNC(glGenQueries, void, (GLsizei n, GLuint *ids)); +void glGenQueriesARB(GLsizei n, GLuint *ids) { + real_glGenQueries()(n, ids); +} +GL_FUNC(glDeleteQueries, void, (GLsizei n, const GLuint *ids)); +void glDeleteQueriesARB(GLsizei n, const GLuint *ids) { + real_glDeleteQueries()(n, ids); +} +GL_FUNC(glBeginQuery, void, (GLenum target, GLuint id)); +void glBeginQueryARB(GLenum target, GLuint id) { + real_glBeginQuery()(target, id); +} +GL_FUNC(glEndQuery, void, (GLenum target)); +void glEndQueryARB(GLenum target) { + real_glEndQuery()(target); +} +GL_FUNC(glGetQueryObjectuiv, void, (GLuint id, GLenum pname, GLuint *params)); +void glGetQueryObjectuivARB(GLuint id, GLenum pname, GLuint *params) { + real_glGetQueryObjectuiv()(id, pname, params); +} +GL_FUNC(glPixelStorei, void, (GLenum pname, GLint param)); +void glPixelStorei(GLenum pname, GLint param) { + real_glPixelStorei()(pname, param); +} diff --git a/src/passthrough.h b/src/passthrough.h new file mode 100644 index 0000000..1b31172 --- /dev/null +++ b/src/passthrough.h @@ -0,0 +1,23 @@ +#include + +#include "log.h" + +// Load GL Function +#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) +#define GL_APIENTRY __stdcall +#else +#define GL_APIENTRY +#endif +#define GL_FUNC(name, return_type, args) \ + typedef return_type (GL_APIENTRY *real_##name##_t)args; \ + \ + real_##name##_t real_##name() { \ + static real_##name##_t func = NULL; \ + if (!func) { \ + func = (real_##name##_t) SDL_GL_GetProcAddress(#name); \ + if (!func) { \ + ERR("Error Resolving GL Symbol: " #name); \ + } \ + } \ + return func; \ + } diff --git a/src/shaders/main.fsh b/src/shaders/main.fsh new file mode 100644 index 0000000..253455e --- /dev/null +++ b/src/shaders/main.fsh @@ -0,0 +1,52 @@ +#version 300 es +precision highp float; +// Result +out vec4 frag_color; +// Texture +uniform bool u_has_texture; +uniform sampler2D u_texture_unit; +// Color +in vec4 v_color; +in vec4 v_texture_pos; +// Highlight Mode +uniform bool u_highlight_mode; +uniform vec4 u_highlight_mode_color; +// Alpha Test +uniform bool u_alpha_test; +// Fog +uniform bool u_fog; +uniform vec4 u_fog_color; +uniform bool u_fog_is_linear; +uniform float u_fog_start; +uniform float u_fog_end; +in vec4 v_fog_eye_position; +// Main +void main(void) { + frag_color = v_color; + // Texture + if (u_has_texture) { + vec4 texture_color = texture(u_texture_unit, v_texture_pos.xy); + if (u_highlight_mode) { + texture_color.rgb = u_highlight_mode_color.rgb; + texture_color.a *= u_highlight_mode_color.a; + frag_color = texture_color; + } else { + frag_color *= texture_color; + } + } + // Fog + if (u_fog) { + float fog_factor; + if (u_fog_is_linear) { + fog_factor = (u_fog_end - length(v_fog_eye_position)) / (u_fog_end - u_fog_start); + } else { + fog_factor = exp(-u_fog_start * length(v_fog_eye_position)); + } + fog_factor = clamp(fog_factor, 0.0, 1.0); + frag_color.rgb = mix(frag_color, u_fog_color, 1.0 - fog_factor).rgb; + } + // Alpha Test + if (u_alpha_test && frag_color.a <= 0.1) { + discard; + } +} diff --git a/src/shaders/main.vsh b/src/shaders/main.vsh new file mode 100644 index 0000000..9185c20 --- /dev/null +++ b/src/shaders/main.vsh @@ -0,0 +1,48 @@ +#version 300 es +precision highp float; +// Matrices +uniform mat4 u_projection; +uniform mat4 u_model_view; +uniform mat4 u_texture; +// Texture +in vec3 a_vertex_coords; +in vec2 a_texture_coords; +out vec4 v_texture_pos; +// Color +in vec4 a_color; +out vec4 v_color; +// Normal +in vec3 a_normal; +uniform float u_normal_rescale_factor; +// Lighting +uniform bool u_lighting; +uniform vec4 u_lighting_ambient; +uniform bool u_lighting_light_source_0; +uniform vec3 u_lighting_light_source_0_position; +uniform vec4 u_lighting_light_source_0_diffuse; +uniform bool u_lighting_light_source_1; +uniform vec3 u_lighting_light_source_1_position; +uniform vec4 u_lighting_light_source_1_diffuse; +// Fog +out vec4 v_fog_eye_position; +// Main +void main(void) { + v_texture_pos = u_texture * vec4(a_texture_coords.xy, 0.0, 1.0); + gl_Position = u_projection * u_model_view * vec4(a_vertex_coords.xyz, 1.0); + v_color = a_color; + v_fog_eye_position = u_model_view * vec4(a_vertex_coords.xyz, 1.0); + + // Lighting + if (u_lighting) { + vec4 transformed_normal = u_model_view * vec4(a_normal, 0.0) * u_normal_rescale_factor; + vec4 total_light = u_lighting_ambient; + if (u_lighting_light_source_0) { + total_light += max(0.0, dot(transformed_normal.xyz, u_lighting_light_source_0_position)) * u_lighting_light_source_0_diffuse; + } + if (u_lighting_light_source_1) { + total_light += max(0.0, dot(transformed_normal.xyz, u_lighting_light_source_1_position)) * u_lighting_light_source_1_diffuse; + } + total_light = clamp(total_light, 0.0, 1.0); + v_color *= total_light; + } +} diff --git a/src/state.c b/src/state.c new file mode 100644 index 0000000..136c65a --- /dev/null +++ b/src/state.c @@ -0,0 +1,336 @@ +#include + +#include "log.h" + +#include "state.h" +#include "passthrough.h" + +// GL State +#define init_array_pointer \ + { \ + .enabled = 0 \ + } +#define init_light_source \ + .enabled = 0, \ + .position = { \ + .x = 0, \ + .y = 0, \ + .z = 1 \ + } +static gl_state_t init_gl_state = { + .color = { + .red = 1, + .green = 1, + .blue = 1, + .alpha = 1 + }, + .normal = { + .x = 0, + .y = 0, + .z = 1 + }, + .rescale_normal = 0, + .array_pointers = { + .vertex = init_array_pointer, + .color = init_array_pointer, + .tex_coord = init_array_pointer, + .normal = init_array_pointer + }, + .matrix_stacks = { + .mode = GL_MODELVIEW + }, + .alpha_test = 0, + .texture_2d = 0, + .fog = { + .enabled = 0, + .mode = GL_LINEAR, + .color = { + .red = 0, + .green = 0, + .blue = 0, + .alpha = 0 + }, + .start = 0, + .end = 1 + }, + .lighting = { + .enabled = 0, + .light_sources = { + { + init_light_source, + .diffuse = { + .red = 1, + .green = 1, + .blue = 1, + .alpha = 1 + } + }, + { + init_light_source, + .diffuse = { + .red = 0, + .green = 0, + .blue = 0, + .alpha = 0 + } + } + }, + .ambient = { + .red = 0.2f, + .green = 0.2f, + .blue = 0.2f, + .alpha = 0.2f + } + }, + .highlight_mode = { + .enabled = 0 + } +}; +gl_state_t gl_state; +void _init_gles_compatibility_layer_state() { + gl_state = init_gl_state; + _init_gles_compatibility_matrix_stacks(); +} + +// Change Color +void glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { + gl_state.color.red = red; + gl_state.color.green = green; + gl_state.color.blue = blue; + gl_state.color.alpha = alpha; +} + +// Change Normal +void glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz) { + gl_state.normal.x = nx; + gl_state.normal.y = ny; + gl_state.normal.z = nz; +} + +// Array Pointer Storage +#define ARRAY_POINTER_FUNC(func, name) \ + void func(GLint size, GLenum type, GLsizei stride, const void *pointer) { \ + gl_state.array_pointers.name.size = size; \ + gl_state.array_pointers.name.type = type; \ + gl_state.array_pointers.name.stride = stride; \ + gl_state.array_pointers.name.pointer = pointer; \ + } +ARRAY_POINTER_FUNC(glVertexPointer, vertex) +ARRAY_POINTER_FUNC(glColorPointer, color) +ARRAY_POINTER_FUNC(glTexCoordPointer, tex_coord) +static ARRAY_POINTER_FUNC(fake_glNormalPointer, normal) +void glNormalPointer(GLenum type, GLsizei stride, const void *pointer) { + fake_glNormalPointer(0, type, stride, pointer); +} +static array_pointer_t *get_array_pointer(GLenum array) { + switch (array) { + case GL_VERTEX_ARRAY: { + return &gl_state.array_pointers.vertex; + } + case GL_COLOR_ARRAY: { + return &gl_state.array_pointers.color; + } + case GL_TEXTURE_COORD_ARRAY: { + return &gl_state.array_pointers.tex_coord; + } + case GL_NORMAL_ARRAY: { + return &gl_state.array_pointers.normal; + } + default: { + ERR("Unsupported Array Pointer: %i", array); + } + } +} +void glEnableClientState(GLenum array) { + get_array_pointer(array)->enabled = 1; +} +void glDisableClientState(GLenum array) { + get_array_pointer(array)->enabled = 0; +} + +// Enable/Disable State +GL_FUNC(glEnable, void, (GLenum cap)); +void glEnable(GLenum cap) { + switch (cap) { + case GL_ALPHA_TEST: { + gl_state.alpha_test = 1; + break; + } + case GL_TEXTURE_2D: { + gl_state.texture_2d = 1; + break; + } + case GL_RESCALE_NORMAL: { + gl_state.rescale_normal = 1; + break; + } + case GL_COLOR_MATERIAL: { + // Ignore + break; + } + case GL_FOG: { + gl_state.fog.enabled = 1; + break; + } + case GL_LIGHTING: { + gl_state.lighting.enabled = 1; + break; + } + case GL_LIGHT0: + case GL_LIGHT1: { + gl_state.lighting.light_sources[cap - GL_LIGHT0].enabled = 1; + break; + } + default: { + real_glEnable()(cap); + break; + } + } +} +GL_FUNC(glDisable, void, (GLenum cap)); +void glDisable(GLenum cap) { + switch (cap) { + case GL_ALPHA_TEST: { + gl_state.alpha_test = 0; + break; + } + case GL_TEXTURE_2D: { + gl_state.texture_2d = 0; + break; + } + case GL_RESCALE_NORMAL: { + gl_state.rescale_normal = 0; + break; + } + case GL_COLOR_MATERIAL: { + // Ignore + break; + } + case GL_FOG: { + gl_state.fog.enabled = 0; + break; + } + case GL_LIGHTING: { + gl_state.lighting.enabled = 0; + break; + } + case GL_LIGHT0: + case GL_LIGHT1: { + gl_state.lighting.light_sources[cap - GL_LIGHT0].enabled = 0; + break; + } + default: { + real_glDisable()(cap); + break; + } + } +} +void glAlphaFunc(GLenum func, GLclampf ref) { + if (func != GL_GREATER && ref != 0.1f) { + ERR("Unsupported Alpha Function"); + } +} + +// Fog +#define UNSUPPORTED_FOG() ERR("Unsupported Fog Configuration") +void glFogfv(GLenum pname, const GLfloat *params) { + if (pname == GL_FOG_COLOR) { + gl_state.fog.color.red = params[0]; + gl_state.fog.color.green = params[1]; + gl_state.fog.color.blue = params[2]; + gl_state.fog.color.alpha = params[3]; + } else { + UNSUPPORTED_FOG(); + } +} +void glFogx(GLenum pname, GLfixed param) { + if (pname == GL_FOG_MODE && (param == GL_LINEAR || param == GL_EXP)) { + gl_state.fog.mode = param; + } else { + UNSUPPORTED_FOG(); + } +} +void glFogf(GLenum pname, GLfloat param) { + switch (pname) { + case GL_FOG_DENSITY: + case GL_FOG_START: { + gl_state.fog.start = param; + break; + } + case GL_FOG_END: { + gl_state.fog.end = param; + break; + } + default: { + UNSUPPORTED_FOG(); + break; + } + } +} + +// Get Matrix Data +GL_FUNC(glGetFloatv, void, (GLenum pname, GLfloat *params)); +void glGetFloatv(GLenum pname, GLfloat *params) { + switch (pname) { + case GL_MODELVIEW_MATRIX: { + memcpy((void *) params, gl_state.matrix_stacks.model_view.stack[gl_state.matrix_stacks.model_view.i].data, MATRIX_DATA_SIZE); + break; + } + case GL_PROJECTION_MATRIX: { + memcpy((void *) params, gl_state.matrix_stacks.projection.stack[gl_state.matrix_stacks.projection.i].data, MATRIX_DATA_SIZE); + break; + } + default: { + real_glGetFloatv()(pname, params); + break; + } + } +} + +// Configure Light Sources +void glLightfv(GLenum light, GLenum pname, const GLfloat *params) { + light_source_t *light_source = &gl_state.lighting.light_sources[light - GL_LIGHT0]; + if (pname == GL_DIFFUSE) { + light_source->diffuse.red = params[0]; + light_source->diffuse.green = params[1]; + light_source->diffuse.blue = params[2]; + light_source->diffuse.alpha = params[3]; + } else if (pname == GL_POSITION) { + // Transform Position By Modelview Matrix + matrix_t model_view = gl_state.matrix_stacks.model_view.stack[gl_state.matrix_stacks.model_view.i]; + GLfloat out[4]; + for (int i = 0; i < 4; i++) { + GLfloat result = 0; + for (int j = 0; j < 4; j++) { + result += model_view.data[j][i] * params[j]; + } + out[i] = result; + } + // Store + light_source->position.x = out[0]; + light_source->position.y = out[1]; + light_source->position.z = out[2]; + } +} + +// Global Ambient Lighting +void glLightModelfv(GLenum pname, const GLfloat *params) { + if (pname == GL_LIGHT_MODEL_AMBIENT) { + gl_state.lighting.ambient.red = params[0]; + gl_state.lighting.ambient.green = params[1]; + gl_state.lighting.ambient.blue = params[2]; + gl_state.lighting.ambient.alpha = params[3]; + } +} + +// Highlight Mode +void extra_enable_highlight_mode(float red, float green, float blue, float alpha) { + gl_state.highlight_mode.enabled = 1; + gl_state.highlight_mode.color.red = red; + gl_state.highlight_mode.color.green = green; + gl_state.highlight_mode.color.blue = blue; + gl_state.highlight_mode.color.alpha = alpha; +} +void extra_disable_highlight_mode() { + gl_state.highlight_mode.enabled = 0; +} diff --git a/src/state.h b/src/state.h new file mode 100644 index 0000000..5933265 --- /dev/null +++ b/src/state.h @@ -0,0 +1,81 @@ +#include + +#include "matrix.h" + +// Matrix Data +#define MATRIX_STACK_DEPTH 256 +typedef struct { + matrix_t stack[MATRIX_STACK_DEPTH]; + unsigned int i; +} matrix_stack_t; + +// Position +typedef struct { + GLfloat x; + GLfloat y; + GLfloat z; +} position_t; + +// Color +typedef struct { + GLfloat red; + GLfloat green; + GLfloat blue; + GLfloat alpha; +} color_t; + +// Array Pointer Storage +typedef struct { + GLboolean enabled; + GLint size; + GLenum type; + GLsizei stride; + const void *pointer; +} array_pointer_t; + +// Light +typedef struct { + GLboolean enabled; + position_t position; + color_t diffuse; +} light_source_t; + +// GL State +typedef struct { + color_t color; + position_t normal; + GLboolean rescale_normal; + struct { + GLenum mode; + matrix_stack_t model_view; + matrix_stack_t projection; + matrix_stack_t texture; + } matrix_stacks; + struct { + array_pointer_t vertex; + array_pointer_t color; + array_pointer_t tex_coord; + array_pointer_t normal; + } array_pointers; + GLboolean alpha_test; + GLboolean texture_2d; + struct { + GLboolean enabled; + GLfixed mode; + color_t color; + GLfloat start; + GLfloat end; + } fog; + struct { + GLboolean enabled; + light_source_t light_sources[2]; + color_t ambient; + } lighting; + struct { + GLboolean enabled; + color_t color; + } highlight_mode; +} gl_state_t; +extern gl_state_t gl_state; +void _init_gles_compatibility_layer_state(); +void _init_gles_compatibility_matrix_stacks();