/* render/textures.cc This file is part of the Osirion project and is distributed under the terms of the GNU General Public License version 2 */ #include #include "render/render.h" #include "render/gl.h" #include "render/image.h" #include "render/textures.h" #include "render/tgafile.h" #include "render/pngfile.h" #include "render/jpgfile.h" #include "render/state.h" #include "sys/sys.h" #include "core/application.h" namespace render { std::map Textures::registry; GLuint Textures::textures[MAXTEXTURES]; math::Vector2f Textures::texture_size[MAXTEXTURES]; void material_loader_func(model::Material *material) { Textures::material_loader(material); } void Textures::init() { con_print << "^BLoading textures..." << std::endl; if (registry.size()) { clear(); } else { memset(textures, 0, sizeof(textures)); } // "no texture" bitmap load("textures/common/notex"); // gui font if (!load("bitmaps/fonts/gui", false)) { con_error << "Essential file bitmaps/fonts/gui missing" << std::endl; core::application()->shutdown(); } // crosshairs load("bitmaps/pointers/pointer"); load("bitmaps/pointers/aim"); load("bitmaps/pointers/center"); load("bitmaps/pointers/control"); load("bitmaps/pointers/target"); model::Material::set_loader_func(Textures::material_loader); } void Textures::shutdown() { model::Material::set_loader_func(0); clear(); } void Textures::list() { for (iterator it = registry.begin(); it != registry.end(); it++) { con_print << " " << (*it).first << " " << (*it).second << std::endl; } con_print << registry.size() << " loaded textures" << std::endl; } void Textures::clear() { for (size_t i = 0; i < MAXTEXTURES; i++) { if (textures[i]) { glDeleteTextures(1, &textures[i]); } texture_size[i].clear(); } registry.clear(); memset(textures, 0, sizeof(textures)); } void Textures::unload(const std::string &name) { iterator it = registry.find(name); if (it != registry.end()) { con_debug << " unloading " << (*it).first << std::endl; size_t id = (*it).second; if (textures[id]) { glDeleteTextures(1, &textures[id]); textures[id] = 0; texture_size[id].clear(); } registry.erase(it); } } void Textures::unload(const size_t id) { // find in map for (iterator it = registry.begin(); it != registry.end(); it++) { if ((*it).second == id) { con_debug << " unloading " << (*it).first << std::endl; size_t id = (*it).second; if (textures[id]) { glDeleteTextures(1, &textures[id]); textures[id] = 0; } registry.erase(it); break; } } } size_t Textures::load(const char *name, const bool filter) { if (name) return load(std::string(name), filter); else return 0; } size_t Textures::load(const std::string &name, const bool filter) { // check if it is already loaded iterator it = registry.find(name); if (it != registry.end()) return (*it).second; // find first available texture size_t id = 0; while ((id < MAXTEXTURES) && (textures[id])) { id++; } if (id == MAXTEXTURES) { con_error << "Texture limit " << MAXTEXTURES << " exceeded!" << std::endl; registry[name] = 0; return 0; } std::string filename; Image *image = 0; if (!image) { // try the png version filename.assign(name); filename.append(".png"); image = PNG::load(filename.c_str()); } if (!image) { // try the tga version filename.assign(name); filename.append(".tga"); image = TGA::load(filename.c_str()); } if (!image) { // try the jpg version filename.assign(name); filename.append(".jpg"); image = JPG::load(filename.c_str()); } if (!image) { // add to the registry with id 0 (texture not found) con_warn << "Could not open texture " << name << std::endl; registry[name] = 0; return 0; } glGenTextures(1, &textures[id]); glBindTexture(GL_TEXTURE_2D, textures[id]); int texture_format; int texture_internalformat; if (filter) { // scaling functions glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 4 levels of mipmaps glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4); if (r_mipmap->value()) { // hardware generated mipmaps (requires OpenGL 1.4) glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); } // enable texture wrapping glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } else { // scaling functions glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // no mipmaps, base level only glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); } //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); if (image->channels() == 4) { texture_format = GL_RGBA; texture_internalformat = GL_RGBA8; } else { texture_format = GL_RGB; texture_internalformat = GL_RGB8; } if (filter && (r_mipmap->value() <= 0)) { gluBuild2DMipmaps(GL_TEXTURE_2D, texture_internalformat, image->width(), image->height(), texture_format, GL_UNSIGNED_BYTE, image->data()); } else { glTexImage2D(GL_TEXTURE_2D, 0, texture_internalformat, image->width(), image->height(), 0, texture_format, GL_UNSIGNED_BYTE, image->data()); } // add to the registry registry[name] = id; texture_size[id].assign((float) image->width(), (float) image->height()); // delete image data delete image; return id; } size_t Textures::find(const std::string &name) { size_t id = 0; iterator it = registry.find(name); if (it != registry.end()) id = (*it).second; return id; } size_t Textures::bind(const char *name, const bool filter) { if (name) return bind(std::string(name), filter); else return 0; } size_t Textures::bind(const std::string &name, const bool filter) { size_t id = 0; iterator it = registry.find(name); if (it != registry.end()) { id = (*it).second; glBindTexture(GL_TEXTURE_2D, textures[id]); } else { id = load(name, filter); } return id; } size_t Textures::bind(const size_t texture, const bool filter) { size_t id = texture; if (!textures[id]) id = 0; glBindTexture(GL_TEXTURE_2D, textures[id]); return id; } void Textures::material_loader(model::Material *material) { if ((material->flags() & model::Material::Texture) && (material->texture().size())) { size_t id = load(material->texture()); material->set_texture_id(id); material->set_size(texture_size[id]); } } }