Make FloatAutos::get_values() always use a PLAY_FORWARD direction.
[cinelerra_cv/pmdumuid.git] / cinelerra / virtualvnode.C
blob1214fe8c95462a3fd78a86ab1a84842fc75b49f3
1 #include "asset.h"
2 #include "automation.h"
3 #include "bcsignals.h"
4 #include "clip.h"
5 #include "edits.h"
6 #include "edl.h"
7 #include "edlsession.h"
8 #include "fadeengine.h"
9 #include "floatauto.h"
10 #include "floatautos.h"
11 #include "intauto.h"
12 #include "intautos.h"
13 #include "maskengine.h"
14 #include "mwindow.h"
15 #include "module.h"
16 #include "overlayframe.h"
17 #include "playabletracks.h"
18 #include "plugin.h"
19 #include "preferences.h"
20 #include "renderengine.h"
21 #include "transition.h"
22 #include "transportque.h"
23 #include "vattachmentpoint.h"
24 #include "vdevicex11.h"
25 #include "vframe.h"
26 #include "videodevice.h"
27 #include "virtualvconsole.h"
28 #include "virtualvnode.h"
29 #include "vmodule.h"
30 #include "vrender.h"
31 #include "vtrack.h"
33 #include <string.h>
36 VirtualVNode::VirtualVNode(RenderEngine *renderengine, 
37                 VirtualConsole *vconsole, 
38                 Module *real_module, 
39                 Plugin *real_plugin,
40                 Track *track, 
41                 VirtualNode *parent_node)
42  : VirtualNode(renderengine, 
43                 vconsole, 
44                 real_module, 
45                 real_plugin,
46                 track, 
47                 parent_node)
49         VRender *vrender = ((VirtualVConsole*)vconsole)->vrender;
50         fader = new FadeEngine(renderengine->preferences->processors);
53 VirtualVNode::~VirtualVNode()
55         delete fader;
58 VirtualNode* VirtualVNode::create_module(Plugin *real_plugin, 
59                                                         Module *real_module, 
60                                                         Track *track)
62         return new VirtualVNode(renderengine, 
63                 vconsole, 
64                 real_module,
65                 0,
66                 track,
67                 this);
71 VirtualNode* VirtualVNode::create_plugin(Plugin *real_plugin)
73         return new VirtualVNode(renderengine, 
74                 vconsole, 
75                 0,
76                 real_plugin,
77                 track,
78                 this);
81 int VirtualVNode::read_data(VFrame *output_temp,
82         int64_t start_position,
83         double frame_rate,
84         int use_opengl)
86         VirtualNode *previous_plugin = 0;
87         int result = 0;
89         if(!output_temp) 
90                 printf("VirtualVNode::read_data output_temp=%p\n", output_temp);
92         if(vconsole->debug_tree) 
93                 printf("  VirtualVNode::read_data position=%lld rate=%f title=%s opengl=%d\n", 
94                         start_position,
95                         frame_rate,
96                         track->title, 
97                         use_opengl);
99 // If there is a parent module but the parent module has no data source,
100 // use our own data source.
101 // Current edit in parent track
102         VEdit *parent_edit = 0;
103         if(parent_node && parent_node->track && renderengine)
104         {
105                 double edl_rate = renderengine->edl->session->frame_rate;
106                 int64_t start_position_project = (int64_t)(start_position *
107                         edl_rate /
108                         frame_rate + 
109                         0.5);
110                 parent_edit = (VEdit*)parent_node->track->edits->editof(start_position_project, 
111                         renderengine->command->get_direction(),
112                         0);
113         }
116 // This is a plugin on parent module with a preceeding effect.
117 // Get data from preceeding effect on parent module.
118         if(parent_node && (previous_plugin = parent_node->get_previous_plugin(this)))
119         {
120                 result = ((VirtualVNode*)previous_plugin)->render(output_temp,
121                         start_position,
122                         frame_rate,
123                         use_opengl);
124         }
125         else
126 // The current node is the first plugin on parent module.
127 // The parent module has an edit to read from or the current node
128 // has no source to read from.
129 // Read data from parent module
130         if(parent_node && (parent_edit || !real_module))
131         {
132                 result = ((VirtualVNode*)parent_node)->read_data(output_temp,
133                         start_position,
134                         frame_rate,
135                         use_opengl);
136         }
137         else
138         if(real_module)
139         {
140 // This is the first node in the tree
141                 result = ((VModule*)real_module)->render(output_temp,
142                         start_position,
143                         renderengine->command->get_direction(),
144                         frame_rate,
145                         0,
146                         vconsole->debug_tree,
147                         use_opengl);
148         }
150         return result;
154 int VirtualVNode::render(VFrame *output_temp, 
155         int64_t start_position,
156         double frame_rate,
157         int use_opengl)
159         VRender *vrender = ((VirtualVConsole*)vconsole)->vrender;
160         if(real_module)
161         {
162                 render_as_module(vrender->video_out, 
163                         output_temp,
164                         start_position,
165                         frame_rate,
166                         use_opengl);
167         }
168         else
169         if(real_plugin)
170         {
171                 render_as_plugin(output_temp,
172                         start_position,
173                         frame_rate,
174                         use_opengl);
175         }
176         return 0;
179 void VirtualVNode::render_as_plugin(VFrame *output_temp, 
180         int64_t start_position,
181         double frame_rate,
182         int use_opengl)
184         if(!attachment ||
185                 !real_plugin ||
186                 !real_plugin->on) return;
189         if(vconsole->debug_tree) 
190                 printf("  VirtualVNode::render_as_plugin title=%s use_opengl=%d\n", 
191                         track->title,
192                         use_opengl);
194         ((VAttachmentPoint*)attachment)->render(
195                 output_temp,
196                 plugin_buffer_number,
197                 start_position,
198                 frame_rate,
199                 vconsole->debug_tree,
200                 use_opengl);
204 int VirtualVNode::render_as_module(VFrame *video_out, 
205         VFrame *output_temp,
206         int64_t start_position,
207         double frame_rate,
208         int use_opengl)
211         int direction = renderengine->command->get_direction();
212         double edl_rate = renderengine->edl->session->frame_rate;
213 // Get position relative to project, compensated for direction
214         int64_t start_position_project = (int64_t)(start_position *
215                 edl_rate / 
216                 frame_rate);
217         if(direction == PLAY_REVERSE) start_position_project--;
219         if(vconsole->debug_tree) 
220                 printf("  VirtualVNode::render_as_module title=%s use_opengl=%d video_out=%p output_temp=%p\n", 
221                         track->title,
222                         use_opengl,
223                         video_out,
224                         output_temp);
226         output_temp->push_next_effect("VirtualVNode::render_as_module");
228 // Process last subnode.  This propogates up the chain of subnodes and finishes
229 // the chain.
230         if(subnodes.total)
231         {
232                 VirtualVNode *node = (VirtualVNode*)subnodes.values[subnodes.total - 1];
233                 node->render(output_temp,
234                         start_position,
235                         frame_rate,
236                         use_opengl);
237         }
238         else
239 // Read data from previous entity
240         {
241                 read_data(output_temp,
242                         start_position,
243                         frame_rate,
244                         use_opengl);
245         }
247         output_temp->pop_next_effect();
249         render_fade(output_temp,
250                                 start_position,
251                                 frame_rate,
252                                 track->automation->autos[AUTOMATION_FADE],
253                                 direction);
255 // Apply mask to output
256         ((VModule *)real_module)->masker->do_mask(output_temp, 
257                 start_position,
258                 frame_rate,
259                 edl_rate,
260                 (MaskAutos*)track->automation->autos[AUTOMATION_MASK], 
261                 direction,
262                 0);      // we are not before plugins
265 // overlay on the final output
266 // Get mute status
267         int mute_constant;
268         int mute_fragment = 1;
269         int64_t mute_position = 0;
272 // Is frame muted?
273         get_mute_fragment(start_position,
274                         mute_constant, 
275                         mute_fragment, 
276                         (Autos*)((VTrack*)track)->automation->autos[AUTOMATION_MUTE],
277                         direction,
278                         0);
280         if(!mute_constant)
281         {
282 // Frame is playable
283                 render_projector(output_temp,
284                         video_out,
285                         start_position,
286                         frame_rate);
287         }
289         output_temp->push_prev_effect("VirtualVNode::render_as_module");
290 //printf("VirtualVNode::render_as_module\n");
291 //output_temp->dump_stacks();
293         Edit *edit = 0;
294         if(renderengine->show_tc)
295                 renderengine->vrender->insert_timecode(edit,
296                         start_position,
297                         output_temp);
299         return 0;
302 int VirtualVNode::render_fade(VFrame *output,        
303 // start of input fragment in project if forward / end of input fragment if reverse
304 // relative to requested frame rate
305                         int64_t start_position, 
306                         double frame_rate, 
307                         Autos *autos,
308                         int direction)
310         double slope, intercept;
311         int64_t slope_len = 1;
312         FloatAuto *previous = 0;
313         FloatAuto *next = 0;
314         double edl_rate = renderengine->edl->session->frame_rate;
315         int64_t start_position_project = (int64_t)(start_position * 
316                 edl_rate /
317                 frame_rate);
319         if(vconsole->debug_tree) 
320                 printf("  VirtualVNode::render_fade title=%s\n", track->title);
322         intercept = ((FloatAutos*)autos)->get_value(start_position_project, 
323                 previous,
324                 next);
327         CLAMP(intercept, 0, 100);
330 // Can't use overlay here because overlayer blends the frame with itself.
331 // The fade engine can compensate for lack of alpha channels by multiplying the 
332 // color components by alpha.
333         if(!EQUIV(intercept / 100, 1))
334         {
335                 if(((VirtualVConsole*)vconsole)->use_opengl)
336                         ((VDeviceX11*)((VirtualVConsole*)vconsole)->get_vdriver())->do_fade(
337                                 output, 
338                                 intercept / 100);
339                 else
340                         fader->do_fade(output, output, intercept / 100);
341         }
343         return 0;
346 // Start of input fragment in project if forward.  End of input fragment if reverse.
347 int VirtualVNode::render_projector(VFrame *input,
348                         VFrame *output,
349                         int64_t start_position,
350                         double frame_rate)
352         float in_x1, in_y1, in_x2, in_y2;
353         float out_x1, out_y1, out_x2, out_y2;
354         double edl_rate = renderengine->edl->session->frame_rate;
355         int64_t start_position_project = (int64_t)(start_position * 
356                 edl_rate /
357                 frame_rate);
358         VRender *vrender = ((VirtualVConsole*)vconsole)->vrender;
359         if(vconsole->debug_tree) 
360                 printf("  VirtualVNode::render_projector input=%p output=%p title=%s\n", 
361                         input, output, track->title);
363         if(output)
364         {
365                 ((VTrack*)track)->calculate_output_transfer(start_position_project,
366                         renderengine->command->get_direction(),
367                         in_x1, 
368                         in_y1, 
369                         in_x2, 
370                         in_y2,
371                         out_x1, 
372                         out_y1, 
373                         out_x2, 
374                         out_y2);
376                 in_x2 += in_x1;
377                 in_y2 += in_y1;
378                 out_x2 += out_x1;
379                 out_y2 += out_y1;
381 //for(int j = 0; j < input->get_w() * 3 * 5; j++)
382 //      input->get_rows()[0][j] = 255;
383 // 
384                 if(out_x2 > out_x1 && 
385                         out_y2 > out_y1 && 
386                         in_x2 > in_x1 && 
387                         in_y2 > in_y1)
388                 {
389                         int direction = renderengine->command->get_direction();
390                         IntAuto *mode_keyframe = 0;
391                         mode_keyframe = 
392                                 (IntAuto*)track->automation->autos[AUTOMATION_MODE]->get_prev_auto(
393                                         start_position_project, 
394                                         direction,
395                                         (Auto* &)mode_keyframe);
397                         int mode = mode_keyframe->value;
399 // Fade is performed in render_fade so as to allow this module
400 // to be chained in another module, thus only 4 component colormodels
401 // can do dissolves, although a blend equation is still required for 3 component
402 // colormodels since fractional translation requires blending.
404 // If this is the first playable video track and the mode_keyframe is "normal"
405 // the mode may be overridden with "replace".  Replace is faster.
406                         if(mode == TRANSFER_NORMAL &&
407                                 vconsole->current_exit_node == vconsole->total_exit_nodes - 1)
408                                 mode = TRANSFER_REPLACE;
410                         if(((VirtualVConsole*)vconsole)->use_opengl)
411                         {
412                                 ((VDeviceX11*)((VirtualVConsole*)vconsole)->get_vdriver())->overlay(
413                                         output,
414                                         input,
415                                         in_x1, 
416                                         in_y1, 
417                                         in_x2, 
418                                         in_y2,
419                                         out_x1, 
420                                         out_y1, 
421                                         out_x2, 
422                                         out_y2, 
423                                         1,
424                                         mode, 
425                                         renderengine->edl);
426                         }
427                         else
428                         {
429                                 vrender->overlayer->overlay(output, 
430                                         input,
431                                         in_x1, 
432                                         in_y1, 
433                                         in_x2, 
434                                         in_y2,
435                                         out_x1, 
436                                         out_y1, 
437                                         out_x2, 
438                                         out_y2, 
439                                         1,
440                                         mode, 
441                                         renderengine->edl->session->interpolation_type);
442                         }
443                 }
444         }
445         return 0;