#include "../../include/mgl/graphics/texture.h" #include "../../include/mgl/mgl.h" #define STBI_NO_PSD #define STBI_NO_TGA #define STBI_NO_HDR #define STBI_NO_PIC #define STBI_NO_PNM #define STB_IMAGE_IMPLEMENTATION #include "../../external/stb_image.h" /* TODO: Check for glTexImage2D failure */ static int mgl_texture_format_to_opengl_format(mgl_texture_format format) { switch(format) { case MGL_TEXTURE_ALPHA: return GL_ALPHA8; case MGL_TEXTURE_GRAY: return GL_LUMINANCE8; case MGL_TEXTURE_GRAY_ALPHA: return GL_LUMINANCE8_ALPHA8; case MGL_TEXTURE_RGB: return GL_RGB8; case MGL_TEXTURE_RGBA: return GL_RGBA8; } return 0; } static int mgl_texture_format_to_compressed_opengl_format(mgl_texture_format format) { switch(format) { case MGL_TEXTURE_ALPHA: return GL_ALPHA8; case MGL_TEXTURE_GRAY: return GL_LUMINANCE8; case MGL_TEXTURE_GRAY_ALPHA: return GL_LUMINANCE8_ALPHA8; case MGL_TEXTURE_RGB: return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; case MGL_TEXTURE_RGBA: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; } return 0; } static int mgl_texture_format_to_source_opengl_format(mgl_texture_format format) { switch(format) { case MGL_TEXTURE_ALPHA: return GL_ALPHA; case MGL_TEXTURE_GRAY: return GL_LUMINANCE8; case MGL_TEXTURE_GRAY_ALPHA: return GL_LUMINANCE8_ALPHA8; case MGL_TEXTURE_RGB: return GL_RGB; case MGL_TEXTURE_RGBA: return GL_RGBA; } return 0; } static mgl_texture_format stbi_format_to_mgl_texture_format(int stbi_format) { switch(stbi_format) { case STBI_grey: return MGL_TEXTURE_GRAY; case STBI_grey_alpha: return MGL_TEXTURE_GRAY_ALPHA; case STBI_rgb: return MGL_TEXTURE_RGB; case STBI_rgb_alpha: return MGL_TEXTURE_RGBA; } return 0; } /* TODO: Ensure texture is power of 2 if the hardware doesn't support non power of two textures */ /* TODO: Verify if source format should always be 4 components (RGBA) because apparently if its another format then opengl will internally convert it to RGBA */ int mgl_texture_load_from_file(mgl_texture *self, const char *filepath, mgl_texture_load_options *load_options) { self->id = 0; int format; stbi_uc *image_data = stbi_load(filepath, &self->width, &self->height, &format, 0); if(!image_data) { fprintf(stderr, "Error: failed to load image %s, error: %s\n", filepath, stbi_failure_reason()); return -1; } self->format = stbi_format_to_mgl_texture_format(format); mgl_context *context = mgl_get_context(); context->gl.glGenTextures(1, &self->id); if(self->id == 0) { fprintf(stderr, "Error: failed to load image %s", filepath); stbi_image_free(image_data); return -1; } const int opengl_texture_format = load_options && load_options->compressed ? mgl_texture_format_to_compressed_opengl_format(self->format) : mgl_texture_format_to_opengl_format(self->format); context->gl.glBindTexture(GL_TEXTURE_2D, self->id); context->gl.glTexImage2D(GL_TEXTURE_2D, 0, opengl_texture_format, self->width, self->height, 0, mgl_texture_format_to_source_opengl_format(self->format), GL_UNSIGNED_BYTE, image_data); context->gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); context->gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); context->gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); context->gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); context->gl.glBindTexture(GL_TEXTURE_2D, 0); stbi_image_free(image_data); return 0; } int mgl_texture_load_from_memory(mgl_texture *self, const unsigned char *data, int width, int height, mgl_texture_format format, mgl_texture_load_options *load_options) { self->id = 0; self->width = width; self->height = height; self->format = format; mgl_context *context = mgl_get_context(); context->gl.glGenTextures(1, &self->id); if(self->id == 0) return -1; const int opengl_texture_format = load_options && load_options->compressed ? mgl_texture_format_to_compressed_opengl_format(self->format) : mgl_texture_format_to_opengl_format(self->format); context->gl.glBindTexture(GL_TEXTURE_2D, self->id); context->gl.glTexImage2D(GL_TEXTURE_2D, 0, opengl_texture_format, self->width, self->height, 0, mgl_texture_format_to_source_opengl_format(self->format), GL_UNSIGNED_BYTE, data); context->gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); context->gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); context->gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); context->gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); context->gl.glBindTexture(GL_TEXTURE_2D, 0); return 0; } void mgl_texture_unload(mgl_texture *self) { mgl_context *context = mgl_get_context(); if(self->id) { context->gl.glDeleteTextures(1, &self->id); self->id = 0; } self->width = 0; self->height = 0; self->format = 0; }