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