X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2Fmoof%2Fimage.cc;h=abe1677095c9bb12df0fb55826a1c35a143441bf;hp=93ef6d6d0e8e7e7f00f9a3b5b0e074b33c42ba22;hb=382626aad0a683ed8642a6a807eea743db45f7f8;hpb=1da520638918096276158ecdfaeebc14a3d70be7 diff --git a/src/moof/image.cc b/src/moof/image.cc index 93ef6d6..abe1677 100644 --- a/src/moof/image.cc +++ b/src/moof/image.cc @@ -11,8 +11,7 @@ #include // FILE #include // strncmp - -#include +#include #include #include @@ -20,271 +19,345 @@ #include "backend.hh" #include "image.hh" #include "log.hh" -#include "manager.hh" +#include "opengl.hh" +#include "script.hh" +#include "video.hh" namespace moof { -class image::impl : public manager -{ -public: +//static int power_of_two(int input) +//{ + //int value = 1; - explicit impl() : - context_(0), - pixels_(0) {} - - ~impl() - { - SDL_FreeSurface(context_); - delete[] pixels_; - } + //while (value < input) + //{ + //value <<= 1; + //} + //return value; +//} +unsigned image::global_object_ = 0; - void flip() - { - unsigned char* pixels = (Uint8*)(context_->pixels); - unsigned pitch = context_->pitch; - unsigned char line[pitch]; +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) +{ + FILE* fp = resource::open_file(path); + if (!fp) throw std::runtime_error("image not found at " + path); - int yBegin = 0; - int yEnd = context_->h - 1; + png_byte signature[8]; + size_t bytesRead; - if (SDL_MUSTLOCK(context_)) SDL_LockSurface(context_); - while (yBegin < yEnd) - { - memcpy(line, pixels + pitch * yBegin, pitch); - memcpy(pixels + pitch * yBegin, pixels + pitch * yEnd, pitch); - memcpy(pixels + pitch * yEnd, line, pitch); - yBegin++; - yEnd--; - } - if (SDL_MUSTLOCK(context_)) SDL_UnlockSurface(context_); - } + png_infop pngInfo = 0; + png_infop pngInfoEnd = 0; + png_structp pngObj = 0; - void set_as_icon() const - { - SDL_WM_SetIcon(context_, 0); - } + int bpp; + png_byte colors; + png_bytepp rows = 0; - void init(const std::string& name, bool flipped = false) - { - std::string path(name); + png_textp texts = 0; + int nutext_s; - FILE* fp = resource::open_file(path); - if (!fp) return; + bytesRead = fread(signature, 1, sizeof(signature), fp); + if (bytesRead < sizeof(signature) || + png_sig_cmp(signature, 0, sizeof(signature)) != 0) goto cleanup; - png_byte signature[8]; - size_t bytesRead; + pngObj = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); + if (!pngObj) goto cleanup; - png_infop pngInfo = 0; - png_infop pngInfoEnd = 0; - png_structp pngObj = 0; + pngInfo = png_create_info_struct(pngObj); + if (!pngInfo) goto cleanup; - int width; - int height; - int pitch; - int bpp; - int channels; + pngInfoEnd = png_create_info_struct(pngObj); + if (!pngInfoEnd) goto cleanup; - png_byte colors; - png_bytepp rows = 0; + if (setjmp(png_jmpbuf(pngObj))) goto cleanup; - png_textp texts = 0; - int nutext_s; + png_init_io(pngObj, fp); + png_set_sig_bytes(pngObj, sizeof(signature)); + png_read_info(pngObj, pngInfo); - bytesRead = fread(signature, 1, sizeof(signature), fp); - if (bytesRead < sizeof(signature) || - png_sig_cmp(signature, 0, sizeof(signature)) != 0) goto cleanup; + bpp = png_get_bit_depth(pngObj, pngInfo); + colors = png_get_color_type(pngObj, pngInfo); + switch (colors) + { + case PNG_COLOR_TYPE_PALETTE: + png_set_palette_to_rgb(pngObj); + break; - pngObj = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); - if (!pngObj) goto cleanup; + case PNG_COLOR_TYPE_GRAY: + if (bpp < 8) png_set_expand(pngObj); + break; - pngInfo = png_create_info_struct(pngObj); - if (!pngInfo) goto cleanup; + case PNG_COLOR_TYPE_GRAY_ALPHA: + png_set_gray_to_rgb(pngObj); + break; + } - pngInfoEnd = png_create_info_struct(pngObj); - if (!pngInfoEnd) goto cleanup; + if (bpp == 16) png_set_strip_16(pngObj); - if (setjmp(png_jmpbuf(pngObj))) goto cleanup; + png_read_update_info(pngObj, pngInfo); - png_init_io(pngObj, fp); - png_set_sig_bytes(pngObj, sizeof(signature)); - png_read_info(pngObj, pngInfo); + bpp = png_get_bit_depth(pngObj, pngInfo); + channels_ = png_get_channels(pngObj, pngInfo); + depth_ = bpp * channels_; - bpp = png_get_bit_depth(pngObj, pngInfo); - colors = png_get_color_type(pngObj, pngInfo); - switch (colors) + // read comments + png_get_text(pngObj, pngInfo, &texts, &nutext_s); + for (int i = 0; i < nutext_s; ++i) + { + if (strncmp(texts[i].key, "TextureInfo", 11) == 0) { - case PNG_COLOR_TYPE_PALETTE: - png_set_palette_to_rgb(pngObj); - break; - - case PNG_COLOR_TYPE_GRAY: - if (bpp < 8) png_set_expand(pngObj); - break; - - case PNG_COLOR_TYPE_GRAY_ALPHA: - png_set_gray_to_rgb(pngObj); - break; + set_texture_info(texts[i].text); + break; } + } - if (bpp == 16) png_set_strip_16(pngObj); + width_ = png_get_image_width(pngObj, pngInfo); + height_ = png_get_image_height(pngObj, pngInfo); - png_read_update_info(pngObj, pngInfo); + pitch_ = png_get_rowbytes(pngObj, pngInfo); + pixels_ = new char[width_ * pitch_]; - bpp = png_get_bit_depth(pngObj, pngInfo); - channels = png_get_channels(pngObj, pngInfo); - depth_ = bpp * channels; + rows = new png_bytep[height_]; + for (int i = 0; i < height_; ++i) + { + rows[i] = (png_bytep)(pixels_ + i * channels_ * width_); + } - if (channels == 3) color_mode_ = GL_RGB; - else color_mode_ = GL_RGBA; - - // read comments - png_get_text(pngObj, pngInfo, &texts, &nutext_s); - for (int i = 0; i < nutext_s; ++i) - { - if (strncmp(texts[i].key, "TextureInfo", 11) == 0) - { - comment_ = texts[i].text; - break; - } - } + png_read_image(pngObj, rows); + png_read_end(pngObj, 0); - width = png_get_image_width(pngObj, pngInfo); - height = png_get_image_height(pngObj, pngInfo); +cleanup: - pitch = png_get_rowbytes(pngObj, pngInfo); - pixels_ = new char[width * pitch]; + delete[] rows; + png_destroy_read_struct(pngObj ? &pngObj : 0, + pngInfo ? &pngInfo : 0, + pngInfoEnd ? &pngInfoEnd : 0); + fclose(fp); +} - rows = new png_bytep[height]; - if (flipped) - { - for (int i = 0; i < height; ++i) - { - rows[height - 1 - i] = (png_bytep)(pixels_ + - i * channels * width); - } - } - else - { - for (int i = 0; i < height; ++i) - { - rows[i] = (png_bytep)(pixels_ + i * channels * width); - } - } +image::~image() +{ + unload_from_gl(); + delete[] pixels_; +} - png_read_image(pngObj, rows); - png_read_end(pngObj, 0); - context_ = SDL_CreateRGBSurfaceFrom - ( - pixels_, - width, - height, - bpp * channels, - pitch, +void image::set_as_icon() const +{ + backend backend; + + SDL_Surface* context = SDL_CreateRGBSurfaceFrom + ( + pixels_, + width_, + height_, + depth_, + pitch_, #if SDL_BYTEORDER == SDL_LIL_ENDIAN - 0x000000FF, - 0x0000FF00, - 0x00FF0000, - 0xFF000000 + 0x000000FF, + 0x0000FF00, + 0x00FF0000, + 0xFF000000 #else - 0xFF000000, - 0x00FF0000, - 0x0000FF00, - 0x000000FF + 0xFF000000, + 0x00FF0000, + 0x0000FF00, + 0x000000FF #endif - ); - - cleanup: - - delete[] rows; - png_destroy_read_struct(pngObj ? &pngObj : 0, - pngInfo ? &pngInfo : 0, - pngInfoEnd ? &pngInfoEnd : 0); - fclose(fp); - } - - - SDL_Surface* context_; - char* pixels_; - - unsigned depth_; - GLuint color_mode_; + ); - std::string comment_; + SDL_WM_SetIcon(context, 0); -private: - - backend backend_; -}; - - -image::image(const std::string& name) : - // pass through - impl_(image::impl::instance(name)) {} + SDL_FreeSurface(context); +} -bool image::is_valid() const +bool image::tile_coordinates(int index, scalar coords[8]) const { - return impl_->context_; + // make sure the index represents a real tile + if (index < 0 && index >= tile_width_ * tile_height_) return false; + + scalar w = 1.0 / scalar(tile_width_); + scalar h = 1.0 / scalar(tile_height_); + + coords[0] = scalar(index % tile_width_) * w; + coords[1] = (scalar(tile_height_ - 1) - scalar(index / tile_width_)) * h; + coords[2] = coords[0] + w; + coords[3] = coords[1]; + coords[4] = coords[2]; + coords[5] = coords[1] + h; + coords[6] = coords[0]; + coords[7] = coords[5]; + + return true; } -int image::width() const -{ - return impl_->context_->w; -} -int image::height() const +void image::bind() const { - return impl_->context_->h; -} + ASSERT(video::current() && "should have a video context set"); -unsigned image::depth() const -{ - return impl_->depth_; + if (object_ == 0) + { + upload_to_gl(); + } + if (object_ != global_object_) + { + glBindTexture(GL_TEXTURE_2D, (GLuint)object_); + global_object_ = object_; + } } -unsigned image::pitch() const +void image::reset_binding() { - return impl_->context_->pitch; + ASSERT(video::current() && "should have a video context set"); + + glBindTexture(GL_TEXTURE_2D, 0); + global_object_ = 0; } -GLuint image::mode() const + +/* + * 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 { - return impl_->color_mode_; + if (object_) + { + // already loaded + return; + } + + glGenTextures(1, (GLuint*)&object_); + glBindTexture(GL_TEXTURE_2D, (GLuint)object_); + + GLuint mode; + if (channels_ == 3) mode = GL_RGB; + else mode = GL_RGBA; + + glTexImage2D + //gluBuild2DMipmaps + ( + GL_TEXTURE_2D, + 0, + mode, + //3, + width_, + height_, + 0, + mode, + GL_UNSIGNED_BYTE, + pixels_ + ); + + set_properties(); + + // we want to know when the GL context is recreated + //dispatcher& dispatcher = dispatcher::global(); + //new_context_ = dispatcher.add_target("video.newcontext", + //boost::bind(&image::context_recreated, this)); + // FIXME this has const issues } -std::string image::comment() const +void image::unload_from_gl() const { - return impl_->comment_; + if (object_) + { + if (object_ == global_object_) + { + global_object_ = 0; + } + + glDeleteTextures(1, (GLuint*)&object_); + object_ = 0; + } } -const char* image::pixels() const +void image::context_recreated() { - return impl_->pixels_; + object_ = global_object_ = 0; + upload_to_gl(); } -char* image::pixels() +/* + * Sets some texture properties such as the filters and external + * coordinate behavior. + */ +void image::set_properties() const { - return impl_->pixels_; + //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::flip() +void image::set_texture_info(const std::string& info) { - // pass through - impl_->flip(); + script script; + log::import(script); + + script::slot g = script.globals(); + g.set_field("CLAMP", GL_CLAMP); + g.set_field("REPEAT", GL_REPEAT); + g.set_field("LINEAR", GL_LINEAR); + g.set_field("NEAREST", GL_NEAREST); + g.set_field("LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR); + g.set_field("LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST); + g.set_field("NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR); + g.set_field("NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST); + + 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(tile_width_, "tiles_s"); + globals.get(tile_height_, "tiles_t"); + globals.get(min_filter_, "min_filter"); + globals.get(mag_filter_, "mag_filter"); + globals.get(wrap_s_, "wrap_s"); + globals.get(wrap_t_, "wrap_t"); + } } -void image::set_as_icon() const + +class image_resource_loader { - // pass through - impl_->set_as_icon(); -} +public: + + image_resource_loader() + { + resource::register_type("png"); + } + + ~image_resource_loader() + { + resource::unregister_type("png"); + } +}; + +static image_resource_loader loader; } // namespace moof