#include "AppHdr.h" #ifdef USE_TILE #include "files.h" #include "tiletex.h" #include #include #include GenericTexture::GenericTexture() : m_handle(0), m_width(0), m_height(0), m_orig_width(0), m_orig_height(0) { } GenericTexture::~GenericTexture() { unload_texture(); } void GenericTexture::unload_texture() { if (!m_handle) return; glDeleteTextures(1, (GLuint*)&m_handle); } bool GenericTexture::load_texture(const char *filename, GenericTexture::MipMapOptions mip_opt, tex_proc_func proc, bool force_power_of_two) { char acBuffer[512]; std::string tex_path = datafile_path(filename); if (tex_path.c_str()[0] == 0) { fprintf(stderr, "Couldn't find texture '%s'.\n", filename); return (false); } SDL_Surface *img = IMG_Load(tex_path.c_str()); if (!img) { fprintf(stderr, "Couldn't load texture '%s'.\n", tex_path.c_str()); return (false); } unsigned int bpp = img->format->BytesPerPixel; glPixelStorei(GL_UNPACK_ALIGNMENT, bpp); // Determine texture format unsigned char *pixels = (unsigned char*)img->pixels; int new_width; int new_height; if (force_power_of_two) { new_width = 1; while (new_width < img->w) new_width *= 2; new_height = 1; while (new_height < img->h) new_height *= 2; } else { new_width = img->w; new_height = img->h; } GLenum texture_format; if (bpp == 4) { // Even if the size is the same, still go through // SDL_GetRGBA to put the image in the right format. SDL_LockSurface(img); pixels = new unsigned char[4 * new_width * new_height]; memset(pixels, 0, 4 * new_width * new_height); int dest = 0; for (int y = 0; y < img->h; y++) { for (int x = 0; x < img->w; x++) { unsigned char *p = ((unsigned char*)img->pixels + y * img->pitch + x * bpp); unsigned int pixel = *(unsigned int*)p; SDL_GetRGBA(pixel, img->format, &pixels[dest], &pixels[dest+1], &pixels[dest+2], &pixels[dest+3]); dest += 4; } dest += 4 * (new_width - img->w); } SDL_UnlockSurface(img); texture_format = GL_RGBA; } else if (bpp == 3) { if (new_width != img->w || new_height != img->h) { SDL_LockSurface(img); pixels = new unsigned char[4 * new_width * new_height]; memset(pixels, 0, 4 * new_width * new_height); int dest = 0; for (int y = 0; y < img->h; y++) { for (int x = 0; x < img->w; x++) { unsigned char *p = ((unsigned char*)img->pixels + y * img->pitch + x * bpp); unsigned int pixel; if (SDL_BYTEORDER == SDL_BIG_ENDIAN) pixel = p[0] << 16 | p[1] << 8 | p[2]; else pixel = p[0] | p[1] << 8 | p[2]; SDL_GetRGBA(pixel, img->format, &pixels[dest], &pixels[dest+1], &pixels[dest+2], &pixels[dest+3]); dest += 4; } dest += 4 * (new_width - img->w); } SDL_UnlockSurface(img); } texture_format = GL_RGBA; } else if (bpp == 1) { // need to depalettize SDL_LockSurface(img); pixels = new unsigned char[4 * new_width * new_height]; SDL_Palette* pal = img->format->palette; ASSERT(pal); ASSERT(pal->colors); int src = 0; int dest = 0; for (int y = 0; y < img->h; y++) { int x; for (x = 0; x < img->w; x++) { unsigned int index = ((unsigned char*)img->pixels)[src++]; pixels[dest*4 ] = pal->colors[index].r; pixels[dest*4 + 1] = pal->colors[index].g; pixels[dest*4 + 2] = pal->colors[index].b; pixels[dest*4 + 3] = (index != img->format->colorkey ? 255 : 0); dest++; } while (x++ < new_width) { // Extend to the right with transparent pixels pixels[dest*4 ] = 0; pixels[dest*4 + 1] = 0; pixels[dest*4 + 2] = 0; pixels[dest*4 + 3] = 0; dest++; } } while (dest < new_width * new_height) { // Extend down with transparent pixels pixels[dest*4 ] = 0; pixels[dest*4 + 1] = 0; pixels[dest*4 + 2] = 0; pixels[dest*4 + 3] = 0; dest++; } SDL_UnlockSurface(img); bpp = 4; texture_format = GL_RGBA; } else { printf("Warning: unsupported format, bpp = %d for '%s'\n", bpp, acBuffer); return (false); } bool success = false; if (!proc || proc(pixels, new_width, new_height)) success |= load_texture(pixels, new_width, new_height, mip_opt); // If conversion has occurred, delete converted data. if (pixels != img->pixels) delete[] pixels; m_orig_width = img->w; m_orig_height = img->h; SDL_FreeSurface(img); return (success); } bool GenericTexture::load_texture(unsigned char *pixels, unsigned int new_width, unsigned int new_height, GenericTexture::MipMapOptions mip_opt) { if (!pixels || !new_width || !new_height) return (false); // Assumptions... const unsigned int bpp = 4; const GLenum texture_format = GL_RGBA; const GLenum format = GL_UNSIGNED_BYTE; m_width = new_width; m_height = new_height; glGenTextures(1, (GLuint*)&m_handle); glBindTexture(GL_TEXTURE_2D, m_handle); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); if (mip_opt == MIPMAP_CREATE) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); gluBuild2DMipmaps(GL_TEXTURE_2D, bpp, m_width, m_height, texture_format, format, pixels); } else { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, bpp, m_width, m_height, 0, texture_format, format, pixels); } return (true); } void GenericTexture::bind() const { ASSERT(m_handle); glBindTexture(GL_TEXTURE_2D, m_handle); } TilesTexture::TilesTexture() : GenericTexture(), m_tile_max(0), m_info_func(NULL) { } void TilesTexture::set_info(int tile_max, tile_info_func *info_func) { m_tile_max = tile_max; m_info_func = info_func; } #endif