+/*
+ Draw an image on top of an another one, using the alpha channel of the
+ source image
+
+ This exists because IImage::copyToWithAlpha() doesn't seem to always
+ work.
+*/
+static void blit_with_alpha(video::IImage *src, video::IImage *dst,
+ v2s32 src_pos, v2s32 dst_pos, v2u32 size)
+{
+ for(u32 y0=0; y0<size.Y; y0++)
+ for(u32 x0=0; x0<size.X; x0++)
+ {
+ s32 src_x = src_pos.X + x0;
+ s32 src_y = src_pos.Y + y0;
+ s32 dst_x = dst_pos.X + x0;
+ s32 dst_y = dst_pos.Y + y0;
+ video::SColor src_c = src->getPixel(src_x, src_y);
+ video::SColor dst_c = dst->getPixel(dst_x, dst_y);
+ dst_c = src_c.getInterpolated(dst_c, (float)src_c.getAlpha()/255.0f);
+ dst->setPixel(dst_x, dst_y, dst_c);
+ }
+}
+
+/*
+ Draw an image on top of an another one, using the alpha channel of the
+ source image; only modify fully opaque pixels in destinaion
+*/
+static void blit_with_alpha_overlay(video::IImage *src, video::IImage *dst,
+ v2s32 src_pos, v2s32 dst_pos, v2u32 size)
+{
+ for(u32 y0=0; y0<size.Y; y0++)
+ for(u32 x0=0; x0<size.X; x0++)
+ {
+ s32 src_x = src_pos.X + x0;
+ s32 src_y = src_pos.Y + y0;
+ s32 dst_x = dst_pos.X + x0;
+ s32 dst_y = dst_pos.Y + y0;
+ video::SColor src_c = src->getPixel(src_x, src_y);
+ video::SColor dst_c = dst->getPixel(dst_x, dst_y);
+ if(dst_c.getAlpha() == 255 && src_c.getAlpha() != 0)
+ {
+ dst_c = src_c.getInterpolated(dst_c, (float)src_c.getAlpha()/255.0f);
+ dst->setPixel(dst_x, dst_y, dst_c);
+ }
+ }
+}
+
+static void draw_crack(video::IImage *crack, video::IImage *dst,
+ bool use_overlay, s32 frame_count, s32 progression,
+ video::IVideoDriver *driver)
+{
+ // Dimension of destination image
+ core::dimension2d<u32> dim_dst = dst->getDimension();
+ // Dimension of original image
+ core::dimension2d<u32> dim_crack = crack->getDimension();
+ // Count of crack stages
+ s32 crack_count = dim_crack.Height / dim_crack.Width;
+ // Limit frame_count
+ if(frame_count > (s32) dim_dst.Height)
+ frame_count = dim_dst.Height;
+ if(frame_count < 1)
+ frame_count = 1;
+ // Limit progression
+ if(progression > crack_count-1)
+ progression = crack_count-1;
+ // Dimension of a single crack stage
+ core::dimension2d<u32> dim_crack_cropped(
+ dim_crack.Width,
+ dim_crack.Width
+ );
+ // Dimension of the scaled crack stage,
+ // which is the same as the dimension of a single destination frame
+ core::dimension2d<u32> dim_crack_scaled(
+ dim_dst.Width,
+ dim_dst.Height / frame_count
+ );
+ // Create cropped and scaled crack images
+ video::IImage *crack_cropped = driver->createImage(
+ video::ECF_A8R8G8B8, dim_crack_cropped);
+ video::IImage *crack_scaled = driver->createImage(
+ video::ECF_A8R8G8B8, dim_crack_scaled);
+
+ if(crack_cropped && crack_scaled)
+ {
+ // Crop crack image
+ v2s32 pos_crack(0, progression*dim_crack.Width);
+ crack->copyTo(crack_cropped,
+ v2s32(0,0),
+ core::rect<s32>(pos_crack, dim_crack_cropped));
+ // Scale crack image by copying
+ crack_cropped->copyToScaling(crack_scaled);
+ // Copy or overlay crack image onto each frame
+ for(s32 i = 0; i < frame_count; ++i)
+ {
+ v2s32 dst_pos(0, dim_crack_scaled.Height * i);
+ if(use_overlay)
+ {
+ blit_with_alpha_overlay(crack_scaled, dst,
+ v2s32(0,0), dst_pos,
+ dim_crack_scaled);
+ }
+ else
+ {
+ blit_with_alpha(crack_scaled, dst,
+ v2s32(0,0), dst_pos,
+ dim_crack_scaled);
+ }
+ }
+ }
+
+ if(crack_scaled)
+ crack_scaled->drop();
+
+ if(crack_cropped)
+ crack_cropped->drop();
+}
+
+void brighten(video::IImage *image)