Full-screen display

Use --fullscreen command line option or press F11 to toggle.
This commit is contained in:
Peter De Wachter 2014-03-23 15:03:39 +01:00
parent 40ce3af070
commit 66dfeb2ada
3 changed files with 124 additions and 21 deletions

View File

@ -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 \

View File

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

View File

@ -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;