2457 lines
58 KiB
C
2457 lines
58 KiB
C
/*
|
|
* atari_sdl.c - SDL library specific port code
|
|
*
|
|
* Copyright (c) 2001-2002 Jacek Poplawski
|
|
* Copyright (C) 2001-2005 Atari800 development team (see DOC/CREDITS)
|
|
*
|
|
* This file is part of the Atari800 emulator project which emulates
|
|
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
|
*
|
|
* Atari800 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.
|
|
*
|
|
* Atari800 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 Atari800; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
/*
|
|
Thanks to David Olofson for scaling tips!
|
|
|
|
TODO:
|
|
- implement all Atari800 parameters
|
|
- turn off fullscreen when error happen
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include <SDL.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#ifdef linux
|
|
#define LPTJOY 1
|
|
#endif
|
|
|
|
#ifdef LPTJOY
|
|
#include <fcntl.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/ioctl.h>
|
|
#include <linux/lp.h>
|
|
#endif /* LPTJOY */
|
|
|
|
/* Atari800 includes */
|
|
#include "input.h"
|
|
#include "akey.h"
|
|
#include "colours.h"
|
|
#include "monitor.h"
|
|
#include "platform.h"
|
|
#include "ui.h"
|
|
#include "screen.h"
|
|
#include "pokeysnd.h"
|
|
#include "gtia.h"
|
|
#include "antic.h"
|
|
#include "devices.h"
|
|
#include "cpu.h"
|
|
#include "memory.h"
|
|
#include "pia.h"
|
|
#include "log.h"
|
|
#include "util.h"
|
|
#include "atari_ntsc.h"
|
|
#include "pbi_proto80.h"
|
|
#include "xep80.h"
|
|
#include "xep80_fonts.h"
|
|
|
|
/* you can set that variables in code, or change it when emulator is running
|
|
I am not sure what to do with sound_enabled (can't turn it on inside
|
|
emulator, probably we need two variables or command line argument) */
|
|
#ifdef SOUND
|
|
#include "sound.h"
|
|
static int sound_enabled = TRUE;
|
|
static int sound_flags = 0;
|
|
#ifdef ANDROID
|
|
static int sound_bits = 16;
|
|
#else
|
|
static int sound_bits = 8;
|
|
#endif
|
|
#endif
|
|
static int fullscreen = 1;
|
|
static int grab_mouse = 0;
|
|
static int bw = 0;
|
|
static int swap_joysticks = 0;
|
|
static int width_mode = 1;
|
|
static int scanlines_percentage = 5;
|
|
static int scanlinesnoint = FALSE;
|
|
static atari_ntsc_t *the_ntscemu = NULL;
|
|
#define SHORT_WIDTH_MODE 0
|
|
#define DEFAULT_WIDTH_MODE 1
|
|
#define FULL_WIDTH_MODE 2
|
|
|
|
/* joystick emulation
|
|
keys are loaded from config file
|
|
Here the defaults if there is no keymap in the config file... */
|
|
|
|
/* a runtime switch for the kbd_joy_X_enabled vars is in the UI */
|
|
int PLATFORM_kbd_joy_0_enabled = TRUE; /* enabled by default, doesn't hurt */
|
|
int PLATFORM_kbd_joy_1_enabled = FALSE; /* disabled, would steal normal keys */
|
|
|
|
static int KBD_TRIG_0 = SDLK_RCTRL;
|
|
static int KBD_STICK_0_LEFT = SDLK_KP4;
|
|
static int KBD_STICK_0_RIGHT = SDLK_KP6;
|
|
static int KBD_STICK_0_DOWN = SDLK_KP5;
|
|
static int KBD_STICK_0_UP = SDLK_KP8;
|
|
static int KBD_TRIG_1 = SDLK_LCTRL;
|
|
static int KBD_STICK_1_LEFT = SDLK_a;
|
|
static int KBD_STICK_1_RIGHT = SDLK_d;
|
|
static int KBD_STICK_1_DOWN = SDLK_s;
|
|
static int KBD_STICK_1_UP = SDLK_w;
|
|
|
|
/* real joysticks */
|
|
|
|
static int fd_joystick0 = -1;
|
|
static int fd_joystick1 = -1;
|
|
|
|
static SDL_Joystick *joystick0 = NULL;
|
|
static SDL_Joystick *joystick1 = NULL;
|
|
static int joystick0_nbuttons;
|
|
static int joystick1_nbuttons;
|
|
|
|
#define minjoy 10000 /* real joystick tolerancy */
|
|
|
|
#ifdef SOUND
|
|
/* sound */
|
|
#define FRAGSIZE 10 /* 1<<FRAGSIZE is size of sound buffer in samples */
|
|
static int dsp_buffer_samps = (1 << FRAGSIZE);
|
|
static int dsp_buffer_bytes;
|
|
static Uint8 *dsp_buffer = NULL;
|
|
static int dsprate = 44100;
|
|
#endif
|
|
|
|
/* video */
|
|
static SDL_Surface *MainScreen = NULL;
|
|
static SDL_Color colors[256]; /* palette */
|
|
static Uint16 Palette16[256]; /* 16-bit palette */
|
|
static Uint32 Palette32[256]; /* 32-bit palette */
|
|
int PLATFORM_xep80 = FALSE; /* is the XEP80 screen displayed? */
|
|
enum PLATFORM_filter_t PLATFORM_filter = PLATFORM_FILTER_NONE;
|
|
|
|
/* SDL port supports 5 "display modes":
|
|
- normal,
|
|
- rotated 9 degrees,
|
|
- ntscemu - emulation of NTSC composite video,
|
|
- xep80 emulation,
|
|
- proto80 - emulation of 80 column board for 1090XL.
|
|
The structure below is used to hold settings and functions used by a single
|
|
display mode. */
|
|
struct display_mode_data_t {
|
|
int w;
|
|
int h;
|
|
int bpp;
|
|
void (*set_video_mode_func)(int, int); /* see below */
|
|
void (*display_screen_func)(Uint8 *); /* see below */
|
|
};
|
|
|
|
/* set_video_mode_func - these functions reset the SDL screen to the given
|
|
width and height. SetNewVideoModeNormal remembers the given W and H
|
|
parameters and sets the screen accordingly, while SetNewVideoModeIgnore
|
|
ignores W and H and sets the screen according to default parameters defined
|
|
in the DISPLAY_MODES table below. */
|
|
static void SetNewVideoModeNormal(int w, int h);
|
|
static void SetNewVideoModeIgnore(int w, int h);
|
|
|
|
/* display_screen_func - these functions fill the given SCREEN buffer with
|
|
screen data, differently for each display mode. */
|
|
static void DisplayNormal(Uint8 *screen);
|
|
static void DisplayRotated240x320(Uint8 *screen);
|
|
static void DisplayNTSCEmu640x480(Uint8 *screen);
|
|
static void DisplayXEP80(Uint8 *screen);
|
|
static void DisplayProto80640x400(Uint8 *screen);
|
|
|
|
/* This table holds default settings for all display modes. */
|
|
static struct display_mode_data_t display_modes[] = {
|
|
/* Normal */
|
|
{ Screen_WIDTH, Screen_HEIGHT, 0, /* bpp = 0 - autodetect */
|
|
&SetNewVideoModeNormal, &DisplayNormal },
|
|
/* Rotated */
|
|
{ 240, 320, 16,
|
|
&SetNewVideoModeIgnore, &DisplayRotated240x320 },
|
|
/* NTSCEmu */
|
|
{ 640, 480, 16,
|
|
&SetNewVideoModeIgnore, &DisplayNTSCEmu640x480 },
|
|
/* XEP80 */
|
|
{ XEP80_SCRN_WIDTH, XEP80_SCRN_HEIGHT, 8,
|
|
&SetNewVideoModeIgnore, &DisplayXEP80 },
|
|
/* Proto80 */
|
|
{ 640, 400, 16,
|
|
&SetNewVideoModeIgnore, &DisplayProto80640x400 }
|
|
};
|
|
|
|
/* An enumerator to switch display modes comfortably. */
|
|
enum display_mode_t {
|
|
display_normal,
|
|
display_rotated,
|
|
display_ntscemu,
|
|
display_xep80,
|
|
display_proto80
|
|
};
|
|
/* Indicates current display mode */
|
|
static enum display_mode_t current_display_mode = display_normal;
|
|
/* Display mode which should be reverted to, when XEP80 mode is turned off */
|
|
static enum display_mode_t xep80_return_display_mode = display_normal;
|
|
|
|
/* keyboard */
|
|
/* static Uint8 *kbhits = NULL; */
|
|
#define kbhits SDL_GetKeyState(NULL)
|
|
|
|
/* For better handling of the PLATFORM_Configure-recognition...
|
|
Takes a keySym as integer-string and fills the value
|
|
into the retval referentially.
|
|
Authors: B.Schreiber, A.Martinez
|
|
fixed and cleaned up by joy */
|
|
static int SDLKeyBind(int *retval, char *sdlKeySymIntStr)
|
|
{
|
|
int ksym;
|
|
|
|
if (retval == NULL || sdlKeySymIntStr == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
/* make an int out of the keySymIntStr... */
|
|
ksym = Util_sscandec(sdlKeySymIntStr);
|
|
|
|
if (ksym > SDLK_FIRST && ksym < SDLK_LAST) {
|
|
*retval = ksym;
|
|
return TRUE;
|
|
}
|
|
else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/* For getting sdl key map out of the config...
|
|
Authors: B.Schreiber, A.Martinez
|
|
cleaned up by joy */
|
|
int PLATFORM_Configure(char *option, char *parameters)
|
|
{
|
|
if (strcmp(option, "SDL_JOY_0_ENABLED") == 0) {
|
|
PLATFORM_kbd_joy_0_enabled = (parameters != NULL && parameters[0] != '0');
|
|
return TRUE;
|
|
}
|
|
else if (strcmp(option, "SDL_JOY_1_ENABLED") == 0) {
|
|
PLATFORM_kbd_joy_1_enabled = (parameters != NULL && parameters[0] != '0');
|
|
return TRUE;
|
|
}
|
|
else if (strcmp(option, "SDL_JOY_0_LEFT") == 0)
|
|
return SDLKeyBind(&KBD_STICK_0_LEFT, parameters);
|
|
else if (strcmp(option, "SDL_JOY_0_RIGHT") == 0)
|
|
return SDLKeyBind(&KBD_STICK_0_RIGHT, parameters);
|
|
else if (strcmp(option, "SDL_JOY_0_DOWN") == 0)
|
|
return SDLKeyBind(&KBD_STICK_0_DOWN, parameters);
|
|
else if (strcmp(option, "SDL_JOY_0_UP") == 0)
|
|
return SDLKeyBind(&KBD_STICK_0_UP, parameters);
|
|
else if (strcmp(option, "SDL_JOY_0_TRIGGER") == 0)
|
|
return SDLKeyBind(&KBD_TRIG_0, parameters);
|
|
else if (strcmp(option, "SDL_JOY_1_LEFT") == 0)
|
|
return SDLKeyBind(&KBD_STICK_1_LEFT, parameters);
|
|
else if (strcmp(option, "SDL_JOY_1_RIGHT") == 0)
|
|
return SDLKeyBind(&KBD_STICK_1_RIGHT, parameters);
|
|
else if (strcmp(option, "SDL_JOY_1_DOWN") == 0)
|
|
return SDLKeyBind(&KBD_STICK_1_DOWN, parameters);
|
|
else if (strcmp(option, "SDL_JOY_1_UP") == 0)
|
|
return SDLKeyBind(&KBD_STICK_1_UP, parameters);
|
|
else if (strcmp(option, "SDL_JOY_1_TRIGGER") == 0)
|
|
return SDLKeyBind(&KBD_TRIG_1, parameters);
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
/* Save the keybindings and the keybindapp options to the config file...
|
|
Authors: B.Schreiber, A.Martinez
|
|
cleaned up by joy */
|
|
void PLATFORM_ConfigSave(FILE *fp)
|
|
{
|
|
fprintf(fp, "SDL_JOY_0_ENABLED=%d\n", PLATFORM_kbd_joy_0_enabled);
|
|
fprintf(fp, "SDL_JOY_0_LEFT=%d\n", KBD_STICK_0_LEFT);
|
|
fprintf(fp, "SDL_JOY_0_RIGHT=%d\n", KBD_STICK_0_RIGHT);
|
|
fprintf(fp, "SDL_JOY_0_UP=%d\n", KBD_STICK_0_UP);
|
|
fprintf(fp, "SDL_JOY_0_DOWN=%d\n", KBD_STICK_0_DOWN);
|
|
fprintf(fp, "SDL_JOY_0_TRIGGER=%d\n", KBD_TRIG_0);
|
|
|
|
fprintf(fp, "SDL_JOY_1_ENABLED=%d\n", PLATFORM_kbd_joy_1_enabled);
|
|
fprintf(fp, "SDL_JOY_1_LEFT=%d\n", KBD_STICK_1_LEFT);
|
|
fprintf(fp, "SDL_JOY_1_RIGHT=%d\n", KBD_STICK_1_RIGHT);
|
|
fprintf(fp, "SDL_JOY_1_UP=%d\n", KBD_STICK_1_UP);
|
|
fprintf(fp, "SDL_JOY_1_DOWN=%d\n", KBD_STICK_1_DOWN);
|
|
fprintf(fp, "SDL_JOY_1_TRIGGER=%d\n", KBD_TRIG_1);
|
|
}
|
|
|
|
void PLATFORM_SetJoystickKey(int joystick, int direction, int value)
|
|
{
|
|
if (joystick == 0) {
|
|
switch(direction) {
|
|
case 0: KBD_STICK_0_LEFT = value; break;
|
|
case 1: KBD_STICK_0_UP = value; break;
|
|
case 2: KBD_STICK_0_RIGHT = value; break;
|
|
case 3: KBD_STICK_0_DOWN = value; break;
|
|
case 4: KBD_TRIG_0 = value; break;
|
|
}
|
|
}
|
|
else {
|
|
switch(direction) {
|
|
case 0: KBD_STICK_1_LEFT = value; break;
|
|
case 1: KBD_STICK_1_UP = value; break;
|
|
case 2: KBD_STICK_1_RIGHT = value; break;
|
|
case 3: KBD_STICK_1_DOWN = value; break;
|
|
case 4: KBD_TRIG_1 = value; break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void PLATFORM_GetJoystickKeyName(int joystick, int direction, char *buffer, int bufsize)
|
|
{
|
|
char *key = "";
|
|
switch(direction) {
|
|
case 0: key = SDL_GetKeyName((SDLKey)(joystick == 0 ? KBD_STICK_0_LEFT : KBD_STICK_1_LEFT));
|
|
break;
|
|
case 1: key = SDL_GetKeyName((SDLKey)(joystick == 0 ? KBD_STICK_0_UP : KBD_STICK_1_UP));
|
|
break;
|
|
case 2: key = SDL_GetKeyName((SDLKey)(joystick == 0 ? KBD_STICK_0_RIGHT : KBD_STICK_1_RIGHT));
|
|
break;
|
|
case 3: key = SDL_GetKeyName((SDLKey)(joystick == 0 ? KBD_STICK_0_DOWN : KBD_STICK_1_DOWN));
|
|
break;
|
|
case 4: key = SDL_GetKeyName((SDLKey)(joystick == 0 ? KBD_TRIG_0 : KBD_TRIG_1));
|
|
break;
|
|
}
|
|
snprintf(buffer, bufsize, "%11s", key);
|
|
buffer[bufsize-1] = '\0';
|
|
}
|
|
|
|
#ifdef SOUND
|
|
|
|
void Sound_Pause(void)
|
|
{
|
|
if (sound_enabled) {
|
|
/* stop audio output */
|
|
SDL_PauseAudio(1);
|
|
}
|
|
}
|
|
|
|
void Sound_Continue(void)
|
|
{
|
|
if (sound_enabled) {
|
|
/* start audio output */
|
|
SDL_PauseAudio(0);
|
|
}
|
|
}
|
|
|
|
void Sound_Update(void)
|
|
{
|
|
/* fake function */
|
|
}
|
|
|
|
#endif /* SOUND */
|
|
|
|
static void SetPalette(void)
|
|
{
|
|
SDL_SetPalette(MainScreen, SDL_LOGPAL | SDL_PHYSPAL, colors, 0, 256);
|
|
}
|
|
|
|
static void CalcPalette(void)
|
|
{
|
|
int i, rgb;
|
|
float y;
|
|
Uint32 c;
|
|
if (bw == 0)
|
|
for (i = 0; i < 256; i++) {
|
|
rgb = Colours_table[i];
|
|
colors[i].r = (rgb & 0x00ff0000) >> 16;
|
|
colors[i].g = (rgb & 0x0000ff00) >> 8;
|
|
colors[i].b = (rgb & 0x000000ff) >> 0;
|
|
}
|
|
else
|
|
for (i = 0; i < 256; i++) {
|
|
rgb = Colours_table[i];
|
|
y = 0.299 * ((rgb & 0x00ff0000) >> 16) +
|
|
0.587 * ((rgb & 0x0000ff00) >> 8) +
|
|
0.114 * ((rgb & 0x000000ff) >> 0);
|
|
colors[i].r = (Uint8)y;
|
|
colors[i].g = (Uint8)y;
|
|
colors[i].b = (Uint8)y;
|
|
}
|
|
for (i = 0; i < 256; i++) {
|
|
c =
|
|
SDL_MapRGB(MainScreen->format, colors[i].r, colors[i].g,
|
|
colors[i].b);
|
|
switch (MainScreen->format->BitsPerPixel) {
|
|
case 16:
|
|
Palette16[i] = (Uint16) c;
|
|
break;
|
|
case 32:
|
|
Palette32[i] = (Uint32) c;
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void PLATFORM_PaletteUpdate(void)
|
|
{
|
|
CalcPalette();
|
|
}
|
|
|
|
static void ModeInfo(void)
|
|
{
|
|
char bwflag, fullflag, width, joyflag;
|
|
if (bw)
|
|
bwflag = '*';
|
|
else
|
|
bwflag = ' ';
|
|
if (fullscreen)
|
|
fullflag = '*';
|
|
else
|
|
fullflag = ' ';
|
|
switch (width_mode) {
|
|
case FULL_WIDTH_MODE:
|
|
width = 'f';
|
|
break;
|
|
case DEFAULT_WIDTH_MODE:
|
|
width = 'd';
|
|
break;
|
|
case SHORT_WIDTH_MODE:
|
|
width = 's';
|
|
break;
|
|
default:
|
|
width = '?';
|
|
break;
|
|
}
|
|
if (swap_joysticks)
|
|
joyflag = '*';
|
|
else
|
|
joyflag = ' ';
|
|
Log_print("Video Mode: %dx%dx%d", MainScreen->w, MainScreen->h,
|
|
MainScreen->format->BitsPerPixel);
|
|
Log_print("[%c] Full screen [%c] BW [%c] Width Mode [%c] Joysticks Swapped",
|
|
fullflag, bwflag, width, joyflag);
|
|
}
|
|
|
|
static void SetVideoMode(int w, int h, int bpp)
|
|
{
|
|
if (fullscreen)
|
|
MainScreen = SDL_SetVideoMode(w, h, bpp, SDL_FULLSCREEN);
|
|
else
|
|
MainScreen = SDL_SetVideoMode(w, h, bpp, SDL_RESIZABLE);
|
|
if (MainScreen == NULL) {
|
|
Log_print("Setting Video Mode: %dx%dx%d FAILED", w, h, bpp);
|
|
Log_flushlog();
|
|
exit(-1);
|
|
}
|
|
}
|
|
|
|
static void SetNewVideoModeNormal(int w, int h)
|
|
{
|
|
int bpp = display_modes[current_display_mode].bpp;
|
|
float ww, hh;
|
|
|
|
if ((h < Screen_HEIGHT) || (w < Screen_WIDTH)) {
|
|
h = Screen_HEIGHT;
|
|
w = Screen_WIDTH;
|
|
}
|
|
|
|
/* aspect ratio, floats needed */
|
|
ww = w;
|
|
hh = h;
|
|
switch (width_mode) {
|
|
case SHORT_WIDTH_MODE:
|
|
if (ww * 0.75 < hh)
|
|
hh = ww * 0.75;
|
|
else
|
|
ww = hh / 0.75;
|
|
break;
|
|
case DEFAULT_WIDTH_MODE:
|
|
if (ww / 1.4 < hh)
|
|
hh = ww / 1.4;
|
|
else
|
|
ww = hh * 1.4;
|
|
break;
|
|
case FULL_WIDTH_MODE:
|
|
if (ww / 1.6 < hh)
|
|
hh = ww / 1.6;
|
|
else
|
|
ww = hh * 1.6;
|
|
break;
|
|
}
|
|
w = (int)ww;
|
|
h = (int)hh;
|
|
w /= 8;
|
|
w *= 8;
|
|
h /= 8;
|
|
h *= 8;
|
|
|
|
display_modes[current_display_mode].w = w;
|
|
display_modes[current_display_mode].h = h;
|
|
|
|
/* Only the BPPs below are supported. Default to 8 bits otherwise. */
|
|
if (bpp != 0 && bpp != 8 && bpp != 16 && bpp != 32) {
|
|
Log_print("BPP %d unsupported, so setting 8bit mode (slow conversion)", bpp);
|
|
bpp = 8;
|
|
}
|
|
SetVideoMode(w, h, bpp);
|
|
if (bpp == 0) {
|
|
bpp = MainScreen->format->BitsPerPixel;
|
|
Log_print("detected %dbpp", bpp);
|
|
if ((bpp != 8) && (bpp != 16)
|
|
&& (bpp != 32)) {
|
|
Log_print("it's unsupported, so setting 8bit mode (slow conversion)");
|
|
bpp = 8;
|
|
SetVideoMode(w, h, 8);
|
|
}
|
|
}
|
|
|
|
/* Save bpp in case it changed above */
|
|
display_modes[current_display_mode].bpp = bpp;
|
|
}
|
|
|
|
static void SetNewVideoModeIgnore(int w, int h)
|
|
{
|
|
SetVideoMode(display_modes[current_display_mode].w,
|
|
display_modes[current_display_mode].h,
|
|
display_modes[current_display_mode].bpp);
|
|
}
|
|
|
|
/* Reinitialises the SDL screen using current_display_mode and its parameters.
|
|
*/
|
|
static void ResetDisplay(void)
|
|
{
|
|
(*display_modes[current_display_mode].set_video_mode_func)(display_modes[current_display_mode].w,
|
|
display_modes[current_display_mode].h);
|
|
CalcPalette();
|
|
SetPalette();
|
|
|
|
SDL_ShowCursor(SDL_DISABLE); /* hide mouse cursor */
|
|
|
|
ModeInfo();
|
|
}
|
|
|
|
/* Resizes the SDL screen using current_display_mode and the given Width and
|
|
Height. */
|
|
static void ResizeDisplay(int w, int h)
|
|
{
|
|
(*display_modes[current_display_mode].set_video_mode_func)(w, h);
|
|
SetPalette();
|
|
|
|
SDL_ShowCursor(SDL_DISABLE); /* hide mouse cursor */
|
|
|
|
ModeInfo();
|
|
}
|
|
|
|
static void SwitchFullscreen(void)
|
|
{
|
|
fullscreen = 1 - fullscreen;
|
|
ResetDisplay();
|
|
PLATFORM_DisplayScreen();
|
|
}
|
|
|
|
void PLATFORM_SetFilter(const enum PLATFORM_filter_t filter)
|
|
{
|
|
/* Mode to return when filter is turned off */
|
|
static enum display_mode_t saved_display_mode;
|
|
|
|
/* When the display is in XEP80 mode, the filter should not be
|
|
switched on/off immediately. It should be switched only when
|
|
XEP80 mode is turned off. The variable below indicates which is
|
|
the case. */
|
|
int change_later = (current_display_mode == display_xep80);
|
|
|
|
/* Currently switching filter makes no sense when the emulator
|
|
is running in PROTO80 mode. */
|
|
if (current_display_mode == display_proto80)
|
|
return;
|
|
|
|
PLATFORM_filter = filter;
|
|
|
|
if (filter == PLATFORM_FILTER_NONE && the_ntscemu != NULL) {
|
|
/* Turning filter off */
|
|
free(the_ntscemu);
|
|
the_ntscemu = NULL;
|
|
if (change_later)
|
|
xep80_return_display_mode = saved_display_mode;
|
|
else {
|
|
current_display_mode = saved_display_mode;
|
|
ResetDisplay();
|
|
}
|
|
}
|
|
else if (filter == PLATFORM_FILTER_NTSC && the_ntscemu == NULL) {
|
|
/* Turning filter on */
|
|
the_ntscemu = (atari_ntsc_t*) Util_malloc(sizeof(atari_ntsc_t));
|
|
atari_ntsc_init( the_ntscemu, &atari_ntsc_setup );
|
|
if (change_later) {
|
|
saved_display_mode = xep80_return_display_mode;
|
|
xep80_return_display_mode = display_ntscemu;
|
|
} else {
|
|
saved_display_mode = current_display_mode;
|
|
current_display_mode = display_ntscemu;
|
|
ResetDisplay();
|
|
}
|
|
}
|
|
}
|
|
|
|
void PLATFORM_SwitchXep80(void)
|
|
{
|
|
PLATFORM_xep80 = 1 - PLATFORM_xep80;
|
|
if (PLATFORM_xep80) {
|
|
xep80_return_display_mode = current_display_mode;
|
|
current_display_mode = display_xep80;
|
|
}
|
|
else
|
|
current_display_mode = xep80_return_display_mode;
|
|
ResetDisplay();
|
|
PLATFORM_DisplayScreen();
|
|
}
|
|
|
|
static void SwitchWidth(void)
|
|
{
|
|
width_mode++;
|
|
if (width_mode > FULL_WIDTH_MODE)
|
|
width_mode = SHORT_WIDTH_MODE;
|
|
|
|
ResetDisplay();
|
|
PLATFORM_DisplayScreen();
|
|
}
|
|
|
|
static void SwitchBW(void)
|
|
{
|
|
bw = 1 - bw;
|
|
CalcPalette();
|
|
SetPalette();
|
|
ModeInfo();
|
|
}
|
|
|
|
static void SwapJoysticks(void)
|
|
{
|
|
swap_joysticks = 1 - swap_joysticks;
|
|
ModeInfo();
|
|
}
|
|
|
|
#ifdef SOUND
|
|
static void SoundCallback(void *userdata, Uint8 *stream, int len)
|
|
{
|
|
int sndn = (sound_bits == 8 ? len : len/2);
|
|
/* in mono, sndn is the number of samples (8 or 16 bit) */
|
|
/* in stereo, 2*sndn is the number of sample pairs */
|
|
POKEYSND_Process(dsp_buffer, sndn);
|
|
memcpy(stream, dsp_buffer, len);
|
|
}
|
|
|
|
static void SoundSetup(void)
|
|
{
|
|
SDL_AudioSpec desired, obtained;
|
|
if (sound_enabled) {
|
|
desired.freq = dsprate;
|
|
if (sound_bits == 8)
|
|
desired.format = AUDIO_U8;
|
|
else if (sound_bits == 16)
|
|
desired.format = AUDIO_S16;
|
|
else {
|
|
Log_print("unknown sound_bits");
|
|
Atari800_Exit(FALSE);
|
|
Log_flushlog();
|
|
}
|
|
|
|
desired.samples = dsp_buffer_samps;
|
|
desired.callback = SoundCallback;
|
|
desired.userdata = NULL;
|
|
#ifdef STEREO_SOUND
|
|
desired.channels = POKEYSND_stereo_enabled ? 2 : 1;
|
|
#else
|
|
desired.channels = 1;
|
|
#endif /* STEREO_SOUND*/
|
|
|
|
if (SDL_OpenAudio(&desired, &obtained) < 0) {
|
|
Log_print("Problem with audio: %s", SDL_GetError());
|
|
Log_print("Sound is disabled.");
|
|
sound_enabled = FALSE;
|
|
return;
|
|
}
|
|
|
|
free(dsp_buffer);
|
|
dsp_buffer_samps = obtained.samples;
|
|
dsp_buffer_bytes = desired.channels*dsp_buffer_samps*(sound_bits == 8 ? 1 : 2);
|
|
dsp_buffer = (Uint8 *)Util_malloc(dsp_buffer_bytes);
|
|
POKEYSND_Init(POKEYSND_FREQ_17_EXACT, dsprate, desired.channels, sound_flags);
|
|
SDL_PauseAudio(0);
|
|
}
|
|
}
|
|
|
|
void Sound_Reinit(void)
|
|
{
|
|
SDL_CloseAudio();
|
|
SoundSetup();
|
|
}
|
|
|
|
static void SoundInitialise(int *argc, char *argv[])
|
|
{
|
|
int i, j;
|
|
|
|
for (i = j = 1; i < *argc; i++) {
|
|
if (strcmp(argv[i], "-sound") == 0)
|
|
sound_enabled = TRUE;
|
|
else if (strcmp(argv[i], "-nosound") == 0)
|
|
sound_enabled = FALSE;
|
|
else if (strcmp(argv[i], "-audio16") == 0) {
|
|
Log_print("audio 16bit enabled");
|
|
sound_flags |= POKEYSND_BIT16;
|
|
sound_bits = 16;
|
|
}
|
|
else if (strcmp(argv[i], "-dsprate") == 0)
|
|
dsprate = Util_sscandec(argv[++i]);
|
|
else {
|
|
if (strcmp(argv[i], "-help") == 0) {
|
|
Log_print("\t-sound Enable sound");
|
|
Log_print("\t-nosound Disable sound");
|
|
Log_print("\t-audio16 Enable 16-bit sound output");
|
|
Log_print("\t-dsprate <rate> Set DSP rate in Hz");
|
|
sound_enabled = FALSE;
|
|
}
|
|
argv[j++] = argv[i];
|
|
}
|
|
}
|
|
*argc = j;
|
|
|
|
SoundSetup();
|
|
}
|
|
#endif /* SOUND */
|
|
|
|
int PLATFORM_GetRawKey(void)
|
|
{
|
|
while(TRUE)
|
|
{
|
|
SDL_Event event;
|
|
if (SDL_PollEvent(&event)) {
|
|
switch (event.type) {
|
|
case SDL_KEYDOWN:
|
|
return event.key.keysym.sym;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int PLATFORM_Keyboard(void)
|
|
{
|
|
static int lastkey = SDLK_UNKNOWN, key_pressed = 0, key_control = 0;
|
|
static int lastuni = 0;
|
|
int shiftctrl = 0;
|
|
SDL_Event event;
|
|
|
|
/* Very ugly fix for SDL CAPSLOCK brokenness. This will let the user
|
|
* press CAPSLOCK and get a brief keypress on the Atari but it is not
|
|
* possible to emulate holding down CAPSLOCK for longer periods with
|
|
* the broken SDL*/
|
|
if (lastkey == SDLK_CAPSLOCK) {
|
|
lastkey = SDLK_UNKNOWN;
|
|
key_pressed = 0;
|
|
lastuni = 0;
|
|
}
|
|
if (SDL_PollEvent(&event)) {
|
|
switch (event.type) {
|
|
case SDL_KEYDOWN:
|
|
lastkey = event.key.keysym.sym;
|
|
lastuni = event.key.keysym.unicode;
|
|
key_pressed = 1;
|
|
break;
|
|
case SDL_KEYUP:
|
|
lastkey = event.key.keysym.sym;
|
|
lastuni = 0; /* event.key.keysym.unicode is not defined for KEYUP */
|
|
key_pressed = 0;
|
|
/* ugly hack to fix broken SDL CAPSLOCK*/
|
|
/* Because SDL is only sending Keydown and keyup for every change
|
|
* of state of the CAPSLOCK status, rather than the actual key.*/
|
|
if(lastkey == SDLK_CAPSLOCK) {
|
|
key_pressed = 1;
|
|
}
|
|
break;
|
|
case SDL_VIDEORESIZE:
|
|
ResizeDisplay(event.resize.w, event.resize.h);
|
|
break;
|
|
case SDL_QUIT:
|
|
return AKEY_EXIT;
|
|
break;
|
|
}
|
|
}
|
|
else if (!key_pressed)
|
|
return AKEY_NONE;
|
|
|
|
/* kbhits = SDL_GetKeyState(NULL); */
|
|
|
|
if (kbhits == NULL) {
|
|
Log_print("oops, kbhits is NULL!");
|
|
Log_flushlog();
|
|
exit(-1);
|
|
}
|
|
|
|
UI_alt_function = -1;
|
|
if (kbhits[SDLK_LALT]) {
|
|
if (key_pressed) {
|
|
switch (lastkey) {
|
|
case SDLK_f:
|
|
key_pressed = 0;
|
|
SwitchFullscreen();
|
|
break;
|
|
case SDLK_x:
|
|
if (INPUT_key_shift && XEP80_enabled) {
|
|
key_pressed = 0;
|
|
PLATFORM_SwitchXep80();
|
|
}
|
|
break;
|
|
case SDLK_g:
|
|
key_pressed = 0;
|
|
SwitchWidth();
|
|
break;
|
|
case SDLK_b:
|
|
key_pressed = 0;
|
|
SwitchBW();
|
|
break;
|
|
case SDLK_j:
|
|
key_pressed = 0;
|
|
SwapJoysticks();
|
|
break;
|
|
case SDLK_r:
|
|
UI_alt_function = UI_MENU_RUN;
|
|
break;
|
|
case SDLK_y:
|
|
UI_alt_function = UI_MENU_SYSTEM;
|
|
break;
|
|
case SDLK_o:
|
|
UI_alt_function = UI_MENU_SOUND;
|
|
break;
|
|
case SDLK_w:
|
|
UI_alt_function = UI_MENU_SOUND_RECORDING;
|
|
break;
|
|
case SDLK_a:
|
|
UI_alt_function = UI_MENU_ABOUT;
|
|
break;
|
|
case SDLK_s:
|
|
UI_alt_function = UI_MENU_SAVESTATE;
|
|
break;
|
|
case SDLK_d:
|
|
UI_alt_function = UI_MENU_DISK;
|
|
break;
|
|
case SDLK_l:
|
|
UI_alt_function = UI_MENU_LOADSTATE;
|
|
break;
|
|
case SDLK_c:
|
|
UI_alt_function = UI_MENU_CARTRIDGE;
|
|
break;
|
|
case SDLK_BACKSLASH:
|
|
return AKEY_PBI_BB_MENU;
|
|
case SDLK_m:
|
|
grab_mouse = !grab_mouse;
|
|
SDL_WM_GrabInput(grab_mouse ? SDL_GRAB_ON : SDL_GRAB_OFF);
|
|
key_pressed = 0;
|
|
break;
|
|
default:
|
|
if(current_display_mode == display_ntscemu){
|
|
switch(lastkey){
|
|
case SDLK_1:
|
|
key_pressed = 0;
|
|
atari_ntsc_setup.sharpness-=0.1;
|
|
atari_ntsc_init( the_ntscemu, &atari_ntsc_setup );
|
|
break;
|
|
case SDLK_2:
|
|
key_pressed = 0;
|
|
atari_ntsc_setup.sharpness+=0.1;
|
|
atari_ntsc_init( the_ntscemu, &atari_ntsc_setup );
|
|
break;
|
|
case SDLK_3:
|
|
key_pressed = 0;
|
|
atari_ntsc_setup.saturation-=0.1;
|
|
atari_ntsc_init( the_ntscemu, &atari_ntsc_setup );
|
|
break;
|
|
case SDLK_4:
|
|
key_pressed = 0;
|
|
atari_ntsc_setup.saturation+=0.1;
|
|
atari_ntsc_init( the_ntscemu, &atari_ntsc_setup );
|
|
break;
|
|
case SDLK_5:
|
|
key_pressed = 0;
|
|
atari_ntsc_setup.brightness-=0.1;
|
|
atari_ntsc_init( the_ntscemu, &atari_ntsc_setup );
|
|
break;
|
|
case SDLK_6:
|
|
key_pressed = 0;
|
|
atari_ntsc_setup.brightness+=0.1;
|
|
atari_ntsc_init( the_ntscemu, &atari_ntsc_setup );
|
|
break;
|
|
case SDLK_7:
|
|
key_pressed = 0;
|
|
atari_ntsc_setup.contrast-=0.1;
|
|
atari_ntsc_init( the_ntscemu, &atari_ntsc_setup );
|
|
break;
|
|
case SDLK_8:
|
|
key_pressed = 0;
|
|
atari_ntsc_setup.contrast+=0.1;
|
|
atari_ntsc_init( the_ntscemu, &atari_ntsc_setup );
|
|
break;
|
|
case SDLK_9:
|
|
key_pressed = 0;
|
|
atari_ntsc_setup.burst_phase-=.05;
|
|
atari_ntsc_init( the_ntscemu, &atari_ntsc_setup );
|
|
break;
|
|
case SDLK_0:
|
|
key_pressed = 0;
|
|
atari_ntsc_setup.burst_phase+=.05;
|
|
atari_ntsc_init( the_ntscemu, &atari_ntsc_setup );
|
|
break;
|
|
case SDLK_MINUS:
|
|
key_pressed = 0;
|
|
atari_ntsc_setup.gaussian_factor-=.2;
|
|
atari_ntsc_init( the_ntscemu, &atari_ntsc_setup );
|
|
break;
|
|
case SDLK_EQUALS:
|
|
key_pressed = 0;
|
|
atari_ntsc_setup.gaussian_factor+=.2;
|
|
atari_ntsc_init( the_ntscemu, &atari_ntsc_setup );
|
|
break;
|
|
case SDLK_LEFTBRACKET:
|
|
key_pressed = 0;
|
|
scanlines_percentage -= 5*(scanlines_percentage>=5);
|
|
Log_print("scanlines percentage:%d",scanlines_percentage);
|
|
break;
|
|
case SDLK_RIGHTBRACKET:
|
|
key_pressed = 0;
|
|
scanlines_percentage += 5*(scanlines_percentage<=100-5);
|
|
Log_print("scanlines percentage:%d",scanlines_percentage);
|
|
break;
|
|
case SDLK_SEMICOLON:
|
|
key_pressed = 0;
|
|
atari_ntsc_setup.hue-=.01;
|
|
atari_ntsc_init( the_ntscemu, &atari_ntsc_setup );
|
|
break;
|
|
case SDLK_QUOTE:
|
|
key_pressed = 0;
|
|
atari_ntsc_setup.hue+=.01;
|
|
atari_ntsc_init( the_ntscemu, &atari_ntsc_setup );
|
|
break;
|
|
case SDLK_COMMA:
|
|
key_pressed = 0;
|
|
atari_ntsc_setup.gamma_adj-=.05;
|
|
atari_ntsc_init( the_ntscemu, &atari_ntsc_setup );
|
|
break;
|
|
case SDLK_PERIOD:
|
|
key_pressed = 0;
|
|
atari_ntsc_setup.gamma_adj+=.05;
|
|
atari_ntsc_init( the_ntscemu, &atari_ntsc_setup );
|
|
break;
|
|
case SDLK_INSERT:
|
|
key_pressed = 0;
|
|
atari_ntsc_setup.saturation_ramp-=.05;
|
|
atari_ntsc_init( the_ntscemu, &atari_ntsc_setup );
|
|
break;
|
|
case SDLK_DELETE:
|
|
key_pressed = 0;
|
|
atari_ntsc_setup.saturation_ramp+=.05;
|
|
atari_ntsc_init( the_ntscemu, &atari_ntsc_setup );
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (UI_alt_function != -1) {
|
|
key_pressed = 0;
|
|
return AKEY_UI;
|
|
}
|
|
}
|
|
|
|
/* SHIFT STATE */
|
|
if ((kbhits[SDLK_LSHIFT]) || (kbhits[SDLK_RSHIFT]))
|
|
INPUT_key_shift = 1;
|
|
else
|
|
INPUT_key_shift = 0;
|
|
|
|
/* CONTROL STATE */
|
|
if ((kbhits[SDLK_LCTRL]) || (kbhits[SDLK_RCTRL]))
|
|
key_control = 1;
|
|
else
|
|
key_control = 0;
|
|
|
|
/*
|
|
if (event.type == 2 || event.type == 3) {
|
|
Log_print("E:%x S:%x C:%x K:%x U:%x M:%x",event.type,INPUT_key_shift,key_control,lastkey,event.key.keysym.unicode,event.key.keysym.mod);
|
|
}
|
|
*/
|
|
|
|
/* OPTION / SELECT / START keys */
|
|
INPUT_key_consol = INPUT_CONSOL_NONE;
|
|
if (kbhits[SDLK_F2])
|
|
INPUT_key_consol &= (~INPUT_CONSOL_OPTION);
|
|
if (kbhits[SDLK_F3])
|
|
INPUT_key_consol &= (~INPUT_CONSOL_SELECT);
|
|
if (kbhits[SDLK_F4])
|
|
INPUT_key_consol &= (~INPUT_CONSOL_START);
|
|
|
|
if (key_pressed == 0)
|
|
return AKEY_NONE;
|
|
|
|
/* Handle movement and special keys. */
|
|
switch (lastkey) {
|
|
case SDLK_F1:
|
|
key_pressed = 0;
|
|
return AKEY_UI;
|
|
case SDLK_F5:
|
|
key_pressed = 0;
|
|
return INPUT_key_shift ? AKEY_COLDSTART : AKEY_WARMSTART;
|
|
case SDLK_F8:
|
|
key_pressed = 0;
|
|
return (PLATFORM_Exit(1) ? AKEY_NONE : AKEY_EXIT);
|
|
case SDLK_F9:
|
|
return AKEY_EXIT;
|
|
case SDLK_F10:
|
|
key_pressed = 0;
|
|
return INPUT_key_shift ? AKEY_SCREENSHOT_INTERLACE : AKEY_SCREENSHOT_INTERLACE;
|
|
}
|
|
|
|
/* keyboard joysticks: don't pass the keypresses to emulation
|
|
* as some games pause on a keypress (River Raid, Bruce Lee)
|
|
*/
|
|
if (!UI_is_active && PLATFORM_kbd_joy_0_enabled) {
|
|
if (lastkey == KBD_STICK_0_LEFT || lastkey == KBD_STICK_0_RIGHT ||
|
|
lastkey == KBD_STICK_0_UP || lastkey == KBD_STICK_0_DOWN || lastkey == KBD_TRIG_0) {
|
|
key_pressed = 0;
|
|
return AKEY_NONE;
|
|
}
|
|
}
|
|
|
|
if (!UI_is_active && PLATFORM_kbd_joy_1_enabled) {
|
|
if (lastkey == KBD_STICK_1_LEFT || lastkey == KBD_STICK_1_RIGHT ||
|
|
lastkey == KBD_STICK_1_UP || lastkey == KBD_STICK_1_DOWN || lastkey == KBD_TRIG_1) {
|
|
key_pressed = 0;
|
|
return AKEY_NONE;
|
|
}
|
|
}
|
|
|
|
if (INPUT_key_shift)
|
|
shiftctrl ^= AKEY_SHFT;
|
|
|
|
if (Atari800_machine_type == Atari800_MACHINE_5200 && !UI_is_active) {
|
|
if (lastkey == SDLK_F4)
|
|
return AKEY_5200_START ^ shiftctrl;
|
|
switch (lastuni) {
|
|
case 'p':
|
|
return AKEY_5200_PAUSE ^ shiftctrl;
|
|
case 'r':
|
|
return AKEY_5200_RESET ^ shiftctrl;
|
|
case '0':
|
|
return AKEY_5200_0 ^ shiftctrl;
|
|
case '1':
|
|
return AKEY_5200_1 ^ shiftctrl;
|
|
case '2':
|
|
return AKEY_5200_2 ^ shiftctrl;
|
|
case '3':
|
|
return AKEY_5200_3 ^ shiftctrl;
|
|
case '4':
|
|
return AKEY_5200_4 ^ shiftctrl;
|
|
case '5':
|
|
return AKEY_5200_5 ^ shiftctrl;
|
|
case '6':
|
|
return AKEY_5200_6 ^ shiftctrl;
|
|
case '7':
|
|
return AKEY_5200_7 ^ shiftctrl;
|
|
case '8':
|
|
return AKEY_5200_8 ^ shiftctrl;
|
|
case '9':
|
|
return AKEY_5200_9 ^ shiftctrl;
|
|
case '#':
|
|
case '=':
|
|
return AKEY_5200_HASH ^ shiftctrl;
|
|
case '*':
|
|
return AKEY_5200_ASTERISK ^ shiftctrl;
|
|
}
|
|
return AKEY_NONE;
|
|
}
|
|
|
|
if (key_control)
|
|
shiftctrl ^= AKEY_CTRL;
|
|
|
|
switch (lastkey) {
|
|
case SDLK_BACKQUOTE: /* fallthrough */
|
|
/* These are the "Windows" keys, but they don't work on Windows*/
|
|
case SDLK_LSUPER:
|
|
return AKEY_ATARI ^ shiftctrl;
|
|
case SDLK_RSUPER:
|
|
if (INPUT_key_shift)
|
|
return AKEY_CAPSLOCK;
|
|
else
|
|
return AKEY_CAPSTOGGLE;
|
|
case SDLK_END:
|
|
case SDLK_F6:
|
|
return AKEY_HELP ^ shiftctrl;
|
|
case SDLK_PAGEDOWN:
|
|
return AKEY_F2 | AKEY_SHFT;
|
|
case SDLK_PAGEUP:
|
|
return AKEY_F1 | AKEY_SHFT;
|
|
case SDLK_HOME:
|
|
return key_control ? AKEY_LESS|shiftctrl : AKEY_CLEAR;
|
|
case SDLK_PAUSE:
|
|
case SDLK_F7:
|
|
return AKEY_BREAK;
|
|
case SDLK_CAPSLOCK:
|
|
if (INPUT_key_shift)
|
|
return AKEY_CAPSLOCK|shiftctrl;
|
|
else
|
|
return AKEY_CAPSTOGGLE|shiftctrl;
|
|
case SDLK_SPACE:
|
|
return AKEY_SPACE ^ shiftctrl;
|
|
case SDLK_BACKSPACE:
|
|
return AKEY_BACKSPACE|shiftctrl;
|
|
case SDLK_RETURN:
|
|
return AKEY_RETURN ^ shiftctrl;
|
|
case SDLK_LEFT:
|
|
return (INPUT_key_shift ? AKEY_PLUS : AKEY_LEFT) ^ shiftctrl;
|
|
case SDLK_RIGHT:
|
|
return (INPUT_key_shift ? AKEY_ASTERISK : AKEY_RIGHT) ^ shiftctrl;
|
|
case SDLK_UP:
|
|
return (INPUT_key_shift ? AKEY_MINUS : AKEY_UP) ^ shiftctrl;
|
|
case SDLK_DOWN:
|
|
return (INPUT_key_shift ? AKEY_EQUAL : AKEY_DOWN) ^ shiftctrl;
|
|
case SDLK_ESCAPE:
|
|
/* Windows takes ctrl+esc and ctrl+shift+esc */
|
|
return AKEY_ESCAPE ^ shiftctrl;
|
|
case SDLK_TAB:
|
|
return AKEY_TAB ^ shiftctrl;
|
|
case SDLK_DELETE:
|
|
if (INPUT_key_shift)
|
|
return AKEY_DELETE_LINE|shiftctrl;
|
|
else
|
|
return AKEY_DELETE_CHAR;
|
|
case SDLK_INSERT:
|
|
if (INPUT_key_shift)
|
|
return AKEY_INSERT_LINE|shiftctrl;
|
|
else
|
|
return AKEY_INSERT_CHAR;
|
|
}
|
|
if (INPUT_cx85) switch (lastkey) {
|
|
case SDLK_KP1:
|
|
return AKEY_CX85_1;
|
|
case SDLK_KP2:
|
|
return AKEY_CX85_2;
|
|
case SDLK_KP3:
|
|
return AKEY_CX85_3;
|
|
case SDLK_KP4:
|
|
return AKEY_CX85_4;
|
|
case SDLK_KP5:
|
|
return AKEY_CX85_5;
|
|
case SDLK_KP6:
|
|
return AKEY_CX85_6;
|
|
case SDLK_KP7:
|
|
return AKEY_CX85_7;
|
|
case SDLK_KP8:
|
|
return AKEY_CX85_8;
|
|
case SDLK_KP9:
|
|
return AKEY_CX85_9;
|
|
case SDLK_KP0:
|
|
return AKEY_CX85_0;
|
|
case SDLK_KP_PERIOD:
|
|
return AKEY_CX85_PERIOD;
|
|
case SDLK_KP_MINUS:
|
|
return AKEY_CX85_MINUS;
|
|
case SDLK_KP_ENTER:
|
|
return AKEY_CX85_PLUS_ENTER;
|
|
case SDLK_KP_DIVIDE:
|
|
return (key_control ? AKEY_CX85_ESCAPE : AKEY_CX85_NO);
|
|
case SDLK_KP_MULTIPLY:
|
|
return AKEY_CX85_DELETE;
|
|
case SDLK_KP_PLUS:
|
|
return AKEY_CX85_YES;
|
|
}
|
|
|
|
/* Handle CTRL-0 to CTRL-9 and other control characters */
|
|
if (key_control) {
|
|
switch(lastuni) {
|
|
case '.':
|
|
return AKEY_FULLSTOP|shiftctrl;
|
|
case ',':
|
|
return AKEY_COMMA|shiftctrl;
|
|
case ';':
|
|
return AKEY_SEMICOLON|shiftctrl;
|
|
}
|
|
switch (lastkey) {
|
|
case SDLK_PERIOD:
|
|
return AKEY_FULLSTOP|shiftctrl;
|
|
case SDLK_COMMA:
|
|
return AKEY_COMMA|shiftctrl;
|
|
case SDLK_SEMICOLON:
|
|
return AKEY_SEMICOLON|shiftctrl;
|
|
case SDLK_SLASH:
|
|
return AKEY_SLASH|shiftctrl;
|
|
case SDLK_BACKSLASH:
|
|
/* work-around for Windows */
|
|
return AKEY_ESCAPE|shiftctrl;
|
|
case SDLK_0:
|
|
return AKEY_CTRL_0|shiftctrl;
|
|
case SDLK_1:
|
|
return AKEY_CTRL_1|shiftctrl;
|
|
case SDLK_2:
|
|
return AKEY_CTRL_2|shiftctrl;
|
|
case SDLK_3:
|
|
return AKEY_CTRL_3|shiftctrl;
|
|
case SDLK_4:
|
|
return AKEY_CTRL_4|shiftctrl;
|
|
case SDLK_5:
|
|
return AKEY_CTRL_5|shiftctrl;
|
|
case SDLK_6:
|
|
return AKEY_CTRL_6|shiftctrl;
|
|
case SDLK_7:
|
|
return AKEY_CTRL_7|shiftctrl;
|
|
case SDLK_8:
|
|
return AKEY_CTRL_8|shiftctrl;
|
|
case SDLK_9:
|
|
return AKEY_CTRL_9|shiftctrl;
|
|
}
|
|
}
|
|
|
|
/* Host Caps Lock will make lastuni switch case, so prevent this*/
|
|
if(lastuni>='A' && lastuni <= 'Z' && !INPUT_key_shift) lastuni += 0x20;
|
|
if(lastuni>='a' && lastuni <= 'z' && INPUT_key_shift) lastuni -= 0x20;
|
|
/* Uses only UNICODE translation, no shift states (this was added to
|
|
* support non-US keyboard layouts)*/
|
|
/* input.c takes care of removing invalid shift+control keys */
|
|
switch (lastuni) {
|
|
case 1:
|
|
return AKEY_CTRL_a|shiftctrl;
|
|
case 2:
|
|
return AKEY_CTRL_b|shiftctrl;
|
|
case 3:
|
|
return AKEY_CTRL_c|shiftctrl;
|
|
case 4:
|
|
return AKEY_CTRL_d|shiftctrl;
|
|
case 5:
|
|
return AKEY_CTRL_e|shiftctrl;
|
|
case 6:
|
|
return AKEY_CTRL_f|shiftctrl;
|
|
case 7:
|
|
return AKEY_CTRL_g|shiftctrl;
|
|
case 8:
|
|
return AKEY_CTRL_h|shiftctrl;
|
|
case 9:
|
|
return AKEY_CTRL_i|shiftctrl;
|
|
case 10:
|
|
return AKEY_CTRL_j|shiftctrl;
|
|
case 11:
|
|
return AKEY_CTRL_k|shiftctrl;
|
|
case 12:
|
|
return AKEY_CTRL_l|shiftctrl;
|
|
case 13:
|
|
return AKEY_CTRL_m|shiftctrl;
|
|
case 14:
|
|
return AKEY_CTRL_n|shiftctrl;
|
|
case 15:
|
|
return AKEY_CTRL_o|shiftctrl;
|
|
case 16:
|
|
return AKEY_CTRL_p|shiftctrl;
|
|
case 17:
|
|
return AKEY_CTRL_q|shiftctrl;
|
|
case 18:
|
|
return AKEY_CTRL_r|shiftctrl;
|
|
case 19:
|
|
return AKEY_CTRL_s|shiftctrl;
|
|
case 20:
|
|
return AKEY_CTRL_t|shiftctrl;
|
|
case 21:
|
|
return AKEY_CTRL_u|shiftctrl;
|
|
case 22:
|
|
return AKEY_CTRL_v|shiftctrl;
|
|
case 23:
|
|
return AKEY_CTRL_w|shiftctrl;
|
|
case 24:
|
|
return AKEY_CTRL_x|shiftctrl;
|
|
case 25:
|
|
return AKEY_CTRL_y|shiftctrl;
|
|
case 26:
|
|
return AKEY_CTRL_z|shiftctrl;
|
|
case 'A':
|
|
return AKEY_A;
|
|
case 'B':
|
|
return AKEY_B;
|
|
case 'C':
|
|
return AKEY_C;
|
|
case 'D':
|
|
return AKEY_D;
|
|
case 'E':
|
|
return AKEY_E;
|
|
case 'F':
|
|
return AKEY_F;
|
|
case 'G':
|
|
return AKEY_G;
|
|
case 'H':
|
|
return AKEY_H;
|
|
case 'I':
|
|
return AKEY_I;
|
|
case 'J':
|
|
return AKEY_J;
|
|
case 'K':
|
|
return AKEY_K;
|
|
case 'L':
|
|
return AKEY_L;
|
|
case 'M':
|
|
return AKEY_M;
|
|
case 'N':
|
|
return AKEY_N;
|
|
case 'O':
|
|
return AKEY_O;
|
|
case 'P':
|
|
return AKEY_P;
|
|
case 'Q':
|
|
return AKEY_Q;
|
|
case 'R':
|
|
return AKEY_R;
|
|
case 'S':
|
|
return AKEY_S;
|
|
case 'T':
|
|
return AKEY_T;
|
|
case 'U':
|
|
return AKEY_U;
|
|
case 'V':
|
|
return AKEY_V;
|
|
case 'W':
|
|
return AKEY_W;
|
|
case 'X':
|
|
return AKEY_X;
|
|
case 'Y':
|
|
return AKEY_Y;
|
|
case 'Z':
|
|
return AKEY_Z;
|
|
case ':':
|
|
return AKEY_COLON;
|
|
case '!':
|
|
return AKEY_EXCLAMATION;
|
|
case '@':
|
|
return AKEY_AT;
|
|
case '#':
|
|
return AKEY_HASH;
|
|
case '$':
|
|
return AKEY_DOLLAR;
|
|
case '%':
|
|
return AKEY_PERCENT;
|
|
case '^':
|
|
return AKEY_CARET;
|
|
case '&':
|
|
return AKEY_AMPERSAND;
|
|
case '*':
|
|
return AKEY_ASTERISK;
|
|
case '(':
|
|
return AKEY_PARENLEFT;
|
|
case ')':
|
|
return AKEY_PARENRIGHT;
|
|
case '+':
|
|
return AKEY_PLUS;
|
|
case '_':
|
|
return AKEY_UNDERSCORE;
|
|
case '"':
|
|
return AKEY_DBLQUOTE;
|
|
case '?':
|
|
return AKEY_QUESTION;
|
|
case '<':
|
|
return AKEY_LESS;
|
|
case '>':
|
|
return AKEY_GREATER;
|
|
case 'a':
|
|
return AKEY_a;
|
|
case 'b':
|
|
return AKEY_b;
|
|
case 'c':
|
|
return AKEY_c;
|
|
case 'd':
|
|
return AKEY_d;
|
|
case 'e':
|
|
return AKEY_e;
|
|
case 'f':
|
|
return AKEY_f;
|
|
case 'g':
|
|
return AKEY_g;
|
|
case 'h':
|
|
return AKEY_h;
|
|
case 'i':
|
|
return AKEY_i;
|
|
case 'j':
|
|
return AKEY_j;
|
|
case 'k':
|
|
return AKEY_k;
|
|
case 'l':
|
|
return AKEY_l;
|
|
case 'm':
|
|
return AKEY_m;
|
|
case 'n':
|
|
return AKEY_n;
|
|
case 'o':
|
|
return AKEY_o;
|
|
case 'p':
|
|
return AKEY_p;
|
|
case 'q':
|
|
return AKEY_q;
|
|
case 'r':
|
|
return AKEY_r;
|
|
case 's':
|
|
return AKEY_s;
|
|
case 't':
|
|
return AKEY_t;
|
|
case 'u':
|
|
return AKEY_u;
|
|
case 'v':
|
|
return AKEY_v;
|
|
case 'w':
|
|
return AKEY_w;
|
|
case 'x':
|
|
return AKEY_x;
|
|
case 'y':
|
|
return AKEY_y;
|
|
case 'z':
|
|
return AKEY_z;
|
|
case ';':
|
|
return AKEY_SEMICOLON;
|
|
case '0':
|
|
return AKEY_0;
|
|
case '1':
|
|
return AKEY_1;
|
|
case '2':
|
|
return AKEY_2;
|
|
case '3':
|
|
return AKEY_3;
|
|
case '4':
|
|
return AKEY_4;
|
|
case '5':
|
|
return AKEY_5;
|
|
case '6':
|
|
return AKEY_6;
|
|
case '7':
|
|
return AKEY_7;
|
|
case '8':
|
|
return AKEY_8;
|
|
case '9':
|
|
return AKEY_9;
|
|
case ',':
|
|
return AKEY_COMMA;
|
|
case '.':
|
|
return AKEY_FULLSTOP;
|
|
case '=':
|
|
return AKEY_EQUAL;
|
|
case '-':
|
|
return AKEY_MINUS;
|
|
case '\'':
|
|
return AKEY_QUOTE;
|
|
case '/':
|
|
return AKEY_SLASH;
|
|
case '\\':
|
|
return AKEY_BACKSLASH;
|
|
case '[':
|
|
return AKEY_BRACKETLEFT;
|
|
case ']':
|
|
return AKEY_BRACKETRIGHT;
|
|
case '|':
|
|
return AKEY_BAR;
|
|
}
|
|
|
|
return AKEY_NONE;
|
|
}
|
|
|
|
static void PLATFORM_Mouse(void)
|
|
{
|
|
Uint8 buttons;
|
|
|
|
if(INPUT_direct_mouse) {
|
|
int potx, poty;
|
|
|
|
buttons = SDL_GetMouseState(&potx, &poty);
|
|
if(potx < 0) potx = 0;
|
|
if(poty < 0) poty = 0;
|
|
potx = (double)potx * (228.0 / (double)MainScreen->w);
|
|
poty = (double)poty * (228.0 / (double)MainScreen->h);
|
|
if(potx > 227) potx = 227;
|
|
if(poty > 227) poty = 227;
|
|
POKEY_POT_input[INPUT_mouse_port << 1] = 227 - potx;
|
|
POKEY_POT_input[(INPUT_mouse_port << 1) + 1] = 227 - poty;
|
|
} else {
|
|
buttons = SDL_GetRelativeMouseState(&INPUT_mouse_delta_x, &INPUT_mouse_delta_y);
|
|
}
|
|
|
|
INPUT_mouse_buttons =
|
|
((buttons & SDL_BUTTON(1)) ? 1 : 0) |
|
|
((buttons & SDL_BUTTON(2)) ? 2 : 0) |
|
|
((buttons & SDL_BUTTON(3)) ? 4 : 0);
|
|
}
|
|
|
|
static void Init_SDL_Joysticks(int first, int second)
|
|
{
|
|
if (first) {
|
|
joystick0 = SDL_JoystickOpen(0);
|
|
if (joystick0 == NULL)
|
|
Log_print("joystick 0 not found");
|
|
else {
|
|
Log_print("joystick 0 found!");
|
|
joystick0_nbuttons = SDL_JoystickNumButtons(joystick0);
|
|
swap_joysticks = 1;
|
|
}
|
|
}
|
|
|
|
if (second) {
|
|
joystick1 = SDL_JoystickOpen(1);
|
|
if (joystick1 == NULL)
|
|
Log_print("joystick 1 not found");
|
|
else {
|
|
Log_print("joystick 1 found!");
|
|
joystick1_nbuttons = SDL_JoystickNumButtons(joystick1);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void Init_Joysticks(int *argc, char *argv[])
|
|
{
|
|
#ifdef LPTJOY
|
|
char *lpt_joy0 = NULL;
|
|
char *lpt_joy1 = NULL;
|
|
int i;
|
|
int j;
|
|
|
|
for (i = j = 1; i < *argc; i++) {
|
|
if (!strcmp(argv[i], "-joy0")) {
|
|
if (i == *argc - 1) {
|
|
Log_print("joystick device path missing!");
|
|
break;
|
|
}
|
|
lpt_joy0 = argv[++i];
|
|
}
|
|
else if (!strcmp(argv[i], "-joy1")) {
|
|
if (i == *argc - 1) {
|
|
Log_print("joystick device path missing!");
|
|
break;
|
|
}
|
|
lpt_joy1 = argv[++i];
|
|
}
|
|
else {
|
|
argv[j++] = argv[i];
|
|
}
|
|
}
|
|
*argc = j;
|
|
|
|
if (lpt_joy0 != NULL) { /* LPT1 joystick */
|
|
fd_joystick0 = open(lpt_joy0, O_RDONLY);
|
|
if (fd_joystick0 == -1)
|
|
perror(lpt_joy0);
|
|
}
|
|
if (lpt_joy1 != NULL) { /* LPT2 joystick */
|
|
fd_joystick1 = open(lpt_joy1, O_RDONLY);
|
|
if (fd_joystick1 == -1)
|
|
perror(lpt_joy1);
|
|
}
|
|
#endif /* LPTJOY */
|
|
Init_SDL_Joysticks(fd_joystick0 == -1, fd_joystick1 == -1);
|
|
if (INPUT_cx85) { /* disable keyboard joystick if using CX85 numpad */
|
|
PLATFORM_kbd_joy_0_enabled = 0;
|
|
}
|
|
}
|
|
|
|
|
|
int PLATFORM_Initialise(int *argc, char *argv[])
|
|
{
|
|
int i, j;
|
|
int no_joystick;
|
|
int help_only = FALSE;
|
|
|
|
no_joystick = 0;
|
|
|
|
for (i = j = 1; i < *argc; i++) {
|
|
int i_a = (i + 1 < *argc); /* is argument available? */
|
|
int a_m = FALSE; /* error, argument missing! */
|
|
|
|
if (strcmp(argv[i], "-ntscemu") == 0) {
|
|
PLATFORM_filter = PLATFORM_FILTER_NTSC;
|
|
}
|
|
else if (strcmp(argv[i], "-scanlines") == 0) {
|
|
if (i_a) {
|
|
scanlines_percentage = Util_sscandec(argv[++i]);
|
|
Log_print("scanlines percentage set");
|
|
}
|
|
else a_m = TRUE;
|
|
}
|
|
else if (strcmp(argv[i], "-scanlinesnoint") == 0) {
|
|
scanlinesnoint = TRUE;
|
|
Log_print("scanlines interpolation disabled");
|
|
}
|
|
else if (strcmp(argv[i], "-rotate90") == 0) {
|
|
current_display_mode = display_rotated;
|
|
no_joystick = 1;
|
|
Log_print("rotate90 mode");
|
|
}
|
|
else if (strcmp(argv[i], "-nojoystick") == 0) {
|
|
no_joystick = 1;
|
|
Log_print("no joystick");
|
|
}
|
|
else if (strcmp(argv[i], "-width") == 0) {
|
|
if (i_a) {
|
|
display_modes[display_normal].w = Util_sscandec(argv[++i]);
|
|
Log_print("width set");
|
|
}
|
|
else a_m = TRUE;
|
|
}
|
|
else if (strcmp(argv[i], "-height") == 0) {
|
|
if (i_a) {
|
|
display_modes[display_normal].h = Util_sscandec(argv[++i]);
|
|
Log_print("height set");
|
|
}
|
|
else a_m = TRUE;
|
|
}
|
|
else if (strcmp(argv[i], "-bpp") == 0) {
|
|
if (i_a) {
|
|
display_modes[display_normal].bpp = Util_sscandec(argv[++i]);
|
|
Log_print("bpp set");
|
|
}
|
|
else a_m = TRUE;
|
|
}
|
|
else if (strcmp(argv[i], "-fullscreen") == 0) {
|
|
fullscreen = 1;
|
|
}
|
|
else if (strcmp(argv[i], "-windowed") == 0) {
|
|
fullscreen = 0;
|
|
}
|
|
else if (strcmp(argv[i], "-grabmouse") == 0) {
|
|
grab_mouse = 1;
|
|
}
|
|
else {
|
|
if (strcmp(argv[i], "-help") == 0) {
|
|
help_only = TRUE;
|
|
Log_print("\t-ntscemu Emulate NTSC composite video (640x480x16)");
|
|
Log_print("\t-scanlines Specify scanlines percentage (ntscemu only)");
|
|
Log_print("\t-scanlinesnoint Disable scanlines interpolation (ntscemu only)");
|
|
Log_print("\t-rotate90 Display 240x320 screen");
|
|
Log_print("\t-nojoystick Disable joystick");
|
|
#ifdef LPTJOY
|
|
Log_print("\t-joy0 <pathname> Select LPTjoy0 device");
|
|
Log_print("\t-joy1 <pathname> Select LPTjoy0 device");
|
|
#endif /* LPTJOY */
|
|
Log_print("\t-width <num> Host screen width");
|
|
Log_print("\t-height <num> Host screen height");
|
|
Log_print("\t-bpp <num> Host color depth");
|
|
Log_print("\t-fullscreen Run fullscreen");
|
|
Log_print("\t-windowed Run in window");
|
|
Log_print("\t-grabmouse Prevent mouse pointer from leaving window");
|
|
}
|
|
argv[j++] = argv[i];
|
|
}
|
|
|
|
if (a_m) {
|
|
Log_print("Missing argument for '%s'", argv[i]);
|
|
return FALSE;
|
|
}
|
|
}
|
|
*argc = j;
|
|
|
|
i = SDL_INIT_VIDEO | SDL_INIT_JOYSTICK;
|
|
#ifdef SOUND
|
|
if (!help_only)
|
|
i |= SDL_INIT_AUDIO;
|
|
#endif
|
|
#ifdef WIN32
|
|
/*Windows SDL version 1.2.10+ uses windib as the default, but it is slower*/
|
|
if (getenv("SDL_VIDEODRIVER")==NULL) {
|
|
#ifdef __STRICT_ANSI__
|
|
extern int putenv(char *string); /* suppress -ansi -pedantic warning */
|
|
#endif
|
|
putenv("SDL_VIDEODRIVER=directx");
|
|
}
|
|
#endif
|
|
if (SDL_Init(i) != 0) {
|
|
Log_print("SDL_Init FAILED");
|
|
Log_print(SDL_GetError());
|
|
Log_flushlog();
|
|
exit(-1);
|
|
}
|
|
atexit(SDL_Quit);
|
|
|
|
/* SDL_WM_SetIcon("/usr/local/atari800/atarixe.ICO"), NULL); */
|
|
SDL_WM_SetCaption(Atari800_TITLE, "Atari800");
|
|
|
|
PLATFORM_Keyboard();
|
|
|
|
#ifdef SOUND
|
|
SoundInitialise(argc, argv);
|
|
#endif
|
|
|
|
if (help_only)
|
|
return TRUE; /* return before changing the gfx mode */
|
|
|
|
/* Prototype 80 column adaptor */
|
|
if (PBI_PROTO80_enabled) {
|
|
current_display_mode = display_proto80;
|
|
Log_print("proto80 mode");
|
|
}
|
|
|
|
if (PLATFORM_filter != PLATFORM_FILTER_NONE)
|
|
PLATFORM_SetFilter(PLATFORM_filter);
|
|
ResetDisplay();
|
|
|
|
Log_print("video initialized");
|
|
|
|
if (no_joystick == 0)
|
|
Init_Joysticks(argc, argv);
|
|
|
|
SDL_EnableUNICODE(1);
|
|
|
|
if(grab_mouse)
|
|
SDL_WM_GrabInput(SDL_GRAB_ON);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
int PLATFORM_Exit(int run_monitor)
|
|
{
|
|
int restart;
|
|
int original_fullscreen = fullscreen;
|
|
|
|
SDL_WM_GrabInput(SDL_GRAB_OFF);
|
|
if (run_monitor) {
|
|
/* disable graphics, set alpha mode */
|
|
if (fullscreen) {
|
|
SwitchFullscreen();
|
|
}
|
|
#ifdef SOUND
|
|
Sound_Pause();
|
|
#endif
|
|
restart = MONITOR_Run();
|
|
#ifdef SOUND
|
|
Sound_Continue();
|
|
#endif
|
|
}
|
|
else {
|
|
restart = FALSE;
|
|
}
|
|
|
|
if (restart) {
|
|
/* set up graphics and all the stuff */
|
|
if (original_fullscreen != fullscreen) {
|
|
SwitchFullscreen();
|
|
}
|
|
if(grab_mouse) SDL_WM_GrabInput(SDL_GRAB_ON);
|
|
return 1;
|
|
}
|
|
|
|
SDL_Quit();
|
|
|
|
Log_flushlog();
|
|
|
|
return restart;
|
|
}
|
|
/* License of scanLines_16():*/
|
|
/* This function has been altered from its original version */
|
|
/* This license is a verbatim copy of the license of ZLib
|
|
* http://www.gnu.org/licenses/license-list.html#GPLCompatibleLicenses
|
|
* This is a free software license, and compatible with the GPL. */
|
|
/*****************************************************************************
|
|
** Original Source: /cvsroot/bluemsx/blueMSX/Src/VideoRender/VideoRender.c,v
|
|
**
|
|
** Original Revision: 1.25
|
|
**
|
|
** Original Date: 2006/01/17 08:49:34
|
|
**
|
|
** More info: http://www.bluemsx.com
|
|
**
|
|
** Copyright (C) 2003-2004 Daniel Vik
|
|
**
|
|
** This software is provided 'as-is', without any express or implied
|
|
** warranty. In no event will the authors be held liable for any damages
|
|
** arising from the use of this software.
|
|
**
|
|
** Permission is granted to anyone to use this software for any purpose,
|
|
** including commercial applications, and to alter it and redistribute it
|
|
** freely, subject to the following restrictions:
|
|
**
|
|
** 1. The origin of this software must not be misrepresented; you must not
|
|
** claim that you wrote the original software. If you use this software
|
|
** in a product, an acknowledgment in the product documentation would be
|
|
** appreciated but is not required.
|
|
** 2. Altered source versions must be plainly marked as such, and must not be
|
|
** misrepresented as being the original software.
|
|
** 3. This notice may not be removed or altered from any source distribution.
|
|
**
|
|
******************************************************************************
|
|
*/
|
|
|
|
static void scanLines_16(void* pBuffer, int width, int height, int pitch, int scanLinesPct)
|
|
{
|
|
Uint32* pBuf = (Uint32*)(pBuffer)+pitch/sizeof(Uint32);
|
|
Uint32* sBuf = (Uint32*)(pBuffer);
|
|
int w, h;
|
|
static int prev_scanLinesPct;
|
|
|
|
pitch = pitch * 2 / (int)sizeof(Uint32);
|
|
height /= 2;
|
|
width /= 2;
|
|
|
|
if (scanLinesPct < 0) scanLinesPct = 0;
|
|
if (scanLinesPct > 100) scanLinesPct = 100;
|
|
|
|
if (scanLinesPct == 100) {
|
|
if (prev_scanLinesPct != 100) {
|
|
/*clean dirty blank scanlines*/
|
|
prev_scanLinesPct = 100;
|
|
for (h = 0; h < height; h++) {
|
|
memset(pBuf, 0, width * sizeof(Uint32));
|
|
pBuf += pitch;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
prev_scanLinesPct = scanLinesPct;
|
|
|
|
|
|
if (scanLinesPct == 0) {
|
|
/* fill in blank scanlines */
|
|
for (h = 0; h < height; h++) {
|
|
memcpy(pBuf, sBuf, width * sizeof(Uint32));
|
|
sBuf += pitch;
|
|
pBuf += pitch;
|
|
}
|
|
return;
|
|
}
|
|
scanLinesPct = (100-scanLinesPct) * 32 / 100;
|
|
|
|
for (h = 0; h < height; h++) {
|
|
for (w = 0; w < width; w++) {
|
|
Uint32 pixel = sBuf[w];
|
|
Uint32 a = (((pixel & 0x07e0f81f) * scanLinesPct) & 0xfc1f03e0) >> 5;
|
|
Uint32 b = (((pixel >> 5) & 0x07c0f83f) * scanLinesPct) & 0xf81f07e0;
|
|
pBuf[w] = a | b;
|
|
}
|
|
sBuf += pitch;
|
|
pBuf += pitch;
|
|
}
|
|
}
|
|
|
|
/* Modified version of the above, which uses interpolation (slower but better)*/
|
|
static void scanLines_16_interp(void* pBuffer, int width, int height, int pitch, int scanLinesPct)
|
|
{
|
|
Uint32* pBuf = (Uint32*)(pBuffer)+pitch/sizeof(Uint32);
|
|
Uint32* sBuf = (Uint32*)(pBuffer);
|
|
Uint32* tBuf = (Uint32*)(pBuffer)+pitch*2/sizeof(Uint32);
|
|
int w, h;
|
|
static int prev_scanLinesPct;
|
|
|
|
pitch = pitch * 2 / (int)sizeof(Uint32);
|
|
height /= 2;
|
|
width /= 2;
|
|
|
|
if (scanLinesPct < 0) scanLinesPct = 0;
|
|
if (scanLinesPct > 100) scanLinesPct = 100;
|
|
|
|
if (scanLinesPct == 100) {
|
|
if (prev_scanLinesPct != 100) {
|
|
/*clean dirty blank scanlines*/
|
|
prev_scanLinesPct = 100;
|
|
for (h = 0; h < height; h++) {
|
|
memset(pBuf, 0, width * sizeof(Uint32));
|
|
pBuf += pitch;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
prev_scanLinesPct = scanLinesPct;
|
|
|
|
|
|
if (scanLinesPct == 0) {
|
|
/* fill in blank scanlines */
|
|
for (h = 0; h < height; h++) {
|
|
memcpy(pBuf, sBuf, width * sizeof(Uint32));
|
|
sBuf += pitch;
|
|
pBuf += pitch;
|
|
}
|
|
return;
|
|
}
|
|
scanLinesPct = (100-scanLinesPct) * 32 / 200;
|
|
|
|
for (h = 0; h < height-1; h++) {
|
|
for (w = 0; w < width; w++) {
|
|
Uint32 pixel = sBuf[w];
|
|
Uint32 pixel2 = tBuf[w];
|
|
Uint32 a = ((((pixel & 0x07e0f81f)+(pixel2 & 0x07e0f81f)) * scanLinesPct) & 0xfc1f03e0) >> 5;
|
|
Uint32 b = ((((pixel >> 5) & 0x07c0f83f)+((pixel2 >> 5) & 0x07c0f83f)) * scanLinesPct) & 0xf81f07e0;
|
|
pBuf[w] = a | b;
|
|
}
|
|
sBuf += pitch;
|
|
tBuf += pitch;
|
|
pBuf += pitch;
|
|
}
|
|
}
|
|
|
|
static void DisplayXEP80(UBYTE *screen)
|
|
{
|
|
static int xep80Frame = 0;
|
|
Uint32 *start32;
|
|
int pitch4;
|
|
int i;
|
|
xep80Frame++;
|
|
if (xep80Frame == 60) xep80Frame = 0;
|
|
if (xep80Frame > 29) {
|
|
screen = XEP80_screen_1;
|
|
}
|
|
else {
|
|
screen = XEP80_screen_2;
|
|
}
|
|
|
|
pitch4 = MainScreen->pitch / 4;
|
|
start32 = (Uint32 *) MainScreen->pixels;
|
|
|
|
i = MainScreen->h;
|
|
while (i > 0) {
|
|
memcpy(start32, screen, XEP80_SCRN_WIDTH);
|
|
screen += XEP80_SCRN_WIDTH;
|
|
start32 += pitch4;
|
|
i--;
|
|
}
|
|
}
|
|
|
|
static void DisplayNTSCEmu640x480(UBYTE *screen)
|
|
{
|
|
/* Number of overscan lines not shown */
|
|
enum { overscan_lines = 24 };
|
|
/* Change to 0 to clip the 8-pixel overscan borders off */
|
|
enum { overscan = 1 };
|
|
|
|
/* Atari active pixel area */
|
|
enum { atari_width = overscan ? atari_ntsc_full_in_width : atari_ntsc_min_in_width };
|
|
enum { atari_height = 240 -overscan_lines };
|
|
|
|
/* Output size */
|
|
enum { width = overscan ? atari_ntsc_full_out_width : atari_ntsc_min_out_width };
|
|
enum { height = atari_height * 2 };
|
|
enum { left_border_adj = ((640 - width)/2) & 0xfffffffc };
|
|
int const raw_width = Screen_WIDTH; /* raw image has extra data */
|
|
|
|
int jumped = 24;
|
|
unsigned short *pixels = (unsigned short*)MainScreen->pixels + overscan_lines / 2 * MainScreen->pitch + left_border_adj;
|
|
/* blit atari image, doubled vertically */
|
|
atari_ntsc_blit( the_ntscemu, screen + jumped + overscan_lines / 2 * Screen_WIDTH, raw_width, width, height / 2, pixels, MainScreen->pitch * 2 );
|
|
|
|
if (!scanlinesnoint) {
|
|
scanLines_16_interp((void *)pixels, width, height, MainScreen->pitch, scanlines_percentage);
|
|
} else {
|
|
scanLines_16((void *)pixels, width, height, MainScreen->pitch, scanlines_percentage);
|
|
}
|
|
}
|
|
|
|
static void DisplayProto80640x400(UBYTE *screen)
|
|
{
|
|
UWORD white = 0xffff;
|
|
UWORD black = 0x0000;
|
|
int skip = MainScreen->pitch - 80*8;
|
|
Uint16 *start16 = (Uint16 *) MainScreen->pixels;
|
|
|
|
int scanline, column;
|
|
UBYTE pixels;
|
|
for (scanline = 0; scanline < 8*24; scanline++) {
|
|
for (column = 0; column < 80; column++) {
|
|
int i;
|
|
pixels = PBI_PROTO80_GetPixels(scanline,column);
|
|
for (i = 0; i < 8; i++) {
|
|
if (pixels & 0x80) {
|
|
*start16++ = white;
|
|
}
|
|
else {
|
|
*start16++ = black;
|
|
}
|
|
pixels <<= 1;
|
|
}
|
|
}
|
|
start16 += skip;
|
|
}
|
|
scanLines_16_interp((void *)MainScreen->pixels, 640, 400, MainScreen->pitch, scanlines_percentage);
|
|
}
|
|
|
|
static void DisplayRotated240x320(Uint8 *screen)
|
|
{
|
|
int i, j;
|
|
register Uint32 *start32;
|
|
if (MainScreen->format->BitsPerPixel != 16) {
|
|
Log_print("rotated display works only for bpp=16 right now");
|
|
Log_flushlog();
|
|
exit(-1);
|
|
}
|
|
start32 = (Uint32 *) MainScreen->pixels;
|
|
for (j = 0; j < MainScreen->h; j++)
|
|
for (i = 0; i < MainScreen->w / 2; i++) {
|
|
Uint8 left = screen[Screen_WIDTH * (i * 2) + 32 + 320 - j];
|
|
Uint8 right = screen[Screen_WIDTH * (i * 2 + 1) + 32 + 320 - j];
|
|
#ifdef WORDS_BIGENDIAN
|
|
*start32++ = (Palette16[left] << 16) + Palette16[right];
|
|
#else
|
|
*start32++ = (Palette16[right] << 16) + Palette16[left];
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static void DisplayWithoutScaling(Uint8 *screen, int jumped, int width)
|
|
{
|
|
register Uint32 quad;
|
|
register Uint32 *start32;
|
|
register Uint8 c;
|
|
register int pos;
|
|
register int pitch4;
|
|
int i;
|
|
|
|
pitch4 = MainScreen->pitch / 4;
|
|
start32 = (Uint32 *) MainScreen->pixels;
|
|
|
|
screen = screen + jumped;
|
|
i = MainScreen->h;
|
|
switch (MainScreen->format->BitsPerPixel) {
|
|
/* Possible values are 8, 16 and 32, as checked earlier in the
|
|
* SetNewVideoModeNormal() function. */
|
|
case 8:
|
|
while (i > 0) {
|
|
memcpy(start32, screen, width);
|
|
screen += Screen_WIDTH;
|
|
start32 += pitch4;
|
|
i--;
|
|
}
|
|
break;
|
|
case 16:
|
|
while (i > 0) {
|
|
pos = width - 1;
|
|
while (pos > 0) {
|
|
c = screen[pos];
|
|
quad = Palette16[c] << 16;
|
|
pos--;
|
|
c = screen[pos];
|
|
quad += Palette16[c];
|
|
start32[pos >> 1] = quad;
|
|
pos--;
|
|
}
|
|
screen += Screen_WIDTH;
|
|
start32 += pitch4;
|
|
i--;
|
|
}
|
|
break;
|
|
default:
|
|
/* MainScreen->format->BitsPerPixel = 32 */
|
|
while (i > 0) {
|
|
pos = width - 1;
|
|
while (pos > 0) {
|
|
c = screen[pos];
|
|
quad = Palette32[c];
|
|
start32[pos] = quad;
|
|
pos--;
|
|
}
|
|
screen += Screen_WIDTH;
|
|
start32 += pitch4;
|
|
i--;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void DisplayWithScaling(Uint8 *screen, int jumped, int width)
|
|
{
|
|
register Uint32 quad;
|
|
register int x;
|
|
register int dx;
|
|
register int yy;
|
|
register Uint8 *ss;
|
|
register Uint32 *start32;
|
|
int i;
|
|
int y;
|
|
int w1, w2, w4;
|
|
int w, h;
|
|
int pos;
|
|
int pitch4;
|
|
int dy;
|
|
Uint8 c;
|
|
pitch4 = MainScreen->pitch / 4;
|
|
start32 = (Uint32 *) MainScreen->pixels;
|
|
|
|
w = (width) << 16;
|
|
h = (Screen_HEIGHT) << 16;
|
|
dx = w / MainScreen->w;
|
|
dy = h / MainScreen->h;
|
|
w1 = MainScreen->w - 1;
|
|
w2 = MainScreen->w / 2 - 1;
|
|
w4 = MainScreen->w / 4 - 1;
|
|
ss = screen;
|
|
y = (0) << 16;
|
|
i = MainScreen->h;
|
|
|
|
switch (MainScreen->format->BitsPerPixel) {
|
|
/* Possible values are 8, 16 and 32, as checked earlier in the
|
|
* SetNewVideoModeNormal() function. */
|
|
case 8:
|
|
while (i > 0) {
|
|
x = (width + jumped) << 16;
|
|
pos = w4;
|
|
yy = Screen_WIDTH * (y >> 16);
|
|
while (pos >= 0) {
|
|
quad = (ss[yy + (x >> 16)] << 24);
|
|
x = x - dx;
|
|
quad += (ss[yy + (x >> 16)] << 16);
|
|
x = x - dx;
|
|
quad += (ss[yy + (x >> 16)] << 8);
|
|
x = x - dx;
|
|
quad += (ss[yy + (x >> 16)] << 0);
|
|
x = x - dx;
|
|
|
|
start32[pos] = quad;
|
|
pos--;
|
|
|
|
}
|
|
start32 += pitch4;
|
|
y = y + dy;
|
|
i--;
|
|
}
|
|
break;
|
|
case 16:
|
|
while (i > 0) {
|
|
x = (width + jumped) << 16;
|
|
pos = w2;
|
|
yy = Screen_WIDTH * (y >> 16);
|
|
while (pos >= 0) {
|
|
|
|
c = ss[yy + (x >> 16)];
|
|
quad = Palette16[c] << 16;
|
|
x = x - dx;
|
|
c = ss[yy + (x >> 16)];
|
|
quad += Palette16[c];
|
|
x = x - dx;
|
|
start32[pos] = quad;
|
|
pos--;
|
|
|
|
}
|
|
start32 += pitch4;
|
|
y = y + dy;
|
|
i--;
|
|
}
|
|
break;
|
|
default:
|
|
/* MainScreen->format->BitsPerPixel = 32 */
|
|
while (i > 0) {
|
|
x = (width + jumped) << 16;
|
|
pos = w1;
|
|
yy = Screen_WIDTH * (y >> 16);
|
|
while (pos >= 0) {
|
|
|
|
c = ss[yy + (x >> 16)];
|
|
quad = Palette32[c];
|
|
x = x - dx;
|
|
start32[pos] = quad;
|
|
pos--;
|
|
|
|
}
|
|
start32 += pitch4;
|
|
y = y + dy;
|
|
i--;
|
|
}
|
|
}
|
|
}
|
|
|
|
void DisplayNormal(Uint8 *screen)
|
|
{
|
|
int width, jumped;
|
|
|
|
switch (width_mode) {
|
|
case SHORT_WIDTH_MODE:
|
|
width = Screen_WIDTH - 2 * 24 - 2 * 8;
|
|
jumped = 24 + 8;
|
|
break;
|
|
case DEFAULT_WIDTH_MODE:
|
|
width = Screen_WIDTH - 2 * 24;
|
|
jumped = 24;
|
|
break;
|
|
case FULL_WIDTH_MODE:
|
|
width = Screen_WIDTH;
|
|
jumped = 0;
|
|
break;
|
|
default:
|
|
Log_print("unsupported width_mode");
|
|
Log_flushlog();
|
|
exit(-1);
|
|
break;
|
|
}
|
|
if (MainScreen->w == width && MainScreen->h == Screen_HEIGHT) {
|
|
DisplayWithoutScaling(screen, jumped, width);
|
|
}
|
|
else {
|
|
DisplayWithScaling(screen, jumped, width);
|
|
}
|
|
}
|
|
|
|
void PLATFORM_DisplayScreen(void)
|
|
{
|
|
/* Use function corresponding to the current_display_mode. */
|
|
(*display_modes[current_display_mode].display_screen_func)((UBYTE *)Screen_atari);
|
|
SDL_Flip(MainScreen);
|
|
}
|
|
|
|
static int get_SDL_joystick_state(SDL_Joystick *joystick)
|
|
{
|
|
int x;
|
|
int y;
|
|
|
|
x = SDL_JoystickGetAxis(joystick, 0);
|
|
y = SDL_JoystickGetAxis(joystick, 1);
|
|
|
|
if (x > minjoy) {
|
|
if (y < -minjoy)
|
|
return INPUT_STICK_UR;
|
|
else if (y > minjoy)
|
|
return INPUT_STICK_LR;
|
|
else
|
|
return INPUT_STICK_RIGHT;
|
|
}
|
|
else if (x < -minjoy) {
|
|
if (y < -minjoy)
|
|
return INPUT_STICK_UL;
|
|
else if (y > minjoy)
|
|
return INPUT_STICK_LL;
|
|
else
|
|
return INPUT_STICK_LEFT;
|
|
}
|
|
else {
|
|
if (y < -minjoy)
|
|
return INPUT_STICK_FORWARD;
|
|
else if (y > minjoy)
|
|
return INPUT_STICK_BACK;
|
|
else
|
|
return INPUT_STICK_CENTRE;
|
|
}
|
|
}
|
|
|
|
static int get_LPT_joystick_state(int fd)
|
|
{
|
|
#ifdef LPTJOY
|
|
int status;
|
|
|
|
ioctl(fd, LPGETSTATUS, &status);
|
|
status ^= 0x78;
|
|
|
|
if (status & 0x40) { /* right */
|
|
if (status & 0x10) { /* up */
|
|
return INPUT_STICK_UR;
|
|
}
|
|
else if (status & 0x20) { /* down */
|
|
return INPUT_STICK_LR;
|
|
}
|
|
else {
|
|
return INPUT_STICK_RIGHT;
|
|
}
|
|
}
|
|
else if (status & 0x80) { /* left */
|
|
if (status & 0x10) { /* up */
|
|
return INPUT_STICK_UL;
|
|
}
|
|
else if (status & 0x20) { /* down */
|
|
return INPUT_STICK_LL;
|
|
}
|
|
else {
|
|
return INPUT_STICK_LEFT;
|
|
}
|
|
}
|
|
else {
|
|
if (status & 0x10) { /* up */
|
|
return INPUT_STICK_FORWARD;
|
|
}
|
|
else if (status & 0x20) { /* down */
|
|
return INPUT_STICK_BACK;
|
|
}
|
|
else {
|
|
return INPUT_STICK_CENTRE;
|
|
}
|
|
}
|
|
#else
|
|
return 0;
|
|
#endif /* LPTJOY */
|
|
}
|
|
|
|
static void get_platform_PORT(Uint8 *s0, Uint8 *s1)
|
|
{
|
|
int stick0, stick1;
|
|
stick0 = stick1 = INPUT_STICK_CENTRE;
|
|
if( !kbhits )
|
|
return;
|
|
|
|
if (PLATFORM_kbd_joy_0_enabled) {
|
|
if (kbhits[KBD_STICK_0_LEFT])
|
|
stick0 = INPUT_STICK_LEFT;
|
|
if (kbhits[KBD_STICK_0_RIGHT])
|
|
stick0 = INPUT_STICK_RIGHT;
|
|
if (kbhits[KBD_STICK_0_UP])
|
|
stick0 = INPUT_STICK_FORWARD;
|
|
if (kbhits[KBD_STICK_0_DOWN])
|
|
stick0 = INPUT_STICK_BACK;
|
|
if ((kbhits[KBD_STICK_0_LEFT]) && (kbhits[KBD_STICK_0_UP]))
|
|
stick0 = INPUT_STICK_UL;
|
|
if ((kbhits[KBD_STICK_0_LEFT]) && (kbhits[KBD_STICK_0_DOWN]))
|
|
stick0 = INPUT_STICK_LL;
|
|
if ((kbhits[KBD_STICK_0_RIGHT]) && (kbhits[KBD_STICK_0_UP]))
|
|
stick0 = INPUT_STICK_UR;
|
|
if ((kbhits[KBD_STICK_0_RIGHT]) && (kbhits[KBD_STICK_0_DOWN]))
|
|
stick0 = INPUT_STICK_LR;
|
|
}
|
|
if (PLATFORM_kbd_joy_1_enabled) {
|
|
if (kbhits[KBD_STICK_1_LEFT])
|
|
stick1 = INPUT_STICK_LEFT;
|
|
if (kbhits[KBD_STICK_1_RIGHT])
|
|
stick1 = INPUT_STICK_RIGHT;
|
|
if (kbhits[KBD_STICK_1_UP])
|
|
stick1 = INPUT_STICK_FORWARD;
|
|
if (kbhits[KBD_STICK_1_DOWN])
|
|
stick1 = INPUT_STICK_BACK;
|
|
if ((kbhits[KBD_STICK_1_LEFT]) && (kbhits[KBD_STICK_1_UP]))
|
|
stick1 = INPUT_STICK_UL;
|
|
if ((kbhits[KBD_STICK_1_LEFT]) && (kbhits[KBD_STICK_1_DOWN]))
|
|
stick1 = INPUT_STICK_LL;
|
|
if ((kbhits[KBD_STICK_1_RIGHT]) && (kbhits[KBD_STICK_1_UP]))
|
|
stick1 = INPUT_STICK_UR;
|
|
if ((kbhits[KBD_STICK_1_RIGHT]) && (kbhits[KBD_STICK_1_DOWN]))
|
|
stick1 = INPUT_STICK_LR;
|
|
}
|
|
|
|
if (swap_joysticks) {
|
|
*s1 = stick0;
|
|
*s0 = stick1;
|
|
}
|
|
else {
|
|
*s0 = stick0;
|
|
*s1 = stick1;
|
|
}
|
|
|
|
if ((joystick0 != NULL) || (joystick1 != NULL)) /* can only joystick1!=NULL ? */
|
|
{
|
|
SDL_JoystickUpdate();
|
|
}
|
|
|
|
if (fd_joystick0 != -1)
|
|
*s0 = get_LPT_joystick_state(fd_joystick0);
|
|
else if (joystick0 != NULL)
|
|
*s0 = get_SDL_joystick_state(joystick0);
|
|
|
|
if (fd_joystick1 != -1)
|
|
*s1 = get_LPT_joystick_state(fd_joystick1);
|
|
else if (joystick1 != NULL)
|
|
*s1 = get_SDL_joystick_state(joystick1);
|
|
}
|
|
|
|
static void get_platform_TRIG(Uint8 *t0, Uint8 *t1)
|
|
{
|
|
int trig0, trig1, i;
|
|
trig0 = trig1 = 1;
|
|
|
|
if (PLATFORM_kbd_joy_0_enabled) {
|
|
trig0 = kbhits[KBD_TRIG_0] ? 0 : 1;
|
|
}
|
|
|
|
if (PLATFORM_kbd_joy_1_enabled) {
|
|
trig1 = kbhits[KBD_TRIG_1] ? 0 : 1;
|
|
}
|
|
|
|
if (swap_joysticks) {
|
|
*t1 = trig0;
|
|
*t0 = trig1;
|
|
}
|
|
else {
|
|
*t0 = trig0;
|
|
*t1 = trig1;
|
|
}
|
|
|
|
if (fd_joystick0 != -1) {
|
|
#ifdef LPTJOY
|
|
int status;
|
|
ioctl(fd_joystick0, LPGETSTATUS, &status);
|
|
if (status & 8)
|
|
*t0 = 1;
|
|
else
|
|
*t0 = 0;
|
|
#endif /* LPTJOY */
|
|
}
|
|
else if (joystick0 != NULL) {
|
|
trig0 = 1;
|
|
for (i = 0; i < joystick0_nbuttons; i++) {
|
|
if (SDL_JoystickGetButton(joystick0, i)) {
|
|
trig0 = 0;
|
|
break;
|
|
}
|
|
}
|
|
*t0 = trig0;
|
|
}
|
|
|
|
if (fd_joystick1 != -1) {
|
|
#ifdef LPTJOY
|
|
int status;
|
|
ioctl(fd_joystick1, LPGETSTATUS, &status);
|
|
if (status & 8)
|
|
*t1 = 1;
|
|
else
|
|
*t1 = 0;
|
|
#endif /* LPTJOY */
|
|
}
|
|
else if (joystick1 != NULL) {
|
|
trig1 = 1;
|
|
for (i = 0; i < joystick1_nbuttons; i++) {
|
|
if (SDL_JoystickGetButton(joystick1, i)) {
|
|
trig1 = 0;
|
|
break;
|
|
}
|
|
}
|
|
*t1 = trig1;
|
|
}
|
|
}
|
|
|
|
int PLATFORM_PORT(int num)
|
|
{
|
|
#ifndef DONT_DISPLAY
|
|
if (num == 0) {
|
|
UBYTE a, b;
|
|
get_platform_PORT(&a, &b);
|
|
return (b << 4) | (a & 0x0f);
|
|
}
|
|
#endif
|
|
return 0xff;
|
|
}
|
|
|
|
int PLATFORM_TRIG(int num)
|
|
{
|
|
#ifndef DONT_DISPLAY
|
|
UBYTE a, b;
|
|
get_platform_TRIG(&a, &b);
|
|
switch (num) {
|
|
case 0:
|
|
return a;
|
|
case 1:
|
|
return b;
|
|
default:
|
|
break;
|
|
}
|
|
#endif
|
|
return 1;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
/* initialise Atari800 core */
|
|
if (!Atari800_Initialise(&argc, argv))
|
|
return 3;
|
|
|
|
/* main loop */
|
|
for (;;) {
|
|
INPUT_key_code = PLATFORM_Keyboard();
|
|
PLATFORM_Mouse();
|
|
Atari800_Frame();
|
|
if (Atari800_display_screen)
|
|
PLATFORM_DisplayScreen();
|
|
}
|
|
}
|
|
|
|
/*
|
|
vim:ts=4:sw=4:
|
|
*/
|