--- /dev/null
+#include "overlayframe.h"
+
+/* Nearest Neighbor scale / translate / blend ********************/
+
+#define XBLEND_3NN(FN, temp_type, type, max, components, ofs, round) { \
+ temp_type opcty = fade * 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, ofs, ofs, round); \
+ ALPHA4_STORE(output, ofs, max); \
+ } \
+ else { \
+ temp_type r, g, b; \
+ ALPHA3_BLEND(FN, temp_type, in_row, output, max, ofs, ofs, round); \
+ ALPHA3_STORE(output, ofs, 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 =
+ 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;
+
+ BLEND_SWITCH(XBLEND_NN);
+}
+
+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;
+}
+
+