]> git.vomp.tv Git - vompclient-marten.git/blob - surface.cc
New gui code
[vompclient-marten.git] / surface.cc
1 /*
2     Copyright 2004-2005 Chris Tallon
3     Portions copyright 2004 Jon Gettler
4
5     This file is part of VOMP.
6
7     VOMP is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11
12     VOMP is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with VOMP; if not, write to the Free Software
19     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20 */
21
22 #include "surface.h"
23 #include "osd.h"
24
25 Surface* Surface::screen = NULL;
26 Surface* Surface::buffer = NULL;
27 int Surface::disableDoubleBuffering = 0;
28 osd_font_t* Surface::font = &font_helvB18;
29
30 Surface::Surface(int id)
31 {
32   if (id == SCREEN) screen = this;
33   if (id == BUFFER) buffer = this;
34
35   fdOsd = Osd::getInstance()->getFD();
36   memset(&surface, 0, sizeof(osd_surface_t));
37   memset(&surface.sfc, 0, sizeof(stbgfx_sfc_t));
38   memset(&surface.map, 0, sizeof(stbgfx_map_t));
39 }
40
41 Surface::~Surface()
42 {
43   for (int i = 0; i < 3; i++)
44   {
45     if (surface.base[i]) munmap(surface.base[i], surface.map.map[i].size);
46   }
47
48   int a;
49
50   a = ioctl(fdOsd, GFX_FB_SFC_UNMAP, surface.sfc.handle);
51   if (a) Log::getInstance()->log("Surface", Log::ERR, "Surface unmap failed");
52
53   a = ioctl(fdOsd, GFX_FB_SFC_FREE, surface.sfc.handle);
54   if (a) Log::getInstance()->log("Surface", Log::ERR, "Surface destroy failed");
55
56 }
57
58 void Surface::disableBuffer()
59 {
60   disableDoubleBuffering = 1;
61 }
62
63 Surface* Surface::getObject(int id)
64 {
65   if (id == SCREEN) return screen;
66   if (disableDoubleBuffering) return screen;
67   if (id == BUFFER) return buffer;
68   return NULL;
69 }
70
71 int Surface::create(UINT width, UINT height)
72 {
73   int r = 0;
74   int displayNumber = 0; // mvpmc iterates 0->15 till it gets one that works?
75
76   surface.sfc.width = width;
77   surface.sfc.height = height;
78   surface.sfc.flags = 0x3f1533;
79
80   surface.sfc.unknown = -1;
81
82 //  r = ioctl(fdOsd, GFX_FB_SET_OSD, &displayNumber);
83 //  if (r) return 0;
84
85   r = ioctl(fdOsd, GFX_FB_OSD_SURFACE, &displayNumber);
86   if (r) return 0;
87
88   r = ioctl(fdOsd, GFX_FB_SFC_ALLOC, &surface.sfc);
89   if (r) return 0;
90
91   surface.map.map[0].unknown = surface.sfc.handle;
92   r = ioctl(fdOsd, GFX_FB_MAP, &surface.map);
93   if (r) return 0;
94
95   surface.base[0] = (unsigned char *)mmap(NULL, surface.map.map[0].size, PROT_READ|PROT_WRITE, MAP_SHARED, fdOsd, surface.map.map[0].addr);
96   if (surface.base[0] == MAP_FAILED) return 0;
97
98   surface.base[1] = (unsigned char *)mmap(NULL, surface.map.map[1].size, PROT_READ|PROT_WRITE, MAP_SHARED, fdOsd, surface.map.map[1].addr);
99   if (surface.base[1] == MAP_FAILED) return 0;
100
101   surface.base[2] = (unsigned char *)mmap(NULL, surface.map.map[2].size, PROT_READ|PROT_WRITE, MAP_SHARED, fdOsd, surface.map.map[2].addr);
102   if (surface.base[2] == MAP_FAILED) return 0;
103
104 //  surface.display.num = displayNumber;
105 //  r = ioctl(fdOsd, GFX_FB_MOVE_DISPLAY, &surface.display);
106 //  if (r) return 0;
107
108 //  r = ioctl(fdOsd, GFX_FB_SET_DISPLAY, &surface.display);
109 //  if (r) return 0;
110
111   return 1;
112 }
113
114 void Surface::display()
115 {
116   unsigned long fb_descriptor[2];
117
118   fb_descriptor[0] = surface.sfc.handle;
119   fb_descriptor[1] = 1;
120
121   ioctl(fdOsd, GFX_FB_ATTACH, fb_descriptor);
122 }
123
124 unsigned long Surface::getSurfaceHandle()
125 {
126   return surface.sfc.handle;
127 }
128
129 // ----------------------------------------------------------------------------
130
131 // Now for the drawing functions
132
133 /*
134  * RGB to YUV conversion tables
135  */
136 int Surface::conv_YB[256];
137 int Surface::conv_YG[256];
138 int Surface::conv_YR[256];
139 int Surface::conv_UB[256];
140 int Surface::conv_UG[256];
141 int Surface::conv_UR[256];
142 int Surface::conv_VB[256];
143 int Surface::conv_VG[256];
144 int Surface::conv_VR[256];
145
146 int Surface::conv_BY[256];
147 int Surface::conv_GY[256];
148 int Surface::conv_RY[256];
149 int Surface::conv_BU[256];
150 int Surface::conv_GU[256];
151 int Surface::conv_RU[256];
152 int Surface::conv_BV[256];
153 int Surface::conv_GV[256];
154 int Surface::conv_RV[256];
155
156 /*
157  * gfx_init() - initialize the RGB to YUV conversion tables
158  */
159 void Surface::initConversionTables(void)
160 {
161   int i;
162
163   for (i=0; i<256; i++) {
164     conv_YB[i] = (int)(0.299 * (double)i);
165     conv_BY[i] = i;
166   }
167   for (i=0; i<256; i++) {
168     conv_YG[i] = (int)(0.587 * (double)i);
169     conv_GY[i] = i;
170   }
171   for (i=0; i<256; i++) {
172     conv_YR[i] = (int)(0.114 * (double)i);
173     conv_RY[i] = i;
174   }
175
176   for (i=0; i<256; i++) {
177     conv_UB[i] = (int)(0.5 * (double)i);
178     conv_BU[i] = (int)(1.732 * (i - 128));
179   }
180   for (i=0; i<256; i++) {
181     conv_UG[i] = (int)(-0.33126 * (double)i);
182     conv_GU[i] = (int)(-0.338 * (i - 128));
183   }
184   for (i=0; i<256; i++) {
185     conv_UR[i] = (int)(-0.16874 * (double)i);
186     conv_RU[i] = 0;
187   }
188
189   for (i=0; i<256; i++) {
190     conv_VB[i] = (int)(-0.08131 * (double)i);
191     conv_BV[i] = 0;
192   }
193   for (i=0; i<256; i++) {
194     conv_VG[i] = (int)(-0.41869 * (double)i);
195     conv_GV[i] = (int)(-0.698 * (i - 128));
196   }
197   for (i=0; i<256; i++) {
198     conv_VR[i] = (int)(0.5 * (double)i);
199     conv_RV[i] = (int)(1.370 * ((double)i - 128));
200   }
201 }
202
203 /*
204  * rgb2yuv() - convert an RGB pixel to YUV
205  */
206  //inline me?
207 void Surface::rgb2yuv(unsigned char r, unsigned char g, unsigned char b, unsigned char *y, unsigned char *u, unsigned char *v)
208 {
209   int Y, U, V;
210
211   Y = conv_YB[b] + conv_YG[g] + conv_YR[r];
212   U = conv_UB[b] + conv_UG[g] + conv_UR[r] + 128;
213   V = conv_VB[b] + conv_VG[g] + conv_VR[r] + 128;
214
215   if (Y > 255)
216     Y = 255;
217   else if (Y < 0)
218     Y = 0;
219   if (U > 255)
220     U = 255;
221   else if (U < 0)
222     U = 0;
223   if (V > 255)
224     V = 255;
225   else if (V < 0)
226     V = 0;
227
228   *y = Y;
229   *u = U;
230   *v = V;
231 }
232
233 int Surface::fillblt(int x, int y, int width, int height, unsigned int c)
234 {
235   osd_fillblt_t fblt;
236
237   fblt.handle = surface.sfc.handle;
238   fblt.x = x;
239   fblt.y = y;
240   fblt.width = width;
241   fblt.height = height;
242   fblt.colour = c;
243
244   return ioctl(fdOsd, GFX_FB_OSD_FILLBLT, &fblt);
245 }
246
247 void Surface::drawPixel(int x, int y, unsigned int c)
248 {
249   int offset;
250   unsigned char r, g, b, a, Y, U, V;
251   unsigned int line, remainder;
252
253   if ((x >= (int)surface.sfc.width) || (y >= (int)surface.sfc.height))
254     return;
255
256   c2rgba(c, &r, &g, &b, &a);
257
258   rgb2yuv(r, g, b, &Y, &U, &V);
259
260   remainder = (surface.sfc.width % 4);
261   if (remainder == 0)
262     line = surface.sfc.width;
263   else
264     line = surface.sfc.width + (4 - remainder);
265
266   offset = (y * line) + x;
267
268   *(surface.base[0] + offset) = Y;
269   *(surface.base[1] + (offset & 0xfffffffe)) = U;
270   *(surface.base[1] + (offset & 0xfffffffe) + 1) = V;
271   *(surface.base[2] + offset) = a;
272
273 }
274
275 void Surface::drawHorzLine(int x1, int x2, int y, unsigned int c)
276 {
277   fillblt(x1, y, x2-x1, 1, c);
278 }
279
280 void Surface::drawVertLine(int x, int y1, int y2, unsigned int c)
281 {
282   fillblt(x, y1, 1, y2-y1, c);
283 }
284
285 void Surface::bufferToScreen() // static, this is for Box::showAll
286 {
287   if (disableDoubleBuffering) return;
288
289   Log::getInstance()->log("Surface", Log::DEBUG, "Full buffer to screen");
290   bufferToScreen(0, 0, buffer->surface.sfc.width, buffer->surface.sfc.height);
291 }
292
293 //int Surface::updateToScreen(int x, int y, int width, int height) // main method for all normal windows
294 //{
295   /*
296   With double buffering:
297     A view has buffer for its surface. this is buffer, copy area specified to screen
298   Without double buffering:
299     A view has screen for its surface. this is screen, all painting work has already been done. ignore
300   */
301
302 //  if (this == screen) return 0;
303 //
304 //  return blt(fdOsd, surface.sfc.handle, x, y, width, height, screen->getSurfaceHandle(), x, y);
305 //}
306
307 int Surface::bufferToScreen(int x, int y, int width, int height) // static
308 {
309   return blt(Osd::getInstance()->getFD(), buffer->getSurfaceHandle(), x, y, width, height, screen->getSurfaceHandle(), x, y);
310 }
311
312 int Surface::updateToBuffer(int x, int y, int width, int height) // main method for all normal windows
313 {
314   return blt(fdOsd, surface.sfc.handle, 0, 0, width, height, buffer->getSurfaceHandle(), x, y);
315 }
316
317 int Surface::blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy)
318 {
319   osd_bitblt_t fblt;
320   memset(&fblt, 0, sizeof(fblt));
321
322   fblt.dst_handle = dhandle;
323   fblt.dst_x = dx;
324   fblt.dst_y = dy;
325
326   fblt.src_handle = shandle;
327   fblt.src_x = sx;
328   fblt.src_y = sy;
329
330   fblt.width = width;
331   fblt.height = height;
332
333   fblt.u1 = 1;
334   fblt.u2 = 0;
335   fblt.u3 = 0x0f;
336
337   return ioctl(fd, GFX_FB_OSD_BITBLT, &fblt);
338 }
339
340 int Surface::drawText(char* text, int x, int y, int r, int g, int b)
341 {
342   int h, n, i;
343   int Y, X, cx;
344   unsigned long fg;
345
346   fg = rgba(r, g, b, 255);
347
348   n = strlen(text);
349   h = font->height;
350
351   X = 0;
352   cx = 0;
353   for (i=0; i<n; i++)
354   {
355     unsigned char c = text[i];
356     unsigned long *character = &font->content[font->offset[c]];
357     int w = font->width[c];
358     int pixels = 0;
359
360     for (X=0; X<w; X++)
361     {
362       for (Y=0; Y<h; Y++)
363       {
364         if ((character[Y] >> (32 - X)) & 0x1)
365         {
366           drawPixel(x+X+cx, y+Y, fg);
367           pixels++;
368         }
369       }
370     }
371     cx += w;
372   }
373   return 1;
374 }
375
376 int Surface::drawTextRJ(char* text, int x, int y, int r, int g, int b)
377 {
378   int i, n, w;
379   w = 0;
380
381   n = strlen(text);
382
383   for (i = 0; i < n; i++)
384   {
385     w += font->width[text[i]];
386   }
387
388   x -= w;
389
390   if (x < 0) return 0;
391   else return drawText(text, x, y, r, g, b);
392 }
393
394 int Surface::getCharWidth(char c)
395 {
396   return font->width[c];
397 }
398
399 int Surface::getFontHeight()
400 {
401   return font->height;
402 }
403
404 void Surface::screenShot(char* fileName)
405 {
406   Log* logger = Log::getInstance();
407
408   FILE* outfile = fopen(fileName, "w");
409   if (outfile == NULL)
410   {
411     logger->log("Surface", Log::ERR, "Can't open JPEG");
412     return;
413   }
414   logger->log("Surface", Log::DEBUG, "File opened %u %u", surface.sfc.height, surface.sfc.width);
415
416   struct jpeg_compress_struct cinfo;
417   struct jpeg_error_mgr jerr;
418   cinfo.err = jpeg_std_error(&jerr);
419   jpeg_create_compress(&cinfo);
420   jpeg_stdio_dest(&cinfo, outfile);
421   cinfo.image_width = surface.sfc.width;
422   cinfo.image_height = surface.sfc.height;
423   cinfo.input_components = 3;
424   cinfo.in_color_space = JCS_RGB;
425   jpeg_set_defaults(&cinfo);
426   jpeg_start_compress(&cinfo, TRUE);
427
428
429   unsigned char row[surface.sfc.width * 3];
430   unsigned char* prow = (unsigned char*)&row;
431   unsigned char r, g, b;
432
433   while (cinfo.next_scanline < cinfo.image_height)
434   {
435     for(unsigned int i = 0; i < surface.sfc.width; i++)
436     {
437       readPixel(i, cinfo.next_scanline, &r, &g, &b);
438       row[i * 3] = r;
439       row[(i * 3) + 1] = g;
440       row[(i * 3) + 2] = b;
441     }
442     jpeg_write_scanlines(&cinfo, (JSAMPLE **)&prow, 1);
443   }
444
445   jpeg_finish_compress(&cinfo);
446   jpeg_destroy_compress(&cinfo);
447   fclose(outfile);
448   logger->log("Surface", Log::DEBUG, "Jpeg saved");
449 }
450
451 void Surface::readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b)
452 {
453   int offset;
454   unsigned char a, Y, U, V;
455   unsigned int line, remainder;
456
457   if (((unsigned int)x >= surface.sfc.width) || ((unsigned int)y >= surface.sfc.height)) return;
458
459   remainder = (surface.sfc.width % 4);
460   if (remainder == 0)
461     line = surface.sfc.width;
462   else
463     line = surface.sfc.width + (4 - remainder);
464
465   offset = (y * line) + x;
466
467   Y = *(surface.base[0] + offset);
468   U = *(surface.base[1] + (offset & 0xfffffffe));
469   V = *(surface.base[1] + (offset & 0xfffffffe) + 1);
470   a = *(surface.base[2] + offset);
471
472   yuv2rgb(Y, U, V, r, g, b);
473 }
474
475 void Surface::yuv2rgb(int y, int u, int v, unsigned char* pr, unsigned char* pg, unsigned char* pb)
476 {
477    // from http://www.fourcc.org/index.php?http%3A//www.fourcc.org/fccyvrgb.php
478
479 //   unsigned int pixel32;
480 //   unsigned char *pixel = (unsigned char *)&pixel32;
481    int r, g, b;
482
483
484    /*
485      One formula I found:  (not the right one)
486
487      R = 1.164(Y - 16) + 1.596(Cr - 128)
488      G = 1.164(Y - 16) - 0.813(Cr - 128) - 0.391(Cb - 128)
489      B = 1.164(Y - 16)                   + 2.018(Cb - 128)
490
491
492    r = (1.164 * (y - 16))
493       + (2.018 * (v - 128));
494    g = (1.164 * (y - 16))
495       - (0.813 * (u - 128))
496       - (0.391 * (v - 128));
497    b = (1.164 * (y - 16))
498       + (1.596 * (u - 128));
499
500
501      Another formula I found:  (seems to work)
502
503      R = Y + 1.370705 (V-128)
504      G = Y - 0.698001 (V-128) - 0.337633 (U-128)
505      B = Y + 1.732446 (U-128)
506    */
507
508    r = (int)( y + (1.370705 * (v-128)) );
509    g = (int)( y - (0.698001 * (v-128)) - (0.337633 * (u-128)) );
510    b = (int)( y + (1.732446 * (u-128)) );
511
512    // Even with proper conversion, some values still need clipping.
513    if (r > 255) r = 255;
514    if (g > 255) g = 255;
515    if (b > 255) b = 255;
516    if (r < 0) r = 0;
517    if (g < 0) g = 0;
518    if (b < 0) b = 0;
519
520    // Values only go from 0-220..  Why?
521 //   pixel[0] = r * 220 / 256;
522 //   pixel[1] = g * 220 / 256;
523 //   pixel[2] = b * 220 / 256;
524 //   pixel[3] = 0;
525
526    *pr = (unsigned char) (r * 220 / 256);
527    *pg = (unsigned char) (g * 220 / 256);
528    *pb = (unsigned char) (b * 220 / 256);
529
530    /* Debug
531    //printf("yuv2rgb(%i, %i, %i) -> %i, %i, %i  (0x%x)\n",
532     y, u, v,
533     pixel[0], pixel[1], pixel[2],
534     pixel32);
535    */
536
537 //   return pixel32;
538 }