Toggle scaling from 1-3x using the F1 key.
We reallocate a larger pixel buffer as well as a larger ximage, and then redraw. If the dimensions have not changed we will preserve the existing fg/bg data (since for pure rescaling those do not change and don't need to be reinitialized).
This commit is contained in:
parent
317c754c67
commit
56a17bd878
|
@ -158,25 +158,36 @@ screen_palette(Uint8 *addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
screen_resize(Uint16 width, Uint16 height)
|
screen_resize(Uint16 width, Uint16 height, int scale)
|
||||||
{
|
{
|
||||||
Uint8 *bg, *fg;
|
Uint8 *bg, *fg;
|
||||||
Uint32 *pixels = NULL;
|
Uint32 *pixels = NULL;
|
||||||
if(width < 0x8 || height < 0x8 || width >= 0x800 || height >= 0x800)
|
int dim_change = uxn_screen.width != width || uxn_screen.height != height;
|
||||||
|
if(width < 0x8 || height < 0x8 || width >= 0x800 || height >= 0x800 || scale < 1 || scale >= 4)
|
||||||
return;
|
return;
|
||||||
if(uxn_screen.width == width && uxn_screen.height == height)
|
if(uxn_screen.width == width && uxn_screen.height == height && uxn_screen.scale == scale)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if(dim_change) {
|
||||||
bg = malloc(width * height), fg = malloc(width * height);
|
bg = malloc(width * height), fg = malloc(width * height);
|
||||||
if(bg && fg)
|
if(bg && fg)
|
||||||
pixels = realloc(uxn_screen.pixels, width * height * sizeof(Uint32));
|
pixels = realloc(uxn_screen.pixels, width * height * sizeof(Uint32) * scale * scale);
|
||||||
if(!bg || !fg || !pixels) {
|
if(!bg || !fg || !pixels) {
|
||||||
free(bg), free(fg);
|
free(bg), free(fg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
free(uxn_screen.bg), free(uxn_screen.fg);
|
free(uxn_screen.bg), free(uxn_screen.fg);
|
||||||
|
} else {
|
||||||
|
bg = uxn_screen.bg, fg = uxn_screen.fg;
|
||||||
|
pixels = realloc(uxn_screen.pixels, width * height * sizeof(Uint32) * scale * scale);
|
||||||
|
if(!pixels)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
uxn_screen.bg = bg, uxn_screen.fg = fg;
|
uxn_screen.bg = bg, uxn_screen.fg = fg;
|
||||||
uxn_screen.pixels = pixels;
|
uxn_screen.pixels = pixels;
|
||||||
uxn_screen.width = width, uxn_screen.height = height;
|
uxn_screen.width = width, uxn_screen.height = height, uxn_screen.scale = scale;
|
||||||
|
if(dim_change)
|
||||||
screen_fill(uxn_screen.bg, 0), screen_fill(uxn_screen.fg, 0);
|
screen_fill(uxn_screen.bg, 0), screen_fill(uxn_screen.fg, 0);
|
||||||
emu_resize(width, height);
|
emu_resize(width, height);
|
||||||
screen_change(0, 0, width, height);
|
screen_change(0, 0, width, height);
|
||||||
|
@ -185,7 +196,7 @@ screen_resize(Uint16 width, Uint16 height)
|
||||||
void
|
void
|
||||||
screen_redraw(Uxn *u)
|
screen_redraw(Uxn *u)
|
||||||
{
|
{
|
||||||
int i, j, o, y;
|
int i, x, y, k, l, s = uxn_screen.scale;
|
||||||
Uint8 *fg = uxn_screen.fg, *bg = uxn_screen.bg;
|
Uint8 *fg = uxn_screen.fg, *bg = uxn_screen.bg;
|
||||||
Uint16 w = uxn_screen.width, h = uxn_screen.height;
|
Uint16 w = uxn_screen.width, h = uxn_screen.height;
|
||||||
Uint16 x1 = uxn_screen.x1, y1 = uxn_screen.y1;
|
Uint16 x1 = uxn_screen.x1, y1 = uxn_screen.y1;
|
||||||
|
@ -197,9 +208,18 @@ screen_redraw(Uxn *u)
|
||||||
screen_debugger(u);
|
screen_debugger(u);
|
||||||
for(i = 0; i < 16; i++)
|
for(i = 0; i < 16; i++)
|
||||||
palette[i] = uxn_screen.palette[(i >> 2) ? (i >> 2) : (i & 3)];
|
palette[i] = uxn_screen.palette[(i >> 2) ? (i >> 2) : (i & 3)];
|
||||||
for(y = y1; y < y2; y++)
|
for(y = y1; y < y2; y++) {
|
||||||
for(o = y * w, i = x1 + o, j = x2 + o; i < j; i++)
|
int ys = y * s;
|
||||||
pixels[i] = palette[fg[i] << 2 | bg[i]];
|
int o = y * w;
|
||||||
|
for(x = x1, i = x1 + o; x < x2; x++, i++) {
|
||||||
|
int c = palette[fg[i] << 2 | bg[i]];
|
||||||
|
for(k = 0; k < s; k++) {
|
||||||
|
int oo = ((ys + k) * w + x) * s;
|
||||||
|
for(l = 0; l < s; l++)
|
||||||
|
pixels[oo + l] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Uint8
|
Uint8
|
||||||
|
@ -222,11 +242,11 @@ screen_deo(Uint8 *ram, Uint8 *d, Uint8 port)
|
||||||
switch(port) {
|
switch(port) {
|
||||||
case 0x3: {
|
case 0x3: {
|
||||||
Uint8 *port_width = d + 0x2;
|
Uint8 *port_width = d + 0x2;
|
||||||
screen_resize(PEEK2(port_width), uxn_screen.height);
|
screen_resize(PEEK2(port_width), uxn_screen.height, uxn_screen.scale);
|
||||||
} break;
|
} break;
|
||||||
case 0x5: {
|
case 0x5: {
|
||||||
Uint8 *port_height = d + 0x4;
|
Uint8 *port_height = d + 0x4;
|
||||||
screen_resize(uxn_screen.width, PEEK2(port_height));
|
screen_resize(uxn_screen.width, PEEK2(port_height), uxn_screen.scale);
|
||||||
} break;
|
} break;
|
||||||
case 0xe: {
|
case 0xe: {
|
||||||
Uint8 ctrl = d[0xe];
|
Uint8 ctrl = d[0xe];
|
||||||
|
|
|
@ -14,7 +14,7 @@ WITH REGARD TO THIS SOFTWARE.
|
||||||
#define SCREEN_DEOMASK 0xc028
|
#define SCREEN_DEOMASK 0xc028
|
||||||
|
|
||||||
typedef struct UxnScreen {
|
typedef struct UxnScreen {
|
||||||
int width, height, x1, y1, x2, y2;
|
int width, height, x1, y1, x2, y2, scale;
|
||||||
Uint32 palette[4], *pixels;
|
Uint32 palette[4], *pixels;
|
||||||
Uint8 *fg, *bg;
|
Uint8 *fg, *bg;
|
||||||
} UxnScreen;
|
} UxnScreen;
|
||||||
|
@ -25,7 +25,7 @@ extern int emu_resize(int width, int height);
|
||||||
void screen_fill(Uint8 *layer, int color);
|
void screen_fill(Uint8 *layer, int color);
|
||||||
void screen_rect(Uint8 *layer, Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2, int color);
|
void screen_rect(Uint8 *layer, Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2, int color);
|
||||||
void screen_palette(Uint8 *addr);
|
void screen_palette(Uint8 *addr);
|
||||||
void screen_resize(Uint16 width, Uint16 height);
|
void screen_resize(Uint16 width, Uint16 height, int scale);
|
||||||
void screen_change(Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2);
|
void screen_change(Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2);
|
||||||
void screen_redraw(Uxn *u);
|
void screen_redraw(Uxn *u);
|
||||||
|
|
||||||
|
|
70
src/uxn11.c
70
src/uxn11.c
|
@ -31,6 +31,7 @@ WITH REGARD TO THIS SOFTWARE.
|
||||||
static XImage *ximage;
|
static XImage *ximage;
|
||||||
static Display *display;
|
static Display *display;
|
||||||
static Window window;
|
static Window window;
|
||||||
|
static char *loaded_rom;
|
||||||
|
|
||||||
#define WIDTH (64 * 8)
|
#define WIDTH (64 * 8)
|
||||||
#define HEIGHT (40 * 8)
|
#define HEIGHT (40 * 8)
|
||||||
|
@ -43,6 +44,18 @@ clamp(int val, int min, int max)
|
||||||
return (val >= min) ? (val <= max) ? val : max : min;
|
return (val >= min) ? (val <= max) ? val : max : min;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hide_cursor(void)
|
||||||
|
{
|
||||||
|
XColor black = {0};
|
||||||
|
static char empty[] = {0};
|
||||||
|
Pixmap bitmap = XCreateBitmapFromData(display, window, empty, 1, 1);
|
||||||
|
Cursor blank = XCreatePixmapCursor(display, bitmap, bitmap, &black, &black, 0, 0);
|
||||||
|
XDefineCursor(display, window, blank);
|
||||||
|
XFreeCursor(display, blank);
|
||||||
|
XFreePixmap(display, bitmap);
|
||||||
|
}
|
||||||
|
|
||||||
Uint8
|
Uint8
|
||||||
emu_dei(Uxn *u, Uint8 addr)
|
emu_dei(Uxn *u, Uint8 addr)
|
||||||
{
|
{
|
||||||
|
@ -77,15 +90,21 @@ emu_deo(Uxn *u, Uint8 addr, Uint8 value)
|
||||||
int
|
int
|
||||||
emu_resize(int width, int height)
|
emu_resize(int width, int height)
|
||||||
{
|
{
|
||||||
(void)width;
|
int w = uxn_screen.width, h = uxn_screen.height, s = uxn_screen.scale;
|
||||||
(void)height;
|
static Visual *visual;
|
||||||
|
if(window) {
|
||||||
|
visual = DefaultVisual(display, 0);
|
||||||
|
ximage = XCreateImage(display, visual, DefaultDepth(display, DefaultScreen(display)), ZPixmap, 0, (char *)uxn_screen.pixels, uxn_screen.width * s, uxn_screen.height * s, 32, 0);
|
||||||
|
XResizeWindow(display, window, w * s, h * s);
|
||||||
|
XMapWindow(display, window);
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
emu_restart(Uxn *u, char *rom, int soft)
|
emu_restart(Uxn *u, char *rom, int soft)
|
||||||
{
|
{
|
||||||
screen_resize(WIDTH, HEIGHT);
|
screen_resize(WIDTH, HEIGHT, uxn_screen.scale);
|
||||||
screen_rect(uxn_screen.bg, 0, 0, uxn_screen.width, uxn_screen.height, 0);
|
screen_rect(uxn_screen.bg, 0, 0, uxn_screen.width, uxn_screen.height, 0);
|
||||||
screen_rect(uxn_screen.fg, 0, 0, uxn_screen.width, uxn_screen.height, 0);
|
screen_rect(uxn_screen.fg, 0, 0, uxn_screen.width, uxn_screen.height, 0);
|
||||||
system_reboot(u, rom, soft);
|
system_reboot(u, rom, soft);
|
||||||
|
@ -103,18 +122,6 @@ emu_end(Uxn *u)
|
||||||
return u->dev[0x0f] & 0x7f;
|
return u->dev[0x0f] & 0x7f;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
hide_cursor(void)
|
|
||||||
{
|
|
||||||
XColor black = {0};
|
|
||||||
static char empty[] = {0};
|
|
||||||
Pixmap bitmap = XCreateBitmapFromData(display, window, empty, 1, 1);
|
|
||||||
Cursor blank = XCreatePixmapCursor(display, bitmap, bitmap, &black, &black, 0, 0);
|
|
||||||
XDefineCursor(display, window, blank);
|
|
||||||
XFreeCursor(display, blank);
|
|
||||||
XFreePixmap(display, bitmap);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Uint8
|
static Uint8
|
||||||
get_button(KeySym sym)
|
get_button(KeySym sym)
|
||||||
{
|
{
|
||||||
|
@ -131,14 +138,23 @@ get_button(KeySym sym)
|
||||||
return 0x00;
|
return 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
toggle_scale(Uxn *u)
|
||||||
|
{
|
||||||
|
int s = uxn_screen.scale + 1;
|
||||||
|
if (s > 3) s = 1;
|
||||||
|
screen_resize(uxn_screen.width, uxn_screen.height, s);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
emu_event(Uxn *u)
|
emu_event(Uxn *u)
|
||||||
{
|
{
|
||||||
XEvent ev;
|
XEvent ev;
|
||||||
|
int s = uxn_screen.scale;
|
||||||
XNextEvent(display, &ev);
|
XNextEvent(display, &ev);
|
||||||
switch(ev.type) {
|
switch(ev.type) {
|
||||||
case Expose:
|
case Expose:
|
||||||
XPutImage(display, window, DefaultGC(display, 0), ximage, 0, 0, PAD, PAD, uxn_screen.width, uxn_screen.height);
|
XPutImage(display, window, DefaultGC(display, 0), ximage, 0, 0, PAD, PAD, uxn_screen.width * s, uxn_screen.height * s);
|
||||||
break;
|
break;
|
||||||
case ClientMessage: {
|
case ClientMessage: {
|
||||||
emu_end(u);
|
emu_end(u);
|
||||||
|
@ -147,7 +163,9 @@ emu_event(Uxn *u)
|
||||||
KeySym sym;
|
KeySym sym;
|
||||||
char buf[7];
|
char buf[7];
|
||||||
XLookupString((XKeyPressedEvent *)&ev, buf, 7, &sym, 0);
|
XLookupString((XKeyPressedEvent *)&ev, buf, 7, &sym, 0);
|
||||||
if(sym == XK_F2)
|
if(sym == XK_F1)
|
||||||
|
toggle_scale(u);
|
||||||
|
else if(sym == XK_F2)
|
||||||
u->dev[0x0e] = !u->dev[0x0e];
|
u->dev[0x0e] = !u->dev[0x0e];
|
||||||
else if(sym == XK_F4)
|
else if(sym == XK_F4)
|
||||||
emu_restart(u, boot_rom, 0);
|
emu_restart(u, boot_rom, 0);
|
||||||
|
@ -177,8 +195,10 @@ emu_event(Uxn *u)
|
||||||
} break;
|
} break;
|
||||||
case MotionNotify: {
|
case MotionNotify: {
|
||||||
XMotionEvent *e = (XMotionEvent *)&ev;
|
XMotionEvent *e = (XMotionEvent *)&ev;
|
||||||
int x = clamp((e->x - PAD), 0, uxn_screen.width - 1);
|
int ex = (e->x - PAD) / s;
|
||||||
int y = clamp((e->y - PAD), 0, uxn_screen.height - 1);
|
int ey = (e->y - PAD) / s;
|
||||||
|
int x = clamp(ex, 0, uxn_screen.width - 1);
|
||||||
|
int y = clamp(ey, 0, uxn_screen.height - 1);
|
||||||
mouse_pos(u, &u->dev[0x90], x, y);
|
mouse_pos(u, &u->dev[0x90], x, y);
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
@ -190,24 +210,25 @@ emu_init(void)
|
||||||
display = XOpenDisplay(NULL);
|
display = XOpenDisplay(NULL);
|
||||||
if(!display)
|
if(!display)
|
||||||
return system_error("X11", "Could not open display");
|
return system_error("X11", "Could not open display");
|
||||||
screen_resize(WIDTH, HEIGHT);
|
screen_resize(WIDTH, HEIGHT, 1);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
emu_run(Uxn *u, char *rom)
|
emu_run(Uxn *u, char *rom)
|
||||||
{
|
{
|
||||||
int i = 1, n;
|
int i = 1, n, s = uxn_screen.scale;
|
||||||
char expirations[8];
|
char expirations[8];
|
||||||
char coninp[CONINBUFSIZE];
|
char coninp[CONINBUFSIZE];
|
||||||
struct pollfd fds[3];
|
struct pollfd fds[3];
|
||||||
static const struct itimerspec screen_tspec = {{0, 16666666}, {0, 16666666}};
|
static const struct itimerspec screen_tspec = {{0, 16666666}, {0, 16666666}};
|
||||||
|
loaded_rom = rom;
|
||||||
|
|
||||||
/* display */
|
/* display */
|
||||||
Atom wmDelete;
|
Atom wmDelete;
|
||||||
static Visual *visual;
|
static Visual *visual;
|
||||||
visual = DefaultVisual(display, 0);
|
visual = DefaultVisual(display, 0);
|
||||||
window = XCreateSimpleWindow(display, RootWindow(display, 0), 0, 0, uxn_screen.width + PAD * 2, uxn_screen.height + PAD * 2, 1, 0, 0);
|
window = XCreateSimpleWindow(display, RootWindow(display, 0), 0, 0, uxn_screen.width * s + PAD * 2, uxn_screen.height * s + PAD * 2, 1, 0, 0);
|
||||||
if(visual->class != TrueColor)
|
if(visual->class != TrueColor)
|
||||||
return system_error("init", "True-color visual failed");
|
return system_error("init", "True-color visual failed");
|
||||||
XSelectInput(display, window, ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ExposureMask | KeyPressMask | KeyReleaseMask);
|
XSelectInput(display, window, ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ExposureMask | KeyPressMask | KeyReleaseMask);
|
||||||
|
@ -215,7 +236,7 @@ emu_run(Uxn *u, char *rom)
|
||||||
XSetWMProtocols(display, window, &wmDelete, 1);
|
XSetWMProtocols(display, window, &wmDelete, 1);
|
||||||
XStoreName(display, window, rom);
|
XStoreName(display, window, rom);
|
||||||
XMapWindow(display, window);
|
XMapWindow(display, window);
|
||||||
ximage = XCreateImage(display, visual, DefaultDepth(display, DefaultScreen(display)), ZPixmap, 0, (char *)uxn_screen.pixels, uxn_screen.width, uxn_screen.height, 32, 0);
|
ximage = XCreateImage(display, visual, DefaultDepth(display, DefaultScreen(display)), ZPixmap, 0, (char *)uxn_screen.pixels, uxn_screen.width * s, uxn_screen.height * s, 32, 0);
|
||||||
hide_cursor();
|
hide_cursor();
|
||||||
|
|
||||||
/* timer */
|
/* timer */
|
||||||
|
@ -234,7 +255,8 @@ emu_run(Uxn *u, char *rom)
|
||||||
read(fds[1].fd, expirations, 8); /* Indicate we handled the timer */
|
read(fds[1].fd, expirations, 8); /* Indicate we handled the timer */
|
||||||
uxn_eval(u, PEEK2(u->dev + 0x20)); /* Call the vector once, even if the timer fired multiple times */
|
uxn_eval(u, PEEK2(u->dev + 0x20)); /* Call the vector once, even if the timer fired multiple times */
|
||||||
if(uxn_screen.x2) {
|
if(uxn_screen.x2) {
|
||||||
int x1 = uxn_screen.x1, y1 = uxn_screen.y1, x2 = uxn_screen.x2, y2 = uxn_screen.y2;
|
s = uxn_screen.scale;
|
||||||
|
int x1 = uxn_screen.x1 * s, y1 = uxn_screen.y1 * s, x2 = uxn_screen.x2 * s, y2 = uxn_screen.y2 * s;
|
||||||
screen_redraw(u);
|
screen_redraw(u);
|
||||||
XPutImage(display, window, DefaultGC(display, 0), ximage, x1, y1, x1 + PAD, y1 + PAD, x2 - x1, y2 - y1);
|
XPutImage(display, window, DefaultGC(display, 0), ximage, x1, y1, x1 + PAD, y1 + PAD, x2 - x1, y2 - y1);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue