mirror of
https://github.com/libretro/oberon-risc-emu.git
synced 2025-03-02 13:35:46 +00:00
Full-screen display
Use --fullscreen command line option or press F11 to toggle.
This commit is contained in:
parent
40ce3af070
commit
66dfeb2ada
2
Makefile
2
Makefile
@ -1,7 +1,7 @@
|
||||
|
||||
CFLAGS = -g -Os -Wall -Wextra -Wconversion -Wno-sign-conversion
|
||||
|
||||
RISC_CFLAGS = $(CFLAGS) -std=c99 `sdl2-config --cflags --libs`
|
||||
RISC_CFLAGS = $(CFLAGS) -std=c99 `sdl2-config --cflags --libs` -lm
|
||||
|
||||
RISC_SOURCE = \
|
||||
sdl-main.c \
|
||||
|
@ -22,6 +22,7 @@ Current emulation status
|
||||
|
||||
* Display
|
||||
* OK. You can adjust the colors by editing `sdl-main.c`.
|
||||
* Use F11 to toggle full screne display.
|
||||
|
||||
* SD-Card
|
||||
* Very inaccurate, but good enough for Oberon. If you're going to
|
||||
|
142
sdl-main.c
142
sdl-main.c
@ -2,7 +2,8 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/time.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <SDL.h>
|
||||
#include "risc.h"
|
||||
#include "sdl-ps2.h"
|
||||
@ -18,14 +19,32 @@ static uint32_t BLACK = 0x657b83, WHITE = 0xfdf6e3;
|
||||
//static uint32_t BLACK = 0x0000FF, WHITE = 0xFFFF00;
|
||||
//static uint32_t BLACK = 0x000000, WHITE = 0x00FF00;
|
||||
|
||||
void init_texture(SDL_Texture *texture);
|
||||
void update_texture(uint32_t *framebuffer, SDL_Texture *texture);
|
||||
|
||||
static void init_texture(SDL_Texture *texture);
|
||||
static void update_texture(uint32_t *framebuffer, SDL_Texture *texture);
|
||||
|
||||
static int clamp(int x, int min, int max);
|
||||
static SDL_Rect scale_display(SDL_Window *window, double *scale);
|
||||
|
||||
static void usage() {
|
||||
fprintf(stderr, "Usage: risc [--fullscreen] disk-file-name\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[]) {
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: risc disk-file-name\n");
|
||||
return 1;
|
||||
bool fullscreen = false;
|
||||
while (argc > 1 && argv[1][0] == '-') {
|
||||
if (strcmp(argv[1], "--fullscreen") == 0) {
|
||||
fullscreen = true;
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
argc--; argv++;
|
||||
}
|
||||
if (argc != 2) {
|
||||
usage();
|
||||
}
|
||||
|
||||
struct RISC *risc = risc_new(argv[1]);
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
|
||||
@ -36,12 +55,29 @@ int main (int argc, char *argv[]) {
|
||||
|
||||
SDL_EnableScreenSaver();
|
||||
SDL_ShowCursor(false);
|
||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best");
|
||||
|
||||
int window_pos = SDL_WINDOWPOS_UNDEFINED;
|
||||
int window_flags = SDL_WINDOW_HIDDEN;
|
||||
if (fullscreen) {
|
||||
window_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
// Search for a 1024x768 display in multi-monitor configurations
|
||||
int display_cnt = SDL_GetNumVideoDisplays();
|
||||
for (int i = 0; i < display_cnt; i++) {
|
||||
SDL_Rect bounds;
|
||||
SDL_GetDisplayBounds(i, &bounds);
|
||||
if (bounds.w >= SCREEN_WIDTH && bounds.h == SCREEN_HEIGHT) {
|
||||
window_pos = SDL_WINDOWPOS_UNDEFINED_DISPLAY(i);
|
||||
if (bounds.w == SCREEN_WIDTH)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Window *window = SDL_CreateWindow("Project Oberon",
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
window_pos, window_pos,
|
||||
SCREEN_WIDTH, SCREEN_HEIGHT,
|
||||
SDL_WINDOW_HIDDEN);
|
||||
window_flags);
|
||||
if (window == NULL) {
|
||||
fprintf(stderr, "Could not create window: %s\n", SDL_GetError());
|
||||
return 1;
|
||||
@ -62,36 +98,73 @@ int main (int argc, char *argv[]) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
double display_scale;
|
||||
SDL_Rect display_rect = scale_display(window, &display_scale);
|
||||
init_texture(texture);
|
||||
SDL_RenderCopy(renderer, texture, NULL, NULL);
|
||||
SDL_RenderPresent(renderer);
|
||||
SDL_ShowWindow(window);
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_RenderCopy(renderer, texture, NULL, &display_rect);
|
||||
SDL_RenderPresent(renderer);
|
||||
|
||||
bool done = false;
|
||||
SDL_Event event;
|
||||
bool mouse_was_offscreen = false;
|
||||
while (!done) {
|
||||
uint32_t frame_start = SDL_GetTicks();
|
||||
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
switch (event.type) {
|
||||
case SDL_QUIT:
|
||||
case SDL_QUIT: {
|
||||
done = true;
|
||||
}
|
||||
|
||||
case SDL_WINDOWEVENT: {
|
||||
if (event.window.event == SDL_WINDOWEVENT_RESIZED) {
|
||||
display_rect = scale_display(window, &display_scale);
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEMOTION:
|
||||
risc_mouse_moved(risc, event.motion.x, SCREEN_HEIGHT - event.motion.y - 1);
|
||||
}
|
||||
|
||||
case SDL_MOUSEMOTION: {
|
||||
int scaled_x = (int)round((event.motion.x - display_rect.x) * display_scale);
|
||||
int scaled_y = (int)round((event.motion.y - display_rect.y) * display_scale);
|
||||
int x = clamp(scaled_x, 0, SCREEN_WIDTH - 1);
|
||||
int y = clamp(scaled_y, 0, SCREEN_HEIGHT - 1);
|
||||
bool mouse_is_offscreen = x != scaled_x || y != scaled_y;
|
||||
if (mouse_is_offscreen != mouse_was_offscreen) {
|
||||
SDL_ShowCursor(mouse_is_offscreen);
|
||||
mouse_was_offscreen = mouse_is_offscreen;
|
||||
}
|
||||
risc_mouse_moved(risc, x, SCREEN_HEIGHT - y - 1);
|
||||
break;
|
||||
}
|
||||
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
case SDL_MOUSEBUTTONUP: {
|
||||
risc_mouse_button(risc, event.button.button,
|
||||
event.button.state == SDL_PRESSED);
|
||||
break;
|
||||
}
|
||||
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP: {
|
||||
if (event.key.keysym.sym == SDLK_F12) {
|
||||
// F12 = Oberon reset
|
||||
if (event.key.state == SDL_PRESSED) {
|
||||
risc_reset(risc);
|
||||
}
|
||||
} else if (event.key.keysym.sym == SDLK_F11) {
|
||||
// F11 = Toggle fullscreen
|
||||
if (event.key.state == SDL_PRESSED) {
|
||||
fullscreen ^= true;
|
||||
if (fullscreen) {
|
||||
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
|
||||
} else {
|
||||
SDL_SetWindowFullscreen(window, 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Pass other keys to Oberon
|
||||
uint8_t scancode[MAX_PS2_CODE_LEN];
|
||||
int len = ps2_encode(event.key.keysym.scancode,
|
||||
event.key.state == SDL_PRESSED,
|
||||
@ -107,7 +180,8 @@ int main (int argc, char *argv[]) {
|
||||
risc_run(risc, CPU_HZ / FPS);
|
||||
|
||||
update_texture(risc_get_framebuffer_ptr(risc), texture);
|
||||
SDL_RenderCopy(renderer, texture, NULL, NULL);
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_RenderCopy(renderer, texture, NULL, &display_rect);
|
||||
SDL_RenderPresent(renderer);
|
||||
|
||||
uint32_t frame_end = SDL_GetTicks();
|
||||
@ -116,15 +190,43 @@ int main (int argc, char *argv[]) {
|
||||
SDL_Delay(delay);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int clamp(int x, int min, int max) {
|
||||
if (x < min) return min;
|
||||
if (x > max) return max;
|
||||
return x;
|
||||
}
|
||||
|
||||
static SDL_Rect scale_display(SDL_Window *window, double *display_scale) {
|
||||
int win_w, win_h;
|
||||
SDL_GetWindowSize(window, &win_w, &win_h);
|
||||
double oberon_aspect = (double)SCREEN_WIDTH / SCREEN_HEIGHT;
|
||||
double window_aspect = (double)win_w / win_h;
|
||||
if (fabs(oberon_aspect - window_aspect) < 0.0001) {
|
||||
// Aspect ratios are equal
|
||||
*display_scale = (double)SCREEN_WIDTH / win_w;
|
||||
return (SDL_Rect){ .x = 0, .y = 0, .w = win_w, .h = win_h };
|
||||
}
|
||||
else if (oberon_aspect > window_aspect) {
|
||||
// Oberon display is wider than our window -- letterbox it
|
||||
*display_scale = (double)SCREEN_WIDTH / win_w;
|
||||
int h = (int)ceil(SCREEN_HEIGHT / *display_scale);
|
||||
return (SDL_Rect){ .x = 0, .y = (win_h - h) / 2, .w = win_w, .h = h };
|
||||
} else {
|
||||
// Oberon display is taller than our window
|
||||
*display_scale = (double)SCREEN_HEIGHT / win_h;
|
||||
int w = (int)ceil(SCREEN_WIDTH / *display_scale);
|
||||
return (SDL_Rect){ .x = (win_w - w) / 2, .y = 0, .w = w, .h = win_h };
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t cache[SCREEN_WIDTH * SCREEN_HEIGHT / 32];
|
||||
static uint32_t buffer[SCREEN_WIDTH * SCREEN_HEIGHT];
|
||||
|
||||
void init_texture(SDL_Texture *texture) {
|
||||
static void init_texture(SDL_Texture *texture) {
|
||||
memset(cache, 0, sizeof(cache));
|
||||
for (size_t i = 0; i < sizeof(buffer)/sizeof(buffer[0]); ++i) {
|
||||
buffer[i] = BLACK;
|
||||
@ -132,7 +234,7 @@ void init_texture(SDL_Texture *texture) {
|
||||
SDL_UpdateTexture(texture, NULL, buffer, SCREEN_WIDTH * 4);
|
||||
}
|
||||
|
||||
void update_texture(uint32_t *framebuffer, SDL_Texture *texture) {
|
||||
static void update_texture(uint32_t *framebuffer, SDL_Texture *texture) {
|
||||
// TODO: move dirty rectangle tracking into emulator core?
|
||||
int dirty_y1 = SCREEN_HEIGHT;
|
||||
int dirty_y2 = 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user