1331 lines
77 KiB
Text
1331 lines
77 KiB
Text
= Singe Manual
|
|
Scott Duensing <scott@kangaroopunch.com>
|
|
:revnumber: 3.00
|
|
:revdate: 2026
|
|
:doctype: book
|
|
:toc: left
|
|
:toclevels: 3
|
|
:sectnums:
|
|
:sectnumlevels: 3
|
|
:title-logo-image: image:images/singeLogo.png[Singe, pdfwidth=2.6in, align=center]
|
|
:source-highlighter: rouge
|
|
:icons: font
|
|
:experimental:
|
|
|
|
== About Singe
|
|
|
|
Singe (SINGE Is Not a Game Emulator, and named after the dragon in
|
|
Dragon's Lair) is a Lua-based scripting system that allows for rapid prototyping
|
|
of new laserdisc games, or the creation of entirely new games. The language is
|
|
easy to learn, very powerful, and fast. All the features needed to develop your
|
|
own game are made available through a simple application programming interface
|
|
(API).
|
|
|
|
Singe provides numerous features to the game developer. Some of the more
|
|
interesting ones are:
|
|
|
|
* 3D scenes with models, animation, lighting, and shadows
|
|
* Physics, including joints, ragdolls, soft bodies, and vehicles
|
|
* Menus, option screens, and HUDs built like web pages
|
|
* Hardware video decoding, even on small machines
|
|
* Online high scores, and a catalogue of games to download and update
|
|
* Games packed into a single file
|
|
* Object-oriented programming language
|
|
* Animated sprites
|
|
* TrueType font support
|
|
* 32-bit color space with transparency
|
|
* Multi-channel, overlapping, stereo sound, and MIDI
|
|
* Analog and digital input device support, including light guns
|
|
* Wide support for video and audio formats
|
|
|
|
Singe runs on Windows, macOS, and Linux, including the Raspberry Pi and
|
|
handhelds like the R36S.
|
|
|
|
For players, Singe allows many unemulated and new games to be enjoyed using any
|
|
desired front end or via the included menu system.
|
|
|
|
Since the original release of Singe back in 2006, several revisions have been
|
|
released, both officially and unofficially. In 2020, Singe 2.00 was released.
|
|
This was a total rewrite from the ground up, adding numerous features while
|
|
staying compatible with existing 1.xx games. Singe 3.00 adds 3D, physics,
|
|
user interfaces, and much more, while still running the games that came
|
|
before it. As of the writing of this manual, the latest release is
|
|
{revnumber}.
|
|
|
|
== Installation and Upgrading
|
|
|
|
=== Installing Singe
|
|
|
|
To install Singe, simply download the appropriate binary for your system. Place
|
|
it in a new folder by itself and run it. On the first run, Singe will create
|
|
all the necessary directories and support files needed. You are now ready to
|
|
install some games.
|
|
|
|
=== Upgrading Singe
|
|
|
|
To upgrade Singe to a newer version, place the new binary in the installation
|
|
folder beside the old one and run it once with `--refresh`. The support folder
|
|
that is there is set aside as `old-Singe-<version>`, named for the version that
|
|
wrote it, and a fresh `Singe/` folder is written in its place. Nothing is
|
|
deleted: the folder that was set aside is yours to keep or remove, and a second
|
|
`--refresh` sets its own aside as `old-Singe-<version>-1` rather than writing
|
|
over the first.
|
|
|
|
The old binary can stay where it is. `Menu.sh` (or `Menu.bat`) runs the newest
|
|
Singe it finds beside itself, and a beta counts as older than the release of the
|
|
same number, so `Singe-v3.00b2` gives way to `Singe-v3.00` the moment it
|
|
arrives. The menu's Engine Update tool does all of this for you; see
|
|
<<servicetools,The Service Tools>>.
|
|
|
|
WARNING: Do not run a new Singe binary against an out-of-date set of support
|
|
files. Always refresh the `Singe/` directory when upgrading.
|
|
|
|
=== Things to Know
|
|
|
|
Do not touch the `Singe/` folder. Files in this folder belong to Singe and may
|
|
be updated or deleted at any time.
|
|
|
|
== Playing Games
|
|
|
|
=== Installing Games
|
|
|
|
A game is either a single `.game` file or a directory. Copy it into the same
|
|
folder where you placed the Singe binary. The included menu system will
|
|
automatically detect it and add it to the menu.
|
|
|
|
=== Game Directory Layout
|
|
|
|
A Singe installation is a game directory containing the `Singe` support
|
|
directory the engine creates on first run, one directory per game, any
|
|
packed `.game` files, and a `data` directory for everything the games and
|
|
the engine write. The executable usually sits there too, but need not:
|
|
`--gamedir` names the game directory from anywhere, and the `Menu.sh` (or
|
|
`Menu.bat`) the engine writes there then runs the executable by its full
|
|
path. Otherwise the launcher searches beside itself for the files whose
|
|
names begin with `Singe` and runs the best of them, in the spirit of the
|
|
launchers `BatMaker` writes, so an upgrade that changes the executable's
|
|
version in its name does not leave a launcher pointing at a file that is no
|
|
longer there.
|
|
|
|
Best means this machine's architecture first and the version after it. The
|
|
platform in the name is compared against what the system reports, because a
|
|
newer build for another architecture cannot run at all, and one game directory
|
|
on a share can be read by a Pi and a PC alike. The launcher works this out when
|
|
it runs rather than being told once, so the same directory is right for every
|
|
machine that opens it. On a Mac a universal build counts as native. Among the
|
|
builds this machine can run, the newest wins: `Singe-v3.10` beats
|
|
`Singe-v3.09`, and a beta loses to the release it leads up to, so
|
|
`Singe-v3.00b2` loses to `Singe-v3.00`. A build for another architecture is
|
|
still run when it is the only one there, since a real complaint from the engine
|
|
beats being told nothing was found, and so is a name the launcher cannot read
|
|
at all.
|
|
|
|
----
|
|
Singe/ Support files extracted by the engine
|
|
Framework.singe Loaded by every game (dofile it)
|
|
Menu.singe The bundled game menu
|
|
Tools.singe The menu's service tools (see The Service Tools)
|
|
MenuDocument.singe The menu drawn as a GUI document
|
|
MenuOverlay.singe The menu drawn into the overlay, for a machine with no GPU
|
|
Backdrop.singe The menu's intro and the grid behind it, drawn live
|
|
menuBackground.mkv The same backdrop recorded, for a machine with no GPU
|
|
menuIntro.flac Its sound, which fades out as the menu takes the screen
|
|
Menu.rml The document renderer's RmlUi document
|
|
menu.rcss Its style sheet, on top of gui.rcss
|
|
gui.rcss The shipped GUI theme
|
|
controls.cfg.example Template for input mappings
|
|
click.wav Used by the menu's audio delay and sound tests
|
|
Manual.pdf This manual
|
|
COPYING The GNU General Public License, version 3
|
|
LICENSES Third-party notices and asset credits
|
|
Collection/ A directory of games
|
|
games.dat Menu entries for the games in this directory
|
|
AsteroidPatrol.singe A script
|
|
frame_AsteroidPatrol.txt Its framefile (or a video with the same base name)
|
|
sprite_*.png, sound_*.wav, font_*.ttf
|
|
MyGame.game A game packed into one file (see Single-File Games)
|
|
data/
|
|
machine.cfg This machine's audio delay and picture geometry
|
|
Collection/ Indexes, trace.txt, screenshots, saves for those games
|
|
----
|
|
|
|
Where Singe looks for a script's files, and where a script may write, is a
|
|
matter for whoever writes the script; the Singe Reference covers both under
|
|
Packaging Your Game.
|
|
|
|
[#bundledmenu]
|
|
=== The Bundled Menu
|
|
|
|
`Menu.sh` (or `Menu.bat`) starts `Singe/Menu.singe`, the bundled menu: an
|
|
RmlUi document, `Singe/Menu.rml` styled by `Singe/menu.rcss`, drawn over a
|
|
live 3D backdrop (see xref:Reference.adoc#gui[GUI]). The menu runs without a
|
|
disc; a machine with no GPU plays `Singe/menuBackground.mkv`, a recording of
|
|
the same backdrop, behind a simpler page drawn on the overlay instead. It reads the `games.dat` of every game
|
|
directory and `.game` file beside it and lists every game it finds, sorted by
|
|
title, down the left of the screen. Beside the list are the selected game's
|
|
cabinet art, its marquee and its attract clip, with the year, genre,
|
|
platform, developer, publisher, port credits and description underneath and
|
|
a line of key hints along the bottom.
|
|
|
|
Up and down move the selection one game at a time and left and right move it
|
|
a page at a time; both wrap from either end of the list to the other. Start
|
|
or any action button launches the selected game, and the key mapped to
|
|
`INPUT_SERVICE` (the `9` key by default) opens the service tools (see
|
|
<<servicetools,The Service Tools>>). With a mouse, a
|
|
click on a row selects that game and a second click on the same row launches
|
|
it; the mouse wheel scrolls a description too long for its panel. If you set
|
|
`--quitchord`, holding those buttons quits a game back to the menu, and quits
|
|
the menu back to your system (see <<handhelds,Handhelds and Small Machines>>). The menu keeps its selection
|
|
in `menu.dat` in its data directory, so it comes back to the same game when
|
|
one quits or when Singe is next started. That file is a Lua fragment the menu
|
|
reads at startup and rewrites at shutdown: `GAME_SELECTED` is the game it was
|
|
showing, `SHOW_INTRO` is false when it is returning from a game so the intro
|
|
is not sat through twice, and `MENU_OVERLAY` chooses a renderer (see
|
|
<<menurenderers,The two renderers>>).
|
|
|
|
[#menurenderers]
|
|
==== The Two Renderers
|
|
|
|
A GUI document is drawn through the GPU device the 3D scene uses, so on a
|
|
machine without one there is no document to build. The menu handles that
|
|
itself: `Singe/Menu.singe` asks xref:Reference.adoc#singehasgpu[singeHasGpu] at startup and
|
|
loads one of two renderers.
|
|
|
|
`Singe/MenuDocument.singe`::
|
|
The RmlUi document described above, for a machine with a GPU device. It also
|
|
draws the intro and the grid behind the menu as one continuous 3D scene, so
|
|
the disc is not used for either.
|
|
|
|
`Singe/MenuOverlay.singe`::
|
|
Sprites and `fontPrint` straight into the overlay, the look Singe 2 had. It
|
|
needs nothing beyond the overlay every game already draws into.
|
|
|
|
Both draw the same menu, take the same keys and run the same service tools;
|
|
`Singe/Menu.singe` holds everything that is not drawing -- the game list, the
|
|
selection, launching a game -- so there is one menu rather than two. The
|
|
overlay renderer shows one game at a time instead of a list, since it has no
|
|
panel to scroll, and it clips a description too long for its column rather
|
|
than scrolling it.
|
|
|
|
To see the overlay renderer on a machine that does have a GPU, put
|
|
`MENU_OVERLAY = true` in `menu.dat` in the menu's data directory; the menu
|
|
writes the line back out, so it survives. That is how the overlay path is
|
|
tested, and how a cabinet builder who prefers the old look gets it.
|
|
|
|
[#onlineservice]
|
|
==== Online: Accounts, Games, and Scores
|
|
|
|
The bundled menu can sign the cabinet in to a master service (by default
|
|
`master.singeengine.com`), which does three things: it holds the account, it
|
|
offers a catalogue of games to download and update, and it keeps high score
|
|
boards.
|
|
|
|
Two service tools cover it. **Online Account** signs in, creates an account,
|
|
recovers a password, and sets the server address -- it is where an operator
|
|
running their own service points the cabinet. A new account is not usable until
|
|
the emailed link is opened. **Get Games** lists everything the
|
|
service offers, marks what is installed here, and downloads, updates or removes
|
|
it. The menu itself says when a newer version of an installed game exists: the
|
|
game wears an `update` mark in the list, the line under its details names the
|
|
version, and button 3 on that page fetches it, so a cabinet need not open a
|
|
service tool to stay current. Nothing about this machine is kept anywhere: the
|
|
menu reads the version out of each game's own `games.dat` and asks about its own
|
|
list, so a game copied in by hand is known as well as one downloaded here. A list longer than the screen scrolls with the selection rather than running
|
|
off the bottom, with `...` showing there is more either way. A game that stops being offered keeps working and is shown as "installed,
|
|
no longer offered": all that stops is being given an update, because a player
|
|
who has a game has it. A download is checked against the digest the catalogue published before it
|
|
replaces anything, so a transfer that arrives wrong fails rather than installing
|
|
a game that will not run.
|
|
|
|
The account belongs to the *machine*, not to a game: the token is kept in
|
|
`master.dat` in the data root, so a game posting a score uses the same sign-in
|
|
the menu made. See xref:Reference.adoc#onlinescores[Online high scores] for the game's side, and
|
|
`Singe/Net.singe` for the asynchronous HTTP client underneath -- nothing here
|
|
blocks a frame, because Lua in Singe is cooperative and a large download would
|
|
otherwise look like a hang.
|
|
|
|
[#servicetools]
|
|
==== The Service Tools
|
|
|
|
The key mapped to `INPUT_SERVICE` opens a list of tools over the game list.
|
|
Up and down choose one and button 1 opens it; button 2 backs out of a tool to
|
|
the list, and the service key again leaves the tools altogether. Everything
|
|
lives in `Singe/Tools.singe`, which the engine extracts beside `Menu.singe`.
|
|
Nothing there draws: a tool builds a list of rows and hands it to the menu,
|
|
which is why the same ten tools run on both renderers (see
|
|
<<menurenderers,The two renderers>>). Nothing here needs a game to be running,
|
|
and nothing changes a game's own files.
|
|
|
|
Audio Delay::
|
|
The downstream audio delay, measured against a click and a flash. See
|
|
xref:Reference.adoc#menucalibration[Calibrating from the menu] for what it is doing and why it
|
|
works.
|
|
|
|
Input Test::
|
|
Every controller, mouse and gun the engine can see, live: the last switch the
|
|
game would have received and how many have arrived, each pad's name with its
|
|
six axes and the buttons held down, and each mouse's name and position. This
|
|
is the screen that answers "the button does nothing" -- either the switch
|
|
arrives and the game ignores it, or it never arrives at all.
|
|
|
|
System Information::
|
|
The engine's version, the operating system, the processor and memory, the
|
|
renderer and the 3D device, which video decoders are in play, the audio
|
|
formats built in, the SoundFont, the MIDI state, the window, canvas and
|
|
overlay sizes, and the data directory. A photograph of this page answers most
|
|
of a bug report.
|
|
|
|
Light Gun::
|
|
Targets in the centre and at each corner of the overlay, over whatever the
|
|
disc is showing. Button 1 marks where the gun actually pointed, keeping the
|
|
last twelve shots; start clears them. A gun that is square on the picture puts
|
|
its crosses on the targets, and one that is not shows which way it is out.
|
|
|
|
Sound Test::
|
|
Button 1 plays the click through the left speaker, then the right, then both,
|
|
which is the whole of a crossed-wires check. It also lists the disc's own
|
|
audio tracks, and left and right switch between them.
|
|
|
|
Display::
|
|
The picture's size, position and rotation, changed live with the arrows,
|
|
buttons 3 and 4, and coin 1, over a test pattern: a 16 by 12 grid to square
|
|
the picture up with, an eight step greyscale wedge to set brightness by, and
|
|
two frames one pixel apart at the very edge -- a monitor that overscans eats
|
|
the outer one first. Button 1 keeps the values for this machine, in the same
|
|
`machine.cfg` the audio delay uses, so they apply to every game rather than
|
|
being set once per game. Start puts everything back.
|
|
|
|
Disc Test::
|
|
Twelve seeks spread over the whole disc, each timed. A rip whose keyframes are
|
|
far apart seeks slowly, and the only symptom in a game is that everything
|
|
feels heavy; this measures it directly and reports the worst of the twelve.
|
|
A seek that has not landed in three seconds is counted as that.
|
|
|
|
Saved Data::
|
|
What each game has kept, found by looking through the data root rather than by
|
|
being told, with the size of each. Button 3 -- not button 1, which is "choose"
|
|
everywhere else -- throws away the selected game's save. Clearing a high score
|
|
table without deleting the game is the usual reason.
|
|
|
|
Engine Update::
|
|
A newer Singe, when the service has one for this machine. A beta is versioned
|
|
`3.00b2`, the second beta of 3.00, and comes before 3.00 itself, so a cabinet
|
|
running a beta is offered the release the day it is published. Shows what is running
|
|
and what is offered, and button 1 fetches it, checks it against the digest the
|
|
service published, puts it beside the running Singe under the release's own
|
|
name, sets the old one aside as `old-<name>`, and restarts into it. Setting
|
|
the old one aside can be refused, by a folder this user cannot write or by a
|
|
scanner holding the file; the tool says so and carries on, since the launcher
|
|
runs the newest Singe in the folder either way. The new
|
|
Singe starts with `--refresh`, so the support folder is rewritten by the
|
|
version that now owns it and the old one is kept as `old-Singe-<version>`; a
|
|
file an older Singe shipped and this one does not cannot linger to confuse a
|
|
game. Nothing happens until that button. Button 3 asks the service again. The menu looks
|
|
once a day on its own and says so in a line under the game's details;
|
|
`no_update_check = true` in `settings.cfg` stops the daily look, and the tool
|
|
still works by hand.
|
|
|
|
Online Account::
|
|
Signing this cabinet in to the master service, creating an account, recovering a
|
|
password, and setting the server address. See
|
|
<<onlineservice,Online: accounts, games and scores>>.
|
|
|
|
Get Games::
|
|
The catalogue: what the service offers, what is installed here, and downloading,
|
|
updating or removing it.
|
|
|
|
MIDI Ports::
|
|
The input and output ports this machine has, which of them Singe has opened,
|
|
and the last few messages that arrived. Button 1 sends a note, button 3 looks
|
|
for ports again after something has been plugged in. Nothing is opened until
|
|
this tool asks, so a cabinet that never touches MIDI never pays for it.
|
|
|
|
Frame Statistics::
|
|
Turns the developer's overlay on and off. It stays on into the game, in the
|
|
top left corner. See xref:Reference.adoc#statsenable[statsEnable].
|
|
|
|
[[controls]]
|
|
== Controls
|
|
|
|
By default, Singe maps controllers as if they were Xbox gamepads. If your
|
|
controller is not recognized or you wish to change the default mappings as they
|
|
appear to Singe, you can use the free SDL2 Gamepad Tool from
|
|
http://generalarcade.com/gamepadtool/.
|
|
|
|
[[controlscfg]]
|
|
=== controls.cfg
|
|
|
|
In addition to configuring your controller, you can remap all the input options
|
|
for Singe as a whole or for any individual game by using `controls.cfg` files.
|
|
When determining how inputs are mapped, Singe reads configuration settings in
|
|
the following order, and a later file replaces an earlier one input by input
|
|
(see <<configorder,Where Configuration Files Are Read From>>):
|
|
|
|
. The defaults from inside Singe.
|
|
. `controls.cfg` from the game's main script directory: what the game's author shipped.
|
|
. `controls.cfg` from the directory Singe was started in: the machine's own (the `Singe` directory holds a `controls.cfg.example` template you can copy).
|
|
. `controls.cfg` from the directory above the game's data directory.
|
|
. `controls.cfg` from the game's data directory: yours, for that one game.
|
|
|
|
You do not have to specify every option in a custom `controls.cfg` file. Feel
|
|
free to just provide the entries you want changed.
|
|
|
|
After installing Singe, you can find a sample input configuration file at
|
|
`<InstallDir>/Singe/controls.cfg.example`. To see the available configuration
|
|
options available to be used in this file, read through
|
|
`<InstallDir>/Singe/Framework.singe`.
|
|
|
|
`--keymapfile` names one file to read instead of making that search, which is
|
|
useful to a front end that wants no doubt about which mappings a game got.
|
|
|
|
Each `INPUT_` entry is a list, and any one thing in it works the switch. A list
|
|
inside that list is a chord: two to four keys or buttons held together, which
|
|
works the switch when the last of them goes down and lets go when any of them
|
|
comes up. A handheld with no Escape key quits on Select and Start together
|
|
this way:
|
|
|
|
[source,lua]
|
|
----
|
|
INPUT_QUIT = { SCANCODE.ESCAPE, { GAMEPAD_0.BUTTON_BACK, GAMEPAD_0.BUTTON_START } }
|
|
----
|
|
|
|
Each key or button in a chord keeps its own meaning too, so pressing Select and
|
|
Start to quit this way also drops a coin and presses Start on the way out.
|
|
|
|
If you want a way to quit that always works, use `--quitchord` instead. When
|
|
you press one of its buttons, Singe waits a quarter of a second for the rest
|
|
before doing anything else, so quitting does not drop a coin or press Start. A
|
|
game can turn its own quit key off, but it cannot turn off `--quitchord`.
|
|
|
|
[[devices]]
|
|
=== Every Device Is a Gamepad
|
|
|
|
Singe has one family of controller, `GAMEPAD_0` through `GAMEPAD_3`, and every
|
|
device it opens is in it. SDL calls a device a gamepad only when it has a
|
|
mapping for it, and an arcade encoder board, a spinner, a wheel or a flight
|
|
stick often has none. Rather than carry a second kind of device with its own
|
|
names, Singe writes a mapping for such a device itself and then opens it as an
|
|
ordinary gamepad, so it reaches `controls.cfg`, `controllerGetAxis`,
|
|
`controllerGetButton` and every `INPUT_*` switch exactly as a recognised pad
|
|
does.
|
|
|
|
The mapping Singe writes is a straight-through one: the device's axes in order
|
|
become the left stick, the right stick and then the two triggers; its buttons
|
|
in order become `BUTTON_A`, `BUTTON_B`, `BUTTON_X`, `BUTTON_Y`, `BUTTON_BACK`,
|
|
`BUTTON_GUIDE`, `BUTTON_START`, `BUTTON_LEFT_STICK`, `BUTTON_RIGHT_STICK`,
|
|
`BUTTON_LEFT_BUMPER` and `BUTTON_RIGHT_BUMPER`; and its first hat becomes the
|
|
D-pad. A device with no hat spends its next four buttons on the D-pad instead.
|
|
**A device with more controls than the gamepad model can name loses the
|
|
extras** -- more than six axes, more than fifteen buttons, or a second hat --
|
|
and a device whose buttons are not wired in that order will have them in the
|
|
wrong places. That is the price of one family instead of two, and it is
|
|
straightforward to correct: `--program` traces the mapping it wrote, in SDL's
|
|
own format, so you can paste it into a `gamecontrollerdb.txt`, rearrange it and
|
|
have it used instead.
|
|
|
|
`--mapjoysticks=false` turns the writing off, in which case a device SDL does
|
|
not recognise is not opened at all, exactly as in earlier releases.
|
|
|
|
[[gamecontrollerdb]]
|
|
=== gamecontrollerdb.txt
|
|
|
|
SDL ships with a large database of controller mappings, and the community keeps
|
|
a larger one -- `gamecontrollerdb.txt`, from
|
|
https://github.com/mdqinc/SDL_GameControllerDB. Singe looks for that file in
|
|
the same four places it looks for `controls.cfg`, in the same order (see
|
|
<<configorder,Where Configuration Files Are Read From>>):
|
|
|
|
. the game's main script directory;
|
|
. the directory Singe was started in;
|
|
. the directory above the game's data directory;
|
|
. the game's data directory.
|
|
|
|
Every file found is loaded, in that order, so the machine's file wins over one
|
|
a game ships, a file in the game's data directory wins over both, and all of
|
|
them win over SDL's own database. Only a device that
|
|
none of them names gets the mapping Singe writes for it, so the order of
|
|
precedence is: SDL's built-in database, then your `gamecontrollerdb.txt`, then
|
|
the synthetic mapping. `--program` reports how many mappings each file added.
|
|
|
|
The files also beat `SDL_GAMECONTROLLERCONFIG`, the environment variable SDL
|
|
takes mappings from, which some handheld systems set for their built-in pad.
|
|
ArkOS's mapping for the R36S, for instance, leaves Select and Start out, so no
|
|
game sees them; a line in `gamecontrollerdb.txt` for the same pad puts them
|
|
back. SDL reads the variable once, when Singe starts, so this holds for the
|
|
files the first game finds. A game started later from the menu still reads its
|
|
own, but a pad the variable names keeps the variable's mapping.
|
|
|
|
A line of that file looks like this, and is exactly what the trace prints for a
|
|
device Singe mapped itself:
|
|
|
|
----
|
|
ff00d87a475300004900000000007603,Arcade Encoder,platform:Linux,a:b0,b:b1,x:b2,y:b3,back:b4,guide:b5,start:b6,leftx:a0,lefty:a1,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,
|
|
----
|
|
|
|
|
|
[[deadzones]]
|
|
=== Dead Zones and Triggers
|
|
|
|
`DEAD_ZONE` in `controls.cfg` is how far an axis must move before it counts as
|
|
a pressed switch, in the raw units SDL reports: `32767` at full deflection, so
|
|
the default of `15000` is a little under half way. It covers every axis of
|
|
every pad, the two analogue triggers included, and a script reads it as
|
|
`SINGE_DEAD_ZONE`.
|
|
|
|
Two settings narrow that down.
|
|
|
|
`DEAD_ZONES` is a list of `{ axis, dead zone }` pairs for one axis at a time,
|
|
in those same raw units, for a stiff stick or a worn trigger that should not
|
|
move everything else:
|
|
|
|
[source,lua]
|
|
----
|
|
DEAD_ZONES = {
|
|
{ GAMEPAD_0.AXIS_LEFT_X, 8000 },
|
|
{ GAMEPAD_1.AXIS_LEFT_TRIGGER, 30000 },
|
|
}
|
|
----
|
|
|
|
The axis may be written as the axis itself or as either of its two directions
|
|
(`GAMEPAD_0.AXIS_LEFT_X`, `AXIS_LEFT_X_L` and `AXIS_LEFT_X_R` all name the same
|
|
axis). Anything not listed keeps `DEAD_ZONE`.
|
|
|
|
`TRIGGER_THRESHOLD` is how far an analogue trigger must travel before it counts
|
|
as a button, as a *per cent of full travel*, which is the unit Hypseus's
|
|
`-trigger-threshold` uses and whose default there is `99.5`. It applies to both
|
|
triggers of all four pads. Singe's default is `0`, meaning the triggers stay on
|
|
`DEAD_ZONE`, so nothing changes for anyone who does not ask; a script reads the
|
|
result in raw units as `SINGE_TRIGGER_THRESHOLD`. The two units convert
|
|
directly: a per cent is `32767 / 100` raw units, so Singe's `DEAD_ZONE` of
|
|
`15000` is `45.8` per cent and Hypseus's `99.5` per cent is `32603` raw units.
|
|
`--trigger_threshold` sets the same number from the command line and wins over
|
|
`controls.cfg`; `DEAD_ZONES` wins over both, being the most specific.
|
|
|
|
[[joymouse]]
|
|
=== Driving the Mouse with a Stick
|
|
|
|
A light gun game on a cabinet with a stick and no mouse is unplayable unless
|
|
the stick can move the cursor. `--joymouse` makes it do so: the **left stick of
|
|
gamepad slot 0** moves the pointer the game sees, through the same
|
|
`onMouseMoved` a real mouse reaches, and the cursor is held inside the picture.
|
|
`--js_range` is the speed, `1` to `20` with `5` the default, measured in video
|
|
pixels a frame at full deflection, so `5` crosses a 720 pixel picture in about
|
|
two seconds. The axis obeys its own dead zone, so a drifting stick does not
|
|
creep.
|
|
|
|
It is off by default, which is where Singe differs from Hypseus: the shipped
|
|
`controls.cfg` already binds that stick to `INPUT_UP`, `INPUT_DOWN`,
|
|
`INPUT_LEFT` and `INPUT_RIGHT`, and having it drive the cursor as well without
|
|
being asked would surprise every existing game. `--joymouse=false` is
|
|
Hypseus's `-nojoymouse`, and a script turns it on and off with `joyMouseEnable`
|
|
and reads it with `joyMouseIsEnabled`. A reload puts it back where the command
|
|
line left it.
|
|
|
|
[[mousedevices]]
|
|
=== Mice, Guns, and Who Chooses
|
|
|
|
`mouseSetMode(MOUSE_MANY)` is a game's decision to tell up to four mice apart,
|
|
which a two gun cabinet needs and which a game that never makes the call cannot
|
|
be given. `--manymouse` is the user's decision and outranks it: the mode is on
|
|
from the start and `mouseSetMode(MOUSE_SINGLE)` no longer switches it off.
|
|
|
|
`--absolutes_only` keeps only the devices that report an absolute position,
|
|
which is what a real light gun does and an ordinary mouse does not, so a
|
|
cabinet with two guns and a desk mouse plugged in is not confused by the mouse.
|
|
Be aware of how it decides: **ManyMouse, the backend Singe uses to tell mice
|
|
apart, offers no way to ask a device what kind it is**, so a device counts as
|
|
absolute once it has reported an absolute position and not before. A gun does
|
|
that with its first movement; until then it is silent, and a relative-only
|
|
device stays silent for good. The option is therefore a filter by observed
|
|
behaviour rather than by device class, and on a machine where no device ever
|
|
reports an absolute position it silences every mouse.
|
|
|
|
`SWITCH_MOUSE_DISCONNECT` is a switch like any other, except that no key or
|
|
button produces it: the engine raises it when a mouse or a light gun is
|
|
unplugged, once as a press and once as a release, so a gun game can say so on
|
|
screen instead of appearing to have died. It is Hypseus's switch of the same
|
|
name. `controls.cfg` leaves it bound to nothing; bind a key to it as well if
|
|
you want to see what a game does without pulling a cable.
|
|
|
|
[[hotkeys]]
|
|
=== Hotkeys
|
|
|
|
`Alt-Enter` switches between full screen and a window while the game runs, as
|
|
it does in Hypseus. The game never sees the key. A window that started in
|
|
exclusive full screen (`--fullscreen`) returns to it in the display mode it was
|
|
given; one that started windowed gets a borderless window covering the desktop.
|
|
Nothing else has to change with it: the renderer presents a logical size in
|
|
video coordinates and scales that to whatever the window now is, the video
|
|
rectangle is built in those same coordinates, and the rotation target is the
|
|
size of the picture rather than of the window, so the picture, the overlay, the
|
|
GUIs and the mouse mapping all follow by themselves.
|
|
|
|
The other switches a user can press -- quit, pause, screenshot, the console and
|
|
the mouse capture toggle -- are ordinary `controls.cfg` mappings and are
|
|
described with the `INPUT_*` names in the sample file.
|
|
|
|
== Settings and Options
|
|
|
|
Almost everything you can put on the command line can also go in a settings
|
|
file. Set things up once and every game uses them.
|
|
|
|
[[settings]]
|
|
=== The Settings File
|
|
|
|
Everything on the command line can also be written down once, in a
|
|
`settings.cfg` file, so a cabinet does not need a launcher script carrying the
|
|
same dozen options for every game. It is Lua, like `controls.cfg`, and Singe
|
|
looks for it in exactly the same four places, in this order:
|
|
|
|
. `settings.cfg` from the game's main script directory.
|
|
. `settings.cfg` from the directory Singe was started in (the `Singe` directory holds a `settings.cfg.example` template you can copy).
|
|
. `settings.cfg` from the directory above the game's data directory.
|
|
. `settings.cfg` from the game's data directory.
|
|
|
|
Each place is read once, and a later file wins key by key, so a machine-wide
|
|
file can set the display and the volumes while a file in one game's data
|
|
directory turns off that game's crosshair. You do not have to write every key
|
|
in a file; write the ones you want changed.
|
|
|
|
Every key is the long name of a command line option with the leading dashes
|
|
removed, so there is no second vocabulary to learn:
|
|
|
|
[source,lua]
|
|
----
|
|
-- The cabinet's own settings.cfg
|
|
screen = 2 -- the second monitor
|
|
fullscreen = true
|
|
volume_vldp = 80
|
|
haptic = 0 -- this cabinet has no rumble
|
|
idleexit = 900 -- hand the screen back after fifteen quiet minutes
|
|
startsilent = true
|
|
----
|
|
|
|
An option that takes no value on the command line takes `true` or `false` here
|
|
(`yes`, `no`, `on`, `off`, `1` and `0` are accepted too). Setting one to `false`
|
|
is the same as leaving it out. An option that takes a value takes the same value
|
|
it would on the command line, as a number or a string.
|
|
|
|
One option, `--deterministic`, takes a value or leaves it out, and its key does
|
|
the same: `deterministic = true` uses the default step, `deterministic = 20`
|
|
names one, and `deterministic = false` leaves the option off.
|
|
|
|
[[configorder]]
|
|
=== Where Configuration Files Are Read From
|
|
|
|
`controls.cfg`, `settings.cfg` and `gamecontrollerdb.txt` are all looked for in
|
|
the same four places, in the same order, and a file read later wins over one
|
|
read earlier:
|
|
|
|
. *The game's main script directory,* which for a packed game is inside its
|
|
`.game` file. This is what the game's author shipped, so it is read first:
|
|
it sets the game's defaults and nothing more.
|
|
. *The directory Singe was started in.* The machine's own files, such as a
|
|
handheld's button layout, go here, and they win over what a game ships. A
|
|
file only replaces what it names, so to take a game's binding off a button,
|
|
name that input: `INPUT_TEST_MODE = { SCANCODE.F2 }` in the machine's
|
|
`controls.cfg` leaves test mode on the keyboard only, whatever button a game
|
|
put it on.
|
|
. *The directory above the game's data directory,* for files shared by every
|
|
game using that data directory.
|
|
. *The game's data directory.* Your own files for one game, which win over
|
|
everything else.
|
|
|
|
Without `--datadir` the data directory can be the game's own directory, in
|
|
which case the file there is read once, as the game's. `--keymapfile` replaces
|
|
the whole search for `controls.cfg` with one named file.
|
|
|
|
=== What Wins
|
|
|
|
. The built in default.
|
|
. The settings file.
|
|
. The game's `games.dat` entry, for the handful of settings it carries (see xref:Reference.adoc#gamesdat[games.dat]).
|
|
. `machine.cfg`, for the audio delay and the picture geometry the service tools
|
|
save (see <<servicetools,The Service Tools>>).
|
|
. The command line, which always wins.
|
|
|
|
A settings file is a set of defaults, in other words, not something you typed:
|
|
if a `games.dat` entry gives a game a resolution or a Sinden border, that entry
|
|
still describes the game better than a machine-wide file does. Anything actually
|
|
typed on the command line beats both. `machine.cfg` sits just under the command
|
|
line because somebody adjusted the picture while looking at this monitor, which
|
|
is better evidence than any file written elsewhere; the audio delay is the
|
|
exception to the ordering entirely, being added to the game's delay rather than
|
|
replacing it.
|
|
|
|
Options that name the game (`--framefile`, `--disc`, `--entry`), name a
|
|
directory (`--gamedir`, `--datadir`), or have to act before the file could be
|
|
found (`--help`, `--apiversion`, `--noconsole`, `--pack`, `--patch`,
|
|
`--unpack`) cannot be set in a settings file. A key that is not an option, one
|
|
of those, or a value the option will not take is an error naming the file and
|
|
the key, so a typo is never silently ignored:
|
|
|
|
----
|
|
settings.cfg: volume_vldpp is not an option.
|
|
settings.cfg: datadir cannot be set here; it belongs on the command line.
|
|
settings.cfg: Display scale must be between 25 and 100 percent.
|
|
----
|
|
|
|
With `--program` or `--trace`, the header at the top of `trace.txt` lists every
|
|
setting that was applied, so there is never a question about which file a
|
|
running game was given.
|
|
|
|
[[commandlineoptions]]
|
|
=== Command Line Options
|
|
|
|
----
|
|
Singe [OPTIONS] gameName
|
|
----
|
|
|
|
The game name is the only required argument. It may be a `.singe` script, a
|
|
directory containing a script of the same name (`MyGame` finds
|
|
`MyGame/MyGame.singe`), or a packed game (`MyGame.game` runs the first
|
|
entry of the `games.dat` inside it, `--entry=N` another). A script or directory
|
|
launched this way also runs with its `games.dat` entry when one names it (see
|
|
xref:Reference.adoc#gamesdat[games.dat]), so a game plays the same from the command line as from
|
|
the menu. For a laserdisc game (`--disc`) with no
|
|
`--framefile`, Singe looks for a video next to the script with the same base
|
|
name and any extension FFmpeg can demux, then for a `.txt` framefile.
|
|
|
|
The options are grouped by what they do.
|
|
|
|
==== The Game and Its Files
|
|
|
|
Which game runs, where it and its data live, and what it is played on.
|
|
|
|
[cols="1,2",options="header"]
|
|
|===
|
|
| Option | Purpose
|
|
| `-C`, `--canvas=WxH` | World size for a game without a disc, default 720x480. Ignored when there is a disc.
|
|
| `-d`, `--datadir=PATHNAME` | Directory for everything Singe writes: video indexes, `trace.txt`, screenshots, saves, the menu's `menu.dat`. A subdirectory named for the game's directory is created inside it (for a packed game, one named for the database and then for the script's directory inside it). Defaults to `data` in the game directory. Singe 2.x wrote beside the game instead; game directories may be read only, so nothing is written there any more.
|
|
| `-D`, `--disc` | Play a laserdisc video: the one named by `--framefile`, or the video found next to the script. Implied by `--framefile`. Without it a video next to the script is reported and ignored.
|
|
| `-E`, `--entry=N` | Run the Nth entry of the `games.dat` inside a `.game` file (default 1). See xref:Reference.adoc#singlefile[Single-File Games].
|
|
| `-v`, `--framefile=FILENAME` | Video file or framefile to use instead of the one found next to the script.
|
|
| `-G`, `--gamedir=PATHNAME` | The directory holding the games, the packed `.game` files and the `Singe` support folder, when the executable lives somewhere else. It becomes the working directory, so the game name, a relative `--datadir` and the packer's names all count from it; absolute paths work as they are. Defaults to the current directory.
|
|
| `-c`, `--showcalculated` | Print the frame ranges of every segment of a framefile, for debugging.
|
|
|===
|
|
|
|
==== Display
|
|
|
|
The window and how the picture fills it.
|
|
|
|
[cols="1,2",options="header"]
|
|
|===
|
|
| Option | Purpose
|
|
| `-a`, `--aspect=N:D` | Force the aspect ratio used to pick a window size (`4:3`, `16:9`, `16:10`).
|
|
| `-f`, `--fullscreen` | Exclusive full screen at the desktop resolution.
|
|
| `-w`, `--fullscreen_window` | Borderless window covering the desktop.
|
|
| `--linearscale=BOOLEAN` | Smooth the overlay as the window scales it (`true`) or take the nearest pixel (`false`, which keeps pixel art crisp). Takes `true`, `false`, `yes`, `no`, `on`, `off`, `1` or `0`. A script changes it while running with `setOverlayLinearScale`. Default: `true`, which is what every Singe release has drawn; Hypseus's own default is the opposite.
|
|
| `-k`, `--nologos` | Skip the splash screens.
|
|
| `-r`, `--rotate=DEGREES` | Turn the whole presentation clockwise by `0`, `90`, `180` or `270` degrees, for a cabinet whose panel is mounted on its side. The video, the overlay, the GUIs, the 3D scene and the particles all turn together, a quarter turn swaps the shape of the picture so a portrait window is filled, and mouse and light gun positions are turned back so a click still lands where it is drawn. Only the four right angles are accepted. A script may change it with `vldpSetRotate`.
|
|
| `--screen=N` | Open the window on display `N`, counting from `1` as Hypseus counts them. A number larger than the number of displays lists the displays that are there and exits. Default: the primary display.
|
|
| `-u`, `--stretch` | Stretch the video to fill the window instead of keeping its aspect ratio.
|
|
| `-x`, `--xresolution=VALUE` | Window width. The height is taken from the matching entry of the built in resolution table when omitted. A size larger than the display -- asked for here or by a game's `games.dat` -- is shrunk to fit it, keeping its shape, and the trace says so.
|
|
| `-y`, `--yresolution=VALUE` | Window height.
|
|
|===
|
|
|
|
==== Picture Placement, Bezels and Guns
|
|
|
|
For a cabinet: where the picture sits, the artwork around it, and the border a Sinden gun tracks. See <<cabinet,Setting Up a Cabinet>>.
|
|
|
|
[cols="1,2",options="header"]
|
|
|===
|
|
| Option | Purpose
|
|
| `-B`, `--bezel=FILENAME` | Draw cabinet artwork around the picture. The file is looked for in the `bezels` folder of the game directory (a packed game may carry its own) and then in the `bezels` folder of the data directory; `--bezeldir` names a different folder. Any format SDL_image reads will do, and transparency is kept. A sidecar beside it says where the picture goes inside it; with none, the picture keeps the whole window and `--shiftx`, `--shifty` and `--scalefactor` place it. Artwork that cannot be found ends the program. See <<bezels,Bezels>>.
|
|
| `-I`, `--bezeldir=PATHNAME` | The folder holding `--bezel`'s artwork, in place of `bezels`. Relative to the game directory, or absolute. Only that folder is searched. See <<bezels,Bezels>>.
|
|
| `-F`, `--bezelflip` | Draw the bezel artwork in front of the picture instead of behind it, which is what Hypseus does with its own bezels; the artwork's transparency is then the hole the game shows through. Without it the artwork is behind everything and the picture covers its cutout. A script chooses whether the overlay and the GUIs stay above the artwork with `setOverlayOnTop`. See <<bezels,Bezels>>.
|
|
| `-b`, `--scalefactor=PERCENT` | Shrink the picture about its centre to `PERCENT` (`25` to `100`) of the window for displays that lose their edges to overscan. Mouse and light gun positions follow the shrunken picture. A script may change it while the game runs with `vldpSetScale`. Combines with `--shiftx`, `--shifty`, `--rotate` and `--sindengun`; see <<videorect,The Video Rectangle>>.
|
|
| `-X`, `--shiftx=PERCENT` | Move the picture horizontally inside the room `--scalefactor` left it, `-100` (hard against the left) to `100` (hard against the right), `0` centred. As in Hypseus, the shift is a percentage of that room and nothing more, so at `--scalefactor=100` there is no room and the shift does nothing: reduce the scale first. See <<videorect,The Video Rectangle>>.
|
|
| `-Y`, `--shifty=PERCENT` | Move the picture vertically inside the room `--scalefactor` left it, `-100` (hard against the top) to `100` (hard against the bottom), `0` centred. It does nothing at full scale, for the same reason. See <<videorect,The Video Rectangle>>.
|
|
| `-S`, `--sindenedge=WHERE` | Where the Sinden border sits: `video` draws it around the picture, `window` at the edge of the screen. Without the option a bezel decides: artwork around the picture puts the border at the window's edge, because the gun's camera sees the whole screen, and with no artwork it goes around the picture as it always has. At the window's edge the two rings are drawn as rings, last of all, so the artwork between them and the picture stays visible. See <<bezels,Bezels>>.
|
|
| `-g`, `--sindengun='PARAMS'` | Draw the border a Sinden light gun tracks and map mouse and light gun positions into the picture inside it: the black ring, when one is given, runs along the edge of the video, the white ring sits inside it, and the game is drawn in the middle. `PARAMS` is one quoted list of numbers: `WW` (white border width in video pixels); `WW WB` (white width, then a black border outside it); `RW GW BW WW` (a custom border color and width); `RW GW BW WW WB` (the same plus a black width); or `RW GW BW WW RB GB BB WB` (custom colors and widths for both). A border that leaves no room for the game (twice the white and black widths together reaching the smaller side of the video), or a negative width, ends the program with a message. The rings are drawn around whatever `--shiftx`, `--shifty` and `--scalefactor` left, so a border stays a border however the picture is placed; see <<videorect,The Video Rectangle>>.
|
|
|===
|
|
|
|
==== Sound
|
|
|
|
[cols="1,2",options="header"]
|
|
|===
|
|
| Option | Purpose
|
|
| `--altaudio=SUFFIX` | Play `<base><SUFFIX>.ogg` beside the disc's video instead of the audio inside it, for a release whose other languages ship as separate files: `--altaudio=-es` next to `game.m2v` plays `game-es.ogg`. Every segment of a framefile is switched together. A file that is not there leaves the game's own audio playing and prints a warning. The `AUDIO_SUFFIX` key in `games.dat` does the same for one game, and a script changes it while running with `discAudioSuffix`. Default: none.
|
|
| `-o`, `--audio=TRACK` | Default audio track (zero based) for videos with several, such as multi-language releases.
|
|
| `-A`, `--audiodelay=MS` | Compensate for audio that is heard `MS` milliseconds later than the engine can measure (negative when it is heard early), `-1000` to `1000`. See xref:Reference.adoc#audiosync[Audio Sync].
|
|
| `-s`, `--nosound` | Mute all audio.
|
|
| `--soundfont=FILE` | The SoundFont (`.sf2`) MIDI files are synthesised with. Singe ships none, because a good one is tens of megabytes for a format almost no game uses. Without this option it looks for `Singe/soundfont.sf2` -- so a packed game can carry its own -- and then in the places a distribution installs one. The `SoundFont:` line of the trace header says which was used, or that none was found. See xref:Reference.adoc#midi[MIDI]. Default: the search.
|
|
| `--startsilent` | Start muted and stay muted until the first input of any kind, then play at the configured volumes. For an attract cabinet in a quiet room. `--nosound` outranks it. Default: off.
|
|
| `-e`, `--volume_nonvldp=PERCENT` | Sound effect and extra video volume, `0` to `100`.
|
|
| `-l`, `--volume_vldp=PERCENT` | Laserdisc volume, `0` to `100`.
|
|
|===
|
|
|
|
==== Input
|
|
|
|
See <<controls,Controls>>.
|
|
|
|
[cols="1,2",options="header"]
|
|
|===
|
|
| Option | Purpose
|
|
| `--absolutes_only` | Keep only the mice that report an absolute position, which is what a real light gun does and an ordinary mouse does not. ManyMouse cannot be asked what a device is, so a device counts as absolute once it has reported an absolute position and not before; see <<mousedevices,Mice, Guns, and Who Chooses>>. Hypseus writes it `-absolutes-only`; the name here uses an underscore because a settings file key has to be a Lua name. Default: off.
|
|
| `--gamepad_reorder=DIGITS` | Which physical pad fills which gamepad slot, as enumeration positions counting from `0`, one for each slot in turn: `--gamepad_reorder=10` makes the second pad found player one and the first player two. Written as bare digits (`3210`) or separated by commas or spaces, as Hypseus writes it; a repeated position is refused. Positions not named fill the slots that are left, in the order SDL found them, and a position with no pad behind it leaves its slot empty. Default: SDL's own order.
|
|
| `--haptic=STEP` | The strongest rumble step a game may use, `0` to `4`. `0` turns rumble off altogether, and a lower number quietens a game that asks for more: `controllerDoRumble` never rumbles harder than this. Default: `4`, which is every step a game asks for.
|
|
| `--joymouse=BOOLEAN` | Let the left stick of gamepad slot `0` drive the mouse cursor, for a light gun game on a cabinet with no mouse. `--joymouse=false` is Hypseus's `-nojoymouse`, and a script sets it with `joyMouseEnable()`. See <<joymouse,Driving the Mouse With a Stick>>. Default: `false`, where Hypseus's default is on -- the shipped `controls.cfg` already binds that stick to the four directions.
|
|
| `--js_range=SPEED` | How fast that stick drives it, `1` to `20`, in video pixels a frame at full deflection. Default: `5`, as in Hypseus.
|
|
| `--keymapfile=FILENAME` | Read the control mappings from this file instead of searching the four places for `controls.cfg`, so a front end can be certain which mappings a game got. The built in defaults still apply underneath it, so a partial file still works, and a file that is not there ends the program. Default: the four place search, described in <<controls,Controls>>.
|
|
| `--manymouse` | Tell up to four mice apart whatever the game asks for, which a two gun cabinet needs from a game that never calls `mouseSetMode(MOUSE_MANY)` itself. The user's choice outranks the game's: `mouseSetMode(MOUSE_SINGLE)` no longer switches it off. Default: off, and the game decides.
|
|
| `--mapjoysticks=BOOLEAN` | Write a gamepad mapping for a device SDL does not recognise, so an arcade encoder, a spinner, a wheel or a flight stick is opened as `GAMEPAD_0` to `GAMEPAD_3` like anything else. `false` leaves such a device unopened, as earlier releases did. See <<devices,Every Device Is a Gamepad>>. Default: `true`.
|
|
| `-n`, `--nocrosshair` | Ask the game not to draw its own crosshair. Exposed to scripts as `singeWantsCrosshairs()`.
|
|
| `--nogamepad` | Ignore every gamepad, the counterpart of `--nomouse`. None is opened and no pad event reaches the game, so a stuck arcade encoder cannot press anything. Default: off.
|
|
| `-m`, `--nomouse` | Disable mouse and lightgun input entirely.
|
|
| `--quitchord=BUTTONS` | Buttons on the first gamepad that quit when held together, whatever the game maps and even when it has turned its quit key off: the way out on a handheld with no keyboard. A game quits back to the menu it was started from, and the menu quits Singe. Two to four of SDL's gamepad button names joined by `+`, such as `back+start` (Select and Start); the names are `a`, `b`, `x`, `y`, `back`, `guide`, `start`, `leftstick`, `rightstick`, `leftshoulder`, `rightshoulder`, `dpup`, `dpdown`, `dpleft` and `dpright`, as the pad's mapping gives them, and `--program` traces the name of every button pressed. A press of one of the chord's buttons waits a quarter of a second for the rest before it does what it normally does, so Start does not launch a game from the menu on the way to quitting it. Belongs in the machine's `settings.cfg`. Default: none.
|
|
| `--trigger_threshold=PERCENT` | How far an analogue trigger must travel before it counts as a button, as a per cent of full travel -- Hypseus's unit, whose own default is `99.5`. `0` leaves the triggers on `DEAD_ZONE`, which is what Singe has always given them. Wins over `TRIGGER_THRESHOLD` in `controls.cfg`; `DEAD_ZONES` wins over both. `0` to `100`; see <<deadzones,Dead Zones and Triggers>>. Default: `0`.
|
|
| `--xratio=FACTOR` | The horizontal scale a light gun game reads with `ratioGetX()` to stretch its own gun coordinates for a display whose shape does not match the video. Singe does nothing with it; the game does the arithmetic, exactly as in Hypseus. `0` to `100`, kept to two decimals as Hypseus keeps it. Default: `0`, which every game that reads it treats as `1`.
|
|
| `--yratio=FACTOR` | The same for `ratioGetY()`. Default: `0`.
|
|
|===
|
|
|
|
==== Video Decoding and Performance
|
|
|
|
Mostly for small machines; see <<handhelds,Handhelds and Small Machines>>.
|
|
|
|
[cols="1,2",options="header"]
|
|
|===
|
|
| Option | Purpose
|
|
| `--deinterlace=MODE` | What an interlaced picture gets: `auto` (the default) deinterlaces only the frames the file marks interlaced, `on` deinterlaces every frame for a file whose flags are wrong, and `off` never touches the picture. A laserdisc held interlaced fields and a rip that kept them combs on a progressive display; a rip that was deinterlaced when it was made needs nothing here. One picture comes out for each one that goes in, so frame numbers never move. Default: `auto`.
|
|
| `--monochrome` | Start with the disc picture in grey. The overlay, the GUIs and the 3D scene keep their colour; a script does the same with `vldpSetMonochrome`, and undoes it. Default: off.
|
|
| `--scenequality=LEVEL` | How much the 3D scene draws: `high`, everything a game asks for, or `low` for a small GPU -- a handheld or an early Raspberry Pi -- which draws the scene at half resolution each way and leaves off antialiasing and bloom whatever the game asks. The 3D picture is softer and bright things have no glow, and it runs much faster where the GPU was the limit; the disc, the overlay and the GUIs are untouched. Belongs in the machine's `settings.cfg` rather than on a game's command line, since it describes the machine. Default: `high`.
|
|
| `-H`, `--softwarevideo` | Decode video in software even when the platform offers a hardware decoder (VA-API or VDPAU on Linux, the V4L2 decoder on the Pi, D3D11VA on Windows, VideoToolbox on macOS). Use it to rule the hardware path in or out when a video misbehaves; the program trace says which decoder is in use.
|
|
| `--zerocopy=BOOLEAN` | Hand hardware decoded video frames straight to the GPU instead of copying them through the CPU: Rockchip's MPP decoder and VA-API on Linux, drawn with OpenGL ES. It saves most of the cost of full screen video on a small machine. Singe falls back to copying by itself when the driver will not take a frame, or when a game reads or changes the picture's pixels, and the program trace says which it is doing; `false` makes it copy from the start, to rule this path in or out. Default: `true`.
|
|
|===
|
|
|
|
==== Cabinets and Front Ends
|
|
|
|
[cols="1,2",options="header"]
|
|
|===
|
|
| Option | Purpose
|
|
| `--apiversion` | Print one machine readable line describing this build to standard output and exit, for front ends. See <<apiversion,The Version Line>>. Nothing else is printed.
|
|
| `--fvalue=NUMBER` | One number handed from the launcher to the game, which reads it with `getFValue()`. Singe does nothing with it. `0` to `100000`, kept to three decimals as Hypseus keeps it. Default: `0`.
|
|
| `-h`, `--help` | Show the option summary and exit.
|
|
| `--idleexit=SECONDS` | Quit after `SECONDS` with no input of any kind -- no key, no button, no pad axis, no mouse. For an attract cabinet that should hand the screen back. `0` never quits. `0` to `86400`. Default: `0`.
|
|
| `--no_update_check` | Never ask the service whether a newer Singe exists. The menu otherwise looks once a day and shows what it found under the game's details; the Engine Update tool still works by hand. Default: off, so the daily look happens.
|
|
| `-z`, `--noconsole` | Print nothing (and open no console window on Windows).
|
|
| `--refresh` | Set the `Singe` support folder aside as `old-Singe-<version>`, named for the version that wrote it, and write a fresh one. For upgrading: a file an older release shipped and this one does not is left in the folder that was set aside rather than sitting in the live one. Nothing is deleted, and a second run sets its own aside as `old-Singe-<version>-1`. The Engine Update tool passes this to the Singe it restarts into.
|
|
|===
|
|
|
|
==== Making and Testing Games
|
|
|
|
See <<troubleshooting,When Something Goes Wrong>> for the traces.
|
|
|
|
[cols="1,2",options="header"]
|
|
|===
|
|
| Option | Purpose
|
|
| `--deterministic[=MS]` | For testing only: ignore real time and run the whole engine on a virtual clock that moves `MS` milliseconds every frame, so the same frame number always means the same moment. The disc follows the virtual clock too, its frames lasting the time they are worth, and the random generators are seeded from the same number, so a run repeats to the pixel. The value is optional and is both the step and the seed, `1` to `1000`. Default when given without one: `15`, the frame time the engine's own rate implies. Audio and pacing are meaningless in this mode; see xref:Reference.adoc#deterministic[Deterministic Test Mode]. Default: off.
|
|
| `-P`, `--pack=DIRECTORY` | Pack the game in `DIRECTORY` into the database named after the options, then exit. See xref:Reference.adoc#singlefile[Single-File Games].
|
|
| `-T`, `--patch=GAME.game` | Replace files in the packed game from the directory or patch database named after the options, then exit.
|
|
| `--perfsync` | With `--program`, wait for the GPU to finish each stage of a frame before timing the next, so the perf lines say which stage the GPU's time belongs to rather than leaving it all in `present`. Everything runs slower while it is on, so it is for measuring, not for playing; see <<perflines,Reading the Perf Lines>>. Default: off.
|
|
| `-p`, `--program` | Trace engine activity to the console and to `trace.txt` in the data directory. The file opens with a header describing the machine; see xref:Reference.adoc#traceheader[The Trace Header]. Every five seconds it also says where the frame's time went; see <<perflines,Reading the Perf Lines>>.
|
|
| `-R`, `--reload` | Watch the game's loose script files and run the game again from scratch when one changes; `F5` does the same on demand. A script that fails to compile stays watched, so saving the fix reloads it. For working on a game; see Reloading While You Work.
|
|
| `-t`, `--trace` | Trace every Lua API call, with the script line that made it, to the console and to `trace.txt`. The file opens with a header describing the machine; see xref:Reference.adoc#traceheader[The Trace Header].
|
|
| `-U`, `--unpack=GAME.game` | Write the packed game's files into the directory named after the options, then exit. A database whose stored names would land outside that directory is refused.
|
|
|===
|
|
|
|
Options may be given as `-x 640`, `-x640`, or `--xresolution=640`. Numeric
|
|
values are validated; a bad value prints the usage text and exits. Newer options
|
|
have no short letter; the alphabet ran out, and a letter picked at random would
|
|
help nobody.
|
|
|
|
Anything here except the options that name the game, name a directory, or must
|
|
act before a file can be found may also be set in a settings file, so a cabinet
|
|
does not need a launcher script for every game. See <<settings,The Settings
|
|
File>>.
|
|
|
|
[[apiversion]]
|
|
=== The Version Line
|
|
|
|
`--apiversion` prints one line and exits with status `0`:
|
|
|
|
----
|
|
singe version=3.00 protocol=1
|
|
----
|
|
|
|
This is a contract for front ends and will not change shape:
|
|
|
|
* The line ends with a newline and is the only thing written to standard
|
|
output. Nothing else is printed, whatever else is on the command line.
|
|
* The first field is always `singe`.
|
|
* Every field after it is `key=value`, separated by one space, with no spaces
|
|
inside a field.
|
|
* `version` is the release, the same number the banner shows.
|
|
* `protocol` is the version of this line's format. It becomes `2` only if the
|
|
rules above ever have to change.
|
|
* Later releases may add fields. A reader must ignore keys it does not know
|
|
rather than treating them as an error.
|
|
|
|
[[cabinet]]
|
|
== Setting Up a Cabinet
|
|
|
|
Arcade cabinets need a few things a desktop does not: moving the picture away
|
|
from edges the monitor hides, turning it for a sideways screen, artwork around
|
|
it, a border for a Sinden light gun, and a scoreboard. You only need this
|
|
chapter if you are building a cabinet. Set these once in the cabinet's
|
|
`settings.cfg`, or use the Display tool in the menu (see
|
|
<<servicetools,The Service Tools>>) to adjust the picture while you look at it.
|
|
|
|
[[videorect]]
|
|
=== The Video Rectangle
|
|
|
|
Everything a game shows -- the disc, the overlay, the GUIs, the 3D scene and
|
|
the particles -- is drawn into one rectangle, and a handful of options decide
|
|
where that rectangle is. They apply in this order:
|
|
|
|
. *The window, or the bezel's cutout.* The rectangle starts as the whole
|
|
window. Singe works in the video's own coordinates and lets the window
|
|
letterbox them (`--stretch` fills instead), so nothing here depends on the
|
|
window's size. When `--bezel` loaded artwork that declares a cutout, the
|
|
rectangle starts as that hole instead and everything below places the picture
|
|
inside it; see <<bezels,Bezels>>.
|
|
. *`--scalefactor`.* The rectangle shrinks to that percentage of what it
|
|
started as, about its own centre.
|
|
. *`--shiftx` and `--shifty`.* The rectangle then moves inside the room the
|
|
scale left, `-100` hard against one side and `100` hard against the other,
|
|
which is what Hypseus's own `-shiftx` and `-shifty` mean. Two consequences
|
|
follow from that and are worth knowing: the picture can never be pushed off
|
|
the screen, and *at `--scalefactor=100` there is no room and a shift does
|
|
nothing at all*. To move the picture on a badly mounted panel, reduce the
|
|
scale first: `--scalefactor=90 --shiftx=-100` puts the shrunken picture hard
|
|
against the left.
|
|
. *`--sindengun`.* The border is applied last, to whatever the shift and the
|
|
scale left. The black ring takes the rectangle's edge, the white ring sits
|
|
inside it, and the game goes inside both, so a border is still a border
|
|
however the picture was placed. A scale small enough to leave no room for the
|
|
game squeezes the two rings rather than swallowing it. With bezel artwork
|
|
loaded the border goes to the window's edge instead and leaves the picture the
|
|
size it already was; `--sindenedge` decides it either way.
|
|
|
|
`--rotate` is not part of that order. The frame is drawn unrotated and the
|
|
finished picture is turned clockwise as a whole, so a shift moves the picture
|
|
along the video's own axes and turns with it. A quarter turn also swaps the
|
|
shape of the presented area, so a portrait window is filled rather than
|
|
letterboxed into a strip.
|
|
|
|
Mouse and light gun positions travel the same path backwards: the rotation
|
|
comes off first, and the position then maps into the rectangle, so a click
|
|
lands where the player sees it under any combination of these options.
|
|
`vldpGetScale`, `vldpSetScale`, `vldpGetRotate` and `vldpSetRotate` let a
|
|
script move the scale and the rotation while the game runs; the shift is a
|
|
display setting and has no script call. None of them is a `games.dat` key:
|
|
like `--scalefactor`, they describe the player's screen, not the game.
|
|
|
|
[[bezels]]
|
|
=== Bezels
|
|
|
|
A bezel is the artwork around an arcade cabinet's screen. Singe draws one from a
|
|
single image file, with the game's picture in a hole cut out of it, and can show
|
|
an arcade scoreboard in the space that leaves. Three options control it, and
|
|
they follow Hypseus's own convention so a cabinet's command line moves across
|
|
unchanged.
|
|
|
|
`--bezel cabinet.png` names the artwork. It is looked for in this order:
|
|
|
|
. `bezels/cabinet.png` in the game directory -- inside a packed `.game`, its own
|
|
copy, so a game can carry its bezel with it;
|
|
. `bezels/cabinet.png` in the data directory, where a user's own artwork can
|
|
live without touching a read-only game directory.
|
|
|
|
`--bezeldir art/cabinets` replaces the `bezels` folder with the one it names,
|
|
relative to the game directory or absolute, and then only that folder is
|
|
searched. Any format SDL_image reads will do (`.png` is the sensible choice,
|
|
because transparency matters). Artwork the option names and Singe cannot find
|
|
ends the program rather than running without it.
|
|
|
|
The artwork is drawn over the whole window, whatever shape either of them is, so
|
|
it stretches with the window exactly as the picture does. Give it the aspect
|
|
ratio you expect to play at.
|
|
|
|
==== The Cutout
|
|
|
|
Beside the image, and named after it, a sidecar file says where the picture
|
|
goes: `bezels/cabinet.png` is described by `bezels/cabinet.cfg`. It is a Lua
|
|
file, as `controls.cfg` is, and sets one table in the artwork's *own pixels*:
|
|
|
|
[source,lua]
|
|
----
|
|
-- The hole in cabinet.png the picture is drawn in, in the artwork's own pixels.
|
|
CUTOUT = { x = 200, y = 120, width = 800, height = 500 }
|
|
----
|
|
|
|
All four fields are required and the rectangle must lie inside the artwork; a
|
|
sidecar that will not run, or that names a rectangle outside the image, ends the
|
|
program with a message. Because the numbers are the artwork's own, they stay
|
|
right at any window size: the image and the hole are scaled together.
|
|
|
|
With a cutout, the picture is drawn in that hole -- stretched to it, so the hole
|
|
decides the shape of the picture -- and `--scalefactor`, `--shiftx` and
|
|
`--shifty` then work *inside* it, shrinking and nudging the picture in the hole.
|
|
With no sidecar the picture keeps the whole window, exactly as it does with no
|
|
bezel, and those three options place it as they always have. See
|
|
<<videorect,The Video Rectangle>>.
|
|
|
|
The hole itself should be transparent in the image. Singe draws the artwork
|
|
behind the picture by default, so an opaque middle would simply be covered, but
|
|
`--bezelflip` puts the artwork in front and then only its transparency lets the
|
|
game through.
|
|
|
|
==== Draw Order
|
|
|
|
Without `--bezelflip` the artwork is the first thing in the frame: the picture,
|
|
the overlay, the GUIs, the 3D scene and the particles all draw over it. With
|
|
`--bezelflip` the artwork draws in front of the picture instead, which is the
|
|
order Hypseus uses for its own bezels, so a frame with soft or shaped edges
|
|
overlaps the picture properly.
|
|
|
|
A script decides what happens to the overlay in that case:
|
|
xref:Reference.adoc#setoverlayontop[`setOverlayOnTop(true)`] draws the overlay and the GUIs above
|
|
the artwork, and `false` (the default, and Hypseus's) leaves the artwork on top
|
|
of them. With the artwork behind the picture the setting changes nothing,
|
|
because everything is already above it.
|
|
xref:Reference.adoc#mainbezelloaded[`mainBezelLoaded()`] tells a script whether artwork is loaded
|
|
and gives it the artwork's identifier, the same number Hypseus reports, so a
|
|
game written for a particular bezel can recognise it.
|
|
|
|
Screen space GUIs and the score panel always draw above the artwork, since the
|
|
point of them is to sit on it.
|
|
|
|
==== The Sinden Border
|
|
|
|
A Sinden light gun watches the screen for a bright border. With bezel artwork
|
|
loaded that border belongs at the *edge of the window*, not around the picture,
|
|
because the gun's camera sees the whole screen, so that is where `--sindengun`
|
|
puts it as soon as a bezel is loaded. There it is drawn as two rings, after
|
|
everything else, so the artwork between the border and the picture stays visible
|
|
and nothing paints over the white ring. With no bezel the border goes around the
|
|
picture, as it always has, and shrinks it.
|
|
|
|
`--sindenedge video` or `--sindenedge window` overrides that choice in either
|
|
direction: a gun cabinet whose artwork is only a thin frame may still want the
|
|
border around the picture, and a cabinet with no artwork at all may want it at
|
|
the screen's edge.
|
|
|
|
==== The Score Panel
|
|
|
|
Sixteen of the Hypseus Singe games can drive an arcade scoreboard: credits, and
|
|
a score and a life count for each of two players. In Singe that scoreboard is
|
|
the RmlUi document `Singe/scoreBezel.rml`, styled by `Singe/scoreBezel.rcss`,
|
|
both written beside the other support files and both replaceable -- a theme or a
|
|
game may restyle the panel by editing them, exactly as it may restyle
|
|
`Singe/gui.rcss`. The shipped style is a seven segment look: every readout shows
|
|
its digits dimly lit behind the live value, the way a real display does.
|
|
|
|
The panel is *off* until a game asks for it with
|
|
xref:Reference.adoc#scorebezelenable[`scoreBezelEnable(true)`], which is how Hypseus ships as
|
|
well, so a game that never asks behaves exactly as before and draws its own
|
|
scoreboard with sprites. xref:Reference.adoc#scorebezelgetstate[`scoreBezelGetState()`] is the
|
|
question every such game asks first.
|
|
|
|
Where it goes is decided for you: the panel takes the deeper of the bands the
|
|
picture leaves above and below it -- the room a bezel's cutout usually leaves --
|
|
centred on the picture, and lies along the bottom of the picture when neither
|
|
band is deep enough to hold it. It is drawn as a screen space GUI, so a game may
|
|
put its own GUIs on the artwork beside it with
|
|
xref:Reference.adoc#guidrawscreen[`guiDrawScreen`].
|
|
|
|
Hypseus's `scoreBezelEnable` takes a second argument choosing among its five
|
|
scoreboard backends. Singe has one, so the argument is accepted and ignored.
|
|
|
|
[[handhelds]]
|
|
== Handhelds and Small Machines
|
|
|
|
Singe runs on the Raspberry Pi and on inexpensive ARM handhelds like the R36S.
|
|
The same games work there as on a desktop, but a small machine needs a little
|
|
help to run them well.
|
|
|
|
=== What a Small Machine Needs
|
|
|
|
Sprites, text, sound, and video work everywhere. The 3D scene and the menu's
|
|
fancy look need a graphics chip with Vulkan or OpenGL ES 3.1.
|
|
|
|
* A Raspberry Pi 4 or later has both, so everything works. A Pi 3 only has
|
|
OpenGL ES 2.0, which is not enough for 3D. It still runs 2D games.
|
|
* Most handhelds, the R36S included, have a Mali graphics chip with OpenGL ES
|
|
3.1, so 3D works there too.
|
|
* On a machine without either, the menu uses a simpler look that does not need
|
|
them.
|
|
|
|
The first time you run a 3D game, Singe builds its shaders, which can take a
|
|
few seconds on a small machine. They are saved in the `Singe` folder inside the
|
|
data directory, so this only happens once.
|
|
|
|
=== Settings for a Small Machine
|
|
|
|
Put these in the `settings.cfg` beside the Singe binary so every game uses
|
|
them:
|
|
|
|
`scenequality = "low"`::
|
|
Draws the 3D scene at half size, without antialiasing or bloom. 3D looks a
|
|
little softer, but runs much faster. Video, sprites, and menus are not
|
|
affected.
|
|
|
|
`zerocopy = true`::
|
|
This is already the default. Video goes from the hardware decoder straight to
|
|
the graphics chip without the CPU copying it. This is what lets a handheld play
|
|
laserdisc video at full speed. Only turn it off if a video misbehaves and you
|
|
want to rule it out.
|
|
|
|
`quitchord = "back+start"`::
|
|
Handhelds do not have an Escape key. Holding Select and Start quits the game
|
|
back to the menu, and quits the menu back to your system, no matter how the
|
|
game is set up.
|
|
|
|
=== The R36S and ArkOS
|
|
|
|
The R36S and similar handhelds running ArkOS use the Linux `aarch64` build of
|
|
Singe. Put the Singe binary, its `Singe` folder, `Menu.sh`, and your games in
|
|
one folder, such as `/roms/singe`. Run `Menu.sh` once so Singe can create its
|
|
support files.
|
|
|
|
To start Singe from the Ports menu, add a script like the one below to
|
|
`/roms/ports`. These handhelds are slow to speed up their processor and
|
|
graphics chip, so the script sets them to full speed while Singe runs and puts
|
|
them back when it exits.
|
|
|
|
[source,bash]
|
|
----
|
|
#!/bin/bash
|
|
# /roms/ports/Singe.sh: Singe in the Ports menu.
|
|
SINGE_DIR=/roms/singe
|
|
|
|
[ "$(id -u)" -eq 0 ] && ESUDO="" || ESUDO="sudo"
|
|
GOVERNORS=()
|
|
for g in /sys/devices/system/cpu/cpufreq/policy*/scaling_governor /sys/class/devfreq/*/governor; do
|
|
[ -f "$g" ] || continue
|
|
GOVERNORS+=("$g:$(cat "$g")")
|
|
echo performance | $ESUDO tee "$g" > /dev/null 2>&1
|
|
done
|
|
restore() {
|
|
for entry in "${GOVERNORS[@]}"; do
|
|
echo "${entry##*:}" | $ESUDO tee "${entry%:*}" > /dev/null 2>&1
|
|
done
|
|
}
|
|
trap restore EXIT
|
|
|
|
cd "$SINGE_DIR" || exit 1
|
|
./Menu.sh "$@"
|
|
----
|
|
|
|
ArkOS does not tell games about the Select and Start buttons, so the quit chord
|
|
will not work until you add this `gamecontrollerdb.txt` beside the Singe binary
|
|
(see <<gamecontrollerdb,gamecontrollerdb.txt>>):
|
|
|
|
----
|
|
1900bb3e4b4800000011000000010000,GO-Super Gamepad,a:b0,b:b1,x:b2,y:b3,back:b12,start:b13,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpdown:b9,dpleft:b10,dpright:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,
|
|
----
|
|
|
|
If a button does not do what you expect, run Singe once with `--program` and
|
|
press it. The trace shows the name of each button you press, or its number if
|
|
the mapping above does not include it.
|
|
|
|
Finally, add a `controls.cfg` beside the Singe binary. This one puts coin and
|
|
start on Select and Start, and keeps a game's test and service menus off the
|
|
face buttons, where some games put them.
|
|
|
|
[source,lua]
|
|
----
|
|
INPUT_1P_COIN = { SCANCODE.MAIN_5, SCANCODE.C, GAMEPAD_0.BUTTON_BACK }
|
|
INPUT_1P_START = { SCANCODE.MAIN_1, GAMEPAD_0.BUTTON_START }
|
|
INPUT_PAUSE = { SCANCODE.P }
|
|
INPUT_SCREENSHOT = { SCANCODE.F12, SCANCODE.F11 }
|
|
INPUT_SERVICE = { SCANCODE.MAIN_9 }
|
|
INPUT_TEST_MODE = { SCANCODE.F2 }
|
|
----
|
|
|
|
This file wins over the one a game includes (see
|
|
<<configorder,Where Configuration Files Are Read From>>). Pause and screenshot
|
|
are moved to the keyboard because Singe normally puts them on Start and
|
|
Select.
|
|
|
|
[[troubleshooting]]
|
|
== When Something Goes Wrong
|
|
|
|
=== The Trace
|
|
|
|
Run Singe with `--program` (or `-p`) to see what it is doing. Everything is
|
|
printed to the console and saved to `trace.txt` in the game's data directory.
|
|
If you report a problem, include `trace.txt` from a run with `--program`.
|
|
`--trace` (or `-t`) also logs every Lua call a game makes, which is mostly
|
|
useful when writing a game.
|
|
|
|
If Singe crashes on Linux or macOS, it writes where it crashed to the console
|
|
and to `trace.txt`.
|
|
|
|
`trace.txt` only has Singe's own messages. Messages from the sound system, the
|
|
video decoder, and the graphics driver only go to the console. When those might
|
|
be the problem, save the console too. On Linux:
|
|
|
|
----
|
|
./Menu.sh --program &> singe.log
|
|
----
|
|
|
|
[[perflines]]
|
|
=== Reading the Perf Lines
|
|
|
|
With `--program`, every five seconds the trace says where the time went, as
|
|
averages per trip round the frame loop:
|
|
|
|
----
|
|
Perf: 58.9 frames/s shown, 353 loops; per loop 13.1 ms (worst 82.3): disc 1.1, script 0.1, scene 0.0, gui 0.4, overlay 0.0, compose 0.0, present 11.4, other 0.1
|
|
Perf script: per loop 0.1 ms of Lua and 0.0 in engine calls it made; 0.0 in engine calls altogether: overlayClear 0.01 (0.8 calls), discGetFrame 0.00 (0.8 calls)
|
|
Video 3 perf: 23.8 frames/s decoded; per frame 0.5 ms, of which read back 0.0, convert 0.0
|
|
----
|
|
|
|
* `disc` -- advancing the laserdisc video and putting its frame on the GPU.
|
|
* `script` -- the game's `onOverlayUpdate`, which the `Perf script` line splits
|
|
into the Lua itself and the engine calls it made, costliest calls first.
|
|
* `scene` -- drawing the 3D scene.
|
|
* `gui` -- laying out and drawing the GUI documents.
|
|
* `overlay` -- sending what changed on the overlay to the GPU.
|
|
* `compose` -- only with `--perfsync`: the GPU drawing the picture, the
|
|
overlay and the GUIs together.
|
|
* `present` -- showing the frame, which includes waiting for the screen's next
|
|
refresh.
|
|
* `other` -- everything else: input, sound, physics and the rest.
|
|
|
|
A video's own line says how fast it decodes and how much of each frame went on
|
|
copying it back from the hardware decoder and converting its colours; zero for
|
|
both means its frames go to the GPU without being copied.
|
|
|
|
The GPU works behind the CPU, so without `--perfsync` its time lands wherever
|
|
the CPU next has to wait for it, which is usually `present`. A large `present`
|
|
at the display's full rate is only the wait for the refresh; a large `present`
|
|
below it means the GPU is busy. `--perfsync` makes each stage wait for the GPU
|
|
before the next starts, so `scene`, `gui`, `overlay` and `compose` include
|
|
their GPU time and `present` is left with the wait for the refresh. The frame
|
|
rate drops while it is on, because the CPU and the GPU no longer work at the
|
|
same time; read the stages against each other, not against the frame rate.
|
|
|
|
=== A Button Does Nothing
|
|
|
|
Open the Input Test tool in the menu (see <<servicetools,The Service Tools>>)
|
|
and press the button. If the tool sees it, the game is ignoring it, so check the
|
|
game's `controls.cfg`. If the tool does not see it, check your own
|
|
`controls.cfg`, or your controller's mapping in `gamecontrollerdb.txt`.
|
|
Running with `--program` shows every button as you press it.
|
|
|
|
=== Sound and Picture Are Out of Sync
|
|
|
|
Some televisions, receivers, and wireless speakers delay the sound. Use the
|
|
Audio Delay tool in the menu to measure the delay. Singe remembers it for every
|
|
game. See xref:Reference.adoc#audiosync[Audio Sync] for details.
|
|
|
|
For choppy or stuttering sound, see the Frequently Asked Questions.
|
|
|
|
== Frequently Asked Questions
|
|
|
|
*Why is it named Singe?*
|
|
|
|
Singe is the name of the dragon in Dragon's Lair. As Singe (the program) began
|
|
as an add-on to Daphne (the princess in Dragon's Lair) the Dragon's Lair theme
|
|
was kept.
|
|
|
|
*What is the difference between Daphne, Singe, Hypseus, and Singe 3.xx?*
|
|
|
|
Daphne is an actual laserdisc game emulator that can run a handful of classic
|
|
laser games. Daphne/Singe (Singe 1.xx) is the original version of Singe that
|
|
was an add-on for the Daphne emulator -- originally shipped as a game DLL for
|
|
Daphne, then later combined into a single binary with the Daphne emulation
|
|
features removed. Hypseus-Singe is an enhanced fork of Daphne with Singe 1.xx
|
|
and some Singe 2.xx support. Singe 2.xx is an all-new, built-from-scratch
|
|
upgrade of the original Singe, and Singe 3.xx builds on it with 3D, physics,
|
|
and much more. In short, if you want accuracy, use Daphne or Hypseus if they
|
|
support emulating the desired game. If it is a Singe game, use Singe, or try
|
|
Hypseus.
|
|
|
|
*Why should we not call it an "emulator"?*
|
|
|
|
Emulators use the real software or ROMs from the original game and pretend to
|
|
be the machine they were originally intended to run on. From the game's
|
|
perspective, it is business as usual. Singe, on the other hand, requires that
|
|
every game be re-implemented (ported) to run on Singe. The end result may be
|
|
very similar, but how it works is entirely different.
|
|
|
|
*Can I run Singe 1.xx and 2.xx games on Singe 3.xx?*
|
|
|
|
Yes, probably. Almost everything from Singe 1.xx has been converted and
|
|
enhanced for newer versions of Singe, and most Singe 2.xx games run as they
|
|
are. Games that use the older sprite functions may need a small change; see
|
|
xref:Reference.adoc#migrating[Migrating from Singe 2.10].
|
|
|
|
*Do I need a laserdisc game to use Singe?*
|
|
|
|
No. Games do not need a disc at all. They can use sprites, video, 3D, and
|
|
anything else Singe offers. See xref:Reference.adoc#withoutadisc[Games Without
|
|
a Disc].
|
|
|
|
*Why does the game I just installed not show in the menu?*
|
|
|
|
Whoever packaged the game failed to include a proper `games.dat` file.
|
|
|
|
*Why is HD video slow?*
|
|
|
|
It should not be any more. Singe now uses your video card to decode video when
|
|
your system supports it, even on the Raspberry Pi and many handhelds. If HD
|
|
video is still slow, your system may not have hardware video decoding, and
|
|
then high definition video requires a lot of CPU. Running with `--program`
|
|
shows which decoder Singe is using.
|
|
|
|
*Why does my audio stutter on Windows?*
|
|
|
|
Users have discovered that most Singe audio and stuttering problems are related
|
|
to their installed audio driver -- especially Realtek-based devices. Try
|
|
updating your sound drivers or switching to the generic Windows HD Audio
|
|
driver. Disable surround sound -- use stereo, not 5.1 or 7.1. If your drivers
|
|
do not allow you to use stereo, you can use Virtual Audio Cable to fix this:
|
|
|
|
. Install VB-CABLE (https://vb-audio.com/Cable/).
|
|
. Go to Windows sound settings (right-click sound on the taskbar, then
|
|
*Sounds*, then *Playback*).
|
|
. Right-click the *Cable Input* device and choose *Set as default device*.
|
|
(You will lose your current sound output temporarily.)
|
|
. Go to the *Recording* tab.
|
|
. Right-click *Cable Output*, then *Properties*, then *Listen*, and finally
|
|
*Enable Listen to This Device*. In the drop-down list, choose your actual
|
|
listening device.
|
|
. You should have sound again. Load up Singe and your audio will be working
|
|
and lag-free.
|
|
|
|
*Does 3D work on a Raspberry Pi or a handheld?*
|
|
|
|
On a Raspberry Pi 4 or later, yes. They have both a Vulkan driver and OpenGL
|
|
ES 3.1, and Singe uses whichever it finds. The Pi 3 has only OpenGL ES 2.0,
|
|
which cannot express the scene's skinning or morph targets, so it runs 2D games
|
|
(2D physics included) exactly as before and refuses the first 3D call. The Pi 4
|
|
is the minimum for any game that uses the 3D Scenes chapter. The same applies to
|
|
the cheap handhelds: a Mali-G31 or G610 has the ES 3.1 the scene needs, whether
|
|
or not it has Vulkan. See <<handhelds,Handhelds and Small Machines>>.
|
|
|
|
*Why does my audio stutter on the Raspberry Pi?*
|
|
|
|
The Raspberry Pi OS now uses Pipewire as the default audio backend. Switching
|
|
to PulseAudio seems to fix the issue:
|
|
|
|
. Run `sudo raspi-config` from a terminal window.
|
|
. Select *Advanced Options*.
|
|
. Select *Audio Config*.
|
|
. Select *PulseAudio*.
|
|
. Press kbd:[Tab], select *Ok*, and let it reboot.
|
|
|
|
|
|
== Making Games
|
|
|
|
This manual is about running Singe: installing it, installing games, setting up
|
|
a cabinet, and the menu. Making games is covered in three more books, which
|
|
are an optional download from the same place as Singe rather than part of it,
|
|
since together they are larger than the engine.
|
|
|
|
* The *Singe Reference* covers everything a game can do: the programming
|
|
model, the game directory, packing a game into one file, and every function
|
|
the engine offers, with its arguments, its return values, and an example.
|
|
* *Learn to Program with Singe* teaches programming from nothing, in thirty
|
|
lessons, to somebody who has never written code. It comes with the scripts
|
|
and the small art kit the lessons use.
|
|
* *Forge* is the authoring tool that makes a game from a description rather
|
|
than from code. Its book has ten tutorials and the vocabulary reference.
|
|
|
|
The download holds the three books as PDF and HTML, the lesson files, and the
|
|
licence. Forge itself is a separate download, since it is a Singe game in its
|
|
own right.
|