From 7b9920c89f069cda4e6ef47f275458ea9051e2b2 Mon Sep 17 00:00:00 2001 From: Adrien Beudin Date: Thu, 24 Oct 2024 17:58:37 +0200 Subject: [PATCH] feat: add supermodel-next --- configs/recalbox-rpi5_64_defconfig | 1 + configs/recalbox-x86_64_defconfig | 2 + .../recalbox-romfs2/systems/model3/system.ini | 16 +- .../supermodel-next/003-cross-compile.patch | 16 + package/supermodel-next/Config.in | 20 + package/supermodel-next/supermodel-next.mk | 37 ++ .../configgen/configgen/emulatorlauncher.py | 4 + .../generators/supermodelnext/__init__.py | 0 .../supermodelnextControllers.py | 424 ++++++++++++++++++ .../supermodelnext/supermodelnextGenerator.py | 283 ++++++++++++ projects/configgen/configgen/recalboxFiles.py | 4 + projects/configgen/setup.py | 1 + 12 files changed, 807 insertions(+), 1 deletion(-) create mode 100644 package/supermodel-next/003-cross-compile.patch create mode 100644 package/supermodel-next/Config.in create mode 100644 package/supermodel-next/supermodel-next.mk create mode 100644 projects/configgen/configgen/generators/supermodelnext/__init__.py create mode 100644 projects/configgen/configgen/generators/supermodelnext/supermodelnextControllers.py create mode 100644 projects/configgen/configgen/generators/supermodelnext/supermodelnextGenerator.py diff --git a/configs/recalbox-rpi5_64_defconfig b/configs/recalbox-rpi5_64_defconfig index 917d2ca9b6..9fc4497e31 100644 --- a/configs/recalbox-rpi5_64_defconfig +++ b/configs/recalbox-rpi5_64_defconfig @@ -364,3 +364,4 @@ BR2_PACKAGE_RTW89=y BR2_PACKAGE_RPI_FIRMWARE_CMDLINE_FILE="$(BR2_EXTERNAL_RECALBOX_PATH)/board/recalbox/rpi/cmdline.txt" BR2_PACKAGE_XPADNEO=y BR2_PACKAGE_VVVVVV=y +BR2_PACKAGE_SUPERMODEL_NEXT=y diff --git a/configs/recalbox-x86_64_defconfig b/configs/recalbox-x86_64_defconfig index 66c80f9963..af80d7f67e 100644 --- a/configs/recalbox-x86_64_defconfig +++ b/configs/recalbox-x86_64_defconfig @@ -401,4 +401,6 @@ BR2_PACKAGE_XPADNEO=y BR2_PACKAGE_XONE=y BR2_PACKAGE_XPAD_NOONE=y BR2_PACKAGE_WII_U_GC_ADAPTER=y +<<<<<<< HEAD BR2_PACKAGE_VVVVVV=y +BR2_PACKAGE_SUPERMODEL_NEXT=y diff --git a/package/recalbox-romfs2/systems/model3/system.ini b/package/recalbox-romfs2/systems/model3/system.ini index 86f506a5ac..e7936e45dc 100644 --- a/package/recalbox-romfs2/systems/model3/system.ini +++ b/package/recalbox-romfs2/systems/model3/system.ini @@ -42,7 +42,7 @@ crt.multiregion = 0 [core.0] package = BR2_PACKAGE_SUPERMODEL -priority = 1 +priority = 0 emulator = "supermodel" core = "supermodel" extensions = ".zip" @@ -52,3 +52,17 @@ compatibility = high speed = high arcade.file = supermodel.lst arcade.ignore = misc,pacman,galaxian + +[core.1] +package = BR2_PACKAGE_SUPERMODEL_NEXT +priority = 1 +emulator = "supermodel-next" +core = "supermodel-next" +extensions = ".zip" +netplay = 0 +softpatching = 0 +compatibility = high +speed = high +arcade.file = supermodel.lst +arcade.ignore = misc,pacman,galaxian +video.backend.rpi5_64 = wayland diff --git a/package/supermodel-next/003-cross-compile.patch b/package/supermodel-next/003-cross-compile.patch new file mode 100644 index 0000000000..4e0d18111f --- /dev/null +++ b/package/supermodel-next/003-cross-compile.patch @@ -0,0 +1,16 @@ +diff --git a/Makefiles/Rules.inc b/Makefiles/Rules.inc +index 3aefc48..64f0508 100644 +--- a/Makefiles/Rules.inc ++++ b/Makefiles/Rules.inc +@@ -302,9 +302,9 @@ MUSASHI_LDFLAGS = -o $(MUSASHI_OUTFILE) $(OBJ_DIR)/m68kmake.o -s + $(MUSASHI_OUTFILE): Src/CPU/68K/Musashi/m68kmake.c Src/CPU/68K/Musashi/m68k_in.c + $(info --------------------------------------------------------------------------------) + $(info Compiling : $< -> $(OBJ_DIR)/m68kmake.o) +- $(SILENT)$(CC) $< $(CFLAGS) -o $(OBJ_DIR)/m68kmake.o ++ $(CC_FOR_BUILD) -o $@ $< + $(info Linking : $(MUSASHI_OUTFILE)) +- $(SILENT)$(LD) $(MUSASHI_LDFLAGS) ++ $(CC_FOR_BUILD) -o $@ $< + + $(OBJ_DIR)/m68kops.h $(OBJ_DIR)/m68kops.c $(OBJ_DIR)/m68kopac.c $(OBJ_DIR)/m68kopdm.c $(OBJ_DIR)/m68kopnz.c: $(MUSASHI_OUTFILE) Src/CPU/68K/Musashi/m68k_in.c Src/CPU/68K/Musashi/m68k.h Src/CPU/68K/Musashi/m68kconf.h + $(info Generating 68K emulator: $@) diff --git a/package/supermodel-next/Config.in b/package/supermodel-next/Config.in new file mode 100644 index 0000000000..f387852844 --- /dev/null +++ b/package/supermodel-next/Config.in @@ -0,0 +1,20 @@ +config BR2_PACKAGE_SUPERMODEL_NEXXT + bool "supermodel-next" + depends on BR2_INSTALL_LIBSTDCPP + depends on BR2_PACKAGE_HAS_LIBGL # libglew + select BR2_PACKAGE_SDL2 + select BR2_PACKAGE_SDL2_NET + select BR2_PACKAGE_ZLIB + select BR2_PACKAGE_LIBGLEW + select BR2_PACKAGE_LIBZIP + select BR2_PACKAGE_LIBGLU + select BR2_PACKAGE_XORG7 if (BR2_PACKAGE_RECALBOX_VIDEO_XORG_SERVER || BR2_PACKAGE_RECALBOX_VIDEO_XWAYLAND) + help + Supermodel is a SEGA Model 3 emulator that uses the SDL-Library. + + http://www.supermodel3.com + source: https://github.com/trzy/Supermodel + +comment "SUPERMODEL needs a toolchain w/ C++" + depends on BR2_PACKAGE_XORG7 + depends on !BR2_INSTALL_LIBSTDCPP || !BR2_PACKAGE_HAS_LIBGL diff --git a/package/supermodel-next/supermodel-next.mk b/package/supermodel-next/supermodel-next.mk new file mode 100644 index 0000000000..616fac744f --- /dev/null +++ b/package/supermodel-next/supermodel-next.mk @@ -0,0 +1,37 @@ +################################################################################ +# +# supermodel-next +# +################################################################################ + +# Commits of 2024/10/20 +SUPERMODEL_NEXT_VERSION = f9cb795d6abd7a18ba3f3d44b62018f0be15b1a6 +SUPERMODEL_NEXT_SITE = $(call github,trzy,Supermodel,$(SUPERMODEL_NEXT_VERSION)) +SUPERMODEL_NEXT_DEPENDENCIES = sdl2 zlib libzip sdl2_net libglew libglu +SUPERMODEL_NEXT_LICENSE = GPLv3 + +define SUPERMODEL_NEXT_BUILD_CMDS + cp $(@D)/Makefiles/Makefile.UNIX $(@D)/Makefile + $(SED) "s|CC = gcc|CC = $(TARGET_CC)|g" $(@D)/Makefile + $(SED) "s|CXX = g++|CXX = $(TARGET_CXX)|g" $(@D)/Makefile + $(SED) "s|LD = gcc|LD = $(TARGET_CC)|g" $(@D)/Makefile + $(SED) "s|sdl2-config|$(STAGING_DIR)/usr/bin/sdl2-config|g" $(@D)/Makefile + $(TARGET_CONFIGURE_OPTS) $(MAKE) -C $(@D) -f Makefile NET_BOARD=1 \ + VERBOSE=1 ARCH=$(BR2_TARGET_OPTIMIZATION) +endef + +define SUPERMODEL_NEXT_INSTALL_TARGET_CMDS + mkdir -p $(TARGET_DIR)/usr/share/supermodel-next + $(INSTALL) -D -m 0755 $(@D)/bin/supermodel \ + $(TARGET_DIR)/usr/bin/supermodel-next + $(INSTALL) -D -m 0644 $(@D)/Config/Games.xml \ + $(TARGET_DIR)/usr/share/supermodel-next/Games.xml + $(INSTALL) -D -m 0644 $(@D)/Config/Supermodel.ini \ + $(TARGET_DIR)/usr/share/supermodel-next/Supermodel.ini.template + $(INSTALL) -D -m 0644 $(@D)/Config/Supermodel.ini \ + $(TARGET_DIR)/usr/share/supermodel-next/Supermodel-Driving.ini.template + mkdir -p $(TARGET_DIR)/usr/share/supermodel-next/Assets + $(INSTALL) -D -m 0644 $(@D)/Assets/* $(TARGET_DIR)/usr/share/supermodel-next/Assets/ +endef + +$(eval $(generic-package)) diff --git a/projects/configgen/configgen/emulatorlauncher.py b/projects/configgen/configgen/emulatorlauncher.py index da08fe5742..2b1cf55242 100644 --- a/projects/configgen/configgen/emulatorlauncher.py +++ b/projects/configgen/configgen/emulatorlauncher.py @@ -109,6 +109,10 @@ def getGenerator(emulator): module = __import__("configgen.generators.supermodel.supermodelGenerator", fromlist=["SupermodelGenerator"]) generatorClass = getattr(module, "SupermodelGenerator") return generatorClass() + elif emulator == "supermodel-next": + module = __import__("configgen.generators.supermodelnext.supermodelnextGenerator", fromlist=["SupermodelnextGenerator"]) + generatorClass = getattr(module, "SupermodelnextGenerator") + return generatorClass() elif emulator == "xroar": module = __import__("configgen.generators.xroar.xroarGenerator", fromlist=["XroarGenerator"]) generatorClass = getattr(module, "XroarGenerator") diff --git a/projects/configgen/configgen/generators/supermodelnext/__init__.py b/projects/configgen/configgen/generators/supermodelnext/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/projects/configgen/configgen/generators/supermodelnext/supermodelnextControllers.py b/projects/configgen/configgen/generators/supermodelnext/supermodelnextControllers.py new file mode 100644 index 0000000000..f8f7090b87 --- /dev/null +++ b/projects/configgen/configgen/generators/supermodelnext/supermodelnextControllers.py @@ -0,0 +1,424 @@ +#!/usr/bin/env python +from typing import Dict + +from configgen.controllers.controller import Controller, InputItem +from configgen.controllers.controller import ControllerPerPlayer +import configgen.recalboxFiles as recalboxFiles + + +def generateControllerConfig(self, playersControllers: ControllerPerPlayer): + + ################ Mapping Conversion Supermodel to Recalbox ################ + + # set recalbox Hotkey + HOTKEY_BUTTONS: Dict[str, int] = \ + { + "InputUIExit": InputItem.ItemStart, + "InputUISaveState": InputItem.ItemY, + "InputUIChangeSlot": InputItem.ItemUp, + "InputUILoadState": InputItem.ItemX, + "InputUIScreenShot": InputItem.ItemL1, + "InputUIReset": InputItem.ItemA, + "InputUIPause": InputItem.ItemB, + } + + SERVICE_TEST_BUTTON: Dict[str, int] = \ + { + "InputServiceA": InputItem.ItemR3, + "InputTestA": InputItem.ItemL3, + } + +##################### Player 1 controllers ############################### + + BUTTONS_P1: Dict[str, int] = \ + { + "InputCoin1": InputItem.ItemSelect, + "InputStart1": InputItem.ItemStart, + # Fighting game buttons + "InputEscape": InputItem.ItemY, + "InputGuard": InputItem.ItemX, + "InputKick": InputItem.ItemB, + "InputPunch": InputItem.ItemA, + # Spikeout buttons + "InputBeat": InputItem.ItemB, + "InputCharge": InputItem.ItemX, + "InputJump": InputItem.ItemA, + "InputShift": InputItem.ItemY, + # Virtua Striker buttons + "InputLongPass": InputItem.ItemB, + "InputShoot": InputItem.ItemY, + "InputShortPass": InputItem.ItemA, + # Ski Champ controls + "InputSkiPollLeft": InputItem.ItemL1, + "InputSkiPollRight": InputItem.ItemR1, + "InputSkiSelect1": InputItem.ItemY, + "InputSkiSelect2": InputItem.ItemB, + "InputSkiSelect3": InputItem.ItemA, + # Magical Truck Adventure controls + "InputMagicalPedal1": InputItem.ItemB, + # Handbrake (Dirt Devils, Sega Rally 2) + "InputHandBrake": InputItem.ItemY, + # Harley-Davidson controls + "InputMusicSelect": InputItem.ItemB, + "InputRearBrake": InputItem.ItemA, + # Virtual On buttons + "InputTwinJoyShot1": InputItem.ItemX, + "InputTwinJoyShot2": InputItem.ItemY, + "InputTwinJoyTurbo1": InputItem.ItemL1, + "InputTwinJoyTurbo2": InputItem.ItemR1, + # Virtual On macros + "InputTwinJoyCrouch": InputItem.ItemA, + "InputTwinJoyJump": InputItem.ItemB, + # Up/down shifter manual transmission (all racers) + "InputGearShiftDown": InputItem.ItemL1, + "InputGearShiftUp": InputItem.ItemR1, + # 4-Speed manual transmission (Daytona 2, Sega Rally 2, Scud Race) + # unsettings N + "InputGearShiftN": -1, + # VR4 view change buttons (Daytona 2, Le Mans 24, Scud Race) + "InputVR1": InputItem.ItemY, + "InputVR2": InputItem.ItemX, + "InputVR3": InputItem.ItemA, + "InputVR4": InputItem.ItemB, + # Single view change button (Dirt Devils, ECA, Harley-Davidson, Sega Rally 2) + "InputViewChange": InputItem.ItemX, + # Sega Bass Fishing / Get Bass controls + "InputFishingCast": InputItem.ItemY, + "InputFishingSelect": InputItem.ItemA, + } + + DIGITAL_JOYSTICK_P1: Dict[str, int] = \ + { + "InputJoyUp": InputItem.ItemUp, + "InputJoyDown": InputItem.ItemDown, + "InputJoyLeft": InputItem.ItemLeft, + "InputJoyRight": InputItem.ItemRight, + # Ski Champ controls + "InputSkiLeft": InputItem.ItemLeft, + "InputSkiRight": InputItem.ItemRight, + "InputSkiUp": InputItem.ItemUp, + "InputSkiDown": InputItem.ItemDown, + # Steering wheel + # Set digital, turn wheel + "InputSteeringLeft": InputItem.ItemLeft, + "InputSteeringRight": InputItem.ItemRight, + # Magical Truck Adventure controls + "InputMagicalLeverUp1": InputItem.ItemUp, + "InputMagicalLeverDown1": InputItem.ItemDown, + # Sega Bass Fishing / Get Bass controls + "InputFishingRodLeft": InputItem.ItemLeft, + "InputFishingRodRight": InputItem.ItemRight, + "InputFishingRodUp": InputItem.ItemUp, + "InputFishingRodDown": InputItem.ItemDown, + # need setting only AXIS don't need a position (POS/NEG) + # Magical Truck Adventure controls + "InputMagicalLever1": InputItem.ItemJoy1Up, + # Steering wheel + "InputSteering": InputItem.ItemJoy1Left, + # Ski Champ controls + "InputSkiX": InputItem.ItemJoy1Left, + "InputSkiY": InputItem.ItemJoy1Up, + # Sega Bass Fishing / Get Bass controls + "InputFishingRodX": InputItem.ItemJoy2Left, + "InputFishingRodY": InputItem.ItemJoy2Up, + "InputFishingStickX": InputItem.ItemJoy1Left, + "InputFishingStickY": InputItem.ItemJoy1Up, + } + + BUTTONS_AXIS: Dict[str, int] = \ + { + #### NEED A BYPASS BUTTON OR AXIS #### + # Pedals + "InputAccelerator": InputItem.ItemR2, + "InputBrake": InputItem.ItemL2, + #### NEED A BYPASS BUTTON OR AXIS #### + "InputFishingReel": InputItem.ItemL2, + "InputFishingTension": InputItem.ItemR2, + } + + ANALOG_JOYSTICK_P1: Dict[str, int] = \ + { + # Need setting all axis position (POS/NEG) + # Virtual On individual joystick mapping + "InputTwinJoyDown1": InputItem.ItemJoy1Down, + "InputTwinJoyDown2": InputItem.ItemJoy2Down, + "InputTwinJoyLeft1": InputItem.ItemJoy1Left, + "InputTwinJoyLeft2": InputItem.ItemJoy2Left, + "InputTwinJoyRight1": InputItem.ItemJoy1Right, + "InputTwinJoyRight2": InputItem.ItemJoy2Right, + "InputTwinJoyUp1": InputItem.ItemJoy1Up, + "InputTwinJoyUp2": InputItem.ItemJoy2Up, + # 4-Speed manual transmission (Daytona 2, Sega Rally 2, Scud Race) + # Setting on joystick2 + "InputGearShift1": InputItem.ItemJoy2Up, + "InputGearShift2": InputItem.ItemJoy2Down, + "InputGearShift3": InputItem.ItemJoy2Left, + "InputGearShift4": InputItem.ItemJoy2Right, + } + + MOUSE_GAME: Dict[str, int] = \ + { + # Light guns (Lost World) + "InputGunX": InputItem.ItemJoy1Left, + "InputGunY": InputItem.ItemJoy1Up, + # Analog guns (Ocean Hunter, LA Machineguns) + "InputAnalogGunX": InputItem.ItemJoy1Left, + "InputAnalogGunY": InputItem.ItemJoy1Up, + # Analog joystick (Star Wars Trilogy) + "InputAnalogJoyX": InputItem.ItemJoy1Left, + "InputAnalogJoyY": InputItem.ItemJoy1Up, + } + + ####################### Players 2 controllers ############################ + + BUTTONS_P2: Dict[str, int] = \ + { + # Commons buttons + "InputCoin2": InputItem.ItemSelect, + "InputStart2": InputItem.ItemStart, + # Fighting game buttons + "InputEscape2": InputItem.ItemY, + "InputGuard2": InputItem.ItemX, + "InputKick2": InputItem.ItemB, + "InputPunch2": InputItem.ItemA, + # Virtua Striker buttons + "InputLongPass2": InputItem.ItemA, + "InputShoot2": InputItem.ItemX, + "InputShortPass2": InputItem.ItemB, + # Magical Truck Adventure controls + "InputMagicalPedal2": InputItem.ItemB, + } + + DIGITAL_JOYSTICK_P2: Dict[str, int] = \ + { + "InputJoyDown2": InputItem.ItemDown, + "InputJoyLeft2": InputItem.ItemLeft, + "InputJoyRight2": InputItem.ItemRight, + "InputJoyUp2": InputItem.ItemUp, + "InputMagicalLeverDown2": InputItem.ItemDown, + "InputMagicalLeverUp2": InputItem.ItemUp, + # Magical Truck Adventure controls + "InputMagicalLever2": InputItem.ItemJoy1Left, #change to joyleft + } + + ###### Map an Recalbox direction to the corresponding Supermodel ###### + + TYPE_TO_NAME: Dict[int, str] = \ + { + InputItem.TypeAxis: 'AXIS', + InputItem.TypeButton: 'BUTTON', + InputItem.TypeHat: 'POV', + } + + HATS_TO_NAME: Dict[int, str] = \ + { + 1: 'UP', + 2: 'RIGHT', + 4: 'DOWN', + 8: 'LEFT', + } + + """SUPERMODEL_DIR = \ + { + 'down': 'DOWN', + 'left': 'LEFT', + 'right': 'RIGHT', + 'up': 'UP', + }""" + + SUPERMODEL_JOY: Dict[int, str] = \ + { + # lEFT JOYSTICK + InputItem.ItemJoy1Down: 'YAXIS', + InputItem.ItemJoy1Left: 'XAXIS', + InputItem.ItemJoy1Right: 'XAXIS', + InputItem.ItemJoy1Up: 'YAXIS', + # RIGHT JOYSTICK + InputItem.ItemJoy2Down: 'RYAXIS', + InputItem.ItemJoy2Left: 'RXAXIS', + InputItem.ItemJoy2Right: 'RXAXIS', + InputItem.ItemJoy2Up: 'RYAXIS', + # AXIS ON L2/R2 BUTTONS + InputItem.ItemL2: 'ZAXIS', + InputItem.ItemR2: 'RZAXIS', + } + + def getConfigValue(inputItem: InputItem, targetConf: Dict[str, int]): + # Output format BUTTONX + if inputItem.IsButton: + return '{}{}'.format(TYPE_TO_NAME[inputItem.Type], inputItem.Id + 1) + # Ouput format RYAXIS, RXAXIS, XAXIS, YAXIS + if inputItem.IsAxis: + return '{}'.format(SUPERMODEL_JOY[targetConf[x]]) + # Output format POV1_DOWN + if inputItem.IsHat: + return '{}{}_{}'.format(TYPE_TO_NAME[inputItem.Type], inputItem.Id + 1, HATS_TO_NAME[inputItem.Value]) + + raise TypeError + + def getConfigValueJ1(inputItem: InputItem): + return getConfigValue(inputItem, DIGITAL_JOYSTICK_P1) + + def getConfigValueJ2(inputItem: InputItem): + return getConfigValue(inputItem, DIGITAL_JOYSTICK_P2) + + # More Games need a Position value of Axis + def getPositionConfigValue(inputItem: InputItem): + if inputItem.IsAxis: + # Output format XAXIS_NEG/XAXIS_POS ,RXAXIS_NEG/RXAXIS_POS + if inputItem.Value == -1: + return '{}_NEG'.format(SUPERMODEL_JOY[ANALOG_JOYSTICK_P1[x]]) + else: + return '{}_POS'.format(SUPERMODEL_JOY[ANALOG_JOYSTICK_P1[x]]) + + raise TypeError + # For R2/L2 axis or button + def getAxisOrButton(inputItem: InputItem): + if inputItem.IsButton: + return '{}{}'.format(TYPE_TO_NAME[inputItem.Type], inputItem.Id + 1) + elif inputItem.IsAxis: + return '{}_POS'.format(SUPERMODEL_JOY[BUTTONS_AXIS[x]]) + + raise TypeError + + def getlightGunConfigValue(inputItem: InputItem): + if inputItem.IsAxis: + return 'MOUSE_{}'.format(SUPERMODEL_JOY[MOUSE_GAME[x]]) + + raise TypeError + + # Load Configuration + from configgen.settings.iniSettings import IniSettings + supermodelControllersSettings = IniSettings(recalboxFiles.supermodelControlsIni, True) + supermodelControllersSettings.loadFile(True) + from configgen.settings.keyValueSettings import keyValueSettings + supermodelSettings = keyValueSettings(recalboxFiles.supermodelConfigFile) + supermodelSettings.loadFile(True) + + ## Set default configuration + ## set emulated Net options desactived on default doesn't work on linux at the moment + ## Network board - experimental build for win32 only + supermodelControllersSettings.setString(self.SECTION_GLOBAL, "AddressOut", '"127.0.0.1"') \ + .setInt(self.SECTION_GLOBAL, "Network", 0) \ + .setInt(self.SECTION_GLOBAL, "SimulateNet", 0) \ + .setInt(self.SECTION_GLOBAL, "PortIn", 1970) \ + .setInt(self.SECTION_GLOBAL, "PortOut", 1971) + + ## Set auto triggers activate on default + ## automatic reload when off-screen + supermodelControllersSettings.setInt(self.SECTION_GLOBAL, "InputAutoTrigger", 1) \ + .setInt(self.SECTION_GLOBAL, "InputAutoTrigger2", 1) + + # Set sensitivity analog configurable in ConfigModel3.ini + #InputKeySensitivity + supermodelControllersSettings.setString(self.SECTION_GLOBAL, "InputKeySensitivity", supermodelSettings.getString("sensitivity", "")) + + # Set deadzone analog configurable in ConfigModel3.ini + deadzone = supermodelSettings.getString("deadzone", "") + # joystick1 Player 1 + supermodelControllersSettings.setString(self.SECTION_GLOBAL, "InputJoy1XDeadZone", deadzone) \ + .setString(self.SECTION_GLOBAL, "InputJoy1YDeadZone", deadzone) + # joystick2 player 1 + supermodelControllersSettings.setString(self.SECTION_GLOBAL, "InputJoy1RXDeadZone", deadzone) \ + .setString(self.SECTION_GLOBAL, "InputJoy1RYDeadZone", deadzone) + # triggers R2/L2 player 1 +# supermodelControllersSettings.setOption(self.SECTION_GLOBAL, "InputJoy1RZDeadZone", deadzone) +# supermodelControllersSettings.setOption(self.SECTION_GLOBAL, "InputJoy1ZDeadZone", deadzone) + # joystick1 Player 2 + supermodelControllersSettings.setString(self.SECTION_GLOBAL, "InputJoy2YDeadZone", deadzone) \ + .setString(self.SECTION_GLOBAL, "InputJoy2ZDeadZone", deadzone) + # joystick2 Player 2 + supermodelControllersSettings.setString(self.SECTION_GLOBAL, "InputJoy2RXDeadZone", deadzone) \ + .setString(self.SECTION_GLOBAL, "InputJoy2RYDeadZone", deadzone) + # triggers R2/L2 player 2 + supermodelControllersSettings.setString(self.SECTION_GLOBAL, "InputJoy2RZDeadZone", deadzone) \ + .setString(self.SECTION_GLOBAL, "InputJoy2XDeadZone", deadzone) + + + # Set Saturation analog configurable in ConfigModel3.ini + saturation = supermodelSettings.getString("saturation", "") + # joystick1 Players 1 + supermodelControllersSettings.setString(self.SECTION_GLOBAL, "InputJoy1RXSaturation", saturation) \ + .setString(self.SECTION_GLOBAL, "InputJoy1RYSaturation", saturation) \ + .setString(self.SECTION_GLOBAL, "InputJoy1RZSaturation", saturation) \ + .setString(self.SECTION_GLOBAL, "InputJoy1XSaturation", saturation) \ + .setString(self.SECTION_GLOBAL, "InputJoy1YSaturation", saturation) \ + .setString(self.SECTION_GLOBAL, "InputJoy1ZSaturation", saturation) + # joystick2 Players 2 + supermodelControllersSettings.setString(self.SECTION_GLOBAL, "InputJoy2RXSaturation", saturation) \ + .setString(self.SECTION_GLOBAL, "InputJoy2RYSaturation", saturation) \ + .setString(self.SECTION_GLOBAL, "InputJoy2RZSaturation", saturation) \ + .setString(self.SECTION_GLOBAL, "InputJoy2XSaturation", saturation) \ + .setString(self.SECTION_GLOBAL, "InputJoy2YSaturation", saturation) \ + .setString(self.SECTION_GLOBAL, "InputJoy2ZSaturation", saturation) + + for playercontroller in playersControllers: + pad: Controller = playersControllers[playercontroller] + # we only care about player 1 + if pad.PlayerIndex != 1: + continue + + # increase +1 controller index + padIndex = 'JOY{}'.format(pad.SdlIndex + 1) + + # Add hotkey buttons + for x in HOTKEY_BUTTONS: + if pad.HasInput(HOTKEY_BUTTONS[x]): + inp = pad.Input(HOTKEY_BUTTONS[x]) + supermodelControllersSettings.setString(self.SECTION_GLOBAL, x, '"{}_{}+{}_{}"'.format(padIndex, getConfigValueJ1(pad.Input(InputItem.ItemHotkey)), padIndex, getConfigValueJ1(inp))) + + # Service and Test menu + # Set on 0 or 1 in ConfigModel3.ini + for x in SERVICE_TEST_BUTTON: + if pad.HasInput(SERVICE_TEST_BUTTON[x]): + inp = pad.Input(SERVICE_TEST_BUTTON[x]) + ServiceBtn = supermodelSettings.getString("service-button", "") + if ServiceBtn == "1" : + supermodelControllersSettings.setString(self.SECTION_GLOBAL, x, '"{}_{}"'.format(padIndex, getConfigValueJ1(inp))) + else: + supermodelControllersSettings.setString(self.SECTION_GLOBAL, x, "NONE") + + for x in BUTTONS_P1: + if pad.HasInput(BUTTONS_P1[x]): + inp = pad.Input(BUTTONS_P1[x]) + supermodelControllersSettings.setString(self.SECTION_GLOBAL, x, '"{}_{}"'.format(padIndex, getConfigValueJ1(inp))) + + for x in DIGITAL_JOYSTICK_P1: + if pad.HasInput(DIGITAL_JOYSTICK_P1[x]): + inp = pad.Input(DIGITAL_JOYSTICK_P1[x]) + supermodelControllersSettings.setString(self.SECTION_GLOBAL, x, '"{}_{}"'.format(padIndex, getConfigValueJ1(inp))) + + for x in ANALOG_JOYSTICK_P1: + if pad.HasInput(ANALOG_JOYSTICK_P1[x]): # for up/left direction + inp = pad.Input(ANALOG_JOYSTICK_P1[x]) + supermodelControllersSettings.setString(self.SECTION_GLOBAL, x, '"{}_{}"'.format(padIndex, getPositionConfigValue(inp))) + + for x in BUTTONS_AXIS: + if pad.HasInput(BUTTONS_AXIS[x]): + inp = pad.Input(BUTTONS_AXIS[x]) + supermodelControllersSettings.setString(self.SECTION_GLOBAL, x, '"{}_{}"'.format(padIndex, getAxisOrButton(inp))) + + for x in MOUSE_GAME: + if pad.HasInput(MOUSE_GAME[x]): + inp = pad.Input(MOUSE_GAME[x]) + supermodelControllersSettings.setString(self.SECTION_GLOBAL, x, '"{}"'.format(getlightGunConfigValue(inp))) + + if pad.PlayerIndex == 2: + continue + + padIndex = 'JOY{}'.format(pad.SdlIndex + 2) + + for x in BUTTONS_P2: + if pad.HasInput(BUTTONS_P2[x]): + inp = pad.Input(BUTTONS_P2[x]) + supermodelControllersSettings.setString(self.SECTION_GLOBAL, x, '"{}_{}"'.format(padIndex, getConfigValueJ2(inp))) + + for x in DIGITAL_JOYSTICK_P2: + if pad.HasInput(DIGITAL_JOYSTICK_P2[x]): + inp = pad.Input(DIGITAL_JOYSTICK_P2[x]) + supermodelControllersSettings.setString(self.SECTION_GLOBAL, x, '"{}_{}"'.format(padIndex, getConfigValueJ2(inp))) + + break + + # Save configuration + supermodelControllersSettings.saveFile() diff --git a/projects/configgen/configgen/generators/supermodelnext/supermodelnextGenerator.py b/projects/configgen/configgen/generators/supermodelnext/supermodelnextGenerator.py new file mode 100644 index 0000000000..8872101074 --- /dev/null +++ b/projects/configgen/configgen/generators/supermodelnext/supermodelnextGenerator.py @@ -0,0 +1,283 @@ +#!/usr/bin/env python +from typing import List + +from configgen.Command import Command +import configgen.recalboxFiles as recalboxFiles +from configgen.Emulator import Emulator +from configgen.controllers.controller import ControllerPerPlayer +from configgen.generators.Generator import Generator +from configgen.settings.keyValueSettings import keyValueSettings + + +class SupermodelGenerator(Generator): + + SECTION_GLOBAL = "Global" + + ## -----AUDIO----- + @staticmethod + def GetMusicVolume(_) -> List[str]: + musicVolume: List[str] = [] + supermodelSettings = keyValueSettings(recalboxFiles.supermodelConfigFile) + supermodelSettings.loadFile(True) + MusicVol = supermodelSettings.getInt("music-volume", 100) + print("MusicVol:{} {}".format(MusicVol, recalboxFiles.supermodelConfigFile)) + if MusicVol != 100: + musicVolume.append("-music-volume={}".format(MusicVol)) + return musicVolume + + @staticmethod + def GetNoSound(_) -> List[str]: + noSound: List[str] = [] + supermodelSettings = keyValueSettings(recalboxFiles.supermodelConfigFile) + supermodelSettings.loadFile(True) + soundState = supermodelSettings.getInt("no-sound", 0) + if soundState == 1: + noSound.append("-no-sound") + return noSound + + @staticmethod + def GetVolume(_) -> List[str]: + Volume: List[str] = [] + supermodelSettings = keyValueSettings(recalboxFiles.supermodelConfigFile) + supermodelSettings.loadFile(True) + Vol = supermodelSettings.getInt("sound-volume", 100) + if Vol != 100: + Volume.append("-sound-volume={}".format(Vol)) + return Volume + + @staticmethod + def GetDsb(_) -> List[str]: + DSB: List[str] = [] + supermodelSettings = keyValueSettings(recalboxFiles.supermodelConfigFile) + supermodelSettings.loadFile(True) + currentDsb = supermodelSettings.getInt("no-dsb", 0) + if currentDsb == 1: + DSB.append("-no-dsb") + return DSB + + @staticmethod + def GetFlipStereo(_) -> List[str]: + flipStereo: List[str] = [] + supermodelSettings = keyValueSettings(recalboxFiles.supermodelConfigFile) + supermodelSettings.loadFile(True) + SwitchStereo = supermodelSettings.getInt("flip-stereo", 0) + if SwitchStereo == 1: + flipStereo.append("-flip-stereo") + return flipStereo + + @staticmethod + def GetBalance(_) -> List[str]: + BalanceSound: List[str] = [] + supermodelSettings = keyValueSettings(recalboxFiles.supermodelConfigFile) + supermodelSettings.loadFile(True) + balance = supermodelSettings.getInt("balance", 0) + if balance != 0: + BalanceSound.append("-balance={}".format(balance)) + return BalanceSound + + ## added in version r818 define new or old sound engine + @staticmethod + def GetSoundEngine(_) -> List[str]: + SoundEngine: List[str] = [] + supermodelSettings = keyValueSettings(recalboxFiles.supermodelConfigFile) + supermodelSettings.loadFile(True) + soundType = supermodelSettings.getInt("sound-engine", -1) + if soundType == 0: + SoundEngine.append("-new-scsp") + else: + SoundEngine.append("-legacy-scsp") + return SoundEngine + + ## -----VIDEO----- + @staticmethod + def GetResolution(_) -> List[str]: + ## get current resolution. + reso: List[str] = [] + supermodelSettings = keyValueSettings(recalboxFiles.supermodelConfigFile) + supermodelSettings.loadFile(True) + getConfig = supermodelSettings.getString("resolution", "") + if getConfig == "auto": + from configgen.utils.videoMode import getCurrentResolution + width, height = getCurrentResolution() + currentResolution = ("{}".format(width)) + "," + ("{}".format(height)) + reso.append("-fullscreen") + reso.append("-res=" + currentResolution) + elif getConfig == "none": + reso.append("-fullscreen") + else: + reso.append("-fullscreen") + reso.append("-res=" + getConfig) + return reso + + ## added in version r835 : + ## -wide-bg When wide-screen mode is enabled, also expand the 2D background layer to screen width + @staticmethod + def GetScreenRatio(system: Emulator) -> List[str]: + ratio: List[str] = [] + if system.Ratio == "16/9": + ratio.append("-wide-screen") + ratio.append("-wide-bg") + return ratio + + @staticmethod + def GetThrottle(_) -> List[str]: + Throttle: List[str] = [] + supermodelSettings = keyValueSettings(recalboxFiles.supermodelConfigFile) + supermodelSettings.loadFile(True) + throttle: int = supermodelSettings.getInt("no-throttle", 0) + if throttle == 1: + Throttle.append("-no-throttle") + return Throttle + + @staticmethod + def GetMultiTexture(_) -> List[str]: + Texture: List[str] = [] + supermodelSettings = keyValueSettings(recalboxFiles.supermodelConfigFile) + supermodelSettings.loadFile(True) + MultiTexture = supermodelSettings.getInt("multi-texture", 0) + if MultiTexture == 1: + Texture.append("-multi-texture") + else: + Texture.append("-no-multi-texture") + return Texture + + @staticmethod + def GetRendering(_) -> List[str]: + Rendering: List[str] = [] + supermodelSettings = keyValueSettings(recalboxFiles.supermodelConfigFile) + supermodelSettings.loadFile(True) + QuadRendering: int = supermodelSettings.getInt("quad-rendering", 0) + if QuadRendering == "1": + Rendering.append("-quad-rendering") + return Rendering + + @staticmethod + def GetEngine(_) -> List[str]: + # Set new3d engine only if have a nvidia driver else use legacy3d engine + # Is nVidia driver on? + import platform + arch = platform.machine() + hasNVidia = False + if arch == "x86_64": + # check if have nvidia driver + import os + if os.path.exists("/etc/modprobe.d/blacklist.conf"): + with open("/etc/modprobe.d/blacklist.conf") as f: + for line in f: + if "blacklist nouveau" in line: + hasNVidia = True + break + return [] if hasNVidia else ['-legacy3d'] + + @staticmethod + def GetCrosshairs(_) -> List[str]: + SetCrosshairs: List[str] = [] + supermodelSettings = keyValueSettings(recalboxFiles.supermodelConfigFile) + supermodelSettings.loadFile(True) + Crosshairs: int = supermodelSettings.getInt("crosshairs", 0) + ## on default set 3 (for players one and two) if enabled in config file + if Crosshairs == 1: + SetCrosshairs.append("-crosshairs=1") + elif Crosshairs == 2: + SetCrosshairs.append("-crosshairs=3") + return SetCrosshairs + +## Disabled because FPS show only on statut bar +# ## -----CORE----- +# @staticmethod +# def GetShowsFps(system): +# ShowFps = [] +# supermodelSettings = keyValueSettings(recalboxFiles.supermodelConfigFile) +# supermodelSettings.loadFile(True) +# showfps = supermodelSettings.getOption("show-fps", "") +# if showfps == "1" : +# ShowFps.append("-show-fps") +# return ShowFps + + @staticmethod + def GetThreads(_) -> List[str]: + Thread: List[str] = [] + supermodelSettings = keyValueSettings(recalboxFiles.supermodelConfigFile) + supermodelSettings.loadFile(True) + ThreadStatut: int = supermodelSettings.getInt("multi-threading", 0) + if ThreadStatut == 1: + Thread.append("-no-gpu-thread") + elif ThreadStatut == 2: + Thread.append("no-threads") + else: + Thread.append("-gpu-multi-threaded") + return Thread + + @staticmethod + def GetPpcFrequency(_) -> List[str]: + PpcFrequency: List[str] = [] + supermodelSettings = keyValueSettings(recalboxFiles.supermodelConfigFile) + supermodelSettings.loadFile(True) + Frequency: int = supermodelSettings.getInt("ppc-frequency", 50) + if Frequency != "50": + PpcFrequency.append("-ppc-frequency={}".format(Frequency)) + return PpcFrequency + +## Disabled because make crash on few games + @staticmethod + def GetSavesState(_) -> List[str]: + savespath: List[str] = [] + supermodelSettings = keyValueSettings(recalboxFiles.supermodelConfigFile) + supermodelSettings.loadFile(True) + model3saves = "/recalbox/share/saves/model3/" + savespath.append("-load-state=" + model3saves) + return savespath + + @staticmethod + def GetLogsPath(_) -> List[str]: + logpath: List[str] = [] + supermodelSettings = keyValueSettings(recalboxFiles.supermodelConfigFile) + supermodelSettings.loadFile(True) + model3logs = recalboxFiles.supermodelRooFolder + "/Supermodel.log" + logpath.append("-log-output=" + model3logs) + return logpath + + @staticmethod + def GetLogsLevel(_) -> List[str]: + loglevel: List[str] = [] + supermodelSettings = keyValueSettings(recalboxFiles.supermodelConfigFile) + supermodelSettings.loadFile(True) + loglevelset = supermodelSettings.getString("log-level", "") + loglevel.append("-log-level=" + loglevelset) + return loglevel + + def generate(self, system: Emulator, playersControllers: ControllerPerPlayer, recalboxOptions: keyValueSettings, args) -> Command: + if not system.HasConfigFile: + # Controllers + import configgen.generators.supermodel.supermodelControllers as supermodelControllers + supermodelControllers.generateControllerConfig(self, playersControllers) + + commandArray = [recalboxFiles.recalboxBins[system.Emulator], args.rom] + ## add other cmd option for more configuration + ## -----AUDIO------ + commandArray.extend(self.GetMusicVolume(system)) + commandArray.extend(self.GetVolume(system)) + commandArray.extend(self.GetFlipStereo(system)) + commandArray.extend(self.GetDsb(system)) + commandArray.extend(self.GetBalance(system)) + commandArray.extend(self.GetSoundEngine(system)) + commandArray.extend(self.GetNoSound(system)) + ## -----VIDEO------ + commandArray.extend(self.GetResolution(system)) + commandArray.extend(self.GetScreenRatio(system)) + commandArray.extend(self.GetThrottle(system)) + commandArray.extend(self.GetMultiTexture(system)) + commandArray.extend(self.GetRendering(system)) + commandArray.extend(self.GetEngine(system)) + commandArray.extend(self.GetCrosshairs(system)) + ## -----CORE------ +# commandArray.extend(self.GetShowsFps(system)) + commandArray.extend(self.GetThreads(system)) + commandArray.extend(self.GetPpcFrequency(system)) + commandArray.extend(self.GetSavesState(system)) + commandArray.extend(self.GetLogsPath(system)) + commandArray.extend(self.GetLogsLevel(system)) + + if system.HasArgs: commandArray.extend(system.Args) + + return Command(videomode=system.VideoMode, array=commandArray) diff --git a/projects/configgen/configgen/recalboxFiles.py b/projects/configgen/configgen/recalboxFiles.py index 1fb29b29ea..a3906b7023 100644 --- a/projects/configgen/configgen/recalboxFiles.py +++ b/projects/configgen/configgen/recalboxFiles.py @@ -52,6 +52,7 @@ recalboxBins =\ 'simcoupe' : '/usr/bin/simcoupe', 'solarus' : '/usr/bin/solarus-run', 'supermodel' : '/usr/bin/supermodel', + 'supermodel-next' : '/usr/bin/supermodel-next', 'ti99sim' : '/usr/bin/ti99sim/ti99sim-sdl', 'vice' : '/usr/bin/x64', 'xroar' : '/usr/bin/xroar', @@ -174,6 +175,9 @@ supermodelRooFolder = CONF + '/model3' supermodelConfigFile = supermodelRooFolder + '/ConfigModel3.ini' supermodelControlsIni = supermodelRooFolder + '/Supermodel.ini' +supermodelRooFolder = CONF + '/supermodel' +supermodelConfigFile = supermodelRooFolder + '/Supermodel.ini' + crtFilesRootFolder = '/recalbox/system/configs/crt/' crtUserFilesRootFolder = '/recalbox/share/system/configs/crt/' diff --git a/projects/configgen/setup.py b/projects/configgen/setup.py index 9fd1087899..506af98566 100644 --- a/projects/configgen/setup.py +++ b/projects/configgen/setup.py @@ -45,6 +45,7 @@ setup(name='recalbox-configgen', 'configgen.generators.rb5000', 'configgen.generators.sdlpop', 'configgen.generators.vvvvvv', + 'configgen.generators.supermodel-next', 'configgen.settings', 'configgen.utils'], scripts=['emulatorlauncher.py'] -- GitLab