mirror of
https://github.com/libretro/blueMSX-libretro.git
synced 2024-11-27 02:30:41 +00:00
1261 lines
43 KiB
C
1261 lines
43 KiB
C
#include "libretro.h"
|
|
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
#include <ctype.h>
|
|
|
|
#include <retro_miscellaneous.h>
|
|
|
|
#include "CommandLine.h"
|
|
#include "Properties.h"
|
|
#include "ArchFile.h"
|
|
#include "VideoRender.h"
|
|
#include "AudioMixer.h"
|
|
#include "Casette.h"
|
|
#include "PrinterIO.h"
|
|
#include "UartIO.h"
|
|
#include "MidiIO.h"
|
|
#include "Machine.h"
|
|
#include "Board.h"
|
|
#include "Emulator.h"
|
|
#include "FileHistory.h"
|
|
#include "Actions.h"
|
|
#include "Language.h"
|
|
#include "LaunchFile.h"
|
|
#include "ArchEvent.h"
|
|
#include "ArchSound.h"
|
|
#include "ArchNotifications.h"
|
|
#include "JoystickPort.h"
|
|
#include "InputEvent.h"
|
|
#include "R800.h"
|
|
|
|
|
|
|
|
retro_log_printf_t log_cb;
|
|
static retro_video_refresh_t video_cb;
|
|
static retro_input_poll_t input_poll_cb;
|
|
static retro_input_state_t input_state_cb;
|
|
static retro_environment_t environ_cb;
|
|
|
|
static Properties* properties;
|
|
static Video* video;
|
|
static Mixer* mixer;
|
|
|
|
static uint16_t* image_buffer;
|
|
static unsigned image_buffer_base_width;
|
|
static unsigned image_buffer_current_width;
|
|
static unsigned image_buffer_height;
|
|
static unsigned width = 272;
|
|
static unsigned height = 240;
|
|
static int double_width;
|
|
|
|
|
|
static char msx_type[256];
|
|
static char msx_cartmapper[256];
|
|
static bool mapper_auto;
|
|
bool is_coleco, is_sega, is_spectra, is_auto, auto_rewind_cas;
|
|
static unsigned msx_vdp_synctype;
|
|
static bool msx_ym2413_enable;
|
|
static bool use_overscan = true;
|
|
int msx2_dif = 0;
|
|
|
|
|
|
void retro_set_video_refresh(retro_video_refresh_t cb) { video_cb = cb; }
|
|
void retro_set_input_poll(retro_input_poll_t cb) { input_poll_cb = cb; }
|
|
void retro_set_input_state(retro_input_state_t cb) { input_state_cb = cb; }
|
|
|
|
#ifdef LOG_PERFORMANCE
|
|
static struct retro_perf_callback perf_cb;
|
|
#define RETRO_PERFORMANCE_INIT(name) static struct retro_perf_counter name = {#name}; if (!name.registered) perf_cb.perf_register(&(name))
|
|
#define RETRO_PERFORMANCE_START(name) perf_cb.perf_start(&(name))
|
|
#define RETRO_PERFORMANCE_STOP(name) perf_cb.perf_stop(&(name))
|
|
#else
|
|
#define RETRO_PERFORMANCE_INIT(name)
|
|
#define RETRO_PERFORMANCE_START(name)
|
|
#define RETRO_PERFORMANCE_STOP(name)
|
|
#endif
|
|
|
|
#define RETRO_DEVICE_MAPPER RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 1)
|
|
#define EC_KEYBOARD_KEYCOUNT 94
|
|
|
|
#ifdef _WIN32
|
|
#define SLASH '\\'
|
|
#else
|
|
#define SLASH '/'
|
|
#endif
|
|
|
|
#ifndef PATH_MAX
|
|
#define PATH_MAX 4096
|
|
#endif
|
|
|
|
static char base_dir[PATH_MAX];
|
|
|
|
/* .dsk support */
|
|
enum{
|
|
MEDIA_TYPE_CART = 0,
|
|
MEDIA_TYPE_TAPE,
|
|
MEDIA_TYPE_DISK,
|
|
MEDIA_TYPE_DISK_BUNDLE,
|
|
MEDIA_TYPE_OTHER
|
|
};
|
|
|
|
void lower_string(char* str)
|
|
{
|
|
int i;
|
|
for (i=0; str[i]; i++)
|
|
{
|
|
str[i] = tolower(str[i]);
|
|
}
|
|
}
|
|
|
|
int get_media_type(const char* filename)
|
|
{
|
|
char workram[PATH_MAX];
|
|
const char *extension = NULL;
|
|
|
|
strcpy(workram, filename);
|
|
lower_string(workram);
|
|
extension = workram + strlen(workram) - 4;
|
|
|
|
if(strcmp(extension, ".dsk") == 0){
|
|
if (is_auto){
|
|
strcpy(msx_type, "MSX2+");
|
|
}
|
|
return MEDIA_TYPE_DISK;
|
|
}
|
|
else if(strcmp(extension, ".m3u") == 0){
|
|
if (is_auto){
|
|
strcpy(msx_type, "MSX2+");
|
|
}
|
|
return MEDIA_TYPE_DISK_BUNDLE;
|
|
}
|
|
else if(strcmp(extension, ".cas") == 0){
|
|
if (is_auto){
|
|
strcpy(msx_type, "MSX2+");
|
|
}
|
|
return MEDIA_TYPE_TAPE;
|
|
}
|
|
else if(strcmp(extension, ".rom") == 0){
|
|
if (is_auto){
|
|
strcpy(msx_type, "MSX2+");
|
|
}
|
|
return MEDIA_TYPE_CART;
|
|
}
|
|
else if(strcmp(extension, ".mx1") == 0){
|
|
if (is_auto){
|
|
strcpy(msx_type, "MSX2+");
|
|
}
|
|
return MEDIA_TYPE_CART;
|
|
}
|
|
else if(strcmp(extension, ".mx2") == 0){
|
|
if (is_auto){
|
|
strcpy(msx_type, "MSX2+");
|
|
}
|
|
return MEDIA_TYPE_CART;
|
|
}
|
|
else if(strcmp(extension, ".col") == 0){
|
|
if (is_auto){
|
|
is_coleco = true;
|
|
strcpy(msx_type, "COL - ColecoVision");
|
|
}
|
|
return MEDIA_TYPE_CART;
|
|
}
|
|
else if(strcmp(extension, ".sg") == 0){
|
|
if (is_auto){
|
|
is_sega = true;
|
|
strcpy(msx_type, "SEGA - SC-3000");
|
|
}
|
|
return MEDIA_TYPE_CART;
|
|
}
|
|
|
|
return MEDIA_TYPE_OTHER;
|
|
}
|
|
|
|
/* end .dsk support */
|
|
/* .dsk swap support */
|
|
struct retro_disk_control_callback dskcb;
|
|
unsigned disk_index = 0;
|
|
unsigned disk_images = 0;
|
|
char disk_paths[10][PATH_MAX];
|
|
bool disk_inserted = false;
|
|
|
|
bool set_eject_state(bool ejected)
|
|
{
|
|
disk_inserted = !ejected;
|
|
return true;
|
|
}
|
|
|
|
bool get_eject_state(void)
|
|
{
|
|
return !disk_inserted;
|
|
}
|
|
|
|
unsigned get_image_index(void)
|
|
{
|
|
return disk_index;
|
|
}
|
|
|
|
bool set_image_index(unsigned index)
|
|
{
|
|
disk_index = index;
|
|
|
|
if(disk_index == disk_images)
|
|
{
|
|
//retroarch is trying to set "no disk in tray"
|
|
return true;
|
|
}
|
|
|
|
emulatorSuspend();
|
|
insertDiskette(properties, 0 /*drive*/, disk_paths[disk_index] /*fname*/, NULL /*inZipFile*/, -1 /*forceAutostart, -1 is force no autostart*/);
|
|
emulatorResume();
|
|
|
|
return true;
|
|
}
|
|
|
|
unsigned get_num_images(void)
|
|
{
|
|
return disk_images;
|
|
}
|
|
|
|
bool add_image_index(void)
|
|
{
|
|
if (disk_images >= 10)
|
|
return false;
|
|
|
|
disk_images++;
|
|
return true;
|
|
}
|
|
|
|
bool replace_image_index(unsigned index, const struct retro_game_info *info)
|
|
{
|
|
if(get_media_type(info->path) != MEDIA_TYPE_DISK)
|
|
return false;//cant swap a cart or tape into a disk slot
|
|
|
|
strcpy(disk_paths[index], info->path);
|
|
return true;
|
|
}
|
|
|
|
void attach_disk_swap_interface(void)
|
|
{
|
|
/* these functions are unused */
|
|
dskcb.set_eject_state = set_eject_state;
|
|
dskcb.get_eject_state = get_eject_state;
|
|
dskcb.set_image_index = set_image_index;
|
|
dskcb.get_image_index = get_image_index;
|
|
dskcb.get_num_images = get_num_images;
|
|
dskcb.add_image_index = add_image_index;
|
|
dskcb.replace_image_index = replace_image_index;
|
|
|
|
environ_cb(RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE, &dskcb);
|
|
}
|
|
/* end .dsk swap support */
|
|
|
|
static bool read_m3u(const char *file)
|
|
{
|
|
char line[PATH_MAX];
|
|
char name[PATH_MAX];
|
|
FILE *f = fopen(file, "r");
|
|
|
|
if (!f)
|
|
return false;
|
|
|
|
while (fgets(line, sizeof(line), f) && disk_images < sizeof(disk_paths) / sizeof(disk_paths[0]))
|
|
{
|
|
char *carriage_return = NULL;
|
|
char *newline = NULL;
|
|
|
|
if (line[0] == '#')
|
|
continue;
|
|
|
|
carriage_return = strchr(line, '\r');
|
|
if (carriage_return)
|
|
*carriage_return = '\0';
|
|
|
|
newline = strchr(line, '\n');
|
|
if (newline)
|
|
*newline = '\0';
|
|
|
|
if (line[0] != '\0')
|
|
{
|
|
snprintf(name, sizeof(name), "%s%c%s", base_dir, SLASH, line);
|
|
strcpy(disk_paths[disk_images], name);
|
|
disk_images++;
|
|
}
|
|
}
|
|
|
|
fclose(f);
|
|
return (disk_images != 0);
|
|
}
|
|
|
|
extern BoardInfo boardInfo;
|
|
|
|
#define MAX_PADS 2
|
|
static unsigned input_devices[MAX_PADS];
|
|
|
|
extern int eventMap[256];
|
|
|
|
static unsigned btn_map[EC_KEYCOUNT] =
|
|
{
|
|
RETROK_UNKNOWN, //EC_NONE 0
|
|
|
|
// ROW 0
|
|
RETROK_F1, //EC_F1 1
|
|
RETROK_F2, //EC_F2 2
|
|
RETROK_F3, //EC_F3 3
|
|
RETROK_F4, //EC_F4 4
|
|
RETROK_F5, //EC_F5 5
|
|
RETROK_END, //EC_STOP 6
|
|
RETROK_HOME, //EC_CLS 7
|
|
RETROK_PAGEUP, //EC_SELECT 8
|
|
RETROK_INSERT, //EC_INS 9
|
|
RETROK_DELETE, //EC_DEL 10
|
|
|
|
// ROW 1
|
|
RETROK_ESCAPE, //EC_ESC 11
|
|
RETROK_1, //EC_1 12
|
|
RETROK_2, //EC_2 13
|
|
RETROK_3, //EC_3 14
|
|
RETROK_4, //EC_4 15
|
|
RETROK_5, //EC_5 16
|
|
RETROK_6, //EC_6 17
|
|
RETROK_7, //EC_7 18
|
|
RETROK_8, //EC_8 19
|
|
RETROK_9, //EC_9 20
|
|
RETROK_0, //EC_0 21
|
|
RETROK_MINUS, //EC_NEG 22
|
|
RETROK_EQUALS, //EC_CIRCFLX 23
|
|
RETROK_BACKSLASH, //EC_BKSLASH 24 (YEN)
|
|
RETROK_BACKSPACE, //EC_BKSPACE 25
|
|
|
|
// ROW 2
|
|
RETROK_TAB, //EC_TAB 26
|
|
RETROK_q, //EC_Q 27
|
|
RETROK_w, //EC_W 28
|
|
RETROK_e, //EC_E 29
|
|
RETROK_r, //EC_R 30
|
|
RETROK_t, //EC_T 31
|
|
RETROK_y, //EC_Y 32
|
|
RETROK_u, //EC_U 33
|
|
RETROK_i, //EC_I 34
|
|
RETROK_o, //EC_O 35
|
|
RETROK_p, //EC_P 36
|
|
RETROK_BACKQUOTE, //EC_AT 37
|
|
RETROK_LEFTBRACKET, //EC_LBRACK 38
|
|
RETROK_RETURN, //EC_RETURN 39
|
|
|
|
// ROW 3
|
|
RETROK_LCTRL, //EC_CTRL 40
|
|
RETROK_a, //EC_A 41
|
|
RETROK_s, //EC_S 42
|
|
RETROK_d, //EC_D 43
|
|
RETROK_f, //EC_F 44
|
|
RETROK_g, //EC_G 45
|
|
RETROK_h, //EC_H 46
|
|
RETROK_j, //EC_J 47
|
|
RETROK_k, //EC_K 48
|
|
RETROK_l, //EC_L 49
|
|
RETROK_SEMICOLON, //EC_SEMICOL 50
|
|
RETROK_QUOTE, //EC_COLON 51
|
|
RETROK_RIGHTBRACKET, //EC_RBRACK 52
|
|
|
|
// ROW 4
|
|
RETROK_LSHIFT, //EC_LSHIFT 53
|
|
RETROK_z, //EC_Z 54
|
|
RETROK_x, //EC_X 55
|
|
RETROK_c, //EC_C 56
|
|
RETROK_v, //EC_V 57
|
|
RETROK_b, //EC_B 58
|
|
RETROK_n, //EC_N 59
|
|
RETROK_m, //EC_M 60
|
|
RETROK_COMMA, //EC_COMMA 61
|
|
RETROK_PERIOD, //EC_PERIOD 62
|
|
RETROK_SLASH, //EC_DIV 63
|
|
RETROK_0, //EC_UNDSCRE 64 (as Shift+0)
|
|
RETROK_RSHIFT, //EC_RSHIFT 65
|
|
|
|
// ROW 5
|
|
RETROK_CAPSLOCK, //EC_CAPS 66
|
|
RETROK_LALT, //EC_GRAPH 67
|
|
RETROK_UNKNOWN, //EC_TORIKE 68
|
|
RETROK_SPACE, //EC_SPACE 69
|
|
RETROK_UNKNOWN, //EC_JIKKOU 70
|
|
RETROK_UNKNOWN, //EC_CODE 71
|
|
RETROK_PAUSE, //EC_PAUSE 72
|
|
|
|
// ARROWS
|
|
RETROK_LEFT, //EC_LEFT 73
|
|
RETROK_UP, //EC_UP 74
|
|
RETROK_DOWN, //EC_DOWN 75
|
|
RETROK_RIGHT, //EC_RIGHT 76
|
|
|
|
// NUMERIC KEYBOARD
|
|
RETROK_KP7, //EC_NUM7 77
|
|
RETROK_KP8, //EC_NUM8 78
|
|
RETROK_KP9, //EC_NUM9 79
|
|
RETROK_KP_DIVIDE, //EC_NUMDIV 80
|
|
RETROK_KP4, //EC_NUM4 81
|
|
RETROK_KP5, //EC_NUM5 82
|
|
RETROK_KP6, //EC_NUM6 83
|
|
RETROK_KP_MULTIPLY, //EC_NUMMUL 84
|
|
RETROK_KP1, //EC_NUM1 85
|
|
RETROK_KP2, //EC_NUM2 86
|
|
RETROK_KP3, //EC_NUM3 87
|
|
RETROK_KP_MINUS, //EC_NUMSUB 88
|
|
RETROK_KP0, //EC_NUM0 89
|
|
RETROK_KP_ENTER, //EC_NUMPER 90
|
|
RETROK_KP_PERIOD, //EC_NUMCOM 91
|
|
RETROK_KP_PLUS, //EC_NUMADD 92
|
|
|
|
// SVI SPECIFIC KEYS
|
|
RETROK_PRINT, //EC_PRINT 93
|
|
|
|
RETROK_UNKNOWN,
|
|
RETROK_UNKNOWN,
|
|
RETROK_UNKNOWN,
|
|
RETROK_UNKNOWN,
|
|
RETROK_UNKNOWN,
|
|
RETROK_UNKNOWN,
|
|
|
|
RETRO_DEVICE_ID_JOYPAD_UP, //EC_JOY1_UP 100
|
|
RETRO_DEVICE_ID_JOYPAD_DOWN, //EC_JOY1_DOWN 101
|
|
RETRO_DEVICE_ID_JOYPAD_LEFT, //EC_JOY1_LEFT 102
|
|
RETRO_DEVICE_ID_JOYPAD_RIGHT, //EC_JOY1_RIGHT 103
|
|
RETRO_DEVICE_ID_JOYPAD_A, //EC_JOY1_BUTTON1 104
|
|
RETRO_DEVICE_ID_JOYPAD_B, //EC_JOY1_BUTTON2 105
|
|
RETRO_DEVICE_ID_JOYPAD_Y, //EC_JOY1_BUTTON3 106
|
|
RETRO_DEVICE_ID_JOYPAD_X, //EC_JOY1_BUTTON4 107
|
|
RETRO_DEVICE_ID_JOYPAD_START, //EC_JOY1_BUTTON5 108
|
|
RETRO_DEVICE_ID_JOYPAD_SELECT, //EC_JOY1_BUTTON6 109
|
|
|
|
RETRO_DEVICE_ID_JOYPAD_UP, //EC_JOY2_UP 110
|
|
RETRO_DEVICE_ID_JOYPAD_DOWN, //EC_JOY2_DOWN 111
|
|
RETRO_DEVICE_ID_JOYPAD_LEFT, //EC_JOY2_LEFT 112
|
|
RETRO_DEVICE_ID_JOYPAD_RIGHT, //EC_JOY2_RIGHT 113
|
|
RETRO_DEVICE_ID_JOYPAD_A, //EC_JOY2_BUTTON1 114
|
|
RETRO_DEVICE_ID_JOYPAD_B, //EC_JOY2_BUTTON2 115
|
|
RETRO_DEVICE_ID_JOYPAD_Y, //EC_JOY2_BUTTON3 116
|
|
RETRO_DEVICE_ID_JOYPAD_X, //EC_JOY2_BUTTON4 117
|
|
RETRO_DEVICE_ID_JOYPAD_START, //EC_JOY2_BUTTON5 118
|
|
RETRO_DEVICE_ID_JOYPAD_SELECT, //EC_JOY2_BUTTON6 119
|
|
|
|
RETROK_UNKNOWN, //EC_COLECO1_0 120
|
|
RETROK_UNKNOWN, //EC_COLECO1_1 121
|
|
RETROK_UNKNOWN, //EC_COLECO1_2 122
|
|
RETROK_UNKNOWN, //EC_COLECO1_3 123
|
|
RETROK_UNKNOWN, //EC_COLECO1_4 124
|
|
RETROK_UNKNOWN, //EC_COLECO1_5 125
|
|
RETROK_UNKNOWN, //EC_COLECO1_6 126
|
|
RETROK_UNKNOWN, //EC_COLECO1_7 127
|
|
RETROK_UNKNOWN, //EC_COLECO1_8 128
|
|
RETROK_UNKNOWN, //EC_COLECO1_9 129
|
|
RETROK_UNKNOWN, //EC_COLECO1_STAR 130
|
|
RETROK_UNKNOWN, //EC_COLECO1_HASH 131
|
|
|
|
RETROK_UNKNOWN, //EC_COLECO2_0 140
|
|
RETROK_UNKNOWN, //EC_COLECO2_1 141
|
|
RETROK_UNKNOWN, //EC_COLECO2_2 142
|
|
RETROK_UNKNOWN, //EC_COLECO2_3 143
|
|
RETROK_UNKNOWN, //EC_COLECO2_4 144
|
|
RETROK_UNKNOWN, //EC_COLECO2_5 145
|
|
RETROK_UNKNOWN, //EC_COLECO2_6 146
|
|
RETROK_UNKNOWN, //EC_COLECO2_7 147
|
|
RETROK_UNKNOWN, //EC_COLECO2_8 148
|
|
RETROK_UNKNOWN, //EC_COLECO2_9 149
|
|
RETROK_UNKNOWN, //EC_COLECO2_STAR 150
|
|
RETROK_UNKNOWN, //EC_COLECO2_HASH 151
|
|
};
|
|
|
|
void retro_get_system_info(struct retro_system_info *info)
|
|
{
|
|
info->library_name = "blueMSX";
|
|
#ifdef GIT_VERSION
|
|
info->library_version = "git" GIT_VERSION;
|
|
#else
|
|
info->library_version = "svn";
|
|
#endif
|
|
info->need_fullpath = true;
|
|
info->block_extract = false;
|
|
info->valid_extensions = "rom|ri|mx1|mx2|dsk|col|sg|sc|cas|m3u";
|
|
}
|
|
|
|
void retro_get_system_av_info(struct retro_system_av_info *info)
|
|
{
|
|
width = use_overscan ? 272 : (272 - 16);
|
|
height = use_overscan ? 240 : (240 - 48 + (msx2_dif * 2));
|
|
info->geometry.base_width = width ;
|
|
info->geometry.base_height = height ;
|
|
info->geometry.max_width = FB_MAX_LINE_WIDTH ;
|
|
info->geometry.max_height = FB_MAX_LINES ;
|
|
info->geometry.aspect_ratio = 0;
|
|
info->timing.fps = 60.0;
|
|
info->timing.sample_rate = 44100.0;
|
|
}
|
|
|
|
void init_input_descriptors(unsigned device){
|
|
struct retro_input_descriptor desc_retropad[] = {
|
|
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Joy Left" },
|
|
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "Joy Up" },
|
|
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "Joy Down" },
|
|
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Joy Right" },
|
|
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "1 / coleco but.1" },
|
|
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "2 / coleco but.2" },
|
|
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "3 / coleco 2" },
|
|
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "4 / coleco 1" },
|
|
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "coleco #" },
|
|
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT,"coleco *" },
|
|
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "5 / coleco 4" },
|
|
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "6 / coleco 3" },
|
|
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "coleco 6" },
|
|
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "coleco 5" },
|
|
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "coleco 8" },
|
|
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "coleco 7" },
|
|
|
|
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Joy Left" },
|
|
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "Joy Up" },
|
|
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "Joy Down" },
|
|
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Joy Right" },
|
|
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "1 / coleco but.1" },
|
|
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "2 / coleco but.2" },
|
|
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "3 / coleco 2" },
|
|
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "4 / coleco 1" },
|
|
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "coleco #" },
|
|
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT,"coleco *" },
|
|
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "5 / coleco 4" },
|
|
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "6 / coleco 3" },
|
|
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "coleco 6" },
|
|
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "coleco 5" },
|
|
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "coleco 8" },
|
|
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "coleco 7" },
|
|
|
|
{ 0, 0, 0, 0, NULL }
|
|
};
|
|
|
|
|
|
struct retro_input_descriptor desc[] = {
|
|
{ 0, 0, 0, 0, NULL }
|
|
};
|
|
/* Todo: RetroPad Keymapper binds */
|
|
|
|
if (device == RETRO_DEVICE_JOYPAD)
|
|
environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc_retropad);
|
|
else
|
|
environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc);
|
|
}
|
|
|
|
void retro_init(void)
|
|
{
|
|
int i;
|
|
struct retro_log_callback log;
|
|
|
|
if (environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log))
|
|
log_cb = log.log;
|
|
else
|
|
log_cb = NULL;
|
|
|
|
|
|
#ifdef LOG_PERFORMANCE
|
|
environ_cb(RETRO_ENVIRONMENT_GET_PERF_INTERFACE, &perf_cb);
|
|
#endif
|
|
|
|
}
|
|
|
|
void retro_deinit(void)
|
|
{
|
|
#ifdef LOG_PERFORMANCE
|
|
perf_cb.perf_log();
|
|
#endif
|
|
}
|
|
|
|
void retro_set_environment(retro_environment_t cb)
|
|
{
|
|
static const struct retro_variable vars[] = {
|
|
{ "bluemsx_msxtype", "Machine Type (Restart); Auto|MSX|MSXturboR|MSX2|MSX2+|SEGA - SG-1000|SEGA - SC-3000|SEGA - SF-7000|SVI - Spectravideo SVI-318|SVI - Spectravideo SVI-328|SVI - Spectravideo SVI-328 MK2|ColecoVision|Coleco (Spectravideo SVI-603)" },
|
|
{ "bluemsx_overscan", "Crop Overscan; disabled|enabled|MSX2" },
|
|
{ "bluemsx_vdp_synctype", "VDP Sync Type (Restart); Auto|50Hz|60Hz" },
|
|
{ "bluemsx_nospritelimits", "No Sprite Limit; OFF|ON" },
|
|
{ "bluemsx_ym2413_enable", "Sound YM2413 Enable (Restart); enabled|disabled" },
|
|
{ "bluemsx_cartmapper", "Cart Mapper Type (Restart); Auto|Normal|mirrored|basic|0x4000|0xC000|ascii8|ascii8sram|ascii16|ascii16sram|ascii16nf|konami4|konami4nf|konami5|konamisynth|korean80|korean90|korean126|MegaFlashRomScc|MegaFlashRomSccPlus|msxdos2|scc|sccexpanded|sccmirrored|sccplus|snatcher|sdsnatcher|SegaBasic|SG1000|SG1000Castle|SG1000RamA|SG1000RamB|SC3000" },
|
|
{ "bluemsx_auto_rewind_cas", "Auto Rewind Cassette; ON|OFF" },
|
|
{ NULL, NULL },
|
|
};
|
|
|
|
static const struct retro_controller_description port[] = {
|
|
{ "RetroPad", RETRO_DEVICE_JOYPAD },
|
|
{ "RetroKeyboard", RETRO_DEVICE_KEYBOARD },
|
|
{ "RetroPad Keyboard Map", RETRO_DEVICE_MAPPER },
|
|
{ 0 },
|
|
};
|
|
|
|
static const struct retro_controller_info ports[] = {
|
|
{ port, 3 },
|
|
{ port, 2 },
|
|
{ NULL, 0 },
|
|
};
|
|
|
|
environ_cb = cb;
|
|
|
|
cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void*)vars);
|
|
cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports);
|
|
}
|
|
|
|
void retro_set_controller_port_device(unsigned port, unsigned device)
|
|
{
|
|
/*there was a buffer overflow when retroarch called this function with a value greater than 1
|
|
corrupting the framebuffer pointer and crashing on first render(MAX_PADS == 2 so any index that is not [0,1] is an overflow)*/
|
|
if(port < MAX_PADS)
|
|
{
|
|
switch (device)
|
|
{
|
|
case RETRO_DEVICE_JOYPAD:
|
|
input_devices[port] = RETRO_DEVICE_JOYPAD;
|
|
init_input_descriptors(RETRO_DEVICE_JOYPAD);
|
|
break;
|
|
case RETRO_DEVICE_MAPPER:
|
|
input_devices[port] = RETRO_DEVICE_MAPPER;
|
|
init_input_descriptors(RETRO_DEVICE_MAPPER);
|
|
break;
|
|
case RETRO_DEVICE_KEYBOARD:
|
|
input_devices[port] = RETRO_DEVICE_KEYBOARD;
|
|
init_input_descriptors(RETRO_DEVICE_KEYBOARD);
|
|
break;
|
|
default:
|
|
if (log_cb)
|
|
log_cb(RETRO_LOG_ERROR, "%s\n", "[libretro]: Invalid device, setting type to RETRO_DEVICE_JOYPAD ...");
|
|
input_devices[port] = RETRO_DEVICE_JOYPAD;
|
|
}
|
|
}
|
|
}
|
|
|
|
void retro_reset(void)
|
|
{
|
|
actionEmuResetSoft();
|
|
|
|
/* Apply mapper override on reset, force mapper detection again */
|
|
if (properties->media.carts[0].fileName[0]){
|
|
if (!mapper_auto)
|
|
insertCartridge(properties, 0, properties->media.carts[0].fileName, properties->media.carts[0].fileNameInZip, mediaDbStringToType(msx_cartmapper), -1);
|
|
else
|
|
insertCartridge(properties, 0, properties->media.carts[0].fileName, properties->media.carts[0].fileNameInZip, 0, -1);
|
|
}
|
|
}
|
|
|
|
static void extract_directory(char *buf, const char *path, size_t size)
|
|
{
|
|
char *base = NULL;
|
|
|
|
strncpy(buf, path, size - 1);
|
|
buf[size - 1] = '\0';
|
|
|
|
base = strrchr(buf, '/');
|
|
if (!base)
|
|
base = strrchr(buf, '\\');
|
|
|
|
if (base)
|
|
*base = '\0';
|
|
else
|
|
buf[0] = '\0';
|
|
}
|
|
|
|
static void check_variables(void)
|
|
{
|
|
struct retro_system_av_info av_info;
|
|
bool geometry_update = false;
|
|
struct retro_variable var;
|
|
|
|
var.key = "bluemsx_msxtype";
|
|
var.value = NULL;
|
|
|
|
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
|
|
{
|
|
if (!strcmp(var.value, "ColecoVision"))
|
|
{
|
|
is_coleco = true;
|
|
strcpy(msx_type, "COL - ColecoVision");
|
|
}
|
|
else if (!strcmp(var.value, "Coleco (Spectravideo SVI-603)"))
|
|
{
|
|
is_coleco = true;
|
|
strcpy(msx_type, "COL - Spectravideo SVI-603 Coleco");
|
|
}
|
|
else if (strcmp(var.value, "Auto"))
|
|
{
|
|
is_coleco = false;
|
|
strcpy(msx_type, var.value);
|
|
|
|
if (!strncmp(var.value, "SEGA", 4))
|
|
is_sega = true;
|
|
if (!strncmp(var.value, "SVI", 3))
|
|
is_spectra = true;
|
|
}
|
|
else
|
|
{
|
|
is_auto = true;
|
|
strcpy(msx_type, "SEGA - SC-3000");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
is_auto = true;
|
|
// Sega machines don't work if not set right from the start
|
|
strcpy(msx_type, "SEGA - SC-3000");
|
|
}
|
|
|
|
var.key = "bluemsx_overscan";
|
|
var.value = NULL;
|
|
|
|
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
|
|
{
|
|
bool newval = (!strcmp(var.value, "disabled"));
|
|
int msx2_dif_old = msx2_dif;
|
|
|
|
if (!strcmp(var.value, "MSX2"))
|
|
msx2_dif = 10;
|
|
else
|
|
msx2_dif = 0;
|
|
|
|
if (msx2_dif_old != msx2_dif)
|
|
geometry_update = true;
|
|
|
|
if (newval != use_overscan)
|
|
{
|
|
use_overscan = newval;
|
|
geometry_update = true;
|
|
}
|
|
}
|
|
|
|
var.key = "bluemsx_vdp_synctype";
|
|
var.value = NULL;
|
|
|
|
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
|
|
{
|
|
if (!strcmp(var.value, "Auto"))
|
|
msx_vdp_synctype = P_VDP_SYNCAUTO;
|
|
else if (!strcmp(var.value, "50Hz"))
|
|
msx_vdp_synctype = P_VDP_SYNC50HZ;
|
|
else if (!strcmp(var.value, "60Hz"))
|
|
msx_vdp_synctype = P_VDP_SYNC60HZ;
|
|
}
|
|
else
|
|
msx_vdp_synctype = P_VDP_SYNCAUTO;
|
|
|
|
var.key = "bluemsx_nospritelimits";
|
|
var.value = NULL;
|
|
|
|
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
|
|
{
|
|
if (!strcmp(var.value, "OFF"))
|
|
vdpSetNoSpriteLimits(0);
|
|
else
|
|
vdpSetNoSpriteLimits(1);
|
|
}
|
|
else
|
|
vdpSetNoSpriteLimits(0);
|
|
|
|
var.key = "bluemsx_ym2413_enable";
|
|
var.value = NULL;
|
|
|
|
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
|
|
{
|
|
if (!strcmp(var.value, "disabled"))
|
|
msx_ym2413_enable = false;
|
|
else if (!strcmp(var.value, "enabled"))
|
|
msx_ym2413_enable = true;
|
|
}
|
|
else
|
|
msx_ym2413_enable = true;
|
|
|
|
var.key = "bluemsx_cartmapper";
|
|
var.value = NULL;
|
|
|
|
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
|
|
{
|
|
if (!strcmp(var.value, "Auto"))
|
|
mapper_auto = true;
|
|
else
|
|
{
|
|
mapper_auto = false;
|
|
strcpy(msx_cartmapper, var.value);
|
|
}
|
|
}
|
|
|
|
var.key = "bluemsx_auto_rewind_cas";
|
|
var.value = NULL;
|
|
|
|
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
|
|
{
|
|
if (!strcmp(var.value, "OFF"))
|
|
auto_rewind_cas = false;
|
|
else
|
|
auto_rewind_cas = true;
|
|
}
|
|
else
|
|
auto_rewind_cas = true;
|
|
|
|
if (geometry_update)
|
|
{
|
|
retro_get_system_av_info(&av_info);
|
|
environ_cb(RETRO_ENVIRONMENT_SET_GEOMETRY, &av_info);
|
|
}
|
|
}
|
|
|
|
bool retro_load_game(const struct retro_game_info *info)
|
|
{
|
|
const char *save_dir = NULL;
|
|
int i, media_type;
|
|
char properties_dir[256], machines_dir[256], mediadb_dir[256];
|
|
const char *dir = NULL;
|
|
enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_RGB565;
|
|
|
|
if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt))
|
|
{
|
|
if (log_cb)
|
|
log_cb(RETRO_LOG_INFO, "%s\n", "RGB565 is not supported.");
|
|
return false;
|
|
}
|
|
|
|
if (!info)
|
|
return false;
|
|
|
|
image_buffer = malloc(FB_MAX_LINE_WIDTH*FB_MAX_LINES*sizeof(uint16_t));
|
|
image_buffer_base_width = 272;
|
|
image_buffer_current_width = image_buffer_base_width;
|
|
image_buffer_height = 240;
|
|
double_width = 0;
|
|
|
|
for (i = 0; i < MAX_PADS; i++)
|
|
input_devices[i] = RETRO_DEVICE_JOYPAD;
|
|
|
|
disk_index = 0;
|
|
disk_images = 0;
|
|
disk_inserted = false;
|
|
extract_directory(base_dir, info->path, sizeof(base_dir));
|
|
|
|
check_variables();
|
|
|
|
if (environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &dir) && dir)
|
|
strcpy(properties_dir, dir);
|
|
else /* Fallback */
|
|
extract_directory(properties_dir, info->path, sizeof(properties_dir));
|
|
|
|
snprintf(machines_dir, sizeof(machines_dir), "%s%c%s", properties_dir, SLASH, "Machines");
|
|
snprintf(mediadb_dir, sizeof(mediadb_dir), "%s%c%s", properties_dir, SLASH, "Databases");
|
|
|
|
propertiesSetDirectory(properties_dir, properties_dir);
|
|
machineSetDirectory(machines_dir);
|
|
|
|
if(environ_cb(RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY, &save_dir) && save_dir)
|
|
boardSetDirectory(save_dir);
|
|
|
|
#if 0
|
|
boardSetDirectory(buffer);
|
|
#endif
|
|
mediaDbLoad(mediadb_dir);
|
|
#if 0
|
|
mediaDbCreateRomdb();
|
|
mediaDbCreateDiskdb();
|
|
mediaDbCreateCasdb();
|
|
#endif
|
|
|
|
properties = propCreate(1, EMU_LANG_ENGLISH, P_KBD_EUROPEAN, P_EMU_SYNCNONE, "");
|
|
|
|
media_type = get_media_type(info->path);
|
|
|
|
if (is_coleco)
|
|
{
|
|
strcpy(properties->joy1.type, "coleco joystick");
|
|
properties->joy1.typeId = JOYSTICK_PORT_COLECOJOYSTICK;
|
|
properties->joy1.autofire = 0;
|
|
|
|
strcpy(properties->joy2.type, "coleco joystick");
|
|
properties->joy2.typeId = JOYSTICK_PORT_COLECOJOYSTICK;
|
|
properties->joy2.autofire = 0;
|
|
}
|
|
else
|
|
{
|
|
strcpy(properties->joy1.type, "joystick");
|
|
properties->joy1.typeId = JOYSTICK_PORT_JOYSTICK;
|
|
properties->joy1.autofire = 0;
|
|
|
|
strcpy(properties->joy2.type, "joystick");
|
|
properties->joy2.typeId = JOYSTICK_PORT_JOYSTICK;
|
|
properties->joy2.autofire = 0;
|
|
}
|
|
|
|
properties->emulation.vdpSyncMode = msx_vdp_synctype;
|
|
properties->video.monitorType = P_VIDEO_PALNONE;
|
|
strcpy(properties->emulation.machineName, msx_type);
|
|
|
|
properties->sound.chip.enableYM2413 = msx_ym2413_enable;
|
|
|
|
mixer = mixerCreate();
|
|
|
|
emulatorInit(properties, mixer);
|
|
actionInit(video, properties, mixer);
|
|
langInit();
|
|
tapeSetReadOnly(properties->cassette.readOnly);
|
|
if (auto_rewind_cas)
|
|
tapeRewindNextInsert();
|
|
|
|
langSetLanguage(properties->language);
|
|
|
|
joystickPortSetType(0, properties->joy1.typeId);
|
|
joystickPortSetType(1, properties->joy2.typeId);
|
|
|
|
#if 0
|
|
printerIoSetType(properties->ports.Lpt.type, properties->ports.Lpt.fileName);
|
|
uartIoSetType(properties->ports.Com.type, properties->ports.Com.fileName);
|
|
midiIoSetMidiOutType(properties->sound.MidiOut.type, properties->sound.MidiOut.fileName);
|
|
midiIoSetMidiInType(properties->sound.MidiIn.type, properties->sound.MidiIn.fileName);
|
|
ykIoSetMidiInType(properties->sound.YkIn.type, properties->sound.YkIn.fileName);
|
|
#endif
|
|
|
|
emulatorRestartSound();
|
|
|
|
for (i = 0; i < MIXER_CHANNEL_TYPE_COUNT; i++)
|
|
{
|
|
mixerSetChannelTypeVolume(mixer, i, properties->sound.mixerChannel[i].volume);
|
|
mixerSetChannelTypePan(mixer, i, properties->sound.mixerChannel[i].pan);
|
|
mixerEnableChannelType(mixer, i, properties->sound.mixerChannel[i].enable);
|
|
}
|
|
|
|
mixerSetMasterVolume(mixer, properties->sound.masterVolume);
|
|
mixerEnableMaster(mixer, properties->sound.masterEnable);
|
|
|
|
|
|
if (mapper_auto)
|
|
mediaDbSetDefaultRomType(properties->cartridge.defaultType);
|
|
else
|
|
mediaDbSetDefaultRomType(mediaDbStringToType(msx_cartmapper));
|
|
|
|
switch(media_type)
|
|
{
|
|
case MEDIA_TYPE_DISK:
|
|
strcpy(disk_paths[0] , info->path);
|
|
strcpy(properties->media.disks[0].fileName , info->path);
|
|
disk_inserted = true;
|
|
attach_disk_swap_interface();
|
|
break;
|
|
case MEDIA_TYPE_DISK_BUNDLE:
|
|
if (!read_m3u(info->path))
|
|
{
|
|
if (log_cb)
|
|
log_cb(RETRO_LOG_ERROR, "%s\n", "[libretro]: failed to read m3u file ...");
|
|
return false;
|
|
}
|
|
for (i = 0; (i <= disk_images) && (i <= 1); i++)
|
|
{
|
|
strcpy(properties->media.disks[i].fileName , disk_paths[i]);
|
|
}
|
|
disk_inserted = true;
|
|
attach_disk_swap_interface();
|
|
break;
|
|
case MEDIA_TYPE_TAPE:
|
|
strcpy(properties->media.tapes[0].fileName , info->path);
|
|
break;
|
|
case MEDIA_TYPE_CART:
|
|
case MEDIA_TYPE_OTHER:
|
|
default:
|
|
strcpy(properties->media.carts[0].fileName , info->path);
|
|
break;
|
|
}
|
|
|
|
for (i = 0; i < PROP_MAX_CARTS; i++)
|
|
{
|
|
/* Breaks database detection
|
|
if (properties->media.carts[i].fileName[0] && mapper_auto)
|
|
insertCartridge(properties, i, properties->media.carts[i].fileName, properties->media.carts[i].fileNameInZip, properties->media.carts[i].type, -1);
|
|
*/
|
|
if (properties->media.carts[i].fileName[0] && !mapper_auto)
|
|
insertCartridge(properties, i, properties->media.carts[i].fileName, properties->media.carts[i].fileNameInZip, mediaDbStringToType(msx_cartmapper), -1);
|
|
|
|
updateExtendedRomName(i, properties->media.carts[i].fileName, properties->media.carts[i].fileNameInZip);
|
|
}
|
|
|
|
for (i = 0; i < PROP_MAX_DISKS; i++)
|
|
{
|
|
if (properties->media.disks[i].fileName[0])
|
|
insertDiskette(properties, i, properties->media.disks[i].fileName, properties->media.disks[i].fileNameInZip, -1);
|
|
updateExtendedDiskName(i, properties->media.disks[i].fileName, properties->media.disks[i].fileNameInZip);
|
|
}
|
|
|
|
for (i = 0; i < PROP_MAX_TAPES; i++)
|
|
{
|
|
if (properties->media.tapes[i].fileName[0])
|
|
insertCassette(properties, i, properties->media.tapes[i].fileName, properties->media.tapes[i].fileNameInZip, 0);
|
|
updateExtendedCasName(i, properties->media.tapes[i].fileName, properties->media.tapes[i].fileNameInZip);
|
|
}
|
|
|
|
{
|
|
Machine* machine = machineCreate(properties->emulation.machineName);
|
|
if (machine != NULL)
|
|
{
|
|
boardSetMachine(machine);
|
|
machineDestroy(machine);
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
boardSetFdcTimingEnable(properties->emulation.enableFdcTiming);
|
|
boardSetY8950Enable(properties->sound.chip.enableY8950);
|
|
boardSetYm2413Enable(properties->sound.chip.enableYM2413);
|
|
boardSetMoonsoundEnable(properties->sound.chip.enableMoonsound);
|
|
boardSetVideoAutodetect(properties->video.detectActiveMonitor);
|
|
|
|
emulatorStart(NULL);
|
|
return true;
|
|
}
|
|
|
|
void timerCallback_global(void* timer);
|
|
|
|
UInt8 archJoystickGetState(int joystickNo)
|
|
{
|
|
return ((eventMap[EC_JOY1_UP] << 0) |
|
|
(eventMap[EC_JOY1_DOWN] << 1) |
|
|
(eventMap[EC_JOY1_LEFT] << 2) |
|
|
(eventMap[EC_JOY1_RIGHT] << 3) |
|
|
(eventMap[EC_JOY1_BUTTON1] << 4) |
|
|
(eventMap[EC_JOY1_BUTTON2] << 5) |
|
|
(eventMap[EC_JOY1_BUTTON3] << 6) |
|
|
(eventMap[EC_JOY1_BUTTON4] << 7));
|
|
}
|
|
|
|
void retro_run(void)
|
|
{
|
|
int i,j;
|
|
bool updated = false;
|
|
|
|
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
|
|
check_variables();
|
|
|
|
RETRO_PERFORMANCE_INIT(core_retro_run);
|
|
RETRO_PERFORMANCE_START(core_retro_run);
|
|
|
|
input_poll_cb();
|
|
|
|
if (is_coleco)
|
|
{
|
|
/* ColecoVision Input Part */
|
|
for (i = 0; i < MAX_PADS; i++)
|
|
{
|
|
switch (input_devices[i])
|
|
{
|
|
case RETRO_DEVICE_JOYPAD:
|
|
if (i == 0){
|
|
for (j = EC_JOY1_UP; j <= (EC_JOY1_BUTTON2); j++)
|
|
eventMap[j] = input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, btn_map[j]) ? 1 : 0;
|
|
}else if (i == 1){
|
|
for (j = EC_JOY2_UP; j <= (EC_JOY2_BUTTON2); j++)
|
|
eventMap[j] = input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, btn_map[j]) ? 1 : 0;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
eventMap[EC_COLECO1_1] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X) ? 1 : 0;
|
|
eventMap[EC_COLECO1_2] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y) ? 1 : 0;
|
|
eventMap[EC_COLECO1_3] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R) ? 1 : 0;
|
|
eventMap[EC_COLECO1_4] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L) ? 1 : 0;
|
|
eventMap[EC_COLECO1_5] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2) ? 1 : 0;
|
|
eventMap[EC_COLECO1_6] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2) ? 1 : 0;
|
|
eventMap[EC_COLECO1_7] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3) ? 1 : 0;
|
|
eventMap[EC_COLECO1_8] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3) ? 1 : 0;
|
|
eventMap[EC_COLECO1_STAR] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT) ? 1 : 0;
|
|
eventMap[EC_COLECO1_HASH] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START) ? 1 : 0;
|
|
eventMap[EC_COLECO1_0] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_1) ? 1 : 0;
|
|
eventMap[EC_COLECO1_9] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_2) ? 1 : 0;
|
|
|
|
eventMap[EC_COLECO2_1] = input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X) ? 1 : 0;
|
|
eventMap[EC_COLECO2_2] = input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y) ? 1 : 0;
|
|
eventMap[EC_COLECO2_3] = input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R) ? 1 : 0;
|
|
eventMap[EC_COLECO2_4] = input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L) ? 1 : 0;
|
|
eventMap[EC_COLECO2_5] = input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2) ? 1 : 0;
|
|
eventMap[EC_COLECO2_6] = input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2) ? 1 : 0;
|
|
eventMap[EC_COLECO2_7] = input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3) ? 1 : 0;
|
|
eventMap[EC_COLECO2_8] = input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3) ? 1 : 0;
|
|
eventMap[EC_COLECO2_STAR] = input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT) ? 1 : 0;
|
|
eventMap[EC_COLECO2_HASH] = input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START) ? 1 : 0;
|
|
eventMap[EC_COLECO2_0] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_3) ? 1 : 0;
|
|
eventMap[EC_COLECO2_9] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_4) ? 1 : 0;
|
|
}
|
|
else
|
|
{
|
|
/* MSX Input Part */
|
|
for (i = 0; i < MAX_PADS; i++)
|
|
{
|
|
switch (input_devices[i])
|
|
{
|
|
case RETRO_DEVICE_JOYPAD:
|
|
if (i == 0)
|
|
for (j = EC_JOY1_UP; j <= (EC_JOY1_BUTTON6); j++)
|
|
eventMap[j] = input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, btn_map[j]) ? 1 : 0;
|
|
else if (i == 1)
|
|
for (j = EC_JOY2_UP; j <= (EC_JOY2_BUTTON6); j++)
|
|
eventMap[j] = input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, btn_map[j]) ? 1 : 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (j = 0; j < EC_KEYBOARD_KEYCOUNT; j++)
|
|
eventMap[j] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, btn_map[j]) ? 1 : 0;
|
|
|
|
if (input_devices[0] == RETRO_DEVICE_MAPPER && !is_spectra){
|
|
eventMap[EC_LEFT] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT) ? 1 : 0;
|
|
eventMap[EC_RIGHT] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT) ? 1 : 0;
|
|
eventMap[EC_UP] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP) ? 1 : 0;
|
|
eventMap[EC_DOWN] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN) ? 1 : 0;
|
|
eventMap[EC_RETURN] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A) ? 1 : 0;
|
|
eventMap[EC_SPACE] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B) ? 1 : 0;
|
|
eventMap[EC_CTRL] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X) ? 1 : 0;
|
|
eventMap[EC_GRAPH] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y) ? 1 : 0;
|
|
}
|
|
|
|
if (input_devices[0] == RETRO_DEVICE_MAPPER && is_spectra){
|
|
eventMap[EC_JOY1_LEFT] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT) ? 1 : 0;
|
|
eventMap[EC_JOY1_RIGHT] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT) ? 1 : 0;
|
|
eventMap[EC_JOY1_UP] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP) ? 1 : 0;
|
|
eventMap[EC_JOY1_DOWN] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN) ? 1 : 0;
|
|
eventMap[EC_JOY1_BUTTON1] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A) ? 1 : 0;
|
|
eventMap[EC_JOY1_BUTTON2] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B) ? 1 : 0;
|
|
eventMap[EC_1] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X) ? 1 : 0;
|
|
eventMap[EC_2] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y) ? 1 : 0;
|
|
eventMap[EC_3] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R) ? 1 : 0;
|
|
eventMap[EC_4] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L) ? 1 : 0;
|
|
eventMap[EC_5] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2) ? 1 : 0;
|
|
eventMap[EC_6] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2) ? 1 : 0;
|
|
eventMap[EC_7] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3) ? 1 : 0;
|
|
eventMap[EC_8] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3) ? 1 : 0;
|
|
eventMap[EC_9] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT) ? 1 : 0;
|
|
eventMap[EC_0] = input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START) ? 1 : 0;
|
|
|
|
eventMap[EC_JOY2_LEFT] = input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT) ? 1 : 0;
|
|
eventMap[EC_JOY2_RIGHT] = input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT) ? 1 : 0;
|
|
eventMap[EC_JOY2_UP] = input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP) ? 1 : 0;
|
|
eventMap[EC_JOY2_DOWN] = input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN) ? 1 : 0;
|
|
eventMap[EC_JOY2_BUTTON1] = input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A) ? 1 : 0;
|
|
eventMap[EC_JOY2_BUTTON2] = input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B) ? 1 : 0;
|
|
}
|
|
}
|
|
|
|
((R800*)boardInfo.cpuRef)->terminate = 0;
|
|
boardInfo.run(boardInfo.cpuRef);
|
|
RETRO_PERFORMANCE_STOP(core_retro_run);
|
|
|
|
if (!use_overscan)
|
|
video_cb(image_buffer + 8 + (image_buffer_current_width * sizeof(uint16_t) * (12 - (msx2_dif / 2))),
|
|
image_buffer_current_width - 16, image_buffer_height - 48 + (msx2_dif * 2), image_buffer_current_width * sizeof(uint16_t));
|
|
else
|
|
video_cb(image_buffer, image_buffer_current_width, image_buffer_height, image_buffer_current_width * sizeof(uint16_t));
|
|
|
|
}
|
|
|
|
/* framebuffer */
|
|
|
|
uint16_t* frameBufferGetLine(FrameBuffer* frameBuffer, int y)
|
|
{
|
|
return (image_buffer + y * image_buffer_current_width);
|
|
}
|
|
|
|
FrameBuffer* frameBufferGetDrawFrame()
|
|
{
|
|
return (void*)image_buffer;
|
|
}
|
|
FrameBuffer* frameBufferFlipDrawFrame()
|
|
{
|
|
return (void*)image_buffer;
|
|
}
|
|
|
|
static int fbScanLine = 0;
|
|
void frameBufferSetScanline(int scanline)
|
|
{
|
|
fbScanLine = scanline;
|
|
}
|
|
|
|
int frameBufferGetScanline() {
|
|
return fbScanLine;
|
|
}
|
|
|
|
FrameBufferData* frameBufferDataCreate(int maxWidth, int maxHeight, int defaultHorizZoom)
|
|
{
|
|
return (void*)image_buffer;
|
|
}
|
|
|
|
FrameBufferData* frameBufferGetActive()
|
|
{
|
|
return (void*)image_buffer;
|
|
}
|
|
|
|
void frameBufferSetLineCount(FrameBuffer* frameBuffer, int val)
|
|
{
|
|
image_buffer_height = val;
|
|
}
|
|
|
|
int frameBufferGetLineCount(FrameBuffer* frameBuffer) {
|
|
return image_buffer_height;
|
|
}
|
|
|
|
int frameBufferGetMaxWidth(FrameBuffer* frameBuffer)
|
|
{
|
|
return FB_MAX_LINE_WIDTH;
|
|
}
|
|
|
|
int frameBufferGetDoubleWidth(FrameBuffer* frameBuffer, int y)
|
|
{
|
|
return double_width;
|
|
}
|
|
|
|
void frameBufferSetDoubleWidth(FrameBuffer* frameBuffer, int y, int val)
|
|
{
|
|
double_width = val;
|
|
image_buffer_current_width = double_width ? image_buffer_base_width * 2 : image_buffer_base_width;
|
|
}
|
|
|
|
/* libretro stubs */
|
|
void retro_set_audio_sample(retro_audio_sample_t unused) {}
|
|
bool retro_load_game_special(unsigned a, const struct retro_game_info *b, size_t c){return false;}
|
|
|
|
void retro_unload_game(void)
|
|
{
|
|
if (image_buffer)
|
|
free(image_buffer);
|
|
|
|
if (properties)
|
|
propDestroy(properties);
|
|
|
|
image_buffer = NULL;
|
|
image_buffer_base_width = 0;
|
|
image_buffer_current_width = 0;
|
|
image_buffer_height = 0;
|
|
}
|
|
unsigned retro_get_region(void){return RETRO_REGION_NTSC;}
|
|
void *retro_get_memory_data(unsigned id)
|
|
{
|
|
if ( id == RETRO_MEMORY_SYSTEM_RAM )
|
|
return g_mainRam;
|
|
return NULL;
|
|
}
|
|
size_t retro_get_memory_size(unsigned id)
|
|
{
|
|
if ( id == RETRO_MEMORY_SYSTEM_RAM )
|
|
return g_mainRamSize;
|
|
return 0;
|
|
}
|
|
unsigned retro_api_version(void){return RETRO_API_VERSION;}
|
|
size_t retro_serialize_size(void){return 0;}
|
|
void retro_cheat_reset(void){}
|
|
void retro_cheat_set(unsigned a, bool b, const char * c){}
|
|
bool retro_serialize(void *data, size_t size){return false;}
|
|
bool retro_unserialize(const void *data, size_t size){return false;}
|
|
|
|
/* Core stubs */
|
|
int archPollEvent(){return 0;}
|
|
void frameBufferDataDestroy(FrameBufferData* frameData){}
|
|
void frameBufferSetActive(FrameBufferData* frameData){}
|
|
void frameBufferSetMixMode(FrameBufferMixMode mode, FrameBufferMixMode mask){}
|
|
void frameBufferClearDeinterlace(){}
|
|
void frameBufferSetInterlace(FrameBuffer* frameBuffer, int val){}
|
|
void archTrap(UInt8 value){}
|
|
void videoUpdateAll(Video* video, Properties* properties){}
|