
/* gl_texture.cpp - simple OpenGL texture class */

#include "gl_texture.hpp"

#define STB_IMAGE_IMPLEMENTATION
#include "../stb/stb_image.h"
#include "sRGB_math.h"

static void premultiplyImageByAlpha(int w, int h, stbi_uc *image)
{
    const stbi_uc *image_end = image + 4*w*h;
    stbi_uc *rgba = image;
    while (rgba != image_end) {
        unsigned int alpha = rgba[3];
        unsigned char pm_r = (rgba[0] * alpha + 0xff) >> 8;
        unsigned char pm_g = (rgba[1] * alpha + 0xff) >> 8;
        unsigned char pm_b = (rgba[2] * alpha + 0xff) >> 8;
        rgba[0] = pm_r;
        rgba[1] = pm_g;
        rgba[2] = pm_b;
        rgba += 4;
    }
}

static void premultiplyImageByAlphaSRGB(int w, int h, stbi_uc *image)
{
    const stbi_uc *image_end = image + 4*w*h;
    stbi_uc *rgba = image;
    while (rgba != image_end) {
        const float scale = 1/255.0f;
        unsigned int alpha = rgba[3];
        const float a = scale*alpha;
        float r = convertSRGBColorComponentToLinearf(scale*rgba[0]);
        float g = convertSRGBColorComponentToLinearf(scale*rgba[1]);
        float b = convertSRGBColorComponentToLinearf(scale*rgba[2]);
        r *= a;
        g *= a;
        b *= a;
        rgba[0] = convertLinearColorComponentToSRGBub(r);
        rgba[1] = convertLinearColorComponentToSRGBub(g);
        rgba[2] = convertLinearColorComponentToSRGBub(b);
        rgba += 4;
    }
}

bool GLTexture2D::loadImageFromFile(const char *filename, bool sRGB_encoded)
{
    int w;
    int h;
    int components;

    stbi_set_flip_vertically_on_load(true);
    stbi_uc *image = stbi_load(filename, &w, &h, &components, 0);
    if (image) {
        assert(w >= 1);
        assert(h >= 1);
        GLenum gl_format = GL_NONE;
        GLenum cpu_format = GL_NONE;
        switch (components) {
        case 1:
            if (sRGB_encoded) {
                gl_format = GL_SLUMINANCE8;
            } else {
                gl_format = GL_LUMINANCE8;
            }
            cpu_format = GL_LUMINANCE;
            break;
        case 2:
            if (sRGB_encoded) {
                gl_format = GL_SLUMINANCE8_ALPHA8;
            } else {
                gl_format = GL_LUMINANCE8_ALPHA8;
            }
            cpu_format = GL_LUMINANCE_ALPHA;
            break;
        case 3:
            if (sRGB_encoded) {
                gl_format = GL_SRGB8;
            } else {
                gl_format = GL_RGB8;
            }
            cpu_format = GL_RGB;
            break;
        case 4:
            cpu_format = GL_RGBA;
            if (sRGB_encoded) {
                gl_format = GL_SRGB8_ALPHA8;
                premultiplyImageByAlphaSRGB(w, h, image);
            } else {
                gl_format = GL_RGBA8;
                premultiplyImageByAlpha(w, h, image);
            }
            break;
        default:
            assert(!"unknown components");
        }
        if (gl_format != GL_NONE) {
            bind();
            glTexImage2D(target, 0, gl_format, w, h, 0, cpu_format, GL_UNSIGNED_BYTE, image);
            width = w;
            height = h;
            depth = 1;
            internal_format = gl_format;
            return true;
        }
    }
    printf("stbi_load: could not load '%s' image\n", filename);
    return false;
}