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