void CompoundUpdateInputVisitor::_updateZoom( const Compound* compound, Frame* frame, const Frame* outputFrame ) { Zoom zoom = frame->getNativeZoom(); if( !zoom.isValid( )) // if zoom is not set, inherit from parent zoom = compound->getInheritZoom(); // Zoom difference between output and input const FrameData* frameData = outputFrame->getMasterData(); zoom /= frameData->getZoom(); frame->setZoom( zoom ); }
static void merge_zoomed_image(Image* dst, const Image* src, const Palette* pal, int x, int y, int opacity, int blend_mode, Zoom zoom) { if (zoom.scale() >= 1.0) merge_zoomed_image_scale_up<DstTraits, SrcTraits>(dst, src, pal, x, y, opacity, blend_mode, zoom); else merge_zoomed_image_scale_down<DstTraits, SrcTraits>(dst, src, pal, x, y, opacity, blend_mode, zoom); }
void Engine::iterBuildPoints( const Skeleton& skelet, const Zoom& zoom, Image& image, const int imax ) const { if ( Function::system == LINEAR ) { for ( int i = 1; i <= imax; ++i ) { skelet.nextPoint( _x, _y, _color ); zoom.toScreen( _x, _y ); image.mem_plot( zoom.screenX, zoom.screenY ); image.mem_coul( zoom.screenX, zoom.screenY, _color ); } } else if ( Function::system == FORMULA || Function::system == SINUSOIDAL ) { // since initial conditions are important, we have to give a new seed to the orbit _x = (float)rand()*2/RAND_MAX - 1; _y = (float)rand()*2/RAND_MAX - 1; skelet.setXY( _x, _y, _color ); // put the seed in the orbit for ( int i = 1; i <= imax; ++i ) { skelet.nextPoint( _x, _y, _color ); zoom.toScreen( _x, _y ); image.mem_plot( zoom.screenX, zoom.screenY ); image.mem_coul( zoom.screenX, zoom.screenY, _color ); if ( i % 1000 == 0 ) { _x = (float)rand()*2/RAND_MAX - 1; _y = (float)rand()*2/RAND_MAX - 1; skelet.setXY( _x, _y, _color ); } } } else { // JULIA Julia& j = zoom.julia; for ( int i = 1; i <= imax; ++i ) { skelet.nextPoint( _x, _y, _color ); zoom.toScreen( _x, _y ); j.handle( _x, _y, image.getHit( zoom.screenX, zoom.screenY ) ); image.mem_plot( zoom.screenX, zoom.screenY ); image.mem_coul( zoom.screenX, zoom.screenY, _color ); } } }
void RenderEngine::renderLayer( const Layer* layer, Image *image, int source_x, int source_y, FrameNumber frame, Zoom zoom, void (*zoomed_func)(Image*, const Image*, const Palette*, int, int, int, int, Zoom), bool render_background, bool render_transparent, int blend_mode) { // we can't read from this layer if (!layer->isVisible()) return; switch (layer->type()) { case ObjectType::LayerImage: { if ((!render_background && layer->isBackground()) || (!render_transparent && !layer->isBackground())) break; const Cel* cel = static_cast<const LayerImage*>(layer)->getCel(frame); if (cel != NULL) { Image* src_image; // Is the 'preview_image' set to be used with this layer? if ((selected_layer == layer) && (selected_frame == frame) && (preview_image != NULL)) { src_image = preview_image; } // If not, we use the original cel-image from the images' stock else { src_image = cel->image(); } if (src_image) { int t, output_opacity; output_opacity = MID(0, cel->opacity(), 255); output_opacity = INT_MULT(output_opacity, global_opacity, t); ASSERT(src_image->maskColor() == m_sprite->transparentColor()); (*zoomed_func)(image, src_image, m_sprite->getPalette(frame), zoom.apply(cel->x()) - source_x, zoom.apply(cel->y()) - source_y, output_opacity, (blend_mode < 0 ? static_cast<const LayerImage*>(layer)->getBlendMode(): blend_mode), zoom); } } break; } case ObjectType::LayerFolder: { LayerConstIterator it = static_cast<const LayerFolder*>(layer)->getLayerBegin(); LayerConstIterator end = static_cast<const LayerFolder*>(layer)->getLayerEnd(); for (; it != end; ++it) { renderLayer(*it, image, source_x, source_y, frame, zoom, zoomed_func, render_background, render_transparent, blend_mode); } break; } } // Draw extras if (m_document->getExtraCel() && layer == m_currentLayer && frame == m_currentFrame) { Cel* extraCel = m_document->getExtraCel(); if (extraCel->opacity() > 0) { Image* extraImage = m_document->getExtraCelImage(); (*zoomed_func)(image, extraImage, m_sprite->getPalette(frame), zoom.apply(extraCel->x()) - source_x, zoom.apply(extraCel->y()) - source_y, extraCel->opacity(), m_document->getExtraCelBlendMode(), zoom); } } }
// static void RenderEngine::renderCheckedBackground(Image* image, int source_x, int source_y, Zoom zoom) { int x, y, u, v; int tile_w = 16; int tile_h = 16; int c1 = color_utils::color_for_image(checked_bg_color1, image->pixelFormat()); int c2 = color_utils::color_for_image(checked_bg_color2, image->pixelFormat()); switch (checked_bg_type) { case CHECKED_BG_16X16: tile_w = 16; tile_h = 16; break; case CHECKED_BG_8X8: tile_w = 8; tile_h = 8; break; case CHECKED_BG_4X4: tile_w = 4; tile_h = 4; break; case CHECKED_BG_2X2: tile_w = 2; tile_h = 2; break; } if (checked_bg_zoom) { tile_w = zoom.apply(tile_w); tile_h = zoom.apply(tile_h); } // Tile size if (tile_w < zoom.apply(1)) tile_w = zoom.apply(1); if (tile_h < zoom.apply(1)) tile_h = zoom.apply(1); if (tile_w < 1) tile_w = 1; if (tile_h < 1) tile_h = 1; // Tile position (u,v) is the number of tile we start in (source_x,source_y) coordinate u = (source_x / tile_w); v = (source_y / tile_h); // Position where we start drawing the first tile in "image" int x_start = -(source_x % tile_w); int y_start = -(source_y % tile_h); // Draw checked background (tile by tile) int u_start = u; for (y=y_start-tile_h; y<image->height()+tile_h; y+=tile_h) { for (x=x_start-tile_w; x<image->width()+tile_w; x+=tile_w) { fill_rect(image, x, y, x+tile_w-1, y+tile_h-1, (((u+v))&1)? c1: c2); ++u; } u = u_start; ++v; } }
static void merge_zoomed_image_scale_down(Image* dst, const Image* src, const Palette* pal, int x, int y, int opacity, int blend_mode, Zoom zoom) { BlenderHelper<DstTraits, SrcTraits> blender(src, pal, blend_mode); int src_x, src_y, src_w, src_h; int dst_x, dst_y, dst_w, dst_h; int unbox_w, unbox_h; int bottom; unbox_w = zoom.remove(1); unbox_h = zoom.remove(1); src_x = 0; src_y = 0; src_w = src->width(); src_h = src->height(); dst_x = x; dst_y = y; dst_w = zoom.apply(src->width()); dst_h = zoom.apply(src->height()); // clipping... if (dst_x < 0) { src_x += zoom.remove(-dst_x); src_w -= zoom.remove(-dst_x); dst_w -= (-dst_x); dst_x = 0; } if (dst_y < 0) { src_y += zoom.remove(-dst_y); src_h -= zoom.remove(-dst_y); dst_h -= (-dst_y); dst_y = 0; } if (dst_x+dst_w > dst->width()) { src_w -= zoom.remove(dst_x+dst_w-dst->width()); dst_w = dst->width() - dst_x; } if (dst_y+dst_h > dst->height()) { src_h -= zoom.remove(dst_y+dst_h-dst->height()); dst_h = dst->height() - dst_y; } src_w = zoom.remove(zoom.apply(src_w)); src_h = zoom.remove(zoom.apply(src_h)); if ((src_w <= 0) || (src_h <= 0) || (dst_w <= 0) || (dst_h <= 0)) return; bottom = dst_y+dst_h-1; // Lock all necessary bits const LockImageBits<SrcTraits> srcBits(src, gfx::Rect(src_x, src_y, src_w, src_h)); LockImageBits<DstTraits> dstBits(dst, gfx::Rect(dst_x, dst_y, dst_w, dst_h)); typename LockImageBits<SrcTraits>::const_iterator src_it = srcBits.begin(); typename LockImageBits<SrcTraits>::const_iterator src_end = srcBits.end(); typename LockImageBits<DstTraits>::iterator dst_it, dst_end; // For each line to draw of the source image... for (y=0; y<src_h; y+=unbox_h) { dst_it = dstBits.begin_area(gfx::Rect(dst_x, dst_y, dst_w, 1)); dst_end = dstBits.end_area(gfx::Rect(dst_x, dst_y, dst_w, 1)); for (x=0; x<src_w; x+=unbox_w) { ASSERT(src_it >= srcBits.begin() && src_it < src_end); ASSERT(dst_it >= dstBits.begin() && dst_it < dst_end); blender(*dst_it, *dst_it, *src_it, opacity); // Skip source pixels for (int delta=0; delta < unbox_w && src_it != src_end; ++delta) ++src_it; ++dst_it; } if (++dst_y > bottom) break; // Skip lines for (int delta=0; delta < src_w * (unbox_h-1) && src_it != src_end; ++delta) ++src_it; } }
static void merge_zoomed_image_scale_up(Image* dst, const Image* src, const Palette* pal, int x, int y, int opacity, int blend_mode, Zoom zoom) { BlenderHelper<DstTraits, SrcTraits> blender(src, pal, blend_mode); int src_x, src_y, src_w, src_h; int dst_x, dst_y, dst_w, dst_h; int box_x, box_y, box_w, box_h; int first_box_w, first_box_h; int line_h, bottom; box_w = zoom.apply(1); box_h = zoom.apply(1); src_x = 0; src_y = 0; src_w = src->width(); src_h = src->height(); dst_x = x; dst_y = y; dst_w = zoom.apply(src->width()); dst_h = zoom.apply(src->height()); // clipping... if (dst_x < 0) { src_x += zoom.remove(-dst_x); src_w -= zoom.remove(-dst_x); dst_w -= (-dst_x); first_box_w = box_w - ((-dst_x) % box_w); dst_x = 0; } else first_box_w = 0; if (dst_y < 0) { src_y += zoom.remove(-dst_y); src_h -= zoom.remove(-dst_y); dst_h -= (-dst_y); first_box_h = box_h - ((-dst_y) % box_h); dst_y = 0; } else first_box_h = 0; if (dst_x+dst_w > dst->width()) { src_w -= zoom.remove(dst_x+dst_w-dst->width()); dst_w = dst->width() - dst_x; } if (dst_y+dst_h > dst->height()) { src_h -= zoom.remove(dst_y+dst_h-dst->height()); dst_h = dst->height() - dst_y; } if ((src_w <= 0) || (src_h <= 0) || (dst_w <= 0) || (dst_h <= 0)) return; bottom = dst_y+dst_h-1; // the scanline variable is used to blend src/dst pixels one time for each pixel typedef std::vector<typename DstTraits::pixel_t> Scanline; Scanline scanline(src_w); typename Scanline::iterator scanline_it; #ifdef _DEBUG typename Scanline::iterator scanline_end = scanline.end(); #endif // Lock all necessary bits const LockImageBits<SrcTraits> srcBits(src, gfx::Rect(src_x, src_y, src_w, src_h)); LockImageBits<DstTraits> dstBits(dst, gfx::Rect(dst_x, dst_y, dst_w, dst_h)); typename LockImageBits<SrcTraits>::const_iterator src_it = srcBits.begin(); #ifdef _DEBUG typename LockImageBits<SrcTraits>::const_iterator src_end = srcBits.end(); #endif typename LockImageBits<DstTraits>::iterator dst_it, dst_end; // For each line to draw of the source image... for (y=0; y<src_h; ++y) { dst_it = dstBits.begin_area(gfx::Rect(dst_x, dst_y, dst_w, 1)); dst_end = dstBits.end_area(gfx::Rect(dst_x, dst_y, dst_w, 1)); // Read 'src' and 'dst' and blend them, put the result in `scanline' scanline_it = scanline.begin(); for (x=0; x<src_w; ++x) { ASSERT(src_it >= srcBits.begin() && src_it < src_end); ASSERT(dst_it >= dstBits.begin() && dst_it < dst_end); ASSERT(scanline_it >= scanline.begin() && scanline_it < scanline_end); blender(*scanline_it, *dst_it, *src_it, opacity); ++src_it; int delta; if ((x == 0) && (first_box_w > 0)) delta = first_box_w; else delta = box_w; while (dst_it != dst_end && delta-- > 0) ++dst_it; ++scanline_it; } // Get the 'height' of the line to be painted in 'dst' if ((y == 0) && (first_box_h > 0)) line_h = first_box_h; else line_h = box_h; // Draw the line in 'dst' for (box_y=0; box_y<line_h; ++box_y) { dst_it = dstBits.begin_area(gfx::Rect(dst_x, dst_y, dst_w, 1)); dst_end = dstBits.end_area(gfx::Rect(dst_x, dst_y, dst_w, 1)); scanline_it = scanline.begin(); x = 0; // first pixel if (first_box_w > 0) { for (box_x=0; box_x<first_box_w; ++box_x) { ASSERT(scanline_it != scanline_end); ASSERT(dst_it != dst_end); *dst_it = *scanline_it; ++dst_it; if (dst_it == dst_end) goto done_with_line; } ++scanline_it; ++x; } // the rest of the line for (; x<src_w; ++x) { for (box_x=0; box_x<box_w; ++box_x) { ASSERT(dst_it != dst_end); *dst_it = *scanline_it; ++dst_it; if (dst_it == dst_end) goto done_with_line; } ++scanline_it; } done_with_line:; if (++dst_y > bottom) goto done_with_blit; } // go to the next line in the source image ++src_y; } done_with_blit:; }
void CompoundUpdateOutputVisitor::_updateZoom(const Compound* compound, Frame* frame) { Zoom zoom = frame->getNativeZoom(); Zoom zoom_1; if (!zoom.isValid()) // if zoom is not set, auto-calculate from parent { zoom_1 = compound->getInheritZoom(); LBASSERT(zoom_1.isValid()); zoom.x() = 1.0f / zoom_1.x(); zoom.y() = 1.0f / zoom_1.y(); } else { zoom_1.x() = 1.0f / zoom.x(); zoom_1.y() = 1.0f / zoom.y(); } if (frame->getType() == Frame::TYPE_TEXTURE) { FrameData* frameData = frame->getMasterData(); frameData->setZoom(zoom_1); // textures are zoomed by input frame frame->setZoom(Zoom::NONE); } else { Zoom inputZoom; /* Output frames downscale pixel data during readback, and upscale it on * the input frame by setting the input frame's inherit zoom. */ if (zoom.x() > 1.0f) { inputZoom.x() = zoom_1.x(); zoom.x() = 1.f; } if (zoom.y() > 1.0f) { inputZoom.y() = zoom_1.y(); zoom.y() = 1.f; } FrameData* frameData = frame->getMasterData(); frameData->setZoom(inputZoom); frame->setZoom(zoom); } }
void Engine::zoom() { const int imagesWidth = ( state == SAVEMNG ) ? animationSavedWidth : w(); const int imagesHeight = ( state == SAVEMNG ) ? animationSavedHeight : h(); Skeleton skelSubframe; // we must check that we are not going to zoom inside the zoom function: if ( skel.selected() == 0 ) { // this section should be synchronized since the selected function // can be changed before its use by Skeleton::subframe skel.shiftSelectedFunction(1); } skelSubframe.subframe(skel); Function functionWork; const Zoom zoom( skel.findFrame( pointsForFraming, _x, _y, _color ), imagesWidth, imagesHeight, skel.getZoomFunction(), framesPerCycle ); for ( std::vector< Image* >::const_iterator i = images.begin(); i != images.end(); ++i ) { delete *i; } images.clear(); for ( int i = 0; i < framesPerCycle; ++i ) { images.push_back( buildImage( imagesWidth, imagesHeight, w(), h() ) ); } int idemo = 1; const int idemoMax = 3; unsigned long clock0 = clock(); const float dilat0 = 1.0/skelSubframe.getFunction().surface(); const float dilat1 = 1.0/skel.getFunction().surface(); const float otherDilat = 1.0/(skel.sumSurfaces() - skel.getFunction().surface()); while ( idemo <= idemoMax ) { for ( int k = 0; k < framesPerCycle; ++k ) { const float rate = (float)k / framesPerCycle; functionWork.spiralMix( skel.getFunction(), skelSubframe.getFunction(), rate ); functionWork.calculateTemp(); int pointsToCalculate = pointsPerFrame; if ( state == SAVEMNG) { // points(t) = points(0)*(1 + S/s(t) * (1/s(t) - 1/s(0))/(1/s(1) - 1/s(0)) ) pointsToCalculate = (int)( ( 1.0 + (1/functionWork.surface()-dilat0) / (dilat1-dilat0) * dilat1 / otherDilat ) * pointsPerFrame ); // to avoid explosion of computation time: if ( pointsToCalculate > 100 * pointsPerFrame ) { pointsToCalculate = 100 * pointsPerFrame; } } for ( int i = 1; clockNumber || i < pointsToCalculate; ++i ) { skel.nextPoint( _x, _y, _color ); float zx = _x; float zy = _y; functionWork.previousPoint( zx, zy, false ); zoom.toScreen( zx, zy ); images[k]->mem_plot( zoom.screenX, zoom.screenY ); images[k]->mem_coul( zoom.screenX, zoom.screenY, _color ); if ( clockNumber ) { if ( i % minimalBuiltPoints == 0 ) { const unsigned long newClock = clock(); if ( newClock - clock0 >= intervalFrame * timecv ) { clock0 = newClock; break; } } } } make_current(); images[k]->mem_draw(); if ( Fl::ready() ) { Fl::check(); } if ( state != ANIMATION && state != DEMO && state != SAVEMNG ) { return; } } if ( state == DEMO ) { ++idemo; } if ( state == SAVEMNG ) { return; } } }