mirror of
https://git.code.sf.net/p/fuse-emulator/fuse
synced 2026-01-27 01:41:34 +03:00
550 lines
16 KiB
C
550 lines
16 KiB
C
/* fbdisplay.c: Routines for dealing with the linux fbdev display
|
|
Copyright (c) 2000-2003 Philip Kendall, Matan Ziv-Av, Darren Salt,
|
|
Witold Filipczyk
|
|
Copyright (c) 2015 Stuart Brady
|
|
|
|
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.,
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
Author contact information:
|
|
|
|
E-mail: philip-fuse@shadowmagic.org.uk
|
|
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <errno.h>
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
#include <linux/fb.h>
|
|
#include <fcntl.h>
|
|
#include <sys/ioctl.h>
|
|
#include <string.h>
|
|
|
|
#include "fbdisplay.h"
|
|
#include "fuse.h"
|
|
#include "display.h"
|
|
#include "screenshot.h"
|
|
#include "ui/ui.h"
|
|
#include "ui/uidisplay.h"
|
|
#include "settings.h"
|
|
|
|
/* A copy of every pixel on the screen */
|
|
libspectrum_word
|
|
fbdisplay_image[ 2 * DISPLAY_SCREEN_HEIGHT ][ DISPLAY_SCREEN_WIDTH ];
|
|
ptrdiff_t fbdisplay_pitch = DISPLAY_SCREEN_WIDTH * sizeof( libspectrum_word );
|
|
|
|
/* The environment variable specifying which device to use */
|
|
static const char * const DEVICE_VARIABLE = "FRAMEBUFFER";
|
|
|
|
/* The device we will use if device_env_variable is not specified */
|
|
static const char * const DEFAULT_DEVICE = "/dev/fb0";
|
|
|
|
/* The size of a 1x1 image in units of
|
|
DISPLAY_ASPECT WIDTH x DISPLAY_SCREEN_HEIGHT */
|
|
int image_scale;
|
|
|
|
/* The height and width of a 1x1 image in pixels */
|
|
int image_width, image_height;
|
|
|
|
/* Are we in a Timex display mode? */
|
|
static int hires;
|
|
|
|
static void register_scalers( void );
|
|
|
|
/* probably 0rrrrrgggggbbbbb */
|
|
static short rgbs[16], greys[16];
|
|
|
|
static int fb_fd = -1; /* The framebuffer's file descriptor */
|
|
static libspectrum_word *gm = 0;
|
|
|
|
static struct fb_fix_screeninfo fixed;
|
|
static struct fb_var_screeninfo orig_display, display;
|
|
static int got_orig_display = 0;
|
|
static int changed_palette = 0;
|
|
|
|
unsigned long fb_resolution; /* == xres << 16 | yres */
|
|
#define FB_RES(X,Y) ((X) << 16 | (Y))
|
|
#define FB_WIDTH (fb_resolution >> 16)
|
|
#define IF_FB_WIDTH(X) ((fb_resolution >> 16) == (X))
|
|
#define IF_FB_HEIGHT(Y) ((fb_resolution & 0xFFFF) == (Y))
|
|
#define IF_FB_RES(X, Y) (fb_resolution == FB_RES ((X), (Y)))
|
|
|
|
typedef struct {
|
|
int xres, yres, pixclock;
|
|
int left_margin, right_margin, upper_margin, lower_margin;
|
|
int hsync_len, vsync_len;
|
|
int sync, doublescan;
|
|
} fuse_fb_mode_t;
|
|
|
|
/* Test monitor is a Compaq V50, default settings
|
|
* A = working on ATI RV100 (Radeon 7000) (2.6.x, old radeonfb)
|
|
* M = working on Matrox MGA2064W (Millennium I) (2.6.x, matroxfb)
|
|
* Large/tall/wide = size indication (overscan)
|
|
* The 640x480 modes are from /etc/fb.modes and should work anywhere.
|
|
*
|
|
* x y clock lm rm tm bm hl vl s d
|
|
*/
|
|
static const fuse_fb_mode_t fb_modes_singlescan[] = {
|
|
{ 640, 480, 32052, 96, 56, 28, 9, 40, 3, 0, 0 }, /* 640x480-72 72.114 */
|
|
{ 640, 480, 39722, 48, 16, 33, 10, 96, 2, 0, 0 }, /* 640x480-60 59.940 std */
|
|
{ 0 } /* end of list */
|
|
};
|
|
static const fuse_fb_mode_t fb_modes_doublescan[] = {
|
|
{ 640, 240, 32052, 92, 56, 14, 4, 40, 3, 0, 1 }, /* 640x240-72 72.185 */
|
|
{ 640, 480, 32052, 96, 56, 28, 9, 40, 3, 0, 0 }, /* 640x480-72 72.114 */
|
|
{ 640, 480, 39722, 48, 16, 33, 10, 96, 2, 0, 0 }, /* 640x480-60 59.940 std */
|
|
{ 320, 240, 64104, 46, 28, 14, 4, 20, 3, 3, 1 }, /* 320x240-72 72.185 M wide */
|
|
{ 0 } /* end of list */
|
|
};
|
|
static const fuse_fb_mode_t fb_modes_doublescan_alt[] = {
|
|
{ 640, 240, 39722, 36, 12, 18, 7, 96, 2, 1, 1 }, /* 640x240-60 60.133 AM large */
|
|
{ 640, 480, 32052, 96, 56, 28, 9, 40, 3, 0, 0 }, /* 640x480-72 72.114 */
|
|
{ 640, 480, 39722, 48, 16, 33, 10, 96, 2, 0, 0 }, /* 640x480-60 59.940 std */
|
|
{ 320, 240, 79444, 18, 6, 18, 7, 48, 2, 1, 1 }, /* 320x240-60 60.133 AM large */
|
|
{ 0 } /* end of list */
|
|
};
|
|
/* Modes not used but which may work are listed here.
|
|
* x y clock lm rm tm bm hl vl s d
|
|
{ 640, 480, 22272, 48, 32, 17, 22, 128, 12, 0, 0 }, ** 640x480-100 99.713
|
|
{ 640, 480, 25057, 120, 32, 14, 25, 40, 14, 0, 0 }, ** 640x480-90 89.995
|
|
{ 640, 480, 31747, 120, 16, 16, 1, 64, 3, 0, 0 }, ** 640x480-75 74.998
|
|
{ 320, 240, 80000, 40, 28, 9, 2, 20, 3, 0, 1 }, ** 320x240-60 60.310 M tall
|
|
{ 320, 240, 55555, 52, 16, 12, 0, 28, 2, 0, 1 }, ** 320x240-85 85.177 M
|
|
*/
|
|
|
|
static unsigned short red16[256], green16[256], blue16[256], transp16[256];
|
|
static struct fb_cmap orig_cmap = {0, 256, red16, green16, blue16, transp16};
|
|
|
|
static int fb_set_mode( void );
|
|
|
|
int uidisplay_init( int width, int height )
|
|
{
|
|
hires = ( width == 640 ? 1 : 0 );
|
|
|
|
image_width = width; image_height = height;
|
|
image_scale = width / DISPLAY_ASPECT_WIDTH;
|
|
|
|
register_scalers();
|
|
|
|
display_ui_initialised = 1;
|
|
|
|
display_refresh_all();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
register_scalers( void )
|
|
{
|
|
scaler_register_clear();
|
|
scaler_select_bitformat( 565 ); /* 16bit always */
|
|
scaler_register( SCALER_NORMAL );
|
|
}
|
|
|
|
static void
|
|
linear_palette(struct fb_cmap *p_cmap)
|
|
{
|
|
int i;
|
|
int rcols = 1 << display.red.length;
|
|
int gcols = 1 << display.green.length;
|
|
int bcols = 1 << display.blue.length;
|
|
|
|
for (i = 0; i < rcols; i++)
|
|
p_cmap->red[i] = (65535 / (rcols - 1)) * i;
|
|
|
|
for (i = 0; i < gcols; i++)
|
|
p_cmap->green[i] = (65535 / (gcols - 1)) * i;
|
|
|
|
for (i = 0; i < bcols; i++)
|
|
p_cmap->blue[i] = (65535 / (bcols - 1)) * i;
|
|
}
|
|
|
|
int fbdisplay_init(void)
|
|
{
|
|
int i;
|
|
const char *dev;
|
|
|
|
static libspectrum_word r16[256], g16[256], b16[256];
|
|
static struct fb_cmap fb_cmap = {
|
|
0, 256, r16, g16, b16, NULL
|
|
};
|
|
|
|
dev = getenv( DEVICE_VARIABLE );
|
|
if( !dev || !*dev ) dev = DEFAULT_DEVICE;
|
|
|
|
fb_fd = open( dev, O_RDWR | O_EXCL );
|
|
if( fb_fd == -1 ) {
|
|
fprintf( stderr, "%s: couldn't open framebuffer device '%s'\n",
|
|
fuse_progname, dev );
|
|
return 1;
|
|
}
|
|
if( ioctl( fb_fd, FBIOGET_FSCREENINFO, &fixed ) ||
|
|
ioctl( fb_fd, FBIOGET_VSCREENINFO, &orig_display ) ) {
|
|
fprintf( stderr, "%s: couldn't read info from framebuffer device '%s'\n",
|
|
fuse_progname, dev );
|
|
return 1;
|
|
}
|
|
got_orig_display = 1;
|
|
|
|
if( fb_set_mode() ) return 1;
|
|
|
|
fputs( "\x1B[H\x1B[J", stdout ); /* clear tty */
|
|
memset( gm, 0, display.xres_virtual * display.yres_virtual * 2 );
|
|
|
|
|
|
display.activate = FB_ACTIVATE_NOW;
|
|
if( ioctl( fb_fd, FBIOPUT_VSCREENINFO, &display ) ) {
|
|
fprintf( stderr, "%s: couldn't set mode for framebuffer device '%s'\n",
|
|
fuse_progname, dev );
|
|
return 1;
|
|
}
|
|
|
|
ioctl( fb_fd, FBIOGET_VSCREENINFO, &display);
|
|
for( i = 0; i < 16; i++ ) {
|
|
int v = ( i & 8 ) ? 0xff : 0xbf;
|
|
int c;
|
|
rgbs[i] = ( ( i & 1 ) ? (v >> (8 - display.blue.length)) << display.blue.offset : 0 )
|
|
| ( ( i & 2 ) ? (v >> (8 - display.red.length)) << display.red.offset : 0 )
|
|
| ( ( i & 4 ) ? (v >> (8 - display.green.length)) << display.green.offset : 0 );
|
|
|
|
c = (( i & 1 ) ? (v * 0.114) : 0.0) +
|
|
(( i & 2) ? (v * 0.299) : 0.0) +
|
|
(( i & 4) ? (v * 0.587) : 0.0) + 0.5;
|
|
greys[i] = (c >> (8 - display.red.length) << display.red.offset)
|
|
| (c >> (8 - display.green.length) << display.green.offset)
|
|
| (c >> (8 - display.blue.length) << display.blue.offset);
|
|
}
|
|
linear_palette(&fb_cmap);
|
|
|
|
if (orig_display.bits_per_pixel == 8 || fixed.visual == FB_VISUAL_DIRECTCOLOR) {
|
|
ioctl( fb_fd, FBIOGETCMAP, &orig_cmap);
|
|
changed_palette = 1;
|
|
}
|
|
ioctl( fb_fd, FBIOGET_FSCREENINFO, &fixed);
|
|
if ( fixed.visual == FB_VISUAL_DIRECTCOLOR) {
|
|
ioctl( fb_fd, FBIOPUTCMAP, &fb_cmap );
|
|
}
|
|
sleep( 1 ); /* give the monitor time to sync before we start emulating */
|
|
|
|
fputs( "\x1B[?25l", stdout ); /* hide cursor */
|
|
fflush( stdout );
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
fb_select_mode( const fuse_fb_mode_t *fb_mode )
|
|
{
|
|
memset (&display, 0, sizeof (struct fb_var_screeninfo));
|
|
display.xres_virtual = display.xres = fb_mode->xres;
|
|
display.yres_virtual = display.yres = fb_mode->yres;
|
|
display.xoffset = display.yoffset = 0;
|
|
display.grayscale = 0;
|
|
display.nonstd = 0;
|
|
display.accel_flags = 0;
|
|
display.pixclock = fb_mode->pixclock;
|
|
display.left_margin = fb_mode->left_margin;
|
|
display.right_margin = fb_mode->right_margin;
|
|
display.upper_margin = fb_mode->upper_margin;
|
|
display.lower_margin = fb_mode->lower_margin;
|
|
display.hsync_len = fb_mode->hsync_len;
|
|
display.vsync_len = fb_mode->vsync_len;
|
|
display.sync = fb_mode->sync;
|
|
display.vmode &= ~FB_VMODE_MASK;
|
|
if( fb_mode->doublescan ) display.vmode |= FB_VMODE_DOUBLE;
|
|
display.vmode |= FB_VMODE_CONUPDATE;
|
|
|
|
display.bits_per_pixel = 16;
|
|
display.red.length = display.green.length = display.blue.length = 5;
|
|
|
|
display.red.offset = 0;
|
|
display.green.offset = 5;
|
|
display.blue.offset = 10;
|
|
|
|
gm = mmap( 0, fixed.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0 );
|
|
if( gm == (void*)-1 ) {
|
|
fprintf (stderr, "%s: couldn't mmap for framebuffer: %s\n",
|
|
fuse_progname, strerror( errno ) );
|
|
return 1;
|
|
}
|
|
|
|
display.activate = FB_ACTIVATE_TEST;
|
|
if( ioctl( fb_fd, FBIOPUT_VSCREENINFO, &display ) ) {
|
|
munmap( gm, fixed.smem_len );
|
|
return 1;
|
|
}
|
|
|
|
fb_resolution = FB_RES( display.xres, display.yres );
|
|
return 0; /* success */
|
|
}
|
|
|
|
static int
|
|
fb_set_mode( void )
|
|
{
|
|
size_t i;
|
|
|
|
const fuse_fb_mode_t *fb_modes =
|
|
(settings_current.doublescan_mode == 0) ? fb_modes_singlescan :
|
|
(settings_current.doublescan_mode == 1) ? fb_modes_doublescan :
|
|
fb_modes_doublescan_alt;
|
|
|
|
/* First, try to use our preferred mode */
|
|
for( i=0; fb_modes[i].xres; i++ )
|
|
if( fb_modes[i].xres == settings_current.fb_mode )
|
|
if( !fb_select_mode( fb_modes + i ) )
|
|
return 0;
|
|
|
|
/* If that failed, try to use the first available mode */
|
|
for( i=0; fb_modes[i].xres; i++ )
|
|
if( !fb_select_mode( fb_modes + i ) )
|
|
return 0;
|
|
|
|
/* If that failed, we can't continue :-( */
|
|
fprintf( stderr, "%s: couldn't find a framebuffer mode to start in\n",
|
|
fuse_progname );
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
uidisplay_hotswap_gfx_mode( void )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
uidisplay_frame_end( void )
|
|
{
|
|
return;
|
|
}
|
|
|
|
void
|
|
uidisplay_area( int x, int start, int width, int height)
|
|
{
|
|
int y;
|
|
const short *colours = settings_current.bw_tv ? greys : rgbs;
|
|
|
|
switch( fb_resolution ) {
|
|
case FB_RES( 640, 480 ):
|
|
for( y = start; y < start + height; y++ )
|
|
{
|
|
int i;
|
|
libspectrum_word *point;
|
|
|
|
if( hires ) {
|
|
|
|
for( i = 0, point = gm + y * display.xres_virtual + x;
|
|
i < width;
|
|
i++, point++ )
|
|
*point = colours[fbdisplay_image[y][x+i]];
|
|
|
|
} else {
|
|
|
|
for( i = 0, point = gm + 2 * y * display.xres_virtual + x * 2;
|
|
i < width;
|
|
i++, point += 2 )
|
|
* point = *( point + display.xres_virtual ) =
|
|
*( point + 1 ) = *( point + 1 + display.xres_virtual ) =
|
|
colours[fbdisplay_image[y][x+i]];
|
|
|
|
}
|
|
}
|
|
break;
|
|
|
|
case FB_RES( 640, 240 ):
|
|
if( hires ) { start >>= 1; height >>= 1; }
|
|
for( y = start; y < start + height; y++ )
|
|
{
|
|
int i;
|
|
libspectrum_word *point;
|
|
|
|
if( hires ) {
|
|
|
|
for ( i = 0, point = gm + y * display.xres_virtual + x;
|
|
i < width;
|
|
i++, point++ )
|
|
*point = colours[fbdisplay_image[y*2][x+i]];
|
|
|
|
} else {
|
|
|
|
for( i = 0, point = gm + y * display.xres_virtual + x * 2;
|
|
i < width;
|
|
i++, point+=2 )
|
|
*point = *(point+1) = colours[fbdisplay_image[y][x+i]];
|
|
|
|
}
|
|
}
|
|
break;
|
|
|
|
case FB_RES( 320, 240 ):
|
|
if( hires ) { start >>= 1; height >>= 1; x >>= 1; width >>= 1; }
|
|
for( y = start; y < start + height; y++ )
|
|
{
|
|
int i;
|
|
libspectrum_word *point;
|
|
|
|
if( hires ) {
|
|
|
|
/* Drop every second pixel */
|
|
for ( i = 0, point = gm + y * display.xres_virtual + x;
|
|
i < width;
|
|
i++, point++ )
|
|
*point = colours[fbdisplay_image[y*2][(x+i)*2]];
|
|
|
|
} else {
|
|
|
|
for( i = 0, point = gm + y * display.xres_virtual + x;
|
|
i < width;
|
|
i++, point++ )
|
|
*point = colours[fbdisplay_image[y][x+i]];
|
|
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
default:; /* Shut gcc up */
|
|
}
|
|
}
|
|
|
|
int
|
|
uidisplay_end( void )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
fbdisplay_end( void )
|
|
{
|
|
if( fb_fd != -1 ) {
|
|
if( got_orig_display ) {
|
|
ioctl( fb_fd, FBIOPUT_VSCREENINFO, &orig_display );
|
|
if (changed_palette) {
|
|
ioctl( fb_fd, FBIOPUTCMAP, &orig_cmap);
|
|
changed_palette = 0;
|
|
}
|
|
}
|
|
close( fb_fd );
|
|
fb_fd = -1;
|
|
fputs( "\x1B[H\x1B[J\x1B[?25h", stdout ); /* clear screen, show cursor */
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Set one pixel in the display */
|
|
void
|
|
uidisplay_putpixel( int x, int y, int colour )
|
|
{
|
|
if( machine_current->timex ) {
|
|
x <<= 1; y <<= 1;
|
|
fbdisplay_image[y ][x ] = colour;
|
|
fbdisplay_image[y ][x+1] = colour;
|
|
fbdisplay_image[y+1][x ] = colour;
|
|
fbdisplay_image[y+1][x+1] = colour;
|
|
} else {
|
|
fbdisplay_image[y][x] = colour;
|
|
}
|
|
}
|
|
|
|
/* Print the 8 pixels in `data' using ink colour `ink' and paper
|
|
colour `paper' to the screen at ( (8*x) , y ) */
|
|
void
|
|
uidisplay_plot8( int x, int y, libspectrum_byte data,
|
|
libspectrum_byte ink, libspectrum_byte paper )
|
|
{
|
|
x <<= 3;
|
|
|
|
if( machine_current->timex ) {
|
|
int i;
|
|
|
|
x <<= 1; y <<= 1;
|
|
for( i=0; i<2; i++,y++ ) {
|
|
fbdisplay_image[y][x+ 0] = ( data & 0x80 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 1] = ( data & 0x80 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 2] = ( data & 0x40 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 3] = ( data & 0x40 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 4] = ( data & 0x20 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 5] = ( data & 0x20 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 6] = ( data & 0x10 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 7] = ( data & 0x10 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 8] = ( data & 0x08 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 9] = ( data & 0x08 ) ? ink : paper;
|
|
fbdisplay_image[y][x+10] = ( data & 0x04 ) ? ink : paper;
|
|
fbdisplay_image[y][x+11] = ( data & 0x04 ) ? ink : paper;
|
|
fbdisplay_image[y][x+12] = ( data & 0x02 ) ? ink : paper;
|
|
fbdisplay_image[y][x+13] = ( data & 0x02 ) ? ink : paper;
|
|
fbdisplay_image[y][x+14] = ( data & 0x01 ) ? ink : paper;
|
|
fbdisplay_image[y][x+15] = ( data & 0x01 ) ? ink : paper;
|
|
}
|
|
} else {
|
|
fbdisplay_image[y][x+ 0] = ( data & 0x80 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 1] = ( data & 0x40 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 2] = ( data & 0x20 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 3] = ( data & 0x10 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 4] = ( data & 0x08 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 5] = ( data & 0x04 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 6] = ( data & 0x02 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 7] = ( data & 0x01 ) ? ink : paper;
|
|
}
|
|
}
|
|
|
|
/* Print the 16 pixels in `data' using ink colour `ink' and paper
|
|
colour `paper' to the screen at ( (16*x) , y ) */
|
|
void
|
|
uidisplay_plot16( int x, int y, libspectrum_word data,
|
|
libspectrum_byte ink, libspectrum_byte paper )
|
|
{
|
|
int i;
|
|
x <<= 4; y <<= 1;
|
|
|
|
for( i=0; i<2; i++,y++ ) {
|
|
fbdisplay_image[y][x+ 0] = ( data & 0x8000 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 1] = ( data & 0x4000 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 2] = ( data & 0x2000 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 3] = ( data & 0x1000 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 4] = ( data & 0x0800 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 5] = ( data & 0x0400 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 6] = ( data & 0x0200 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 7] = ( data & 0x0100 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 8] = ( data & 0x0080 ) ? ink : paper;
|
|
fbdisplay_image[y][x+ 9] = ( data & 0x0040 ) ? ink : paper;
|
|
fbdisplay_image[y][x+10] = ( data & 0x0020 ) ? ink : paper;
|
|
fbdisplay_image[y][x+11] = ( data & 0x0010 ) ? ink : paper;
|
|
fbdisplay_image[y][x+12] = ( data & 0x0008 ) ? ink : paper;
|
|
fbdisplay_image[y][x+13] = ( data & 0x0004 ) ? ink : paper;
|
|
fbdisplay_image[y][x+14] = ( data & 0x0002 ) ? ink : paper;
|
|
fbdisplay_image[y][x+15] = ( data & 0x0001 ) ? ink : paper;
|
|
}
|
|
}
|
|
|
|
void
|
|
uidisplay_frame_save( void )
|
|
{
|
|
/* FIXME: Save current framebuffer state as the widget UI wants to scribble
|
|
in here */
|
|
}
|
|
|
|
void
|
|
uidisplay_frame_restore( void )
|
|
{
|
|
/* FIXME: Restore saved framebuffer state as the widget UI wants to draw a
|
|
new menu */
|
|
}
|