prevent popup deactivation while button_down
[goodguy/history.git] / cinelerra-5.0 / cinelerra / virtualvnode.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  * 
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * 
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  * 
20  */
21
22 #include "automation.h"
23 #include "bcsignals.h"
24 #include "clip.h"
25 #include "edits.h"
26 #include "edl.h"
27 #include "edlsession.h"
28 #include "fadeengine.h"
29 #include "floatauto.h"
30 #include "floatautos.h"
31 #include "format.inc"
32 #include "intauto.h"
33 #include "intautos.h"
34 #include "maskauto.h"
35 #include "maskautos.h"
36 #include "maskengine.h"
37 #include "mwindow.h"
38 #include "module.h"
39 #include "overlayframe.h"
40 #include "plugin.h"
41 #include "preferences.h"
42 #include "renderengine.h"
43 #include "transition.h"
44 #include "transportque.h"
45 #include "vattachmentpoint.h"
46 #include "vdevicex11.h"
47 #include "vframe.h"
48 #include "videodevice.h"
49 #include "virtualvconsole.h"
50 #include "virtualvnode.h"
51 #include "vmodule.h"
52 #include "vrender.h"
53 #include "vtrack.h"
54
55 #include <string.h>
56
57
58 VirtualVNode::VirtualVNode(RenderEngine *renderengine, 
59                 VirtualConsole *vconsole, Module *real_module, 
60                 Plugin *real_plugin, Track *track,
61                 VirtualNode *parent_node)
62  : VirtualNode(renderengine, vconsole, real_module, real_plugin,
63                 track, parent_node)
64 {
65         //VRender *vrender = ((VirtualVConsole*)vconsole)->vrender;
66         fader = new FadeEngine(renderengine->preferences->processors);
67         masker = new MaskEngine(renderengine->preferences->processors);
68         alpha = 1;
69 }
70
71 VirtualVNode::~VirtualVNode()
72 {
73         delete fader;
74         delete masker;
75 }
76
77 VirtualNode* VirtualVNode::create_module(Plugin *real_plugin, 
78                                                         Module *real_module, 
79                                                         Track *track)
80 {
81         return new VirtualVNode(renderengine, vconsole, 
82                 real_module, 0, track, this);
83 }
84
85
86 VirtualNode* VirtualVNode::create_plugin(Plugin *real_plugin)
87 {
88         return new VirtualVNode(renderengine, vconsole, 
89                 0, real_plugin, track, this);
90 }
91
92 int VirtualVNode::read_data(VFrame *output_temp,
93         int64_t start_position, double frame_rate, int use_opengl)
94 {
95         VirtualNode *previous_plugin = 0;
96         int result = 0;
97
98         if(!output_temp) 
99                 printf("VirtualVNode::read_data output_temp=%p\n", output_temp);
100
101         if(vconsole->debug_tree) 
102                 printf("  VirtualVNode::read_data position=" _LD " rate=%f title=%s opengl=%d\n", 
103                         start_position, frame_rate, track->title, use_opengl);
104
105 // If there is a parent module but the parent module has no data source,
106 // use our own data source.
107 // Current edit in parent track
108         VEdit *parent_edit = 0;
109         if(parent_node && parent_node->track && renderengine)
110         {
111                 double edl_rate = renderengine->get_edl()->session->frame_rate;
112                 int64_t start_position_project = (int64_t)(start_position *
113                         edl_rate / frame_rate + 0.5);
114                 parent_edit = (VEdit*)parent_node->track->edits->editof(start_position_project, 
115                         renderengine->command->get_direction(), 0);
116         }
117
118
119 // This is a plugin on parent module with a preceeding effect.
120 // Get data from preceeding effect on parent module.
121         if(parent_node && (previous_plugin = parent_node->get_previous_plugin(this)))
122         {
123                 result = ((VirtualVNode*)previous_plugin)->render(output_temp,
124                         start_position, frame_rate, use_opengl);
125         }
126         else
127 // The current node is the first plugin on parent module.
128 // The parent module has an edit to read from or the current node
129 // has no source to read from.
130 // Read data from parent module
131         if(parent_node && (parent_edit || !real_module))
132         {
133                 result = ((VirtualVNode*)parent_node)->read_data(output_temp,
134                         start_position, frame_rate, use_opengl);
135         }
136         else
137         if(real_module)
138         {
139 // This is the first node in the tree
140                 result = ((VModule*)real_module)->render(output_temp,
141                         start_position, renderengine->command->get_direction(),
142                         frame_rate, 0, vconsole->debug_tree, use_opengl);
143         }
144
145         return result;
146 }
147
148
149 int VirtualVNode::render(VFrame *output_temp, 
150         int64_t start_position,
151         double frame_rate,
152         int use_opengl)
153 {
154         VRender *vrender = ((VirtualVConsole*)vconsole)->vrender;
155         if(real_module)
156         {
157                 render_as_module(vrender->video_out, output_temp,
158                         start_position, frame_rate, use_opengl);
159         }
160         else
161         if(real_plugin)
162         {
163                 render_as_plugin(output_temp,
164                         start_position, frame_rate, use_opengl);
165         }
166         return 0;
167 }
168
169 void VirtualVNode::render_as_plugin(VFrame *output_temp, 
170         int64_t start_position,
171         double frame_rate,
172         int use_opengl)
173 {
174         if(!attachment || !real_plugin || !real_plugin->on) return;
175
176
177         if(vconsole->debug_tree) 
178                 printf("  VirtualVNode::render_as_plugin title=%s use_opengl=%d\n", 
179                         track->title, use_opengl);
180
181         ((VAttachmentPoint*)attachment)->render(
182                 output_temp, plugin_buffer_number, start_position,
183                 frame_rate, vconsole->debug_tree, use_opengl);
184 }
185
186
187 int VirtualVNode::render_as_module(VFrame *video_out, 
188         VFrame *output_temp,
189         int64_t start_position,
190         double frame_rate,
191         int use_opengl)
192 {
193
194         int direction = renderengine->command->get_direction();
195         double edl_rate = renderengine->get_edl()->session->frame_rate;
196
197
198
199
200
201 // Get position relative to project, compensated for direction
202         int64_t start_position_project = (int64_t)(start_position *
203                 edl_rate / 
204                 frame_rate);
205         if(direction == PLAY_REVERSE) start_position_project--;
206
207
208 // speed curve
209         if(track->has_speed())
210         {
211 // integrate position from start of track.  1/speed is duration of each frame
212                 
213         }
214
215         if(vconsole->debug_tree) 
216                 printf("  VirtualVNode::render_as_module title=%s use_opengl=%d video_out=%p output_temp=%p\n", 
217                         track->title, use_opengl, video_out, output_temp);
218
219         output_temp->push_next_effect("VirtualVNode::render_as_module");
220
221 // Process last subnode.  This propogates up the chain of subnodes and finishes
222 // the chain.
223         if(subnodes.total)
224         {
225                 VirtualVNode *node = (VirtualVNode*)subnodes.values[subnodes.total - 1];
226                 node->render(output_temp, start_position, frame_rate, use_opengl);
227         }
228         else
229 // Read data from previous entity
230         {
231                 read_data(output_temp, start_position, frame_rate, use_opengl);
232         }
233
234         output_temp->pop_next_effect();
235
236         render_fade(output_temp, start_position,
237                 frame_rate, track->automation->autos[AUTOMATION_FADE],
238                 direction, use_opengl);
239
240         render_mask(output_temp, start_position_project, use_opengl);
241
242
243 // overlay on the final output
244 // Get mute status
245         int mute_constant;
246         int mute_fragment = 1;
247
248
249 // Is frame muted?
250         get_mute_fragment(start_position, mute_constant, mute_fragment, 
251                         (Autos*)((VTrack*)track)->automation->autos[AUTOMATION_MUTE],
252                         direction, 0);
253
254         if(!mute_constant)
255         {
256 // Frame is playable
257                 render_projector(output_temp, video_out, start_position,
258                         frame_rate, use_opengl);
259         }
260
261         output_temp->push_prev_effect("VirtualVNode::render_as_module");
262 //printf("VirtualVNode::render_as_module\n");
263 //output_temp->dump_stacks();
264
265         return 0;
266 }
267
268 int VirtualVNode::render_fade(VFrame *output,        
269 // start of input fragment in project if forward / end of input fragment if reverse
270 // relative to requested frame rate
271                         int64_t start_position, double frame_rate, 
272                         Autos *autos, int direction, int use_opengl)
273 {
274         FloatAuto *previous = 0;
275         FloatAuto *next = 0;
276         double edl_rate = renderengine->get_edl()->session->frame_rate;
277         int64_t start_position_project =
278                 (int64_t)(start_position * edl_rate / frame_rate);
279
280         if(vconsole->debug_tree) 
281                 printf("  VirtualVNode::render_fade title=%s\n", track->title);
282
283         double intercept = ((FloatAutos*)autos)->get_value(start_position_project, 
284                 direction, previous, next);
285
286 //      CLAMP(intercept, 0, 100);
287
288
289 #if 0
290 // Can't use overlay here because overlayer blends the frame with itself.
291 // The fade engine can compensate for lack of alpha channels by multiplying the 
292 // color components by alpha.
293         if(!EQUIV(intercept / 100, 1))
294         {
295                 if(use_opengl)
296                         ((VDeviceX11*)((VirtualVConsole*)vconsole)->get_vdriver())->do_fade(
297                                 output, 
298                                 intercept / 100);
299                 else
300                         fader->do_fade(output, output, intercept / 100);
301         }
302 #else
303         alpha = intercept / 100;
304 #endif
305
306         return 0;
307 }
308
309
310
311 void VirtualVNode::render_mask(VFrame *output_temp,
312         int64_t start_position_project,
313         int use_opengl)
314 {
315         MaskAutos *keyframe_set = 
316                 (MaskAutos*)track->automation->autos[AUTOMATION_MASK];
317
318         Auto *current = 0;
319 //      MaskAuto *default_auto = (MaskAuto*)keyframe_set->default_auto;
320         MaskAuto *keyframe = (MaskAuto*)keyframe_set->get_prev_auto(start_position_project, 
321                 PLAY_FORWARD,
322                 current);
323
324         int total_points = 0;
325         for(int i = 0; i < keyframe->masks.total; i++)
326         {
327                 SubMask *mask = keyframe->get_submask(i);
328                 int submask_points = mask->points.total;
329                 if(submask_points > 1) total_points += submask_points;
330         }
331
332 //printf("VirtualVNode::render_mask 1 %d %d\n", total_points, keyframe->value);
333 // Ignore certain masks
334         if(total_points <= 2 || 
335                 (keyframe->value == 0 && keyframe->mode == MASK_SUBTRACT_ALPHA))
336         {
337                 return;
338         }
339
340 // Fake certain masks
341         if(keyframe->value == 0 && keyframe->mode == MASK_MULTIPLY_ALPHA)
342         {
343                 output_temp->clear_frame();
344                 return;
345         }
346
347         if(use_opengl)
348         {
349                 ((VDeviceX11*)((VirtualVConsole*)vconsole)->get_vdriver())->do_mask(
350                         output_temp, start_position_project,
351                         keyframe_set, keyframe, keyframe);
352         }
353         else
354         {
355 // Revert to software
356                 masker->do_mask(output_temp, start_position_project,
357                         keyframe_set, keyframe, keyframe);
358         }
359 }
360
361
362 // Start of input fragment in project if forward.  
363 // End of input fragment if reverse.
364 int VirtualVNode::render_projector(VFrame *input, VFrame *output,
365                         int64_t start_position, double frame_rate,
366                         int use_opengl)
367 {
368         float in_x1, in_y1, in_x2, in_y2;
369         float out_x1, out_y1, out_x2, out_y2;
370         double edl_rate = renderengine->get_edl()->session->frame_rate;
371         int64_t start_position_project = (int64_t)(start_position * 
372                 edl_rate /
373                 frame_rate);
374         VRender *vrender = ((VirtualVConsole*)vconsole)->vrender;
375         if(vconsole->debug_tree) 
376                 printf("  VirtualVNode::render_projector input=%p output=%p cmodel=%d title=%s\n", 
377                         input, output, output->get_color_model(), track->title);
378
379         if(output)
380         {
381                 ((VTrack*)track)->calculate_output_transfer(start_position_project,
382                         renderengine->command->get_direction(),
383                         in_x1, in_y1, in_x2, in_y2,
384                         out_x1, out_y1, out_x2, out_y2);
385
386                 in_x2 += in_x1;   in_y2 += in_y1;
387                 out_x2 += out_x1; out_y2 += out_y1;
388
389 //for(int j = 0; j < input->get_w() * 3 * 5; j++)
390 //      input->get_rows()[0][j] = 255;
391 // 
392                 if(out_x2 > out_x1 && out_y2 > out_y1 && 
393                         in_x2 > in_x1 && in_y2 > in_y1)
394                 {
395                         int direction = renderengine->command->get_direction();
396                         IntAuto *mode_keyframe = 0;
397                         mode_keyframe = 
398                                 (IntAuto*)track->automation->autos[AUTOMATION_MODE]->get_prev_auto(
399                                         start_position_project, direction, (Auto* &)mode_keyframe);
400
401                         int mode = mode_keyframe->value;
402
403 // Fade is performed in render_fade so as to allow this module
404 // to be chained in another module, thus only 4 component colormodels
405 // can do dissolves, although a blend equation is still required for 3 component
406 // colormodels since fractional translation requires blending.
407
408 // If this is the first playable video track and the mode_keyframe is "src_over"
409 // the mode may be overridden with "replace".  Replace is faster.
410                         if(mode == TRANSFER_NORMAL &&
411                                 vconsole->current_exit_node == vconsole->total_exit_nodes - 1)
412                                 mode = TRANSFER_REPLACE;
413
414                         if(use_opengl)
415                         {
416 // Nested EDL's overlay on a PBuffer instead of a screen
417 // is_nested < 0 ? flatten alpha channel, last draw before driver render
418                                 int is_nested = renderengine->is_nested ? 1 :
419                                         vconsole->current_exit_node == 0 ? -1 : 0;
420                                 ((VDeviceX11*)((VirtualVConsole*)vconsole)->get_vdriver())->overlay(
421                                         output, input,
422                                         in_x1, in_y1, in_x2, in_y2,
423                                         out_x1, out_y1, out_x2, out_y2, 
424                                         alpha, mode, 
425                                         renderengine->get_edl(),
426                                         is_nested);
427                         }
428                         else
429                         {
430                                 vrender->overlayer->overlay(output, input,
431                                         in_x1, in_y1, in_x2, in_y2,
432                                         out_x1, out_y1, out_x2, out_y2, 
433                                         alpha, mode, 
434                                         renderengine->get_edl()->session->interpolation_type);
435                         }
436                 }
437         }
438         return 0;
439 }
440