#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;
}
}