]> Dogcows Code - chaz/yoink/blobdiff - src/moof/image.cc
pch support
[chaz/yoink] / src / moof / image.cc
index 94d468727107a5e45e8b9fcabb8a73e6344fa2ca..77b15c13903bead2a4bd05bc33e3a0081fbd2f91 100644 (file)
@@ -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 <cstdio>              // FILE
-#include <cstring>             // strncmp
+#include <fstream>
 #include <stdexcept>
-
 #include <png.h>
+
 #include <SDL/SDL.h>
 
+#include <stlplus/portability/file_system.hpp>
+
 #include "backend.hh"
+#include "debug.hh"
 #include "image.hh"
 #include "log.hh"
 #include "opengl.hh"
 namespace moof {
 
 
+MOOF_REGISTER_RESOURCE(image, bmp, textures);
 MOOF_REGISTER_RESOURCE(image, png, textures);
 
-//static int power_of_two(int input)
-//{
-       //int value = 1;
-
-       //while (value < input)
-       //{
-               //value <<= 1;
-       //}
-       //return value;
-//}
-
-unsigned image::global_object_ = 0;
-
-
-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)
+
+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);
+}
+
+
+struct texture_attributes
+{
+       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)
 {
-       FILE* fp = fopen(path.c_str(), "rb");
-       if (!fp) throw std::runtime_error("image not found at " + path);
+       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;
+               png_sig_cmp(signature, 0, sizeof(signature)) != 0) throw 0;
 
-       pngObj = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
-       if (!pngObj)     goto cleanup;
-
-       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[height_-1-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()
@@ -182,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];
@@ -207,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");
@@ -231,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
@@ -279,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;
        }
@@ -307,7 +364,6 @@ void image::set_properties() const
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t_);
 }
 
-
 void image::set_texture_info(const std::string& info)
 {
        script script;
@@ -334,16 +390,12 @@ 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");
-               //min_filter_ = GL_LINEAR;
-               //mag_filter_ = GL_LINEAR;
-               //wrap_s_ = GL_CLAMP;
-               //wrap_t_ = GL_CLAMP;
        }
 }
 
This page took 0.035117 seconds and 4 git commands to generate.