Credit Andrew - improve in-tree documentation
[goodguy/cinelerra.git] / cinelerra / overlaynearest.C
1 #include "overlayframe.h"
2
3 /* Nearest Neighbor scale / translate / blend ********************/
4
5 #define XBLEND_3NN(FN, temp_type, type, max, components, ofs, round) { \
6         temp_type opcty = fade * max + round, trnsp = max - opcty; \
7         type** output_rows = (type**)output->get_rows(); \
8         type** input_rows = (type**)input->get_rows(); \
9         ox *= components; \
10  \
11         for(int i = pkg->out_row1; i < pkg->out_row2; i++) { \
12                 int *lx = engine->in_lookup_x; \
13                 type* in_row = input_rows[*ly++]; \
14                 type* output = output_rows[i] + ox; \
15                 for(int j = 0; j < ow; j++) { \
16                         in_row += *lx++; \
17                         if( components == 4 ) { \
18                                 temp_type r, g, b, a; \
19                                 ALPHA4_BLEND(FN, temp_type, in_row, output, max, ofs, ofs, round); \
20                                 ALPHA4_STORE(output, ofs, max); \
21                         } \
22                         else { \
23                                 temp_type r, g, b; \
24                                 ALPHA3_BLEND(FN, temp_type, in_row, output, max, ofs, ofs, round); \
25                                 ALPHA3_STORE(output, ofs, max); \
26                         } \
27                         output += components; \
28                 } \
29         } \
30         break; \
31 }
32
33 #define XBLEND_NN(FN) { \
34         switch(input->get_color_model()) { \
35         case BC_RGB_FLOAT:      XBLEND_3NN(FN, z_float,   z_float,    1.f,    3, 0,       0.f); \
36         case BC_RGBA_FLOAT:     XBLEND_3NN(FN, z_float,   z_float,    1.f,    4, 0,       0.f); \
37         case BC_RGB888:         XBLEND_3NN(FN, z_int32_t, z_uint8_t,  0xff,   3, 0,      .5f); \
38         case BC_YUV888:         XBLEND_3NN(FN, z_int32_t, z_uint8_t,  0xff,   3, 0x80,   .5f); \
39         case BC_RGBA8888:       XBLEND_3NN(FN, z_int32_t, z_uint8_t,  0xff,   4, 0,      .5f); \
40         case BC_YUVA8888:       XBLEND_3NN(FN, z_int32_t, z_uint8_t,  0xff,   4, 0x80,   .5f); \
41         case BC_RGB161616:      XBLEND_3NN(FN, z_int64_t, z_uint16_t, 0xffff, 3, 0,      .5f); \
42         case BC_YUV161616:      XBLEND_3NN(FN, z_int64_t, z_uint16_t, 0xffff, 3, 0x8000, .5f); \
43         case BC_RGBA16161616:   XBLEND_3NN(FN, z_int64_t, z_uint16_t, 0xffff, 4, 0,      .5f); \
44         case BC_YUVA16161616:   XBLEND_3NN(FN, z_int64_t, z_uint16_t, 0xffff, 4, 0x8000, .5f); \
45         } \
46         break; \
47 }
48
49 NNPackage::NNPackage()
50 {
51 }
52
53 NNUnit::NNUnit(NNEngine *server)
54  : LoadClient(server)
55 {
56         this->engine = server;
57 }
58
59 NNUnit::~NNUnit()
60 {
61 }
62
63 void NNUnit::process_package(LoadPackage *package)
64 {
65         NNPackage *pkg = (NNPackage*)package;
66         VFrame *output = engine->output;
67         VFrame *input = engine->input;
68         int mode = engine->mode;
69         float fade =
70                 BC_CModels::has_alpha(input->get_color_model()) &&
71                 mode == TRANSFER_REPLACE ? 1.f : engine->alpha;
72
73         int ox = engine->out_x1i;
74         int ow = engine->out_x2i - ox;
75         int *ly = engine->in_lookup_y + pkg->out_row1;
76
77         BLEND_SWITCH(XBLEND_NN);
78 }
79
80 NNEngine::NNEngine(int cpus)
81  : LoadServer(cpus, cpus)
82 {
83         in_lookup_x = 0;
84         in_lookup_y = 0;
85 }
86
87 NNEngine::~NNEngine()
88 {
89         if(in_lookup_x)
90                 delete[] in_lookup_x;
91         if(in_lookup_y)
92                 delete[] in_lookup_y;
93 }
94
95 void NNEngine::init_packages()
96 {
97         int in_w = input->get_w();
98         int in_h = input->get_h();
99         int out_w = output->get_w();
100         int out_h = output->get_h();
101
102         float in_subw = in_x2 - in_x1;
103         float in_subh = in_y2 - in_y1;
104         float out_subw = out_x2 - out_x1;
105         float out_subh = out_y2 - out_y1;
106         int first, last, count, i;
107         int components = 3;
108
109         out_x1i = rint(out_x1);
110         out_x2i = rint(out_x2);
111         if(out_x1i < 0) out_x1i = 0;
112         if(out_x1i > out_w) out_x1i = out_w;
113         if(out_x2i < 0) out_x2i = 0;
114         if(out_x2i > out_w) out_x2i = out_w;
115         int out_wi = out_x2i - out_x1i;
116         if( !out_wi ) return;
117
118         delete[] in_lookup_x;
119         in_lookup_x = new int[out_wi];
120         delete[] in_lookup_y;
121         in_lookup_y = new int[out_h];
122
123         switch(input->get_color_model()) {
124         case BC_RGBA_FLOAT:
125         case BC_RGBA8888:
126         case BC_YUVA8888:
127         case BC_RGBA16161616:
128                 components = 4;
129                 break;
130         }
131
132         first = count = 0;
133
134         for(i = out_x1i; i < out_x2i; i++) {
135                 int in = (i - out_x1 + .5) * in_subw / out_subw + in_x1;
136                 if(in < in_x1)
137                         in = in_x1;
138                 if(in > in_x2)
139                         in = in_x2;
140
141                 if(in >= 0 && in < in_w && in >= in_x1 && i >= 0 && i < out_w) {
142                         if(count == 0) {
143                                 first = i;
144                                 in_lookup_x[0] = in * components;
145                         }
146                         else {
147                                 in_lookup_x[count] = (in-last)*components;
148                         }
149                         last = in;
150                         count++;
151                 }
152                 else if(count)
153                         break;
154         }
155         out_x1i = first;
156         out_x2i = first + count;
157         first = count = 0;
158
159         for(i = out_y1; i < out_y2; i++) {
160                 int in = (i - out_y1+.5) * in_subh / out_subh + in_y1;
161                 if(in < in_y1) in = in_y1;
162                 if(in > in_y2) in = in_y2;
163                 if(in >= 0 && in < in_h && i >= 0 && i < out_h) {
164                         if(count == 0) first = i;
165                         in_lookup_y[i] = in;
166                         count++;
167                 }
168                 else if(count)
169                         break;
170         }
171         out_y1 = first;
172         out_y2 = first + count;
173
174         int rows = count;
175         int pkgs = get_total_packages();
176         int row1 = out_y1, row2 = row1;
177         for(int i = 0; i < pkgs; row1=row2 ) {
178                 NNPackage *package = (NNPackage*)get_package(i);
179                 row2 = ++i * rows / pkgs + out_y1;
180                 package->out_row1 = row1;
181                 package->out_row2 = row2;
182         }
183 }
184
185 LoadClient* NNEngine::new_client()
186 {
187         return new NNUnit(this);
188 }
189
190 LoadPackage* NNEngine::new_package()
191 {
192         return new NNPackage;
193 }
194
195