diff --git a/src/gfx/clip.h b/src/gfx/clip.h index a8ad02f8a..8364e2e06 100644 --- a/src/gfx/clip.h +++ b/src/gfx/clip.h @@ -63,6 +63,13 @@ namespace gfx { , size(bounds.w, bounds.h) { } + template + ClipT(const ClipT& other) + : dst(other.dst) + , src(other.src) + , size(other.size) { + } + RectT dstBounds() const { return RectT(dst, size); } RectT srcBounds() const { return RectT(src, size); } diff --git a/src/render/render.cpp b/src/render/render.cpp index bebe4add2..c861760f8 100644 --- a/src/render/render.cpp +++ b/src/render/render.cpp @@ -131,17 +131,14 @@ public: } }; -#if 0 - template void composite_image_without_scale( - Image* dst, - const Image* src, - const Palette* pal, - const gfx::Clip& _area, + Image* dst, const Image* src, const Palette* pal, + const gfx::ClipF& areaF, const int opacity, const BlendMode blendMode, - const Projection& proj) + const double sx, + const double sy) { ASSERT(dst); ASSERT(src); @@ -150,7 +147,7 @@ void composite_image_without_scale( BlenderHelper blender(src, pal, blendMode); - gfx::Clip area = _area; + gfx::Clip area(areaF); if (!area.clip(dst->width(), dst->height(), src->width(), src->height())) return; @@ -189,33 +186,36 @@ void composite_image_without_scale( template void composite_image_scale_up( - Image* dst, - const Image* src, - const Palette* pal, - const gfx::Clip& _area, + Image* dst, const Image* src, const Palette* pal, + const gfx::ClipF& areaF, const int opacity, const BlendMode blendMode, - const Projection& proj) + const double sx, + const double sy) { ASSERT(dst); ASSERT(src); ASSERT(DstTraits::pixel_format == dst->pixelFormat()); ASSERT(SrcTraits::pixel_format == src->pixelFormat()); - gfx::Clip area = _area; + gfx::Clip area(areaF); if (!area.clip(dst->width(), dst->height(), - proj.applyX(src->width()), - proj.applyY(src->height()))) + int(sx*double(src->width())), + int(sy*double(src->height())))) return; BlenderHelper blender(src, pal, blendMode); int px_x, px_y; - int px_w = proj.applyX(1); - int px_h = proj.applyY(1); + int px_w = sx; + int px_h = sy; int first_px_w = px_w - (area.src.x % px_w); int first_px_h = px_h - (area.src.y % px_h); - gfx::Rect srcBounds = proj.remove(area.srcBounds()); + gfx::Rect srcBounds = area.srcBounds(); + srcBounds.w = (srcBounds.x+srcBounds.w)/px_w - srcBounds.x/px_w; + srcBounds.h = (srcBounds.y+srcBounds.h)/px_h - srcBounds.y/px_h; + srcBounds.x /= px_w; + srcBounds.y /= px_h; if ((area.src.x+area.size.w) % px_w > 0) ++srcBounds.w; if ((area.src.y+area.size.h) % px_h > 0) ++srcBounds.h; if (srcBounds.isEmpty()) @@ -326,29 +326,34 @@ done_with_blit:; template void composite_image_scale_down( Image* dst, const Image* src, const Palette* pal, - const gfx::Clip& _area, + const gfx::ClipF& areaF, const int opacity, const BlendMode blendMode, - const Projection& proj) + const double sx, + const double sy) { ASSERT(dst); ASSERT(src); ASSERT(DstTraits::pixel_format == dst->pixelFormat()); ASSERT(SrcTraits::pixel_format == src->pixelFormat()); - gfx::Clip area = _area; + gfx::Clip area(areaF); if (!area.clip(dst->width(), dst->height(), - proj.applyX(src->width()), - proj.applyY(src->height()))) + int(sx*double(src->width())), + int(sy*double(src->height())))) return; BlenderHelper blender(src, pal, blendMode); - int step_w = proj.removeX(1); - int step_h = proj.removeY(1); + int step_w = 1.0 / sx; + int step_h = 1.0 / sy; if (step_w < 1 || step_h < 1) return; - gfx::Rect srcBounds = proj.remove(area.srcBounds()); + gfx::Rect srcBounds = area.srcBounds(); + srcBounds.w = (srcBounds.x+srcBounds.w)*step_w - srcBounds.x*step_w; + srcBounds.h = (srcBounds.y+srcBounds.h)*step_h - srcBounds.y*step_h; + srcBounds.x *= step_w; + srcBounds.y *= step_h; if (srcBounds.isEmpty()) return; @@ -383,70 +388,10 @@ void composite_image_scale_down( } } -template -void composite_image_scale_down_non_square_pixel_ratio( - Image* dst, const Image* src, const Palette* pal, - const gfx::Clip& _area, - const int opacity, - const BlendMode blendMode, - const Projection& proj) -{ - ASSERT(dst); - ASSERT(src); - ASSERT(DstTraits::pixel_format == dst->pixelFormat()); - ASSERT(SrcTraits::pixel_format == src->pixelFormat()); - - gfx::Clip area = _area; - if (!area.clip(dst->width(), dst->height(), - proj.applyX(src->width()), - proj.applyY(src->height()))) - return; - - BlenderHelper blender(src, pal, blendMode); - float step_w = proj.removeX(1.0f); - float step_h = proj.removeY(1.0f); - if (step_w < 1.0f || step_h < 1.0f) - return; - - gfx::Rect srcBounds = proj.remove(area.srcBounds()); - if (srcBounds.isEmpty()) - return; - - gfx::Rect dstBounds = area.dstBounds(); - - // Lock all necessary bits - LockImageBits dstBits(dst, dstBounds); - auto dst_it = dstBits.begin(); - auto dst_end = dstBits.end(); - - // For each line to draw of the source image... - float v = float(srcBounds.y); - for (int y=0; y= dstBits.begin() && dst_it < dst_end); - - *dst_it = blender(*dst_it, - get_pixel_fast(src, int(u), int(v)), - opacity); - - // Skip columns - u += step_w; - ++dst_it; - } - - // Skip rows - v += step_h; - } -} - -#else - template void composite_image_general( Image* dst, const Image* src, const Palette* pal, - const gfx::ClipF& _area, + const gfx::ClipF& areaF, const int opacity, const BlendMode blendMode, const double sx, @@ -457,14 +402,14 @@ void composite_image_general( ASSERT(DstTraits::pixel_format == dst->pixelFormat()); ASSERT(SrcTraits::pixel_format == src->pixelFormat()); - gfx::ClipF area = _area; + gfx::ClipF area(areaF); if (!area.clip(dst->width(), dst->height(), sx*src->width(), sy*src->height())) return; BlenderHelper blender(src, pal, blendMode); - gfx::RectF dstBounds = area.dstBounds(); + gfx::Rect dstBounds = area.dstBounds(); gfx::RectF srcBounds = area.srcBounds(); int dstY = dstBounds.y; @@ -487,13 +432,14 @@ void composite_image_general( } } -#endif - template -CompositeImageFunc get_image_composition_impl(const Projection& proj) +CompositeImageFunc get_fastest_composition_path(const Projection& proj, + const bool finegrain) { -#if 0 - if (proj.applyX(1) == 1 && proj.applyY(1) == 1) { + if (finegrain) { + return composite_image_general; + } + else if (proj.applyX(1) == 1 && proj.applyY(1) == 1) { return composite_image_without_scale; } else if (proj.scaleX() >= 1.0 && proj.scaleY() >= 1.0) { @@ -502,49 +448,27 @@ CompositeImageFunc get_image_composition_impl(const Projection& proj) // Slower composite function for special cases with odd zoom and non-square pixel ratio else if (((proj.removeX(1) > 1) && (proj.removeX(1) & 1)) || ((proj.removeY(1) > 1) && (proj.removeY(1) & 1))) { - return composite_image_scale_down_non_square_pixel_ratio; + return composite_image_general; } else { return composite_image_scale_down; } -#else - return composite_image_general; -#endif } -CompositeImageFunc get_image_composition(const PixelFormat dstFormat, - const PixelFormat srcFormat, - const Projection& proj) +bool has_visible_reference_layers(const LayerGroup* group) { - switch (srcFormat) { + for (const Layer* child : group->layers()) { + if (!child->isVisible()) + continue; - case IMAGE_RGB: - switch (dstFormat) { - case IMAGE_RGB: return get_image_composition_impl(proj); - case IMAGE_GRAYSCALE: return get_image_composition_impl(proj); - case IMAGE_INDEXED: return get_image_composition_impl(proj); - } - break; + if (child->isReference()) + return true; - case IMAGE_GRAYSCALE: - switch (dstFormat) { - case IMAGE_RGB: return get_image_composition_impl(proj); - case IMAGE_GRAYSCALE: return get_image_composition_impl(proj); - case IMAGE_INDEXED: return get_image_composition_impl(proj); - } - break; - - case IMAGE_INDEXED: - switch (dstFormat) { - case IMAGE_RGB: return get_image_composition_impl(proj); - case IMAGE_GRAYSCALE: return get_image_composition_impl(proj); - case IMAGE_INDEXED: return get_image_composition_impl(proj); - } - break; + if (child->isGroup() && + has_visible_reference_layers(static_cast(child))) + return true; } - - ASSERT(false && "Invalid pixel formats"); - return NULL; + return false; } } // anonymous namespace @@ -674,9 +598,9 @@ void Render::renderLayer( m_sprite = layer->sprite(); CompositeImageFunc compositeImage = - get_image_composition( + getImageComposition( dstImage->pixelFormat(), - m_sprite->pixelFormat(), m_proj); + m_sprite->pixelFormat(), layer); if (!compositeImage) return; @@ -696,9 +620,9 @@ void Render::renderSprite( m_sprite = sprite; CompositeImageFunc compositeImage = - get_image_composition( + getImageComposition( dstImage->pixelFormat(), - m_sprite->pixelFormat(), m_proj); + m_sprite->pixelFormat(), sprite->root()); if (!compositeImage) return; @@ -900,9 +824,9 @@ void Render::renderImage( const BlendMode blendMode) { CompositeImageFunc compositeImage = - get_image_composition( + getImageComposition( dst_image->pixelFormat(), - src_image->pixelFormat(), m_proj); + src_image->pixelFormat(), nullptr); if (!compositeImage) return; @@ -1113,6 +1037,54 @@ void Render::renderImage( m_proj.scaleY() * double(cel_image->height()) / celBounds.h); } +CompositeImageFunc Render::getImageComposition( + const PixelFormat dstFormat, + const PixelFormat srcFormat, + const Layer* layer) +{ + // True if we need blending pixel by pixel. If this is false we can + // blend src+dst one time and repeat the resulting color in dst + // image n-times (where n is the zoom scale). + const bool finegrain = + (m_bgCheckedSize.w < m_proj.applyX(1) || + m_bgCheckedSize.h < m_proj.applyY(1) || + // Check if we are rendering reference images with zoom scale > 1 + ((m_proj.applyX(1) > 1 || m_proj.applyY(1) > 1) && + layer && + layer->isGroup() && + has_visible_reference_layers(static_cast(layer)))); + + switch (srcFormat) { + + case IMAGE_RGB: + switch (dstFormat) { + case IMAGE_RGB: return get_fastest_composition_path(m_proj, finegrain); + case IMAGE_GRAYSCALE: return get_fastest_composition_path(m_proj, finegrain); + case IMAGE_INDEXED: return get_fastest_composition_path(m_proj, finegrain); + } + break; + + case IMAGE_GRAYSCALE: + switch (dstFormat) { + case IMAGE_RGB: return get_fastest_composition_path(m_proj, finegrain); + case IMAGE_GRAYSCALE: return get_fastest_composition_path(m_proj, finegrain); + case IMAGE_INDEXED: return get_fastest_composition_path(m_proj, finegrain); + } + break; + + case IMAGE_INDEXED: + switch (dstFormat) { + case IMAGE_RGB: return get_fastest_composition_path(m_proj, finegrain); + case IMAGE_GRAYSCALE: return get_fastest_composition_path(m_proj, finegrain); + case IMAGE_INDEXED: return get_fastest_composition_path(m_proj, finegrain); + } + break; + } + + ASSERT(false && "Invalid pixel formats"); + return nullptr; +} + void composite_image(Image* dst, const Image* src, const Palette* pal, diff --git a/src/render/render.h b/src/render/render.h index 23b8893b9..e70009378 100644 --- a/src/render/render.h +++ b/src/render/render.h @@ -208,6 +208,11 @@ namespace render { const int opacity, const BlendMode blendMode); + CompositeImageFunc getImageComposition( + const PixelFormat dstFormat, + const PixelFormat srcFormat, + const Layer* layer); + const Sprite* m_sprite; const Layer* m_currentLayer; frame_t m_currentFrame;