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 			}