Added Glitch Room Source code to Gitty

This commit is contained in:
Jeff Luke committed 2026-10-04 11:31:17 -07:00
commit 1ac9eb5644
505 files changed
+28504

No files matched your search

+6
View File
@@ -0,0 +1,6 @@
[gd_scene format=3 uid="uid://du56pbkblp1bx"]
[ext_resource type="Script" uid="uid://c7fye4iaedapj" path="res://games/launcher/arcade_launcher.gd" id="1"]
[node name="ArcadeLauncher" type="Node" unique_id=3868404]
script = ExtResource("1")
+65
View File
@@ -0,0 +1,65 @@
# Arcade launcher and cabinet controls
For central staff operation, see the separate [Arcade room controller guide](../../tools/room_controller/README.md). Open the controller URL in a browser for the multi-cabinet operator on Mac/iPad, or use `-- --operator` for Cabinet 01 quick controls. Run `-- --managed-cabinet --cabinet=cabinet_01 --gpio=real` on the appropriate Pi. These modes bypass the standalone launcher; managed mode uses central scenario mappings instead of local rewards.
For physical Raspberry Pi outputs, follow [the GPIO setup and LED test guide](../../tools/pi_gpio/README.md). The launcher forwards matching Hardware Scenario events; its default scenario connects Pac-Man's win to cabinet 01's GPIO17 coin-release pulse. Start the local helper and use `--gpio=real` to enable electrical outputs.
Open `res://games/launcher/ArcadeLauncher.tscn` and press F6. It lists all seven games with their icons. Move the joystick up/down and press Start to open a game's attract screen; press Start again to begin. Select returns to the list and unloads the game, including its sound players. Mouse selection and double-click also work.
This is a standalone arcade frontend, separate from the room/scenario runtime. To boot directly into it in an export, use this scene as **Project Settings > Application > Run > Main Scene**.
## Map your cabinet
The exported game opens **Control Setup** automatically until a local profile is saved. You can reopen it from the last entry in the game list, or press **F1** on a keyboard as a recovery shortcut. No Godot editor is needed on the Pi.
1. Connect both controllers before beginning. Press any controller button / Enter, or click **Begin Setup**.
2. Follow the prompts for player-one Start, Select, joystick directions and the three game buttons. Release each button or center the joystick before the next prompt. Small axis drift is ignored.
3. For Robotron firing, use four face buttons or move the second joystick in each requested direction. Player-one movement is automatically reused for Robotron movement.
4. Review the list and test inputs: the monitor shows which controller/input was detected and the actions assigned to it. An unassigned player-two button should show no actions. Move the trackball to confirm mouse motion is arriving.
5. Press the learned **Start** button or click **Save Controls**. Learned Select cancels from review. The Cancel button cancels at any point without altering the previous profile. **Escape quits the entire application**, including from setup; unfinished changes are not saved.
Saving replaces the default bindings for the configured actions instead of adding more overlapping bindings. The saved controls load for standalone game scenes and the room runtime as well as the launcher. Project Settings Input Map remains the fallback until a local profile exists; afterwards, the local profile takes precedence.
Profiles are saved outside the exported game as `user://arcade_controls.cfg`, usually `~/.local/share/godot/app_userdata/ArcadeEscape/arcade_controls.cfg` on Linux and `%APPDATA%/Godot/app_userdata/ArcadeEscape/arcade_controls.cfg` on Windows. They survive replacing the game export. Configure each machine independently; do not copy Windows bindings onto the Pi. If saving fails, the screen reports it and keeps the previous profile.
## Two controllers
The shipped default bindings use All Devices, which lets either gamepad activate the same action. Setup records each joypad's identity and specific input, then binds only that device. Different encoders are resolved by name/GUID when device numbers change. A disconnected controller's inputs are disabled rather than assigned to another controller.
Identical encoders can have the same name/GUID and no distinguishable serial identity through Godot. These are separated by their instance order, with a visible warning to check player one after reconnecting. Keep them in consistent USB ports and rerun setup if the players swap. If the count of identical encoders changes, affected bindings are disabled until all are connected again or setup is repeated. Changing connections during setup restarts the wizard.
Keyboard-mode encoders are supported, but two encoders emitting the same keyboard key cannot be distinguished by this setup. Give their players different key codes in the encoder configuration, or use gamepad mode. F1 and Escape are reserved for setup and quitting and cannot be learned as gameplay buttons.
## Action reference (project defaults)
| Action | Cabinet use | Keyboard default |
| --- | --- | --- |
| `arcade_up/down/left/right` | Joystick, menu and most games | Arrow keys |
| `arcade_start` | Start | Enter |
| `arcade_menu` | Select: leave game | Use your learned Select button; Escape quits the application |
| `arcade_action_1` | Fire; Missile Command left battery | Space / left mouse |
| `arcade_action_2` | Tempest Superzapper; Missile Command center battery | Z / middle mouse |
| `arcade_action_3` | Missile Command right battery | X / right mouse |
| `robotron_move_left/right/up/down` | Bind the same movement joystick | A / D / W / S |
| `robotron_fire_left/right/up/down` | Four face buttons arranged directionally | Arrow keys |
| `arcade_rotate_left/right` | Optional Tempest spinner pulses | Mouse wheel down/up |
The default gamepad bindings remain in Project Settings. Use Control Setup to learn the actual cabinet buttons rather than assuming printed button numbers match the operating system. Four face buttons cover Robotron, including diagonal shots by holding two buttons; the second joystick can also handle firing. The remaining games need at most three face buttons.
The trackball must report as a mouse. The launcher enables Missile Command's **Relative Mouse Aim** and captures the pointer for Missile Command and Tempest, so trackball travel continues beyond desktop edges. Select releases the pointer when returning to the menu. Tempest accepts horizontal mouse motion with **Trackball Pixels Per Lane** sensitivity. Continuous mouse motion is handled as motion, not a button action.
## Raspberry Pi 4/5
Input Map settings ship with the project/export. Use Linux ARM64 for a 64-bit Raspberry Pi OS installation and retain the Compatibility renderer. There are no Windows-only input APIs in these controls. Keyboard/mouse USB encoders and recognized gamepads use the same actions, but a generic encoder may report different button/axis mappings on Linux: test the actual hardware on the Pi before final deployment. This change does not add a GPIO input driver.
Godot references: [Linux export](https://docs.godotengine.org/en/stable/tutorials/export/exporting_for_linux.html), [controller mappings](https://docs.godotengine.org/en/stable/tutorials/inputs/controllers_gamepads_joysticks.html).
## Quick check
1. Navigate all seven entries with the joystick, open each with Start, begin play, and return with Select.
2. Test Missile Command's three batteries independently with the trackball; test Tempest fire and Superzapper separately.
3. Test Robotron movement independently of all four fire buttons and their diagonals.
4. Save setup, restart the game, and verify the learned bindings persist and unassigned player-two buttons have no effect.
5. Repeat on the Pi after export and reconnecting the USB encoders. Check player-one identity if the encoders are identical.
Automated checks: run `tests/launcher/check_launcher.gd` and `tests/launcher/check_controls.gd` using Godot's headless script runner. The latter uses a temporary profile in `.godot`, not your real saved controls.
+175
View File
@@ -0,0 +1,175 @@
extends Node
@export var hardware_scenario: ScenarioDefinition = preload("res://data/scenarios/proof_of_concept.tres")
## Standalone arcade selector. Room/scenario startup remains separate.
const GAMES := [
["Pac-Man", "pacman/Pacman", "pacman", "JOYSTICK"],
["Galaga", "galaga/Galaga", "galaga", "JOYSTICK / FIRE"],
["Tempest", "tempest/Tempest", "tempest", "JOYSTICK OR TRACKBALL / FIRE / SUPERZAPPER"],
["Missile Command", "missile_command/MissileCommand", "missilecommand", "TRACKBALL / THREE LAUNCH BUTTONS"],
["Frogger", "frogger/Frogger", "frogger", "JOYSTICK"],
["Space Invaders", "space_invaders/SpaceInvaders", "spaceinvaders", "JOYSTICK / FIRE"],
["Robotron 2084", "robotron/Robotron", "robotron", "JOYSTICK / FOUR DIRECTIONAL FIRE BUTTONS"],
]
var selected := 0
var game: Node
var menu: Control
var list: ItemList
var description: Label
var switching := false
var setup: CanvasLayer
var control_status: Label
var gpio_status: Label
func _ready() -> void:
if "--managed-cabinet" in OS.get_cmdline_user_args():
set_process_input(false)
add_child(preload("res://core/network/managed_cabinet.gd").new())
return
if "--operator" in OS.get_cmdline_user_args():
set_process_input(false)
add_child(preload("res://operator/ArcadeRoomOperator.tscn").instantiate())
return
var layer := CanvasLayer.new()
add_child(layer)
menu = Control.new()
menu.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
layer.add_child(menu)
var background := ColorRect.new()
background.color = Color("080d18")
background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
menu.add_child(background)
var center := CenterContainer.new()
center.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
menu.add_child(center)
var column := VBoxContainer.new()
column.custom_minimum_size = Vector2(700, 0)
column.add_theme_constant_override("separation", 18)
center.add_child(column)
var title := Label.new()
title.text = "ARCADE GALLERY"
title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
title.add_theme_font_size_override("font_size", 46)
title.modulate = Color("75e8ef")
column.add_child(title)
list = ItemList.new()
list.custom_minimum_size = Vector2(700, 520)
list.fixed_icon_size = Vector2i(48, 48)
list.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
list.add_theme_font_size_override("font_size", 28)
list.add_theme_constant_override("v_separation", 12)
list.focus_mode = Control.FOCUS_NONE
column.add_child(list)
for entry in GAMES:
list.add_item(entry[0], load("res://games/launcher/icons/ico_%s.png" % entry[2]))
list.add_item("Control Setup")
list.item_selected.connect(_select)
list.item_activated.connect(func(index: int): _select(index); launch.call_deferred())
description = Label.new()
description.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
description.add_theme_font_size_override("font_size", 18)
column.add_child(description)
var hint := Label.new()
hint.text = "JOYSTICK: CHOOSE START: PLAY SELECT: RETURN TO MENU"
hint.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
hint.modulate = Color("91a1bb")
column.add_child(hint)
control_status = Label.new()
control_status.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
control_status.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
control_status.add_theme_font_size_override("font_size", 16)
column.add_child(control_status)
ArcadeControls.changed.connect(_refresh_control_status)
_refresh_control_status()
gpio_status = Label.new()
gpio_status.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
gpio_status.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
gpio_status.text = HardwareManager.status
column.add_child(gpio_status)
HardwareManager.status_changed.connect(func(message: String): gpio_status.text = message)
_select(0)
if ArcadeControls.bindings.is_empty(): open_setup.call_deferred()
func _refresh_control_status() -> void:
control_status.text = ArcadeControls.problem if not ArcadeControls.problem.is_empty() else "CONTROL SETUP: LAST MENU ENTRY / F1"
func _select(index: int) -> void:
selected = wrapi(index, 0, GAMES.size() + 1)
list.select(selected)
list.ensure_current_is_visible()
description.text = GAMES[selected][3] if selected < GAMES.size() else "CONFIGURE THIS CABINET'S JOYSTICKS AND BUTTONS"
func _input(event: InputEvent) -> void:
if ArcadeControls.handle_quit(event): return
if is_instance_valid(setup): return
if event.is_echo() or switching: return
if event is InputEventKey and event.pressed and event.physical_keycode == KEY_F1:
get_viewport().set_input_as_handled()
if is_instance_valid(game): return_to_menu()
open_setup.call_deferred()
return
if is_instance_valid(game):
if event.is_action_pressed("arcade_menu"):
get_viewport().set_input_as_handled()
switching = true
return_to_menu.call_deferred()
return
if event.is_action_pressed("arcade_down"):
_select(selected + 1)
elif event.is_action_pressed("arcade_up"):
_select(selected - 1)
elif event.is_action_pressed("arcade_start"):
switching = true
launch.call_deferred()
else:
return
get_viewport().set_input_as_handled()
func launch() -> void:
if selected == GAMES.size():
open_setup()
switching = false
return
if is_instance_valid(game): return
var scene := load("res://games/%s.tscn" % GAMES[selected][1]) as PackedScene
if scene == null:
switching = false
return
game = scene.instantiate()
RoomRuntime.active_assignment = null
if hardware_scenario != null:
for assignment in hardware_scenario.assignments:
if assignment.game != null and assignment.game.scene == scene:
RoomRuntime.configure(assignment)
game.game_started.connect(func(): RoomRuntime.fire_game_event(GameEvents.STARTED))
game.game_won.connect(func(): RoomRuntime.fire_game_event(GameEvents.WON))
game.game_lost.connect(func(): RoomRuntime.fire_game_event(GameEvents.LOST))
game.game_reset.connect(func(): RoomRuntime.fire_game_event(GameEvents.RESET))
break
if GAMES[selected][2] == "missilecommand":
game.set("relative_mouse_aim", true)
if GAMES[selected][2] in ["missilecommand", "tempest"]:
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
menu.hide()
add_child(game)
# Present the game's attract screen; Start begins its own opening sequence.
switching = false
func open_setup() -> void:
if is_instance_valid(setup): return
setup = preload("res://games/launcher/control_setup.gd").new()
menu.hide()
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
setup.closed.connect(func(): menu.show(); _select(selected))
add_child(setup)
func return_to_menu() -> void:
if is_instance_valid(game):
remove_child(game)
game.queue_free()
game = null
RoomRuntime.active_assignment = null
HardwareManager.active_cabinet = null
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
menu.show()
_select(selected)
switching = false
+1
View File
@@ -0,0 +1 @@
uid://c7fye4iaedapj
+177
View File
@@ -0,0 +1,177 @@
extends CanvasLayer
signal closed
var panel: Control
var heading: Label
var prompt: Label
var monitor: Label
var details: Label
var buttons: HBoxContainer
var draft: Dictionary = {}
var step := -1
var waiting: InputEvent
var armed_at := 0
func _ready() -> void:
layer = 10
panel = ColorRect.new()
panel.color = Color("080d18")
panel.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
add_child(panel)
var center := CenterContainer.new()
center.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
panel.add_child(center)
var column := VBoxContainer.new()
column.custom_minimum_size = Vector2(1100, 0)
column.add_theme_constant_override("separation", 18)
center.add_child(column)
heading = label(column, 36)
prompt = label(column, 26)
details = label(column, 18)
monitor = label(column, 20)
monitor.modulate = Color("75e8ef")
buttons = HBoxContainer.new()
buttons.alignment = BoxContainer.ALIGNMENT_CENTER
buttons.add_theme_constant_override("separation", 24)
column.add_child(buttons)
welcome()
Input.joy_connection_changed.connect(_controller_changed)
func _controller_changed(_id: int, _connected: bool) -> void:
waiting = null
draft.clear()
welcome()
prompt.text = "Controllers changed. Begin again with all controllers connected."
func label(parent: Node, font_size: int) -> Label:
var result := Label.new()
result.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
result.custom_minimum_size.x = 1100
result.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
result.add_theme_font_size_override("font_size", font_size)
parent.add_child(result)
return result
func clear_buttons() -> void:
for child in buttons.get_children():
buttons.remove_child(child)
child.queue_free()
func button(text: String, callback: Callable) -> void:
var control := Button.new()
control.text = text
control.add_theme_font_size_override("font_size", 24)
control.focus_mode = Control.FOCUS_NONE
control.pressed.connect(callback)
buttons.add_child(control)
func welcome() -> void:
step = -1
heading.text = "CONTROL SETUP"
prompt.text = "Configure this cabinet — no editor needed"
details.text = "Use PLAYER ONE for movement, Start, Select and game buttons.\nFor Robotron firing, use four face buttons OR your second joystick.\nEach controller is recorded separately. Release each input when asked.\n\nThe trackball works as a mouse; move it to see it detected below.\nKeyboard encoders work too. Escape quits the application. F1 opens setup.\n\nPress any controller button / Enter to begin, or click Begin Setup.\nCancel keeps your saved controls. Escape quits without saving."
if not ArcadeControls.problem.is_empty(): details.text += "\n\n" + ArcadeControls.problem
monitor.text = "Waiting for input…"
clear_buttons()
button("Begin Setup", begin)
button("Cancel / Keep Current Controls", close)
armed_at = Time.get_ticks_msec() + 350
func begin() -> void:
draft.clear()
waiting = null
step = 0
armed_at = Time.get_ticks_msec() + 350
show_step()
func show_step() -> void:
clear_buttons()
if step >= ArcadeControls.STEPS.size():
heading.text = "REVIEW & TEST CONTROLS"
prompt.text = "Try both joysticks and buttons; watch the detected actions below."
details.text = ""
for entry in ArcadeControls.STEPS:
details.text += "%s: %s\n" % [entry[0].replace("arcade_", "").replace("robotron_", "Robotron ").replace("_", " ").capitalize(), ArcadeControls.describe(draft[entry[0]])]
details.text += "\nPress your learned START to save, SELECT to cancel, or click a button.\nTrackball motion needs no button binding. Identical USB encoders may swap after reconnecting."
button("Save Controls", save)
button("Start Over", begin)
button("Cancel", close)
return
heading.text = "CONTROL SETUP %d / %d" % [step + 1, ArcadeControls.STEPS.size()]
prompt.text = ArcadeControls.STEPS[step][1]
details.text = "Move one direction or press one button, then release it.\nUse the actual cabinet controls. Nothing is saved until you finish.\nCancel keeps your saved controls; Escape quits. Trackball motion is shown below but is not bound as a button."
button("Start Over", begin)
button("Cancel", close)
func close() -> void:
closed.emit()
queue_free()
func save() -> void:
var error := ArcadeControls.save_profile(draft)
if error != OK:
prompt.text = "Could not save controls (%s). Your previous settings are unchanged." % error_string(error)
return
close()
func released(event: InputEvent) -> bool:
if waiting == null or event.device != waiting.device: return false
if waiting is InputEventJoypadMotion and event is InputEventJoypadMotion:
return event.axis == waiting.axis and absf(event.axis_value) < .25
if waiting is InputEventJoypadButton and event is InputEventJoypadButton:
return event.button_index == waiting.button_index and not event.pressed
if waiting is InputEventKey and event is InputEventKey:
return event.physical_keycode == waiting.physical_keycode and event.keycode == waiting.keycode and not event.pressed
return false
func conflict(action: String, binding: Dictionary) -> String:
for other in draft:
if draft[other] != binding: continue
# Reusing game fire buttons for Robotron is deliberate; within each game it isn't.
if action.begins_with("robotron_") != other.begins_with("robotron_") and other not in ["arcade_start", "arcade_menu"]:
continue
return other
return ""
func _input(event: InputEvent) -> void:
if ArcadeControls.handle_quit(event): return
if event.is_echo(): return
if event is InputEventMouseMotion:
monitor.text = "Trackball / mouse motion: %s" % event.relative
return
if event is InputEventMouseButton: return # Leave setup buttons clickable.
if not (event is InputEventKey or event is InputEventJoypadButton or event is InputEventJoypadMotion): return
get_viewport().set_input_as_handled()
if waiting != null:
if released(event):
waiting = null
step += 1
armed_at = Time.get_ticks_msec() + 200
show_step()
return
if Time.get_ticks_msec() < armed_at: return
if event is InputEventJoypadMotion:
if absf(event.axis_value) < .65: return
elif not event.is_pressed(): return
var binding: Dictionary = ArcadeControls.encode(event, ArcadeControls.devices())
if binding.is_empty(): return
monitor.text = "Detected: " + ArcadeControls.describe(binding)
if step < 0:
if event is InputEventJoypadButton or (event is InputEventKey and event.physical_keycode == KEY_ENTER):
begin()
return
if step >= ArcadeControls.STEPS.size():
var actions: Array[String] = []
for action in draft:
if draft[action] == binding: actions.append(action)
monitor.text += "\nActions: " + (", ".join(actions) if not actions.is_empty() else "unassigned — will not control gameplay")
if binding == draft.arcade_start: save()
elif binding == draft.arcade_menu: close()
return
var action: String = ArcadeControls.STEPS[step][0]
var duplicate := conflict(action, binding)
if not duplicate.is_empty():
monitor.text = "Already used for %s. Choose a different input." % duplicate
return
draft[action] = binding
waiting = event.duplicate()
prompt.text = "Recorded. Release the button / center the joystick to continue."
+1
View File
@@ -0,0 +1 @@
uid://diw7s6drttvyq
Binary file not shown.

After

Width:  |  Height:  |  Size: 448 B

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b8bqn824u85vl"
path="res://.godot/imported/ico_frogger.png-b57a3a61500c7a320cf15c673d6eb4d6.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://games/launcher/icons/ico_frogger.png"
dest_files=["res://.godot/imported/ico_frogger.png-b57a3a61500c7a320cf15c673d6eb4d6.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dac8qj4ricufo"
path="res://.godot/imported/ico_galaga.png-36d03105f6c4a933b9c92d2d355e468c.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://games/launcher/icons/ico_galaga.png"
dest_files=["res://.godot/imported/ico_galaga.png-36d03105f6c4a933b9c92d2d355e468c.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 421 B

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://85qgr4tqlnqh"
path="res://.godot/imported/ico_missilecommand.png-eb97b766183d581f71965f33acf01b65.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://games/launcher/icons/ico_missilecommand.png"
dest_files=["res://.godot/imported/ico_missilecommand.png-eb97b766183d581f71965f33acf01b65.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 415 B

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cqo136wb6s53w"
path="res://.godot/imported/ico_pacman.png-b602b4a9bac1a4babcfeec75859abcff.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://games/launcher/icons/ico_pacman.png"
dest_files=["res://.godot/imported/ico_pacman.png-b602b4a9bac1a4babcfeec75859abcff.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://nqduggsfhj00"
path="res://.godot/imported/ico_robotron.png-f9c39bc84b1f503f3d58b52dd3a17ef9.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://games/launcher/icons/ico_robotron.png"
dest_files=["res://.godot/imported/ico_robotron.png-f9c39bc84b1f503f3d58b52dd3a17ef9.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c1kd33ac3lilj"
path="res://.godot/imported/ico_spaceinvaders.png-16def212c976698b79583e1a2fe208eb.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://games/launcher/icons/ico_spaceinvaders.png"
dest_files=["res://.godot/imported/ico_spaceinvaders.png-16def212c976698b79583e1a2fe208eb.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 415 B

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://druv26hjagfnl"
path="res://.godot/imported/ico_tempest.png-5c3137c1b36eaca1076a9d0dde7b4414.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://games/launcher/icons/ico_tempest.png"
dest_files=["res://.godot/imported/ico_tempest.png-5c3137c1b36eaca1076a9d0dde7b4414.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1