Merged the master branch into new-svg-renderer.
22
CHANGELOG.md
|
@ -22,7 +22,14 @@
|
|||
* Added ares standalone as an alternative emulator for many systems
|
||||
* Added MAME standalone as an alternative emulator for the gameandwatch system
|
||||
* Added openMSX standalone as an alternative emulator for the colecovision, msx, msx1, msx2 and msxturbor systems
|
||||
* (Linux) Added support for the Nintendo Wii U (wiiu) game system
|
||||
* (Linux) Added support for the Nintendo Wii U (wiiu) game system by adding the Cemu standalone emulator
|
||||
* (Linux) Added support for the Sega Model 3 (model3) game system by adding the Supermodel standalone emulator
|
||||
* (Linux) Added Supermodel standalone as an alternative emulator for the arcade and mame systems
|
||||
* Added support for the Sega Model 2 (model2) game system on Linux on macOS by adding the MAME - Current RetroArch core
|
||||
* Added MAME standalone as an alternative emulator for the model2 system
|
||||
* (Windows) Added the MAME - Current RetroArch core as an alternative emulator for the model2 system
|
||||
* (Windows) Added a -force-feedback option and an %INJECT% variable to the Supermodel emulator for the arcade, mame and model3 systems
|
||||
* Added a %GAMEDIR% variable to the -rompath option for all MAME standalone entries to allow launching games from subdirectories
|
||||
* Added Triforce (Dolphin fork) standalone as an alternative emulator for the gc system on Linux and Windows
|
||||
* Added simple64 standalone as an alternative emulator for the n64 system on Linux and Windows
|
||||
* (Linux) Added Rosalie's Mupen GUI standalone as an alternative emulator for the n64 system
|
||||
|
@ -33,6 +40,8 @@
|
|||
* (Windows) Changed the binary for emulator Citra from citra.exe to citra-qt.exe as the command line binary is broken on this OS
|
||||
* Added CPCemu standalone as an alternative emulator for the amstradcpc system
|
||||
* Added MAME standalone as an alternative emulator for the gx4000 system
|
||||
* Added the .car and .rom file extensions to the a5200 system
|
||||
* Added the .car file extension to the atari800 system
|
||||
* Added the .bin file extension to the gx4000 system
|
||||
* Added the .m3u file extension to the pcfx system
|
||||
* Removed the .7z and .zip file extensions from the 3do, neogeocd and neogeocdjp systems
|
||||
|
@ -40,7 +49,7 @@
|
|||
* Removed the .ccd, .cue and .iso file extensions from the neogeo system
|
||||
* Added the FinalBurn Neo RetroArch core as an alternative emulator for the neogeocd and neogeocdjp systems
|
||||
* Added MAME standalone as an alternative emulator for the neogeo, neogeocd and neogeocdjp systems
|
||||
* Added FinalBurn Neo standalone as an alternative emulator for the fbneo, neogeo, neogeocd and neogeocdjp systems on Unix
|
||||
* Added FinalBurn Neo standalone as an alternative emulator for the fbneo, neogeo, neogeocd and neogeocdjp systems on Linux
|
||||
* Added FinalBurn Neo standalone as an alternative emulator for the fbneo and neogeo system on Windows
|
||||
* Set DOSBox-X and DOSBox Staging to start in the game directory so per-game dosbox.conf files can be used
|
||||
* (macOS) Added an additional find rule entry for DOSBox-X as the binary name has been changed
|
||||
|
@ -56,6 +65,8 @@
|
|||
* OpenGL ES: Added an OpenGLVersion setting for choosing between OpenGL ES 3.0, 3.1 and 3.2 (has to be manually set in es_settings.xml)
|
||||
* Greatly improved the performance of shader post-processing such as scanlines and blur rendering
|
||||
* Greatly improved application startup speed by avoiding a lot of unnecessary SVG rasterizations
|
||||
* Implemented dynamic texture allocation to the font code to reduce memory usage and avoid missing glyphs
|
||||
* Large optimizations to the text wrapping code (generallly 300-400% faster)
|
||||
* Added support for texture mipmapping with trilinear filtering
|
||||
* Added on-demand texture loading to the carousel
|
||||
* Improved the renderer scaling accuracy
|
||||
|
@ -87,6 +98,7 @@
|
|||
* Added theme support for defining color saturation for images, videos and animations
|
||||
* Added theme support for defining the video fade-in time
|
||||
* Added theme support for enabling and disabling video pillarboxes and scanline rendering
|
||||
* Added theme support for defining the threshold for when pillarboxes should be applied to a video
|
||||
* Added theme support for enabling or disabling audio playback for videos
|
||||
* Added theme support for setting separate textColorDimmed and iconColorDimmed properties for the system and gamelist views
|
||||
* Added support for nesting of theme variables
|
||||
|
@ -179,7 +191,9 @@
|
|||
### Bug fixes
|
||||
|
||||
* Multiple levels of symlinking in the ROMs directory tree could crash the application on startup
|
||||
* For the cps system, MAME standalone was configured with the wrong system directory for the -rompath option, pointing to "arcade" instead of "cps"
|
||||
* During some menu operations that reloaded the gamelist view, the cached background could miss some components as they were not rendered in time
|
||||
* Text wrapping did not work correctly for text that typically does not contain spaces, like Japanese
|
||||
* Changing some values using the metadata editor could lead to an incorrect sort order if the changes were done from within a grouped custom collection
|
||||
* Changing the setting "Group unthemed custom collections" could lead to incorrect custom collections sorting under some circumstances
|
||||
* Games located in subdirectories were not added back to custom collections when disabling the "Exclude from game counter" metadata option
|
||||
|
@ -200,10 +214,14 @@
|
|||
* When a legacy theme set had a video view style but did not have a valid md_video entry then the video player would still start (and play the audio)
|
||||
* Clearing a game in the metadata editor would sometimes not remove all media files (if there were both a .jpg and a .png for a certain file type)
|
||||
* The tile property for the image element did not work correctly with SVG images
|
||||
* Defining an itemScale (logoScale) property lower than 1.0 for the carousel did not work correctly
|
||||
* Carousel text did not get scaled/multiplied correctly with the itemScale property (bug retained for legacy themes for maximum backward compatibility)
|
||||
* Letters would sometimes get rendered with ugly edge artifacts, visible when scaling text on the carousel
|
||||
* Text opacity did not work correctly in some places, such as for the help prompts
|
||||
* ScrollableContainer faded semi-transparent text to fully opaque when resetting
|
||||
* ScrollableContainer faded in the background text color in addition to the text color when resetting
|
||||
* Text elements that had an opacity set to lower than FF via the color tag were faded in during gamelist scrolling
|
||||
* The help system was rendered on top of menus if placed at such a location on the screen
|
||||
* Theme sets were not always sorted correctly (as seen when mixing uppercase and lowercase letters in theme names)
|
||||
* The SliderComponent knob was not consistently positioned
|
||||
* The device text flickered in GuiDetectDevice when configuring a controller
|
||||
|
|
|
@ -67,15 +67,17 @@ The roadmap is under constant review so expect it to change from time to time. S
|
|||
#### v2.0 (in progress)
|
||||
|
||||
* New theme engine with generalized views (only System and Gamelist) and theme variants support
|
||||
* Multiple new gamelist components (more carousel modes, grid component etc.)
|
||||
* Multiple new components (carousel support for the Gamelist view, grid component etc.)
|
||||
* Lottie animation (vector graphics) and GIF animation support
|
||||
* OpenGL ES 3.0 renderer for use on the Raspberry Pi
|
||||
* Replace the OpenGL fixed function pipeline with a shader-based renderer
|
||||
* Replace the OpenGL fixed function pipeline renderer with a shader-based renderer
|
||||
* Replace NanoSVG with a more capable SVG rendering library
|
||||
* Improve text and font functions, e.g. dynamic texture allocation and faster and cleaner text wrapping
|
||||
* Improve the performance of the GLSL shader post-processing
|
||||
|
||||
#### v2.1
|
||||
|
||||
* Add element transition animations to the theme engine
|
||||
* New texture/cache manager with improved memory management and support for GIF and Lottie animations
|
||||
* Reduced amount of gamelist reloading to retain cached textures and improve overall performance
|
||||
* Add scraping of game manuals and maps and create a viewer for these (with PDF, GIF, JPG and PNG support)
|
||||
|
@ -93,7 +95,8 @@ The roadmap is under constant review so expect it to change from time to time. S
|
|||
* Proper audio mixer
|
||||
* Checksum support for the scraper for exact searches and for determining when to overwrite files
|
||||
* Support for portrait orientation, e.g. for Tate Mode arcade cabinets
|
||||
* Improved text and font functions, e.g. faster and cleaner line wrapping and more exact sizing
|
||||
* Replace the built-in Unicode functions and lookup tables with those of the ICU library
|
||||
* Add text kerning support using the HarfBuzz library
|
||||
|
||||
#### v2.3
|
||||
|
||||
|
|
4
FAQ.md
|
@ -86,11 +86,11 @@ This release of RetroArch has multiple technical issues so it's not officially s
|
|||
|
||||
## How do I add more themes?
|
||||
|
||||
Most RetroPie EmulationStation theme sets will work with ES-DE, and there are numerous resources online on where to find these. How to install them is described in the _Themes_ section of the [User guide](USERGUIDE.md#themes). Just be aware that some of these themes do not include support for modern systems like PlayStation 3 and Nintendo Switch so those platforms may look a bit ugly depending on how the theme is written.
|
||||
Refer to the official list of [recommended theme sets](https://gitlab.com/es-de/themes/themes-list) for a selection of high-quality themes. There are also some brief instructions there on how to download and install them. More comprehensive documentation is available in the _Themes_ section of the [User guide](USERGUIDE.md#themes). In addition to the recommended theme sets you'll be able to find a lot of additional themes if doing a web search as almost all RetroPie-compatible themes can be used with ES-DE. Just be aware that many of these do not include support for modern systems like PlayStation 3 and Nintendo Switch so those platforms may look a bit ugly depending on how the theme has been written.
|
||||
|
||||
## The themes I've added don't seem to work?
|
||||
|
||||
Only RetroPie EmulationStation themes are supported, you can't use themes that were specifically developed for Batocera or Recalbox EmulationStation. A very few RetroPie themes like es-theme-carbon-2021 will not work either due to technical reasons.
|
||||
Only RetroPie EmulationStation themes are supported, you can't use themes that were specifically developed for Batocera or Recalbox EmulationStation. A very few RetroPie themes like es-theme-carbon-2021 will not work either due to technical reasons. Refer to the official list of [recommended theme sets](https://gitlab.com/es-de/themes/themes-list) for a selection of high-quality themes that have been thoroughly tested with ES-DE.
|
||||
|
||||
## I used to be a Batocera/Recalbox user and ES-DE can't seem to find some of my games?
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ With the new theme engine the view presets were removed and the only views now a
|
|||
|
||||
In addition to the variant support which provides an unlimited flexibility for creating custom theme profiles, support for specific aspect ratios was introduced. This makes it possible to define different theme configuration for different display aspect ratios and to provide the user with the option to choose between these from the _UI Settings_ menu. That could for example be choice between a 16:9 and a 4:3 layout, or perhaps also a vertical screen orientation layout in addition to these.
|
||||
|
||||
As well new theming abilities like Lottie animations were added with the new theme engine.
|
||||
As well new theming abilities like GIF and Lottie animations were added with the new theme engine.
|
||||
|
||||
The following are the most important changes compared to the legacy theme structure:
|
||||
|
||||
|
@ -95,6 +95,13 @@ Attempting to use any of the legacy logic in the new theme structure will make t
|
|||
|
||||
Except the points mentioned above, theme configuration looks pretty similar to the legacy theme structure, so anyone having experience with these older themes should hopefully feel quite at home with the new theme engine. Probably the most important thing to keep in mind is that as there are no longer any view presets available, some more effort is needed from the theme developer to define values for some elements. This is especially true for zIndex values as elements could now be hidden by other elements if care is not taken to explicitly set the zIndex for each of them. This additional work is however a small price to pay for the much more powerful and flexible theming functionality provided by the new theme engine.
|
||||
|
||||
Note that the legacy theme engine had quite inaccurate text sizing and font rendering and while this has been greatly improved in the new engine, for legacy themes most old bugs are retained for maximum backward compatibility. This means that you may need to revise font sizes and text placements when porting a legacy theme to the new engine. Here are some examples:
|
||||
|
||||
* Line spacing for the textlist element was not consistently applied across different screen resolutions
|
||||
* Carousel text entries did not multiply the font size by the itemScale (logoScale) property value
|
||||
* The defined line spacing was not always applied for automatically sized text elements
|
||||
* Font sizes were rounded to integers, leading to imprecise text sizing across different resolutions (the rounding was also done incorrectly)
|
||||
|
||||
## Simple example
|
||||
|
||||
Here is a very simple theme that changes the color of the game name text:
|
||||
|
@ -699,13 +706,14 @@ The `helpsystem` element does not really have a zIndex value and is always rende
|
|||
|
||||
## Theme variables
|
||||
|
||||
Theme variables can be used to simplify theme construction. There are 2 types of variables available.
|
||||
Theme variables can be used to simplify theme construction and there are two types available:
|
||||
|
||||
* System variables
|
||||
* Theme defined variables
|
||||
|
||||
### System variables
|
||||
|
||||
System variables are system specific and are derived from the values in es_systems.xml (except for collections).
|
||||
System variables are system specific and are derived from the values defined in es_systems.xml (except for collections which are derived from hardcoded application-internal values).
|
||||
* `system.name`
|
||||
* `system.name.collections`
|
||||
* `system.name.noCollections`
|
||||
|
@ -716,9 +724,35 @@ System variables are system specific and are derived from the values in es_syste
|
|||
* `system.theme.collections`
|
||||
* `system.theme.noCollections`
|
||||
|
||||
`system.name` expands to the short name of the system as defined by the `name` tag in es_systems.xml\
|
||||
`system.fullName` expands to the full system name as defined by the `fullname` tag in es_systems.xml\
|
||||
`system.theme` expands to the theme directory as defined by the `theme` tag in es_systems.xml
|
||||
|
||||
The `.collections` and `.noCollections` versions of these variables make it possible to differentiate between regular systems and collections. This can for example be used to apply different formatting to the names of the collections as opposed to regular systems. The below example capitalizes the names of the collections while leaving the regular systems at their default formatting (as they are defined in es_systems.xml). The reason this works is that the .collections and .noCollections variables are mutually exclusive, i.e. they can never both hold a value at the same time as a system is either a real system or a collection and never both.
|
||||
|
||||
```xml
|
||||
<view name="system">
|
||||
<text name="system_name, collection_name">
|
||||
<pos>0.05 0.83</pos>
|
||||
<size>0.9 0.06</size>
|
||||
<fontSize>0.06</fontSize>
|
||||
<fontPath>./core/font.ttf</fontPath>
|
||||
</text>
|
||||
<text name="collection_name">
|
||||
<letterCase>capitalize</letterCase>
|
||||
</text>
|
||||
<text name="system_name">
|
||||
<text>${system.fullName.noCollections}</text>
|
||||
</text>
|
||||
<text name="collection_name">
|
||||
<text>${system.fullName.collections}</text>
|
||||
</text>
|
||||
</view>
|
||||
```
|
||||
|
||||
### Theme defined variables
|
||||
Variables can also be defined in the theme.
|
||||
```
|
||||
```xml
|
||||
<variables>
|
||||
<themeColor>8B0000</themeColor>
|
||||
</variables>
|
||||
|
@ -726,19 +760,19 @@ Variables can also be defined in the theme.
|
|||
|
||||
### Usage in themes
|
||||
Variables can be used to specify the value of a theme property:
|
||||
```
|
||||
```xml
|
||||
<color>${themeColor}</color>
|
||||
```
|
||||
|
||||
It can also be used to specify only a portion of the value of a theme property:
|
||||
|
||||
```
|
||||
```xml
|
||||
<color>${themeColor}C0</color>
|
||||
<path>./core/images/${system.theme}.svg</path>
|
||||
````
|
||||
|
||||
Nesting of variables is supported, so the following could be done:
|
||||
```
|
||||
```xml
|
||||
<variables>
|
||||
<colorRed>8b0000</colorRed>
|
||||
<themeColor>${colorRed}</themeColor>
|
||||
|
@ -915,6 +949,10 @@ Properties:
|
|||
* `pillarboxes` - type: BOOLEAN
|
||||
- Whether to render black pillarboxes (and to a lesses extent letterboxes) for videos with aspect ratios where this is applicable. This is for instance useful for arcade game videos in vertical orientation.
|
||||
- Default is `true`
|
||||
* `pillarboxThreshold` - type: NORMALIZED_PAIR
|
||||
- Normally it doesn't look very good to add really narrow pillarboxes or letterboxes, so by default they are skipped if the actual video size is not reaching a threshold value as compared to the overall defined video area size. By modifying this property it's possible to control that threshold, as for some theme designs it will look better with the consistency of always rendering the pillarboxes/letterboxes even if they are narrow. To clarify, the default X axis value of 0.85 means that if the video width is 85% or less as compared to the X axis defined by the `size` property, then pillarboxes will be rendered. So setting the `pillarboxThreshold` value to `1 1` will always apply pillarboxes/letterboxes regardless of the video file dimension.
|
||||
- Minimum value per axis is `0.2` and maximum value per axis is `1`
|
||||
- Default is `0.85 0.90`
|
||||
* `scanlines` - type: BOOLEAN
|
||||
- Whether to use a shader to render scanlines.
|
||||
- Default is `false`
|
||||
|
@ -1209,7 +1247,9 @@ Properties:
|
|||
* `fontPath` - type: PATH
|
||||
- Path to a TrueType font (.ttf).
|
||||
* `fontSize` - type: FLOAT
|
||||
- Size of the font as a percentage of screen height (e.g. for a value of `0.1`, the text's height would be 10% of the screen height).
|
||||
- Size of the font as a percentage of screen height (e.g. for a value of `0.1`, the text's height would be 10% of the screen height). This calculation is based on the reference 'S' character so other glyphs may not fill this area, or they may exceed this area.
|
||||
- Minimum value is `0.001` and maximum value is `1.5`. Note that when running at a really low resolution, the minimum value may get clamped to a larger relative size. The font is allowed to overflow the height of the element by 100%, i.e. `fontSize` can be set to twice that of the y axis of the `size` property. Any value above that will be clamped.
|
||||
- Default is `0.045`
|
||||
* `horizontalAlignment` - type: STRING
|
||||
- Controls alignment on the X axis.
|
||||
- Valid values are `left`, `center` or `right`
|
||||
|
@ -1224,7 +1264,7 @@ Properties:
|
|||
- Valid values are `none`, `uppercase`, `lowercase` or `capitalize`
|
||||
- Default is `none` (original letter case is retained)
|
||||
* `lineSpacing` - type: FLOAT
|
||||
- Controls the space between lines (as a multiple of font height).
|
||||
- Controls the space between lines (as a multiple of the font height). Due to the imprecise nature of typefaces where certain glyphs (characters) may exceed the requested font size, it's recommended to keep this value at around `1.1` or higher for multi-line text fields. This way overlapping glyphs or characters being cut off at the top or bottom will be prevented.
|
||||
- Minimum value is `0.5` and maximum value is `3`
|
||||
- Default is `1.5`
|
||||
* `opacity` - type: FLOAT
|
||||
|
@ -1277,7 +1317,9 @@ Properties:
|
|||
* `fontPath` - type: PATH
|
||||
- Path to a TrueType font (.ttf).
|
||||
* `fontSize` - type: FLOAT
|
||||
- Size of the font as a percentage of screen height (e.g. for a value of `0.1`, the text's height would be 10% of the screen height).
|
||||
- Size of the font as a percentage of screen height (e.g. for a value of `0.1`, the text's height would be 10% of the screen height). This calculation is based on the reference 'S' character so other glyphs may not fill this area, or they may exceed this area.
|
||||
- Minimum value is `0.001` and maximum value is `1.5`. Note that when running at a really low resolution, the minimum value may get clamped to a larger relative size. The font is allowed to overflow the height of the element by 100%, i.e. `fontSize` can be set to twice that of the y axis of the `size` property. Any value above that will be clamped.
|
||||
- Default is `0.045`
|
||||
* `horizontalAlignment` - type: STRING
|
||||
- Controls alignment on the X axis.
|
||||
- Valid values are `left`, `center` or `right`
|
||||
|
@ -1348,7 +1390,9 @@ Properties:
|
|||
* `fontPath` - type: PATH
|
||||
- Path to a TrueType font (.ttf).
|
||||
* `fontSize` - type: FLOAT
|
||||
- Size of the font as a percentage of screen height (e.g. for a value of `0.1`, the text's height would be 10% of the screen height).
|
||||
- Size of the font as a percentage of screen height (e.g. for a value of `0.1`, the text's height would be 10% of the screen height). This calculation is based on the reference 'S' character so other glyphs may not fill this area, or they may exceed this area.
|
||||
- Minimum value is `0.001` and maximum value is `1.5`. Note that when running at a really low resolution, the minimum value may get clamped to a larger relative size. The font is allowed to overflow the height of the element by 100%, i.e. `fontSize` can be set to twice that of the y axis of the `size` property. Any value above that will be clamped.
|
||||
- Default is `0.045`
|
||||
* `color` - type: COLOR
|
||||
* `backgroundColor` - type: COLOR
|
||||
* `horizontalAlignment` - type: STRING
|
||||
|
@ -1482,12 +1526,12 @@ Properties:
|
|||
- Minimum value is `0` and maximum value is `20`
|
||||
- Default is `8`
|
||||
* `itemSize` - type: NORMALIZED_PAIR
|
||||
- Both axes need to be defined.
|
||||
- Size of the item prior to multiplication by the `itemScale` value, i.e. the size of all unselected items. Both axes need to be defined.
|
||||
- Minimum value per axis is `0.05` and maximum value per axis is `1`
|
||||
- Default is `0.25 0.155`
|
||||
* `itemScale` - type: FLOAT.
|
||||
- Selected item is increased in size by this scale.
|
||||
- Minimum value is `0.5` and maximum value is `3`
|
||||
- Minimum value is `0.2` and maximum value is `3`
|
||||
- Default is `1.2`
|
||||
* `itemTransitions` - type: STRING
|
||||
- How to render item transitions when navigating the carousel. By default a slide animation will be played when moving between items but if this property is set to `instant` instead then the transitions will be immediate.
|
||||
|
@ -1562,13 +1606,14 @@ Properties:
|
|||
* `fontPath` - type: PATH
|
||||
- Path to a TrueType font (.ttf) used as fallback if there is no `staticItem` / `itemType` image defined or found, and if `defaultItem` has not been defined.
|
||||
* `fontSize` - type: FLOAT
|
||||
- Size of the font as a percentage of screen height (e.g. for a value of `0.1`, the text's height would be 10% of the screen height).
|
||||
- Size of the font as a percentage of screen height (e.g. for a value of `0.1`, the text's height would be 10% of the screen height). This calculation is based on the reference 'S' character so other glyphs may not fill this area, or they may exceed this area. This property value is effectively multiplied by the `itemScale` value for the currently selected item (but if this property is omitted then the default value will not get multiplied by `itemScale`).
|
||||
- Minimum value is `0.001` and maximum value is `1.5`. Note that when running at a really low resolution, the minimum value may get clamped to a larger relative size.
|
||||
- Default is `0.085`
|
||||
* `letterCase` - type: STRING
|
||||
- Valid values are `none`, `uppercase`, `lowercase` or `capitalize`
|
||||
- Default is `none` (original letter case is retained)
|
||||
* `lineSpacing` - type: FLOAT
|
||||
- Controls the space between lines (as a multiple of font height).
|
||||
- Controls the space between lines (as a multiple of the font height). Due to the imprecise nature of typefaces where certain glyphs (characters) may exceed the requested font size, it's recommended to keep this value at around `1.1` or higher. This way overlapping glyphs or characters being cut off at the top or bottom will be prevented.
|
||||
- Minimum value is `0.5` and maximum value is `3`
|
||||
- Default is `1.5`
|
||||
* `fadeAbovePrimary` - type: BOOLEAN
|
||||
|
@ -1625,6 +1670,8 @@ Properties:
|
|||
- Secondary color; what this means depends on the text list. For example, for game lists, it is the color of a folder.
|
||||
* `fontPath` - type: PATH
|
||||
* `fontSize` - type: FLOAT
|
||||
- Size of the font as a percentage of screen height (e.g. for a value of `0.1`, the text's height would be 10% of the screen height). This calculation is based on the reference 'S' character so other glyphs may not fill this area, or they may exceed this area.
|
||||
- Default is `0.045`
|
||||
* `horizontalAlignment` - type: STRING
|
||||
- Controls alignment on the X axis.
|
||||
- Valid values are `left`, `center` or `right`
|
||||
|
@ -1636,7 +1683,7 @@ Properties:
|
|||
- Valid values are `none`, `uppercase`, `lowercase` or `capitalize`
|
||||
- Default is `none` (original letter case is retained)
|
||||
* `lineSpacing` - type: FLOAT
|
||||
- Controls the space between lines (as a multiple of font height).
|
||||
- Controls the space between lines (as a multiple of the font height).
|
||||
- Minimum value is `0.5` and maximum value is `3`
|
||||
- Default is `1.5`
|
||||
* `indicators` - type: STRING
|
||||
|
@ -1706,7 +1753,8 @@ Properties:
|
|||
- Default is the same value as iconColor.
|
||||
* `fontPath` - type: PATH
|
||||
* `fontSize` - type: FLOAT
|
||||
- This property also implicitly sets the icon size and is therefore the means to change the overall size of the helpsystem element.
|
||||
- This property implicitly sets the icon size and is therefore the means to change the overall size of the helpsystem element. This calculation is based on the reference 'S' character so other glyphs may not fill this area, or they may exceed this area.
|
||||
- Minimum value is `0.001` and maximum value is `1.5`. Note that when running at a really low resolution, the minimum value may get clamped to a larger relative size.
|
||||
- Default is `0.035`
|
||||
* `entrySpacing` - type: FLOAT
|
||||
- Spacing between the help element pairs.
|
||||
|
|
|
@ -664,7 +664,7 @@ RetroArch does not embed any version information into the filename so no wildcar
|
|||
|
||||
## Using manually downloaded emulators on Linux
|
||||
|
||||
Normally on Linux you would install emulators using either one of the established package formats, i.e. Flatpak, AppImage or Snap, or you would install them using the operating system repository. Less likely would be to build from source code and install to a standard system directory. In all these instances ES-DE should be able to find the emulator when launching a game. But in some rare cases you may instead manually download an emulator as an archive file to unzip somewhere on the file system. Normally you would want to place these files in your home directory, and if running a distribution that has an immutable filesystem (such as SteamOS), you don't even have the choice to install them to a standard system directory.
|
||||
Normally on Linux you would install emulators using either one of the established cross-distribution package formats, i.e. AppImage, Snap or Flatpak, or you would install them using the operating system repository (including the AUR if available on your OS). Less likely would be to manually build from source code and install to a standard system directory. In all these instances ES-DE should be able to find the emulator when launching a game. But in some rare cases you may instead manually download an emulator as an archive file to unzip somewhere on the file system. Normally you would want to place these files in your home directory, and if running a distribution that has an immutable filesystem (such as SteamOS or Fedora Silverblue), you don't even have the choice to install them to a standard system directory.
|
||||
|
||||
For these situations ES-DE looks for emulators in the same directories where it looks for AppImages (as explained in the section above), meaning:
|
||||
```
|
||||
|
@ -691,6 +691,7 @@ The following manually downloaded emulators are supported when using the bundled
|
|||
| flash | Lightspark | lightspark/lightspark |
|
||||
| flash | Ruffle | ruffle/ruffle |
|
||||
| fmtowns | Tsugaru | tsugaru/Tsugaru_CUI |
|
||||
| model3 | Supermodel | Supermodel/supermodel |
|
||||
| oric | Oricutron | oricutron/Oricutron |
|
||||
| pico8 | PICO-8 | pico-8/pico8 |
|
||||
| psvita | Vita3K | Vita3K/Vita3K |
|
||||
|
@ -908,15 +909,21 @@ Not all systems are as simple as described above, or there may be multiple ways
|
|||
|
||||
#### Arcade and Neo Geo
|
||||
|
||||
**General**
|
||||
|
||||
For all the supported MAME variants as well as Final Burn Alpha/FinalBurn Neo and Neo Geo, single file archives should be used. But these should retain the MAME names as filenames since ES-DE ships with MAME lookup tables, meaning the MAME names are expanded to the full game names.
|
||||
|
||||
For instance `topgunnr.7z` will be expanded to `Top Gunner`.
|
||||
|
||||
This is required by the TheGamesDB scraper where the expanded filenames are used for game searches. (Screenscraper natively supports searches using the MAME names). It's also quite nice to have the gamelist populated with the expanded game names even before any scraping has taken place.
|
||||
|
||||
By default ES-DE will filter out BIOSes and devices that can't be launched directly, meaning these will never show up in the gamelist. But this only applies to files that are listed in the regular MAME driver file and BIOSes and devices for systems like MESS and Model 2 will not be filtered out. You'll instead need to manually hide these files using the _Hidden_ option in the metadata editor.
|
||||
By default ES-DE will filter out BIOSes and devices that can't be launched directly, meaning these will never show up in the gamelist. But this only applies to files that are listed in the regular MAME driver file and BIOSes and devices for systems like MESS will not be filtered out. You'll instead need to manually hide these files using the _Hidden_ option in the metadata editor.
|
||||
|
||||
If emulating Sega Model 2 games using _Model 2 Emulator_, then you need to change the ROM directory path in the EMULATOR.INI file to point to your Model 2 ROMs. If you're using a portable ES-DE installation, then you can set the ROM directory path to be relative, for example:
|
||||
If using the standalone release of FinalBurn Neo you also need to define the ROM directory in the fbneo.ini file or via the user interface as this emulator does not support passing the full path to the game ROM on game launch (see the comments about Model 2 Emulator below for more details).
|
||||
|
||||
**Sega Model 2**
|
||||
|
||||
If emulating Sega Model 2 games using _Model 2 Emulator_ on Windows, then you need to change the ROM directory path in the EMULATOR.INI file to point to your Model 2 ROMs. If you're using a portable ES-DE installation, then you can set the ROM directory path to be relative, for example:
|
||||
```
|
||||
[RomDirs]
|
||||
Dir1=..\..\ROMs\arcade\Sega Model 2
|
||||
|
@ -926,7 +933,26 @@ The EMULATOR.INI file is found in the _Model 2 Emulator_ installation directory.
|
|||
|
||||
Also note that Model 2 Emulator is a bit broken and on most GPU drivers it will only work correctly if ES-DE keeps running in the background while the game is launched. However, for some GPU drivers the opposite is true and the emulator will only work if ES-DE is suspended. To use the latter setup, switch to the alternative emulator entry _Model 2 Emulator [Suspend ES-DE] (Standalone)_.
|
||||
|
||||
Likewise, if using the standalone release of FinalBurn Neo you also need to define the ROM directory in the fbneo.ini file or via the user interface as this emulator does not support passing the full path to the game ROM on game launch.
|
||||
On Unix/Linux and macOS, the only available emulator for Sega Model 2 is MAME, either the RetroArch - Current core or MAME standalone. Compatibility is still quite poor with only a handful of games working correctly, but this is likely to improve going forward as almost all games for this platform can already start and run to a certain degree. Some games flagged as not working by MAME are still playable with only minor glitches to audio and graphics, just make sure to use a recent ROM set for maximum compatibility.
|
||||
|
||||
**Sega Model 3**
|
||||
|
||||
For Sega Model 3 emulation on Linux download the custom [Supermodel_2022-10-07.tar.gz](https://gitlab.com/es-de/emulationstation-de/-/package_files/55835402/download) package for ES-DE and follow the instructions in the Readme.txt file. In summary you need to place the `supermodel` binary into `~/Applications/Supermodel/` and you need to place the `Config` and `NVRAM` directories into `~/ROMs/model3/`. Note that this build does not include network support as that would make it incompatible with SteamOS. Apart from that it runs really well. If you're using a Linux OS with access to the AUR, then you can use that release of Supermodel instead. But if you do, you still need to place your Config and NVRAM directories into ~/ROMs/model3/ so it's a good idea to download the custom package linked above and read the Readme.txt file to fully understand the required setup.
|
||||
|
||||
Although there is a Homebrew release of Supermodel for macOS this seems to be quite old and is apparently not working correctly so for the time being the model3 system is unsupported on this operating system.
|
||||
|
||||
It's possible to add per-game command line parameters that will be passed to Supermodel on launch. To accomplish this, create a file named _\<game\>.commands_ in the same directory as the game file, for example `daytona2.commands` and add the options to this file. Here is an example of what the file contents could look like:
|
||||
```
|
||||
-legacy3d -show-fps
|
||||
```
|
||||
|
||||
**MAME standalone on macOS**
|
||||
|
||||
If using the Homebrew release of MAME standalone on macOS and emulating MESS systems like astrocde and ti99, then you need to configure the path to the MAME hash files in the mame.ini file. Alternatively you can symlink the installed hash directory to `~/.mame/` like the following (you will of course need to modify the command depending on which MAME version you have installed):
|
||||
```
|
||||
ln -s /opt/homebrew/Cellar/mame/0.248/share/mame/hash ~/.mame/ # on ARM/Apple
|
||||
ln -s /usr/local/Cellar/mame/0.248/share/mame/hash ~/.mame/ # on x86/Intel
|
||||
```
|
||||
|
||||
#### Nintendo Game and Watch
|
||||
|
||||
|
@ -2881,31 +2907,33 @@ If you're migrating from a previous version of EmulationStation that has absolut
|
|||
|
||||
## Themes
|
||||
|
||||
ES-DE is fully themeable, and although the application ships with the comprehensive slate-DE and modern-DE theme sets, you can use most RetroPie-compatible EmulationStation themes as well. Just be aware that ES-DE has added additional theme functionality compared to the RetroPie fork and more still will be added in future versions. This means that you may not get the full benefits of the application if you're using a theme set which has not been updated specifically for ES-DE. Some themes may also look slightly different as bugs that were present in the RetroPie fork have been fixed. Also note that most Batocera and Recalbox themes are not compatible as these forks are quite different.
|
||||
ES-DE is fully themeable, and although the application ships with the comprehensive slate-DE and modern-DE theme sets, you can use most RetroPie-compatible EmulationStation themes as well as any themes made specifically for the ES-DE 2.0 theme engine. Note that most Batocera and Recalbox themes are not compatible as these forks use a different theme engine than ES-DE.
|
||||
|
||||
As a side comment, the terms _theme_ and _theme set_ are both used when talking about theming. The technically correct term for what you apply to the application to achieve a different look is a _theme set_ as it's a collection of a number of themes for a number of game systems. But in practice it doesn't matter as both terms refer to the same thing and the terms are used interchangeably in this guide.
|
||||
As a side comment, the terms _theme_ and _theme set_ are both used when talking about theming. The technically correct term for what you apply to the application to achieve a different look is a _theme set_ as it's a collection of a number of themes for a number of game systems. But in practice it doesn't matter as both terms refer to the same thing and the terms are used interchangeably in the ES-DE documentation.
|
||||
|
||||
|
||||
Themes are most easily installed to your ES-DE home directory, i.e. `~/.emulationstation/themes`. By just adding the theme sets there, one folder each, they will be found during startup and you can then choose between them via the _UI Settings_ menu on the main menu.
|
||||
Themes are most easily installed to your ES-DE home directory, i.e. `~/.emulationstation/themes/`. By just adding the theme sets there, one folder each, they will be found during startup and you can then choose between them via the _UI Settings_ menu on the main menu. If using the portable release of ES-DE on Windows, the .emulationstation folder can be found in the root of the EmulationStation-DE directory.
|
||||
|
||||
For this example, we've downloaded the [Carbon](https://github.com/RetroPie/es-theme-carbon) and [Fundamental](https://github.com/G-rila/es-theme-fundamental) themes and uncompressed them to the ES-DE home directory:
|
||||
To download a theme from its GitHub page, press the green _Code_ button in the upper right corner and choose _Download ZIP_. The process is identical on GitLab, but this site uses a button with a download symbol instead of a green button. You then simply unpack the file into `~/.emulationstation/themes/` and restart ES-DE.
|
||||
|
||||
For this example, we've downloaded the [alekfull-nx-es-de](https://github.com/anthonycaccese/alekfull-nx-es-de) and [es-theme-carbon](https://github.com/RetroPie/es-theme-carbon) themes and uncompressed them to the themes directory:
|
||||
|
||||
```
|
||||
~/.emulationstation/themes/alekfull-nx-es-de
|
||||
~/.emulationstation/themes/es-theme-carbon
|
||||
~/.emulationstation/themes/es-theme-fundamental
|
||||
```
|
||||
|
||||
We now have four entries in the Theme set selector in the UI settings menu, i.e. _slate-DE, modern-DE, es-theme-carbon_ and _es-theme-fundamental_.
|
||||
We now have four entries in the _Theme set_ selector in the UI settings menu, i.e. _alekfull-nx-es-de, es-theme-carbon, modern-DE_ and _slate-DE_.
|
||||
|
||||
Although you place additional themes in your ES-DE home directory, the default slate-DE and modern-DE themes are located in the installation folder. For example this could be `/usr/share/emulationstation/themes` or `/usr/local/share/emulationstation/themes` on Unix, `/Applications/EmulationStation Desktop Edition.app/Contents/Resources/themes` on macOS or `C:\Program Files\EmulationStation-DE\themes` on Windows.
|
||||
Although you should place additional themes in your ES-DE home directory, the default slate-DE and modern-DE themes are located in the installation folder as they come bundled with the application. For example this could be `/usr/share/emulationstation/themes/` or `/usr/local/share/emulationstation/themes/` on Unix, `/Applications/EmulationStation Desktop Edition.app/Contents/Resources/themes/` on macOS or `C:\Program Files\EmulationStation-DE\themes\` on Windows. If using the portable ES-DE release on Windows, the themes folder will be located in the root of the EmulationStation-DE directory.
|
||||
|
||||
Note that if using the AppImage release on Linux, then there is no installation folder as all files are contained inside the AppImage file.
|
||||
|
||||
So if you would like to customize the slate-DE or modern-DE theme sets, simply make a copy of their directories to ~/.emulationstation/themes and then those copies will take precedence over the ones in the application installation directory.
|
||||
If you would like to customize the slate-DE or modern-DE theme sets, simply make a copy of their directories to `~/.emulationstation/themes/` and then those copies will take precedence over the ones in the application installation directory.
|
||||
|
||||
Here is a good resource with a list of themes (although you will have to search online for the download location for each theme set):
|
||||
Refer to the official list of recommended theme sets for a selection of high-quality themes:
|
||||
|
||||
https://retropie.org.uk/docs/Themes
|
||||
https://gitlab.com/es-de/themes/themes-list
|
||||
|
||||
![alt text](images/es-de_ui_theme_support.png "ES-DE Theme Support")
|
||||
_This is a screenshot of the modern-DE theme that is bundled with ES-DE (in addition to the default slate-DE theme)._
|
||||
|
@ -2971,7 +2999,7 @@ The **@** symbol indicates that the emulator is _deprecated_ and will be removed
|
|||
| android | Google Android | BlueStacks **(Standalone)** [W] | | No | Shortcut (.lnk) file in root folder |
|
||||
| apple2 | Apple II | LinApple **(Standalone)** [U],<br>Mednafen **(Standalone)** [M],<br>AppleWin **(Standalone)** [W*] | Mednafen **(Standalone)** [UW*],<br>MAME **(Standalone)** [UMW*] | Yes for Mednafen and MAME | See the specific _Apple II_ section elsewhere in this guide |
|
||||
| apple2gs | Apple IIGS | MAME **(Standalone)** [UMW*] | | Yes | See the specific _Apple IIGS_ section elsewhere in this guide |
|
||||
| arcade | Arcade | MAME - Current | MAME 2010,<br>MAME 2003-Plus,<br>MAME 2000,<br>MAME **(Standalone)** [UMW*],<br>FinalBurn Neo,<br>FB Alpha 2012,<br>Flycast,<br>Flycast **(Standalone)** [UMW*],<br>Kronos [UW],<br>Model 2 Emulator **(Standalone)** [W*],<br>Model 2 Emulator [Suspend ES-DE] **(Standalone)** [W*],<br>Supermodel **(Standalone)** [W*] | Depends | See the specific _Arcade and Neo Geo_ section elsewhere in this guide |
|
||||
| arcade | Arcade | MAME - Current | MAME 2010,<br>MAME 2003-Plus,<br>MAME 2000,<br>MAME **(Standalone)** [UMW*],<br>FinalBurn Neo,<br>FB Alpha 2012,<br>Flycast,<br>Flycast **(Standalone)** [UMW*],<br>Kronos [UW],<br>Model 2 Emulator **(Standalone)** [W*],<br>Model 2 Emulator [Suspend ES-DE] **(Standalone)** [W*],<br>Supermodel **(Standalone)** [UW*] | Depends | See the specific _Arcade and Neo Geo_ section elsewhere in this guide |
|
||||
| astrocde | Bally Astrocade | MAME - Current | MAME **(Standalone)** [UMW*] | | See the specific _Bally Astrocade_ section elsewhere in this guide |
|
||||
| atari2600 | Atari 2600 | Stella | Stella 2014,<br>ares **(Standalone)** [UMW*] | No | Single archive or ROM file in root folder |
|
||||
| atari5200 | Atari 5200 | a5200 | Atari800,<br>Atari800 **(Standalone)** [UMW*] | Yes | |
|
||||
|
@ -2993,7 +3021,7 @@ The **@** symbol indicates that the emulator is _deprecated_ and will be removed
|
|||
| coco | Tandy Color Computer | XRoar CoCo 2 NTSC **(Standalone)** [UMW*] | XRoar CoCo 2 PAL **(Standalone)** [UMW*] | Yes | See the specific _Tandy Color Computer_ section elsewhere in this guide |
|
||||
| colecovision | ColecoVision | blueMSX | Gearcoleco,<br>openMSX **(Standalone)** [UMW*],<br>ares **(Standalone)** [UMW*] | Yes | Single archive or ROM file in root folder |
|
||||
| cps | Capcom Play System | MAME - Current | MAME 2010,<br>MAME 2003-Plus,<br>MAME 2000,<br>MAME **(Standalone)** [UMW*],<br>FinalBurn Neo,<br>FB Alpha 2012,<br>FB Alpha 2012 CPS-1,<br>FB Alpha 2012 CPS-2,<br>FB Alpha 2012 CPS-3 | Depends | See the specific _Arcade and Neo Geo_ section elsewhere in this guide |
|
||||
| daphne | Daphne Arcade LaserDisc Emulator | Hypseus [Daphne] **(Standalone)** [UW*] | Hypseus [Singe] **(Standalone)** [UW*] | Yes (Daphne games) | See the specific _Hypseus Singe (Daphne)_ section elsewhere in this guide |
|
||||
| daphne | Daphne Arcade LaserDisc Emulator | Hypseus [Daphne] **(Standalone)** [UW*] | Hypseus [Singe] **(Standalone)** [UW*] | Yes for Daphne games | See the specific _Hypseus Singe (Daphne)_ section elsewhere in this guide |
|
||||
| desktop | Desktop Applications | _Suspend ES-DE_ | _Keep ES-DE running_ | | See the specific _Ports and desktop applications_ section elsewhere in this guide |
|
||||
| doom | Doom | PrBoom | Boom 3 [UW],<br>Boom 3 xp [UW],<br>_Shortcut or script_ | No | |
|
||||
| dos | DOS (PC) | DOSBox-Pure | DOSBox-Core,<br>DOSBox-SVN,<br>DOSBox-X **(Standalone)**,<br>DOSBox Staging **(Standalone)** [UMW*] | No | See the specific _DOS / PC_ section elsewhere in this guide |
|
||||
|
@ -3021,7 +3049,7 @@ The **@** symbol indicates that the emulator is _deprecated_ and will be removed
|
|||
| lutris | Lutris Open Gaming Platform | Lutris application **(Standalone)** [U] | | No | See the specific _Lutris_ section elsewhere in this guide |
|
||||
| lutro | Lutro Game Engine | Lutro | | | |
|
||||
| macintosh | Apple Macintosh | Basilisk II **(Standalone)** [UMW*] | SheepShaver **(Standalone)** [UMW*] | Yes | See the specific _Apple Macintosh_ section elsewhere in this guide |
|
||||
| mame | Multiple Arcade Machine Emulator | MAME - Current | MAME 2010,<br>MAME 2003-Plus,<br>MAME 2000,<br>MAME **(Standalone)** [UMW*],<br>FinalBurn Neo,<br>FB Alpha 2012,<br>Flycast,<br>Flycast **(Standalone)** [UMW*],<br>Kronos [UW],<br>Model 2 Emulator **(Standalone)** [W*],<br>Model 2 Emulator [Suspend ES-DE] **(Standalone)** [W*],<br>Supermodel **(Standalone)** [W*] | Depends | See the specific _Arcade and Neo Geo_ section elsewhere in this guide |
|
||||
| mame | Multiple Arcade Machine Emulator | MAME - Current | MAME 2010,<br>MAME 2003-Plus,<br>MAME 2000,<br>MAME **(Standalone)** [UMW*],<br>FinalBurn Neo,<br>FB Alpha 2012,<br>Flycast,<br>Flycast **(Standalone)** [UMW*],<br>Kronos [UW],<br>Model 2 Emulator **(Standalone)** [W*],<br>Model 2 Emulator [Suspend ES-DE] **(Standalone)** [W*],<br>Supermodel **(Standalone)** [UW*] | Depends | See the specific _Arcade and Neo Geo_ section elsewhere in this guide |
|
||||
| mame-advmame | AdvanceMAME | _Placeholder_ | | Depends | |
|
||||
| mame-mame4all | MAME4ALL | _Placeholder_ | | Depends | |
|
||||
| mastersystem | Sega Master System | Genesis Plus GX | Genesis Plus GX Wide,<br>SMS Plus GX,<br>Gearsystem,<br>PicoDrive,<br>Mednafen **(Standalone)** [UMW*],<br>ares **(Standalone)** [UMW*] | No | Single archive or ROM file in root folder |
|
||||
|
@ -3030,8 +3058,8 @@ The **@** symbol indicates that the emulator is _deprecated_ and will be removed
|
|||
| megadrive | Sega Mega Drive | Genesis Plus GX | Genesis Plus GX Wide,<br>PicoDrive,<br>BlastEm,<br>BlastEm **(Standalone)** [U],<br>Mednafen **(Standalone)** [UMW*],<br>ares **(Standalone)** [UMW*] | No | Single archive or ROM file in root folder |
|
||||
| megaduck | Creatronic Mega Duck | SameDuck | | No | Single archive or ROM file in root folder |
|
||||
| mess | Multi Emulator Super System | MESS 2015 | | | |
|
||||
| model2 | Sega Model 2 | Model 2 Emulator **(Standalone)** [W*] | Model 2 Emulator [Suspend ES-DE] **(Standalone)** [W*] | | See the specific _Arcade and Neo Geo_ section elsewhere in this guide |
|
||||
| model3 | Sega Model 3 | Supermodel **(Standalone)** [W*] | | | See the specific _Arcade and Neo Geo_ section elsewhere in this guide |
|
||||
| model2 | Sega Model 2 | Model 2 Emulator **(Standalone)** [W*],<br>MAME - Current [UM] | Model 2 Emulator [Suspend ES-DE] **(Standalone)** [W*],<br>MAME - Current [W],<br>MAME **(Standalone)** [UMW*] | Yes for MAME | See the specific _Arcade and Neo Geo_ section elsewhere in this guide |
|
||||
| model3 | Sega Model 3 | Supermodel **(Standalone)** [UW*] | | No | See the specific _Arcade and Neo Geo_ section elsewhere in this guide |
|
||||
| moonlight | Moonlight Game Streaming | _Placeholder_ | | | |
|
||||
| moto | Thomson MO/TO Series | Theodore | | | |
|
||||
| msx | MSX | blueMSX | fMSX,<br>openMSX **(Standalone)** [UMW*],<br>openMSX No Machine **(Standalone)** [UMW*],<br>ares **(Standalone)** [UMW*] | Yes | |
|
||||
|
@ -3065,7 +3093,7 @@ The **@** symbol indicates that the emulator is _deprecated_ and will be removed
|
|||
| pico8 | PICO-8 Fantasy Console | PICO-8 **(Standalone)** | PICO-8 Splore **(Standalone)** | No | See the specific _PICO-8_ section elsewhere in this guide |
|
||||
| pokemini | Nintendo Pokémon Mini | PokeMini | | No | |
|
||||
| ports | Ports | _Various_ | | No | See the specific _Ports and desktop applications_ section elsewhere in this guide |
|
||||
| ps2 | Sony PlayStation 2 | PCSX2 [UW],<br>PCSX2 **(Standalone)** [M] | PCSX2 **(Standalone)** [UW*],<br>PCSX2 Legacy **(Standalone)**@,<br>Play! **(Standalone)** [UMW*],<br>AetherSX2 **(Standalone)** [M] | Yes (No for Play!) | |
|
||||
| ps2 | Sony PlayStation 2 | PCSX2 [UW],<br>PCSX2 **(Standalone)** [M] | PCSX2 **(Standalone)** [UW*],<br>PCSX2 Legacy **(Standalone)**@,<br>Play! **(Standalone)** [UMW*],<br>AetherSX2 **(Standalone)** [M] | Yes except for Play! | |
|
||||
| ps3 | Sony PlayStation 3 | RPCS3 Shortcut **(Standalone)** [UMW*] | RPCS3 Directory **(Standalone)** [UMW*] | Yes | See the specific _Sony PlayStation 3_ section elsewhere in this guide |
|
||||
| ps4 | Sony PlayStation 4 | _Placeholder_ | | | |
|
||||
| psp | Sony PlayStation Portable | PPSSPP | PPSSPP **(Standalone)** | No | Single .iso file in root folder |
|
||||
|
@ -3097,7 +3125,7 @@ The **@** symbol indicates that the emulator is _deprecated_ and will be removed
|
|||
| tanodragon | Tano Dragon | XRoar **(Standalone)** | | Yes | See the specific _Dragon 32 and Tano Dragon_ section elsewhere in this guide |
|
||||
| tg16 | NEC TurboGrafx-16 | Beetle PCE | Beetle PCE FAST,<br>Mednafen **(Standalone)** [UMW*],<br>ares **(Standalone)** [UMW*] | No | Single archive or ROM file in root folder |
|
||||
| tg-cd | NEC TurboGrafx-CD | Beetle PCE | Beetle PCE FAST,<br>Mednafen **(Standalone)** [UMW*],<br>ares **(Standalone)** [UMW*] | Yes | |
|
||||
| ti99 | Texas Instruments TI-99 | MAME **(Standalone)** [UW*] | | Yes | See the specific _Texas Instruments TI-99_ section elsewhere in this guide |
|
||||
| ti99 | Texas Instruments TI-99 | MAME **(Standalone)** [UMW*] | | Yes | See the specific _Texas Instruments TI-99_ section elsewhere in this guide |
|
||||
| tic80 | TIC-80 Game Engine | TIC-80 | | No | Single .tic file in root folder |
|
||||
| to8 | Thomson TO8 | Theodore | | | |
|
||||
| trs-80 | Tandy TRS-80 | sdl2trs DOS Diskette **(Standalone)** [UW*] | sdl2trs Bootable Diskette **(Standalone)** [UW*],<br>sdl2trs CMD File **(Standalone)** [UW*] | Yes | See the specific _Tandy TRS-80_ section elsewhere in this guide |
|
||||
|
|
34
USERGUIDE.md
|
@ -659,7 +659,7 @@ RetroArch does not embed any version information into the filename so no wildcar
|
|||
|
||||
## Using manually downloaded emulators on Linux
|
||||
|
||||
Normally on Linux you would install emulators using either one of the established package formats, i.e. Flatpak, AppImage or Snap, or you would install them using the operating system repository. Less likely would be to build from source code and install to a standard system directory. In all these instances ES-DE should be able to find the emulator when launching a game. But in some rare cases you may instead manually download an emulator as an archive file to unzip somewhere on the file system. Normally you would want to place these files in your home directory, and if running a distribution that has an immutable filesystem (such as SteamOS), you don't even have the choice to install them to a standard system directory.
|
||||
Normally on Linux you would install emulators using either one of the established cross-distribution package formats, i.e. AppImage, Snap or Flatpak, or you would install them using the operating system repository (including the AUR if available on your OS). Less likely would be to manually build from source code and install to a standard system directory. In all these instances ES-DE should be able to find the emulator when launching a game. But in some rare cases you may instead manually download an emulator as an archive file to unzip somewhere on the file system. Normally you would want to place these files in your home directory, and if running a distribution that has an immutable filesystem (such as SteamOS or Fedora Silverblue), you don't even have the choice to install them to a standard system directory.
|
||||
|
||||
For these situations ES-DE looks for emulators in the same directories where it looks for AppImages (as explained in the section above), meaning:
|
||||
```
|
||||
|
@ -912,6 +912,12 @@ The EMULATOR.INI file is found in the _Model 2 Emulator_ installation directory.
|
|||
|
||||
Also note that Model 2 Emulator is a bit broken and on most GPU drivers it will only work correctly if ES-DE keeps running in the background while the game is launched. However, for some GPU drivers the opposite is true and the emulator will only work if ES-DE is suspended. To use the latter setup, switch to the alternative emulator entry _Model 2 Emulator [Suspend ES-DE] (Standalone)_.
|
||||
|
||||
If using the Homebrew release of MAME standalone on macOS and emulating MESS systems like astrocde and ti99, then you need to configure the path to the MAME hash files in the mame.ini file. Alternatively you can symlink the installed hash directory to `~/.mame/` like the following (you will of course need to modify the command depending on which MAME version you have installed):
|
||||
```
|
||||
ln -s /opt/homebrew/Cellar/mame/0.248/share/mame/hash ~/.mame/ # on ARM/Apple
|
||||
ln -s /usr/local/Cellar/mame/0.248/share/mame/hash ~/.mame/ # on x86/Intel
|
||||
```
|
||||
|
||||
#### Nintendo Switch
|
||||
|
||||
The Nintendo Switch emulator Yuzu is distributed as a Snap package, Flatpak package or AppImage on Linux and as a regular installer on Windows. At the moment there is unfortunately no macOS release of this emulator and it's unclear if it can run on BSD Unix.
|
||||
|
@ -2811,29 +2817,33 @@ If you're migrating from a previous version of EmulationStation that has absolut
|
|||
|
||||
## Themes
|
||||
|
||||
ES-DE is fully themeable, and although the application ships with the comprehensive rbsimple-DE and modern-DE theme sets, you can use most RetroPie-compatible EmulationStation themes as well. Just be aware that ES-DE has added additional theme functionality compared to the RetroPie fork and more still will be added in future versions. This means that you may not get the full benefits of the application if you're using a theme set which has not been updated specifically for ES-DE. Some themes may also look slightly different as bugs that were present in the RetroPie fork have been fixed. Also note that most Batocera and Recalbox themes are not compatible as these forks are quite different.
|
||||
ES-DE is fully themeable, and although the application ships with the comprehensive rbsimple-DE and modern-DE theme sets, you can use most RetroPie-compatible EmulationStation themes as well. Note that most Batocera and Recalbox themes are not compatible as these forks use a different theme engine than ES-DE.
|
||||
|
||||
As a side comment, the terms _theme_ and _theme set_ are both used when talking about theming. The technically correct term for what you apply to the application to achieve a different look is a _theme set_ as it's a collection of a number of themes for a number of game systems. But in practice it doesn't matter as both terms refer to the same thing and the terms are used interchangeably in this guide.
|
||||
As a side comment, the terms _theme_ and _theme set_ are both used when talking about theming. The technically correct term for what you apply to the application to achieve a different look is a _theme set_ as it's a collection of a number of themes for a number of game systems. But in practice it doesn't matter as both terms refer to the same thing and the terms are used interchangeably in the ES-DE documentation.
|
||||
|
||||
|
||||
Themes are most easily installed to your ES-DE home directory, i.e. `~/.emulationstation/themes`. By just adding the theme sets there, one folder each, they will be found during startup and you can then choose between them via the _UI Settings_ menu on the main menu.
|
||||
Themes are most easily installed to your ES-DE home directory, i.e. `~/.emulationstation/themes/`. By just adding the theme sets there, one folder each, they will be found during startup and you can then choose between them via the _UI Settings_ menu on the main menu. If using the portable release of ES-DE on Windows, the .emulationstation folder can be found in the root of the EmulationStation-DE directory.
|
||||
|
||||
For this example, we've downloaded the [Carbon](https://github.com/RetroPie/es-theme-carbon) and [Fundamental](https://github.com/G-rila/es-theme-fundamental) themes and uncompressed them to the ES-DE home directory:
|
||||
To download a theme from its GitHub page, press the green _Code_ button in the upper right corner and choose _Download ZIP_. The process is identical on GitLab, but this site uses a button with a download symbol instead of a green button. You then simply unpack the file into `~/.emulationstation/themes/` and restart ES-DE.
|
||||
|
||||
For this example, we've downloaded the [alekfull-nx-retropie](https://github.com/anthonycaccese/alekfull-nx-retropie) and [es-theme-carbon](https://github.com/RetroPie/es-theme-carbon) themes and uncompressed them to the themes directory:
|
||||
|
||||
```
|
||||
~/.emulationstation/themes/alekfull-nx-retropie
|
||||
~/.emulationstation/themes/es-theme-carbon
|
||||
~/.emulationstation/themes/es-theme-fundamental
|
||||
```
|
||||
|
||||
We now have four entries in the Theme set selector in the UI settings menu, i.e. _rbsimple-DE, modern-DE, es-theme-carbon_ and _es-theme-fundamental_.
|
||||
We now have four entries in the _Theme set_ selector in the UI settings menu, i.e. _alekfull-nx-retropie, es-theme-carbon, modern-DE_ and _rbsimple-DE_.
|
||||
|
||||
Although you place additional themes in your ES-DE home directory, the default rbsimple-DE and modern-DE themes are located in the installation folder. For example this could be `/usr/share/emulationstation/themes` or `/usr/local/share/emulationstation/themes` on Unix, `/Applications/EmulationStation Desktop Edition.app/Contents/Resources/themes` on macOS or `C:\Program Files\EmulationStation-DE\themes` on Windows.
|
||||
Although you should place additional themes in your ES-DE home directory, the default rbsimple-DE and modern-DE themes are located in the installation folder as they come bundled with the application. For example this could be `/usr/share/emulationstation/themes/` or `/usr/local/share/emulationstation/themes/` on Unix, `/Applications/EmulationStation Desktop Edition.app/Contents/Resources/themes/` on macOS or `C:\Program Files\EmulationStation-DE\themes\` on Windows. If using the portable ES-DE release on Windows, the themes folder will be located in the root of the EmulationStation-DE directory.
|
||||
|
||||
So if you would like to customize the rbsimple-DE or modern-DE theme sets, simply make a copy of their directories to ~/.emulationstation/themes and then those copies will take precedence over the ones in the application installation directory.
|
||||
Note that if using the AppImage release on Linux, then there is no installation folder as all files are contained inside the AppImage file.
|
||||
|
||||
Here is a good resource with a list of themes (although you will have to search online for the download location for each theme set):
|
||||
If you would like to customize the rbsimple-DE or modern-DE theme sets, simply make a copy of their directories to `~/.emulationstation/themes/` and then those copies will take precedence over the ones in the application installation directory.
|
||||
|
||||
https://retropie.org.uk/docs/Themes
|
||||
Refer to the official list of recommended theme sets for a selection of high-quality themes:
|
||||
|
||||
https://gitlab.com/es-de/themes/themes-list
|
||||
|
||||
![alt text](images/es-de_ui_theme_support.png "ES-DE Theme Support")
|
||||
_This is a screenshot of the modern-DE theme that is bundled with ES-DE (in addition to the default rbsimple-DE theme)._
|
||||
|
@ -3025,7 +3035,7 @@ The **@** symbol indicates that the emulator is _deprecated_ and will be removed
|
|||
| tanodragon | Tano Dragon | XRoar **(Standalone)** | | Yes | See the specific _Dragon 32 and Tano Dragon_ section elsewhere in this guide |
|
||||
| tg16 | NEC TurboGrafx-16 | Beetle PCE | Beetle PCE FAST,<br>Mednafen **(Standalone)** [UMW*] | No | Single archive or ROM file in root folder |
|
||||
| tg-cd | NEC TurboGrafx-CD | Beetle PCE | Beetle PCE FAST,<br>Mednafen **(Standalone)** [UMW*] | Yes | |
|
||||
| ti99 | Texas Instruments TI-99 | MAME **(Standalone)** [UW*] | | Yes | See the specific _Texas Instruments TI-99_ section elsewhere in this guide |
|
||||
| ti99 | Texas Instruments TI-99 | MAME **(Standalone)** [UMW*] | | Yes | See the specific _Texas Instruments TI-99_ section elsewhere in this guide |
|
||||
| tic80 | TIC-80 Game Engine | TIC-80 | | No | Single .tic file in root folder |
|
||||
| to8 | Thomson TO8 | Theodore | | | |
|
||||
| trs-80 | Tandy TRS-80 | sdl2trs DOS Diskette **(Standalone)** [UW*] | sdl2trs Bootable Diskette **(Standalone)** [UW*],<br>sdl2trs CMD File **(Standalone)** [UW*] | Yes | See the specific _Tandy TRS-80_ section elsewhere in this guide |
|
||||
|
|
|
@ -490,8 +490,8 @@ bool SystemData::loadConfig()
|
|||
std::string path;
|
||||
std::string themeFolder;
|
||||
|
||||
name = system.child("name").text().get();
|
||||
fullname = system.child("fullname").text().get();
|
||||
name = Utils::String::replace(system.child("name").text().get(), "\n", "");
|
||||
fullname = Utils::String::replace(system.child("fullname").text().get(), "\n", "");
|
||||
sortName = system.child("systemsortname").text().get();
|
||||
path = system.child("path").text().get();
|
||||
|
||||
|
@ -1303,7 +1303,9 @@ void SystemData::loadTheme()
|
|||
}
|
||||
|
||||
try {
|
||||
// Build map with system variables for theme to use.
|
||||
// Build a map with system variables for the theme to use. Assign a backspace character
|
||||
// to the variables that are not applicable. This will be used in ThemeData to make sure
|
||||
// unpopulated system variables do not lead to theme loading errors.
|
||||
std::map<std::string, std::string> sysData;
|
||||
sysData.insert(std::pair<std::string, std::string>("system.name", getName()));
|
||||
sysData.insert(std::pair<std::string, std::string>("system.theme", getThemeFolder()));
|
||||
|
@ -1315,6 +1317,10 @@ void SystemData::loadTheme()
|
|||
std::pair<std::string, std::string>("system.fullName.collections", getFullName()));
|
||||
sysData.insert(
|
||||
std::pair<std::string, std::string>("system.theme.collections", getThemeFolder()));
|
||||
sysData.insert(std::pair<std::string, std::string>("system.name.noCollections", "\b"));
|
||||
sysData.insert(
|
||||
std::pair<std::string, std::string>("system.fullName.noCollections", "\b"));
|
||||
sysData.insert(std::pair<std::string, std::string>("system.theme.noCollections", "\b"));
|
||||
}
|
||||
else {
|
||||
sysData.insert(
|
||||
|
@ -1323,6 +1329,10 @@ void SystemData::loadTheme()
|
|||
getFullName()));
|
||||
sysData.insert(std::pair<std::string, std::string>("system.theme.noCollections",
|
||||
getThemeFolder()));
|
||||
sysData.insert(std::pair<std::string, std::string>("system.name.collections", "\b"));
|
||||
sysData.insert(
|
||||
std::pair<std::string, std::string>("system.fullName.collections", "\b"));
|
||||
sysData.insert(std::pair<std::string, std::string>("system.theme.collections", "\b"));
|
||||
}
|
||||
|
||||
mTheme->loadFile(sysData, path);
|
||||
|
|
|
@ -55,8 +55,8 @@ void GuiLaunchScreen::displayLaunchScreen(FileData* game)
|
|||
// Title.
|
||||
mTitle = std::make_shared<TextComponent>(
|
||||
"LAUNCHING GAME",
|
||||
Font::get(static_cast<int>(
|
||||
titleFontSize * std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth()))),
|
||||
Font::get(titleFontSize *
|
||||
std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth())),
|
||||
0x666666FF, ALIGN_CENTER);
|
||||
mGrid->setEntry(mTitle, glm::ivec2 {1, 1}, false, true, glm::ivec2 {1, 1});
|
||||
|
||||
|
@ -75,8 +75,8 @@ void GuiLaunchScreen::displayLaunchScreen(FileData* game)
|
|||
// Game name.
|
||||
mGameName = std::make_shared<TextComponent>(
|
||||
"GAME NAME",
|
||||
Font::get(static_cast<int>(
|
||||
gameNameFontSize * std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth()))),
|
||||
Font::get(gameNameFontSize *
|
||||
std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth())),
|
||||
0x444444FF, ALIGN_CENTER);
|
||||
mGrid->setEntry(mGameName, glm::ivec2 {1, 5}, false, true, glm::ivec2 {1, 1});
|
||||
|
||||
|
@ -108,9 +108,8 @@ void GuiLaunchScreen::displayLaunchScreen(FileData* game)
|
|||
float maxWidth {Renderer::getScreenWidth() * maxWidthModifier};
|
||||
float minWidth {Renderer::getScreenWidth() * minWidthModifier};
|
||||
|
||||
float fontWidth {
|
||||
Font::get(static_cast<int>(gameNameFontSize * std::min(Renderer::getScreenHeight(),
|
||||
Renderer::getScreenWidth())))
|
||||
float fontWidth {Font::get(gameNameFontSize *
|
||||
std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth()))
|
||||
->sizeText(Utils::String::toUpper(game->getName()))
|
||||
.x};
|
||||
|
||||
|
|
|
@ -296,7 +296,7 @@ void GuiMenu::openUIOptions()
|
|||
it != SystemData::sSystemVector.cend(); ++it) {
|
||||
if ((*it)->getName() != "retropie") {
|
||||
// If required, abbreviate the system name so it doesn't overlap the setting name.
|
||||
float maxNameLength {mSize.x * 0.48f};
|
||||
float maxNameLength {mSize.x * 0.51f};
|
||||
startupSystem->add((*it)->getFullName(), (*it)->getName(),
|
||||
Settings::getInstance()->getString("StartupSystem") ==
|
||||
(*it)->getName(),
|
||||
|
|
|
@ -240,7 +240,7 @@ void GuiScraperSearch::resizeMetadata()
|
|||
{
|
||||
mMD_Grid->setSize(mGrid.getColWidth(2), mGrid.getRowHeight(1));
|
||||
if (mMD_Grid->getSize().y > mMD_Pairs.size()) {
|
||||
const int fontHeight {static_cast<int>(mMD_Grid->getSize().y / mMD_Pairs.size() * 0.8f)};
|
||||
const float fontHeight {mMD_Grid->getSize().y / mMD_Pairs.size() * 0.8f};
|
||||
auto fontLbl = Font::get(fontHeight, FONT_PATH_REGULAR);
|
||||
auto fontComp = Font::get(fontHeight, FONT_PATH_LIGHT);
|
||||
|
||||
|
@ -554,7 +554,7 @@ void GuiScraperSearch::updateInfoPane()
|
|||
|
||||
// Cache the thumbnail image in mScraperResults so that we don't need to download
|
||||
// it every time the list is scrolled back and forth.
|
||||
if (mScraperResults[i].thumbnailImageData.size() > 0) {
|
||||
if (mScraperResults[i].thumbnailImageData.size() > 350) {
|
||||
std::string content {mScraperResults[i].thumbnailImageData};
|
||||
mResultThumbnail->setImage(content.data(), content.length());
|
||||
mGrid.onSizeChanged(); // A hack to fix the thumbnail position since its size changed.
|
||||
|
@ -837,7 +837,7 @@ void GuiScraperSearch::updateThumbnail()
|
|||
}
|
||||
// Activate the thumbnail in the GUI.
|
||||
std::string content {mScraperResults[mResultList->getCursorId()].thumbnailImageData};
|
||||
if (content.size() > 0) {
|
||||
if (content.size() > 350) {
|
||||
mResultThumbnail->setImage(content.data(), content.length());
|
||||
mGrid.onSizeChanged(); // A hack to fix the thumbnail position since its size changed.
|
||||
}
|
||||
|
|
|
@ -150,7 +150,7 @@ void GuiScraperSingle::onSizeChanged()
|
|||
mGrid.setColWidthPerc(1, 0.04f);
|
||||
|
||||
mGrid.setSize(glm::round(mSize));
|
||||
mBackground.fitTo(mSize, glm::vec3 {}, glm::vec2 {-32.0f, -32.0f});
|
||||
mBackground.fitTo(mSize, glm::vec3 {0.0f, 0.0f, 0.0f}, glm::vec2 {-32.0f, -32.0f});
|
||||
|
||||
// Add some extra margins to the game name.
|
||||
const float newSizeX {mSize.x * 0.96f};
|
||||
|
|
|
@ -1183,12 +1183,11 @@ void SystemView::legacyApplyTheme(const std::shared_ptr<ThemeData>& theme)
|
|||
mPrimary->applyTheme(theme, "system", "textlist_gamelist", ThemeFlags::ALL);
|
||||
|
||||
mLegacySystemInfo->setSize(mSize.x, mLegacySystemInfo->getFont()->getLetterHeight() * 2.2f);
|
||||
mLegacySystemInfo->setPosition(0.0f, std::round(mPrimary->getPosition().y) +
|
||||
std::round(mPrimary->getSize().y));
|
||||
mLegacySystemInfo->setPosition(0.0f,
|
||||
std::floor(mPrimary->getPosition().y) + mPrimary->getSize().y);
|
||||
mLegacySystemInfo->setBackgroundColor(0xDDDDDDD8);
|
||||
mLegacySystemInfo->setRenderBackground(true);
|
||||
mLegacySystemInfo->setFont(
|
||||
Font::get(static_cast<int>(0.035f * mSize.y), Font::getDefaultPath()));
|
||||
mLegacySystemInfo->setFont(Font::get(0.035f * mSize.y, Font::getDefaultPath()));
|
||||
mLegacySystemInfo->setColor(0x000000FF);
|
||||
mLegacySystemInfo->setUppercase(true);
|
||||
mLegacySystemInfo->setZIndex(50.0f);
|
||||
|
|
|
@ -160,6 +160,8 @@ public:
|
|||
mComponentThemeFlags ^= ComponentThemeFlags::METADATA_ELEMENT;
|
||||
}
|
||||
|
||||
virtual int getTextCacheGlyphHeight() { return 0; }
|
||||
|
||||
// Returns the center point of the image (takes origin into account).
|
||||
const glm::vec2 getCenter() const;
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ HelpStyle::HelpStyle()
|
|||
, opacity {1.0f}
|
||||
, letterCase {"uppercase"}
|
||||
{
|
||||
|
||||
if (FONT_SIZE_SMALL != 0)
|
||||
font = Font::get(FONT_SIZE_SMALL);
|
||||
else
|
||||
|
@ -61,7 +60,7 @@ void HelpStyle::applyTheme(const std::shared_ptr<ThemeData>& theme, const std::s
|
|||
iconColorDimmed = iconColor;
|
||||
|
||||
if (elem->has("fontPath") || elem->has("fontSize"))
|
||||
font = Font::getFromTheme(elem, ThemeFlags::ALL, font);
|
||||
font = Font::getFromTheme(elem, ThemeFlags::ALL, font, 0.0f, theme->isLegacyTheme());
|
||||
|
||||
if (elem->has("entrySpacing"))
|
||||
entrySpacing = glm::clamp(elem->get<float>("entrySpacing"), 0.0f, 0.04f);
|
||||
|
|
|
@ -123,6 +123,7 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
|
|||
{"audio", BOOLEAN},
|
||||
{"interpolation", STRING},
|
||||
{"pillarboxes", BOOLEAN},
|
||||
{"pillarboxThreshold", NORMALIZED_PAIR},
|
||||
{"scanlines", BOOLEAN},
|
||||
{"delay", FLOAT},
|
||||
{"fadeInTime", FLOAT},
|
||||
|
@ -1204,6 +1205,14 @@ void ThemeData::parseElement(const pugi::xml_node& root,
|
|||
|
||||
std::string str {resolvePlaceholders(node.text().as_string())};
|
||||
|
||||
// Handle the special case with mutually exclusive system variables, for example
|
||||
// system.fullName.collections and system.fullName.noCollections which can never
|
||||
// exist at the same time. A backspace is assigned in SystemData to flag the
|
||||
// variables that do not apply and if it's encountered here we simply skip the
|
||||
// property.
|
||||
if (!mLegacyTheme && str == "\b")
|
||||
continue;
|
||||
|
||||
// Skip this check for legacy themes to not break backward compatibility with some
|
||||
// themes sets that include empty property values.
|
||||
if (!mLegacyTheme && str == "")
|
||||
|
|
|
@ -541,6 +541,9 @@ void Window::render()
|
|||
}
|
||||
}
|
||||
|
||||
if (!mRenderedHelpPrompts)
|
||||
mHelp->render(trans);
|
||||
|
||||
if (!mRenderLaunchScreen)
|
||||
top->render(trans);
|
||||
}
|
||||
|
@ -568,9 +571,6 @@ void Window::render()
|
|||
delete cache;
|
||||
}
|
||||
|
||||
if (!mRenderedHelpPrompts)
|
||||
mHelp->render(trans);
|
||||
|
||||
unsigned int screensaverTimer =
|
||||
static_cast<unsigned int>(Settings::getInstance()->getInt("ScreensaverTimer"));
|
||||
if (mTimeSinceLastInput >= screensaverTimer && screensaverTimer != 0) {
|
||||
|
|
|
@ -134,7 +134,7 @@ void ComponentList::update(int deltaTime)
|
|||
mLoopTime = 0;
|
||||
}
|
||||
|
||||
const float totalHeight = getTotalRowHeight();
|
||||
const float totalHeight {getTotalRowHeight()};
|
||||
|
||||
// Scroll indicator logic, used by ScrollIndicatorComponent.
|
||||
bool scrollIndicatorChanged = false;
|
||||
|
@ -236,17 +236,17 @@ void ComponentList::onCursorChanged(const CursorState& state)
|
|||
|
||||
void ComponentList::updateCameraOffset()
|
||||
{
|
||||
float oldCameraOffset = mCameraOffset;
|
||||
float oldCameraOffset {mCameraOffset};
|
||||
|
||||
// Move the camera to scroll.
|
||||
const float totalHeight = getTotalRowHeight();
|
||||
const float totalHeight {getTotalRowHeight()};
|
||||
if (totalHeight > mSize.y) {
|
||||
float target =
|
||||
mSelectorBarOffset + getRowHeight(mEntries.at(mCursor).data) / 2.0f - (mSize.y / 2.0f);
|
||||
float target {mSelectorBarOffset + getRowHeight(mEntries.at(mCursor).data) / 2.0f -
|
||||
(mSize.y / 2.0f)};
|
||||
|
||||
// Clamp the camera to prevent a fraction of a row from being displayed.
|
||||
mCameraOffset = 0.0f;
|
||||
unsigned int i = 0;
|
||||
unsigned int i {0};
|
||||
while (mCameraOffset < target && i < mEntries.size()) {
|
||||
mCameraOffset += getRowHeight(mEntries.at(i).data);
|
||||
if (mCameraOffset > totalHeight - mSize.y) {
|
||||
|
@ -290,22 +290,22 @@ void ComponentList::render(const glm::mat4& parentTrans)
|
|||
dim.x = (trans[0].x * dim.x + trans[3].x) - trans[3].x;
|
||||
dim.y = (trans[1].y * dim.y + trans[3].y) - trans[3].y;
|
||||
|
||||
const int clipRectPosX {static_cast<int>(std::ceil(trans[3].x))};
|
||||
const int clipRectPosY {static_cast<int>(std::ceil(trans[3].y))};
|
||||
const int clipRectSizeX {static_cast<int>(std::ceil(dim.x))};
|
||||
const int clipRectSizeY {static_cast<int>(std::ceil(dim.y))};
|
||||
const int clipRectPosX {static_cast<int>(std::floor(trans[3].x))};
|
||||
const int clipRectPosY {static_cast<int>(std::floor(trans[3].y))};
|
||||
const int clipRectSizeX {static_cast<int>(std::round(dim.x))};
|
||||
const int clipRectSizeY {static_cast<int>(std::ceil(dim.y) + 1.0f)};
|
||||
|
||||
mRenderer->pushClipRect(glm::ivec2 {clipRectPosX, clipRectPosY},
|
||||
glm::ivec2 {clipRectSizeX, clipRectSizeY});
|
||||
|
||||
// Scroll the camera.
|
||||
trans = glm::translate(trans, glm::vec3 {0.0f, std::round(-mCameraOffset), 0.0f});
|
||||
trans = glm::translate(trans, glm::vec3 {0.0f, -mCameraOffset, 0.0f});
|
||||
|
||||
glm::mat4 loopTrans {trans};
|
||||
|
||||
// Draw our entries.
|
||||
std::vector<GuiComponent*> drawAfterCursor;
|
||||
bool drawAll;
|
||||
bool drawAll {false};
|
||||
for (size_t i = 0; i < mEntries.size(); ++i) {
|
||||
|
||||
if (mLoopRows && mFocused && mLoopOffset > 0) {
|
||||
|
@ -337,16 +337,16 @@ void ComponentList::render(const glm::mat4& parentTrans)
|
|||
if (mFocused && i == static_cast<size_t>(mCursor) &&
|
||||
it->component->getValue() != "") {
|
||||
// Check if we're dealing with text or an image component.
|
||||
bool isTextComponent = true;
|
||||
unsigned int origColor = it->component->getColor();
|
||||
bool isTextComponent {true};
|
||||
unsigned int origColor {it->component->getColor()};
|
||||
if (origColor == 0) {
|
||||
origColor = it->component->getColorShift();
|
||||
isTextComponent = false;
|
||||
}
|
||||
// Check if the color is neutral.
|
||||
unsigned char byteRed = origColor >> 24 & 0xFF;
|
||||
unsigned char byteGreen = origColor >> 16 & 0xFF;
|
||||
unsigned char byteBlue = origColor >> 8 & 0xFF;
|
||||
unsigned char byteRed {static_cast<unsigned char>(origColor >> 24 & 0xFF)};
|
||||
unsigned char byteGreen {static_cast<unsigned char>(origColor >> 16 & 0xFF)};
|
||||
unsigned char byteBlue {static_cast<unsigned char>(origColor >> 8 & 0xFF)};
|
||||
// If it's neutral, just proceed with normal rendering.
|
||||
if (byteRed == byteGreen && byteGreen == byteBlue) {
|
||||
renderLoopFunc();
|
||||
|
@ -379,17 +379,17 @@ void ComponentList::render(const glm::mat4& parentTrans)
|
|||
|
||||
// Draw selector bar.
|
||||
if (mFocused) {
|
||||
const float selectedRowHeight = getRowHeight(mEntries.at(mCursor).data);
|
||||
const float selectedRowHeight {getRowHeight(mEntries.at(mCursor).data)};
|
||||
|
||||
if (mOpacity == 1.0f) {
|
||||
mRenderer->drawRect(0.0f, mSelectorBarOffset, std::round(mSize.x), selectedRowHeight,
|
||||
0xFFFFFFFF, 0xFFFFFFFF, false, mOpacity, mDimming,
|
||||
mRenderer->drawRect(0.0f, mSelectorBarOffset, mSize.x, selectedRowHeight, 0xFFFFFFFF,
|
||||
0xFFFFFFFF, false, mOpacity, mDimming,
|
||||
Renderer::BlendFactor::ONE_MINUS_DST_COLOR,
|
||||
Renderer::BlendFactor::ZERO);
|
||||
|
||||
mRenderer->drawRect(0.0f, mSelectorBarOffset, std::round(mSize.x), selectedRowHeight,
|
||||
0x777777FF, 0x777777FF, false, mOpacity, mDimming,
|
||||
Renderer::BlendFactor::ONE, Renderer::BlendFactor::ONE);
|
||||
mRenderer->drawRect(0.0f, mSelectorBarOffset, mSize.x, selectedRowHeight, 0x777777FF,
|
||||
0x777777FF, false, mOpacity, mDimming, Renderer::BlendFactor::ONE,
|
||||
Renderer::BlendFactor::ONE);
|
||||
}
|
||||
|
||||
for (auto it = drawAfterCursor.cbegin(); it != drawAfterCursor.cend(); ++it)
|
||||
|
@ -401,34 +401,34 @@ void ComponentList::render(const glm::mat4& parentTrans)
|
|||
}
|
||||
|
||||
// Draw separators.
|
||||
float y = 0;
|
||||
float y {0.0f};
|
||||
for (unsigned int i = 0; i < mEntries.size(); ++i) {
|
||||
mRenderer->drawRect(0.0f, y, std::round(mSize.x),
|
||||
1.0f * Renderer::getScreenHeightModifier(), 0xC6C7C6FF, 0xC6C7C6FF,
|
||||
false, mOpacity, mDimming);
|
||||
mRenderer->drawRect(0.0f, y, mSize.x, 1.0f * Renderer::getScreenHeightModifier(),
|
||||
0xC6C7C6FF, 0xC6C7C6FF, false, mOpacity, mDimming);
|
||||
y += getRowHeight(mEntries.at(i).data);
|
||||
}
|
||||
|
||||
mRenderer->drawRect(0.0f, y, std::round(mSize.x), 1.0f * Renderer::getScreenHeightModifier(),
|
||||
0xC6C7C6FF, 0xC6C7C6FF, false, mOpacity, mDimming);
|
||||
mRenderer->drawRect(0.0f, y, mSize.x, 1.0f * Renderer::getScreenHeightModifier(), 0xC6C7C6FF,
|
||||
0xC6C7C6FF, false, mOpacity, mDimming);
|
||||
mRenderer->popClipRect();
|
||||
}
|
||||
|
||||
float ComponentList::getRowHeight(const ComponentListRow& row) const
|
||||
{
|
||||
// Returns the highest component height found in the row.
|
||||
float height = 0;
|
||||
float height {0.0f};
|
||||
for (unsigned int i = 0; i < row.elements.size(); ++i) {
|
||||
if (row.elements.at(i).component->getSize().y > height)
|
||||
height = row.elements.at(i).component->getSize().y;
|
||||
}
|
||||
|
||||
// We round down to avoid separator single-pixel alignment issues.
|
||||
return std::floor(height);
|
||||
}
|
||||
|
||||
float ComponentList::getTotalRowHeight() const
|
||||
{
|
||||
float height = 0;
|
||||
float height {0.0f};
|
||||
for (auto it = mEntries.cbegin(); it != mEntries.cend(); ++it)
|
||||
height += getRowHeight(it->data);
|
||||
|
||||
|
@ -437,13 +437,13 @@ float ComponentList::getTotalRowHeight() const
|
|||
|
||||
void ComponentList::updateElementPosition(const ComponentListRow& row)
|
||||
{
|
||||
float yOffset = 0;
|
||||
float yOffset {0.0f};
|
||||
for (auto it = mEntries.cbegin(); it != mEntries.cend() && &it->data != &row; ++it)
|
||||
yOffset += getRowHeight(it->data);
|
||||
|
||||
// Assumes updateElementSize has already been called.
|
||||
float rowHeight = getRowHeight(row);
|
||||
float x = mHorizontalPadding / 2.0f;
|
||||
float rowHeight {getRowHeight(row)};
|
||||
float x {mHorizontalPadding / 2.0f};
|
||||
|
||||
for (unsigned int i = 0; i < row.elements.size(); ++i) {
|
||||
const auto comp = row.elements.at(i).component;
|
||||
|
@ -456,7 +456,7 @@ void ComponentList::updateElementPosition(const ComponentListRow& row)
|
|||
|
||||
void ComponentList::updateElementSize(const ComponentListRow& row)
|
||||
{
|
||||
float width = mSize.x - mHorizontalPadding;
|
||||
float width {mSize.x - mHorizontalPadding};
|
||||
std::vector<std::shared_ptr<GuiComponent>> resizeVec;
|
||||
|
||||
for (auto it = row.elements.cbegin(); it != row.elements.cend(); ++it) {
|
||||
|
@ -485,11 +485,11 @@ std::vector<HelpPrompt> ComponentList::getHelpPrompts()
|
|||
if (!size())
|
||||
return std::vector<HelpPrompt>();
|
||||
|
||||
std::vector<HelpPrompt> prompts =
|
||||
mEntries.at(mCursor).data.elements.back().component->getHelpPrompts();
|
||||
std::vector<HelpPrompt> prompts {
|
||||
mEntries.at(mCursor).data.elements.back().component->getHelpPrompts()};
|
||||
|
||||
if (size() > 1) {
|
||||
bool addMovePrompt = true;
|
||||
bool addMovePrompt {true};
|
||||
for (auto it = prompts.cbegin(); it != prompts.cend(); ++it) {
|
||||
if (it->first == "up/down" || it->first == "up/down/left/right") {
|
||||
addMovePrompt = false;
|
||||
|
@ -505,7 +505,7 @@ std::vector<HelpPrompt> ComponentList::getHelpPrompts()
|
|||
|
||||
bool ComponentList::moveCursor(int amt)
|
||||
{
|
||||
bool ret = listInput(amt);
|
||||
bool ret {listInput(amt)};
|
||||
listInput(0);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -209,6 +209,14 @@ void DateTimeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
}
|
||||
}
|
||||
|
||||
float maxHeight {0.0f};
|
||||
|
||||
if (!theme->isLegacyTheme() && elem->has("size")) {
|
||||
const glm::vec2 size {elem->get<glm::vec2>("size")};
|
||||
if (size.x != 0.0f && size.y != 0.0f)
|
||||
maxHeight = mSize.y * 2.0f;
|
||||
}
|
||||
|
||||
// Legacy themes only.
|
||||
if (properties & FORCE_UPPERCASE && elem->has("forceUppercase"))
|
||||
setUppercase(elem->get<bool>("forceUppercase"));
|
||||
|
@ -216,5 +224,5 @@ void DateTimeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
if (properties & LINE_SPACING && elem->has("lineSpacing"))
|
||||
setLineSpacing(glm::clamp(elem->get<float>("lineSpacing"), 0.5f, 3.0f));
|
||||
|
||||
setFont(Font::getFromTheme(elem, properties, mFont));
|
||||
setFont(Font::getFromTheme(elem, properties, mFont, maxHeight, theme->isLegacyTheme()));
|
||||
}
|
||||
|
|
|
@ -211,7 +211,11 @@ void HelpComponent::updateGrid()
|
|||
std::vector<std::shared_ptr<TextComponent>> labels;
|
||||
|
||||
float width {0.0f};
|
||||
const float height {std::round(font->getLetterHeight() * 1.25f)};
|
||||
float height {std::round(font->getLetterHeight() * 1.25f)};
|
||||
|
||||
// Make sure both text and icons have either odd or equal sizes to avoid alignment issues.
|
||||
if (static_cast<int>(font->getHeight()) % 2 != static_cast<int>(height) % 2)
|
||||
--height;
|
||||
|
||||
// State variable indicating whether the GUI is dimmed.
|
||||
bool isDimmed {mWindow->isBackgroundDimmed()};
|
||||
|
@ -244,8 +248,8 @@ void HelpComponent::updateGrid()
|
|||
|
||||
mGrid->setSize(width, height);
|
||||
|
||||
for (unsigned int i = 0; i < icons.size(); ++i) {
|
||||
const int col = i * 4;
|
||||
for (int i = 0; i < static_cast<int>(icons.size()); ++i) {
|
||||
const int col {i * 4};
|
||||
mGrid->setColWidthPerc(col, icons.at(i)->getSize().x / width);
|
||||
mGrid->setColWidthPerc(col + 1,
|
||||
(mStyle.iconTextSpacing * mRenderer->getScreenWidth()) / width);
|
||||
|
@ -256,7 +260,6 @@ void HelpComponent::updateGrid()
|
|||
}
|
||||
|
||||
mGrid->setPosition({mStyle.position.x, mStyle.position.y, 0.0f});
|
||||
|
||||
mGrid->setOrigin(mStyle.origin);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,9 +11,8 @@
|
|||
#include "Settings.h"
|
||||
#include "components/ButtonComponent.h"
|
||||
|
||||
#define BUTTON_GRID_VERT_PADDING std::round(Font::get(FONT_SIZE_MEDIUM)->getLetterHeight() * 0.915f)
|
||||
#define BUTTON_GRID_HORIZ_PADDING \
|
||||
std::round(Font::get(FONT_SIZE_MEDIUM)->getLetterHeight() * 0.283f)
|
||||
#define BUTTON_GRID_VERT_PADDING Font::get(FONT_SIZE_MEDIUM)->getLetterHeight() * 0.915f
|
||||
#define BUTTON_GRID_HORIZ_PADDING Font::get(FONT_SIZE_MEDIUM)->getLetterHeight() * 0.283f
|
||||
|
||||
#define TITLE_HEIGHT (mTitle->getFont()->getLetterHeight() + Renderer::getScreenHeight() * 0.0637f)
|
||||
|
||||
|
@ -86,7 +85,7 @@ void MenuComponent::setTitle(std::string title, const std::shared_ptr<Font>& fon
|
|||
float MenuComponent::getButtonGridHeight() const
|
||||
{
|
||||
return (mButtonGrid ? mButtonGrid->getSize().y :
|
||||
Font::get(FONT_SIZE_MEDIUM)->getHeight() + BUTTON_GRID_VERT_PADDING);
|
||||
Font::get(FONT_SIZE_MEDIUM)->getSize() * 1.5f + BUTTON_GRID_VERT_PADDING);
|
||||
}
|
||||
|
||||
void MenuComponent::updateSize()
|
||||
|
@ -114,7 +113,7 @@ void MenuComponent::updateSize()
|
|||
|
||||
void MenuComponent::onSizeChanged()
|
||||
{
|
||||
mBackground.fitTo(mSize, glm::vec3 {}, glm::vec2 {-32.0f, -32.0f});
|
||||
mBackground.fitTo(mSize, glm::vec3 {0.0f, 0.0f, 0.0f}, glm::vec2 {-32.0f, -32.0f});
|
||||
|
||||
// Update grid row/column sizes.
|
||||
mGrid.setRowHeightPerc(0, TITLE_HEIGHT / mSize.y / 2.0f);
|
||||
|
@ -132,7 +131,7 @@ void MenuComponent::onSizeChanged()
|
|||
mTitle->setSize(titleSize.x - indicatorsSize, titleSize.y);
|
||||
|
||||
glm::vec3 titlePos {mTitle->getPosition()};
|
||||
mTitle->setPosition(titlePos.x + std::round(indicatorsSize / 2.0f), titlePos.y, titlePos.z);
|
||||
mTitle->setPosition(titlePos.x + indicatorsSize / 2.0f, titlePos.y, titlePos.z);
|
||||
}
|
||||
|
||||
void MenuComponent::addButton(const std::string& name,
|
||||
|
@ -186,7 +185,7 @@ std::shared_ptr<ComponentGrid> makeButtonGrid(
|
|||
std::shared_ptr<ImageComponent> makeArrow()
|
||||
{
|
||||
auto bracket = std::make_shared<ImageComponent>();
|
||||
bracket->setResize(0, std::round(Font::get(FONT_SIZE_MEDIUM)->getLetterHeight()));
|
||||
bracket->setResize(0, Font::get(FONT_SIZE_MEDIUM)->getLetterHeight());
|
||||
bracket->setImage(":/graphics/arrow.svg");
|
||||
return bracket;
|
||||
}
|
||||
|
|
|
@ -60,9 +60,8 @@ void NinePatchComponent::buildVertices()
|
|||
else {
|
||||
// Scale the corner size relative to the screen resolution (using the medium sized
|
||||
// default font as size reference).
|
||||
relCornerSize =
|
||||
glm::round(mCornerSize * (Font::get(FONT_SIZE_MEDIUM)->getLetterHeight() *
|
||||
(mSharpCorners == true ? 0.0568f : 0.09f) / 2.0f));
|
||||
relCornerSize = mCornerSize * (Font::get(FONT_SIZE_MEDIUM)->getLetterHeight() *
|
||||
(mSharpCorners == true ? 0.0568f : 0.09f) / 2.0f);
|
||||
}
|
||||
|
||||
glm::vec2 texSize {relCornerSize * 3.0f};
|
||||
|
|
|
@ -86,11 +86,11 @@ public:
|
|||
mText.getFont()->getHeight());
|
||||
|
||||
// Position.
|
||||
mLeftArrow.setPosition(0.0f, std::round((mSize.y - mLeftArrow.getSize().y) / 2.0f));
|
||||
mLeftArrow.setPosition(0.0f, (mSize.y - mLeftArrow.getSize().y) / 2.0f);
|
||||
mText.setPosition(mLeftArrow.getPosition().x + mLeftArrow.getSize().x,
|
||||
(mSize.y - mText.getSize().y) / 2.0f);
|
||||
mRightArrow.setPosition(mText.getPosition().x + mText.getSize().x,
|
||||
std::round((mSize.y - mRightArrow.getSize().y) / 2.0f));
|
||||
(mSize.y - mRightArrow.getSize().y) / 2.0f);
|
||||
}
|
||||
|
||||
bool input(InputConfig* config, Input input) override
|
||||
|
@ -327,7 +327,7 @@ private:
|
|||
mText.setText(ss.str());
|
||||
mText.setSize(0, mText.getSize().y);
|
||||
setSize(mText.getSize().x + mRightArrow.getSize().x +
|
||||
std::round(Font::get(FONT_SIZE_MEDIUM)->getLetterHeight() * 0.68f),
|
||||
Font::get(FONT_SIZE_MEDIUM)->getLetterHeight() * 0.68f,
|
||||
mText.getSize().y);
|
||||
if (mParent) // Hack since there's no "on child size changed" callback.
|
||||
mParent->onSizeChanged();
|
||||
|
@ -342,26 +342,8 @@ private:
|
|||
// A maximum length parameter has been passed and the "name" size surpasses
|
||||
// this value, so abbreviate the string inside the arrows.
|
||||
auto font = Font::get(FONT_SIZE_MEDIUM);
|
||||
// Calculate with an extra dot to give some leeway.
|
||||
float dotsSize {font->sizeText("....").x};
|
||||
std::string abbreviatedString {font->getTextMaxWidth(
|
||||
Utils::String::toUpper(it->name), it->maxNameLength)};
|
||||
float sizeDifference {font->sizeText(Utils::String::toUpper(it->name)).x -
|
||||
font->sizeText(abbreviatedString).x};
|
||||
if (sizeDifference > 0.0f) {
|
||||
// It doesn't make sense to abbreviate if the number of pixels removed
|
||||
// by the abbreviation is less or equal to the size of the three dots
|
||||
// that would be appended to the string.
|
||||
if (sizeDifference <= dotsSize) {
|
||||
abbreviatedString = it->name;
|
||||
}
|
||||
else {
|
||||
if (abbreviatedString.back() == ' ')
|
||||
abbreviatedString.pop_back();
|
||||
abbreviatedString += "...";
|
||||
}
|
||||
}
|
||||
mText.setText(Utils::String::toUpper(abbreviatedString));
|
||||
mText.setText(Utils::String::toUpper(
|
||||
font->wrapText(Utils::String::toUpper(it->name), it->maxNameLength)));
|
||||
}
|
||||
else {
|
||||
mText.setText(Utils::String::toUpper(it->name));
|
||||
|
@ -369,7 +351,7 @@ private:
|
|||
|
||||
mText.setSize(0.0f, mText.getSize().y);
|
||||
setSize(mText.getSize().x + mLeftArrow.getSize().x + mRightArrow.getSize().x +
|
||||
std::round(Font::get(FONT_SIZE_MEDIUM)->getLetterHeight() * 0.68f),
|
||||
Font::get(FONT_SIZE_MEDIUM)->getLetterHeight() * 0.68f,
|
||||
mText.getSize().y);
|
||||
if (mParent) // Hack since there's no "on child size changed" callback.
|
||||
mParent->onSizeChanged();
|
||||
|
|
|
@ -66,10 +66,15 @@ void ScrollableContainer::reset()
|
|||
mAutoScrollResetAccumulator = 0;
|
||||
mAutoScrollAccumulator = -mAutoScrollDelay + mAutoScrollSpeed;
|
||||
mAtEnd = false;
|
||||
// This is needed to resize to the designated area when the backgrund image gets invalidated.
|
||||
// This is needed to resize to the designated area when the background image gets invalidated.
|
||||
if (!mChildren.empty()) {
|
||||
float combinedHeight {
|
||||
mChildren.front()->getFont()->getHeight(mChildren.front()->getLineSpacing())};
|
||||
float combinedHeight {0.0f};
|
||||
const float cacheGlyphHeight {
|
||||
static_cast<float>(mChildren.front()->getTextCacheGlyphHeight())};
|
||||
if (cacheGlyphHeight > 0.0f)
|
||||
combinedHeight = cacheGlyphHeight * mChildren.front()->getLineSpacing();
|
||||
else
|
||||
return;
|
||||
if (mChildren.front()->getSize().y > mSize.y) {
|
||||
if (mVerticalSnap) {
|
||||
float numLines {std::floor(mSize.y / combinedHeight)};
|
||||
|
@ -118,11 +123,16 @@ void ScrollableContainer::update(int deltaTime)
|
|||
if (!isVisible() || mSize == glm::vec2 {0.0f, 0.0f})
|
||||
return;
|
||||
|
||||
const glm::vec2 contentSize {mChildren.front()->getSize()};
|
||||
const glm::vec2 contentSize {glm::round(mChildren.front()->getSize())};
|
||||
float rowModifier {1.0f};
|
||||
|
||||
float lineSpacing {mChildren.front()->getLineSpacing()};
|
||||
float combinedHeight {mChildren.front()->getFont()->getHeight(lineSpacing)};
|
||||
const float lineSpacing {mChildren.front()->getLineSpacing()};
|
||||
float combinedHeight {0.0f};
|
||||
const float cacheGlyphHeight {static_cast<float>(mChildren.front()->getTextCacheGlyphHeight())};
|
||||
if (cacheGlyphHeight > 0.0f)
|
||||
combinedHeight = cacheGlyphHeight * lineSpacing;
|
||||
else
|
||||
return;
|
||||
|
||||
// Calculate the spacing which will be used to clip the container.
|
||||
if (lineSpacing > 1.2f && mClipSpacing == 0.0f) {
|
||||
|
@ -175,7 +185,7 @@ void ScrollableContainer::update(int deltaTime)
|
|||
mAutoScrollAccumulator += deltaTime;
|
||||
while (mAutoScrollAccumulator >=
|
||||
static_cast<int>(rowModifier * static_cast<float>(mAdjustedAutoScrollSpeed))) {
|
||||
if (contentSize.y > mAdjustedHeight)
|
||||
if (!mAtEnd && contentSize.y > mAdjustedHeight)
|
||||
mScrollPos += mScrollDir;
|
||||
mAutoScrollAccumulator -=
|
||||
static_cast<int>(rowModifier * static_cast<float>(mAdjustedAutoScrollSpeed));
|
||||
|
@ -188,18 +198,15 @@ void ScrollableContainer::update(int deltaTime)
|
|||
if (mScrollPos.y < 0.0f)
|
||||
mScrollPos.y = 0.0f;
|
||||
|
||||
if (mScrollPos.x + mSize.x > contentSize.x) {
|
||||
mScrollPos.x = contentSize.x - mSize.x;
|
||||
if (mScrollPos.x + std::round(mSize.x) > contentSize.x) {
|
||||
mScrollPos.x = contentSize.x - std::round(mSize.x);
|
||||
mAtEnd = true;
|
||||
}
|
||||
|
||||
if (contentSize.y < mAdjustedHeight) {
|
||||
if (contentSize.y < mAdjustedHeight)
|
||||
mScrollPos.y = 0.0f;
|
||||
}
|
||||
else if (mScrollPos.y + mAdjustedHeight > contentSize.y) {
|
||||
mScrollPos.y = contentSize.y - mAdjustedHeight;
|
||||
else if (mScrollPos.y + mAdjustedHeight > contentSize.y)
|
||||
mAtEnd = true;
|
||||
}
|
||||
|
||||
if (mAtEnd) {
|
||||
mAutoScrollResetAccumulator += deltaTime;
|
||||
|
@ -237,8 +244,8 @@ void ScrollableContainer::render(const glm::mat4& parentTrans)
|
|||
dimScaled.x = std::fabs(trans[3].x + mSize.x);
|
||||
dimScaled.y = std::fabs(trans[3].y + mAdjustedHeight);
|
||||
|
||||
glm::ivec2 clipDim {static_cast<int>(ceilf(dimScaled.x - trans[3].x)),
|
||||
static_cast<int>(ceilf(dimScaled.y - trans[3].y))};
|
||||
glm::ivec2 clipDim {static_cast<int>(dimScaled.x - trans[3].x),
|
||||
static_cast<int>(dimScaled.y - trans[3].y)};
|
||||
|
||||
// By effectively clipping the upper and lower boundaries of the container we mostly avoid
|
||||
// scrolling outside the vertical starting and ending positions.
|
||||
|
@ -247,7 +254,7 @@ void ScrollableContainer::render(const glm::mat4& parentTrans)
|
|||
|
||||
mRenderer->pushClipRect(clipPos, clipDim);
|
||||
|
||||
trans = glm::translate(trans, glm::round(-glm::vec3 {mScrollPos.x, mScrollPos.y, 0.0f}));
|
||||
trans = glm::translate(trans, -glm::vec3 {mScrollPos.x, mScrollPos.y, 0.0f});
|
||||
mRenderer->setMatrix(trans);
|
||||
|
||||
if (Settings::getInstance()->getBool("DebugText"))
|
||||
|
|
|
@ -97,11 +97,8 @@ void SliderComponent::render(const glm::mat4& parentTrans)
|
|||
if (mTextCache)
|
||||
mFont->renderTextCache(mTextCache.get());
|
||||
|
||||
const float barPosY {mBarHeight == 1.0f ? std::floor(mSize.y / 2.0f - mBarHeight / 2.0f) :
|
||||
std::round(mSize.y / 2.0f - mBarHeight / 2.0f)};
|
||||
|
||||
// Render bar.
|
||||
mRenderer->drawRect(mKnob.getSize().x / 2.0f, barPosY, width, mBarHeight, 0x777777FF,
|
||||
mRenderer->drawRect(mKnob.getSize().x / 2.0f, mSize.y / 2.0f, width, mBarHeight, 0x777777FF,
|
||||
0x777777FF);
|
||||
|
||||
// Render knob.
|
||||
|
@ -124,7 +121,7 @@ void SliderComponent::setValue(float value)
|
|||
void SliderComponent::onSizeChanged()
|
||||
{
|
||||
if (!mSuffix.empty())
|
||||
mFont = Font::get(static_cast<int>(mSize.y), FONT_PATH_LIGHT);
|
||||
mFont = Font::get(mSize.y, FONT_PATH_LIGHT);
|
||||
|
||||
onValueChanged();
|
||||
}
|
||||
|
@ -154,7 +151,7 @@ void SliderComponent::onValueChanged()
|
|||
mTextCache->metrics.size.x = textSize.x; // Fudge the width.
|
||||
}
|
||||
|
||||
mKnob.setResize(0.0f, std::round(mSize.y * 0.7f));
|
||||
mKnob.setResize(0.0f, mSize.y * 0.7f);
|
||||
|
||||
float barLength {
|
||||
mSize.x - mKnob.getSize().x -
|
||||
|
@ -175,11 +172,11 @@ void SliderComponent::onValueChanged()
|
|||
barHeight = 1;
|
||||
|
||||
// Resize the knob one pixel if necessary to keep the bar centered.
|
||||
if (barHeight % 2 == 0 && static_cast<int>(mKnob.getSize().y) % 2 != 0) {
|
||||
if (barHeight % 2 == 0 && static_cast<int>(std::round(mKnob.getSize().y)) % 2 != 0) {
|
||||
mKnob.setResize(mKnob.getSize().x - 1.0f, mKnob.getSize().y - 1.0f);
|
||||
setSize(getSize().x, getSize().y - 1.0f);
|
||||
}
|
||||
else if (barHeight == 1 && static_cast<int>(mKnob.getSize().y) % 2 == 0) {
|
||||
else if (barHeight == 1 && static_cast<int>(std::round(mKnob.getSize().y)) % 2 == 0) {
|
||||
mKnob.setResize(mKnob.getSize().x - 1.0f, mKnob.getSize().y - 1);
|
||||
setSize(getSize().x, getSize().y - 1.0f);
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ TextComponent::TextComponent()
|
|||
, mNoTopMargin {false}
|
||||
, mSelectable {false}
|
||||
, mVerticalAutoSizing {false}
|
||||
, mLegacyTheme {false}
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -58,6 +59,7 @@ TextComponent::TextComponent(const std::string& text,
|
|||
, mNoTopMargin {false}
|
||||
, mSelectable {false}
|
||||
, mVerticalAutoSizing {false}
|
||||
, mLegacyTheme {false}
|
||||
{
|
||||
setFont(font);
|
||||
setColor(color);
|
||||
|
@ -69,7 +71,7 @@ TextComponent::TextComponent(const std::string& text,
|
|||
|
||||
void TextComponent::onSizeChanged()
|
||||
{
|
||||
mAutoCalcExtent = glm::ivec2 {(getSize().x == 0), (getSize().y == 0)};
|
||||
mAutoCalcExtent = glm::ivec2 {getSize().x == 0, getSize().y == 0};
|
||||
onTextChanged();
|
||||
}
|
||||
|
||||
|
@ -180,11 +182,11 @@ void TextComponent::render(const glm::mat4& parentTrans)
|
|||
break;
|
||||
}
|
||||
case ALIGN_BOTTOM: {
|
||||
yOff = (getSize().y - textSize.y);
|
||||
yOff = mSize.y - textSize.y;
|
||||
break;
|
||||
}
|
||||
case ALIGN_CENTER: {
|
||||
yOff = (getSize().y - textSize.y) / 2.0f;
|
||||
yOff = (mSize.y - textSize.y) / 2.0f;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
@ -194,7 +196,7 @@ void TextComponent::render(const glm::mat4& parentTrans)
|
|||
}
|
||||
else {
|
||||
// If height is smaller than the font height, then always center vertically.
|
||||
yOff = std::round((getSize().y - textSize.y) / 2.0f);
|
||||
yOff = (mSize.y - textSize.y) / 2.0f;
|
||||
}
|
||||
|
||||
// Draw the overall textbox area. If we're inside a scrollable container then this
|
||||
|
@ -236,57 +238,14 @@ void TextComponent::render(const glm::mat4& parentTrans)
|
|||
}
|
||||
}
|
||||
|
||||
void TextComponent::calculateExtent()
|
||||
{
|
||||
if (mAutoCalcExtent.x) {
|
||||
if (mUppercase)
|
||||
mSize = mFont->sizeText(Utils::String::toUpper(mText), mLineSpacing);
|
||||
else if (mLowercase)
|
||||
mSize = mFont->sizeText(Utils::String::toLower(mText), mLineSpacing);
|
||||
else if (mCapitalize)
|
||||
mSize = mFont->sizeText(Utils::String::toCapitalized(mText), mLineSpacing);
|
||||
else
|
||||
mSize = mFont->sizeText(mText, mLineSpacing); // Original case.
|
||||
}
|
||||
else {
|
||||
if (mAutoCalcExtent.y) {
|
||||
if (mUppercase) {
|
||||
mSize.y =
|
||||
mFont->sizeWrappedText(Utils::String::toUpper(mText), getSize().x, mLineSpacing)
|
||||
.y;
|
||||
}
|
||||
else if (mLowercase) {
|
||||
mSize.y =
|
||||
mFont->sizeWrappedText(Utils::String::toLower(mText), getSize().x, mLineSpacing)
|
||||
.y;
|
||||
}
|
||||
else if (mCapitalize) {
|
||||
mSize.y = mFont
|
||||
->sizeWrappedText(Utils::String::toCapitalized(mText), getSize().x,
|
||||
mLineSpacing)
|
||||
.y;
|
||||
}
|
||||
else {
|
||||
mSize.y = mFont->sizeWrappedText(mText, getSize().x, mLineSpacing).y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TextComponent::onTextChanged()
|
||||
{
|
||||
if (!mVerticalAutoSizing)
|
||||
mVerticalAutoSizing = (mSize.x != 0.0f && mSize.y == 0.0f);
|
||||
|
||||
calculateExtent();
|
||||
|
||||
if (!mFont || mText.empty() || mSize.x == 0.0f || mSize.y == 0.0f) {
|
||||
mTextCache.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
std::string text;
|
||||
|
||||
if (mText != "") {
|
||||
if (mUppercase)
|
||||
text = Utils::String::toUpper(mText);
|
||||
else if (mLowercase)
|
||||
|
@ -295,50 +254,52 @@ void TextComponent::onTextChanged()
|
|||
text = Utils::String::toCapitalized(mText);
|
||||
else
|
||||
text = mText; // Original case.
|
||||
}
|
||||
|
||||
std::shared_ptr<Font> f {mFont};
|
||||
const float lineHeight {f->getHeight(mLineSpacing)};
|
||||
const bool isMultiline {mSize.y > lineHeight};
|
||||
if (mFont && mAutoCalcExtent.x) {
|
||||
mSize = mFont->sizeText(text, mLineSpacing);
|
||||
// This can happen under special circumstances like when a blank/dummy font is used.
|
||||
if (mSize.x == 0.0f)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mFont || text.empty() || mSize.x < 0.0f)
|
||||
return;
|
||||
|
||||
float lineHeight {0.0f};
|
||||
const bool isScrollable {mParent && mParent->isScrollable()};
|
||||
std::shared_ptr<Font> font {mFont};
|
||||
|
||||
bool addAbbrev {false};
|
||||
if (!isMultiline) {
|
||||
size_t newline {text.find('\n')};
|
||||
// Single line of text - stop at the first newline since it'll mess everything up.
|
||||
text = text.substr(0, newline);
|
||||
addAbbrev = newline != std::string::npos;
|
||||
}
|
||||
|
||||
glm::vec2 size {f->sizeText(text)};
|
||||
if (!isMultiline && text.size() && (size.x > mSize.x || addAbbrev)) {
|
||||
// Abbreviate text.
|
||||
const std::string abbrev {"..."};
|
||||
float abbrevSize {f->sizeText(abbrev).x};
|
||||
|
||||
while (text.size() && size.x + abbrevSize > mSize.x) {
|
||||
size_t newSize {Utils::String::prevCursor(text, text.size())};
|
||||
text.erase(newSize, text.size() - newSize);
|
||||
if (!text.empty() && text.back() == ' ')
|
||||
text.pop_back();
|
||||
size = f->sizeText(text);
|
||||
}
|
||||
|
||||
text.append(abbrev);
|
||||
mTextCache = std::shared_ptr<TextCache>(f->buildTextCache(
|
||||
text, glm::vec2 {}, mColor, mSize.x, mHorizontalAlignment, mLineSpacing, mNoTopMargin));
|
||||
}
|
||||
else if (isMultiline && text.size() && !isScrollable) {
|
||||
const std::string wrappedText {f->wrapText(
|
||||
text, mSize.x, (mVerticalAutoSizing ? 0.0f : mSize.y - lineHeight), mLineSpacing)};
|
||||
mTextCache = std::shared_ptr<TextCache>(f->buildTextCache(wrappedText, glm::vec2 {}, mColor,
|
||||
mSize.x, mHorizontalAlignment,
|
||||
mLineSpacing, mNoTopMargin));
|
||||
if (mLegacyTheme && !isScrollable && (mVerticalAutoSizing || mAutoCalcExtent.x)) {
|
||||
// This is needed to retain a bug from the legacy theme engine where lineSpacing
|
||||
// is not sized correctly when using automatic text element sizing. This is only
|
||||
// applied to legacy themes for backward compatibility reasons.
|
||||
font->useLegacyMaxGlyphHeight();
|
||||
lineHeight = font->getHeight(mLineSpacing);
|
||||
}
|
||||
else {
|
||||
// Used to initialize all glyphs, which is needed to populate mMaxGlyphHeight.
|
||||
lineHeight = mFont->loadGlyphs(text + "\n") * mLineSpacing;
|
||||
}
|
||||
|
||||
const bool isMultiline {mAutoCalcExtent.y == 1 || mSize.y > lineHeight};
|
||||
|
||||
if (isMultiline && !isScrollable) {
|
||||
const std::string wrappedText {
|
||||
font->wrapText(text, mSize.x, (mVerticalAutoSizing ? 0.0f : mSize.y - lineHeight),
|
||||
mLineSpacing, isMultiline)};
|
||||
mTextCache = std::shared_ptr<TextCache>(
|
||||
f->buildTextCache(f->wrapText(text, mSize.x), glm::vec2 {0.0f, 0.0f}, mColor, mSize.x,
|
||||
font->buildTextCache(wrappedText, glm::vec2 {0.0f, 0.0f}, mColor, mSize.x,
|
||||
mHorizontalAlignment, mLineSpacing, mNoTopMargin));
|
||||
}
|
||||
else {
|
||||
mTextCache = std::shared_ptr<TextCache>(font->buildTextCache(
|
||||
font->wrapText(text, mSize.x, 0.0f, mLineSpacing, isMultiline), glm::vec2 {0.0f, 0.0f},
|
||||
mColor, mSize.x, mHorizontalAlignment, mLineSpacing, mNoTopMargin));
|
||||
}
|
||||
|
||||
if (mAutoCalcExtent.y)
|
||||
mSize.y = mTextCache->metrics.size.y;
|
||||
|
||||
if (mOpacity != 1.0f || mThemeOpacity != 1.0f)
|
||||
setOpacity(mOpacity);
|
||||
|
@ -387,6 +348,8 @@ void TextComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
using namespace ThemeFlags;
|
||||
GuiComponent::applyTheme(theme, view, element, properties);
|
||||
|
||||
mLegacyTheme = theme->isLegacyTheme();
|
||||
|
||||
std::string elementType {"text"};
|
||||
std::string componentName {"TextComponent"};
|
||||
|
||||
|
@ -395,7 +358,7 @@ void TextComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
componentName = "gamelistInfoComponent";
|
||||
}
|
||||
|
||||
const ThemeData::ThemeElement* elem = theme->getElement(view, element, elementType);
|
||||
const ThemeData::ThemeElement* elem {theme->getElement(view, element, elementType)};
|
||||
if (!elem)
|
||||
return;
|
||||
|
||||
|
@ -511,6 +474,14 @@ void TextComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
}
|
||||
}
|
||||
|
||||
float maxHeight {0.0f};
|
||||
|
||||
if (!theme->isLegacyTheme() && elem->has("size")) {
|
||||
const glm::vec2 size {elem->get<glm::vec2>("size")};
|
||||
if (size.x != 0.0f && size.y != 0.0f)
|
||||
maxHeight = mSize.y * 2.0f;
|
||||
}
|
||||
|
||||
// Legacy themes only.
|
||||
if (properties & FORCE_UPPERCASE && elem->has("forceUppercase"))
|
||||
setUppercase(elem->get<bool>("forceUppercase"));
|
||||
|
@ -518,5 +489,5 @@ void TextComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
if (properties & LINE_SPACING && elem->has("lineSpacing"))
|
||||
setLineSpacing(glm::clamp(elem->get<float>("lineSpacing"), 0.5f, 3.0f));
|
||||
|
||||
setFont(Font::getFromTheme(elem, properties, mFont));
|
||||
setFont(Font::getFromTheme(elem, properties, mFont, maxHeight, theme->isLegacyTheme()));
|
||||
}
|
||||
|
|
|
@ -14,13 +14,10 @@
|
|||
|
||||
class ThemeData;
|
||||
|
||||
// Used to display text.
|
||||
// TextComponent::setSize(x, y) works a little differently than most components:
|
||||
// * (0, 0) - Will automatically calculate a size that fits
|
||||
// the text on one line (expand horizontally).
|
||||
// * (x != 0, 0) - Wrap text so that it does not reach beyond x. Will
|
||||
// automatically calculate a vertical size (expand vertically).
|
||||
// * (x != 0, y <= fontHeight) - Will truncate text so it fits within this box.
|
||||
// TextComponent sizing works in the following ways:
|
||||
// setSize(0.0f, 0.0f) - Automatically sizes single-line text by expanding horizontally.
|
||||
// setSize(width, 0.0f) - Limits size horizontally and automatically expands vertically.
|
||||
// setSize(width, height) - Wraps and abbreviates text inside the width and height boundaries.
|
||||
class TextComponent : public GuiComponent
|
||||
{
|
||||
public:
|
||||
|
@ -81,6 +78,11 @@ public:
|
|||
Alignment getHorizontalAlignment() { return mHorizontalAlignment; }
|
||||
Alignment getVerticalAlignment() { return mVerticalAlignment; }
|
||||
|
||||
int getTextCacheGlyphHeight() override
|
||||
{
|
||||
return (mTextCache == nullptr ? 0 : mTextCache->metrics.maxGlyphHeight);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void onTextChanged();
|
||||
|
||||
|
@ -89,7 +91,6 @@ protected:
|
|||
std::shared_ptr<Font> mFont;
|
||||
|
||||
private:
|
||||
void calculateExtent();
|
||||
void onColorChanged();
|
||||
|
||||
static inline std::vector<std::string> supportedSystemdataTypes {
|
||||
|
@ -118,6 +119,7 @@ private:
|
|||
bool mNoTopMargin;
|
||||
bool mSelectable;
|
||||
bool mVerticalAutoSizing;
|
||||
bool mLegacyTheme;
|
||||
};
|
||||
|
||||
#endif // ES_CORE_COMPONENTS_TEXT_COMPONENT_H
|
||||
|
|
|
@ -27,6 +27,7 @@ TextEditComponent::TextEditComponent()
|
|||
, mBlinkTime {0}
|
||||
, mCursorRepeatDir {0}
|
||||
, mScrollOffset {0.0f, 0.0f}
|
||||
, mCursorPos {0.0f, 0.0f}
|
||||
, mBox {":/graphics/textinput.svg"}
|
||||
, mFont {Font::get(FONT_SIZE_MEDIUM, FONT_PATH_LIGHT)}
|
||||
{
|
||||
|
@ -51,6 +52,9 @@ void TextEditComponent::onFocusLost()
|
|||
|
||||
void TextEditComponent::onSizeChanged()
|
||||
{
|
||||
if (mSize.x == 0.0f || mSize.y == 0.0f)
|
||||
return;
|
||||
|
||||
mBox.fitTo(
|
||||
mSize, glm::vec3 {},
|
||||
glm::vec2 {-34.0f, -32.0f - (TEXT_PADDING_VERT * Renderer::getScreenHeightModifier())});
|
||||
|
@ -263,9 +267,10 @@ void TextEditComponent::setCursor(size_t pos)
|
|||
|
||||
void TextEditComponent::onTextChanged()
|
||||
{
|
||||
std::string wrappedText = (isMultiline() ? mFont->wrapText(mText, getTextAreaSize().x) : mText);
|
||||
mWrappedText =
|
||||
(isMultiline() ? mFont->wrapText(mText, getTextAreaSize().x, 0.0f, 1.5f, true) : mText);
|
||||
mTextCache = std::unique_ptr<TextCache>(mFont->buildTextCache(
|
||||
wrappedText, 0.0f, 0.0f, 0x77777700 | static_cast<unsigned char>(mOpacity * 255.0f)));
|
||||
mWrappedText, 0.0f, 0.0f, 0x77777700 | static_cast<unsigned char>(mOpacity * 255.0f)));
|
||||
|
||||
if (mCursor > static_cast<int>(mText.length()))
|
||||
mCursor = static_cast<int>(mText.length());
|
||||
|
@ -274,22 +279,23 @@ void TextEditComponent::onTextChanged()
|
|||
void TextEditComponent::onCursorChanged()
|
||||
{
|
||||
if (isMultiline()) {
|
||||
glm::vec2 textSize {mFont->getWrappedTextCursorOffset(mText, getTextAreaSize().x, mCursor)};
|
||||
mCursorPos = mFont->getWrappedTextCursorOffset(mWrappedText, mCursor);
|
||||
|
||||
// Need to scroll down?
|
||||
if (mScrollOffset.y + getTextAreaSize().y < textSize.y + mFont->getHeight())
|
||||
mScrollOffset.y = textSize.y - getTextAreaSize().y + mFont->getHeight();
|
||||
if (mScrollOffset.y + getTextAreaSize().y < mCursorPos.y + mFont->getHeight())
|
||||
mScrollOffset.y = mCursorPos.y - getTextAreaSize().y + mFont->getHeight();
|
||||
// Need to scroll up?
|
||||
else if (mScrollOffset.y > textSize.y)
|
||||
mScrollOffset.y = textSize.y;
|
||||
else if (mScrollOffset.y > mCursorPos.y)
|
||||
mScrollOffset.y = mCursorPos.y;
|
||||
}
|
||||
else {
|
||||
glm::vec2 cursorPos {mFont->sizeText(mText.substr(0, mCursor))};
|
||||
mCursorPos = mFont->sizeText(mText.substr(0, mCursor));
|
||||
mCursorPos.y = 0.0f;
|
||||
|
||||
if (mScrollOffset.x + getTextAreaSize().x < cursorPos.x)
|
||||
mScrollOffset.x = cursorPos.x - getTextAreaSize().x;
|
||||
else if (mScrollOffset.x > cursorPos.x)
|
||||
mScrollOffset.x = cursorPos.x;
|
||||
if (mScrollOffset.x + getTextAreaSize().x < mCursorPos.x)
|
||||
mScrollOffset.x = mCursorPos.x - getTextAreaSize().x;
|
||||
else if (mScrollOffset.x > mCursorPos.x)
|
||||
mScrollOffset.x = mCursorPos.x;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -323,25 +329,16 @@ void TextEditComponent::render(const glm::mat4& parentTrans)
|
|||
mRenderer->popClipRect();
|
||||
|
||||
// Draw cursor.
|
||||
glm::vec2 cursorPos;
|
||||
if (isMultiline()) {
|
||||
cursorPos = mFont->getWrappedTextCursorOffset(mText, getTextAreaSize().x, mCursor);
|
||||
}
|
||||
else {
|
||||
cursorPos = mFont->sizeText(mText.substr(0, mCursor));
|
||||
cursorPos[1] = 0;
|
||||
}
|
||||
|
||||
float cursorHeight = mFont->getHeight() * 0.8f;
|
||||
float cursorHeight {mFont->getHeight() * 0.8f};
|
||||
|
||||
if (!mEditing) {
|
||||
mRenderer->drawRect(cursorPos.x, cursorPos.y + (mFont->getHeight() - cursorHeight) / 2.0f,
|
||||
mRenderer->drawRect(mCursorPos.x, mCursorPos.y + (mFont->getHeight() - cursorHeight) / 2.0f,
|
||||
2.0f * Renderer::getScreenWidthModifier(), cursorHeight, 0xC7C7C7FF,
|
||||
0xC7C7C7FF);
|
||||
}
|
||||
|
||||
if (mEditing && mBlinkTime < BLINKTIME / 2) {
|
||||
mRenderer->drawRect(cursorPos.x, cursorPos.y + (mFont->getHeight() - cursorHeight) / 2.0f,
|
||||
mRenderer->drawRect(mCursorPos.x, mCursorPos.y + (mFont->getHeight() - cursorHeight) / 2.0f,
|
||||
2.0f * Renderer::getScreenWidthModifier(), cursorHeight, 0x777777FF,
|
||||
0x777777FF);
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ private:
|
|||
|
||||
Renderer* mRenderer;
|
||||
std::string mText;
|
||||
std::string mWrappedText;
|
||||
std::string mTextOrig;
|
||||
bool mFocused;
|
||||
bool mEditing;
|
||||
|
@ -70,6 +71,7 @@ private:
|
|||
int mCursorRepeatDir;
|
||||
|
||||
glm::vec2 mScrollOffset;
|
||||
glm::vec2 mCursorPos;
|
||||
|
||||
NinePatchComponent mBox;
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ VideoComponent::VideoComponent()
|
|||
, mTargetSize {0.0f, 0.0f}
|
||||
, mVideoAreaPos {0.0f, 0.0f}
|
||||
, mVideoAreaSize {0.0f, 0.0f}
|
||||
, mPillarboxThreshold {0.85f, 0.90f}
|
||||
, mStartTime {0}
|
||||
, mIsPlaying {false}
|
||||
, mIsActuallyPlaying {false}
|
||||
|
@ -256,6 +257,12 @@ void VideoComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
if (elem->has("pillarboxes"))
|
||||
mDrawPillarboxes = elem->get<bool>("pillarboxes");
|
||||
|
||||
if (elem->has("pillarboxThreshold")) {
|
||||
const glm::vec2 pillarboxThreshold {elem->get<glm::vec2>("pillarboxThreshold")};
|
||||
mPillarboxThreshold.x = glm::clamp(pillarboxThreshold.x, 0.2f, 1.0f);
|
||||
mPillarboxThreshold.y = glm::clamp(pillarboxThreshold.y, 0.2f, 1.0f);
|
||||
}
|
||||
|
||||
if (elem->has("scanlines"))
|
||||
mRenderScanlines = elem->get<bool>("scanlines");
|
||||
|
||||
|
|
|
@ -110,6 +110,7 @@ protected:
|
|||
glm::vec2 mTargetSize;
|
||||
glm::vec2 mVideoAreaPos;
|
||||
glm::vec2 mVideoAreaSize;
|
||||
glm::vec2 mPillarboxThreshold;
|
||||
std::shared_ptr<TextureResource> mTexture;
|
||||
std::string mStaticImagePath;
|
||||
std::string mDefaultImagePath;
|
||||
|
|
|
@ -103,7 +103,6 @@ void VideoFFmpegComponent::resize()
|
|||
mSize.y *= resizeScale.y;
|
||||
}
|
||||
|
||||
mSize.y = std::round(mSize.y);
|
||||
mSize.x = (mSize.y / textureSize.y) * textureSize.x;
|
||||
}
|
||||
else {
|
||||
|
@ -113,11 +112,11 @@ void VideoFFmpegComponent::resize()
|
|||
|
||||
// If only one component is set, we resize in a way that maintains aspect ratio.
|
||||
if (!mTargetSize.x && mTargetSize.y) {
|
||||
mSize.y = std::round(mTargetSize.y);
|
||||
mSize.y = mTargetSize.y;
|
||||
mSize.x = (mSize.y / textureSize.y) * textureSize.x;
|
||||
}
|
||||
else if (mTargetSize.x && !mTargetSize.y) {
|
||||
mSize.y = std::round((mTargetSize.x / textureSize.x) * textureSize.y);
|
||||
mSize.y = (mTargetSize.x / textureSize.x) * textureSize.y;
|
||||
mSize.x = (mSize.y / textureSize.y) * textureSize.x;
|
||||
}
|
||||
}
|
||||
|
@ -933,6 +932,11 @@ void VideoFFmpegComponent::calculateBlackRectangle()
|
|||
// otherwise it will exactly match the video size. The reason to add a black rectangle
|
||||
// behind videos in this second instance is that the scanline rendering will make the
|
||||
// video partially transparent so this may avoid some unforseen issues with some themes.
|
||||
// In general, adding very narrow pillarboxes or letterboxes doesn't look good, so by
|
||||
// default this is not done unless the size of the video vs the overall video area is
|
||||
// above the threshold defined by mPillarboxThreshold. By default this is set to 0.85
|
||||
// for the X axis and 0.90 for the Y axis, but this is theme-controllable via the
|
||||
// pillarboxThreshold property.
|
||||
if (mVideoAreaPos != glm::vec2 {0.0f, 0.0f} && mVideoAreaSize != glm::vec2 {0.0f, 0.0f}) {
|
||||
mVideoRectangleCoords.clear();
|
||||
mRectangleOffset = {0.0f, 0.0f};
|
||||
|
@ -949,20 +953,24 @@ void VideoFFmpegComponent::calculateBlackRectangle()
|
|||
// and then scaled, there could be rounding errors that make the video height
|
||||
// slightly higher than allowed. It's only a single pixel or a few pixels, but
|
||||
// it's still visible for some videos.
|
||||
if (mSize.y < mVideoAreaSize.y && mSize.y / mVideoAreaSize.y < 0.90f)
|
||||
if (mSize.y < mVideoAreaSize.y &&
|
||||
mSize.y / mVideoAreaSize.y < mPillarboxThreshold.y)
|
||||
rectHeight = mVideoAreaSize.y;
|
||||
else
|
||||
rectHeight = mSize.y;
|
||||
// Don't add a black border that is too narrow, that's what the 0.85 constant
|
||||
// takes care of.
|
||||
if (mSize.x < mVideoAreaSize.x && mSize.x / mVideoAreaSize.x < 0.85f)
|
||||
if (mSize.x < mVideoAreaSize.x &&
|
||||
mSize.x / mVideoAreaSize.x < mPillarboxThreshold.x)
|
||||
rectWidth = mVideoAreaSize.x;
|
||||
else
|
||||
rectWidth = mSize.x;
|
||||
}
|
||||
// Video is in portrait orientation (or completely square).
|
||||
else {
|
||||
if (mSize.x <= mVideoAreaSize.x &&
|
||||
mSize.x / mVideoAreaSize.x < mPillarboxThreshold.x)
|
||||
rectWidth = mVideoAreaSize.x;
|
||||
else
|
||||
rectWidth = mSize.x;
|
||||
rectHeight = mSize.y;
|
||||
}
|
||||
// If an origin value other than 0.5 is used, then create an offset for centering
|
||||
|
|
|
@ -183,7 +183,8 @@ CarouselComponent<T>::CarouselComponent()
|
|||
, mMaxItemCount {3.0f}
|
||||
, mItemsBeforeCenter {8}
|
||||
, mItemsAfterCenter {8}
|
||||
, mItemSize {Renderer::getScreenWidth() * 0.25f, Renderer::getScreenHeight() * 0.155f}
|
||||
, mItemSize {glm::vec2 {Renderer::getScreenWidth() * 0.25f,
|
||||
Renderer::getScreenHeight() * 0.155f}}
|
||||
, mLinearInterpolation {false}
|
||||
, mInstantItemTransitions {false}
|
||||
, mItemAxisHorizontal {false}
|
||||
|
@ -226,7 +227,7 @@ void CarouselComponent<T>::addEntry(Entry& entry, const std::shared_ptr<ThemeDat
|
|||
auto item = std::make_shared<ImageComponent>(false, dynamic);
|
||||
item->setLinearInterpolation(mLinearInterpolation);
|
||||
item->setMipmapping(true);
|
||||
item->setMaxSize(mItemSize * mItemScale);
|
||||
item->setMaxSize(glm::round(mItemSize * (mItemScale >= 1.0f ? mItemScale : 1.0f)));
|
||||
item->applyTheme(theme, "system", "image_logo",
|
||||
ThemeFlags::PATH | ThemeFlags::COLOR);
|
||||
item->setRotateByTargetSize(true);
|
||||
|
@ -240,7 +241,7 @@ void CarouselComponent<T>::addEntry(Entry& entry, const std::shared_ptr<ThemeDat
|
|||
auto item = std::make_shared<ImageComponent>(false, dynamic);
|
||||
item->setLinearInterpolation(mLinearInterpolation);
|
||||
item->setMipmapping(true);
|
||||
item->setMaxSize(mItemSize * mItemScale);
|
||||
item->setMaxSize(glm::round(mItemSize * (mItemScale >= 1.0f ? mItemScale : 1.0f)));
|
||||
item->setImage(entry.data.itemPath);
|
||||
item->applyTheme(theme, "system", "", ThemeFlags::ALL);
|
||||
item->setRotateByTargetSize(true);
|
||||
|
@ -251,7 +252,8 @@ void CarouselComponent<T>::addEntry(Entry& entry, const std::shared_ptr<ThemeDat
|
|||
auto defaultItem = std::make_shared<ImageComponent>(false, dynamic);
|
||||
defaultItem->setLinearInterpolation(mLinearInterpolation);
|
||||
defaultItem->setMipmapping(true);
|
||||
defaultItem->setMaxSize(mItemSize * mItemScale);
|
||||
defaultItem->setMaxSize(
|
||||
glm::round(mItemSize * (mItemScale >= 1.0f ? mItemScale : 1.0f)));
|
||||
defaultItem->setImage(entry.data.defaultItemPath);
|
||||
defaultItem->applyTheme(theme, "system", "", ThemeFlags::ALL);
|
||||
defaultItem->setRotateByTargetSize(true);
|
||||
|
@ -275,7 +277,8 @@ void CarouselComponent<T>::addEntry(Entry& entry, const std::shared_ptr<ThemeDat
|
|||
|
||||
auto text = std::make_shared<TextComponent>(
|
||||
nameEntry, mFont, 0x000000FF, mItemHorizontalAlignment, mItemVerticalAlignment,
|
||||
glm::vec3 {0.0f, 0.0f, 0.0f}, mItemSize * mItemScale, 0x00000000);
|
||||
glm::vec3 {0.0f, 0.0f, 0.0f},
|
||||
glm::round(mItemSize * (mItemScale >= 1.0f ? mItemScale : 1.0f)), 0x00000000);
|
||||
if (legacyMode) {
|
||||
text->applyTheme(theme, "system", "text_logoText",
|
||||
ThemeFlags::FONT_PATH | ThemeFlags::FONT_SIZE | ThemeFlags::COLOR |
|
||||
|
@ -310,7 +313,7 @@ void CarouselComponent<T>::addEntry(Entry& entry, const std::shared_ptr<ThemeDat
|
|||
else
|
||||
entry.data.item->setOrigin(entry.data.item->getOrigin().x, 0.5f);
|
||||
|
||||
glm::vec2 denormalized {mItemSize * entry.data.item->getOrigin()};
|
||||
glm::vec2 denormalized {glm::round(mItemSize * entry.data.item->getOrigin())};
|
||||
entry.data.item->setPosition(glm::vec3 {denormalized.x, denormalized.y, 0.0f});
|
||||
|
||||
List::add(entry);
|
||||
|
@ -323,7 +326,7 @@ void CarouselComponent<T>::updateEntry(Entry& entry, const std::shared_ptr<Theme
|
|||
auto item = std::make_shared<ImageComponent>(false, true);
|
||||
item->setLinearInterpolation(mLinearInterpolation);
|
||||
item->setMipmapping(true);
|
||||
item->setMaxSize(mItemSize * mItemScale);
|
||||
item->setMaxSize(glm::round(mItemSize * (mItemScale >= 1.0f ? mItemScale : 1.0f)));
|
||||
item->setImage(entry.data.itemPath);
|
||||
item->applyTheme(theme, "system", "", ThemeFlags::ALL);
|
||||
item->setRotateByTargetSize(true);
|
||||
|
@ -348,7 +351,7 @@ void CarouselComponent<T>::updateEntry(Entry& entry, const std::shared_ptr<Theme
|
|||
else
|
||||
entry.data.item->setOrigin(entry.data.item->getOrigin().x, 0.5f);
|
||||
|
||||
glm::vec2 denormalized {mItemSize * entry.data.item->getOrigin()};
|
||||
glm::vec2 denormalized {glm::round(mItemSize * entry.data.item->getOrigin())};
|
||||
entry.data.item->setPosition(glm::vec3 {denormalized.x, denormalized.y, 0.0f});
|
||||
}
|
||||
|
||||
|
@ -567,11 +570,10 @@ template <typename T> void CarouselComponent<T>::render(const glm::mat4& parentT
|
|||
|
||||
glm::mat4 carouselTrans {parentTrans};
|
||||
carouselTrans = glm::translate(
|
||||
carouselTrans,
|
||||
glm::round(glm::vec3 {GuiComponent::mPosition.x, GuiComponent::mPosition.y, 0.0f}));
|
||||
carouselTrans = glm::translate(
|
||||
carouselTrans, glm::round(glm::vec3 {GuiComponent::mOrigin.x * mSize.x * -1.0f,
|
||||
GuiComponent::mOrigin.y * mSize.y * -1.0f, 0.0f}));
|
||||
carouselTrans, glm::vec3 {GuiComponent::mPosition.x, GuiComponent::mPosition.y, 0.0f});
|
||||
carouselTrans =
|
||||
glm::translate(carouselTrans, glm::vec3 {GuiComponent::mOrigin.x * mSize.x * -1.0f,
|
||||
GuiComponent::mOrigin.y * mSize.y * -1.0f, 0.0f});
|
||||
|
||||
if (carouselTrans[3].x + mSize.x <= 0.0f || carouselTrans[3].y + mSize.y <= 0.0f)
|
||||
return;
|
||||
|
@ -609,7 +611,7 @@ template <typename T> void CarouselComponent<T>::render(const glm::mat4& parentT
|
|||
float scaleSize {mItemSize.x * mItemScale - mItemSize.x};
|
||||
|
||||
if (isWheel) {
|
||||
xOff = (mSize.x - mItemSize.x) / 2.0f - (camOffset * itemSpacing.y);
|
||||
xOff = (mSize.x - mItemSize.x) / 2.0f;
|
||||
yOff = (mSize.y - mItemSize.y) / 2.0f;
|
||||
// Alignment of the actual carousel inside to the overall component area.
|
||||
if (mLegacyMode) {
|
||||
|
@ -769,16 +771,24 @@ template <typename T> void CarouselComponent<T>::render(const glm::mat4& parentT
|
|||
if (singleEntry)
|
||||
distance = 0.0f;
|
||||
|
||||
float scale {1.0f + ((mItemScale - 1.0f) * (1.0f - fabsf(distance)))};
|
||||
float scale {0.0f};
|
||||
|
||||
if (mItemScale >= 1.0f) {
|
||||
scale = 1.0f + ((mItemScale - 1.0f) * (1.0f - fabsf(distance)));
|
||||
scale = std::min(mItemScale, std::max(1.0f, scale));
|
||||
scale /= mItemScale;
|
||||
}
|
||||
else {
|
||||
scale = 1.0f + ((1.0f - mItemScale) * (fabsf(distance) - 1.0f));
|
||||
scale = std::max(mItemScale, std::min(1.0f, scale));
|
||||
}
|
||||
|
||||
glm::mat4 itemTrans {carouselTrans};
|
||||
if (singleEntry)
|
||||
itemTrans = glm::translate(carouselTrans, glm::vec3 {xOff, yOff, 0.0f});
|
||||
else
|
||||
itemTrans = glm::translate(
|
||||
itemTrans, glm::vec3 {i * itemSpacing.x + xOff, i * itemSpacing.y + yOff, 0.0f});
|
||||
itemTrans = glm::translate(itemTrans, glm::vec3 {(i * itemSpacing.x) + xOff,
|
||||
(i * itemSpacing.y) + yOff, 0.0f});
|
||||
|
||||
float opacity {0.0f};
|
||||
|
||||
|
@ -1012,7 +1022,7 @@ void CarouselComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
}
|
||||
|
||||
if (elem->has("itemScale"))
|
||||
mItemScale = glm::clamp(elem->get<float>("itemScale"), 0.5f, 3.0f);
|
||||
mItemScale = glm::clamp(elem->get<float>("itemScale"), 0.2f, 3.0f);
|
||||
|
||||
if (elem->has("itemTransitions")) {
|
||||
const std::string itemTransitions {elem->get<std::string>("itemTransitions")};
|
||||
|
@ -1145,8 +1155,9 @@ void CarouselComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
|
||||
// Legacy themes.
|
||||
if (mLegacyMode) {
|
||||
// Don't allow logoScale below 1.0 for legacy themes as it introduces compatibility issues.
|
||||
if (elem->has("logoScale"))
|
||||
mItemScale = glm::clamp(elem->get<float>("logoScale"), 0.5f, 3.0f);
|
||||
mItemScale = glm::clamp(elem->get<float>("logoScale"), 1.0f, 3.0f);
|
||||
if (elem->has("logoSize")) {
|
||||
// Keep size within a 0.05 and 1.0 multiple of the screen size.
|
||||
glm::vec2 itemSize {elem->get<glm::vec2>("logoSize")};
|
||||
|
@ -1206,7 +1217,9 @@ void CarouselComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
}
|
||||
}
|
||||
|
||||
mFont = Font::getFromTheme(elem, properties, mFont);
|
||||
// For non-legacy themes, scale the font size with the itemScale property value.
|
||||
mFont = Font::getFromTheme(elem, properties, mFont, 0.0f, mLegacyMode,
|
||||
(mLegacyMode ? 1.0f : (mItemScale >= 1.0f ? mItemScale : 1.0f)));
|
||||
|
||||
if (elem->has("textColor"))
|
||||
mTextColor = elem->get<unsigned int>("textColor");
|
||||
|
|
|
@ -350,10 +350,19 @@ template <typename T> void TextListComponent<T>::render(const glm::mat4& parentT
|
|||
int screenCount {0};
|
||||
float y {0.0f};
|
||||
|
||||
const float entrySize {
|
||||
std::max(floorf(font->getHeight(1.0f)), floorf(static_cast<float>(font->getSize()))) *
|
||||
mLineSpacing};
|
||||
const float lineSpacingHeight {floorf(font->getHeight(mLineSpacing) - font->getHeight(1.0f))};
|
||||
float entrySize {0.0f};
|
||||
float lineSpacingHeight {0.0f};
|
||||
|
||||
// The vertical spacing between rows for legacy themes is very inaccurate and will look
|
||||
// different depending on the resolution, but it's done for maximum backward compatibility.
|
||||
if (mLegacyMode) {
|
||||
entrySize = std::floor(font->getSize()) * mLineSpacing;
|
||||
lineSpacingHeight = std::floor(font->getSize()) * mLineSpacing - font->getSize() * 1.0f;
|
||||
}
|
||||
else {
|
||||
entrySize = font->getSize() * mLineSpacing;
|
||||
lineSpacingHeight = font->getSize() * mLineSpacing - font->getSize() * 1.0f;
|
||||
}
|
||||
|
||||
if (mLegacyMode) {
|
||||
// This extra vertical margin is technically incorrect, but it adds a little extra leeway
|
||||
|
@ -366,7 +375,9 @@ template <typename T> void TextListComponent<T>::render(const glm::mat4& parentT
|
|||
floorf((mSize.y + lineSpacingHeight / 2.0f + extraMargin) / entrySize));
|
||||
}
|
||||
else {
|
||||
screenCount = static_cast<int>(floorf((mSize.y + lineSpacingHeight / 2.0f) / entrySize));
|
||||
// Number of entries that can fit on the screen simultaneously.
|
||||
screenCount =
|
||||
static_cast<int>(std::floor((mSize.y + lineSpacingHeight / 2.0f) / entrySize));
|
||||
}
|
||||
|
||||
if (size() >= screenCount) {
|
||||
|
@ -478,11 +489,10 @@ template <typename T> void TextListComponent<T>::render(const glm::mat4& parentT
|
|||
// Currently selected item text might be looping.
|
||||
if (mCursor == i && mLoopOffset1 > 0) {
|
||||
drawTrans = glm::translate(
|
||||
drawTrans,
|
||||
glm::round(offset - glm::vec3 {static_cast<float>(mLoopOffset1), 0.0f, 0.0f}));
|
||||
drawTrans, offset - glm::vec3 {static_cast<float>(mLoopOffset1), 0.0f, 0.0f});
|
||||
}
|
||||
else {
|
||||
drawTrans = glm::translate(drawTrans, glm::round(offset));
|
||||
drawTrans = glm::translate(drawTrans, offset);
|
||||
}
|
||||
|
||||
// Needed to avoid flickering when returning to the start position.
|
||||
|
@ -497,8 +507,7 @@ template <typename T> void TextListComponent<T>::render(const glm::mat4& parentT
|
|||
mLoopScroll = true;
|
||||
drawTrans = trans;
|
||||
drawTrans = glm::translate(
|
||||
drawTrans,
|
||||
glm::round(offset - glm::vec3 {static_cast<float>(mLoopOffset2), 0.0f, 0.0f}));
|
||||
drawTrans, offset - glm::vec3 {static_cast<float>(mLoopOffset2), 0.0f, 0.0f});
|
||||
mRenderer->setMatrix(drawTrans);
|
||||
font->renderTextCache(entry.data.textCache.get());
|
||||
}
|
||||
|
@ -555,9 +564,8 @@ void TextListComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
setColor(1, elem->get<unsigned int>("secondaryColor"));
|
||||
}
|
||||
|
||||
setFont(Font::getFromTheme(elem, properties, mFont));
|
||||
const float selectorHeight {
|
||||
std::max(mFont->getHeight(1.0), static_cast<float>(mFont->getSize())) * mLineSpacing};
|
||||
setFont(Font::getFromTheme(elem, properties, mFont, 0.0f, mLegacyMode));
|
||||
const float selectorHeight {mFont->getHeight(mLineSpacing)};
|
||||
setSelectorHeight(selectorHeight);
|
||||
|
||||
if (properties & ALIGNMENT) {
|
||||
|
|
|
@ -52,7 +52,7 @@ void Renderer::setIcon()
|
|||
// Try creating SDL surface from logo data.
|
||||
SDL_Surface* logoSurface {SDL_CreateRGBSurfaceFrom(
|
||||
static_cast<void*>(rawData.data()), static_cast<int>(width), static_cast<int>(height),
|
||||
32, static_cast<int>((width * 4)), rmask, gmask, bmask, amask)};
|
||||
32, static_cast<int>(width * 4), rmask, gmask, bmask, amask)};
|
||||
|
||||
if (logoSurface != nullptr) {
|
||||
SDL_SetWindowIcon(mSDLWindow, logoSurface);
|
||||
|
@ -147,7 +147,7 @@ bool Renderer::createWindow()
|
|||
if (mWindowWidth != displayMode.w || mWindowHeight != displayMode.h)
|
||||
userResolution = true;
|
||||
|
||||
unsigned int windowFlags;
|
||||
unsigned int windowFlags {0};
|
||||
setup();
|
||||
|
||||
#if defined(_WIN64)
|
||||
|
@ -201,7 +201,7 @@ bool Renderer::createWindow()
|
|||
// instead we simply indicate the physical pixel dimensions in parenthesis in the log
|
||||
// file and make sure to double the window and screen sizes in case of a high DPI
|
||||
// display so that the full application window is used for rendering.
|
||||
int width = 0;
|
||||
int width {0};
|
||||
SDL_GL_GetDrawableSize(mSDLWindow, &width, nullptr);
|
||||
int scaleFactor = static_cast<int>(width / mWindowWidth);
|
||||
|
||||
|
@ -309,11 +309,11 @@ void Renderer::pushClipRect(const glm::ivec2& pos, const glm::ivec2& size)
|
|||
box.h = sScreenHeight - box.y;
|
||||
|
||||
if (mScreenRotated) {
|
||||
box = Rect(mWindowWidth - mScreenOffsetX - box.x - box.w,
|
||||
mWindowHeight - mScreenOffsetY - box.y - box.h, box.w, box.h);
|
||||
box = Rect {mWindowWidth - mScreenOffsetX - box.x - box.w,
|
||||
mWindowHeight - mScreenOffsetY - box.y - box.h, box.w, box.h};
|
||||
}
|
||||
else {
|
||||
box = Rect(mScreenOffsetX + box.x, mScreenOffsetY + box.y, box.w, box.h);
|
||||
box = Rect {mScreenOffsetX + box.x, mScreenOffsetY + box.y, box.w, box.h};
|
||||
}
|
||||
|
||||
// Make sure the box fits within mClipStack.top(), and clip further accordingly.
|
||||
|
@ -349,7 +349,7 @@ void Renderer::popClipRect()
|
|||
mClipStack.pop();
|
||||
|
||||
if (mClipStack.empty())
|
||||
setScissor(Rect(0, 0, 0, 0));
|
||||
setScissor(Rect {0, 0, 0, 0});
|
||||
else
|
||||
setScissor(mClipStack.top());
|
||||
}
|
||||
|
@ -360,7 +360,7 @@ void Renderer::drawRect(const float x,
|
|||
const float h,
|
||||
const unsigned int color,
|
||||
const unsigned int colorEnd,
|
||||
bool horizontalGradient,
|
||||
const bool horizontalGradient,
|
||||
const float opacity,
|
||||
const float dimming,
|
||||
const BlendFactor srcBlendFactor,
|
||||
|
|
|
@ -146,7 +146,7 @@ public:
|
|||
const float h,
|
||||
const unsigned int color,
|
||||
const unsigned int colorEnd,
|
||||
bool horizontalGradient = false,
|
||||
const bool horizontalGradient = false,
|
||||
const float opacity = 1.0,
|
||||
const float dimming = 1.0,
|
||||
const BlendFactor srcBlendFactor = BlendFactor::SRC_ALPHA,
|
||||
|
|
|
@ -33,19 +33,13 @@ RendererOpenGL::RendererOpenGL() noexcept
|
|||
{
|
||||
}
|
||||
|
||||
RendererOpenGL::~RendererOpenGL()
|
||||
{
|
||||
for (auto it = mShaderProgramVector.cbegin(); it != mShaderProgramVector.cend(); ++it)
|
||||
delete *it;
|
||||
}
|
||||
|
||||
RendererOpenGL* RendererOpenGL::getInstance()
|
||||
{
|
||||
static RendererOpenGL instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
ShaderOpenGL* RendererOpenGL::getShaderProgram(unsigned int shaderID)
|
||||
std::shared_ptr<ShaderOpenGL> RendererOpenGL::getShaderProgram(unsigned int shaderID)
|
||||
{
|
||||
unsigned int index {0};
|
||||
|
||||
|
@ -67,13 +61,13 @@ bool RendererOpenGL::loadShaders()
|
|||
LOG(LogInfo) << "Loading shaders...";
|
||||
|
||||
std::vector<std::string> shaderFiles;
|
||||
shaderFiles.push_back(":/shaders/glsl/core.glsl");
|
||||
shaderFiles.push_back(":/shaders/glsl/blur_horizontal.glsl");
|
||||
shaderFiles.push_back(":/shaders/glsl/blur_vertical.glsl");
|
||||
shaderFiles.push_back(":/shaders/glsl/scanlines.glsl");
|
||||
shaderFiles.emplace_back(":/shaders/glsl/core.glsl");
|
||||
shaderFiles.emplace_back(":/shaders/glsl/blur_horizontal.glsl");
|
||||
shaderFiles.emplace_back(":/shaders/glsl/blur_vertical.glsl");
|
||||
shaderFiles.emplace_back(":/shaders/glsl/scanlines.glsl");
|
||||
|
||||
for (auto it = shaderFiles.cbegin(); it != shaderFiles.cend(); ++it) {
|
||||
ShaderOpenGL* loadShader = new ShaderOpenGL();
|
||||
auto loadShader = std::make_shared<ShaderOpenGL>();
|
||||
|
||||
loadShader->loadShaderFile(*it, GL_VERTEX_SHADER);
|
||||
loadShader->loadShaderFile(*it, GL_FRAGMENT_SHADER);
|
||||
|
@ -83,7 +77,7 @@ bool RendererOpenGL::loadShaders()
|
|||
return false;
|
||||
}
|
||||
|
||||
mShaderProgramVector.push_back(loadShader);
|
||||
mShaderProgramVector.emplace_back(std::move(loadShader));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -576,7 +570,7 @@ void RendererOpenGL::shaderPostprocessing(unsigned int shaders,
|
|||
|
||||
for (size_t i = 0; i < shaderList.size(); ++i) {
|
||||
vertices->shaders = shaderList[i];
|
||||
int shaderPasses = 1;
|
||||
int shaderPasses {1};
|
||||
// For the blur shaders there is an optional variable to set the number of passes
|
||||
// to execute, which proportionally affects the blur amount.
|
||||
if (shaderList[i] == Renderer::Shader::BLUR_HORIZONTAL ||
|
||||
|
|
|
@ -20,15 +20,14 @@
|
|||
#include <SDL2/SDL_opengl.h>
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
|
||||
class RendererOpenGL : public Renderer
|
||||
{
|
||||
public:
|
||||
RendererOpenGL() noexcept;
|
||||
~RendererOpenGL();
|
||||
|
||||
static RendererOpenGL* getInstance();
|
||||
|
||||
ShaderOpenGL* getShaderProgram(unsigned int shaderID);
|
||||
std::shared_ptr<ShaderOpenGL> getShaderProgram(unsigned int shaderID);
|
||||
bool loadShaders() override;
|
||||
|
||||
GLenum convertBlendFactor(const BlendFactor BlendFactor);
|
||||
|
@ -73,7 +72,9 @@ public:
|
|||
unsigned char* textureRGBA = nullptr) override;
|
||||
|
||||
private:
|
||||
std::vector<ShaderOpenGL*> mShaderProgramVector;
|
||||
RendererOpenGL() noexcept;
|
||||
|
||||
std::vector<std::shared_ptr<ShaderOpenGL>> mShaderProgramVector;
|
||||
GLuint mShaderFBO1;
|
||||
GLuint mShaderFBO2;
|
||||
GLuint mVertexBuffer1;
|
||||
|
@ -83,14 +84,16 @@ private:
|
|||
GLuint mWhiteTexture;
|
||||
GLuint mPostProcTexture1;
|
||||
GLuint mPostProcTexture2;
|
||||
ShaderOpenGL* mCoreShader;
|
||||
ShaderOpenGL* mBlurHorizontalShader;
|
||||
ShaderOpenGL* mBlurVerticalShader;
|
||||
ShaderOpenGL* mScanlinelShader;
|
||||
ShaderOpenGL* mLastShader;
|
||||
std::shared_ptr<ShaderOpenGL> mCoreShader;
|
||||
std::shared_ptr<ShaderOpenGL> mBlurHorizontalShader;
|
||||
std::shared_ptr<ShaderOpenGL> mBlurVerticalShader;
|
||||
std::shared_ptr<ShaderOpenGL> mScanlinelShader;
|
||||
std::shared_ptr<ShaderOpenGL> mLastShader;
|
||||
|
||||
int mMajorGLVersion;
|
||||
int mMinorGLVersion;
|
||||
|
||||
friend Renderer;
|
||||
};
|
||||
|
||||
#endif // ES_CORE_RENDERER_RENDERER_OPENGL_H
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// Font.h
|
||||
//
|
||||
// Loading, unloading, caching and rendering of fonts.
|
||||
// Also functions for word wrapping and similar.
|
||||
// Also functions for text wrapping and similar.
|
||||
//
|
||||
|
||||
#include "resources/Font.h"
|
||||
|
@ -12,24 +12,23 @@
|
|||
#include "Log.h"
|
||||
#include "renderers/Renderer.h"
|
||||
#include "utils/FileSystemUtil.h"
|
||||
#include "utils/PlatformUtil.h"
|
||||
#include "utils/StringUtil.h"
|
||||
|
||||
FT_Library Font::sLibrary {nullptr};
|
||||
|
||||
std::map<std::pair<std::string, int>, std::weak_ptr<Font>> Font::sFontMap;
|
||||
|
||||
Font::Font(int size, const std::string& path)
|
||||
Font::Font(float size, const std::string& path)
|
||||
: mRenderer {Renderer::getInstance()}
|
||||
, mSize(size)
|
||||
, mMaxGlyphHeight {0}
|
||||
, mPath(path)
|
||||
, mFontSize {size}
|
||||
, mLetterHeight {0.0f}
|
||||
, mMaxGlyphHeight {static_cast<int>(std::round(size))}
|
||||
, mLegacyMaxGlyphHeight {0}
|
||||
{
|
||||
if (mSize < 9) {
|
||||
mSize = 9;
|
||||
if (mFontSize < 3.0f) {
|
||||
mFontSize = 3.0f;
|
||||
LOG(LogWarning) << "Requested font size too small, changing to minimum supported size";
|
||||
}
|
||||
else if (mSize > Renderer::getScreenHeight()) {
|
||||
mSize = static_cast<int>(Renderer::getScreenHeight());
|
||||
else if (mFontSize > Renderer::getScreenHeight() * 1.5f) {
|
||||
mFontSize = Renderer::getScreenHeight() * 1.5f;
|
||||
LOG(LogWarning) << "Requested font size too large, changing to maximum supported size";
|
||||
}
|
||||
|
||||
|
@ -37,7 +36,7 @@ Font::Font(int size, const std::string& path)
|
|||
initLibrary();
|
||||
|
||||
// Always initialize ASCII characters.
|
||||
for (unsigned int i = 32; i < 128; ++i)
|
||||
for (unsigned int i = 32; i < 127; ++i)
|
||||
getGlyph(i);
|
||||
|
||||
clearFaceCache();
|
||||
|
@ -47,7 +46,7 @@ Font::~Font()
|
|||
{
|
||||
unload(ResourceManager::getInstance());
|
||||
|
||||
auto fontEntry = sFontMap.find(std::pair<std::string, int>(mPath, mSize));
|
||||
auto fontEntry = sFontMap.find(std::pair<std::string, float>(mPath, mFontSize));
|
||||
|
||||
if (fontEntry != sFontMap.cend())
|
||||
sFontMap.erase(fontEntry);
|
||||
|
@ -58,50 +57,11 @@ Font::~Font()
|
|||
}
|
||||
}
|
||||
|
||||
void Font::initLibrary()
|
||||
{
|
||||
assert(sLibrary == nullptr);
|
||||
|
||||
if (FT_Init_FreeType(&sLibrary)) {
|
||||
sLibrary = nullptr;
|
||||
LOG(LogError) << "Couldn't initialize FreeType";
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> Font::getFallbackFontPaths()
|
||||
{
|
||||
std::vector<std::string> fontPaths;
|
||||
|
||||
// Standard fonts, let's include them here for exception handling purposes even though that's
|
||||
// not really the correct location. (The application will crash if they are missing.)
|
||||
ResourceManager::getInstance().getResourcePath(":/fonts/Akrobat-Regular.ttf");
|
||||
ResourceManager::getInstance().getResourcePath(":/fonts/Akrobat-SemiBold.ttf");
|
||||
ResourceManager::getInstance().getResourcePath(":/fonts/Akrobat-Bold.ttf");
|
||||
|
||||
// Vera sans Unicode.
|
||||
fontPaths.push_back(ResourceManager::getInstance().getResourcePath(":/fonts/DejaVuSans.ttf"));
|
||||
// GNU FreeFont monospaced.
|
||||
fontPaths.push_back(ResourceManager::getInstance().getResourcePath(":/fonts/FreeMono.ttf"));
|
||||
// Various languages, such as Japanese and Chinese.
|
||||
fontPaths.push_back(
|
||||
ResourceManager::getInstance().getResourcePath(":/fonts/DroidSansFallbackFull.ttf"));
|
||||
// Korean.
|
||||
fontPaths.push_back(
|
||||
ResourceManager::getInstance().getResourcePath(":/fonts/NanumMyeongjo.ttf"));
|
||||
// Font Awesome icon glyphs, used for various special symbols like stars, folders etc.
|
||||
fontPaths.push_back(
|
||||
ResourceManager::getInstance().getResourcePath(":/fonts/fontawesome-webfont.ttf"));
|
||||
// This is only needed for some really rare special characters.
|
||||
fontPaths.push_back(ResourceManager::getInstance().getResourcePath(":/fonts/Ubuntu-C.ttf"));
|
||||
|
||||
return fontPaths;
|
||||
}
|
||||
|
||||
std::shared_ptr<Font> Font::get(int size, const std::string& path)
|
||||
std::shared_ptr<Font> Font::get(float size, const std::string& path)
|
||||
{
|
||||
const std::string canonicalPath {Utils::FileSystem::getCanonicalPath(path)};
|
||||
std::pair<std::string, int> def {canonicalPath.empty() ? getDefaultPath() : canonicalPath,
|
||||
size};
|
||||
const std::pair<std::string, float> def {
|
||||
canonicalPath.empty() ? getDefaultPath() : canonicalPath, size};
|
||||
|
||||
auto foundFont = sFontMap.find(def);
|
||||
if (foundFont != sFontMap.cend()) {
|
||||
|
@ -109,7 +69,7 @@ std::shared_ptr<Font> Font::get(int size, const std::string& path)
|
|||
return foundFont->second.lock();
|
||||
}
|
||||
|
||||
std::shared_ptr<Font> font {std::shared_ptr<Font>(new Font(def.second, def.first))};
|
||||
std::shared_ptr<Font> font {new Font(def.second, def.first)};
|
||||
sFontMap[def] = std::weak_ptr<Font>(font);
|
||||
ResourceManager::getInstance().addReloadable(font);
|
||||
return font;
|
||||
|
@ -117,11 +77,9 @@ std::shared_ptr<Font> Font::get(int size, const std::string& path)
|
|||
|
||||
glm::vec2 Font::sizeText(std::string text, float lineSpacing)
|
||||
{
|
||||
const float lineHeight {getHeight(lineSpacing)};
|
||||
float lineWidth {0.0f};
|
||||
float highestWidth {0.0f};
|
||||
|
||||
const float lineHeight {getHeight(lineSpacing)};
|
||||
|
||||
float y {lineHeight};
|
||||
|
||||
size_t i {0};
|
||||
|
@ -147,14 +105,18 @@ glm::vec2 Font::sizeText(std::string text, float lineSpacing)
|
|||
return glm::vec2 {highestWidth, y};
|
||||
}
|
||||
|
||||
std::string Font::getTextMaxWidth(std::string text, float maxWidth)
|
||||
int Font::loadGlyphs(const std::string& text)
|
||||
{
|
||||
float width {sizeText(text).x};
|
||||
while (width > maxWidth) {
|
||||
text.pop_back();
|
||||
width = sizeText(text).x;
|
||||
mMaxGlyphHeight = static_cast<int>(std::round(mFontSize));
|
||||
|
||||
for (size_t i = 0; i < text.length();) {
|
||||
unsigned int character {Utils::String::chars2Unicode(text, i)}; // Advances i.
|
||||
Glyph* glyph {getGlyph(character)};
|
||||
|
||||
if (glyph->rows > mMaxGlyphHeight)
|
||||
mMaxGlyphHeight = glyph->rows;
|
||||
}
|
||||
return text;
|
||||
return mMaxGlyphHeight;
|
||||
}
|
||||
|
||||
TextCache* Font::buildTextCache(const std::string& text,
|
||||
|
@ -185,11 +147,14 @@ TextCache* Font::buildTextCache(const std::string& text,
|
|||
yBot = getHeight(1.5);
|
||||
}
|
||||
else {
|
||||
// TODO: This is lacking some precision which is especially visible at higher resolutions
|
||||
// like 4K where the text is not always placed entirely correctly vertically. Try to find
|
||||
// a way to improve on this.
|
||||
yTop = getGlyph('S')->bearing.y;
|
||||
yBot = getHeight(lineSpacing);
|
||||
}
|
||||
|
||||
float y {offset[1] + (yBot + yTop) / 2.0f};
|
||||
float y {std::round(offset[1] + (yBot + yTop) / 2.0f)};
|
||||
|
||||
// Vertices by texture.
|
||||
std::map<FontTexture*, std::vector<Renderer::Vertex>> vertMap;
|
||||
|
@ -254,14 +219,15 @@ TextCache* Font::buildTextCache(const std::string& text,
|
|||
|
||||
TextCache* cache {new TextCache()};
|
||||
cache->vertexLists.resize(vertMap.size());
|
||||
cache->metrics = {sizeText(text, lineSpacing)};
|
||||
cache->metrics.size = {sizeText(text, lineSpacing)};
|
||||
cache->metrics.maxGlyphHeight = mMaxGlyphHeight;
|
||||
|
||||
unsigned int i {0};
|
||||
size_t i {0};
|
||||
for (auto it = vertMap.cbegin(); it != vertMap.cend(); ++it) {
|
||||
TextCache::VertexList& vertList = cache->vertexLists.at(i);
|
||||
|
||||
TextCache::VertexList& vertList {cache->vertexLists.at(i)};
|
||||
vertList.textureIdPtr = &it->first->textureId;
|
||||
vertList.verts = it->second;
|
||||
++i;
|
||||
}
|
||||
|
||||
clearFaceCache();
|
||||
|
@ -287,220 +253,198 @@ void Font::renderTextCache(TextCache* cache)
|
|||
}
|
||||
}
|
||||
|
||||
std::string Font::wrapText(std::string text, float maxLength, float maxHeight, float lineSpacing)
|
||||
std::string Font::wrapText(const std::string& text,
|
||||
const float maxLength,
|
||||
const float maxHeight,
|
||||
const float lineSpacing,
|
||||
const bool multiLine)
|
||||
{
|
||||
assert(maxLength != 0.0f);
|
||||
|
||||
std::string out;
|
||||
std::string line;
|
||||
std::string word;
|
||||
std::string abbreviatedWord;
|
||||
std::string temp;
|
||||
|
||||
size_t space {0};
|
||||
glm::vec2 textSize {0.0f, 0.0f};
|
||||
const float dotsSize {sizeText("...").x};
|
||||
assert(maxLength > 0.0f);
|
||||
const float lineHeight {getHeight(lineSpacing)};
|
||||
float accumHeight {0.0f};
|
||||
const bool restrictHeight {maxHeight > 0.0f};
|
||||
bool skipLastLine {false};
|
||||
float currLineLength {0.0f};
|
||||
|
||||
// While there's text or we still have text to render.
|
||||
while (text.length() > 0) {
|
||||
if (restrictHeight && accumHeight > maxHeight)
|
||||
break;
|
||||
|
||||
space = text.find_first_of(" \t\n");
|
||||
|
||||
if (space == std::string::npos) {
|
||||
space = text.length() - 1;
|
||||
}
|
||||
else if (restrictHeight) {
|
||||
if (text.at(space) == '\n')
|
||||
accumHeight += lineHeight;
|
||||
}
|
||||
|
||||
word = text.substr(0, space + 1);
|
||||
text.erase(0, space + 1);
|
||||
|
||||
temp = line + word;
|
||||
|
||||
textSize = sizeText(temp);
|
||||
|
||||
// If the word will fit on the line, add it to our line and continue.
|
||||
if (textSize.x <= maxLength) {
|
||||
line = temp;
|
||||
currLineLength = textSize.x;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
// If the word is too long to fit within maxLength then abbreviate it.
|
||||
float wordSize {sizeText(word).x};
|
||||
if (restrictHeight && currLineLength != 0.0f && maxHeight < lineHeight &&
|
||||
wordSize > maxLength - textSize.x) {
|
||||
// Multi-word lines.
|
||||
if (maxLength - currLineLength + dotsSize < wordSize &&
|
||||
sizeText(line).x + dotsSize > maxLength) {
|
||||
while (sizeText(line).x + dotsSize > maxLength)
|
||||
line.pop_back();
|
||||
}
|
||||
else {
|
||||
while (word != "" && wordSize + dotsSize > maxLength - currLineLength) {
|
||||
word.pop_back();
|
||||
wordSize = sizeText(word).x;
|
||||
}
|
||||
|
||||
line = line + word;
|
||||
}
|
||||
|
||||
if (line.back() == ' ')
|
||||
line.pop_back();
|
||||
|
||||
line.append("...");
|
||||
break;
|
||||
}
|
||||
if (wordSize > maxLength) {
|
||||
|
||||
if (line != "" && line.back() != '\n') {
|
||||
if (restrictHeight) {
|
||||
if (accumHeight + lineHeight > maxHeight)
|
||||
continue;
|
||||
accumHeight += lineHeight;
|
||||
}
|
||||
line.append("\n");
|
||||
}
|
||||
|
||||
const float cutTarget {wordSize - maxLength + dotsSize};
|
||||
float cutSize {0.0f};
|
||||
|
||||
while (word != "" && cutSize < cutTarget) {
|
||||
cutSize += sizeText(word.substr(word.size() - 1)).x;
|
||||
word.pop_back();
|
||||
}
|
||||
|
||||
word.append("...");
|
||||
line = line + word;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
out += line + '\n';
|
||||
if (restrictHeight)
|
||||
accumHeight += lineHeight;
|
||||
|
||||
if (restrictHeight && accumHeight > maxHeight) {
|
||||
out.pop_back();
|
||||
skipLastLine = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
line = word;
|
||||
}
|
||||
}
|
||||
|
||||
// Whatever's left should fit.
|
||||
if (!skipLastLine)
|
||||
out.append(line);
|
||||
|
||||
if (restrictHeight && out.back() == '\n')
|
||||
out.pop_back();
|
||||
|
||||
// If the text has been abbreviated vertically then add "..." at the end of the string.
|
||||
if (restrictHeight && accumHeight > maxHeight) {
|
||||
if (out.back() != '\n') {
|
||||
float cutSize {0.0f};
|
||||
float cutTarget {sizeText(line).x - maxLength + dotsSize};
|
||||
while (cutSize < cutTarget) {
|
||||
cutSize += sizeText(out.substr(out.size() - 1)).x;
|
||||
out.pop_back();
|
||||
}
|
||||
}
|
||||
if (out.back() == ' ')
|
||||
out.pop_back();
|
||||
out.append("...");
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
glm::vec2 Font::sizeWrappedText(std::string text, float xLen, float lineSpacing)
|
||||
{
|
||||
text = wrapText(text, xLen);
|
||||
return sizeText(text, lineSpacing);
|
||||
}
|
||||
|
||||
glm::vec2 Font::getWrappedTextCursorOffset(std::string text,
|
||||
float xLen,
|
||||
size_t stop,
|
||||
float lineSpacing)
|
||||
{
|
||||
std::string wrappedText {wrapText(text, xLen)};
|
||||
|
||||
const float dotsWidth {sizeText("...").x};
|
||||
float accumHeight {lineHeight};
|
||||
float lineWidth {0.0f};
|
||||
float y {0.0f};
|
||||
|
||||
size_t wrapCursor {0};
|
||||
float charWidth {0.0f};
|
||||
float lastSpacePos {0.0f};
|
||||
unsigned int charID {0};
|
||||
size_t cursor {0};
|
||||
while (cursor < stop) {
|
||||
unsigned int wrappedCharacter {Utils::String::chars2Unicode(wrappedText, wrapCursor)};
|
||||
unsigned int character {Utils::String::chars2Unicode(text, cursor)};
|
||||
size_t lastSpace {0};
|
||||
size_t spaceAccum {0};
|
||||
size_t byteCount {0};
|
||||
std::string wrappedText;
|
||||
std::string charEntry;
|
||||
std::vector<std::pair<size_t, float>> dotsSection;
|
||||
bool addDots {false};
|
||||
|
||||
if (wrappedCharacter == '\n' && character != '\n') {
|
||||
// This is where the wordwrap inserted a newline
|
||||
// Reset lineWidth and increment y, but don't consume .a cursor character.
|
||||
for (size_t i = 0; i < text.length(); ++i) {
|
||||
if (text[i] == '\n') {
|
||||
if (!multiLine) {
|
||||
addDots = true;
|
||||
break;
|
||||
}
|
||||
wrappedText.append("\n");
|
||||
accumHeight += lineHeight;
|
||||
lineWidth = 0.0f;
|
||||
y += getHeight(lineSpacing);
|
||||
|
||||
cursor = Utils::String::prevCursor(text, cursor); // Unconsume.
|
||||
lastSpace = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
charWidth = 0.0f;
|
||||
byteCount = 0;
|
||||
cursor = i;
|
||||
|
||||
// Needed to handle multi-byte Unicode characters.
|
||||
charID = Utils::String::chars2Unicode(text, cursor);
|
||||
charEntry = text.substr(i, cursor - i);
|
||||
|
||||
Glyph* glyph {getGlyph(charID)};
|
||||
if (glyph != nullptr) {
|
||||
charWidth = glyph->advance.x;
|
||||
byteCount = cursor - i;
|
||||
}
|
||||
else {
|
||||
// Missing glyph.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (multiLine && (charEntry == " " || charEntry == "\t")) {
|
||||
lastSpace = i;
|
||||
lastSpacePos = lineWidth;
|
||||
}
|
||||
|
||||
if (lineWidth + charWidth <= maxLength) {
|
||||
if (lineWidth + charWidth + dotsWidth > maxLength)
|
||||
dotsSection.emplace_back(std::make_pair(byteCount, charWidth));
|
||||
lineWidth += charWidth;
|
||||
wrappedText.append(charEntry);
|
||||
}
|
||||
else if (!multiLine) {
|
||||
addDots = true;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if (maxHeight == 0.0f || accumHeight < maxHeight) {
|
||||
// New row.
|
||||
float spaceOffset {0.0f};
|
||||
if (lastSpace == wrappedText.size()) {
|
||||
wrappedText.append("\n");
|
||||
}
|
||||
else if (lastSpace != 0) {
|
||||
if (lastSpace + spaceAccum == wrappedText.size())
|
||||
wrappedText.append("\n");
|
||||
else
|
||||
wrappedText[lastSpace + spaceAccum] = '\n';
|
||||
spaceOffset = lineWidth - lastSpacePos;
|
||||
}
|
||||
else {
|
||||
if (lastSpace == 0)
|
||||
++spaceAccum;
|
||||
wrappedText.append("\n");
|
||||
}
|
||||
if (charEntry != " " && charEntry != "\t") {
|
||||
wrappedText.append(charEntry);
|
||||
lineWidth = charWidth;
|
||||
}
|
||||
else {
|
||||
lineWidth = 0.0f;
|
||||
}
|
||||
accumHeight += lineHeight;
|
||||
lineWidth += spaceOffset;
|
||||
lastSpacePos = 0.0f;
|
||||
lastSpace = 0;
|
||||
}
|
||||
else {
|
||||
if (multiLine)
|
||||
addDots = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
i = cursor - 1;
|
||||
}
|
||||
|
||||
if (addDots) {
|
||||
if (!wrappedText.empty() && wrappedText.back() == ' ') {
|
||||
lineWidth -= sizeText(" ").x;
|
||||
wrappedText.pop_back();
|
||||
}
|
||||
else if (!wrappedText.empty() && wrappedText.back() == '\t') {
|
||||
lineWidth -= sizeText("\t").x;
|
||||
wrappedText.pop_back();
|
||||
}
|
||||
while (!wrappedText.empty() && !dotsSection.empty() && lineWidth + dotsWidth > maxLength) {
|
||||
lineWidth -= dotsSection.back().second;
|
||||
wrappedText.erase(wrappedText.length() - dotsSection.back().first);
|
||||
dotsSection.pop_back();
|
||||
}
|
||||
if (!wrappedText.empty() && wrappedText.back() == ' ')
|
||||
wrappedText.pop_back();
|
||||
|
||||
wrappedText.append("...");
|
||||
}
|
||||
|
||||
return wrappedText;
|
||||
}
|
||||
|
||||
glm::vec2 Font::getWrappedTextCursorOffset(const std::string& wrappedText,
|
||||
const size_t stop,
|
||||
const float lineSpacing)
|
||||
{
|
||||
float lineWidth {0.0f};
|
||||
float yPos {0.0f};
|
||||
size_t cursor {0};
|
||||
|
||||
while (cursor < stop) {
|
||||
unsigned int character {Utils::String::chars2Unicode(wrappedText, cursor)};
|
||||
if (character == '\n') {
|
||||
lineWidth = 0.0f;
|
||||
y += getHeight(lineSpacing);
|
||||
yPos += getHeight(lineSpacing);
|
||||
continue;
|
||||
}
|
||||
|
||||
Glyph* glyph = getGlyph(character);
|
||||
Glyph* glyph {getGlyph(character)};
|
||||
if (glyph)
|
||||
lineWidth += glyph->advance.x;
|
||||
}
|
||||
|
||||
return glm::vec2 {lineWidth, y};
|
||||
}
|
||||
|
||||
float Font::getHeight(float lineSpacing) const
|
||||
{
|
||||
// Return overall height including line spacing.
|
||||
return mMaxGlyphHeight * lineSpacing;
|
||||
return glm::vec2 {lineWidth, yPos};
|
||||
}
|
||||
|
||||
float Font::getLetterHeight()
|
||||
{
|
||||
Glyph* glyph {getGlyph('S')};
|
||||
assert(glyph);
|
||||
return glyph->texSize.y * glyph->texture->textureSize.y;
|
||||
if (mLetterHeight == 0.0f)
|
||||
return mFontSize * 0.737f; // Only needed if face does not contain the letter 'S'.
|
||||
else
|
||||
return mLetterHeight;
|
||||
}
|
||||
|
||||
std::shared_ptr<Font> Font::getFromTheme(const ThemeData::ThemeElement* elem,
|
||||
unsigned int properties,
|
||||
const std::shared_ptr<Font>& orig)
|
||||
const std::shared_ptr<Font>& orig,
|
||||
const float maxHeight,
|
||||
const bool legacyTheme,
|
||||
const float sizeMultiplier)
|
||||
{
|
||||
mLegacyTheme = legacyTheme;
|
||||
|
||||
using namespace ThemeFlags;
|
||||
if (!(properties & FONT_PATH) && !(properties & FONT_SIZE))
|
||||
return orig;
|
||||
|
||||
std::shared_ptr<Font> font;
|
||||
int size {static_cast<int>(orig ? orig->mSize : FONT_SIZE_MEDIUM)};
|
||||
float size {static_cast<float>(orig ? orig->mFontSize : FONT_SIZE_MEDIUM)};
|
||||
std::string path {orig ? orig->mPath : getDefaultPath()};
|
||||
|
||||
float sh {static_cast<float>(Renderer::getScreenHeight())};
|
||||
float screenHeight {static_cast<float>(Renderer::getScreenHeight())};
|
||||
|
||||
// Make sure the size is not unreasonably large (which may be caused by a mistake in the
|
||||
// theme configuration).
|
||||
if (properties & FONT_SIZE && elem->has("fontSize"))
|
||||
size = glm::clamp(static_cast<int>(sh * elem->get<float>("fontSize")), 0,
|
||||
static_cast<int>(Renderer::getInstance()->getScreenHeight()));
|
||||
if (properties & FONT_SIZE && elem->has("fontSize")) {
|
||||
size = glm::clamp(screenHeight * elem->get<float>("fontSize"), screenHeight * 0.001f,
|
||||
screenHeight * 1.5f);
|
||||
// This is used by the carousel where the itemScale property also scales the font size.
|
||||
size *= sizeMultiplier;
|
||||
}
|
||||
|
||||
if (maxHeight != 0.0f && size > maxHeight)
|
||||
size = maxHeight;
|
||||
|
||||
if (properties & FONT_PATH && elem->has("fontPath"))
|
||||
path = elem->get<std::string>("fontPath");
|
||||
|
@ -513,6 +457,9 @@ std::shared_ptr<Font> Font::getFromTheme(const ThemeData::ThemeElement* elem,
|
|||
path = getDefaultPath();
|
||||
}
|
||||
|
||||
if (mLegacyTheme)
|
||||
return get(std::floor(size), path);
|
||||
else
|
||||
return get(size, path);
|
||||
}
|
||||
|
||||
|
@ -520,7 +467,7 @@ size_t Font::getMemUsage() const
|
|||
{
|
||||
size_t memUsage {0};
|
||||
for (auto it = mTextures.cbegin(); it != mTextures.cend(); ++it)
|
||||
memUsage += it->textureSize.x * it->textureSize.y * 4;
|
||||
memUsage += (*it)->textureSize.x * (*it)->textureSize.y * 4;
|
||||
|
||||
for (auto it = mFaceCache.cbegin(); it != mFaceCache.cend(); ++it)
|
||||
memUsage += it->second->data.length;
|
||||
|
@ -546,38 +493,43 @@ size_t Font::getTotalMemUsage()
|
|||
return total;
|
||||
}
|
||||
|
||||
Font::FontTexture::FontTexture(const int mSize)
|
||||
std::vector<std::string> Font::getFallbackFontPaths()
|
||||
{
|
||||
std::vector<std::string> fontPaths;
|
||||
|
||||
// Default application fonts.
|
||||
ResourceManager::getInstance().getResourcePath(":/fonts/Akrobat-Regular.ttf");
|
||||
ResourceManager::getInstance().getResourcePath(":/fonts/Akrobat-SemiBold.ttf");
|
||||
ResourceManager::getInstance().getResourcePath(":/fonts/Akrobat-Bold.ttf");
|
||||
|
||||
// Vera sans Unicode.
|
||||
fontPaths.push_back(ResourceManager::getInstance().getResourcePath(":/fonts/DejaVuSans.ttf"));
|
||||
// GNU FreeFont monospaced.
|
||||
fontPaths.push_back(ResourceManager::getInstance().getResourcePath(":/fonts/FreeMono.ttf"));
|
||||
// Various languages, such as Japanese and Chinese.
|
||||
fontPaths.push_back(
|
||||
ResourceManager::getInstance().getResourcePath(":/fonts/DroidSansFallbackFull.ttf"));
|
||||
// Korean.
|
||||
fontPaths.push_back(
|
||||
ResourceManager::getInstance().getResourcePath(":/fonts/NanumMyeongjo.ttf"));
|
||||
// Font Awesome icon glyphs, used for various special symbols like stars, folders etc.
|
||||
fontPaths.push_back(
|
||||
ResourceManager::getInstance().getResourcePath(":/fonts/fontawesome-webfont.ttf"));
|
||||
// This is only needed for some really rare special characters.
|
||||
fontPaths.push_back(ResourceManager::getInstance().getResourcePath(":/fonts/Ubuntu-C.ttf"));
|
||||
|
||||
return fontPaths;
|
||||
}
|
||||
|
||||
Font::FontTexture::FontTexture(const int mFontSize)
|
||||
{
|
||||
textureId = 0;
|
||||
|
||||
// This is a hack to add some extra texture size when running at very low resolutions. If not
|
||||
// doing this, the use of fallback fonts (such as Japanese characters) could result in the
|
||||
// texture not fitting the glyphs.
|
||||
int extraTextureSize {0};
|
||||
const float screenSizeModifier {
|
||||
std::min(Renderer::getScreenWidthModifier(), Renderer::getScreenHeightModifier())};
|
||||
|
||||
if (screenSizeModifier < 0.2f)
|
||||
extraTextureSize += 6;
|
||||
if (screenSizeModifier < 0.45f)
|
||||
extraTextureSize += 4;
|
||||
|
||||
// It's not entirely clear if the 20 and 16 constants are correct, but they seem to provide
|
||||
// a texture buffer large enough to hold the fonts. This logic is obviously a hack though
|
||||
// and needs to be properly reviewed and improved.
|
||||
textureSize = glm::ivec2 {mSize * (20 + extraTextureSize), mSize * (16 + extraTextureSize / 2)};
|
||||
|
||||
// Make sure the size is not unreasonably large (which may be caused by a mistake in the
|
||||
// theme configuration).
|
||||
if (textureSize.x > static_cast<int>(Renderer::getScreenWidth()) * 10)
|
||||
textureSize.x =
|
||||
glm::clamp(textureSize.x, 0, static_cast<int>(Renderer::getScreenWidth()) * 10);
|
||||
if (textureSize.y > static_cast<int>(Renderer::getScreenHeight()) * 10)
|
||||
textureSize.y =
|
||||
glm::clamp(textureSize.y, 0, static_cast<int>(Renderer::getScreenHeight()) * 10);
|
||||
|
||||
writePos = glm::ivec2 {0, 0};
|
||||
rowHeight = 0;
|
||||
writePos = glm::ivec2 {0, 0};
|
||||
|
||||
// Set the texture to a reasonable size, if we run out of space for adding glyphs then
|
||||
// more textures will be created dynamically.
|
||||
textureSize = glm::ivec2 {mFontSize * 6, mFontSize * 6};
|
||||
}
|
||||
|
||||
Font::FontTexture::~FontTexture()
|
||||
|
@ -593,19 +545,18 @@ bool Font::FontTexture::findEmpty(const glm::ivec2& size, glm::ivec2& cursor_out
|
|||
|
||||
if (writePos.x + size.x >= textureSize.x &&
|
||||
writePos.y + rowHeight + size.y + 1 < textureSize.y) {
|
||||
// Row full, but it should fit on the next row so move the cursor there.
|
||||
// Leave 1px of space between glyphs.
|
||||
// Row is full, but the glyph should fit on the next row so move the cursor there.
|
||||
// Leave 1 pixel of space between glyphs so that pixels from adjacent glyphs will
|
||||
// not get sampled during scaling which would lead to edge artifacts.
|
||||
writePos = glm::ivec2 {0, writePos.y + rowHeight + 1};
|
||||
rowHeight = 0;
|
||||
}
|
||||
|
||||
if (writePos.x + size.x >= textureSize.x || writePos.y + size.y >= textureSize.y) {
|
||||
// Nope, still won't fit.
|
||||
return false;
|
||||
}
|
||||
if (writePos.x + size.x >= textureSize.x || writePos.y + size.y >= textureSize.y)
|
||||
return false; // No it still won't fit.
|
||||
|
||||
cursor_out = writePos;
|
||||
// Leave 1px of space between glyphs.
|
||||
// Leave 1 pixel of space between glyphs.
|
||||
writePos.x += size.x + 1;
|
||||
|
||||
if (size.y > rowHeight)
|
||||
|
@ -617,9 +568,13 @@ bool Font::FontTexture::findEmpty(const glm::ivec2& size, glm::ivec2& cursor_out
|
|||
void Font::FontTexture::initTexture()
|
||||
{
|
||||
assert(textureId == 0);
|
||||
// Create a black texture with zero alpha value so that the single-pixel spaces between the
|
||||
// glyphs will not be visible. That would otherwise lead to edge artifacts as these pixels
|
||||
// would get sampled during scaling.
|
||||
std::vector<uint8_t> texture(textureSize.x * textureSize.y * 4, 0);
|
||||
textureId =
|
||||
Renderer::getInstance()->createTexture(Renderer::TextureType::RED, true, false, false,
|
||||
false, textureSize.x, textureSize.y, nullptr);
|
||||
false, textureSize.x, textureSize.y, &texture[0]);
|
||||
}
|
||||
|
||||
void Font::FontTexture::deinitTexture()
|
||||
|
@ -630,15 +585,19 @@ void Font::FontTexture::deinitTexture()
|
|||
}
|
||||
}
|
||||
|
||||
Font::FontFace::FontFace(ResourceData&& d, int size)
|
||||
Font::FontFace::FontFace(ResourceData&& d, float size, const std::string& path)
|
||||
: data {d}
|
||||
{
|
||||
int err {
|
||||
FT_New_Memory_Face(sLibrary, data.ptr.get(), static_cast<FT_Long>(data.length), 0, &face)};
|
||||
assert(!err);
|
||||
if (FT_New_Memory_Face(sLibrary, d.ptr.get(), static_cast<FT_Long>(d.length), 0, &face) != 0) {
|
||||
LOG(LogError) << "Couldn't load font file \"" << path << "\"";
|
||||
Utils::Platform::emergencyShutdown();
|
||||
}
|
||||
|
||||
if (!err)
|
||||
FT_Set_Pixel_Sizes(face, 0, size);
|
||||
// Even though a fractional font size can be requested, the glyphs will always be rounded
|
||||
// to integers. It's not useless to call FT_Set_Char_Size() instead of FT_Set_Pixel_Sizes()
|
||||
// though as the glyphs will still be much more evenely sized across different resolutions.
|
||||
FT_Set_Char_Size(face, static_cast<FT_F26Dot6>(0.0f), static_cast<FT_F26Dot6>(size * 64.0f), 0,
|
||||
0);
|
||||
}
|
||||
|
||||
Font::FontFace::~FontFace()
|
||||
|
@ -647,11 +606,21 @@ Font::FontFace::~FontFace()
|
|||
FT_Done_Face(face);
|
||||
}
|
||||
|
||||
void Font::initLibrary()
|
||||
{
|
||||
assert(sLibrary == nullptr);
|
||||
|
||||
if (FT_Init_FreeType(&sLibrary)) {
|
||||
sLibrary = nullptr;
|
||||
LOG(LogError) << "Couldn't initialize FreeType";
|
||||
}
|
||||
}
|
||||
|
||||
void Font::rebuildTextures()
|
||||
{
|
||||
// Recreate OpenGL textures.
|
||||
for (auto it = mTextures.begin(); it != mTextures.end(); ++it)
|
||||
it->initTexture();
|
||||
(*it)->initTexture();
|
||||
|
||||
// Re-upload the texture data.
|
||||
for (auto it = mGlyphMap.cbegin(); it != mGlyphMap.cend(); ++it) {
|
||||
|
@ -678,7 +647,7 @@ void Font::rebuildTextures()
|
|||
void Font::unloadTextures()
|
||||
{
|
||||
for (auto it = mTextures.begin(); it != mTextures.end(); ++it)
|
||||
it->deinitTexture();
|
||||
(*it)->deinitTexture();
|
||||
}
|
||||
|
||||
void Font::getTextureForNewGlyph(const glm::ivec2& glyphSize,
|
||||
|
@ -686,29 +655,19 @@ void Font::getTextureForNewGlyph(const glm::ivec2& glyphSize,
|
|||
glm::ivec2& cursor_out)
|
||||
{
|
||||
if (mTextures.size()) {
|
||||
// Check if the most recent texture has space.
|
||||
tex_out = &mTextures.back();
|
||||
// Check if the most recent texture has space available for the glyph.
|
||||
tex_out = mTextures.back().get();
|
||||
|
||||
// Will this one work?
|
||||
if (tex_out->findEmpty(glyphSize, cursor_out))
|
||||
return; // Yes.
|
||||
}
|
||||
|
||||
// This should never happen, assuming the texture size is large enough to fit the font,
|
||||
// as set in the FontTexture constructor. In the unlikely situation that it still happens,
|
||||
// setting the texture to nullptr makes sure the application doesn't crash and that the
|
||||
// user is clearly notified of the problem by the fact that the glyph/character will be
|
||||
// completely missing.
|
||||
if (mGlyphMap.size() > 0) {
|
||||
tex_out = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
mTextures.push_back(FontTexture(mSize));
|
||||
tex_out = &mTextures.back();
|
||||
mTextures.emplace_back(std::make_unique<FontTexture>(static_cast<int>(std::round(mFontSize))));
|
||||
tex_out = mTextures.back().get();
|
||||
tex_out->initTexture();
|
||||
|
||||
bool ok = tex_out->findEmpty(glyphSize, cursor_out);
|
||||
bool ok {tex_out->findEmpty(glyphSize, cursor_out)};
|
||||
if (!ok) {
|
||||
LOG(LogError) << "Glyph too big to fit on a new texture (glyph size > "
|
||||
<< tex_out->textureSize.x << ", " << tex_out->textureSize.y << ")";
|
||||
|
@ -720,18 +679,15 @@ FT_Face Font::getFaceForChar(unsigned int id)
|
|||
{
|
||||
static const std::vector<std::string> fallbackFonts {getFallbackFontPaths()};
|
||||
|
||||
// Look through our current font + fallback fonts to see if any have the
|
||||
// glyph we're looking for.
|
||||
// Look for the glyph in our current font and then in the fallback fonts if needed.
|
||||
for (unsigned int i = 0; i < fallbackFonts.size() + 1; ++i) {
|
||||
auto fit = mFaceCache.find(i);
|
||||
|
||||
// Doesn't exist yet.
|
||||
if (fit == mFaceCache.cend()) {
|
||||
// i == 0 -> mPath
|
||||
// Otherwise, take from fallbackFonts.
|
||||
const std::string& path {i == 0 ? mPath : fallbackFonts.at(i - 1)};
|
||||
ResourceData data {ResourceManager::getInstance().getFileData(path)};
|
||||
mFaceCache[i] = std::unique_ptr<FontFace>(new FontFace(std::move(data), mSize));
|
||||
mFaceCache[i] =
|
||||
std::unique_ptr<FontFace>(new FontFace(std::move(data), mFontSize, mPath));
|
||||
fit = mFaceCache.find(i);
|
||||
}
|
||||
|
||||
|
@ -739,18 +695,18 @@ FT_Face Font::getFaceForChar(unsigned int id)
|
|||
return fit->second->face;
|
||||
}
|
||||
|
||||
// Nothing has a valid glyph - return the "real" face so we get a "missing" character.
|
||||
// Couldn't find a valid glyph, return the "real" face so we get a "missing" character.
|
||||
return mFaceCache.cbegin()->second->face;
|
||||
}
|
||||
|
||||
Font::Glyph* Font::getGlyph(const unsigned int id)
|
||||
{
|
||||
// Is it already loaded?
|
||||
// Check if the glyph has already been loaded.
|
||||
auto it = mGlyphMap.find(id);
|
||||
if (it != mGlyphMap.cend())
|
||||
return &it->second;
|
||||
|
||||
// Nope, need to make a glyph.
|
||||
// We need to create a new entry.
|
||||
FT_Face face {getFaceForChar(id)};
|
||||
if (!face) {
|
||||
LOG(LogError) << "Couldn't find appropriate font face for character " << id << " for font "
|
||||
|
@ -758,28 +714,39 @@ Font::Glyph* Font::getGlyph(const unsigned int id)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
FT_GlyphSlot g {face->glyph};
|
||||
const FT_GlyphSlot glyphSlot {face->glyph};
|
||||
|
||||
if (FT_Load_Char(face, id, FT_LOAD_RENDER)) {
|
||||
// TODO: Evaluate/test hinting when HarfBuzz has been added.
|
||||
// If the font does not contain hinting information then force the use of the automatic
|
||||
// hinter that is built into FreeType.
|
||||
// const bool hasHinting {static_cast<bool>(glyphSlot->face->face_flags & FT_FACE_FLAG_HINTER)};
|
||||
const bool hasHinting {true};
|
||||
|
||||
if (FT_Load_Char(face, id,
|
||||
(hasHinting ?
|
||||
FT_LOAD_RENDER :
|
||||
FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT))) {
|
||||
LOG(LogError) << "Couldn't find glyph for character " << id << " for font " << mPath
|
||||
<< ", size " << mSize;
|
||||
<< ", size " << mFontSize;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
glm::ivec2 glyphSize {g->bitmap.width, g->bitmap.rows};
|
||||
|
||||
FontTexture* tex {nullptr};
|
||||
glm::ivec2 cursor {0, 0};
|
||||
const glm::ivec2 glyphSize {glyphSlot->bitmap.width, glyphSlot->bitmap.rows};
|
||||
getTextureForNewGlyph(glyphSize, tex, cursor);
|
||||
|
||||
// getTextureForNewGlyph can fail if the glyph is bigger than the max texture
|
||||
// size (absurdly large font size).
|
||||
// This should (hopefully) never occur as size constraints are enforced earlier on.
|
||||
if (tex == nullptr) {
|
||||
LOG(LogError) << "Couldn't create glyph for character " << id << " for font " << mPath
|
||||
<< ", size " << mSize << " (no suitable texture found)";
|
||||
<< ", size " << mFontSize << " (no suitable texture found)";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Use the letter 'S' as a size reference.
|
||||
if (mLetterHeight == 0 && id == 'S')
|
||||
mLetterHeight = static_cast<float>(glyphSize.y);
|
||||
|
||||
// Create glyph.
|
||||
Glyph& glyph {mGlyphMap[id]};
|
||||
|
||||
|
@ -788,21 +755,19 @@ Font::Glyph* Font::getGlyph(const unsigned int id)
|
|||
cursor.y / static_cast<float>(tex->textureSize.y)};
|
||||
glyph.texSize = glm::vec2 {glyphSize.x / static_cast<float>(tex->textureSize.x),
|
||||
glyphSize.y / static_cast<float>(tex->textureSize.y)};
|
||||
|
||||
glyph.advance = glm::vec2 {static_cast<float>(g->metrics.horiAdvance) / 64.0f,
|
||||
static_cast<float>(g->metrics.vertAdvance) / 64.0f};
|
||||
glyph.bearing = glm::vec2 {static_cast<float>(g->metrics.horiBearingX) / 64.0f,
|
||||
static_cast<float>(g->metrics.horiBearingY) / 64.0f};
|
||||
glyph.advance = glm::vec2 {static_cast<float>(glyphSlot->metrics.horiAdvance) / 64.0f,
|
||||
static_cast<float>(glyphSlot->metrics.vertAdvance) / 64.0f};
|
||||
glyph.bearing = glm::vec2 {static_cast<float>(glyphSlot->metrics.horiBearingX) / 64.0f,
|
||||
static_cast<float>(glyphSlot->metrics.horiBearingY) / 64.0f};
|
||||
glyph.rows = glyphSlot->bitmap.rows;
|
||||
|
||||
// Upload glyph bitmap to texture.
|
||||
mRenderer->updateTexture(tex->textureId, Renderer::TextureType::RED, cursor.x, cursor.y,
|
||||
glyphSize.x, glyphSize.y, g->bitmap.buffer);
|
||||
glyphSize.x, glyphSize.y, glyphSlot->bitmap.buffer);
|
||||
|
||||
// Update max glyph height.
|
||||
if (glyphSize.y > mMaxGlyphHeight)
|
||||
mMaxGlyphHeight = glyphSize.y;
|
||||
if (glyphSize.y > mLegacyMaxGlyphHeight)
|
||||
mLegacyMaxGlyphHeight = glyphSize.y;
|
||||
|
||||
// Done.
|
||||
return &glyph;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// Font.h
|
||||
//
|
||||
// Loading, unloading, caching and rendering of fonts.
|
||||
// Also functions for word wrapping and similar.
|
||||
// Also functions for text wrapping and similar.
|
||||
//
|
||||
|
||||
#ifndef ES_CORE_RESOURCES_FONT_H
|
||||
|
@ -21,16 +21,10 @@
|
|||
|
||||
class TextCache;
|
||||
|
||||
// clang-format off
|
||||
#define FONT_SIZE_MINI (static_cast<unsigned int>(0.030f * \
|
||||
std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth())))
|
||||
#define FONT_SIZE_SMALL (static_cast<unsigned int>(0.035f * \
|
||||
std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth())))
|
||||
#define FONT_SIZE_MEDIUM (static_cast<unsigned int>(0.045f * \
|
||||
std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth())))
|
||||
#define FONT_SIZE_LARGE (static_cast<unsigned int>(0.085f * \
|
||||
std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth())))
|
||||
// clang-format on
|
||||
#define FONT_SIZE_MINI 0.030f * std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth())
|
||||
#define FONT_SIZE_SMALL 0.035f * std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth())
|
||||
#define FONT_SIZE_MEDIUM 0.045f * std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth())
|
||||
#define FONT_SIZE_LARGE 0.085f * std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth())
|
||||
|
||||
#define FONT_PATH_LIGHT ":/fonts/Akrobat-Regular.ttf"
|
||||
#define FONT_PATH_REGULAR ":/fonts/Akrobat-SemiBold.ttf"
|
||||
|
@ -42,15 +36,19 @@ class Font : public IReloadable
|
|||
{
|
||||
public:
|
||||
virtual ~Font();
|
||||
static void initLibrary();
|
||||
std::vector<std::string> getFallbackFontPaths();
|
||||
static std::shared_ptr<Font> get(int size, const std::string& path = getDefaultPath());
|
||||
static std::shared_ptr<Font> get(float size, const std::string& path = getDefaultPath());
|
||||
|
||||
// Returns the expected size of a string when rendered. Extra spacing is applied to the Y axis.
|
||||
glm::vec2 sizeText(std::string text, float lineSpacing = 1.5f);
|
||||
|
||||
// Returns the portion of a string that fits within the passed argument maxWidth.
|
||||
std::string getTextMaxWidth(std::string text, float maxWidth);
|
||||
// Used to determine mMaxGlyphHeight upfront which is needed for accurate text sizing by
|
||||
// wrapText and buildTextCache. This is required as the requested font height is not
|
||||
// guaranteed and can be exceeded by a few pixels for some glyphs.
|
||||
int loadGlyphs(const std::string& text);
|
||||
|
||||
// This is needed to retain a bug from the legacy theme engine where lineSpacing is not
|
||||
// sized correctly when using automatic text element sizing.
|
||||
void useLegacyMaxGlyphHeight() { mMaxGlyphHeight = mLegacyMaxGlyphHeight; }
|
||||
|
||||
TextCache* buildTextCache(const std::string& text,
|
||||
float offsetX,
|
||||
|
@ -69,34 +67,35 @@ public:
|
|||
|
||||
void renderTextCache(TextCache* cache);
|
||||
|
||||
// Inserts newlines into text to make it wrap properly.
|
||||
std::string wrapText(std::string text,
|
||||
float maxLength,
|
||||
float maxHeight = 0.0f,
|
||||
float lineSpacing = 1.5f);
|
||||
// Inserts newlines to make text wrap properly and also abbreviates single-line text.
|
||||
std::string wrapText(const std::string& text,
|
||||
const float maxLength,
|
||||
const float maxHeight = 0.0f,
|
||||
const float lineSpacing = 1.5f,
|
||||
const bool multiLine = false);
|
||||
|
||||
// Returns the expected size of a string after wrapping is applied.
|
||||
glm::vec2 sizeWrappedText(std::string text, float xLen, float lineSpacing = 1.5f);
|
||||
// Returns the position of the cursor after moving it to the stop position.
|
||||
glm::vec2 getWrappedTextCursorOffset(const std::string& wrappedText,
|
||||
const size_t stop,
|
||||
const float lineSpacing = 1.5f);
|
||||
|
||||
// Returns the position of the cursor after moving a "cursor" amount of characters.
|
||||
glm::vec2 getWrappedTextCursorOffset(std::string text,
|
||||
float xLen,
|
||||
size_t cursor,
|
||||
float lineSpacing = 1.5f);
|
||||
|
||||
float getHeight(float lineSpacing = 1.5f) const;
|
||||
// Return overall height including line spacing.
|
||||
float getHeight(float lineSpacing = 1.5f) const { return mMaxGlyphHeight * lineSpacing; }
|
||||
float getLetterHeight();
|
||||
|
||||
void reload(ResourceManager& rm) override { rebuildTextures(); }
|
||||
void unload(ResourceManager& rm) override { unloadTextures(); }
|
||||
|
||||
int getSize() const { return mSize; }
|
||||
const float getSize() const { return mFontSize; }
|
||||
const std::string& getPath() const { return mPath; }
|
||||
static std::string getDefaultPath() { return FONT_PATH_REGULAR; }
|
||||
|
||||
static std::shared_ptr<Font> getFromTheme(const ThemeData::ThemeElement* elem,
|
||||
unsigned int properties,
|
||||
const std::shared_ptr<Font>& orig);
|
||||
const std::shared_ptr<Font>& orig,
|
||||
const float maxHeight = 0.0f,
|
||||
const bool legacyTheme = false,
|
||||
const float sizeMultiplier = 1.0f);
|
||||
|
||||
// Returns an approximation of VRAM used by this font's texture (in bytes).
|
||||
size_t getMemUsage() const;
|
||||
|
@ -104,20 +103,16 @@ public:
|
|||
static size_t getTotalMemUsage();
|
||||
|
||||
private:
|
||||
Renderer* mRenderer;
|
||||
static FT_Library sLibrary;
|
||||
static std::map<std::pair<std::string, int>, std::weak_ptr<Font>> sFontMap;
|
||||
|
||||
Font(int size, const std::string& path);
|
||||
Font(float size, const std::string& path);
|
||||
static void initLibrary();
|
||||
|
||||
struct FontTexture {
|
||||
unsigned int textureId;
|
||||
glm::ivec2 textureSize;
|
||||
|
||||
glm::ivec2 writePos;
|
||||
int rowHeight;
|
||||
|
||||
FontTexture(const int mSize);
|
||||
FontTexture(const int mFontSize);
|
||||
~FontTexture();
|
||||
bool findEmpty(const glm::ivec2& size, glm::ivec2& cursor_out);
|
||||
|
||||
|
@ -126,8 +121,7 @@ private:
|
|||
// updating textureId.
|
||||
void initTexture();
|
||||
|
||||
// Deinitializes the OpenGL texture if any exists, is automatically called
|
||||
// in the destructor.
|
||||
// Deinitializes any existing OpenGL textures, is automatically called in destructor.
|
||||
void deinitTexture();
|
||||
};
|
||||
|
||||
|
@ -135,10 +129,19 @@ private:
|
|||
const ResourceData data;
|
||||
FT_Face face;
|
||||
|
||||
FontFace(ResourceData&& d, int size);
|
||||
FontFace(ResourceData&& d, float size, const std::string& path);
|
||||
virtual ~FontFace();
|
||||
};
|
||||
|
||||
struct Glyph {
|
||||
FontTexture* texture;
|
||||
glm::vec2 texPos;
|
||||
glm::vec2 texSize; // In texels.
|
||||
glm::vec2 advance;
|
||||
glm::vec2 bearing;
|
||||
int rows;
|
||||
};
|
||||
|
||||
// Completely recreate the texture data for all textures based on mGlyphs information.
|
||||
void rebuildTextures();
|
||||
void unloadTextures();
|
||||
|
@ -147,34 +150,31 @@ private:
|
|||
FontTexture*& tex_out,
|
||||
glm::ivec2& cursor_out);
|
||||
|
||||
std::map<unsigned int, std::unique_ptr<FontFace>> mFaceCache;
|
||||
std::vector<std::string> getFallbackFontPaths();
|
||||
FT_Face getFaceForChar(unsigned int id);
|
||||
void clearFaceCache() { mFaceCache.clear(); }
|
||||
|
||||
struct Glyph {
|
||||
FontTexture* texture;
|
||||
|
||||
glm::vec2 texPos;
|
||||
glm::vec2 texSize; // In texels.
|
||||
|
||||
glm::vec2 advance;
|
||||
glm::vec2 bearing;
|
||||
};
|
||||
|
||||
std::vector<FontTexture> mTextures;
|
||||
std::map<unsigned int, Glyph> mGlyphMap;
|
||||
Glyph* getGlyph(const unsigned int id);
|
||||
|
||||
int mSize;
|
||||
int mMaxGlyphHeight;
|
||||
const std::string mPath;
|
||||
|
||||
float getNewlineStartOffset(const std::string& text,
|
||||
const unsigned int& charStart,
|
||||
const float& xLen,
|
||||
const Alignment& alignment);
|
||||
|
||||
friend TextCache;
|
||||
void clearFaceCache() { mFaceCache.clear(); }
|
||||
|
||||
static inline FT_Library sLibrary {nullptr};
|
||||
static inline std::map<std::pair<std::string, float>, std::weak_ptr<Font>> sFontMap;
|
||||
static inline bool mLegacyTheme {false};
|
||||
|
||||
Renderer* mRenderer;
|
||||
std::vector<std::unique_ptr<FontTexture>> mTextures;
|
||||
std::map<unsigned int, std::unique_ptr<FontFace>> mFaceCache;
|
||||
std::map<unsigned int, Glyph> mGlyphMap;
|
||||
|
||||
const std::string mPath;
|
||||
float mFontSize;
|
||||
float mLetterHeight;
|
||||
int mMaxGlyphHeight;
|
||||
int mLegacyMaxGlyphHeight;
|
||||
};
|
||||
|
||||
// Used to store a sort of "pre-rendered" string.
|
||||
|
@ -188,6 +188,7 @@ class TextCache
|
|||
public:
|
||||
struct CacheMetrics {
|
||||
glm::vec2 size;
|
||||
int maxGlyphHeight;
|
||||
} metrics;
|
||||
|
||||
void setColor(unsigned int color);
|
||||
|
@ -199,8 +200,6 @@ public:
|
|||
protected:
|
||||
struct VertexList {
|
||||
std::vector<Renderer::Vertex> verts;
|
||||
// This is a pointer because the texture ID can change during
|
||||
// deinit/reinit (when launching a game).
|
||||
unsigned int* textureIdPtr;
|
||||
};
|
||||
|
||||
|
|
|
@ -24,13 +24,7 @@ TextureDataManager::TextureDataManager()
|
|||
data[i * 4 + 3] = 0;
|
||||
}
|
||||
mBlank->initFromRGBA(data, 5, 5);
|
||||
mLoader = new TextureLoader;
|
||||
}
|
||||
|
||||
TextureDataManager::~TextureDataManager()
|
||||
{
|
||||
// Delete TextureLoader object when destroyed.
|
||||
delete mLoader;
|
||||
mLoader = std::make_unique<TextureLoader>();
|
||||
}
|
||||
|
||||
std::shared_ptr<TextureData> TextureDataManager::add(const TextureResource* key, bool tiled)
|
||||
|
|
|
@ -63,7 +63,6 @@ class TextureDataManager
|
|||
{
|
||||
public:
|
||||
TextureDataManager();
|
||||
~TextureDataManager();
|
||||
|
||||
std::shared_ptr<TextureData> add(const TextureResource* key, bool tiled);
|
||||
|
||||
|
@ -90,7 +89,7 @@ private:
|
|||
std::map<const TextureResource*, std::list<std::shared_ptr<TextureData>>::const_iterator>
|
||||
mTextureLookup;
|
||||
std::shared_ptr<TextureData> mBlank;
|
||||
TextureLoader* mLoader;
|
||||
std::unique_ptr<TextureLoader> mLoader;
|
||||
};
|
||||
|
||||
#endif // ES_CORE_RESOURCES_TEXTURE_DATA_MANAGER_H
|
||||
|
|
9
external/CMakeLists.txt
vendored
|
@ -26,17 +26,18 @@ unset(CMAKE_EXE_LINKER_FLAGS)
|
|||
|
||||
if(WIN32)
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
|
||||
# Disable DLL interface warnings for LunaSVG.
|
||||
# Disable DLL interface warnings.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4251")
|
||||
else()
|
||||
# Strip the DLL files when building with MinGW.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s")
|
||||
endif()
|
||||
if (WIN32)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
else()
|
||||
else()
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_subdirectory(lunasvg EXCLUDE_FROM_ALL)
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="64" height="64" version="1.1" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle id="outline" cx="32" cy="32" r="28" fill="none" stroke="#fff" stroke-width="2"/>
|
||||
<path id="button_1" d="m32 4a28 28 0 0 0-28 28 28 28 0 0 0 28 28 28 28 0 0 0 28-28 28 28 0 0 0-28-28zm-0.986328 13.917969h5.878906v28.554687h-6.738281v-16.679687l0.214844-4.101563c-1.471355 1.523438-2.610677 2.708334-3.417969 3.554688l-3.730469-4.082032 7.792969-7.246093z" fill="#fff"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 523 B |
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="64" height="64" version="1.1" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle id="outline" cx="32" cy="32" r="28" fill="none" stroke="#fff" stroke-width="2"/>
|
||||
<path id="button_2" d="m32 4a28 28 0 0 0-28 28 28 28 0 0 0 28 28 28 28 0 0 0 28-28 28 28 0 0 0-28-28zm-0.126953 13.527344c2.591146 0 4.563802 0.703125 5.917969 2.109375 1.354166 1.393229 2.03125 3.307291 2.03125 5.742187 0 1.601563-0.286459 3.131511-0.859375 4.589844-0.572917 1.458333-1.341146 2.897135-2.304688 4.316406-0.950521 1.419271-2.643229 3.671875-5.078125 6.757813h8.828125v5.429687h-16.523437v-4.296875l5.078125-7.1875c0.690104-0.976562 1.217448-1.751302 1.582031-2.324219 0.377604-0.572916 0.794271-1.282552 1.25-2.128906 0.859375-1.614583 1.289062-3.248698 1.289062-4.902344 0-0.898437-0.15625-1.582031-0.46875-2.050781-0.3125-0.481771-0.735677-0.722656-1.269531-0.722656-0.625 0-1.25 0.266927-1.875 0.800781-0.546875 0.481771-1.028646 0.957032-1.445312 1.425782-0.416667 0.46875-0.638021 0.722656-0.664063 0.761718l-3.769531-3.984375c1.328125-1.458333 2.630208-2.545573 3.90625-3.261719 1.289062-0.716145 2.747396-1.074218 4.375-1.074218z" fill="#fff"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.2 KiB |
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="64" height="64" version="1.1" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle id="outline" cx="32" cy="32" r="28" fill="none" stroke="#fff" stroke-width="2"/>
|
||||
<path id="button_3" d="m32 4a28 28 0 0 0-28 28 28 28 0 0 0 28 28 28 28 0 0 0 28-28 28 28 0 0 0-28-28zm-0.439453 13.527344c1.536458 0 2.916667 0.260416 4.140625 0.78125 1.236979 0.507812 2.233073 1.308594 2.988281 2.402344 0.768229 1.080729 1.152344 2.402343 1.152344 3.964843 0 1.549479-0.384115 2.910156-1.152344 4.082031-0.755208 1.158855-1.842448 2.044271-3.261719 2.65625 1.601563 0.442709 2.825521 1.223959 3.671875 2.34375 0.859375 1.119792 1.289063 2.552084 1.289063 4.296876 0 2.747395-0.898438 4.902343-2.695313 6.464843-1.796875 1.549479-4.147135 2.324219-7.050781 2.324219s-5.234375-0.455729-6.992187-1.367188v-5.664062c1.40625 0.807292 2.890625 1.373698 4.453125 1.699219 0.664062 0.130208 1.295573 0.195312 1.894531 0.195312 1.210937 0 2.115885-0.305989 2.714844-0.917969 0.598958-0.611979 0.898437-1.57552 0.898437-2.890624 0-2.48698-1.425781-3.730469-4.277344-3.730469h-1.328125v-4.6875h1.269532c1.25 0 2.20052-0.319011 2.851562-0.957031 0.651042-0.651042 0.976563-1.601563 0.976563-2.851563 0-0.950521-0.182292-1.673177-0.546875-2.167969-0.364584-0.494791-0.885417-0.742187-1.5625-0.742187-1.223959 0-2.48698 0.390625-3.789063 1.171875-0.3125 0.182291-0.625 0.397135-0.9375 0.644531l-2.636719-3.867187c0.221355-0.260417 0.631511-0.598959 1.230469-1.015626 0.598958-0.429687 1.184896-0.78125 1.757813-1.054687 0.572916-0.286458 1.308593-0.540365 2.207031-0.761719 0.898437-0.234375 1.809896-0.351562 2.734375-0.351562z" fill="#fff"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.6 KiB |
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="64" height="64" version="1.1" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle id="outline" cx="32" cy="32" r="28" fill="none" stroke="#fff" stroke-width="2"/>
|
||||
<path id="button_4" d="m32 4a28 28 0 0 0-28 28 28 28 0 0 0 28 28 28 28 0 0 0 28-28 28 28 0 0 0-28-28zm-1.158203 13.722656h6.992187v17.636719h2.8125v5.097656h-2.8125v5.820313h-6.523437v-5.820313h-9.042969v-4.628906l8.574219-18.105469zm0.585937 10-3.671875 7.636719h3.554688v-5.429687l0.117187-2.207032z" fill="#fff"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 552 B |
|
@ -1,19 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64"
|
||||
height="64"
|
||||
version="1.1"
|
||||
viewBox="0 0 64 64"
|
||||
id="svg16"
|
||||
sodipodi:docname="button_start.svg"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<metadata
|
||||
id="metadata22">
|
||||
<rdf:RDF>
|
||||
|
@ -22,36 +18,13 @@
|
|||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs20" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2065"
|
||||
id="namedview18"
|
||||
showgrid="false"
|
||||
inkscape:pagecheckerboard="true"
|
||||
inkscape:zoom="8.110593"
|
||||
inkscape:cx="15.256979"
|
||||
inkscape:cy="28.10138"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg16" />
|
||||
<path
|
||||
style="opacity:1;fill:#ffffff;fill-opacity:0.97137403;stroke:none;stroke-width:2.86624074;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2.86624074;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
d="m 36.705078,7.9726562 c 13.495895,0 24.359375,10.7159498 24.359375,24.0273438 0,13.311394 -10.86348,24.027344 -24.359375,24.027344 H 27.294922 C 13.799027,56.027344 2.9355469,45.311394 2.9355469,32 2.9355469,18.688606 13.799027,7.9726562 27.294922,7.9726562 Z m 4.1875,7.1289058 L 27.240234,23.550781 13.587891,32 27.240234,40.449219 40.892578,48.898438 V 32 Z"
|
||||
id="rect4801"
|
||||
inkscape:connector-curvature="0" />
|
||||
id="rect4801" />
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.3 KiB |
|
@ -1,19 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64"
|
||||
height="64"
|
||||
version="1.1"
|
||||
viewBox="0 0 64 64"
|
||||
id="svg4"
|
||||
sodipodi:docname="button_start_PS5.svg"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<metadata
|
||||
id="metadata10">
|
||||
<rdf:RDF>
|
||||
|
@ -22,36 +18,13 @@
|
|||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs8" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2065"
|
||||
id="namedview6"
|
||||
showgrid="false"
|
||||
inkscape:pagecheckerboard="true"
|
||||
inkscape:zoom="10.114756"
|
||||
inkscape:cx="-29.467155"
|
||||
inkscape:cy="35.704758"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg4" />
|
||||
<path
|
||||
style="opacity:1;fill:#ffffff;fill-opacity:0.99427478;stroke:none;stroke-width:3.00568366;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3.00568366;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
d="M 32,3 A 28.999998,28.999998 0 0 0 3,32 28.999998,28.999998 0 0 0 32,61 28.999998,28.999998 0 0 0 61,32 28.999998,28.999998 0 0 0 32,3 Z M 15.1393,18.994908 h 33.7214 c 0.194964,0 0.37709,0.04431 0.532018,0.139579 0.154927,0.09528 0.301408,0.270435 0.301408,0.497628 v 2.751116 c 0,0.227193 -0.146481,0.40033 -0.301408,0.495605 -0.154928,0.09528 -0.337054,0.139579 -0.532018,0.139579 H 15.1393 c -0.194964,0 -0.37709,-0.04431 -0.532018,-0.139579 -0.154927,-0.09528 -0.301408,-0.268412 -0.301408,-0.495605 v -2.751116 c 0,-0.227193 0.146481,-0.402353 0.301408,-0.497628 0.154928,-0.09528 0.337054,-0.139579 0.532018,-0.139579 z m 0,8.963379 h 33.7214 c 0.194964,0 0.37709,0.04431 0.532018,0.139579 0.154927,0.09528 0.301408,0.268411 0.301408,0.495606 v 2.751116 c 0,0.227191 -0.146481,0.400329 -0.301408,0.495604 -0.154928,0.09528 -0.337054,0.139579 -0.532018,0.139579 H 15.1393 c -0.194964,0 -0.37709,-0.04431 -0.532018,-0.139579 -0.154927,-0.09527 -0.301408,-0.268413 -0.301408,-0.495604 v -2.751116 c 0,-0.227196 0.146481,-0.400331 0.301408,-0.495606 0.154928,-0.09528 0.337054,-0.139579 0.532018,-0.139579 z m 0,8.961356 h 33.7214 c 0.194964,0 0.37709,0.04431 0.532018,0.139579 0.154927,0.09528 0.301408,0.268413 0.301408,0.495605 v 2.751116 c 0,0.227193 -0.146481,0.40033 -0.301408,0.495606 -0.154928,0.09528 -0.337054,0.139578 -0.532018,0.139578 H 15.1393 c -0.194964,0 -0.37709,-0.0443 -0.532018,-0.139578 -0.154927,-0.09528 -0.301408,-0.268413 -0.301408,-0.495606 v -2.751116 c 0,-0.227192 0.146481,-0.40033 0.301408,-0.495605 0.154928,-0.09527 0.337054,-0.139579 0.532018,-0.139579 z"
|
||||
id="path4749"
|
||||
inkscape:connector-curvature="0" />
|
||||
id="path4749" />
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 2.5 KiB |
|
@ -1,19 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64"
|
||||
height="64"
|
||||
version="1.1"
|
||||
viewBox="0 0 64 64"
|
||||
id="svg4"
|
||||
sodipodi:docname="button_start_XBOX.svg"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<metadata
|
||||
id="metadata10">
|
||||
<rdf:RDF>
|
||||
|
@ -22,36 +18,13 @@
|
|||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs8" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2065"
|
||||
id="namedview6"
|
||||
showgrid="false"
|
||||
inkscape:pagecheckerboard="true"
|
||||
inkscape:zoom="10.114756"
|
||||
inkscape:cx="54.855698"
|
||||
inkscape:cy="22.84784"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg4" />
|
||||
<path
|
||||
style="opacity:1;fill:#ffffff;fill-opacity:0.99427478;stroke:none;stroke-width:3.00568366;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3.00568366;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
d="M 32,3 A 28.999998,28.999998 0 0 0 3,32 28.999998,28.999998 0 0 0 32,61 28.999998,28.999998 0 0 0 61,32 28.999998,28.999998 0 0 0 32,3 Z M 15.1393,18.994908 h 33.7214 c 0.194964,0 0.37709,0.04431 0.532018,0.139579 0.154927,0.09528 0.301408,0.270435 0.301408,0.497628 v 2.751116 c 0,0.227193 -0.146481,0.40033 -0.301408,0.495605 -0.154928,0.09528 -0.337054,0.139579 -0.532018,0.139579 H 15.1393 c -0.194964,0 -0.37709,-0.04431 -0.532018,-0.139579 -0.154927,-0.09528 -0.301408,-0.268412 -0.301408,-0.495605 v -2.751116 c 0,-0.227193 0.146481,-0.402353 0.301408,-0.497628 0.154928,-0.09528 0.337054,-0.139579 0.532018,-0.139579 z m 0,8.963379 h 33.7214 c 0.194964,0 0.37709,0.04431 0.532018,0.139579 0.154927,0.09528 0.301408,0.268411 0.301408,0.495606 v 2.751116 c 0,0.227191 -0.146481,0.400329 -0.301408,0.495604 -0.154928,0.09528 -0.337054,0.139579 -0.532018,0.139579 H 15.1393 c -0.194964,0 -0.37709,-0.04431 -0.532018,-0.139579 -0.154927,-0.09527 -0.301408,-0.268413 -0.301408,-0.495604 v -2.751116 c 0,-0.227196 0.146481,-0.400331 0.301408,-0.495606 0.154928,-0.09528 0.337054,-0.139579 0.532018,-0.139579 z m 0,8.961356 h 33.7214 c 0.194964,0 0.37709,0.04431 0.532018,0.139579 0.154927,0.09528 0.301408,0.268413 0.301408,0.495605 v 2.751116 c 0,0.227193 -0.146481,0.40033 -0.301408,0.495606 -0.154928,0.09528 -0.337054,0.139578 -0.532018,0.139578 H 15.1393 c -0.194964,0 -0.37709,-0.0443 -0.532018,-0.139578 -0.154927,-0.09528 -0.301408,-0.268413 -0.301408,-0.495606 v -2.751116 c 0,-0.227192 0.146481,-0.40033 0.301408,-0.495605 0.154928,-0.09527 0.337054,-0.139579 0.532018,-0.139579 z"
|
||||
id="path4749"
|
||||
inkscape:connector-curvature="0" />
|
||||
id="path4749" />
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 2.5 KiB |
|
@ -1,19 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64"
|
||||
height="64"
|
||||
version="1.1"
|
||||
viewBox="0 0 64 64"
|
||||
id="svg16"
|
||||
sodipodi:docname="button_start.svg"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<metadata
|
||||
id="metadata22">
|
||||
<rdf:RDF>
|
||||
|
@ -22,35 +18,13 @@
|
|||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs20" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2065"
|
||||
id="namedview18"
|
||||
showgrid="false"
|
||||
inkscape:pagecheckerboard="true"
|
||||
inkscape:zoom="8.110593"
|
||||
inkscape:cx="15.256979"
|
||||
inkscape:cy="28.10138"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg16" />
|
||||
<path
|
||||
style="opacity:1;fill:#ffffff;fill-opacity:0.97137403;stroke:none;stroke-width:2.86624074;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2.86624074;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
d="M 27.294922 7.9726562 C 13.799027 7.9726562 2.9355469 18.688606 2.9355469 32 C 2.9355469 45.311394 13.799027 56.027344 27.294922 56.027344 L 36.705078 56.027344 C 50.200973 56.027344 61.064453 45.311394 61.064453 32 C 61.064453 18.688606 50.200973 7.9726562 36.705078 7.9726562 L 27.294922 7.9726562 z M 23.107422 15.101562 L 36.759766 23.550781 L 50.412109 32 L 36.759766 40.449219 L 23.107422 48.898438 L 23.107422 32 L 23.107422 15.101562 z "
|
||||
id="rect4801" />
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 1.3 KiB |
|
@ -85,7 +85,7 @@
|
|||
<path>%ROMPATH%/apple2</path>
|
||||
<extension>.do .DO .dsk .DSK .nib .NIB .po .PO</extension>
|
||||
<command label="Mednafen (Standalone)">%EMULATOR_MEDNAFEN% -force_module apple2 %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %ROMPATH%/apple2 apple2e -flop1 %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/apple2 apple2e -flop1 %ROM%</command>
|
||||
<platform>apple2</platform>
|
||||
<theme>apple2</theme>
|
||||
</system>
|
||||
|
@ -94,7 +94,7 @@
|
|||
<fullname>Apple IIGS</fullname>
|
||||
<path>%ROMPATH%/apple2gs</path>
|
||||
<extension>.2mg .2MG</extension>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %ROMPATH%/apple2gs apple2gs -flop3 %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/apple2gs apple2gs -flop3 %ROM%</command>
|
||||
<platform>apple2gs</platform>
|
||||
<theme>apple2gs</theme>
|
||||
</system>
|
||||
|
@ -107,7 +107,7 @@
|
|||
<command label="MAME 2010">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/mame2010_libretro.dylib %ROM%</command>
|
||||
<command label="MAME 2003-Plus">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/mame2003_plus_libretro.dylib %ROM%</command>
|
||||
<command label="MAME 2000">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/mame2000_libretro.dylib %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %ROMPATH%/arcade %BASENAME%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/arcade %BASENAME%</command>
|
||||
<command label="FinalBurn Neo">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/fbneo_libretro.dylib %ROM%</command>
|
||||
<command label="FB Alpha 2012">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/fbalpha2012_libretro.dylib %ROM%</command>
|
||||
<command label="Flycast">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/flycast_libretro.dylib %ROM%</command>
|
||||
|
@ -121,7 +121,7 @@
|
|||
<path>%ROMPATH%/astrocde</path>
|
||||
<extension>.7z .7Z .zip .ZIP</extension>
|
||||
<command label="MAME - Current">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/mame_libretro.dylib %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %ROMPATH%/astrocde astrocde -cart %BASENAME%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/astrocde astrocde -cart %BASENAME%</command>
|
||||
<platform>astrocde</platform>
|
||||
<theme>astrocade</theme>
|
||||
</system>
|
||||
|
@ -140,7 +140,7 @@
|
|||
<name>atari5200</name>
|
||||
<fullname>Atari 5200</fullname>
|
||||
<path>%ROMPATH%/atari5200</path>
|
||||
<extension>.a52 .A52 .atr .ATR .atx .ATX .bin .BIN .cas .CAS .cdm .CDM .xex .XEX .xfd .XFD .7z .7Z .zip .ZIP</extension>
|
||||
<extension>.a52 .A52 .atr .ATR .atx .ATX .bin .BIN .car .CAR .cas .CAS .cdm .CDM .rom .ROM .xex .XEX .xfd .XFD .7z .7Z .zip .ZIP</extension>
|
||||
<command label="a5200">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/a5200_libretro.dylib %ROM%</command>
|
||||
<command label="Atari800">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/atari800_libretro.dylib %ROM%</command>
|
||||
<command label="Atari800 (Standalone)">%EMULATOR_ATARI800% %ROM%</command>
|
||||
|
@ -160,7 +160,7 @@
|
|||
<name>atari800</name>
|
||||
<fullname>Atari 800</fullname>
|
||||
<path>%ROMPATH%/atari800</path>
|
||||
<extension>.a52 .A52 .atr .ATR .atx .ATX .bin .BIN .cas .CAS .cdm .CDM .rom .ROM .xex .XEX .xfd .XFD .7z .7Z .zip .ZIP</extension>
|
||||
<extension>.a52 .A52 .atr .ATR .atx .ATX .bin .BIN .car .CAR .cas .CAS .cdm .CDM .rom .ROM .xex .XEX .xfd .XFD .7z .7Z .zip .ZIP</extension>
|
||||
<command label="Atari800">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/atari800_libretro.dylib %ROM%</command>
|
||||
<command label="Atari800 (Standalone)">%EMULATOR_ATARI800% %ROM%</command>
|
||||
<platform>atari800</platform>
|
||||
|
@ -325,7 +325,7 @@
|
|||
<command label="MAME 2010">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/mame2010_libretro.dylib %ROM%</command>
|
||||
<command label="MAME 2003-Plus">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/mame2003_plus_libretro.dylib %ROM%</command>
|
||||
<command label="MAME 2000">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/mame2000_libretro.dylib %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %ROMPATH%/arcade %BASENAME%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/cps %BASENAME%</command>
|
||||
<command label="FinalBurn Neo">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/fbneo_libretro.dylib %ROM%</command>
|
||||
<command label="FB Alpha 2012">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/fbalpha2012_libretro.dylib %ROM%</command>
|
||||
<command label="FB Alpha 2012 CPS-1">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/fbalpha2012_cps1_libretro.dylib %ROM%</command>
|
||||
|
@ -491,8 +491,8 @@
|
|||
<path>%ROMPATH%/gameandwatch</path>
|
||||
<extension>.mgw .MGW .7z .7Z .zip .ZIP</extension>
|
||||
<command label="Handheld Electronic (GW)">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/gw_libretro.dylib %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %ROMPATH%/gameandwatch %BASENAME%</command>
|
||||
<command label="MAME Local Artwork (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -artpath %ROMPATH%/gameandwatch/artwork -rompath %ROMPATH%/gameandwatch %BASENAME%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/gameandwatch %BASENAME%</command>
|
||||
<command label="MAME Local Artwork (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -artpath %ROMPATH%/gameandwatch/artwork -rompath %GAMEDIR%\;%ROMPATH%/gameandwatch %BASENAME%</command>
|
||||
<platform>gameandwatch</platform>
|
||||
<theme>gameandwatch</theme>
|
||||
</system>
|
||||
|
@ -590,7 +590,7 @@
|
|||
<extension>.bin .BIN .cdt .CDT .cpr .CPR .dsk .DSK .kcr .KCR .m3u .M3U .sna .SNA .tap .TAR .voc .VOC .7z .7Z .zip .ZIP</extension>
|
||||
<command label="Caprice32">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/cap32_libretro.dylib %ROM%</command>
|
||||
<command label="CrocoDS">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/crocods_libretro.dylib %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %ROMPATH%/gx4000 gx4000 -cart %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/gx4000 gx4000 -cart %ROM%</command>
|
||||
<platform>gx4000</platform>
|
||||
<theme>gx4000</theme>
|
||||
</system>
|
||||
|
@ -658,7 +658,7 @@
|
|||
<command label="MAME 2010">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/mame2010_libretro.dylib %ROM%</command>
|
||||
<command label="MAME 2003-Plus">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/mame2003_plus_libretro.dylib %ROM%</command>
|
||||
<command label="MAME 2000">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/mame2000_libretro.dylib %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %ROMPATH%/mame %BASENAME%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/mame %BASENAME%</command>
|
||||
<command label="FinalBurn Neo">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/fbneo_libretro.dylib %ROM%</command>
|
||||
<command label="FB Alpha 2012">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/fbalpha2012_libretro.dylib %ROM%</command>
|
||||
<command label="Flycast">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/flycast_libretro.dylib %ROM%</command>
|
||||
|
@ -760,7 +760,8 @@
|
|||
<fullname>Sega Model 2</fullname>
|
||||
<path>%ROMPATH%/model2</path>
|
||||
<extension>.7z .7Z .zip .ZIP</extension>
|
||||
<command>PLACEHOLDER %ROM%</command>
|
||||
<command label="MAME - Current">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/mame_libretro.dylib %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/model2 %BASENAME%</command>
|
||||
<platform>arcade</platform>
|
||||
<theme>model2</theme>
|
||||
</system>
|
||||
|
@ -927,7 +928,7 @@
|
|||
<path>%ROMPATH%/neogeo</path>
|
||||
<extension>.7z .7Z .zip .ZIP</extension>
|
||||
<command label="FinalBurn Neo">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/fbneo_libretro.dylib %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %ROMPATH%/neogeo %BASENAME%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/neogeo %BASENAME%</command>
|
||||
<platform>neogeo</platform>
|
||||
<theme>neogeo</theme>
|
||||
</system>
|
||||
|
@ -938,7 +939,7 @@
|
|||
<extension>.chd .CHD .cue .CUE</extension>
|
||||
<command label="NeoCD">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/neocd_libretro.dylib %ROM%</command>
|
||||
<command label="FinalBurn Neo">%EMULATOR_RETROARCH% --subsystem neocd -L %CORE_RETROARCH%/fbneo_libretro.dylib %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %ROMPATH%/neogeocd neocdz -cdrm %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/neogeocd neocdz -cdrm %ROM%</command>
|
||||
<platform>neogeocd</platform>
|
||||
<theme>neogeocd</theme>
|
||||
</system>
|
||||
|
@ -949,7 +950,7 @@
|
|||
<extension>.chd .CHD .cue .CUE</extension>
|
||||
<command label="NeoCD">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/neocd_libretro.dylib %ROM%</command>
|
||||
<command label="FinalBurn Neo">%EMULATOR_RETROARCH% --subsystem neocd -L %CORE_RETROARCH%/fbneo_libretro.dylib %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %ROMPATH%/neogeocdjp neocdz -cdrm %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/neogeocdjp neocdz -cdrm %ROM%</command>
|
||||
<platform>neogeocd</platform>
|
||||
<theme>neogeocdjp</theme>
|
||||
</system>
|
||||
|
@ -1486,7 +1487,7 @@
|
|||
<fullname>Texas Instruments TI-99</fullname>
|
||||
<path>%ROMPATH%/ti99</path>
|
||||
<extension>.rpk .RPK .7z .7Z .zip .ZIP</extension>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %ROMPATH%/ti99 ti99_4a -ioport peb -ioport:peb:slot3 speech -cart %BASENAME%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/ti99 ti99_4a -ioport peb -ioport:peb:slot3 speech -cart %BASENAME%</command>
|
||||
<platform>ti99</platform>
|
||||
<theme>ti99</theme>
|
||||
</system>
|
||||
|
|
|
@ -576,6 +576,17 @@
|
|||
<entry>steam</entry>
|
||||
</rule>
|
||||
</emulator>
|
||||
<emulator name="SUPERMODEL">
|
||||
<!-- Sega Model 3 emulator Supermodel -->
|
||||
<rule type="systempath">
|
||||
<entry>supermodel</entry>
|
||||
</rule>
|
||||
<rule type="staticpath">
|
||||
<entry>~/Applications/Supermodel/supermodel</entry>
|
||||
<entry>~/.local/bin/Supermodel/supermodel</entry>
|
||||
<entry>~/bin/Supermodel/supermodel</entry>
|
||||
</rule>
|
||||
</emulator>
|
||||
<emulator name="TRIFORCE">
|
||||
<!-- Triforce, fork of Nintendo GameCube and Wii emulator Dolphin -->
|
||||
<rule type="systempath">
|
||||
|
|
|
@ -86,7 +86,7 @@
|
|||
<extension>.do .DO .dsk .DSK .nib .NIB .po .PO</extension>
|
||||
<command label="LinApple (Standalone)">%EMULATOR_LINAPPLE% -f -b --d1 %ROM%</command>
|
||||
<command label="Mednafen (Standalone)">%EMULATOR_MEDNAFEN% -force_module apple2 %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %ROMPATH%/apple2 apple2e -flop1 %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/apple2 apple2e -flop1 %ROM%</command>
|
||||
<platform>apple2</platform>
|
||||
<theme>apple2</theme>
|
||||
</system>
|
||||
|
@ -95,7 +95,7 @@
|
|||
<fullname>Apple IIGS</fullname>
|
||||
<path>%ROMPATH%/apple2gs</path>
|
||||
<extension>.2mg .2MG</extension>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %ROMPATH%/apple2gs apple2gs -flop3 %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/apple2gs apple2gs -flop3 %ROM%</command>
|
||||
<platform>apple2gs</platform>
|
||||
<theme>apple2gs</theme>
|
||||
</system>
|
||||
|
@ -108,12 +108,13 @@
|
|||
<command label="MAME 2010">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/mame2010_libretro.so %ROM%</command>
|
||||
<command label="MAME 2003-Plus">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/mame2003_plus_libretro.so %ROM%</command>
|
||||
<command label="MAME 2000">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/mame2000_libretro.so %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %ROMPATH%/arcade %BASENAME%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/arcade %BASENAME%</command>
|
||||
<command label="FinalBurn Neo">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/fbneo_libretro.so %ROM%</command>
|
||||
<command label="FB Alpha 2012">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/fbalpha2012_libretro.so %ROM%</command>
|
||||
<command label="Flycast">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/flycast_libretro.so %ROM%</command>
|
||||
<command label="Flycast (Standalone)">%EMULATOR_FLYCAST% %ROM%</command>
|
||||
<command label="Kronos">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/kronos_libretro.so %ROM%</command>
|
||||
<command label="Supermodel (Standalone)">%STARTDIR%=%GAMEDIR% %EMULATOR_SUPERMODEL% -log-output=%GAMEDIR%/Config/Supermodel.log -force-feedback %INJECT%=%BASENAME%.commands %ROM%</command>
|
||||
<platform>arcade</platform>
|
||||
<theme>arcade</theme>
|
||||
</system>
|
||||
|
@ -123,7 +124,7 @@
|
|||
<path>%ROMPATH%/astrocde</path>
|
||||
<extension>.7z .7Z .zip .ZIP</extension>
|
||||
<command label="MAME - Current">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/mame_libretro.so %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %ROMPATH%/astrocde astrocde -cart %BASENAME%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/astrocde astrocde -cart %BASENAME%</command>
|
||||
<platform>astrocde</platform>
|
||||
<theme>astrocade</theme>
|
||||
</system>
|
||||
|
@ -142,7 +143,7 @@
|
|||
<name>atari5200</name>
|
||||
<fullname>Atari 5200</fullname>
|
||||
<path>%ROMPATH%/atari5200</path>
|
||||
<extension>.a52 .A52 .atr .ATR .atx .ATX .bin .BIN .cas .CAS .cdm .CDM .xex .XEX .xfd .XFD .7z .7Z .zip .ZIP</extension>
|
||||
<extension>.a52 .A52 .atr .ATR .atx .ATX .bin .BIN .car .CAR .cas .CAS .cdm .CDM .rom .ROM .xex .XEX .xfd .XFD .7z .7Z .zip .ZIP</extension>
|
||||
<command label="a5200">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/a5200_libretro.so %ROM%</command>
|
||||
<command label="Atari800">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/atari800_libretro.so %ROM%</command>
|
||||
<command label="Atari800 (Standalone)">%EMULATOR_ATARI800% %ROM%</command>
|
||||
|
@ -162,7 +163,7 @@
|
|||
<name>atari800</name>
|
||||
<fullname>Atari 800</fullname>
|
||||
<path>%ROMPATH%/atari800</path>
|
||||
<extension>.a52 .A52 .atr .ATR .atx .ATX .bin .BIN .cas .CAS .cdm .CDM .rom .ROM .xex .XEX .xfd .XFD .7z .7Z .zip .ZIP</extension>
|
||||
<extension>.a52 .A52 .atr .ATR .atx .ATX .bin .BIN .car .CAR .cas .CAS .cdm .CDM .rom .ROM .xex .XEX .xfd .XFD .7z .7Z .zip .ZIP</extension>
|
||||
<command label="Atari800">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/atari800_libretro.so %ROM%</command>
|
||||
<command label="Atari800 (Standalone)">%EMULATOR_ATARI800% %ROM%</command>
|
||||
<platform>atari800</platform>
|
||||
|
@ -327,7 +328,7 @@
|
|||
<command label="MAME 2010">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/mame2010_libretro.so %ROM%</command>
|
||||
<command label="MAME 2003-Plus">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/mame2003_plus_libretro.so %ROM%</command>
|
||||
<command label="MAME 2000">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/mame2000_libretro.so %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %ROMPATH%/arcade %BASENAME%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/cps %BASENAME%</command>
|
||||
<command label="FinalBurn Neo">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/fbneo_libretro.so %ROM%</command>
|
||||
<command label="FB Alpha 2012">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/fbalpha2012_libretro.so %ROM%</command>
|
||||
<command label="FB Alpha 2012 CPS-1">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/fbalpha2012_cps1_libretro.so %ROM%</command>
|
||||
|
@ -499,8 +500,8 @@
|
|||
<path>%ROMPATH%/gameandwatch</path>
|
||||
<extension>.mgw .MGW .7z .7Z .zip .ZIP</extension>
|
||||
<command label="Handheld Electronic (GW)">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/gw_libretro.so %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %ROMPATH%/gameandwatch %BASENAME%</command>
|
||||
<command label="MAME Local Artwork (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -artpath %ROMPATH%/gameandwatch/artwork -rompath %ROMPATH%/gameandwatch %BASENAME%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/gameandwatch %BASENAME%</command>
|
||||
<command label="MAME Local Artwork (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -artpath %ROMPATH%/gameandwatch/artwork -rompath %GAMEDIR%\;%ROMPATH%/gameandwatch %BASENAME%</command>
|
||||
<platform>gameandwatch</platform>
|
||||
<theme>gameandwatch</theme>
|
||||
</system>
|
||||
|
@ -601,7 +602,7 @@
|
|||
<extension>.bin .BIN .cdt .CDT .cpr .CPR .dsk .DSK .kcr .KCR .m3u .M3U .sna .SNA .tap .TAR .voc .VOC .7z .7Z .zip .ZIP</extension>
|
||||
<command label="Caprice32">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/cap32_libretro.so %ROM%</command>
|
||||
<command label="CrocoDS">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/crocods_libretro.so %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %ROMPATH%/gx4000 gx4000 -cart %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/gx4000 gx4000 -cart %ROM%</command>
|
||||
<platform>gx4000</platform>
|
||||
<theme>gx4000</theme>
|
||||
</system>
|
||||
|
@ -669,12 +670,13 @@
|
|||
<command label="MAME 2010">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/mame2010_libretro.so %ROM%</command>
|
||||
<command label="MAME 2003-Plus">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/mame2003_plus_libretro.so %ROM%</command>
|
||||
<command label="MAME 2000">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/mame2000_libretro.so %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %ROMPATH%/mame %BASENAME%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/mame %BASENAME%</command>
|
||||
<command label="FinalBurn Neo">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/fbneo_libretro.so %ROM%</command>
|
||||
<command label="FB Alpha 2012">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/fbalpha2012_libretro.so %ROM%</command>
|
||||
<command label="Flycast">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/flycast_libretro.so %ROM%</command>
|
||||
<command label="Flycast (Standalone)">%EMULATOR_FLYCAST% %ROM%</command>
|
||||
<command label="Kronos">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/kronos_libretro.so %ROM%</command>
|
||||
<command label="Supermodel (Standalone)">%STARTDIR%=%GAMEDIR% %EMULATOR_SUPERMODEL% -log-output=%GAMEDIR%/Config/Supermodel.log -force-feedback %INJECT%=%BASENAME%.commands %ROM%</command>
|
||||
<platform>arcade</platform>
|
||||
<theme>mame</theme>
|
||||
</system>
|
||||
|
@ -773,7 +775,8 @@
|
|||
<fullname>Sega Model 2</fullname>
|
||||
<path>%ROMPATH%/model2</path>
|
||||
<extension>.7z .7Z .zip .ZIP</extension>
|
||||
<command>PLACEHOLDER %ROM%</command>
|
||||
<command label="MAME - Current">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/mame_libretro.so %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/model2 %BASENAME%</command>
|
||||
<platform>arcade</platform>
|
||||
<theme>model2</theme>
|
||||
</system>
|
||||
|
@ -782,7 +785,7 @@
|
|||
<fullname>Sega Model 3</fullname>
|
||||
<path>%ROMPATH%/model3</path>
|
||||
<extension>.7z .7Z .zip .ZIP</extension>
|
||||
<command>PLACEHOLDER %ROM%</command>
|
||||
<command label="Supermodel (Standalone)">%STARTDIR%=%GAMEDIR% %EMULATOR_SUPERMODEL% -log-output=%GAMEDIR%/Config/Supermodel.log -force-feedback %INJECT%=%BASENAME%.commands %ROM%</command>
|
||||
<platform>arcade</platform>
|
||||
<theme>model3</theme>
|
||||
</system>
|
||||
|
@ -947,7 +950,7 @@
|
|||
<extension>.7z .7Z .zip .ZIP</extension>
|
||||
<command label="FinalBurn Neo">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/fbneo_libretro.so %ROM%</command>
|
||||
<command label="FinalBurn Neo (Standalone)">%EMULATOR_FINALBURN-NEO% -fullscreen %BASENAME%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %ROMPATH%/neogeo %BASENAME%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/neogeo %BASENAME%</command>
|
||||
<platform>neogeo</platform>
|
||||
<theme>neogeo</theme>
|
||||
</system>
|
||||
|
@ -959,7 +962,7 @@
|
|||
<command label="NeoCD">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/neocd_libretro.so %ROM%</command>
|
||||
<command label="FinalBurn Neo">%EMULATOR_RETROARCH% --subsystem neocd -L %CORE_RETROARCH%/fbneo_libretro.so %ROM%</command>
|
||||
<command label="FinalBurn Neo (Standalone)">%EMULATOR_FINALBURN-NEO% neocdz -fullscreen -cd %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %ROMPATH%/neogeocd neocdz -cdrm %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/neogeocd neocdz -cdrm %ROM%</command>
|
||||
<platform>neogeocd</platform>
|
||||
<theme>neogeocd</theme>
|
||||
</system>
|
||||
|
@ -971,7 +974,7 @@
|
|||
<command label="NeoCD">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%/neocd_libretro.so %ROM%</command>
|
||||
<command label="FinalBurn Neo">%EMULATOR_RETROARCH% --subsystem neocd -L %CORE_RETROARCH%/fbneo_libretro.so %ROM%</command>
|
||||
<command label="FinalBurn Neo (Standalone)">%EMULATOR_FINALBURN-NEO% neocdz -fullscreen -cd %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %ROMPATH%/neogeocdjp neocdz -cdrm %ROM%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/neogeocdjp neocdz -cdrm %ROM%</command>
|
||||
<platform>neogeocd</platform>
|
||||
<theme>neogeocdjp</theme>
|
||||
</system>
|
||||
|
@ -1522,7 +1525,7 @@
|
|||
<fullname>Texas Instruments TI-99</fullname>
|
||||
<path>%ROMPATH%/ti99</path>
|
||||
<extension>.rpk .RPK .7z .7Z .zip .ZIP</extension>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %ROMPATH%/ti99 ti99_4a -ioport peb -ioport:peb:slot3 speech -cart %BASENAME%</command>
|
||||
<command label="MAME (Standalone)">%STARTDIR%=~/.mame %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%/ti99 ti99_4a -ioport peb -ioport:peb:slot3 speech -cart %BASENAME%</command>
|
||||
<platform>ti99</platform>
|
||||
<theme>ti99</theme>
|
||||
</system>
|
||||
|
|
|
@ -86,7 +86,7 @@
|
|||
<extension>.do .DO .dsk .DSK .nib .NIB .po .PO</extension>
|
||||
<command label="AppleWin (Standalone)">%EMULATOR_APPLEWIN% -f -d1 %ROM%</command>
|
||||
<command label="Mednafen (Standalone)">%EMULATOR_MEDNAFEN% -force_module apple2 %ROM%</command>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %ROMPATH%\apple2 apple2e -flop1 %ROM%</command>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%\apple2 apple2e -flop1 %ROM%</command>
|
||||
<platform>apple2</platform>
|
||||
<theme>apple2</theme>
|
||||
</system>
|
||||
|
@ -95,7 +95,7 @@
|
|||
<fullname>Apple IIGS</fullname>
|
||||
<path>%ROMPATH%\apple2gs</path>
|
||||
<extension>.2mg .2MG</extension>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %ROMPATH%\apple2gs apple2gs -flop3 %ROM%</command>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%\apple2gs apple2gs -flop3 %ROM%</command>
|
||||
<platform>apple2gs</platform>
|
||||
<theme>apple2gs</theme>
|
||||
</system>
|
||||
|
@ -108,7 +108,7 @@
|
|||
<command label="MAME 2010">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\mame2010_libretro.dll %ROM%</command>
|
||||
<command label="MAME 2003-Plus">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\mame2003_plus_libretro.dll %ROM%</command>
|
||||
<command label="MAME 2000">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\mame2000_libretro.dll %ROM%</command>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %ROMPATH%\arcade %BASENAME%</command>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%\arcade %BASENAME%</command>
|
||||
<command label="FinalBurn Neo">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\fbneo_libretro.dll %ROM%</command>
|
||||
<command label="FB Alpha 2012">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\fbalpha2012_libretro.dll %ROM%</command>
|
||||
<command label="Flycast">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\flycast_libretro.dll %ROM%</command>
|
||||
|
@ -116,7 +116,7 @@
|
|||
<command label="Kronos">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\kronos_libretro.dll %ROM%</command>
|
||||
<command label="Model 2 Emulator (Standalone)">%RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_M2EMULATOR% %BASENAME%</command>
|
||||
<command label="Model 2 Emulator [Suspend ES-DE] (Standalone)">%STARTDIR%=%EMUDIR% %EMULATOR_M2EMULATOR% %BASENAME%</command>
|
||||
<command label="Supermodel (Standalone)">%STARTDIR%=%EMUDIR% %EMULATOR_SUPERMODEL% -fullscreen %ROM%</command>
|
||||
<command label="Supermodel (Standalone)">%STARTDIR%=%EMUDIR% %EMULATOR_SUPERMODEL% -fullscreen -force-feedback %INJECT%=%BASENAME%.commands %ROM%</command>
|
||||
<platform>arcade</platform>
|
||||
<theme>arcade</theme>
|
||||
</system>
|
||||
|
@ -126,7 +126,7 @@
|
|||
<path>%ROMPATH%\astrocde</path>
|
||||
<extension>.7z .7Z .zip .ZIP</extension>
|
||||
<command label="MAME - Current">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\mame_libretro.dll %ROM%</command>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %ROMPATH%\astrocde astrocde -cart %BASENAME%</command>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%\astrocde astrocde -cart %BASENAME%</command>
|
||||
<platform>astrocde</platform>
|
||||
<theme>astrocade</theme>
|
||||
</system>
|
||||
|
@ -145,7 +145,7 @@
|
|||
<name>atari5200</name>
|
||||
<fullname>Atari 5200</fullname>
|
||||
<path>%ROMPATH%\atari5200</path>
|
||||
<extension>.a52 .A52 .atr .ATR .atx .ATX .bin .BIN .cas .CAS .cdm .CDM .xex .XEX .xfd .XFD .7z .7Z .zip .ZIP</extension>
|
||||
<extension>.a52 .A52 .atr .ATR .atx .ATX .bin .BIN .car .CAR .cas .CAS .cdm .CDM .rom .ROM .xex .XEX .xfd .XFD .7z .7Z .zip .ZIP</extension>
|
||||
<command label="a5200">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\a5200_libretro.dll %ROM%</command>
|
||||
<command label="Atari800">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\atari800_libretro.dll %ROM%</command>
|
||||
<command label="Atari800 (Standalone)">%STARTDIR%=%EMUDIR% %EMULATOR_ATARI800% %ROM%</command>
|
||||
|
@ -165,7 +165,7 @@
|
|||
<name>atari800</name>
|
||||
<fullname>Atari 800</fullname>
|
||||
<path>%ROMPATH%\atari800</path>
|
||||
<extension>.a52 .A52 .atr .ATR .atx .ATX .bin .BIN .cas .CAS .cdm .CDM .rom .ROM .xex .XEX .xfd .XFD .7z .7Z .zip .ZIP</extension>
|
||||
<extension>.a52 .A52 .atr .ATR .atx .ATX .bin .BIN .car .CAR .cas .CAS .cdm .CDM .rom .ROM .xex .XEX .xfd .XFD .7z .7Z .zip .ZIP</extension>
|
||||
<command label="Atari800">%STARTDIR%=%EMUDIR% %EMULATOR_RETROARCH% -L %CORE_RETROARCH%\atari800_libretro.dll %ROM%</command>
|
||||
<command label="Atari800 (Standalone)">%STARTDIR%=%EMUDIR% %EMULATOR_ATARI800% %ROM%</command>
|
||||
<platform>atari800</platform>
|
||||
|
@ -330,7 +330,7 @@
|
|||
<command label="MAME 2010">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\mame2010_libretro.dll %ROM%</command>
|
||||
<command label="MAME 2003-Plus">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\mame2003_plus_libretro.dll %ROM%</command>
|
||||
<command label="MAME 2000">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\mame2000_libretro.dll %ROM%</command>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %ROMPATH%\arcade %BASENAME%</command>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%\cps %BASENAME%</command>
|
||||
<command label="FinalBurn Neo">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\fbneo_libretro.dll %ROM%</command>
|
||||
<command label="FB Alpha 2012">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\fbalpha2012_libretro.dll %ROM%</command>
|
||||
<command label="FB Alpha 2012 CPS-1">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\fbalpha2012_cps1_libretro.dll %ROM%</command>
|
||||
|
@ -500,8 +500,8 @@
|
|||
<path>%ROMPATH%\gameandwatch</path>
|
||||
<extension>.mgw .MGW .7z .7Z .zip .ZIP</extension>
|
||||
<command label="Handheld Electronic (GW)">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\gw_libretro.dll %ROM%</command>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %ROMPATH%\gameandwatch %BASENAME%</command>
|
||||
<command label="MAME Local Artwork (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -artpath %ROMPATH%\gameandwatch\artwork -rompath %ROMPATH%\gameandwatch %BASENAME%</command>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%\gameandwatch %BASENAME%</command>
|
||||
<command label="MAME Local Artwork (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -artpath %ROMPATH%\gameandwatch\artwork -rompath %GAMEDIR%\;%ROMPATH%\gameandwatch %BASENAME%</command>
|
||||
<platform>gameandwatch</platform>
|
||||
<theme>gameandwatch</theme>
|
||||
</system>
|
||||
|
@ -601,7 +601,7 @@
|
|||
<extension>.bin .BIN .cdt .CDT .cpr .CPR .dsk .DSK .kcr .KCR .m3u .M3U .sna .SNA .tap .TAR .voc .VOC .7z .7Z .zip .ZIP</extension>
|
||||
<command label="Caprice32">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\cap32_libretro.dll %ROM%</command>
|
||||
<command label="CrocoDS">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\crocods_libretro.dll %ROM%</command>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %ROMPATH%\gx4000 gx4000 -cart %ROM%</command>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%\gx4000 gx4000 -cart %ROM%</command>
|
||||
<platform>gx4000</platform>
|
||||
<theme>gx4000</theme>
|
||||
</system>
|
||||
|
@ -670,7 +670,7 @@
|
|||
<command label="MAME 2010">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\mame2010_libretro.dll %ROM%</command>
|
||||
<command label="MAME 2003-Plus">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\mame2003_plus_libretro.dll %ROM%</command>
|
||||
<command label="MAME 2000">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\mame2000_libretro.dll %ROM%</command>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %ROMPATH%\mame %BASENAME%</command>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%\mame %BASENAME%</command>
|
||||
<command label="FinalBurn Neo">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\fbneo_libretro.dll %ROM%</command>
|
||||
<command label="FB Alpha 2012">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\fbalpha2012_libretro.dll %ROM%</command>
|
||||
<command label="Flycast">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\flycast_libretro.dll %ROM%</command>
|
||||
|
@ -678,7 +678,7 @@
|
|||
<command label="Kronos">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\kronos_libretro.dll %ROM%</command>
|
||||
<command label="Model 2 Emulator (Standalone)">%RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_M2EMULATOR% %BASENAME%</command>
|
||||
<command label="Model 2 Emulator [Suspend ES-DE] (Standalone)">%STARTDIR%=%EMUDIR% %EMULATOR_M2EMULATOR% %BASENAME%</command>
|
||||
<command label="Supermodel (Standalone)">%STARTDIR%=%EMUDIR% %EMULATOR_SUPERMODEL% -fullscreen %ROM%</command>
|
||||
<command label="Supermodel (Standalone)">%STARTDIR%=%EMUDIR% %EMULATOR_SUPERMODEL% -fullscreen -force-feedback %INJECT%=%BASENAME%.commands %ROM%</command>
|
||||
<platform>arcade</platform>
|
||||
<theme>mame</theme>
|
||||
</system>
|
||||
|
@ -778,6 +778,8 @@
|
|||
<extension>.7z .7Z .zip .ZIP</extension>
|
||||
<command label="Model 2 Emulator (Standalone)">%RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_M2EMULATOR% %BASENAME%</command>
|
||||
<command label="Model 2 Emulator [Suspend ES-DE] (Standalone)">%STARTDIR%=%EMUDIR% %EMULATOR_M2EMULATOR% %BASENAME%</command>
|
||||
<command label="MAME - Current">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\mame_libretro.dll %ROM%</command>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%\model2 %BASENAME%</command>
|
||||
<platform>arcade</platform>
|
||||
<theme>model2</theme>
|
||||
</system>
|
||||
|
@ -786,7 +788,7 @@
|
|||
<fullname>Sega Model 3</fullname>
|
||||
<path>%ROMPATH%\model3</path>
|
||||
<extension>.7z .7Z .zip .ZIP</extension>
|
||||
<command label="Supermodel (Standalone)">%STARTDIR%=%EMUDIR% %EMULATOR_SUPERMODEL% -fullscreen %ROM%</command>
|
||||
<command label="Supermodel (Standalone)">%STARTDIR%=%EMUDIR% %EMULATOR_SUPERMODEL% -fullscreen -force-feedback %INJECT%=%BASENAME%.commands %ROM%</command>
|
||||
<platform>arcade</platform>
|
||||
<theme>model3</theme>
|
||||
</system>
|
||||
|
@ -950,7 +952,7 @@
|
|||
<extension>.7z .7Z .zip .ZIP</extension>
|
||||
<command label="FinalBurn Neo">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\fbneo_libretro.dll %ROM%</command>
|
||||
<command label="FinalBurn Neo (Standalone)">%STARTDIR%=%EMUDIR% %EMULATOR_FINALBURN-NEO% %BASENAME%</command>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %ROMPATH%\neogeo %BASENAME%</command>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%\neogeo %BASENAME%</command>
|
||||
<platform>neogeo</platform>
|
||||
<theme>neogeo</theme>
|
||||
</system>
|
||||
|
@ -961,7 +963,7 @@
|
|||
<extension>.chd .CHD .cue .CUE</extension>
|
||||
<command label="NeoCD">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\neocd_libretro.dll %ROM%</command>
|
||||
<command label="FinalBurn Neo">%EMULATOR_RETROARCH% --subsystem neocd -L %CORE_RETROARCH%\fbneo_libretro.dll %ROM%</command>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %ROMPATH%\neogeocd neocdz -cdrm %ROM%</command>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%\neogeocd neocdz -cdrm %ROM%</command>
|
||||
<platform>neogeocd</platform>
|
||||
<theme>neogeocd</theme>
|
||||
</system>
|
||||
|
@ -972,7 +974,7 @@
|
|||
<extension>.chd .CHD .cue .CUE</extension>
|
||||
<command label="NeoCD">%EMULATOR_RETROARCH% -L %CORE_RETROARCH%\neocd_libretro.dll %ROM%</command>
|
||||
<command label="FinalBurn Neo">%EMULATOR_RETROARCH% --subsystem neocd -L %CORE_RETROARCH%\fbneo_libretro.dll %ROM%</command>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %ROMPATH%\neogeocdjp neocdz -cdrm %ROM%</command>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%\neogeocdjp neocdz -cdrm %ROM%</command>
|
||||
<platform>neogeocd</platform>
|
||||
<theme>neogeocdjp</theme>
|
||||
</system>
|
||||
|
@ -1524,7 +1526,7 @@
|
|||
<fullname>Texas Instruments TI-99</fullname>
|
||||
<path>%ROMPATH%\ti99</path>
|
||||
<extension>.rpk .RPK .7z .7Z .zip .ZIP</extension>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %ROMPATH%\ti99 ti99_4a -ioport peb -ioport:peb:slot3 speech -cart %BASENAME%</command>
|
||||
<command label="MAME (Standalone)">%HIDEWINDOW% %RUNINBACKGROUND% %STARTDIR%=%EMUDIR% %EMULATOR_MAME% -rompath %GAMEDIR%\;%ROMPATH%\ti99 ti99_4a -ioport peb -ioport:peb:slot3 speech -cart %BASENAME%</command>
|
||||
<platform>ti99</platform>
|
||||
<theme>ti99</theme>
|
||||
</system>
|
||||
|
|
|
@ -206,13 +206,13 @@
|
|||
md_lbl_genre, md_lbl_players, md_lbl_lastplayed ">
|
||||
<size>0.14 0.02</size>
|
||||
<fontPath>./core/fonts/Exo2-BoldCondensed.otf</fontPath>
|
||||
<fontSize>0.02</fontSize>
|
||||
<fontSize>0.0195</fontSize>
|
||||
<letterCase>uppercase</letterCase>
|
||||
</text>
|
||||
<text name="md_developer, md_publisher, md_genre, md_players">
|
||||
<size>0.14 0.02</size>
|
||||
<fontPath>./core/fonts/Exo2-RegularCondensed.otf</fontPath>
|
||||
<fontSize>0.02</fontSize>
|
||||
<fontSize>0.0195</fontSize>
|
||||
<letterCase>uppercase</letterCase>
|
||||
</text>
|
||||
<text name="md_description">
|
||||
|
@ -225,14 +225,14 @@
|
|||
<containerResetDelay>7</containerResetDelay>
|
||||
<metadata>description</metadata>
|
||||
<fontPath>./core/fonts/Exo2-SemiBoldCondensed.otf</fontPath>
|
||||
<fontSize>0.02</fontSize>
|
||||
<fontSize>0.0195</fontSize>
|
||||
<letterCase>uppercase</letterCase>
|
||||
<lineSpacing>1.2</lineSpacing>
|
||||
</text>
|
||||
<datetime name="md_releasedate, md_lastplayed">
|
||||
<size>0.14 0.02</size>
|
||||
<fontPath>./core/fonts/Exo2-RegularCondensed.otf</fontPath>
|
||||
<fontSize>0.02</fontSize>
|
||||
<fontSize>0.0195</fontSize>
|
||||
<letterCase>uppercase</letterCase>
|
||||
</datetime>
|
||||
<text name="md_lbl_releasedate">
|
||||
|
@ -328,6 +328,8 @@
|
|||
<origin>0.5 0.5</origin>
|
||||
<imageType>image</imageType>
|
||||
<interpolation>nearest</interpolation>
|
||||
<pillarboxes>true</pillarboxes>
|
||||
<pillarboxThreshold>0.85 0.90</pillarboxThreshold>
|
||||
<delay>1.7</delay>
|
||||
<scrollFadeIn>true</scrollFadeIn>
|
||||
</video>
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<horizontalOffset>-0.05</horizontalOffset>
|
||||
<text>${system.fullName}</text>
|
||||
<fontPath>./core/fonts/Exo2-RegularCondensed.otf</fontPath>
|
||||
<fontSize>0.070</fontSize>
|
||||
<fontSize>0.056</fontSize>
|
||||
<letterCase>uppercase</letterCase>
|
||||
<lineSpacing>1.2</lineSpacing>
|
||||
</carousel>
|
||||
|
|
|
@ -107,7 +107,7 @@
|
|||
<horizontalOffset>0</horizontalOffset>
|
||||
<verticalOffset>0</verticalOffset>
|
||||
<fontPath>./core/fonts/Exo2-RegularCondensed.otf</fontPath>
|
||||
<fontSize>0.070</fontSize>
|
||||
<fontSize>0.056</fontSize>
|
||||
<letterCase>uppercase</letterCase>
|
||||
<lineSpacing>1.2</lineSpacing>
|
||||
<zIndex>80</zIndex>
|
||||
|
|
|
@ -111,7 +111,7 @@
|
|||
<unfocusedItemOpacity>1</unfocusedItemOpacity>
|
||||
<textBackgroundColor>323232CC</textBackgroundColor>
|
||||
<fontPath>./core/fonts/Exo2-RegularCondensed.otf</fontPath>
|
||||
<fontSize>0.050</fontSize>
|
||||
<fontSize>0.032</fontSize>
|
||||
<letterCase>uppercase</letterCase>
|
||||
<lineSpacing>1.2</lineSpacing>
|
||||
<zIndex>60</zIndex>
|
||||
|
|