2016-02-08 05:01:25 +00:00
|
|
|
/*
|
2018-08-13 17:22:40 +00:00
|
|
|
GSPLUS - Advanced Apple IIGS Emulator Environment
|
|
|
|
Based on the KEGS emulator written by Kent Dickey
|
|
|
|
See COPYRIGHT.txt for Copyright information
|
|
|
|
See LICENSE.txt for license (GPL v2)
|
|
|
|
*/
|
2016-02-08 05:01:25 +00:00
|
|
|
|
2018-08-10 15:11:22 +00:00
|
|
|
// fps shiz
|
|
|
|
unsigned int lastTime = 0, currentTime, frames;
|
|
|
|
|
2016-10-19 05:01:19 +00:00
|
|
|
// @todo: mouse clip bugs.. great western shootout. Paint 8/16. still in win32
|
2016-02-08 05:01:25 +00:00
|
|
|
#include "SDL.h"
|
2016-10-19 18:12:19 +00:00
|
|
|
#include "SDL_image.h"
|
2016-11-03 02:28:16 +00:00
|
|
|
#include "glog.h"
|
2016-10-19 18:12:19 +00:00
|
|
|
|
2016-02-08 05:01:25 +00:00
|
|
|
#include <stdbool.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <signal.h>
|
2016-10-26 15:57:57 +00:00
|
|
|
#include <libgen.h> // just for basename :P
|
2016-10-03 00:37:45 +00:00
|
|
|
#include <string.h>
|
2016-02-08 05:01:25 +00:00
|
|
|
#include "defc.h"
|
2016-04-30 21:01:28 +00:00
|
|
|
#ifdef HAVE_ICON // Currently a flag because not supported outside of SDL builds. Looking at full solution.
|
|
|
|
#include "icongs.h"
|
|
|
|
#endif
|
2018-08-24 16:40:25 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
2016-02-08 05:01:25 +00:00
|
|
|
// BITMASKS
|
2018-08-13 17:22:40 +00:00
|
|
|
#define ShiftMask 1
|
|
|
|
#define ControlMask 4
|
|
|
|
#define LockMask 2
|
2016-02-08 05:01:25 +00:00
|
|
|
|
2019-02-17 19:15:13 +00:00
|
|
|
#include "adb_keycodes.h"
|
|
|
|
|
2016-02-08 05:01:25 +00:00
|
|
|
int g_use_shmem = 0;
|
|
|
|
|
|
|
|
int g_num_check_input_calls = 0;
|
|
|
|
int g_check_input_flush_rate = 2;
|
2018-08-13 17:22:40 +00:00
|
|
|
int g_win_status_debug = 0; // Current visibility of status lines.
|
|
|
|
int g_win_status_debug_request = 0; // Desired visibility of status lines.
|
2016-02-08 05:01:25 +00:00
|
|
|
int g_screen_mdepth = 0;
|
|
|
|
int kb_shift_control_state = 0;
|
|
|
|
|
2018-08-24 17:45:51 +00:00
|
|
|
void debuginfo_renderer(SDL_Renderer *r);
|
2016-10-19 18:12:19 +00:00
|
|
|
void x_take_screenshot(); // screenshot stuff
|
2018-09-07 14:29:46 +00:00
|
|
|
void x_grabmouse();
|
2016-10-19 18:12:19 +00:00
|
|
|
int g_screenshot_requested = 0; // DB to know if we want to save a screenshot
|
|
|
|
extern char g_config_gsplus_name[];
|
2017-01-20 04:53:30 +00:00
|
|
|
extern char g_config_gsplus_screenshot_dir[];
|
2016-10-19 18:12:19 +00:00
|
|
|
int screenshot_index = 0; // allows us to save time by not scanning from 0 each time
|
|
|
|
char screenshot_filename[256];
|
|
|
|
|
2018-02-27 12:56:45 +00:00
|
|
|
extern int g_fullscreen; // only checked at start if set via CLI, otherwise it's set via function call x_full_screen()
|
2018-09-07 14:29:46 +00:00
|
|
|
extern int g_grabmouse;
|
2018-03-11 20:10:46 +00:00
|
|
|
extern int g_highdpi;
|
|
|
|
extern int g_borderless;
|
|
|
|
extern int g_resizeable;
|
2018-08-30 14:55:10 +00:00
|
|
|
extern int g_noaspect;
|
2018-08-24 17:45:51 +00:00
|
|
|
extern int g_novsync;
|
|
|
|
extern int g_nohwaccel;
|
2018-08-30 14:55:10 +00:00
|
|
|
extern int g_fullscreen_desktop;
|
2017-01-21 22:31:32 +00:00
|
|
|
extern int g_scanline_simulator;
|
2018-02-27 12:56:45 +00:00
|
|
|
extern int g_startx;
|
|
|
|
extern int g_starty;
|
2018-08-30 14:55:10 +00:00
|
|
|
extern int g_startw;
|
|
|
|
extern int g_starth;
|
2016-02-08 05:01:25 +00:00
|
|
|
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;
|
2018-08-13 17:22:40 +00:00
|
|
|
extern const char g_gsplus_version_str[]; // version string for title bar
|
2016-02-08 05:01:25 +00:00
|
|
|
|
|
|
|
SDL_Window *window; // Declare a pointer
|
|
|
|
SDL_Renderer *renderer;
|
|
|
|
SDL_Texture *texture;
|
2017-01-21 22:31:32 +00:00
|
|
|
SDL_Texture *overlay_texture; // This is used for scanline simulation. Could be more in future (HUD).
|
|
|
|
Uint32 *overlay_pixels;
|
|
|
|
|
|
|
|
static char *g_clipboard = NULL; // clipboard variables
|
2018-08-13 17:22:40 +00:00
|
|
|
static size_t g_clipboard_pos = 0;
|
2016-02-08 05:01:25 +00:00
|
|
|
|
|
|
|
void dev_video_init_sdl();
|
|
|
|
void handle_sdl_key_event(SDL_Event event);
|
|
|
|
void check_input_events_sdl();
|
2018-08-27 16:21:59 +00:00
|
|
|
void handle_sdl_mouse_event(SDL_Event event);
|
2016-02-08 05:01:25 +00:00
|
|
|
|
2018-08-13 17:22:40 +00:00
|
|
|
int g_num_a2_keycodes = 0;
|
2016-02-08 05:01:25 +00:00
|
|
|
int a2_key_to_sdlkeycode[][3] = {
|
2019-02-17 19:15:13 +00:00
|
|
|
{ kVK_Escape, SDLK_ESCAPE, 0 },
|
|
|
|
{ kVK_F1, SDLK_F1, 0 },
|
|
|
|
{ kVK_F2, SDLK_F2, 0 },
|
|
|
|
{ kVK_F3, SDLK_F3, 0 },
|
|
|
|
{ kVK_F4, SDLK_F4, 0 },
|
|
|
|
{ kVK_F5, SDLK_F5, 0 },
|
|
|
|
{ kVK_F6, SDLK_F6, 0 },
|
|
|
|
{ kVK_F7, SDLK_F7, 0 },
|
|
|
|
{ kVK_F8, SDLK_F8, 0 },
|
|
|
|
{ kVK_F9, SDLK_F9, 0 },
|
|
|
|
{ kVK_F10, SDLK_F10, 0 },
|
|
|
|
{ kVK_F11, SDLK_F11, 0 },
|
|
|
|
{ kVK_F12, SDLK_F12, 0 },
|
|
|
|
{ kVK_F13, SDLK_F13, 0 },
|
|
|
|
{ kVK_F14, SDLK_F14, 0 },
|
|
|
|
{ kVK_F15, SDLK_F15, 0 },
|
|
|
|
{ kVK_F16, SDLK_F16, 0 },
|
|
|
|
{ kVK_F17, SDLK_F17, 0 },
|
|
|
|
{ kVK_F18, SDLK_F18, 0 },
|
|
|
|
{ kVK_F19, SDLK_F19, 0 },
|
|
|
|
{ kVK_F20, SDLK_F20, 0 },
|
|
|
|
{ kVK_Reset, SDLK_PAUSE, 0 },
|
|
|
|
{ kVK_ANSI_Grave, SDLK_BACKQUOTE, '~' },
|
|
|
|
{ kVK_ANSI_1, SDLK_1, '!' },
|
|
|
|
{ kVK_ANSI_2, SDLK_2, '@' },
|
|
|
|
{ kVK_ANSI_3, SDLK_3, '#' },
|
|
|
|
{ kVK_ANSI_4, SDLK_4, '$' },
|
|
|
|
{ kVK_ANSI_5, SDLK_5, '%' },
|
|
|
|
{ kVK_ANSI_6, SDLK_6, '^' },
|
|
|
|
{ kVK_ANSI_7, SDLK_7, '&' },
|
|
|
|
{ kVK_ANSI_8, SDLK_8, '*' },
|
|
|
|
{ kVK_ANSI_9, SDLK_9, '(' },
|
|
|
|
{ kVK_ANSI_0, SDLK_0, ')' },
|
|
|
|
{ kVK_ANSI_Minus, SDLK_MINUS, SDLK_UNDERSCORE },
|
|
|
|
{ kVK_ANSI_Equal, SDLK_EQUALS, SDLK_PLUS },
|
|
|
|
{ kVK_Delete, SDLK_BACKSPACE, 0 },
|
|
|
|
{ kVK_Help, SDLK_INSERT, 0 }, /* Help? XK_Help */
|
|
|
|
{ kVK_Home, SDLK_HOME, 0 },
|
|
|
|
{ kVK_PageUp, SDLK_PAGEUP, 0 },
|
|
|
|
{ kVK_Tab, SDLK_TAB, 0 },
|
|
|
|
{ kVK_ANSI_Q, SDLK_q, 'Q' },
|
|
|
|
{ kVK_ANSI_W, SDLK_w, 'W' },
|
|
|
|
{ kVK_ANSI_E, SDLK_e, 'E' },
|
|
|
|
{ kVK_ANSI_R, SDLK_r, 'R' },
|
|
|
|
{ kVK_ANSI_T, SDLK_t, 'T' },
|
|
|
|
{ kVK_ANSI_Y, SDLK_y, 'Y' },
|
|
|
|
{ kVK_ANSI_U, SDLK_u, 'U' },
|
|
|
|
{ kVK_ANSI_I, SDLK_i, 'I' },
|
|
|
|
{ kVK_ANSI_O, SDLK_o, 'O' },
|
|
|
|
{ kVK_ANSI_P, SDLK_p, 'P' },
|
|
|
|
{ kVK_ANSI_LeftBracket, SDLK_LEFTBRACKET, '{' },
|
|
|
|
{ kVK_ANSI_RightBracket, SDLK_RIGHTBRACKET, '}' },
|
|
|
|
{ kVK_ANSI_Backslash, SDLK_BACKSLASH, '|' }, /* backslash, bar */
|
|
|
|
{ kVK_ForwardDelete, SDLK_DELETE, 0 },
|
|
|
|
{ kVK_End, SDLK_END, 0 },
|
|
|
|
{ kVK_PageDown, SDLK_PAGEDOWN, 0 },
|
|
|
|
{ kVK_ANSI_A, SDLK_a, 'A' },
|
|
|
|
{ kVK_ANSI_S, SDLK_s, 'S' },
|
|
|
|
{ kVK_ANSI_D, SDLK_d, 'D' },
|
|
|
|
{ kVK_ANSI_F, SDLK_f, 'F' },
|
|
|
|
{ kVK_ANSI_G, SDLK_g, 'G' },
|
|
|
|
{ kVK_ANSI_H, SDLK_h, 'H' },
|
|
|
|
{ kVK_ANSI_J, SDLK_j, 'J' },
|
|
|
|
{ kVK_ANSI_K, SDLK_k, 'K' },
|
|
|
|
{ kVK_ANSI_L, SDLK_l, 'L' },
|
|
|
|
{ kVK_ANSI_Semicolon, SDLK_SEMICOLON, SDLK_COLON },
|
|
|
|
{ kVK_ANSI_Quote, SDLK_QUOTE, SDLK_QUOTEDBL },
|
|
|
|
{ kVK_Return, SDLK_RETURN, 0 },
|
|
|
|
{ kVK_Shift, SDLK_LSHIFT, 0 },
|
|
|
|
{ kVK_RightShift, SDLK_RSHIFT, 0 },
|
|
|
|
{ kVK_ANSI_Z, SDLK_z, 'Z' },
|
|
|
|
{ kVK_ANSI_X, SDLK_x, 'X' },
|
|
|
|
{ kVK_ANSI_C, SDLK_c, 'C' },
|
|
|
|
{ kVK_ANSI_V, SDLK_v, 'V' },
|
|
|
|
{ kVK_ANSI_B, SDLK_b, 'B' },
|
|
|
|
{ kVK_ANSI_N, SDLK_n, 'N' },
|
|
|
|
{ kVK_ANSI_M, SDLK_m, 'M' },
|
|
|
|
{ kVK_ANSI_Comma, SDLK_COMMA, SDLK_LESS },
|
|
|
|
{ kVK_ANSI_Period, SDLK_PERIOD, SDLK_GREATER },
|
|
|
|
{ kVK_ANSI_Slash, SDLK_SLASH, SDLK_QUESTION },
|
|
|
|
|
|
|
|
{ kVK_CapsLock, SDLK_CAPSLOCK, 0 },
|
|
|
|
|
|
|
|
{ kVK_Control, SDLK_LCTRL, 0 },
|
|
|
|
{ kVK_RightControl, SDLK_RCTRL, 0 },
|
2018-08-25 04:20:47 +00:00
|
|
|
#if defined(__APPLE__)
|
2019-02-17 19:15:13 +00:00
|
|
|
{ kVK_Option, SDLK_LALT, 0 }, /* Option */
|
|
|
|
{ kVK_RightOption, SDLK_RALT, 0 }, /* Option */
|
|
|
|
{ kVK_Command, SDLK_LGUI, 0 }, /* Command */
|
|
|
|
{ kVK_RightCommand, SDLK_RGUI, 0 }, /* Command */
|
2018-08-25 04:20:47 +00:00
|
|
|
#else
|
2019-02-17 19:15:13 +00:00
|
|
|
{ kVK_Option, SDLK_LGUI, 0 }, /* Command */
|
|
|
|
{ kVK_RightOption, SDLK_RGUI, 0 }, /* Command */
|
|
|
|
{ kVK_Command, SDLK_LALT, 0 }, /* Option */
|
|
|
|
{ kVK_RightCommand, SDLK_RALT, 0 }, /* Option */
|
2018-08-25 04:20:47 +00:00
|
|
|
#endif
|
2019-02-17 19:15:13 +00:00
|
|
|
{ kVK_Space, SDLK_SPACE, 0 },
|
|
|
|
{ kVK_LeftArrow, SDLK_LEFT, 0 },
|
|
|
|
{ kVK_DownArrow, SDLK_DOWN, 0 },
|
|
|
|
{ kVK_RightArrow, SDLK_RIGHT, 0 },
|
|
|
|
{ kVK_UpArrow, SDLK_UP, 0 },
|
|
|
|
|
|
|
|
{ kVK_ANSI_Keypad0, SDLK_KP_0, 0 },
|
|
|
|
{ kVK_ANSI_Keypad1, SDLK_KP_1, 0 },
|
|
|
|
{ kVK_ANSI_Keypad2, SDLK_KP_2, 0 },
|
|
|
|
{ kVK_ANSI_Keypad3, SDLK_KP_3, 0 },
|
|
|
|
{ kVK_ANSI_Keypad4, SDLK_KP_4, 0 },
|
|
|
|
{ kVK_ANSI_Keypad5, SDLK_KP_5, 0 },
|
|
|
|
{ kVK_ANSI_Keypad6, SDLK_KP_6, 0 },
|
|
|
|
{ kVK_ANSI_Keypad7, SDLK_KP_7, 0 },
|
|
|
|
{ kVK_ANSI_Keypad8, SDLK_KP_8, 0 },
|
|
|
|
{ kVK_ANSI_Keypad9, SDLK_KP_9, 0 },
|
|
|
|
|
|
|
|
{ kVK_ANSI_KeypadMinus, SDLK_KP_MINUS, 0 },
|
|
|
|
{ kVK_ANSI_KeypadPlus, SDLK_KP_PLUS, 0 },
|
|
|
|
{ kVK_ANSI_KeypadEquals, SDLK_KP_EQUALS, 0 }, /* Note XK_Home alias! XK_Home */
|
|
|
|
{ kVK_ANSI_KeypadDivide, SDLK_KP_DIVIDE, 0 },
|
|
|
|
{ kVK_ANSI_KeypadMultiply,SDLK_KP_MULTIPLY, 0 },
|
|
|
|
{ kVK_ANSI_KeypadDecimal, SDLK_KP_PERIOD, 0 },
|
|
|
|
{ kVK_ANSI_KeypadEnter, SDLK_KP_ENTER, 0 },
|
|
|
|
{ kVK_ANSI_KeypadClear, SDLK_NUMLOCKCLEAR, 0 }, /* Clear, XK_Clear */
|
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
{ -1, -1, -1 }
|
2016-02-08 05:01:25 +00:00
|
|
|
};
|
2016-10-19 05:01:19 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
|
|
|
|
|
2018-08-13 17:22:40 +00:00
|
|
|
int main(int argc, char **argv) {
|
2017-01-21 22:31:32 +00:00
|
|
|
return gsplusmain(argc, argv);
|
2016-02-08 05:01:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
const char *byte_to_binary(int x) {
|
|
|
|
static char b[9];
|
|
|
|
b[0] = '\0';
|
2016-04-28 02:58:38 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
int z;
|
|
|
|
for (z = 128; z > 0; z >>= 1)
|
|
|
|
{
|
|
|
|
strcat(b, ((x & z) == z) ? "1" : "0");
|
|
|
|
}
|
|
|
|
|
|
|
|
return b;
|
2016-04-28 02:58:38 +00:00
|
|
|
}
|
2016-02-08 05:01:25 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
|
|
|
|
// Queries the Screen to see if set to Fullscreen or Not
|
|
|
|
// @return SDL_FALSE when windowed, SDL_TRUE when 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
|
2016-02-08 05:01:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
void dev_video_init() {
|
2018-08-13 17:22:40 +00:00
|
|
|
word32 lores_col;
|
2016-02-08 05:01:25 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
// build keycode map ??
|
|
|
|
g_num_a2_keycodes = 0;
|
2018-08-13 17:22:40 +00:00
|
|
|
int i;
|
|
|
|
int keycode;
|
2017-01-21 22:31:32 +00:00
|
|
|
|
|
|
|
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) {
|
2017-01-22 03:44:44 +00:00
|
|
|
glogf("a2_key_to_xsym[%d] = %02x!\n", i, keycode);
|
2017-01-21 22:31:32 +00:00
|
|
|
exit(2);
|
|
|
|
}
|
|
|
|
}
|
2016-02-08 05:01:25 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
// This actually creates our window
|
|
|
|
dev_video_init_sdl();
|
2016-02-08 05:01:25 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
// @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];
|
|
|
|
}
|
2016-04-30 21:01:28 +00:00
|
|
|
|
2016-02-08 05:01:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-30 21:01:28 +00:00
|
|
|
void do_icon() {
|
2017-01-21 22:31:32 +00:00
|
|
|
#ifdef HAVE_ICON
|
|
|
|
//surface = SDL_CreateRGBSurfaceFrom(pixels,w,h,depth,pitch,rmask,gmask,bmask,amask);
|
|
|
|
int size = 256; // icon size
|
|
|
|
SDL_Surface *surface; // declare an SDL_Surface to be filled in with pixel data from an image file
|
|
|
|
surface = SDL_CreateRGBSurfaceFrom(icon_pixels,size,size,32,size*4,0xff000000,0x00ff0000,0x0000ff00,0x000000ff);
|
|
|
|
|
|
|
|
// The icon is attached to the window pointer
|
|
|
|
SDL_SetWindowIcon(window, surface);
|
|
|
|
// ...and the surface containing the icon pixel data is no longer required.
|
|
|
|
SDL_FreeSurface(surface);
|
|
|
|
#endif
|
2016-04-30 21:01:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-08 05:01:25 +00:00
|
|
|
// Initialize our SDL window and texture
|
2017-01-21 22:31:32 +00:00
|
|
|
void dev_video_init_sdl() {
|
|
|
|
SDL_Init(SDL_INIT_VIDEO); // Initialize SDL2
|
|
|
|
|
2017-02-11 01:06:11 +00:00
|
|
|
#if defined __APPLE__
|
|
|
|
extern void fix_mac_menu();
|
|
|
|
fix_mac_menu();
|
|
|
|
#endif
|
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
// Create an application window with the following settings:
|
|
|
|
char window_title[32];
|
2018-02-27 12:56:45 +00:00
|
|
|
sprintf(window_title, "GSplus v%-6s", g_gsplus_version_str);
|
2018-07-17 20:47:44 +00:00
|
|
|
int startx = SDL_WINDOWPOS_UNDEFINED;
|
|
|
|
int starty = SDL_WINDOWPOS_UNDEFINED;
|
2018-02-27 12:56:45 +00:00
|
|
|
if (g_startx != WINDOWPOS_UNDEFINED) { startx = g_startx; }
|
|
|
|
if (g_starty != WINDOWPOS_UNDEFINED) { starty = g_starty; }
|
|
|
|
int more_flags = 0;
|
|
|
|
// check for CLI fullscreen
|
|
|
|
if (g_fullscreen) {
|
|
|
|
more_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
|
|
|
|
}
|
2018-03-11 20:10:46 +00:00
|
|
|
if (g_highdpi) {
|
|
|
|
more_flags |= SDL_WINDOW_ALLOW_HIGHDPI;
|
|
|
|
}
|
|
|
|
if (g_borderless) {
|
|
|
|
more_flags |= SDL_WINDOW_BORDERLESS;
|
|
|
|
}
|
|
|
|
if (g_resizeable) {
|
|
|
|
more_flags |= SDL_WINDOW_RESIZABLE;
|
|
|
|
}
|
2018-07-17 20:47:44 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
window = SDL_CreateWindow(
|
2018-08-30 14:55:10 +00:00
|
|
|
window_title, // window title (GSport vX.X)
|
2018-08-13 17:22:40 +00:00
|
|
|
startx,
|
|
|
|
starty,
|
2018-08-30 14:55:10 +00:00
|
|
|
g_startw, // width, in pixels
|
|
|
|
g_starth, // height, in pixels
|
|
|
|
SDL_WINDOW_OPENGL // flags - see below
|
2018-02-27 12:56:45 +00:00
|
|
|
| more_flags
|
2018-08-13 17:22:40 +00:00
|
|
|
);
|
2018-07-17 20:47:44 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
|
|
|
|
// Check that the window was successfully created
|
|
|
|
if (window == NULL) {
|
|
|
|
// In the case that the window could not be made...
|
|
|
|
glogf("Could not create window: %s", SDL_GetError());
|
|
|
|
//@todo die, i guess
|
|
|
|
} else {
|
|
|
|
glog("SDL2 graphics initialized");
|
|
|
|
}
|
2016-02-08 05:01:25 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
// SET WINDOW ICON
|
|
|
|
do_icon();
|
|
|
|
|
2018-08-24 17:45:51 +00:00
|
|
|
int renderer_hints = 0;
|
|
|
|
if (!g_novsync) {
|
|
|
|
renderer_hints |= SDL_RENDERER_PRESENTVSYNC;
|
|
|
|
}
|
|
|
|
if (!g_nohwaccel) {
|
|
|
|
renderer_hints |= SDL_RENDERER_ACCELERATED;
|
|
|
|
}
|
|
|
|
renderer = SDL_CreateRenderer(window, -1, renderer_hints);
|
|
|
|
debuginfo_renderer(renderer);
|
2017-01-21 22:31:32 +00:00
|
|
|
|
|
|
|
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.
|
2018-08-30 14:55:10 +00:00
|
|
|
if (!g_noaspect) {
|
|
|
|
SDL_RenderSetLogicalSize(renderer, BASE_WINDOW_WIDTH, X_A2_WINDOW_HEIGHT);
|
|
|
|
}
|
2017-01-21 22:31:32 +00:00
|
|
|
|
|
|
|
texture = SDL_CreateTexture(renderer,
|
2018-08-13 17:22:40 +00:00
|
|
|
SDL_PIXELFORMAT_ARGB8888,
|
|
|
|
SDL_TEXTUREACCESS_STREAMING,
|
|
|
|
BASE_WINDOW_WIDTH, X_A2_WINDOW_HEIGHT);
|
2017-01-21 22:31:32 +00:00
|
|
|
// The window is open: could enter program loop here (see SDL_PollEvent())
|
|
|
|
//overlay test
|
|
|
|
overlay_texture = SDL_CreateTexture(renderer,
|
2018-08-13 17:22:40 +00:00
|
|
|
SDL_PIXELFORMAT_ARGB8888,
|
|
|
|
SDL_TEXTUREACCESS_STREAMING,
|
|
|
|
BASE_WINDOW_WIDTH,
|
|
|
|
X_A2_WINDOW_HEIGHT);
|
2017-01-21 22:31:32 +00:00
|
|
|
|
|
|
|
SDL_SetTextureBlendMode(overlay_texture, SDL_BLENDMODE_BLEND);
|
|
|
|
overlay_pixels = malloc(BASE_WINDOW_WIDTH*X_A2_WINDOW_HEIGHT*sizeof(Uint32));
|
2018-02-27 12:56:45 +00:00
|
|
|
Uint32 pixelARGB = 0x33000000; // default "low grey"
|
2017-01-21 22:31:32 +00:00
|
|
|
if (overlay_pixels) {
|
2018-02-27 12:56:45 +00:00
|
|
|
if (g_scanline_simulator > 0) {
|
|
|
|
pixelARGB = (int)(g_scanline_simulator*2.56) << 24;
|
|
|
|
}
|
2017-01-21 22:31:32 +00:00
|
|
|
for (int y=0; y<X_A2_WINDOW_HEIGHT; y++) {
|
|
|
|
for (int x=0; x<BASE_WINDOW_WIDTH; x++) {
|
2016-04-30 21:01:28 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
if (y%2 == 1) {
|
2018-03-20 02:21:11 +00:00
|
|
|
overlay_pixels[(y*BASE_WINDOW_WIDTH)+x] = pixelARGB;
|
2017-01-21 22:31:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SDL_Rect dstrect;
|
|
|
|
dstrect.x = 0;
|
|
|
|
dstrect.y = 0;
|
|
|
|
dstrect.w = BASE_WINDOW_WIDTH;
|
|
|
|
dstrect.h = X_A2_WINDOW_HEIGHT;
|
|
|
|
int pitch = BASE_WINDOW_WIDTH;
|
2018-07-17 20:47:44 +00:00
|
|
|
|
2016-02-08 05:01:25 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
// UPDATE A RECT OF THE APPLE II SCREEN TEXTURE
|
|
|
|
SDL_UpdateTexture(overlay_texture, &dstrect, overlay_pixels, pitch*sizeof(Uint32) );
|
2016-02-08 05:01:25 +00:00
|
|
|
|
2018-08-27 16:21:59 +00:00
|
|
|
// Turn off host mouse cursor
|
2017-01-21 22:31:32 +00:00
|
|
|
SDL_ShowCursor(SDL_DISABLE);
|
2016-02-08 05:01:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Copy a rect to our SDL window
|
2017-01-21 22:31:32 +00:00
|
|
|
void sdl_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, int width, int height) {
|
2018-08-10 15:11:22 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
byte *src_ptr;
|
|
|
|
int pixel_size = 4;
|
|
|
|
src_ptr = kimage_ptr->data_ptr + (srcy * kimage_ptr->width_act + srcx) * pixel_size;
|
|
|
|
|
|
|
|
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;
|
|
|
|
// seems to be the correct value, but would like clarification
|
|
|
|
pitch = BORDER_WIDTH+72;
|
|
|
|
}
|
|
|
|
SDL_UpdateTexture(texture, &dstrect, src_ptr, pitch*4 );
|
2016-02-08 05:01:25 +00:00
|
|
|
|
2018-08-26 18:59:39 +00:00
|
|
|
// We now call the render step seperately in sdl_present_buffer once per frame
|
|
|
|
// SDL picks up the buffer and waits for VBLANK to send it
|
2016-02-08 05:01:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void set_refresh_needed() {
|
2017-01-21 22:31:32 +00:00
|
|
|
g_a2_screen_buffer_changed = -1;
|
|
|
|
g_full_refresh_needed = -1;
|
2016-02-08 05:01:25 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
g_border_sides_refresh_needed = 1;
|
|
|
|
g_border_special_refresh_needed = 1;
|
|
|
|
g_status_refresh_needed = 1;
|
2016-02-08 05:01:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
void x_get_kimage(Kimage *kimage_ptr) {
|
|
|
|
byte *data;
|
2018-08-13 17:22:40 +00:00
|
|
|
int width;
|
|
|
|
int height;
|
|
|
|
int depth;
|
2016-02-08 05:01:25 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
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;
|
2016-02-08 05:01:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
void check_input_events() {
|
2016-02-08 05:01:25 +00:00
|
|
|
check_input_events_sdl();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
void check_input_events_sdl() {
|
2016-02-08 05:01:25 +00:00
|
|
|
SDL_Event event;
|
|
|
|
|
|
|
|
while (SDL_PollEvent(&event)) {
|
2017-01-21 22:31:32 +00:00
|
|
|
/* Check all window events (mostly for Fullscreen) */
|
|
|
|
if (event.type == SDL_WINDOWEVENT) {
|
|
|
|
set_refresh_needed();
|
|
|
|
}
|
2018-08-13 17:22:40 +00:00
|
|
|
switch( event.type ) {
|
2017-01-21 22:31:32 +00:00
|
|
|
case SDL_KEYDOWN:
|
|
|
|
case SDL_KEYUP:
|
|
|
|
handle_sdl_key_event(event);
|
|
|
|
break;
|
|
|
|
case SDL_MOUSEMOTION:
|
|
|
|
case SDL_MOUSEBUTTONUP:
|
|
|
|
case SDL_MOUSEBUTTONDOWN:
|
2018-08-27 16:21:59 +00:00
|
|
|
handle_sdl_mouse_event(event);
|
2017-01-21 22:31:32 +00:00
|
|
|
break;
|
|
|
|
case SDL_QUIT:
|
2018-08-27 16:21:59 +00:00
|
|
|
xdriver_end();
|
2017-02-11 01:06:11 +00:00
|
|
|
my_exit(1);
|
2017-01-21 22:31:32 +00:00
|
|
|
break;
|
|
|
|
case SDL_DROPFILE:
|
|
|
|
{
|
|
|
|
char *file = event.drop.file;
|
|
|
|
cfg_inspect_maybe_insert_file(file, 0);
|
|
|
|
SDL_free(file);
|
|
|
|
}
|
2018-08-13 17:22:40 +00:00
|
|
|
break;
|
2017-01-21 22:31:32 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2016-02-08 05:01:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
int sdl_keysym_to_a2code(int keysym, int is_up) {
|
2018-08-13 17:22:40 +00:00
|
|
|
int i;
|
2017-01-21 22:31:32 +00:00
|
|
|
|
|
|
|
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]) ||
|
2018-08-13 17:22:40 +00:00
|
|
|
(keysym == a2_key_to_sdlkeycode[i][2])) {
|
2017-01-21 22:31:32 +00:00
|
|
|
return a2_key_to_sdlkeycode[i][0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
2016-02-08 05:01:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
void handle_sdl_key_event(SDL_Event event) {
|
2018-08-13 17:22:40 +00:00
|
|
|
int state_xor;
|
2017-01-21 22:31:32 +00:00
|
|
|
int state = 0;
|
2018-08-13 17:22:40 +00:00
|
|
|
int is_up;
|
2017-01-21 22:31:32 +00:00
|
|
|
|
|
|
|
int mod = event.key.keysym.mod;
|
2016-02-08 05:01:25 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
// 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 ||
|
2018-08-13 17:22:40 +00:00
|
|
|
event.type == (SDL_KEYDOWN && (event.key.keysym.sym == SDLK_LCTRL || event.key.keysym.sym == SDLK_RCTRL))) {
|
|
|
|
state = state | ControlMask;
|
2017-01-21 22:31:32 +00:00
|
|
|
}
|
|
|
|
if( (mod & KMOD_LSHIFT) || (mod & KMOD_RSHIFT) ||
|
2018-08-13 17:22:40 +00:00
|
|
|
event.type == (SDL_KEYDOWN && (event.key.keysym.sym == SDLK_LSHIFT || event.key.keysym.sym == SDLK_RSHIFT))) {
|
2017-01-21 22:31:32 +00:00
|
|
|
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;
|
|
|
|
}
|
2018-08-13 17:22:40 +00:00
|
|
|
switch( event.key.keysym.sym ) {
|
2017-01-21 22:31:32 +00:00
|
|
|
case SDLK_F11:
|
|
|
|
if (kb_shift_control_state & ShiftMask) { // SHIFT+F11
|
|
|
|
if (!is_up) {
|
|
|
|
if (g_scanline_simulator) {
|
|
|
|
glog("Enable scanline simulator");
|
|
|
|
g_scanline_simulator = 0;
|
|
|
|
} else {
|
|
|
|
glog("Disable scanline simulator");
|
|
|
|
g_scanline_simulator = 1;
|
|
|
|
}
|
|
|
|
set_refresh_needed(); // make sure user sees it right away
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!is_up) {
|
|
|
|
if (!IsFullScreen(window)) {
|
|
|
|
glog("Enable fullscreen");
|
2018-08-27 17:16:57 +00:00
|
|
|
SDL_SetWindowGrab(window, true);
|
2018-09-07 14:29:46 +00:00
|
|
|
SDL_SetRelativeMouseMode(true);
|
|
|
|
|
2018-08-30 14:55:10 +00:00
|
|
|
Uint32 fullmode = g_fullscreen_desktop ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN;
|
|
|
|
SDL_SetWindowFullscreen(window, fullmode);
|
2017-01-21 22:31:32 +00:00
|
|
|
} else {
|
|
|
|
glog("Disable fullscreen");
|
|
|
|
SDL_SetWindowFullscreen(window, 0);
|
2018-08-27 17:16:57 +00:00
|
|
|
SDL_SetWindowGrab(window, false);
|
2018-08-30 14:55:10 +00:00
|
|
|
SDL_SetWindowSize(window, g_startw, g_starth);
|
2018-09-07 14:29:46 +00:00
|
|
|
SDL_SetRelativeMouseMode(false);
|
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
a2code = sdl_keysym_to_a2code(event.key.keysym.sym, is_up);
|
|
|
|
if(a2code >= 0) {
|
|
|
|
adb_physical_key_update(a2code, is_up);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2016-02-08 05:01:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-08-27 16:21:59 +00:00
|
|
|
void handle_sdl_mouse_event(SDL_Event event) {
|
2017-01-21 22:31:32 +00:00
|
|
|
int x, y;
|
2018-08-27 16:21:59 +00:00
|
|
|
|
2018-09-07 14:29:46 +00:00
|
|
|
int scaledmotion = 0;
|
|
|
|
if (scaledmotion) {
|
|
|
|
x = event.motion.x * A2_WINDOW_WIDTH / g_startw;
|
|
|
|
y = event.motion.y * A2_WINDOW_HEIGHT / g_starth;
|
|
|
|
} else {
|
|
|
|
x = event.motion.x - BASE_MARGIN_LEFT;
|
|
|
|
y = event.motion.y - BASE_MARGIN_TOP;
|
|
|
|
}
|
|
|
|
|
2018-08-27 16:21:59 +00:00
|
|
|
switch (event.type) {
|
|
|
|
case SDL_MOUSEMOTION:
|
2018-09-07 14:29:46 +00:00
|
|
|
update_mouse_w_delta(x, y, 0, 0, event.motion.xrel, event.motion.yrel);
|
2018-08-27 16:21:59 +00:00
|
|
|
break;
|
|
|
|
case SDL_MOUSEBUTTONUP:
|
2018-09-07 14:29:46 +00:00
|
|
|
update_mouse_w_delta(x, y, 0, event.motion.state &7, 0, 0);
|
2018-08-27 16:21:59 +00:00
|
|
|
break;
|
|
|
|
case SDL_MOUSEBUTTONDOWN:
|
2018-09-07 14:29:46 +00:00
|
|
|
update_mouse_w_delta(x, y, event.motion.state &7, event.motion.state &7 , 0, 0);
|
2018-08-27 16:21:59 +00:00
|
|
|
break;
|
2017-01-21 22:31:32 +00:00
|
|
|
}
|
2016-02-08 05:01:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
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);
|
2016-02-08 05:01:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// called by src/sim65816.c
|
2017-01-21 22:31:32 +00:00
|
|
|
void x_dialog_create_gsport_conf(const char *str) {
|
|
|
|
// Just write the config file already...
|
|
|
|
config_write_config_gsplus_file();
|
2016-02-08 05:01:25 +00:00
|
|
|
}
|
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
|
2016-10-19 18:12:19 +00:00
|
|
|
void x_full_screen(int do_full) {
|
|
|
|
if (do_full) {
|
|
|
|
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
|
|
|
|
} else {
|
|
|
|
SDL_SetWindowFullscreen(window, 0);
|
|
|
|
SDL_SetWindowSize(window, BASE_WINDOW_WIDTH, X_A2_WINDOW_HEIGHT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
|
|
|
|
int file_exists(char *fname) {
|
2016-10-19 18:12:19 +00:00
|
|
|
if( access( fname, F_OK ) != -1 ) {
|
|
|
|
return 1; // file exists
|
|
|
|
} else {
|
2017-01-21 22:31:32 +00:00
|
|
|
return 0; // file does not exist
|
2016-10-19 18:12:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
|
2017-01-20 16:17:58 +00:00
|
|
|
// This tries to determine the next screenshot name.
|
|
|
|
// It uses the config name as the basename.
|
2017-01-21 22:31:32 +00:00
|
|
|
void make_next_screenshot_filename() {
|
2016-10-19 18:12:19 +00:00
|
|
|
char filepart[256];
|
|
|
|
char filename[256];
|
|
|
|
|
|
|
|
int available_filename = 0;
|
|
|
|
while (!available_filename) {
|
2016-10-26 15:57:57 +00:00
|
|
|
char *bn = basename(g_config_gsplus_name);
|
2016-10-19 18:12:19 +00:00
|
|
|
// get location of '.'
|
2016-10-26 15:57:57 +00:00
|
|
|
char *dotptr = strchr(bn, '.');
|
|
|
|
int index = dotptr - bn;
|
|
|
|
strncpy(filepart, bn, index);
|
2016-10-19 18:12:19 +00:00
|
|
|
filepart[index] = '\0'; //terminator
|
2016-10-26 15:57:57 +00:00
|
|
|
// handle trailing "/" vs no "/"
|
|
|
|
char tchar = g_config_gsplus_screenshot_dir[strlen(g_config_gsplus_screenshot_dir) - 1];
|
|
|
|
if (tchar == '/') {
|
|
|
|
sprintf(filename, "%s%s%04d.png",g_config_gsplus_screenshot_dir,filepart,screenshot_index);
|
2016-10-19 18:12:19 +00:00
|
|
|
} else {
|
2016-10-26 15:57:57 +00:00
|
|
|
sprintf(filename, "%s/%s%04d.png",g_config_gsplus_screenshot_dir,filepart,screenshot_index);
|
|
|
|
}
|
|
|
|
screenshot_index++;
|
|
|
|
if (!file_exists(filename)) {
|
2016-10-19 18:12:19 +00:00
|
|
|
available_filename = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
strcpy(screenshot_filename, filename);
|
|
|
|
}
|
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
|
|
|
|
|
2016-10-19 18:12:19 +00:00
|
|
|
// @todo: some error with writing data direct to png. output is empty/transparent?
|
|
|
|
// workaround is this horrible hack of saving the bmp -> load bmp -> save png
|
|
|
|
void x_take_screenshot() {
|
|
|
|
make_next_screenshot_filename();
|
2017-01-20 20:19:07 +00:00
|
|
|
glogf("Taking screenshot - %s", screenshot_filename);
|
2016-10-19 18:12:19 +00:00
|
|
|
SDL_Surface *sshot = SDL_CreateRGBSurface(0, BASE_WINDOW_WIDTH, X_A2_WINDOW_HEIGHT, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
|
|
|
|
SDL_LockSurface(sshot);
|
|
|
|
int read = SDL_RenderReadPixels(renderer, NULL, SDL_PIXELFORMAT_ARGB8888, sshot->pixels, sshot->pitch);
|
|
|
|
if (read != 0) {
|
|
|
|
printf("READPXL FAIL!\n%s\n", SDL_GetError());
|
|
|
|
}
|
|
|
|
SDL_SaveBMP(sshot, "screenshot.bmp");
|
|
|
|
SDL_UnlockSurface(sshot);
|
|
|
|
SDL_FreeSurface(sshot);
|
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
SDL_Surface *s = SDL_CreateRGBSurface(0, BASE_WINDOW_WIDTH, X_A2_WINDOW_HEIGHT, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
|
2018-08-13 17:22:40 +00:00
|
|
|
if (s) {
|
|
|
|
SDL_Surface * image = SDL_LoadBMP("screenshot.bmp");
|
|
|
|
IMG_SavePNG(image, screenshot_filename);
|
|
|
|
SDL_FreeSurface(image);
|
2016-10-19 18:12:19 +00:00
|
|
|
}
|
2018-08-13 17:22:40 +00:00
|
|
|
SDL_FreeSurface(s);
|
|
|
|
}
|
2016-05-01 12:56:02 +00:00
|
|
|
|
2016-02-08 05:01:25 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
void clipboard_paste(void) {
|
2016-02-08 05:01:25 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
char *cp;
|
2016-02-08 05:01:25 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
if (g_clipboard) {
|
|
|
|
free(g_clipboard);
|
|
|
|
g_clipboard = NULL;
|
|
|
|
g_clipboard_pos = 0;
|
|
|
|
}
|
2016-05-01 12:56:02 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
cp = SDL_GetClipboardText();
|
|
|
|
if (!cp) return;
|
2016-05-01 12:56:02 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
g_clipboard = strdup(cp);
|
|
|
|
g_clipboard_pos = 0;
|
2016-10-03 00:37:45 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
SDL_free(cp);
|
|
|
|
}
|
2016-10-03 00:37:45 +00:00
|
|
|
|
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
int clipboard_get_char(void) {
|
|
|
|
char c;
|
2016-10-03 00:37:45 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
if (!g_clipboard)
|
2018-08-13 17:22:40 +00:00
|
|
|
return 0;
|
2016-10-03 00:37:45 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
/* skip utf-8 characters. */
|
|
|
|
do {
|
|
|
|
c = g_clipboard[g_clipboard_pos++];
|
|
|
|
} while (c & 0x80);
|
2016-10-03 00:37:45 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
/* windows -- skip the \n in \r\n. */
|
|
|
|
if (c == '\r' && g_clipboard[g_clipboard_pos] == '\n')
|
2018-08-13 17:22:40 +00:00
|
|
|
g_clipboard_pos++;
|
2016-10-03 00:37:45 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
/* everybody else -- convert \n to \r */
|
|
|
|
if (c == '\n') c = '\r';
|
2016-10-03 00:37:45 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
if (c == 0) {
|
|
|
|
free(g_clipboard);
|
|
|
|
g_clipboard = NULL;
|
|
|
|
g_clipboard_pos = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
2016-10-03 00:37:45 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
return c | 0x80;
|
|
|
|
}
|
2016-10-03 20:48:18 +00:00
|
|
|
|
2018-08-10 14:32:55 +00:00
|
|
|
int x_show_alert(int is_fatal, const char *str) {
|
|
|
|
if (str) {
|
|
|
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "GS+ Alert", str, NULL);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2016-10-03 20:48:18 +00:00
|
|
|
|
2018-08-24 19:18:44 +00:00
|
|
|
void xdriver_end() {
|
2018-08-27 16:21:59 +00:00
|
|
|
SDL_DestroyWindow(window);
|
|
|
|
iwm_shut();
|
|
|
|
// Clean up
|
2018-08-24 19:18:44 +00:00
|
|
|
SDL_Quit();
|
|
|
|
}
|
|
|
|
|
2018-08-24 17:45:51 +00:00
|
|
|
// This will help us determine how well and which drivers are supported on
|
|
|
|
// different SDL platforms
|
|
|
|
void debuginfo_renderer(SDL_Renderer *r) {
|
|
|
|
int n = SDL_GetNumRenderDrivers();
|
|
|
|
glogf("**--- SDL DEBUG ------ (%i) drivers", n);
|
|
|
|
for(int i = 0; i < n; i++) {
|
|
|
|
SDL_RendererInfo info;
|
|
|
|
SDL_GetRenderDriverInfo(i, &info);
|
2018-09-07 14:29:46 +00:00
|
|
|
glogf("* '%s'", info.name);
|
2018-08-24 17:45:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SDL_RendererInfo info = {0};
|
|
|
|
if (SDL_GetRendererInfo(r,&info) == 0) {
|
|
|
|
glogf("* SDL_RENDERER_SOFTWARE: %d", (info.flags & SDL_RENDERER_SOFTWARE) > 0 );
|
|
|
|
glogf("* SDL_RENDERER_ACCELERATED: %d", (info.flags & SDL_RENDERER_ACCELERATED) > 0 );
|
|
|
|
glogf("* SDL_RENDERER_PRESENTVSYNC: %d", (info.flags & SDL_RENDERER_PRESENTVSYNC) > 0 );
|
|
|
|
glogf("* SDL_RENDERER_TARGETTEXTURE: %d", (info.flags & SDL_RENDERER_TARGETTEXTURE) > 0 );
|
|
|
|
glogf("* active renderer -> '%s'", info.name);
|
|
|
|
} else {
|
|
|
|
glog("NO Renderinfo");
|
|
|
|
}
|
|
|
|
}
|
2016-10-03 00:37:45 +00:00
|
|
|
|
2018-08-30 14:55:10 +00:00
|
|
|
// as this is triggered when new images were pushed to backing buffer,
|
|
|
|
// this is when we want to update frames.
|
|
|
|
// putting it in x_push_done means we can skip frames that weren't changed.
|
|
|
|
// the emulator will still run at whatever specified speed. but this way,
|
|
|
|
// when running in faster 8mhz/unlimited modes, it won't be slowed down by
|
|
|
|
// forcing every draw at 60FPS sync.
|
|
|
|
void x_push_done() {
|
|
|
|
void sdl_present_buffer();
|
|
|
|
sdl_present_buffer();
|
|
|
|
}
|
|
|
|
|
2018-08-26 18:59:39 +00:00
|
|
|
void sdl_present_buffer() {
|
|
|
|
SDL_RenderClear(renderer);
|
|
|
|
SDL_RenderCopy(renderer, texture, NULL, NULL);
|
|
|
|
if (g_scanline_simulator) {
|
|
|
|
SDL_RenderCopy(renderer, overlay_texture, NULL, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_RenderPresent(renderer);
|
|
|
|
if (g_screenshot_requested) {
|
|
|
|
x_take_screenshot();
|
|
|
|
g_screenshot_requested = 0;
|
|
|
|
}
|
|
|
|
}
|
2016-10-03 00:37:45 +00:00
|
|
|
|
2018-09-07 14:29:46 +00:00
|
|
|
void x_grabmouse() {
|
|
|
|
SDL_SetWindowGrab(window, g_grabmouse);
|
|
|
|
SDL_SetRelativeMouseMode(g_grabmouse);
|
|
|
|
}
|
2018-08-30 14:55:10 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
// BELOW ARE FUNCTIONS THAT ARE EITHER UNIMPLEMENTED, OR AR NOT RELEVANT TO
|
|
|
|
// THIS DRIVER.
|
2016-10-03 00:37:45 +00:00
|
|
|
|
2017-01-21 22:31:32 +00:00
|
|
|
// called by src/sim65816.c
|
|
|
|
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_release_kimage(Kimage* kimage_ptr) { }
|
|
|
|
int x_calc_ratio(float x,float y) { return 1; }
|
2018-08-13 17:22:40 +00:00
|
|
|
void x_set_mask_and_shift(word32 x_mask, word32 *mask_ptr, int *shift_left_ptr, int *shift_right_ptr) { return; }
|
2016-02-08 05:01:25 +00:00
|
|
|
void x_update_color(int col_num, int red, int green, int blue, word32 rgb) { }
|
|
|
|
void x_update_physical_colormap() { }
|
|
|
|
void show_xcolor_array() { }
|