graphic art overlay modes, pref window resize, submenu fixes
[goodguy/history.git] / cinelerra-5.1 / cinelerra / overlaysample.C
1 #include "overlayframe.h"
2
3 /* Fully resampled scale / translate / blend ******************************/
4 /* resample into a temporary row vector, then blend */
5
6 #define XSAMPLE(FN, temp_type, type, max, components, ofs, round) { \
7         float temp[oh*components]; \
8         temp_type opcty = fade * max + round, trnsp = max - opcty; \
9         type **output_rows = (type**)voutput->get_rows() + o1i; \
10         type **input_rows = (type**)vinput->get_rows(); \
11  \
12         for(int i = pkg->out_col1; i < pkg->out_col2; i++) { \
13                 type *input = input_rows[i - engine->col_out1 + engine->row_in]; \
14                 float *tempp = temp; \
15                 if( !k ) { /* direct copy case */ \
16                         type *ip = input + i1i * components; \
17                         for(int j = 0; j < oh; j++) { \
18                                 *tempp++ = *ip++; \
19                                 *tempp++ = *ip++ - ofs; \
20                                 *tempp++ = *ip++ - ofs; \
21                                 if( components == 4 ) *tempp++ = *ip++; \
22                         } \
23                 } \
24                 else { /* resample */ \
25                         for(int j = 0; j < oh; j++) { \
26                                 float racc=0.f, gacc=0.f, bacc=0.f, aacc=0.f; \
27                                 int ki = lookup_sk[j], x = lookup_sx0[j]; \
28                                 type *ip = input + x * components; \
29                                 float wacc = 0, awacc = 0; \
30                                 while(x++ < lookup_sx1[j]) { \
31                                         float kv = k[abs(ki >> INDEX_FRACTION)]; \
32                                         /* handle fractional pixels on edges of input */ \
33                                         if(x == i1i) kv *= i1f; \
34                                         if(x + 1 == i2i) kv *= i2f; \
35                                         if( components == 4 ) { awacc += kv;  kv *= ip[3]; } \
36                                         wacc += kv; \
37                                         racc += kv * *ip++; \
38                                         gacc += kv * (*ip++ - ofs); \
39                                         bacc += kv * (*ip++ - ofs); \
40                                         if( components == 4 ) { aacc += kv;  ++ip; } \
41                                         ki += kd; \
42                                 } \
43                                 if(wacc > 0.) wacc = 1. / wacc; \
44                                 *tempp++ = racc * wacc; \
45                                 *tempp++ = gacc * wacc; \
46                                 *tempp++ = bacc * wacc; \
47                                 if( components == 4 ) { \
48                                         if(awacc > 0.) awacc = 1. / awacc; \
49                                         *tempp++ = aacc * awacc; \
50                                 } \
51                         } \
52                 } \
53  \
54                 /* handle fractional pixels on edges of output */ \
55                 temp[0] *= o1f;   temp[1] *= o1f;   temp[2] *= o1f; \
56                 if( components == 4 ) temp[3] *= o1f; \
57                 tempp = temp + (oh-1)*components; \
58                 tempp[0] *= o2f;  tempp[1] *= o2f;  tempp[2] *= o2f; \
59                 if( components == 4 ) tempp[3] *= o2f; \
60                 tempp = temp; \
61                 /* blend output */ \
62                 for(int j = 0; j < oh; j++) { \
63                         type *output = output_rows[j] + i * components; \
64                         if( components == 4 ) { \
65                                 temp_type r, g, b, a; \
66                                 ALPHA4_BLEND(FN, temp_type, tempp, output, max, 0, ofs, round); \
67                                 ALPHA4_STORE(output, ofs, max); \
68                         } \
69                         else { \
70                                 temp_type r, g, b; \
71                                 ALPHA3_BLEND(FN, temp_type, tempp, output, max, 0, ofs, round); \
72                                 ALPHA3_STORE(output, ofs, max); \
73                         } \
74                         tempp += components; \
75                 } \
76         } \
77         break; \
78 }
79
80 #define XBLEND_SAMPLE(FN) { \
81         switch(vinput->get_color_model()) { \
82         case BC_RGB_FLOAT:      XSAMPLE(FN, z_float,   z_float,    1.f,    3, 0.f,    0.f); \
83         case BC_RGBA_FLOAT:     XSAMPLE(FN, z_float,   z_float,    1.f,    4, 0.f,    0.f); \
84         case BC_RGB888:         XSAMPLE(FN, z_int32_t, z_uint8_t,  0xff,   3, 0,      .5f); \
85         case BC_YUV888:         XSAMPLE(FN, z_int32_t, z_uint8_t,  0xff,   3, 0x80,   .5f); \
86         case BC_RGBA8888:       XSAMPLE(FN, z_int32_t, z_uint8_t,  0xff,   4, 0,      .5f); \
87         case BC_YUVA8888:       XSAMPLE(FN, z_int32_t, z_uint8_t,  0xff,   4, 0x80,   .5f); \
88         case BC_RGB161616:      XSAMPLE(FN, z_int64_t, z_uint16_t, 0xffff, 3, 0,      .5f); \
89         case BC_YUV161616:      XSAMPLE(FN, z_int64_t, z_uint16_t, 0xffff, 3, 0x8000, .5f); \
90         case BC_RGBA16161616:   XSAMPLE(FN, z_int64_t, z_uint16_t, 0xffff, 4, 0,      .5f); \
91         case BC_YUVA16161616:   XSAMPLE(FN, z_int64_t, z_uint16_t, 0xffff, 4, 0x8000, .5f); \
92         } \
93         break; \
94 }
95
96
97 SamplePackage::SamplePackage()
98 {
99 }
100
101 SampleUnit::SampleUnit(SampleEngine *server)
102  : LoadClient(server)
103 {
104         this->engine = server;
105 }
106
107 SampleUnit::~SampleUnit()
108 {
109 }
110
111 void SampleUnit::process_package(LoadPackage *package)
112 {
113         SamplePackage *pkg = (SamplePackage*)package;
114
115         float i1  = engine->in1;
116         float i2  = engine->in2;
117         float o1  = engine->out1;
118         float o2  = engine->out2;
119
120         if(i2 - i1 <= 0 || o2 - o1 <= 0)
121                 return;
122
123         VFrame *voutput = engine->output;
124         VFrame *vinput = engine->input;
125         int mode = engine->mode;
126         float fade =
127                 BC_CModels::has_alpha(vinput->get_color_model()) &&
128                 mode == TRANSFER_REPLACE ? 1.f : engine->alpha;
129
130         //int   iw  = vinput->get_w();
131         int   i1i = floor(i1);
132         int   i2i = ceil(i2);
133         float i1f = 1.f - i1 + i1i;
134         float i2f = 1.f - i2i + i2;
135
136         int   o1i = floor(o1);
137         int   o2i = ceil(o2);
138         float o1f = 1.f - o1 + o1i;
139         float o2f = 1.f - o2i + o2;
140         int   oh  = o2i - o1i;
141
142         float *k  = engine->kernel->lookup;
143         //float kw  = engine->kernel->width;
144         //int   kn  = engine->kernel->n;
145         int   kd = engine->kd;
146
147         int *lookup_sx0 = engine->lookup_sx0;
148         int *lookup_sx1 = engine->lookup_sx1;
149         int *lookup_sk = engine->lookup_sk;
150         //float *lookup_wacc = engine->lookup_wacc;
151
152         BLEND_SWITCH(XBLEND_SAMPLE);
153 }
154
155
156 SampleEngine::SampleEngine(int cpus)
157  : LoadServer(cpus, cpus)
158 {
159         lookup_sx0 = 0;
160         lookup_sx1 = 0;
161         lookup_sk = 0;
162         lookup_wacc = 0;
163         kd = 0;
164 }
165
166 SampleEngine::~SampleEngine()
167 {
168         if(lookup_sx0) delete [] lookup_sx0;
169         if(lookup_sx1) delete [] lookup_sx1;
170         if(lookup_sk) delete [] lookup_sk;
171         if(lookup_wacc) delete [] lookup_wacc;
172 }
173
174 /*
175  * unlike the Direct and NN engines, the Sample engine works across
176  * output columns (it makes for more economical memory addressing
177  * during convolution)
178  */
179 void SampleEngine::init_packages()
180 {
181         int   iw  = input->get_w();
182         int   i1i = floor(in1);
183         int   i2i = ceil(in2);
184         float i1f = 1.f - in1 + i1i;
185         float i2f = 1.f - i2i + in2;
186
187         int   oy  = floor(out1);
188         float oyf = out1 - oy;
189         int   oh  = ceil(out2) - oy;
190
191         float *k  = kernel->lookup;
192         float kw  = kernel->width;
193         int   kn  = kernel->n;
194
195         if(in2 - in1 <= 0 || out2 - out1 <= 0)
196                 return;
197
198         /* determine kernel spatial coverage */
199         float scale = (out2 - out1) / (in2 - in1);
200         float iscale = (in2 - in1) / (out2 - out1);
201         float coverage = fabs(1.f / scale);
202         float bound = (coverage < 1.f ? kw : kw * coverage) - (.5f / TRANSFORM_SPP);
203         float coeff = (coverage < 1.f ? 1.f : scale) * TRANSFORM_SPP;
204
205         delete [] lookup_sx0;
206         delete [] lookup_sx1;
207         delete [] lookup_sk;
208         delete [] lookup_wacc;
209
210         lookup_sx0 = new int[oh];
211         lookup_sx1 = new int[oh];
212         lookup_sk = new int[oh];
213         lookup_wacc = new float[oh];
214
215         kd = (double)coeff * (1 << INDEX_FRACTION) + .5;
216
217         /* precompute kernel values and weight sums */
218         for(int i = 0; i < oh; i++) {
219                 /* map destination back to source */
220                 double sx = (i - oyf + .5) * iscale + in1 - .5;
221
222                 /*
223                  * clip iteration to source area but not source plane. Points
224                  * outside the source plane count as transparent. Points outside
225                  * the source area don't count at all.  The actual convolution
226                  * later will be clipped to both, but we need to compute
227                  * weights.
228                  */
229                 int sx0 = mmax((int)floor(sx - bound) + 1, i1i);
230                 int sx1 = mmin((int)ceil(sx + bound), i2i);
231                 int ki = (double)(sx0 - sx) * coeff * (1 << INDEX_FRACTION)
232                                 + (1 << (INDEX_FRACTION - 1)) + .5;
233                 float wacc=0.;
234
235                 lookup_sx0[i] = -1;
236                 lookup_sx1[i] = -1;
237
238                 for(int j= sx0; j < sx1; j++) {
239                         int kv = (ki >> INDEX_FRACTION);
240                         if(kv > kn) break;
241                         if(kv >= -kn) {
242                                 /*
243                                  * the contribution of the first and last input pixel (if
244                                  * fractional) are linearly weighted by the fraction
245                                  */
246                                 if(j == i1i)
247                                         wacc += k[abs(kv)] * i1f;
248                                 else if(j + 1 == i2i)
249                                         wacc += k[abs(kv)] * i2f;
250                                 else
251                                         wacc += k[abs(kv)];
252
253                                 /* this is where we clip the kernel convolution to the source plane */
254                                 if(j >= 0 && j < iw) {
255                                         if(lookup_sx0[i] == -1) {
256                                                 lookup_sx0[i] = j;
257                                                 lookup_sk[i] = ki;
258                                         }
259                                         lookup_sx1[i] = j + 1;
260                                 }
261                         }
262                         ki += kd;
263                 }
264                 lookup_wacc[i] = wacc > 0. ? 1. / wacc : 0.;
265         }
266
267         int cols = col_out2 - col_out1;
268         int pkgs = get_total_packages();
269         int col1 = col_out1, col2 = col1;
270         for(int i = 0; i < pkgs; col1=col2 ) {
271                 SamplePackage *package = (SamplePackage*)get_package(i);
272                 col2 = ++i * cols / pkgs + col_out1;
273                 package->out_col1 = col1;
274                 package->out_col2 = col2;
275         }
276 }
277
278 LoadClient* SampleEngine::new_client()
279 {
280         return new SampleUnit(this);
281 }
282
283 LoadPackage* SampleEngine::new_package()
284 {
285         return new SamplePackage;
286 }
287
288