]> Dogcows Code - chaz/yoink/blobdiff - src/moof/image.cc
compression functions; fixed texture seams
[chaz/yoink] / src / moof / image.cc
index 77b15c13903bead2a4bd05bc33e3a0081fbd2f91..c9c0638dba4adf6561eccdfc9ba941ab00f9f33c 100644 (file)
@@ -115,7 +115,7 @@ static SDL_Surface* load_png(const std::string& path, texture_attributes& attrib
        int             bpp;
 
        png_byte        colors;
-       png_bytepp      rows = 0;
+       png_bytepp      rows;
 
        png_textp       texts = 0;
        int             nutext_s;
@@ -170,53 +170,139 @@ static SDL_Surface* load_png(const std::string& path, texture_attributes& attrib
        png_read_update_info(png.context, png.info);
 
        bpp = png_get_bit_depth(png.context, png.info);
-       channels_ = png_get_channels(png.context, png.info);
-       depth_ = bpp * channels_;
+       int channels = png_get_channels(png.context, png.info);
+       int depth = bpp * channels;
 
        // read comments
        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, "X-Yoink-Texture", 11) == 0)
+               if (std::string(texts[i].key) == "X-Yoink-Texture")
                {
-                       set_texture_info(texts[i].text);
+                       attribs.init(texts[i].text);
                        texture = true;
                        break;
                }
        }
 
-       width_  = png_get_image_width(png.context, png.info);
-       height_ = png_get_image_height(png.context, png.info);
+       int width       = png_get_image_width(png.context, png.info);
+       int height      = png_get_image_height(png.context, png.info);
+       int pitch       = png_get_rowbytes(png.context, png.info);
+       char* pixels    = new char[height * pitch];
 
-       pitch_ = png_get_rowbytes(png.context, png.info);
-       pixels_ = new char[width_ * pitch_];
-
-       rows = new png_bytep[height_];
+       rows = new png_bytep[height];
        if (texture)
        {
                log_debug("texture detected; loading flipped");
-               for (int i = 0; i < height_; ++i)
+               for (int i = 0; i < height; ++i)
                {
-                       rows[height_-1-i] = (png_bytep)(pixels_ +
-                                       i * channels_ * width_);
+                       rows[height-1-i] = (png_bytep)(pixels +
+                                       i * channels * width);
                }
        }
        else
        {
                log_debug("no texture attributes found");
-               for (int i = 0; i < height_; ++i)
+               for (int i = 0; i < height; ++i)
                {
-                       rows[i] = (png_bytep)(pixels_ +
-                                       i * channels_ * width_);
+                       rows[i] = (png_bytep)(pixels +
+                                       i * channels * width);
                }
        }
 
        png_read_image(png.context, rows);
+       delete[] rows;
+
        png_read_end(png.context, 0);
 
-       // TODO leak
-       delete[] rows;
+       SDL_Surface* src = SDL_CreateRGBSurfaceFrom
+       (
+               pixels,
+               width,
+               height, 
+               depth,
+               pitch,
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+               0x000000FF,
+               0x0000FF00,
+               0x00FF0000,
+               0xFF000000
+#else
+               0xFF000000,
+               0x00FF0000,
+               0x0000FF00,
+               0x000000FF
+#endif
+       );
+       if (!src) throw std::runtime_error(SDL_GetError());
+       return src;
+}
+
+static SDL_Surface* load_bmp(const std::string& path)
+{
+       return SDL_LoadBMP(path.c_str());
+}
+
+
+#if 0
+static void save_bmp(SDL_Surface* image, const std::string& path)
+{
+       if (SDL_SaveBMP(image, path.c_str()) != 0)
+               throw std::runtime_error(SDL_GetError());
+}
+
+
+static void destroy_context(SDL_Surface* context)
+{
+       if (context->flags & SDL_PREALLOC) delete[] (char*)context->pixels;
+       SDL_FreeSurface(context);
+}
+#endif
+
+
+image::image(const std::string& path) :
+       pixels_(0),
+       object_(0),
+       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)
+{
+       std::string ext = stlplus::extension_part(path);
+
+       SDL_Surface* context = 0;
+       if (ext == "png")
+       {
+               texture_attributes attribs;
+               context = load_png(path, attribs);
+               pixels_ = (char*)context->pixels;
+               width_ = context->w;
+               height_ = context->h;
+               depth_ = 32;
+               pitch_ = context->pitch;
+               channels_ = 4;
+               min_filter_ = attribs.min_filter;
+               mag_filter_ = attribs.mag_filter;
+               tile_s_ = attribs.tile_s;
+               tile_t_ = attribs.tile_t;
+               wrap_s_ = attribs.wrap_s;
+               wrap_t_ = attribs.wrap_t;
+               postprocess();
+       }
+       else if (ext == "bmp")
+       {
+               context = load_bmp(path);
+               pixels_ = (char*)context->pixels;
+               width_ = context->w;
+               height_ = context->h;
+               depth_ = 32;
+               pitch_ = context->pitch;
+               channels_ = 4;
+       }
+       // TODO leaking context
 }
 
 image::~image()
