X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2F3dengfx%2Fsrc%2F3dengfx%2Ftexman.cpp;fp=src%2F3dengfx%2Fsrc%2F3dengfx%2Ftexman.cpp;h=66ef695ce31dbc83eb6ffe7e505bf0317b92e0db;hb=6e23259dbabaeb1711a2a5ca25b9cb421f693759;hp=0000000000000000000000000000000000000000;hpb=fe068fa879814784c45e0cb2e65dac489e8f5594;p=summerhack diff --git a/src/3dengfx/src/3dengfx/texman.cpp b/src/3dengfx/src/3dengfx/texman.cpp new file mode 100644 index 0000000..66ef695 --- /dev/null +++ b/src/3dengfx/src/3dengfx/texman.cpp @@ -0,0 +1,360 @@ +/* +This file is part of 3dengfx, realtime visualization system. +Copyright (C) 2004, 2005, 2006 John Tsiombikas + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +/* texture manager + * + * Author: John Tsiombikas 2004 + */ + +#include "3dengfx_config.h" + +#include +#include +#include "texman.hpp" +#include "common/hashtable.hpp" +#include "gfx/image.h" +#include "gfx/color.hpp" +#include "n3dmath2/n3dmath2.hpp" +#include "common/string_hash.hpp" +#include "common/err_msg.h" + +using std::string; + +static void create_normal_cube_map(); + +static HashTable *textures; +static Texture *normal_cubemap; + +static void delete_texture(Texture *tex) { + glDeleteTextures(1, &tex->tex_id); + glGetError(); + //delete tex; +} + +static void init_tex_man() { + if(textures) return; + textures = new HashTable; + textures->set_hash_function(string_hash); + textures->set_data_destructor(delete_texture); +} + +void add_texture(Texture *texture, const char *fname) { + + if(!textures) init_tex_man(); + + if(!fname) { // enter a randomly named texture + textures->insert(tmpnam(0), texture); + } else { + textures->insert(fname, texture); + } +} + +// TODO: implement this one, after making HashTable remove by value +void remove_texture(Texture *texture) { +} + +Texture *find_texture(const char *fname) { + + if(!textures) init_tex_man(); + + Pair *res = textures->find(fname); + return res ? res->val : 0; +} + + +/* ----- get_texture() function ----- + * first looks in the texture database in constant time (hash table) + * if the texture is already there it just returns the pointer. If the + * texture is not there it tries to load the image data, create the texture + * and return it, and if it fails it returns a NULL pointer + */ +Texture *get_texture(const char *fname) { + if(!fname) return 0; + + Texture *tex; + if((tex = find_texture(fname))) return tex; + + // first check to see if it's a custom file (cubemap). + if(is_cubemap(fname)) { + tex = load_cubemap(fname); + add_texture(tex, fname); + return tex; + } + + PixelBuffer pbuf; + + void *img_buf = load_image(fname, &pbuf.width, &pbuf.height); + if(!img_buf) return 0; + + pbuf.buffer = new Pixel[pbuf.width * pbuf.height]; + memcpy(pbuf.buffer, img_buf, pbuf.width * pbuf.height * sizeof(Pixel)); + + free_image(img_buf); + + tex = new Texture; + tex->set_pixel_data(pbuf); + add_texture(tex, fname); + return tex; +} + + +void destroy_textures() { + static bool called_again = false; + + if(called_again) { + warning("Multiple destroy_textures() calls"); + return; + } else { + called_again = true; + } + + info("Shutting down texture manager, destroying all textures..."); + delete textures; + textures = 0; +} + + +Texture *make_cube_map(Texture **tex_array) { + int size = tex_array[0]->width; + + Texture *cube = new Texture(size, size, TEX_CUBE); + + cube->lock(CUBE_MAP_PX); + tex_array[CUBE_MAP_INDEX_PX]->lock(); + memcpy(cube->buffer, tex_array[CUBE_MAP_INDEX_PX]->buffer, size * size * sizeof(Pixel)); + tex_array[CUBE_MAP_INDEX_PX]->unlock(); + cube->unlock(CUBE_MAP_PX); + + cube->lock(CUBE_MAP_NX); + tex_array[CUBE_MAP_INDEX_NX]->lock(); + memcpy(cube->buffer, tex_array[CUBE_MAP_INDEX_NX]->buffer, size * size * sizeof(Pixel)); + tex_array[CUBE_MAP_INDEX_NX]->unlock(); + cube->unlock(CUBE_MAP_NX); + + cube->lock(CUBE_MAP_PY); + tex_array[CUBE_MAP_INDEX_PY]->lock(); + memcpy(cube->buffer, tex_array[CUBE_MAP_INDEX_PY]->buffer, size * size * sizeof(Pixel)); + tex_array[CUBE_MAP_INDEX_PY]->unlock(); + cube->unlock(CUBE_MAP_PY); + + cube->lock(CUBE_MAP_NY); + tex_array[CUBE_MAP_INDEX_NY]->lock(); + memcpy(cube->buffer, tex_array[CUBE_MAP_INDEX_NY]->buffer, size * size * sizeof(Pixel)); + tex_array[CUBE_MAP_INDEX_NY]->unlock(); + cube->unlock(CUBE_MAP_NY); + + cube->lock(CUBE_MAP_PZ); + tex_array[CUBE_MAP_INDEX_PZ]->lock(); + memcpy(cube->buffer, tex_array[CUBE_MAP_INDEX_PZ]->buffer, size * size * sizeof(Pixel)); + tex_array[CUBE_MAP_INDEX_PZ]->unlock(); + cube->unlock(CUBE_MAP_PZ); + + cube->lock(CUBE_MAP_NZ); + tex_array[CUBE_MAP_INDEX_NZ]->lock(); + memcpy(cube->buffer, tex_array[CUBE_MAP_INDEX_NZ]->buffer, size * size * sizeof(Pixel)); + tex_array[CUBE_MAP_INDEX_NZ]->unlock(); + cube->unlock(CUBE_MAP_NZ); + + return cube; +} + + +Texture *get_normal_cube() { + if(!normal_cubemap) create_normal_cube_map(); + return normal_cubemap; +} + +static Color vec_to_color(const Vector3 &v) { + return Color(v.x * 0.5 + 0.5, v.y * 0.5 + 0.5, v.z * 0.5 + 0.5); +} + +static void create_normal_cube_map() { + static const int size = 32; + static const scalar_t fsize = (scalar_t)size; + static const scalar_t half_size = fsize / 2.0; + Pixel *ptr; + + delete normal_cubemap; + normal_cubemap = new Texture(size, size, TEX_CUBE); + + // +X + normal_cubemap->lock(CUBE_MAP_PX); + ptr = normal_cubemap->buffer; + for(int j=0; junlock(CUBE_MAP_PX); + + // -X + normal_cubemap->lock(CUBE_MAP_NX); + ptr = normal_cubemap->buffer; + for(int j=0; junlock(CUBE_MAP_NX); + + // +Y + normal_cubemap->lock(CUBE_MAP_PY); + ptr = normal_cubemap->buffer; + for(int j=0; junlock(CUBE_MAP_PY); + + // -Y + normal_cubemap->lock(CUBE_MAP_NY); + ptr = normal_cubemap->buffer; + for(int j=0; junlock(CUBE_MAP_NY); + + // +Z + normal_cubemap->lock(CUBE_MAP_PZ); + ptr = normal_cubemap->buffer; + for(int j=0; junlock(CUBE_MAP_PZ); + + // -Z + normal_cubemap->lock(CUBE_MAP_NZ); + ptr = normal_cubemap->buffer; + for(int j=0; junlock(CUBE_MAP_NZ); +} + + +bool is_cubemap(const char *fname) { + FILE *fp = fopen(fname, "r"); + if(!fp) { + return false; + } + + char idstr[5]; + fread(idstr, 1, 4, fp); + idstr[4] = 0; + + fclose(fp); + return strcmp(idstr, "CUBE") == 0; +} + +Texture *load_cubemap(const char *fname) { + FILE *fp = fopen(fname, "r"); + if(!fp) { + error("could not open %s", fname); + return 0; + } + + if(!is_cubemap(fname)) { + error("%s is not a cubemap", fname); + fclose(fp); + return 0; + } + + char line[512]; + unsigned int cube_size = 0; + unsigned long xsz = 0, ysz = 0; + void *img[6] = {0}; + + fgets(line, 512, fp); // skip file id & text description + + if(fgets(line, 512, fp) && isdigit(*line)) { + cube_size = atoi(line); + } + + for(int i=0; i<6; i++) { + if(!fgets(line, 512, fp)) { + error("%s is not a complete cubemap file, EOF encountered", fname); + break; + } + + if(line[strlen(line)-1] == '\n') { + line[strlen(line)-1] = 0; + } + + unsigned long x, y; + if(!(img[i] = load_image(line, &x, &y))) { + error("cubemap %s requires %s, which cannot be opened", fname, line); + break; + } + + if(i > 0 && (x != xsz || y != ysz)) { + error("inconsistent cubemap %s, image sizes differ", fname); + break; + } + xsz = x; + ysz = y; + + if(xsz != ysz) { + error("cubemap %s contains non-square textures", fname); + break; + } + } + + fclose(fp); + + if(!img[5]) { + for(int i=0; i<6; i++) { + if(img[i]) free_image(img[i]); + } + return 0; + } + + if(xsz != cube_size) { + warning("cubemap %s loaded correctly, but wrong size in the header", fname); + } + + Texture *cube = new Texture(cube_size, cube_size, TEX_CUBE); + + CubeMapFace faces[] = { + CUBE_MAP_PX, CUBE_MAP_NX, + CUBE_MAP_PY, CUBE_MAP_NY, + CUBE_MAP_PZ, CUBE_MAP_NZ + }; + + for(int i=0; i<6; i++) { + cube->lock(faces[i]); + memcpy(cube->buffer, img[i], cube_size * cube_size * sizeof(Pixel)); + cube->unlock(faces[i]); + + free_image(img[i]); + } + + return cube; +}