diff --git a/projects/recalbox-fbv/.gitignore b/projects/recalbox-fbv/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..bf797c5fe75b3e882c98b694e912b65ddcffd5e2
--- /dev/null
+++ b/projects/recalbox-fbv/.gitignore
@@ -0,0 +1 @@
+cmake-build-debug
\ No newline at end of file
diff --git a/projects/recalbox-fbv/.idea/.gitignore b/projects/recalbox-fbv/.idea/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..73f69e0958611ac6e00bde95641f6699030ad235
--- /dev/null
+++ b/projects/recalbox-fbv/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/projects/recalbox-fbv/.idea/.name b/projects/recalbox-fbv/.idea/.name
new file mode 100644
index 0000000000000000000000000000000000000000..27a223c909d2e4c5e2d1db904138a95750e0eb03
--- /dev/null
+++ b/projects/recalbox-fbv/.idea/.name
@@ -0,0 +1 @@
+fbv2
\ No newline at end of file
diff --git a/projects/recalbox-fbv/.idea/fbv.iml b/projects/recalbox-fbv/.idea/fbv.iml
new file mode 100644
index 0000000000000000000000000000000000000000..f08604bb65b25149b195f9e9f282f9683a428592
--- /dev/null
+++ b/projects/recalbox-fbv/.idea/fbv.iml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/projects/recalbox-fbv/.idea/inspectionProfiles/Project_Default.xml b/projects/recalbox-fbv/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1ac5b580d43a0d808b765c3dea3bff22bd84829a
--- /dev/null
+++ b/projects/recalbox-fbv/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/recalbox-fbv/.idea/misc.xml b/projects/recalbox-fbv/.idea/misc.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8822db8f1c2b8ceffb5d86c69dd1952cf6552980
--- /dev/null
+++ b/projects/recalbox-fbv/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/recalbox-fbv/.idea/modules.xml b/projects/recalbox-fbv/.idea/modules.xml
new file mode 100644
index 0000000000000000000000000000000000000000..23361f90e879c908c7b078c2bcce801f0834e277
--- /dev/null
+++ b/projects/recalbox-fbv/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/recalbox-fbv/.idea/vcs.xml b/projects/recalbox-fbv/.idea/vcs.xml
new file mode 100644
index 0000000000000000000000000000000000000000..94a25f7f4cb416c083d265558da75d457237d671
--- /dev/null
+++ b/projects/recalbox-fbv/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/recalbox-fbv/CMakeLists.txt b/projects/recalbox-fbv/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d0d61ed2ef8d6f870b7e7c1dd952a79ad8d5c4b7
--- /dev/null
+++ b/projects/recalbox-fbv/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 2.8)
+project(fbv2 C)
+
+set(CMAKE_C_STANDARD 11)
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra")
+
+include_directories(.)
+
+add_executable(fbv2
+ bmp.c
+ fb_display.c
+ fbv.h
+ gif.c
+ jpeg.c
+ main.c
+ png.c
+ transforms.c)
+
+target_link_libraries(fbv2 gif png jpeg)
diff --git a/projects/recalbox-fbv/COPYING b/projects/recalbox-fbv/COPYING
new file mode 100644
index 0000000000000000000000000000000000000000..42a1b9318c663105d1b5314ff6c2bf62b763e784
--- /dev/null
+++ b/projects/recalbox-fbv/COPYING
@@ -0,0 +1,5 @@
+The package is licensed under the GPL license, version 2.
+
+It was to large to include it here (bigger than the whole source).
+
+Obtain your copy from http://www.gnu.org
diff --git a/projects/recalbox-fbv/README.md b/projects/recalbox-fbv/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..f64cac3558e6a24ac9d4997444a524ed104c18ea
--- /dev/null
+++ b/projects/recalbox-fbv/README.md
@@ -0,0 +1,49 @@
+1. OVERVIEW
+ fbv (FrameBuffer Viewer) is a simple program to view pictures on
+ a linux framebuffer device. In 2000, when fbv was created, there
+ were no other situable programs performing the same task, so the
+ authors decided to follow the rule: 'If you need a tool - write
+ it yourself!' :-)
+
+2. REQUIREMENTS
+ - Linux, configured to provide the framebuffer device interface
+ (/dev/fb0 or /dev/fb/0)
+ - libungif for GIF support
+ - libjpeg for JPEG support
+ - libpng for PNG support
+
+3. INSTALLATION
+ - unpack the archive (you've propably already done it)
+ - run ./configure
+ - type: make
+ - type: make install
+ - enjoy...
+
+4. USAGE
+ Just run fbv without any arguments, and a short help message
+ will appear...
+
+5. AUTHORS
+ Tomasz 'smoku' Sterna
+ Mateusz 'mteg' Golicz
+
+ Feel free to send any comments, patches, bugfixes, suggestions, etc. The
+ authors are not native english speakers, and they are aware of the fact
+ that their english is far from perfect. Because of that, reports on
+ grammar and vocabulary mistakes in this file are also welcome.
+
+6. BUGS & TODO
+ - the code is really awfully formated and requires some fixes...
+ - the english in messages is not the best at all :-)
+
+7. ACKNOWLEDGEMENTS
+ - the fbset authors: some code in fb_display.c is based on it...
+ - Nat Ersoz - for his suggestions and bugfixes
+ - Mauro Meneghin - for the transparent GIF support
+ - Marcin 'Piaskowy' Zieba - for his minor bugfixes
+ - Mariusz 'Ma-rYu-sH' Witkowski - for his suggestions on alpha
+ channel support and testing
+
+8. LICENSE
+ The package is licensed under the GNU GPL license, version 2.
+ Obtain your copy at http://www.gnu.org.
diff --git a/projects/recalbox-fbv/bmp.c b/projects/recalbox-fbv/bmp.c
new file mode 100644
index 0000000000000000000000000000000000000000..5f143c660e02f62a96bbdbc4f5e49eab456b85e1
--- /dev/null
+++ b/projects/recalbox-fbv/bmp.c
@@ -0,0 +1,259 @@
+/*
+ fbv -- simple image viewer for the linux framebuffer
+ Copyright (C) 2002 Tomasz Sterna
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+#include "config.h"
+#ifdef FBV_SUPPORT_BMP
+#include "fbv.h"
+#include
+#include
+#include
+
+#define BMP_TORASTER_OFFSET 10
+#define BMP_SIZE_OFFSET 18
+#define BMP_BPP_OFFSET 28
+//#define BMP_RLE_OFFSET 30
+#define BMP_COLOR_OFFSET 54
+
+#define fill4B(a) ( ( 4 - ( (a) % 4 ) ) & 0x03)
+
+struct color {
+ unsigned char red;
+ unsigned char green;
+ unsigned char blue;
+};
+
+int fh_bmp_id(char *name)
+{
+ char id[2];
+
+ int fd = open(name, O_RDONLY);
+ if (fd == -1) {
+ return(0);
+ }
+
+ read(fd, id, 2);
+ close(fd);
+ if ( id[0]=='B' && id[1]=='M' ) {
+ return(1);
+ }
+ return(0);
+}
+
+void fetch_pallete(int fd, struct color pallete[], int count)
+{
+ unsigned char buff[4];
+
+ lseek(fd, BMP_COLOR_OFFSET, SEEK_SET);
+ for (int i=0; i> 4;
+ buff[2] = buff[0] & 0x0f;
+ *wr_buffer++ = pallete[buff[1]].red;
+ *wr_buffer++ = pallete[buff[1]].green;
+ *wr_buffer++ = pallete[buff[1]].blue;
+ *wr_buffer++ = pallete[buff[2]].red;
+ *wr_buffer++ = pallete[buff[2]].green;
+ *wr_buffer++ = pallete[buff[2]].blue;
+ }
+ if (x % 2)
+ {
+ read(fd, buff, 1);
+ buff[1] = buff[0] >> 4;
+ *wr_buffer++ = pallete[buff[1]].red;
+ *wr_buffer++ = pallete[buff[1]].green;
+ *wr_buffer++ = pallete[buff[1]].blue;
+ }
+ if (skip)
+ {
+ read(fd, buff, skip);
+ }
+ wr_buffer -= x * 6; /* backoff 2 lines - x*2 *3 */
+ }
+ break;
+ }
+ case 8:
+ { /* 8bit palletized */
+ int skip = fill4B(x);
+ fetch_pallete(fd, pallete, 256);
+ lseek(fd, raster, SEEK_SET);
+ for (int i = 0; i < y; i++)
+ {
+ for (int j = 0; j < x; j++)
+ {
+ read(fd, buff, 1);
+ *wr_buffer++ = pallete[buff[0]].red;
+ *wr_buffer++ = pallete[buff[0]].green;
+ *wr_buffer++ = pallete[buff[0]].blue;
+ }
+ if (skip)
+ {
+ read(fd, buff, skip);
+ }
+ wr_buffer -= x * 6; /* backoff 2 lines - x*2 *3 */
+ }
+ break;
+ }
+ case 16: /* 16bit RGB */
+ return(FH_ERROR_FORMAT);
+ case 24:
+ { /* 24bit RGB */
+ int skip = fill4B(x * 3);
+ lseek(fd, raster, SEEK_SET);
+ for (int i = 0; i < y; i++)
+ {
+ for (int j = 0; j < x; j++)
+ {
+ read(fd, buff, 3);
+ *wr_buffer++ = buff[2];
+ *wr_buffer++ = buff[1];
+ *wr_buffer++ = buff[0];
+ }
+ if (skip)
+ {
+ read(fd, buff, skip);
+ }
+ wr_buffer -= x * 6; /* backoff 2 lines - x*2 *3 */
+ }
+ break;
+ }
+ default:
+ return(FH_ERROR_FORMAT);
+ }
+
+ close(fd);
+ return(FH_ERROR_OK);
+}
+int fh_bmp_getsize(char *name,int *x,int *y)
+{
+ unsigned char size[4];
+
+ int fd = open(name, O_RDONLY);
+ if (fd == -1) {
+ return(FH_ERROR_FILE);
+ }
+ if (lseek(fd, BMP_SIZE_OFFSET, SEEK_SET) == -1) {
+ return(FH_ERROR_FORMAT);
+ }
+
+ read(fd, size, 4);
+ *x = size[0] + (size[1]<<8) + (size[2]<<16) + (size[3]<<24);
+// *x-=1;
+ read(fd, size, 4);
+ *y = size[0] + (size[1]<<8) + (size[2]<<16) + (size[3]<<24);
+
+ close(fd);
+ return(FH_ERROR_OK);
+}
+#endif
diff --git a/projects/recalbox-fbv/config.h b/projects/recalbox-fbv/config.h
new file mode 100644
index 0000000000000000000000000000000000000000..19b65d6fdac146422c77402dbd10963b3f050bca
--- /dev/null
+++ b/projects/recalbox-fbv/config.h
@@ -0,0 +1,5 @@
+#define DEFAULT_FRAMEBUFFER "/dev/fb0"
+#define FBV_SUPPORT_GIF
+#define FBV_SUPPORT_JPEG
+#define FBV_SUPPORT_PNG
+#define FBV_SUPPORT_BMP
\ No newline at end of file
diff --git a/projects/recalbox-fbv/fb_display.c b/projects/recalbox-fbv/fb_display.c
new file mode 100644
index 0000000000000000000000000000000000000000..885b5b36599424747613842e99577c8572fa0954
--- /dev/null
+++ b/projects/recalbox-fbv/fb_display.c
@@ -0,0 +1,398 @@
+/*`
+ fbv -- simple image viewer for the linux framebuffer
+ Copyright (C) 2000 Tomasz Sterna
+ Copyright (C) 2003 Mateusz Golicz
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "config.h"
+
+/* Public Use Functions:
+ *
+ * extern void fb_display(unsigned char *rgbbuff,
+ * int x_size, int y_size,
+ * int x_pan, int y_pan,
+ * int x_offs, int y_offs);
+ *
+ * extern void getCurrentRes(int *x,int *y);
+ *
+ */
+
+unsigned short red[256], green[256], blue[256];
+struct fb_cmap map332 = {
+ 0,
+ 256,
+ red,
+ green,
+ blue,
+ NULL
+};
+unsigned short red_b[256], green_b[256], blue_b[256];
+struct fb_cmap map_back = {
+ 0,
+ 256,
+ red_b,
+ green_b,
+ blue_b,
+ NULL
+};
+
+
+int openFB(const char* name);
+
+void closeFB(int fh);
+
+void getVarScreenInfo(int fh, struct fb_var_screeninfo* var);
+
+//void setVarScreenInfo(int fh, struct fb_var_screeninfo* var);
+
+void getFixScreenInfo(int fh, struct fb_fix_screeninfo* fix);
+
+void set332map(int fh);
+
+void* convertRGB2FB(int fh, unsigned char* rgbbuff, unsigned long count, int bpp, int* cpp);
+
+void blit2FB(int fh, void* fbbuff, unsigned char* alpha, unsigned int pic_xs, unsigned int pic_ys, unsigned int scr_xs,
+ unsigned int scr_ys, unsigned int xp, unsigned int yp, unsigned int xoffs, unsigned int yoffs, int cpp,
+ int clear_before);
+
+void fb_display(unsigned char* rgbbuff, unsigned char* alpha, int x_size, int y_size, int x_pan, int y_pan, int x_offs,
+ int y_offs, int clear_before)
+{
+ struct fb_var_screeninfo var;
+ struct fb_fix_screeninfo fix;
+ int bp = 0;
+
+ /* get the framebuffer device handle */
+ int fh = openFB(NULL);
+
+ /* read current video mode */
+ getVarScreenInfo(fh, &var);
+ getFixScreenInfo(fh, &fix);
+
+ int x_stride = (int)((fix.line_length * 8) / var.bits_per_pixel);
+
+ /* correct panning */
+ if (x_pan > x_size - x_stride) x_pan = 0;
+ if (y_pan > y_size - (int)var.yres) y_pan = 0;
+ /* correct offset */
+ if (x_offs + x_size > x_stride) x_offs = 0;
+ if (y_offs + y_size > (int)var.yres) y_offs = 0;
+
+ /* blit buffer 2 fb */
+ unsigned short* fbbuff = convertRGB2FB(fh, rgbbuff, x_size * y_size, var.bits_per_pixel, &bp);
+
+ #if 0
+ blit2FB(fh, fbbuff, alpha, x_size, y_size, x_stride, var.yres, x_pan, y_pan, x_offs, y_offs, bp);
+ #else
+ blit2FB(fh, fbbuff, alpha, x_size, y_size, x_stride, var.yres_virtual, x_pan, y_pan, x_offs, y_offs + var.yoffset,
+ bp, clear_before);
+ #endif
+ free(fbbuff);
+
+ /* close device */
+ closeFB(fh);
+}
+
+void getCurrentRes(int* x, int* y)
+{
+ struct fb_var_screeninfo var;
+ int fh = openFB(NULL);
+ getVarScreenInfo(fh, &var);
+ *x = var.xres;
+ *y = var.yres;
+ closeFB(fh);
+}
+
+int openFB(const char* name)
+{
+ if (name == NULL)
+ {
+ char* dev = getenv("FRAMEBUFFER");
+ if (dev) name = dev;
+ else name = DEFAULT_FRAMEBUFFER;
+ }
+
+ int fh = open(name, O_RDWR);
+ if (fh == -1)
+ {
+ fprintf(stderr, "open %s: %s\n", name, strerror(errno));
+ exit(1);
+ }
+ return fh;
+}
+
+void closeFB(int fh)
+{
+ close(fh);
+}
+
+void getVarScreenInfo(int fh, struct fb_var_screeninfo* var)
+{
+ if (ioctl(fh, FBIOGET_VSCREENINFO, var))
+ {
+ fprintf(stderr, "ioctl FBIOGET_VSCREENINFO: %s\n", strerror(errno));
+ exit(1);
+ }
+}
+
+/*void setVarScreenInfo(int fh, struct fb_var_screeninfo* var)
+{
+ if (ioctl(fh, FBIOPUT_VSCREENINFO, var))
+ {
+ fprintf(stderr, "ioctl FBIOPUT_VSCREENINFO: %s\n", strerror(errno));
+ exit(1);
+ }
+}*/
+
+void getFixScreenInfo(int fh, struct fb_fix_screeninfo* fix)
+{
+ if (ioctl(fh, FBIOGET_FSCREENINFO, fix))
+ {
+ fprintf(stderr, "ioctl FBIOGET_FSCREENINFO: %s\n", strerror(errno));
+ exit(1);
+ }
+}
+
+void make332map(struct fb_cmap* map)
+{
+ int r = 8, g = 8, b = 4;
+
+ map->red = red;
+ map->green = green;
+ map->blue = blue;
+
+ int rs = 256 / (r - 1);
+ int gs = 256 / (g - 1);
+ int bs = 256 / (b - 1);
+
+ for (int i = 0; i < 256; i++)
+ {
+ map->red[i] = (rs * ((i / (g * b)) % r)) * 255;
+ map->green[i] = (gs * ((i / b) % g)) * 255;
+ map->blue[i] = (bs * ((i) % b)) * 255;
+ }
+}
+
+void set8map(int fh, struct fb_cmap* map)
+{
+ if (ioctl(fh, FBIOPUTCMAP, map) < 0)
+ {
+ fprintf(stderr, "Error putting colormap");
+ exit(1);
+ }
+}
+
+void get8map(int fh, struct fb_cmap* map)
+{
+ if (ioctl(fh, FBIOGETCMAP, map) < 0)
+ {
+ fprintf(stderr, "Error getting colormap");
+ exit(1);
+ }
+}
+
+void set332map(int fh)
+{
+ make332map(&map332);
+ set8map(fh, &map332);
+}
+
+void blit2FB(int fh, void* fbbuff, unsigned char* alpha, unsigned int pic_xs, unsigned int pic_ys, unsigned int scr_xs,
+ unsigned int scr_ys, unsigned int xp, unsigned int yp, unsigned int xoffs, unsigned int yoffs, int cpp, int clear_before)
+{
+ int xc = (int)((pic_xs > scr_xs) ? scr_xs : pic_xs);
+ int yc = (int)((pic_ys > scr_ys) ? scr_ys : pic_ys);
+
+ unsigned char* fb = (unsigned char*)malloc(scr_xs * scr_ys * cpp);
+ if (clear_before != 0) memset(fb, 0, scr_xs * scr_ys * cpp);
+ else
+ {
+ read(fh, fb, scr_xs * scr_ys * cpp);
+ lseek(fh, 0, SEEK_SET);
+ }
+
+ if (fb == NULL /*MAP_FAILED*/)
+ {
+ perror("mmap");
+ return;
+ }
+
+ if (cpp == 1)
+ {
+ get8map(fh, &map_back);
+ set332map(fh);
+ }
+
+ unsigned char* fbptr = fb + (yoffs * scr_xs + xoffs) * cpp;
+ unsigned char* imptr = fbbuff + (yp * pic_xs + xp) * cpp;
+
+ if (alpha)
+ {
+ unsigned char* alphaptr = alpha + (yp * pic_xs + xp);
+
+ for (int i = 0; i < yc; i++, fbptr += scr_xs * cpp, imptr += pic_xs * cpp, alphaptr += pic_xs)
+ {
+ for (int x = 0; x < xc; x++)
+ {
+ int from = -1, to = -1;
+ for (int v = x; v < xc; v++)
+ {
+ if (from == -1)
+ {
+ if (alphaptr[v] > 0x80) from = v;
+ }
+ else
+ {
+ if (alphaptr[v] < 0x80)
+ {
+ to = v;
+ break;
+ }
+ }
+ }
+ if (from == -1)
+ break;
+
+ if (to == -1) to = xc;
+
+ memcpy(fbptr + (from * cpp), imptr + (from * cpp), (to - from - 1) * cpp);
+ x += to - from - 1;
+ }
+ }
+ }
+ else
+ for (int i = 0; i < yc; i++, fbptr += scr_xs * cpp, imptr += pic_xs * cpp)
+ memcpy(fbptr, imptr, xc * cpp);
+
+ if (cpp == 1)
+ set8map(fh, &map_back);
+
+ if (write(fh, fb, scr_xs * scr_ys * cpp) != scr_xs * scr_ys * cpp)
+ perror("write");
+ lseek(fh, 0, SEEK_SET);
+ free(fb);
+}
+
+inline static unsigned char make8color(unsigned char r, unsigned char g, unsigned char b)
+{
+ return ((((r >> 5) & 7) << 5) | (((g >> 5) & 7) << 2) | ((b >> 6) & 3));
+}
+
+inline static unsigned short make15color(unsigned char r, unsigned char g, unsigned char b)
+{
+ return ((((r >> 3) & 31) << 10) | (((g >> 3) & 31) << 5) | ((b >> 3) & 31));
+}
+
+inline static unsigned short make15color_bgr(unsigned char r, unsigned char g, unsigned char b)
+{
+ return ((((b >> 3) & 31) << 10) | (((g >> 3) & 31) << 5) | ((r >> 3) & 31));
+}
+
+inline static unsigned short make16color(unsigned char r, unsigned char g, unsigned char b)
+{
+ return ((((r >> 3) & 31) << 11) | (((g >> 2) & 63) << 5) | ((b >> 3) & 31));
+}
+
+void* convertRGB2FB(int fh, unsigned char* rgbbuff, unsigned long count, int bpp, int* cpp)
+{
+ void* fbbuff = NULL;
+ u_int8_t* c_fbbuff = NULL;
+ u_int16_t* s_fbbuff = NULL;
+ u_int32_t* i_fbbuff = NULL;
+
+ switch (bpp)
+ {
+ case 8:
+ {
+ *cpp = 1;
+ c_fbbuff = (unsigned char*) malloc(count * sizeof(unsigned char));
+ for (unsigned long i = 0; i < count; i++)
+ c_fbbuff[i] = make8color(rgbbuff[i * 3], rgbbuff[i * 3 + 1], rgbbuff[i * 3 + 2]);
+ fbbuff = (void*) c_fbbuff;
+ break;
+ }
+ case 15:
+ {
+ struct fb_var_screeninfo var;
+ getVarScreenInfo(fh, &var);
+ int is_bgr555 = (var.red.offset == 0 && var.green.offset == 5 && var.blue.offset == 10) ? 1 : 0;
+ *cpp = 2;
+ s_fbbuff = (unsigned short*) malloc(count * sizeof(unsigned short));
+ if (is_bgr555 != 0)
+ for (unsigned long i = 0; i < count; i++)
+ s_fbbuff[i] = make15color_bgr(rgbbuff[i * 3], rgbbuff[i * 3 + 1], rgbbuff[i * 3 + 2]);
+ else
+ for (unsigned long i = 0; i < count; i++)
+ s_fbbuff[i] = make15color(rgbbuff[i * 3], rgbbuff[i * 3 + 1], rgbbuff[i * 3 + 2]);
+ fbbuff = (void*) s_fbbuff;
+ break;
+ }
+ case 16:
+ {
+ struct fb_var_screeninfo var;
+ getVarScreenInfo(fh, &var);
+ int is_bgr555 = (var.red.offset == 0 && var.green.offset == 5 && var.blue.offset == 10) ? 1 : 0;
+ *cpp = 2;
+ s_fbbuff = (unsigned short*) malloc(count * sizeof(unsigned short));
+ if (is_bgr555 != 0)
+ for (unsigned long i = 0; i < count; i++)
+ s_fbbuff[i] = make15color_bgr(rgbbuff[i * 3], rgbbuff[i * 3 + 1], rgbbuff[i * 3 + 2]);
+ else
+ for (unsigned long i = 0; i < count; i++)
+ s_fbbuff[i] = make16color(rgbbuff[i * 3], rgbbuff[i * 3 + 1], rgbbuff[i * 3 + 2]);
+ fbbuff = (void*) s_fbbuff;
+ break;
+ }
+ case 24:
+ {
+ *cpp = 3;
+ c_fbbuff = (unsigned char *) malloc(count * 3 * sizeof(unsigned char));
+ for(unsigned long i = 0; i < (3 * count); i += 3)
+ {
+ /* Big endian framebuffer. */
+ c_fbbuff[i] = rgbbuff[i+2];
+ c_fbbuff[i+1] = rgbbuff[i+1];
+ c_fbbuff[i+2] = rgbbuff[i];
+ }
+ fbbuff = (void *) c_fbbuff;
+ break;
+ }
+ case 32:
+ {
+ *cpp = 4;
+ i_fbbuff = (unsigned int*) malloc(count * sizeof(unsigned int));
+ for (unsigned long i = 0; i < count; i++)
+ i_fbbuff[i] = ((rgbbuff[i * 3] << 16) & 0xFF0000) | ((rgbbuff[i * 3 + 1] << 8) & 0xFF00) |
+ (rgbbuff[i * 3 + 2] & 0xFF);
+ fbbuff = (void*) i_fbbuff;
+ break;
+ }
+ default: fprintf(stderr, "Unsupported video mode! You've got: %dbpp\n", bpp);
+ exit(1);
+ }
+ return fbbuff;
+}
diff --git a/projects/recalbox-fbv/fbv.h b/projects/recalbox-fbv/fbv.h
new file mode 100644
index 0000000000000000000000000000000000000000..694a57dbd22807910fb1c6baf1d2f3d501cdb72e
--- /dev/null
+++ b/projects/recalbox-fbv/fbv.h
@@ -0,0 +1,61 @@
+/*
+ fbv -- simple image viewer for the linux framebuffer
+ Copyright (C) 2000, 2001, 2003 Mateusz Golicz
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define FH_ERROR_OK 0
+#define FH_ERROR_FILE 1 /* read/access error */
+#define FH_ERROR_FORMAT 2 /* file format error */
+
+void fb_display(unsigned char *rgbbuff, unsigned char * alpha, int x_size, int y_size, int x_pan, int y_pan, int x_offs, int y_offs, int clear_before);
+void getCurrentRes(int *x, int *y);
+
+int fh_bmp_id(char *name);
+int fh_bmp_load(char *name,unsigned char *buffer, unsigned char **alpha, int x,int y);
+int fh_bmp_getsize(char *name,int *x,int *y);
+
+int fh_jpeg_id(char *name);
+int fh_jpeg_load(char *name,unsigned char *buffer, unsigned char **alpha, int x,int y);
+int fh_jpeg_getsize(char *name,int *x,int *y);
+
+int fh_png_id(char *name);
+int fh_png_load(char *name,unsigned char *buffer, unsigned char **alpha, int x,int y);
+int fh_png_getsize(char *name,int *x,int *y);
+
+int fh_gif_id(char *name);
+int fh_gif_load(char *name,unsigned char *buffer, unsigned char **alpha, int x,int y);
+int fh_gif_getsize(char *name,int *x,int *y);
+
+struct image
+{
+ int width, height;
+ unsigned char *rgb;
+ unsigned char *alpha;
+ int do_free;
+};
+
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef max
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+unsigned char * simple_resize(unsigned char * orgin,int ox,int oy,int dx,int dy);
+unsigned char * alpha_resize(unsigned char * alpha,int ox,int oy,int dx,int dy);
+unsigned char * color_average_resize(unsigned char * orgin,int ox,int oy,int dx,int dy);
+unsigned char * rotate(unsigned char *i, int ox, int oy, int rot);
+unsigned char * alpha_rotate(unsigned char *i, int ox, int oy, int rot);
diff --git a/projects/recalbox-fbv/gif.c b/projects/recalbox-fbv/gif.c
new file mode 100644
index 0000000000000000000000000000000000000000..1eed1ac4f454b63ee4ad6d6185175005125574e7
--- /dev/null
+++ b/projects/recalbox-fbv/gif.c
@@ -0,0 +1,226 @@
+/*
+ fbv -- simple image viewer for the linux framebuffer
+ Copyright (C) 2000, 2001, 2003 Mateusz Golicz
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+#include "config.h"
+
+#ifdef FBV_SUPPORT_GIF
+
+ #include "fbv.h"
+ #include
+ //#include
+ //#include
+ #include
+ //#include
+ #include
+ //#include
+ #include
+ #include
+ #include
+
+ #define min(a, b) ((a) < (b) ? (a) : (b))
+ #define gflush do { return(FH_ERROR_FILE); } while(false)
+ #define grflush do { DGifCloseFile(gft, NULL); return(FH_ERROR_FORMAT); } while(false)
+ #define mgrflush do { free(lb); free(slb); DGifCloseFile(gft, NULL); return(FH_ERROR_FORMAT); } while(false)
+ //#define agflush return(FH_ERROR_FORMAT);
+ //#define agrflush { DGifCloseFile(gft); return(FH_ERROR_FORMAT); }
+
+
+int fh_gif_id(char* name)
+{
+ char id[4];
+ int fd = open(name, O_RDONLY);
+ if (fd == -1) return (0);
+ read(fd, id, 4);
+ close(fd);
+ if (id[0] == 'G' && id[1] == 'I' && id[2] == 'F') return (1);
+ return (0);
+}
+
+void
+m_rend_gif_decodecolormap(const unsigned char* cmb, unsigned char* rgbb, ColorMapObject* cm, int s, int l, int transparency)
+{
+ (void)s;
+ (void)transparency;
+ for (int i = 0; i < l; i++)
+ {
+ GifColorType* cmentry = &cm->Colors[cmb[i]];
+ *(rgbb++) = cmentry->Red;
+ *(rgbb++) = cmentry->Green;
+ *(rgbb++) = cmentry->Blue;
+ }
+}
+
+
+/* Thanks goes here to Mauro Meneghin, who implemented interlaced GIF files support */
+
+int fh_gif_load(char* name, unsigned char* buffer, unsigned char** alpha, int x, int y)
+{
+ (void)x;
+ (void)y;
+ int in_nextrow[4] = { 8, 8, 4, 2 }; //interlaced jump to the row current+in_nextrow
+ int in_beginrow[4] = { 0, 4, 2, 1 }; //begin pass j from that row number
+ int transparency = -1; //-1 means not transparency present
+ int ibxs = 0;
+ GifByteType* extension = NULL;
+ int extcode = 0;
+
+ GifFileType* gft = DGifOpenFileName(name, NULL);
+ if (gft == NULL)
+ {
+ printf("err5\n");
+ gflush;
+ } //////////
+ GifRecordType rt = UNDEFINED_RECORD_TYPE;
+ do
+ {
+ if (DGifGetRecordType(gft, &rt) == GIF_ERROR)
+ grflush;
+ switch (rt)
+ {
+ case IMAGE_DESC_RECORD_TYPE:
+ if (DGifGetImageDesc(gft) == GIF_ERROR)
+ grflush;
+ int px = gft->Image.Width;
+ int py = gft->Image.Height;
+ char* lb = (char*) malloc(px * 3);
+ char* slb = (char*) malloc(px);
+ // printf("reading...\n");
+ if (lb != NULL && slb != NULL)
+ {
+ unsigned char* alphaptr = NULL;
+
+ ColorMapObject* cmap = (gft->Image.ColorMap ? gft->Image.ColorMap : gft->SColorMap);
+ int cmaps = cmap->ColorCount;
+
+ ibxs = ibxs * 3;
+ char* fbptr = (char*) buffer;
+
+ if (transparency != -1)
+ {
+ alphaptr = malloc(px * py);
+ *alpha = alphaptr;
+ }
+
+ if (!(gft->Image.Interlace))
+ {
+ for (int i = 0; i < py; i++, fbptr += px * 3)
+ {
+ if (DGifGetLine(gft, (GifPixelType*) slb, px) == GIF_ERROR)
+ mgrflush;
+ m_rend_gif_decodecolormap((unsigned char*) slb, (unsigned char*) lb, cmap, cmaps, px, transparency);
+ memcpy(fbptr, lb, px * 3);
+ if (alphaptr)
+ for (int j = 0; j < px; j++) *(alphaptr++) = (((unsigned char*) slb)[j] == transparency) ? 0x00 : 0xff;
+ }
+ }
+ else
+ {
+ unsigned char* aptr = NULL;
+
+ for (int j = 0; j < 4; j++)
+ {
+ if (alphaptr)
+ aptr = alphaptr + (in_beginrow[j] * px);
+
+ fbptr = (char*) buffer + (in_beginrow[j] * px * 3);
+
+ for (int i = in_beginrow[j];
+ i < py; i += in_nextrow[j], fbptr += px * 3 * in_nextrow[j], aptr += px * in_nextrow[j])
+ {
+ if (DGifGetLine(gft, (GifPixelType*) slb, px) == GIF_ERROR)
+ mgrflush; /////////////
+ m_rend_gif_decodecolormap((unsigned char*) slb, (unsigned char*) lb, cmap, cmaps, px, transparency);
+ memcpy(fbptr, lb, px * 3);
+ if (alphaptr)
+ for (int k = 0; k < px; k++) aptr[k] = (((unsigned char*) slb)[k] == transparency) ? 0x00 : 0xff;
+ }
+ }
+ }
+ }
+ if (lb) free(lb);
+ if (slb) free(slb);
+ break;
+ case EXTENSION_RECORD_TYPE:
+ if (DGifGetExtension(gft, &extcode, &extension) == GIF_ERROR)
+ grflush; //////////
+ if (extcode == 0xf9) //look image transparency in graph ctr extension
+ {
+ if (extension[1] & 1)
+ {
+ transparency = extension[4];
+
+ }
+ // tran_off=(int)*extension;
+ // transparency=(int)*(extension+tran_off);
+ // printf("transparency: %d\n", transparency);
+ }
+ while (extension != NULL)
+ {
+ if (DGifGetExtensionNext(gft, &extension) == GIF_ERROR)
+ grflush;
+ }
+ break;
+ default: break;
+ }
+ } while (rt != TERMINATE_RECORD_TYPE);
+ DGifCloseFile(gft, NULL);
+ return (FH_ERROR_OK);
+}
+
+
+int fh_gif_getsize(char* name, int* x, int* y)
+{
+ GifByteType* extension = NULL;
+ int extcode = 0;
+
+ GifFileType* gft = DGifOpenFileName(name, NULL);
+ if (gft == NULL) gflush;
+ GifRecordType rt = UNDEFINED_RECORD_TYPE;
+ do
+ {
+ if (DGifGetRecordType(gft, &rt) == GIF_ERROR)
+ grflush;
+ switch (rt)
+ {
+ case IMAGE_DESC_RECORD_TYPE:
+
+ if (DGifGetImageDesc(gft) == GIF_ERROR)
+ grflush;
+ int px = gft->Image.Width;
+ int py = gft->Image.Height;
+ *x = px;
+ *y = py;
+ DGifCloseFile(gft, NULL);
+ return (FH_ERROR_OK);
+ case EXTENSION_RECORD_TYPE:
+ if (DGifGetExtension(gft, &extcode, &extension) == GIF_ERROR)
+ grflush;
+ while (extension != NULL)
+ {
+ if (DGifGetExtensionNext(gft, &extension) == GIF_ERROR)
+ grflush;
+ }
+ break;
+ default: break;
+ }
+ } while (rt != TERMINATE_RECORD_TYPE);
+ DGifCloseFile(gft, NULL);
+ return (FH_ERROR_FORMAT);
+}
+
+#endif
diff --git a/projects/recalbox-fbv/jpeg.c b/projects/recalbox-fbv/jpeg.c
new file mode 100644
index 0000000000000000000000000000000000000000..4b253af7d5840ee74697ab648772bd8e284d64b3
--- /dev/null
+++ b/projects/recalbox-fbv/jpeg.c
@@ -0,0 +1,144 @@
+/*
+ fbv -- simple image viewer for the linux framebuffer
+ Copyright (C) 2000, 2001, 2003 Mateusz Golicz
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+#include "config.h"
+
+#ifdef FBV_SUPPORT_JPEG
+
+ #include
+//#include
+//#include
+ #include
+ #include
+ #include
+ #include
+ #include
+ #include "fbv.h"
+
+struct r_jpeg_error_mgr
+{
+ struct jpeg_error_mgr pub;
+ jmp_buf envbuffer;
+};
+
+
+int fh_jpeg_id(char* name)
+{
+ unsigned char id[10];
+ int fd = open(name, O_RDONLY);
+ if (fd == -1) return (0);
+ read(fd, id, 10);
+ close(fd);
+ if (id[6] == 'J' && id[7] == 'F' && id[8] == 'I' && id[9] == 'F') return (1);
+ if (id[0] == 0xff && id[1] == 0xd8 && id[2] == 0xff) return (1);
+ return (0);
+}
+
+
+void jpeg_cb_error_exit(j_common_ptr cinfo)
+{
+ struct r_jpeg_error_mgr* mptr = (struct r_jpeg_error_mgr*) cinfo->err;
+ (*cinfo->err->output_message)(cinfo);
+ longjmp(mptr->envbuffer, 1);
+}
+
+int fh_jpeg_load(char* filename, unsigned char* buffer, unsigned char** alpha, int x, int y)
+{
+ (void)alpha;
+ (void)x;
+ (void)y;
+ struct jpeg_decompress_struct cinfo;
+ struct r_jpeg_error_mgr emgr;
+
+ struct jpeg_decompress_struct* ciptr = &cinfo;
+ FILE* fh = NULL;
+ if (!(fh = fopen(filename, "rb"))) return (FH_ERROR_FILE);
+ ciptr->err = jpeg_std_error(&emgr.pub);
+ emgr.pub.error_exit = jpeg_cb_error_exit;
+ if (setjmp(emgr.envbuffer) == 1)
+ {
+ // FATAL ERROR - Free the object and return...
+ jpeg_destroy_decompress(ciptr);
+ fclose(fh);
+ return (FH_ERROR_FORMAT);
+ }
+
+ jpeg_create_decompress(ciptr);
+ jpeg_stdio_src(ciptr, fh);
+ jpeg_read_header(ciptr, TRUE);
+ ciptr->out_color_space = JCS_RGB;
+ jpeg_start_decompress(ciptr);
+
+ int px = ciptr->output_width;
+ //int py = ciptr->output_height;
+ int c = ciptr->output_components;
+
+
+ if (c == 3)
+ {
+ JSAMPLE* lb = (*ciptr->mem->alloc_small)((j_common_ptr) ciptr, JPOOL_PERMANENT, c * px);
+ unsigned char* bp = buffer;
+ while (ciptr->output_scanline < ciptr->output_height)
+ {
+ jpeg_read_scanlines(ciptr, &lb, 1);
+ memcpy(bp, lb, px * c);
+ bp += px * c;
+ }
+
+ }
+ jpeg_finish_decompress(ciptr);
+ jpeg_destroy_decompress(ciptr);
+ fclose(fh);
+ return (FH_ERROR_OK);
+}
+
+int fh_jpeg_getsize(char* filename, int* x, int* y)
+{
+ struct jpeg_decompress_struct cinfo;
+ struct r_jpeg_error_mgr emgr;
+
+ struct jpeg_decompress_struct* ciptr = &cinfo;
+ FILE* fh = NULL;
+ if (!(fh = fopen(filename, "rb"))) return (FH_ERROR_FILE);
+
+ ciptr->err = jpeg_std_error(&emgr.pub);
+ emgr.pub.error_exit = jpeg_cb_error_exit;
+ if (setjmp(emgr.envbuffer) == 1)
+ {
+ // FATAL ERROR - Free the object and return...
+ jpeg_destroy_decompress(ciptr);
+ fclose(fh);
+ return (FH_ERROR_FORMAT);
+ }
+
+ jpeg_create_decompress(ciptr);
+ jpeg_stdio_src(ciptr, fh);
+ jpeg_read_header(ciptr, TRUE);
+ ciptr->out_color_space = JCS_RGB;
+ jpeg_start_decompress(ciptr);
+ int px = ciptr->output_width;
+ int py = ciptr->output_height;
+ //int c = ciptr->output_components;
+ *x = px;
+ *y = py;
+ jpeg_destroy_decompress(ciptr);
+ fclose(fh);
+ return (FH_ERROR_OK);
+}
+
+#endif
diff --git a/projects/recalbox-fbv/main.c b/projects/recalbox-fbv/main.c
new file mode 100644
index 0000000000000000000000000000000000000000..c685b874fb3285cfb991e2ef85a0759e4afd6daa
--- /dev/null
+++ b/projects/recalbox-fbv/main.c
@@ -0,0 +1,345 @@
+/*
+ fbv -- simple image viewer for the linux framebuffer
+ Copyright (C) 2000, 2001, 2003, 2004 Mateusz 'mteg' Golicz
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "config.h"
+#include "fbv.h"
+
+static int opt_clear = 1, opt_alpha = 0, opt_image_info = 1, opt_stretch = 0, opt_delay = 0, opt_enlarge = 0, opt_ignore_aspect = 0, opt_loop = 0;
+
+static inline void do_enlarge(struct image* i, int screen_width, int screen_height, int ignoreaspect)
+{
+ if (((i->width > screen_width) || (i->height > screen_height)) && (!ignoreaspect))
+ return;
+ if ((i->width < screen_width) || (i->height < screen_height))
+ {
+ int xsize = i->width, ysize = i->height;
+ unsigned char* image = NULL, * alpha = NULL;
+
+ if (ignoreaspect)
+ {
+ if (i->width < screen_width)
+ xsize = screen_width;
+ if (i->height < screen_height)
+ ysize = screen_height;
+
+ goto have_sizes;
+ }
+
+ if ((i->height * screen_width / i->width) <= screen_height)
+ {
+ xsize = screen_width;
+ ysize = i->height * screen_width / i->width;
+ goto have_sizes;
+ }
+
+ if ((i->width * screen_height / i->height) <= screen_width)
+ {
+ xsize = i->width * screen_height / i->height;
+ ysize = screen_height;
+ goto have_sizes;
+ }
+ return;
+ have_sizes:
+ image = simple_resize(i->rgb, i->width, i->height, xsize, ysize);
+ if (i->alpha)
+ alpha = alpha_resize(i->alpha, i->width, i->height, xsize, ysize);
+
+ if (i->do_free)
+ {
+ free(i->alpha);
+ free(i->rgb);
+ }
+
+ i->rgb = image;
+ i->alpha = alpha;
+ i->do_free = 1;
+ i->width = xsize;
+ i->height = ysize;
+ }
+}
+
+
+static inline void do_fit_to_screen(struct image* i, int screen_width, int screen_height, int ignoreaspect, int cal)
+{
+ if ((i->width > screen_width) || (i->height > screen_height))
+ {
+ unsigned char* new_image = NULL, * new_alpha = NULL;
+ int nx_size = i->width, ny_size = i->height;
+
+ if (ignoreaspect)
+ {
+ if (i->width > screen_width)
+ nx_size = screen_width;
+ if (i->height > screen_height)
+ ny_size = screen_height;
+ }
+ else
+ {
+ if ((i->height * screen_width / i->width) <= screen_height)
+ {
+ nx_size = screen_width;
+ ny_size = i->height * screen_width / i->width;
+ }
+ else
+ {
+ nx_size = i->width * screen_height / i->height;
+ ny_size = screen_height;
+ }
+ }
+
+ if (cal)
+ new_image = color_average_resize(i->rgb, i->width, i->height, nx_size, ny_size);
+ else
+ new_image = simple_resize(i->rgb, i->width, i->height, nx_size, ny_size);
+
+ if (i->alpha)
+ new_alpha = alpha_resize(i->alpha, i->width, i->height, nx_size, ny_size);
+
+ if (i->do_free)
+ {
+ free(i->alpha);
+ free(i->rgb);
+ }
+
+ i->rgb = new_image;
+ i->alpha = new_alpha;
+ i->do_free = 1;
+ i->width = nx_size;
+ i->height = ny_size;
+ }
+}
+
+static int always_false()
+{
+ return 0;
+}
+
+int show_image(char* filename)
+{
+ int (* load)(char*, unsigned char*, unsigned char**, int, int) = NULL;
+
+ unsigned char* image = NULL;
+ unsigned char* alpha = NULL;
+
+ int x_size = 0, y_size = 0, screen_width = 0, screen_height = 0;
+ int ret = 1;
+
+ int transform_stretch = opt_stretch, transform_enlarge = opt_enlarge,
+ transform_cal = (opt_stretch == 2), transform_iaspect = opt_ignore_aspect;
+
+ struct image i;
+
+ if (always_false())
+ {
+ }
+#ifdef FBV_SUPPORT_GIF
+ else if (fh_gif_id(filename))
+ {
+ if (fh_gif_getsize(filename, &x_size, &y_size) == FH_ERROR_OK)
+ load = fh_gif_load;
+ }
+#endif
+#ifdef FBV_SUPPORT_PNG
+ else if (fh_png_id(filename))
+ {
+ if (fh_png_getsize(filename, &x_size, &y_size) == FH_ERROR_OK)
+ load = fh_png_load;
+ }
+#endif
+#ifdef FBV_SUPPORT_JPEG
+ else if (fh_jpeg_id(filename))
+ {
+ if (fh_jpeg_getsize(filename, &x_size, &y_size) == FH_ERROR_OK)
+ load = fh_jpeg_load;
+ }
+#endif
+#ifdef FBV_SUPPORT_BMP
+ else if (fh_bmp_id(filename))
+ {
+ if (fh_bmp_getsize(filename, &x_size, &y_size) == FH_ERROR_OK)
+ load = fh_bmp_load;
+ }
+#endif
+ else
+ {
+ fprintf(stderr, "%s: Unable to access file or file format unknown.\n", filename);
+ return (1);
+ }
+
+ if (!(image = (unsigned char*) malloc(x_size * y_size * 3)))
+ {
+ fprintf(stderr, "%s: Out of memory.\n", filename);
+ goto error_mem;
+ }
+
+ if (load(filename, image, &alpha, x_size, y_size) != FH_ERROR_OK)
+ {
+ fprintf(stderr, "%s: Image data is corrupt?\n", filename);
+ goto error_mem;
+ }
+
+ if (!opt_alpha)
+ {
+ free(alpha);
+ alpha = NULL;
+ }
+
+ getCurrentRes(&screen_width, &screen_height);
+ i.do_free = 0;
+ i.width = x_size;
+ i.height = y_size;
+ i.rgb = image;
+ i.alpha = alpha;
+
+ if (transform_stretch)
+ do_fit_to_screen(&i, screen_width, screen_height, transform_iaspect, transform_cal);
+
+ if (transform_enlarge)
+ do_enlarge(&i, screen_width, screen_height, transform_iaspect);
+
+ if (opt_image_info)
+ printf("fbv - The Framebuffer Viewer\n%s\n%d x %d\n", filename, x_size, y_size);
+
+ int x_offs = (i.width < screen_width) ? (screen_width - i.width) / 2 : 0;
+ int y_offs = (i.height < screen_height) ? (screen_height - i.height) / 2 : 0;
+
+ fb_display(i.rgb, i.alpha, i.width, i.height, 0, 0, x_offs, y_offs, opt_clear);
+ opt_clear = 0; // Clear only once
+
+ if (opt_delay != 0) usleep(opt_delay * 100000);
+
+ error_mem:
+ free(image);
+ free(alpha);
+ if (i.do_free)
+ {
+ free(i.rgb);
+ free(i.alpha);
+ }
+ return (ret);
+}
+
+void help(char* name)
+{
+ printf("Usage: %s [options] image1 image2 image3 ...\n\n"
+ "Available options:\n"
+ " --help | -h : Show this help\n"
+ " --alpha | -a : Use the alpha channel (if applicable)\n"
+ " --dontclear | -c : Do not clear the screen before and after displaying the image\n"
+ " --donthide | -u : Do not hide the cursor before and after displaying the image\n"
+ " --noinfo | -i : Supress image information\n"
+ " --stretch | -f : Strech (using a simple resizing routine) the image to fit onto screen if necessary\n"
+ " --colorstretch| -k : Strech (using a 'color average' resizing routine) the image to fit onto screen if necessary\n"
+ " --enlarge | -e : Enlarge the image to fit the whole screen if necessary\n"
+ " --ignore-aspect| -r : Ignore the image aspect while resizing\n"
+ " --delay | -s : Slideshow, 'delay' is the slideshow delay in tenths of seconds.\n\n"
+ " --loop | -l : Loop after displaying all images\n"
+ "Copyright (C) 2000 - 2004 Mateusz Golicz, Tomasz Sterna.\n", name);
+}
+
+void sighandler(int s)
+{
+ _exit(128 + s);
+}
+
+int main(int argc, char** argv)
+{
+ static struct option long_options[] = {{"help", no_argument, 0, 'h'},
+ {"noclear", no_argument, 0, 'c'},
+ {"alpha", no_argument, 0, 'a'},
+ {"noinfo", no_argument, 0, 'i'},
+ {"stretch", no_argument, 0, 'f'},
+ {"colorstrech", no_argument, 0, 'k'},
+ {"delay", required_argument, 0, 's'},
+ {"enlarge", no_argument, 0, 'e'},
+ {"ignore-aspect", no_argument, 0, 'r'},
+ {"loop", no_argument, 0, 'l'},
+ {0, 0, 0, 0}};
+
+ int c = argc;
+ if (c < 2)
+ {
+ help(argv[0]);
+ fprintf(stderr, "Error: Required argument missing.\n");
+ return (1);
+ }
+
+ while((c = getopt_long_only(argc, argv, "hcaifks:erl", long_options, NULL)) != EOF)
+ {
+ switch (c)
+ {
+ case 'a': opt_alpha = 1;
+ break;
+ case 'c': opt_clear = 0;
+ break;
+ case 's': opt_delay = (int) strtol(optarg, NULL, 10);
+ break;
+ case 'h': help(argv[0]);
+ return (0);
+ case 'i': opt_image_info = 0;
+ break;
+ case 'f': opt_stretch = 1;
+ break;
+ case 'k': opt_stretch = 2;
+ break;
+ case 'e': opt_enlarge = 1;
+ break;
+ case 'r': opt_ignore_aspect = 1;
+ break;
+ case 'l': opt_loop = 1;
+ break;
+ default: break;
+ }
+ }
+
+ if (!argv[optind])
+ {
+ fprintf(stderr, "Required argument missing! Consult %s -h.\n", argv[0]);
+ return (1);
+ }
+
+ signal(SIGHUP, sighandler);
+ signal(SIGINT, sighandler);
+ signal(SIGQUIT, sighandler);
+ signal(SIGSEGV, sighandler);
+ signal(SIGTERM, sighandler);
+ signal(SIGABRT, sighandler);
+
+ do
+ {
+ for (int i = optind; argv[i];)
+ {
+ int r = show_image(argv[i]);
+
+ if (!r) break;
+
+ i += r;
+ if (i < optind)
+ i = optind;
+ }
+ } while (opt_loop != 0);
+
+ return (0);
+}
diff --git a/projects/recalbox-fbv/png.c b/projects/recalbox-fbv/png.c
new file mode 100644
index 0000000000000000000000000000000000000000..5be110d66c9864285afe2ffab6f4e7d9c9722e7f
--- /dev/null
+++ b/projects/recalbox-fbv/png.c
@@ -0,0 +1,175 @@
+/*
+ fbv -- simple image viewer for the linux framebuffer
+ Copyright (C) 2000, 2001, 2003 Mateusz Golicz
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "config.h"
+
+#ifdef FBV_SUPPORT_PNG
+
+ #include
+ #include "fbv.h"
+ #include
+ #include
+ #include
+ #include
+
+ //#define PNG_BYTES_TO_CHECK 4
+ #ifndef min
+ #define min(x,y) ((x) < (y) ? (x) : (y))
+ #endif
+
+int fh_png_id(char* name)
+{
+ char id[4];
+ int fd = open(name, O_RDONLY);
+ if (fd == -1) return (0);
+ read(fd, id, 4);
+ close(fd);
+ if (id[1] == 'P' && id[2] == 'N' && id[3] == 'G') return (1);
+ return (0);
+}
+
+int fh_png_load(char* name, unsigned char* buffer, unsigned char** alpha, int x, int y)
+{
+ (void)x;
+ (void)y;
+ png_bytep rptr[2];
+ FILE* fh = NULL;
+
+ if (!(fh = fopen(name, "rb"))) return (FH_ERROR_FILE);
+
+ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (png_ptr == NULL) return (FH_ERROR_FORMAT);
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+ if (info_ptr == NULL)
+ {
+ png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
+ fclose(fh);
+ return (FH_ERROR_FORMAT);
+ }
+ //rp = 0;
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
+ //if (rp) free(rp);
+ fclose(fh);
+ return (FH_ERROR_FORMAT);
+ }
+
+ png_init_io(png_ptr, fh);
+
+ png_read_info(png_ptr, info_ptr);
+ png_uint_32 width = 0, height = 0;
+ int bit_depth = 0, color_type = 0, interlace_type = 0;
+ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
+ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr);
+ if (bit_depth < 8) png_set_packing(png_ptr);
+ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr);
+ int trans = 0;
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+ {
+ trans = 1;
+ png_set_tRNS_to_alpha(png_ptr);
+ }
+
+ if (bit_depth == 16) png_set_strip_16(png_ptr);
+ int number_passes = png_set_interlace_handling(png_ptr);
+ png_read_update_info(png_ptr, info_ptr);
+
+ if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_RGB_ALPHA || trans)
+ {
+ unsigned char* alpha_buffer = (unsigned char*) malloc(width * height);
+ unsigned char* aptr = NULL;
+
+ unsigned char* rp = (unsigned char*) malloc(width * 4);
+ rptr[0] = (png_bytep) rp;
+
+ *alpha = alpha_buffer;
+
+ for (int pass = 0; pass < number_passes; pass++)
+ {
+ unsigned char* fbptr = buffer;
+ aptr = alpha_buffer;
+
+ for (int i = 0; i < (int)height; i++)
+ {
+ unsigned char* trp = rp;
+
+ png_read_rows(png_ptr, rptr, NULL, 1);
+
+ for (int n = 0; n < (int)width; n++, fbptr += 3, trp += 4)
+ {
+ memcpy(fbptr, trp, 3);
+ *(aptr++) = trp[3];
+ }
+ }
+ }
+ free(rp);
+ }
+ else
+ {
+ for (int pass = 0; pass < number_passes; pass++)
+ {
+ unsigned char* fbptr = buffer;
+ for (int i = 0; i < (int)height; i++, fbptr += width * 3)
+ {
+ rptr[0] = (png_bytep) fbptr;
+ png_read_rows(png_ptr, rptr, NULL, 1);
+ }
+ }
+ }
+ png_read_end(png_ptr, info_ptr);
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
+ fclose(fh);
+ return (FH_ERROR_OK);
+}
+
+int fh_png_getsize(char* name, int* x, int* y)
+{
+ FILE* fh = NULL;
+ if (!(fh = fopen(name, "rb"))) return (FH_ERROR_FILE);
+
+ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (png_ptr == NULL) return (FH_ERROR_FORMAT);
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+ if (info_ptr == NULL)
+ {
+ png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
+ fclose(fh);
+ return (FH_ERROR_FORMAT);
+ }
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
+ fclose(fh);
+ return (FH_ERROR_FORMAT);
+ }
+
+ png_init_io(png_ptr, fh);
+ png_read_info(png_ptr, info_ptr);
+ png_uint_32 width = 0, height = 0;
+ int bit_depth = 0, color_type = 0, interlace_type = 0;
+ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
+ *x = width;
+ *y = height;
+ fclose(fh);
+ return (FH_ERROR_OK);
+}
+
+#endif
diff --git a/projects/recalbox-fbv/transforms.c b/projects/recalbox-fbv/transforms.c
new file mode 100644
index 0000000000000000000000000000000000000000..06bc6679cdae703ed0406179dd774c845ff14025
--- /dev/null
+++ b/projects/recalbox-fbv/transforms.c
@@ -0,0 +1,116 @@
+/*
+ fbv -- simple image viewer for the linux framebuffer
+ Copyright (C) 2000, 2001, 2003 Mateusz Golicz
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include
+#include
+
+unsigned char* simple_resize(unsigned char* orgin, int ox, int oy, int dx, int dy)
+{
+ unsigned char* cr = (unsigned char*) malloc(dx * dy * 3);
+ assert(cr);
+ unsigned char* l = cr;
+
+ // Get 16:16 floating point increment
+ double xStep = (double)ox / (double)dx;
+ int pfXStep = (int)(xStep * 65536.0);
+
+ for (int j = 0; j < dy; j++, l += dx * 3)
+ {
+ unsigned char* p = orgin + (j * oy / dy * ox * 3);
+ unsigned int ip = 0;
+ unsigned int* li = ((unsigned int*)l);
+ for (int i = dx >> 2; --i >= 0; )
+ {
+ unsigned int pip = (ip >> 16) * 3; ip += pfXStep;
+ unsigned p1 = p[pip] | (p[pip + 1] << 8) | (p[pip + 2] << 16);
+ pip = (ip >> 16) * 3; ip += pfXStep;
+ p1 |= (p[pip] << 24);
+ unsigned p2 = p[pip + 1] | (p[pip + 2] << 8);
+ pip = (ip >> 16) * 3; ip += pfXStep;
+ p2 |= (p[pip] << 16) | (p[pip + 1] << 24);
+ unsigned p3 = p[pip + 2];
+ pip = (ip >> 16) * 3; ip += pfXStep;
+ p3 |= (p[pip] << 8) | (p[pip + 1] << 16) | (p[pip + 2] << 24);
+ li[0] = p1;
+ li[1] = p2;
+ li[2] = p3;
+ li += 3;
+ }
+ unsigned char* lb = ((unsigned char*)li);
+ for (int i = dx & 3; --i >= 0; ip += pfXStep)
+ {
+ unsigned int pip = (ip >> 16) * 3;
+ lb[0] = p[pip];
+ lb[1] = p[pip + 1];
+ lb[2] = p[pip + 2];
+ lb += 3;
+ }
+ }
+ return (cr);
+}
+
+unsigned char* alpha_resize(unsigned char* alpha, int ox, int oy, int dx, int dy)
+{
+ unsigned char* cr = (unsigned char*) malloc(dx * dy);
+ unsigned char* l = cr;
+
+ for (int j = 0; j < dy; j++, l += dx)
+ {
+ unsigned char* p = alpha + (j * oy / dy * ox);
+ for (int i = 0, k = 0; i < dx; i++)
+ l[k++] = p[i * ox / dx];
+ }
+
+ return (cr);
+}
+
+unsigned char* color_average_resize(unsigned char* orgin, int ox, int oy, int dx, int dy)
+{
+ unsigned char* cr = (unsigned char*) malloc(dx * dy * 3);
+ assert(cr);
+ unsigned char* p = cr;
+
+ for (int j = 0; j < dy; j++)
+ {
+ for (int i = 0; i < dx; i++, p += 3)
+ {
+ int xa = i * ox / dx;
+ int ya = j * oy / dy;
+ int xb = (i + 1) * ox / dx;
+ if (xb >= ox) xb = ox - 1;
+ int yb = (j + 1) * oy / dy;
+ if (yb >= oy) yb = oy - 1;
+ int r = 0, g = 0, b =0, sq = 0;
+ for (int l = ya; l <= yb; l++)
+ {
+ unsigned char* q = orgin + ((l * ox + xa) * 3);
+ for (int k = xa; k <= xb; k++, q += 3, sq++)
+ {
+ r += q[0];
+ g += q[1];
+ b += q[2];
+ }
+ }
+ p[0] = r / sq;
+ p[1] = g / sq;
+ p[2] = b / sq;
+ }
+ }
+ return (cr);
+}