X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fmoof%2Fimage.cc;h=77b15c13903bead2a4bd05bc33e3a0081fbd2f91;hb=44b3014bce798789e795242d1556cb7449e6386a;hp=abe1677095c9bb12df0fb55826a1c35a143441bf;hpb=382626aad0a683ed8642a6a807eea743db45f7f8;p=chaz%2Fyoink diff --git a/src/moof/image.cc b/src/moof/image.cc index abe1677..77b15c1 100644 --- a/src/moof/image.cc +++ b/src/moof/image.cc @@ -1,22 +1,22 @@ -/*] Copyright (c) 2009-2010, Charles McGarvey [************************** +/*] Copyright (c) 2009-2011, Charles McGarvey [***************************** **] All rights reserved. * -* vi:ts=4 sw=4 tw=75 -* * Distributable under the terms and conditions of the 2-clause BSD license; * see the file COPYING for a complete text of the license. * -**************************************************************************/ +*****************************************************************************/ -#include // FILE -#include // strncmp +#include #include - #include + #include +#include + #include "backend.hh" +#include "debug.hh" #include "image.hh" #include "log.hh" #include "opengl.hh" @@ -27,125 +27,196 @@ namespace moof { -//static int power_of_two(int input) -//{ - //int value = 1; +MOOF_REGISTER_RESOURCE(image, bmp, textures); +MOOF_REGISTER_RESOURCE(image, png, textures); - //while (value < input) - //{ - //value <<= 1; - //} - //return value; -//} -unsigned image::global_object_ = 0; +static int higher_power_of_two(int input) +{ + int value = 2; + while (value <= input) value <<= 1; + return value; +} + +static void read_from_stream(png_structp context, + png_bytep data, png_size_t length) +{ + std::istream& stream(*(std::istream*)png_get_io_ptr(context)); + stream.read((char*)data, length); +} -image::image(const std::string& path) : - pixels_(0), - object_(0), - min_filter_(GL_NEAREST), - mag_filter_(GL_NEAREST), - wrap_s_(GL_CLAMP), - wrap_t_(GL_CLAMP), - tile_width_(1), - tile_height_(1) +struct texture_attributes { - FILE* fp = resource::open_file(path); - if (!fp) throw std::runtime_error("image not found at " + path); + texture_attributes() : + min_filter(GL_NEAREST), + mag_filter(GL_NEAREST), + tile_s(1), + tile_t(1), + wrap_s(GL_CLAMP_TO_EDGE), + wrap_t(GL_CLAMP_TO_EDGE) {} + + void init(const std::string& info) + { + script script; + log::import(script); + + script::slot g = script.globals(); +#define EXPORT_CONSTANT(K) g.set_field(#K, GL_##K) + EXPORT_CONSTANT(CLAMP); + EXPORT_CONSTANT(CLAMP_TO_EDGE); + EXPORT_CONSTANT(REPEAT); + EXPORT_CONSTANT(LINEAR); + EXPORT_CONSTANT(NEAREST); + EXPORT_CONSTANT(LINEAR_MIPMAP_LINEAR); + EXPORT_CONSTANT(LINEAR_MIPMAP_NEAREST); + EXPORT_CONSTANT(NEAREST_MIPMAP_LINEAR); + EXPORT_CONSTANT(NEAREST_MIPMAP_NEAREST); +#undef export_constant + + if (script.do_string(info) != script::success) + { + std::string str; + script[-1].get(str); + log_warning(str); + } + else + { + log_info("loading texture information..."); + + script::slot globals = script.globals(); + globals.get(min_filter, "min_filter"); + globals.get(mag_filter, "mag_filter"); + globals.get(tile_s, "tile_s"); + globals.get(tile_t, "tile_t"); + globals.get(wrap_s, "wrap_s"); + globals.get(wrap_t, "wrap_t"); + } + } + + GLuint min_filter; + GLuint mag_filter; + int tile_s; + int tile_t; + GLuint wrap_s; + GLuint wrap_t; +}; + + +static SDL_Surface* load_png(const std::string& path, texture_attributes& attribs) +{ + std::ifstream file(path.c_str(), std::ifstream::binary); + if (!file.good()) + throw std::runtime_error("no valid image found at " + path); png_byte signature[8]; size_t bytesRead; - png_infop pngInfo = 0; - png_infop pngInfoEnd = 0; - png_structp pngObj = 0; - - int bpp; + int bpp; png_byte colors; png_bytepp rows = 0; png_textp texts = 0; - int nutext_s; + int nutext_s; - bytesRead = fread(signature, 1, sizeof(signature), fp); + bytesRead = file.read((char*)signature, sizeof(signature)).gcount(); if (bytesRead < sizeof(signature) || - png_sig_cmp(signature, 0, sizeof(signature)) != 0) goto cleanup; - - pngObj = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); - if (!pngObj) goto cleanup; + png_sig_cmp(signature, 0, sizeof(signature)) != 0) throw 0; - pngInfo = png_create_info_struct(pngObj); - if (!pngInfo) goto cleanup; - - pngInfoEnd = png_create_info_struct(pngObj); - if (!pngInfoEnd) goto cleanup; + struct png + { + png_structp context; + png_infop info; + png() : + context(png_create_read_struct(PNG_LIBPNG_VER_STRING, + 0, 0, 0)), + info(png_create_info_struct(context)) + { + if (!context || !info) throw 0; + } + ~png() + { + png_destroy_read_struct(context ? &context : 0, + info ? &info : 0, 0); + } + } png; - if (setjmp(png_jmpbuf(pngObj))) goto cleanup; + if (setjmp(png_jmpbuf(png.context))) throw 0; - png_init_io(pngObj, fp); - png_set_sig_bytes(pngObj, sizeof(signature)); - png_read_info(pngObj, pngInfo); + png_set_read_fn(png.context, (void*)&file, read_from_stream); + png_set_sig_bytes(png.context, sizeof(signature)); + png_read_info(png.context, png.info); - bpp = png_get_bit_depth(pngObj, pngInfo); - colors = png_get_color_type(pngObj, pngInfo); + bpp = png_get_bit_depth(png.context, png.info); + colors = png_get_color_type(png.context, png.info); switch (colors) { - case PNG_COLOR_TYPE_PALETTE: - png_set_palette_to_rgb(pngObj); - break; + case PNG_COLOR_TYPE_PALETTE: + png_set_palette_to_rgb(png.context); + break; - case PNG_COLOR_TYPE_GRAY: - if (bpp < 8) png_set_expand(pngObj); - break; + case PNG_COLOR_TYPE_GRAY: + if (bpp < 8) png_set_expand(png.context); + break; - case PNG_COLOR_TYPE_GRAY_ALPHA: - png_set_gray_to_rgb(pngObj); - break; + case PNG_COLOR_TYPE_GRAY_ALPHA: + png_set_gray_to_rgb(png.context); + break; } - if (bpp == 16) png_set_strip_16(pngObj); + if (bpp == 16) png_set_strip_16(png.context); - png_read_update_info(pngObj, pngInfo); + png_read_update_info(png.context, png.info); - bpp = png_get_bit_depth(pngObj, pngInfo); - channels_ = png_get_channels(pngObj, pngInfo); + bpp = png_get_bit_depth(png.context, png.info); + channels_ = png_get_channels(png.context, png.info); depth_ = bpp * channels_; // read comments - png_get_text(pngObj, pngInfo, &texts, &nutext_s); + bool texture = false; + png_get_text(png.context, png.info, &texts, &nutext_s); for (int i = 0; i < nutext_s; ++i) { - if (strncmp(texts[i].key, "TextureInfo", 11) == 0) + if (strncmp(texts[i].key, "X-Yoink-Texture", 11) == 0) { set_texture_info(texts[i].text); + texture = true; break; } } - width_ = png_get_image_width(pngObj, pngInfo); - height_ = png_get_image_height(pngObj, pngInfo); + width_ = png_get_image_width(png.context, png.info); + height_ = png_get_image_height(png.context, png.info); - pitch_ = png_get_rowbytes(pngObj, pngInfo); + pitch_ = png_get_rowbytes(png.context, png.info); pixels_ = new char[width_ * pitch_]; rows = new png_bytep[height_]; - for (int i = 0; i < height_; ++i) + if (texture) { - rows[i] = (png_bytep)(pixels_ + i * channels_ * width_); + log_debug("texture detected; loading flipped"); + for (int i = 0; i < height_; ++i) + { + rows[height_-1-i] = (png_bytep)(pixels_ + + i * channels_ * width_); + } + } + else + { + log_debug("no texture attributes found"); + for (int i = 0; i < height_; ++i) + { + rows[i] = (png_bytep)(pixels_ + + i * channels_ * width_); + } } - png_read_image(pngObj, rows); - png_read_end(pngObj, 0); - -cleanup: + png_read_image(png.context, rows); + png_read_end(png.context, 0); + // TODO leak delete[] rows; - png_destroy_read_struct(pngObj ? &pngObj : 0, - pngInfo ? &pngInfo : 0, - pngInfoEnd ? &pngInfoEnd : 0); - fclose(fp); } image::~image() @@ -180,21 +251,19 @@ void image::set_as_icon() const ); SDL_WM_SetIcon(context, 0); - SDL_FreeSurface(context); } - bool image::tile_coordinates(int index, scalar coords[8]) const { // make sure the index represents a real tile - if (index < 0 && index >= tile_width_ * tile_height_) return false; + if (index < 0 && index >= tile_s_ * tile_t_) return false; - scalar w = 1.0 / scalar(tile_width_); - scalar h = 1.0 / scalar(tile_height_); + scalar w = 1.0 / scalar(tile_s_); + scalar h = 1.0 / scalar(tile_t_); - coords[0] = scalar(index % tile_width_) * w; - coords[1] = (scalar(tile_height_ - 1) - scalar(index / tile_width_)) * h; + coords[0] = scalar(index % tile_s_) * w; + coords[1] = (scalar(tile_t_ - 1) - scalar(index / tile_s_)) * h; coords[2] = coords[0] + w; coords[3] = coords[1]; coords[4] = coords[2]; @@ -205,7 +274,6 @@ bool image::tile_coordinates(int index, scalar coords[8]) const return true; } - void image::bind() const { ASSERT(video::current() && "should have a video context set"); @@ -229,25 +297,20 @@ void image::reset_binding() global_object_ = 0; } - /* * Upload the image to GL so that it will be accessible by a much more * manageable handle and hopefully reside in video memory. */ void image::upload_to_gl() const { - if (object_) - { - // already loaded - return; - } + if (object_) return; // already loaded glGenTextures(1, (GLuint*)&object_); glBindTexture(GL_TEXTURE_2D, (GLuint)object_); GLuint mode; if (channels_ == 3) mode = GL_RGB; - else mode = GL_RGBA; + else mode = GL_RGBA; glTexImage2D //gluBuild2DMipmaps @@ -277,11 +340,7 @@ void image::unload_from_gl() const { if (object_) { - if (object_ == global_object_) - { - global_object_ = 0; - } - + if (object_ == global_object_) global_object_ = 0; glDeleteTextures(1, (GLuint*)&object_); object_ = 0; } @@ -299,13 +358,12 @@ void image::context_recreated() */ void image::set_properties() const { - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_); - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_); - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s_); - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t_); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s_); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t_); } - void image::set_texture_info(const std::string& info) { script script; @@ -332,33 +390,15 @@ void image::set_texture_info(const std::string& info) log_info("loading texture information..."); script::slot globals = script.globals(); - globals.get(tile_width_, "tiles_s"); - globals.get(tile_height_, "tiles_t"); globals.get(min_filter_, "min_filter"); globals.get(mag_filter_, "mag_filter"); + globals.get(tile_s_, "tile_s"); + globals.get(tile_t_, "tile_t"); globals.get(wrap_s_, "wrap_s"); globals.get(wrap_t_, "wrap_t"); } } -class image_resource_loader -{ -public: - - image_resource_loader() - { - resource::register_type("png"); - } - - ~image_resource_loader() - { - resource::unregister_type("png"); - } -}; - -static image_resource_loader loader; - - } // namespace moof