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