Created
January 29, 2016 15:08
-
-
Save digarok/b47f29b5a8d2551b8432 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
GSport - an Apple //gs Emulator | |
Copyright (C) 2010 - 2012 by GSport contributors | |
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey | |
This program is free software; you can redistribute it and/or modify it | |
under the terms of the GNU General Public License as published by the | |
Free Software Foundation; either version 2 of the License, or (at your | |
option) any later version. | |
This program is distributed in the hope that it will be useful, but | |
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
for more details. | |
You should have received a copy of the GNU General Public License along | |
with this program; if not, write to the Free Software Foundation, Inc., | |
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
*/ | |
// This is an experimental video driver for the KEGS/GSport emulator. | |
// It requires SDL2 libraries to build. I've tested on Mac, but should | |
// be easy to port to other platforms. -DagenBrock | |
// @todo: mouse clip bugs.. great western shootout. | |
// @todo: force refresh after screen mode change | |
#include "SDL.h" | |
#include <stdbool.h> | |
#include <time.h> | |
#include <stdlib.h> | |
#include <signal.h> | |
#include "defc.h" | |
// BITMASKS | |
#define ShiftMask 1 | |
#define ControlMask 4 | |
#define LockMask 2 | |
int g_use_shmem = 0; | |
int g_num_check_input_calls = 0; | |
int g_check_input_flush_rate = 2; | |
int g_win_status_debug = 0; // Current visibility of status lines. | |
int g_win_status_debug_request = 0; // Desired visibility of status lines. | |
int g_screen_mdepth = 0; | |
int kb_shift_control_state = 0; | |
extern int g_screen_depth; | |
extern int g_quit_sim_now; | |
extern int g_border_sides_refresh_needed; | |
extern int g_border_special_refresh_needed; | |
extern int g_status_refresh_needed; | |
extern int g_lores_colors[]; | |
extern int g_a2vid_palette; | |
extern int g_installed_full_superhires_colormap; | |
extern char *g_status_ptrs[MAX_STATUS_LINES]; | |
extern word32 g_a2_screen_buffer_changed; | |
extern word32 g_full_refresh_needed; | |
extern word32 g_palette_8to1624[256]; | |
extern word32 g_a2palette_8to1624[256]; | |
extern Kimage g_mainwin_kimage; | |
SDL_Window *window; // Declare a pointer | |
SDL_Renderer *renderer; | |
SDL_Texture *texture; | |
void dev_video_init_sdl(); | |
void handle_sdl_key_event(SDL_Event event); | |
void check_input_events_sdl(); | |
int g_num_a2_keycodes = 0; | |
int a2_key_to_sdlkeycode[][3] = { | |
{ 0x12, SDLK_1, 0}, | |
{ 0x35, SDLK_ESCAPE,0 }, | |
{ 0x7a, SDLK_F1, 0 }, | |
{ 0x78, SDLK_F2, 0 }, | |
{ 0x63, SDLK_F3, 0 }, | |
{ 0x76, SDLK_F4, 0 }, | |
{ 0x60, SDLK_F5, 0 }, | |
{ 0x61, SDLK_F6, 0 }, | |
{ 0x62, SDLK_F7, 0 }, | |
{ 0x64, SDLK_F8, 0 }, | |
{ 0x65, SDLK_F9, 0 }, | |
{ 0x6d, SDLK_F10, 0 }, | |
{ 0x67, SDLK_F11, 0 }, | |
{ 0x6f, SDLK_F12, 0 }, | |
{ 0x69, SDLK_F13, 0 }, | |
{ 0x6b, SDLK_F14, 0 }, | |
{ 0x71, SDLK_F15, 0 }, | |
{ 0x7f, SDLK_PAUSE, 0 }, | |
{ 0x32, '`', '~' }, /* Key number 18? */ | |
{ 0x12, '1', '!' }, | |
{ 0x13, '2', '@' }, | |
{ 0x14, '3', '#' }, | |
{ 0x15, '4', '$' }, | |
{ 0x17, '5', '%' }, | |
{ 0x16, '6', '^' }, | |
{ 0x1a, '7', '&' }, | |
{ 0x1c, '8', '*' }, | |
{ 0x19, '9', '(' }, | |
{ 0x1d, '0', ')' }, | |
{ 0x1b, '-', '_' }, | |
{ 0x18, '=', '+' }, | |
{ 0x33, SDLK_BACKSPACE, 0 }, | |
{ 0x72, SDLK_INSERT, 0 }, /* Help? XK_Help */ | |
/* { 0x73, XK_Home, 0 }, alias XK_Home to be XK_KP_Equal! */ | |
{ 0x74, SDLK_PAGEUP, 0 }, | |
{ 0x47, SDLK_NUMLOCKCLEAR, 0 }, /* Clear, XK_Clear */ | |
{ 0x51, SDLK_KP_EQUALS, 0 }, /* Note XK_Home alias! XK_Home */ | |
{ 0x4b, SDLK_KP_DIVIDE, 0 }, | |
{ 0x43, SDLK_KP_MULTIPLY, 0 }, | |
{ 0x30, SDLK_TAB, 0 }, | |
{ 0x0c, 'q', 'Q' }, | |
{ 0x0d, 'w', 'W' }, | |
{ 0x0e, 'e', 'E' }, | |
{ 0x0f, 'r', 'R' }, | |
{ 0x11, 't', 'T' }, | |
{ 0x10, 'y', 'Y' }, | |
{ 0x20, 'u', 'U' }, | |
{ 0x22, 'i', 'I' }, | |
{ 0x1f, 'o', 'O' }, | |
{ 0x23, 'p', 'P' }, | |
{ 0x21, '[', '{' }, | |
{ 0x1e, ']', '}' }, | |
{ 0x2a, 0x5c, '|' }, /* backslash, bar */ | |
{ 0x75, SDLK_DELETE, 0 }, | |
{ 0x77, SDLK_END, 0 }, | |
{ 0x79, SDLK_PAGEDOWN, 0 }, | |
{ 0x59, SDLK_KP_7, 0 }, | |
{ 0x5b, SDLK_KP_8, 0 }, | |
{ 0x5c, SDLK_KP_9, 0 }, | |
{ 0x4e, SDLK_KP_MINUS, 0 }, | |
{ 0x39, SDLK_CAPSLOCK, 0 }, | |
{ 0x00, 'a', 'A' }, | |
{ 0x01, 's', 'S' }, | |
{ 0x02, 'd', 'D' }, | |
{ 0x03, 'f', 'F' }, | |
{ 0x05, 'g', 'G' }, | |
{ 0x04, 'h', 'H' }, | |
{ 0x26, 'j', 'J' }, | |
{ 0x28, 'k', 'K' }, | |
{ 0x25, 'l', 'L' }, | |
{ 0x29, ';', ':' }, | |
{ 0x27, 0x27, '"' }, /* single quote */ | |
{ 0x24, SDLK_RETURN, 0 }, | |
{ 0x56, SDLK_KP_4, SDLK_LEFT}, | |
{ 0x57, SDLK_KP_5, 0 }, | |
{ 0x58, SDLK_KP_6, SDLK_RIGHT }, | |
{ 0x45, SDLK_KP_PLUS, 0 }, | |
{ 0x38, SDLK_LSHIFT, SDLK_RSHIFT }, | |
{ 0x06, 'z', 'Z' }, | |
{ 0x07, 'x', 'X' }, | |
{ 0x08, 'c', 'C' }, | |
{ 0x09, 'v', 'V' }, | |
{ 0x0b, 'b', 'B' }, | |
{ 0x2d, 'n', 'N' }, | |
{ 0x2e, 'm', 'M' }, | |
{ 0x2b, ',', '<' }, | |
{ 0x2f, '.', '>' }, | |
{ 0x2c, '/', '?' }, | |
{ 0x3e, SDLK_UP, 0 }, | |
{ 0x53, SDLK_KP_1, 0 }, | |
{ 0x54, SDLK_KP_2, SDLK_DOWN }, | |
{ 0x55, SDLK_KP_3, 0 }, | |
{ 0x36, SDLK_RCTRL, SDLK_LCTRL }, | |
{ 0x3a, SDLK_LALT, SDLK_RALT }, /* Option */ | |
{ 0x37, SDLK_LGUI, SDLK_RGUI }, /* Command */ | |
{ 0x31, ' ', 0 }, | |
{ 0x3b, SDLK_LEFT, 0 }, | |
{ 0x3d, SDLK_DOWN, 0 }, | |
{ 0x3c, SDLK_RIGHT, 0 }, | |
{ 0x52, SDLK_KP_0, 0 }, | |
{ 0x41, SDLK_KP_PERIOD, 0 }, | |
{ 0x4c, SDLK_KP_ENTER, 0 }, | |
{ -1, -1, -1 } | |
}; | |
int | |
main(int argc, char **argv) | |
{ | |
return gsportmain(argc, argv); | |
} | |
/// Queries the Screen to see if it's set to Fullscreen or Not | |
/// @return SDL_FALSE if windowed, SDL_TRUE if fullscreen | |
SDL_bool IsFullScreen(SDL_Window *win) | |
{ | |
Uint32 flags = SDL_GetWindowFlags(win); | |
if (flags & SDL_WINDOW_FULLSCREEN) return SDL_TRUE; // return SDL_TRUE if fullscreen | |
return SDL_FALSE; // Return SDL_FALSE if windowed | |
} | |
void | |
dev_video_init() | |
{ | |
word32 lores_col; | |
// build keycode map ?? | |
g_num_a2_keycodes = 0; | |
int i; | |
int keycode; | |
int tmp_array[0x80]; | |
for(i = 0; i <= 0x7f; i++) { | |
tmp_array[i] = 0; | |
} | |
for(i = 0; i < 0x7f; i++) { | |
keycode = a2_key_to_sdlkeycode[i][0]; | |
if(keycode < 0) { | |
g_num_a2_keycodes = i; | |
break; | |
} else if(keycode > 0x7f) { | |
printf("a2_key_to_xsym[%d] = %02x!\n", i, keycode); | |
exit(2); | |
} else { | |
if(tmp_array[keycode]) { | |
printf("a2_key_to_x[%d] = %02x used by %d\n", | |
i, keycode, tmp_array[keycode] - 1); | |
} | |
tmp_array[keycode] = i + 1; | |
} | |
} | |
// This actually creates our window | |
dev_video_init_sdl(); | |
// @todo DANGER DANGER. HARD CODING THESE.. there was logic for stepping values in xdriver | |
g_screen_depth = 24; | |
g_screen_mdepth =32; | |
video_get_kimages(); | |
video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth,g_screen_mdepth); | |
for(i = 0; i < 256; i++) { | |
//g_xcolor_a2vid_array[i].pixel = i; | |
lores_col = g_lores_colors[i & 0xf]; | |
video_update_color_raw(i, lores_col); | |
g_a2palette_8to1624[i] = g_palette_8to1624[i]; | |
} | |
} | |
// Initialize our SDL window and texture | |
void | |
dev_video_init_sdl() | |
{ | |
SDL_Init(SDL_INIT_VIDEO); // Initialize SDL2 | |
// Create an application window with the following settings: | |
window = SDL_CreateWindow( | |
"GSPLUS V.0", // window title | |
SDL_WINDOWPOS_UNDEFINED, // initial x position | |
SDL_WINDOWPOS_UNDEFINED, // initial y position | |
BASE_WINDOW_WIDTH, // width, in pixels | |
X_A2_WINDOW_HEIGHT, // height, in pixels | |
SDL_WINDOW_OPENGL // flags - see below | |
); | |
// Check that the window was successfully created | |
if (window == NULL) { | |
// In the case that the window could not be made... | |
printf("Could not create window: %s\n", SDL_GetError()); | |
//@todo die, i guess | |
} else { | |
printf("SDL Window has been created\n"); | |
} | |
renderer = SDL_CreateRenderer(window, -1, 0); | |
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); // make the scaled rendering look smoother. | |
// SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best"); // make the scaled rendering look smoother. | |
SDL_RenderSetLogicalSize(renderer, BASE_WINDOW_WIDTH, X_A2_WINDOW_HEIGHT); | |
texture = SDL_CreateTexture(renderer, | |
SDL_PIXELFORMAT_ARGB8888, | |
SDL_TEXTUREACCESS_STREAMING, | |
BASE_WINDOW_WIDTH, X_A2_WINDOW_HEIGHT); | |
// The window is open: could enter program loop here (see SDL_PollEvent()) | |
SDL_ShowCursor(SDL_DISABLE); | |
} | |
// Copy a rect to our SDL window | |
void sdl_push_kimage(Kimage *kimage_ptr, | |
int destx, int desty, int srcx, int srcy, int width, int height) | |
{ | |
byte *src_ptr; | |
int pixel_size = 4; | |
src_ptr = kimage_ptr->data_ptr + (srcy * kimage_ptr->width_act + srcx) * pixel_size; | |
//src_ptr = kimage_ptr->data_ptr; | |
SDL_Rect dstrect; | |
dstrect.x = destx; | |
dstrect.y = desty; | |
dstrect.w = width; | |
dstrect.h = height; | |
int pitch = 640; | |
if (width < 560) { | |
pitch = EFF_BORDER_WIDTH; | |
// This is another bad hack. Possibly not cross platform. | |
pitch = BORDER_WIDTH+72; | |
//printf("EFF_BORDER_WIDTH : %d" ,EFF_BORDER_WIDTH); | |
} | |
//SDL_UpdateTexture(texture, NULL, src_ptr, 640 * sizeof (Uint32)); | |
SDL_UpdateTexture(texture, &dstrect, src_ptr, pitch*4 ); | |
SDL_RenderClear(renderer); | |
SDL_RenderCopy(renderer, texture, NULL, NULL); | |
SDL_RenderPresent(renderer); | |
} | |
void set_refresh_needed() { | |
g_a2_screen_buffer_changed = -1; | |
g_full_refresh_needed = -1; | |
g_border_sides_refresh_needed = 1; | |
g_border_special_refresh_needed = 1; | |
g_status_refresh_needed = 1; | |
} | |
void | |
x_get_kimage(Kimage *kimage_ptr) { | |
byte *data; | |
int width; | |
int height; | |
int depth; | |
width = kimage_ptr->width_req; | |
height = kimage_ptr->height; | |
depth = kimage_ptr->depth; | |
// this might be too big!!! I had it at depth/3 but it segfaults | |
data = malloc(width*height*(depth/4)); | |
kimage_ptr->data_ptr = data; | |
} | |
void | |
check_input_events() | |
{ | |
check_input_events_sdl(); | |
} | |
void | |
check_input_events_sdl() | |
{ | |
// @todo: make sure it's not queueing events / processing full queue each call | |
int motion = 0; | |
SDL_Event event; | |
while (SDL_PollEvent(&event)) { | |
switch( event.type ){ | |
case SDL_KEYDOWN: | |
case SDL_KEYUP: | |
handle_sdl_key_event(event); | |
break; | |
case SDL_MOUSEMOTION: | |
case SDL_MOUSEBUTTONUP: | |
case SDL_MOUSEBUTTONDOWN: | |
motion |= handle_sdl_mouse_motion_event(event); | |
break; | |
case SDL_QUIT: | |
//quit = 1; /* SDL_QUIT event (window close) */ | |
SDL_DestroyWindow(window); | |
iwm_shut(); | |
// Clean up | |
SDL_Quit(); | |
my_exit(1); | |
break; | |
default: | |
break; | |
} | |
} | |
} | |
int | |
sdl_keysym_to_a2code(int keysym, int is_up) | |
{ | |
int i; | |
if(keysym == 0) { | |
return -1; | |
} | |
if((keysym == SDLK_LSHIFT) || (keysym == SDLK_RSHIFT)) { | |
if(is_up) { | |
kb_shift_control_state &= ~ShiftMask; | |
} else { | |
kb_shift_control_state |= ShiftMask; | |
} | |
} | |
if(keysym == SDLK_CAPSLOCK) { | |
if(is_up) { | |
kb_shift_control_state &= ~LockMask; | |
} else { | |
kb_shift_control_state |= LockMask; | |
} | |
} | |
if((keysym == SDLK_LCTRL) || (keysym == SDLK_RCTRL)) { | |
if(is_up) { | |
kb_shift_control_state &= ~ControlMask; | |
} else { | |
kb_shift_control_state |= ControlMask; | |
} | |
} | |
/* Look up Apple 2 keycode */ | |
for(i = g_num_a2_keycodes - 1; i >= 0; i--) { | |
if((keysym == a2_key_to_sdlkeycode[i][1]) || | |
(keysym == a2_key_to_sdlkeycode[i][2])) { | |
return a2_key_to_sdlkeycode[i][0]; | |
} | |
} | |
return -1; | |
} | |
void | |
handle_sdl_key_event(SDL_Event event) | |
{ | |
int state_xor; | |
int state = 0; | |
int is_up; | |
int mod = event.key.keysym.mod; | |
// simulate xmask style here | |
// @todo: this can probably all be refactored now that X is gone | |
//state = state & (ControlMask | LockMask | ShiftMask); | |
// when mod key is first press, comes as event, otherwise just a modifier | |
if( mod & KMOD_LCTRL || mod & KMOD_RCTRL || | |
event.type == (SDL_KEYDOWN && (event.key.keysym.sym == SDLK_LCTRL || event.key.keysym.sym == SDLK_RCTRL))) { | |
state = state | ControlMask; | |
} | |
if( (mod & KMOD_LSHIFT) || (mod & KMOD_RSHIFT) || | |
event.type == (SDL_KEYDOWN && (event.key.keysym.sym == SDLK_LSHIFT || event.key.keysym.sym == SDLK_RSHIFT))) { | |
state = state | ShiftMask; | |
} | |
if( mod & KMOD_CAPS) { | |
state = state | LockMask; | |
} | |
state_xor = kb_shift_control_state ^ state; | |
is_up = 0; | |
if(state_xor & ControlMask) { | |
is_up = ((state & ControlMask) == 0); | |
adb_physical_key_update(0x36, is_up); | |
} | |
if(state_xor & LockMask) { | |
is_up = ((state & LockMask) == 0); | |
adb_physical_key_update(0x39, is_up); | |
} | |
if(state_xor & ShiftMask) { | |
is_up = ((state & ShiftMask) == 0); | |
adb_physical_key_update(0x38, is_up); | |
} | |
kb_shift_control_state = state; | |
is_up = 0; | |
int a2code; | |
if (event.type == SDL_KEYUP) { | |
is_up = 1; | |
} | |
switch( event.key.keysym.sym ){ | |
case SDLK_F11: | |
printf("Toggle Fullscreen"); | |
if (!is_up) { | |
if (!IsFullScreen(window)) { | |
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP); | |
} else { | |
SDL_SetWindowFullscreen(window, 0); | |
SDL_SetWindowSize(window, BASE_WINDOW_WIDTH, X_A2_WINDOW_HEIGHT); | |
} | |
} | |
break; | |
default: | |
a2code = sdl_keysym_to_a2code(event.key.keysym.sym, is_up); | |
if(a2code >= 0) { | |
adb_physical_key_update(a2code, is_up); | |
} | |
break; | |
} | |
} | |
int | |
handle_sdl_mouse_motion_event(SDL_Event event) { | |
int x, y; | |
// @todo: FIX MOUSE BUTTON MAPPING, AT LEAST CLEAN UP AND DOCUMENT BEHAVIOR | |
//printf (" %04x\t", event.motion.state &7); | |
x = event.motion.x - BASE_MARGIN_LEFT; | |
y = event.motion.y - BASE_MARGIN_TOP; | |
if (event.type == SDL_MOUSEBUTTONUP) { | |
return update_mouse(x, y, 0 , event.motion.state &7 ); | |
} else { | |
return update_mouse(x, y, event.motion.state, event.motion.state &7 ); | |
} | |
} | |
void | |
x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, int width, int height) | |
{ | |
sdl_push_kimage(kimage_ptr, destx, desty, srcx, srcy, width, height); | |
} | |
// called by src/sim65816.c | |
void | |
x_dialog_create_gsport_conf(const char *str) | |
{ | |
// Just write the config file already... | |
config_write_config_gsport_file(); | |
} | |
// Old driver cruft | |
// called by src/sim65816.c | |
int x_show_alert(int is_fatal, const char *str) { return 0; } | |
void get_ximage(Kimage *kimage_ptr) { } | |
void x_toggle_status_lines() { } | |
void x_redraw_status_lines() { } | |
void x_hide_pointer(int do_hide) { } | |
void x_auto_repeat_on(int must) { } | |
void x_auto_repeat_off(int must) { } | |
void x_full_screen(int do_full) { } | |
// OG Adding release | |
void x_release_kimage(Kimage* kimage_ptr) { } | |
// OG Addding ratio | |
int x_calc_ratio(float x,float y) { return 1; } | |
// TODO: Add clipboard support | |
void clipboard_paste(void) { } | |
int clipboard_get_char(void) { return 0; } | |
void x_set_mask_and_shift(word32 x_mask, word32 *mask_ptr, int *shift_left_ptr, int *shift_right_ptr) { return; } | |
void x_update_color(int col_num, int red, int green, int blue, word32 rgb) { } | |
void x_update_physical_colormap() { } | |
void show_xcolor_array() { } | |
void xdriver_end() { } | |
void x_push_done() { } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment