... | ... |
@@ -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 @@ |
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 |
} |