diff --git a/.gitignore b/.gitignore index 2bb067773..2e3e62783 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ build/ +artifact/ # macOS .DS_Store @@ -6,8 +7,13 @@ shell/apple/emulator-ios/OpenMP/OpenMP.xcframework # Visual Studio .vs/ +.vscode/ out/ # JetBrains IDES .idea/ cmake-build-*/ + +# Dependencies from .gitmodules +core/deps/breakpad/ +core/deps/glslang/ diff --git a/core/hw/maple/maple_cfg.cpp b/core/hw/maple/maple_cfg.cpp index 1a1b0d2e8..5b6f977aa 100644 --- a/core/hw/maple/maple_cfg.cpp +++ b/core/hw/maple/maple_cfg.cpp @@ -76,8 +76,14 @@ void MapleConfigMap::GetInput(PlainJoystickState* pjs) pjs->kcode = inputState.kcode; pjs->joy[PJAI_X1] = GetBtFromSgn(inputState.fullAxes[PJAI_X1]); pjs->joy[PJAI_Y1] = GetBtFromSgn(inputState.fullAxes[PJAI_Y1]); + pjs->joy[PJAI_X2] = GetBtFromSgn(inputState.fullAxes[PJAI_X2]); + pjs->joy[PJAI_Y2] = GetBtFromSgn(inputState.fullAxes[PJAI_Y2]); + pjs->joy[PJAI_X3] = GetBtFromSgn(inputState.fullAxes[PJAI_X3]); + pjs->joy[PJAI_Y3] = GetBtFromSgn(inputState.fullAxes[PJAI_Y3]); pjs->trigger[PJTI_R] = inputState.halfAxes[PJTI_R]; pjs->trigger[PJTI_L] = inputState.halfAxes[PJTI_L]; + pjs->trigger[PJTI_L2] = inputState.halfAxes[PJTI_L2]; + pjs->trigger[PJTI_R2] = inputState.halfAxes[PJTI_R2]; } else if (settings.platform.isAtomiswave()) { @@ -290,27 +296,20 @@ static void createDreamcastDevices() break; case MDT_Keyboard: - mcfg_Create(MDT_Keyboard, bus, 5); - break; - case MDT_Mouse: - mcfg_Create(MDT_Mouse, bus, 5); + case MDT_MaracasController: + case MDT_FishingController: + case MDT_PopnMusicController: + case MDT_RacingController: + case MDT_DenshaDeGoController: + case MDT_Dreameye: + mcfg_Create(config::MapleMainDevices[bus], bus, 5); break; case MDT_LightGun: - mcfg_Create(MDT_LightGun, bus, 5); - if (config::MapleExpansionDevices[bus][0] != MDT_None) - mcfg_Create(config::MapleExpansionDevices[bus][0], bus, 0); - break; - case MDT_TwinStick: - mcfg_Create(MDT_TwinStick, bus, 5); - if (config::MapleExpansionDevices[bus][0] != MDT_None) - mcfg_Create(config::MapleExpansionDevices[bus][0], bus, 0); - break; - case MDT_AsciiStick: - mcfg_Create(MDT_AsciiStick, bus, 5); + mcfg_Create(config::MapleMainDevices[bus], bus, 5); if (config::MapleExpansionDevices[bus][0] != MDT_None) mcfg_Create(config::MapleExpansionDevices[bus][0], bus, 0); break; diff --git a/core/hw/maple/maple_cfg.h b/core/hw/maple/maple_cfg.h index ccd8b1cdd..dc82abbbf 100644 --- a/core/hw/maple/maple_cfg.h +++ b/core/hw/maple/maple_cfg.h @@ -3,21 +3,25 @@ enum MapleDeviceType { - MDT_SegaController, - - MDT_SegaVMU, - MDT_Microphone, - MDT_PurupuruPack, - MDT_AsciiStick, - MDT_Keyboard, - MDT_Mouse, - MDT_LightGun, - MDT_TwinStick, - - MDT_NaomiJamma, - - MDT_None, - MDT_RFIDReaderWriter, + MDT_SegaController = 0, + MDT_SegaVMU = 1, + MDT_Microphone = 2, + MDT_PurupuruPack = 3, + MDT_AsciiStick = 4, + MDT_Keyboard = 5, + MDT_Mouse = 6, + MDT_LightGun = 7, + MDT_TwinStick = 8, + MDT_NaomiJamma = 9, + MDT_None = 10, + MDT_RFIDReaderWriter = 11, + MDT_MaracasController = 12, + MDT_FishingController = 13, + MDT_PopnMusicController = 14, + MDT_RacingController = 15, + MDT_DenshaDeGoController = 16, + MDT_Dreameye = 17, + MDT_Count }; enum PlainJoystickAxisId @@ -26,24 +30,29 @@ enum PlainJoystickAxisId PJAI_Y1 = 1, PJAI_X2 = 2, PJAI_Y2 = 3, - - PJAI_Count = 4 + PJAI_X3 = 4, + PJAI_Y3 = 5, + PJAI_Count = 6 }; enum PlainJoystickTriggerId { PJTI_L = 0, PJTI_R = 1, - - PJTI_Count = 2 + PJTI_L2 = 2, + PJTI_R2 = 3, + PJTI_Count = 4 }; struct PlainJoystickState { PlainJoystickState() { - joy[0]=joy[1]=joy[2]=joy[3]=0x80; - trigger[0]=trigger[1]=0; + u32 i; + for (i=0; i < PJAI_Count; i++) + joy[i] = 0x80; + for (i=0; i < PJTI_Count; i++) + trigger[i] = 0; } u32 kcode = ~0; @@ -81,8 +90,8 @@ struct MapleInputState } u32 kcode = ~0; - u8 halfAxes[PJTI_Count]; // LT, RT - int8_t fullAxes[PJAI_Count]; // Left X, Y, Right X, Y + u8 halfAxes[PJTI_Count]; // LT, RT, 2, 3 + int8_t fullAxes[PJAI_Count]; // Left X, Y, Right X, Y, Other X, Other Y u8 mouseButtons = ~0; struct { int x = -1; diff --git a/core/hw/maple/maple_devs.cpp b/core/hw/maple/maple_devs.cpp index 7b817e6c0..c911202c8 100755 --- a/core/hw/maple/maple_devs.cpp +++ b/core/hw/maple/maple_devs.cpp @@ -11,16 +11,21 @@ #include const char* maple_sega_controller_name = "Dreamcast Controller"; -const char* maple_sega_vmu_name = "Visual Memory"; -const char* maple_sega_kbd_name = "Emulated Dreamcast Keyboard"; -const char* maple_sega_mouse_name = "Emulated Dreamcast Mouse"; -const char* maple_sega_dreameye_name_1 = "Dreamcast Camera Flash Devic"; -const char* maple_sega_dreameye_name_2 = "Dreamcast Camera Flash LDevic"; -const char* maple_sega_mic_name = "MicDevice for Dreameye"; -const char* maple_sega_purupuru_name = "Puru Puru Pack"; -const char* maple_sega_lightgun_name = "Dreamcast Gun"; -const char* maple_sega_twinstick_name = "Twin Stick"; -const char* maple_ascii_stick_name = "ASCII STICK"; +const char* maple_sega_vmu_name = "Visual Memory"; +const char* maple_sega_kbd_name = "Emulated Dreamcast Keyboard"; +const char* maple_sega_mouse_name = "Emulated Dreamcast Mouse"; +const char* maple_sega_dreameye_name_1 = "Dreamcast Camera Flash Device"; +const char* maple_sega_dreameye_name_2 = "Dreamcast Camera Flash LDevice"; +const char* maple_sega_mic_name = "MicDevice for Dreameye"; +const char* maple_sega_purupuru_name = "Puru Puru Pack"; +const char* maple_sega_lightgun_name = "Dreamcast Gun"; +const char* maple_sega_twinstick_name = "Twin Stick"; +const char* maple_ascii_stick_name = "ASCII STICK"; +const char* maple_maracas_controller_name = "Maracas Controller"; +const char* maple_fishing_controller_name = "Dreamcast Fishing Controller"; +const char* maple_popnmusic_controller_name = "pop'n music controller"; +const char* maple_racing_controller_name = "Racing Controller"; +const char* maple_densha_controller_name = "TAITO 001 Controller"; const char* maple_sega_brand = "Produced By or Under License From SEGA ENTERPRISES,LTD."; @@ -104,6 +109,11 @@ struct maple_sega_controller: maple_base return maple_sega_brand; } + virtual u32 get_device_current(int get_max_current) + { + return get_max_current ? 0x01F4 : 0x01AE; // Max. 50 mA, standby: 43 mA + } + u32 dma(u32 cmd) override { //printf("maple_sega_controller::dma Called 0x%X;Command %d\n", bus_id, cmd); @@ -111,6 +121,8 @@ struct maple_sega_controller: maple_base { case MDC_DeviceRequest: case MDC_AllStatusReq: + // Fixed Device Status + // (Device ID) //caps //4 w32(MFID_0_Input); @@ -121,23 +133,23 @@ struct maple_sega_controller: maple_base w32(0); w32(0); - //1 area code + //1 area code (Country specification) w8(0xFF); - //1 direction + //1 direction (Connection method) w8(0); - //30 + //30 (Model name) wstr(get_device_name(), 30); - //60 + //60 (License) wstr(get_device_brand(), 60); - //2 - w16(0x01AE); // 43 mA + //2 (Standby current consumption) + w16(get_device_current(0)); - //2 - w16(0x01F4); // 50 mA + //2 (Maximum current consumption) + w16(get_device_current(1)); return cmd == MDC_DeviceRequest ? MDRS_DeviceStatus : MDRS_DeviceStatusAll; @@ -249,6 +261,10 @@ struct maple_sega_twinstick: maple_sega_controller const char *get_device_name() override { return maple_sega_twinstick_name; } + + u32 get_device_current(int get_max_current) override { + return get_max_current ? 0x012C : 0x00DC; // Max. 30 mA, standby: 22 mA + } }; @@ -284,14 +300,16 @@ struct maple_ascii_stick: maple_sega_controller const char *get_device_name() override { return maple_ascii_stick_name; } + + u32 get_device_current(int get_max_current) override { + return get_max_current ? 0x0172 : 0x010E; // Max. 37 mA, standby: 27 mA + } }; /* Sega Dreamcast Visual Memory Unit This is pretty much done (?) */ - - u8 vmu_default[] = { 0x78,0x9c,0xed,0xd2,0x31,0x4e,0x02,0x61,0x10,0x06,0xd0,0x8f,0x04,0x28,0x4c,0x2c, 0x28,0x2d,0x0c,0xa5,0x57,0xe0,0x16,0x56,0x16,0x76,0x14,0x1e,0xc4,0x03,0x50,0x98, @@ -718,7 +736,6 @@ struct maple_sega_vmu: maple_base } }; - struct maple_microphone: maple_base { u32 gain; @@ -896,7 +913,6 @@ struct maple_microphone: maple_base } }; - struct maple_sega_purupuru : maple_base { u16 AST = 19, AST_ms = 5000; @@ -1327,6 +1343,391 @@ struct atomiswave_lightgun : maple_lightgun } }; +struct maple_maracas_controller: maple_sega_controller +{ + u32 get_capabilities() override { + // byte 0: 0 0 0 0 0 0 0 0 + // byte 1: 0 0 a5 a4 a3 a2 a1 a0 + // byte 2: R2 L2 D2 U2 D X Y Z + // byte 3: R L D U St A B C + + return 0x0f093c00; // 4 analog axes (2-5) A B C D Z Start + } + + u32 transform_kcode(u32 kcode) override { + return kcode | 0xf6f0; // mask off DPad2, X, Y, DPad; + } + + MapleDeviceType get_device_type() override { + return MDT_MaracasController; + } + + u32 get_analog_axis(int index, const PlainJoystickState &pjs) override { + if (index < 2 || index > 5) + return 0; + return pjs.joy[index -2]; + /* // This should be tested with real maracas to see if it is worth implementing or not + u8 maracas_saturation_reduction = 2; + s32 axis_val = (pjs.joy[index -2] - 0x80) / maracas_saturation_reduction + 0x80; + if (axis_val < 0) axis_val = 0; + else if (axis_val > 0xff) axis_val = 0xFF; + return axis_val; */ + } + + const char *get_device_name() override { + return maple_maracas_controller_name; + } + + u32 get_device_current(int get_max_current) override { + return get_max_current ? 0x0546 : 0x044C; // Max. 130 mA, standby: 100 mA + } +}; + +struct maple_fishing_controller: maple_sega_controller +{ + u32 get_capabilities() override { + // byte 0: 0 0 0 0 0 0 0 0 + // byte 1: 0 0 a5 a4 a3 a2 a1 a0 + // byte 2: R2 L2 D2 U2 D X Y Z + // byte 3: R L D U St A B C + + return 0x0fe063f00; // Ra,La,Da,Ua,A,B,X,Y,Start,A1,A2,A3,A4,A5,A6 + } + + u32 transform_kcode(u32 kcode) override { + mutualExclusion(kcode, DC_DPAD_UP | DC_DPAD_DOWN); + mutualExclusion(kcode, DC_DPAD_LEFT | DC_DPAD_RIGHT); + return kcode | 0xf901; // mask off DPad2, D, Z, C; + } + + MapleDeviceType get_device_type() override { + return MDT_FishingController; + } + + u32 get_analog_axis(int index, const PlainJoystickState &pjs) override { + // In the XYZ axes, acceleration sensor outputs 80 ± 8H (home position) + // in the static state (± 0G), F0h or greater for maximum force (+10G) + // in the positive direction and 11h or less + // for the maximum force (-10G) applied in the negative direction + // From the perspective of the player operating the controller: + // X: Right is positive, left is negative + // Y: Down is positive, up is negative + // Z: Forward is positive, backward is negative + if (index == 0) + return pjs.trigger[PJTI_R]; // A1: Reel handle output + else if (index == 1) + return pjs.joy[4]; // A2: acceleration sensor Z + else if (index >= 2 || index <= 5) // A3, A4 are also output as Ra, La, Ua, Da + return pjs.joy[index -2]; // A5, A6: acceleration sensors X and Y + return 0x80; + } + + const char *get_device_name() override { + return maple_fishing_controller_name; + } + + u32 get_device_current(int get_max_current) override { + return get_max_current ? 0x0960 : 0x0258; // Max. 240 mA, standby: 60 mA + } + + u32 dma(u32 cmd) override { + //printf("maple_fishing_controller::dma Called 0x%X;Command %d\n", bus_id, cmd); + switch (cmd) + { + case MDC_DeviceRequest: + case MDC_AllStatusReq: + // Fixed Device Status + // (Device ID) + //caps + //4 + w32(MFID_0_Input); + + //struct data + //3*4 + w32(get_capabilities()); + w32(0); + w32(0); + + //1 area code (Country specification) + w8(0xFF); + + //1 direction (Connection method) + w8(0); + + //30 (Model name) + wstr(get_device_name(), 30); + + //60 (License) + wstr(get_device_brand(), 60); + + //2 (Standby current consumption) + w16(get_device_current(0)); + + //2 (Maximum current consumption) + w16(get_device_current(1)); + + return cmd == MDC_DeviceRequest ? MDRS_DeviceStatus : MDRS_DeviceStatusAll; + + //controller condition + case MDCF_GetCondition: + { + PlainJoystickState pjs; + config->GetInput(&pjs); + //INFO_LOG(MAPLE, "maple_fishing_controller: MDCF_GetCondition: r32(): %d", r32()); + //caps + //4 + w32(MFID_0_Input); + + //state data + //2 key code + w16(transform_kcode(pjs.kcode)); + + //triggers + //1 R + w8(get_analog_axis(0, pjs)); + //1 L + w8(get_analog_axis(1, pjs)); + + //joyx + //1 + w8(get_analog_axis(2, pjs)); + //joyy + //1 + w8(get_analog_axis(3, pjs)); + + //not used on dreamcast + //1 + w8(get_analog_axis(4, pjs)); + //1 + w8(get_analog_axis(5, pjs)); + } + + return MDRS_DataTransfer; + + case MDC_DeviceReset: + return MDRS_DeviceReply; + + case MDC_DeviceKill: + return MDRS_DeviceReply; + + default: + INFO_LOG(MAPLE, "maple_fishing_controller: Unknown maple command %d", cmd); + return MDRE_UnknownCmd; + } + } +}; + +struct maple_popnmusic_controller: maple_sega_controller +{ + u32 get_capabilities() override { + // byte 0: 0 0 0 0 0 0 0 0 + // byte 1: 0 0 a5 a4 a3 a2 a1 a0 + // byte 2: R2 L2 D2 U2 D X Y Z + // byte 3: R L D U St A B C + + return 0xff060000; // no analog axes, X Y A B C Start U/D/L/R + } + + u32 transform_kcode(u32 kcode) override + { + return kcode | 0xf100; // mask off DPad2 and Z + } + + MapleDeviceType get_device_type() override { + return MDT_PopnMusicController; + } + + u32 get_analog_axis(int index, const PlainJoystickState &pjs) override { + if (index == 0 || index == 1) + return 0; // Right and left triggers + return 0x80; + } + + const char *get_device_name() override { + return maple_popnmusic_controller_name; + } + + u32 get_device_current(int get_max_current) override { + return get_max_current ? 0x012C : 0x00AA; // Max. 30 mA, standby: 17 mA + } +}; + +struct maple_racing_controller: maple_sega_controller +{ + u32 get_capabilities() override { + // byte 0: 0 0 0 0 0 0 0 0 + // byte 1: 0 0 a5 a4 a3 a2 a1 a0 + // byte 2: R2 L2 D2 U2 D X Y Z + // byte 3: R L D U St A B C + + return 0xfe003700; // Steering + accelerator/brake unit: Ra,La,Da,Ua,A,B,Start,A1,A2,A3,A5,A6 + // (A5 & A6 only valid when the accelerator/brake unit is connected.) + //return 0xfe000700; // Steering only + } + + u32 transform_kcode_racing(const PlainJoystickState &pjs) { + // Ra, La are ON when A3 threshold values (La: 40h, Ra: BEh) are exceeded + u32 kcode = pjs.kcode; + if (pjs.joy[PJAI_X1] < 0x40) + kcode &= 0xffff -DC_DPAD_LEFT; + else if (pjs.joy[PJAI_X1] > 0xBE) + kcode &= 0xffff -DC_DPAD_RIGHT; + mutualExclusion(kcode, DC_DPAD_UP | DC_DPAD_DOWN); + mutualExclusion(kcode, DC_DPAD_LEFT | DC_DPAD_RIGHT); + return kcode | 0xff01; // mask off DPad2, D, X, Y, Z, C + } + + MapleDeviceType get_device_type() override { + return MDT_RacingController; + } + + u32 get_analog_axis(int index, const PlainJoystickState &pjs) override { + if (index == 0) + return pjs.trigger[PJTI_R]; // A1: lever, 0 at rest + else if (index == 1) + return pjs.trigger[PJTI_L]; // A2: lever, 0 at rest + else if (index == 2) + return pjs.joy[PJAI_X1]; // A3: 0-0xff, 0x80 at rest + else if (index == 4) // (A5 and A6 are only valid when the accelerator/brake unit is connected) + return pjs.trigger[PJTI_R2];// A5: lever, 0 at rest + else if (index == 5) + return pjs.trigger[PJTI_L2];// A6: lever, 0 at rest + return 0x80; // unused + } + + const char *get_device_name() override { + return maple_racing_controller_name; + } + + u32 get_device_current(int get_max_current) override { + return get_max_current ? 0x0226 : 0x01B8; // Max. 55 mA, standby: 44 mA + } + + u32 dma(u32 cmd) override + { + //printf("maple_sega_controller::dma Called 0x%X;Command %d\n", bus_id, cmd); + switch (cmd) + { + case MDC_DeviceRequest: + case MDC_AllStatusReq: + // Fixed Device Status + // (Device ID) + //caps + //4 + w32(MFID_0_Input); + + //struct data + //3*4 + w32(get_capabilities()); + w32(0); + w32(0); + + //1 area code (Country specification) + w8(0xFF); + + //1 direction (Connection method) + w8(0); + + //30 (Model name) + wstr(get_device_name(), 30); + + //60 (License) + wstr(get_device_brand(), 60); + + //2 (Standby current consumption) + w16(get_device_current(0)); + + //2 (Maximum current consumption) + w16(get_device_current(1)); + + return cmd == MDC_DeviceRequest ? MDRS_DeviceStatus : MDRS_DeviceStatusAll; + + //controller condition + case MDCF_GetCondition: + { + PlainJoystickState pjs; + config->GetInput(&pjs); + //caps + //4 + w32(MFID_0_Input); + + //state data + //2 key code + w16(transform_kcode_racing(pjs)); + + //triggers + //1 R + w8(get_analog_axis(0, pjs)); + //1 L + w8(get_analog_axis(1, pjs)); + + //joyx + //1 + w8(get_analog_axis(2, pjs)); + //joyy + //1 + w8(get_analog_axis(3, pjs)); + + //not used on dreamcast + //1 + w8(get_analog_axis(4, pjs)); + //1 + w8(get_analog_axis(5, pjs)); + } + + return MDRS_DataTransfer; + + case MDC_DeviceReset: + return MDRS_DeviceReply; + + case MDC_DeviceKill: + return MDRS_DeviceReply; + + default: + INFO_LOG(MAPLE, "maple_racing_controller: Unknown maple command %d", cmd); + return MDRE_UnknownCmd; + } + } +}; + +struct maple_densha_controller: maple_sega_controller +{ + u32 get_capabilities() override { + // byte 0: 0 0 0 0 0 0 0 0 + // byte 1: 0 0 a5 a4 a3 a2 a1 a0 + // byte 2: R2 L2 D2 U2 D X Y Z + // byte 3: R L D U St A B C + + return 0xff0f3f00; // Ra,La,Da,Ua A,B,C,D,X,Y,Z,Start Xa,Ya,Xb,Yb Analog levers R,L + } + + u32 transform_kcode(u32 kcode) override { + // Ra,La,Da,Ua are used together, corresponding to the brake lever. + return kcode | 0xF000; // mask off DPad2 + } + + MapleDeviceType get_device_type() override { + return MDT_DenshaDeGoController; + } + + u32 get_analog_axis(int index, const PlainJoystickState &pjs) override { + if (index == 2 || index == 3) + return 0; + if (index == 0 || index == 1 || index == 4 || index == 5) + return 0xff; + return 0xff; + } + + const char *get_device_name() override { + return maple_densha_controller_name; + } + + u32 get_device_current(int get_max_current) override { + return get_max_current ? 0x01F4 : 0x00DC; // Max. 50 mA, standby: 22 mA + } +}; + + // Emulates a 838-14245-92 maple to RS232 converter // wired to a 838-14243 RFID reader/writer (apparently Saxa HW210) struct RFIDReaderWriter : maple_base @@ -1689,6 +2090,26 @@ maple_device* maple_Create(MapleDeviceType type) rv = new maple_ascii_stick(); break; + case MDT_MaracasController: + rv = new maple_maracas_controller(); + break; + + case MDT_FishingController: + rv = new maple_fishing_controller(); + break; + + case MDT_PopnMusicController: + rv = new maple_popnmusic_controller(); + break; + + case MDT_RacingController: + rv = new maple_racing_controller(); + break; + + case MDT_DenshaDeGoController: + rv = new maple_densha_controller(); + break; + case MDT_RFIDReaderWriter: rv = new RFIDReaderWriter(); break; diff --git a/core/input/gamepad.h b/core/input/gamepad.h index e4eb0e2c7..eaf8fb0ee 100644 --- a/core/input/gamepad.h +++ b/core/input/gamepad.h @@ -55,6 +55,8 @@ enum DreamcastKey DC_AXIS_TRIGGERS = 0x1000000, DC_AXIS_LT, DC_AXIS_RT, + DC_AXIS_LT2, + DC_AXIS_RT2, DC_AXIS_STICKS = 0x2000000, DC_AXIS_LEFT, DC_AXIS_RIGHT, @@ -64,6 +66,10 @@ enum DreamcastKey DC_AXIS2_RIGHT, DC_AXIS2_UP, DC_AXIS2_DOWN, + DC_AXIS3_LEFT, + DC_AXIS3_RIGHT, + DC_AXIS3_UP, + DC_AXIS3_DOWN, // System axes EMU_AXIS_NONE = 0, diff --git a/core/input/gamepad_device.cpp b/core/input/gamepad_device.cpp index ebc7255d4..23545a0b0 100644 --- a/core/input/gamepad_device.cpp +++ b/core/input/gamepad_device.cpp @@ -39,7 +39,11 @@ s8 joyrx[4]; s8 joyry[4]; u8 rt[4]; u8 lt[4]; +s8 joy3x[4]; +s8 joy3y[4]; // Keyboards +u8 lt2[4]; +u8 rt2[4]; u8 kb_shift[MAPLE_PORTS]; // shift keys pressed (bitmask) u8 kb_key[MAPLE_PORTS][6]; // normal keys pressed @@ -103,7 +107,14 @@ bool GamepadDevice::handleButtonInput(int port, DreamcastKey key, bool pressed) if (port >= 0) rt[port] = pressed ? 255 : 0; break; - + case DC_AXIS_LT2: + if (port >= 0) + lt2[port] = pressed ? 255 : 0; + break; + case DC_AXIS_RT2: + if (port >= 0) + rt2[port] = pressed ? 255 : 0; + break; case DC_AXIS_UP: case DC_AXIS_DOWN: buttonToAnalogInput(port, key, pressed, joyy[port]); @@ -120,6 +131,14 @@ bool GamepadDevice::handleButtonInput(int port, DreamcastKey key, bool pressed) case DC_AXIS2_RIGHT: buttonToAnalogInput(port, key, pressed, joyrx[port]); break; + case DC_AXIS3_UP: + case DC_AXIS3_DOWN: + buttonToAnalogInput(port, key, pressed, joy3y[port]); + break; + case DC_AXIS3_LEFT: + case DC_AXIS3_RIGHT: + buttonToAnalogInput(port, key, pressed, joy3x[port]); + break; default: return false; @@ -186,6 +205,10 @@ bool GamepadDevice::gamepad_axis_input(u32 code, int value) lt[port] = std::min(std::abs(v) >> 7, 255); else if (key == DC_AXIS_RT) rt[port] = std::min(std::abs(v) >> 7, 255); + else if (key == DC_AXIS_LT2) + lt2[port] = std::min(std::abs(v) >> 7, 255); + else if (key == DC_AXIS_RT2) + rt2[port] = std::min(std::abs(v) >> 7, 255); else return false; } @@ -229,6 +252,22 @@ bool GamepadDevice::gamepad_axis_input(u32 code, int value) other_axis = &joyrx[port]; break; + case DC_AXIS3_RIGHT: + axisDirection = 1; + //no break + case DC_AXIS3_LEFT: + this_axis = &joy3x[port]; + other_axis = &joy3y[port]; + break; + + case DC_AXIS3_DOWN: + axisDirection = 1; + //no break + case DC_AXIS3_UP: + this_axis = &joy3y[port]; + other_axis = &joy3x[port]; + break; + default: return false; } diff --git a/core/input/gamepad_device.h b/core/input/gamepad_device.h index 058396124..68160a339 100644 --- a/core/input/gamepad_device.h +++ b/core/input/gamepad_device.h @@ -124,6 +124,10 @@ private: DIGANA2_RIGHT = 1 << 5, DIGANA2_UP = 1 << 6, DIGANA2_DOWN = 1 << 7, + DIGANA3_LEFT = 1 << 8, + DIGANA3_RIGHT = 1 << 9, + DIGANA3_UP = 1 << 10, + DIGANA3_DOWN = 1 << 11, }; template @@ -167,6 +171,7 @@ void replay_input(); #endif extern u32 kcode[4]; -extern u8 rt[4], lt[4]; +extern u8 rt[4], lt[4], rt2[4], lt2[4]; extern s8 joyx[4], joyy[4]; extern s8 joyrx[4], joyry[4]; +extern s8 joy3x[4], joy3y[4]; diff --git a/core/input/mapping.cpp b/core/input/mapping.cpp index ea2f77473..270579907 100644 --- a/core/input/mapping.cpp +++ b/core/input/mapping.cpp @@ -50,6 +50,8 @@ button_list[] = { EMU_BTN_FFORWARD, "emulator", "btn_fforward" }, { DC_AXIS_LT, "compat", "btn_trigger_left" }, { DC_AXIS_RT, "compat", "btn_trigger_right" }, + { DC_AXIS_LT2, "compat", "btn_trigger_left2" }, + { DC_AXIS_RT2, "compat", "btn_trigger_right2" }, { DC_AXIS_UP, "compat", "btn_analog_up" }, { DC_AXIS_DOWN, "compat", "btn_analog_down" }, { DC_AXIS_LEFT, "compat", "btn_analog_left" }, @@ -79,8 +81,14 @@ axis_list[] = { DC_AXIS2_RIGHT, "", "axis2_right", "", "" }, { DC_AXIS2_UP, "", "axis2_up", "", "" }, { DC_AXIS2_DOWN, "", "axis2_down", "", "" }, + { DC_AXIS3_LEFT, "", "axis3_left", "", "" }, + { DC_AXIS3_RIGHT, "", "axis3_right", "", "" }, + { DC_AXIS3_UP, "", "axis3_up", "", "" }, + { DC_AXIS3_DOWN, "", "axis3_down", "", "" }, { DC_AXIS_LT, "dreamcast", "axis_trigger_left", "compat", "axis_trigger_left_inverted" }, { DC_AXIS_RT, "dreamcast", "axis_trigger_right", "compat", "axis_trigger_right_inverted" }, + { DC_AXIS_LT2, "dreamcast", "axis_trigger_left2", "compat", "axis_trigger_left2_inverted" }, + { DC_AXIS_RT2, "dreamcast", "axis_trigger_right2", "compat", "axis_trigger_right2_inverted" }, // legacy (v2) { DC_AXIS_RIGHT, "dreamcast", "axis_x", "compat", "axis_x_inverted" }, @@ -306,6 +314,10 @@ void InputMapping::loadv1(ConfigFile& mf) this->set_axis(port, DC_AXIS2_LEFT, axis_code, inverted); else if (axis_list[i].id == DC_AXIS2_DOWN) this->set_axis(port, DC_AXIS2_UP, axis_code, inverted); + else if (axis_list[i].id == DC_AXIS3_RIGHT) + this->set_axis(port, DC_AXIS3_LEFT, axis_code, inverted); + else if (axis_list[i].id == DC_AXIS3_DOWN) + this->set_axis(port, DC_AXIS3_UP, axis_code, inverted); } } } diff --git a/core/input/mapping.h b/core/input/mapping.h index c7a6a8e27..9e3d2530e 100644 --- a/core/input/mapping.h +++ b/core/input/mapping.h @@ -116,9 +116,15 @@ public: set_axis(0, DC_AXIS_DOWN, DC_AXIS_DOWN, true); set_axis(0, DC_AXIS_LT, DC_AXIS_LT, true); set_axis(0, DC_AXIS_RT, DC_AXIS_RT, true); + set_axis(0, DC_AXIS_LT2, DC_AXIS_LT2, true); + set_axis(0, DC_AXIS_RT2, DC_AXIS_RT2, true); set_axis(0, DC_AXIS2_LEFT, DC_AXIS2_LEFT, true); set_axis(0, DC_AXIS2_RIGHT, DC_AXIS2_RIGHT, true); set_axis(0, DC_AXIS2_UP, DC_AXIS2_UP, true); set_axis(0, DC_AXIS2_DOWN, DC_AXIS2_DOWN, true); + set_axis(0, DC_AXIS3_LEFT, DC_AXIS3_LEFT, true); + set_axis(0, DC_AXIS3_RIGHT, DC_AXIS3_RIGHT, true); + set_axis(0, DC_AXIS3_UP, DC_AXIS3_UP, true); + set_axis(0, DC_AXIS3_DOWN, DC_AXIS3_DOWN, true); } }; diff --git a/core/network/ggpo.cpp b/core/network/ggpo.cpp index 344ae1dc7..18f5134c3 100644 --- a/core/network/ggpo.cpp +++ b/core/network/ggpo.cpp @@ -43,10 +43,14 @@ static void getLocalInput(MapleInputState inputState[4]) state.kcode = kcode[player]; state.halfAxes[PJTI_L] = lt[player]; state.halfAxes[PJTI_R] = rt[player]; + state.halfAxes[PJTI_L2] = lt2[player]; + state.halfAxes[PJTI_R2] = rt2[player]; state.fullAxes[PJAI_X1] = joyx[player]; state.fullAxes[PJAI_Y1] = joyy[player]; state.fullAxes[PJAI_X2] = joyrx[player]; state.fullAxes[PJAI_Y2] = joyry[player]; + state.fullAxes[PJAI_X3] = joy3x[player]; + state.fullAxes[PJAI_Y3] = joy3y[player]; state.mouseButtons = mo_buttons[player]; state.absPos.x = mo_x_abs[player]; state.absPos.y = mo_y_abs[player]; diff --git a/core/rend/gui.cpp b/core/rend/gui.cpp index 60915d578..0b354d8d8 100644 --- a/core/rend/gui.cpp +++ b/core/rend/gui.cpp @@ -656,8 +656,30 @@ inline static void header(const char *title) ImGui::PopStyleVar(); } -const char *maple_device_types[] = { "None", "Sega Controller", "Light Gun", "Keyboard", "Mouse", "Twin Stick", "Ascii Stick" }; -const char *maple_expansion_device_types[] = { "None", "Sega VMU", "Purupuru", "Microphone" }; +const char *maple_device_types[] = +{ + "None", + "Sega Controller", + "Light Gun", + "Keyboard", + "Mouse", + "Twin Stick", + "Ascii Stick", + "Maracas Controller", + "Fishing Controller", + "Pop'n Music controller", + "Racing Controller", + "Densha de Go! Controller", + "Dreameye", +}; + +const char *maple_expansion_device_types[] = +{ + "None", + "Sega VMU", + "Purupuru", + "Microphone" +}; static const char *maple_device_name(MapleDeviceType type) { @@ -675,6 +697,18 @@ static const char *maple_device_name(MapleDeviceType type) return maple_device_types[5]; case MDT_AsciiStick: return maple_device_types[6]; + case MDT_MaracasController: + return maple_device_types[7]; + case MDT_FishingController: + return maple_device_types[8]; + case MDT_PopnMusicController: + return maple_device_types[9]; + case MDT_RacingController: + return maple_device_types[10]; + case MDT_DenshaDeGoController: + return maple_device_types[11]; + case MDT_Dreameye: + return maple_device_types[12]; case MDT_None: default: return maple_device_types[0]; @@ -697,6 +731,18 @@ static MapleDeviceType maple_device_type_from_index(int idx) return MDT_TwinStick; case 6: return MDT_AsciiStick; + case 7: + return MDT_MaracasController; + case 8: + return MDT_FishingController; + case 9: + return MDT_PopnMusicController; + case 10: + return MDT_RacingController; + case 11: + return MDT_DenshaDeGoController; + case 12: + return MDT_Dreameye; case 0: default: return MDT_None; @@ -738,9 +784,19 @@ const Mapping dcButtons[] = { { DC_AXIS_LEFT, "Thumbstick Left" }, { DC_AXIS_RIGHT, "Thumbstick Right" }, - { DC_DPAD2_UP, "DPad2 Up" }, - { DC_DPAD2_DOWN, "DPad2 Down" }, - { DC_DPAD2_LEFT, "DPad2 Left" }, + { DC_AXIS2_UP, "R.Thumbstick Up" }, + { DC_AXIS2_DOWN, "R.Thumbstick Down" }, + { DC_AXIS2_LEFT, "R.Thumbstick Left" }, + { DC_AXIS2_RIGHT, "R.Thumbstick Right" }, + + { DC_AXIS3_UP, "Axis 3 Up" }, + { DC_AXIS3_DOWN, "Axis 3 Down" }, + { DC_AXIS3_LEFT, "Axis 3 Left" }, + { DC_AXIS3_RIGHT, "Axis 3 Right" }, + + { DC_DPAD2_UP, "DPad2 Up" }, + { DC_DPAD2_DOWN, "DPad2 Down" }, + { DC_DPAD2_LEFT, "DPad2 Left" }, { DC_DPAD2_RIGHT, "DPad2 Right" }, { EMU_BTN_NONE, "Buttons" }, @@ -752,9 +808,11 @@ const Mapping dcButtons[] = { { DC_BTN_D, "D" }, { DC_BTN_Z, "Z" }, - { EMU_BTN_NONE, "Triggers" }, - { DC_AXIS_LT, "Left Trigger" }, - { DC_AXIS_RT, "Right Trigger" }, + { EMU_BTN_NONE, "Triggers" }, + { DC_AXIS_LT, "Left Trigger" }, + { DC_AXIS_RT, "Right Trigger" }, + { DC_AXIS_LT2, "Left Trigger 2" }, + { DC_AXIS_RT2, "Right Trigger 2" }, { EMU_BTN_NONE, "System Buttons" }, { DC_BTN_START, "Start" }, @@ -886,6 +944,14 @@ static DreamcastKey getOppositeDirectionKey(DreamcastKey key) return DC_AXIS2_RIGHT; case DC_AXIS2_RIGHT: return DC_AXIS2_LEFT; + case DC_AXIS3_UP: + return DC_AXIS3_DOWN; + case DC_AXIS3_DOWN: + return DC_AXIS3_UP; + case DC_AXIS3_LEFT: + return DC_AXIS3_RIGHT; + case DC_AXIS3_RIGHT: + return DC_AXIS3_LEFT; default: return EMU_BTN_NONE; } @@ -1646,9 +1712,19 @@ static void gui_display_settings() } ImGui::EndCombo(); } - int port_count = config::MapleMainDevices[bus] == MDT_SegaController ? 2 - : config::MapleMainDevices[bus] == MDT_LightGun || config::MapleMainDevices[bus] == MDT_TwinStick || config::MapleMainDevices[bus] == MDT_AsciiStick ? 1 - : 0; + int port_count = 0; + switch (config::MapleMainDevices[bus]) { + case MDT_SegaController: + port_count = 2; + break; + case MDT_LightGun: + case MDT_TwinStick: + case MDT_AsciiStick: + case MDT_RacingController: + port_count = 1; + break; + default: break; + } for (int port = 0; port < port_count; port++) { ImGui::SameLine(); diff --git a/core/serialize.h b/core/serialize.h index 44ea41316..07392d59b 100644 --- a/core/serialize.h +++ b/core/serialize.h @@ -61,7 +61,8 @@ public: V34, V35, V36, - Current = V36, + V37, + Current = V37, Next = Current + 1, }; diff --git a/shell/libretro/libretro.cpp b/shell/libretro/libretro.cpp index 7701c21e5..7e15ee7c0 100644 --- a/shell/libretro/libretro.cpp +++ b/shell/libretro/libretro.cpp @@ -130,9 +130,12 @@ static bool lightgunSettingsShown = true; u32 kcode[4] = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}; u8 rt[4]; u8 lt[4]; +u8 lt2[4]; +u8 rt2[4]; u32 vks[4]; s8 joyx[4], joyy[4]; s8 joyrx[4], joyry[4]; +s8 joy3x[4], joy3y[4]; // Mouse buttons // bit 0: Button C // bit 1: Right button (B)