Add simple rendering of tiles w/flags (x/y/d flip)

This commit is contained in:
David Capello 2023-07-17 19:37:27 -03:00
parent d114b62483
commit b43fbe2249
2 changed files with 148 additions and 30 deletions

View File

@ -155,7 +155,8 @@ void composite_image_without_scale(
const BlendMode blendMode,
const double sx,
const double sy,
const bool newBlend)
const bool newBlend,
const tile_flags) // Ignored
{
ASSERT(dst);
ASSERT(src);
@ -178,9 +179,9 @@ void composite_image_without_scale(
// Lock all necessary bits
const LockImageBits<SrcTraits> srcBits(src, srcBounds);
LockImageBits<DstTraits> dstBits(dst, dstBounds);
typename LockImageBits<SrcTraits>::const_iterator src_it = srcBits.begin();
auto src_it = srcBits.begin();
#ifdef _DEBUG
typename LockImageBits<SrcTraits>::const_iterator src_end = srcBits.end();
auto src_end = srcBits.end();
#endif
typename LockImageBits<DstTraits>::iterator dst_it, dst_end;
@ -211,7 +212,8 @@ void composite_image_scale_up(
const BlendMode blendMode,
const double sx,
const double sy,
const bool newBlend)
const bool newBlend,
const tile_flags) // Ignored
{
ASSERT(dst);
ASSERT(src);
@ -363,7 +365,8 @@ void composite_image_scale_down(
const BlendMode blendMode,
const double sx,
const double sy,
const bool newBlend)
const bool newBlend,
const tile_flags) // Ignored
{
ASSERT(dst);
ASSERT(src);
@ -431,7 +434,8 @@ void composite_image_general(
const BlendMode blendMode,
const double sx,
const double sy,
const bool newBlend)
const bool newBlend,
const tile_flags) // Ignored
{
ASSERT(dst);
ASSERT(src);
@ -498,10 +502,106 @@ void composite_image_general(
}
template<class DstTraits, class SrcTraits>
CompositeImageFunc get_fastest_composition_path(const Projection& proj,
const bool finegrain)
void composite_image_general_with_tile_flags(
Image* dst, const Image* src, const Palette* pal,
const gfx::ClipF& areaF,
const int opacity,
const BlendMode blendMode,
const double sx,
const double sy,
const bool newBlend,
const tile_flags tileFlags)
{
if (finegrain || !proj.zoom().isSimpleZoomLevel()) {
ASSERT(dst);
ASSERT(src);
ASSERT(DstTraits::pixel_format == dst->pixelFormat());
ASSERT(SrcTraits::pixel_format == src->pixelFormat());
gfx::ClipF area(areaF);
if (!area.clip(dst->width(), dst->height(),
sx*src->width(), sy*src->height()))
return;
BlenderHelper<DstTraits, SrcTraits> blender(src, pal, blendMode, newBlend);
gfx::Rect dstBounds(
area.dstBounds().x, area.dstBounds().y,
int(std::ceil(area.dstBounds().w)),
int(std::ceil(area.dstBounds().h)));
gfx::Rect srcBounds = area.srcBounds();
const gfx::Size srcMinSize = src->size();
dstBounds &= dst->bounds();
if (tileFlags & tile_f_xflip) {
srcBounds.x = src->bounds().x2()-srcBounds.w-srcBounds.x;
}
if (tileFlags & tile_f_yflip) {
srcBounds.y = src->bounds().y2()-srcBounds.h-srcBounds.y;
}
int dstY = dstBounds.y;
for (int y=0; y<dstBounds.h; ++y, ++dstY) {
ASSERT(dstY >= 0 && dstY < dst->height());
auto dstPtr = get_pixel_address_fast<DstTraits>(dst, dstBounds.x, dstY);
#if _DEBUG
int dstX = dstBounds.x;
#endif
for (int x=0; x<dstBounds.w; ++x, ++dstPtr) {
int srcX;
int srcY;
if (tileFlags & tile_f_xflip) {
srcX = (srcBounds.x2()-1-x) / sx;
}
else {
srcX = srcBounds.x+x / sx;
}
if (tileFlags & tile_f_yflip) {
srcY = (srcBounds.y2()-1-y) / sy;
}
else {
srcY = (srcBounds.y+y) / sy;
}
gfx::Size minSize;
if (tileFlags & tile_f_dflip) {
std::swap(srcX, srcY);
minSize.w = minSize.h = std::min(srcMinSize.w, srcMinSize.h);
}
else {
minSize = srcMinSize;
}
ASSERT(dstX >= 0 && dstX < dst->width());
if (srcX >= 0 && srcX < minSize.w &&
srcY >= 0 && srcY < minSize.h) {
auto srcPtr = get_pixel_address_fast<SrcTraits>(src, srcX, srcY);
*dstPtr = blender(*dstPtr, *srcPtr, opacity);
}
else {
*dstPtr = 0;
}
#if _DEBUG
++dstX;
#endif
}
}
}
template<class DstTraits, class SrcTraits>
CompositeImageFunc get_fastest_composition_path(const Projection& proj,
const bool finegrain,
const tile_flags tileFlags)
{
if (tileFlags) {
return composite_image_general_with_tile_flags<DstTraits, SrcTraits>;
}
else if (finegrain || !proj.zoom().isSimpleZoomLevel()) {
return composite_image_general<DstTraits, SrcTraits>;
}
else if (proj.applyX(1) == 1 && proj.applyY(1) == 1) {
@ -976,10 +1076,12 @@ void Render::renderImage(
const int opacity,
const BlendMode blendMode)
{
const tile_flags tileFlags = 0;
CompositeImageFunc compositeImage =
getImageComposition(
dst_image->pixelFormat(),
src_image->pixelFormat(), nullptr);
src_image->pixelFormat(), nullptr, tileFlags);
if (!compositeImage)
return;
@ -991,7 +1093,8 @@ void Render::renderImage(
opacity, blendMode,
m_proj.scaleX(),
m_proj.scaleY(),
m_newBlendMethod);
m_newBlendMethod,
tileFlags);
}
void Render::renderPlan(
@ -1297,7 +1400,7 @@ void Render::renderCel(
continue;
renderImage(dst_image, tile_image.get(), pal, tileBoundsOnCanvas,
area, compositeImage, opacity, blendMode);
area, compositeImage, opacity, blendMode, tile_getf(t));
}
}
}
@ -1315,15 +1418,24 @@ void Render::renderImage(
const Palette* pal,
const gfx::RectF& celBounds,
const gfx::Clip& area,
const CompositeImageFunc compositeImage,
CompositeImageFunc compositeImage,
const int opacity,
const BlendMode blendMode)
const BlendMode blendMode,
const tile_flags tileFlags)
{
gfx::RectF scaledBounds = m_proj.apply(celBounds);
gfx::RectF srcBounds = gfx::RectF(area.srcBounds()).createIntersection(scaledBounds);
if (srcBounds.isEmpty())
return;
// Get the function to composite the tile with the given flip flags
if (tileFlags) {
compositeImage = getImageComposition(
dst_image->pixelFormat(),
cel_image->pixelFormat(),
nullptr, tileFlags);
}
compositeImage(
dst_image, cel_image, pal,
gfx::ClipF(
@ -1337,13 +1449,15 @@ void Render::renderImage(
blendMode,
m_proj.scaleX() * celBounds.w / double(cel_image->width()),
m_proj.scaleY() * celBounds.h / double(cel_image->height()),
m_newBlendMethod);
m_newBlendMethod,
tileFlags);
}
CompositeImageFunc Render::getImageComposition(
const PixelFormat dstFormat,
const PixelFormat srcFormat,
const Layer* layer)
const Layer* layer,
const tile_flags tileFlags)
{
// 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
@ -1362,32 +1476,32 @@ CompositeImageFunc Render::getImageComposition(
case IMAGE_RGB:
switch (dstFormat) {
case IMAGE_RGB: return get_fastest_composition_path<RgbTraits, RgbTraits>(m_proj, finegrain);
case IMAGE_GRAYSCALE: return get_fastest_composition_path<GrayscaleTraits, RgbTraits>(m_proj, finegrain);
case IMAGE_INDEXED: return get_fastest_composition_path<IndexedTraits, RgbTraits>(m_proj, finegrain);
case IMAGE_RGB: return get_fastest_composition_path<RgbTraits, RgbTraits>(m_proj, finegrain, tileFlags);
case IMAGE_GRAYSCALE: return get_fastest_composition_path<GrayscaleTraits, RgbTraits>(m_proj, finegrain, tileFlags);
case IMAGE_INDEXED: return get_fastest_composition_path<IndexedTraits, RgbTraits>(m_proj, finegrain, tileFlags);
}
break;
case IMAGE_GRAYSCALE:
switch (dstFormat) {
case IMAGE_RGB: return get_fastest_composition_path<RgbTraits, GrayscaleTraits>(m_proj, finegrain);
case IMAGE_GRAYSCALE: return get_fastest_composition_path<GrayscaleTraits, GrayscaleTraits>(m_proj, finegrain);
case IMAGE_INDEXED: return get_fastest_composition_path<IndexedTraits, GrayscaleTraits>(m_proj, finegrain);
case IMAGE_RGB: return get_fastest_composition_path<RgbTraits, GrayscaleTraits>(m_proj, finegrain, tileFlags);
case IMAGE_GRAYSCALE: return get_fastest_composition_path<GrayscaleTraits, GrayscaleTraits>(m_proj, finegrain, tileFlags);
case IMAGE_INDEXED: return get_fastest_composition_path<IndexedTraits, GrayscaleTraits>(m_proj, finegrain, tileFlags);
}
break;
case IMAGE_INDEXED:
switch (dstFormat) {
case IMAGE_RGB: return get_fastest_composition_path<RgbTraits, IndexedTraits>(m_proj, finegrain);
case IMAGE_GRAYSCALE: return get_fastest_composition_path<GrayscaleTraits, IndexedTraits>(m_proj, finegrain);
case IMAGE_INDEXED: return get_fastest_composition_path<IndexedTraits, IndexedTraits>(m_proj, finegrain);
case IMAGE_RGB: return get_fastest_composition_path<RgbTraits, IndexedTraits>(m_proj, finegrain, tileFlags);
case IMAGE_GRAYSCALE: return get_fastest_composition_path<GrayscaleTraits, IndexedTraits>(m_proj, finegrain, tileFlags);
case IMAGE_INDEXED: return get_fastest_composition_path<IndexedTraits, IndexedTraits>(m_proj, finegrain, tileFlags);
}
break;
case IMAGE_TILEMAP:
switch (dstFormat) {
case IMAGE_TILEMAP:
return get_fastest_composition_path<TilemapTraits, TilemapTraits>(m_proj, finegrain);
return get_fastest_composition_path<TilemapTraits, TilemapTraits>(m_proj, finegrain, tileFlags);
}
break;
}

View File

@ -15,6 +15,7 @@
#include "doc/doc.h"
#include "doc/frame.h"
#include "doc/pixel_format.h"
#include "doc/tile.h"
#include "gfx/clip.h"
#include "gfx/point.h"
#include "gfx/size.h"
@ -45,7 +46,8 @@ namespace render {
const BlendMode blendMode,
const double sx,
const double sy,
const bool newBlend);
const bool newBlend,
const tile_flags tileFlags);
class Render {
enum Flags {
@ -187,14 +189,16 @@ namespace render {
const Palette* pal,
const gfx::RectF& celBounds,
const gfx::Clip& area,
const CompositeImageFunc compositeImage,
CompositeImageFunc compositeImage,
const int opacity,
const BlendMode blendMode);
const BlendMode blendMode,
const tile_flags tileFlags = notile);
CompositeImageFunc getImageComposition(
const PixelFormat dstFormat,
const PixelFormat srcFormat,
const Layer* layer);
const Layer* layer,
const tile_flags tileFlags = notile);
bool checkIfWeShouldUsePreview(const Cel* cel) const;