X-Git-Url: http://git.cinelerra-gg.org/git/?p=goodguy%2Fhistory.git;a=blobdiff_plain;f=cinelerra-5.1%2Fcinelerra%2Foverlayframe.C;h=c8690339a4b62c3a250079106467e5eee64ebd50;hp=4de38e3670ce12afb261ea8983639e8b5496942f;hb=HEAD;hpb=dab459d8fcf93c377836bc30a1c4bc5505b79323 diff --git a/cinelerra-5.1/cinelerra/overlayframe.C b/cinelerra-5.1/cinelerra/overlayframe.C index 4de38e36..c8690339 100644 --- a/cinelerra-5.1/cinelerra/overlayframe.C +++ b/cinelerra-5.1/cinelerra/overlayframe.C @@ -3,71 +3,28 @@ * CINELERRA * Copyright (C) 2008 Adam Williams * Copyright (C) 2012 Monty - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * */ -#include -#include -#include -#include -#include -#include - #include "clip.h" #include "edl.inc" #include "mutex.h" #include "overlayframe.h" #include "units.h" -#include "vframe.h" - -static inline int mabs(int32_t v) { return abs(v); } -static inline int mabs(int64_t v) { return llabs(v); } -static inline float mabs(float v) { return fabsf(v); } - -static inline int32_t aclip(int32_t v, int mx) { - return v < 0 ? 0 : v > mx ? mx : v; -} -static inline int64_t aclip(int64_t v, int mx) { - return v < 0 ? 0 : v > mx ? mx : v; -} -static inline float aclip(float v, float mx) { - return v < 0 ? 0 : v > mx ? mx : v; -} -static inline float aclip(float v, int mx) { - return v < 0 ? 0 : v > mx ? mx : v; -} -static inline int aclip(int v, float mx) { - return v < 0 ? 0 : v > mx ? mx : v; -} -static inline int32_t cclip(int32_t v, int mx) { - return v > (mx/=2) ? mx : v < (mx=(-mx-1)) ? mx : v; -} -static inline int64_t cclip(int64_t v, int mx) { - return v > (mx/=2) ? mx : v < (mx=(-mx-1)) ? mx : v; -} -static inline float cclip(float v, float mx) { - return v > (mx/=2) ? mx : v < (mx=(-mx)) ? mx : v; -} -static inline float cclip(float v, int mx) { - return v > (mx/=2) ? mx : v < (mx=(-mx-1)) ? mx : v; -} -static inline int cclip(int v, float mx) { - return v > (mx/=2) ? mx : v < (mx=(-mx-1)) ? mx : v; -} /* * New resampler code; replace the original somehwat blurry engine @@ -107,19 +64,11 @@ static inline int cclip(int v, float mx) { * output_alpha = output_alpha + ((max - output_alpha) * input_alpha) / max; */ -#define TRANSFORM_SPP (4096) /* number of data pts per unit x in lookup table */ -#define INDEX_FRACTION (8) /* bits of fraction past TRANSFORM_SPP on kernel - index accumulation */ -#define TRANSFORM_MIN (.5 / TRANSFORM_SPP) - /* Sinc needed for Lanczos kernel */ static float sinc(const float x) { + if(fabsf(x) < TRANSFORM_MIN) return 1.0f; float y = x * M_PI; - - if(fabsf(x) < TRANSFORM_MIN) - return 1.0f; - return sinf(y) / y; } @@ -224,17 +173,61 @@ int OverlayFrame::overlay(VFrame *output, VFrame *input, isnan(out_x1) || isnan(out_x2) || isnan(out_y1) || isnan(out_y2)) return 1; - if(in_x1 < 0) in_x1 = 0; - if(in_y1 < 0) in_y1 = 0; - if(in_x2 > input->get_w()) in_x2 = input->get_w(); - if(in_y2 > input->get_h()) in_y2 = input->get_h(); - if(out_x1 < 0) out_x1 = 0; - if(out_y1 < 0) out_y1 = 0; - if(out_x2 > output->get_w()) out_x2 = output->get_w(); - if(out_y2 > output->get_h()) out_y2 = output->get_h(); + if( in_x2 <= in_x1 || in_y2 <= in_y1 ) return 1; + if( out_x2 <= out_x1 || out_y2 <= out_y1 ) return 1; float xscale = (out_x2 - out_x1) / (in_x2 - in_x1); float yscale = (out_y2 - out_y1) / (in_y2 - in_y1); + int in_w = input->get_w(), in_h = input->get_h(); + int out_w = output->get_w(), out_h = output->get_h(); + + if( in_x1 < 0 ) { + out_x1 -= in_x1 * xscale; + in_x1 = 0; + } + if( in_x2 > in_w ) { + out_x2 -= (in_x2 - in_w) * xscale; + in_x2 = in_w; + } + if( in_y1 < 0 ) { + out_y1 -= in_y1 * yscale; + in_y1 = 0; + } + if( in_y2 > in_h ) { + out_y2 -= (in_y2 - in_h) * yscale; + in_y2 = in_h; + } + + if( out_x1 < 0 ) { + in_x1 -= out_x1 / xscale; + out_x1 = 0; + } + if( out_x2 > out_w ) { + in_x2 -= (out_x2 - out_w) / xscale; + out_x2 = out_w; + } + if( out_y1 < 0 ) { + in_y1 -= out_y1 / yscale; + out_y1 = 0; + } + if( out_y2 > out_h ) { + in_y2 -= (out_y2 - out_h) / yscale; + out_y2 = out_h; + } + + if( in_x1 < 0) in_x1 = 0; + if( in_y1 < 0) in_y1 = 0; + if( in_x2 > in_w ) in_x2 = in_w; + if( in_y2 > in_h ) in_y2 = in_h; + if( out_x1 < 0) out_x1 = 0; + if( out_y1 < 0) out_y1 = 0; + if( out_x2 > out_w ) out_x2 = out_w; + if( out_y2 > out_h ) out_y2 = out_h; + + if( in_x2 <= in_x1 || in_y2 <= in_y1 ) return 1; + if( out_x2 <= out_x1 || out_y2 <= out_y1 ) return 1; + xscale = (out_x2 - out_x1) / (in_x2 - in_x1); + yscale = (out_y2 - out_y1) / (in_y2 - in_y1); /* don't interpolate integer translations, or scale no-ops */ if(xscale == 1. && yscale == 1. && @@ -320,8 +313,8 @@ int OverlayFrame::overlay(VFrame *output, VFrame *input, } if(!temp_frame) { - temp_frame = new VFrame(0, -1, temp_w, temp_h, - input->get_color_model(), -1); + temp_frame = + new VFrame(temp_w, temp_h, input->get_color_model(), 0); } temp_frame->clear_frame(); @@ -361,855 +354,4 @@ int OverlayFrame::overlay(VFrame *output, VFrame *input, return 0; } -// NORMAL [Sa + Da * (1 - Sa), Sc * Sa + Dc * (1 - Sa)]) -#define ALPHA_NORMAL(mx, Sa, Da) (Sa + (Da * (mx - Sa)) / mx) -#define COLOR_NORMAL(mx, Sc, Sa, Dc, Da) ((Sc * Sa + Dc * (mx - Sa)) / mx) -#define CHROMA_NORMAL COLOR_NORMAL - -// ADDITION [(Sa + Da), (Sc + Dc)] -#define ALPHA_ADDITION(mx, Sa, Da) (Sa + Da) -#define COLOR_ADDITION(mx, Sc, Sa, Dc, Da) (Sc + Dc) -#define CHROMA_ADDITION(mx, Sc, Sa, Dc, Da) (Sc + Dc) - -// SUBTRACT [(Sa - Da), (Sc - Dc)] -#define ALPHA_SUBTRACT(mx, Sa, Da) (Sa - Da) -#define COLOR_SUBTRACT(mx, Sc, Sa, Dc, Da) (Sc - Dc) -#define CHROMA_SUBTRACT(mx, Sc, Sa, Dc, Da) (Sc - Dc) - -// MULTIPLY [(Sa * Da), Sc * Dc] -#define ALPHA_MULTIPLY(mx, Sa, Da) ((Sa * Da) / mx) -#define COLOR_MULTIPLY(mx, Sc, Sa, Dc, Da) ((Sc * Dc) / mx) -#define CHROMA_MULTIPLY(mx, Sc, Sa, Dc, Da) ((Sc * Dc) / mx) - -// DIVIDE [(Sa / Da), (Sc / Dc)] -#define ALPHA_DIVIDE(mx, Sa, Da) (Da ? ((Sa * mx) / Da) : mx) -#define COLOR_DIVIDE(mx, Sc, Sa, Dc, Da) (Dc ? ((Sc * mx) / Dc) : mx) -#define CHROMA_DIVIDE(mx, Sc, Sa, Dc, Da) (Dc ? ((Sc * mx) / Dc) : mx) - -// REPLACE [Sa, Sc] (fade = 1) -#define ALPHA_REPLACE(mx, Sa, Da) Sa -#define COLOR_REPLACE(mx, Sc, Sa, Dc, Da) Sc -#define CHROMA_REPLACE COLOR_REPLACE - -// MAX [max(Sa, Da), MAX(Sc, Dc)] -#define ALPHA_MAX(mx, Sa, Da) (Sa > Da ? Sa : Da) -#define COLOR_MAX(mx, Sc, Sa, Dc, Da) (Sc > Dc ? Sc : Dc) -#define CHROMA_MAX(mx, Sc, Sa, Dc, Da) (mabs(Sc) > mabs(Dc) ? Sc : Dc) - -// MIN [min(Sa, Da), MIN(Sc, Dc)] -#define ALPHA_MIN(mx, Sa, Da) (Sa < Da ? Sa : Da) -#define COLOR_MIN(mx, Sc, Sa, Dc, Da) (Sc < Dc ? Sc : Dc) -#define CHROMA_MIN(mx, Sc, Sa, Dc, Da) (mabs(Sc) < mabs(Dc) ? Sc : Dc) - -// AVERAGE [(Sa + Da) * 0.5, (Sc + Dc) * 0.5] -#define ALPHA_AVERAGE(mx, Sa, Da) ((Sa + Da) / 2) -#define COLOR_AVERAGE(mx, Sc, Sa, Dc, Da) ((Sc + Dc) / 2) -#define CHROMA_AVERAGE COLOR_AVERAGE - -// DARKEN [Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)] -#define ALPHA_DARKEN(mx, Sa, Da) (Sa + Da - (Sa * Da) / mx) -#define COLOR_DARKEN(mx, Sc, Sa, Dc, Da) ((Sc * (mx - Da) + Dc * (mx - Sa)) / mx + (Sc < Dc ? Sc : Dc)) -#define CHROMA_DARKEN(mx, Sc, Sa, Dc, Da) ((Sc * (mx - Da) + Dc * (mx - Sa)) / mx + (mabs(Sc) < mabs(Dc) ? Sc : Dc)) - -// LIGHTEN [Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)] -#define ALPHA_LIGHTEN(mx, Sa, Da) (Sa + Da - Sa * Da / mx) -#define COLOR_LIGHTEN(mx, Sc, Sa, Dc, Da) ((Sc * (mx - Da) + Dc * (mx - Sa)) / mx + (Sc > Dc ? Sc : Dc)) -#define CHROMA_LIGHTEN(mx, Sc, Sa, Dc, Da) ((Sc * (mx - Da) + Dc * (mx - Sa)) / mx + (mabs(Sc) > mabs(Dc) ? Sc : Dc)) - -// DST [Da, Dc] -#define ALPHA_DST(mx, Sa, Da) Da -#define COLOR_DST(mx, Sc, Sa, Dc, Da) Dc -#define CHROMA_DST COLOR_DST - -// DST_ATOP [Sa, Sc * (1 - Da) + Dc * Sa] -#define ALPHA_DST_ATOP(mx, Sa, Da) Sa -#define COLOR_DST_ATOP(mx, Sc, Sa, Dc, Da) ((Sc * (mx - Da) + Dc * Sa) / mx) -#define CHROMA_DST_ATOP COLOR_DST_ATOP - -// DST_IN [Da * Sa, Dc * Sa] -#define ALPHA_DST_IN(mx, Sa, Da) ((Da * Sa) / mx) -#define COLOR_DST_IN(mx, Sc, Sa, Dc, Da) ((Dc * Sa) / mx) -#define CHROMA_DST_IN COLOR_DST_IN - -// DST_OUT [Da * (1 - Sa), Dc * (1 - Sa)] -#define ALPHA_DST_OUT(mx, Sa, Da) (Da * (mx - Sa) / mx) -#define COLOR_DST_OUT(mx, Sc, Sa, Dc, Da) (Dc * (mx - Sa) / mx) -#define CHROMA_DST_OUT COLOR_DST_OUT - -// DST_OVER [Sa * (1 - Da) + Da, Sc * (1 - Da) + Dc] -#define ALPHA_DST_OVER(mx, Sa, Da) ((Sa * (mx - Da)) / mx + Da) -#define COLOR_DST_OVER(mx, Sc, Sa, Dc, Da) (Sc * (mx - Da)/ mx + Dc) -#define CHROMA_DST_OVER COLOR_DST_OVER - -// SRC [Sa, Sc] -#define ALPHA_SRC(mx, Sa, Da) Sa -#define COLOR_SRC(mx, Sc, Sa, Dc, Da) Sc -#define CHROMA_SRC COLOR_SRC - -// SRC_ATOP [Da, Sc * Da + Dc * (1 - Sa)] -#define ALPHA_SRC_ATOP(mx, Sa, Da) Da -#define COLOR_SRC_ATOP(mx, Sc, Sa, Dc, Da) ((Sc * Da + Dc * (mx - Sa)) / mx) -#define CHROMA_SRC_ATOP COLOR_SRC_ATOP - -// SRC_IN [Sa * Da, Sc * Da] -#define ALPHA_SRC_IN(mx, Sa, Da) ((Sa * Da) / mx) -#define COLOR_SRC_IN(mx, Sc, Sa, Dc, Da) (Sc * Da / mx) -#define CHROMA_SRC_IN COLOR_SRC_IN - -// SRC_OUT [Sa * (1 - Da), Sc * (1 - Da)] -#define ALPHA_SRC_OUT(mx, Sa, Da) (Sa * (mx - Da) / mx) -#define COLOR_SRC_OUT(mx, Sc, Sa, Dc, Da) (Sc * (mx - Da) / mx) -#define CHROMA_SRC_OUT COLOR_SRC_OUT - -// SRC_OVER [Sa + Da * (1 - Sa), Sc + (1 - Sa) * Dc] -#define ALPHA_SRC_OVER(mx, Sa, Da) (Sa + Da * (mx - Sa) / mx) -#define COLOR_SRC_OVER(mx, Sc, Sa, Dc, Da) (Sc + Dc * (mx - Sa) / mx) -#define CHROMA_SRC_OVER COLOR_SRC_OVER - -// OR [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -#define ALPHA_OR(mx, Sa, Da) (Sa + Da - (Sa * Da) / mx) -#define COLOR_OR(mx, Sc, Sa, Dc, Da) (Sc + Dc - (Sc * Dc) / mx) -#define CHROMA_OR COLOR_OR - -// XOR [Sa * (1 - Da) + Da * (1 - Sa), Sc * (1 - Da) + Dc * (1 - Sa)] -#define ALPHA_XOR(mx, Sa, Da) ((Sa * (mx - Da) + Da * (mx - Sa)) / mx) -#define COLOR_XOR(mx, Sc, Sa, Dc, Da) ((Sc * (mx - Da) + Dc * (mx - Sa)) / mx) -#define CHROMA_XOR COLOR_XOR - -#define ZTYP(ty) typedef ty z_##ty __attribute__ ((__unused__)) -ZTYP(int8_t); ZTYP(uint8_t); -ZTYP(int16_t); ZTYP(uint16_t); -ZTYP(int32_t); ZTYP(uint32_t); -ZTYP(int64_t); ZTYP(uint64_t); -ZTYP(float); ZTYP(double); - -#define ALPHA3_BLEND(FN, typ, inp, out, mx, ofs, rnd) \ - typ inp0 = (typ)inp[0], inp1 = (typ)inp[1] - ofs; \ - typ inp2 = (typ)inp[2] - ofs, inp3 = fade * mx + rnd; \ - typ out0 = (typ)out[0], out1 = (typ)out[1] - ofs; \ - typ out2 = (typ)out[2] - ofs, out3 = mx; \ - r = COLOR_##FN(mx, inp0, inp3, out0, out3); \ - if( ofs ) { \ - g = CHROMA_##FN(mx, inp1, inp3, out1, out3); \ - b = CHROMA_##FN(mx, inp2, inp3, out2, out3); \ - } \ - else { \ - g = COLOR_##FN(mx, inp1, inp3, out1, out3); \ - b = COLOR_##FN(mx, inp2, inp3, out2, out3); \ - } - -#define ALPHA4_BLEND(FN, typ, inp, out, mx, ofs, rnd) \ - typ inp0 = (typ)inp[0], inp1 = (typ)inp[1] - ofs; \ - typ inp2 = (typ)inp[2] - ofs, inp3 = (typ)inp[3] * fade + rnd; \ - typ out0 = (typ)out[0], out1 = (typ)out[1] - ofs; \ - typ out2 = (typ)out[2] - ofs, out3 = out[3]; \ - r = COLOR_##FN(mx, inp0, inp3, out0, out3); \ - if( ofs ) { \ - g = CHROMA_##FN(mx, inp1, inp3, out1, out3); \ - b = CHROMA_##FN(mx, inp2, inp3, out2, out3); \ - } \ - else { \ - g = COLOR_##FN(mx, inp1, inp3, out1, out3); \ - b = COLOR_##FN(mx, inp2, inp3, out2, out3); \ - } \ - a = ALPHA_##FN(mx, inp3, out3) - -#define ALPHA_STORE(out, ofs, mx) \ - out[0] = r; \ - out[1] = g + ofs; \ - out[2] = b + ofs - -#define ALPHA3_STORE(out, ofs, mx) \ - r = aclip(r, mx); \ - g = ofs ? cclip(g, mx) : aclip(g, mx); \ - b = ofs ? cclip(b, mx) : aclip(b, mx); \ - if( trnsp ) { \ - r = (r * opcty + out0 * trnsp) / mx; \ - g = (g * opcty + out1 * trnsp) / mx; \ - b = (b * opcty + out2 * trnsp) / mx; \ - } \ - ALPHA_STORE(out, ofs, mx) - -#define ALPHA4_STORE(out, ofs, mx) \ - r = aclip(r, mx); \ - g = ofs ? cclip(g, mx) : aclip(g, mx); \ - b = ofs ? cclip(b, mx) : aclip(b, mx); \ - if( trnsp ) { \ - r = (r * opcty + out0 * trnsp) / mx; \ - g = (g * opcty + out1 * trnsp) / mx; \ - b = (b * opcty + out2 * trnsp) / mx; \ - a = (a * opcty + out3 * trnsp) / mx; \ - } \ - ALPHA_STORE(out, ofs, mx); \ - out[3] = aclip(a, mx) - -#define XBLEND(FN, temp_type, type, max, components, chroma_offset, round) { \ - temp_type opcty = alpha * max + round, trnsp = max - opcty; \ - type** output_rows = (type**)output->get_rows(); \ - type** input_rows = (type**)input->get_rows(); \ - ix *= components; ox *= components; \ - \ - for(int i = pkg->out_row1; i < pkg->out_row2; i++) { \ - type* in_row = input_rows[i + iy] + ix; \ - type* output = output_rows[i] + ox; \ - for(int j = 0; j < ow; j++) { \ - if( components == 4 ) { \ - temp_type r, g, b, a; \ - ALPHA4_BLEND(FN, temp_type, in_row, output, max, chroma_offset, round); \ - ALPHA4_STORE(output, chroma_offset, max); \ - } \ - else { \ - temp_type r, g, b; \ - ALPHA3_BLEND(FN, temp_type, in_row, output, max, chroma_offset, round); \ - ALPHA3_STORE(output, chroma_offset, max); \ - } \ - in_row += components; output += components; \ - } \ - } \ - break; \ -} - -#define XBLEND_ONLY(FN) { \ - switch(input->get_color_model()) { \ - case BC_RGB_FLOAT: XBLEND(FN, z_float, z_float, 1.f, 3, 0, 0.f); \ - case BC_RGBA_FLOAT: XBLEND(FN, z_float, z_float, 1.f, 4, 0, 0.f); \ - case BC_RGB888: XBLEND(FN, z_int32_t, z_uint8_t, 0xff, 3, 0, .5f); \ - case BC_YUV888: XBLEND(FN, z_int32_t, z_uint8_t, 0xff, 3, 0x80, .5f); \ - case BC_RGBA8888: XBLEND(FN, z_int32_t, z_uint8_t, 0xff, 4, 0, .5f); \ - case BC_YUVA8888: XBLEND(FN, z_int32_t, z_uint8_t, 0xff, 4, 0x80, .5f); \ - case BC_RGB161616: XBLEND(FN, z_int64_t, z_uint16_t, 0xffff, 3, 0, .5f); \ - case BC_YUV161616: XBLEND(FN, z_int64_t, z_uint16_t, 0xffff, 3, 0x8000, .5f); \ - case BC_RGBA16161616: XBLEND(FN, z_int64_t, z_uint16_t, 0xffff, 4, 0, .5f); \ - case BC_YUVA16161616: XBLEND(FN, z_int64_t, z_uint16_t, 0xffff, 4, 0x8000, .5f); \ - } \ - break; \ -} - -/* Direct translate / blend **********************************************/ - -DirectPackage::DirectPackage() -{ -} - -DirectUnit::DirectUnit(DirectEngine *server) - : LoadClient(server) -{ - this->engine = server; -} - -DirectUnit::~DirectUnit() -{ -} - -void DirectUnit::process_package(LoadPackage *package) -{ - DirectPackage *pkg = (DirectPackage*)package; - - VFrame *output = engine->output; - VFrame *input = engine->input; - int mode = engine->mode; - float fade = engine->alpha; - float alpha = - BC_CModels::has_alpha(input->get_color_model()) && - mode == TRANSFER_REPLACE ? 1.f : engine->alpha; - - int ix = engine->in_x1; - int ox = engine->out_x1; - int ow = engine->out_x2 - ox; - int iy = engine->in_y1 - engine->out_y1; - - switch( mode ) { - case TRANSFER_NORMAL: XBLEND_ONLY(NORMAL); - case TRANSFER_ADDITION: XBLEND_ONLY(ADDITION); - case TRANSFER_SUBTRACT: XBLEND_ONLY(SUBTRACT); - case TRANSFER_MULTIPLY: XBLEND_ONLY(MULTIPLY); - case TRANSFER_DIVIDE: XBLEND_ONLY(DIVIDE); - case TRANSFER_REPLACE: XBLEND_ONLY(REPLACE); - case TRANSFER_MAX: XBLEND_ONLY(MAX); - case TRANSFER_MIN: XBLEND_ONLY(MIN); - case TRANSFER_AVERAGE: XBLEND_ONLY(AVERAGE); - case TRANSFER_DARKEN: XBLEND_ONLY(DARKEN); - case TRANSFER_LIGHTEN: XBLEND_ONLY(LIGHTEN); - case TRANSFER_DST: XBLEND_ONLY(DST); - case TRANSFER_DST_ATOP: XBLEND_ONLY(DST_ATOP); - case TRANSFER_DST_IN: XBLEND_ONLY(DST_IN); - case TRANSFER_DST_OUT: XBLEND_ONLY(DST_OUT); - case TRANSFER_DST_OVER: XBLEND_ONLY(DST_OVER); - case TRANSFER_SRC: XBLEND_ONLY(SRC); - case TRANSFER_SRC_ATOP: XBLEND_ONLY(SRC_ATOP); - case TRANSFER_SRC_IN: XBLEND_ONLY(SRC_IN); - case TRANSFER_SRC_OUT: XBLEND_ONLY(SRC_OUT); - case TRANSFER_SRC_OVER: XBLEND_ONLY(SRC_OVER); - case TRANSFER_OR: XBLEND_ONLY(OR); - case TRANSFER_XOR: XBLEND_ONLY(XOR); - } -} - -DirectEngine::DirectEngine(int cpus) - : LoadServer(cpus, cpus) -{ -} - -DirectEngine::~DirectEngine() -{ -} - -void DirectEngine::init_packages() -{ - if(in_x1 < 0) { out_x1 -= in_x1; in_x1 = 0; } - if(in_y1 < 0) { out_y1 -= in_y1; in_y1 = 0; } - if(out_x1 < 0) { in_x1 -= out_x1; out_x1 = 0; } - if(out_y1 < 0) { in_y1 -= out_y1; out_y1 = 0; } - if(out_x2 > output->get_w()) out_x2 = output->get_w(); - if(out_y2 > output->get_h()) out_y2 = output->get_h(); - int out_w = out_x2 - out_x1; - int out_h = out_y2 - out_y1; - if( !out_w || !out_h ) return; - - int rows = out_h; - int pkgs = get_total_packages(); - int row1 = out_y1, row2 = row1; - for(int i = 0; i < pkgs; row1=row2 ) { - DirectPackage *package = (DirectPackage*)get_package(i); - row2 = ++i * rows / pkgs + out_y1; - package->out_row1 = row1; - package->out_row2 = row2; - } -} - -LoadClient* DirectEngine::new_client() -{ - return new DirectUnit(this); -} - -LoadPackage* DirectEngine::new_package() -{ - return new DirectPackage; -} - -/* Nearest Neighbor scale / translate / blend ********************/ - -#define XBLEND_3NN(FN, temp_type, type, max, components, chroma_offset, round) { \ - temp_type opcty = alpha * max + round, trnsp = max - opcty; \ - type** output_rows = (type**)output->get_rows(); \ - type** input_rows = (type**)input->get_rows(); \ - ox *= components; \ - \ - for(int i = pkg->out_row1; i < pkg->out_row2; i++) { \ - int *lx = engine->in_lookup_x; \ - type* in_row = input_rows[*ly++]; \ - type* output = output_rows[i] + ox; \ - for(int j = 0; j < ow; j++) { \ - in_row += *lx++; \ - if( components == 4 ) { \ - temp_type r, g, b, a; \ - ALPHA4_BLEND(FN, temp_type, in_row, output, max, chroma_offset, round); \ - ALPHA4_STORE(output, chroma_offset, max); \ - } \ - else { \ - temp_type r, g, b; \ - ALPHA3_BLEND(FN, temp_type, in_row, output, max, chroma_offset, round); \ - ALPHA3_STORE(output, chroma_offset, max); \ - } \ - output += components; \ - } \ - } \ - break; \ -} - -#define XBLEND_NN(FN) { \ - switch(input->get_color_model()) { \ - case BC_RGB_FLOAT: XBLEND_3NN(FN, z_float, z_float, 1.f, 3, 0, 0.f); \ - case BC_RGBA_FLOAT: XBLEND_3NN(FN, z_float, z_float, 1.f, 4, 0, 0.f); \ - case BC_RGB888: XBLEND_3NN(FN, z_int32_t, z_uint8_t, 0xff, 3, 0, .5f); \ - case BC_YUV888: XBLEND_3NN(FN, z_int32_t, z_uint8_t, 0xff, 3, 0x80, .5f); \ - case BC_RGBA8888: XBLEND_3NN(FN, z_int32_t, z_uint8_t, 0xff, 4, 0, .5f); \ - case BC_YUVA8888: XBLEND_3NN(FN, z_int32_t, z_uint8_t, 0xff, 4, 0x80, .5f); \ - case BC_RGB161616: XBLEND_3NN(FN, z_int64_t, z_uint16_t, 0xffff, 3, 0, .5f); \ - case BC_YUV161616: XBLEND_3NN(FN, z_int64_t, z_uint16_t, 0xffff, 3, 0x8000, .5f); \ - case BC_RGBA16161616: XBLEND_3NN(FN, z_int64_t, z_uint16_t, 0xffff, 4, 0, .5f); \ - case BC_YUVA16161616: XBLEND_3NN(FN, z_int64_t, z_uint16_t, 0xffff, 4, 0x8000, .5f); \ - } \ - break; \ -} - -NNPackage::NNPackage() -{ -} -NNUnit::NNUnit(NNEngine *server) - : LoadClient(server) -{ - this->engine = server; -} - -NNUnit::~NNUnit() -{ -} - -void NNUnit::process_package(LoadPackage *package) -{ - NNPackage *pkg = (NNPackage*)package; - VFrame *output = engine->output; - VFrame *input = engine->input; - int mode = engine->mode; - float fade = engine->alpha; - float alpha = - BC_CModels::has_alpha(input->get_color_model()) && - mode == TRANSFER_REPLACE ? 1.f : engine->alpha; - - int ox = engine->out_x1i; - int ow = engine->out_x2i - ox; - int *ly = engine->in_lookup_y + pkg->out_row1; - - switch( mode ) { - case TRANSFER_NORMAL: XBLEND_NN(NORMAL); - case TRANSFER_ADDITION: XBLEND_NN(ADDITION); - case TRANSFER_SUBTRACT: XBLEND_NN(SUBTRACT); - case TRANSFER_MULTIPLY: XBLEND_NN(MULTIPLY); - case TRANSFER_DIVIDE: XBLEND_NN(DIVIDE); - case TRANSFER_REPLACE: XBLEND_NN(REPLACE); - case TRANSFER_MAX: XBLEND_NN(MAX); - case TRANSFER_MIN: XBLEND_NN(MIN); - case TRANSFER_AVERAGE: XBLEND_NN(AVERAGE); - case TRANSFER_DARKEN: XBLEND_NN(DARKEN); - case TRANSFER_LIGHTEN: XBLEND_NN(LIGHTEN); - case TRANSFER_DST: XBLEND_NN(DST); - case TRANSFER_DST_ATOP: XBLEND_NN(DST_ATOP); - case TRANSFER_DST_IN: XBLEND_NN(DST_IN); - case TRANSFER_DST_OUT: XBLEND_NN(DST_OUT); - case TRANSFER_DST_OVER: XBLEND_NN(DST_OVER); - case TRANSFER_SRC: XBLEND_NN(SRC); - case TRANSFER_SRC_ATOP: XBLEND_NN(SRC_ATOP); - case TRANSFER_SRC_IN: XBLEND_NN(SRC_IN); - case TRANSFER_SRC_OUT: XBLEND_NN(SRC_OUT); - case TRANSFER_SRC_OVER: XBLEND_NN(SRC_OVER); - case TRANSFER_OR: XBLEND_NN(OR); - case TRANSFER_XOR: XBLEND_NN(XOR); - } -} - -NNEngine::NNEngine(int cpus) - : LoadServer(cpus, cpus) -{ - in_lookup_x = 0; - in_lookup_y = 0; -} - -NNEngine::~NNEngine() -{ - if(in_lookup_x) - delete[] in_lookup_x; - if(in_lookup_y) - delete[] in_lookup_y; -} - -void NNEngine::init_packages() -{ - int in_w = input->get_w(); - int in_h = input->get_h(); - int out_w = output->get_w(); - int out_h = output->get_h(); - - float in_subw = in_x2 - in_x1; - float in_subh = in_y2 - in_y1; - float out_subw = out_x2 - out_x1; - float out_subh = out_y2 - out_y1; - int first, last, count, i; - int components = 3; - - out_x1i = rint(out_x1); - out_x2i = rint(out_x2); - if(out_x1i < 0) out_x1i = 0; - if(out_x1i > out_w) out_x1i = out_w; - if(out_x2i < 0) out_x2i = 0; - if(out_x2i > out_w) out_x2i = out_w; - int out_wi = out_x2i - out_x1i; - if( !out_wi ) return; - - delete[] in_lookup_x; - in_lookup_x = new int[out_wi]; - delete[] in_lookup_y; - in_lookup_y = new int[out_h]; - - switch(input->get_color_model()) { - case BC_RGBA_FLOAT: - case BC_RGBA8888: - case BC_YUVA8888: - case BC_RGBA16161616: - components = 4; - break; - } - - first = count = 0; - - for(i = out_x1i; i < out_x2i; i++) { - int in = (i - out_x1 + .5) * in_subw / out_subw + in_x1; - if(in < in_x1) - in = in_x1; - if(in > in_x2) - in = in_x2; - - if(in >= 0 && in < in_w && in >= in_x1 && i >= 0 && i < out_w) { - if(count == 0) { - first = i; - in_lookup_x[0] = in * components; - } - else { - in_lookup_x[count] = (in-last)*components; - } - last = in; - count++; - } - else if(count) - break; - } - out_x1i = first; - out_x2i = first + count; - first = count = 0; - - for(i = out_y1; i < out_y2; i++) { - int in = (i - out_y1+.5) * in_subh / out_subh + in_y1; - if(in < in_y1) in = in_y1; - if(in > in_y2) in = in_y2; - if(in >= 0 && in < in_h && i >= 0 && i < out_h) { - if(count == 0) first = i; - in_lookup_y[i] = in; - count++; - } - else if(count) - break; - } - out_y1 = first; - out_y2 = first + count; - - int rows = count; - int pkgs = get_total_packages(); - int row1 = out_y1, row2 = row1; - for(int i = 0; i < pkgs; row1=row2 ) { - NNPackage *package = (NNPackage*)get_package(i); - row2 = ++i * rows / pkgs + out_y1; - package->out_row1 = row1; - package->out_row2 = row2; - } -} - -LoadClient* NNEngine::new_client() -{ - return new NNUnit(this); -} - -LoadPackage* NNEngine::new_package() -{ - return new NNPackage; -} - -/* Fully resampled scale / translate / blend ******************************/ -/* resample into a temporary row vector, then blend */ - -#define XSAMPLE(FN, temp_type, type, max, components, chroma_offset, round) { \ - float temp[oh*components]; \ - temp_type opcty = alpha * max + round, trnsp = max - opcty; \ - type **output_rows = (type**)voutput->get_rows() + o1i; \ - type **input_rows = (type**)vinput->get_rows(); \ - \ - for(int i = pkg->out_col1; i < pkg->out_col2; i++) { \ - type *input = input_rows[i - engine->col_out1 + engine->row_in]; \ - float *tempp = temp; \ - if( !k ) { /* direct copy case */ \ - type *ip = input + i1i * components; \ - for(int j = 0; j < oh; j++) { \ - *tempp++ = *ip++; \ - *tempp++ = *ip++ - chroma_offset; \ - *tempp++ = *ip++ - chroma_offset; \ - if( components == 4 ) *tempp++ = *ip++; \ - } \ - } \ - else { /* resample */ \ - for(int j = 0; j < oh; j++) { \ - float racc=0.f, gacc=0.f, bacc=0.f, aacc=0.f; \ - int ki = lookup_sk[j], x = lookup_sx0[j]; \ - type *ip = input + x * components; \ - float wacc = 0, awacc = 0; \ - while(x++ < lookup_sx1[j]) { \ - float kv = k[abs(ki >> INDEX_FRACTION)]; \ - /* handle fractional pixels on edges of input */ \ - if(x == i1i) kv *= i1f; \ - if(x + 1 == i2i) kv *= i2f; \ - if( components == 4 ) { awacc += kv; kv *= ip[3]; } \ - wacc += kv; \ - racc += kv * *ip++; \ - gacc += kv * (*ip++ - chroma_offset); \ - bacc += kv * (*ip++ - chroma_offset); \ - if( components == 4 ) { aacc += kv; ++ip; } \ - ki += kd; \ - } \ - if(wacc > 0.) wacc = 1. / wacc; \ - *tempp++ = racc * wacc; \ - *tempp++ = gacc * wacc; \ - *tempp++ = bacc * wacc; \ - if( components == 4 ) { \ - if(awacc > 0.) awacc = 1. / awacc; \ - *tempp++ = aacc * awacc; \ - } \ - } \ - } \ - \ - /* handle fractional pixels on edges of output */ \ - temp[0] *= o1f; temp[1] *= o1f; temp[2] *= o1f; \ - if( components == 4 ) temp[3] *= o1f; \ - tempp = temp + (oh-1)*components; \ - tempp[0] *= o2f; tempp[1] *= o2f; tempp[2] *= o2f; \ - if( components == 4 ) tempp[3] *= o2f; \ - tempp = temp; \ - /* blend output */ \ - for(int j = 0; j < oh; j++) { \ - type *output = output_rows[j] + i * components; \ - if( components == 4 ) { \ - temp_type r, g, b, a; \ - ALPHA4_BLEND(FN, temp_type, tempp, output, max, 0, round); \ - ALPHA4_STORE(output, chroma_offset, max); \ - } \ - else { \ - temp_type r, g, b; \ - ALPHA3_BLEND(FN, temp_type, tempp, output, max, 0, round); \ - ALPHA3_STORE(output, chroma_offset, max); \ - } \ - tempp += components; \ - } \ - } \ - break; \ -} - -#define XBLEND_SAMPLE(FN) { \ - switch(vinput->get_color_model()) { \ - case BC_RGB_FLOAT: XSAMPLE(FN, z_float, z_float, 1.f, 3, 0.f, 0.f); \ - case BC_RGBA_FLOAT: XSAMPLE(FN, z_float, z_float, 1.f, 4, 0.f, 0.f); \ - case BC_RGB888: XSAMPLE(FN, z_int32_t, z_uint8_t, 0xff, 3, 0, .5f); \ - case BC_YUV888: XSAMPLE(FN, z_int32_t, z_uint8_t, 0xff, 3, 0x80, .5f); \ - case BC_RGBA8888: XSAMPLE(FN, z_int32_t, z_uint8_t, 0xff, 4, 0, .5f); \ - case BC_YUVA8888: XSAMPLE(FN, z_int32_t, z_uint8_t, 0xff, 4, 0x80, .5f); \ - case BC_RGB161616: XSAMPLE(FN, z_int64_t, z_uint16_t, 0xffff, 3, 0, .5f); \ - case BC_YUV161616: XSAMPLE(FN, z_int64_t, z_uint16_t, 0xffff, 3, 0x8000, .5f); \ - case BC_RGBA16161616: XSAMPLE(FN, z_int64_t, z_uint16_t, 0xffff, 4, 0, .5f); \ - case BC_YUVA16161616: XSAMPLE(FN, z_int64_t, z_uint16_t, 0xffff, 4, 0x8000, .5f); \ - } \ - break; \ -} - - -SamplePackage::SamplePackage() -{ -} - -SampleUnit::SampleUnit(SampleEngine *server) - : LoadClient(server) -{ - this->engine = server; -} - -SampleUnit::~SampleUnit() -{ -} - -void SampleUnit::process_package(LoadPackage *package) -{ - SamplePackage *pkg = (SamplePackage*)package; - - float i1 = engine->in1; - float i2 = engine->in2; - float o1 = engine->out1; - float o2 = engine->out2; - - if(i2 - i1 <= 0 || o2 - o1 <= 0) - return; - - VFrame *voutput = engine->output; - VFrame *vinput = engine->input; - int mode = engine->mode; - float fade = engine->alpha; - float alpha = - BC_CModels::has_alpha(vinput->get_color_model()) && - mode == TRANSFER_REPLACE ? 1.f : engine->alpha; - - //int iw = vinput->get_w(); - int i1i = floor(i1); - int i2i = ceil(i2); - float i1f = 1.f - i1 + i1i; - float i2f = 1.f - i2i + i2; - - int o1i = floor(o1); - int o2i = ceil(o2); - float o1f = 1.f - o1 + o1i; - float o2f = 1.f - o2i + o2; - int oh = o2i - o1i; - - float *k = engine->kernel->lookup; - //float kw = engine->kernel->width; - //int kn = engine->kernel->n; - int kd = engine->kd; - - int *lookup_sx0 = engine->lookup_sx0; - int *lookup_sx1 = engine->lookup_sx1; - int *lookup_sk = engine->lookup_sk; - //float *lookup_wacc = engine->lookup_wacc; - - switch( mode ) { - case TRANSFER_NORMAL: XBLEND_SAMPLE(NORMAL); - case TRANSFER_ADDITION: XBLEND_SAMPLE(ADDITION); - case TRANSFER_SUBTRACT: XBLEND_SAMPLE(SUBTRACT); - case TRANSFER_MULTIPLY: XBLEND_SAMPLE(MULTIPLY); - case TRANSFER_DIVIDE: XBLEND_SAMPLE(DIVIDE); - case TRANSFER_REPLACE: XBLEND_SAMPLE(REPLACE); - case TRANSFER_MAX: XBLEND_SAMPLE(MAX); - case TRANSFER_MIN: XBLEND_SAMPLE(MIN); - case TRANSFER_AVERAGE: XBLEND_SAMPLE(AVERAGE); - case TRANSFER_DARKEN: XBLEND_SAMPLE(DARKEN); - case TRANSFER_LIGHTEN: XBLEND_SAMPLE(LIGHTEN); - case TRANSFER_DST: XBLEND_SAMPLE(DST); - case TRANSFER_DST_ATOP: XBLEND_SAMPLE(DST_ATOP); - case TRANSFER_DST_IN: XBLEND_SAMPLE(DST_IN); - case TRANSFER_DST_OUT: XBLEND_SAMPLE(DST_OUT); - case TRANSFER_DST_OVER: XBLEND_SAMPLE(DST_OVER); - case TRANSFER_SRC: XBLEND_SAMPLE(SRC); - case TRANSFER_SRC_ATOP: XBLEND_SAMPLE(SRC_ATOP); - case TRANSFER_SRC_IN: XBLEND_SAMPLE(SRC_IN); - case TRANSFER_SRC_OUT: XBLEND_SAMPLE(SRC_OUT); - case TRANSFER_SRC_OVER: XBLEND_SAMPLE(SRC_OVER); - case TRANSFER_OR: XBLEND_SAMPLE(OR); - case TRANSFER_XOR: XBLEND_SAMPLE(XOR); - } -} - - -SampleEngine::SampleEngine(int cpus) - : LoadServer(cpus, cpus) -{ - lookup_sx0 = 0; - lookup_sx1 = 0; - lookup_sk = 0; - lookup_wacc = 0; - kd = 0; -} - -SampleEngine::~SampleEngine() -{ - if(lookup_sx0) delete [] lookup_sx0; - if(lookup_sx1) delete [] lookup_sx1; - if(lookup_sk) delete [] lookup_sk; - if(lookup_wacc) delete [] lookup_wacc; -} - -/* - * unlike the Direct and NN engines, the Sample engine works across - * output columns (it makes for more economical memory addressing - * during convolution) - */ -void SampleEngine::init_packages() -{ - int iw = input->get_w(); - int i1i = floor(in1); - int i2i = ceil(in2); - float i1f = 1.f - in1 + i1i; - float i2f = 1.f - i2i + in2; - - int oy = floor(out1); - float oyf = out1 - oy; - int oh = ceil(out2) - oy; - - float *k = kernel->lookup; - float kw = kernel->width; - int kn = kernel->n; - - if(in2 - in1 <= 0 || out2 - out1 <= 0) - return; - - /* determine kernel spatial coverage */ - float scale = (out2 - out1) / (in2 - in1); - float iscale = (in2 - in1) / (out2 - out1); - float coverage = fabs(1.f / scale); - float bound = (coverage < 1.f ? kw : kw * coverage) - (.5f / TRANSFORM_SPP); - float coeff = (coverage < 1.f ? 1.f : scale) * TRANSFORM_SPP; - - delete [] lookup_sx0; - delete [] lookup_sx1; - delete [] lookup_sk; - delete [] lookup_wacc; - - lookup_sx0 = new int[oh]; - lookup_sx1 = new int[oh]; - lookup_sk = new int[oh]; - lookup_wacc = new float[oh]; - - kd = (double)coeff * (1 << INDEX_FRACTION) + .5; - - /* precompute kernel values and weight sums */ - for(int i = 0; i < oh; i++) { - /* map destination back to source */ - double sx = (i - oyf + .5) * iscale + in1 - .5; - - /* - * clip iteration to source area but not source plane. Points - * outside the source plane count as transparent. Points outside - * the source area don't count at all. The actual convolution - * later will be clipped to both, but we need to compute - * weights. - */ - int sx0 = MAX((int)floor(sx - bound) + 1, i1i); - int sx1 = MIN((int)ceil(sx + bound), i2i); - int ki = (double)(sx0 - sx) * coeff * (1 << INDEX_FRACTION) - + (1 << (INDEX_FRACTION - 1)) + .5; - float wacc=0.; - - lookup_sx0[i] = -1; - lookup_sx1[i] = -1; - - for(int j= sx0; j < sx1; j++) { - int kv = (ki >> INDEX_FRACTION); - if(kv > kn) break; - if(kv >= -kn) { - /* - * the contribution of the first and last input pixel (if - * fractional) are linearly weighted by the fraction - */ - if(j == i1i) - wacc += k[abs(kv)] * i1f; - else if(j + 1 == i2i) - wacc += k[abs(kv)] * i2f; - else - wacc += k[abs(kv)]; - - /* this is where we clip the kernel convolution to the source plane */ - if(j >= 0 && j < iw) { - if(lookup_sx0[i] == -1) { - lookup_sx0[i] = j; - lookup_sk[i] = ki; - } - lookup_sx1[i] = j + 1; - } - } - ki += kd; - } - lookup_wacc[i] = wacc > 0. ? 1. / wacc : 0.; - } - - int cols = col_out2 - col_out1; - int pkgs = get_total_packages(); - int col1 = col_out1, col2 = col1; - for(int i = 0; i < pkgs; col1=col2 ) { - SamplePackage *package = (SamplePackage*)get_package(i); - col2 = ++i * cols / pkgs + col_out1; - package->out_col1 = col1; - package->out_col2 = col2; - } -} - -LoadClient* SampleEngine::new_client() -{ - return new SampleUnit(this); -} - -LoadPackage* SampleEngine::new_package() -{ - return new SamplePackage; -}