r854: Merge 2.1:
[cinelerra_cv/ct.git] / cinelerra / virtualvnode.C
blobbbc8eb60a87df2c08b3e89e971b27fb6900332e7
1 #include "asset.h"
2 #include "automation.h"
3 #include "bcsignals.h"
4 #include "clip.h"
5 #include "edit.h"
6 #include "edits.h"
7 #include "edl.h"
8 #include "edlsession.h"
9 #include "fadeengine.h"
10 #include "floatauto.h"
11 #include "floatautos.h"
12 #include "intauto.h"
13 #include "intautos.h"
14 #include "maskengine.h"
15 #include "mwindow.h"
16 #include "module.h"
17 #include "overlayframe.h"
18 #include "playabletracks.h"
19 #include "plugin.h"
20 #include "preferences.h"
21 #include "renderengine.h"
22 #include "transition.h"
23 #include "transportque.h"
24 #include "vattachmentpoint.h"
25 #include "vdevicex11.h"
26 #include "vframe.h"
27 #include "videodevice.h"
28 #include "virtualvconsole.h"
29 #include "virtualvnode.h"
30 #include "vmodule.h"
31 #include "vrender.h"
32 #include "vtrack.h"
34 #include <string.h>
37 VirtualVNode::VirtualVNode(RenderEngine *renderengine, 
38                 VirtualConsole *vconsole, 
39                 Module *real_module, 
40                 Plugin *real_plugin,
41                 Track *track, 
42                 VirtualNode *parent_node)
43  : VirtualNode(renderengine, 
44                 vconsole, 
45                 real_module, 
46                 real_plugin,
47                 track, 
48                 parent_node)
50         VRender *vrender = ((VirtualVConsole*)vconsole)->vrender;
51         fader = new FadeEngine(renderengine->preferences->processors);
54 VirtualVNode::~VirtualVNode()
56         delete fader;
59 VirtualNode* VirtualVNode::create_module(Plugin *real_plugin, 
60                                                         Module *real_module, 
61                                                         Track *track)
63         return new VirtualVNode(renderengine, 
64                 vconsole, 
65                 real_module,
66                 0,
67                 track,
68                 this);
72 VirtualNode* VirtualVNode::create_plugin(Plugin *real_plugin)
74         return new VirtualVNode(renderengine, 
75                 vconsole, 
76                 0,
77                 real_plugin,
78                 track,
79                 this);
82 int VirtualVNode::read_data(VFrame *output_temp,
83         int64_t start_position,
84         double frame_rate,
85         int use_opengl)
87         VirtualNode *previous_plugin = 0;
88         int result = 0;
90         if(!output_temp) 
91                 printf("VirtualVNode::read_data output_temp=%p\n", output_temp);
93         if(vconsole->debug_tree) 
94                 printf("  VirtualVNode::read_data position=%lld rate=%f title=%s opengl=%d\n", 
95                         start_position,
96                         frame_rate,
97                         track->title, 
98                         use_opengl);
100 // This is a plugin on parent module with a preceeding effect.
101 // Get data from preceeding effect on parent module.
102         if(parent_node && (previous_plugin = parent_node->get_previous_plugin(this)))
103         {
104                 result = ((VirtualVNode*)previous_plugin)->render(output_temp,
105                         start_position,
106                         frame_rate,
107                         use_opengl);
108         }
109         else
110 // The current node is the first plugin on parent module.
111 // The parent module has an edit to read from or the current node
112 // has no source to read from.
113 // Read data from parent module
114         if(parent_node)
115         {
116                 result = ((VirtualVNode*)parent_node)->read_data(output_temp,
117                         start_position,
118                         frame_rate,
119                         use_opengl);
120         }
121         else
122         {
123 // This is the first node in the tree
124                 result = ((VModule*)real_module)->render(output_temp,
125                         start_position,
126                         renderengine->command->get_direction(),
127                         frame_rate,
128                         0,
129                         vconsole->debug_tree,
130                         use_opengl);
131         }
133         return result;
137 int VirtualVNode::render(VFrame *output_temp, 
138         int64_t start_position,
139         double frame_rate,
140         int use_opengl)
142         VRender *vrender = ((VirtualVConsole*)vconsole)->vrender;
143         if(real_module)
144         {
145                 render_as_module(vrender->video_out, 
146                         output_temp,
147                         start_position,
148                         frame_rate,
149                         use_opengl);
150         }
151         else
152         if(real_plugin)
153         {
154                 render_as_plugin(output_temp,
155                         start_position,
156                         frame_rate,
157                         use_opengl);
158         }
159         return 0;
162 void VirtualVNode::render_as_plugin(VFrame *output_temp, 
163         int64_t start_position,
164         double frame_rate,
165         int use_opengl)
167         if(!attachment ||
168                 !real_plugin ||
169                 !real_plugin->on) return;
172         if(vconsole->debug_tree) 
173                 printf("  VirtualVNode::render_as_plugin title=%s use_opengl=%d\n", 
174                         track->title,
175                         use_opengl);
177         ((VAttachmentPoint*)attachment)->render(
178                 output_temp,
179                 plugin_buffer_number,
180                 start_position,
181                 frame_rate,
182                 vconsole->debug_tree,
183                 use_opengl);
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)
194         int direction = renderengine->command->get_direction();
195         double edl_rate = renderengine->edl->session->frame_rate;
196 // Get position relative to project, compensated for direction
197         int64_t start_position_project = (int64_t)(start_position *
198                 edl_rate / 
199                 frame_rate);
200         if(direction == PLAY_REVERSE) start_position_project--;
202         if(vconsole->debug_tree) 
203                 printf("  VirtualVNode::render_as_module title=%s use_opengl=%d video_out=%p output_temp=%p\n", 
204                         track->title,
205                         use_opengl,
206                         video_out,
207                         output_temp);
209         output_temp->push_next_effect("VirtualVNode::render_as_module");
211 // Process last subnode.  This propogates up the chain of subnodes and finishes
212 // the chain.
213         if(subnodes.total)
214         {
215                 VirtualVNode *node = (VirtualVNode*)subnodes.values[subnodes.total - 1];
216                 node->render(output_temp,
217                         start_position,
218                         frame_rate,
219                         use_opengl);
220         }
221         else
222 // Read data from previous entity
223         {
224                 read_data(output_temp,
225                         start_position,
226                         frame_rate,
227                         use_opengl);
228         }
230         output_temp->pop_next_effect();
232         render_fade(output_temp,
233                                 start_position,
234                                 frame_rate,
235                                 track->automation->autos[AUTOMATION_FADE],
236                                 direction);
238 // Apply mask to output
239         ((VModule *)real_module)->masker->do_mask(output_temp, 
240                 start_position,
241                 frame_rate,
242                 edl_rate,
243                 (MaskAutos*)track->automation->autos[AUTOMATION_MASK], 
244                 direction,
245                 0);      // we are not before plugins
248 // overlay on the final output
249 // Get mute status
250         int mute_constant;
251         int mute_fragment = 1;
252         int64_t mute_position = 0;
255 // Is frame muted?
256         get_mute_fragment(start_position,
257                         mute_constant, 
258                         mute_fragment, 
259                         (Autos*)((VTrack*)track)->automation->autos[AUTOMATION_MUTE],
260                         direction,
261                         0);
263         if(!mute_constant)
264         {
265 // Frame is playable
266                 render_projector(output_temp,
267                         video_out,
268                         start_position,
269                         frame_rate);
270         }
272         output_temp->push_prev_effect("VirtualVNode::render_as_module");
273 //printf("VirtualVNode::render_as_module\n");
274 //output_temp->dump_stacks();
276         Edit *edit = 0;
277         if(renderengine->show_tc)
278                 renderengine->vrender->insert_timecode(edit,
279                         start_position,
280                         output_temp);
282         return 0;
285 int VirtualVNode::render_fade(VFrame *output,        
286 // start of input fragment in project if forward / end of input fragment if reverse
287 // relative to requested frame rate
288                         int64_t start_position, 
289                         double frame_rate, 
290                         Autos *autos,
291                         int direction)
293         double slope, intercept;
294         int64_t slope_len = 1;
295         FloatAuto *previous = 0;
296         FloatAuto *next = 0;
297         double edl_rate = renderengine->edl->session->frame_rate;
298         int64_t start_position_project = (int64_t)(start_position * 
299                 edl_rate /
300                 frame_rate);
302         if(vconsole->debug_tree) 
303                 printf("  VirtualVNode::render_fade title=%s\n", track->title);
305         intercept = ((FloatAutos*)autos)->get_value(start_position_project, 
306                 direction,
307                 previous,
308                 next);
311 //      CLAMP(intercept, 0, 100);
314 // Can't use overlay here because overlayer blends the frame with itself.
315 // The fade engine can compensate for lack of alpha channels by multiplying the 
316 // color components by alpha.
317         if(!EQUIV(intercept / 100, 1))
318         {
319                 if(((VirtualVConsole*)vconsole)->use_opengl)
320                         ((VDeviceX11*)((VirtualVConsole*)vconsole)->get_vdriver())->do_fade(
321                                 output, 
322                                 intercept / 100);
323                 else
324                         fader->do_fade(output, output, intercept / 100);
325         }
327         return 0;
330 // Start of input fragment in project if forward.  End of input fragment if reverse.
331 int VirtualVNode::render_projector(VFrame *input,
332                         VFrame *output,
333                         int64_t start_position,
334                         double frame_rate)
336         float in_x1, in_y1, in_x2, in_y2;
337         float out_x1, out_y1, out_x2, out_y2;
338         double edl_rate = renderengine->edl->session->frame_rate;
339         int64_t start_position_project = (int64_t)(start_position * 
340                 edl_rate /
341                 frame_rate);
342         VRender *vrender = ((VirtualVConsole*)vconsole)->vrender;
343         if(vconsole->debug_tree) 
344                 printf("  VirtualVNode::render_projector input=%p output=%p title=%s\n", 
345                         input, output, track->title);
347         if(output)
348         {
349                 ((VTrack*)track)->calculate_output_transfer(start_position_project,
350                         renderengine->command->get_direction(),
351                         in_x1, 
352                         in_y1, 
353                         in_x2, 
354                         in_y2,
355                         out_x1, 
356                         out_y1, 
357                         out_x2, 
358                         out_y2);
360                 in_x2 += in_x1;
361                 in_y2 += in_y1;
362                 out_x2 += out_x1;
363                 out_y2 += out_y1;
365 //for(int j = 0; j < input->get_w() * 3 * 5; j++)
366 //      input->get_rows()[0][j] = 255;
367 // 
368                 if(out_x2 > out_x1 && 
369                         out_y2 > out_y1 && 
370                         in_x2 > in_x1 && 
371                         in_y2 > in_y1)
372                 {
373                         int direction = renderengine->command->get_direction();
374                         IntAuto *mode_keyframe = 0;
375                         mode_keyframe = 
376                                 (IntAuto*)track->automation->autos[AUTOMATION_MODE]->get_prev_auto(
377                                         start_position_project, 
378                                         direction,
379                                         (Auto* &)mode_keyframe);
381                         int mode = mode_keyframe->value;
383 // Fade is performed in render_fade so as to allow this module
384 // to be chained in another module, thus only 4 component colormodels
385 // can do dissolves, although a blend equation is still required for 3 component
386 // colormodels since fractional translation requires blending.
388 // If this is the first playable video track and the mode_keyframe is "normal"
389 // the mode may be overridden with "replace".  Replace is faster.
390                         if(mode == TRANSFER_NORMAL &&
391                                 vconsole->current_exit_node == vconsole->total_exit_nodes - 1)
392                                 mode = TRANSFER_REPLACE;
394                         if(((VirtualVConsole*)vconsole)->use_opengl)
395                         {
396                                 ((VDeviceX11*)((VirtualVConsole*)vconsole)->get_vdriver())->overlay(
397                                         output,
398                                         input,
399                                         in_x1, 
400                                         in_y1, 
401                                         in_x2, 
402                                         in_y2,
403                                         out_x1, 
404                                         out_y1, 
405                                         out_x2, 
406                                         out_y2, 
407                                         1,
408                                         mode, 
409                                         renderengine->edl);
410                         }
411                         else
412                         {
413                                 vrender->overlayer->overlay(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->session->interpolation_type);
426                         }
427                 }
428         }
429         return 0;