commit 56a17bd
d_m
·
2023-11-14 04:18:58 +0000 UTC
parent 317c754
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).
3 files changed,
+86,
-44
+38,
-18
1@@ -158,26 +158,37 @@ screen_palette(Uint8 *addr)
2 }
3
4 void
5-screen_resize(Uint16 width, Uint16 height)
6+screen_resize(Uint16 width, Uint16 height, int scale)
7 {
8 Uint8 *bg, *fg;
9 Uint32 *pixels = NULL;
10- if(width < 0x8 || height < 0x8 || width >= 0x800 || height >= 0x800)
11+ int dim_change = uxn_screen.width != width || uxn_screen.height != height;
12+ if(width < 0x8 || height < 0x8 || width >= 0x800 || height >= 0x800 || scale < 1 || scale >= 4)
13 return;
14- if(uxn_screen.width == width && uxn_screen.height == height)
15- return;
16- bg = malloc(width * height), fg = malloc(width * height);
17- if(bg && fg)
18- pixels = realloc(uxn_screen.pixels, width * height * sizeof(Uint32));
19- if(!bg || !fg || !pixels) {
20- free(bg), free(fg);
21+ if(uxn_screen.width == width && uxn_screen.height == height && uxn_screen.scale == scale)
22 return;
23+
24+ if(dim_change) {
25+ bg = malloc(width * height), fg = malloc(width * height);
26+ if(bg && fg)
27+ pixels = realloc(uxn_screen.pixels, width * height * sizeof(Uint32) * scale * scale);
28+ if(!bg || !fg || !pixels) {
29+ free(bg), free(fg);
30+ return;
31+ }
32+ free(uxn_screen.bg), free(uxn_screen.fg);
33+ } else {
34+ bg = uxn_screen.bg, fg = uxn_screen.fg;
35+ pixels = realloc(uxn_screen.pixels, width * height * sizeof(Uint32) * scale * scale);
36+ if(!pixels)
37+ return;
38 }
39- free(uxn_screen.bg), free(uxn_screen.fg);
40+
41 uxn_screen.bg = bg, uxn_screen.fg = fg;
42 uxn_screen.pixels = pixels;
43- uxn_screen.width = width, uxn_screen.height = height;
44- screen_fill(uxn_screen.bg, 0), screen_fill(uxn_screen.fg, 0);
45+ uxn_screen.width = width, uxn_screen.height = height, uxn_screen.scale = scale;
46+ if(dim_change)
47+ screen_fill(uxn_screen.bg, 0), screen_fill(uxn_screen.fg, 0);
48 emu_resize(width, height);
49 screen_change(0, 0, width, height);
50 }
51@@ -185,7 +196,7 @@ screen_resize(Uint16 width, Uint16 height)
52 void
53 screen_redraw(Uxn *u)
54 {
55- int i, j, o, y;
56+ int i, x, y, k, l, s = uxn_screen.scale;
57 Uint8 *fg = uxn_screen.fg, *bg = uxn_screen.bg;
58 Uint16 w = uxn_screen.width, h = uxn_screen.height;
59 Uint16 x1 = uxn_screen.x1, y1 = uxn_screen.y1;
60@@ -197,9 +208,18 @@ screen_redraw(Uxn *u)
61 screen_debugger(u);
62 for(i = 0; i < 16; i++)
63 palette[i] = uxn_screen.palette[(i >> 2) ? (i >> 2) : (i & 3)];
64- for(y = y1; y < y2; y++)
65- for(o = y * w, i = x1 + o, j = x2 + o; i < j; i++)
66- pixels[i] = palette[fg[i] << 2 | bg[i]];
67+ for(y = y1; y < y2; y++) {
68+ int ys = y * s;
69+ int o = y * w;
70+ for(x = x1, i = x1 + o; x < x2; x++, i++) {
71+ int c = palette[fg[i] << 2 | bg[i]];
72+ for(k = 0; k < s; k++) {
73+ int oo = ((ys + k) * w + x) * s;
74+ for(l = 0; l < s; l++)
75+ pixels[oo + l] = c;
76+ }
77+ }
78+ }
79 }
80
81 Uint8
82@@ -222,11 +242,11 @@ screen_deo(Uint8 *ram, Uint8 *d, Uint8 port)
83 switch(port) {
84 case 0x3: {
85 Uint8 *port_width = d + 0x2;
86- screen_resize(PEEK2(port_width), uxn_screen.height);
87+ screen_resize(PEEK2(port_width), uxn_screen.height, uxn_screen.scale);
88 } break;
89 case 0x5: {
90 Uint8 *port_height = d + 0x4;
91- screen_resize(uxn_screen.width, PEEK2(port_height));
92+ screen_resize(uxn_screen.width, PEEK2(port_height), uxn_screen.scale);
93 } break;
94 case 0xe: {
95 Uint8 ctrl = d[0xe];
+2,
-2
1@@ -14,7 +14,7 @@ WITH REGARD TO THIS SOFTWARE.
2 #define SCREEN_DEOMASK 0xc028
3
4 typedef struct UxnScreen {
5- int width, height, x1, y1, x2, y2;
6+ int width, height, x1, y1, x2, y2, scale;
7 Uint32 palette[4], *pixels;
8 Uint8 *fg, *bg;
9 } UxnScreen;
10@@ -25,7 +25,7 @@ extern int emu_resize(int width, int height);
11 void screen_fill(Uint8 *layer, int color);
12 void screen_rect(Uint8 *layer, Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2, int color);
13 void screen_palette(Uint8 *addr);
14-void screen_resize(Uint16 width, Uint16 height);
15+void screen_resize(Uint16 width, Uint16 height, int scale);
16 void screen_change(Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2);
17 void screen_redraw(Uxn *u);
18
+46,
-24
1@@ -31,6 +31,7 @@ WITH REGARD TO THIS SOFTWARE.
2 static XImage *ximage;
3 static Display *display;
4 static Window window;
5+static char *loaded_rom;
6
7 #define WIDTH (64 * 8)
8 #define HEIGHT (40 * 8)
9@@ -43,6 +44,18 @@ clamp(int val, int min, int max)
10 return (val >= min) ? (val <= max) ? val : max : min;
11 }
12
13+static void
14+hide_cursor(void)
15+{
16+ XColor black = {0};
17+ static char empty[] = {0};
18+ Pixmap bitmap = XCreateBitmapFromData(display, window, empty, 1, 1);
19+ Cursor blank = XCreatePixmapCursor(display, bitmap, bitmap, &black, &black, 0, 0);
20+ XDefineCursor(display, window, blank);
21+ XFreeCursor(display, blank);
22+ XFreePixmap(display, bitmap);
23+}
24+
25 Uint8
26 emu_dei(Uxn *u, Uint8 addr)
27 {
28@@ -77,15 +90,21 @@ emu_deo(Uxn *u, Uint8 addr, Uint8 value)
29 int
30 emu_resize(int width, int height)
31 {
32- (void)width;
33- (void)height;
34+ int w = uxn_screen.width, h = uxn_screen.height, s = uxn_screen.scale;
35+ static Visual *visual;
36+ if(window) {
37+ visual = DefaultVisual(display, 0);
38+ ximage = XCreateImage(display, visual, DefaultDepth(display, DefaultScreen(display)), ZPixmap, 0, (char *)uxn_screen.pixels, uxn_screen.width * s, uxn_screen.height * s, 32, 0);
39+ XResizeWindow(display, window, w * s, h * s);
40+ XMapWindow(display, window);
41+ }
42 return 1;
43 }
44
45 static void
46 emu_restart(Uxn *u, char *rom, int soft)
47 {
48- screen_resize(WIDTH, HEIGHT);
49+ screen_resize(WIDTH, HEIGHT, uxn_screen.scale);
50 screen_rect(uxn_screen.bg, 0, 0, uxn_screen.width, uxn_screen.height, 0);
51 screen_rect(uxn_screen.fg, 0, 0, uxn_screen.width, uxn_screen.height, 0);
52 system_reboot(u, rom, soft);
53@@ -103,18 +122,6 @@ emu_end(Uxn *u)
54 return u->dev[0x0f] & 0x7f;
55 }
56
57-static void
58-hide_cursor(void)
59-{
60- XColor black = {0};
61- static char empty[] = {0};
62- Pixmap bitmap = XCreateBitmapFromData(display, window, empty, 1, 1);
63- Cursor blank = XCreatePixmapCursor(display, bitmap, bitmap, &black, &black, 0, 0);
64- XDefineCursor(display, window, blank);
65- XFreeCursor(display, blank);
66- XFreePixmap(display, bitmap);
67-}
68-
69 static Uint8
70 get_button(KeySym sym)
71 {
72@@ -131,14 +138,23 @@ get_button(KeySym sym)
73 return 0x00;
74 }
75
76+static void
77+toggle_scale(Uxn *u)
78+{
79+ int s = uxn_screen.scale + 1;
80+ if (s > 3) s = 1;
81+ screen_resize(uxn_screen.width, uxn_screen.height, s);
82+}
83+
84 static void
85 emu_event(Uxn *u)
86 {
87 XEvent ev;
88+ int s = uxn_screen.scale;
89 XNextEvent(display, &ev);
90 switch(ev.type) {
91 case Expose:
92- XPutImage(display, window, DefaultGC(display, 0), ximage, 0, 0, PAD, PAD, uxn_screen.width, uxn_screen.height);
93+ XPutImage(display, window, DefaultGC(display, 0), ximage, 0, 0, PAD, PAD, uxn_screen.width * s, uxn_screen.height * s);
94 break;
95 case ClientMessage: {
96 emu_end(u);
97@@ -147,7 +163,9 @@ emu_event(Uxn *u)
98 KeySym sym;
99 char buf[7];
100 XLookupString((XKeyPressedEvent *)&ev, buf, 7, &sym, 0);
101- if(sym == XK_F2)
102+ if(sym == XK_F1)
103+ toggle_scale(u);
104+ else if(sym == XK_F2)
105 u->dev[0x0e] = !u->dev[0x0e];
106 else if(sym == XK_F4)
107 emu_restart(u, boot_rom, 0);
108@@ -177,8 +195,10 @@ emu_event(Uxn *u)
109 } break;
110 case MotionNotify: {
111 XMotionEvent *e = (XMotionEvent *)&ev;
112- int x = clamp((e->x - PAD), 0, uxn_screen.width - 1);
113- int y = clamp((e->y - PAD), 0, uxn_screen.height - 1);
114+ int ex = (e->x - PAD) / s;
115+ int ey = (e->y - PAD) / s;
116+ int x = clamp(ex, 0, uxn_screen.width - 1);
117+ int y = clamp(ey, 0, uxn_screen.height - 1);
118 mouse_pos(u, &u->dev[0x90], x, y);
119 } break;
120 }
121@@ -190,24 +210,25 @@ emu_init(void)
122 display = XOpenDisplay(NULL);
123 if(!display)
124 return system_error("X11", "Could not open display");
125- screen_resize(WIDTH, HEIGHT);
126+ screen_resize(WIDTH, HEIGHT, 1);
127 return 1;
128 }
129
130 static int
131 emu_run(Uxn *u, char *rom)
132 {
133- int i = 1, n;
134+ int i = 1, n, s = uxn_screen.scale;
135 char expirations[8];
136 char coninp[CONINBUFSIZE];
137 struct pollfd fds[3];
138 static const struct itimerspec screen_tspec = {{0, 16666666}, {0, 16666666}};
139+ loaded_rom = rom;
140
141 /* display */
142 Atom wmDelete;
143 static Visual *visual;
144 visual = DefaultVisual(display, 0);
145- window = XCreateSimpleWindow(display, RootWindow(display, 0), 0, 0, uxn_screen.width + PAD * 2, uxn_screen.height + PAD * 2, 1, 0, 0);
146+ window = XCreateSimpleWindow(display, RootWindow(display, 0), 0, 0, uxn_screen.width * s + PAD * 2, uxn_screen.height * s + PAD * 2, 1, 0, 0);
147 if(visual->class != TrueColor)
148 return system_error("init", "True-color visual failed");
149 XSelectInput(display, window, ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ExposureMask | KeyPressMask | KeyReleaseMask);
150@@ -215,7 +236,7 @@ emu_run(Uxn *u, char *rom)
151 XSetWMProtocols(display, window, &wmDelete, 1);
152 XStoreName(display, window, rom);
153 XMapWindow(display, window);
154- ximage = XCreateImage(display, visual, DefaultDepth(display, DefaultScreen(display)), ZPixmap, 0, (char *)uxn_screen.pixels, uxn_screen.width, uxn_screen.height, 32, 0);
155+ ximage = XCreateImage(display, visual, DefaultDepth(display, DefaultScreen(display)), ZPixmap, 0, (char *)uxn_screen.pixels, uxn_screen.width * s, uxn_screen.height * s, 32, 0);
156 hide_cursor();
157
158 /* timer */
159@@ -234,7 +255,8 @@ emu_run(Uxn *u, char *rom)
160 read(fds[1].fd, expirations, 8); /* Indicate we handled the timer */
161 uxn_eval(u, PEEK2(u->dev + 0x20)); /* Call the vector once, even if the timer fired multiple times */
162 if(uxn_screen.x2) {
163- int x1 = uxn_screen.x1, y1 = uxn_screen.y1, x2 = uxn_screen.x2, y2 = uxn_screen.y2;
164+ s = uxn_screen.scale;
165+ int x1 = uxn_screen.x1 * s, y1 = uxn_screen.y1 * s, x2 = uxn_screen.x2 * s, y2 = uxn_screen.y2 * s;
166 screen_redraw(u);
167 XPutImage(display, window, DefaultGC(display, 0), ximage, x1, y1, x1 + PAD, y1 + PAD, x2 - x1, y2 - y1);
168 }