2 Copyright 2004-2005 Chris Tallon
3 Portions copyright 2004 Jon Gettler
5 This file is part of VOMP.
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.
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.
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
25 Surface* Surface::screen = NULL;
26 Surface* Surface::buffer = NULL;
27 int Surface::disableDoubleBuffering = 0;
28 osd_font_t* Surface::font = &font_helvB18;
30 Surface::Surface(int id)
32 if (id == SCREEN) screen = this;
33 if (id == BUFFER) buffer = this;
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));
43 for (int i = 0; i < 3; i++)
45 if (surface.base[i]) munmap(surface.base[i], surface.map.map[i].size);
50 a = ioctl(fdOsd, GFX_FB_SFC_UNMAP, surface.sfc.handle);
51 if (a) Log::getInstance()->log("Surface", Log::ERR, "Surface unmap failed");
53 a = ioctl(fdOsd, GFX_FB_SFC_FREE, surface.sfc.handle);
54 if (a) Log::getInstance()->log("Surface", Log::ERR, "Surface destroy failed");
58 void Surface::disableBuffer()
60 disableDoubleBuffering = 1;
63 Surface* Surface::getObject(int id)
65 if (id == SCREEN) return screen;
66 if (disableDoubleBuffering) return screen;
67 if (id == BUFFER) return buffer;
71 int Surface::create(UINT width, UINT height)
74 int displayNumber = 0; // mvpmc iterates 0->15 till it gets one that works?
76 surface.sfc.width = width;
77 surface.sfc.height = height;
78 surface.sfc.flags = 0x3f1533;
80 surface.sfc.unknown = -1;
82 // r = ioctl(fdOsd, GFX_FB_SET_OSD, &displayNumber);
85 r = ioctl(fdOsd, GFX_FB_OSD_SURFACE, &displayNumber);
88 r = ioctl(fdOsd, GFX_FB_SFC_ALLOC, &surface.sfc);
91 surface.map.map[0].unknown = surface.sfc.handle;
92 r = ioctl(fdOsd, GFX_FB_MAP, &surface.map);
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;
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;
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;
104 // surface.display.num = displayNumber;
105 // r = ioctl(fdOsd, GFX_FB_MOVE_DISPLAY, &surface.display);
108 // r = ioctl(fdOsd, GFX_FB_SET_DISPLAY, &surface.display);
114 void Surface::display()
116 unsigned long fb_descriptor[2];
118 fb_descriptor[0] = surface.sfc.handle;
119 fb_descriptor[1] = 1;
121 ioctl(fdOsd, GFX_FB_ATTACH, fb_descriptor);
124 unsigned long Surface::getSurfaceHandle()
126 return surface.sfc.handle;
129 // ----------------------------------------------------------------------------
131 // Now for the drawing functions
134 * RGB to YUV conversion tables
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];
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];
157 * gfx_init() - initialize the RGB to YUV conversion tables
159 void Surface::initConversionTables(void)
163 for (i=0; i<256; i++) {
164 conv_YB[i] = (int)(0.299 * (double)i);
167 for (i=0; i<256; i++) {
168 conv_YG[i] = (int)(0.587 * (double)i);
171 for (i=0; i<256; i++) {
172 conv_YR[i] = (int)(0.114 * (double)i);
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));
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));
184 for (i=0; i<256; i++) {
185 conv_UR[i] = (int)(-0.16874 * (double)i);
189 for (i=0; i<256; i++) {
190 conv_VB[i] = (int)(-0.08131 * (double)i);
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));
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));
204 * rgb2yuv() - convert an RGB pixel to YUV
207 void Surface::rgb2yuv(unsigned char r, unsigned char g, unsigned char b, unsigned char *y, unsigned char *u, unsigned char *v)
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;
233 int Surface::fillblt(int x, int y, int width, int height, unsigned int c)
237 fblt.handle = surface.sfc.handle;
241 fblt.height = height;
244 return ioctl(fdOsd, GFX_FB_OSD_FILLBLT, &fblt);
247 void Surface::drawPixel(int x, int y, unsigned int c)
250 unsigned char r, g, b, a, Y, U, V;
251 unsigned int line, remainder;
253 if ((x >= (int)surface.sfc.width) || (y >= (int)surface.sfc.height))
256 c2rgba(c, &r, &g, &b, &a);
258 rgb2yuv(r, g, b, &Y, &U, &V);
260 remainder = (surface.sfc.width % 4);
262 line = surface.sfc.width;
264 line = surface.sfc.width + (4 - remainder);
266 offset = (y * line) + x;
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;
275 void Surface::drawHorzLine(int x1, int x2, int y, unsigned int c)
277 fillblt(x1, y, x2-x1, 1, c);
280 void Surface::drawVertLine(int x, int y1, int y2, unsigned int c)
282 fillblt(x, y1, 1, y2-y1, c);
285 void Surface::bufferToScreen() // static, this is for Box::showAll
287 if (disableDoubleBuffering) return;
289 Log::getInstance()->log("Surface", Log::DEBUG, "Full buffer to screen");
290 bufferToScreen(0, 0, buffer->surface.sfc.width, buffer->surface.sfc.height);
293 //int Surface::updateToScreen(int x, int y, int width, int height) // main method for all normal windows
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
302 // if (this == screen) return 0;
304 // return blt(fdOsd, surface.sfc.handle, x, y, width, height, screen->getSurfaceHandle(), x, y);
307 int Surface::bufferToScreen(int x, int y, int width, int height) // static
309 return blt(Osd::getInstance()->getFD(), buffer->getSurfaceHandle(), x, y, width, height, screen->getSurfaceHandle(), x, y);
312 int Surface::updateToBuffer(int x, int y, int width, int height) // main method for all normal windows
314 return blt(fdOsd, surface.sfc.handle, 0, 0, width, height, buffer->getSurfaceHandle(), x, y);
317 int Surface::blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy)
320 memset(&fblt, 0, sizeof(fblt));
322 fblt.dst_handle = dhandle;
326 fblt.src_handle = shandle;
331 fblt.height = height;
337 return ioctl(fd, GFX_FB_OSD_BITBLT, &fblt);
340 int Surface::drawText(char* text, int x, int y, int r, int g, int b)
346 fg = rgba(r, g, b, 255);
355 unsigned char c = text[i];
356 unsigned long *character = &font->content[font->offset[c]];
357 int w = font->width[c];
364 if ((character[Y] >> (32 - X)) & 0x1)
366 drawPixel(x+X+cx, y+Y, fg);
376 int Surface::drawTextRJ(char* text, int x, int y, int r, int g, int b)
383 for (i = 0; i < n; i++)
385 w += font->width[text[i]];
391 else return drawText(text, x, y, r, g, b);
394 int Surface::getCharWidth(char c)
396 return font->width[c];
399 int Surface::getFontHeight()
404 void Surface::screenShot(char* fileName)
406 Log* logger = Log::getInstance();
408 FILE* outfile = fopen(fileName, "w");
411 logger->log("Surface", Log::ERR, "Can't open JPEG");
414 logger->log("Surface", Log::DEBUG, "File opened %u %u", surface.sfc.height, surface.sfc.width);
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);
429 unsigned char row[surface.sfc.width * 3];
430 unsigned char* prow = (unsigned char*)&row;
431 unsigned char r, g, b;
433 while (cinfo.next_scanline < cinfo.image_height)
435 for(unsigned int i = 0; i < surface.sfc.width; i++)
437 readPixel(i, cinfo.next_scanline, &r, &g, &b);
439 row[(i * 3) + 1] = g;
440 row[(i * 3) + 2] = b;
442 jpeg_write_scanlines(&cinfo, (JSAMPLE **)&prow, 1);
445 jpeg_finish_compress(&cinfo);
446 jpeg_destroy_compress(&cinfo);
448 logger->log("Surface", Log::DEBUG, "Jpeg saved");
451 void Surface::readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b)
454 unsigned char a, Y, U, V;
455 unsigned int line, remainder;
457 if (((unsigned int)x >= surface.sfc.width) || ((unsigned int)y >= surface.sfc.height)) return;
459 remainder = (surface.sfc.width % 4);
461 line = surface.sfc.width;
463 line = surface.sfc.width + (4 - remainder);
465 offset = (y * line) + x;
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);
472 yuv2rgb(Y, U, V, r, g, b);
475 void Surface::yuv2rgb(int y, int u, int v, unsigned char* pr, unsigned char* pg, unsigned char* pb)
477 // from http://www.fourcc.org/index.php?http%3A//www.fourcc.org/fccyvrgb.php
479 // unsigned int pixel32;
480 // unsigned char *pixel = (unsigned char *)&pixel32;
485 One formula I found: (not the right one)
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)
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));
501 Another formula I found: (seems to work)
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)
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)) );
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;
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;
526 *pr = (unsigned char) (r * 220 / 256);
527 *pg = (unsigned char) (g * 220 / 256);
528 *pb = (unsigned char) (b * 220 / 256);
531 //printf("yuv2rgb(%i, %i, %i) -> %i, %i, %i (0x%x)\n",
533 pixel[0], pixel[1], pixel[2],