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