ce33171fb4adcf6c130978b392b43b7add9801d3
[vuplus_dvbapp] / lib / gdi / grc.cpp
1 #include <unistd.h>
2 #include <lib/gdi/grc.h>
3 #include <lib/gdi/font.h>
4 #include <lib/base/init.h>
5 #include <lib/base/init_num.h>
6 #ifdef USE_LIBVUGLES2
7 #include <vuplus_gles.h>
8 #endif
9
10 #ifndef SYNC_PAINT
11 void *gRC::thread_wrapper(void *ptr)
12 {
13         return ((gRC*)ptr)->thread();
14 }
15 #endif
16
17 gRC *gRC::instance=0;
18
19 gRC::gRC(): rp(0), wp(0)
20 #ifdef SYNC_PAINT
21 ,m_notify_pump(eApp, 0)
22 #else
23 ,m_notify_pump(eApp, 1)
24 #endif
25 {
26         ASSERT(!instance);
27         instance=this;
28         CONNECT(m_notify_pump.recv_msg, gRC::recv_notify);
29 #ifndef SYNC_PAINT
30         pthread_mutex_init(&mutex, 0);
31         pthread_cond_init(&cond, 0);
32         int res = pthread_create(&the_thread, 0, thread_wrapper, this);
33         if (res)
34                 eFatal("RC thread couldn't be created");
35         else
36                 eDebug("RC thread created successfully");
37 #endif
38         m_spinner_enabled = 0;
39 }
40
41 DEFINE_REF(gRC);
42
43 gRC::~gRC()
44 {
45         instance=0;
46
47         gOpcode o;
48         o.opcode=gOpcode::shutdown;
49         submit(o);
50 #ifndef SYNC_PAINT
51         eDebug("waiting for gRC thread shutdown");
52         pthread_join(the_thread, 0);
53         eDebug("gRC thread has finished");
54 #endif
55 }
56
57 void gRC::submit(const gOpcode &o)
58 {
59         while(1)
60         {
61 #ifndef SYNC_PAINT
62                 pthread_mutex_lock(&mutex);
63 #endif
64                 int tmp=wp+1;
65                 if ( tmp == MAXSIZE )
66                         tmp=0;
67                 if ( tmp == rp )
68                 {
69 #ifndef SYNC_PAINT
70                         pthread_cond_signal(&cond);  // wakeup gdi thread
71                         pthread_mutex_unlock(&mutex);
72 #else
73                         thread();
74 #endif
75                         //printf("render buffer full...\n");
76                         //fflush(stdout);
77                         usleep(1000);  // wait 1 msec
78                         continue;
79                 }
80                 int free=rp-wp;
81                 if ( free <= 0 )
82                         free+=MAXSIZE;
83                 queue[wp++]=o;
84                 if ( wp == MAXSIZE )
85                         wp = 0;
86                 if (o.opcode==gOpcode::flush||o.opcode==gOpcode::shutdown||o.opcode==gOpcode::notify)
87 #ifndef SYNC_PAINT
88                         pthread_cond_signal(&cond);  // wakeup gdi thread
89                 pthread_mutex_unlock(&mutex);
90 #else
91                         thread(); // paint
92 #endif
93                 break;
94         }
95 }
96
97 void *gRC::thread()
98 {
99         int need_notify = 0;
100 #ifdef USE_LIBVUGLES2
101         if (gles_open()) {
102                 gles_state_open();
103                 gles_viewport(720, 576, 720 * 4);
104         }
105 #endif
106 #ifndef SYNC_PAINT
107         while (1)
108         {
109 #else
110         while (rp != wp)
111         {
112 #endif
113 #ifndef SYNC_PAINT
114                 pthread_mutex_lock(&mutex);
115 #endif
116                 if ( rp != wp )
117                 {
118                                 /* make sure the spinner is not displayed when we something is painted */
119                         disableSpinner();
120
121                         gOpcode o(queue[rp++]);
122                         if ( rp == MAXSIZE )
123                                 rp=0;
124 #ifndef SYNC_PAINT
125                         pthread_mutex_unlock(&mutex);
126 #endif
127                         if (o.opcode==gOpcode::shutdown)
128                                 break;
129                         else if (o.opcode==gOpcode::notify)
130                                 need_notify = 1;
131                         else if (o.opcode==gOpcode::setCompositing)
132                         {
133                                 m_compositing = o.parm.setCompositing;
134                                 m_compositing->Release();
135                         } else if(o.dc)
136                         {
137                                 o.dc->exec(&o);
138                                 // o.dc is a gDC* filled with grabref... so we must release it here
139                                 o.dc->Release();
140                         }
141                 }
142                 else
143                 {
144                         if (need_notify)
145                         {
146                                 need_notify = 0;
147                                 m_notify_pump.send(1);
148                         }
149 #ifndef SYNC_PAINT
150                         while(rp == wp)
151                         {
152                         
153                                         /* when the main thread is non-idle for a too long time without any display output,
154                                            we want to display a spinner. */
155                                 struct timespec timeout;
156                                 clock_gettime(CLOCK_REALTIME, &timeout);
157
158                                 if (m_spinner_enabled)
159                                 {
160                                         timeout.tv_nsec += 100*1000*1000;
161                                         /* yes, this is required. */
162                                         if (timeout.tv_nsec > 1000*1000*1000)
163                                         {
164                                                 timeout.tv_nsec -= 1000*1000*1000;
165                                                 timeout.tv_sec++;
166                                         }
167                                 }
168                                 else
169                                         timeout.tv_sec += 2;
170
171                                 int idle = 1;
172
173                                 if (pthread_cond_timedwait(&cond, &mutex, &timeout) == ETIMEDOUT)
174                                 {
175                                         if (eApp && !eApp->isIdle())
176                                         {
177                                                 int idle_count = eApp->idleCount();
178                                                 if (idle_count == m_prev_idle_count)
179                                                         idle = 0;
180                                                 else
181                                                         m_prev_idle_count = idle_count;
182                                         }
183                                 }
184
185                                 if (!idle)
186                                 {
187                                         if (!m_spinner_enabled)
188                                                 eDebug("main thread is non-idle! display spinner!");
189                                         enableSpinner();
190                                 } else
191                                         disableSpinner();
192                         }
193                         pthread_mutex_unlock(&mutex);
194 #endif
195                 }
196         }
197 #ifdef USE_LIBVUGLES2
198         gles_state_close();
199         gles_close();
200 #endif
201 #ifndef SYNC_PAINT
202         pthread_exit(0);
203 #endif
204         return 0;
205 }
206
207 void gRC::recv_notify(const int &i)
208 {
209         notify();
210 }
211
212 gRC *gRC::getInstance()
213 {
214         return instance;
215 }
216
217 void gRC::enableSpinner()
218 {
219         if (!m_spinner_dc)
220         {
221                 eDebug("no spinner DC!");
222                 return;
223         }
224
225         gOpcode o;
226         o.opcode = m_spinner_enabled ? gOpcode::incrementSpinner : gOpcode::enableSpinner;
227         m_spinner_dc->exec(&o);
228         m_spinner_enabled = 1;
229         o.opcode = gOpcode::flush;
230         m_spinner_dc->exec(&o);
231 }
232
233 void gRC::disableSpinner()
234 {
235         if (!m_spinner_enabled)
236                 return;
237
238         if (!m_spinner_dc)
239         {
240                 eDebug("no spinner DC!");
241                 return;
242         }
243
244         m_spinner_enabled = 0;
245         
246         gOpcode o;
247         o.opcode = gOpcode::disableSpinner;
248         m_spinner_dc->exec(&o);
249         o.opcode = gOpcode::flush;
250         m_spinner_dc->exec(&o);
251 }
252
253 static int gPainter_instances;
254
255 gPainter::gPainter(gDC *dc, eRect rect): m_dc(dc), m_rc(gRC::getInstance())
256 {
257 //      ASSERT(!gPainter_instances);
258         gPainter_instances++;
259 //      begin(rect);
260 }
261
262 gPainter::~gPainter()
263 {
264         end();
265         gPainter_instances--;
266 }
267
268 void gPainter::setBackgroundColor(const gColor &color)
269 {
270         if ( m_dc->islocked() )
271                 return;
272         gOpcode o;
273         o.opcode = gOpcode::setBackgroundColor;
274         o.dc = m_dc.grabRef();
275         o.parm.setColor = new gOpcode::para::psetColor;
276         o.parm.setColor->color = color;
277
278         m_rc->submit(o);
279 }
280
281 void gPainter::setForegroundColor(const gColor &color)
282 {
283         if ( m_dc->islocked() )
284                 return;
285         gOpcode o;
286         o.opcode = gOpcode::setForegroundColor;
287         o.dc = m_dc.grabRef();
288         o.parm.setColor = new gOpcode::para::psetColor;
289         o.parm.setColor->color = color;
290
291         m_rc->submit(o);
292 }
293
294 void gPainter::setBackgroundColor(const gRGB &color)
295 {
296         if ( m_dc->islocked() )
297                 return;
298         gOpcode o;
299         o.opcode = gOpcode::setBackgroundColorRGB;
300         o.dc = m_dc.grabRef();
301         o.parm.setColorRGB = new gOpcode::para::psetColorRGB;
302         o.parm.setColorRGB->color = color;
303
304         m_rc->submit(o);
305 }
306
307 void gPainter::setForegroundColor(const gRGB &color)
308 {
309         if ( m_dc->islocked() )
310                 return;
311         gOpcode o;
312         o.opcode = gOpcode::setForegroundColorRGB;
313         o.dc = m_dc.grabRef();
314         o.parm.setColorRGB = new gOpcode::para::psetColorRGB;
315         o.parm.setColorRGB->color = color;
316
317         m_rc->submit(o);
318 }
319
320 void gPainter::setFont(gFont *font)
321 {
322         if ( m_dc->islocked() )
323                 return;
324         gOpcode o;
325         o.opcode = gOpcode::setFont;
326         o.dc = m_dc.grabRef();
327         font->AddRef();
328         o.parm.setFont = new gOpcode::para::psetFont;
329         o.parm.setFont->font = font;
330
331         m_rc->submit(o);
332 }
333
334 void gPainter::renderText(const eRect &pos, const std::string &string, int flags)
335 {
336         if ( m_dc->islocked() )
337                 return;
338         gOpcode o;
339         o.opcode=gOpcode::renderText;
340         o.dc = m_dc.grabRef();
341         o.parm.renderText = new gOpcode::para::prenderText;
342         o.parm.renderText->area = pos;
343         o.parm.renderText->text = string.empty()?0:strdup(string.c_str());
344         o.parm.renderText->flags = flags;
345         m_rc->submit(o);
346 }
347
348 void gPainter::renderPara(eTextPara *para, ePoint offset)
349 {
350         if ( m_dc->islocked() )
351                 return;
352         ASSERT(para);
353         gOpcode o;
354         o.opcode=gOpcode::renderPara;
355         o.dc = m_dc.grabRef();
356         o.parm.renderPara = new gOpcode::para::prenderPara;
357         o.parm.renderPara->offset = offset;
358
359         para->AddRef();
360         o.parm.renderPara->textpara = para;
361         m_rc->submit(o);
362 }
363
364 void gPainter::fill(const eRect &area)
365 {
366         if ( m_dc->islocked() )
367                 return;
368         gOpcode o;
369         o.opcode=gOpcode::fill;
370
371         o.dc = m_dc.grabRef();
372         o.parm.fill = new gOpcode::para::pfillRect;
373         o.parm.fill->area = area;
374         m_rc->submit(o);
375 }
376
377 void gPainter::fill(const gRegion &region)
378 {
379         if ( m_dc->islocked() )
380                 return;
381         gOpcode o;
382         o.opcode=gOpcode::fillRegion;
383
384         o.dc = m_dc.grabRef();
385         o.parm.fillRegion = new gOpcode::para::pfillRegion;
386         o.parm.fillRegion->region = region;
387         m_rc->submit(o);
388 }
389
390 void gPainter::clear()
391 {
392         if ( m_dc->islocked() )
393                 return;
394         gOpcode o;
395         o.opcode=gOpcode::clear;
396         o.dc = m_dc.grabRef();
397         o.parm.fill = new gOpcode::para::pfillRect;
398         o.parm.fill->area = eRect();
399         m_rc->submit(o);
400 }
401
402 void gPainter::blit(gPixmap *pixmap, ePoint pos, const eRect &clip, int flags)
403 {
404         blitScale(pixmap, eRect(pos, eSize()), clip, flags, 0);
405 }
406
407 void gPainter::blitScale(gPixmap *pixmap, const eRect &position, const eRect &clip, int flags, int aflags)
408 {
409         flags |= aflags;
410
411         if ( m_dc->islocked() )
412                 return;
413         gOpcode o;
414
415         ASSERT(pixmap);
416
417         o.opcode=gOpcode::blit;
418         o.dc = m_dc.grabRef();
419         pixmap->AddRef();
420         o.parm.blit  = new gOpcode::para::pblit;
421         o.parm.blit->pixmap = pixmap;
422         o.parm.blit->clip = clip;
423         o.parm.blit->flags = flags;
424         o.parm.blit->position = position;
425         m_rc->submit(o);
426 }
427
428 void gPainter::setPalette(gRGB *colors, int start, int len)
429 {
430         if ( m_dc->islocked() )
431                 return;
432         ASSERT(colors);
433         gOpcode o;
434         o.opcode=gOpcode::setPalette;
435         o.dc = m_dc.grabRef();
436         gPalette *p=new gPalette;
437
438         o.parm.setPalette = new gOpcode::para::psetPalette;
439         p->data=new gRGB[len];
440
441         memcpy(p->data, colors, len*sizeof(gRGB));
442         p->start=start;
443         p->colors=len;
444         o.parm.setPalette->palette = p;
445         m_rc->submit(o);
446 }
447
448 void gPainter::setPalette(gPixmap *source)
449 {
450         ASSERT(source);
451         setPalette(source->surface->clut.data, source->surface->clut.start, source->surface->clut.colors);
452 }
453
454 void gPainter::mergePalette(gPixmap *target)
455 {
456         if ( m_dc->islocked() )
457                 return;
458         ASSERT(target);
459         gOpcode o;
460         o.opcode = gOpcode::mergePalette;
461         o.dc = m_dc.grabRef();
462         target->AddRef();
463         o.parm.mergePalette = new gOpcode::para::pmergePalette;
464         o.parm.mergePalette->target = target;
465         m_rc->submit(o);
466 }
467
468 void gPainter::line(ePoint start, ePoint end)
469 {
470         if ( m_dc->islocked() )
471                 return;
472         gOpcode o;
473         o.opcode=gOpcode::line;
474         o.dc = m_dc.grabRef();
475         o.parm.line = new gOpcode::para::pline;
476         o.parm.line->start = start;
477         o.parm.line->end = end;
478         m_rc->submit(o);
479 }
480
481 void gPainter::setOffset(ePoint val)
482 {
483         if ( m_dc->islocked() )
484                 return;
485         gOpcode o;
486         o.opcode=gOpcode::setOffset;
487         o.dc = m_dc.grabRef();
488         o.parm.setOffset = new gOpcode::para::psetOffset;
489         o.parm.setOffset->rel = 0;
490         o.parm.setOffset->value = val;
491         m_rc->submit(o);
492 }
493
494 void gPainter::moveOffset(ePoint rel)
495 {
496         if ( m_dc->islocked() )
497                 return;
498         gOpcode o;
499         o.opcode=gOpcode::setOffset;
500         o.dc = m_dc.grabRef();
501         o.parm.setOffset = new gOpcode::para::psetOffset;
502         o.parm.setOffset->rel = 1;
503         o.parm.setOffset->value = rel;
504         m_rc->submit(o);
505 }
506
507 void gPainter::resetOffset()
508 {
509         if ( m_dc->islocked() )
510                 return;
511         gOpcode o;
512         o.opcode=gOpcode::setOffset;
513         o.dc = m_dc.grabRef();
514         o.parm.setOffset = new gOpcode::para::psetOffset;
515         o.parm.setOffset->rel = 0;
516         o.parm.setOffset->value = ePoint(0, 0);
517         m_rc->submit(o);
518 }
519
520 void gPainter::resetClip(const gRegion &region)
521 {
522         if ( m_dc->islocked() )
523                 return;
524         gOpcode o;
525         o.opcode = gOpcode::setClip;
526         o.dc = m_dc.grabRef();
527         o.parm.clip = new gOpcode::para::psetClip;
528         o.parm.clip->region = region;
529         m_rc->submit(o);
530 }
531
532 void gPainter::clip(const gRegion &region)
533 {
534         if ( m_dc->islocked() )
535                 return;
536         gOpcode o;
537         o.opcode = gOpcode::addClip;
538         o.dc = m_dc.grabRef();
539         o.parm.clip = new gOpcode::para::psetClip;
540         o.parm.clip->region = region;
541         m_rc->submit(o);
542 }
543
544 void gPainter::clippop()
545 {
546         if ( m_dc->islocked() )
547                 return;
548         gOpcode o;
549         o.opcode = gOpcode::popClip;
550         o.dc = m_dc.grabRef();
551         m_rc->submit(o);
552 }
553
554 void gPainter::waitVSync()
555 {
556         if ( m_dc->islocked() )
557                 return;
558         gOpcode o;
559         o.opcode = gOpcode::waitVSync;
560         o.dc = m_dc.grabRef();
561         m_rc->submit(o);
562 }
563
564 void gPainter::flip()
565 {
566         if ( m_dc->islocked() )
567                 return;
568         gOpcode o;
569         o.opcode = gOpcode::flip;
570         o.dc = m_dc.grabRef();
571         m_rc->submit(o);
572 }
573
574 void gPainter::notify()
575 {
576         if ( m_dc->islocked() )
577                 return;
578         gOpcode o;
579         o.opcode = gOpcode::notify;
580         o.dc = m_dc.grabRef();
581         m_rc->submit(o);
582 }
583
584 void gPainter::setCompositing(gCompositingData *comp)
585 {
586         gOpcode o;
587         o.opcode = gOpcode::setCompositing;
588         o.dc = 0;
589         o.parm.setCompositing = comp;
590         comp->AddRef(); /* will be freed in ::thread */
591         m_rc->submit(o);
592 }
593
594 void gPainter::flush()
595 {
596         if ( m_dc->islocked() )
597                 return;
598         gOpcode o;
599         o.opcode = gOpcode::flush;
600         o.dc = m_dc.grabRef();
601         m_rc->submit(o);
602 }
603
604 void gPainter::end()
605 {
606         if ( m_dc->islocked() )
607                 return;
608 }
609
610 void gPainter::sendShow(ePoint point, eSize size)
611 {
612         if ( m_dc->islocked() )
613                 return;
614         gOpcode o;
615         o.opcode=gOpcode::sendShow;
616         o.dc = m_dc.grabRef();
617         o.parm.setShowHideInfo = new gOpcode::para::psetShowHideInfo;
618         o.parm.setShowHideInfo->point = point;
619         o.parm.setShowHideInfo->size = size;
620         m_rc->submit(o);
621 }
622
623 void gPainter::sendHide(ePoint point, eSize size)
624 {
625         if ( m_dc->islocked() )
626                 return;
627         gOpcode o;
628         o.opcode=gOpcode::sendHide;
629         o.dc = m_dc.grabRef();
630         o.parm.setShowHideInfo = new gOpcode::para::psetShowHideInfo;
631         o.parm.setShowHideInfo->point = point;
632         o.parm.setShowHideInfo->size = size;
633         m_rc->submit(o);
634 }
635
636 #ifdef USE_LIBVUGLES2
637 void gPainter::setView(eSize size)
638 {
639         if ( m_dc->islocked() )
640                 return;
641         gOpcode o;
642         o.opcode=gOpcode::setView;
643         o.dc = m_dc.grabRef();
644         o.parm.setViewInfo = new gOpcode::para::psetViewInfo;
645         o.parm.setViewInfo->size = size;
646         m_rc->submit(o);
647 }
648 #endif
649
650 gDC::gDC()
651 {
652         m_spinner_pic = 0;
653 }
654
655 gDC::gDC(gPixmap *pixmap): m_pixmap(pixmap)
656 {
657         m_spinner_pic = 0;
658 }
659
660 gDC::~gDC()
661 {
662         delete[] m_spinner_pic;
663 }
664
665 void gDC::exec(const gOpcode *o)
666 {
667         switch (o->opcode)
668         {
669         case gOpcode::setBackgroundColor:
670                 m_background_color = o->parm.setColor->color;
671                 m_background_color_rgb = getRGB(m_background_color);
672                 delete o->parm.setColor;
673                 break;
674         case gOpcode::setForegroundColor:
675                 m_foreground_color = o->parm.setColor->color;
676                 m_background_color_rgb = getRGB(m_foreground_color);
677                 delete o->parm.setColor;
678                 break;
679         case gOpcode::setBackgroundColorRGB:
680                 if (m_pixmap->needClut())
681                         m_background_color = m_pixmap->surface->clut.findColor(o->parm.setColorRGB->color);
682                 m_background_color_rgb = o->parm.setColorRGB->color;
683                 delete o->parm.setColorRGB;
684                 break;
685         case gOpcode::setForegroundColorRGB:
686                 if (m_pixmap->needClut())
687                         m_foreground_color = m_pixmap->surface->clut.findColor(o->parm.setColorRGB->color);
688                 m_foreground_color_rgb = o->parm.setColorRGB->color;
689                 delete o->parm.setColorRGB;
690                 break;
691         case gOpcode::setFont:
692                 m_current_font = o->parm.setFont->font;
693                 o->parm.setFont->font->Release();
694                 delete o->parm.setFont;
695                 break;
696         case gOpcode::renderText:
697         {
698                 ePtr<eTextPara> para = new eTextPara(o->parm.renderText->area);
699                 int flags = o->parm.renderText->flags;
700                 ASSERT(m_current_font);
701                 para->setFont(m_current_font);
702                 para->renderString(o->parm.renderText->text, (flags & gPainter::RT_WRAP) ? RS_WRAP : 0);
703                 if (o->parm.renderText->text)
704                         free(o->parm.renderText->text);
705                 if (flags & gPainter::RT_HALIGN_RIGHT)
706                         para->realign(eTextPara::dirRight);
707                 else if (flags & gPainter::RT_HALIGN_CENTER)
708                         para->realign(eTextPara::dirCenter);
709                 else if (flags & gPainter::RT_HALIGN_BLOCK)
710                         para->realign(eTextPara::dirBlock);
711                 
712                 ePoint offset = m_current_offset;
713                 
714                 if (o->parm.renderText->flags & gPainter::RT_VALIGN_CENTER)
715                 {
716                         eRect bbox = para->getBoundBox();
717                         int vcentered_top = o->parm.renderText->area.top() + ((o->parm.renderText->area.height() - bbox.height()) / 2);
718                         int correction = vcentered_top - bbox.top();
719                         offset += ePoint(0, correction);
720                 }
721                 
722                 para->blit(*this, offset, m_background_color_rgb, m_foreground_color_rgb);
723                 delete o->parm.renderText;
724                 break;
725         }
726         case gOpcode::renderPara:
727         {
728                 o->parm.renderPara->textpara->blit(*this, o->parm.renderPara->offset + m_current_offset, m_background_color_rgb, m_foreground_color_rgb);
729                 o->parm.renderPara->textpara->Release();
730                 delete o->parm.renderPara;
731                 break;
732         }
733         case gOpcode::fill:
734         {
735                 eRect area = o->parm.fill->area;
736                 area.moveBy(m_current_offset);
737                 gRegion clip = m_current_clip & area;
738                 if (m_pixmap->needClut())
739                         m_pixmap->fill(clip, m_foreground_color);
740                 else
741                         m_pixmap->fill(clip, m_foreground_color_rgb);
742                 delete o->parm.fill;
743                 break;
744         }
745         case gOpcode::fillRegion:
746         {
747                 o->parm.fillRegion->region.moveBy(m_current_offset);
748                 gRegion clip = m_current_clip & o->parm.fillRegion->region;
749                 if (m_pixmap->needClut())
750                         m_pixmap->fill(clip, m_foreground_color);
751                 else
752                         m_pixmap->fill(clip, m_foreground_color_rgb);
753                 delete o->parm.fillRegion;
754                 break;
755         }
756         case gOpcode::clear:
757                 if (m_pixmap->needClut())
758                         m_pixmap->fill(m_current_clip, m_background_color);
759                 else
760                         m_pixmap->fill(m_current_clip, m_background_color_rgb);
761                 delete o->parm.fill;
762                 break;
763         case gOpcode::blit:
764         {
765                 gRegion clip;
766                                 // this code should be checked again but i'm too tired now
767                 
768                 o->parm.blit->position.moveBy(m_current_offset);
769                 
770                 if (o->parm.blit->clip.valid())
771                 {
772                         o->parm.blit->clip.moveBy(m_current_offset);
773                         clip.intersect(gRegion(o->parm.blit->clip), m_current_clip);
774                 } else
775                         clip = m_current_clip;
776                 
777                 m_pixmap->blit(*o->parm.blit->pixmap, o->parm.blit->position, clip, o->parm.blit->flags);
778                 o->parm.blit->pixmap->Release();
779                 delete o->parm.blit;
780                 break;
781         }
782         case gOpcode::setPalette:
783                 if (o->parm.setPalette->palette->start > m_pixmap->surface->clut.colors)
784                         o->parm.setPalette->palette->start = m_pixmap->surface->clut.colors;
785                 if (o->parm.setPalette->palette->colors > (m_pixmap->surface->clut.colors-o->parm.setPalette->palette->start))
786                         o->parm.setPalette->palette->colors = m_pixmap->surface->clut.colors-o->parm.setPalette->palette->start;
787                 if (o->parm.setPalette->palette->colors)
788                         memcpy(m_pixmap->surface->clut.data+o->parm.setPalette->palette->start, o->parm.setPalette->palette->data, o->parm.setPalette->palette->colors*sizeof(gRGB));
789                 
790                 delete[] o->parm.setPalette->palette->data;
791                 delete o->parm.setPalette->palette;
792                 delete o->parm.setPalette;
793                 break;
794         case gOpcode::mergePalette:
795                 m_pixmap->mergePalette(*o->parm.mergePalette->target);
796                 o->parm.mergePalette->target->Release();
797                 delete o->parm.mergePalette;
798                 break; 
799         case gOpcode::line:
800         {
801                 ePoint start = o->parm.line->start + m_current_offset, end = o->parm.line->end + m_current_offset;
802                 m_pixmap->line(m_current_clip, start, end, m_foreground_color);
803                 delete o->parm.line;
804                 break;
805         }
806         case gOpcode::addClip:
807                 m_clip_stack.push(m_current_clip);
808                 o->parm.clip->region.moveBy(m_current_offset);
809                 m_current_clip &= o->parm.clip->region;
810                 delete o->parm.clip;
811                 break;
812         case gOpcode::setClip:
813                 o->parm.clip->region.moveBy(m_current_offset);
814                 m_current_clip = o->parm.clip->region & eRect(ePoint(0, 0), m_pixmap->size());
815                 delete o->parm.clip;
816                 break;
817         case gOpcode::popClip:
818                 if (!m_clip_stack.empty())
819                 {
820                         m_current_clip = m_clip_stack.top();
821                         m_clip_stack.pop();
822                 }
823                 break;
824         case gOpcode::setOffset:
825                 if (o->parm.setOffset->rel)
826                         m_current_offset += o->parm.setOffset->value;
827                 else
828                         m_current_offset  = o->parm.setOffset->value;
829                 delete o->parm.setOffset;
830                 break;
831         case gOpcode::waitVSync:
832                 break;
833         case gOpcode::flip:
834                 break;
835         case gOpcode::flush:
836                 break;
837         case gOpcode::sendShow:
838                 break;
839         case gOpcode::sendHide:
840                 break;
841 #ifdef USE_LIBVUGLES2
842         case gOpcode::setView:
843                 break;
844 #endif
845         case gOpcode::enableSpinner:
846                 enableSpinner();
847                 break;
848         case gOpcode::disableSpinner:
849                 disableSpinner();
850                 break;
851         case gOpcode::incrementSpinner:
852                 incrementSpinner();
853                 break;
854         default:
855                 eFatal("illegal opcode %d. expect memory leak!", o->opcode);
856         }
857 }
858
859 gRGB gDC::getRGB(gColor col)
860 {
861         if ((!m_pixmap) || (!m_pixmap->surface->clut.data))
862                 return gRGB(col, col, col);
863         if (col<0)
864         {
865                 eFatal("bla transp");
866                 return gRGB(0, 0, 0, 0xFF);
867         }
868         return m_pixmap->surface->clut.data[col];
869 }
870
871 void gDC::enableSpinner()
872 {
873         ASSERT(m_spinner_saved);
874         
875                 /* save the background to restore it later. We need to negative position because we want to blit from the middle of the screen. */
876         m_spinner_saved->blit(*m_pixmap, eRect(-m_spinner_pos.topLeft(), eSize()), gRegion(eRect(ePoint(0, 0), m_spinner_saved->size())), 0);
877         
878         incrementSpinner();
879 }
880
881 void gDC::disableSpinner()
882 {
883         ASSERT(m_spinner_saved);
884
885                 /* restore background */
886         m_pixmap->blit(*m_spinner_saved, eRect(m_spinner_pos.topLeft(), eSize()), gRegion(m_spinner_pos), 0);
887 }
888
889 void gDC::incrementSpinner()
890 {
891         ASSERT(m_spinner_saved);
892         
893         static int blub;
894         blub++;
895
896 #if 0
897         int i;
898         
899         for (i = 0; i < 5; ++i)
900         {
901                 int x = i * 20 + m_spinner_pos.left();
902                 int y = m_spinner_pos.top();
903                 
904                 int col = ((blub - i) * 30) % 256;
905
906                 m_pixmap->fill(eRect(x, y, 10, 10), gRGB(col, col, col));
907         }
908 #endif
909
910         m_spinner_temp->blit(*m_spinner_saved, eRect(0, 0, 0, 0), eRect(ePoint(0, 0), m_spinner_pos.size()));
911
912         if (m_spinner_pic[m_spinner_i])
913                 m_spinner_temp->blit(*m_spinner_pic[m_spinner_i], eRect(0, 0, 0, 0), eRect(ePoint(0, 0), m_spinner_pos.size()), gPixmap::blitAlphaTest);
914
915         m_pixmap->blit(*m_spinner_temp, eRect(m_spinner_pos.topLeft(), eSize()), gRegion(m_spinner_pos), 0);
916         m_spinner_i++;
917         m_spinner_i %= m_spinner_num;
918 }
919
920 void gDC::setSpinner(eRect pos, ePtr<gPixmap> *pic, int len)
921 {
922         ASSERT(m_pixmap);
923         ASSERT(m_pixmap->surface);
924         m_spinner_saved = new gPixmap(pos.size(), m_pixmap->surface->bpp);
925         m_spinner_temp = new gPixmap(pos.size(), m_pixmap->surface->bpp);
926         m_spinner_pos = pos;
927         
928         m_spinner_i = 0;
929         m_spinner_num = len;
930         
931         int i;
932         if (m_spinner_pic)
933                 delete[] m_spinner_pic;
934         
935         m_spinner_pic = new ePtr<gPixmap>[len];
936         
937         for (i = 0; i < len; ++i)
938                 m_spinner_pic[i] = pic[i];
939 }
940
941 DEFINE_REF(gDC);
942
943 eAutoInitPtr<gRC> init_grc(eAutoInitNumbers::graphic, "gRC");