From: Kahrl Date: Thu, 29 Mar 2012 19:58:01 +0000 (+0300) Subject: [transformN image modifier X-Git-Url: http://81.2.79.47:8989/gitweb/?a=commitdiff_plain;h=0983f65da7f8302fe6db7bc922a95187584b4e63;p=zefram%2Fminetest%2Fminetest_engine.git [transformN image modifier --- diff --git a/src/tile.cpp b/src/tile.cpp index c35952b7..25f8a000 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -492,6 +492,12 @@ void overlay(video::IImage *image, video::IImage *overlay); // Brighten image void brighten(video::IImage *image); +// Parse a transform name +u32 parseImageTransform(const std::string& s); +// Apply transform to image dimension +core::dimension2d imageTransformDimension(u32 transform, core::dimension2d dim); +// Apply transform to image data +void imageTransform(u32 transform, video::IImage *src, video::IImage *dst); /* Generate image based on a string like "stone.png" or "[crack0". @@ -1405,6 +1411,46 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg, baseimg->setPixel(x,y,c); } } + /* + "[transformN" + Rotates and/or flips the image. + + N can be a number (between 0 and 7) or a transform name. + Rotations are counter-clockwise. + 0 I identity + 1 R90 rotate by 90 degrees + 2 R180 rotate by 180 degrees + 3 R270 rotate by 270 degrees + 4 FX flip X + 5 FXR90 flip X then rotate by 90 degrees + 6 FY flip Y + 7 FYR90 flip Y then rotate by 90 degrees + + Note: Transform names can be concatenated to produce + their product (applies the first then the second). + The resulting transform will be equivalent to one of the + eight existing ones, though (see: dihedral group). + */ + else if(part_of_name.substr(0,10) == "[transform") + { + if(baseimg == NULL) + { + errorstream<<"generate_image(): baseimg==NULL " + <<"for part_of_name=\""< dim = imageTransformDimension( + transform, baseimg->getDimension()); + video::IImage *image = driver->createImage( + baseimg->getColorFormat(), dim); + assert(image); + imageTransform(transform, baseimg, image); + baseimg->drop(); + baseimg = image; + } /* [inventorycube{topimage{leftimage{rightimage In every subimage, replace ^ with &. @@ -1577,3 +1623,106 @@ void brighten(video::IImage *image) } } +u32 parseImageTransform(const std::string& s) +{ + int total_transform = 0; + + std::string transform_names[8]; + transform_names[0] = "i"; + transform_names[1] = "r90"; + transform_names[2] = "r180"; + transform_names[3] = "r270"; + transform_names[4] = "fx"; + transform_names[6] = "fy"; + + std::size_t pos = 0; + while(pos < s.size()) + { + int transform = -1; + for(int i = 0; i <= 7; ++i) + { + const std::string &name_i = transform_names[i]; + + if(s[pos] == ('0' + i)) + { + transform = i; + pos++; + break; + } + else if(!(name_i.empty()) && + lowercase(s.substr(pos, name_i.size())) == name_i) + { + transform = i; + pos += name_i.size(); + break; + } + } + if(transform < 0) + break; + + // Multiply total_transform and transform in the group D4 + int new_total = 0; + if(transform < 4) + new_total = (transform + total_transform) % 4; + else + new_total = (transform - total_transform + 8) % 4; + if((transform >= 4) ^ (total_transform >= 4)) + new_total += 4; + + total_transform = new_total; + } + return total_transform; +} + +core::dimension2d imageTransformDimension(u32 transform, core::dimension2d dim) +{ + if(transform % 2 == 0) + return dim; + else + return core::dimension2d(dim.Height, dim.Width); +} + +void imageTransform(u32 transform, video::IImage *src, video::IImage *dst) +{ + if(src == NULL || dst == NULL) + return; + + core::dimension2d srcdim = src->getDimension(); + core::dimension2d dstdim = dst->getDimension(); + + assert(dstdim == imageTransformDimension(transform, srcdim)); + assert(transform >= 0 && transform <= 7); + + /* + Compute the transformation from source coordinates (sx,sy) + to destination coordinates (dx,dy). + */ + int sxn = 0; + int syn = 2; + if(transform == 0) // identity + sxn = 0, syn = 2; // sx = dx, sy = dy + else if(transform == 1) // rotate by 90 degrees ccw + sxn = 3, syn = 0; // sx = (H-1) - dy, sy = dx + else if(transform == 2) // rotate by 180 degrees + sxn = 1, syn = 3; // sx = (W-1) - dx, sy = (H-1) - dy + else if(transform == 3) // rotate by 270 degrees ccw + sxn = 2, syn = 1; // sx = dy, sy = (W-1) - dx + else if(transform == 4) // flip x + sxn = 1, syn = 2; // sx = (W-1) - dx, sy = dy + else if(transform == 5) // flip x then rotate by 90 degrees ccw + sxn = 2, syn = 0; // sx = dy, sy = dx + else if(transform == 6) // flip y + sxn = 0, syn = 3; // sx = dx, sy = (H-1) - dy + else if(transform == 7) // flip y then rotate by 90 degrees ccw + sxn = 3, syn = 1; // sx = (H-1) - dy, sy = (W-1) - dx + + for(u32 dy=0; dygetPixel(sx,sy); + dst->setPixel(dx,dy,c); + } +}