descratch again reworked + icons, add agingtv plugin params, add alias chkbox in...
[goodguy/history.git] / cinelerra-5.1 / guicast / vicon.C
1 #include "vicon.h"
2
3 #include "bctimer.h"
4 #include "bcwindow.h"
5 #include "bccolors.h"
6 #include "keys.h"
7 #include "mutex.h"
8 #include "condition.h"
9
10 VIcon::
11 VIcon(int vw, int vh, double rate)
12 {
13         this->vw = vw;
14         this->vh = vh;
15         this->frame_rate = rate;
16
17         cycle_start = 0;
18         age = 0;
19         seq_no = 0;
20         in_use = 1;
21         hidden = 0;
22         audio_data = 0;
23         audio_size = 0;
24         playing_audio = 0;
25 }
26
27 VIcon::
28 ~VIcon()
29 {
30         clear_images();
31         delete [] audio_data;
32 }
33
34 void VIcon::
35 add_image(VFrame *frm, int ww, int hh, int vcmdl)
36 {
37         VIFrame *vifrm = new VIFrame(ww, hh, vcmdl);
38         VFrame *img = *vifrm;
39         img->transfer_from(frm);
40         images.append(vifrm);
41 }
42
43 void VIcon::
44 draw_vframe(BC_WindowBase *wdw, int x, int y)
45 {
46         wdw->draw_vframe(frame(), x,y, vw,vh);
47 }
48
49 VIcon *VIconThread::low_vicon()
50 {
51         if( !t_heap.size() ) return 0;
52         VIcon *vip = t_heap[0];
53         remove_vicon(0);
54         return vip;
55 }
56
57 void VIconThread::remove_vicon(int i)
58 {
59         int sz = t_heap.size();
60         for( int k; (k=2*(i+1)) < sz; i=k ) {
61                 if( t_heap[k]->age > t_heap[k-1]->age ) --k;
62                 t_heap[i] = t_heap[k];
63         }
64         VIcon *last = t_heap[--sz];
65         t_heap.remove_number(sz);
66         double age = last->age;
67         for( int k; i>0 && age<t_heap[k=(i-1)/2]->age; i=k )
68                 t_heap[i] = t_heap[k];
69         t_heap[i] = last;
70 }
71
72
73 VIconThread::
74 VIconThread(BC_WindowBase *wdw, int vw, int vh)
75  : Thread(1, 0, 0)
76 {
77         this->wdw = wdw;
78         this->view_win = 0;  this->vicon = 0;
79         this->view_w = vw;   this->view_h = vh;
80         this->viewing = 0;
81         draw_lock = new Condition(0, "VIconThread::draw_lock", 1);
82         timer = new Timer();
83         this->refresh_rate = VICON_RATE;
84         done = 0;
85         interrupted = -1;
86 }
87
88 VIconThread::
89 ~VIconThread()
90 {
91         stop_drawing();
92         done = 1;
93         draw_lock->unlock();
94         if( Thread::running() ) {
95                 Thread::cancel();
96         }
97         Thread::join();
98         t_heap.remove_all_objects();
99         delete timer;
100         delete draw_lock;
101 }
102
103 void VIconThread::
104 start_drawing()
105 {
106         wdw->lock_window("VIconThread::start_drawing");
107         if( view_win )
108                 wdw->set_active_subwindow(view_win);
109         if( interrupted < 0 )
110                 draw_lock->unlock();
111         interrupted = 0;
112         wdw->unlock_window();
113 }
114
115 void VIconThread::
116 stop_drawing()
117 {
118         wdw->lock_window("VIconThread::stop_drawing");
119         set_view_popup(0);
120         if( !interrupted )
121                 interrupted = 1;
122         wdw->unlock_window();
123 }
124
125 int VIconThread::keypress_event(int key)
126 {
127         if( key != ESC ) return 0;
128         set_view_popup(0);
129         return 1;
130 }
131
132 int ViewPopup::button_press_event()
133 {
134         vt->set_view_popup(0);
135         return 1;
136 }
137
138 bool VIconThread::
139 visible(VIcon *vicon, int x, int y)
140 {
141         if( vicon->hidden ) return false;
142         int y0 = 0;
143         int my = y + vicon->vh;
144         if( my <= y0 ) return false;
145         int y1 = y0 + wdw->get_h();
146         if( y >= y1 ) return false;
147         int x0 = 0;
148         int mx = x + vicon->vw;
149         if( mx <= x0 ) return false;
150         int x1 = x0 + wdw->get_w();
151         if( x >= x1 ) return false;
152         return true;
153 }
154
155 int ViewPopup::keypress_event()
156 {
157         int key = get_keypress();
158         return vt->keypress_event(key);
159 }
160 ViewPopup::ViewPopup(VIconThread *vt, VFrame *frame, int x, int y, int w, int h)
161  : BC_Popup(vt->wdw, x, y, w, h, BLACK)
162 {
163         this->vt = vt;
164 }
165
166 ViewPopup::~ViewPopup()
167 {
168         vt->wdw->set_active_subwindow(0);
169 }
170
171 void ViewPopup::draw_vframe(VFrame *frame)
172 {
173         BC_WindowBase::draw_vframe(frame, 0,0, get_w(),get_h());
174 }
175
176 ViewPopup *VIconThread::new_view_window(VFrame *frame)
177 {
178         BC_WindowBase *parent = wdw->get_parent();
179         XineramaScreenInfo *info = parent->get_xinerama_info(-1);
180         int cx = info ? info->x_org + info->width/2 : parent->get_root_w(0)/2;
181         int cy = info ? info->y_org + info->height/2 : parent->get_root_h(0)/2;
182         int vx = viewing->get_vx(), rx = 0;
183         int vy = viewing->get_vy(), ry = 0;
184         wdw->get_root_coordinates(vx, vy, &rx, &ry);
185         rx += (rx >= cx ? -view_w : viewing->vw);
186         ry += (ry >= cy ? -view_h : viewing->vh);
187         ViewPopup *vwin = new ViewPopup(this, frame, rx, ry, view_w, view_h);
188         wdw->set_active_subwindow(vwin);
189         return vwin;
190 }
191
192 void VIconThread::
193 reset_images()
194 {
195         for( int i=t_heap.size(); --i>=0; ) t_heap[i]->reset();
196         timer->update();
197         img_dirty = win_dirty = 0;
198 }
199
200 void VIconThread::add_vicon(VIcon *vip)
201 {
202         double age = vip->age;
203         int i = t_heap.size();  t_heap.append(vip);
204         for( int k; i>0 && age<t_heap[(k=(i-1)/2)]->age; i=k )
205                 t_heap[i] = t_heap[k];
206         t_heap[i] = vip;
207 }
208
209 int VIconThread::del_vicon(VIcon *&vicon)
210 {
211         int i = t_heap.size();
212         while( --i >= 0 && t_heap[i] != vicon );
213         if( i < 0 ) return 0;
214         remove_vicon(i);
215         delete vicon;  vicon = 0;
216         return 1;
217 }
218
219 void VIconThread::set_view_popup(VIcon *vicon)
220 {
221         if( !vicon && this->vicon )
222                 this->vicon->stop_audio();
223         this->vicon = vicon;
224 }
225
226 int VIconThread::
227 update_view()
228 {
229         delete view_win;  view_win = 0;
230         if( (viewing=vicon) != 0 ) {
231                 VFrame *frame = viewing->frame();
232                 view_win = new_view_window(frame);
233                 view_win->show_window();
234                 vicon->start_audio();
235         }
236         wdw->set_active_subwindow(view_win);
237         return 1;
238 }
239
240
241 void VIconThread::
242 draw_images()
243 {
244         for( int i=0; i<t_heap.size(); ++i )
245                 draw(t_heap[i]);
246 }
247
248 void VIconThread::
249 flash()
250 {
251         if( !img_dirty && !win_dirty ) return;
252         if( img_dirty ) wdw->flash();
253         if( win_dirty && view_win ) view_win->flash();
254         win_dirty = img_dirty = 0;
255 }
256
257 int VIconThread::
258 draw(VIcon *vicon)
259 {
260         int x = vicon->get_vx(), y = vicon->get_vy();
261         int draw_img = visible(vicon, x, y);
262         int draw_win = view_win && viewing == vicon ? 1 : 0;
263         if( !draw_img && !draw_win ) return 0;
264         if( !vicon->frame() ) return 0;
265         if( draw_img ) {
266                 vicon->draw_vframe(wdw, x, y);
267                 img_dirty = 1;
268         }
269         if( draw_win ) {
270                 view_win->draw_vframe(vicon->frame());
271                 win_dirty = 1;
272         }
273         return 1;
274 }
275
276 void VIconThread::
277 run()
278 {
279         while(!done) {
280                 draw_lock->lock("VIconThread::run 0");
281                 if( done ) break;
282                 wdw->lock_window("BC_WindowBase::run 1");
283                 drawing_started();
284                 reset_images();
285                 int64_t seq_no = 0, now = 0;
286                 int64_t draw_flash = 1000 / refresh_rate;
287                 while( !interrupted ) {
288                         if( viewing != vicon )
289                                 update_view();
290                         VIcon *next = low_vicon();
291                         while( next && next->age < draw_flash ) {
292                                 now = timer->get_difference();
293                                 if( now >= draw_flash ) break;
294                                 draw(next);
295                                 if( !next->seq_no ) {
296                                         next->cycle_start = now;
297                                         if( next->playing_audio )
298                                                 next->start_audio();
299                                 }
300                                 int64_t ref_no = (now - next->cycle_start) / 1000. * refresh_rate;
301                                 int count = ref_no - next->seq_no;
302                                 if( count < 1 ) count = 1;
303                                 ref_no = next->seq_no + count;
304                                 next->age =  next->cycle_start + 1000. * ref_no / refresh_rate;
305                                 if( !next->set_seq_no(ref_no) )
306                                         next->age = now + 1000.;
307                                 add_vicon(next);
308                                 next = low_vicon();
309                         }
310                         if( !next ) break;
311                         add_vicon(next);
312                         if( draw_flash < now+1 )
313                                 draw_flash = now+1;
314                         wdw->unlock_window();
315                         while( !interrupted ) {
316                                 now = timer->get_difference();
317                                 int64_t ms = draw_flash - now;
318                                 if( ms <= 0 ) break;
319                                 if( ms > 100 ) ms = 100;
320                                 Timer::delay(ms);
321                         }
322                         wdw->lock_window("BC_WindowBase::run 2");
323                         now = timer->get_difference();
324                         int64_t late = now - draw_flash;
325                         if( late < 1000 ) flash();
326                         int64_t ref_no = now / 1000. * refresh_rate;
327                         int64_t count = ref_no - seq_no;
328                         if( count < 1 ) count = 1;
329                         seq_no += count;
330                         draw_flash = seq_no * 1000. / refresh_rate;
331                 }
332                 if( viewing != vicon )
333                         update_view();
334                 drawing_stopped();
335                 interrupted = -1;
336                 wdw->unlock_window();
337         }
338 }
339
340
341 void VIcon::init_audio(int audio_size)
342 {
343         this->audio_size = audio_size;
344         audio_data = new uint8_t[audio_size];
345         memset(audio_data, 0, audio_size);
346 }
347
348 void VIcon::dump(const char *dir)
349 {
350         mkdir(dir,0777);
351         for( int i=0; i<images.size(); ++i ) {
352                 char fn[1024];  sprintf(fn,"%s/img%05d.png",dir,i);
353                 printf("\r%s",fn);
354                 VFrame *img = *images[i];
355                 img->write_png(fn);
356         }
357         printf("\n");
358 }
359