@@ -226,6 +312,189 @@ image::~image()
 }
 
 
+void image::postprocess()
+{
+       if (1 == tile_s_ && 1 == tile_t_) return;
+
+       SDL_Surface* src = SDL_CreateRGBSurfaceFrom
+       (
+               pixels_,
+               width_,
+               height_, 
+               depth_,
+               pitch_,
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+               0x000000FF,
+               0x0000FF00,
+               0x00FF0000,
+               0xFF000000
+#else
+               0xFF000000,
+               0x00FF0000,
+               0x0000FF00,
+               0x000000FF
+#endif
+       );
+       SDL_Surface* dst = SDL_CreateRGBSurface(
+               SDL_SWSURFACE,
+               higher_power_of_two(width_),
+               higher_power_of_two(height_),
+               depth_,
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+               0x000000FF,
+               0x0000FF00,
+               0x00FF0000,
+               0xFF000000
+#else
+               0xFF000000,
+               0x00FF0000,
+               0x0000FF00,
+               0x000000FF
+#endif
+       );
+       ASSERT(src && dst);
+
+       SDL_SetAlpha(src, 0, 128);
+       SDL_SetAlpha(dst, 0, 128);
+
+       int src_tilew = src->w / tile_s_;
+       int src_tileh = src->h / tile_t_;
+       int dst_tilew = dst->w / tile_s_;
+       int dst_tileh = dst->h / tile_t_;
+
+       for (int t = 0; t < tile_t_; ++t) for (int s = 0; s < tile_s_; ++s)
+       {
+               SDL_Rect srcrect;
+               SDL_Rect dstrect;
+               srcrect.x = s * src_tilew;
+               srcrect.y = t * src_tileh;
+               srcrect.w = src_tilew;
+               srcrect.h = src_tileh;
+               dstrect.x = s * dst_tilew + (src_tilew / 2);
+               dstrect.y = t * dst_tileh + (src_tileh / 2);
+               log_warning("SRC", srcrect.x, srcrect.y, srcrect.w, srcrect.h);
+               log_warning("DST", dstrect.x, dstrect.y);
+               SDL_BlitSurface(src, &srcrect, dst, &dstrect);
+
+               srcrect.x = s * src_tilew;
+               srcrect.y = t * src_tileh;
+               srcrect.w = 1;
+               srcrect.h = src_tileh;
+               dstrect.y = t * dst_tileh + (src_tileh / 2);
+               for (int x = s * dst_tilew + (src_tilew / 2) - 1; s * dst_tilew <= x; --x)
+               {
+                       dstrect.x = x;
+                       SDL_BlitSurface(src, &srcrect, dst, &dstrect);
+               }
+
+               srcrect.x = (s + 1) * src_tilew - 1;
+               srcrect.y = t * src_tileh;
+               srcrect.w = 1;
+               srcrect.h = src_tileh;
+               dstrect.y = t * dst_tileh + (src_tileh / 2);
+               for (int x = (s + 1) * dst_tilew - (src_tilew / 2); x < (s + 1) * dst_tilew; ++x)
+               {
+                       dstrect.x = x;
+                       SDL_BlitSurface(src, &srcrect, dst, &dstrect);
+               }
+
+               srcrect.x = s * src_tilew;
+               srcrect.y = t * src_tileh;
+               srcrect.w = src_tilew;
+               srcrect.h = 1;
+               dstrect.x = s * dst_tilew + (src_tilew / 2);
+               for (int y = t * dst_tileh + (src_tileh / 2) - 1; t * dst_tileh <= y; --y)
+               {
+                       dstrect.y = y;
+                       SDL_BlitSurface(src, &srcrect, dst, &dstrect);
+               }
+
+               srcrect.x = s * src_tilew;
+               srcrect.y = (t + 1) * src_tileh - 1;
+               srcrect.w = src_tilew;
+               srcrect.h = 1;
+               dstrect.x = s * dst_tilew + (src_tilew / 2);
+               for (int y = (t + 1) * dst_tileh - (src_tileh / 2); y < (t + 1) * dst_tileh; ++y)
+               {
+                       dstrect.y = y;
+                       SDL_BlitSurface(src, &srcrect, dst, &dstrect);
+               }
+       }
+       SDL_FreeSurface(src);
+
+       char* pixels = new char[dst->w * dst->pitch];
+       SDL_Surface* finaldst = SDL_CreateRGBSurfaceFrom
+       (
+               pixels,
+               dst->w,
+               dst->h, 
+               depth_,
+               dst->pitch,
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+               0x000000FF,
+               0x0000FF00,
+               0x00FF0000,
+               0xFF000000
+#else
+               0xFF000000,
+               0x00FF0000,
+               0x0000FF00,
+               0x000000FF
+#endif
+       );
+       SDL_BlitSurface(dst, 0, finaldst, 0);
+
+       //SDL_SaveBMP(dst, (stlplus::basename_part(path) + ".bmp").c_str());
+       SDL_FreeSurface(dst);
+
+       width_ = finaldst->w;
+       height_ = finaldst->h;
+       pitch_ = finaldst->pitch;
+
+       SDL_FreeSurface(finaldst);
+
+       delete[] pixels_;
+       pixels_ = pixels;
+}
+
+
+void image::fix_uv(std::vector<vector2>& p) const
+{
+       vector2 mid(SCALAR(0.0), SCALAR(0.0));
+       for (int i = 0; i < p.size(); ++i)
+       {
+               mid[0] += p[i][0];
+               mid[1] += p[i][1];
+       }
+       mid[0] /= p.size();
+       mid[1] /= p.size();
+       mid[0] *= tile_s_;
+       mid[1] *= tile_t_;
+       mid[0] = std::floor(mid[0]);
+       mid[1] = std::floor(mid[1]);
+       log_warning("midpoint:", mid);
+       scalar s = mid[0];
+       scalar t = mid[1];
+
+       scalar  src_width = width_ >> 1;
+       scalar  src_height = height_ >> 1;
+       int     src_tilew = src_width / tile_s_;
+       int     src_tileh = src_height / tile_t_;
+       int     dst_tilew = width_ / tile_s_;
+       int     dst_tileh = height_ / tile_t_;
+
+       for (int i = 0; i < p.size(); ++i)
+       {
+               //scalar s = p[i][0] * src_width;
+               scalar x = s * dst_tilew + (src_tilew / 2) + (p[i][0] * src_width - s * src_tilew);
+               p[i][0] = x / width_;
+               //scalar t = p[i][1] * src_height;
+               scalar y = t * dst_tileh + (src_tileh / 2) + (p[i][1] * src_height - t * src_tileh);;
+               p[i][1] = y / height_;
+       }
+}
+
+
 void image::set_as_icon() const
 {
        backend backend;
@@ -276,7 +545,7 @@ bool image::tile_coordinates(int index, scalar coords[8]) const
 
 void image::bind() const
 {
-       ASSERT(video::current() && "should have a video context set");
+       ASSERT(video::ready() && "should have a video context set");
 
        if (object_ == 0)
        {
@@ -291,7 +560,7 @@ void image::bind() const
 
 void image::reset_binding()
 {
-       ASSERT(video::current() && "should have a video context set");
+       ASSERT(video::ready() && "should have a video context set");
 
        glBindTexture(GL_TEXTURE_2D, 0);
        global_object_ = 0;
@@ -364,40 +633,8 @@ 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;
-       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(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");
-       }
-}
+
+unsigned image::global_object_ = 0;
 
 
 } // namespace moof
This page took 0.026274 seconds and 4 git commands to generate.