/* * mogltk * Copyright (C) 1999-2004 Nicolas "Pixel" Noble * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* $Id: texture.cc,v 1.9 2004-07-15 14:21:31 pixel Exp $ */ #include #include #include #include #include "texture.h" #include "engine.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "gettext.h" #define DEBUG 1 mogltk::texture * mogltk::texture::header = 0; mogltk::texture * mogltk::texture::footer = 0; mogltk::texture * mogltk::texture::active = 0; mogltk::texture::texture(int w, int h, bool plane) throw (GeneralException) : width(w), height(h), texture_allocated(false), planar(plane), tainted(true), taintable(true) { if ((!ISPOT(w)) || (!ISPOT(h))) throw GeneralException(_("Size of the texture not a power of 2!")); if (!(surface = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, #if SDL_BYTEORDER == SDL_BIG_ENDIAN 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff #else 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 #endif ))) { throw GeneralException(_("Can't create RGB Surface")); } SDL_FillRect(surface, 0, 0); next = 0; prev = footer; footer = this; if (!header) { header = this; } if (prev) { prev->next = this; } } mogltk::texture::texture(Handle * h, bool plane) throw (GeneralException) : texture_allocated(false), planar(plane), tainted(true), taintable(true) { SDL_Surface * temp; temp = LoadNTEX(h); width = temp->w; height = temp->h; #ifdef DEBUG printm(M_INFO, "Creating texture from file: size %ix%i\n", height, width); #endif if ((!ISPOT(width)) || (!ISPOT(height))) { SDL_FreeSurface(temp); throw GeneralException(_("Size of the texture not a power of 2!")); } SDL_PixelFormat f; f.palette = 0; f.BitsPerPixel = 32; f.BytesPerPixel = 4; #if SDL_BYTEORDER == SDL_BIG_ENDIAN f.Amask = 0x000000ff; f.Bmask = 0x0000ff00; f.Gmask = 0x00ff0000; f.Rmask = 0xff000000; f.Ashift = 0; f.Bshift = 8; f.Gshift = 16; f.Rshift = 24; #else f.Rmask = 0x000000ff; f.Gmask = 0x0000ff00; f.Bmask = 0x00ff0000; f.Amask = 0xff000000; f.Rshift = 0; f.Gshift = 8; f.Bshift = 16; f.Ashift = 24; #endif f.Rloss = 0; f.Gloss = 0; f.Bloss = 0; f.Aloss = 0; if (!(surface = SDL_ConvertSurface(temp, &f, 0))) { throw GeneralException("Could not convert texture to OpenGL format"); } SDL_FreeSurface(temp); next = 0; prev = footer; footer = this; if (!header) { header = this; } if (prev) { prev->next = this; } } inline static unsigned int nextpower(unsigned int n) { unsigned int i; if (!n) return n; if (ISPOT(n)) return n; for (i = 31; i >= 0; i--) { if ((n >> i) & 1) { return 1 << (i + 1); } } } mogltk::texture::texture(int x, int y, int w, int h) : width(nextpower(w)), height(nextpower(h)), texture_allocated(true), planar(false), tainted(false), taintable(false) { glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D, tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, x, y, w, h); } mogltk::texture::~texture() { if (surface) { SDL_FreeSurface(surface); } if (texture_allocated) { glDeleteTextures(1, &tex); } if (prev) { prev->next = next; } if (next) { next->prev = prev; } if (this == footer) { footer = prev; } if (this == header) { header = next; } } Uint32 * mogltk::texture::GetPixels() { if (surface) return (Uint32 *) surface->pixels; else return 0; } SDL_Surface * mogltk::texture::GetSurface() { return surface; } SDL_PixelFormat * mogltk::texture::GetFormat() { if (surface) return surface->format; else return 0; } void mogltk::texture::Generate() { if (texture_allocated) { glDeleteTextures(1, &tex); } glGenTextures(1, &tex); #ifdef DEBUG printm(M_INFO, _("Generated texture index: %i\n"), tex); #endif glBindTexture(GL_TEXTURE_2D, tex); #if 0 if (planar) { #ifdef DEBUG printm(M_INFO, _("Generating planar texture: %i\n"), tex); #endif glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels); } else { #endif #ifdef DEBUG printm(M_INFO, _("Generating 3D texture: %i\n"), tex); #endif glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, width, height, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels); // glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels); #if 0 } #endif texture_allocated = true; tainted = false; } void mogltk::texture::Bind(bool expand) { if ((!texture_allocated) || tainted) Generate(); glEnable(GL_TEXTURE_2D); if (active == this) return; glBindTexture(GL_TEXTURE_2D, tex); if (expand) { glMatrixMode(GL_TEXTURE); glLoadIdentity(); glScaled(1 / (double) width, 1 / (double) height, 1); glMatrixMode(GL_MODELVIEW); } active = this; if (header == this) return; if (prev) { prev->next = next; } if (next) { next->prev = prev; } if (footer = this) { footer = prev; } next = header; prev = 0; header->prev = this; header = this; } GLuint mogltk::texture::GetWidth() { return width; } GLuint mogltk::texture::GetHeight() { return height; } void mogltk::texture::Unbind(void) { if (active) { glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); active = 0; } } void mogltk::texture::Taint(void) { if (taintable) tainted = true; } void mogltk::texture::Taintall(void) { if (header) header->recTaint(); } void mogltk::texture::recTaint(void) { Taint(); if (next) next->recTaint(); } #ifdef WORDS_BIGENDIAN #define NTEX_SIGNATURE 0x4e544558 #else #define NTEX_SIGNATURE 0x5845544e #endif SDL_Surface * mogltk::texture::LoadNTEX(Handle * h) throw (GeneralException) { SDL_Surface * r; char buffer[5]; Uint16 height, width; h->read(buffer, 4); buffer[4] = 0; if (*((Uint32 *) buffer) != NTEX_SIGNATURE) throw GeneralException("Texture file " + h->GetName() + " corrupted"); height = h->readU16(); width = h->readU16(); if (!(r = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, #if SDL_BYTEORDER == SDL_BIG_ENDIAN 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff #else 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 #endif ))) { throw GeneralException(_("Can't create RGB Surface for LoadNTEX")); } h->read(r->pixels, height * width * 4); return r; } void mogltk::texture::DumpBMP(const String & n) { if (surface) SDL_SaveBMP(surface, n.to_charp()); }