Browse code

Modularize uxn256emu to prepare for having several roms executing simultaneously

Dario Rodriguez authored on 11/01/2024 16:32:28
Showing 5 changed files
... ...
@@ -23,6 +23,6 @@ Uint8 audio_get_vu(int instance);
23 23
 Uint16 audio_get_position(int instance);
24 24
 int audio_render(int instance, Sint16 *sample, Sint16 *end);
25 25
 void audio_start(int instance, Uint8 *d, Uxn *u);
26
-void audio_finished_handler(int instance);
26
+void audio_finished_handler(int instance, void *userptr);
27 27
 void audio_handler(void *ctx, Uint8 *out_stream, int len);
28 28
 Uint8 audio_dei(int instance, Uint8 *d, Uint8 port);
... ...
@@ -63,7 +63,7 @@ screen_2bpp(Uint8 *layer, Uint8 *addr, Uint16 x1, Uint16 y1, Uint16 color, int f
63 63
 	Uint16 y, ymod = (fy < 0 ? 7 : 0), ymax = y1 + ymod + fy * 8;
64 64
 	Uint16 x, xmod = (fx > 0 ? 7 : 0), xmax = x1 + xmod - fx * 8;
65 65
 	for(y = y1 + ymod; y != ymax; y += fy) {
66
-		int c = *addr++ | (*(addr + 7) << 8), row = y * w;
66
+		int c = *addr | ((*(addr + 7) << 8)), row = y * w, addr=addr+1;
67 67
 		if(y < h)
68 68
 			for(x = x1 + xmod; x != xmax; x -= fx, c >>= 1) {
69 69
 				Uint8 ch = (c & 1) | ((c >> 7) & 2);
... ...
@@ -154,7 +154,7 @@ screen_palette(Uint8 *addr)
154 154
 }
155 155
 
156 156
 void
157
-screen_resize(Uint16 width, Uint16 height)
157
+screen_resize(Uxn *u, Uint16 width, Uint16 height)
158 158
 {
159 159
 	Uint8 *bg, *fg;
160 160
 	Uint32 *pixels = NULL;
... ...
@@ -174,7 +174,7 @@ screen_resize(Uint16 width, Uint16 height)
174 174
 	uxn_screen.pixels = pixels;
175 175
 	uxn_screen.width = width, uxn_screen.height = height;
176 176
 	screen_fill(uxn_screen.bg, 0), screen_fill(uxn_screen.fg, 0);
177
-	emu_resize(width, height);
177
+	emu_resize(u, width, height);
178 178
 	screen_change(0, 0, width, height);
179 179
 }
180 180
 
... ...
@@ -211,18 +211,18 @@ screen_dei(Uxn *u, Uint8 addr)
211 211
 }
212 212
 
213 213
 void
214
-screen_deo(Uint8 *ram, Uint8 *d, Uint8 port)
214
+screen_deo(Uxn *u, Uint8 *ram, Uint8 *d, Uint8 port)
215 215
 {
216 216
 	Uint8 *port_x, *port_y, *port_addr;
217 217
 	Uint16 x, y, dx, dy, dxy, dyx, addr, addr_incr;
218 218
 	switch(port) {
219 219
 	case 0x3: {
220 220
 		Uint8 *port_width = d + 0x2;
221
-		screen_resize(PEEK2(port_width), uxn_screen.height);
221
+		screen_resize(u, PEEK2(port_width), uxn_screen.height);
222 222
 	} break;
223 223
 	case 0x5: {
224 224
 		Uint8 *port_height = d + 0x4;
225
-		screen_resize(uxn_screen.width, PEEK2(port_height));
225
+		screen_resize(u, uxn_screen.width, PEEK2(port_height));
226 226
 	} break;
227 227
 	case 0xe: {
228 228
 		Uint8 ctrl = d[0xe];
... ...
@@ -20,14 +20,14 @@ typedef struct UxnScreen {
20 20
 } UxnScreen;
21 21
 
22 22
 extern UxnScreen uxn_screen;
23
-extern int emu_resize(int width, int height);
23
+extern int emu_resize(Uxn *u, int width, int height);
24 24
 
25 25
 void screen_fill(Uint8 *layer, int color);
26 26
 void screen_rect(Uint8 *layer, Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2, int color);
27 27
 void screen_palette(Uint8 *addr);
28
-void screen_resize(Uint16 width, Uint16 height);
28
+void screen_resize(Uxn *u, Uint16 width, Uint16 height);
29 29
 void screen_change(Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2);
30 30
 void screen_redraw(Uxn *u);
31 31
 
32 32
 Uint8 screen_dei(Uxn *u, Uint8 addr);
33
-void screen_deo(Uint8 *ram, Uint8 *d, Uint8 port);
33
+void screen_deo(Uxn *u, Uint8 *ram, Uint8 *d, Uint8 port);
... ...
@@ -31,6 +31,7 @@ typedef struct {
31 31
 typedef struct Uxn {
32 32
 	Uint8 *ram, *dev;
33 33
 	Stack wst, rst;
34
+	void *userptr;
34 35
 } Uxn;
35 36
 
36 37
 /* required functions */
... ...
@@ -31,6 +31,7 @@
31 31
 
32 32
 /*
33 33
 Copyright (c) 2021-2023 Devine Lu Linvega, Andrew Alderwick
34
+Copyright (c) 2024 Dario Rodriguez
34 35
 
35 36
 Permission to use, copy, modify, and distribute this software for any
36 37
 purpose with or without fee is hereby granted, provided that the above
... ...
@@ -40,486 +41,686 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
40 41
 WITH REGARD TO THIS SOFTWARE.
41 42
 */
42 43
 
44
+#define INSTANCESSIZE 256
45
+
43 46
 #define PAD 2
44 47
 #define PAD2 4
45 48
 #define WIDTH 64 * 8
46 49
 #define HEIGHT 40 * 8
47 50
 #define TIMEOUT_MS 334
48 51
 
49
-static SDL_Window *emu_window;
50
-static SDL_Texture *emu_texture;
51
-static SDL_Renderer *emu_renderer;
52
-static SDL_Rect emu_viewport;
53
-static SDL_AudioDeviceID audio_id;
54
-static SDL_Thread *stdin_thread;
52
+typedef struct video_t {
53
+        SDL_Window *emu_window;
54
+        SDL_Texture *emu_texture;
55
+        SDL_Renderer *emu_renderer;
56
+        SDL_Rect emu_viewport;
57
+        Uint32 zoom;
58
+        int flag_windowcreated;
59
+        int flag_fullscreen;
60
+        int flag_borderless;
61
+} video_t;
62
+
63
+typedef struct instance_t {
64
+        video_t *video;
65
+        Uint8 dev[0x100];
66
+        Uxn u;
67
+        Uxn u_audio;
68
+        Uint8 *ram;
69
+        char *rom;
70
+        SDL_AudioDeviceID audio_id;
71
+        SDL_Thread *stdin_thread;
72
+        Uint32 stdin_event;
73
+        Uint32 audio0_event;
74
+        Uint64 exec_deadline;
75
+        Uint64 deadline_interval;
76
+        Uint64 ms_interval;
77
+} instance_t;
78
+
79
+typedef struct varvara_t {
80
+        video_t video;
81
+        int sizeinstances;
82
+        instance_t **instances;
83
+} varvara_t;
84
+
85
+varvara_t *varvara_init(char *romfilename, int flag_fullscreen, int zoom);
86
+void varvara_free(varvara_t *varvara);
87
+
88
+instance_t *instance_init(video_t *video);
89
+void instance_free(instance_t *instance);
90
+
91
+
92
+/* prototypes: devices */
93
+
94
+static int clamp(int v, int min, int max);
95
+static void audio_deo(instance_t *instance, int instanceno, Uint8 *d, Uint8 port, Uxn *u);
96
+Uint8 emu_dei(Uxn *u, Uint8 addr);
97
+void emu_deo(Uxn *u, Uint8 addr, Uint8 value);
98
+
99
+/* prototypes: Handlers */
100
+
101
+void audio_finished_handler(int instance, void *userptr);
102
+static int stdin_handler(void *userptr);
103
+static void set_window_size(video_t *video, SDL_Window *window, int w, int h);
104
+static void set_zoom(video_t *video, Uint8 z, int win);
105
+static void set_flag_fullscreen(video_t *video, int value, int win);
106
+static void set_flag_borderless(video_t *video, int value);
107
+static void set_debugger(Uxn *u, int value);
108
+
109
+/* prototypes: emulator primitives */
110
+
111
+int emu_resize(Uxn *u, int width, int height);
112
+static void emu_redraw(Uxn *u);
113
+static int emu_init(Uxn *u);
114
+static void emu_restart(Uxn *u, char *rom, int soft);
115
+static void capture_screen(Uxn *u);
116
+static Uint8 get_button(SDL_Event *event);
117
+static Uint8 get_button_joystick(SDL_Event *event);
118
+static Uint8 get_vector_joystick(SDL_Event *event);
119
+static Uint8 get_key(SDL_Event *event);
120
+static int handle_events(Uxn *u);
121
+static int emu_run(Uxn *u, char *rom);
122
+static int emu_end(Uxn *u);
123
+
124
+/* overall init/free */
125
+
126
+varvara_t *
127
+varvara_init(char *romfilename, int flag_fullscreen, int zoom)
128
+{
55 129
 
56
-/* devices */
130
+        varvara_t *varvara;
131
+        if((varvara=malloc(sizeof(varvara_t)))==NULL
132
+          || memset(varvara,0,sizeof(varvara_t))==NULL
133
+          || (varvara->instances=malloc(sizeof(instance_t *)*INSTANCESSIZE))==NULL
134
+          || memset(varvara->instances,0,sizeof(instance_t *)*INSTANCESSIZE)==NULL
135
+          || (varvara->sizeinstances=INSTANCESSIZE)!=INSTANCESSIZE
136
+        ) {
137
+                varvara_free(varvara),varvara=NULL;
138
+                system_error("Init", "Failed to allocate varvara structs.");
139
+                return(NULL);
140
+        }
141
+
142
+        set_zoom(&(varvara->video),zoom, 0);
143
+        set_flag_fullscreen(&(varvara->video), flag_fullscreen, 0);
144
+        /* Start system. */
145
+        if((varvara->instances[0]=instance_init(&(varvara->video)))==NULL) {
146
+                varvara_free(varvara),varvara=NULL;
147
+                system_error("Init", "Failed to initialize varvara unx instance.");
148
+                return NULL;
149
+        }
150
+        varvara->instances[0]->u.userptr=(varvara->instances[0]);
151
+        varvara->instances[0]->u_audio.userptr=(varvara->instances[0]);
152
+        varvara->instances[0]->u.dev = (Uint8 *)&(varvara->instances[0]->dev);
153
+        varvara->instances[0]->u_audio.dev = (Uint8 *)&(varvara->instances[0]->dev);
154
+        if((varvara->instances[0]->ram=(Uint8 *)calloc(0x10000 * RAM_PAGES, sizeof(Uint8)))==NULL
155
+          || (varvara->instances[0]->rom=(char *)malloc(strlen(romfilename)+1))==NULL
156
+          || memcpy(varvara->instances[0]->rom,romfilename,strlen(romfilename)+1)==NULL
157
+          || !system_init(&(varvara->instances[0]->u), varvara->instances[0]->ram, varvara->instances[0]->rom)
158
+          || !system_init(&(varvara->instances[0]->u_audio), varvara->instances[0]->ram, varvara->instances[0]->rom)) {
159
+                varvara_free(varvara),varvara=NULL;
160
+                system_error("Init", "Failed to initialize uxn.");
161
+                return(NULL);
162
+        }
163
+        if(!emu_init(&(varvara->instances[0]->u_audio))) {
164
+                varvara_free(varvara),varvara=NULL;
165
+                system_error("Init", "Failed to initialize varvara.");
166
+                return NULL;
167
+        }
168
+        return(varvara);
169
+}
170
+
171
+void
172
+varvara_free(varvara_t *varvara)
173
+{
174
+        int i;
175
+        if(varvara==NULL)
176
+                return;
177
+        if(varvara->instances!=NULL) {
178
+                for(i=0;i<varvara->sizeinstances;i++) {
179
+                        if(varvara->instances[i]==NULL)
180
+                                continue;
181
+                        instance_free(varvara->instances[i]),varvara->instances[i]=NULL;
182
+                }
183
+                free(varvara->instances),varvara->instances=NULL,varvara->sizeinstances=0;
184
+        }
185
+        free(varvara),varvara=NULL;
186
+}
57 187
 
58
-static int window_created, fullscreen, borderless;
59
-static Uint32 stdin_event, audio0_event, zoom = 1;
60
-static Uint64 exec_deadline, deadline_interval, ms_interval;
188
+instance_t *
189
+instance_init(video_t *video)
190
+{
191
+        instance_t *instance;
192
+        if((instance=malloc(sizeof(instance_t)))==NULL)
193
+                return(NULL);
194
+        memset(instance,0,sizeof(instance_t));
195
+        instance->video=video;
196
+        return(instance);
197
+}
198
+
199
+void
200
+instance_free(instance_t *instance)
201
+{
202
+        if(instance==NULL)
203
+                return;
204
+        if(instance->ram!=NULL)
205
+                free(instance->ram),instance->ram=NULL;
206
+        if(instance->rom!=NULL)
207
+                free(instance->rom),instance->rom=NULL;
208
+        free(instance),instance=NULL;
209
+        return;
210
+}
211
+
212
+/* devices */
61 213
 
62 214
 static int
63 215
 clamp(int v, int min, int max)
64 216
 {
65
-	return v < min ? min : v > max ? max
66
-								   : v;
217
+        return (v<min)?min
218
+               :(v>max)?max
219
+               :v;
67 220
 }
68 221
 
69 222
 static void
70
-audio_deo(int instance, Uint8 *d, Uint8 port, Uxn *u)
223
+audio_deo(instance_t *instance, int instanceno, Uint8 *d, Uint8 port, Uxn *u)
71 224
 {
72
-	if(!audio_id) return;
73
-	if(port == 0xf) {
74
-		SDL_LockAudioDevice(audio_id);
75
-		audio_start(instance, d, u);
76
-		SDL_UnlockAudioDevice(audio_id);
77
-		SDL_PauseAudioDevice(audio_id, 0);
78
-	}
225
+        if(instance==NULL)
226
+                return; /* sanity check failed */
227
+        if(!instance->audio_id) return;
228
+        if(port == 0xf) {
229
+                SDL_LockAudioDevice(instance->audio_id);
230
+                audio_start(instanceno, d, u);
231
+                SDL_UnlockAudioDevice(instance->audio_id);
232
+                SDL_PauseAudioDevice(instance->audio_id, 0);
233
+        }
79 234
 }
80 235
 
81 236
 Uint8
82 237
 emu_dei(Uxn *u, Uint8 addr)
83 238
 {
84
-	Uint8 p = addr & 0x0f, d = addr & 0xf0;
85
-	switch(d) {
86
-	case 0x00: return system_dei(u, addr);
87
-	case 0x20: return screen_dei(u, addr);
88
-	case 0x30: return audio_dei(0, &u->dev[d], p);
89
-	case 0x40: return audio_dei(1, &u->dev[d], p);
90
-	case 0x50: return audio_dei(2, &u->dev[d], p);
91
-	case 0x60: return audio_dei(3, &u->dev[d], p);
92
-	case 0xc0: return datetime_dei(u, addr);
93
-	}
94
-	return u->dev[addr];
239
+        instance_t *instance;
240
+        Uint8 p = addr & 0x0f, d = addr & 0xf0;
241
+        if(u==NULL || (instance=((instance_t *)u->userptr))==NULL)
242
+                return(0); /* sanity check failed */
243
+        switch(d) {
244
+        case 0x00: return system_dei(u, addr);
245
+        case 0x20: return screen_dei(u, addr);
246
+        case 0x30: return audio_dei(0, &u->dev[d], p);
247
+        case 0x40: return audio_dei(1, &u->dev[d], p);
248
+        case 0x50: return audio_dei(2, &u->dev[d], p);
249
+        case 0x60: return audio_dei(3, &u->dev[d], p);
250
+        case 0xc0: return datetime_dei(u, addr);
251
+        }
252
+        return u->dev[addr];
95 253
 }
96 254
 
97 255
 void
98 256
 emu_deo(Uxn *u, Uint8 addr, Uint8 value)
99 257
 {
100
-	Uint8 p = addr & 0x0f, d = addr & 0xf0;
101
-	u->dev[addr] = value;
102
-	switch(d) {
103
-	case 0x00:
104
-		system_deo(u, &u->dev[d], p);
105
-		if(p > 0x7 && p < 0xe) screen_palette(&u->dev[0x8]);
106
-		break;
107
-	case 0x10: console_deo(&u->dev[d], p); break;
108
-	case 0x20: screen_deo(u->ram, &u->dev[d], p); break;
109
-	case 0x30: audio_deo(0, &u->dev[d], p, u); break;
110
-	case 0x40: audio_deo(1, &u->dev[d], p, u); break;
111
-	case 0x50: audio_deo(2, &u->dev[d], p, u); break;
112
-	case 0x60: audio_deo(3, &u->dev[d], p, u); break;
113
-	case 0xa0: file_deo(0, u->ram, &u->dev[d], p); break;
114
-	case 0xb0: file_deo(1, u->ram, &u->dev[d], p); break;
115
-	}
258
+        instance_t *instance;
259
+        Uint8 p = addr & 0x0f, d = addr & 0xf0;
260
+        if(u==NULL || (instance=((instance_t *)u->userptr))==NULL)
261
+                return; /* sanity check failed */
262
+        u->dev[addr] = value;
263
+        switch(d) {
264
+        case 0x00:
265
+                system_deo(u, &u->dev[d], p);
266
+                if(p > 0x7 && p < 0xe) screen_palette(&u->dev[0x8]);
267
+                break;
268
+        case 0x10: console_deo(&u->dev[d], p); break;
269
+        case 0x20: screen_deo(u, u->ram, &u->dev[d], p); break;
270
+        case 0x30: audio_deo(instance, 0, &u->dev[d], p, u); break;
271
+        case 0x40: audio_deo(instance, 1, &u->dev[d], p, u); break;
272
+        case 0x50: audio_deo(instance, 2, &u->dev[d], p, u); break;
273
+        case 0x60: audio_deo(instance, 3, &u->dev[d], p, u); break;
274
+        case 0xa0: file_deo(0, u->ram, &u->dev[d], p); break;
275
+        case 0xb0: file_deo(1, u->ram, &u->dev[d], p); break;
276
+        }
116 277
 }
117 278
 
118 279
 /* Handlers */
119 280
 
120 281
 void
121
-audio_finished_handler(int instance)
282
+audio_finished_handler(int instanceno, void *userptr)
122 283
 {
123
-	SDL_Event event;
124
-	event.type = audio0_event + instance;
125
-	SDL_PushEvent(&event);
284
+        instance_t *instance;
285
+        SDL_Event event;
286
+        if((instance=((instance_t *)userptr))==NULL)
287
+                return; /* sanity check failed */
288
+        event.type = instance->audio0_event + instanceno;
289
+        SDL_PushEvent(&event);
126 290
 }
127 291
 
128 292
 static int
129
-stdin_handler(void *p)
293
+stdin_handler(void *userptr)
130 294
 {
131
-	SDL_Event event;
132
-	USED(p);
133
-	event.type = stdin_event;
134
-	while(read(0, &event.cbutton.button, 1) > 0 && SDL_PushEvent(&event) >= 0)
135
-		;
136
-	return 0;
295
+        instance_t *instance;
296
+        SDL_Event event;
297
+        if((instance=((instance_t *)userptr))==NULL)
298
+                return(0); /* sanity check failed */
299
+        USED(userptr);
300
+        event.type = instance->stdin_event;
301
+        while(read(0, &event.cbutton.button, 1) > 0 && SDL_PushEvent(&event) >= 0)
302
+                ;
303
+        return 0;
137 304
 }
138 305
 
139 306
 static void
140
-set_window_size(SDL_Window *window, int w, int h)
307
+set_window_size(video_t *video, SDL_Window *window, int w, int h)
141 308
 {
142
-	SDL_Point win_old;
143
-	SDL_GetWindowSize(window, &win_old.x, &win_old.y);
144
-	if(w == win_old.x && h == win_old.y) return;
145
-	SDL_RenderClear(emu_renderer);
146
-	SDL_SetWindowSize(window, w, h);
309
+        SDL_Point win_old;
310
+        if(video==NULL || window==NULL)
311
+                return; /* sanity check failed */
312
+        SDL_GetWindowSize(window, &win_old.x, &win_old.y);
313
+        if(w == win_old.x && h == win_old.y) return;
314
+        SDL_RenderClear(video->emu_renderer);
315
+        SDL_SetWindowSize(window, w, h);
147 316
 }
148 317
 
149 318
 static void
150
-set_zoom(Uint8 z, int win)
319
+set_zoom(video_t *video, Uint8 z, int win)
151 320
 {
152
-	if(z < 1) return;
153
-	if(win)
154
-		set_window_size(emu_window, (uxn_screen.width + PAD2) * z, (uxn_screen.height + PAD2) * z);
155
-	zoom = z;
321
+        if(video==NULL)
322
+                return; /* sanity check failed */
323
+        if(z < 1) return;
324
+        if(win)
325
+                set_window_size(video, video->emu_window, (uxn_screen.width + PAD2) * z, (uxn_screen.height + PAD2) * z);
326
+        video->zoom = z;
156 327
 }
157 328
 
158 329
 static void
159
-set_fullscreen(int value, int win)
330
+set_flag_fullscreen(video_t *video, int value, int win)
160 331
 {
161
-	Uint32 flags = 0; /* windowed mode; SDL2 has no constant for this */
162
-	fullscreen = value;
163
-	if(fullscreen)
164
-		flags = SDL_WINDOW_FULLSCREEN_DESKTOP;
165
-	if(win)
166
-		SDL_SetWindowFullscreen(emu_window, flags);
332
+        Uint32 flags = 0; /* windowed mode; SDL2 has no constant for this */
333
+        if(video==NULL)
334
+                return; /* sanity check failed */
335
+        video->flag_fullscreen = value;
336
+        if(video->flag_fullscreen)
337
+                flags = SDL_WINDOW_FULLSCREEN_DESKTOP;
338
+        if(win)
339
+                SDL_SetWindowFullscreen(video->emu_window, flags);
167 340
 }
168 341
 
169 342
 static void
170
-set_borderless(int value)
343
+set_flag_borderless(video_t *video, int value)
171 344
 {
172
-	if(fullscreen) return;
173
-	borderless = value;
174
-	SDL_SetWindowBordered(emu_window, !value);
345
+        if(video==NULL)
346
+                return; /* sanity check failed */
347
+        if(video->flag_fullscreen) return;
348
+        video->flag_borderless = value;
349
+        SDL_SetWindowBordered(video->emu_window, !value);
175 350
 }
176 351
 
177 352
 static void
178 353
 set_debugger(Uxn *u, int value)
179 354
 {
180
-	u->dev[0x0e] = value;
181
-	screen_fill(uxn_screen.fg, 0);
182
-	screen_redraw(u);
355
+        u->dev[0x0e] = value;
356
+        screen_fill(uxn_screen.fg, 0);
357
+        screen_redraw(u);
183 358
 }
184 359
 
185 360
 /* emulator primitives */
186 361
 
187 362
 int
188
-emu_resize(int width, int height)
363
+emu_resize(Uxn *u, int width, int height)
189 364
 {
190
-	if(!window_created)
191
-		return 0;
192
-	if(emu_texture != NULL)
193
-		SDL_DestroyTexture(emu_texture);
194
-	SDL_RenderSetLogicalSize(emu_renderer, width + PAD2, height + PAD2);
195
-	emu_texture = SDL_CreateTexture(emu_renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_STATIC, width, height);
196
-	if(emu_texture == NULL || SDL_SetTextureBlendMode(emu_texture, SDL_BLENDMODE_NONE))
197
-		return system_error("SDL_SetTextureBlendMode", SDL_GetError());
198
-	if(SDL_UpdateTexture(emu_texture, NULL, uxn_screen.pixels, sizeof(Uint32)) != 0)
199
-		return system_error("SDL_UpdateTexture", SDL_GetError());
200
-	emu_viewport.x = PAD;
201
-	emu_viewport.y = PAD;
202
-	emu_viewport.w = uxn_screen.width;
203
-	emu_viewport.h = uxn_screen.height;
204
-	set_window_size(emu_window, (width + PAD2) * zoom, (height + PAD2) * zoom);
205
-	return 1;
365
+        video_t *video;
366
+        if(u==NULL || u->userptr==NULL || (video=((instance_t *)u->userptr)->video)==NULL)
367
+                return(0);
368
+        if(!video->flag_windowcreated)
369
+                return 0;
370
+        if(video->emu_texture != NULL)
371
+                SDL_DestroyTexture(video->emu_texture);
372
+        SDL_RenderSetLogicalSize(video->emu_renderer, width + PAD2, height + PAD2);
373
+        video->emu_texture = SDL_CreateTexture(video->emu_renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_STATIC, width, height);
374
+        if(video->emu_texture == NULL || SDL_SetTextureBlendMode(video->emu_texture, SDL_BLENDMODE_NONE))
375
+                return system_error("SDL_SetTextureBlendMode", SDL_GetError());
376
+        if(SDL_UpdateTexture(video->emu_texture, NULL, uxn_screen.pixels, sizeof(Uint32)) != 0)
377
+                return system_error("SDL_UpdateTexture", SDL_GetError());
378
+        video->emu_viewport.x = PAD;
379
+        video->emu_viewport.y = PAD;
380
+        video->emu_viewport.w = uxn_screen.width;
381
+        video->emu_viewport.h = uxn_screen.height;
382
+        set_window_size(video, video->emu_window, (width + PAD2) * video->zoom, (height + PAD2) * video->zoom);
383
+        return 1;
206 384
 }
207 385
 
208 386
 static void
209 387
 emu_redraw(Uxn *u)
210 388
 {
211
-	screen_redraw(u);
212
-	if(SDL_UpdateTexture(emu_texture, NULL, uxn_screen.pixels, uxn_screen.width * sizeof(Uint32)) != 0)
213
-		system_error("SDL_UpdateTexture", SDL_GetError());
214
-	SDL_RenderClear(emu_renderer);
215
-	SDL_RenderCopy(emu_renderer, emu_texture, NULL, &emu_viewport);
216
-	SDL_RenderPresent(emu_renderer);
389
+        video_t *video;
390
+        if(u==NULL || u->userptr==NULL || (video=((instance_t *)u->userptr)->video)==NULL)
391
+                return;
392
+        screen_redraw(u);
393
+        if(SDL_UpdateTexture(video->emu_texture, NULL, uxn_screen.pixels, uxn_screen.width * sizeof(Uint32)) != 0)
394
+                system_error("SDL_UpdateTexture", SDL_GetError());
395
+        SDL_RenderClear(video->emu_renderer);
396
+        SDL_RenderCopy(video->emu_renderer, video->emu_texture, NULL, &(video->emu_viewport));
397
+        SDL_RenderPresent(video->emu_renderer);
217 398
 }
218 399
 
219 400
 static int
220 401
 emu_init(Uxn *u)
221 402
 {
222
-	SDL_AudioSpec as;
223
-	SDL_zero(as);
224
-	as.freq = SAMPLE_FREQUENCY;
225
-	as.format = AUDIO_S16SYS;
226
-	as.channels = 2;
227
-	as.callback = audio_handler;
228
-	as.samples = AUDIO_BUFSIZE;
229
-	as.userdata = u;
230
-	if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0)
231
-		return system_error("sdl", SDL_GetError());
232
-	audio_id = SDL_OpenAudioDevice(NULL, 0, &as, NULL, 0);
233
-	if(!audio_id)
234
-		system_error("sdl_audio", SDL_GetError());
235
-	if(SDL_NumJoysticks() > 0 && SDL_JoystickOpen(0) == NULL)
236
-		system_error("sdl_joystick", SDL_GetError());
237
-	stdin_event = SDL_RegisterEvents(1);
238
-	audio0_event = SDL_RegisterEvents(POLYPHONY);
239
-	SDL_DetachThread(stdin_thread = SDL_CreateThread(stdin_handler, "stdin", NULL));
240
-	SDL_StartTextInput();
241
-	SDL_ShowCursor(SDL_DISABLE);
242
-	SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
243
-	SDL_SetRenderDrawColor(emu_renderer, 0x00, 0x00, 0x00, 0xff);
244
-	ms_interval = SDL_GetPerformanceFrequency() / 1000;
245
-	deadline_interval = ms_interval * TIMEOUT_MS;
246
-	exec_deadline = SDL_GetPerformanceCounter() + deadline_interval;
247
-	screen_resize(WIDTH, HEIGHT);
248
-	SDL_PauseAudioDevice(audio_id, 1);
249
-	return 1;
403
+        instance_t *instance;
404
+        SDL_AudioSpec as;
405
+        if(u==NULL || (instance=((instance_t *)u->userptr))==NULL)
406
+                return system_error("emu_init", "corrupted parameters");
407
+        SDL_zero(as);
408
+        as.freq = SAMPLE_FREQUENCY;
409
+        as.format = AUDIO_S16SYS;
410
+        as.channels = 2;
411
+        as.callback = audio_handler;
412
+        as.samples = AUDIO_BUFSIZE;
413
+        as.userdata = u;
414
+        if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0)
415
+                return system_error("sdl", SDL_GetError());
416
+        instance->audio_id = SDL_OpenAudioDevice(NULL, 0, &as, NULL, 0);
417
+        if(!instance->audio_id)
418
+                system_error("sdl_audio", SDL_GetError());
419
+        if(SDL_NumJoysticks() > 0 && SDL_JoystickOpen(0) == NULL)
420
+                system_error("sdl_joystick", SDL_GetError());
421
+        instance->stdin_event = SDL_RegisterEvents(1);
422
+        instance->audio0_event = SDL_RegisterEvents(POLYPHONY);
423
+        SDL_DetachThread(instance->stdin_thread = SDL_CreateThread(stdin_handler, "stdin", (void *)instance));
424
+        SDL_StartTextInput();
425
+        SDL_ShowCursor(SDL_DISABLE);
426
+        SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
427
+        SDL_SetRenderDrawColor(instance->video->emu_renderer, 0x00, 0x00, 0x00, 0xff);
428
+        instance->ms_interval = SDL_GetPerformanceFrequency() / 1000;
429
+        instance->deadline_interval = instance->ms_interval * TIMEOUT_MS;
430
+        instance->exec_deadline = SDL_GetPerformanceCounter() + instance->deadline_interval;
431
+        screen_resize(u,WIDTH, HEIGHT);
432
+        SDL_PauseAudioDevice(instance->audio_id, 1);
433
+        return 1;
250 434
 }
251 435
 
252 436
 static void
253 437
 emu_restart(Uxn *u, char *rom, int soft)
254 438
 {
255
-	screen_resize(WIDTH, HEIGHT);
256
-	screen_fill(uxn_screen.bg, 0);
257
-	screen_fill(uxn_screen.fg, 0);
258
-	system_reboot(u, rom, soft);
259
-	SDL_SetWindowTitle(emu_window, boot_rom);
439
+        instance_t *instance;
440
+        if(u==NULL || (instance=((instance_t *)u->userptr))==NULL)
441
+                return; /* sanity check error */
442
+        screen_resize(u,WIDTH, HEIGHT);
443
+        screen_fill(uxn_screen.bg, 0);
444
+        screen_fill(uxn_screen.fg, 0);
445
+        system_reboot(u, rom, soft);
446
+        SDL_SetWindowTitle(instance->video->emu_window, boot_rom);
260 447
 }
261 448
 
262 449
 static void
263
-capture_screen(void)
450
+capture_screen(Uxn *u)
264 451
 {
265
-	const Uint32 format = SDL_PIXELFORMAT_RGB24;
452
+        const Uint32 format = SDL_PIXELFORMAT_RGB24;
266 453
 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
267
-	/* SDL_PIXELFORMAT_RGB24 */
268
-	Uint32 Rmask = 0x000000FF;
269
-	Uint32 Gmask = 0x0000FF00;
270
-	Uint32 Bmask = 0x00FF0000;
454
+        /* SDL_PIXELFORMAT_RGB24 */
455
+        Uint32 Rmask = 0x000000FF;
456
+        Uint32 Gmask = 0x0000FF00;
457
+        Uint32 Bmask = 0x00FF0000;
271 458
 #else
272
-	/* SDL_PIXELFORMAT_BGR24 */
273
-	Uint32 Rmask = 0x00FF0000;
274
-	Uint32 Gmask = 0x0000FF00;
275
-	Uint32 Bmask = 0x000000FF;
459
+        /* SDL_PIXELFORMAT_BGR24 */
460
+        Uint32 Rmask = 0x00FF0000;
461
+        Uint32 Gmask = 0x0000FF00;
462
+        Uint32 Bmask = 0x000000FF;
276 463
 #endif
277
-	time_t t = time(NULL);
278
-	char fname[64];
279
-	int w, h;
280
-	SDL_Surface *surface;
281
-	SDL_GetRendererOutputSize(emu_renderer, &w, &h);
282
-	if((surface = SDL_CreateRGBSurface(0, w, h, 24, Rmask, Gmask, Bmask, 0)) == NULL)
283
-		return;
284
-	SDL_RenderReadPixels(emu_renderer, NULL, format, surface->pixels, surface->pitch);
285
-	strftime(fname, sizeof(fname), "screenshot-%Y%m%d-%H%M%S.bmp", localtime(&t));
286
-	if(SDL_SaveBMP(surface, fname) == 0) {
287
-		fprintf(stderr, "Saved %s\n", fname);
288
-		fflush(stderr);
289
-	}
290
-	SDL_FreeSurface(surface);
464
+        time_t t = time(NULL);
465
+        char fname[64];
466
+        int w, h;
467
+        SDL_Surface *surface;
468
+        instance_t *instance;
469
+        if(u==NULL || (instance=((instance_t *)u->userptr))==NULL)
470
+                return; /* sanity check error */
471
+        SDL_GetRendererOutputSize(instance->video->emu_renderer, &w, &h);
472
+        if((surface = SDL_CreateRGBSurface(0, w, h, 24, Rmask, Gmask, Bmask, 0)) == NULL)
473
+                return;
474
+        SDL_RenderReadPixels(instance->video->emu_renderer, NULL, format, surface->pixels, surface->pitch);
475
+        strftime(fname, sizeof(fname), "screenshot-%Y%m%d-%H%M%S.bmp", localtime(&t));
476
+        if(SDL_SaveBMP(surface, fname) == 0) {
477
+                fprintf(stderr, "Saved %s\n", fname);
478
+                fflush(stderr);
479
+        }
480
+        SDL_FreeSurface(surface);
291 481
 }
292 482
 
293 483
 static Uint8
294 484
 get_button(SDL_Event *event)
295 485
 {
296
-	switch(event->key.keysym.sym) {
297
-	case SDLK_LCTRL: return 0x01;
298
-	case SDLK_LALT: return 0x02;
299
-	case SDLK_LSHIFT: return 0x04;
300
-	case SDLK_HOME: return 0x08;
301
-	case SDLK_UP: return 0x10;
302
-	case SDLK_DOWN: return 0x20;
303
-	case SDLK_LEFT: return 0x40;
304
-	case SDLK_RIGHT: return 0x80;
305
-	}
306
-	return 0x00;
486
+        switch(event->key.keysym.sym) {
487
+        case SDLK_LCTRL: return 0x01;
488
+        case SDLK_LALT: return 0x02;
489
+        case SDLK_LSHIFT: return 0x04;
490
+        case SDLK_HOME: return 0x08;
491
+        case SDLK_UP: return 0x10;
492
+        case SDLK_DOWN: return 0x20;
493
+        case SDLK_LEFT: return 0x40;
494
+        case SDLK_RIGHT: return 0x80;
495
+        }
496
+        return 0x00;
307 497
 }
308 498
 
309 499
 static Uint8
310 500
 get_button_joystick(SDL_Event *event)
311 501
 {
312
-	return 0x01 << (event->jbutton.button & 0x3);
502
+        return 0x01 << (event->jbutton.button & 0x3);
313 503
 }
314 504
 
315 505
 static Uint8
316 506
 get_vector_joystick(SDL_Event *event)
317 507
 {
318
-	if(event->jaxis.value < -3200)
319
-		return 1;
320
-	if(event->jaxis.value > 3200)
321
-		return 2;
322
-	return 0;
508
+        if(event->jaxis.value < -3200)
509
+                return 1;
510
+        if(event->jaxis.value > 3200)
511
+                return 2;
512
+        return 0;
323 513
 }
324 514
 
325 515
 static Uint8
326 516
 get_key(SDL_Event *event)
327 517
 {
328
-	int sym = event->key.keysym.sym;
329
-	SDL_Keymod mods = SDL_GetModState();
330
-	if(sym < 0x20 || sym == SDLK_DELETE)
331
-		return sym;
332
-	if(mods & KMOD_CTRL) {
333
-		if(sym < SDLK_a)
334
-			return sym;
335
-		else if(sym <= SDLK_z)
336
-			return sym - (mods & KMOD_SHIFT) * 0x20;
337
-	}
338
-	return 0x00;
518
+        int sym = event->key.keysym.sym;
519
+        SDL_Keymod mods = SDL_GetModState();
520
+        if(sym < 0x20 || sym == SDLK_DELETE)
521
+                return sym;
522
+        if(mods & KMOD_CTRL) {
523
+                if(sym < SDLK_a)
524
+                        return sym;
525
+                else if(sym <= SDLK_z)
526
+                        return sym - (mods & KMOD_SHIFT) * 0x20;
527
+        }
528
+        return 0x00;
339 529
 }
340 530
 
341 531
 static int
342 532
 handle_events(Uxn *u)
343 533
 {
344
-	SDL_Event event;
345
-	while(SDL_PollEvent(&event)) {
346
-		/* Window */
347
-		if(event.type == SDL_QUIT)
348
-			return 0;
349
-		else if(event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_EXPOSED)
350
-			emu_redraw(u);
351
-		else if(event.type == SDL_DROPFILE) {
352
-			emu_restart(u, event.drop.file, 0);
353
-			SDL_free(event.drop.file);
354
-		}
355
-		/* Mouse */
356
-		else if(event.type == SDL_MOUSEMOTION)
357
-			mouse_pos(u, &u->dev[0x90], clamp(event.motion.x - PAD, 0, uxn_screen.width - 1), clamp(event.motion.y - PAD, 0, uxn_screen.height - 1));
358
-		else if(event.type == SDL_MOUSEBUTTONUP)
359
-			mouse_up(u, &u->dev[0x90], SDL_BUTTON(event.button.button));
360
-		else if(event.type == SDL_MOUSEBUTTONDOWN)
361
-			mouse_down(u, &u->dev[0x90], SDL_BUTTON(event.button.button));
362
-		else if(event.type == SDL_MOUSEWHEEL)
363
-			mouse_scroll(u, &u->dev[0x90], event.wheel.x, event.wheel.y);
364
-		/* Controller */
365
-		else if(event.type == SDL_TEXTINPUT)
366
-			controller_key(u, &u->dev[0x80], event.text.text[0]);
367
-		else if(event.type == SDL_KEYDOWN) {
368
-			int ksym;
369
-			if(get_key(&event))
370
-				controller_key(u, &u->dev[0x80], get_key(&event));
371
-			else if(get_button(&event))
372
-				controller_down(u, &u->dev[0x80], get_button(&event));
373
-			else if(event.key.keysym.sym == SDLK_F1)
374
-				set_zoom(zoom == 3 ? 1 : zoom + 1, 1);
375
-			else if(event.key.keysym.sym == SDLK_F2)
376
-				set_debugger(u, !u->dev[0x0e]);
377
-			else if(event.key.keysym.sym == SDLK_F3)
378
-				capture_screen();
379
-			else if(event.key.keysym.sym == SDLK_F4)
380
-				emu_restart(u, boot_rom, 0);
381
-			else if(event.key.keysym.sym == SDLK_F5)
382
-				emu_restart(u, boot_rom, 1);
383
-			else if(event.key.keysym.sym == SDLK_F11)
384
-				set_fullscreen(!fullscreen, 1);
385
-			else if(event.key.keysym.sym == SDLK_F12)
386
-				set_borderless(!borderless);
387
-			ksym = event.key.keysym.sym;
388
-			if(SDL_PeepEvents(&event, 1, SDL_PEEKEVENT, SDL_KEYUP, SDL_KEYUP) == 1 && ksym == event.key.keysym.sym)
389
-				return 1;
390
-		} else if(event.type == SDL_KEYUP)
391
-			controller_up(u, &u->dev[0x80], get_button(&event));
392
-		else if(event.type == SDL_JOYAXISMOTION) {
393
-			Uint8 vec = get_vector_joystick(&event);
394
-			if(!vec)
395
-				controller_up(u, &u->dev[0x80], (3 << (!event.jaxis.axis * 2)) << 4);
396
-			else
397
-				controller_down(u, &u->dev[0x80], (1 << ((vec + !event.jaxis.axis * 2) - 1)) << 4);
398
-		} else if(event.type == SDL_JOYBUTTONDOWN)
399
-			controller_down(u, &u->dev[0x80], get_button_joystick(&event));
400
-		else if(event.type == SDL_JOYBUTTONUP)
401
-			controller_up(u, &u->dev[0x80], get_button_joystick(&event));
402
-		else if(event.type == SDL_JOYHATMOTION) {
403
-			/* NOTE: Assuming there is only one joyhat in the controller */
404
-			switch(event.jhat.value) {
405
-			case SDL_HAT_UP: controller_down(u, &u->dev[0x80], 0x10); break;
406
-			case SDL_HAT_DOWN: controller_down(u, &u->dev[0x80], 0x20); break;
407
-			case SDL_HAT_LEFT: controller_down(u, &u->dev[0x80], 0x40); break;
408
-			case SDL_HAT_RIGHT: controller_down(u, &u->dev[0x80], 0x80); break;
409
-			case SDL_HAT_LEFTDOWN: controller_down(u, &u->dev[0x80], 0x40 | 0x20); break;
410
-			case SDL_HAT_LEFTUP: controller_down(u, &u->dev[0x80], 0x40 | 0x10); break;
411
-			case SDL_HAT_RIGHTDOWN: controller_down(u, &u->dev[0x80], 0x80 | 0x20); break;
412
-			case SDL_HAT_RIGHTUP: controller_down(u, &u->dev[0x80], 0x80 | 0x10); break;
413
-			case SDL_HAT_CENTERED: controller_up(u, &u->dev[0x80], 0x10 | 0x20 | 0x40 | 0x80); break;
414
-			}
415
-		}
416
-		/* Console */
417
-		else if(event.type == stdin_event)
418
-			console_input(u, event.cbutton.button, CONSOLE_STD);
419
-	}
420
-	return 1;
534
+        SDL_Event event;
535
+        instance_t *instance;
536
+        if(u==NULL || (instance=((instance_t *)u->userptr))==NULL)
537
+                return 0; /* sanity check error */
538
+        while(SDL_PollEvent(&event)) {
539
+                /* Window */
540
+                if(event.type == SDL_QUIT)
541
+                        return 0;
542
+                else if(event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_EXPOSED)
543
+                        emu_redraw(u);
544
+                else if(event.type == SDL_DROPFILE) {
545
+                        emu_restart(u, event.drop.file, 0);
546
+                        SDL_free(event.drop.file);
547
+                }
548
+                /* Mouse */
549
+                else if(event.type == SDL_MOUSEMOTION)
550
+                        mouse_pos(u, &u->dev[0x90], clamp(event.motion.x - PAD, 0, uxn_screen.width - 1), clamp(event.motion.y - PAD, 0, uxn_screen.height - 1));
551
+                else if(event.type == SDL_MOUSEBUTTONUP)
552
+                        mouse_up(u, &u->dev[0x90], SDL_BUTTON(event.button.button));
553
+                else if(event.type == SDL_MOUSEBUTTONDOWN)
554
+                        mouse_down(u, &u->dev[0x90], SDL_BUTTON(event.button.button));
555
+                else if(event.type == SDL_MOUSEWHEEL)
556
+                        mouse_scroll(u, &u->dev[0x90], event.wheel.x, event.wheel.y);
557
+                /* Controller */
558
+                else if(event.type == SDL_TEXTINPUT)
559
+                        controller_key(u, &u->dev[0x80], event.text.text[0]);
560
+                else if(event.type == SDL_KEYDOWN) {
561
+                        int ksym;
562
+                        if(get_key(&event))
563
+                                controller_key(u, &u->dev[0x80], get_key(&event));
564
+                        else if(get_button(&event))
565
+                                controller_down(u, &u->dev[0x80], get_button(&event));
566
+                        else if(event.key.keysym.sym == SDLK_F1)
567
+                                set_zoom(instance->video,(instance->video->zoom==4)?1:(instance->video->zoom+1), 1);
568
+                        else if(event.key.keysym.sym == SDLK_F2)
569
+                                set_debugger(u, !u->dev[0x0e]);
570
+                        else if(event.key.keysym.sym == SDLK_F3)
571
+                                capture_screen(u);
572
+                        else if(event.key.keysym.sym == SDLK_F4)
573
+                                emu_restart(u, boot_rom, 0);
574
+                        else if(event.key.keysym.sym == SDLK_F5)
575
+                                emu_restart(u, boot_rom, 1);
576
+                        else if(event.key.keysym.sym == SDLK_F11)
577
+                                set_flag_fullscreen(instance->video, !instance->video->flag_fullscreen, 1);
578
+                        else if(event.key.keysym.sym == SDLK_F12)
579
+                                set_flag_borderless(instance->video, !instance->video->flag_borderless);
580
+                        ksym = event.key.keysym.sym;
581
+                        if(SDL_PeepEvents(&event, 1, SDL_PEEKEVENT, SDL_KEYUP, SDL_KEYUP) == 1 && ksym == event.key.keysym.sym)
582
+                                return 1;
583
+                } else if(event.type == SDL_KEYUP)
584
+                        controller_up(u, &u->dev[0x80], get_button(&event));
585
+                else if(event.type == SDL_JOYAXISMOTION) {
586
+                        Uint8 vec = get_vector_joystick(&event);
587
+                        if(!vec)
588
+                                controller_up(u, &u->dev[0x80], (3 << (!event.jaxis.axis * 2)) << 4);
589
+                        else
590
+                                controller_down(u, &u->dev[0x80], (1 << ((vec + !event.jaxis.axis * 2) - 1)) << 4);
591
+                } else if(event.type == SDL_JOYBUTTONDOWN)
592
+                        controller_down(u, &u->dev[0x80], get_button_joystick(&event));
593
+                else if(event.type == SDL_JOYBUTTONUP)
594
+                        controller_up(u, &u->dev[0x80], get_button_joystick(&event));
595
+                else if(event.type == SDL_JOYHATMOTION) {
596
+                        /* NOTE: Assuming there is only one joyhat in the controller */
597
+                        switch(event.jhat.value) {
598
+                        case SDL_HAT_UP: controller_down(u, &u->dev[0x80], 0x10); break;
599
+                        case SDL_HAT_DOWN: controller_down(u, &u->dev[0x80], 0x20); break;
600
+                        case SDL_HAT_LEFT: controller_down(u, &u->dev[0x80], 0x40); break;
601
+                        case SDL_HAT_RIGHT: controller_down(u, &u->dev[0x80], 0x80); break;
602
+                        case SDL_HAT_LEFTDOWN: controller_down(u, &u->dev[0x80], 0x40 | 0x20); break;
603
+                        case SDL_HAT_LEFTUP: controller_down(u, &u->dev[0x80], 0x40 | 0x10); break;
604
+                        case SDL_HAT_RIGHTDOWN: controller_down(u, &u->dev[0x80], 0x80 | 0x20); break;
605
+                        case SDL_HAT_RIGHTUP: controller_down(u, &u->dev[0x80], 0x80 | 0x10); break;
606
+                        case SDL_HAT_CENTERED: controller_up(u, &u->dev[0x80], 0x10 | 0x20 | 0x40 | 0x80); break;
607
+                        }
608
+                }
609
+                /* Console */
610
+                else if(event.type == instance->stdin_event)
611
+                        console_input(u, event.cbutton.button, CONSOLE_STD);
612
+        }
613
+        return 1;
421 614
 }
422 615
 
423 616
 static int
424 617
 emu_run(Uxn *u, char *rom)
425 618
 {
426
-	Uint64 next_refresh = 0;
427
-	Uint64 frame_interval = SDL_GetPerformanceFrequency() / 60;
428
-	Uint8 *vector_addr = &u->dev[0x20];
429
-	Uint32 window_flags = SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI;
430
-	window_created = 1;
431
-	if(fullscreen)
432
-		window_flags = window_flags | SDL_WINDOW_FULLSCREEN_DESKTOP;
433
-	emu_window = SDL_CreateWindow(rom,
434
-		SDL_WINDOWPOS_UNDEFINED,
435
-		SDL_WINDOWPOS_UNDEFINED,
436
-		(uxn_screen.width + PAD2) * zoom,
437
-		(uxn_screen.height + PAD2) * zoom,
438
-		window_flags);
439
-	if(emu_window == NULL)
440
-		return system_error("sdl_window", SDL_GetError());
441
-	emu_renderer = SDL_CreateRenderer(emu_window, -1, SDL_RENDERER_ACCELERATED);
442
-	if(emu_renderer == NULL)
443
-		return system_error("sdl_renderer", SDL_GetError());
444
-	emu_resize(uxn_screen.width, uxn_screen.height);
445
-	/* game loop */
446
-	for(;;) {
447
-		Uint16 screen_vector;
448
-		Uint64 now = SDL_GetPerformanceCounter();
449
-		/* .System/halt */
450
-		if(u->dev[0x0f])
451
-			return system_error("Run", "Ended.");
452
-		exec_deadline = now + deadline_interval;
453
-		if(!handle_events(u))
454
-			return 0;
455
-		screen_vector = PEEK2(vector_addr);
456
-		if(now >= next_refresh) {
457
-			now = SDL_GetPerformanceCounter();
458
-			next_refresh = now + frame_interval;
459
-			uxn_eval(u, screen_vector);
460
-			if(uxn_screen.x2)
461
-				emu_redraw(u);
462
-		}
463
-		if(screen_vector || uxn_screen.x2) {
464
-			Uint64 delay_ms = (next_refresh - now) / ms_interval;
465
-			if(delay_ms > 0) SDL_Delay(delay_ms);
466
-		} else
467
-			SDL_WaitEvent(NULL);
468
-	}
619
+        Uint64 next_refresh = 0;
620
+        Uint64 frame_interval;
621
+        Uint8 *vector_addr;
622
+        Uint32 window_flags = SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI;
623
+        instance_t *instance;
624
+        if(u==NULL || (instance=((instance_t *)u->userptr))==NULL)
625
+                return system_error("Init", "emu_run parameters corrupted");
626
+        instance->video->flag_windowcreated = 1;
627
+        if(u==NULL || rom==NULL || (instance=((instance_t *)u->userptr))==NULL)
628
+                return system_error("Init", "emu_run parameters");
629
+        frame_interval=SDL_GetPerformanceFrequency()/60;
630
+        vector_addr=&u->dev[0x20];
631
+        if(instance->video->flag_fullscreen)
632
+                window_flags = window_flags | SDL_WINDOW_FULLSCREEN_DESKTOP;
633
+        instance->video->emu_window = SDL_CreateWindow(rom,
634
+                SDL_WINDOWPOS_UNDEFINED,
635
+                SDL_WINDOWPOS_UNDEFINED,
636
+                (uxn_screen.width + PAD2) * instance->video->zoom,
637
+                (uxn_screen.height + PAD2) * instance->video->zoom,
638
+                window_flags);
639
+        if(instance->video->emu_window == NULL)
640
+                return system_error("sdl_window", SDL_GetError());
641
+        instance->video->emu_renderer = SDL_CreateRenderer(instance->video->emu_window, -1, SDL_RENDERER_ACCELERATED);
642
+        if(instance->video->emu_renderer == NULL)
643
+                return system_error("sdl_renderer", SDL_GetError());
644
+        emu_resize(u, uxn_screen.width, uxn_screen.height);
645
+        /* game loop */
646
+        for(;;) {
647
+                Uint16 screen_vector;
648
+                Uint64 now = SDL_GetPerformanceCounter();
649
+                /* .System/halt */
650
+                if(u->dev[0x0f])
651
+                        return system_error("Run", "Ended.");
652
+                instance->exec_deadline = now + instance->deadline_interval;
653
+                if(!handle_events(u))
654
+                        return 0;
655
+                screen_vector = PEEK2(vector_addr);
656
+                if(now >= next_refresh) {
657
+                        now = SDL_GetPerformanceCounter();
658
+                        next_refresh = now + frame_interval;
659
+                        uxn_eval(u, screen_vector);
660
+                        if(uxn_screen.x2)
661
+                                emu_redraw(u);
662
+                }
663
+                if(screen_vector || uxn_screen.x2) {
664
+                        Uint64 delay_ms = (next_refresh - now) / instance->ms_interval;
665
+                        if(delay_ms > 0) SDL_Delay(delay_ms);
666
+                } else
667
+                        SDL_WaitEvent(NULL);
668
+        }
469 669
 }
470 670
 
471 671
 static int
472 672
 emu_end(Uxn *u)
473 673
 {
474
-	SDL_CloseAudioDevice(audio_id);
674
+        instance_t *instance;
675
+        if(u==NULL || (instance=((instance_t *)u->userptr))==NULL)
676
+                return 0;
677
+        SDL_CloseAudioDevice(instance->audio_id);
475 678
 #ifdef _WIN32
476 679
 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
477
-	TerminateThread((HANDLE)SDL_GetThreadID(stdin_thread), 0);
680
+        TerminateThread((HANDLE)SDL_GetThreadID(instance->stdin_thread), 0);
478 681
 #elif !defined(__APPLE__)
479
-	close(0); /* make stdin thread exit */
682
+        close(0); /* make stdin thread exit */
480 683
 #endif
481
-	SDL_Quit();
482
-	free(u->ram);
483
-	return u->dev[0x0f] & 0x7f;
684
+        SDL_Quit();
685
+        free(u->ram);
686
+        return u->dev[0x0f] & 0x7f;
484 687
 }
485 688
 
486 689
 int
487 690
 main(int argc, char **argv)
488 691
 {
489
-	Uint8 *ram;
490
-	char *rom;
491
-	Uint8 dev[0x100] = {0};
492
-	Uxn u = {0}, u_audio = {0};
493
-	u.dev = (Uint8 *)&dev;
494
-	u_audio.dev = (Uint8 *)&dev;
495
-	int i = 1;
496
-	if(i == argc)
497
-		return system_error("usage", "uxnemu [-v] | uxnemu [-f | -2x | -3x | --] file.rom [args...]");
498
-	/* Read flag. Right now, there can be only one. */
499
-	if(argv[i][0] == '-') {
500
-		if(argv[i][1] == 'v')
501
-			return system_version("Uxnemu - Graphical Varvara Emulator", "18 Dec 2023");
502
-		if(argv[i][1] == '-')
503
-			i++;
504
-		if(strcmp(argv[i], "-2x") == 0 || strcmp(argv[i], "-3x") == 0)
505
-			set_zoom(argv[i++][1] - '0', 0);
506
-		if(strcmp(argv[i], "-f") == 0) {
507
-			i++;
508
-			set_fullscreen(1, 0);
509
-		}
510
-	}
511
-	/* Start system. */
512
-	ram = (Uint8 *)calloc(0x10000 * RAM_PAGES, sizeof(Uint8));
513
-	rom = argv[i++];
514
-	if(!system_init(&u, ram, rom) || !system_init(&u_audio, ram, rom))
515
-		return system_error("Init", "Failed to initialize uxn.");
516
-	if(!emu_init(&u_audio))
517
-		return system_error("Init", "Failed to initialize varvara.");
518
-	/* Game Loop */
519
-	u.dev[0x17] = argc - i;
520
-	if(uxn_eval(&u, PAGE_PROGRAM)) {
521
-		console_listen(&u, i, argc, argv);
522
-		emu_run(&u, boot_rom);
523
-	}
524
-	return emu_end(&u);
692
+        int zoom;
693
+        int flag_fullscreen;
694
+        char *rom;
695
+        varvara_t *varvara;
696
+        int i;
697
+
698
+        zoom=1;
699
+        flag_fullscreen=0;
700
+        i = 1;
701
+        if(i == argc)
702
+                return system_error("usage", "uxn256emu [-v] | uxnemu [-f | -2x | -3x | --] file.rom [args...]");
703
+        /* Read flag. Right now, there can be only one. */
704
+        if(argv[i][0] == '-') {
705
+                if(argv[i][1] == 'v')
706
+                        return system_version("Uxn256emu - Graphical Varvara256 Emulator", "31 Dec 2023");
707
+                if(argv[i][1] == '-')
708
+                        i++;
709
+                if(strcmp(argv[i], "-2x") == 0 || strcmp(argv[i], "-3x") == 0 || strcmp(argv[i], "-4x") == 0 )
710
+                        zoom=argv[i++][1] - '0';
711
+                if(strcmp(argv[i], "-f") == 0) {
712
+                        i++;
713
+                        flag_fullscreen=1;
714
+                }
715
+        }
716
+        rom = argv[i++];
717
+        if((varvara=varvara_init(rom,flag_fullscreen,zoom))==NULL)
718
+                return system_error("init", "Couln't init varvara256");
719
+        /* Game Loop */
720
+        varvara->instances[0]->u.dev[0x17] = argc - i;
721
+        if(uxn_eval(&(varvara->instances[0]->u), PAGE_PROGRAM)) {
722
+                console_listen(&(varvara->instances[0]->u), i, argc, argv);
723
+                emu_run(&(varvara->instances[0]->u), boot_rom);
724
+        }
725
+        return emu_end(&(varvara->instances[0]->u));
525 726
 }