aboutsummaryrefslogtreecommitdiff
#include "../util/util.h"
#include "renderer.h"
#include "texture.h"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>

#define MAX_HASH_TEXTURES 1024
static Texture *texture_hash_table[MAX_HASH_TEXTURES];

Texture *texture_new(const char *path)
{
    return texture_with_name_new(path, path);
}

Texture *texture_with_name_new(const char *name, const char *path)
{
    if(strlen(name) > MAX_PATH_LENGTH)
        Util_FatalError("File following texture name is too long: %s", name);

    Texture *tex;
    tex = texture_get(name);

    if(tex != NULL)
        return tex;

    if(render.num_textures >= MAX_TEXTURES)
        return NULL;

    /** Alloc the new texture **/
    tex = malloc( sizeof(Texture) );
    memset(tex, 0, sizeof(Texture) );
    tex->number_of_rows = 1;
    tex->type = GL_TEXTURE_2D;

    SDL_Surface *data = IMG_Load(path);

    if(data == NULL)
        Util_FatalError("Texture %s could not be found!\n", path);

    glGenTextures(1, &tex->tex_id);
    glBindTexture(GL_TEXTURE_2D, tex->tex_id);

    SDL_LockSurface(data);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, data->w, data->h, GL_FALSE, GL_RGBA, GL_UNSIGNED_BYTE, data->pixels);
    SDL_UnlockSurface(data);
    SDL_FreeSurface(data);

    /** Configure the texture **/
    glGenerateMipmap(GL_TEXTURE_2D);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -2.4);

    glBindTexture(GL_TEXTURE_2D, 0);

    /** Register inside the resource manager **/
    unsigned int hash_ = Util_Hash( name );
    hash_ %= MAX_HASH_TEXTURES;

    render.textures[render.num_textures] = tex;
    render.num_textures += 1;

    strcpy(tex->_name, name);
    tex->_hash_next = texture_hash_table[hash_];
    texture_hash_table[hash_] = tex;

    tex->hash_ = hash_;

    /** Return the final result **/
    return tex;
}

Texture *texture_cubemap_new(const char *paths[6])
{
    return texture_cubemap_with_name_new(paths[0], paths);
}

Texture *texture_cubemap_with_name_new(const char *name, const char *paths[6])
{
    Texture *tex;
    tex = texture_get(name);

    if(tex != NULL)
    {
        puts("s");
        return tex;
    }

    if(render.num_textures >= MAX_TEXTURES)
        return NULL;

    /** Alloc the new texture **/
    tex = malloc( sizeof(Texture) );
    memset(tex, 0, sizeof(Texture) );
    tex->number_of_rows = 1;
    tex->type = GL_TEXTURE_CUBE_MAP;

    glGenTextures(1, &tex->tex_id);
    glBindTexture(GL_TEXTURE_CUBE_MAP, tex->tex_id);

    SDL_Surface *data;

    int i;
    for(i = 0; i < 6; i++)
    {
        data = IMG_Load(paths[i]);

        if(data == NULL)
            Util_FatalError("Texture %s could not be found!\n", paths[i]);

        SDL_LockSurface(data);
        /** All the textures sides are linearly stored so we just add "i" **/
        glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA,
                     data->w, data->h, GL_FALSE, GL_RGBA, GL_UNSIGNED_BYTE, data->pixels);

        SDL_UnlockSurface(data);
        SDL_FreeSurface(data);
    }

    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    glBindTexture(GL_TEXTURE_CUBE_MAP, 0);

    /** Register inside the resource manager **/
    unsigned int hash_ = Util_Hash( name );
    hash_ %= MAX_HASH_TEXTURES;

    render.textures[render.num_textures] = tex;
    render.num_textures += 1;

    strcpy(tex->_name, name);
    tex->_hash_next = texture_hash_table[hash_];
    texture_hash_table[hash_] = tex;

    tex->hash_ = hash_;

    /** Return the final result **/
    return tex;
}

Texture *texture_get(const char *name)
{
    Texture *tex;

    unsigned int hash_ = Util_Hash( name );
    hash_ %= MAX_HASH_TEXTURES;

    if(texture_hash_table[hash_] != NULL)
    {
        for(tex = texture_hash_table[hash_]; tex; tex = tex->_hash_next)
        {
            if( tex->hash_ == hash_ )
                return tex;
        }
    }
    return NULL;
}

void texture_bind(Texture *tex, int slot)
{
    glActiveTexture(GL_TEXTURE0 + slot);

    if(tex->type != GL_TEXTURE_2D && tex->type != GL_TEXTURE_CUBE_MAP)
        return;


    glBindTexture(tex->type, tex->tex_id);
}

void texture_purge(Texture *tex)
{
    /** Purge the opengl data **/
    if(tex->tex_id != 0)
    {
        glDeleteTextures(1, &tex->tex_id);
        tex->tex_id = 0;
    }
}