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