mirror of
https://github.com/pruten/shoebill.git
synced 2024-09-28 15:54:35 +00:00
952fe7ae89
- sdl-gui/sdl.c is a tiny, basically working SDL2-based GUI that can compile and run on linux. It still needs PRAM integration and a config file. - Fixed a dumb bug in shoebill_initialize that was causing sporadic crashes - Replaced a million printf() calls with slog(), to make the SDL client run more quietly on the CLI - Added more corruption checking to alloc_pool
424 lines
12 KiB
C
424 lines
12 KiB
C
/*
|
|
* Copyright (c) 2014, Peter Rutenbar <pruten@gmail.com>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
* list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include <pthread.h>
|
|
#include <SDL2/SDL.h>
|
|
#include <SDL2/SDL_opengl.h>
|
|
#include "../core/shoebill.h"
|
|
|
|
rb_tree *keymap;
|
|
static void _init_keyboard_map (void)
|
|
{
|
|
#define mapkeymod(u, a, m) do { \
|
|
assert((a >> 7) == 0); \
|
|
void *value = (void*)(((m) << 8)| (a)); \
|
|
rb_insert(keymap, u, value, NULL); \
|
|
} while (0)
|
|
|
|
#define mapkey(_u, a) mapkeymod(_u, a, 0)
|
|
|
|
keymap = rb_new(p_new_pool(NULL));
|
|
|
|
// Letters
|
|
mapkey('a', 0x00);
|
|
mapkey('b', 0x0b);
|
|
mapkey('c', 0x08);
|
|
mapkey('d', 0x02);
|
|
mapkey('e', 0x0e);
|
|
mapkey('f', 0x03);
|
|
mapkey('g', 0x05);
|
|
mapkey('h', 0x04);
|
|
mapkey('i', 0x22);
|
|
mapkey('j', 0x26);
|
|
mapkey('k', 0x28);
|
|
mapkey('l', 0x25);
|
|
mapkey('m', 0x2e);
|
|
mapkey('n', 0x2d);
|
|
mapkey('o', 0x1f);
|
|
mapkey('p', 0x23);
|
|
mapkey('q', 0x0c);
|
|
mapkey('r', 0x0f);
|
|
mapkey('s', 0x01);
|
|
mapkey('t', 0x11);
|
|
mapkey('u', 0x20);
|
|
mapkey('v', 0x09);
|
|
mapkey('w', 0x0d);
|
|
mapkey('x', 0x07);
|
|
mapkey('y', 0x10);
|
|
mapkey('z', 0x06);
|
|
|
|
// Numbers
|
|
mapkey('0', 0x1d);
|
|
mapkey('1', 0x12);
|
|
mapkey('2', 0x13);
|
|
mapkey('3', 0x14);
|
|
mapkey('4', 0x15);
|
|
mapkey('5', 0x17);
|
|
mapkey('6', 0x16);
|
|
mapkey('7', 0x1a);
|
|
mapkey('8', 0x1c);
|
|
mapkey('9', 0x19);
|
|
|
|
// Top row symbols
|
|
mapkeymod(')', 0x1d, modShift);
|
|
mapkeymod('!', 0x12, modShift);
|
|
mapkeymod('@', 0x13, modShift);
|
|
mapkeymod('#', 0x14, modShift);
|
|
mapkeymod('$', 0x15, modShift);
|
|
mapkeymod('%', 0x17, modShift);
|
|
mapkeymod('^', 0x16, modShift);
|
|
mapkeymod('&', 0x1a, modShift);
|
|
mapkeymod('*', 0x1c, modShift);
|
|
mapkeymod('(', 0x19, modShift);
|
|
|
|
// Other symbols (no shift)
|
|
mapkeymod('`', 0x32, 0);
|
|
mapkeymod('-', 0x1b, 0);
|
|
mapkeymod('=', 0x18, 0);
|
|
mapkeymod('[', 0x21, 0);
|
|
mapkeymod(']', 0x1e, 0);
|
|
mapkeymod('\\', 0x2a, 0);
|
|
mapkeymod(';', 0x29, 0);
|
|
mapkeymod('\'', 0x27, 0);
|
|
mapkeymod(',', 0x2b, 0);
|
|
mapkeymod('.', 0x2f, 0);
|
|
mapkeymod('/', 0x2c, 0);
|
|
|
|
// Other symbols (with shift)
|
|
mapkeymod('~', 0x32, modShift);
|
|
mapkeymod('_', 0x1b, modShift);
|
|
mapkeymod('+', 0x18, modShift);
|
|
mapkeymod('{', 0x21, modShift);
|
|
mapkeymod('}', 0x1e, modShift);
|
|
mapkeymod('|', 0x2a, modShift);
|
|
mapkeymod(':', 0x29, modShift);
|
|
mapkeymod('"', 0x27, modShift);
|
|
mapkeymod('<', 0x2b, modShift);
|
|
mapkeymod('>', 0x2f, modShift);
|
|
mapkeymod('?', 0x2c, modShift);
|
|
|
|
// Function keys
|
|
mapkey(SDLK_F1, 0x7a);
|
|
mapkey(SDLK_F2, 0x78);
|
|
mapkey(SDLK_F3, 0x63);
|
|
mapkey(SDLK_F4, 0x76);
|
|
mapkey(SDLK_F5, 0x60);
|
|
mapkey(SDLK_F6, 0x61);
|
|
mapkey(SDLK_F7, 0x62);
|
|
mapkey(SDLK_F8, 0x64);
|
|
mapkey(SDLK_F9, 0x65);
|
|
mapkey(SDLK_F10, 0x6d);
|
|
mapkey(SDLK_F11, 0x67);
|
|
mapkey(SDLK_F12, 0x6f);
|
|
mapkey(SDLK_F13, 0x69);
|
|
mapkey(SDLK_F14, 0x6b);
|
|
mapkey(SDLK_F15, 0x71);
|
|
|
|
// Arrows
|
|
mapkey(SDLK_UP, 0x3e);
|
|
mapkey(SDLK_DOWN, 0x3d);
|
|
mapkey(SDLK_RIGHT, 0x3c);
|
|
mapkey(SDLK_LEFT, 0x3b);
|
|
|
|
// Delete
|
|
mapkey(SDLK_DELETE, 0x75);
|
|
mapkey(SDLK_BACKSPACE, 0x33);
|
|
mapkey(SDLK_BACKSPACE, 0x33);
|
|
|
|
// Enter, NL, CR
|
|
mapkey(SDLK_RETURN2, 0x24);
|
|
mapkey(SDLK_RETURN, 0x24);
|
|
// mapkey(0x03, 0x24);
|
|
|
|
// Other keys
|
|
mapkey(SDLK_ESCAPE, 0x35); // escape
|
|
mapkey(SDLK_SPACE, 0x31); // space
|
|
mapkey(SDLK_TAB, 0x30); // tab
|
|
}
|
|
|
|
static void _display_frame (SDL_Window *win)
|
|
{
|
|
shoebill_video_frame_info_t frame = shoebill_get_video_frame(9, 0);
|
|
|
|
shoebill_send_vbl_interrupt(9);
|
|
|
|
glDrawBuffer(GL_BACK);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
glClearColor(0, 0, 0, 1.0);
|
|
|
|
glViewport(0, 0, frame.width, frame.height);
|
|
glRasterPos2i(0, frame.height);
|
|
glPixelStorei(GL_UNPACK_LSB_FIRST, GL_TRUE);
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
|
|
glPixelZoom(1.0, -1.0);
|
|
|
|
glDrawPixels(frame.width,
|
|
frame.height,
|
|
GL_RGBA,
|
|
GL_UNSIGNED_BYTE,
|
|
frame.buf);
|
|
|
|
SDL_GL_SwapWindow(win);
|
|
}
|
|
|
|
struct {
|
|
const char *scsi_path[8];
|
|
const char *rom_path;
|
|
const char *relative_unix_path;
|
|
|
|
uint32_t height, width;
|
|
uint32_t ram_megabytes;
|
|
_Bool verbose;
|
|
} user_params;
|
|
|
|
#define equals_arg(name) keylen = strlen(name); value = argv[i]+keylen; if (strncmp((name), argv[i], keylen) == 0)
|
|
|
|
static void _init_user_params (int argc, char **argv)
|
|
{
|
|
char *key;
|
|
uint32_t i;
|
|
for (i=0; i<8; i++)
|
|
user_params.scsi_path[i] = NULL;
|
|
|
|
user_params.rom_path = "macii.rom";
|
|
user_params.relative_unix_path = "/unix";
|
|
|
|
user_params.height = 640;
|
|
user_params.width = 800;
|
|
user_params.ram_megabytes = 16;
|
|
user_params.verbose = 1;
|
|
|
|
|
|
for (i=1; i<argc; i++) {
|
|
key = "ram=";
|
|
if (strncmp(key, argv[i], strlen(key)) == 0) {
|
|
user_params.ram_megabytes = strtoul(argv[i]+strlen(key), NULL, 10);
|
|
continue;
|
|
}
|
|
|
|
key = "height=";
|
|
if (strncmp(key, argv[i], strlen(key)) == 0) {
|
|
user_params.height = strtoul(argv[i]+strlen(key), NULL, 10);
|
|
continue;
|
|
}
|
|
|
|
key = "width=";
|
|
if (strncmp(key, argv[i], strlen(key)) == 0) {
|
|
user_params.width = strtoul(argv[i]+strlen(key), NULL, 10);
|
|
continue;
|
|
}
|
|
|
|
key = "verbose=";
|
|
if (strncmp(key, argv[i], strlen(key)) == 0) {
|
|
user_params.verbose = strtoul(argv[i]+strlen(key), NULL, 10);
|
|
continue;
|
|
}
|
|
|
|
key = "rom=";
|
|
if (strncmp(key, argv[i], strlen(key)) == 0) {
|
|
user_params.rom_path = argv[i] + strlen(key);
|
|
continue;
|
|
}
|
|
|
|
key = "unix-path=";
|
|
if (strncmp(key, argv[i], strlen(key)) == 0) {
|
|
user_params.relative_unix_path = argv[i] + strlen(key);
|
|
continue;
|
|
}
|
|
|
|
if ((strncmp("disk", argv[i], 4) == 0) && (isdigit(argv[i][4])) && (argv[i][5] == '=')) {
|
|
uint8_t scsi_num = argv[i][4] - '0';
|
|
if (scsi_num < 7) {
|
|
user_params.scsi_path[scsi_num] = &argv[i][6];
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
static _Bool _setup_shoebill (void)
|
|
{
|
|
uint32_t i;
|
|
shoebill_config_t config;
|
|
|
|
bzero(&config, sizeof(shoebill_config_t));
|
|
|
|
config.aux_verbose = user_params.verbose;
|
|
config.ram_size = user_params.ram_megabytes * 1024 * 1024;
|
|
config.aux_kernel_path = user_params.relative_unix_path;
|
|
config.rom_path = user_params.rom_path;
|
|
|
|
for (i=0; i<7; i++)
|
|
config.scsi_devices[i].path = user_params.scsi_path[i];
|
|
|
|
if (!shoebill_initialize(&config)) {
|
|
printf("%s\n", config.error_msg);
|
|
return 0;
|
|
}
|
|
|
|
shoebill_install_video_card(&config,
|
|
9, // slotnum
|
|
user_params.width, // 1024,
|
|
user_params.height); // 768,
|
|
|
|
shoebill_start();
|
|
return 1;
|
|
}
|
|
|
|
static void _handle_key_event (SDL_Event *event)
|
|
{
|
|
const SDL_Keycode sym = event->key.keysym.sym;
|
|
const _Bool key_down = (event->type == SDL_KEYDOWN);
|
|
const SDL_Keymod sdl_mod = SDL_GetModState();
|
|
uint16_t adb_mod = 0;
|
|
void *_value;
|
|
|
|
if (sdl_mod & KMOD_SHIFT) adb_mod |= modShift;
|
|
if (sdl_mod & KMOD_CTRL) adb_mod |= modControl;
|
|
if (sdl_mod & KMOD_ALT) adb_mod |= modOption;
|
|
if (sdl_mod & KMOD_GUI) adb_mod |= modCommand;
|
|
if (sdl_mod & KMOD_CAPS) adb_mod |= modCapsLock;
|
|
|
|
if (rb_find(keymap, sym, &_value)) {
|
|
const uint16_t value = (uint16_t)_value;
|
|
shoebill_key_modifier((value >> 8) | adb_mod);
|
|
shoebill_key(key_down, value & 0xff);
|
|
}
|
|
}
|
|
|
|
int main (int argc, char **argv)
|
|
{
|
|
const uint32_t frame_ticks = 1000 / 60;
|
|
uint32_t last_frame_ticks;
|
|
_Bool capture_cursor;
|
|
|
|
_init_keyboard_map();
|
|
_init_user_params(argc, argv);
|
|
if (!_setup_shoebill())
|
|
return 0;
|
|
|
|
shoebill_video_frame_info_t frame = shoebill_get_video_frame(9, 1);
|
|
|
|
SDL_Init(SDL_INIT_VIDEO);
|
|
|
|
SDL_Window *win = SDL_CreateWindow("Shoebill",
|
|
SDL_WINDOWPOS_UNDEFINED,
|
|
SDL_WINDOWPOS_UNDEFINED,
|
|
frame.width, frame.height,
|
|
SDL_WINDOW_OPENGL);
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
|
SDL_GLContext glctx = SDL_GL_CreateContext(win);
|
|
|
|
glShadeModel(GL_FLAT);
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
glClearColor(0.5, 0.5, 0.5, 1.0);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
glOrtho(0, frame.width, 0, frame.height, -1.0, 1.0);
|
|
|
|
capture_cursor = 1;
|
|
SDL_ShowCursor(0);
|
|
SDL_SetRelativeMouseMode(1);
|
|
|
|
last_frame_ticks = SDL_GetTicks();
|
|
while (1) {
|
|
const uint32_t now = SDL_GetTicks();
|
|
uint32_t ticks_to_next_frame;
|
|
SDL_Event event;
|
|
|
|
if ((now - last_frame_ticks) >= frame_ticks) {
|
|
_display_frame(win);
|
|
last_frame_ticks = now;
|
|
ticks_to_next_frame = frame_ticks;
|
|
}
|
|
else
|
|
ticks_to_next_frame = frame_ticks - (now - last_frame_ticks);
|
|
|
|
event.type = SDL_USEREVENT;
|
|
SDL_WaitEventTimeout(&event, ticks_to_next_frame);
|
|
|
|
switch (event.type) {
|
|
case SDL_QUIT:
|
|
exit(0);
|
|
|
|
case SDL_MOUSEBUTTONDOWN: {
|
|
if ((event.button.button == SDL_BUTTON_LEFT) && capture_cursor)
|
|
shoebill_mouse_click(1);
|
|
break;
|
|
}
|
|
|
|
case SDL_MOUSEBUTTONUP: {
|
|
// If the cursor isn't captured, then any click will capture it
|
|
if (!capture_cursor)
|
|
capture_cursor = 1;
|
|
// If the cursor is captured, then left clicks get sent to the OS
|
|
else if (event.button.button == SDL_BUTTON_LEFT)
|
|
shoebill_mouse_click(0);
|
|
// If the cursor is captured, then right clicks will uncapture it
|
|
else if ((event.button.button == SDL_BUTTON_RIGHT) && capture_cursor)
|
|
capture_cursor = 0;
|
|
break;
|
|
}
|
|
|
|
case SDL_MOUSEMOTION: {
|
|
if (capture_cursor) {
|
|
_Bool down = event.motion.state & SDL_BUTTON(SDL_BUTTON_LEFT);
|
|
shoebill_mouse_click(down);
|
|
shoebill_mouse_move_delta(event.motion.xrel, event.motion.yrel);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SDL_KEYDOWN:
|
|
case SDL_KEYUP:
|
|
if (!event.key.repeat)
|
|
_handle_key_event(&event);
|
|
break;
|
|
}
|
|
|
|
if (capture_cursor) {
|
|
SDL_ShowCursor(0);
|
|
SDL_SetRelativeMouseMode(1);
|
|
}
|
|
else {
|
|
SDL_ShowCursor(1);
|
|
SDL_SetRelativeMouseMode(0);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|