diff --git a/src/dusk/assert/assert.c b/src/dusk/assert/assert.c index b7a3ed8..73973d3 100644 --- a/src/dusk/assert/assert.c +++ b/src/dusk/assert/assert.c @@ -7,6 +7,7 @@ #include "assert.h" #include "log/log.h" +#include "util/string.h" #ifndef DUSK_ASSERTIONS_FAKED #ifdef DUSK_TEST_ASSERT @@ -98,4 +99,14 @@ ) { assertUnreachableImpl(file, line, message); } + + void assertStringEqualImpl( + const char *file, + const int32_t line, + const char *a, + const char *b, + const char *message + ) { + assertTrueImpl(file, line, stringCompare(a, b) == 0, message); + } #endif \ No newline at end of file diff --git a/src/dusk/assert/assert.h b/src/dusk/assert/assert.h index c50dd9c..2ea2ed5 100644 --- a/src/dusk/assert/assert.h +++ b/src/dusk/assert/assert.h @@ -104,6 +104,23 @@ const char *message ); + /** + * Asserts two strings to be equal. + * + * @param file File that the assertion is being made from. + * @param line Line that the assertion is being made from. + * @param a First string to compare. + * @param b Second string to compare. + * @param message Message to throw against assertion failure. + */ + void assertStringEqualImpl( + const char *file, + const int32_t line, + const char *a, + const char *b, + const char *message + ); + /** * Asserts a given value to be true. * @@ -178,6 +195,16 @@ #define assertStrLenMin(str, len, message) \ assertTrue(strlen(str) >= len, message) + /** + * Asserts two strings to be equal. + * + * @param a First string to compare. + * @param b Second string to compare. + * @param message Message to throw against assertion failure. + */ + #define assertStringEqual(a, b, message) \ + assertStringEqualImpl(__FILE__, __LINE__, a, b, message) + #else // If assertions are faked, we define the macros to do nothing. #define assertTrue(x, message) ((void)0) diff --git a/src/dusk/display/display.c b/src/dusk/display/display.c index b9009ce..875f2c0 100644 --- a/src/dusk/display/display.c +++ b/src/dusk/display/display.c @@ -22,12 +22,9 @@ display_t DISPLAY = { 0 }; -texture_t TEXTURE; - -uint8_t indices[2 * 2] = { - 0, 1, - 2, 3 -}; +texture_t PALETTE_TEXTURE; +texture_t UNCOMPRESSED_TEXTURE; +texture_t COMPRESSED_TEXTURE; errorret_t displayInit(void) { memoryZero(&DISPLAY, sizeof(DISPLAY)); @@ -48,19 +45,34 @@ errorret_t displayInit(void) { PALETTES[0].colors[2] = COLOR_BLUE; PALETTES[0].colors[3] = COLOR_WHITE; PALETTES[0].count = 4; - + errorChain(textureInit( - &TEXTURE, + &PALETTE_TEXTURE, 2, 2, TEXTURE_FORMAT_PALETTE, (texturedata_t){ .paletted = { - .indices = indices, + .indices = (uint8_t[]){ + 0, 1, + 2, 3 + }, .palette = &PALETTES[0] } } )); + errorChain(textureInit( + &UNCOMPRESSED_TEXTURE, + 2, 2, + TEXTURE_FORMAT_RGBA, + (texturedata_t){ + .rgbaColors = (color_t[]){ + COLOR_RED, COLOR_GREEN, + COLOR_BLUE, COLOR_WHITE + } + } + )); + errorOk(); } @@ -100,7 +112,7 @@ errorret_t displayUpdate(void) { errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_PROJECTION, proj)); errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_VIEW, view)); errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_MODEL, model)); - errorChain(shaderSetTexture(&SHADER_UNLIT, SHADER_UNLIT_TEXTURE, &TEXTURE)); + errorChain(shaderSetTexture(&SHADER_UNLIT, SHADER_UNLIT_TEXTURE, &UNCOMPRESSED_TEXTURE)); errorChain(spriteBatchPush( 0.0f, 0.0f, 1.0f, 1.0f, diff --git a/src/dusk/display/texture/texture.h b/src/dusk/display/texture/texture.h index cb6f202..94d6a69 100644 --- a/src/dusk/display/texture/texture.h +++ b/src/dusk/display/texture/texture.h @@ -26,6 +26,7 @@ typedef union texturedata_u { palette_t *palette; } paletted; color_t *rgbaColors; + uint8_t *compressedData; } texturedata_t; /** diff --git a/src/duskgl/display/shader/shadergl.c b/src/duskgl/display/shader/shadergl.c index 8d0691f..86f4d61 100644 --- a/src/duskgl/display/shader/shadergl.c +++ b/src/duskgl/display/shader/shadergl.c @@ -28,6 +28,11 @@ errorret_t shaderInitGL(shadergl_t *shader, const shaderdefinitiongl_t *def) { SHADER_LEGACY.boundShader = NULL; errorOk(); #else + assertNotNull(def->vert, "Vertex shader source cannot be null"); + assertNotNull(def->frag, "Fragment shader source cannot be null"); + + shader->setTexture = def->setTexture; + // Create vertex shader shader->vertexShaderId = glCreateShader(GL_VERTEX_SHADER); errorret_t err = errorGLCheck(); @@ -212,6 +217,12 @@ errorret_t shaderSetTextureGL( assertStrLenMin(name, 1, "Uniform name cannot be empty"); #ifdef DUSK_OPENGL_LEGACY + assertStringEqual( + name, + SHADER_UNLIT_TEXTURE, + "Only one texture supported in legacy opengl." + ) + if(texture == NULL) { glDisable(GL_TEXTURE_2D); errorChain(errorGLCheck()); @@ -226,44 +237,10 @@ errorret_t shaderSetTextureGL( errorChain(errorGLCheck()); #else - if(texture == NULL) { - glActiveTexture(GL_TEXTURE0); - errorChain(errorGLCheck()); - glBindTexture(GL_TEXTURE_2D, 0); - errorChain(errorGLCheck()); - errorOk(); + if(shader->setTexture == NULL) { + assertUnreachable("Shader does not support setting textures."); } - - GLint location; - errorChain(shaderParamGetLocationGL(shader, name, &location)); - - glActiveTexture(GL_TEXTURE0); - errorChain(errorGLCheck()); - glBindTexture(GL_TEXTURE_2D, texture->id); - errorChain(errorGLCheck()); - glUniform1i(location, 0); - errorChain(errorGLCheck()); - - if(texture->format == TEXTURE_FORMAT_PALETTE) { - shaderParamGetLocationGL(shader, "u_ColorCount", &location); - glUniform1i(location, texture->palette->count); - errorChain(errorGLCheck()); - - shaderParamGetLocationGL(shader, "u_Colors", &location); - GLuint paletteData[texture->palette->count]; - for(size_t i = 0; i < texture->palette->count; i++) { - color_t color = texture->palette->colors[i]; - paletteData[i] = ( - ((uint32_t)color.r << 24) | - ((uint32_t)color.g << 16) | - ((uint32_t)color.b << 8) | - ((uint32_t)color.a << 0) - ); - } - glUniform1uiv(location, texture->palette->count, paletteData); - errorChain(errorGLCheck()); - } - + errorChain(shader->setTexture(shader, name, texture)); #endif errorOk(); diff --git a/src/duskgl/display/shader/shadergl.h b/src/duskgl/display/shader/shadergl.h index a3d2cea..470eb44 100644 --- a/src/duskgl/display/shader/shadergl.h +++ b/src/duskgl/display/shader/shadergl.h @@ -9,28 +9,35 @@ #include "error/errorgl.h" #include "display/texture/texture.h" -typedef struct { +typedef struct shadergl_s shadergl_t; + +typedef errorret_t (*shadersettexturefn_t)( + shadergl_t *, + const char_t *, + texture_t * +); + +typedef struct shadergl_s { #ifdef DUSK_OPENGL_LEGACY - void *nothing; + mat4 view; + mat4 proj; + mat4 model; #else GLuint shaderProgramId; GLuint vertexShaderId; GLuint fragmentShaderId; - #endif - - #if DUSK_OPENGL_LEGACY - mat4 view; - mat4 proj; - mat4 model; + shadersettexturefn_t setTexture; #endif } shadergl_t; + typedef struct { #ifdef DUSK_OPENGL_LEGACY void *nothing; #else const char_t *vert; const char_t *frag; + shadersettexturefn_t setTexture; #endif } shaderdefinitiongl_t; diff --git a/src/duskgl/display/shader/shaderunlitgl.c b/src/duskgl/display/shader/shaderunlitgl.c index 3cca146..467ed9d 100644 --- a/src/duskgl/display/shader/shaderunlitgl.c +++ b/src/duskgl/display/shader/shaderunlitgl.c @@ -6,84 +6,135 @@ */ #include "display/shader/shaderunlit.h" +#include "assert/assertgl.h" #ifdef DUSK_OPENGL_LEGACY shaderdefinition_t SHADER_UNLIT_DEFINITION = { 0 }; -#elif defined(DUSK_OPENGL_ES) - shaderdefinition_t SHADER_UNLIT_DEFINITION = { - .vert = - "#version 300 es\n" - "layout(location = 0) in vec3 a_Pos;\n" - "layout(location = 1) in vec2 a_TexCoord;\n" - "layout(location = 2) in vec4 a_Color;\n" - "uniform mat4 u_Proj;\n" - "uniform mat4 u_View;\n" - "uniform mat4 u_Model;\n" - "out vec4 v_Color;\n" - "out vec2 v_TexCoord;\n" - "void main() {\n" - " gl_Position = u_Proj * u_View * u_Model * vec4(a_Pos, 1.0);\n" - " v_Color = a_Color;\n" - " v_TexCoord = a_TexCoord;\n" - "}\n", - - .frag = - "#version 300 es\n" - "precision mediump float;\n" - "uniform sampler2D u_Texture;\n" - "uniform uint u_Colors[256];\n" - "uniform int u_ColorCount;\n" - "in vec4 v_Color;\n" - "in vec2 v_TexCoord;\n" - "out vec4 FragColor;\n" - "void main() {\n" - " vec4 texColor = texture(u_Texture, v_TexCoord);\n" - " uint index = uint(clamp(texColor.r * 255.0 + 0.5, 0.0, 255.0));\n" - " uint palColor = u_Colors[index];\n" - " float r = float((palColor >> 24) & 0xFFu) / 255.0;\n" - " float g = float((palColor >> 16) & 0xFFu) / 255.0;\n" - " float b = float((palColor >> 8) & 0xFFu) / 255.0;\n" - " float a = float((palColor >> 0) & 0xFFu) / 255.0;\n" - " vec4 paletteColor = vec4(r, g, b, a);\n" - " FragColor = paletteColor;\n" - "}\n" - }; #else + errorret_t shaderUnlitSetTextureGL( + shadergl_t *shader, + const char_t *name, + texture_t *texture + ) { + assertNotNull(shader, "Shader cannot be null"); + assertStrLenMin(name, 1, "Uniform name cannot be empty"); + assertStringEqual( + name, + SHADER_UNLIT_TEXTURE, + "Only one texture supported in unlit shader." + ); + + GLint locTexture, locType, locColorCount, locColors; + + errorChain(shaderParamGetLocationGL(shader, "u_TextureType", &locType)); + + // NULL textures + if(texture == NULL) { + glUniform1i(locType, 0); + errorChain(errorGLCheck()); + errorOk(); + } + + // Set texture. + glActiveTexture(GL_TEXTURE0); + errorChain(errorGLCheck()); + glBindTexture(GL_TEXTURE_2D, texture->id); + errorChain(errorGLCheck()); + + errorChain(shaderParamGetLocationGL(shader, name, &locTexture)); + glUniform1i(locTexture, 0); + errorChain(errorGLCheck()); + + // Set texture type + if(texture->format == TEXTURE_FORMAT_PALETTE) { + shaderParamGetLocationGL(shader, "u_ColorCount", &locColorCount); + glUniform1i(locColorCount, texture->palette->count); + errorChain(errorGLCheck()); + + shaderParamGetLocationGL(shader, "u_Colors", &locColors); + GLuint paletteData[texture->palette->count]; + for(size_t i = 0; i < texture->palette->count; i++) { + color_t color = texture->palette->colors[i]; + paletteData[i] = ( + ((uint32_t)color.r << 24) | + ((uint32_t)color.g << 16) | + ((uint32_t)color.b << 8) | + ((uint32_t)color.a << 0) + ); + } + glUniform1uiv(locColors, texture->palette->count, paletteData); + errorChain(errorGLCheck()); + } else { + glUniform1i(locType, 1); + errorChain(errorGLCheck()); + } + + errorOk(); + } + shaderdefinition_t SHADER_UNLIT_DEFINITION = { .vert = - "#version 330 core\n" - "layout(location = 0) in vec3 a_Pos;\n" - "layout(location = 1) in vec2 a_TexCoord;\n" - "layout(location = 2) in vec4 a_Color;\n" - "uniform mat4 u_Proj;\n" - "uniform mat4 u_View;\n" - "uniform mat4 u_Model;\n" - "out vec4 v_Color;\n" - "out vec2 v_TexCoord;\n" - "void main() {\n" - " gl_Position = u_Proj * u_View * u_Model * vec4(a_Pos, 1.0);\n" - " v_Color = a_Color;\n" - " v_TexCoord = a_TexCoord;\n" - "}\n", + #ifdef DUSK_OPENGL_ES + #else + "#version 330 core\n" + // Attributes + "layout(location = 0) in vec3 a_Pos;\n" + "layout(location = 1) in vec2 a_TexCoord;\n" + "layout(location = 2) in vec4 a_Color;\n" + // Uniforms + "uniform mat4 u_Proj;\n" + "uniform mat4 u_View;\n" + "uniform mat4 u_Model;\n" + // Vertex shader outputs + "out vec4 v_Color;\n" + "out vec2 v_TexCoord;\n" + "void main() {\n" + " gl_Position = u_Proj * u_View * u_Model * vec4(a_Pos, 1.0);\n" + " v_Color = a_Color;\n" + " v_TexCoord = a_TexCoord;\n" + "}\n", + #endif .frag = - "#version 330 core\n" - "uniform sampler2D u_Texture;\n" - "uniform uint u_Colors[256];\n" - "uniform int u_ColorCount;\n" - "in vec4 v_Color;\n" - "in vec2 v_TexCoord;\n" - "out vec4 FragColor;\n" - "void main() {\n" - " vec4 texColor = texture(u_Texture, v_TexCoord);\n" - " uint index = uint(floor(texColor.r * 255.0));\n" - " uint palColor = u_Colors[index];\n" - " float r = float((palColor >> 24) & 0xFFu) / 255.0;\n" - " float g = float((palColor >> 16) & 0xFFu) / 255.0;\n" - " float b = float((palColor >> 8) & 0xFFu) / 255.0;\n" - " float a = float((palColor >> 0) & 0xFFu) / 255.0;\n" - " vec4 paletteColor = vec4(r, g, b, a);\n" - " FragColor = paletteColor;\n" - "}\n" + #ifdef DUSK_OPENGL_ES + + #else + "#version 330 core\n" + // Uniforms + "uniform sampler2D u_Texture;\n" + "uniform int u_TextureType;\n" + "uniform uint u_Colors[256];\n"// For paletted textures. + "uniform int u_ColorCount;\n" + // Fragment shader inputs + "in vec4 v_Color;\n" + "in vec2 v_TexCoord;\n" + // Fragment shader output + "out vec4 FragColor;\n" + "void main() {\n" + " if(u_TextureType == 0) {\n"// No texture + " FragColor = v_Color;\n" + " return;\n" + " }\n" + " if(u_TextureType == 1) {\n"// Regular texture + " FragColor = texture(u_Texture, v_TexCoord) * v_Color;\n" + " return;\n" + " }\n" + " if(u_TextureType == 2) {\n"// Paletted texture + " vec4 texColor = texture(u_Texture, v_TexCoord);\n" + " uint index = uint(floor(texColor.r * 255.0));\n" + " uint palColor = u_Colors[index];\n" + " float r = float((palColor >> 24) & 0xFFu) / 255.0;\n" + " float g = float((palColor >> 16) & 0xFFu) / 255.0;\n" + " float b = float((palColor >> 8) & 0xFFu) / 255.0;\n" + " float a = float((palColor >> 0) & 0xFFu) / 255.0;\n" + " vec4 paletteColor = vec4(r, g, b, a);\n" + " FragColor = paletteColor;\n" + " return;\n" + " }\n" + " FragColor = v_Color;\n"// Unknown texture type? + "}\n", + #endif + + .setTexture = shaderUnlitSetTextureGL }; #endif \ No newline at end of file diff --git a/src/duskgl/display/texture/texturegl.h b/src/duskgl/display/texture/texturegl.h index 427b744..21ec2cd 100644 --- a/src/duskgl/display/texture/texturegl.h +++ b/src/duskgl/display/texture/texturegl.h @@ -13,6 +13,7 @@ typedef union texturedata_u texturedata_t; typedef enum { TEXTURE_FORMAT_RGBA = GL_RGBA, TEXTURE_FORMAT_PALETTE = GL_COLOR_INDEX8_EXT, + // TEXTURE_FORMAT_DXT5 = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT } textureformatgl_t; typedef struct {