/*
 * DMLib
 * -- Bitmap image conversion and loading
 * Programmed and designed by Matti 'ccr' Hamalainen
 * (C) Copyright 2012 Tecnic Software productions (TNSP)
 */
#include "dmimage.h"


#define STBI_FAILURE_USERMSG 1
#define STBI_NO_STDIO 1
#define STBI_NO_HDR 1
#include "stb_image.c"


SDL_Surface *dmCreateRGBSurfaceFrom(void *data, const int width, const int height, const int depth, const int pitch, const int rmask, const int gmask, const int bmask, const int amask)
{
    // Create source surface from given data
    SDL_Surface *tmp = SDL_CreateRGBSurfaceFrom(data, width, height, depth, pitch, bmask, gmask, rmask, amask);

    // Result surface component orders as masks
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
    Uint32
        Xrmask = 0xff000000,
        Xgmask = 0x00ff0000,
        Xbmask = 0x0000ff00,
        Xamask = 0x000000ff;
#else
    Uint32
        Xrmask = 0x000000ff,
        Xgmask = 0x0000ff00,
        Xbmask = 0x00ff0000,
        Xamask = 0xff000000;
#endif

    // Create result conversion surface
    SDL_Surface
        *result = NULL,
        *pixtmp = SDL_CreateRGBSurface(
        SDL_SWSURFACE | SDL_SRCALPHA, 16, 16, 32, Xrmask, Xgmask, Xbmask, Xamask);

    if (tmp != NULL && pixtmp != NULL)
    {
        // Convert surface
        result = SDL_ConvertSurface(tmp, pixtmp->format, SDL_SWSURFACE | SDL_SRCALPHA);
        SDL_FreeSurface(tmp);
    }
    if (pixtmp != NULL)
        SDL_FreeSurface(pixtmp);
    
    return result;
}


SDL_Surface *dmCreatePaletteSurfaceFrom(void *data, const int width, const int height, const int pitch)
{
    int yc;
    Uint8 *dst, *src;
    SDL_Surface *result;
    result = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 8, 0,0,0,0);
    if (result == NULL)
        return NULL;
    
    dst = result->pixels;
    src = data;
    for (yc = 0; yc < height; yc++)
    {
        memcpy(dst, src, width * sizeof(Uint8));
        dst += result->pitch;
        src += pitch;
    }

    return result;
}



static int dmSTBIread(void *user, char *data, int size)
{
    return dmfread(data, 1, size, (DMResource *) user);
}


static void dmSTBIskip(void *user, unsigned int n)
{
    dmfseek((DMResource *) user, n, SEEK_CUR);
}


static int dmSTBIeof(void *user)
{
    return dmfeof((DMResource *) user);
}


static const stbi_io_callbacks dmSTBICallbacks =
{
    dmSTBIread,
    dmSTBIskip,
    dmSTBIeof,
};


SDL_Surface *dmLoadImage(DMResource *file)
{
    Uint32 rmask, gmask, bmask, amask;
    SDL_Surface *result = NULL;
    int width, height, comp;
    Uint8 *data;

    data = stbi_load_from_callbacks(&dmSTBICallbacks, file, &width, &height, &comp, 0);

    if (data == NULL)
    {
        dmError("Error decoding image resource %p '%s' [%d, %d, %d]: %s\n",
            file, file->filename, width, height, comp, stbi_failure_reason());
        return NULL;
    }


    switch (comp)
    {
        case 4:
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
            rmask = 0xff000000;
            gmask = 0x00ff0000;
            bmask = 0x0000ff00;
            amask = 0x000000ff;
#else
            rmask = 0x000000ff;
            gmask = 0x0000ff00;
            bmask = 0x00ff0000;
            amask = 0xff000000;
#endif
            result = dmCreateRGBSurfaceFrom(data, width, height, comp * 8,
                width * comp, rmask, gmask, bmask, amask);
            break;

        case 3:
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
            rmask = 0x00ff0000;
            gmask = 0x0000ff00;
            bmask = 0x000000ff;
            amask = 0x00000000;
#else
            rmask = 0x000000ff;
            gmask = 0x0000ff00;
            bmask = 0x00ff0000;
            amask = 0x00000000;
#endif
            result = dmCreateRGBSurfaceFrom(data, width, height, comp * 8,
                width * comp, rmask, gmask, bmask, amask);
            break;

        case 1:
            result = dmCreatePaletteSurfaceFrom(data, width, height, width * comp);
            break;
    }
    
    stbi_image_free(data);

    if (result == NULL)
    {
        dmError("Format conversion failed for image resource %p '%s' [%d, %d, %d].\n",
            file, file->filename, width, height, comp);
    }

    return result;
}
