uxn/src/uxnemu.c

602 lines
16 KiB
C
Raw Normal View History

2021-02-08 22:18:01 +00:00
#include <stdio.h>
2021-03-26 21:01:51 +00:00
#include <time.h>
2021-05-13 01:28:45 +00:00
#include "uxn.h"
2021-06-27 17:53:54 +00:00
#ifdef __ANDROID__
#include <android/log.h>
#undef stdout
#undef stderr
#define stdout ANDROID_LOG_VERBOSE
#define stderr ANDROID_LOG_VERBOSE
#define fprintf(f, ...) __android_log_print(f, "Uxn", __VA_ARGS__)
#endif
2021-06-27 17:53:54 +00:00
#pragma GCC diagnostic push
#pragma clang diagnostic push
2021-06-27 17:53:54 +00:00
#pragma GCC diagnostic ignored "-Wpedantic"
#pragma clang diagnostic ignored "-Wtypedef-redefinition"
2021-06-27 17:53:54 +00:00
#include <SDL.h>
#include "devices/system.h"
2021-12-28 21:37:26 +00:00
#include "devices/screen.h"
2021-12-28 21:47:35 +00:00
#include "devices/audio.h"
#include "devices/file.h"
#include "devices/controller.h"
2021-12-27 05:02:24 +00:00
#include "devices/mouse.h"
2022-01-07 18:02:28 +00:00
#include "devices/datetime.h"
2021-06-27 17:53:54 +00:00
#pragma GCC diagnostic pop
#pragma clang diagnostic pop
2021-02-08 22:18:01 +00:00
/*
Copyright (c) 2021 Devine Lu Linvega
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE.
*/
2021-09-21 22:41:59 +00:00
#define WIDTH 64 * 8
#define HEIGHT 40 * 8
#ifdef __ANDROID__
#define PAD 0
#else
2021-08-05 03:30:57 +00:00
#define PAD 4
#endif
2021-08-05 03:30:57 +00:00
#define BENCH 0
2021-03-16 16:01:47 +00:00
static SDL_Window *gWindow;
static SDL_Texture *gTexture;
static SDL_Renderer *gRenderer;
static SDL_AudioDeviceID audio_id;
static SDL_Rect gRect;
static SDL_Point gScrSize;
static SDL_Rect gScrDst;
2021-12-28 21:37:26 +00:00
/* devices */
2021-12-28 21:37:26 +00:00
static Device *devscreen, *devmouse, *devctrl, *devaudio0;
2021-09-30 00:58:58 +00:00
static Uint8 zoom = 1;
2021-12-27 17:57:48 +00:00
static Uint32 stdin_event, audio0_event;
2021-02-19 02:16:39 +00:00
static int
clamp(int val, int min, int max)
{
return (val >= min) ? (val <= max) ? val : max : min;
}
2021-06-28 21:42:36 +00:00
static int
2021-02-14 18:22:42 +00:00
error(char *msg, const char *err)
{
2021-07-25 00:09:46 +00:00
fprintf(stderr, "%s: %s\n", msg, err);
2021-02-14 18:22:42 +00:00
return 0;
2021-02-09 18:58:06 +00:00
}
2021-09-21 22:41:59 +00:00
#pragma mark - Generics
static void
audio_callback(void *u, Uint8 *stream, int len)
{
int i, running = 0;
2021-04-25 14:12:45 +00:00
Sint16 *samples = (Sint16 *)stream;
SDL_memset(stream, 0, len);
for(i = 0; i < POLYPHONY; i++)
2021-12-29 17:11:03 +00:00
running += audio_render(&uxn_audio[i], samples, samples + len / 2);
if(!running)
SDL_PauseAudioDevice(audio_id, 1);
2021-04-25 14:12:45 +00:00
(void)u;
}
2021-09-21 22:41:59 +00:00
void
2021-12-29 17:11:03 +00:00
audio_finished_handler(UxnAudio *c)
2021-09-21 22:41:59 +00:00
{
SDL_Event event;
2021-12-29 17:11:03 +00:00
event.type = audio0_event + (c - uxn_audio);
2021-09-21 22:41:59 +00:00
SDL_PushEvent(&event);
}
int
uxn_interrupt(Uxn *u)
{
2022-01-13 02:40:51 +00:00
(void)u;
return 0;
}
2021-09-21 22:41:59 +00:00
static int
stdin_handler(void *p)
{
SDL_Event event;
event.type = stdin_event;
2022-01-11 23:50:41 +00:00
while(fread(&event.cbutton.button, 1, 1, stdin) > 0)
2021-09-21 22:41:59 +00:00
SDL_PushEvent(&event);
return 0;
(void)p;
}
2021-09-21 20:21:48 +00:00
static void
set_window_size(SDL_Window *window, int w, int h)
{
#ifdef __ANDROID__
(void)window;
(void)w;
(void)h;
#else
2021-09-22 17:57:43 +00:00
SDL_Point win, win_old;
2021-09-21 22:56:42 +00:00
SDL_GetWindowPosition(window, &win.x, &win.y);
SDL_GetWindowSize(window, &win_old.x, &win_old.y);
2021-09-22 17:57:43 +00:00
SDL_SetWindowPosition(window, (win.x + win_old.x / 2) - w / 2, (win.y + win_old.y / 2) - h / 2);
2021-09-21 20:21:48 +00:00
SDL_SetWindowSize(window, w, h);
#endif
2021-09-21 20:21:48 +00:00
}
static void
resized(void)
{
#ifdef __ANDROID__
/* on Android we want to move the screen to the top when in portrait mode */
SDL_GetWindowSize(gWindow, &gScrSize.x, &gScrSize.y);
#else
gScrSize.x = uxn_screen.width + PAD * 2;
gScrSize.y = uxn_screen.height + PAD * 2;
#endif
SDL_RenderSetLogicalSize(gRenderer, gScrSize.x, gScrSize.y);
}
int
2021-09-22 17:57:43 +00:00
set_size(Uint16 width, Uint16 height, int is_resize)
{
2021-12-29 17:11:03 +00:00
screen_resize(&uxn_screen, width, height);
2021-09-22 17:57:43 +00:00
gRect.x = PAD;
gRect.y = PAD;
2021-12-29 17:11:03 +00:00
gRect.w = uxn_screen.width;
gRect.h = uxn_screen.height;
2021-09-22 17:57:43 +00:00
if(gTexture != NULL) SDL_DestroyTexture(gTexture);
#ifndef __ANDROID__
2021-12-29 17:11:03 +00:00
SDL_RenderSetLogicalSize(gRenderer, uxn_screen.width + PAD * 2, uxn_screen.height + PAD * 2);
#endif
gTexture = SDL_CreateTexture(gRenderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_STATIC, uxn_screen.width, uxn_screen.height);
2021-09-22 17:57:43 +00:00
if(gTexture == NULL || SDL_SetTextureBlendMode(gTexture, SDL_BLENDMODE_NONE))
return error("gTexture", SDL_GetError());
2021-12-29 17:11:03 +00:00
if(SDL_UpdateTexture(gTexture, NULL, uxn_screen.pixels, sizeof(Uint32)) != 0)
return error("SDL_UpdateTexture", SDL_GetError());
2021-09-22 17:57:43 +00:00
if(is_resize)
2021-12-29 17:11:03 +00:00
set_window_size(gWindow, (uxn_screen.width + PAD * 2) * zoom, (uxn_screen.height + PAD * 2) * zoom);
resized();
2021-09-22 17:57:43 +00:00
return 1;
}
2021-06-28 21:42:36 +00:00
static void
2022-01-06 04:44:33 +00:00
redraw(void)
2021-02-08 23:46:52 +00:00
{
2021-12-29 17:11:03 +00:00
screen_redraw(&uxn_screen, uxn_screen.pixels);
if(SDL_UpdateTexture(gTexture, NULL, uxn_screen.pixels, uxn_screen.width * sizeof(Uint32)) != 0)
error("SDL_UpdateTexture", SDL_GetError());
SDL_RenderClear(gRenderer);
#ifdef __ANDROID__
gScrDst.x = 0;
gScrDst.y = 0;
if(gScrSize.y > gScrSize.x) { /* portrait */
gScrDst.w = gScrSize.x;
gScrDst.h = gScrSize.x * uxn_screen.height / uxn_screen.width;
} else { /* landscape */
gScrDst.h = gScrSize.y;
gScrDst.w = gScrSize.y * uxn_screen.width / uxn_screen.height;
gScrDst.x = (gScrSize.x - gScrDst.w) / 2;
}
SDL_RenderCopy(gRenderer, gTexture, NULL, &gScrDst);
#else
SDL_RenderCopy(gRenderer, gTexture, NULL, &gRect);
#endif
SDL_RenderPresent(gRenderer);
2021-02-08 23:46:52 +00:00
}
2021-06-28 21:42:36 +00:00
static int
2021-11-08 15:51:09 +00:00
init(void)
2021-02-08 23:46:52 +00:00
{
int winflags;
SDL_AudioSpec as;
SDL_zero(as);
as.freq = SAMPLE_FREQUENCY;
as.format = AUDIO_S16;
as.channels = 2;
as.callback = audio_callback;
as.samples = 512;
as.userdata = NULL;
SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
2021-12-29 22:01:11 +00:00
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0)
return error("sdl", SDL_GetError());
#ifdef __ANDROID__
winflags = SDL_WINDOW_RESIZABLE;
#else
2021-12-28 20:48:28 +00:00
winflags = 0;
#endif
gWindow = SDL_CreateWindow("Uxn", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, (WIDTH + PAD * 2) * zoom, (HEIGHT + PAD * 2) * zoom, winflags);
2021-02-08 23:46:52 +00:00
if(gWindow == NULL)
2021-07-25 00:09:46 +00:00
return error("sdl_window", SDL_GetError());
gRenderer = SDL_CreateRenderer(gWindow, -1, 0);
if(gRenderer == NULL)
return error("sdl_renderer", SDL_GetError());
SDL_SetRenderDrawColor(gRenderer, 0x00, 0x00, 0x00, 0xff);
2021-12-29 01:38:55 +00:00
audio_id = SDL_OpenAudioDevice(NULL, 0, &as, NULL, 0);
if(!audio_id)
error("sdl_audio", SDL_GetError());
2021-12-29 17:33:23 +00:00
if(SDL_NumJoysticks() > 0 && SDL_JoystickOpen(0) == NULL)
2021-12-29 01:38:55 +00:00
error("sdl_joystick", SDL_GetError());
2021-09-21 22:41:59 +00:00
stdin_event = SDL_RegisterEvents(1);
audio0_event = SDL_RegisterEvents(POLYPHONY);
SDL_CreateThread(stdin_handler, "stdin", NULL);
SDL_StartTextInput();
2021-02-18 23:11:02 +00:00
SDL_ShowCursor(SDL_DISABLE);
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
2021-02-08 23:46:52 +00:00
return 1;
}
2021-02-09 05:59:46 +00:00
#pragma mark - Devices
void
system_deo_special(Device *d, Uint8 port)
{
2021-11-04 17:13:01 +00:00
if(port > 0x7 && port < 0xe)
2021-12-29 17:11:03 +00:00
screen_palette(&uxn_screen, &d->dat[0x8]);
}
static void
2021-11-04 17:13:01 +00:00
console_deo(Device *d, Uint8 port)
{
2022-01-11 23:50:41 +00:00
FILE *fd = port == 0x8 ? stdout : port == 0x9 ? stderr
: 0;
if(fd) {
fputc(d->dat[port], fd);
fflush(fd);
}
}
static Uint8
2021-11-04 17:13:01 +00:00
audio_dei(Device *d, Uint8 port)
{
2021-12-29 17:11:03 +00:00
UxnAudio *c = &uxn_audio[d - devaudio0];
2021-11-04 17:13:01 +00:00
if(!audio_id) return d->dat[port];
switch(port) {
2021-12-28 21:47:35 +00:00
case 0x4: return audio_get_vu(c);
2022-01-03 21:23:57 +00:00
case 0x2: DEVPOKE16(0x2, c->i); /* fall through */
2021-11-04 17:13:01 +00:00
default: return d->dat[port];
}
}
static void
2021-11-04 17:13:01 +00:00
audio_deo(Device *d, Uint8 port)
{
2021-12-29 17:11:03 +00:00
UxnAudio *c = &uxn_audio[d - devaudio0];
if(!audio_id) return;
2021-11-04 17:13:01 +00:00
if(port == 0xf) {
2022-01-03 21:29:47 +00:00
Uint16 addr, adsr;
2021-04-26 18:49:34 +00:00
SDL_LockAudioDevice(audio_id);
2022-01-03 21:29:47 +00:00
DEVPEEK16(adsr, 0x8);
DEVPEEK16(c->len, 0xa);
DEVPEEK16(addr, 0xc);
2022-01-11 22:51:25 +00:00
c->addr = &d->u->ram[addr];
2021-04-26 18:49:34 +00:00
c->volume[0] = d->dat[0xe] >> 4;
c->volume[1] = d->dat[0xe] & 0xf;
2021-04-25 14:12:45 +00:00
c->repeat = !(d->dat[0xf] & 0x80);
2022-01-03 21:29:47 +00:00
audio_start(c, adsr, d->dat[0xf] & 0x7f);
2021-04-26 18:49:34 +00:00
SDL_UnlockAudioDevice(audio_id);
SDL_PauseAudioDevice(audio_id, 0);
2021-04-25 14:12:45 +00:00
}
2021-03-24 23:30:52 +00:00
}
static Uint8
2021-11-04 17:13:01 +00:00
nil_dei(Device *d, Uint8 port)
{
2021-11-04 17:13:01 +00:00
return d->dat[port];
}
static void
2021-11-04 17:13:01 +00:00
nil_deo(Device *d, Uint8 port)
{
2022-01-08 00:46:50 +00:00
(void)d;
(void)port;
}
2021-11-08 15:51:09 +00:00
/* Boot */
static int
load(Uxn *u, char *rom)
{
SDL_RWops *f;
int r;
if(!(f = SDL_RWFromFile(rom, "rb"))) return 0;
2022-01-08 00:51:43 +00:00
r = f->read(f, u->ram + PAGE_PROGRAM, 1, 0x10000 - PAGE_PROGRAM);
f->close(f);
if(r < 1) return 0;
2021-11-08 15:51:09 +00:00
fprintf(stderr, "Loaded %s\n", rom);
SDL_SetWindowTitle(gWindow, rom);
return 1;
}
static int
2021-11-08 17:12:17 +00:00
start(Uxn *u, char *rom)
2021-11-08 15:51:09 +00:00
{
2022-01-13 02:56:59 +00:00
if(!uxn_boot(u, (Uint8 *)calloc(0x10000, sizeof(Uint8))))
2021-11-08 15:51:09 +00:00
return error("Boot", "Failed to start uxn.");
if(!load(u, rom))
return error("Boot", "Failed to load rom.");
2022-01-13 18:55:02 +00:00
/* system */ uxn_port(u, 0x0, system_dei, system_deo);
2022-01-11 22:38:55 +00:00
/* console */ uxn_port(u, 0x1, nil_dei, console_deo);
2021-11-08 15:51:09 +00:00
/* screen */ devscreen = uxn_port(u, 0x2, screen_dei, screen_deo);
/* audio0 */ devaudio0 = uxn_port(u, 0x3, audio_dei, audio_deo);
/* audio1 */ uxn_port(u, 0x4, audio_dei, audio_deo);
/* audio2 */ uxn_port(u, 0x5, audio_dei, audio_deo);
/* audio3 */ uxn_port(u, 0x6, audio_dei, audio_deo);
/* unused */ uxn_port(u, 0x7, nil_dei, nil_deo);
/* control */ devctrl = uxn_port(u, 0x8, nil_dei, nil_deo);
/* mouse */ devmouse = uxn_port(u, 0x9, nil_dei, nil_deo);
/* file */ uxn_port(u, 0xa, nil_dei, file_deo);
/* datetime */ uxn_port(u, 0xb, datetime_dei, nil_deo);
/* unused */ uxn_port(u, 0xc, nil_dei, nil_deo);
/* unused */ uxn_port(u, 0xd, nil_dei, nil_deo);
/* unused */ uxn_port(u, 0xe, nil_dei, nil_deo);
/* unused */ uxn_port(u, 0xf, nil_dei, nil_deo);
if(!uxn_eval(u, PAGE_PROGRAM))
return error("Boot", "Failed to start rom.");
return 1;
}
2021-12-27 21:59:22 +00:00
static void
set_zoom(Uint8 scale)
{
#ifdef __ANDROID__
(void)scale;
#else
2021-12-27 21:59:22 +00:00
zoom = clamp(scale, 1, 3);
2021-12-29 17:11:03 +00:00
set_window_size(gWindow, (uxn_screen.width + PAD * 2) * zoom, (uxn_screen.height + PAD * 2) * zoom);
#endif
2021-12-27 21:59:22 +00:00
}
static void
capture_screen(void)
{
const Uint32 format = SDL_PIXELFORMAT_RGB24;
time_t t = time(NULL);
char fname[64];
int w, h;
SDL_Surface *surface;
SDL_GetRendererOutputSize(gRenderer, &w, &h);
surface = SDL_CreateRGBSurfaceWithFormat(0, w, h, 24, format);
SDL_RenderReadPixels(gRenderer, NULL, format, surface->pixels, surface->pitch);
strftime(fname, sizeof(fname), "screenshot-%Y%m%d-%H%M%S.bmp", localtime(&t));
SDL_SaveBMP(surface, fname);
SDL_FreeSurface(surface);
fprintf(stderr, "Saved %s\n", fname);
}
2021-11-08 17:13:43 +00:00
static void
2021-11-08 17:12:17 +00:00
restart(Uxn *u)
2021-11-08 15:51:09 +00:00
{
set_size(WIDTH, HEIGHT, 1);
2022-01-11 04:35:34 +00:00
start(u, "launcher.rom");
2021-11-08 15:51:09 +00:00
}
2021-12-27 18:04:24 +00:00
static Uint8
get_button(SDL_Event *event)
{
switch(event->key.keysym.sym) {
case SDLK_LCTRL: return 0x01;
case SDLK_LALT: return 0x02;
case SDLK_LSHIFT: return 0x04;
2021-12-27 21:42:36 +00:00
case SDLK_HOME: return 0x08;
case SDLK_UP: return 0x10;
case SDLK_DOWN: return 0x20;
case SDLK_LEFT: return 0x40;
case SDLK_RIGHT: return 0x80;
}
return 0x00;
}
2021-12-27 18:04:24 +00:00
static Uint8
2021-12-27 19:44:57 +00:00
get_button_joystick(SDL_Event *event)
{
return 0x01 << (event->jbutton.button & 0x3);
}
static Uint8
get_vector_joystick(SDL_Event *event)
{
if(event->jaxis.value < -3200)
return 1;
if(event->jaxis.value > 3200)
return 2;
return 0;
2021-12-27 18:04:24 +00:00
}
static Uint8
get_key(SDL_Event *event)
{
SDL_Keymod mods = SDL_GetModState();
if(event->key.keysym.sym < 0x20 || event->key.keysym.sym == SDLK_DELETE)
return event->key.keysym.sym;
if((mods & KMOD_CTRL) && event->key.keysym.sym >= SDLK_a && event->key.keysym.sym <= SDLK_z)
return event->key.keysym.sym - (mods & KMOD_SHIFT) * 0x20;
return 0x00;
}
2021-11-08 15:51:09 +00:00
static void
do_shortcut(Uxn *u, SDL_Event *event)
2021-11-08 15:51:09 +00:00
{
if(event->key.keysym.sym == SDLK_F1)
set_zoom(zoom > 2 ? 1 : zoom + 1);
2021-12-27 21:59:22 +00:00
else if(event->key.keysym.sym == SDLK_F2)
2022-01-13 16:34:32 +00:00
system_inspect(u);
2021-12-27 21:59:22 +00:00
else if(event->key.keysym.sym == SDLK_F3)
capture_screen();
else if(event->key.keysym.sym == SDLK_F4)
restart(u);
2021-11-08 15:51:09 +00:00
}
static int
console_input(Uxn *u, char c)
{
2022-01-11 22:38:55 +00:00
Device *d = &u->dev[1];
d->dat[0x2] = c;
return uxn_eval(u, GETVECTOR(d));
}
static int
mouse_steal(SDL_Event *event)
{
#ifdef __ANDROID__
int x, y;
event->motion.x = (event->motion.x - gScrDst.x) * (uxn_screen.width + PAD * 2) / gScrDst.w;
event->motion.y = (event->motion.y - gScrDst.y) * (uxn_screen.height + PAD * 2) / gScrDst.h;
x = event->motion.x - PAD;
y = event->motion.y - PAD;
if(x < 0 || x > uxn_screen.width || y < 0 || y > uxn_screen.height) {
if(event->type == SDL_MOUSEBUTTONDOWN) {
if(SDL_IsTextInputActive())
SDL_StopTextInput();
else
SDL_StartTextInput();
}
return 1;
}
#else
(void)event;
#endif
return 0;
}
2021-09-21 22:41:59 +00:00
static int
2021-06-29 13:43:28 +00:00
run(Uxn *u)
2021-02-08 22:18:01 +00:00
{
Device *devsys = &u->dev[0];
2022-01-06 04:44:33 +00:00
redraw();
while(!devsys->dat[0xf]) {
2021-04-05 03:58:47 +00:00
SDL_Event event;
2021-12-29 17:33:23 +00:00
double elapsed, begin;
int force_redraw = 0;
2021-08-05 03:30:57 +00:00
if(!BENCH)
begin = SDL_GetPerformanceCounter();
2021-04-05 03:58:47 +00:00
while(SDL_PollEvent(&event) != 0) {
/* Window */
if(event.type == SDL_QUIT)
return error("Run", "Quit.");
else if(event.type == SDL_WINDOWEVENT) {
int e = event.window.event;
if(e == SDL_WINDOWEVENT_RESTORED || e == SDL_WINDOWEVENT_RESIZED || e == SDL_WINDOWEVENT_EXPOSED) {
#ifdef __ANDROID__
/* rotation does something weird, have to redraw twice */
resized();
2022-01-15 23:58:02 +00:00
redraw();
#endif
force_redraw = 1;
}
} else if(event.type == SDL_DROPFILE) {
set_size(WIDTH, HEIGHT, 0);
start(u, event.drop.file);
SDL_free(event.drop.file);
force_redraw = 1;
}
/* Audio */
2022-01-03 21:29:47 +00:00
else if(event.type >= audio0_event && event.type < audio0_event + POLYPHONY) {
Device *d = devaudio0 + (event.type - audio0_event);
2022-01-11 19:07:25 +00:00
uxn_eval(u, GETVECTOR(d));
2022-01-03 21:29:47 +00:00
}
/* Mouse */
else if(event.type == SDL_MOUSEMOTION && !mouse_steal(&event))
2021-12-28 18:45:34 +00:00
mouse_pos(devmouse,
2021-12-29 17:11:03 +00:00
clamp(event.motion.x - PAD, 0, uxn_screen.width - 1),
clamp(event.motion.y - PAD, 0, uxn_screen.height - 1));
else if(event.type == SDL_MOUSEBUTTONUP && !mouse_steal(&event))
mouse_up(devmouse, SDL_BUTTON(event.button.button));
else if(event.type == SDL_MOUSEBUTTONDOWN && !mouse_steal(&event))
mouse_down(devmouse, SDL_BUTTON(event.button.button));
2021-12-28 19:21:56 +00:00
else if(event.type == SDL_MOUSEWHEEL)
mouse_scroll(devmouse, event.wheel.x, event.wheel.y);
/* Controller */
else if(event.type == SDL_TEXTINPUT)
controller_key(devctrl, event.text.text[0]);
else if(event.type == SDL_KEYDOWN) {
int ksym;
if(get_key(&event))
2021-12-27 21:37:37 +00:00
controller_key(devctrl, get_key(&event));
2021-12-27 21:59:22 +00:00
else if(get_button(&event))
2021-12-27 21:37:37 +00:00
controller_down(devctrl, get_button(&event));
2021-12-27 21:50:39 +00:00
else
2021-12-27 21:37:37 +00:00
do_shortcut(u, &event);
ksym = event.key.keysym.sym;
if(SDL_PeepEvents(&event, 1, SDL_PEEKEVENT, SDL_KEYUP, SDL_KEYUP) == 1 && ksym == event.key.keysym.sym)
break;
} else if(event.type == SDL_KEYUP)
controller_up(devctrl, get_button(&event));
2021-12-27 19:44:57 +00:00
else if(event.type == SDL_JOYAXISMOTION) {
Uint8 vec = get_vector_joystick(&event);
if(!vec)
controller_up(devctrl, (0x03 << (!event.jaxis.axis * 2)) << 4);
else
controller_down(devctrl, (0x01 << ((vec + !event.jaxis.axis * 2) - 1)) << 4);
2021-12-28 19:21:56 +00:00
} else if(event.type == SDL_JOYBUTTONDOWN)
controller_down(devctrl, get_button_joystick(&event));
else if(event.type == SDL_JOYBUTTONUP)
controller_up(devctrl, get_button_joystick(&event));
/* Console */
else if(event.type == stdin_event)
console_input(u, event.cbutton.button);
2021-04-05 03:58:47 +00:00
}
2022-01-08 00:46:50 +00:00
uxn_eval(u, GETVECTOR(devscreen));
2022-01-15 23:58:02 +00:00
if(uxn_screen.fg.changed || uxn_screen.bg.changed || force_redraw)
2022-01-06 04:44:33 +00:00
redraw();
2021-08-05 03:30:57 +00:00
if(!BENCH) {
elapsed = (SDL_GetPerformanceCounter() - begin) / (double)SDL_GetPerformanceFrequency() * 1000.0f;
SDL_Delay(clamp(16.666f - elapsed, 0, 1000));
2021-05-19 07:29:00 +00:00
}
2021-02-08 23:46:52 +00:00
}
2021-09-21 22:41:59 +00:00
return error("Run", "Ended.");
2021-02-08 23:46:52 +00:00
}
int
main(int argc, char **argv)
{
SDL_DisplayMode DM;
2021-02-09 18:58:06 +00:00
Uxn u;
int i, loaded = 0;
2021-11-08 15:51:09 +00:00
if(!init())
return error("Init", "Failed to initialize emulator.");
if(!set_size(WIDTH, HEIGHT, 0))
return error("Window", "Failed to set window size.");
2021-08-30 02:52:12 +00:00
2021-09-22 18:21:57 +00:00
/* set default zoom */
if(SDL_GetCurrentDisplayMode(0, &DM) == 0)
set_zoom(DM.w / 1280);
for(i = 1; i < argc; i++) {
/* get default zoom from flags */
2021-09-21 22:56:42 +00:00
if(strcmp(argv[i], "-s") == 0) {
if(i < argc - 1)
2021-09-30 01:03:56 +00:00
set_zoom(atoi(argv[++i]));
2021-09-21 22:56:42 +00:00
else
return error("Opt", "-s No scale provided.");
} else if(strcmp(argv[i], "-cd") == 0) {
if(i < argc - 1)
chdir(argv[++i]);
else
return error("Opt", "-cd No path provided.");
} else if(!loaded++) {
2021-11-08 17:12:17 +00:00
if(!start(&u, argv[i]))
2021-11-08 15:51:09 +00:00
return error("Boot", "Failed to boot.");
} else {
char *p = argv[i];
while(*p) console_input(&u, *p++);
console_input(&u, '\n');
2021-09-21 22:56:42 +00:00
}
}
2022-01-11 04:35:34 +00:00
if(!loaded && !start(&u, "launcher.rom"))
2021-11-03 03:15:25 +00:00
return error("usage", "uxnemu [-s scale] file.rom");
2021-06-29 13:43:28 +00:00
run(&u);
SDL_Quit();
2021-02-08 22:18:01 +00:00
return 0;
}