Compare commits

...

380 commits

Author SHA1 Message Date
Stenzek
b798d8f1aa
Settings: Add option for enabling GPU-based validation 2025-03-30 23:20:39 +10:00
Stenzek
049ec4af90
CI/Linux: Bump discord-rpc/lunasvg commits 2025-03-30 22:27:59 +10:00
Stenzek
162d742cc0
CDROM: Remove hack for Fighting Force
Instead properly handle the one-sector-delay that occurs when autopause
detects the start of a new track.
2025-03-30 22:00:21 +10:00
Stenzek
8c1f75ab8c
GameDatabase: Add overrides for maximum CD speedup cycles 2025-03-30 22:00:21 +10:00
Stenzek
d2c09dfaff
Settings: Split read and seek cycles for maximum CD speedup 2025-03-30 22:00:21 +10:00
Stenzek
3292833fb8
FullscreenUI: Add option to turn off animations 2025-03-30 15:58:48 +10:00
Stenzek
04c5a9f1b2
FullscreenUI: Improve leaderboard text contrast 2025-03-30 15:43:15 +10:00
Stenzek
c5cc94c4b7
FullscreenUI: Fix hotkey categories duplicating 2025-03-30 15:22:46 +10:00
Stenzek
64513395f3
FullscreenUI: Add fade transition to most screen changes 2025-03-30 15:22:46 +10:00
Stenzek
e6e6313219
FullscreenUI: Add offscreen-based screen fade 2025-03-30 15:22:46 +10:00
Stenzek
4e2872f248
FullscreenUI: Fix consecutive choice dialogs 2025-03-30 14:45:26 +10:00
Stenzek
2d31bf5685
FullscreenUI: Convert input binding into a PopupDialog 2025-03-30 14:45:26 +10:00
Stenzek
9bcd738f5c
FullscreenUI: Make save state selector a main window
More reliable, saves messing around with popups.
2025-03-30 14:45:26 +10:00
Stenzek
3bf5ded0d2
FullscreenUI: Fix various issues
- Pause menu losing key focus the first time it's opened.
- Pause menu being unopenable after close when paused.
- Key nav not being enabled after closing game via main UI.
2025-03-30 11:47:31 +10:00
Stenzek
a3e840526a
FullscreenUI: Fix multi-disc selection with duplicate filenames 2025-03-29 21:46:56 +10:00
Stenzek
54c42f9c27
Achievements: Consider all-hidden-leaderboards as no leaderboards
Stops the menu option being available and showing 0 leaderboards.
2025-03-29 20:06:09 +10:00
Stenzek
b4ae19411b
Achievements: Show unconfirmed unlocks in pause menu 2025-03-29 20:06:09 +10:00
Stenzek
37230107f4
FullscreenUI: Run idle while notifications/toasts are onscreen 2025-03-29 20:06:09 +10:00
Stenzek
730fa67952
FullscreenUI: Darken titled toast text 2025-03-29 20:06:09 +10:00
Stenzek
3cf2f41723
FullscreenUI: Fix crash changing renderer 2025-03-29 20:06:09 +10:00
Stenzek
ba3c693717
Qt: Fix double memcard warning on shutdown 2025-03-29 18:01:10 +10:00
Stenzek
0687e59bda
FullscreenUI: Rewrite popup dialog handling
Add animations, fix background dimming.
2025-03-29 17:57:37 +10:00
Stenzek
576658b6eb
Settings: Max speedup cycles should be at least 1 2025-03-28 21:23:32 +10:00
Stenzek
c7504e7016
dep/fmt: Bump to v11.1.4 2025-03-28 20:54:04 +10:00
Stenzek
e4a028834a
FullscreenUI: Fix keynav default in open-in-game-list mode 2025-03-28 20:44:54 +10:00
Stenzek
f36062a94e
FullscreenUI: Fix duplicate item in advanced settings 2025-03-28 20:40:52 +10:00
Stenzek
9ef7f54f19
FullscreenUI: Enable all windows to nav-wrap
i.e. when pressing down at the end, it wraps to the top.
2025-03-28 20:38:31 +10:00
Stenzek
003518c234
FullscreenUI: Fix nav wrapping if first item is disabled 2025-03-28 20:12:41 +10:00
Stenzek
6f2225fb61
FullscreenUI: Remove redundant ActiveButton() and friends 2025-03-28 19:45:52 +10:00
Stenzek
f80a77fa27
FullscreenUI: Fix popup item border going outside of window 2025-03-28 19:27:24 +10:00
Stenzek
ea3774cece
FullscreenUI: Fix setting BIOS to Auto Detect 2025-03-28 18:54:14 +10:00
Stenzek
58bd87666e
Qt: Fix crash when FSUI open and game list activated 2025-03-28 17:25:53 +10:00
Stenzek
fbadacae78
CDROM: Fudge track autopause hold position
Fudge the hold position by 2 sectors to reduce the number of GetlocP's
that will return a MSF in the old track.

Works around the music hang in Fighting Force.
2025-03-28 17:24:39 +10:00
Stenzek
ceef7af1da
GameList: Fix crash if cache fails to open 2025-03-28 17:07:13 +10:00
Stenzek
ece18d10c5
PCDrv: Allow opening by absolute path 2025-03-24 18:59:15 +10:00
Stenzek
ae9023ddf3
CI: Build armhf AppImages 2025-03-23 23:41:19 +10:00
Stenzek
3f0abccb59
CI: Don't use zlib-ng on cross-compiled AppImages
Seems to be problematic on armhf, and I can't be arsed debugging it.
2025-03-23 23:41:00 +10:00
Stenzek
104c82c2c3
Mini: Fix right button forwarding 2025-03-23 23:39:26 +10:00
Stenzek
2cb6ce635f
Mini: Fix non-first game list refresh 2025-03-23 23:39:15 +10:00
Stenzek
4ce001aef3
GameDatabase: Add DisableFullTrueColor trait 2025-03-23 17:08:25 +10:00
Stenzek
1fca8ae6bf
FullscreenUI: Fix start-in-game-list mode using grid 2025-03-23 17:02:52 +10:00
Stenzek
3ffd20b833
FullscreenUI: Display game list attributes in darker colour 2025-03-23 16:59:23 +10:00
Stenzek
9411e40c20
FullscreenUI: Fix assert when booting+loading state 2025-03-23 16:43:57 +10:00
Stenzek
03d7af2efc
FullscreenUI: Add border rounding to menu items 2025-03-23 16:42:24 +10:00
Stenzek
9020959511
Qt: Add game list background function 2025-03-23 15:58:56 +10:00
Stenzek
98d1c71981
GameDB: Force full true color for Bust a Move 2
Not strictly accurate, but looks better.
2025-03-22 18:32:31 +10:00
Stenzek
741e971681
GPU/HW: Add 'True Color (Full)' dithering mode
This is equivalent to the old 'True Color' mode.

The new 'True Color' mode truncates flat-shaded sprites/polygons
to 16-bit color before drawing. Doing so fixes:

- Menu background in Breath of Fire IV.
- Loading background in JumpStart Wildlife Safari - Field Trip.
- and other similar games.
2025-03-22 18:32:31 +10:00
Stenzek
2d477f80b0
Qt: Add tooltips to setup wizard graphics settings
Same strings as the main graphics settings page, so translation should
be just a matter of accepting them as-is.
2025-03-22 18:32:31 +10:00
Stenzek
2311c8d287
Settings: Convert dithering/true color options to a dropdown
Half of them are mutually exclusive, so this simplifies things.
Fewer options = better, right?
2025-03-22 18:20:51 +10:00
Stenzek
32b09193d1
Qt: Move force video timing to console settings
Since it's related to the region, it makes sense to be in here.
And it frees up precious vertical space.
2025-03-22 18:20:51 +10:00
Stenzek
4afa41b927
Qt: Move async readahead sectors to advanced settings 2025-03-22 18:20:51 +10:00
Stenzek
3ab3e4be06
ImGuiManager: Tweak OSD message rounding 2025-03-22 18:20:51 +10:00
zkdpower
f4e93df1b1
Update the Simple-Chinese translation to latest. (#3395) 2025-03-22 17:10:12 +10:00
Stenzek
115ba4433c
CPU/Interpreter: Emulate lo/hi read stall after mult/div
Still need to do the recompiler.
2025-03-22 01:59:00 +10:00
Stenzek
74064af730
GameDB: Set disable scaled interlacing on various games
Fixes intro fade/transitions in Final Fantasy VIII.
Fixes menu corruption in Destruction Derby Raw.
2025-03-22 01:19:01 +10:00
Stenzek
62d7a73381
GPU/HW: Add 'Scaled Interlacing' option
Disabling this option causes rendering to skip N lines instead of 1
line, where N is the internal resolution multiplier.
2025-03-22 01:19:01 +10:00
Stenzek
d176109d3b
GPU/HW: Fix incorrect interlaced VRAM extract offset
Fixes exascerbated combing when upscaling.
2025-03-22 01:11:24 +10:00
Stenzek
6eddc0b982
GPUDevice: Don't allow copy-resize between different formats
That's a spec violation.
2025-03-22 01:11:23 +10:00
Stenzek
346f0f945d
GameDatabase: Fix incorrect multitap key parsing 2025-03-21 19:11:50 +10:00
Stenzek
de6a8fba51
BIOS: Set priority of v4.1 E to 10
It doesn't have the additional region check.
2025-03-21 19:11:47 +10:00
Stenzek
5c41a48e39
GPU/HW: Fix crash when changing downsampling factor 2025-03-20 21:19:08 +10:00
zkdpower
19c03aff4d
Update the Simple-Chinese translation to latest. (#3394) 2025-03-20 21:17:47 +10:00
Anderson Cardoso
fffa44911c
Atualização Português do Brasil (#3393)
Atualizado para a última versão.
2025-03-20 21:17:39 +10:00
JukePlz
10fea83b4a
GameDB: Intelligent Qube doesn't support analog controller (#3392)
Same for the demos.
2025-03-20 21:17:20 +10:00
Daniel Nylander
eea4159756
Updated Swedish translation (#3391) 2025-03-20 21:17:08 +10:00
KamFretoZ
e5cec05633
Qt/BPM: Add Green Giant Theme (#3390)
WHAT ARE YE DOING IN MY SWAMP???
2025-03-20 21:16:45 +10:00
Stenzek
a1d69982f3
CI: Update AppStream metainfo 2025-03-15 18:49:58 +10:00
Stenzek
e3cb3d029b
FullscreenUI: Fix system not unpausing after HC disable popup 2025-03-15 16:27:43 +10:00
Stenzek
27fc7de07a
FullscreenUI: Add translucency/shadow to achievement notifications 2025-03-15 16:27:43 +10:00
Stenzek
a1e5bb7bc0
FullscreenUI: Display legend for achievement status icons 2025-03-15 15:58:39 +10:00
Stenzek
61de096d26
FullscreenUI: Add status text (left side of footer) 2025-03-15 15:58:22 +10:00
Stenzek
4f00a7c7c1
FullscreenUI: Add rounding to achievements progress bars 2025-03-15 15:44:23 +10:00
Stenzek
3420af829c
FullscreenUI: Display unlock rarity in achievements view 2025-03-15 15:41:30 +10:00
Stenzek
830842891e
GameList: Rename max value enum for consistency 2025-03-15 15:03:42 +10:00
Stenzek
dd885cfe2f
GameList: Cache invalid entries
Saves repeatedly scanning them every time the application starts.
2025-03-15 15:02:56 +10:00
Stenzek
8a0400ad2c
GameList: Don't try to scan gpudump files 2025-03-15 14:46:19 +10:00
Stenzek
bcd4b918dc
FullscreenUI: Fix black screen on renderer change 2025-03-15 14:39:22 +10:00
Stenzek
c82c007a75
FullscreenUI: Add settings reset option to settings 2025-03-15 14:33:51 +10:00
Stenzek
0a470067f5
FullscreenUI: Move appearance up in settings order 2025-03-15 14:07:35 +10:00
Stenzek
9734066514
FullscreenUI: Add StaticGray background 2025-03-15 14:05:09 +10:00
Stenzek
2a86faa51e
FullscreenUI: Replace landing icons with colourable icons 2025-03-15 13:56:29 +10:00
Stenzek
4bac7cb79e
FullscreenUI: Fix some dialogs not being cancellable
i.e. exitable with right mouse click/B button.
2025-03-15 02:18:20 +10:00
KamFretoZ
db3b689166
FullscreenUI: Add Dark Ruby theme (#3389) 2025-03-15 02:17:54 +10:00
Stenzek
1189f53840
FullscreenUI: Add 'Automatic' theme that syncs with Qt 2025-03-15 00:42:02 +10:00
Stenzek
6e27b8ab91
FullscreenUI: Add option to start/open to game list 2025-03-14 23:57:14 +10:00
Stenzek
3d0f038697
FullscreenUI: Move game list settings to main tab
And add resume to game list/grid.
2025-03-14 23:53:50 +10:00
Stenzek
6c867859bf
FullscreenUI: Apply theme to loading screen 2025-03-14 23:07:14 +10:00
Stenzek
f11c31b41c
ImGuiOverlays: Apply theme to save state selector 2025-03-14 22:58:02 +10:00
Stenzek
cffafad2ca
ImGuiManager: Use fullscreen UI theme for OSD 2025-03-14 22:36:14 +10:00
Stenzek
b6fa2cecd3
FullscreenUI: Fix shadowed text alpha again 2025-03-14 22:36:14 +10:00
Stenzek
9c971825a9
FullscreenUI: Apply theme to ingame achievement overlays 2025-03-14 21:22:17 +10:00
Stenzek
c57689cc90
FullscreenUI: Inherit colour alpha for shadowed text 2025-03-14 21:21:56 +10:00
Stenzek
511663198e
Qt: Update glyph ranges 2025-03-14 20:52:43 +10:00
zkdpower
531b3e103a
Update the Simple-Chinese translation to latest. (#3388) 2025-03-14 20:52:19 +10:00
Stenzek
e422afdec1
FullscreenUI: Improve achievements pause menu overlays
- Add most recent unlock/nearest completion.
- Make it look nicer and better fit with the rest of the interface.
2025-03-14 20:50:20 +10:00
Stenzek
ba3295930c
VulkanDevice: Allow 0x0 window size
Fixes minimizing in render-to-separate-window mode.
2025-03-12 23:54:25 +10:00
KamFretoZ
4fc49ee0ca
FullscreenUI: Tweak the highlight background color (#3387) 2025-03-12 23:54:15 +10:00
Stenzek
f6296ceb09
Qt: Increase setup wizard dialog height
Needs it on Linux otherwise graphics combos are shrunk.
2025-03-12 01:46:10 +10:00
Stenzek
9a9ed52b70
Qt: Fix vertical alignment in patches page 2025-03-12 01:46:07 +10:00
Stenzek
44af55a77f
FullscreenUI: Differentiate title/subtitle colours
Makes it easier to read.
2025-03-12 01:46:04 +10:00
Stenzek
72a0ba1e8e
FullscreenUI: Fix pause menu light theme shadow colour 2025-03-12 00:19:32 +10:00
Stenzek
aeadd4c280
FullscreenUI: Move game info to top of pause menu 2025-03-11 23:19:00 +10:00
Stenzek
d6ab840e4b
FullscreenUI: Use RetroAchievements game icon as fallback game image 2025-03-11 22:38:43 +10:00
Stenzek
492a55ee8b
FullscreenUI: Add icons to achievement list categories 2025-03-11 22:27:08 +10:00
Stenzek
541af8d5de
GDBServer: Stub out thread commands 2025-03-11 22:07:18 +10:00
Stenzek
7bae23d79d
GDBServer: Implement memory breakpoints 2025-03-11 21:50:26 +10:00
Stenzek
a0c06f8d9c
GDBServer: Implement 's' command (single step) 2025-03-11 21:32:03 +10:00
Stenzek
814263b442
GDBServer: Mostly rewrite handlers and fix undefined behaviour
Remove all heap allocations.
Remove copies.
2025-03-11 21:29:29 +10:00
Stenzek
2f5855a7a4
GDBServer: Get rid of <map> usage 2025-03-11 20:37:37 +10:00
Stenzek
cd694c01d8
GDBServer: Improve ack handling
Treat acks as complete packets, that way it doesn't spam an error
when only an ack is sent.
2025-03-11 20:30:47 +10:00
Stenzek
c717f547cf
Deps: Update to SDL3 3.2.8 2025-03-10 21:54:45 +10:00
Stenzek
8bffd9725e
Qt: Lock system when automatic updater shows
Prevents messyness when launching in fullscreen+big picture.
2025-03-10 21:54:45 +10:00
Stenzek
e25f287d60
Qt: Avoid stuck in temporary render-to-separate mode 2025-03-10 21:54:45 +10:00
Stenzek
9f0bbccd50
Achievements: Fix progress bar text alignment 2025-03-10 21:54:45 +10:00
Víctor "IlDucci
29f19d0ab6
Spanish (Spain) translation update (#3386)
- Adding new strings.
2025-03-09 16:10:49 +10:00
Stenzek
58dc7562a3
GPU/HW: Add in-pass clear depth pipeline
Instead of clearing the entire buffer, we only need to wipe out the
current drawing area. Saves a decent chunk of memory bandwidth in games
that end up spamming clears.
2025-03-07 21:33:06 +10:00
Stenzek
ee6887b68a
GPU/HW: Add stat for depth buffer clears 2025-03-07 21:33:02 +10:00
Stenzek
2bfbec3e9e
Settings: Use new key name for depth threshold
Because of the changed range.
2025-03-07 21:32:57 +10:00
Stenzek
705fe11e07
Qt: Fix incorrect file filter for memory card import 2025-03-07 21:32:57 +10:00
Stenzek
e73ca9e052
Qt: Fix new range for depth clear threshold 2025-03-07 18:05:20 +10:00
Stenzek
6437a5db60
GPU/TextureCache: Dump textures asynchronously
Saves lagging the emulation.
2025-03-07 16:05:36 +10:00
Stenzek
95797b05f1
GPU: Force early run on GP0 FIFO overflow
And don't crash if a game spams GP0 writes and it overflows.
2025-03-07 15:49:07 +10:00
Stenzek
9939f1cd05
CPU/Interpreter: Use __builtin_{add,sub}_overflow for exceptions
Recompiler already does this.
2025-03-07 15:48:28 +10:00
Stenzek
7eb7ad684c
CPU/Recompiler: Remove load delay flag from lwc2
Shouldn't make any difference since it's not a register write.
2025-03-07 15:08:00 +10:00
Stenzek
826f10239c
CPU/Recompiler: Flush GTE completion cycle on load without fastmem 2025-03-06 22:41:10 +10:00
Stenzek
78bb14bd23
CPU: Fix disassembly of GTE instructions in log 2025-03-06 22:41:10 +10:00
Stenzek
b230c9c639
CPU/PGXP: Use GTE MAX_Z for Z normalization
Fixes clipping with depth buffer in some games, e.g. Final Fantasy VII battles.
2025-03-06 22:41:10 +10:00
Stenzek
8cfd843d8f
System: Fix depth clear threshold not applying immediately 2025-03-06 22:41:09 +10:00
Stenzek
160f1ea8a0
Qt: Fix vibration motor binding not showing some devices 2025-03-06 22:41:09 +10:00
Anderson Cardoso
c3ce0eece2
Atualização Português do Brasil (#3385)
Melhoria de consistência dos textos e adição de novos conforme última atualização mais recente.
2025-03-06 22:40:54 +10:00
bl@ck_m@ge
b8d86a18da
GameDB: Kagero II & III 2025-03-04 17:55:00 +10:00
Stenzek
0bf0b5c22b
Qt: Fix typo in setup wizard 2025-03-04 14:07:17 +10:00
Stenzek
4c64e4879f
Mini: Log fatal errors to stderr 2025-03-04 14:07:17 +10:00
Daniel Nylander
af4eb68065
Updated Swedish translation (#3383) 2025-03-04 14:06:10 +10:00
JukePlz
c775872a6c
GameDB: ASCII and VIP demos don't support analog controllers. (#3384) 2025-03-04 14:05:47 +10:00
Stenzek
859f5090c8
FullscreenUI: Update translation strings 2025-03-02 12:01:55 +10:00
KamFretoZ
38146f2023
FullscreenUI: Fix toast colors and add more themes (#3381) 2025-03-02 12:01:27 +10:00
Stenzek
a0fef2d5ab
Qt: Merge gamelistmodel.cpp and gamelistwidget.cpp
They're constantly referring to each other.
2025-03-01 18:13:37 +10:00
Stenzek
4bfb37f8fb
Qt: Add graphics and achievements to setup wizard 2025-03-01 18:05:48 +10:00
Stenzek
965da856db
FullscreenUI: Add additional rounding to some dialogs 2025-03-01 17:10:09 +10:00
Stenzek
34fdbafe85
FullscreenUI: Add drop shadows to most text
Improves readability with custom backgrounds.
2025-03-01 16:00:05 +10:00
Stenzek
9bfc3e90cc
FullscreenUI: Hook up dynamic toast colour 2025-03-01 13:10:50 +10:00
Stenzek
9d9da94b7b
FullscreenUI: Default to dark theme on unknown value 2025-03-01 13:10:50 +10:00
Stenzek
5a4e87aba3
FullscreenUI: Reorder interface settings to match Qt 2025-03-01 13:10:44 +10:00
KamFretoZ
5dc0a3630a
FullscreenUI: Add Themes (#3380) 2025-03-01 12:41:06 +10:00
Stenzek
15fde6a51b
CI: Add ARM64 AppImage builds 2025-03-01 01:34:48 +10:00
Stenzek
ea8f3e5e58
Scripts: Support generating both Qt and Mini AppImages 2025-03-01 01:27:29 +10:00
Stenzek
89d9842c7e
FullscreenUI: Fix popup title colours 2025-03-01 01:11:26 +10:00
Stenzek
be970bcfe4
Qt: Handle inverted+negated axes when mapping 2025-02-28 18:06:51 +10:00
Stenzek
ec7c83a58e
Settings: Fix race toggling OSD messages 2025-02-28 16:29:18 +10:00
Stenzek
6a86c80445
CPU: Correct wording about cop2 and IRQs 2025-02-28 16:29:18 +10:00
Stenzek
37fa0d135c
Mini: Add duckstation-mini interface 2025-02-28 16:29:18 +10:00
Stenzek
df9f15eb68
OpenGLDevice: Support SDL window type 2025-02-28 16:29:18 +10:00
Stenzek
ee1a3b904e
VulkanDevice: Support SDL window type 2025-02-28 15:46:53 +10:00
Stenzek
4bddd38d70
WindowInfo: Add SDL window type 2025-02-28 15:46:53 +10:00
Stenzek
0733e173b2
FullscreenUI: Add BackgroundProgressCallback 2025-02-28 15:46:53 +10:00
Stenzek
498e7aac56
X11Tools: Load libxcb and friends dynamically 2025-02-28 15:46:53 +10:00
Stenzek
f7f17a077c
Cheats: Add Enable8MBRAM option for patches 2025-02-26 22:43:18 +10:00
Anderson Cardoso
0b167aad52
Atualização Português do Brasil (#3379)
Atualizado para a última versão.
2025-02-26 22:42:50 +10:00
Renzo Pigliacampo
08bbb4a981
Updated Spanish (Latin America) translation (#3378) 2025-02-26 22:42:42 +10:00
Stenzek
fbbc4943f6
FullscreenUI: Fix crash in game properties on non-scanned file 2025-02-24 23:48:23 +10:00
Stenzek
eda32e0695
Qt: Fix image key in overlay export 2025-02-23 18:03:02 +10:00
Stenzek
b764ed4682
DDGoController: Fix incorrect translation context 2025-02-23 18:03:02 +10:00
zkdpower
2011c5511c
Update the Simple-Chinese translation to latest. (#3377) 2025-02-23 18:02:52 +10:00
Stenzek
3ea26cc910
GPU: Rewrite automatic resolution scaling
Make it play nice with rewind/runahead.
2025-02-21 23:58:05 +10:00
Stenzek
d812463649
Qt: Ensure SIGCHLD is ignored properly 2025-02-21 23:58:04 +10:00
Stenzek
5fea81c07d
Qt: Show only HC achievement count if HC == SC 2025-02-21 23:58:04 +10:00
Stenzek
91370ee5ac
Achievements: Update both HC and SC counts on unlock/boot 2025-02-21 23:58:04 +10:00
Stenzek
fa3815d681
Achievements: Fix progress database corruption 2025-02-21 23:58:04 +10:00
Stenzek
90cb92bcc7
CI: Ensure libz.so.1 is packaged in AppImage 2025-02-21 23:58:04 +10:00
JukePlz
f2715b39ec
GameDB: Falcata - Astran Pardma no Monshou hash (#3376) 2025-02-21 23:31:38 +10:00
bl@ck_m@ge
d5c83a80a3
GameDB: Sorcerer's Maze (#3375) 2025-02-21 23:31:21 +10:00
Stenzek
f96ab3afda
Deps: Switch zlib to zlib-ng
Mac is ommitted because the updater is currently still dynamically
linked, and libz is not part of the bundle (yet).
2025-02-20 16:56:43 +10:00
Stenzek
d1b9473cd2
Deps: Update cpuinfo 2025-02-20 16:56:43 +10:00
Stenzek
373c83c357
GameDB: PGXP-CPU for Twisted Metal 2 2025-02-20 13:47:23 +10:00
KamFretoZ
6a0c73b547
Qt: Add AMOLED theme (#3374) 2025-02-20 13:18:27 +10:00
Stenzek
78bd0fdf3e
Qt: Always use ARGB32 for padded cover images
Fixes black background around non-square covers.
2025-02-17 22:53:10 +10:00
Stenzek
31a5d8c481
GameDB: Tama - Adventurous Ball in Giddy Labyrinth hash 2025-02-17 22:53:10 +10:00
Stenzek
72ac4f94db
CDROM: Increase delay for pause-when-paused
Fixes lockup in Tama - Adventurous Ball in Giddy Labyrinth.
2025-02-17 22:53:10 +10:00
Stenzek
6f25cf31a7
CDROM: Add randomness to repeated seek times
I hate it, but it fixes lockups in Dino Crisis 2, and probably
other games with dodgy code too.

Also Simple 1500 Series Vol. 57 - The Meiro.
2025-02-17 22:52:56 +10:00
Stenzek
2f5c4d819e
Common: Add xorshift-based PRNG class 2025-02-17 21:33:37 +10:00
Stenzek
b57049f1aa
CI: Enable Wayland on AppImage/Flatpak builds
Might have to revert this, we'll see how many systems it breaks on.
2025-02-17 00:24:52 +10:00
Stenzek
9a75af2fa9
Qt: Explicitly set desktop file path on startup
Fixes window icon when running under Wayland.

Or, well, as much as it can given the fact that smug GNOME developers
think that windows should not be able to set their own icons.
2025-02-16 23:49:19 +10:00
Stenzek
0c30acb285
Qt: Work around QtWayland bugs
- Render to main no longer screws up the game list/menu bar.
- Toggling render to main no longer breaks the main window.

Positioning still sucks, but the various groups involved would
rather sit around arguing with each other rather than actually
shipping solutions ¯\_(ツ)_/¯.
2025-02-16 22:16:19 +10:00
Stenzek
cb10c6fbf4
Qt: Ensure build warning is themed 2025-02-16 22:16:17 +10:00
Stenzek
4ce1b1afed
GameDB: Set PGXPPreserveProjFP for Vagrant Story
Improves jitter on character models.

Haven't seen any other game with this much of an impact.
2025-02-16 19:03:09 +10:00
Stenzek
5bd1a492be
GameDatabase: Turn PGXPPreserveProjFP into a boolean setting 2025-02-16 19:02:56 +10:00
Stenzek
e688e24eb9
GTE: Use floating-point math for preserve-proj-fp 2025-02-16 18:04:24 +10:00
Stenzek
9928d01ac4
Common: Fix ARM64 build on clang-cl 19
Also fix Vector4 extract32().
2025-02-16 18:03:33 +10:00
Stenzek
cba9d00019
Qt: Further improve async cover loading
- Fix non-square images not centering.
- Fix possible crash when changing scale quickly.
- Avoid repeatedly resizing placeholder.
2025-02-16 13:18:37 +10:00
Anderson Cardoso
b45f9c39c7
Atualização Português do Brasil (#3373)
Atualizado para a última versão.
2025-02-16 13:18:22 +10:00
Stenzek
1b3ca81efc
Qt: Fix hotkey search placeholder localisation 2025-02-15 23:02:19 +10:00
Stenzek
369f62318f
Cheats: Only display codes for selected revision 2025-02-15 22:45:17 +10:00
shikulja
4562573711
Update Russian translation (#3372)
* Update ts

* Update Russian translation

* .
2025-02-15 22:44:50 +10:00
Stenzek
ce8b1f0996
GPU: Small optimization to lanczos shader
Apparently the Adreno shader compiler can't do this on its own.

~23% performance improvement.
2025-02-15 17:44:41 +10:00
Stenzek
958fd0049c
GPU/HW: Don't use shader for self-overlapping copies
If we use the shader here, we're going to immediately end the
render pass since the area we read and wrote to is going to be
dirty again.

This is problematic on Mali where the render passes are really
expensive. Test case: Dino Crisis 2 - open menu
2025-02-15 17:20:30 +10:00
Stenzek
8772c336ec
CPU: Don't stall until GTE completion on write
Apparently this is what the real CPU does, and some very optimized
code can run slower if we stall early.

Obviously if you write to a register being read by the command,
things are going to break.
2025-02-15 12:57:18 +10:00
Stenzek
7d80a74dc3
GameDatabase: Remove now-unused traits 2025-02-15 12:57:02 +10:00
Stenzek
2fcf115d0b
GameDB: Drop LUT fastmem overrides
No longer needed with the previous commit.
2025-02-15 12:55:07 +10:00
Stenzek
2bfc408242
Bus: Enable mmap fastmem on uppermost KSEG0 mirror
Instead of mapping all the RAM mirrors, we only map the KSEG0
uppermost mirror. This is where some games place their stack, so
we avoid the backpatching overhead/slowdown, but don't pay the
cost of 4x the mprotect() calls when a page's protection changes,
which can have a non-trivial impact on slow ARM devices.
2025-02-15 12:42:43 +10:00
Stenzek
e9bfca8cca
System: Add 'Fast Forward Memory Card Access' option
Does what it says on the tin.
2025-02-15 12:38:32 +10:00
Stenzek
13d58d8ed0
Qt: Move fast boot/fast forward to console settings
Makes more sense there, and matches Android.
2025-02-15 12:32:22 +10:00
Stenzek
f4aa5e1b98
MemoryCard: Filename -> Path 2025-02-15 11:39:31 +10:00
Stenzek
e0620fcd40
System: Fix setting-altering game patch behaviour
e.g. overclock was only half applying
2025-02-14 23:50:34 +10:00
Stenzek
bceadadcb4
Image: Fix possible unaligned movaps 2025-02-14 22:51:29 +10:00
Stenzek
6802f77cb9
CrashHandler: More Wcast-function-type-mismatch fixes 2025-02-14 22:06:44 +10:00
Stenzek
af085d7e5a
CI: Bump to LLVM/clang 19 2025-02-14 19:25:05 +10:00
Stenzek
ced9ee4b0b
Qt: Update glyph ranges 2025-02-14 19:02:22 +10:00
Stenzek
dc6d6b91d4
PostProcessing: Fix abort on slow compile in big picture 2025-02-14 19:01:40 +10:00
Stenzek
5060e72b96
Qt: Fix missing vibration binding for NegConRumble 2025-02-14 19:01:40 +10:00
Stenzek
5ae32d3c70
System: Fix black screen when changing options while paused 2025-02-14 19:01:40 +10:00
Stenzek
953bd0919b
RegTest: Fix flipped images in OpenGL
We're reading the framebuffer, not rendered image.
2025-02-14 19:01:40 +10:00
Stenzek
b68d7c8adb
Image: Vectorize RGBA8 conversion and add A1BGR5 2025-02-14 19:01:40 +10:00
Stenzek
9b2cf0abbd
InputSource: Fix Wcast-function-type-mismatch 2025-02-14 19:01:40 +10:00
Stenzek
5913de947f
VulkanDevice: Fix incorrect texture format for A1BGR5 2025-02-14 19:01:40 +10:00
Stenzek
3a44c3a758
GPU: Fix prerotated presenting with OpenGL 2025-02-14 19:01:39 +10:00
Stenzek
995a34e0e3
CMake: Correctly unset host page size if set via cache
Fixes x86 flatpak builds unnecessarily using dynamic page size.
2025-02-14 19:01:39 +10:00
zkdpower
f90fdf66c8
Update the Simple-Chinese translation to latest. (#3371)
* Update the Simple-Chinese translation to latest.
2025-02-14 19:01:28 +10:00
Stenzek
7bc18c8538
DDGoController: Rewrite to support axis input
And add virtual buttons for each of the possible states.
2025-02-12 21:52:02 +10:00
Stenzek
a25d5dcd2f
CI: Apply SDL3 joystick patch 2025-02-12 19:24:24 +10:00
Anderson Cardoso
cd89f62935
Atualização Português do Brasil (#3369)
Atualizado para a última versão.
2025-02-12 19:22:13 +10:00
Stenzek
ce616f1c5c
Cheats: Reapply frame end codes immediately on reload
Otherwise you end up with a single frame where the old code is used.
2025-02-10 23:45:24 +10:00
Stenzek
c137c562cd
Qt: Fix incorrect recommended value 2025-02-10 23:45:24 +10:00
Stenzek
36d5708391
GPU/HW: Fall back to replacements from first disc
So you only need one copy.
2025-02-10 23:45:24 +10:00
Daniel Nylander
f6e8ebec99
Updating Swedish translation (100%) (#3367) 2025-02-10 23:44:23 +10:00
zkdpower
2876713f0f
Update the Simple-Chinese translation to latest. (#3368)
* Update the Simple-Chinese translation to latest.

* Update the Simple-Chinese translation to latest.
2025-02-10 23:44:11 +10:00
Stenzek
ef4c00a896
Qt: Use display name for a couple of recommended values 2025-02-10 02:21:19 +10:00
Stenzek
7a587d927f
Qt: Fix overlapping widgets in macro trigger shift-click 2025-02-10 02:15:27 +10:00
Stenzek
3eed0d0613
CI/Flatpak: Don't strip SDL3 libraries 2025-02-10 02:01:50 +10:00
zkdpower
788b9cd3bf
Update the Simple-Chinese translation to latest. (#3365) 2025-02-10 02:00:38 +10:00
JukePlz
2dfa164629
GameDB: Dezaemon Plus Select 100 does not support analog mode (#3364) 2025-02-10 02:00:08 +10:00
Víctor "IlDucci
c1f8a525ca
Spanish (Spain) translation update 2025-02-09 (#3366)
Adding latest changes and cleaning up unused translations.
2025-02-10 01:59:49 +10:00
Stenzek
5fb5dcdd70
Achievements: Improve summary popup
Put hardcore mode notice on its own line, rather than in
parenthesis in the title.
2025-02-09 18:24:06 +10:00
Stenzek
46ae3e55ea
Cheats: Show disabled code count when HC/safe mode is active 2025-02-09 17:45:19 +10:00
Stenzek
4ce48abfc1
GPU/HW: Fix incorrect source rect for page replacements 2025-02-09 17:45:16 +10:00
Stenzek
ac4ef4f853
Gt: Update glyph ranges 2025-02-09 16:50:02 +10:00
zkdpower
07f973076d
update the Simple-Chinese Translation to latest. (#3363) 2025-02-09 16:49:38 +10:00
Stenzek
8132c51a12
Cheats: Add 'Ignore' field to file format
Codes with Ignore set to true will not be listed/loaded.
2025-02-09 15:58:23 +10:00
Stenzek
4236beabaf
System: Fix setting-altering patches not applying on startup 2025-02-09 15:38:12 +10:00
Stenzek
0428a93315
Qt: Fix possible crash when rescanning game list 2025-02-09 15:04:09 +10:00
Stenzek
3e8ef44a1d
Deps: Update to SDL3 3.2.4 2025-02-09 15:04:09 +10:00
Stenzek
901927d7fe
CDROM: Don't panic on unknown register read 2025-02-09 13:23:37 +10:00
Stenzek
94b2060979
GPU: Clear display texture on fatal error 2025-02-09 13:22:03 +10:00
Stenzek
06b02183cb
GPU/HW: Split transparent draws if dual-source blend unsupported
The ordering is not correct otherwise. Ape Escape has a bunch of
overlapping sprites that have a mix of opaque and transparent texels,
and the transparent texels are repeated multiple times when the
opaque texels should cancel them out.

Only affects old Mali drivers.
2025-02-09 13:07:53 +10:00
Stenzek
2663ac9666
CDImage: Improve PBP load error reporting 2025-02-08 17:33:58 +10:00
Stenzek
160c34ef28
CDROM: Avoid additional stat() call loading subchannel
And use BuildRelativePath() for title-based subchannel files.

Fixes flaky loading on Android, some devices return a zero-sized file
when querying a non-existant file.........
2025-02-08 15:54:38 +10:00
Stenzek
81bca06707
System: Add hash to OnGameChanged 2025-02-08 15:03:17 +10:00
Stenzek
acb355a8c3
CDImage: Make .bin loader track length match .cue
Fixes different hashes for loading single-track .bin games directly.
2025-02-08 15:02:56 +10:00
Stenzek
f2cca01e29
ImGuiManager: Fix achievement unlock icon not showing 2025-02-08 01:46:44 +10:00
Daniel Nylander
084422355a
Updated Swedish translation (#3362) 2025-02-08 01:46:34 +10:00
Stenzek
063bb96e5d
D3D11Device: Always query timestamp before present start
Fixes high GPU usage reporting in D3D11 with AMD GPUs + Optimal Frame
Pacing.
2025-02-07 15:58:35 +10:00
zkdpower
5ae6d9084a
update Chinese translation. (#3361)
just UI.
2025-02-07 12:31:58 +10:00
Anderson Cardoso
51480818cd
Atualização Português do Brasil (#3360)
Atualizado para a última versão
2025-02-06 22:04:07 +10:00
Stenzek
f8c39ace1c
GPU/HW: Warning fix 2025-02-05 22:40:59 +10:00
Stenzek
bee2dabc77
Misc: Replace stringstream str() with C++20 move str()
No extra heap allocation/copy.
2025-02-05 22:38:48 +10:00
Stenzek
8aa97a8118
Data: Update game controller database 2025-02-05 22:14:00 +10:00
Stenzek
2cfc39e874
System: Move cheat reload to Initialize() 2025-02-05 22:13:51 +10:00
Stenzek
57cb2f846e
FullscreenUI: Fix system unpausing on shutdown 2025-02-05 20:03:58 +10:00
Stenzek
ecbb79c4bf
GPU: Add Lanczos scaling option 2025-02-05 20:01:26 +10:00
Stenzek
99e81f1559
GPU: Fix incorrect condition in WaitForOneQueuedFrame() 2025-02-05 19:31:01 +10:00
Stenzek
c6563a4656
VulkanDevice: Require Vulkan 1.1 for most extension probing
Too much of a headache to deal with these ancient Mali drivers that
support some extensions but not full Vulkan 1.1, and VMA does not
support this scenario.
2025-02-04 17:15:29 +10:00
Stenzek
4ad2d0ac2d
GPU: Fix incorrect PAL overscan range 2025-02-03 19:31:23 +10:00
Stenzek
51bef1b3da
CMake: Don't print status messages for deps CMakeLists
fmt is noisy.
2025-02-03 00:31:21 +10:00
Stenzek
455836af89
CMake: Check C++20 features that are missing on some systems 2025-02-03 00:30:59 +10:00
Stenzek
cb205c4c36
Qt: Show icon in settings console region dropdown 2025-02-02 22:57:59 +10:00
Stenzek
af277d4d14
Settings: Default to nearest sprite texture filtering
Instead of whatever the 3D texture filter is.

Less confusing since the UI is not disconnected when upgrading from very
old releases, or Android.
2025-02-02 22:57:31 +10:00
Stenzek
59773509af
System: Recreate memory save states when device options change 2025-02-02 22:54:32 +10:00
Stenzek
1f5a10371e
GPUThread: Handle rare race condition in frame queueing 2025-02-02 22:18:13 +10:00
Stenzek
1ca5782396
Threading: Handle EINTR on sem_wait() 2025-02-02 22:17:56 +10:00
Stenzek
57883910d6
CI: Add ARM64 flatpak build 2025-02-02 18:51:46 +10:00
Stenzek
4ceeb58dbc
GPU: Use display size for calculating internal screenshot size
Fixes detail being lost due to added padding when not cropping.
2025-02-02 17:14:35 +10:00
Stenzek
64d3716cfd
GPU: Further simplify draw rect calculation
Remove "Stretch Vertically" option, it was very confusing to users.

Integer scale will prefer whichever direction gets a larger draw
rectangle/preserves as much detail.
2025-02-02 17:02:58 +10:00
Stenzek
0c3d55a1a1
GPU: Fix incorrect PAR with overscan cropping 2025-02-02 16:07:06 +10:00
Stenzek
a5940b2e21
GPU: Use constants for display overscan range 2025-02-02 15:39:20 +10:00
Stenzek
7316b011a4
CI: Dependency library updates
HarfBuzz -> 10.2.0
Qt -> 6.8.2
SDL3 -> 3.2.2
SPIRV-Cross -> 1.4.304.0
libjpeg-turbo -> 3.1.0
libpng -> 1.6.45
libwebp -> 1.5.0
libzip -> 1.13.3
shaderc -> 2024.5
2025-02-02 13:56:23 +10:00
Stenzek
24354cb39f
GPU: Fix more GPU thread-reading-CPU-thread-settings locations 2025-02-02 13:08:08 +10:00
Stenzek
804d90d48f
System: Fix overriding console region 2025-02-02 13:00:18 +10:00
Stenzek
a681386f28
Qt: Fix some options not being disabled with SW 2025-02-01 23:19:12 +10:00
Stenzek
b01c06b412
GPU/TextureCache: Prevent wrapping for replacement lookup
Fixes replacements for 8 and 16-bit textures placed in the right-most
page of VRAM.
2025-01-31 20:56:11 +10:00
Stenzek
635ae5de31
GPU/HW: Don't use sprites-as-fills for small/offscreen points 2025-01-31 19:50:33 +10:00
Stenzek
d65c4efdd8
GPU/TextureCache: Prefill dumped texture list with replacements
Allows skipping dumping replaced textures without replacements enabled.
2025-01-31 15:47:22 +10:00
Stenzek
b5925ab139
Achievements: Include any codepoints above 0x100 in dynamic range 2025-01-31 13:48:57 +10:00
Stenzek
03181d1179
GPUThread: Fix crash during FSUI language switch 2025-01-31 13:47:29 +10:00
Stenzek
96058f5d7e
System: Use recreation logic for toggling GPU threading 2025-01-31 12:56:19 +10:00
Stenzek
f7d7eecb6c
GPU/TextureCache: Fix replacements starting in second page 2025-01-30 13:33:00 +10:00
Stenzek
44a75d6586
GPUThread: Fix setting change crash with thread off 2025-01-30 13:32:32 +10:00
Stenzek
369879e685
Settings: Log when creating EmuFolders fails 2025-01-30 02:11:23 +10:00
Stenzek
aae7573e63
Achievements: Fix build with regtest 2025-01-30 02:10:49 +10:00
Stenzek
9b6021b79e
FullscreenUI: Fix progress bar padding in loading screen 2025-01-30 01:43:22 +10:00
Stenzek
0d9e6bd482
FullscreenUI: Use effective value for achievement options enable 2025-01-30 01:18:47 +10:00
Stenzek
d314b25f91
System: Fix per-game achievements hardcore mode
By mostly reverting 4dd6365a99, I didn't
think of all the implications. Not just per-game HC mode, but it's also
problematic on Android too.
2025-01-30 01:18:47 +10:00
Stenzek
02234715c5
FullscreenUI: Move UpdateRunIdleState() for system soft-fail to host
That way it's always in the correct state for e.g. memory card shutdown
confirmations.
2025-01-29 20:40:14 +10:00
Stenzek
128bab29f8
Host: Allow button title override in ConfirmMessageAsync() 2025-01-29 19:19:53 +10:00
Stenzek
4dd6365a99
System: Simplify HC disable confirm on startup
Use one path on all platforms, always asynchronous.
2025-01-29 19:19:53 +10:00
Stenzek
28f6358ec5
Qt: Use FSUI to service ConfirmMessageAsync() if active 2025-01-29 19:19:53 +10:00
Stenzek
4da7692a2d
System: Adjust initialization order to better fit FullscreenUI
Fixes jankyness of rendering the landing page when trying to resume
a game with achievements active, or when loading state.
2025-01-29 19:19:53 +10:00
Stenzek
1b678d0ebc
FullscreenUI: Allow using right mouse button for 'back' 2025-01-29 19:19:53 +10:00
Stenzek
224cb6ac8e
FullscreenUI: Fix ClosePauseMenu() running on wrong thread 2025-01-29 19:19:49 +10:00
Stenzek
231ba050a2
GPUThread: Switch to borderless if exclusive fullscreen fails
Better than ending up windowed.
2025-01-29 18:20:41 +10:00
Stenzek
e36dbaf255
Qt: Show current fullscreen resolution in UI even if invalid 2025-01-29 18:20:08 +10:00
Stenzek
70c45f7cf8
GPU/TextureCache: Handle replacements larger than 256x256
I left this unfinished because it was a pain...
2025-01-28 17:36:00 +10:00
Stenzek
f58fa2297e
GPU/TextureCache: Only use a single palette record for C16
Stops C16 textures larger than 256x256 being split up.
2025-01-28 17:36:00 +10:00
Stenzek
b0c0d6444c
GPU/TextureCache: Fix parsing of C16 replacement names 2025-01-28 17:36:00 +10:00
Stenzek
7188ab863a
GPU/HW: Treat fill-like sprites as fills if TC is enabled
Umihara Kawase Shun clears the framebuffer with a single large
sprite, which causes the texture cache to think the pages have
been drawn.
2025-01-28 17:35:52 +10:00
Stenzek
d7c78eedce
GPU/HW: Fix box downsampling on OpenGL ES 2025-01-28 15:59:35 +10:00
JukePlz
afd619a7d8
GameDB: Pro-Pinball needs same traits as others in the series (#3359)
otherwise hangs on loading and has inferior performance. Probably missed due to title hyphenation.
2025-01-27 13:35:17 +10:00
Stenzek
0665cb5306
FullscreenUI: Further refine achievements login dialog 2025-01-27 13:34:45 +10:00
Stenzek
5630f3958b
Qt: Fix loading webp images on Windows 2025-01-26 14:01:42 +10:00
Stenzek
0e3668a7bb
GameList: Show achievement information in game list 2025-01-26 13:49:08 +10:00
Stenzek
6512ed8a8c
Achievements: Add offline tracking of progress and hash library 2025-01-26 13:49:08 +10:00
Stenzek
d4b0b7fc29
Achievements: Include rc_client version in user agent 2025-01-26 13:49:08 +10:00
Stenzek
6a09d6ecda
Achievements: Don't store hash as a string
This is needed to store achievement metadata in the game list.
2025-01-26 13:30:26 +10:00
Stenzek
1bfc4b6e6c
dep/rcheevos: Update to 08999e0 2025-01-26 13:30:23 +10:00
Stenzek
21aa6ead5f
Scripts: Add script to download/generate achievement database 2025-01-26 00:09:44 +10:00
Stenzek
ca509a8b97
StringUtil: Add fixed-length DecodeHex() 2025-01-25 22:35:06 +10:00
Stenzek
543704d57c
HTTPDownloader: Drop some log messages to debug 2025-01-25 22:35:06 +10:00
Stenzek
2b7a4f8d19
Qt: Avoid game list refresh on shutdown
We only need to invalidate the entries that have had their play times
changed, not the entire list.
2025-01-25 19:45:42 +10:00
Stenzek
4e97420b3b
InputManager: Switch to SDL3 2025-01-24 15:54:31 +10:00
Stenzek
573b2eb529
SPU: Move device failure message to OSD 2025-01-24 14:54:57 +10:00
Stenzek
9666abc172
FullscreenUI: Hook up to disc change hotkey 2025-01-24 13:47:55 +10:00
JukePlz
9096402a30
GameDB: Rakugaki Showtime does not support analog mode (#3358)
Only supports vibration.
2025-01-24 13:10:32 +10:00
Stenzek
dc5f85a34e
System: Display safe mode warning when toggling on 2025-01-24 12:50:35 +10:00
Anderson Cardoso
807094d627
Atualização Português do Brasil (#3357)
Atualizado para a última versão
2025-01-23 12:38:43 +10:00
Stenzek
13c7b8542d
GPUThread: Fix starting big picture mode 2025-01-23 12:37:26 +10:00
Stenzek
4da1f613b6
System: Simplify CD speedup warnings 2025-01-23 12:22:32 +10:00
Stenzek
df8822760a
GPU/HW: Further tweaks to replacement alpha handling
We can't simply clear the alpha channel unconditionally here, because that
would result in any black pixels with zero alpha being transparency-culled.

Instead, we set it to a minimum value (2/255 in case of rounding error, I
don't trust drivers here) so that transparent polygons in the source still
set bit 15 to zero in the framebuffer, but are not transparency-culled.

Silent Hill needs it to be zero, I'm not aware of anything that needs
specific values yet. If it did, we'd need a different dumping technique.
2025-01-23 12:12:58 +10:00
Stenzek
9113a6e6a6
Qt: Add 'Multiple Devices' to automatic mapping
Also populate the "current device" label with the device from
the config when running the setup wizard, instead of always setting
the label to Keyboard.
2025-01-22 18:38:37 +10:00
Stenzek
b08ab9f712
Qt: Fix border overlay export button 2025-01-22 18:38:37 +10:00
Stenzek
d395be07ee
Qt: Fix global setting showing incorrectly for int-list 2025-01-22 18:38:37 +10:00
Stenzek
89504b0184
GPUThread: Push settings through FIFO
Saves the std::function heap allocation.
2025-01-22 18:38:37 +10:00
Stenzek
f045a1742d
GPUThread: Fix order of updating state
Fixes unoverwritten textures not dumping on system shutdown.
2025-01-22 18:38:37 +10:00
Stenzek
8eaa1f312d
GPU: Fix overlay destination alpha with postfx
Also don't assume the image has premultiplied alpha.
2025-01-22 18:38:37 +10:00
Stenzek
0129679bb0
GPU: Reduce overdraw when using overlays
Clear the four borders individually instead of a blit over the
entire texture.
2025-01-22 18:38:37 +10:00
Stenzek
0166939609
PostProcessing/GLSL: Clear alpha to 1.0 2025-01-22 18:23:12 +10:00
Stenzek
be75a97efe
GPUDevice: Fix swap chain clear colour normalization 2025-01-22 18:23:11 +10:00
Stenzek
af58740f5d
System: Always display OSD warning messages
I regretted what I did in f2720b98dd
less than a week after I pushed the change.

As a compromise, only display the unsafe settings warnings on startup.
2025-01-22 18:23:10 +10:00
Stenzek
4e588bb6c1
GPU: Fix incorrect interface for postfx config 2025-01-21 20:55:26 +10:00
Stenzek
78f6e11b91
GPUThread: Skip debug window update on Android 2025-01-21 20:22:10 +10:00
Stenzek
19ca9cb47d
GPU/HW: Use texture loads for native resolution
Hopefully work around sampling precision issues in older AMD drivers
and Mali Midgard if we're lucky. But I don't have anything this old
to verify with.
2025-01-21 20:15:07 +10:00
Stenzek
080eccd8fc
GPUThread: Shutdown instead of panicing on switch failure 2025-01-21 20:12:38 +10:00
Stenzek
9c4b2112ae
GPU: Fix incorrect screen draw rect
Fixes loading screen in Alundra 2, as well as incorrect effective
PAR when using None crop mode.
2025-01-21 19:54:54 +10:00
Stenzek
fb3e290133
GPUDevice: Move exclusive fullscreen to features
Also fixes it not enabling in D3D12 renderer.
2025-01-21 19:12:44 +10:00
Stenzek
389276bb03
GPUDevice: Normalize supports_texture_buffers => texture_buffers 2025-01-21 19:06:59 +10:00
Stenzek
9d4789e082
FullscreenUI: Fix blank screen flicker starting game
Also returns to whichever menu the system boot was initiated from.
2025-01-20 23:17:24 +10:00
Stenzek
17b0da7283
GameList: URL encode custom properties paths with brackets
Fixes custom properties not applying on restart to games with
brackets in their paths.
2025-01-20 21:59:24 +10:00
Stenzek
4b20fc6922
Path: Fix several errors in URLEncode/Decode and add tests 2025-01-20 21:44:44 +10:00
Stenzek
78902d7632
FullscreenUI: Fix several more unsafe reads 2025-01-20 19:00:51 +10:00
Stenzek
cc0ccf2648
Data: Update resources 2025-01-20 17:24:36 +10:00
Stenzek
f219b47e98
FullscreenUI: Use constant width/height scale on Android
Fixes achievement notifications being differently sized
depending on the screen rotation.
2025-01-20 00:01:46 +10:00
Stenzek
7c2488c942
PostProcessing/GLSL: Fix image moved off-screen with alignment 2025-01-19 21:40:38 +10:00
Stenzek
c03b6f3d84
Misc: Replace isspace() usage with StringUtil::IsWhitespace()
Avoids the UB if the character is negative (e.g. reading from a binary
file), as well as locale-specific rubbish.
2025-01-19 21:29:14 +10:00
Stenzek
21b167d382
CDImage: Tidy up Open() method 2025-01-19 21:29:14 +10:00
Stenzek
7905793ae0
GPU: Use screen alignment for overlay instead of display rect 2025-01-19 21:13:16 +10:00
Stenzek
8c5c0e6114
Common: Fix Vector2->Vector4 zero-extend constructor
And add loadl(const GSVector2i&) as an easier-to-read overload.
2025-01-19 21:13:16 +10:00
Stenzek
ade8bf7b3b
GPU: Fix overlay+postprocessing combination 2025-01-19 21:13:16 +10:00
Stenzek
9fdeeb3fb6
GPU: Add alpha blending support to overlay 2025-01-19 16:37:51 +10:00
Stenzek
9b8d2a88de
System: Required changes for Android 2025-01-19 15:31:58 +10:00
Stenzek
e1cbb50c64
GPU: Fix various capture/screenshot issues
- Simplify functions for rendering display.

- Post-processing should only when the target size matches the window.
  Otherwise the shaders are constantly recompiled.

- Include border overlay in capture/screenshots when above condition
  is satisfied.

- Relax video alignment size when using screen resolution + auto.

- Fix "Internal Resolution (Uncorrected)" capture mode.
2025-01-19 13:42:38 +10:00
Stenzek
725dcea05a
GPU: Fix crash toggling border overlays 2025-01-19 12:25:19 +10:00
Stenzek
6131ddbefe
GPU: Fill in unused/padded area in overlays 2025-01-18 22:59:49 +10:00
Stenzek
88b43370dc
GPUDevice: Replace explicit GL_PUSH/GL_POP with nested GL_SCOPE 2025-01-18 22:59:49 +10:00
Stenzek
d62261e7a4
GPUDevice: Allow nested GL_SCOPE macros 2025-01-18 22:59:49 +10:00
Stenzek
7fcf0a3283
README: Update feature list for 2025 2025-01-18 22:59:48 +10:00
Stenzek
313f653fe0
Data: Add one example overlay 2025-01-18 22:59:48 +10:00
Stenzek
e0a9bbe600
PostProcessing: Move into GPU presenter
Means that the renderer can be changed without reloading shaders,
and speeds up config change detection.
2025-01-18 22:59:48 +10:00
Stenzek
d589696eff
PostProcessing: Get rid of GPU-dependent globals 2025-01-18 22:59:48 +10:00
Stenzek
338d29d271
GPUDevice: Move empty/null texture to base class 2025-01-18 22:59:48 +10:00
Stenzek
609fa5c7d7
GPUDevice: Add sampler cache to base class
Removes per-backend bookkeeping in D3D12 and Vulkan.
2025-01-18 22:59:48 +10:00
Stenzek
da13579356
GPU: Align presenter/backends to cache line 2025-01-18 22:59:48 +10:00
Stenzek
dd9788262e
GPU: Refactor display presentation workflow
Adds the ability to set overlays, and fixes postfx with prerotation.
2025-01-18 22:59:48 +10:00
Stenzek
6cba825bac
System: Add fatal error shutdown path
Switch to a null backend and shut down the system instead of crashing.
2025-01-18 22:59:48 +10:00
Stenzek
d52bf795e4
GPU: Split backend into Backend+Presenter 2025-01-18 22:59:48 +10:00
Stenzek
8f19ac2dee
System: Set rapidyaml error handlers on startup
That way it can be used in multiple places.
2025-01-18 22:59:48 +10:00
Stenzek
08d2586a86
System: Allow host to set async worker count
For regtest.
2025-01-18 22:59:48 +10:00
Stenzek
e41f179108
PostProcessing: Fix erroneous reload message 2025-01-18 22:59:48 +10:00
Stenzek
1481c1d231
System: Post-processing is shut down on GPU thread 2025-01-18 22:59:48 +10:00
Stenzek
b9822602b2
FullscreenUI: Show game icons in game list 2025-01-18 22:59:48 +10:00
Stenzek
f98b904c50
FullscreenUI: Add 'Set Cover Image' to game list 2025-01-18 22:59:48 +10:00
Stenzek
7cc47551a4
FullscreenUI: Fix parent scroll resetting on directory change 2025-01-18 22:59:48 +10:00
Stenzek
e34d23c8e7
FullscreenUI: Implicitly close non-multichoice dialogs
Also fixes disc swap using a multichoice instead of single.
2025-01-18 22:59:47 +10:00
326 changed files with 60406 additions and 36678 deletions

View file

@ -64,7 +64,7 @@ jobs:
run: |
mkdir build
cd build
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DCMAKE_PREFIX_PATH="$HOME/deps" -DCMAKE_C_COMPILER=clang-18 -DCMAKE_CXX_COMPILER=clang++-18 -DCMAKE_EXE_LINKER_FLAGS_INIT="-fuse-ld=lld" -DCMAKE_MODULE_LINKER_FLAGS_INIT="-fuse-ld=lld" -DCMAKE_SHARED_LINKER_FLAGS_INIT="-fuse-ld=lld" ..
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DCMAKE_PREFIX_PATH="$HOME/deps" -DCMAKE_C_COMPILER=clang-19 -DCMAKE_CXX_COMPILER=clang++-19 -DCMAKE_EXE_LINKER_FLAGS_INIT="-fuse-ld=lld" -DCMAKE_MODULE_LINKER_FLAGS_INIT="-fuse-ld=lld" -DCMAKE_SHARED_LINKER_FLAGS_INIT="-fuse-ld=lld" ..
cmake --build . --parallel
cd ..
scripts/packaging/appimage/make-appimage.sh $(realpath .) $(realpath ./build) $HOME/deps DuckStation-x64
@ -135,7 +135,7 @@ jobs:
run: |
mkdir build
cd build
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DDISABLE_SSE4=ON -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DCMAKE_PREFIX_PATH="$HOME/deps" -DCMAKE_C_COMPILER=clang-18 -DCMAKE_CXX_COMPILER=clang++-18 -DCMAKE_EXE_LINKER_FLAGS_INIT="-fuse-ld=lld" -DCMAKE_MODULE_LINKER_FLAGS_INIT="-fuse-ld=lld" -DCMAKE_SHARED_LINKER_FLAGS_INIT="-fuse-ld=lld" ..
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DDISABLE_SSE4=ON -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DCMAKE_PREFIX_PATH="$HOME/deps" -DCMAKE_C_COMPILER=clang-19 -DCMAKE_CXX_COMPILER=clang++-19 -DCMAKE_EXE_LINKER_FLAGS_INIT="-fuse-ld=lld" -DCMAKE_MODULE_LINKER_FLAGS_INIT="-fuse-ld=lld" -DCMAKE_SHARED_LINKER_FLAGS_INIT="-fuse-ld=lld" ..
cmake --build . --parallel
cd ..
scripts/packaging/appimage/make-appimage.sh $(realpath .) $(realpath ./build) $HOME/deps DuckStation-x64-SSE2

View file

@ -0,0 +1,103 @@
name: 🐧 Linux Cross-Compiled AppImage
on:
workflow_call:
workflow_dispatch:
jobs:
build:
name: "Build"
strategy:
fail-fast: true
matrix:
arch: ["arm64", "armhf"]
runs-on: ubuntu-22.04
container:
image: ghcr.io/duckstation/cross-build-${{ matrix.arch }}:latest
timeout-minutes: 120
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Cache Dependencies
id: cache-deps
uses: actions/cache@v4
with:
path: ~/deps
key: deps-cross ${{ matrix.arch }} ${{ hashFiles('scripts/deps/build-dependencies-linux.sh', 'scripts/deps/build-dependencies-linux-cross.sh') }}
- name: Build Dependencies
if: steps.cache-deps.outputs.cache-hit != 'true'
run: |
scripts/deps/build-dependencies-linux.sh -skip-cleanup "$HOME/deps/host"
scripts/deps/build-dependencies-linux-cross.sh -skip-download "$HOME/deps/host" "${{ matrix.arch }}" "/${{ matrix.arch }}-chroot" "$HOME/deps/cross"
# Work around container ownership issue
- name: Set Safe Directory
shell: bash
run: git config --global --add safe.directory "*"
- name: Create Binary Aliases
run: |
ln -s llvm-strip-19 /usr/bin/llvm-strip
- name: Set Up Toolchain File
run: |
cp "$HOME/deps/cross/toolchain.cmake" "$HOME/toolchain.cmake"
echo 'set(CMAKE_C_COMPILER clang-19)' >> "$HOME/toolchain.cmake"
echo 'set(CMAKE_C_COMPILER_AR llvm-ar-19)' >> "$HOME/toolchain.cmake"
echo 'set(CMAKE_C_COMPILER_RANLIB llvm-ranlib-19)' >> "$HOME/toolchain.cmake"
echo 'set(CMAKE_CXX_COMPILER clang++-19)' >> "$HOME/toolchain.cmake"
echo 'set(CMAKE_CXX_COMPILER_AR llvm-ar-19)' >> "$HOME/toolchain.cmake"
echo 'set(CMAKE_CXX_COMPILER_RANLIB llvm-ranlib-19)' >> "$HOME/toolchain.cmake"
echo 'set(CMAKE_EXE_LINKER_FLAGS_INIT "-fuse-ld=lld")' >> "$HOME/toolchain.cmake"
echo 'set(CMAKE_MODULE_LINKER_FLAGS_INIT "-fuse-ld=lld")' >> "$HOME/toolchain.cmake"
echo 'set(CMAKE_SHARED_LINKER_FLAGS_INIT "-fuse-ld=lld")' >> "$HOME/toolchain.cmake"
- name: Initialize Build Tag
run: |
echo '#pragma once' > src/scmversion/tag.h
- name: Set Build Tag Asset
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/dev'
run: |
echo '#define SCM_RELEASE_ASSET "DuckStation-${{ matrix.arch }}.AppImage"' >> src/scmversion/tag.h
echo '#define SCM_RELEASE_TAGS {"latest", "preview"}' >> src/scmversion/tag.h
- name: Tag as Preview Release
if: github.ref == 'refs/heads/master'
run: |
echo '#define SCM_RELEASE_TAG "preview"' >> src/scmversion/tag.h
- name: Tag as Rolling Release
if: github.ref == 'refs/heads/dev'
run: |
echo '#define SCM_RELEASE_TAG "latest"' >> src/scmversion/tag.h
- name: Download Patch Archives
shell: bash
run: |
cd data/resources
curl -LO "https://github.com/duckstation/chtdb/releases/download/latest/cheats.zip"
curl -LO "https://github.com/duckstation/chtdb/releases/download/latest/patches.zip"
- name: Generate CMake
shell: bash
run: |
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DCMAKE_TOOLCHAIN_FILE="$HOME/toolchain.cmake" -DLCONVERT_EXE="$HOME/deps/host/bin/lconvert" -DHOST_MIN_PAGE_SIZE=4096 -DHOST_MAX_PAGE_SIZE=16384 -DHOST_CACHE_LINE_SIZE=64 -DBUILD_QT_FRONTEND=ON -DBUILD_MINI_FRONTEND=ON
- name: Compile Build
shell: bash
run: |
cmake --build build --parallel
scripts/packaging/appimage/make-cross-appimage.sh duckstation-qt ${{ matrix.arch }} "$(realpath build)" "$HOME/deps/cross" "/${{ matrix.arch }}-chroot"
scripts/packaging/appimage/make-cross-appimage.sh -inject-libc duckstation-mini ${{ matrix.arch }} "$(realpath build)" "$HOME/deps/cross" "/${{ matrix.arch }}-chroot"
- name: Upload AppImages
uses: actions/upload-artifact@v4
with:
name: "linux-${{ matrix.arch }}-appimage"
path: "DuckStation-*.AppImage"

View file

@ -15,12 +15,17 @@ on:
jobs:
linux-flatpak-build:
name: "x64"
runs-on: ubuntu-22.04
name: "Build"
strategy:
fail-fast: true
matrix:
setup: [{arch: "x86_64", runner: "ubuntu-22.04"}, {arch: "aarch64", runner: "ubuntu-24.04-arm"}]
runs-on: ${{ matrix.setup.runner }}
container:
image: ghcr.io/flathub-infra/flatpak-github-actions:kde-6.8
options: --privileged
timeout-minutes: 120
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
with:
@ -72,17 +77,17 @@ jobs:
- name: Build Flatpak
uses: flathub-infra/flatpak-github-actions/flatpak-builder@23796715b3dfa4c86ddf50cf29c3cc8b3c82dca8
with:
bundle: duckstation-x64.flatpak
bundle: duckstation-${{ matrix.setup.arch }}.flatpak
upload-artifact: false
manifest-path: scripts/packaging/flatpak/org.duckstation.DuckStation.yaml
arch: x86_64
arch: ${{ matrix.setup.arch }}
build-bundle: true
verbose: true
mirror-screenshots-url: https://dl.flathub.org/media
branch: stable
cache: true
restore-cache: true
cache-key: flatpak-x64-${{ hashFiles('scripts/packaging/flatpak/**/*.yaml') }}
cache-key: flatpak-${{ hashFiles('scripts/packaging/flatpak/**/*.yaml') }}
- name: Validate Build
run: |
@ -109,5 +114,5 @@ jobs:
- name: Upload Flatpak
uses: actions/upload-artifact@v4
with:
name: "linux-flatpak"
path: "duckstation-x64.flatpak"
name: "linux-flatpak-${{ matrix.setup.arch }}"
path: "duckstation-${{ matrix.setup.arch }}.flatpak"

View file

@ -25,6 +25,9 @@ jobs:
linux-appimage:
name: 🐧 Linux AppImage
uses: "./.github/workflows/linux-appimage-build.yml"
linux-cross-appimage:
name: 🐧 Linux Cross-Compiled AppImage
uses: "./.github/workflows/linux-cross-appimage-build.yml"
linux-flatpak:
name: 📦 Linux Flatpak
uses: "./.github/workflows/linux-flatpak-build.yml"
@ -34,7 +37,7 @@ jobs:
create-release:
name: 📤 Create Release
needs: [windows, linux-appimage, linux-flatpak, macos]
needs: [windows, linux-appimage, linux-cross-appimage, linux-flatpak, macos]
runs-on: ubuntu-22.04
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/dev'
steps:
@ -63,7 +66,12 @@ jobs:
./artifacts/windows-arm64/duckstation-windows-arm64-release-symbols.zip
./artifacts/linux-x64-appimage/DuckStation-x64.AppImage
./artifacts/linux-x64-sse2-appimage/DuckStation-x64-SSE2.AppImage
./artifacts/linux-flatpak/duckstation-x64.flatpak
./artifacts/linux-arm64-appimage/DuckStation-arm64.AppImage
./artifacts/linux-arm64-appimage/DuckStation-Mini-arm64.AppImage
./artifacts/linux-armhf-appimage/DuckStation-armhf.AppImage
./artifacts/linux-armhf-appimage/DuckStation-Mini-armhf.AppImage
./artifacts/linux-flatpak-x86_64/duckstation-x86_64.flatpak
./artifacts/linux-flatpak-aarch64/duckstation-aarch64.flatpak
./artifacts/macos/duckstation-mac-release.zip
- name: Create Rolling Release
@ -83,6 +91,11 @@ jobs:
./artifacts/windows-arm64/duckstation-windows-arm64-release-symbols.zip
./artifacts/linux-x64-appimage/DuckStation-x64.AppImage
./artifacts/linux-x64-sse2-appimage/DuckStation-x64-SSE2.AppImage
./artifacts/linux-flatpak/duckstation-x64.flatpak
./artifacts/linux-arm64-appimage/DuckStation-arm64.AppImage
./artifacts/linux-arm64-appimage/DuckStation-Mini-arm64.AppImage
./artifacts/linux-armhf-appimage/DuckStation-armhf.AppImage
./artifacts/linux-armhf-appimage/DuckStation-Mini-armhf.AppImage
./artifacts/linux-flatpak-x86_64/duckstation-x86_64.flatpak
./artifacts/linux-flatpak-aarch64/duckstation-aarch64.flatpak
./artifacts/macos/duckstation-mac-release.zip

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.16)
cmake_minimum_required(VERSION 3.19)
project(duckstation C CXX)
# Policy settings.
@ -16,10 +16,6 @@ if(NOT CMAKE_BUILD_TYPE MATCHES "Debug|Devel|MinSizeRel|RelWithDebInfo|Release")
set(CMAKE_BUILD_TYPE "Release")
endif()
message(STATUS "CMake Version: ${CMAKE_VERSION}")
message(STATUS "CMake System Name: ${CMAKE_SYSTEM_NAME}")
message(STATUS "Build Type: ${CMAKE_BUILD_TYPE}")
# Pull in modules.
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/CMakeModules/")
include(DuckStationUtils)
@ -34,6 +30,7 @@ detect_cache_line_size()
# Build options. Depends on system attributes.
include(DuckStationBuildOptions)
include(DuckStationDependencies)
include(DuckStationCompilerRequirement)
# Enable PIC on Linux, otherwise the builds do not support ASLR.
if(LINUX OR BSD)
@ -120,10 +117,6 @@ endif()
# Prevent fmt from being built with exceptions, or being thrown at call sites.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DFMT_EXCEPTIONS=0")
# Use C++20.
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Recursively include the source tree.
add_subdirectory(dep)
add_subdirectory(src)

View file

@ -1,8 +1,8 @@
# Renderer options.
option(ENABLE_OPENGL "Build with OpenGL renderer" ON)
option(ENABLE_VULKAN "Build with Vulkan renderer" ON)
option(BUILD_NOGUI_FRONTEND "Build the NoGUI frontend" OFF)
option(BUILD_QT_FRONTEND "Build the Qt frontend" ON)
option(BUILD_MINI_FRONTEND "Build the Mini frontend" OFF)
option(BUILD_REGTEST "Build regression test runner" OFF)
option(BUILD_TESTS "Build unit tests" OFF)
option(DISABLE_SSE4 "Build with SSE4 instructions disabled, reduces performance" OFF)

View file

@ -1,3 +1,5 @@
message(STATUS "Build Type: ${CMAKE_BUILD_TYPE}")
if(ENABLE_OPENGL)
message(STATUS "Building with OpenGL support.")
endif()

View file

@ -0,0 +1,16 @@
# Use C++20.
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# C++20 feature checks. Some Linux environments are incomplete.
check_cpp20_feature("__cpp_structured_bindings" 201606)
check_cpp20_feature("__cpp_constinit" 201907)
check_cpp20_feature("__cpp_designated_initializers" 201707)
check_cpp20_feature("__cpp_using_enum" 201907)
check_cpp20_feature("__cpp_lib_bit_cast" 201806)
check_cpp20_feature("__cpp_lib_bitops" 201907)
check_cpp20_feature("__cpp_lib_int_pow2" 202002)
check_cpp20_feature("__cpp_lib_starts_ends_with" 201711)
check_cpp20_attribute("likely" 201803)
check_cpp20_attribute("unlikely" 201803)
check_cpp20_attribute("no_unique_address" 201803)

View file

@ -9,7 +9,7 @@ endif()
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
find_package(SDL2 2.30.8 REQUIRED)
find_package(SDL3 3.2.0 REQUIRED)
find_package(Zstd 1.5.6 REQUIRED)
find_package(WebP REQUIRED) # v1.4.0, spews an error on Linux because no pkg-config.
find_package(ZLIB REQUIRED) # 1.3, but Mac currently doesn't use it.

View file

@ -1,3 +1,5 @@
include(CheckSourceCompiles)
function(disable_compiler_warnings_for_target target)
if(MSVC)
target_compile_options(${target} PRIVATE "/W0")
@ -118,8 +120,11 @@ function(detect_page_size)
# For universal Apple builds, we use preprocessor macros to determine page size.
# Similar for Windows, except it's always 4KB.
if(NOT CPU_ARCH_ARM64 OR NOT LINUX)
unset(HOST_PAGE_SIZE CACHE)
unset(HOST_PAGE_SIZE PARENT_SCOPE)
unset(HOST_MIN_PAGE_SIZE CACHE)
unset(HOST_MIN_PAGE_SIZE PARENT_SCOPE)
unset(HOST_MAX_PAGE_SIZE CACHE)
unset(HOST_MAX_PAGE_SIZE PARENT_SCOPE)
return()
elseif(DEFINED HOST_PAGE_SIZE)
@ -166,6 +171,7 @@ endfunction()
function(detect_cache_line_size)
# This is only needed for ARM64, or if the user hasn't overridden it explicitly.
if(NOT CPU_ARCH_ARM64 OR HOST_CACHE_LINE_SIZE)
unset(HOST_CACHE_LINE_SIZE CACHE)
unset(HOST_CACHE_LINE_SIZE PARENT_SCOPE)
return()
endif()
@ -245,3 +251,48 @@ function(install_imported_dep_library name)
get_target_property(LOCATION "${name}" IMPORTED_LOCATION_RELEASE)
install(FILES "${LOCATION}" RENAME "${SONAME}" DESTINATION "${CMAKE_INSTALL_LIBDIR}")
endfunction()
function(check_cpp20_feature MACRO MINIMUM_VALUE)
set(CACHE_VAR "CHECK_CPP20_FEATURE_${MACRO}")
if(NOT DEFINED ${CACHE_VAR})
# Create a small source code snippet that fails to compile if the feature is not available.
set(TEMP_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.cpp")
file(WRITE "${TEMP_FILE}" "#include <version>
#if !defined(${MACRO}) || ${MACRO} < ${MINIMUM_VALUE}L
#error Missing feature
#endif
")
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
try_compile(HAS_FEATURE
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY} "${TEMP_FILE}"
CXX_STANDARD 20
CXX_STANDARD_REQUIRED TRUE
)
set(${CACHE_VAR} ${HAS_FEATURE} CACHE INTERNAL "Cached feature test result for ${MACRO}")
endif()
if(NOT HAS_FEATURE)
message(FATAL_ERROR "${MACRO} is not supported by your compiler, at least ${MINIMUM_VALUE} is required.")
endif()
endfunction()
function(check_cpp20_attribute ATTRIBUTE MINIMUM_VALUE)
set(CACHE_VAR "CHECK_CPP20_ATTRIBUTE_${MACRO}")
if(NOT DEFINED ${CACHE_VAR})
set(TEMP_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.cpp")
file(WRITE "${TEMP_FILE}" "#include <version>
#if !defined(__has_cpp_attribute) || __has_cpp_attribute(${ATTRIBUTE}) < ${MINIMUM_VALUE}L
#error Missing feature
#endif
")
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
try_compile(HAS_FEATURE
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY} "${TEMP_FILE}"
CXX_STANDARD 20
CXX_STANDARD_REQUIRED TRUE
)
set(${CACHE_VAR} ${HAS_FEATURE} CACHE INTERNAL "Cached attribute test result for ${MACRO}")
endif()
if(NOT HAS_FEATURE)
message(FATAL_ERROR "${ATTRIBUTE} is not supported by your compiler, at least ${MINIMUM_VALUE} is required.")
endif()
endfunction()

View file

@ -23,20 +23,23 @@ DuckStation features a fully-featured frontend built using Qt, as well as a full
Other features include:
- CPU Recompiler/JIT (x86-64, armv7/AArch32, AArch64, RISC-V/RV64).
- Hardware (D3D11, D3D12, OpenGL, Vulkan, Metal) and software rendering.
- Hardware renderer supporting D3D11, D3D12, OpenGL, Vulkan and Metal APIs.
- Upscaling, texture filtering, and true colour (24-bit) in hardware renderers.
- Accurate blending via Rasterizer Order Views/Fragment Shader Interlock.
- PGXP for geometry precision, texture correction, and depth buffer emulation.
- Accurate blending via Rasterizer Order Views/Fragment Shader Interlock.
- Texture replacement system in hardware renderers.
- Vectorized and multi-threaded software renderer.
- Motion adaptive deinterlacing.
- Adaptive downsampling filter.
- Screen rotation for vertical or "TATE" shmup games.
- Post processing shader chains (GLSL and Reshade FX).
- Border overlays/bezels displayed around game content.
- "Fast boot" for skipping BIOS splash/intro.
- Save state support, with runahead and rewind.
- Windows, Linux, macOS support.
- Supports reading directly from CD, bin/cue images, raw bin/img files, MAME CHD, single-track ECM, MDS/MDF, and unencrypted PBP formats.
- Preloading of disc images to RAM to avoid disk sleeping hitches.
- Merging of multi-disc games in game list/grid with memory cards shared between discs.
- Automatic loading/applying of PPF patches.
- Direct booting of homebrew executables.
- Direct loading of Portable Sound Format (psf) files.
@ -44,6 +47,7 @@ Other features include:
- Digital and analog controllers for input (rumble is forwarded to host).
- GunCon and Justifier lightgun support (simulated with mouse).
- NeGcon support.
- Controller presets and per-game configuration.
- Qt and "Big Picture" UI.
- Automatic updates with preview and latest channels.
- Automatic content scanning - game titles/hashes are provided by redump.org.
@ -56,6 +60,8 @@ Other features include:
- RetroAchievements.
- Discord Rich Presence.
- Video capture with Media Foundation (Windows) and [FFmpeg](https://www.ffmpeg.org/) (All Platforms) backends.
- Free camera function.
- Parallel port cartridge emulation.
## System Requirements
- A CPU faster than a potato. But it needs to be x86_64, AArch32/armv7, AArch64/ARMv8, or RISC-V/RV64.

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#ffffff" d="M12 2C17.52 2 22 6.48 22 12C22 17.52 17.52 22 12 22C6.48 22 2 17.52 2 12C2 6.48 6.48 2 12 2ZM12 20C16.42 20 20 16.42 20 12C20 7.58 16.42 4 12 4C7.58 4 4 7.58 4 12C4 16.42 7.58 20 12 20ZM12 11H16V13H12V16L8 12L12 8V11Z"></path></svg>

After

Width:  |  Height:  |  Size: 316 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#ffffff" d="M21 3C21.5523 3 22 3.44772 22 4V11H20V5H4V19H10V21H3C2.44772 21 2 20.5523 2 20V4C2 3.44772 2.44772 3 3 3H21ZM21 13C21.5523 13 22 13.4477 22 14V20C22 20.5523 21.5523 21 21 21H13C12.4477 21 12 20.5523 12 20V14C12 13.4477 12.4477 13 13 13H21ZM11.5 7L9.45711 9.04311L11.7071 11.2929L10.2929 12.7071L8.04311 10.4571L6 12.5V7H11.5Z"></path></svg>

After

Width:  |  Height:  |  Size: 424 B

View file

Before

Width:  |  Height:  |  Size: 117 KiB

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 512 512"
version="1.1"
id="svg1"
sodipodi:docname="exit.svg"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1" />
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="true"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="2.640625"
inkscape:cx="256"
inkscape:cy="256"
inkscape:window-width="2856"
inkscape:window-height="1651"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg1" />
<!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
<path
fill="#ffffff"
d="m 363.3838,123.77433 108.17663,108.17663 c 6.3426,6.3426 9.95436,15.06368 9.95436,24.04904 0,8.98535 -3.61176,17.70643 -9.95436,24.04904 L 363.3838,388.22566 c -5.63787,5.63787 -13.21376,8.72108 -21.14202,8.72108 -16.47315,0 -29.86309,-13.38994 -29.86309,-29.86309 V 312.37869 H 199.6213 c -15.59223,0 -28.18935,-12.59711 -28.18935,-28.18935 v -56.37869 c 0,-15.59223 12.59712,-28.18935 28.18935,-28.18935 h 112.75739 v -54.70496 c 0,-16.47315 13.38994,-29.86309 29.86309,-29.86309 7.92826,0 15.50415,3.1713 21.14202,8.72108 z m -191.95185,-8.72108 h -56.3787 c -15.59222,0 -28.189349,12.59712 -28.189349,28.18935 v 225.51479 c 0,15.59223 12.597119,28.18935 28.189349,28.18935 h 56.3787 c 15.59223,0 28.18935,12.59712 28.18935,28.18935 0,15.59223 -12.59712,28.18935 -28.18935,28.18935 h -56.3787 c -46.688603,0 -84.56804,-37.87944 -84.56804,-84.56805 V 143.2426 c 0,-46.688607 37.879437,-84.568041 84.56804,-84.568041 h 56.3787 c 15.59223,0 28.18935,12.597115 28.18935,28.189347 0,15.592224 -12.59712,28.189344 -28.18935,28.189344 z"
id="path1"
style="stroke-width:0.880917" />
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

View file

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 640 640"
version="1.1"
id="svg1"
sodipodi:docname="game-list.svg"
width="640"
height="640"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1" />
<sodipodi:namedview
id="namedview1"
pagecolor="#000001"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="true"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="0.93429246"
inkscape:cx="436.69409"
inkscape:cy="330.73156"
inkscape:window-width="2844"
inkscape:window-height="1651"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg1" />
<!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
<path
fill="#ffffff"
d="m 264.14016,286.21023 c -46.25894,0 -83.78977,37.53084 -83.78977,83.78977 0,46.25893 37.53083,83.78978 83.78977,83.78978 h 111.71968 c 46.25894,0 83.78977,-37.53085 83.78977,-83.78978 0,-46.25894 -37.53083,-83.78977 -83.78977,-83.78977 z m 132.66713,45.38613 a 17.456203,17.456203 0 1 1 0,34.91239 17.456203,17.456203 0 1 1 0,-34.91239 z m -45.38612,59.35108 a 17.456203,17.456203 0 1 1 34.91239,0 17.456203,17.456203 0 1 1 -34.91239,0 z m -97.75473,-45.38612 c 0,-5.80419 4.66954,-10.47373 10.47372,-10.47373 5.80418,0 10.47371,4.66954 10.47371,10.47373 v 13.96496 h 13.96497 c 5.80417,0 10.47373,4.66953 10.47373,10.47372 0,5.80419 -4.66954,10.47372 -10.47373,10.47372 h -13.96497 v 13.96496 c 0,5.80419 -4.66953,10.47373 -10.47371,10.47373 -5.80419,0 -10.47372,-4.66954 -10.47372,-10.47373 v -13.96496 h -13.96496 c -5.8042,0 -10.47373,-4.66953 -10.47373,-10.47372 0,-5.8042 4.66953,-10.47373 10.47373,-10.47373 h 13.96496 z"
id="path1"
style="stroke-width:0.436405" />
<path
fill="#ffffff"
d="m 89.226718,138.67812 c -9.066093,0 -16.483806,7.41772 -16.483806,16.48381 v 329.67613 c 0,9.06609 7.417713,16.4838 16.483806,16.4838 H 550.77329 c 9.06608,0 16.4838,-7.41771 16.4838,-16.4838 V 155.16193 c 0,-9.06609 -7.41772,-16.48381 -16.4838,-16.48381 z m -65.935226,16.48381 c 0,-36.36739 29.567828,-65.935223 65.935226,-65.935223 H 550.77329 c 36.36739,0 65.93522,29.567833 65.93522,65.935223 v 329.67613 c 0,36.36739 -29.56783,65.93523 -65.93522,65.93523 H 89.226718 c -36.367398,0 -65.935226,-29.56784 -65.935226,-65.93523 z m 98.902838,65.93523 c 0,-18.20753 14.76011,-32.96759 32.96761,-32.96759 18.20751,0 32.96761,14.76006 32.96761,32.96759 0,18.20752 -14.7601,32.96759 -32.96761,32.96759 -18.2075,0 -32.96761,-14.76007 -32.96761,-32.96759 z m 107.14475,0 c 0,-13.70217 11.02352,-24.72572 24.72569,-24.72572 h 230.77329 c 13.70216,0 24.72571,11.02355 24.72571,24.72572 0,13.70217 -11.02355,24.72572 -24.72571,24.72572 H 254.06477 c -13.70217,0 -24.72569,-11.02355 -24.72569,-24.72572 z"
id="path1-5"
style="stroke-width:1.03024"
sodipodi:nodetypes="ssssssssssssssssssssssssssssss" />
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#ffffff" d="M2.13127 13.6308C1.9492 12.5349 1.95521 11.434 2.13216 10.3695C3.23337 10.3963 4.22374 9.86798 4.60865 8.93871C4.99357 8.00944 4.66685 6.93557 3.86926 6.17581C4.49685 5.29798 5.27105 4.51528 6.17471 3.86911C6.9345 4.66716 8.0087 4.99416 8.93822 4.60914C9.86774 4.22412 10.3961 3.23332 10.369 2.13176C11.4649 1.94969 12.5658 1.9557 13.6303 2.13265C13.6036 3.23385 14.1319 4.22422 15.0612 4.60914C15.9904 4.99406 17.0643 4.66733 17.8241 3.86975C18.7019 4.49734 19.4846 5.27153 20.1308 6.1752C19.3327 6.93499 19.0057 8.00919 19.3907 8.93871C19.7757 9.86823 20.7665 10.3966 21.8681 10.3695C22.0502 11.4654 22.0442 12.5663 21.8672 13.6308C20.766 13.6041 19.7756 14.1324 19.3907 15.0616C19.0058 15.9909 19.3325 17.0648 20.1301 17.8245C19.5025 18.7024 18.7283 19.4851 17.8247 20.1312C17.0649 19.3332 15.9907 19.0062 15.0612 19.3912C14.1316 19.7762 13.6033 20.767 13.6303 21.8686C12.5344 22.0507 11.4335 22.0447 10.3691 21.8677C10.3958 20.7665 9.86749 19.7761 8.93822 19.3912C8.00895 19.0063 6.93508 19.333 6.17532 20.1306C5.29749 19.503 4.51479 18.7288 3.86862 17.8252C4.66667 17.0654 4.99367 15.9912 4.60865 15.0616C4.22363 14.1321 3.23284 13.6038 2.13127 13.6308ZM11.9997 15.0002C13.6565 15.0002 14.9997 13.657 14.9997 12.0002C14.9997 10.3433 13.6565 9.00018 11.9997 9.00018C10.3428 9.00018 8.99969 10.3433 8.99969 12.0002C8.99969 13.657 10.3428 15.0002 11.9997 15.0002Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 512 512"
version="1.1"
id="svg1"
sodipodi:docname="start-bios.svg"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1" />
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="true"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="2.640625"
inkscape:cx="256"
inkscape:cy="256"
inkscape:window-width="2852"
inkscape:window-height="1651"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg1" />
<!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
<path
fill="#ffffff"
d="m 186.11835,53.343194 c 0,-11.617826 -9.34668,-20.964498 -20.9645,-20.964498 -11.61782,0 -20.9645,9.346672 -20.9645,20.964498 v 34.940832 c -30.83528,0 -55.905324,25.070044 -55.905324,55.905324 H 53.343194 c -11.617826,0 -20.964498,9.34668 -20.964498,20.9645 0,11.61782 9.346672,20.9645 20.964498,20.9645 H 88.284026 V 235.0355 H 53.343194 c -11.617826,0 -20.964498,9.34668 -20.964498,20.96449 0,11.61783 9.346672,20.96451 20.964498,20.96451 h 34.940832 v 48.91716 H 53.343194 c -11.617826,0 -20.964498,9.34666 -20.964498,20.96449 0,11.61783 9.346672,20.9645 20.964498,20.9645 h 34.940832 c 0,30.83528 25.070044,55.90533 55.905324,55.90533 v 34.94082 c 0,11.61783 9.34668,20.9645 20.9645,20.9645 11.61782,0 20.9645,-9.34667 20.9645,-20.9645 v -34.94082 h 48.91715 v 34.94082 c 0,11.61783 9.34668,20.9645 20.96449,20.9645 11.61783,0 20.96451,-9.34667 20.96451,-20.9645 v -34.94082 h 48.91716 v 34.94082 c 0,11.61783 9.34666,20.9645 20.96449,20.9645 11.61783,0 20.9645,-9.34667 20.9645,-20.9645 v -34.94082 c 30.83528,0 55.90533,-25.07005 55.90533,-55.90533 h 34.94082 c 11.61783,0 20.9645,-9.34667 20.9645,-20.9645 0,-11.61783 -9.34667,-20.96449 -20.9645,-20.96449 H 423.71598 V 276.9645 h 34.94082 c 11.61783,0 20.9645,-9.34668 20.9645,-20.96451 0,-11.61781 -9.34667,-20.96449 -20.9645,-20.96449 h -34.94082 v -48.91715 h 34.94082 c 11.61783,0 20.9645,-9.34668 20.9645,-20.9645 0,-11.61782 -9.34667,-20.9645 -20.9645,-20.9645 h -34.94082 c 0,-30.83528 -25.07005,-55.905324 -55.90533,-55.905324 V 53.343194 c 0,-11.617826 -9.34667,-20.964498 -20.9645,-20.964498 -11.61783,0 -20.96449,9.346672 -20.96449,20.964498 V 88.284026 H 276.9645 V 53.343194 c 0,-11.617826 -9.34668,-20.964498 -20.96451,-20.964498 -11.61781,0 -20.96449,9.346672 -20.96449,20.964498 v 34.940832 h -48.91715 z m -13.97634,90.846156 h 167.71598 c 15.46131,0 27.95266,12.49134 27.95266,27.95266 v 167.71598 c 0,15.46131 -12.49135,27.95266 -27.95266,27.95266 H 172.14201 c -15.46132,0 -27.95266,-12.49135 -27.95266,-27.95266 V 172.14201 c 0,-15.46132 12.49134,-27.95266 27.95266,-27.95266 z m 167.71598,27.95266 H 172.14201 v 167.71598 h 167.71598 z"
id="path1"
style="stroke-width:0.87352" />
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 512 512"
version="1.1"
id="svg1"
sodipodi:docname="start-disc.svg"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1" />
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="true"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="1.8685849"
inkscape:cx="269.72282"
inkscape:cy="294.60797"
inkscape:window-width="2856"
inkscape:window-height="1652"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg1" />
<!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
<path
fill="#ffffff"
d="m 49.005172,256 a 206.99483,206.99483 0 1 1 413.989658,0 206.99483,206.99483 0 1 1 -413.989658,0 z M 256,281.87436 a 25.874355,25.874355 0 1 1 0,-51.74871 25.874355,25.874355 0 1 1 0,51.74871 z M 178.37694,256 a 77.62306,77.62306 0 1 0 155.24612,0 77.62306,77.62306 0 1 0 -155.24612,0 z m -51.7487,-12.93717 c 0,-28.30008 14.15003,-57.48958 36.54752,-79.88707 22.39749,-22.39749 51.58699,-36.54752 79.88707,-36.54752 7.11544,0 12.93717,-5.82173 12.93717,-12.93718 0,-7.11545 -5.82173,-12.93718 -12.93717,-12.93718 -36.70924,0 -72.12476,18.03119 -98.24169,44.06726 -26.11692,26.03607 -44.06726,61.53245 -44.06726,98.24169 0,7.11544 5.82173,12.93717 12.93718,12.93717 7.11545,0 12.93718,-5.82173 12.93718,-12.93717 z"
id="path1"
style="stroke-width:0.808574" />
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 576 576"
version="1.1"
id="svg1"
sodipodi:docname="start-file.svg"
width="576"
height="576"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1" />
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="true"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="2.640625"
inkscape:cx="287.81065"
inkscape:cy="225.70414"
inkscape:window-width="2852"
inkscape:window-height="1651"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg1" />
<!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
<path
fill="#ffffff"
d="m 375.58614,492.32782 h 43.78453 c 10.39883,0 19.97669,-5.47306 25.17611,-14.50363 L 546.71069,302.68606 c 5.29063,-9.03055 5.29063,-20.15913 0.0912,-29.2809 -5.19941,-9.12179 -14.77728,-14.59484 -25.26731,-14.59484 H 156.66347 c -10.39883,0 -19.9767,5.47306 -25.17611,14.50363 L 69.0944,380.22117 V 142.05155 c 0,-8.02715 6.567679,-14.59484 14.594844,-14.59484 H 190.87013 c 3.83116,0 7.57108,1.55071 10.30762,4.28724 l 24.17271,24.17271 c 19.15573,19.15573 45.15279,29.91943 72.24447,29.91943 h 107.1809 c 8.02716,0 14.59484,6.56767 14.59484,14.59484 v 29.1897 h 43.78454 v -29.1897 c 0,-32.19988 -26.17951,-58.37938 -58.37938,-58.37938 h -107.1809 c -15.50702,0 -30.37551,-6.11158 -41.32164,-17.05772 L 232.10058,100.72991 C 221.15444,89.783772 206.28594,83.672181 190.77892,83.672181 H 83.689244 c -32.199876,0 -58.379378,26.179509 -58.379378,58.379369 v 291.89689 c 0,32.19988 26.179502,58.37938 58.379378,58.37938 h 21.618616 z"
id="path1"
style="stroke-width:0.912178" />
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -211,7 +211,7 @@
03000000b50700000399000000000000,Firestorm 2,a:b2,b:b4,back:b10,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,righttrigger:b9,start:b11,x:b3,y:b5,platform:Windows,
03000000b50700001302000000000000,Firestorm D3,a:b0,b:b2,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,x:b1,y:b3,platform:Windows,
03000000b40400001024000000000000,Flydigi Apex,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000151900004000000000000000,Flydigi Vader 2,a:b27,b:b26,back:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b23,leftstick:b17,lefttrigger:b21,leftx:a0,lefty:a1,misc1:b15,paddle1:b11,paddle2:b10,paddle3:b13,paddle4:b12,rightshoulder:b22,rightstick:b16,righttrigger:b20,rightx:a3,righty:a4,start:b18,x:b25,y:b24,platform:Windows,
03000000151900004000000000000000,Flydigi Vader 2,a:b27,b:b26,back:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b23,leftstick:b17,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b22,rightstick:b16,righttrigger:b20,rightx:a3,righty:a4,start:b18,x:b25,y:b24,platform:Windows,
03000000b40400001124000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b14,paddle1:b4,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b2,y:b3,platform:Windows,
03000000b40400001224000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
030000008305000000a0000000000000,G08XU,a:b0,b:b1,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b5,x:b2,y:b3,platform:Windows,
@ -325,7 +325,7 @@
030000000d0f0000c100000000000000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f0000f600000000000000,Horipad Nintendo Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
030000000d0f00006700000000000000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000000d0f00009601000000000000,Horipad Steam,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b2,paddle1:b15,paddle2:b5,paddle3:b19,paddle4:b18,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
030000000d0f00009601000000000000,Horipad Steam,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc2:b2,paddle1:b5,paddle2:b15,paddle3:b18,paddle4:b19,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
030000000d0f0000dc00000000000000,Horipad Switch,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000242e00000b20000000000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Windows,
03000000242e0000ff0b000000000000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Windows,
@ -638,7 +638,7 @@
030000008916000000fe000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000c6240000045d000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000a30600001af5000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
03000000a306000023f6000000000000,Saitek Cyborg V.1 Game,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
03000000a306000023f6000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
03000000300f00001201000000000000,Saitek Dual Analog,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
03000000a30600000701000000000000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Windows,
03000000a30600000cff000000000000,Saitek P2500 Force Rumble,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b0,y:b1,platform:Windows,
@ -1051,7 +1051,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000b40400000a01000000000000,Sega Saturn,a:b0,b:b1,back:b5,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b2,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X,
030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
0300000000f00000f100000000000000,SNES RetroPort,a:b2,b:b3,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,rightshoulder:b7,start:b6,x:b0,y:b1,platform:Mac OS X,
03000000bc2000000155000000010000,SNK NEOGEO Arcade Stick Pro,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b2,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b11,x:b0,y:b3,platform:Mac OS X,
030000004c050000a00b000000000000,Sony DualShock 4 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
03000000666600006706000088020000,Sony PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Mac OS X,
@ -1266,6 +1265,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006f0e00008101000011010000,Faceoff Deluxe Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e00008001000011010000,Faceoff Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03005036852100000201000010010000,Final Fantasy XIV Online Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
05000000b40400001224000001010000,Flydigi APEX 4,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b20,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
03000000b40400001124000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000b40400001224000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
@ -1328,6 +1328,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000000d0f0000ee00000011010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f0000c100000011010000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00006700000001010000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000000d0f0000ab01000011010000,Horipad Steam,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc2:b2,paddle1:b19,paddle2:b18,paddle3:b15,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000000d0f00009601000091000000,Horipad Steam,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc2:b2,paddle1:b19,paddle2:b18,paddle3:b15,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000000d0f0000f600000001000000,Horipad Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
03000000341a000005f7000010010000,HuiJia GameCube Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,
05000000242e00000b20000001000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Linux,
@ -1499,8 +1501,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006f0e0000a702000023020000,PDP Xbox One Raven Black,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e0000d802000006640000,PDP Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e0000ef02000007640000,PDP Xbox Series Kinetic Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e0000f102000000000000,PDP Xbox Atomic,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftshoulder:b4,rightshoulder:b5,leftstick:b9,rightstick:b10,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c62400003a54000001010000,PowerA 1428124-01,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000000540000001010000,PowerA Advantage Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d620000011a7000011010000,PowerA Core Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000dd62000015a7000011010000,PowerA Fusion Nintendo Switch Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000d620000012a7000011010000,PowerA Fusion Nintendo Switch Fight Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
@ -1517,7 +1521,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000d62000000240000001010000,PowerA Xbox One Spectra Infinity,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000000f20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000000b20000001010000,PowerA Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000000540000001010000,PowerA Advantage Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000250900000017000010010000,PS/SS/N64 Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b5,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2~,righty:a3,start:b8,platform:Linux,
03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
@ -1591,6 +1594,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
0300000032150000030a000001010000,Razer Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000321500000b10000011010000,Razer Wolverine PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
0300000032150000140a000001010000,Razer Wolverine Ultimate Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000000d0f0000c100000010010000,Retro Bit Legacy16,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b12,leftshoulder:b4,lefttrigger:b6,misc1:b13,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f0000c100000072056800,Retro Bit Legacy16,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b5,leftshoulder:b9,lefttrigger:+a4,misc1:b11,rightshoulder:b10,righttrigger:+a5,start:b6,x:b3,y:b2,platform:Linux,
03000000790000001100000010010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Linux,
@ -1627,7 +1631,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000790000001100000011010000,Sega Saturn,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Linux,
03000000790000002201000011010000,Sega Saturn,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,
03000000b40400000a01000000010000,Sega Saturn,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux,
030000001f08000001e4000010010000,SFC Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,
03000000632500002305000010010000,ShanWan Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000632500002605000010010000,Shanwan Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000632500007505000010010000,Shanwan Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
@ -1664,6 +1667,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000110100001914000009010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000ad1b000038f0000090040000,Street Fighter IV Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000003b07000004a1000000010000,Suncom SFX Plus,a:b0,b:b2,back:b7,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Linux,
030000001f08000001e4000010010000,Super Famicom Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,
03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,
0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,
030000008f0e00000d31000010010000,SZMY Power 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,13 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 113.48 122.88">
<!-- https://uxwing.com/wp-content/themes/uxwing/download/sport-and-awards/trophy-icon.png -->
<defs>
<style>.cls-1{fill:#808080;}.cls-2{fill:#A0A0A0;}.cls-3{fill:#222;}.cls-4{fill:#C0C0C0;}.cls-5{fill:#909090;}.cls-6{fill:#B0B0B0;}.cls-7,.cls-8{fill:#FFF;}.cls-8{fill-rule:evenodd;}</style>
</defs>
<title>trophy</title>
<path class="cls-1" d="M3.21,18.74H19.86q0-4,.06-8.26V0H93.05V10.49c0,2.92,0,5.66,0,8.26h17.24a3.08,3.08,0,0,1,3.07,2.93,77.67,77.67,0,0,1-.4,13.9A34,34,0,0,1,109.11,48a21.77,21.77,0,0,1-8.8,8.6A31.91,31.91,0,0,1,86.41,60C83.14,65.43,78.78,68,73.68,72.67c-6.17,4.71-10.81,8.26-7.2,19.13h5.39a7.84,7.84,0,0,1,7.82,7.82v3.15h.77A7.69,7.69,0,0,1,85.91,105h0a7.67,7.67,0,0,1,2.26,5.45v5.23a1.77,1.77,0,0,1-1.77,1.77H26.58a1.77,1.77,0,0,1-1.77-1.77v-5.23A7.66,7.66,0,0,1,27.07,105h0a7.66,7.66,0,0,1,5.44-2.26h.77V99.62a7.75,7.75,0,0,1,2.3-5.51v0a7.81,7.81,0,0,1,5.51-2.29h6.06c3.22-10.26-1-13.58-6.83-18.17A44.47,44.47,0,0,1,27.34,60,31.87,31.87,0,0,1,13,56.54a21.47,21.47,0,0,1-8.73-8.6A34.07,34.07,0,0,1,.51,35.58,78.1,78.1,0,0,1,.13,21.9v-.08a3.08,3.08,0,0,1,3.09-3.08ZM92.71,30a121.67,121.67,0,0,1-2,18,15.17,15.17,0,0,0,5-1.9,10.49,10.49,0,0,0,3.69-3.89,18,18,0,0,0,1.93-6,45.37,45.37,0,0,0,.5-6.25H92.71ZM20.12,30H12a49.78,49.78,0,0,0,.45,6.27,18.41,18.41,0,0,0,1.8,6,10.13,10.13,0,0,0,3.57,3.88A14.57,14.57,0,0,0,22.54,48a92,92,0,0,1-2.42-18Z"/>
<path class="cls-2" d="M20.08,21.82H3.21C2.75,31.1,3.34,40,7,46.43c3.43,6.11,9.7,10.15,20.62,10.46a27.9,27.9,0,0,1-3.48-5.51c-6.56-.88-10.36-3.59-12.54-7.67S8.94,34.32,8.94,28.14a1.23,1.23,0,0,1,1.23-1.23h9.91V21.82Zm72.77,5.1h10.82a1.23,1.23,0,0,1,1.23,1.22c0,6.2-.56,11.54-2.84,15.6s-6.16,6.75-12.7,7.64a25.38,25.38,0,0,1-3.69,5.52c11-.29,17.29-4.33,20.77-10.45,3.67-6.47,4.29-15.34,3.84-24.62H92.85v5.09Z"/>
<path class="cls-3" d="M79.69,102.76h.77A7.69,7.69,0,0,1,85.91,105h0a7.67,7.67,0,0,1,2.26,5.45v10.63a1.77,1.77,0,0,1-1.77,1.77H26.58a1.77,1.77,0,0,1-1.77-1.77V110.48A7.66,7.66,0,0,1,27.07,105h0a7.66,7.66,0,0,1,5.44-2.26H79.69Z"/>
<path class="cls-4" d="M70.64,108H35.72a4.22,4.22,0,0,0-3,1.25h0a4.26,4.26,0,0,0-1.25,3v5.28H81.55v-5.28a4.26,4.26,0,0,0-1.26-3,4.31,4.31,0,0,0-3-1.26Z"/>
<path class="cls-5" d="M50.71,93h6V75.21c-22.17-7.88-24.26-35-29.55-72.57H22.53V29.41C23,39.6,24.68,47.14,27,52.91a38.19,38.19,0,0,0,8.39,12.8,68.65,68.65,0,0,0,6.71,5.78C49.11,77,54.19,81,50.71,93Z"/>
<path class="cls-6" d="M56.71,93H63c-3.88-12.71,1.68-17,9-22.55,8.05-6.14,18.5-14.12,18.5-40.35V2.64H27.16C30.58,26.92,32.66,46.81,39.67,60A39.14,39.14,0,0,0,49,71.13a29.3,29.3,0,0,0,5.47,3.17,19.1,19.1,0,0,0,2.21.74v.15l.07,0V93Z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -0,0 +1,16 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 113.48 122.88">
<!-- https://uxwing.com/wp-content/themes/uxwing/download/sport-and-awards/trophy-icon.png -->
<defs>
<style>.cls-1{fill:#f39d00;}.cls-2{fill:#f9c809;}.cls-3{fill:#222;}.cls-4{fill:#ead79e;}.cls-5{fill:#f8b705;}.cls-6{fill:#fac809;}.cls-7,.cls-8{fill:#fff;}.cls-8{fill-rule:evenodd;}</style>
</defs>
<title>trophy</title>
<path class="cls-1" d="M3.21,18.74H19.86q0-4,.06-8.26V0H93.05V10.49c0,2.92,0,5.66,0,8.26h17.24a3.08,3.08,0,0,1,3.07,2.93,77.67,77.67,0,0,1-.4,13.9A34,34,0,0,1,109.11,48a21.77,21.77,0,0,1-8.8,8.6A31.91,31.91,0,0,1,86.41,60C83.14,65.43,78.78,68,73.68,72.67c-6.17,4.71-10.81,8.26-7.2,19.13h5.39a7.84,7.84,0,0,1,7.82,7.82v3.15h.77A7.69,7.69,0,0,1,85.91,105h0a7.67,7.67,0,0,1,2.26,5.45v5.23a1.77,1.77,0,0,1-1.77,1.77H26.58a1.77,1.77,0,0,1-1.77-1.77v-5.23A7.66,7.66,0,0,1,27.07,105h0a7.66,7.66,0,0,1,5.44-2.26h.77V99.62a7.75,7.75,0,0,1,2.3-5.51v0a7.81,7.81,0,0,1,5.51-2.29h6.06c3.22-10.26-1-13.58-6.83-18.17A44.47,44.47,0,0,1,27.34,60,31.87,31.87,0,0,1,13,56.54a21.47,21.47,0,0,1-8.73-8.6A34.07,34.07,0,0,1,.51,35.58,78.1,78.1,0,0,1,.13,21.9v-.08a3.08,3.08,0,0,1,3.09-3.08ZM92.71,30a121.67,121.67,0,0,1-2,18,15.17,15.17,0,0,0,5-1.9,10.49,10.49,0,0,0,3.69-3.89,18,18,0,0,0,1.93-6,45.37,45.37,0,0,0,.5-6.25H92.71ZM20.12,30H12a49.78,49.78,0,0,0,.45,6.27,18.41,18.41,0,0,0,1.8,6,10.13,10.13,0,0,0,3.57,3.88A14.57,14.57,0,0,0,22.54,48a92,92,0,0,1-2.42-18Z"/>
<path class="cls-2" d="M20.08,21.82H3.21C2.75,31.1,3.34,40,7,46.43c3.43,6.11,9.7,10.15,20.62,10.46a27.9,27.9,0,0,1-3.48-5.51c-6.56-.88-10.36-3.59-12.54-7.67S8.94,34.32,8.94,28.14a1.23,1.23,0,0,1,1.23-1.23h9.91V21.82Zm72.77,5.1h10.82a1.23,1.23,0,0,1,1.23,1.22c0,6.2-.56,11.54-2.84,15.6s-6.16,6.75-12.7,7.64a25.38,25.38,0,0,1-3.69,5.52c11-.29,17.29-4.33,20.77-10.45,3.67-6.47,4.29-15.34,3.84-24.62H92.85v5.09Z"/>
<path class="cls-3" d="M79.69,102.76h.77A7.69,7.69,0,0,1,85.91,105h0a7.67,7.67,0,0,1,2.26,5.45v10.63a1.77,1.77,0,0,1-1.77,1.77H26.58a1.77,1.77,0,0,1-1.77-1.77V110.48A7.66,7.66,0,0,1,27.07,105h0a7.66,7.66,0,0,1,5.44-2.26H79.69Z"/>
<path class="cls-4" d="M70.64,108H35.72a4.22,4.22,0,0,0-3,1.25h0a4.26,4.26,0,0,0-1.25,3v5.28H81.55v-5.28a4.26,4.26,0,0,0-1.26-3,4.31,4.31,0,0,0-3-1.26Z"/>
<path class="cls-5" d="M50.71,93h6V75.21c-22.17-7.88-24.26-35-29.55-72.57H22.53V29.41C23,39.6,24.68,47.14,27,52.91a38.19,38.19,0,0,0,8.39,12.8,68.65,68.65,0,0,0,6.71,5.78C49.11,77,54.19,81,50.71,93Z"/>
<path class="cls-6" d="M56.71,93H63c-3.88-12.71,1.68-17,9-22.55,8.05-6.14,18.5-14.12,18.5-40.35V2.64H27.16C30.58,26.92,32.66,46.81,39.67,60A39.14,39.14,0,0,0,49,71.13a29.3,29.3,0,0,0,5.47,3.17,19.1,19.1,0,0,0,2.21.74v.15l.07,0V93Z"/>
<path class="cls-1" d="M58.26,20.13,61.06,27l7.39.56a1.9,1.9,0,0,1,1,3.41l-5.59,4.74,1.76,7.18a1.9,1.9,0,0,1-1.41,2.29,1.88,1.88,0,0,1-1.49-.26L56.5,41l-6.29,3.89a1.9,1.9,0,0,1-2.62-.62,1.85,1.85,0,0,1-.23-1.44l1.75-7.18-5.66-4.8a1.91,1.91,0,0,1,1.09-3.35L51.93,27l2.81-6.84a1.91,1.91,0,0,1,3.52,0Z"/>
<polygon class="cls-7" points="56.5 20.86 59.75 28.78 68.31 29.43 61.76 34.98 63.79 43.3 56.5 38.79 49.21 43.3 51.24 34.98 44.69 29.43 53.24 28.78 56.5 20.86 56.5 20.86 56.5 20.86"/>
<path class="cls-8" d="M76.62,47.62l-.07.1a3.79,3.79,0,0,0-5.17.83l-.1-.08a3.52,3.52,0,0,0,.62-2.75,3.57,3.57,0,0,0-1.44-2.42,26.79,26.79,0,0,0,2.82.53,3.58,3.58,0,0,0,2.42-1.45l.1.07a3.81,3.81,0,0,0,.82,5.17ZM84.27,34.8l-.07.1a3.78,3.78,0,0,0-5.17.82l-.1-.07a3.79,3.79,0,0,0-.83-5.17l.07-.1a3.8,3.8,0,0,0,5.18-.83l.09.08a3.79,3.79,0,0,0,.83,5.17Zm.06-13.56-.13.18a6.94,6.94,0,0,0-9.46,1.51l-.18-.13a6.5,6.5,0,0,0,1.14-5,6.49,6.49,0,0,0-2.65-4.43l.13-.18a6.94,6.94,0,0,0,9.46-1.51l.18.13a6.5,6.5,0,0,0-1.14,5,6.51,6.51,0,0,0,2.65,4.43Z"/>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

View file

@ -0,0 +1,13 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 113.48 122.88">
<!-- https://uxwing.com/wp-content/themes/uxwing/download/sport-and-awards/trophy-icon.png -->
<defs>
<style>.cls-1{fill:#f39d00;}.cls-2{fill:#f9c809;}.cls-3{fill:#222;}.cls-4{fill:#ead79e;}.cls-5{fill:#f8b705;}.cls-6{fill:#fac809;}.cls-7,.cls-8{fill:#fff;}.cls-8{fill-rule:evenodd;}</style>
</defs>
<title>trophy</title>
<path class="cls-1" d="M3.21,18.74H19.86q0-4,.06-8.26V0H93.05V10.49c0,2.92,0,5.66,0,8.26h17.24a3.08,3.08,0,0,1,3.07,2.93,77.67,77.67,0,0,1-.4,13.9A34,34,0,0,1,109.11,48a21.77,21.77,0,0,1-8.8,8.6A31.91,31.91,0,0,1,86.41,60C83.14,65.43,78.78,68,73.68,72.67c-6.17,4.71-10.81,8.26-7.2,19.13h5.39a7.84,7.84,0,0,1,7.82,7.82v3.15h.77A7.69,7.69,0,0,1,85.91,105h0a7.67,7.67,0,0,1,2.26,5.45v5.23a1.77,1.77,0,0,1-1.77,1.77H26.58a1.77,1.77,0,0,1-1.77-1.77v-5.23A7.66,7.66,0,0,1,27.07,105h0a7.66,7.66,0,0,1,5.44-2.26h.77V99.62a7.75,7.75,0,0,1,2.3-5.51v0a7.81,7.81,0,0,1,5.51-2.29h6.06c3.22-10.26-1-13.58-6.83-18.17A44.47,44.47,0,0,1,27.34,60,31.87,31.87,0,0,1,13,56.54a21.47,21.47,0,0,1-8.73-8.6A34.07,34.07,0,0,1,.51,35.58,78.1,78.1,0,0,1,.13,21.9v-.08a3.08,3.08,0,0,1,3.09-3.08ZM92.71,30a121.67,121.67,0,0,1-2,18,15.17,15.17,0,0,0,5-1.9,10.49,10.49,0,0,0,3.69-3.89,18,18,0,0,0,1.93-6,45.37,45.37,0,0,0,.5-6.25H92.71ZM20.12,30H12a49.78,49.78,0,0,0,.45,6.27,18.41,18.41,0,0,0,1.8,6,10.13,10.13,0,0,0,3.57,3.88A14.57,14.57,0,0,0,22.54,48a92,92,0,0,1-2.42-18Z"/>
<path class="cls-2" d="M20.08,21.82H3.21C2.75,31.1,3.34,40,7,46.43c3.43,6.11,9.7,10.15,20.62,10.46a27.9,27.9,0,0,1-3.48-5.51c-6.56-.88-10.36-3.59-12.54-7.67S8.94,34.32,8.94,28.14a1.23,1.23,0,0,1,1.23-1.23h9.91V21.82Zm72.77,5.1h10.82a1.23,1.23,0,0,1,1.23,1.22c0,6.2-.56,11.54-2.84,15.6s-6.16,6.75-12.7,7.64a25.38,25.38,0,0,1-3.69,5.52c11-.29,17.29-4.33,20.77-10.45,3.67-6.47,4.29-15.34,3.84-24.62H92.85v5.09Z"/>
<path class="cls-3" d="M79.69,102.76h.77A7.69,7.69,0,0,1,85.91,105h0a7.67,7.67,0,0,1,2.26,5.45v10.63a1.77,1.77,0,0,1-1.77,1.77H26.58a1.77,1.77,0,0,1-1.77-1.77V110.48A7.66,7.66,0,0,1,27.07,105h0a7.66,7.66,0,0,1,5.44-2.26H79.69Z"/>
<path class="cls-4" d="M70.64,108H35.72a4.22,4.22,0,0,0-3,1.25h0a4.26,4.26,0,0,0-1.25,3v5.28H81.55v-5.28a4.26,4.26,0,0,0-1.26-3,4.31,4.31,0,0,0-3-1.26Z"/>
<path class="cls-5" d="M50.71,93h6V75.21c-22.17-7.88-24.26-35-29.55-72.57H22.53V29.41C23,39.6,24.68,47.14,27,52.91a38.19,38.19,0,0,0,8.39,12.8,68.65,68.65,0,0,0,6.71,5.78C49.11,77,54.19,81,50.71,93Z"/>
<path class="cls-6" d="M56.71,93H63c-3.88-12.71,1.68-17,9-22.55,8.05-6.14,18.5-14.12,18.5-40.35V2.64H27.16C30.58,26.92,32.66,46.81,39.67,60A39.14,39.14,0,0,0,49,71.13a29.3,29.3,0,0,0,5.47,3.17,19.1,19.1,0,0,0,2.21.74v.15l.07,0V93Z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -0,0 +1,11 @@
# Psx.jpg Credits
To the Author: SOQUEROEU.
The "psx.jpg" background was edited from the one obtained from "Soqueroeu TV Backgrounds 2.0" repository: https://github.com/soqueroeu/Soqueroeu-TV-Backgrounds_V2.0/tree/main.
The material is free to use according to the agreement below:
## AGREEMENT
This pack is free. You should not pay for anything related to this graphics pack and shader preset. You may distribute and reproduce part from this content, as long as you give credit to the authors involved. You may not profit from the sale of products that contain material in this package without the author's prior permission.

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 KiB

View file

@ -0,0 +1,7 @@
image: "psx.webp"
displayStartX: 990
displayStartY: 260
displayEndX: 2850
displayEndY: 1655
alphaBlend: false
destinationAlphaBlend: false

View file

@ -1,2 +0,0 @@
lbsubmit.wav: https://freesound.org/people/Eponn/sounds/636656/
unlock.wav and message.wav are from https://github.com/RetroAchievements/RAInterface

View file

@ -0,0 +1,3 @@
lbsubmit.wav: https://pixabay.com/sound-effects/notification-sound-7062/
unlock.wav: https://pixabay.com/sound-effects/notification-pluck-on-269288/
message.wav: https://pixabay.com/sound-effects/system-notification-199277/

View file

@ -1,3 +1,6 @@
set(_saved_CMAKE_MESSAGE_LOG_LEVEL ${CMAKE_MESSAGE_LOG_LEVEL})
set(CMAKE_MESSAGE_LOG_LEVEL NOTICE)
set(FMT_INSTALL OFF CACHE BOOL "")
add_subdirectory(fmt EXCLUDE_FROM_ALL)
disable_compiler_warnings_for_target(fmt)
@ -55,3 +58,4 @@ if(WIN32)
add_subdirectory(winpixeventruntime EXCLUDE_FROM_ALL)
endif()
set(CMAKE_MESSAGE_LOG_LEVEL ${_saved_CMAKE_MESSAGE_LOG_LEVEL})

View file

@ -6,3 +6,9 @@ IndentPPDirectives: AfterHash
IndentCaseLabels: false
AlwaysBreakTemplateDeclarations: false
DerivePointerAlignment: false
AllowShortCaseLabelsOnASingleLine: true
AlignConsecutiveShortCaseStatements:
Enabled: true
AcrossEmptyLines: true
AcrossComments: true
AlignCaseColons: false

View file

@ -27,7 +27,13 @@ endfunction()
# DEPRECATED! Should be merged into add_module_library.
function(enable_module target)
if (MSVC)
set(BMI ${CMAKE_CURRENT_BINARY_DIR}/${target}.ifc)
if(CMAKE_GENERATOR STREQUAL "Ninja")
# Ninja dyndep expects the .ifc output to be located in a specific relative path
file(RELATIVE_PATH BMI_DIR "${CMAKE_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${target}.dir")
else()
set(BMI_DIR "${CMAKE_CURRENT_BINARY_DIR}")
endif()
file(TO_NATIVE_PATH "${BMI_DIR}/${target}.ifc" BMI)
target_compile_options(${target}
PRIVATE /interface /ifcOutput ${BMI}
INTERFACE /reference fmt=${BMI})
@ -69,8 +75,6 @@ function(add_module_library name)
target_compile_options(${name} PUBLIC -fmodules-ts)
endif ()
target_compile_definitions(${name} PRIVATE FMT_MODULE)
if (FMT_USE_CMAKE_MODULES)
target_sources(${name} PUBLIC FILE_SET fmt TYPE CXX_MODULES
FILES ${sources})
@ -240,7 +244,13 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
endif ()
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0)
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wshift-overflow=2
-Wnull-dereference -Wduplicated-cond)
-Wduplicated-cond)
# Workaround for GCC regression
# [12/13/14/15 regression] New (since gcc 12) false positive null-dereference in vector.resize
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108860
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.0)
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wnull-dereference)
endif ()
endif ()
set(WERROR_FLAG -Werror)
endif ()
@ -289,6 +299,7 @@ function(add_headers VAR)
endfunction()
# Define the fmt library, its includes and the needed defines.
set(FMT_HEADERS)
add_headers(FMT_HEADERS args.h base.h chrono.h color.h compile.h core.h format.h
format-inl.h os.h ostream.h printf.h ranges.h std.h
xchar.h)
@ -319,7 +330,7 @@ else ()
message(WARNING "Feature cxx_std_11 is unknown for the CXX compiler")
endif ()
target_include_directories(fmt ${FMT_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC
target_include_directories(fmt ${FMT_SYSTEM_HEADERS_ATTRIBUTE} BEFORE PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${FMT_INC_DIR}>)
@ -359,8 +370,8 @@ if (NOT MSVC)
# Unicode is always supported on compilers other than MSVC.
elseif (FMT_UNICODE)
# Unicode support requires compiling with /utf-8.
target_compile_options(fmt PUBLIC $<$<COMPILE_LANGUAGE:CXX>:/utf-8>)
target_compile_options(fmt-header-only INTERFACE $<$<COMPILE_LANGUAGE:CXX>:/utf-8>)
target_compile_options(fmt PUBLIC $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:MSVC>>:/utf-8>)
target_compile_options(fmt-header-only INTERFACE $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:MSVC>>:/utf-8>)
else ()
target_compile_definitions(fmt PUBLIC FMT_UNICODE=0)
endif ()
@ -369,7 +380,7 @@ target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1)
target_compile_features(fmt-header-only INTERFACE cxx_std_11)
target_include_directories(fmt-header-only
${FMT_SYSTEM_HEADERS_ATTRIBUTE} INTERFACE
${FMT_SYSTEM_HEADERS_ATTRIBUTE} BEFORE INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${FMT_INC_DIR}>)
@ -420,7 +431,9 @@ if (FMT_INSTALL)
endif()
# Install the library and headers.
install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name}
install(TARGETS ${INSTALL_TARGETS}
COMPONENT fmt-core
EXPORT ${targets_export_name}
LIBRARY DESTINATION ${FMT_LIB_DIR}
ARCHIVE DESTINATION ${FMT_LIB_DIR}
PUBLIC_HEADER DESTINATION "${FMT_INC_DIR}/fmt"
@ -433,13 +446,15 @@ if (FMT_INSTALL)
FILE ${PROJECT_BINARY_DIR}/${targets_export_name}.cmake)
# Install version, config and target files.
install(
FILES ${project_config} ${version_config}
DESTINATION ${FMT_CMAKE_DIR})
install(FILES ${project_config} ${version_config}
DESTINATION ${FMT_CMAKE_DIR}
COMPONENT fmt-core)
install(EXPORT ${targets_export_name} DESTINATION ${FMT_CMAKE_DIR}
NAMESPACE fmt::)
NAMESPACE fmt::
COMPONENT fmt-core)
install(FILES "${pkgconfig}" DESTINATION "${FMT_PKGCONFIG_DIR}")
install(FILES "${pkgconfig}" DESTINATION "${FMT_PKGCONFIG_DIR}"
COMPONENT fmt-core)
endif ()
function(add_doc_target)
@ -475,7 +490,8 @@ function(add_doc_target)
include(GNUInstallDirs)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc-html/
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/doc/fmt OPTIONAL)
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/doc/fmt
COMPONENT fmt-doc OPTIONAL)
endfunction()
if (FMT_DOC)

View file

@ -1,3 +1,322 @@
# 11.1.4 - 2025-02-26
- Fixed ABI compatibility with earlier 11.x versions on Windows
(https://github.com/fmtlib/fmt/issues/4359).
- Improved the logic of switching between fixed and exponential format for
`float` (https://github.com/fmtlib/fmt/issues/3649).
- Moved `is_compiled_string` to the public API
(https://github.com/fmtlib/fmt/issues/4342). Thanks @SwooshyCueb.
- Simplified implementation of `operator""_cf`
(https://github.com/fmtlib/fmt/pull/4349). Thanks @LocalSpook.
- Fixed `__builtin_strlen` detection (https://github.com/fmtlib/fmt/pull/4329).
Thanks @LocalSpook.
- Fixed handling of BMI paths with the Ninja generator
(https://github.com/fmtlib/fmt/pull/4344). Thanks @tkhyn.
- Fixed gcc 8.3 compile errors (https://github.com/fmtlib/fmt/issues/4331,
https://github.com/fmtlib/fmt/pull/4336). Thanks @sergiud.
- Fixed a bogus MSVC warning (https://github.com/fmtlib/fmt/pull/4356).
Thanks @dinomight.
# 11.1.3 - 2025-01-25
- Fixed compilation on GCC 9.4 (https://github.com/fmtlib/fmt/issues/4313).
- Worked around an internal compiler error when using C++20 modules with GCC
14.2 and earlier (https://github.com/fmtlib/fmt/issues/4295).
- Worked around a bug in GCC 6 (https://github.com/fmtlib/fmt/issues/4318).
- Fixed an issue caused by instantiating `formatter<const T>`
(https://github.com/fmtlib/fmt/issues/4303,
https://github.com/fmtlib/fmt/pull/4325). Thanks @timsong-cpp.
- Fixed formatting into `std::ostreambuf_iterator` when using format string
compilation (https://github.com/fmtlib/fmt/issues/4309,
https://github.com/fmtlib/fmt/pull/4312). Thanks @phprus.
- Restored a constraint on the map formatter so that it correctly reports as
unformattable when the element is (https://github.com/fmtlib/fmt/pull/4326).
Thanks @timsong-cpp.
- Reduced the size of format specs (https://github.com/fmtlib/fmt/issues/4298).
- Readded `args()` to `fmt::format_context`
(https://github.com/fmtlib/fmt/issues/4307,
https://github.com/fmtlib/fmt/pull/4310). Thanks @Erroneous1.
- Fixed a bogus MSVC warning (https://github.com/fmtlib/fmt/issues/4314,
https://github.com/fmtlib/fmt/pull/4322). Thanks @ZehMatt.
- Fixed a pedantic mode error in the CMake config
(https://github.com/fmtlib/fmt/pull/4327). Thanks @rlalik.
# 11.1.2 - 2025-01-12
- Fixed ABI compatibility with earlier 11.x versions
(https://github.com/fmtlib/fmt/issues/4292).
- Added `wchar_t` support to the `std::bitset` formatter
(https://github.com/fmtlib/fmt/issues/4285,
https://github.com/fmtlib/fmt/pull/4286,
https://github.com/fmtlib/fmt/issues/4289,
https://github.com/fmtlib/fmt/pull/4290). Thanks @phprus.
- Prefixed CMake components with `fmt-` to simplify usage of {fmt} via
`add_subdirectory` (https://github.com/fmtlib/fmt/issues/4283).
- Updated docs for meson (https://github.com/fmtlib/fmt/pull/4291).
Thanks @trim21.
- Fixed a compilation error in chrono on nvcc
(https://github.com/fmtlib/fmt/issues/4297,
https://github.com/fmtlib/fmt/pull/4301). Thanks @breyerml.
- Fixed various warnings
(https://github.com/fmtlib/fmt/pull/4288,
https://github.com/fmtlib/fmt/pull/4299). Thanks @GamesTrap and @edo9300.
# 11.1.1 - 2024-12-27
- Fixed ABI compatibility with earlier 11.x versions
(https://github.com/fmtlib/fmt/issues/4278).
- Defined CMake components (`core` and `doc`) to allow docs to be installed
separately (https://github.com/fmtlib/fmt/pull/4276).
Thanks @carlsmedstad.
# 11.1.0 - 2024-12-25
- Improved C++20 module support
(https://github.com/fmtlib/fmt/issues/4081,
https://github.com/fmtlib/fmt/pull/4083,
https://github.com/fmtlib/fmt/pull/4084,
https://github.com/fmtlib/fmt/pull/4152,
https://github.com/fmtlib/fmt/issues/4153,
https://github.com/fmtlib/fmt/pull/4169,
https://github.com/fmtlib/fmt/issues/4190,
https://github.com/fmtlib/fmt/issues/4234,
https://github.com/fmtlib/fmt/pull/4239).
Thanks @kamrann and @Arghnews.
- Reduced debug (unoptimized) binary code size and the number of template
instantiations when passing formatting arguments. For example, unoptimized
binary code size for `fmt::print("{}", 42)` was reduced by ~40% on GCC and
~60% on clang (x86-64).
GCC:
- Before: 161 instructions of which 105 are in reusable functions
([godbolt](https://www.godbolt.org/z/s9bGoo4ze)).
- After: 116 instructions of which 60 are in reusable functions
([godbolt](https://www.godbolt.org/z/r7GGGxMs6)).
Clang:
- Before: 310 instructions of which 251 are in reusable functions
([godbolt](https://www.godbolt.org/z/Ts88b7M9o)).
- After: 194 instructions of which 135 are in reusable functions
([godbolt](https://www.godbolt.org/z/vcrjP8ceW)).
- Added an experimental `fmt::writer` API that can be used for writing to
different destinations such as files or strings
(https://github.com/fmtlib/fmt/issues/2354).
For example ([godbolt](https://www.godbolt.org/z/rWoKfbP7e)):
```c++
#include <fmt/os.h>
void write_text(fmt::writer w) {
w.print("The answer is {}.", 42);
}
int main() {
// Write to FILE.
write_text(stdout);
// Write to fmt::ostream.
auto f = fmt::output_file("myfile");
write_text(f);
// Write to std::string.
auto sb = fmt::string_buffer();
write_text(sb);
std::string s = sb.str();
}
```
- Added width and alignment support to the formatter of `std::error_code`.
- Made `std::expected<void, E>` formattable
(https://github.com/fmtlib/fmt/issues/4145,
https://github.com/fmtlib/fmt/pull/4148).
For example ([godbolt](https://www.godbolt.org/z/hrj5c6G86)):
```c++
fmt::print("{}", std::expected<void, int>());
```
prints
```
expected()
```
Thanks @phprus.
- Made `fmt::is_formattable<void>` SFINAE-friendly
(https://github.com/fmtlib/fmt/issues/4147).
- Added support for `_BitInt` formatting when using clang
(https://github.com/fmtlib/fmt/issues/4007,
https://github.com/fmtlib/fmt/pull/4072,
https://github.com/fmtlib/fmt/issues/4140,
https://github.com/fmtlib/fmt/issues/4173,
https://github.com/fmtlib/fmt/pull/4176).
For example ([godbolt](https://www.godbolt.org/z/KWjbWec5z)):
```c++
using int42 = _BitInt(42);
fmt::print("{}", int42(100));
```
Thanks @Arghnews.
- Added the `n` specifier for tuples and pairs
(https://github.com/fmtlib/fmt/pull/4107). Thanks @someonewithpc.
- Added support for tuple-like types to `fmt::join`
(https://github.com/fmtlib/fmt/issues/4226,
https://github.com/fmtlib/fmt/pull/4230). Thanks @phprus.
- Made more types formattable at compile time
(https://github.com/fmtlib/fmt/pull/4127). Thanks @AnthonyVH.
- Implemented a more efficient compile-time `fmt::formatted_size`
(https://github.com/fmtlib/fmt/issues/4102,
https://github.com/fmtlib/fmt/pull/4103). Thanks @phprus.
- Fixed compile-time formatting of some string types
(https://github.com/fmtlib/fmt/pull/4065). Thanks @torshepherd.
- Made compiled version of `fmt::format_to` work with
`std::back_insert_iterator<std::vector<char>>`
(https://github.com/fmtlib/fmt/issues/4206,
https://github.com/fmtlib/fmt/pull/4211). Thanks @phprus.
- Added a formatter for `std::reference_wrapper`
(https://github.com/fmtlib/fmt/pull/4163,
https://github.com/fmtlib/fmt/pull/4164). Thanks @yfeldblum and @phprus.
- Added experimental padding support (glibc `strftime` extension) to `%m`, `%j`
and `%Y` (https://github.com/fmtlib/fmt/pull/4161). Thanks @KKhanhH.
- Made microseconds formatted as `us` instead of `µs` if the Unicode support is
disabled (https://github.com/fmtlib/fmt/issues/4088).
- Fixed an unreleased regression in transcoding of surrogate pairs
(https://github.com/fmtlib/fmt/issues/4094,
https://github.com/fmtlib/fmt/pull/4095). Thanks @phprus.
- Made `fmt::appender` satisfy `std::output_iterator` concept
(https://github.com/fmtlib/fmt/issues/4092,
https://github.com/fmtlib/fmt/pull/4093). Thanks @phprus.
- Made `std::iterator_traits<fmt::appender>` standard-conforming
(https://github.com/fmtlib/fmt/pull/4185). Thanks @CaseyCarter.
- Made it easier to reuse `fmt::formatter<std::string_view>` for types with
an implicit conversion to `std::string_view`
(https://github.com/fmtlib/fmt/issues/4036,
https://github.com/fmtlib/fmt/pull/4055). Thanks @Arghnews.
- Made it possible to disable `<filesystem>` use via `FMT_CPP_LIB_FILESYSTEM`
for compatibility with some video game console SDKs, e.g. Nintendo Switch SDK
(https://github.com/fmtlib/fmt/issues/4257,
https://github.com/fmtlib/fmt/pull/4258,
https://github.com/fmtlib/fmt/pull/4259). Thanks @W4RH4WK and @phprus.
- Fixed compatibility with platforms that use 80-bit `long double`
(https://github.com/fmtlib/fmt/issues/4245,
https://github.com/fmtlib/fmt/pull/4246). Thanks @jsirpoma.
- Added support for UTF-32 code units greater than `0xFFFF` in fill
(https://github.com/fmtlib/fmt/issues/4201).
- Fixed handling of legacy encodings on Windows with GCC
(https://github.com/fmtlib/fmt/issues/4162).
- Made `fmt::to_string` take `fmt::basic_memory_buffer` by const reference
(https://github.com/fmtlib/fmt/issues/4261,
https://github.com/fmtlib/fmt/pull/4262). Thanks @sascha-devel.
- Added `fmt::dynamic_format_arg_store::size`
(https://github.com/fmtlib/fmt/pull/4270). Thanks @hannes-harnisch.
- Removed the ability to control locale usage via an undocumented
`FMT_STATIC_THOUSANDS_SEPARATOR` in favor of `FMT_USE_LOCALE`.
- Renamed `FMT_EXCEPTIONS` to `FMT_USE_EXCEPTIONS` for consistency with other
similar macros.
- Improved include directory ordering to reduce the chance of including
incorrect headers when using multiple versions of {fmt}
(https://github.com/fmtlib/fmt/pull/4116). Thanks @cdzhan.
- Made it possible to compile a subset of {fmt} without the C++ runtime.
- Improved documentation and README
(https://github.com/fmtlib/fmt/pull/4066,
https://github.com/fmtlib/fmt/issues/4117,
https://github.com/fmtlib/fmt/issues/4203,
https://github.com/fmtlib/fmt/pull/4235). Thanks @zyctree and @nikola-sh.
- Improved the documentation generator (https://github.com/fmtlib/fmt/pull/4110,
https://github.com/fmtlib/fmt/pull/4115). Thanks @rturrado.
- Improved CI (https://github.com/fmtlib/fmt/pull/4155,
https://github.com/fmtlib/fmt/pull/4151). Thanks @phprus.
- Fixed various warnings and compilation issues
(https://github.com/fmtlib/fmt/issues/2708,
https://github.com/fmtlib/fmt/issues/4091,
https://github.com/fmtlib/fmt/issues/4109,
https://github.com/fmtlib/fmt/issues/4113,
https://github.com/fmtlib/fmt/issues/4125,
https://github.com/fmtlib/fmt/issues/4129,
https://github.com/fmtlib/fmt/pull/4130,
https://github.com/fmtlib/fmt/pull/4131,
https://github.com/fmtlib/fmt/pull/4132,
https://github.com/fmtlib/fmt/issues/4133,
https://github.com/fmtlib/fmt/issues/4144,
https://github.com/fmtlib/fmt/issues/4150,
https://github.com/fmtlib/fmt/issues/4158,
https://github.com/fmtlib/fmt/pull/4159,
https://github.com/fmtlib/fmt/issues/4160,
https://github.com/fmtlib/fmt/pull/4170,
https://github.com/fmtlib/fmt/issues/4177,
https://github.com/fmtlib/fmt/pull/4187,
https://github.com/fmtlib/fmt/pull/4188,
https://github.com/fmtlib/fmt/pull/4194,
https://github.com/fmtlib/fmt/pull/4200,
https://github.com/fmtlib/fmt/issues/4205,
https://github.com/fmtlib/fmt/issues/4207,
https://github.com/fmtlib/fmt/pull/4208,
https://github.com/fmtlib/fmt/pull/4210,
https://github.com/fmtlib/fmt/issues/4220,
https://github.com/fmtlib/fmt/issues/4231,
https://github.com/fmtlib/fmt/issues/4232,
https://github.com/fmtlib/fmt/pull/4233,
https://github.com/fmtlib/fmt/pull/4236,
https://github.com/fmtlib/fmt/pull/4267,
https://github.com/fmtlib/fmt/pull/4271).
Thanks @torsten48, @Arghnews, @tinfoilboy, @aminya, @Ottani, @zeroomega,
@c4v4, @kongy, @vinayyadav3016, @sergio-nsk, @phprus and @YexuanXiao.
# 11.0.2 - 2024-07-20
- Fixed compatibility with non-POSIX systems
@ -268,6 +587,9 @@
- Fixed handling of negative ids in `fmt::basic_format_args::get`
(https://github.com/fmtlib/fmt/pull/3945). Thanks @marlenecota.
- Fixed handling of a buffer boundary on flush
(https://github.com/fmtlib/fmt/issues/4229).
- Improved named argument validation
(https://github.com/fmtlib/fmt/issues/3817).

View file

@ -291,6 +291,7 @@ converts to `std::print`.)
- [ccache](https://ccache.dev/): a compiler cache
- [ClickHouse](https://github.com/ClickHouse/ClickHouse): an
analytical database management system
- [ContextVision](https://www.contextvision.com/): medical imaging software
- [Contour](https://github.com/contour-terminal/contour/): a modern
terminal emulator
- [CUAUV](https://cuauv.org/): Cornell University\'s autonomous

View file

@ -17,7 +17,6 @@
#include "format.h" // std_string_view
FMT_BEGIN_NAMESPACE
namespace detail {
template <typename T> struct is_reference_wrapper : std::false_type {};
@ -72,19 +71,13 @@ class dynamic_arg_list {
* It can be implicitly converted into `fmt::basic_format_args` for passing
* into type-erased formatting functions such as `fmt::vformat`.
*/
template <typename Context>
class dynamic_format_arg_store
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
// Workaround a GCC template argument substitution bug.
: public basic_format_args<Context>
#endif
{
template <typename Context> class dynamic_format_arg_store {
private:
using char_type = typename Context::char_type;
template <typename T> struct need_copy {
static constexpr detail::type mapped_type =
detail::mapped_type_constant<T, Context>::value;
detail::mapped_type_constant<T, char_type>::value;
enum {
value = !(detail::is_reference_wrapper<T>::value ||
@ -97,7 +90,7 @@ class dynamic_format_arg_store
};
template <typename T>
using stored_type = conditional_t<
using stored_t = conditional_t<
std::is_convertible<T, std::basic_string<char_type>>::value &&
!detail::is_reference_wrapper<T>::value,
std::basic_string<char_type>, T>;
@ -112,41 +105,37 @@ class dynamic_format_arg_store
friend class basic_format_args<Context>;
auto get_types() const -> unsigned long long {
return detail::is_unpacked_bit | data_.size() |
(named_info_.empty()
? 0ULL
: static_cast<unsigned long long>(detail::has_named_args_bit));
}
auto data() const -> const basic_format_arg<Context>* {
return named_info_.empty() ? data_.data() : data_.data() + 1;
}
template <typename T> void emplace_arg(const T& arg) {
data_.emplace_back(detail::make_arg<Context>(arg));
data_.emplace_back(arg);
}
template <typename T>
void emplace_arg(const detail::named_arg<char_type, T>& arg) {
if (named_info_.empty()) {
constexpr const detail::named_arg_info<char_type>* zero_ptr{nullptr};
data_.insert(data_.begin(), {zero_ptr, 0});
}
data_.emplace_back(detail::make_arg<Context>(detail::unwrap(arg.value)));
if (named_info_.empty())
data_.insert(data_.begin(), basic_format_arg<Context>(nullptr, 0));
data_.emplace_back(detail::unwrap(arg.value));
auto pop_one = [](std::vector<basic_format_arg<Context>>* data) {
data->pop_back();
};
std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype(pop_one)>
guard{&data_, pop_one};
named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)});
data_[0].value_.named_args = {named_info_.data(), named_info_.size()};
data_[0] = {named_info_.data(), named_info_.size()};
guard.release();
}
public:
constexpr dynamic_format_arg_store() = default;
operator basic_format_args<Context>() const {
return basic_format_args<Context>(data(), static_cast<int>(data_.size()),
!named_info_.empty());
}
/**
* Adds an argument into the dynamic store for later passing to a formatting
* function.
@ -164,7 +153,7 @@ class dynamic_format_arg_store
*/
template <typename T> void push_back(const T& arg) {
if (detail::const_check(need_copy<T>::value))
emplace_arg(dynamic_args_.push<stored_type<T>>(arg));
emplace_arg(dynamic_args_.push<stored_t<T>>(arg));
else
emplace_arg(detail::unwrap(arg));
}
@ -200,7 +189,7 @@ class dynamic_format_arg_store
dynamic_args_.push<std::basic_string<char_type>>(arg.name).c_str();
if (detail::const_check(need_copy<T>::value)) {
emplace_arg(
fmt::arg(arg_name, dynamic_args_.push<stored_type<T>>(arg.value)));
fmt::arg(arg_name, dynamic_args_.push<stored_t<T>>(arg.value)));
} else {
emplace_arg(fmt::arg(arg_name, arg.value));
}
@ -210,17 +199,20 @@ class dynamic_format_arg_store
void clear() {
data_.clear();
named_info_.clear();
dynamic_args_ = detail::dynamic_arg_list();
dynamic_args_ = {};
}
/// Reserves space to store at least `new_cap` arguments including
/// `new_cap_named` named arguments.
void reserve(size_t new_cap, size_t new_cap_named) {
FMT_ASSERT(new_cap >= new_cap_named,
"Set of arguments includes set of named arguments");
"set of arguments includes set of named arguments");
data_.reserve(new_cap);
named_info_.reserve(new_cap_named);
}
/// Returns the number of elements in the store.
size_t size() const noexcept { return data_.size(); }
};
FMT_END_NAMESPACE

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -330,7 +330,7 @@ FMT_CONSTEXPR inline auto operator|(emphasis lhs, emphasis rhs) noexcept
namespace detail {
template <typename Char> struct ansi_color_escape {
FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color,
FMT_CONSTEXPR ansi_color_escape(color_type text_color,
const char* esc) noexcept {
// If we have a terminal color, we need to output another escape code
// sequence.
@ -412,13 +412,13 @@ template <typename Char> struct ansi_color_escape {
};
template <typename Char>
FMT_CONSTEXPR auto make_foreground_color(detail::color_type foreground) noexcept
FMT_CONSTEXPR auto make_foreground_color(color_type foreground) noexcept
-> ansi_color_escape<Char> {
return ansi_color_escape<Char>(foreground, "\x1b[38;2;");
}
template <typename Char>
FMT_CONSTEXPR auto make_background_color(detail::color_type background) noexcept
FMT_CONSTEXPR auto make_background_color(color_type background) noexcept
-> ansi_color_escape<Char> {
return ansi_color_escape<Char>(background, "\x1b[48;2;");
}
@ -434,36 +434,35 @@ template <typename Char> inline void reset_color(buffer<Char>& buffer) {
buffer.append(reset_color.begin(), reset_color.end());
}
template <typename T> struct styled_arg : detail::view {
template <typename T> struct styled_arg : view {
const T& value;
text_style style;
styled_arg(const T& v, text_style s) : value(v), style(s) {}
};
template <typename Char>
void vformat_to(
buffer<Char>& buf, const text_style& ts, basic_string_view<Char> format_str,
basic_format_args<buffered_context<type_identity_t<Char>>> args) {
void vformat_to(buffer<Char>& buf, const text_style& ts,
basic_string_view<Char> fmt,
basic_format_args<buffered_context<Char>> args) {
bool has_style = false;
if (ts.has_emphasis()) {
has_style = true;
auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis());
auto emphasis = make_emphasis<Char>(ts.get_emphasis());
buf.append(emphasis.begin(), emphasis.end());
}
if (ts.has_foreground()) {
has_style = true;
auto foreground = detail::make_foreground_color<Char>(ts.get_foreground());
auto foreground = make_foreground_color<Char>(ts.get_foreground());
buf.append(foreground.begin(), foreground.end());
}
if (ts.has_background()) {
has_style = true;
auto background = detail::make_background_color<Char>(ts.get_background());
auto background = make_background_color<Char>(ts.get_background());
buf.append(background.begin(), background.end());
}
detail::vformat_to(buf, format_str, args, {});
if (has_style) detail::reset_color<Char>(buf);
vformat_to(buf, fmt, args);
if (has_style) reset_color<Char>(buf);
}
} // namespace detail
inline void vprint(FILE* f, const text_style& ts, string_view fmt,
@ -485,7 +484,7 @@ inline void vprint(FILE* f, const text_style& ts, string_view fmt,
template <typename... T>
void print(FILE* f, const text_style& ts, format_string<T...> fmt,
T&&... args) {
vprint(f, ts, fmt, fmt::make_format_args(args...));
vprint(f, ts, fmt.str, vargs<T...>{{args...}});
}
/**
@ -524,7 +523,7 @@ inline auto vformat(const text_style& ts, string_view fmt, format_args args)
template <typename... T>
inline auto format(const text_style& ts, format_string<T...> fmt, T&&... args)
-> std::string {
return fmt::vformat(ts, fmt, fmt::make_format_args(args...));
return fmt::vformat(ts, fmt.str, vargs<T...>{{args...}});
}
/// Formats a string with the given text_style and writes the output to `out`.
@ -551,7 +550,7 @@ template <typename OutputIt, typename... T,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
inline auto format_to(OutputIt out, const text_style& ts,
format_string<T...> fmt, T&&... args) -> OutputIt {
return vformat_to(out, ts, fmt, fmt::make_format_args(args...));
return vformat_to(out, ts, fmt.str, vargs<T...>{{args...}});
}
template <typename T, typename Char>
@ -560,31 +559,30 @@ struct formatter<detail::styled_arg<T>, Char> : formatter<T, Char> {
auto format(const detail::styled_arg<T>& arg, FormatContext& ctx) const
-> decltype(ctx.out()) {
const auto& ts = arg.style;
const auto& value = arg.value;
auto out = ctx.out();
bool has_style = false;
if (ts.has_emphasis()) {
has_style = true;
auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis());
out = std::copy(emphasis.begin(), emphasis.end(), out);
out = detail::copy<Char>(emphasis.begin(), emphasis.end(), out);
}
if (ts.has_foreground()) {
has_style = true;
auto foreground =
detail::make_foreground_color<Char>(ts.get_foreground());
out = std::copy(foreground.begin(), foreground.end(), out);
out = detail::copy<Char>(foreground.begin(), foreground.end(), out);
}
if (ts.has_background()) {
has_style = true;
auto background =
detail::make_background_color<Char>(ts.get_background());
out = std::copy(background.begin(), background.end(), out);
out = detail::copy<Char>(background.begin(), background.end(), out);
}
out = formatter<T, Char>::format(value, ctx);
out = formatter<T, Char>::format(arg.value, ctx);
if (has_style) {
auto reset_color = string_view("\x1b[0m");
out = std::copy(reset_color.begin(), reset_color.end(), out);
out = detail::copy<Char>(reset_color.begin(), reset_color.end(), out);
}
return out;
}

View file

@ -19,17 +19,11 @@ FMT_BEGIN_NAMESPACE
// A compile-time string which is compiled into fast formatting code.
FMT_EXPORT class compiled_string {};
namespace detail {
template <typename T, typename InputIt>
FMT_CONSTEXPR inline auto copy(InputIt begin, InputIt end, counting_iterator it)
-> counting_iterator {
return it + (end - begin);
}
template <typename S>
struct is_compiled_string : std::is_base_of<compiled_string, S> {};
namespace detail {
/**
* Converts a string literal `s` into a format string that will be parsed at
* compile time and converted into efficient formatting code. Requires C++17
@ -42,22 +36,11 @@ struct is_compiled_string : std::is_base_of<compiled_string, S> {};
* std::string s = fmt::format(FMT_COMPILE("{}"), 42);
*/
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
# define FMT_COMPILE(s) FMT_STRING_IMPL(s, fmt::compiled_string, explicit)
# define FMT_COMPILE(s) FMT_STRING_IMPL(s, fmt::compiled_string)
#else
# define FMT_COMPILE(s) FMT_STRING(s)
#endif
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
template <typename Char, size_t N,
fmt::detail_exported::fixed_string<Char, N> Str>
struct udl_compiled_string : compiled_string {
using char_type = Char;
explicit constexpr operator basic_string_view<char_type>() const {
return {Str.data, N - 1};
}
};
#endif
template <typename T, typename... Tail>
auto first(const T& value, const Tail&...) -> const T& {
return value;
@ -77,6 +60,29 @@ constexpr const auto& get([[maybe_unused]] const T& first,
return detail::get<N - 1>(rest...);
}
# if FMT_USE_NONTYPE_TEMPLATE_ARGS
template <int N, typename T, typename... Args, typename Char>
constexpr auto get_arg_index_by_name(basic_string_view<Char> name) -> int {
if constexpr (is_static_named_arg<T>()) {
if (name == T::name) return N;
}
if constexpr (sizeof...(Args) > 0)
return get_arg_index_by_name<N + 1, Args...>(name);
(void)name; // Workaround an MSVC bug about "unused" parameter.
return -1;
}
# endif
template <typename... Args, typename Char>
FMT_CONSTEXPR auto get_arg_index_by_name(basic_string_view<Char> name) -> int {
# if FMT_USE_NONTYPE_TEMPLATE_ARGS
if constexpr (sizeof...(Args) > 0)
return get_arg_index_by_name<0, Args...>(name);
# endif
(void)name;
return -1;
}
template <typename Char, typename... Args>
constexpr int get_arg_index_by_name(basic_string_view<Char> name,
type_list<Args...>) {
@ -149,8 +155,9 @@ template <typename Char, typename T, int N> struct field {
if constexpr (std::is_convertible<T, basic_string_view<Char>>::value) {
auto s = basic_string_view<Char>(arg);
return copy<Char>(s.begin(), s.end(), out);
} else {
return write<Char>(out, arg);
}
return write<Char>(out, arg);
}
};
@ -275,6 +282,7 @@ constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
}
template <typename Char> struct arg_id_handler {
arg_id_kind kind;
arg_ref<Char> arg_id;
constexpr int on_auto() {
@ -282,25 +290,28 @@ template <typename Char> struct arg_id_handler {
return 0;
}
constexpr int on_index(int id) {
kind = arg_id_kind::index;
arg_id = arg_ref<Char>(id);
return 0;
}
constexpr int on_name(basic_string_view<Char> id) {
kind = arg_id_kind::name;
arg_id = arg_ref<Char>(id);
return 0;
}
};
template <typename Char> struct parse_arg_id_result {
arg_id_kind kind;
arg_ref<Char> arg_id;
const Char* arg_id_end;
};
template <int ID, typename Char>
constexpr auto parse_arg_id(const Char* begin, const Char* end) {
auto handler = arg_id_handler<Char>{arg_ref<Char>{}};
auto handler = arg_id_handler<Char>{arg_id_kind::none, arg_ref<Char>{}};
auto arg_id_end = parse_arg_id(begin, end, handler);
return parse_arg_id_result<Char>{handler.arg_id, arg_id_end};
return parse_arg_id_result<Char>{handler.kind, handler.arg_id, arg_id_end};
}
template <typename T, typename Enable = void> struct field_type {
@ -363,18 +374,18 @@ constexpr auto compile_format_string(S fmt) {
constexpr char_type c =
arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type();
static_assert(c == '}' || c == ':', "missing '}' in format string");
if constexpr (arg_id_result.arg_id.kind == arg_id_kind::index) {
if constexpr (arg_id_result.kind == arg_id_kind::index) {
static_assert(
ID == manual_indexing_id || ID == 0,
"cannot switch from automatic to manual argument indexing");
constexpr auto arg_index = arg_id_result.arg_id.val.index;
constexpr auto arg_index = arg_id_result.arg_id.index;
return parse_replacement_field_then_tail<get_type<arg_index, Args>,
Args, arg_id_end_pos,
arg_index, manual_indexing_id>(
fmt);
} else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) {
} else if constexpr (arg_id_result.kind == arg_id_kind::name) {
constexpr auto arg_index =
get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{});
get_arg_index_by_name(arg_id_result.arg_id.name, Args{});
if constexpr (arg_index >= 0) {
constexpr auto next_id =
ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
@ -383,8 +394,7 @@ constexpr auto compile_format_string(S fmt) {
arg_index, next_id>(fmt);
} else if constexpr (c == '}') {
return parse_tail<Args, arg_id_end_pos + 1, ID>(
runtime_named_field<char_type>{arg_id_result.arg_id.val.name},
fmt);
runtime_named_field<char_type>{arg_id_result.arg_id.name}, fmt);
} else if constexpr (c == ':') {
return unknown_format(); // no type info for specs parsing
}
@ -405,7 +415,7 @@ constexpr auto compile_format_string(S fmt) {
}
template <typename... Args, typename S,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
FMT_ENABLE_IF(is_compiled_string<S>::value)>
constexpr auto compile(S fmt) {
constexpr auto str = basic_string_view<typename S::char_type>(fmt);
if constexpr (str.size() == 0) {
@ -441,7 +451,7 @@ constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf,
}
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
FMT_ENABLE_IF(is_compiled_string<S>::value)>
FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
Args&&... args) {
if constexpr (std::is_same<typename S::char_type, char>::value) {
@ -468,7 +478,7 @@ FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
}
template <typename OutputIt, typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
FMT_ENABLE_IF(is_compiled_string<S>::value)>
FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) {
constexpr auto compiled = detail::compile<Args...>(S());
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
@ -483,7 +493,7 @@ FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) {
#endif
template <typename OutputIt, typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
FMT_ENABLE_IF(is_compiled_string<S>::value)>
auto format_to_n(OutputIt out, size_t n, const S& fmt, Args&&... args)
-> format_to_n_result<OutputIt> {
using traits = detail::fixed_buffer_traits;
@ -493,32 +503,32 @@ auto format_to_n(OutputIt out, size_t n, const S& fmt, Args&&... args)
}
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
FMT_ENABLE_IF(is_compiled_string<S>::value)>
FMT_CONSTEXPR20 auto formatted_size(const S& fmt, const Args&... args)
-> size_t {
return fmt::format_to(detail::counting_iterator(), fmt, args...).count();
auto buf = detail::counting_buffer<>();
fmt::format_to(appender(buf), fmt, args...);
return buf.count();
}
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
FMT_ENABLE_IF(is_compiled_string<S>::value)>
void print(std::FILE* f, const S& fmt, const Args&... args) {
memory_buffer buffer;
fmt::format_to(std::back_inserter(buffer), fmt, args...);
detail::print(f, {buffer.data(), buffer.size()});
auto buf = memory_buffer();
fmt::format_to(appender(buf), fmt, args...);
detail::print(f, {buf.data(), buf.size()});
}
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
FMT_ENABLE_IF(is_compiled_string<S>::value)>
void print(const S& fmt, const Args&... args) {
print(stdout, fmt, args...);
}
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
inline namespace literals {
template <detail_exported::fixed_string Str> constexpr auto operator""_cf() {
using char_t = remove_cvref_t<decltype(Str.data[0])>;
return detail::udl_compiled_string<char_t, sizeof(Str.data) / sizeof(char_t),
Str>();
template <detail::fixed_string Str> constexpr auto operator""_cf() {
return FMT_COMPILE(Str.data);
}
} // namespace literals
#endif

View file

@ -14,10 +14,6 @@
# include <climits>
# include <cmath>
# include <exception>
# if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
# include <locale>
# endif
#endif
#if defined(_WIN32) && !defined(FMT_USE_WRITE_CONSOLE)
@ -26,16 +22,22 @@
#include "format.h"
#if FMT_USE_LOCALE
# include <locale>
#endif
#ifndef FMT_FUNC
# define FMT_FUNC
#endif
FMT_BEGIN_NAMESPACE
namespace detail {
FMT_FUNC void assert_fail(const char* file, int line, const char* message) {
// Use unchecked std::fprintf to avoid triggering another assertion when
// writing to stderr fails
std::fprintf(stderr, "%s:%d: assertion failed: %s", file, line, message);
// Chosen instead of std::abort to satisfy Clang in CUDA mode during device
// code pass.
std::terminate();
// writing to stderr fails.
fprintf(stderr, "%s:%d: assertion failed: %s", file, line, message);
abort();
}
FMT_FUNC void format_error_code(detail::buffer<char>& out, int error_code,
@ -61,86 +63,95 @@ FMT_FUNC void format_error_code(detail::buffer<char>& out, int error_code,
FMT_ASSERT(out.size() <= inline_buffer_size, "");
}
FMT_FUNC void report_error(format_func func, int error_code,
const char* message) noexcept {
FMT_FUNC void do_report_error(format_func func, int error_code,
const char* message) noexcept {
memory_buffer full_message;
func(full_message, error_code, message);
// Don't use fwrite_fully because the latter may throw.
// Don't use fwrite_all because the latter may throw.
if (std::fwrite(full_message.data(), full_message.size(), 1, stderr) > 0)
std::fputc('\n', stderr);
}
// A wrapper around fwrite that throws on error.
inline void fwrite_fully(const void* ptr, size_t count, FILE* stream) {
inline void fwrite_all(const void* ptr, size_t count, FILE* stream) {
size_t written = std::fwrite(ptr, 1, count, stream);
if (written < count)
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
}
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
#if FMT_USE_LOCALE
using std::locale;
using std::numpunct;
using std::use_facet;
template <typename Locale>
locale_ref::locale_ref(const Locale& loc) : locale_(&loc) {
static_assert(std::is_same<Locale, std::locale>::value, "");
static_assert(std::is_same<Locale, locale>::value, "");
}
#else
struct locale {};
template <typename Char> struct numpunct {
auto grouping() const -> std::string { return "\03"; }
auto thousands_sep() const -> Char { return ','; }
auto decimal_point() const -> Char { return '.'; }
};
template <typename Facet> Facet use_facet(locale) { return {}; }
#endif // FMT_USE_LOCALE
template <typename Locale> auto locale_ref::get() const -> Locale {
static_assert(std::is_same<Locale, std::locale>::value, "");
return locale_ ? *static_cast<const std::locale*>(locale_) : std::locale();
static_assert(std::is_same<Locale, locale>::value, "");
#if FMT_USE_LOCALE
if (locale_) return *static_cast<const locale*>(locale_);
#endif
return locale();
}
template <typename Char>
FMT_FUNC auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result<Char> {
auto& facet = std::use_facet<std::numpunct<Char>>(loc.get<std::locale>());
auto&& facet = use_facet<numpunct<Char>>(loc.get<locale>());
auto grouping = facet.grouping();
auto thousands_sep = grouping.empty() ? Char() : facet.thousands_sep();
return {std::move(grouping), thousands_sep};
}
template <typename Char>
FMT_FUNC auto decimal_point_impl(locale_ref loc) -> Char {
return std::use_facet<std::numpunct<Char>>(loc.get<std::locale>())
.decimal_point();
return use_facet<numpunct<Char>>(loc.get<locale>()).decimal_point();
}
#else
template <typename Char>
FMT_FUNC auto thousands_sep_impl(locale_ref) -> thousands_sep_result<Char> {
return {"\03", FMT_STATIC_THOUSANDS_SEPARATOR};
}
template <typename Char> FMT_FUNC Char decimal_point_impl(locale_ref) {
return '.';
}
#endif
#if FMT_USE_LOCALE
FMT_FUNC auto write_loc(appender out, loc_value value,
const format_specs& specs, locale_ref loc) -> bool {
#ifdef FMT_STATIC_THOUSANDS_SEPARATOR
value.visit(loc_writer<>{
out, specs, std::string(1, FMT_STATIC_THOUSANDS_SEPARATOR), "\3", "."});
return true;
#else
auto locale = loc.get<std::locale>();
// We cannot use the num_put<char> facet because it may produce output in
// a wrong encoding.
using facet = format_facet<std::locale>;
if (std::has_facet<facet>(locale))
return std::use_facet<facet>(locale).put(out, value, specs);
return use_facet<facet>(locale).put(out, value, specs);
return facet(locale).put(out, value, specs);
#endif
}
#endif
} // namespace detail
FMT_FUNC void report_error(const char* message) {
#if FMT_USE_EXCEPTIONS
// Use FMT_THROW instead of throw to avoid bogus unreachable code warnings
// from MSVC.
FMT_THROW(format_error(message));
#else
fputs(message, stderr);
abort();
#endif
}
template <typename Locale> typename Locale::id format_facet<Locale>::id;
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
template <typename Locale> format_facet<Locale>::format_facet(Locale& loc) {
auto& numpunct = std::use_facet<std::numpunct<char>>(loc);
grouping_ = numpunct.grouping();
if (!grouping_.empty()) separator_ = std::string(1, numpunct.thousands_sep());
auto& np = detail::use_facet<detail::numpunct<char>>(loc);
grouping_ = np.grouping();
if (!grouping_.empty()) separator_ = std::string(1, np.thousands_sep());
}
#if FMT_USE_LOCALE
template <>
FMT_API FMT_FUNC auto format_facet<std::locale>::do_put(
appender out, loc_value val, const format_specs& specs) const -> bool {
@ -1425,7 +1436,7 @@ FMT_FUNC void format_system_error(detail::buffer<char>& out, int error_code,
FMT_FUNC void report_system_error(int error_code,
const char* message) noexcept {
report_error(format_system_error, error_code, message);
do_report_error(format_system_error, error_code, message);
}
FMT_FUNC auto vformat(string_view fmt, format_args args) -> std::string {
@ -1438,6 +1449,15 @@ FMT_FUNC auto vformat(string_view fmt, format_args args) -> std::string {
namespace detail {
FMT_FUNC void vformat_to(buffer<char>& buf, string_view fmt, format_args args,
locale_ref loc) {
auto out = appender(buf);
if (fmt.size() == 2 && equal2(fmt.data(), "{}"))
return args.get(0).visit(default_arg_formatter<char>{out});
parse_format_string(
fmt, format_handler<char>{parse_context<char>(fmt), {out, args, loc}});
}
template <typename T> struct span {
T* data;
size_t size;
@ -1508,6 +1528,7 @@ template <typename F> class glibc_file : public file_base<F> {
void init_buffer() {
if (this->file_->_IO_write_ptr) return;
// Force buffer initialization by placing and removing a char in a buffer.
assume(this->file_->_IO_write_ptr >= this->file_->_IO_write_end);
putc_unlocked(0, this->file_);
--this->file_->_IO_write_ptr;
}
@ -1615,7 +1636,7 @@ template <typename F> class fallback_file : public file_base<F> {
};
#ifndef FMT_USE_FALLBACK_FILE
# define FMT_USE_FALLBACK_FILE 1
# define FMT_USE_FALLBACK_FILE 0
#endif
template <typename F,
@ -1692,7 +1713,7 @@ FMT_FUNC void vprint_mojibake(std::FILE* f, string_view fmt, format_args args,
auto buffer = memory_buffer();
detail::vformat_to(buffer, fmt, args);
if (newline) buffer.push_back('\n');
fwrite_fully(buffer.data(), buffer.size(), f);
fwrite_all(buffer.data(), buffer.size(), f);
}
#endif
@ -1704,7 +1725,7 @@ FMT_FUNC void print(std::FILE* f, string_view text) {
if (write_console(fd, text)) return;
}
#endif
fwrite_fully(text.data(), text.size(), f);
fwrite_all(text.data(), text.size(), f);
}
} // namespace detail

File diff suppressed because it is too large Load diff

View file

@ -118,7 +118,7 @@ FMT_API void format_windows_error(buffer<char>& out, int error_code,
const char* message) noexcept;
}
FMT_API std::system_error vwindows_error(int error_code, string_view format_str,
FMT_API std::system_error vwindows_error(int error_code, string_view fmt,
format_args args);
/**
@ -146,10 +146,10 @@ FMT_API std::system_error vwindows_error(int error_code, string_view format_str,
* "cannot open file '{}'", filename);
* }
*/
template <typename... Args>
std::system_error windows_error(int error_code, string_view message,
const Args&... args) {
return vwindows_error(error_code, message, fmt::make_format_args(args...));
template <typename... T>
auto windows_error(int error_code, string_view message, const T&... args)
-> std::system_error {
return vwindows_error(error_code, message, vargs<T...>{{args...}});
}
// Reports a Windows error without throwing an exception.
@ -164,8 +164,8 @@ inline auto system_category() noexcept -> const std::error_category& {
// std::system is not available on some platforms such as iOS (#2248).
#ifdef __OSX__
template <typename S, typename... Args, typename Char = char_t<S>>
void say(const S& format_str, Args&&... args) {
std::system(format("say \"{}\"", format(format_str, args...)).c_str());
void say(const S& fmt, Args&&... args) {
std::system(format("say \"{}\"", format(fmt, args...)).c_str());
}
#endif
@ -176,24 +176,24 @@ class buffered_file {
friend class file;
explicit buffered_file(FILE* f) : file_(f) {}
inline explicit buffered_file(FILE* f) : file_(f) {}
public:
buffered_file(const buffered_file&) = delete;
void operator=(const buffered_file&) = delete;
// Constructs a buffered_file object which doesn't represent any file.
buffered_file() noexcept : file_(nullptr) {}
inline buffered_file() noexcept : file_(nullptr) {}
// Destroys the object closing the file it represents if any.
FMT_API ~buffered_file() noexcept;
public:
buffered_file(buffered_file&& other) noexcept : file_(other.file_) {
inline buffered_file(buffered_file&& other) noexcept : file_(other.file_) {
other.file_ = nullptr;
}
auto operator=(buffered_file&& other) -> buffered_file& {
inline auto operator=(buffered_file&& other) -> buffered_file& {
close();
file_ = other.file_;
other.file_ = nullptr;
@ -207,13 +207,13 @@ class buffered_file {
FMT_API void close();
// Returns the pointer to a FILE object representing this file.
auto get() const noexcept -> FILE* { return file_; }
inline auto get() const noexcept -> FILE* { return file_; }
FMT_API auto descriptor() const -> int;
template <typename... T>
inline void print(string_view fmt, const T&... args) {
const auto& vargs = fmt::make_format_args(args...);
fmt::vargs<T...> vargs = {{args...}};
detail::is_locking<T...>() ? fmt::vprint_buffered(file_, fmt, vargs)
: fmt::vprint(file_, fmt, vargs);
}
@ -248,7 +248,7 @@ class FMT_API file {
};
// Constructs a file object which doesn't represent any file.
file() noexcept : fd_(-1) {}
inline file() noexcept : fd_(-1) {}
// Opens a file and constructs a file object representing this file.
file(cstring_view path, int oflag);
@ -257,10 +257,10 @@ class FMT_API file {
file(const file&) = delete;
void operator=(const file&) = delete;
file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; }
inline file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; }
// Move assignment is not noexcept because close may throw.
auto operator=(file&& other) -> file& {
inline auto operator=(file&& other) -> file& {
close();
fd_ = other.fd_;
other.fd_ = -1;
@ -271,7 +271,7 @@ class FMT_API file {
~file() noexcept;
// Returns the file descriptor.
auto descriptor() const noexcept -> int { return fd_; }
inline auto descriptor() const noexcept -> int { return fd_; }
// Closes the file.
void close();
@ -324,9 +324,9 @@ auto getpagesize() -> long;
namespace detail {
struct buffer_size {
buffer_size() = default;
constexpr buffer_size() = default;
size_t value = 0;
auto operator=(size_t val) const -> buffer_size {
FMT_CONSTEXPR auto operator=(size_t val) const -> buffer_size {
auto bs = buffer_size();
bs.value = val;
return bs;
@ -337,7 +337,7 @@ struct ostream_params {
int oflag = file::WRONLY | file::CREATE | file::TRUNC;
size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768;
ostream_params() {}
constexpr ostream_params() {}
template <typename... T>
ostream_params(T... params, int new_oflag) : ostream_params(params...) {
@ -358,59 +358,47 @@ struct ostream_params {
# endif
};
class file_buffer final : public buffer<char> {
} // namespace detail
FMT_INLINE_VARIABLE constexpr auto buffer_size = detail::buffer_size();
/// A fast buffered output stream for writing from a single thread. Writing from
/// multiple threads without external synchronization may result in a data race.
class FMT_API ostream : private detail::buffer<char> {
private:
file file_;
FMT_API static void grow(buffer<char>& buf, size_t);
ostream(cstring_view path, const detail::ostream_params& params);
static void grow(buffer<char>& buf, size_t);
public:
FMT_API file_buffer(cstring_view path, const ostream_params& params);
FMT_API file_buffer(file_buffer&& other) noexcept;
FMT_API ~file_buffer();
ostream(ostream&& other) noexcept;
~ostream();
void flush() {
operator writer() {
detail::buffer<char>& buf = *this;
return buf;
}
inline void flush() {
if (size() == 0) return;
file_.write(data(), size() * sizeof(data()[0]));
clear();
}
void close() {
flush();
file_.close();
}
};
} // namespace detail
constexpr auto buffer_size = detail::buffer_size();
/// A fast output stream for writing from a single thread. Writing from
/// multiple threads without external synchronization may result in a data race.
class FMT_API ostream {
private:
FMT_MSC_WARNING(suppress : 4251)
detail::file_buffer buffer_;
ostream(cstring_view path, const detail::ostream_params& params)
: buffer_(path, params) {}
public:
ostream(ostream&& other) : buffer_(std::move(other.buffer_)) {}
~ostream();
void flush() { buffer_.flush(); }
template <typename... T>
friend auto output_file(cstring_view path, T... params) -> ostream;
void close() { buffer_.close(); }
inline void close() {
flush();
file_.close();
}
/// Formats `args` according to specifications in `fmt` and writes the
/// output to the file.
template <typename... T> void print(format_string<T...> fmt, T&&... args) {
vformat_to(appender(buffer_), fmt, fmt::make_format_args(args...));
vformat_to(appender(*this), fmt.str, vargs<T...>{{args...}});
}
};

View file

@ -22,6 +22,14 @@
#include "chrono.h" // formatbuf
#ifdef _MSVC_STL_UPDATE
# define FMT_MSVC_STL_UPDATE _MSVC_STL_UPDATE
#elif defined(_MSC_VER) && _MSC_VER < 1912 // VS 15.5
# define FMT_MSVC_STL_UPDATE _MSVC_LANG
#else
# define FMT_MSVC_STL_UPDATE 0
#endif
FMT_BEGIN_NAMESPACE
namespace detail {
@ -35,53 +43,18 @@ class file_access {
friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; }
};
#if FMT_MSC_VERSION
#if FMT_MSVC_STL_UPDATE
template class file_access<file_access_tag, std::filebuf,
&std::filebuf::_Myfile>;
auto get_file(std::filebuf&) -> FILE*;
#endif
inline auto write_ostream_unicode(std::ostream& os, fmt::string_view data)
-> bool {
FILE* f = nullptr;
#if FMT_MSC_VERSION && FMT_USE_RTTI
if (auto* buf = dynamic_cast<std::filebuf*>(os.rdbuf()))
f = get_file(*buf);
else
return false;
#elif defined(_WIN32) && defined(__GLIBCXX__) && FMT_USE_RTTI
auto* rdbuf = os.rdbuf();
if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf))
f = sfbuf->file();
else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf))
f = fbuf->file();
else
return false;
#else
ignore_unused(os, data, f);
#endif
#ifdef _WIN32
if (f) {
int fd = _fileno(f);
if (_isatty(fd)) {
os.flush();
return write_console(fd, data);
}
}
#endif
return false;
}
inline auto write_ostream_unicode(std::wostream&,
fmt::basic_string_view<wchar_t>) -> bool {
return false;
}
// Write the content of buf to os.
// It is a separate function rather than a part of vprint to simplify testing.
template <typename Char>
void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
const Char* buf_data = buf.data();
using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
using unsigned_streamsize = make_unsigned_t<std::streamsize>;
unsigned_streamsize size = buf.size();
unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>());
do {
@ -92,21 +65,9 @@ void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
} while (size != 0);
}
template <typename Char, typename T>
void format_value(buffer<Char>& buf, const T& value) {
auto&& format_buf = formatbuf<std::basic_streambuf<Char>>(buf);
auto&& output = std::basic_ostream<Char>(&format_buf);
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
output.imbue(std::locale::classic()); // The default is always unlocalized.
#endif
output << value;
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
}
template <typename T> struct streamed_view {
const T& value;
};
} // namespace detail
// Formats an object of type T that has an overloaded ostream operator<<.
@ -117,7 +78,11 @@ struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> {
template <typename T, typename Context>
auto format(const T& value, Context& ctx) const -> decltype(ctx.out()) {
auto buffer = basic_memory_buffer<Char>();
detail::format_value(buffer, value);
auto&& formatbuf = detail::formatbuf<std::basic_streambuf<Char>>(buffer);
auto&& output = std::basic_ostream<Char>(&formatbuf);
output.imbue(std::locale::classic()); // The default is always unlocalized.
output << value;
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
return formatter<basic_string_view<Char>, Char>::format(
{buffer.data(), buffer.size()}, ctx);
}
@ -148,24 +113,30 @@ constexpr auto streamed(const T& value) -> detail::streamed_view<T> {
return {value};
}
namespace detail {
inline void vprint_directly(std::ostream& os, string_view format_str,
format_args args) {
inline void vprint(std::ostream& os, string_view fmt, format_args args) {
auto buffer = memory_buffer();
detail::vformat_to(buffer, format_str, args);
detail::write_buffer(os, buffer);
}
} // namespace detail
FMT_EXPORT template <typename Char>
void vprint(std::basic_ostream<Char>& os,
basic_string_view<type_identity_t<Char>> format_str,
typename detail::vformat_args<Char>::type args) {
auto buffer = basic_memory_buffer<Char>();
detail::vformat_to(buffer, format_str, args);
if (detail::write_ostream_unicode(os, {buffer.data(), buffer.size()})) return;
detail::vformat_to(buffer, fmt, args);
FILE* f = nullptr;
#if FMT_MSVC_STL_UPDATE && FMT_USE_RTTI
if (auto* buf = dynamic_cast<std::filebuf*>(os.rdbuf()))
f = detail::get_file(*buf);
#elif defined(_WIN32) && defined(__GLIBCXX__) && FMT_USE_RTTI
auto* rdbuf = os.rdbuf();
if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf))
f = sfbuf->file();
else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf))
f = fbuf->file();
#endif
#ifdef _WIN32
if (f) {
int fd = _fileno(f);
if (_isatty(fd)) {
os.flush();
if (detail::write_console(fd, {buffer.data(), buffer.size()})) return;
}
}
#endif
detail::ignore_unused(f);
detail::write_buffer(os, buffer);
}
@ -178,19 +149,11 @@ void vprint(std::basic_ostream<Char>& os,
*/
FMT_EXPORT template <typename... T>
void print(std::ostream& os, format_string<T...> fmt, T&&... args) {
const auto& vargs = fmt::make_format_args(args...);
if (detail::use_utf8())
vprint(os, fmt, vargs);
else
detail::vprint_directly(os, fmt, vargs);
}
FMT_EXPORT
template <typename... Args>
void print(std::wostream& os,
basic_format_string<wchar_t, type_identity_t<Args>...> fmt,
Args&&... args) {
vprint(os, fmt, fmt::make_format_args<buffered_context<wchar_t>>(args...));
fmt::vargs<T...> vargs = {{args...}};
if (detail::const_check(detail::use_utf8)) return vprint(os, fmt.str, vargs);
auto buffer = memory_buffer();
detail::vformat_to(buffer, fmt.str, vargs);
detail::write_buffer(os, buffer);
}
FMT_EXPORT template <typename... T>
@ -198,14 +161,6 @@ void println(std::ostream& os, format_string<T...> fmt, T&&... args) {
fmt::print(os, "{}\n", fmt::format(fmt, std::forward<T>(args)...));
}
FMT_EXPORT
template <typename... Args>
void println(std::wostream& os,
basic_format_string<wchar_t, type_identity_t<Args>...> fmt,
Args&&... args) {
print(os, L"{}\n", fmt::format(fmt, std::forward<Args>(args)...));
}
FMT_END_NAMESPACE
#endif // FMT_OSTREAM_H_

View file

@ -33,8 +33,9 @@ template <typename Char> class basic_printf_context {
public:
using char_type = Char;
using parse_context_type = basic_format_parse_context<Char>;
using parse_context_type = parse_context<Char>;
template <typename T> using formatter_type = printf_formatter<T>;
enum { builtin_types = 1 };
/// Constructs a `printf_context` object. References to the arguments are
/// stored in the context object so make sure they have appropriate lifetimes.
@ -54,6 +55,23 @@ template <typename Char> class basic_printf_context {
namespace detail {
// Return the result via the out param to workaround gcc bug 77539.
template <bool IS_CONSTEXPR, typename T, typename Ptr = const T*>
FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr& out) -> bool {
for (out = first; out != last; ++out) {
if (*out == value) return true;
}
return false;
}
template <>
inline auto find<false, char>(const char* first, const char* last, char value,
const char*& out) -> bool {
out =
static_cast<const char*>(memchr(first, value, to_unsigned(last - first)));
return out != nullptr;
}
// Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers.
template <bool IsSigned> struct int_checker {
@ -61,7 +79,7 @@ template <bool IsSigned> struct int_checker {
unsigned max = to_unsigned(max_value<int>());
return value <= max;
}
static auto fits_in_int(bool) -> bool { return true; }
inline static auto fits_in_int(bool) -> bool { return true; }
};
template <> struct int_checker<true> {
@ -69,7 +87,7 @@ template <> struct int_checker<true> {
return value >= (std::numeric_limits<int>::min)() &&
value <= max_value<int>();
}
static auto fits_in_int(int) -> bool { return true; }
inline static auto fits_in_int(int) -> bool { return true; }
};
struct printf_precision_handler {
@ -127,25 +145,19 @@ template <typename T, typename Context> class arg_converter {
using target_type = conditional_t<std::is_same<T, void>::value, U, T>;
if (const_check(sizeof(target_type) <= sizeof(int))) {
// Extra casts are used to silence warnings.
if (is_signed) {
auto n = static_cast<int>(static_cast<target_type>(value));
arg_ = detail::make_arg<Context>(n);
} else {
using unsigned_type = typename make_unsigned_or_bool<target_type>::type;
auto n = static_cast<unsigned>(static_cast<unsigned_type>(value));
arg_ = detail::make_arg<Context>(n);
}
using unsigned_type = typename make_unsigned_or_bool<target_type>::type;
if (is_signed)
arg_ = static_cast<int>(static_cast<target_type>(value));
else
arg_ = static_cast<unsigned>(static_cast<unsigned_type>(value));
} else {
if (is_signed) {
// glibc's printf doesn't sign extend arguments of smaller types:
// std::printf("%lld", -42); // prints "4294967254"
// but we don't have to do the same because it's a UB.
auto n = static_cast<long long>(value);
arg_ = detail::make_arg<Context>(n);
} else {
auto n = static_cast<typename make_unsigned_or_bool<U>::type>(value);
arg_ = detail::make_arg<Context>(n);
}
// glibc's printf doesn't sign extend arguments of smaller types:
// std::printf("%lld", -42); // prints "4294967254"
// but we don't have to do the same because it's a UB.
if (is_signed)
arg_ = static_cast<long long>(value);
else
arg_ = static_cast<typename make_unsigned_or_bool<U>::type>(value);
}
}
@ -172,8 +184,7 @@ template <typename Context> class char_converter {
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
void operator()(T value) {
auto c = static_cast<typename Context::char_type>(value);
arg_ = detail::make_arg<Context>(c);
arg_ = static_cast<typename Context::char_type>(value);
}
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
@ -194,13 +205,13 @@ class printf_width_handler {
format_specs& specs_;
public:
explicit printf_width_handler(format_specs& specs) : specs_(specs) {}
inline explicit printf_width_handler(format_specs& specs) : specs_(specs) {}
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
auto operator()(T value) -> unsigned {
auto width = static_cast<uint32_or_64_or_128_t<T>>(value);
if (detail::is_negative(value)) {
specs_.align = align::left;
specs_.set_align(align::left);
width = 0 - width;
}
unsigned int_max = to_unsigned(max_value<int>());
@ -234,69 +245,74 @@ class printf_arg_formatter : public arg_formatter<Char> {
void write_null_pointer(bool is_string = false) {
auto s = this->specs;
s.type = presentation_type::none;
s.set_type(presentation_type::none);
write_bytes<Char>(this->out, is_string ? "(null)" : "(nil)", s);
}
template <typename T> void write(T value) {
detail::write<Char>(this->out, value, this->specs, this->locale);
}
public:
printf_arg_formatter(basic_appender<Char> iter, format_specs& s,
context_type& ctx)
: base(make_arg_formatter(iter, s)), context_(ctx) {}
void operator()(monostate value) { base::operator()(value); }
void operator()(monostate value) { write(value); }
template <typename T, FMT_ENABLE_IF(detail::is_integral<T>::value)>
void operator()(T value) {
// MSVC2013 fails to compile separate overloads for bool and Char so use
// std::is_same instead.
if (!std::is_same<T, Char>::value) {
base::operator()(value);
write(value);
return;
}
format_specs s = this->specs;
if (s.type != presentation_type::none && s.type != presentation_type::chr) {
if (s.type() != presentation_type::none &&
s.type() != presentation_type::chr) {
return (*this)(static_cast<int>(value));
}
s.sign = sign::none;
s.alt = false;
s.fill = ' '; // Ignore '0' flag for char types.
s.set_sign(sign::none);
s.clear_alt();
s.set_fill(' '); // Ignore '0' flag for char types.
// align::numeric needs to be overwritten here since the '0' flag is
// ignored for non-numeric types
if (s.align == align::none || s.align == align::numeric)
s.align = align::right;
write<Char>(this->out, static_cast<Char>(value), s);
if (s.align() == align::none || s.align() == align::numeric)
s.set_align(align::right);
detail::write<Char>(this->out, static_cast<Char>(value), s);
}
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
void operator()(T value) {
base::operator()(value);
write(value);
}
void operator()(const char* value) {
if (value)
base::operator()(value);
write(value);
else
write_null_pointer(this->specs.type != presentation_type::pointer);
write_null_pointer(this->specs.type() != presentation_type::pointer);
}
void operator()(const wchar_t* value) {
if (value)
base::operator()(value);
write(value);
else
write_null_pointer(this->specs.type != presentation_type::pointer);
write_null_pointer(this->specs.type() != presentation_type::pointer);
}
void operator()(basic_string_view<Char> value) { base::operator()(value); }
void operator()(basic_string_view<Char> value) { write(value); }
void operator()(const void* value) {
if (value)
base::operator()(value);
write(value);
else
write_null_pointer();
}
void operator()(typename basic_format_arg<context_type>::handle handle) {
auto parse_ctx = basic_format_parse_context<Char>({});
auto parse_ctx = parse_context<Char>({});
handle.format(parse_ctx, context_);
}
};
@ -305,23 +321,14 @@ template <typename Char>
void parse_flags(format_specs& specs, const Char*& it, const Char* end) {
for (; it != end; ++it) {
switch (*it) {
case '-':
specs.align = align::left;
break;
case '+':
specs.sign = sign::plus;
break;
case '0':
specs.fill = '0';
break;
case '-': specs.set_align(align::left); break;
case '+': specs.set_sign(sign::plus); break;
case '0': specs.set_fill('0'); break;
case ' ':
if (specs.sign != sign::plus) specs.sign = sign::space;
if (specs.sign() != sign::plus) specs.set_sign(sign::space);
break;
case '#':
specs.alt = true;
break;
default:
return;
case '#': specs.set_alt(); break;
default: return;
}
}
}
@ -339,7 +346,7 @@ auto parse_header(const Char*& it, const Char* end, format_specs& specs,
++it;
arg_index = value != -1 ? value : max_value<int>();
} else {
if (c == '0') specs.fill = '0';
if (c == '0') specs.set_fill('0');
if (value != 0) {
// Nonzero value means that we parsed width and don't need to
// parse it or flags again, so return now.
@ -369,43 +376,22 @@ inline auto parse_printf_presentation_type(char c, type t, bool& upper)
using pt = presentation_type;
constexpr auto integral_set = sint_set | uint_set | bool_set | char_set;
switch (c) {
case 'd':
return in(t, integral_set) ? pt::dec : pt::none;
case 'o':
return in(t, integral_set) ? pt::oct : pt::none;
case 'X':
upper = true;
FMT_FALLTHROUGH;
case 'x':
return in(t, integral_set) ? pt::hex : pt::none;
case 'E':
upper = true;
FMT_FALLTHROUGH;
case 'e':
return in(t, float_set) ? pt::exp : pt::none;
case 'F':
upper = true;
FMT_FALLTHROUGH;
case 'f':
return in(t, float_set) ? pt::fixed : pt::none;
case 'G':
upper = true;
FMT_FALLTHROUGH;
case 'g':
return in(t, float_set) ? pt::general : pt::none;
case 'A':
upper = true;
FMT_FALLTHROUGH;
case 'a':
return in(t, float_set) ? pt::hexfloat : pt::none;
case 'c':
return in(t, integral_set) ? pt::chr : pt::none;
case 's':
return in(t, string_set | cstring_set) ? pt::string : pt::none;
case 'p':
return in(t, pointer_set | cstring_set) ? pt::pointer : pt::none;
default:
return pt::none;
case 'd': return in(t, integral_set) ? pt::dec : pt::none;
case 'o': return in(t, integral_set) ? pt::oct : pt::none;
case 'X': upper = true; FMT_FALLTHROUGH;
case 'x': return in(t, integral_set) ? pt::hex : pt::none;
case 'E': upper = true; FMT_FALLTHROUGH;
case 'e': return in(t, float_set) ? pt::exp : pt::none;
case 'F': upper = true; FMT_FALLTHROUGH;
case 'f': return in(t, float_set) ? pt::fixed : pt::none;
case 'G': upper = true; FMT_FALLTHROUGH;
case 'g': return in(t, float_set) ? pt::general : pt::none;
case 'A': upper = true; FMT_FALLTHROUGH;
case 'a': return in(t, float_set) ? pt::hexfloat : pt::none;
case 'c': return in(t, integral_set) ? pt::chr : pt::none;
case 's': return in(t, string_set | cstring_set) ? pt::string : pt::none;
case 'p': return in(t, pointer_set | cstring_set) ? pt::pointer : pt::none;
default: return pt::none;
}
}
@ -415,7 +401,7 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
using iterator = basic_appender<Char>;
auto out = iterator(buf);
auto context = basic_printf_context<Char>(out, args);
auto parse_ctx = basic_format_parse_context<Char>(format);
auto parse_ctx = parse_context<Char>(format);
// Returns the argument with specified index or, if arg_index is -1, the next
// argument.
@ -444,7 +430,7 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
write(out, basic_string_view<Char>(start, to_unsigned(it - 1 - start)));
auto specs = format_specs();
specs.align = align::right;
specs.set_align(align::right);
// Parse argument index, flags and width.
int arg_index = parse_header(it, end, specs, get_arg);
@ -468,9 +454,9 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
auto arg = get_arg(arg_index);
// For d, i, o, u, x, and X conversion specifiers, if a precision is
// specified, the '0' flag is ignored
if (specs.precision >= 0 && arg.is_integral()) {
if (specs.precision >= 0 && is_integral_type(arg.type())) {
// Ignore '0' for non-numeric types or if '-' present.
specs.fill = ' ';
specs.set_fill(' ');
}
if (specs.precision >= 0 && arg.type() == type::cstring_type) {
auto str = arg.visit(get_cstring<Char>());
@ -478,15 +464,16 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
auto nul = std::find(str, str_end, Char());
auto sv = basic_string_view<Char>(
str, to_unsigned(nul != str_end ? nul - str : specs.precision));
arg = make_arg<basic_printf_context<Char>>(sv);
arg = sv;
}
if (specs.alt && arg.visit(is_zero_int())) specs.alt = false;
if (specs.fill.template get<Char>() == '0') {
if (arg.is_arithmetic() && specs.align != align::left)
specs.align = align::numeric;
else
specs.fill = ' '; // Ignore '0' flag for non-numeric types or if '-'
// flag is also present.
if (specs.alt() && arg.visit(is_zero_int())) specs.clear_alt();
if (specs.fill_unit<Char>() == '0') {
if (is_arithmetic_type(arg.type()) && specs.align() != align::left) {
specs.set_align(align::numeric);
} else {
// Ignore '0' flag for non-numeric types or if '-' flag is also present.
specs.set_fill(' ');
}
}
// Parse length and convert the argument to the required type.
@ -511,44 +498,34 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
convert_arg<long>(arg, t);
}
break;
case 'j':
convert_arg<intmax_t>(arg, t);
break;
case 'z':
convert_arg<size_t>(arg, t);
break;
case 't':
convert_arg<std::ptrdiff_t>(arg, t);
break;
case 'j': convert_arg<intmax_t>(arg, t); break;
case 'z': convert_arg<size_t>(arg, t); break;
case 't': convert_arg<std::ptrdiff_t>(arg, t); break;
case 'L':
// printf produces garbage when 'L' is omitted for long double, no
// need to do the same.
break;
default:
--it;
convert_arg<void>(arg, c);
default: --it; convert_arg<void>(arg, c);
}
// Parse type.
if (it == end) report_error("invalid format string");
char type = static_cast<char>(*it++);
if (arg.is_integral()) {
if (is_integral_type(arg.type())) {
// Normalize type.
switch (type) {
case 'i':
case 'u':
type = 'd';
break;
case 'u': type = 'd'; break;
case 'c':
arg.visit(char_converter<basic_printf_context<Char>>(arg));
break;
}
}
bool upper = false;
specs.type = parse_printf_presentation_type(type, arg.type(), upper);
if (specs.type == presentation_type::none)
specs.set_type(parse_printf_presentation_type(type, arg.type(), upper));
if (specs.type() == presentation_type::none)
report_error("invalid format specifier");
specs.upper = upper;
if (upper) specs.set_upper();
start = it;
@ -583,7 +560,7 @@ inline auto vsprintf(basic_string_view<Char> fmt,
-> std::basic_string<Char> {
auto buf = basic_memory_buffer<Char>();
detail::vprintf(buf, fmt, args);
return to_string(buf);
return {buf.data(), buf.size()};
}
/**
@ -594,7 +571,7 @@ inline auto vsprintf(basic_string_view<Char> fmt,
*
* std::string message = fmt::sprintf("The answer is %d", 42);
*/
template <typename S, typename... T, typename Char = char_t<S>>
template <typename S, typename... T, typename Char = detail::char_t<S>>
inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string<Char> {
return vsprintf(detail::to_string_view(fmt),
fmt::make_format_args<basic_printf_context<Char>>(args...));
@ -619,7 +596,7 @@ inline auto vfprintf(std::FILE* f, basic_string_view<Char> fmt,
*
* fmt::fprintf(stderr, "Don't %s!", "panic");
*/
template <typename S, typename... T, typename Char = char_t<S>>
template <typename S, typename... T, typename Char = detail::char_t<S>>
inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int {
return vfprintf(f, detail::to_string_view(fmt),
make_printf_args<Char>(args...));

View file

@ -44,18 +44,6 @@ template <typename T> class is_set {
!std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value;
};
template <typename... Ts> struct conditional_helper {};
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
#if !FMT_MSC_VERSION || FMT_MSC_VERSION > 1800
# define FMT_DECLTYPE_RETURN(val) \
->decltype(val) { return val; } \
static_assert( \
true, "") // This makes it so that a semicolon is required after the
// macro, which helps clang-format handle the formatting.
// C array overload
template <typename T, std::size_t N>
auto range_begin(const T (&arr)[N]) -> const T* {
@ -76,9 +64,13 @@ struct has_member_fn_begin_end_t<T, void_t<decltype(*std::declval<T>().begin()),
// Member function overloads.
template <typename T>
auto range_begin(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).begin());
auto range_begin(T&& rng) -> decltype(static_cast<T&&>(rng).begin()) {
return static_cast<T&&>(rng).begin();
}
template <typename T>
auto range_end(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).end());
auto range_end(T&& rng) -> decltype(static_cast<T&&>(rng).end()) {
return static_cast<T&&>(rng).end();
}
// ADL overloads. Only participate in overload resolution if member functions
// are not found.
@ -115,17 +107,16 @@ struct has_mutable_begin_end<
// SFINAE properly unless there are distinct types
int>> : std::true_type {};
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
template <typename T>
struct is_range_<T, void>
: std::integral_constant<bool, (has_const_begin_end<T>::value ||
has_mutable_begin_end<T>::value)> {};
# undef FMT_DECLTYPE_RETURN
#endif
// tuple_size and tuple_element check.
template <typename T> class is_tuple_like_ {
template <typename U>
static auto check(U* p) -> decltype(std::tuple_size<U>::value, int());
template <typename U, typename V = typename std::remove_cv<U>::type>
static auto check(U* p) -> decltype(std::tuple_size<V>::value, 0);
template <typename> static void check(...);
public:
@ -266,12 +257,12 @@ template <range_format K>
using range_format_constant = std::integral_constant<range_format, K>;
// These are not generic lambdas for compatibility with C++11.
template <typename ParseContext> struct parse_empty_specs {
template <typename Char> struct parse_empty_specs {
template <typename Formatter> FMT_CONSTEXPR void operator()(Formatter& f) {
f.parse(ctx);
detail::maybe_set_debug_format(f, true);
}
ParseContext& ctx;
parse_context<Char>& ctx;
};
template <typename FormatContext> struct format_tuple_element {
using char_type = typename FormatContext::char_type;
@ -327,11 +318,17 @@ struct formatter<Tuple, Char,
closing_bracket_ = close;
}
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
auto it = ctx.begin();
if (it != ctx.end() && *it != '}') report_error("invalid format specifier");
detail::for_each(formatters_, detail::parse_empty_specs<ParseContext>{ctx});
auto end = ctx.end();
if (it != end && detail::to_ascii(*it) == 'n') {
++it;
set_brackets({}, {});
set_separator({});
}
if (it != end && *it != '}') report_error("invalid format specifier");
ctx.advance_to(it);
detail::for_each(formatters_, detail::parse_empty_specs<Char>{ctx});
return it;
}
@ -352,38 +349,17 @@ template <typename T, typename Char> struct is_range {
};
namespace detail {
template <typename Context> struct range_mapper {
using mapper = arg_mapper<Context>;
template <typename T,
FMT_ENABLE_IF(has_formatter<remove_cvref_t<T>, Context>::value)>
static auto map(T&& value) -> T&& {
return static_cast<T&&>(value);
}
template <typename T,
FMT_ENABLE_IF(!has_formatter<remove_cvref_t<T>, Context>::value)>
static auto map(T&& value)
-> decltype(mapper().map(static_cast<T&&>(value))) {
return mapper().map(static_cast<T&&>(value));
}
};
template <typename Char, typename Element>
using range_formatter_type =
formatter<remove_cvref_t<decltype(range_mapper<buffered_context<Char>>{}
.map(std::declval<Element>()))>,
Char>;
using range_formatter_type = formatter<remove_cvref_t<Element>, Char>;
template <typename R>
using maybe_const_range =
conditional_t<has_const_begin_end<R>::value, const R, R>;
// Workaround a bug in MSVC 2015 and earlier.
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
template <typename R, typename Char>
struct is_formattable_delayed
: is_formattable<uncvref_type<maybe_const_range<R>>, Char> {};
#endif
} // namespace detail
template <typename...> struct conjunction : std::true_type {};
@ -415,7 +391,7 @@ struct range_formatter<
auto buf = basic_memory_buffer<Char>();
for (; it != end; ++it) buf.push_back(*it);
auto specs = format_specs();
specs.type = presentation_type::debug;
specs.set_type(presentation_type::debug);
return detail::write<Char>(
out, basic_string_view<Char>(buf.data(), buf.size()), specs);
}
@ -443,8 +419,7 @@ struct range_formatter<
closing_bracket_ = close;
}
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
auto it = ctx.begin();
auto end = ctx.end();
detail::maybe_set_debug_format(underlying_, true);
@ -486,7 +461,6 @@ struct range_formatter<
template <typename R, typename FormatContext>
auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) {
auto mapper = detail::range_mapper<buffered_context<Char>>();
auto out = ctx.out();
auto it = detail::range_begin(range);
auto end = detail::range_end(range);
@ -498,7 +472,7 @@ struct range_formatter<
if (i > 0) out = detail::copy<Char>(separator_, out);
ctx.advance_to(out);
auto&& item = *it; // Need an lvalue
out = underlying_.format(mapper.map(item), ctx);
out = underlying_.format(item, ctx);
++i;
}
out = detail::copy<Char>(closing_bracket_, out);
@ -521,13 +495,8 @@ struct formatter<
range_format_kind<R, Char>::value != range_format::disabled &&
range_format_kind<R, Char>::value != range_format::map &&
range_format_kind<R, Char>::value != range_format::string &&
range_format_kind<R, Char>::value != range_format::debug_string>
// Workaround a bug in MSVC 2015 and earlier.
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
,
detail::is_formattable_delayed<R, Char>
#endif
>::value>> {
range_format_kind<R, Char>::value != range_format::debug_string>,
detail::is_formattable_delayed<R, Char>>::value>> {
private:
using range_type = detail::maybe_const_range<R>;
range_formatter<detail::uncvref_type<range_type>, Char> range_formatter_;
@ -543,8 +512,7 @@ struct formatter<
detail::string_literal<Char, '}'>{});
}
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
return range_formatter_.parse(ctx);
}
@ -559,7 +527,9 @@ struct formatter<
template <typename R, typename Char>
struct formatter<
R, Char,
enable_if_t<range_format_kind<R, Char>::value == range_format::map>> {
enable_if_t<conjunction<
bool_constant<range_format_kind<R, Char>::value == range_format::map>,
detail::is_formattable_delayed<R, Char>>::value>> {
private:
using map_type = detail::maybe_const_range<R>;
using element_type = detail::uncvref_type<map_type>;
@ -571,8 +541,7 @@ struct formatter<
public:
FMT_CONSTEXPR formatter() {}
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
auto it = ctx.begin();
auto end = ctx.end();
if (it != end) {
@ -586,7 +555,7 @@ struct formatter<
}
ctx.advance_to(it);
}
detail::for_each(formatters_, detail::parse_empty_specs<ParseContext>{ctx});
detail::for_each(formatters_, detail::parse_empty_specs<Char>{ctx});
return it;
}
@ -596,12 +565,11 @@ struct formatter<
basic_string_view<Char> open = detail::string_literal<Char, '{'>{};
if (!no_delimiters_) out = detail::copy<Char>(open, out);
int i = 0;
auto mapper = detail::range_mapper<buffered_context<Char>>();
basic_string_view<Char> sep = detail::string_literal<Char, ',', ' '>{};
for (auto&& value : map) {
if (i > 0) out = detail::copy<Char>(sep, out);
ctx.advance_to(out);
detail::for_each2(formatters_, mapper.map(value),
detail::for_each2(formatters_, value,
detail::format_tuple_element<FormatContext>{
0, ctx, detail::string_literal<Char, ':', ' '>{}});
++i;
@ -631,8 +599,7 @@ struct formatter<
formatter<string_type, Char> underlying_;
public:
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
return underlying_.parse(ctx);
}
@ -673,22 +640,22 @@ struct formatter<join_view<It, Sentinel, Char>, Char> {
#endif
formatter<remove_cvref_t<value_type>, Char> value_formatter_;
using view_ref = conditional_t<std::is_copy_constructible<It>::value,
const join_view<It, Sentinel, Char>&,
join_view<It, Sentinel, Char>&&>;
using view = conditional_t<std::is_copy_constructible<It>::value,
const join_view<It, Sentinel, Char>,
join_view<It, Sentinel, Char>>;
public:
using nonlocking = void;
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> const Char* {
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
return value_formatter_.parse(ctx);
}
template <typename FormatContext>
auto format(view_ref& value, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto it = std::forward<view_ref>(value).begin;
auto format(view& value, FormatContext& ctx) const -> decltype(ctx.out()) {
using iter =
conditional_t<std::is_copy_constructible<view>::value, It, It&>;
iter it = value.begin;
auto out = ctx.out();
if (it == value.end) return out;
out = value_formatter_.format(*it, ctx);
@ -703,39 +670,11 @@ struct formatter<join_view<It, Sentinel, Char>, Char> {
}
};
/// Returns a view that formats the iterator range `[begin, end)` with elements
/// separated by `sep`.
template <typename It, typename Sentinel>
auto join(It begin, Sentinel end, string_view sep) -> join_view<It, Sentinel> {
return {std::move(begin), end, sep};
}
/**
* Returns a view that formats `range` with elements separated by `sep`.
*
* **Example**:
*
* auto v = std::vector<int>{1, 2, 3};
* fmt::print("{}", fmt::join(v, ", "));
* // Output: 1, 2, 3
*
* `fmt::join` applies passed format specifiers to the range elements:
*
* fmt::print("{:02}", fmt::join(v, ", "));
* // Output: 01, 02, 03
*/
template <typename Range>
auto join(Range&& r, string_view sep)
-> join_view<decltype(detail::range_begin(r)),
decltype(detail::range_end(r))> {
return {detail::range_begin(r), detail::range_end(r), sep};
}
template <typename Char, typename... T> struct tuple_join_view : detail::view {
const std::tuple<T...>& tuple;
template <typename Char, typename Tuple> struct tuple_join_view : detail::view {
const Tuple& tuple;
basic_string_view<Char> sep;
tuple_join_view(const std::tuple<T...>& t, basic_string_view<Char> s)
tuple_join_view(const Tuple& t, basic_string_view<Char> s)
: tuple(t), sep{s} {}
};
@ -746,37 +685,36 @@ template <typename Char, typename... T> struct tuple_join_view : detail::view {
# define FMT_TUPLE_JOIN_SPECIFIERS 0
#endif
template <typename Char, typename... T>
struct formatter<tuple_join_view<Char, T...>, Char> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return do_parse(ctx, std::integral_constant<size_t, sizeof...(T)>());
template <typename Char, typename Tuple>
struct formatter<tuple_join_view<Char, Tuple>, Char,
enable_if_t<is_tuple_like<Tuple>::value>> {
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
return do_parse(ctx, std::tuple_size<Tuple>());
}
template <typename FormatContext>
auto format(const tuple_join_view<Char, T...>& value,
auto format(const tuple_join_view<Char, Tuple>& value,
FormatContext& ctx) const -> typename FormatContext::iterator {
return do_format(value, ctx,
std::integral_constant<size_t, sizeof...(T)>());
return do_format(value, ctx, std::tuple_size<Tuple>());
}
private:
std::tuple<formatter<typename std::decay<T>::type, Char>...> formatters_;
decltype(detail::tuple::get_formatters<Tuple, Char>(
detail::tuple_index_sequence<Tuple>())) formatters_;
template <typename ParseContext>
FMT_CONSTEXPR auto do_parse(ParseContext& ctx,
FMT_CONSTEXPR auto do_parse(parse_context<Char>& ctx,
std::integral_constant<size_t, 0>)
-> decltype(ctx.begin()) {
-> const Char* {
return ctx.begin();
}
template <typename ParseContext, size_t N>
FMT_CONSTEXPR auto do_parse(ParseContext& ctx,
template <size_t N>
FMT_CONSTEXPR auto do_parse(parse_context<Char>& ctx,
std::integral_constant<size_t, N>)
-> decltype(ctx.begin()) {
-> const Char* {
auto end = ctx.begin();
#if FMT_TUPLE_JOIN_SPECIFIERS
end = std::get<sizeof...(T) - N>(formatters_).parse(ctx);
end = std::get<std::tuple_size<Tuple>::value - N>(formatters_).parse(ctx);
if (N > 1) {
auto end1 = do_parse(ctx, std::integral_constant<size_t, N - 1>());
if (end != end1)
@ -787,18 +725,20 @@ struct formatter<tuple_join_view<Char, T...>, Char> {
}
template <typename FormatContext>
auto do_format(const tuple_join_view<Char, T...>&, FormatContext& ctx,
auto do_format(const tuple_join_view<Char, Tuple>&, FormatContext& ctx,
std::integral_constant<size_t, 0>) const ->
typename FormatContext::iterator {
return ctx.out();
}
template <typename FormatContext, size_t N>
auto do_format(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
auto do_format(const tuple_join_view<Char, Tuple>& value, FormatContext& ctx,
std::integral_constant<size_t, N>) const ->
typename FormatContext::iterator {
auto out = std::get<sizeof...(T) - N>(formatters_)
.format(std::get<sizeof...(T) - N>(value.tuple), ctx);
using std::get;
auto out =
std::get<std::tuple_size<Tuple>::value - N>(formatters_)
.format(get<std::tuple_size<Tuple>::value - N>(value.tuple), ctx);
if (N <= 1) return out;
out = detail::copy<Char>(value.sep, out);
ctx.advance_to(out);
@ -846,6 +786,34 @@ struct formatter<
FMT_BEGIN_EXPORT
/// Returns a view that formats the iterator range `[begin, end)` with elements
/// separated by `sep`.
template <typename It, typename Sentinel>
auto join(It begin, Sentinel end, string_view sep) -> join_view<It, Sentinel> {
return {std::move(begin), end, sep};
}
/**
* Returns a view that formats `range` with elements separated by `sep`.
*
* **Example**:
*
* auto v = std::vector<int>{1, 2, 3};
* fmt::print("{}", fmt::join(v, ", "));
* // Output: 1, 2, 3
*
* `fmt::join` applies passed format specifiers to the range elements:
*
* fmt::print("{:02}", fmt::join(v, ", "));
* // Output: 01, 02, 03
*/
template <typename Range, FMT_ENABLE_IF(!is_tuple_like<Range>::value)>
auto join(Range&& r, string_view sep)
-> join_view<decltype(detail::range_begin(r)),
decltype(detail::range_end(r))> {
return {detail::range_begin(r), detail::range_end(r), sep};
}
/**
* Returns an object that formats `std::tuple` with elements separated by `sep`.
*
@ -855,9 +823,9 @@ FMT_BEGIN_EXPORT
* fmt::print("{}", fmt::join(t, ", "));
* // Output: 1, a
*/
template <typename... T>
FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple, string_view sep)
-> tuple_join_view<char, T...> {
template <typename Tuple, FMT_ENABLE_IF(is_tuple_like<Tuple>::value)>
FMT_CONSTEXPR auto join(const Tuple& tuple, string_view sep)
-> tuple_join_view<char, Tuple> {
return {tuple, sep};
}

View file

@ -17,6 +17,7 @@
# include <complex>
# include <cstdlib>
# include <exception>
# include <functional>
# include <memory>
# include <thread>
# include <type_traits>
@ -26,7 +27,8 @@
// Check FMT_CPLUSPLUS to suppress a bogus warning in MSVC.
# if FMT_CPLUSPLUS >= 201703L
# if FMT_HAS_INCLUDE(<filesystem>)
# if FMT_HAS_INCLUDE(<filesystem>) && \
(!defined(FMT_CPP_LIB_FILESYSTEM) || FMT_CPP_LIB_FILESYSTEM != 0)
# include <filesystem>
# endif
# if FMT_HAS_INCLUDE(<variant>)
@ -122,14 +124,16 @@ template <typename Char> struct formatter<std::filesystem::path, Char> {
public:
FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; }
template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) {
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) {
auto it = ctx.begin(), end = ctx.end();
if (it == end) return it;
it = detail::parse_align(it, end, specs_);
if (it == end) return it;
it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx);
Char c = *it;
if ((c >= '0' && c <= '9') || c == '{')
it = detail::parse_width(it, end, specs_, width_ref_, ctx);
if (it != end && *it == '?') {
debug_ = true;
++it;
@ -145,8 +149,8 @@ template <typename Char> struct formatter<std::filesystem::path, Char> {
!path_type_ ? p.native()
: p.generic_string<std::filesystem::path::value_type>();
detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_,
ctx);
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
ctx);
if (!debug_) {
auto s = detail::get_path_string<Char>(p, path_string);
return detail::write(ctx.out(), basic_string_view<Char>(s), specs);
@ -180,7 +184,8 @@ FMT_END_NAMESPACE
FMT_BEGIN_NAMESPACE
FMT_EXPORT
template <std::size_t N, typename Char>
struct formatter<std::bitset<N>, Char> : nested_formatter<string_view> {
struct formatter<std::bitset<N>, Char>
: nested_formatter<basic_string_view<Char>, Char> {
private:
// Functor because C++11 doesn't support generic lambdas.
struct writer {
@ -200,7 +205,7 @@ struct formatter<std::bitset<N>, Char> : nested_formatter<string_view> {
template <typename FormatContext>
auto format(const std::bitset<N>& bs, FormatContext& ctx) const
-> decltype(ctx.out()) {
return write_padded(ctx, writer{bs});
return this->write_padded(ctx, writer{bs});
}
};
@ -233,7 +238,7 @@ struct formatter<std::optional<T>, Char,
FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {}
public:
template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) {
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) {
maybe_set_debug_format(underlying_, true);
return underlying_.parse(ctx);
}
@ -277,10 +282,10 @@ FMT_BEGIN_NAMESPACE
FMT_EXPORT
template <typename T, typename E, typename Char>
struct formatter<std::expected<T, E>, Char,
std::enable_if_t<is_formattable<T, Char>::value &&
std::enable_if_t<(std::is_void<T>::value ||
is_formattable<T, Char>::value) &&
is_formattable<E, Char>::value>> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
return ctx.begin();
}
@ -291,7 +296,8 @@ struct formatter<std::expected<T, E>, Char,
if (value.has_value()) {
out = detail::write<Char>(out, "expected(");
out = detail::write_escaped_alternative<Char>(out, *value);
if constexpr (!std::is_void<T>::value)
out = detail::write_escaped_alternative<Char>(out, *value);
} else {
out = detail::write<Char>(out, "unexpected(");
out = detail::write_escaped_alternative<Char>(out, value.error());
@ -307,9 +313,7 @@ FMT_END_NAMESPACE
FMT_BEGIN_NAMESPACE
FMT_EXPORT
template <> struct formatter<std::source_location> {
template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) {
return ctx.begin();
}
FMT_CONSTEXPR auto parse(parse_context<>& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const std::source_location& loc, FormatContext& ctx) const
@ -365,8 +369,7 @@ template <typename T, typename C> struct is_variant_formattable {
FMT_EXPORT
template <typename Char> struct formatter<std::monostate, Char> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
return ctx.begin();
}
@ -383,8 +386,7 @@ struct formatter<
Variant, Char,
std::enable_if_t<std::conjunction_v<
is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
return ctx.begin();
}
@ -413,20 +415,37 @@ FMT_END_NAMESPACE
FMT_BEGIN_NAMESPACE
FMT_EXPORT
template <typename Char> struct formatter<std::error_code, Char> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
template <> struct formatter<std::error_code> {
private:
format_specs specs_;
detail::arg_ref<char> width_ref_;
public:
FMT_CONSTEXPR auto parse(parse_context<>& ctx) -> const char* {
auto it = ctx.begin(), end = ctx.end();
if (it == end) return it;
it = detail::parse_align(it, end, specs_);
if (it == end) return it;
char c = *it;
if ((c >= '0' && c <= '9') || c == '{')
it = detail::parse_width(it, end, specs_, width_ref_, ctx);
return it;
}
template <typename FormatContext>
FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
out = detail::write_bytes<Char>(out, ec.category().name(), format_specs());
out = detail::write<Char>(out, Char(':'));
out = detail::write<Char>(out, ec.value());
return out;
FMT_CONSTEXPR20 auto format(const std::error_code& ec,
FormatContext& ctx) const -> decltype(ctx.out()) {
auto specs = specs_;
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
ctx);
memory_buffer buf;
buf.append(string_view(ec.category().name()));
buf.push_back(':');
detail::write<char>(appender(buf), ec.value());
return detail::write<char>(ctx.out(), string_view(buf.data(), buf.size()),
specs);
}
};
@ -506,8 +525,7 @@ template <typename Char>
struct formatter<std::type_info, Char // DEPRECATED! Mixing code unit types.
> {
public:
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
-> decltype(ctx.begin()) {
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
return ctx.begin();
}
@ -528,8 +546,7 @@ struct formatter<
bool with_typename_ = false;
public:
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
-> decltype(ctx.begin()) {
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
auto it = ctx.begin();
auto end = ctx.end();
if (it == end || *it == '}') return it;
@ -643,7 +660,7 @@ template <typename T, typename Char> struct formatter<std::complex<T>, Char> {
if (c.real() != 0) {
*out++ = Char('(');
out = detail::write<Char>(out, c.real(), specs, ctx.locale());
specs.sign = sign::plus;
specs.set_sign(sign::plus);
out = detail::write<Char>(out, c.imag(), specs, ctx.locale());
if (!detail::isfinite(c.imag())) *out++ = Char(' ');
*out++ = Char('i');
@ -657,8 +674,7 @@ template <typename T, typename Char> struct formatter<std::complex<T>, Char> {
}
public:
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
-> decltype(ctx.begin()) {
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
if (ctx.begin() == ctx.end() || *ctx.begin() == '}') return ctx.begin();
return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx,
detail::type_constant<T, Char>::value);
@ -668,12 +684,11 @@ template <typename T, typename Char> struct formatter<std::complex<T>, Char> {
auto format(const std::complex<T>& c, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto specs = specs_;
if (specs.width_ref.kind != detail::arg_id_kind::none ||
specs.precision_ref.kind != detail::arg_id_kind::none) {
detail::handle_dynamic_spec<detail::width_checker>(specs.width,
specs.width_ref, ctx);
detail::handle_dynamic_spec<detail::precision_checker>(
specs.precision, specs.precision_ref, ctx);
if (specs.dynamic()) {
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width,
specs.width_ref, ctx);
detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
specs.precision_ref, ctx);
}
if (specs.width == 0) return do_format(c, specs, ctx, ctx.out());
@ -681,12 +696,12 @@ template <typename T, typename Char> struct formatter<std::complex<T>, Char> {
auto outer_specs = format_specs();
outer_specs.width = specs.width;
outer_specs.fill = specs.fill;
outer_specs.align = specs.align;
outer_specs.copy_fill_from(specs);
outer_specs.set_align(specs.align());
specs.width = 0;
specs.fill = {};
specs.align = align::none;
specs.set_fill({});
specs.set_align(align::none);
do_format(c, specs, ctx, basic_appender<Char>(buf));
return detail::write<Char>(ctx.out(),
@ -695,5 +710,17 @@ template <typename T, typename Char> struct formatter<std::complex<T>, Char> {
}
};
FMT_EXPORT
template <typename T, typename Char>
struct formatter<std::reference_wrapper<T>, Char,
enable_if_t<is_formattable<remove_cvref_t<T>, Char>::value>>
: formatter<remove_cvref_t<T>, Char> {
template <typename FormatContext>
auto format(std::reference_wrapper<T> ref, FormatContext& ctx) const
-> decltype(ctx.out()) {
return formatter<remove_cvref_t<T>, Char>::format(ref.get(), ctx);
}
};
FMT_END_NAMESPACE
#endif // FMT_STD_H_

View file

@ -10,11 +10,12 @@
#include "color.h"
#include "format.h"
#include "ostream.h"
#include "ranges.h"
#ifndef FMT_MODULE
# include <cwchar>
# if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
# if FMT_USE_LOCALE
# include <locale>
# endif
#endif
@ -34,7 +35,8 @@ struct format_string_char<
};
template <typename S>
struct format_string_char<S, enable_if_t<is_compile_string<S>::value>> {
struct format_string_char<
S, enable_if_t<std::is_base_of<detail::compile_string, S>::value>> {
using type = typename S::char_type;
};
@ -43,7 +45,7 @@ using format_string_char_t = typename format_string_char<S>::type;
inline auto write_loc(basic_appender<wchar_t> out, loc_value value,
const format_specs& specs, locale_ref loc) -> bool {
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
#if FMT_USE_LOCALE
auto& numpunct =
std::use_facet<std::numpunct<wchar_t>>(loc.get<std::locale>());
auto separator = std::wstring();
@ -58,30 +60,64 @@ inline auto write_loc(basic_appender<wchar_t> out, loc_value value,
FMT_BEGIN_EXPORT
using wstring_view = basic_string_view<wchar_t>;
using wformat_parse_context = basic_format_parse_context<wchar_t>;
using wformat_parse_context = parse_context<wchar_t>;
using wformat_context = buffered_context<wchar_t>;
using wformat_args = basic_format_args<wformat_context>;
using wmemory_buffer = basic_memory_buffer<wchar_t>;
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
// Workaround broken conversion on older gcc.
template <typename... Args> using wformat_string = wstring_view;
inline auto runtime(wstring_view s) -> wstring_view { return s; }
#else
template <typename... Args>
using wformat_string = basic_format_string<wchar_t, type_identity_t<Args>...>;
template <typename Char, typename... T> struct basic_fstring {
private:
basic_string_view<Char> str_;
static constexpr int num_static_named_args =
detail::count_static_named_args<T...>();
using checker = detail::format_string_checker<
Char, static_cast<int>(sizeof...(T)), num_static_named_args,
num_static_named_args != detail::count_named_args<T...>()>;
using arg_pack = detail::arg_pack<T...>;
public:
using t = basic_fstring;
template <typename S,
FMT_ENABLE_IF(
std::is_convertible<const S&, basic_string_view<Char>>::value)>
FMT_CONSTEVAL FMT_ALWAYS_INLINE basic_fstring(const S& s) : str_(s) {
if (FMT_USE_CONSTEVAL)
detail::parse_format_string<Char>(s, checker(s, arg_pack()));
}
template <typename S,
FMT_ENABLE_IF(std::is_base_of<detail::compile_string, S>::value&&
std::is_same<typename S::char_type, Char>::value)>
FMT_ALWAYS_INLINE basic_fstring(const S&) : str_(S()) {
FMT_CONSTEXPR auto sv = basic_string_view<Char>(S());
FMT_CONSTEXPR int ignore =
(parse_format_string(sv, checker(sv, arg_pack())), 0);
detail::ignore_unused(ignore);
}
basic_fstring(runtime_format_string<Char> fmt) : str_(fmt.str) {}
operator basic_string_view<Char>() const { return str_; }
auto get() const -> basic_string_view<Char> { return str_; }
};
template <typename Char, typename... T>
using basic_format_string = basic_fstring<Char, T...>;
template <typename... T>
using wformat_string = typename basic_format_string<wchar_t, T...>::t;
inline auto runtime(wstring_view s) -> runtime_format_string<wchar_t> {
return {{s}};
}
#endif
template <> struct is_char<wchar_t> : std::true_type {};
template <> struct is_char<char16_t> : std::true_type {};
template <> struct is_char<char32_t> : std::true_type {};
#ifdef __cpp_char8_t
template <>
struct is_char<char8_t> : bool_constant<detail::is_utf8_enabled()> {};
template <> struct is_char<char8_t> : bool_constant<detail::is_utf8_enabled> {};
#endif
template <typename... T>
@ -90,14 +126,13 @@ constexpr auto make_wformat_args(T&... args)
return fmt::make_format_args<wformat_context>(args...);
}
#if !FMT_USE_NONTYPE_TEMPLATE_ARGS
inline namespace literals {
#if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_ARGS
constexpr auto operator""_a(const wchar_t* s, size_t)
-> detail::udl_arg<wchar_t> {
inline auto operator""_a(const wchar_t* s, size_t) -> detail::udl_arg<wchar_t> {
return {s};
}
#endif
} // namespace literals
#endif
template <typename It, typename Sentinel>
auto join(It begin, Sentinel end, wstring_view sep)
@ -105,9 +140,9 @@ auto join(It begin, Sentinel end, wstring_view sep)
return {begin, end, sep};
}
template <typename Range>
template <typename Range, FMT_ENABLE_IF(!is_tuple_like<Range>::value)>
auto join(Range&& range, wstring_view sep)
-> join_view<detail::iterator_t<Range>, detail::sentinel_t<Range>,
-> join_view<decltype(std::begin(range)), decltype(std::end(range)),
wchar_t> {
return join(std::begin(range), std::end(range), sep);
}
@ -118,19 +153,19 @@ auto join(std::initializer_list<T> list, wstring_view sep)
return join(std::begin(list), std::end(list), sep);
}
template <typename... T>
auto join(const std::tuple<T...>& tuple, basic_string_view<wchar_t> sep)
-> tuple_join_view<wchar_t, T...> {
template <typename Tuple, FMT_ENABLE_IF(is_tuple_like<Tuple>::value)>
auto join(const Tuple& tuple, basic_string_view<wchar_t> sep)
-> tuple_join_view<wchar_t, Tuple> {
return {tuple, sep};
}
template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
auto vformat(basic_string_view<Char> format_str,
auto vformat(basic_string_view<Char> fmt,
typename detail::vformat_args<Char>::type args)
-> std::basic_string<Char> {
auto buf = basic_memory_buffer<Char>();
detail::vformat_to(buf, format_str, args);
return to_string(buf);
detail::vformat_to(buf, fmt, args);
return {buf.data(), buf.size()};
}
template <typename... T>
@ -151,8 +186,8 @@ template <typename S, typename... T,
typename Char = detail::format_string_char_t<S>,
FMT_ENABLE_IF(!std::is_same<Char, char>::value &&
!std::is_same<Char, wchar_t>::value)>
auto format(const S& format_str, T&&... args) -> std::basic_string<Char> {
return vformat(detail::to_string_view(format_str),
auto format(const S& fmt, T&&... args) -> std::basic_string<Char> {
return vformat(detail::to_string_view(fmt),
fmt::make_format_args<buffered_context<Char>>(args...));
}
@ -160,31 +195,33 @@ template <typename Locale, typename S,
typename Char = detail::format_string_char_t<S>,
FMT_ENABLE_IF(detail::is_locale<Locale>::value&&
detail::is_exotic_char<Char>::value)>
inline auto vformat(const Locale& loc, const S& format_str,
inline auto vformat(const Locale& loc, const S& fmt,
typename detail::vformat_args<Char>::type args)
-> std::basic_string<Char> {
return detail::vformat(loc, detail::to_string_view(format_str), args);
auto buf = basic_memory_buffer<Char>();
detail::vformat_to(buf, detail::to_string_view(fmt), args,
detail::locale_ref(loc));
return {buf.data(), buf.size()};
}
template <typename Locale, typename S, typename... T,
typename Char = detail::format_string_char_t<S>,
FMT_ENABLE_IF(detail::is_locale<Locale>::value&&
detail::is_exotic_char<Char>::value)>
inline auto format(const Locale& loc, const S& format_str, T&&... args)
inline auto format(const Locale& loc, const S& fmt, T&&... args)
-> std::basic_string<Char> {
return detail::vformat(
loc, detail::to_string_view(format_str),
fmt::make_format_args<buffered_context<Char>>(args...));
return vformat(loc, detail::to_string_view(fmt),
fmt::make_format_args<buffered_context<Char>>(args...));
}
template <typename OutputIt, typename S,
typename Char = detail::format_string_char_t<S>,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_exotic_char<Char>::value)>
auto vformat_to(OutputIt out, const S& format_str,
auto vformat_to(OutputIt out, const S& fmt,
typename detail::vformat_args<Char>::type args) -> OutputIt {
auto&& buf = detail::get_buffer<Char>(out);
detail::vformat_to(buf, detail::to_string_view(format_str), args);
detail::vformat_to(buf, detail::to_string_view(fmt), args);
return detail::get_iterator(buf, out);
}
@ -203,37 +240,35 @@ template <typename Locale, typename S, typename OutputIt, typename... Args,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_locale<Locale>::value&&
detail::is_exotic_char<Char>::value)>
inline auto vformat_to(OutputIt out, const Locale& loc, const S& format_str,
inline auto vformat_to(OutputIt out, const Locale& loc, const S& fmt,
typename detail::vformat_args<Char>::type args)
-> OutputIt {
auto&& buf = detail::get_buffer<Char>(out);
vformat_to(buf, detail::to_string_view(format_str), args,
detail::locale_ref(loc));
vformat_to(buf, detail::to_string_view(fmt), args, detail::locale_ref(loc));
return detail::get_iterator(buf, out);
}
template <typename OutputIt, typename Locale, typename S, typename... T,
template <typename Locale, typename OutputIt, typename S, typename... T,
typename Char = detail::format_string_char_t<S>,
bool enable = detail::is_output_iterator<OutputIt, Char>::value &&
detail::is_locale<Locale>::value &&
detail::is_exotic_char<Char>::value>
inline auto format_to(OutputIt out, const Locale& loc, const S& format_str,
inline auto format_to(OutputIt out, const Locale& loc, const S& fmt,
T&&... args) ->
typename std::enable_if<enable, OutputIt>::type {
return vformat_to(out, loc, detail::to_string_view(format_str),
return vformat_to(out, loc, detail::to_string_view(fmt),
fmt::make_format_args<buffered_context<Char>>(args...));
}
template <typename OutputIt, typename Char, typename... Args,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_exotic_char<Char>::value)>
inline auto vformat_to_n(OutputIt out, size_t n,
basic_string_view<Char> format_str,
inline auto vformat_to_n(OutputIt out, size_t n, basic_string_view<Char> fmt,
typename detail::vformat_args<Char>::type args)
-> format_to_n_result<OutputIt> {
using traits = detail::fixed_buffer_traits;
auto buf = detail::iterator_buffer<OutputIt, Char, traits>(out, n);
detail::vformat_to(buf, format_str, args);
detail::vformat_to(buf, fmt, args);
return {buf.out(), buf.count()};
}
@ -291,7 +326,7 @@ inline auto vformat(const text_style& ts, wstring_view fmt, wformat_args args)
-> std::wstring {
auto buf = wmemory_buffer();
detail::vformat_to(buf, ts, fmt, args);
return fmt::to_string(buf);
return {buf.data(), buf.size()};
}
template <typename... T>
@ -312,6 +347,22 @@ FMT_DEPRECATED void print(const text_style& ts, wformat_string<T...> fmt,
return print(stdout, ts, fmt, args...);
}
inline void vprint(std::wostream& os, wstring_view fmt, wformat_args args) {
auto buffer = basic_memory_buffer<wchar_t>();
detail::vformat_to(buffer, fmt, args);
detail::write_buffer(os, buffer);
}
template <typename... T>
void print(std::wostream& os, wformat_string<T...> fmt, T&&... args) {
vprint(os, fmt, fmt::make_format_args<buffered_context<wchar_t>>(args...));
}
template <typename... T>
void println(std::wostream& os, wformat_string<T...> fmt, T&&... args) {
print(os, L"{}\n", fmt::format(fmt, std::forward<T>(args)...));
}
/// Converts `value` to `std::wstring` using the default format for type `T`.
template <typename T> inline auto to_wstring(const T& value) -> std::wstring {
return format(FMT_STRING(L"{}"), value);

View file

@ -1,5 +1,13 @@
module;
#define FMT_MODULE
#ifdef _MSVC_LANG
# define FMT_CPLUSPLUS _MSVC_LANG
#else
# define FMT_CPLUSPLUS __cplusplus
#endif
// Put all implementation-provided headers into the global module fragment
// to prevent attachment to this module.
#ifndef FMT_IMPORT_STD
@ -15,7 +23,9 @@ module;
# include <cstring>
# include <ctime>
# include <exception>
# include <expected>
# if FMT_CPLUSPLUS > 202002L
# include <expected>
# endif
# include <filesystem>
# include <fstream>
# include <functional>
@ -127,9 +137,17 @@ extern "C++" {
module :private;
#endif
#ifdef FMT_ATTACH_TO_GLOBAL_MODULE
extern "C++" {
#endif
#if FMT_HAS_INCLUDE("format.cc")
# include "format.cc"
#endif
#if FMT_OS && FMT_HAS_INCLUDE("os.cc")
# include "os.cc"
#endif
#ifdef FMT_ATTACH_TO_GLOBAL_MODULE
}
#endif

View file

@ -15,7 +15,8 @@ template FMT_API auto dragonbox::to_decimal(float x) noexcept
template FMT_API auto dragonbox::to_decimal(double x) noexcept
-> dragonbox::decimal_fp<double>;
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
#if FMT_USE_LOCALE
// DEPRECATED! locale_ref in the detail namespace
template FMT_API locale_ref::locale_ref(const std::locale& loc);
template FMT_API auto locale_ref::get<std::locale>() const -> std::locale;
#endif
@ -26,8 +27,10 @@ template FMT_API auto thousands_sep_impl(locale_ref)
-> thousands_sep_result<char>;
template FMT_API auto decimal_point_impl(locale_ref) -> char;
// DEPRECATED!
template FMT_API void buffer<char>::append(const char*, const char*);
// DEPRECATED!
template FMT_API void vformat_to(buffer<char>&, string_view,
typename vformat_args<>::type, locale_ref);

View file

@ -160,7 +160,7 @@ void detail::format_windows_error(detail::buffer<char>& out, int error_code,
}
void report_windows_error(int error_code, const char* message) noexcept {
report_error(detail::format_windows_error, error_code, message);
do_report_error(detail::format_windows_error, error_code, message);
}
#endif // _WIN32
@ -374,30 +374,25 @@ long getpagesize() {
}
# endif
namespace detail {
void file_buffer::grow(buffer<char>& buf, size_t) {
if (buf.size() == buf.capacity()) static_cast<file_buffer&>(buf).flush();
void ostream::grow(buffer<char>& buf, size_t) {
if (buf.size() == buf.capacity()) static_cast<ostream&>(buf).flush();
}
file_buffer::file_buffer(cstring_view path, const ostream_params& params)
ostream::ostream(cstring_view path, const detail::ostream_params& params)
: buffer<char>(grow), file_(path, params.oflag) {
set(new char[params.buffer_size], params.buffer_size);
}
file_buffer::file_buffer(file_buffer&& other) noexcept
ostream::ostream(ostream&& other) noexcept
: buffer<char>(grow, other.data(), other.size(), other.capacity()),
file_(std::move(other.file_)) {
other.clear();
other.set(nullptr, 0);
}
file_buffer::~file_buffer() {
ostream::~ostream() {
flush();
delete[] data();
}
} // namespace detail
ostream::~ostream() = default;
#endif // FMT_USE_FCNTL
FMT_END_NAMESPACE

View file

@ -29,3 +29,5 @@
#define ICON_EMOJI_UNLOCKED "\xf0\x9f\x94\x93"
#define ICON_EMOJI_REFRESH "\xf0\x9f\x94\x84"
#define ICON_EMOJI_PROHIBITED "\xf0\x9f\x9a\xab"
#define ICON_EMOJI_CALENDAR "\xF0\x9F\x93\x85"
#define ICON_EMOJI_HOURGLASS "\xe2\x8f\xb3"

View file

@ -10957,7 +10957,7 @@ void ImGui::SetScrollY(float scroll_y)
void ImGui::SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio)
{
IM_ASSERT(center_x_ratio >= 0.0f && center_x_ratio <= 1.0f);
window->ScrollTarget.x = IM_TRUNC(local_x - window->DecoOuterSizeX1 - window->DecoInnerSizeX1 + window->Scroll.x); // Convert local position to scroll offset
window->ScrollTarget.x = IM_TRUNC(local_x - window->DecoOuterSizeX1 - window->DecoInnerSizeX1 + window->ScrollExpected.x); // Convert local position to scroll offset
window->ScrollTargetCenterRatio.x = center_x_ratio;
window->ScrollTargetEdgeSnapDist.x = 0.0f;
}
@ -10965,7 +10965,7 @@ void ImGui::SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x
void ImGui::SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio)
{
IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f);
window->ScrollTarget.y = IM_TRUNC(local_y - window->DecoOuterSizeY1 - window->DecoInnerSizeY1 + window->Scroll.y); // Convert local position to scroll offset
window->ScrollTarget.y = IM_TRUNC(local_y - window->DecoOuterSizeY1 - window->DecoInnerSizeY1 + window->ScrollExpected.y); // Convert local position to scroll offset
window->ScrollTargetCenterRatio.y = center_y_ratio;
window->ScrollTargetEdgeSnapDist.y = 0.0f;
}
@ -12959,6 +12959,7 @@ static void ImGui::NavUpdateCreateWrappingRequest()
bb_rel.TranslateX(-bb_rel.GetWidth()); // Previous column
clip_dir = ImGuiDir_Left;
}
SetScrollY(window, window->ScrollMax.y);
do_forward = true;
}
if (g.NavMoveDir == ImGuiDir_Down && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY)))
@ -12969,6 +12970,7 @@ static void ImGui::NavUpdateCreateWrappingRequest()
bb_rel.TranslateX(+bb_rel.GetWidth()); // Next column
clip_dir = ImGuiDir_Right;
}
SetScrollY(window, 0.0f);
do_forward = true;
}
if (!do_forward)

View file

@ -225,6 +225,42 @@ RC_EXPORT int RC_CCONV rc_api_init_fetch_game_titles_request(rc_api_request_t* r
RC_EXPORT int RC_CCONV rc_api_process_fetch_game_titles_server_response(rc_api_fetch_game_titles_response_t* response, const rc_api_server_response_t* server_response);
RC_EXPORT void RC_CCONV rc_api_destroy_fetch_game_titles_response(rc_api_fetch_game_titles_response_t* response);
/* --- Fetch Game Hashes --- */
/**
* API parameters for a fetch games list request.
*/
typedef struct rc_api_fetch_hash_library_request_t {
/* The unique identifier of the console to query */
uint32_t console_id;
} rc_api_fetch_hash_library_request_t;
/* A hash library entry */
typedef struct rc_api_hash_library_entry_t {
/* The hash for the game */
const char* hash;
/* The unique identifier of the game */
uint32_t game_id;
} rc_api_hash_library_entry_t;
/**
* Response data for a fetch hash library request.
*/
typedef struct rc_api_fetch_hash_library_response_t {
/* An array of entries, one per game */
rc_api_hash_library_entry_t* entries;
/* The number of items in the entries array */
uint32_t num_entries;
/* Common server-provided response information */
rc_api_response_t response;
}
rc_api_fetch_hash_library_response_t;
RC_EXPORT int RC_CCONV rc_api_init_fetch_hash_library_request(rc_api_request_t* request, const rc_api_fetch_hash_library_request_t* api_params);
RC_EXPORT int RC_CCONV rc_api_process_fetch_hash_library_server_response(rc_api_fetch_hash_library_response_t* response, const rc_api_server_response_t* server_response);
RC_EXPORT void RC_CCONV rc_api_destroy_fetch_hash_library_response(rc_api_fetch_hash_library_response_t* response);
RC_END_C_DECLS
#endif /* RC_API_INFO_H */

View file

@ -147,6 +147,49 @@ RC_EXPORT int RC_CCONV rc_api_process_fetch_user_unlocks_response(rc_api_fetch_u
RC_EXPORT int RC_CCONV rc_api_process_fetch_user_unlocks_server_response(rc_api_fetch_user_unlocks_response_t* response, const rc_api_server_response_t* server_response);
RC_EXPORT void RC_CCONV rc_api_destroy_fetch_user_unlocks_response(rc_api_fetch_user_unlocks_response_t* response);
/* --- Fetch All Progress --- */
/**
* API parameters for a fetch all progress request.
*/
typedef struct rc_api_fetch_all_progress_request_t {
/* The username of the player */
const char* username;
/* The API token from the login request */
const char* api_token;
/* The unique identifier of the console to query */
uint32_t console_id;
} rc_api_fetch_all_progress_request_t;
/* An all-progress entry */
typedef struct rc_api_all_progress_entry_t {
/* The unique identifier of the game */
uint32_t game_id;
/* The total number of achievements for this game */
uint32_t num_achievements;
/* The total number of unlocked achievements for this game in softcore mode */
uint32_t num_unlocked_achievements;
/* The total number of unlocked achievements for this game in hardcore mode */
uint32_t num_unlocked_achievements_hardcore;
} rc_api_all_progress_entry_t;
/**
* Response data for a fetch all progress request.
*/
typedef struct rc_api_fetch_all_progress_response_t {
/* An array of entries, one per game */
rc_api_all_progress_entry_t* entries;
/* The number of items in the entries array */
uint32_t num_entries;
/* Common server-provided response information */
rc_api_response_t response;
} rc_api_fetch_all_progress_response_t;
RC_EXPORT int RC_CCONV rc_api_init_fetch_all_progress_request(rc_api_request_t* request, const rc_api_fetch_all_progress_request_t* api_params);
RC_EXPORT int RC_CCONV rc_api_process_fetch_all_progress_server_response(rc_api_fetch_all_progress_response_t* response, const rc_api_server_response_t* server_response);
RC_EXPORT void RC_CCONV rc_api_destroy_fetch_all_progress_response(rc_api_fetch_all_progress_response_t* response);
RC_END_C_DECLS
#endif /* RC_API_H */

View file

@ -141,6 +141,11 @@ RC_EXPORT void RC_CCONV rc_client_abort_async(rc_client_t* client, rc_client_asy
*/
RC_EXPORT size_t RC_CCONV rc_client_get_user_agent_clause(rc_client_t* client, char buffer[], size_t buffer_size);
/**
* Returns true if any achievement submissions have failed and are currently pending.
*/
RC_EXPORT int RC_CCONV rc_client_is_disconnected(rc_client_t* client);
/*****************************************************************************\
| Logging |
\*****************************************************************************/
@ -310,6 +315,88 @@ typedef struct rc_client_subset_t {
RC_EXPORT const rc_client_subset_t* RC_CCONV rc_client_get_subset_info(rc_client_t* client, uint32_t subset_id);
/*****************************************************************************\
| Game Info |
\*****************************************************************************/
typedef struct rc_client_hash_library_entry_t
{
/* The hash for the game */
const char* hash;
/* The unique identifier of the game */
uint32_t game_id;
} rc_client_hash_library_entry_t;
typedef struct rc_client_hash_library_t
{
/* An array of entries, one per game */
rc_client_hash_library_entry_t* entries;
/* The number of items in the entries array */
uint32_t num_entries;
} rc_client_hash_library_t;
/**
* Callback that is fired when a hash library request completes. list may be null if the query failed.
*/
typedef void(RC_CCONV* rc_client_fetch_hash_library_callback_t)(int result, const char* error_message,
rc_client_hash_library_t* list, rc_client_t* client,
void* callback_userdata);
/**
* Starts an asynchronous request for all hashes for the given console.
* This request returns a mapping from hashes to the game's unique identifier. A single game may have multiple
* hashes in the case of multi-disc games, or variants that are still compatible with the same achievement set.
*/
RC_EXPORT rc_client_async_handle_t* RC_CCONV rc_client_begin_fetch_hash_library(
rc_client_t* client, uint32_t console_id, rc_client_fetch_hash_library_callback_t callback, void* callback_userdata);
/**
* Destroys a previously-allocated result from the rc_client_destroy_hash_library() callback.
*/
RC_EXPORT void RC_CCONV rc_client_destroy_hash_library(rc_client_hash_library_t* list);
typedef struct rc_client_all_progress_list_entry_t
{
/* The unique identifier of the game */
uint32_t game_id;
/* The total number of achievements for this game */
uint32_t num_achievements;
/* The total number of unlocked achievements for this game in softcore mode */
uint32_t num_unlocked_achievements;
/* The total number of unlocked achievements for this game in hardcore mode */
uint32_t num_unlocked_achievements_hardcore;
} rc_client_all_progress_list_entry_t;
typedef struct rc_client_all_progress_list_t
{
/* An array of entries, one per game */
rc_client_all_progress_list_entry_t* entries;
/* The number of items in the entries array */
uint32_t num_entries;
} rc_client_all_progress_list_t;
/**
* Callback that is fired when an all progress query completes. list may be null if the query failed.
*/
typedef void(RC_CCONV* rc_client_fetch_all_progress_list_callback_t)(int result, const char* error_message,
rc_client_all_progress_list_t* list,
rc_client_t* client, void* callback_userdata);
/**
* Starts an asynchronous request for all progress for the given console.
* This query returns the total number of achievements for all games tracked by this console, as well as
* the user's achievement unlock count for both softcore and hardcore modes.
*/
RC_EXPORT rc_client_async_handle_t* RC_CCONV
rc_client_begin_fetch_all_progress_list(rc_client_t* client, uint32_t console_id,
rc_client_fetch_all_progress_list_callback_t callback, void* callback_userdata);
/**
* Destroys a previously-allocated result from the rc_client_begin_fetch_all_progress_list() callback.
*/
RC_EXPORT void RC_CCONV rc_client_destroy_all_progress_list(rc_client_all_progress_list_t* list);
/*****************************************************************************\
| Achievements |
\*****************************************************************************/
@ -421,6 +508,11 @@ RC_EXPORT void RC_CCONV rc_client_destroy_achievement_list(rc_client_achievement
*/
RC_EXPORT int RC_CCONV rc_client_has_achievements(rc_client_t* client);
/**
* Returns the number of outstanding achievement unlocks.
*/
RC_EXPORT int RC_CCONV rc_client_get_award_achievement_pending_count(rc_client_t* client);
/*****************************************************************************\
| Leaderboards |
\*****************************************************************************/
@ -504,7 +596,7 @@ RC_EXPORT void RC_CCONV rc_client_destroy_leaderboard_list(rc_client_leaderboard
/**
* Returns non-zero if the current game has any leaderboards.
*/
RC_EXPORT int RC_CCONV rc_client_has_leaderboards(rc_client_t* client);
RC_EXPORT int RC_CCONV rc_client_has_leaderboards(rc_client_t* client, int include_hidden);
typedef struct rc_client_leaderboard_entry_t {
const char* user;

View file

@ -1,6 +1,7 @@
#include "rc_api_info.h"
#include "rc_api_common.h"
#include "rc_consoles.h"
#include "rc_runtime_types.h"
#include "../rc_compat.h"
@ -464,3 +465,87 @@ int rc_api_process_fetch_game_titles_server_response(rc_api_fetch_game_titles_re
void rc_api_destroy_fetch_game_titles_response(rc_api_fetch_game_titles_response_t* response) {
rc_buffer_destroy(&response->response.buffer);
}
/* --- Fetch Game Hashes --- */
int rc_api_init_fetch_hash_library_request(rc_api_request_t* request,
const rc_api_fetch_hash_library_request_t* api_params)
{
rc_api_url_builder_t builder;
rc_api_url_build_dorequest_url(request);
if (api_params->console_id == RC_CONSOLE_UNKNOWN)
return RC_INVALID_STATE;
rc_url_builder_init(&builder, &request->buffer, 48);
rc_url_builder_append_str_param(&builder, "r", "hashlibrary");
rc_url_builder_append_unum_param(&builder, "c", api_params->console_id);
request->post_data = rc_url_builder_finalize(&builder);
request->content_type = RC_CONTENT_TYPE_URLENCODED;
return builder.result;
}
int rc_api_process_fetch_hash_library_server_response(rc_api_fetch_hash_library_response_t* response,
const rc_api_server_response_t* server_response)
{
rc_api_hash_library_entry_t* entry;
rc_json_iterator_t iterator;
rc_json_field_t field;
int result;
char* end;
rc_json_field_t fields[] = {
RC_JSON_NEW_FIELD("Success"),
RC_JSON_NEW_FIELD("Error"),
RC_JSON_NEW_FIELD("MD5List"),
};
memset(response, 0, sizeof(*response));
rc_buffer_init(&response->response.buffer);
result =
rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
if (result != RC_OK)
return result;
if (!fields[2].value_start)
{
/* call rc_json_get_required_object to generate the error message */
rc_json_get_required_object(NULL, 0, &response->response, &fields[2], "MD5List");
return RC_MISSING_VALUE;
}
response->num_entries = fields[2].array_size;
rc_buffer_reserve(&response->response.buffer, response->num_entries * (32 + sizeof(rc_api_hash_library_entry_t)));
response->entries = (rc_api_hash_library_entry_t*)rc_buffer_alloc(
&response->response.buffer, response->num_entries * sizeof(rc_api_hash_library_entry_t));
if (!response->entries)
return RC_OUT_OF_MEMORY;
memset(&iterator, 0, sizeof(iterator));
iterator.json = fields[2].value_start;
iterator.end = fields[2].value_end;
entry = response->entries;
while (rc_json_get_next_object_field(&iterator, &field))
{
/* TODO: This isn't handling escape characters in the key, the RC JSON parsing functions have no method for it. */
entry->hash = rc_buffer_strncpy(&response->response.buffer, field.name, field.name_len);
field.name = "";
if (!rc_json_get_unum(&entry->game_id, &field, ""))
return RC_MISSING_VALUE;
++entry;
}
return RC_OK;
}
void rc_api_destroy_fetch_hash_library_response(rc_api_fetch_hash_library_response_t* response)
{
rc_buffer_destroy(&response->response.buffer);
}

View file

@ -1,8 +1,10 @@
#include "rc_api_user.h"
#include "rc_api_common.h"
#include "rc_consoles.h"
#include "../rc_version.h"
#include <stdlib.h>
#include <string.h>
/* --- Login --- */
@ -252,3 +254,101 @@ int rc_api_process_fetch_user_unlocks_server_response(rc_api_fetch_user_unlocks_
void rc_api_destroy_fetch_user_unlocks_response(rc_api_fetch_user_unlocks_response_t* response) {
rc_buffer_destroy(&response->response.buffer);
}
/* --- Fetch All Progress --- */
int rc_api_init_fetch_all_progress_request(rc_api_request_t* request,
const rc_api_fetch_all_progress_request_t* api_params)
{
rc_api_url_builder_t builder;
rc_api_url_build_dorequest_url(request);
if (api_params->console_id == RC_CONSOLE_UNKNOWN)
return RC_INVALID_STATE;
rc_url_builder_init(&builder, &request->buffer, 48);
if (rc_api_url_build_dorequest(&builder, "allprogress", api_params->username, api_params->api_token))
{
rc_url_builder_append_unum_param(&builder, "c", api_params->console_id);
request->post_data = rc_url_builder_finalize(&builder);
request->content_type = RC_CONTENT_TYPE_URLENCODED;
}
return builder.result;
}
int rc_api_process_fetch_all_progress_server_response(rc_api_fetch_all_progress_response_t* response,
const rc_api_server_response_t* server_response)
{
rc_api_all_progress_entry_t* entry;
rc_json_iterator_t iterator;
rc_json_field_t field;
int result;
char* end;
rc_json_field_t fields[] = {
RC_JSON_NEW_FIELD("Success"),
RC_JSON_NEW_FIELD("Error"),
RC_JSON_NEW_FIELD("Response"),
};
rc_json_field_t entry_fields[] = {
RC_JSON_NEW_FIELD("Achievements"),
RC_JSON_NEW_FIELD("Unlocked"),
RC_JSON_NEW_FIELD("UnlockedHardcore"),
};
memset(response, 0, sizeof(*response));
rc_buffer_init(&response->response.buffer);
result =
rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
if (result != RC_OK)
return result;
if (!fields[2].value_start)
{
/* call rc_json_get_required_object to generate the error message */
rc_json_get_required_object(NULL, 0, &response->response, &fields[2], "Response");
return RC_MISSING_VALUE;
}
response->num_entries = fields[2].array_size;
rc_buffer_reserve(&response->response.buffer, response->num_entries * sizeof(rc_api_all_progress_entry_t));
response->entries = (rc_api_all_progress_entry_t*)rc_buffer_alloc(
&response->response.buffer, response->num_entries * sizeof(rc_api_all_progress_entry_t));
if (!response->entries)
return RC_OUT_OF_MEMORY;
memset(&iterator, 0, sizeof(iterator));
iterator.json = fields[2].value_start;
iterator.end = fields[2].value_end;
entry = response->entries;
while (rc_json_get_next_object_field(&iterator, &field))
{
entry->game_id = strtol(field.name, &end, 10);
field.name = "";
if (!rc_json_get_required_object(entry_fields, sizeof(entry_fields) / sizeof(entry_fields[0]), response, &field,
""))
{
return RC_MISSING_VALUE;
}
rc_json_get_optional_unum(&entry->num_achievements, &entry_fields[0], "Achievements", 0);
rc_json_get_optional_unum(&entry->num_unlocked_achievements, &entry_fields[1], "Unlocked", 0);
rc_json_get_optional_unum(&entry->num_unlocked_achievements_hardcore, &entry_fields[2], "UnlockedHardcore", 0);
++entry;
}
return RC_OK;
}
void rc_api_destroy_fetch_all_progress_response(rc_api_fetch_all_progress_response_t* response)
{
rc_buffer_destroy(&response->response.buffer);
}

View file

@ -3209,6 +3209,272 @@ const rc_client_subset_t* rc_client_get_subset_info(rc_client_t* client, uint32_
return NULL;
}
/* ===== Game Info ===== */
typedef struct rc_client_fetch_hash_library_callback_data_t
{
rc_client_t* client;
rc_client_fetch_hash_library_callback_t callback;
void* callback_userdata;
uint32_t console_id;
rc_client_async_handle_t async_handle;
} rc_client_fetch_hash_library_callback_data_t;
static void rc_client_fetch_hash_library_callback(const rc_api_server_response_t* server_response, void* callback_data)
{
rc_client_fetch_hash_library_callback_data_t* hashlib_callback_data =
(rc_client_fetch_hash_library_callback_data_t*)callback_data;
rc_client_t* client = hashlib_callback_data->client;
rc_api_fetch_hash_library_response_t hashlib_response;
const char* error_message;
int result;
result = rc_client_end_async(client, &hashlib_callback_data->async_handle);
if (result)
{
if (result != RC_CLIENT_ASYNC_DESTROYED)
RC_CLIENT_LOG_VERBOSE(client, "Fetch hash library aborted");
free(hashlib_callback_data);
return;
}
result = rc_api_process_fetch_hash_library_server_response(&hashlib_response, server_response);
error_message =
rc_client_server_error_message(&result, server_response->http_status_code, &hashlib_response.response);
if (error_message)
{
RC_CLIENT_LOG_ERR_FORMATTED(client, "Fetch hash library for console %u failed: %s",
hashlib_callback_data->console_id, error_message);
hashlib_callback_data->callback(result, error_message, NULL, client, hashlib_callback_data->callback_userdata);
}
else
{
rc_client_hash_library_t* list;
const size_t list_size = sizeof(*list) + sizeof(rc_client_leaderboard_entry_t) * hashlib_response.num_entries;
size_t needed_size = list_size;
uint32_t i;
for (i = 0; i < hashlib_response.num_entries; i++)
needed_size += strlen(hashlib_response.entries[i].hash) + 1;
list = (rc_client_hash_library_t*)malloc(needed_size);
if (!list)
{
hashlib_callback_data->callback(RC_OUT_OF_MEMORY, rc_error_str(RC_OUT_OF_MEMORY), NULL, client,
hashlib_callback_data->callback_userdata);
}
else
{
rc_client_hash_library_entry_t* entry = list->entries =
(rc_client_hash_library_entry_t*)((uint8_t*)list + sizeof(*list));
char* hash = (char*)((uint8_t*)list + list_size);
const rc_api_hash_library_entry_t* hlentry = hashlib_response.entries;
const rc_api_hash_library_entry_t* stop = hlentry + hashlib_response.num_entries;
for (; hlentry < stop; ++hlentry, ++entry)
{
const size_t len = strlen(hlentry->hash) + 1;
entry->hash = hash;
entry->game_id = hlentry->game_id;
memcpy(hash, hlentry->hash, len);
hash += len;
}
list->num_entries = hashlib_response.num_entries;
hashlib_callback_data->callback(RC_OK, NULL, list, client, hashlib_callback_data->callback_userdata);
}
}
rc_api_destroy_fetch_hash_library_response(&hashlib_response);
free(hashlib_callback_data);
}
rc_client_async_handle_t* rc_client_begin_fetch_hash_library(rc_client_t* client, uint32_t console_id,
rc_client_fetch_hash_library_callback_t callback,
void* callback_userdata)
{
rc_api_fetch_hash_library_request_t api_params;
rc_client_fetch_hash_library_callback_data_t* callback_data;
rc_client_async_handle_t* async_handle;
rc_api_request_t request;
int result;
const char* error_message;
if (!client)
{
callback(RC_INVALID_STATE, "client is required", NULL, client, callback_userdata);
return NULL;
}
api_params.console_id = console_id;
result = rc_api_init_fetch_hash_library_request(&request, &api_params);
if (result != RC_OK)
{
error_message = rc_error_str(result);
callback(result, error_message, NULL, client, callback_userdata);
return NULL;
}
callback_data = (rc_client_fetch_hash_library_callback_data_t*)calloc(1, sizeof(*callback_data));
if (!callback_data)
{
callback(RC_OUT_OF_MEMORY, rc_error_str(RC_OUT_OF_MEMORY), NULL, client, callback_userdata);
return NULL;
}
callback_data->client = client;
callback_data->callback = callback;
callback_data->callback_userdata = callback_userdata;
callback_data->console_id = console_id;
async_handle = &callback_data->async_handle;
rc_client_begin_async(client, async_handle);
client->callbacks.server_call(&request, rc_client_fetch_hash_library_callback, callback_data, client);
rc_api_destroy_request(&request);
return rc_client_async_handle_valid(client, async_handle) ? async_handle : NULL;
}
void rc_client_destroy_hash_library(rc_client_hash_library_t* list)
{
free(list);
}
typedef struct rc_client_fetch_all_progress_callback_data_t
{
rc_client_t* client;
rc_client_fetch_all_progress_list_callback_t callback;
void* callback_userdata;
uint32_t console_id;
rc_client_async_handle_t async_handle;
} rc_client_fetch_all_progress_callback_data_t;
static void rc_client_fetch_all_progress_callback(const rc_api_server_response_t* server_response, void* callback_data)
{
rc_client_fetch_all_progress_callback_data_t* ap_callback_data =
(rc_client_fetch_all_progress_callback_data_t*)callback_data;
rc_client_t* client = ap_callback_data->client;
rc_api_fetch_all_progress_response_t ap_response;
const char* error_message;
int result;
result = rc_client_end_async(client, &ap_callback_data->async_handle);
if (result)
{
if (result != RC_CLIENT_ASYNC_DESTROYED)
RC_CLIENT_LOG_VERBOSE(client, "Fetch all progress aborted");
free(ap_callback_data);
return;
}
result = rc_api_process_fetch_all_progress_server_response(&ap_response, server_response);
error_message = rc_client_server_error_message(&result, server_response->http_status_code, &ap_response.response);
if (error_message)
{
RC_CLIENT_LOG_ERR_FORMATTED(client, "Fetch all progress for console %u failed: %s", ap_callback_data->console_id,
error_message);
ap_callback_data->callback(result, error_message, NULL, client, ap_callback_data->callback_userdata);
}
else
{
rc_client_all_progress_list_t* list;
const size_t list_size = sizeof(*list) + sizeof(rc_client_all_progress_list_entry_t) * ap_response.num_entries;
list = (rc_client_all_progress_list_t*)malloc(list_size);
if (!list)
{
ap_callback_data->callback(RC_OUT_OF_MEMORY, rc_error_str(RC_OUT_OF_MEMORY), NULL, client,
ap_callback_data->callback_userdata);
}
else
{
rc_client_all_progress_list_entry_t* entry = list->entries =
(rc_client_all_progress_list_entry_t*)((uint8_t*)list + sizeof(*list));
const rc_api_all_progress_entry_t* hlentry = ap_response.entries;
const rc_api_all_progress_entry_t* stop = hlentry + ap_response.num_entries;
for (; hlentry < stop; ++hlentry, ++entry)
{
entry->game_id = hlentry->game_id;
entry->num_achievements = hlentry->num_achievements;
entry->num_unlocked_achievements = hlentry->num_unlocked_achievements;
entry->num_unlocked_achievements_hardcore = hlentry->num_unlocked_achievements_hardcore;
}
list->num_entries = ap_response.num_entries;
ap_callback_data->callback(RC_OK, NULL, list, client, ap_callback_data->callback_userdata);
}
}
rc_api_destroy_fetch_all_progress_response(&ap_response);
free(ap_callback_data);
}
rc_client_async_handle_t* rc_client_begin_fetch_all_progress_list(rc_client_t* client, uint32_t console_id,
rc_client_fetch_all_progress_list_callback_t callback,
void* callback_userdata)
{
rc_api_fetch_all_progress_request_t api_params;
rc_client_fetch_all_progress_callback_data_t* callback_data;
rc_client_async_handle_t* async_handle;
rc_api_request_t request;
int result;
const char* error_message;
if (!client)
{
callback(RC_INVALID_STATE, "client is required", NULL, client, callback_userdata);
return NULL;
}
else if (client->state.user != RC_CLIENT_USER_STATE_LOGGED_IN)
{
callback(RC_INVALID_STATE, "client must be logged in", NULL, client, callback_userdata);
return NULL;
}
api_params.username = client->user.username;
api_params.api_token = client->user.token;
api_params.console_id = console_id;
result = rc_api_init_fetch_all_progress_request(&request, &api_params);
if (result != RC_OK)
{
error_message = rc_error_str(result);
callback(result, error_message, NULL, client, callback_userdata);
return NULL;
}
callback_data = (rc_client_fetch_all_progress_callback_data_t*)calloc(1, sizeof(*callback_data));
if (!callback_data)
{
callback(RC_OUT_OF_MEMORY, rc_error_str(RC_OUT_OF_MEMORY), NULL, client, callback_userdata);
return NULL;
}
callback_data->client = client;
callback_data->callback = callback;
callback_data->callback_userdata = callback_userdata;
callback_data->console_id = console_id;
async_handle = &callback_data->async_handle;
rc_client_begin_async(client, async_handle);
client->callbacks.server_call(&request, rc_client_fetch_all_progress_callback, callback_data, client);
rc_api_destroy_request(&request);
return rc_client_async_handle_valid(client, async_handle) ? async_handle : NULL;
}
void rc_client_destroy_all_progress_list(rc_client_all_progress_list_t* list)
{
free(list);
}
/* ===== Achievements ===== */
static void rc_client_update_achievement_display_information(rc_client_t* client, rc_client_achievement_info_t* achievement, time_t recent_unlock_time)
@ -3675,6 +3941,20 @@ static int rc_client_is_award_achievement_pending(const rc_client_t* client, uin
return 0;
}
int rc_client_get_award_achievement_pending_count(rc_client_t* client)
{
/* assume lock already held */
int count = 0;
rc_client_scheduled_callback_data_t* scheduled_callback = client->state.scheduled_callbacks;
for (; scheduled_callback; scheduled_callback = scheduled_callback->next)
{
if (scheduled_callback->callback == rc_client_award_achievement_retry)
count++;
}
return count;
}
static void rc_client_award_achievement_server_call(rc_client_award_achievement_callback_data_t* ach_data);
static void rc_client_award_achievement_retry(rc_client_scheduled_callback_data_t* callback_data, rc_client_t* client, rc_clock_t now)
@ -4185,10 +4465,10 @@ void rc_client_destroy_leaderboard_list(rc_client_leaderboard_list_t* list)
free(list);
}
int rc_client_has_leaderboards(rc_client_t* client)
int rc_client_has_leaderboards(rc_client_t* client, int include_hidden)
{
rc_client_subset_info_t* subset;
int result;
int i, result;
if (!client)
return 0;
@ -4211,8 +4491,20 @@ int rc_client_has_leaderboards(rc_client_t* client)
continue;
if (subset->public_.num_leaderboards > 0) {
result = 1;
break;
if (!include_hidden) {
for (i = 0; i < subset->public_.num_leaderboards; i++) {
if (subset->leaderboards[i].hidden)
continue;
result = 1;
break;
}
if (result)
break;
} else {
result = 1;
break;
}
}
}
@ -6145,3 +6437,8 @@ size_t rc_client_get_user_agent_clause(rc_client_t* client, char buffer[], size_
buffer[buffer_size - 1] = '\0';
return result;
}
int rc_client_is_disconnected(rc_client_t* client)
{
return (client && (client->state.disconnect & (RC_CLIENT_DISCONNECT_VISIBLE | RC_CLIENT_DISCONNECT_SHOW_PENDING) != 0));
}

View file

@ -465,6 +465,17 @@ int rc_operand_type_is_memref(uint8_t type) {
}
}
int rc_operand_type_is_transform(uint8_t type) {
switch (type) {
case RC_OPERAND_BCD:
case RC_OPERAND_INVERTED:
return 1;
default:
return 0;
}
}
int rc_operand_is_memref(const rc_operand_t* self) {
return rc_operand_type_is_memref(self->type);
}
@ -603,9 +614,15 @@ void rc_operand_addsource(rc_operand_t* self, rc_parse_state_t* parse, uint8_t n
self->value.memref = (rc_memref_t*)modified_memref;
/* if adding a constant, change the type to be address (current value) */
if (!rc_operand_is_memref(self))
if (!rc_operand_is_memref(self)) {
/* if adding a constant, change the type to be address (current value) */
self->type = self->memref_access_type = RC_OPERAND_ADDRESS;
}
else if (rc_operand_type_is_transform(self->type)) {
/* transform is applied in the modified_memref. change the type to be
* address (current value) to avoid applying the transform again */
self->type = self->memref_access_type = RC_OPERAND_ADDRESS;
}
/* result of an AddSource operation is always a 32-bit integer (even if parent or modifier is a float) */
self->size = RC_MEMSIZE_32_BITS;

View file

@ -352,6 +352,7 @@ int rc_operand_is_float_memref(const rc_operand_t* self);
int rc_operand_is_float(const rc_operand_t* self);
int rc_operand_is_recall(const rc_operand_t* self);
int rc_operand_type_is_memref(uint8_t type);
int rc_operand_type_is_transform(uint8_t type);
int rc_operands_are_equal(const rc_operand_t* left, const rc_operand_t* right);
void rc_operand_addsource(rc_operand_t* self, rc_parse_state_t* parse, uint8_t new_size);
void rc_operand_set_const(rc_operand_t* self, uint32_t value);

View file

@ -55,6 +55,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reshadefx", "dep\reshadefx\
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rapidyaml", "dep\rapidyaml\rapidyaml.vcxproj", "{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "duckstation-mini", "src\duckstation-mini\duckstation-mini.vcxproj", "{FA259BC0-1007-4FD9-8A47-87CC0ECB8445}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
@ -967,6 +969,28 @@ Global
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.ReleaseLTCG-Clang-SSE2|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.ReleaseLTCG-Clang-SSE2|x64.ActiveCfg = ReleaseLTCG-Clang-SSE2|x64
{1AD23A8A-4C20-434C-AE6B-0E07759EEB1E}.ReleaseLTCG-Clang-SSE2|x64.Build.0 = ReleaseLTCG-Clang-SSE2|x64
{FA259BC0-1007-4FD9-8A47-87CC0ECB8445}.Debug|ARM64.ActiveCfg = Debug-Clang|ARM64
{FA259BC0-1007-4FD9-8A47-87CC0ECB8445}.Debug|x64.ActiveCfg = Debug|x64
{FA259BC0-1007-4FD9-8A47-87CC0ECB8445}.Debug-Clang|ARM64.ActiveCfg = Debug-Clang|ARM64
{FA259BC0-1007-4FD9-8A47-87CC0ECB8445}.Debug-Clang|x64.ActiveCfg = Debug-Clang|x64
{FA259BC0-1007-4FD9-8A47-87CC0ECB8445}.Debug-Clang-SSE2|ARM64.ActiveCfg = Debug-Clang|ARM64
{FA259BC0-1007-4FD9-8A47-87CC0ECB8445}.Debug-Clang-SSE2|x64.ActiveCfg = Debug-Clang-SSE2|x64
{FA259BC0-1007-4FD9-8A47-87CC0ECB8445}.DebugFast|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{FA259BC0-1007-4FD9-8A47-87CC0ECB8445}.DebugFast|x64.ActiveCfg = DebugFast|x64
{FA259BC0-1007-4FD9-8A47-87CC0ECB8445}.DebugFast-Clang|ARM64.ActiveCfg = DebugFast-Clang|ARM64
{FA259BC0-1007-4FD9-8A47-87CC0ECB8445}.DebugFast-Clang|x64.ActiveCfg = DebugFast-Clang|x64
{FA259BC0-1007-4FD9-8A47-87CC0ECB8445}.Devel-Clang|ARM64.ActiveCfg = Devel-Clang|ARM64
{FA259BC0-1007-4FD9-8A47-87CC0ECB8445}.Devel-Clang|x64.ActiveCfg = Devel-Clang|x64
{FA259BC0-1007-4FD9-8A47-87CC0ECB8445}.Release|ARM64.ActiveCfg = Release-Clang|ARM64
{FA259BC0-1007-4FD9-8A47-87CC0ECB8445}.Release|x64.ActiveCfg = Release|x64
{FA259BC0-1007-4FD9-8A47-87CC0ECB8445}.Release-Clang|ARM64.ActiveCfg = Release-Clang|ARM64
{FA259BC0-1007-4FD9-8A47-87CC0ECB8445}.Release-Clang|x64.ActiveCfg = Release-Clang|x64
{FA259BC0-1007-4FD9-8A47-87CC0ECB8445}.ReleaseLTCG|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{FA259BC0-1007-4FD9-8A47-87CC0ECB8445}.ReleaseLTCG|x64.ActiveCfg = ReleaseLTCG|x64
{FA259BC0-1007-4FD9-8A47-87CC0ECB8445}.ReleaseLTCG-Clang|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{FA259BC0-1007-4FD9-8A47-87CC0ECB8445}.ReleaseLTCG-Clang|x64.ActiveCfg = ReleaseLTCG-Clang|x64
{FA259BC0-1007-4FD9-8A47-87CC0ECB8445}.ReleaseLTCG-Clang-SSE2|ARM64.ActiveCfg = ReleaseLTCG-Clang|ARM64
{FA259BC0-1007-4FD9-8A47-87CC0ECB8445}.ReleaseLTCG-Clang-SSE2|x64.ActiveCfg = ReleaseLTCG-Clang-SSE2|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View file

@ -336,7 +336,8 @@ def check_regression_test(baselinedir, testdir, name):
def check_regression_tests(baselinedir, testdir):
gamedirs = glob.glob(baselinedir + "/*", recursive=False)
gamedirs.sort(key=lambda x: os.path.basename(x))
success = 0
failure = 0

View file

@ -1,12 +1,12 @@
#!/usr/bin/env bash
# SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
# SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
# SPDX-License-Identifier: CC-BY-NC-ND-4.0
set -e
if [ "$#" -lt 4 ]; then
echo "Syntax: $0 [-system-freetype] [-system-harfbuzz] [-system-libjpeg] [-system-libpng] [-system-libwebp] [-system-libzip] [-system-zstd] [-system-qt] [-skip-download] [-skip-cleanup] [-only-download] <host directory> <cross architecture> <cross chroot> <output directory>"
echo "Syntax: $0 [-system-freetype] [-system-harfbuzz] [-system-libjpeg] [-system-libpng] [-system-libwebp] [-system-libzip] [-system-zlib] [-system-zstd] [-system-qt] [-skip-download] [-skip-cleanup] [-only-download] <host directory> <cross architecture> <cross chroot> <output directory>"
exit 1
fi
@ -35,6 +35,10 @@ for arg in "$@"; do
echo "Skipping building libzip."
SKIP_LIBZIP=true
shift
elif [ "$arg" == "-system-zlib" ]; then
echo "Skipping building zlib-ng."
SKIP_ZLIBNG=true
shift
elif [ "$arg" == "-system-zstd" ]; then
echo "Skipping building zstd."
SKIP_ZSTD=true
@ -81,34 +85,49 @@ CMAKE_COMMON=(
-DCMAKE_INSTALL_PREFIX="$INSTALLDIR"
)
# Determine architecture.
if [ "$CROSSARCH" == "arm64" ]; then
CROSSSYSARCH="aarch64"
CROSSTRIPLET="aarch64-linux-gnu"
CMAKEPROCESSOR="aarch64"
elif [ "$CROSSARCH" == "armhf" ]; then
CROSSSYSARCH="armhf"
CROSSTRIPLET="arm-linux-gnueabihf"
CMAKEPROCESSOR="armv7-a"
else
echo "Unknown cross arch $CROSSARCH"
exit 1
fi
# TODO: Pull all of this from the main file.
FREETYPE=2.13.3
HARFBUZZ=10.1.0
HARFBUZZ=10.2.0
LIBBACKTRACE=86885d14049fab06ef8a33aac51664230ca09200
LIBJPEGTURBO=3.0.4
LIBPNG=1.6.44
LIBWEBP=1.4.0
LIBZIP=1.11.2
SDL2=2.30.11
QT=6.8.1
LIBJPEGTURBO=3.1.0
LIBPNG=1.6.45
LIBWEBP=1.5.0
LIBZIP=1.11.3
SDL3=3.2.8
QT=6.8.2
ZLIBNG=2.2.4
ZSTD=1.5.6
CPUINFO=7524ad504fdcfcf75a18a133da6abd75c5d48053
DISCORD_RPC=144f3a3f1209994d8d9e8a87964a989cb9911c1e
LUNASVG=9af1ac7b90658a279b372add52d6f77a4ebb482c
SHADERC=1c0d3d18819aa75ec74f1fbd9ff0461e1b69a4d6
CPUINFO=3ebbfd45645650c4940bf0f3b4d25ab913466bb0
DISCORD_RPC=cc59d26d1d628fbd6527aac0ac1d6301f4978b92
LUNASVG=4a1c98ccb1da8a5a92ddc4f97339869b1ae556f4
SHADERC=fc65b19d2098cf81e55b4edc10adad2ad8268361
SOUNDTOUCH=463ade388f3a51da078dc9ed062bf28e4ba29da7
SPIRV_CROSS=vulkan-sdk-1.3.290.0
SPIRV_CROSS=vulkan-sdk-1.4.304.0
mkdir -p "${INSTALLDIR}"
mkdir -p deps-build
cd deps-build
if [ "$SKIP_DOWNLOAD" != true ]; then
if [[ "$SKIP_DOWNLOAD" != true && ! -f "libbacktrace-$LIBBACKTRACE.tar.gz" ]]; then
curl -C - -L \
-O "https://github.com/ianlancetaylor/libbacktrace/archive/$LIBBACKTRACE.tar.gz" \
-O "https://github.com/libsdl-org/SDL/releases/download/release-$SDL2/SDL2-$SDL2.tar.gz" \
-o "libbacktrace-$LIBBACKTRACE.tar.gz" "https://github.com/ianlancetaylor/libbacktrace/archive/$LIBBACKTRACE.tar.gz" \
-O "https://github.com/libsdl-org/SDL/releases/download/release-$SDL3/SDL3-$SDL3.tar.gz" \
-o "cpuinfo-$CPUINFO.tar.gz" "https://github.com/stenzek/cpuinfo/archive/$CPUINFO.tar.gz" \
-o "discord-rpc-$DISCORD_RPC.tar.gz" "https://github.com/stenzek/discord-rpc/archive/$DISCORD_RPC.tar.gz" \
-o "lunasvg-$LUNASVG.tar.gz" "https://github.com/stenzek/lunasvg/archive/$LUNASVG.tar.gz" \
@ -117,17 +136,17 @@ if [ "$SKIP_DOWNLOAD" != true ]; then
fi
cat > SHASUMS <<EOF
baf8aebd22002b762d803ba0e1e389b6b4415159334e9d34bba1a938f6de8ce6 $LIBBACKTRACE.tar.gz
8b8d4aef2038533da814965220f88f77d60dfa0f32685f80ead65e501337da7f SDL2-$SDL2.tar.gz
e1351218d270db49c3dddcba04fb2153b09731ea3fa6830e423f5952f44585be cpuinfo-$CPUINFO.tar.gz
3eea5ccce6670c126282f1ba4d32c19d486db49a1a5cbfb8d6f48774784d310c discord-rpc-$DISCORD_RPC.tar.gz
3998b024b0d442614a9ee270e76e018bb37a17b8c6941212171731123cbbcac7 lunasvg-$LUNASVG.tar.gz
3826d86f8a13564be1c047ac105041a3c5d0dc0bf826fe47cc582fe17a2ce7b1 shaderc-$SHADERC.tar.gz
baf8aebd22002b762d803ba0e1e389b6b4415159334e9d34bba1a938f6de8ce6 libbacktrace-$LIBBACKTRACE.tar.gz
13388fabb361de768ecdf2b65e52bb27d1054cae6ccb6942ba926e378e00db03 SDL3-$SDL3.tar.gz
b60832071919220d2fe692151fb420fa9ea489aa4c7a2eb0e01c830cbe469858 cpuinfo-$CPUINFO.tar.gz
297cd48a287a9113eec44902574084c6ab3b6a8b28d02606765a7fded431d7d8 discord-rpc-$DISCORD_RPC.tar.gz
5fe7abc6c4601f21fa56ffbf12507e80684942c3134b7888701ede836e6287e2 lunasvg-$LUNASVG.tar.gz
d1ef912c27e06307f2b2a5b6386070d0b8fae2bb5851f50841df7b73dcf5abdf shaderc-$SHADERC.tar.gz
fe45c2af99f6102d2704277d392c1c83b55180a70bfd17fb888cc84a54b70573 soundtouch-$SOUNDTOUCH.tar.gz
EOF
if [ "$SKIP_FREETYPE" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
if [[ "$SKIP_DOWNLOAD" != true && ! -f "freetype-$FREETYPE.tar.xz" ]]; then
curl -C - -L -o "freetype-$FREETYPE.tar.xz" "https://sourceforge.net/projects/freetype/files/freetype2/$FREETYPE/freetype-$FREETYPE.tar.xz/download"
fi
cat >> SHASUMS <<EOF
@ -135,47 +154,55 @@ if [ "$SKIP_FREETYPE" != true ]; then
EOF
fi
if [ "$SKIP_HARFBUZZ" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
if [[ "$SKIP_DOWNLOAD" != true && ! -f "harfbuzz-$HARFBUZZ.tar.gz" ]]; then
curl -C - -L -o "harfbuzz-$HARFBUZZ.tar.gz" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/$HARFBUZZ.tar.gz"
fi
cat >> SHASUMS <<EOF
c758fdce8587641b00403ee0df2cd5d30cbea7803d43c65fddd76224f7b49b88 harfbuzz-$HARFBUZZ.tar.gz
11749926914fd488e08e744538f19329332487a6243eec39ef3c63efa154a578 harfbuzz-$HARFBUZZ.tar.gz
EOF
fi
if [ "$SKIP_LIBJPEG" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
if [[ "$SKIP_DOWNLOAD" != true && ! -f "libjpeg-turbo-$LIBJPEGTURBO.tar.gz" ]]; then
curl -C - -L -O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz"
fi
cat >> SHASUMS <<EOF
99130559e7d62e8d695f2c0eaeef912c5828d5b84a0537dcb24c9678c9d5b76b libjpeg-turbo-$LIBJPEGTURBO.tar.gz
9564c72b1dfd1d6fe6274c5f95a8d989b59854575d4bbee44ade7bc17aa9bc93 libjpeg-turbo-$LIBJPEGTURBO.tar.gz
EOF
fi
if [ "$SKIP_LIBPNG" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
if [[ "$SKIP_DOWNLOAD" != true && ! -f "libpng-$LIBPNG.tar.xz" ]]; then
curl -C - -L -O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz"
fi
cat >> SHASUMS <<EOF
60c4da1d5b7f0aa8d158da48e8f8afa9773c1c8baa5d21974df61f1886b8ce8e libpng-$LIBPNG.tar.xz
926485350139ffb51ef69760db35f78846c805fef3d59bfdcb2fba704663f370 libpng-$LIBPNG.tar.xz
EOF
fi
if [ "$SKIP_LIBWEBP" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
if [[ "$SKIP_DOWNLOAD" != true && ! -f "libwebp-$LIBWEBP.tar.gz" ]]; then
curl -C - -L -O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz"
fi
cat >> SHASUMS <<EOF
61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 libwebp-$LIBWEBP.tar.gz
7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c libwebp-$LIBWEBP.tar.gz
EOF
fi
if [ "$SKIP_LIBZIP" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
if [[ "$SKIP_DOWNLOAD" != true && ! -f "libzip-$LIBZIP.tar.xz" ]]; then
curl -C - -L -O "https://github.com/nih-at/libzip/releases/download/v$LIBZIP/libzip-$LIBZIP.tar.xz"
fi
cat >> SHASUMS <<EOF
5d471308cef4c4752bbcf973d9cd37ba4cb53739116c30349d4764ba1410dfc1 libzip-$LIBZIP.tar.xz
9509d878ba788271c8b5abca9cfde1720f075335686237b7e9a9e7210fe67c1b libzip-$LIBZIP.tar.xz
EOF
fi
if [ "$SKIP_ZLIBNG" != true ]; then
if [[ "$SKIP_DOWNLOAD" != true && ! -f "zlib-ng-$ZLIBNG.tar.gz" ]]; then
curl -C - -L -o "zlib-ng-$ZLIBNG.tar.gz" "https://github.com/zlib-ng/zlib-ng/archive/refs/tags/$ZLIBNG.tar.gz"
fi
cat >> SHASUMS <<EOF
a73343c3093e5cdc50d9377997c3815b878fd110bf6511c2c7759f2afb90f5a3 zlib-ng-$ZLIBNG.tar.gz
EOF
fi
if [ "$SKIP_ZSTD" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
if [[ "$SKIP_DOWNLOAD" != true && ! -f "zstd-$ZSTD.tar.gz" ]]; then
curl -C - -L -O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz"
fi
cat >> SHASUMS <<EOF
@ -183,7 +210,7 @@ if [ "$SKIP_ZSTD" != true ]; then
EOF
fi
if [ "$SKIP_QT" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
if [[ "$SKIP_DOWNLOAD" != true && ! -f "qtbase-everywhere-src-$QT.tar.xz" ]]; then
curl -C - -L \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
@ -193,22 +220,20 @@ if [ "$SKIP_QT" != true ]; then
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtwayland-everywhere-src-$QT.tar.xz"
fi
cat >> SHASUMS <<EOF
40b14562ef3bd779bc0e0418ea2ae08fa28235f8ea6e8c0cb3bce1d6ad58dcaf qtbase-everywhere-src-$QT.tar.xz
138cc2909aa98f5ff7283e36eb3936eb5e625d3ca3b4febae2ca21d8903dd237 qtimageformats-everywhere-src-$QT.tar.xz
3d0de73596e36b2daa7c48d77c4426bb091752856912fba720215f756c560dd0 qtsvg-everywhere-src-$QT.tar.xz
9d43d409be08b8681a0155a9c65114b69c9a3fc11aef6487bb7fdc5b283c432d qttools-everywhere-src-$QT.tar.xz
635a6093e99152243b807de51077485ceadd4786d4acb135b9340b2303035a4a qttranslations-everywhere-src-$QT.tar.xz
2226fbde4e2ddd12f8bf4b239c8f38fd706a54e789e63467dfddc77129eca203 qtwayland-everywhere-src-$QT.tar.xz
012043ce6d411e6e8a91fdc4e05e6bedcfa10fcb1347d3c33908f7fdd10dfe05 qtbase-everywhere-src-$QT.tar.xz
d2a1bbb84707b8a0aec29227b170be00f04383fbf2361943596d09e7e443c8e1 qtimageformats-everywhere-src-$QT.tar.xz
aa2579f21ca66d19cbcf31d87e9067e07932635d36869c8239d4decd0a9dc1fa qtsvg-everywhere-src-$QT.tar.xz
326381b7d43f07913612f291abc298ae79bd95382e2233abce982cff2b53d2c0 qttools-everywhere-src-$QT.tar.xz
d2106e8a580bfd77702c4c1840299288d344902b0e2c758ca813ea04c6d6a3d1 qttranslations-everywhere-src-$QT.tar.xz
5e46157908295f2bf924462d8c0855b0508ba338ced9e810891fefa295dc9647 qtwayland-everywhere-src-$QT.tar.xz
EOF
fi
shasum -a 256 --check SHASUMS
# Have to clone with git, because it does version detection.
if [ "$SKIP_DOWNLOAD" != true ]; then
if [ ! -d "SPIRV-Cross" ]; then
git clone https://github.com/KhronosGroup/SPIRV-Cross/ -b $SPIRV_CROSS --depth 1
fi
if [[ "$SKIP_DOWNLOAD" != true && ! -d "SPIRV-Cross" ]]; then
git clone https://github.com/KhronosGroup/SPIRV-Cross/ -b $SPIRV_CROSS --depth 1
fi
# Only downloading sources?
@ -217,24 +242,24 @@ if [ "$ONLY_DOWNLOAD" == true ]; then
fi
# Stop pkg-config picking up host files.
export PKG_CONFIG_PATH=${SYSROOTDIR}/usr/lib/${CROSSARCH}-linux-gnu/pkgconfig:${SYSROOTDIR}/usr/lib/pkgconfig:${SYSROOTDIR}/usr/share/pkgconfig
export PKG_CONFIG_PATH=${SYSROOTDIR}/usr/lib/${CROSSTRIPLET}/pkgconfig:${SYSROOTDIR}/usr/lib/pkgconfig:${SYSROOTDIR}/usr/share/pkgconfig
export PKG_CONFIG_SYSROOT_DIR=${SYSROOTDIR}
# Generate cmake toolchain file.
cat > "$TOOLCHAINFILE" << EOF
set(CMAKE_CROSSCOMPILING TRUE)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR ${CROSSARCH})
set(CMAKE_SYSTEM_PROCESSOR ${CMAKEPROCESSOR})
set(CMAKE_C_COMPILER "/usr/bin/${CROSSARCH}-linux-gnu-gcc")
set(CMAKE_C_COMPILER_TARGET "${CROSSARCH}-linux-gnu")
set(CMAKE_C_COMPILER_AR "/usr/bin/${CROSSARCH}-linux-gnu-ar")
set(CMAKE_C_COMPILER_RANLIB "/usr/bin/${CROSSARCH}-linux-gnu-ranlib")
set(CMAKE_C_COMPILER "/usr/bin/${CROSSTRIPLET}-gcc")
set(CMAKE_C_COMPILER_TARGET "${CROSSTRIPLET}")
set(CMAKE_C_COMPILER_AR "/usr/bin/${CROSSTRIPLET}-ar")
set(CMAKE_C_COMPILER_RANLIB "/usr/bin/${CROSSTRIPLET}-ranlib")
set(CMAKE_CXX_COMPILER "/usr/bin/${CROSSARCH}-linux-gnu-g++")
set(CMAKE_CXX_COMPILER_TARGET "${CROSSARCH}-linux-gnu")
set(CMAKE_CXX_COMPILER_AR "/usr/bin/${CROSSARCH}-linux-gnu-ar")
set(CMAKE_CXX_COMPILER_RANLIB "/usr/bin/${CROSSARCH}-linux-gnu-ranlib")
set(CMAKE_CXX_COMPILER "/usr/bin/${CROSSTRIPLET}-g++")
set(CMAKE_CXX_COMPILER_TARGET "${CROSSTRIPLET}")
set(CMAKE_CXX_COMPILER_AR "/usr/bin/${CROSSTRIPLET}-ar")
set(CMAKE_CXX_COMPILER_RANLIB "/usr/bin/${CROSSTRIPLET}-ranlib")
set(CMAKE_FIND_ROOT_PATH "${INSTALLDIR};${SYSROOTDIR}")
set(CMAKE_SYSROOT "${SYSROOTDIR}")
@ -248,12 +273,25 @@ set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
EOF
# Build zlib first because of the things that depend on it.
# Disabled because it currently causes crashes on armhf.
#if [ "$SKIP_ZLIBNG" != true ]; then
# echo "Building zlib-ng..."
# rm -fr "zlib-ng-$ZLIBNG"
# tar xf "zlib-ng-$ZLIBNG.tar.gz"
# cd "zlib-ng-$ZLIBNG"
# cmake "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DZLIB_COMPAT=ON -DZLIBNG_ENABLE_TESTS=OFF -DZLIB_ENABLE_TESTS=OFF -DWITH_GTEST=OFF -B build -G Ninja
# cmake --build build --parallel
# ninja -C build install
# cd ..
#fi
# NOTE: Must be a shared library because otherwise aarch64 libgcc symbols are missing when building with clang.
echo "Building libbacktrace..."
rm -fr "libbacktrace-$LIBBACKTRACE"
tar xf "$LIBBACKTRACE.tar.gz"
tar xf "libbacktrace-$LIBBACKTRACE.tar.gz"
cd "libbacktrace-$LIBBACKTRACE"
./configure --prefix="$INSTALLDIR" --build=x86_64-linux-gnu --host="${CROSSARCH}-linux-gnu" --with-pic --enable-shared --disable-static
./configure --prefix="$INSTALLDIR" --build=x86_64-linux-gnu --host="${CROSSTRIPLET}" --with-pic --enable-shared --disable-static
make
make install
cd ..
@ -349,13 +387,11 @@ if [ "$SKIP_FREETYPE" != true ]; then
cd ..
fi
echo "Building SDL2..."
rm -fr "SDL2-$SDL2"
tar xf "SDL2-$SDL2.tar.gz"
cd "SDL2-$SDL2"
# needed because -Isystem with chroot/usr/include breaks
patch -p1 < "$SCRIPTDIR/sdl2-disable-isystem.patch"
cmake -B build "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -G Ninja
echo "Building SDL..."
rm -fr "SDL3-$SDL3"
tar xf "SDL3-$SDL3.tar.gz"
cd "SDL3-$SDL3"
cmake -B build "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -DSDL_TESTS=OFF -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..

View file

@ -1,12 +1,12 @@
#!/usr/bin/env bash
# SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
# SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
# SPDX-License-Identifier: CC-BY-NC-ND-4.0
set -e
if [ "$#" -lt 1 ]; then
echo "Syntax: $0 [-system-freetype] [-system-harfbuzz] [-system-libjpeg] [-system-libpng] [-system-libwebp] [-system-libzip] [-system-zstd] [-system-qt] [-skip-download] [-skip-cleanup] [-only-download] <output directory>"
echo "Syntax: $0 [-system-freetype] [-system-harfbuzz] [-system-libjpeg] [-system-libpng] [-system-libwebp] [-system-libzip] [-system-zlib] [-system-zstd] [-system-qt] [-skip-download] [-skip-cleanup] [-only-download] <output directory>"
exit 1
fi
@ -35,6 +35,10 @@ for arg in "$@"; do
echo "Skipping building libzip."
SKIP_LIBZIP=true
shift
elif [ "$arg" == "-system-zlib" ]; then
echo "Skipping building zlib-ng."
SKIP_ZLIBNG=true
shift
elif [ "$arg" == "-system-zstd" ]; then
echo "Skipping building zstd."
SKIP_ZSTD=true
@ -66,30 +70,31 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
fi
FREETYPE=2.13.3
HARFBUZZ=10.1.0
HARFBUZZ=10.2.0
LIBBACKTRACE=86885d14049fab06ef8a33aac51664230ca09200
LIBJPEGTURBO=3.0.4
LIBPNG=1.6.44
LIBWEBP=1.4.0
LIBZIP=1.11.2
SDL2=2.30.11
QT=6.8.1
LIBJPEGTURBO=3.1.0
LIBPNG=1.6.45
LIBWEBP=1.5.0
LIBZIP=1.11.3
SDL3=3.2.8
QT=6.8.2
ZLIBNG=2.2.4
ZSTD=1.5.6
CPUINFO=7524ad504fdcfcf75a18a133da6abd75c5d48053
DISCORD_RPC=144f3a3f1209994d8d9e8a87964a989cb9911c1e
LUNASVG=9af1ac7b90658a279b372add52d6f77a4ebb482c
SHADERC=1c0d3d18819aa75ec74f1fbd9ff0461e1b69a4d6
CPUINFO=3ebbfd45645650c4940bf0f3b4d25ab913466bb0
DISCORD_RPC=cc59d26d1d628fbd6527aac0ac1d6301f4978b92
LUNASVG=4a1c98ccb1da8a5a92ddc4f97339869b1ae556f4
SHADERC=fc65b19d2098cf81e55b4edc10adad2ad8268361
SOUNDTOUCH=463ade388f3a51da078dc9ed062bf28e4ba29da7
SPIRV_CROSS=vulkan-sdk-1.3.290.0
SPIRV_CROSS=vulkan-sdk-1.4.304.0
mkdir -p deps-build
cd deps-build
if [ "$SKIP_DOWNLOAD" != true ]; then
if [[ "$SKIP_DOWNLOAD" != true && ! -f "libbacktrace-$LIBBACKTRACE.tar.gz" ]]; then
curl -C - -L \
-O "https://github.com/ianlancetaylor/libbacktrace/archive/$LIBBACKTRACE.tar.gz" \
-O "https://github.com/libsdl-org/SDL/releases/download/release-$SDL2/SDL2-$SDL2.tar.gz" \
-o "libbacktrace-$LIBBACKTRACE.tar.gz" "https://github.com/ianlancetaylor/libbacktrace/archive/$LIBBACKTRACE.tar.gz" \
-O "https://github.com/libsdl-org/SDL/releases/download/release-$SDL3/SDL3-$SDL3.tar.gz" \
-o "cpuinfo-$CPUINFO.tar.gz" "https://github.com/stenzek/cpuinfo/archive/$CPUINFO.tar.gz" \
-o "discord-rpc-$DISCORD_RPC.tar.gz" "https://github.com/stenzek/discord-rpc/archive/$DISCORD_RPC.tar.gz" \
-o "lunasvg-$LUNASVG.tar.gz" "https://github.com/stenzek/lunasvg/archive/$LUNASVG.tar.gz" \
@ -98,17 +103,17 @@ if [ "$SKIP_DOWNLOAD" != true ]; then
fi
cat > SHASUMS <<EOF
baf8aebd22002b762d803ba0e1e389b6b4415159334e9d34bba1a938f6de8ce6 $LIBBACKTRACE.tar.gz
8b8d4aef2038533da814965220f88f77d60dfa0f32685f80ead65e501337da7f SDL2-$SDL2.tar.gz
e1351218d270db49c3dddcba04fb2153b09731ea3fa6830e423f5952f44585be cpuinfo-$CPUINFO.tar.gz
3eea5ccce6670c126282f1ba4d32c19d486db49a1a5cbfb8d6f48774784d310c discord-rpc-$DISCORD_RPC.tar.gz
3998b024b0d442614a9ee270e76e018bb37a17b8c6941212171731123cbbcac7 lunasvg-$LUNASVG.tar.gz
3826d86f8a13564be1c047ac105041a3c5d0dc0bf826fe47cc582fe17a2ce7b1 shaderc-$SHADERC.tar.gz
baf8aebd22002b762d803ba0e1e389b6b4415159334e9d34bba1a938f6de8ce6 libbacktrace-$LIBBACKTRACE.tar.gz
13388fabb361de768ecdf2b65e52bb27d1054cae6ccb6942ba926e378e00db03 SDL3-$SDL3.tar.gz
b60832071919220d2fe692151fb420fa9ea489aa4c7a2eb0e01c830cbe469858 cpuinfo-$CPUINFO.tar.gz
297cd48a287a9113eec44902574084c6ab3b6a8b28d02606765a7fded431d7d8 discord-rpc-$DISCORD_RPC.tar.gz
5fe7abc6c4601f21fa56ffbf12507e80684942c3134b7888701ede836e6287e2 lunasvg-$LUNASVG.tar.gz
d1ef912c27e06307f2b2a5b6386070d0b8fae2bb5851f50841df7b73dcf5abdf shaderc-$SHADERC.tar.gz
fe45c2af99f6102d2704277d392c1c83b55180a70bfd17fb888cc84a54b70573 soundtouch-$SOUNDTOUCH.tar.gz
EOF
if [ "$SKIP_FREETYPE" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
if [[ "$SKIP_DOWNLOAD" != true && ! -f "freetype-$FREETYPE.tar.xz" ]]; then
curl -C - -L -o "freetype-$FREETYPE.tar.xz" "https://sourceforge.net/projects/freetype/files/freetype2/$FREETYPE/freetype-$FREETYPE.tar.xz/download"
fi
cat >> SHASUMS <<EOF
@ -116,47 +121,55 @@ if [ "$SKIP_FREETYPE" != true ]; then
EOF
fi
if [ "$SKIP_HARFBUZZ" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
if [[ "$SKIP_DOWNLOAD" != true && ! -f "harfbuzz-$HARFBUZZ.tar.gz" ]]; then
curl -C - -L -o "harfbuzz-$HARFBUZZ.tar.gz" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/$HARFBUZZ.tar.gz"
fi
cat >> SHASUMS <<EOF
c758fdce8587641b00403ee0df2cd5d30cbea7803d43c65fddd76224f7b49b88 harfbuzz-$HARFBUZZ.tar.gz
11749926914fd488e08e744538f19329332487a6243eec39ef3c63efa154a578 harfbuzz-$HARFBUZZ.tar.gz
EOF
fi
if [ "$SKIP_LIBJPEG" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
if [[ "$SKIP_DOWNLOAD" != true && ! -f "libjpeg-turbo-$LIBJPEGTURBO.tar.gz" ]]; then
curl -C - -L -O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz"
fi
cat >> SHASUMS <<EOF
99130559e7d62e8d695f2c0eaeef912c5828d5b84a0537dcb24c9678c9d5b76b libjpeg-turbo-$LIBJPEGTURBO.tar.gz
9564c72b1dfd1d6fe6274c5f95a8d989b59854575d4bbee44ade7bc17aa9bc93 libjpeg-turbo-$LIBJPEGTURBO.tar.gz
EOF
fi
if [ "$SKIP_LIBPNG" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
if [[ "$SKIP_DOWNLOAD" != true && ! -f "libpng-$LIBPNG.tar.xz" ]]; then
curl -C - -L -O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz"
fi
cat >> SHASUMS <<EOF
60c4da1d5b7f0aa8d158da48e8f8afa9773c1c8baa5d21974df61f1886b8ce8e libpng-$LIBPNG.tar.xz
926485350139ffb51ef69760db35f78846c805fef3d59bfdcb2fba704663f370 libpng-$LIBPNG.tar.xz
EOF
fi
if [ "$SKIP_LIBWEBP" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
if [[ "$SKIP_DOWNLOAD" != true && ! -f "libwebp-$LIBWEBP.tar.gz" ]]; then
curl -C - -L -O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz"
fi
cat >> SHASUMS <<EOF
61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 libwebp-$LIBWEBP.tar.gz
7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c libwebp-$LIBWEBP.tar.gz
EOF
fi
if [ "$SKIP_LIBZIP" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
if [[ "$SKIP_DOWNLOAD" != true && ! -f "libzip-$LIBZIP.tar.xz" ]]; then
curl -C - -L -O "https://github.com/nih-at/libzip/releases/download/v$LIBZIP/libzip-$LIBZIP.tar.xz"
fi
cat >> SHASUMS <<EOF
5d471308cef4c4752bbcf973d9cd37ba4cb53739116c30349d4764ba1410dfc1 libzip-$LIBZIP.tar.xz
9509d878ba788271c8b5abca9cfde1720f075335686237b7e9a9e7210fe67c1b libzip-$LIBZIP.tar.xz
EOF
fi
if [ "$SKIP_ZLIBNG" != true ]; then
if [[ "$SKIP_DOWNLOAD" != true && ! -f "zlib-ng-$ZLIBNG.tar.gz" ]]; then
curl -C - -L -o "zlib-ng-$ZLIBNG.tar.gz" "https://github.com/zlib-ng/zlib-ng/archive/refs/tags/$ZLIBNG.tar.gz"
fi
cat >> SHASUMS <<EOF
a73343c3093e5cdc50d9377997c3815b878fd110bf6511c2c7759f2afb90f5a3 zlib-ng-$ZLIBNG.tar.gz
EOF
fi
if [ "$SKIP_ZSTD" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
if [[ "$SKIP_DOWNLOAD" != true && ! -f "zstd-$ZSTD.tar.gz" ]]; then
curl -C - -L -O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz"
fi
cat >> SHASUMS <<EOF
@ -164,7 +177,7 @@ if [ "$SKIP_ZSTD" != true ]; then
EOF
fi
if [ "$SKIP_QT" != true ]; then
if [ "$SKIP_DOWNLOAD" != true ]; then
if [[ "$SKIP_DOWNLOAD" != true && ! -f "qtbase-everywhere-src-$QT.tar.xz" ]]; then
curl -C - -L \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
@ -174,22 +187,20 @@ if [ "$SKIP_QT" != true ]; then
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtwayland-everywhere-src-$QT.tar.xz"
fi
cat >> SHASUMS <<EOF
40b14562ef3bd779bc0e0418ea2ae08fa28235f8ea6e8c0cb3bce1d6ad58dcaf qtbase-everywhere-src-$QT.tar.xz
138cc2909aa98f5ff7283e36eb3936eb5e625d3ca3b4febae2ca21d8903dd237 qtimageformats-everywhere-src-$QT.tar.xz
3d0de73596e36b2daa7c48d77c4426bb091752856912fba720215f756c560dd0 qtsvg-everywhere-src-$QT.tar.xz
9d43d409be08b8681a0155a9c65114b69c9a3fc11aef6487bb7fdc5b283c432d qttools-everywhere-src-$QT.tar.xz
635a6093e99152243b807de51077485ceadd4786d4acb135b9340b2303035a4a qttranslations-everywhere-src-$QT.tar.xz
2226fbde4e2ddd12f8bf4b239c8f38fd706a54e789e63467dfddc77129eca203 qtwayland-everywhere-src-$QT.tar.xz
012043ce6d411e6e8a91fdc4e05e6bedcfa10fcb1347d3c33908f7fdd10dfe05 qtbase-everywhere-src-$QT.tar.xz
d2a1bbb84707b8a0aec29227b170be00f04383fbf2361943596d09e7e443c8e1 qtimageformats-everywhere-src-$QT.tar.xz
aa2579f21ca66d19cbcf31d87e9067e07932635d36869c8239d4decd0a9dc1fa qtsvg-everywhere-src-$QT.tar.xz
326381b7d43f07913612f291abc298ae79bd95382e2233abce982cff2b53d2c0 qttools-everywhere-src-$QT.tar.xz
d2106e8a580bfd77702c4c1840299288d344902b0e2c758ca813ea04c6d6a3d1 qttranslations-everywhere-src-$QT.tar.xz
5e46157908295f2bf924462d8c0855b0508ba338ced9e810891fefa295dc9647 qtwayland-everywhere-src-$QT.tar.xz
EOF
fi
shasum -a 256 --check SHASUMS
# Have to clone with git, because it does version detection.
if [ "$SKIP_DOWNLOAD" != true ]; then
if [ ! -d "SPIRV-Cross" ]; then
git clone https://github.com/KhronosGroup/SPIRV-Cross/ -b $SPIRV_CROSS --depth 1
fi
if [[ "$SKIP_DOWNLOAD" != true && ! -d "SPIRV-Cross" ]]; then
git clone https://github.com/KhronosGroup/SPIRV-Cross/ -b $SPIRV_CROSS --depth 1
fi
# Only downloading sources?
@ -197,9 +208,21 @@ if [ "$ONLY_DOWNLOAD" == true ]; then
exit 0
fi
# Build zlib first because of the things that depend on it.
if [ "$SKIP_ZLIBNG" != true ]; then
echo "Building zlib-ng..."
rm -fr "zlib-ng-$ZLIBNG"
tar xf "zlib-ng-$ZLIBNG.tar.gz"
cd "zlib-ng-$ZLIBNG"
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -DZLIB_COMPAT=ON -DZLIBNG_ENABLE_TESTS=OFF -DZLIB_ENABLE_TESTS=OFF -DWITH_GTEST=OFF -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
fi
echo "Building libbacktrace..."
rm -fr "libbacktrace-$LIBBACKTRACE"
tar xf "$LIBBACKTRACE.tar.gz"
tar xf "libbacktrace-$LIBBACKTRACE.tar.gz"
cd "libbacktrace-$LIBBACKTRACE"
./configure --prefix="$INSTALLDIR" --with-pic
make
@ -297,11 +320,11 @@ if [ "$SKIP_FREETYPE" != true ]; then
cd ..
fi
echo "Building SDL2..."
rm -fr "SDL2-$SDL2"
tar xf "SDL2-$SDL2.tar.gz"
cd "SDL2-$SDL2"
cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -G Ninja
echo "Building SDL..."
rm -fr "SDL3-$SDL3"
tar xf "SDL3-$SDL3.tar.gz"
cd "SDL3-$SDL3"
cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -DSDL_TESTS=OFF -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..

View file

@ -37,23 +37,23 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
fi
FREETYPE=2.13.3
HARFBUZZ=10.1.0
SDL2=2.30.11
HARFBUZZ=10.2.0
SDL3=3.2.8
ZSTD=1.5.6
LIBPNG=1.6.44
LIBJPEGTURBO=3.0.4
LIBWEBP=1.4.0
LIBZIP=1.11.2
LIBPNG=1.6.45
LIBJPEGTURBO=3.1.0
LIBWEBP=1.5.0
LIBZIP=1.11.3
FFMPEG=7.1
MOLTENVK=1.2.9
QT=6.8.1
QT=6.8.2
CPUINFO=7524ad504fdcfcf75a18a133da6abd75c5d48053
CPUINFO=3ebbfd45645650c4940bf0f3b4d25ab913466bb0
DISCORD_RPC=144f3a3f1209994d8d9e8a87964a989cb9911c1e
LUNASVG=9af1ac7b90658a279b372add52d6f77a4ebb482c
SHADERC=1c0d3d18819aa75ec74f1fbd9ff0461e1b69a4d6
SHADERC=fc65b19d2098cf81e55b4edc10adad2ad8268361
SOUNDTOUCH=463ade388f3a51da078dc9ed062bf28e4ba29da7
SPIRV_CROSS=vulkan-sdk-1.3.290.0
SPIRV_CROSS=vulkan-sdk-1.4.304.0
mkdir -p deps-build
cd deps-build
@ -81,24 +81,24 @@ CMAKE_COMMON_QT=(
cat > SHASUMS <<EOF
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
c758fdce8587641b00403ee0df2cd5d30cbea7803d43c65fddd76224f7b49b88 harfbuzz-$HARFBUZZ.tar.gz
60c4da1d5b7f0aa8d158da48e8f8afa9773c1c8baa5d21974df61f1886b8ce8e libpng-$LIBPNG.tar.xz
99130559e7d62e8d695f2c0eaeef912c5828d5b84a0537dcb24c9678c9d5b76b libjpeg-turbo-$LIBJPEGTURBO.tar.gz
61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 libwebp-$LIBWEBP.tar.gz
5d471308cef4c4752bbcf973d9cd37ba4cb53739116c30349d4764ba1410dfc1 libzip-$LIBZIP.tar.xz
8b8d4aef2038533da814965220f88f77d60dfa0f32685f80ead65e501337da7f SDL2-$SDL2.tar.gz
11749926914fd488e08e744538f19329332487a6243eec39ef3c63efa154a578 harfbuzz-$HARFBUZZ.tar.gz
926485350139ffb51ef69760db35f78846c805fef3d59bfdcb2fba704663f370 libpng-$LIBPNG.tar.xz
9564c72b1dfd1d6fe6274c5f95a8d989b59854575d4bbee44ade7bc17aa9bc93 libjpeg-turbo-$LIBJPEGTURBO.tar.gz
7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c libwebp-$LIBWEBP.tar.gz
9509d878ba788271c8b5abca9cfde1720f075335686237b7e9a9e7210fe67c1b libzip-$LIBZIP.tar.xz
13388fabb361de768ecdf2b65e52bb27d1054cae6ccb6942ba926e378e00db03 SDL3-$SDL3.tar.gz
8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1 zstd-$ZSTD.tar.gz
40973d44970dbc83ef302b0609f2e74982be2d85916dd2ee7472d30678a7abe6 ffmpeg-$FFMPEG.tar.xz
f415a09385030c6510a936155ce211f617c31506db5fbc563e804345f1ecf56e v$MOLTENVK.tar.gz
40b14562ef3bd779bc0e0418ea2ae08fa28235f8ea6e8c0cb3bce1d6ad58dcaf qtbase-everywhere-src-$QT.tar.xz
138cc2909aa98f5ff7283e36eb3936eb5e625d3ca3b4febae2ca21d8903dd237 qtimageformats-everywhere-src-$QT.tar.xz
3d0de73596e36b2daa7c48d77c4426bb091752856912fba720215f756c560dd0 qtsvg-everywhere-src-$QT.tar.xz
9d43d409be08b8681a0155a9c65114b69c9a3fc11aef6487bb7fdc5b283c432d qttools-everywhere-src-$QT.tar.xz
635a6093e99152243b807de51077485ceadd4786d4acb135b9340b2303035a4a qttranslations-everywhere-src-$QT.tar.xz
e1351218d270db49c3dddcba04fb2153b09731ea3fa6830e423f5952f44585be cpuinfo-$CPUINFO.tar.gz
012043ce6d411e6e8a91fdc4e05e6bedcfa10fcb1347d3c33908f7fdd10dfe05 qtbase-everywhere-src-$QT.tar.xz
d2a1bbb84707b8a0aec29227b170be00f04383fbf2361943596d09e7e443c8e1 qtimageformats-everywhere-src-$QT.tar.xz
aa2579f21ca66d19cbcf31d87e9067e07932635d36869c8239d4decd0a9dc1fa qtsvg-everywhere-src-$QT.tar.xz
326381b7d43f07913612f291abc298ae79bd95382e2233abce982cff2b53d2c0 qttools-everywhere-src-$QT.tar.xz
d2106e8a580bfd77702c4c1840299288d344902b0e2c758ca813ea04c6d6a3d1 qttranslations-everywhere-src-$QT.tar.xz
b60832071919220d2fe692151fb420fa9ea489aa4c7a2eb0e01c830cbe469858 cpuinfo-$CPUINFO.tar.gz
3eea5ccce6670c126282f1ba4d32c19d486db49a1a5cbfb8d6f48774784d310c discord-rpc-$DISCORD_RPC.tar.gz
3998b024b0d442614a9ee270e76e018bb37a17b8c6941212171731123cbbcac7 lunasvg-$LUNASVG.tar.gz
3826d86f8a13564be1c047ac105041a3c5d0dc0bf826fe47cc582fe17a2ce7b1 shaderc-$SHADERC.tar.gz
d1ef912c27e06307f2b2a5b6386070d0b8fae2bb5851f50841df7b73dcf5abdf shaderc-$SHADERC.tar.gz
fe45c2af99f6102d2704277d392c1c83b55180a70bfd17fb888cc84a54b70573 soundtouch-$SOUNDTOUCH.tar.gz
EOF
@ -109,7 +109,7 @@ curl -L \
-O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz" \
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
-O "https://github.com/nih-at/libzip/releases/download/v$LIBZIP/libzip-$LIBZIP.tar.xz" \
-O "https://github.com/libsdl-org/SDL/releases/download/release-$SDL2/SDL2-$SDL2.tar.gz" \
-O "https://github.com/libsdl-org/SDL/releases/download/release-$SDL3/SDL3-$SDL3.tar.gz" \
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
-O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \
-O "https://github.com/KhronosGroup/MoltenVK/archive/refs/tags/v$MOLTENVK.tar.gz" \
@ -222,11 +222,11 @@ cmake --build build --parallel
cmake --install build
cd ..
echo "Installing SDL2..."
rm -fr "SDL2-$SDL2"
tar xf "SDL2-$SDL2.tar.gz"
cd "SDL2-$SDL2"
cmake -B build "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DSDL_X11=OFF -DBUILD_SHARED_LIBS=ON
echo "Installing SDL..."
rm -fr "SDL3-$SDL3"
tar xf "SDL3-$SDL3.tar.gz"
cd "SDL3-$SDL3"
cmake -B build "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DSDL_SHARED=ON -DSDL_STATIC=OFF -DSDL_TESTS=OFF -DSDL_X11=OFF -DBUILD_SHARED_LIBS=ON
make -C build "-j$NPROCS"
make -C build install
cd ..

View file

@ -1,7 +1,7 @@
@echo off
setlocal enabledelayedexpansion
rem SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
rem SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
rem SPDX-License-Identifier: CC-BY-NC-ND-4.0
echo Setting environment...
@ -46,47 +46,46 @@ echo INSTALLDIR=%INSTALLDIR%
cd "%BUILDDIR%"
set FREETYPE=2.13.3
set HARFBUZZ=10.1.0
set LIBJPEGTURBO=3.0.4
set LIBPNG=1644
set QT=6.8.1
set HARFBUZZ=10.2.0
set LIBJPEGTURBO=3.1.0
set LIBPNG=1645
set QT=6.8.2
set QTMINOR=6.8
set SDL2=2.30.11
set WEBP=1.4.0
set LIBZIP=1.11.2
set ZLIB=1.3.1
set ZLIBSHORT=131
set SDL3=3.2.8
set WEBP=1.5.0
set LIBZIP=1.11.3
set ZLIBNG=2.2.4
set ZSTD=1.5.6
set CPUINFO=7524ad504fdcfcf75a18a133da6abd75c5d48053
set CPUINFO=3ebbfd45645650c4940bf0f3b4d25ab913466bb0
set DISCORD_RPC=144f3a3f1209994d8d9e8a87964a989cb9911c1e
set LUNASVG=9af1ac7b90658a279b372add52d6f77a4ebb482c
set SHADERC=1c0d3d18819aa75ec74f1fbd9ff0461e1b69a4d6
set SHADERC=fc65b19d2098cf81e55b4edc10adad2ad8268361
set SOUNDTOUCH=463ade388f3a51da078dc9ed062bf28e4ba29da7
set SPIRV_CROSS=vulkan-sdk-1.3.290.0
set SPIRV_CROSS=vulkan-sdk-1.4.304.0
set DXCOMPILER=1.8.2407.12
set DXAGILITY=1.614.1
call :downloadfile "freetype-%FREETYPE%.tar.gz" "https://download.savannah.gnu.org/releases/freetype/freetype-%FREETYPE%.tar.gz" 5c3a8e78f7b24c20b25b54ee575d6daa40007a5f4eea2845861c3409b3021747 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip" f93ff7ec6f2fcb9242256976a7e6d1da2588b5e57a559fb71a025b74bd1f5539 || goto error
call :downloadfile "lpng%LIBPNG%.zip" "https://download.sourceforge.net/libpng/lpng%LIBPNG%.zip" 7d7571a1faa1898b69888716dfdea0e4d466f1a5cf518e6aa626df2242bbadbe || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 99130559e7d62e8d695f2c0eaeef912c5828d5b84a0537dcb24c9678c9d5b76b || goto error
call :downloadfile "SDL2-%SDL2%.zip" "https://github.com/libsdl-org/SDL/releases/download/release-%SDL2%/SDL2-%SDL2%.zip" a0b3e7ac5f708042683ff0f22e069bdf75563540c615f9854ecc9bc8913e2488 || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" e22d997bd15b795a176c8da62c8c1da0a674eb534e02f7c01ca507bf11bce0c3 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 247a0a58039275a5a4fb499a600a90f66dc6e00321bb6f86a9b8d8020344d853 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 57bd332e5550ff70a852560c591b786b6ba587c5e41cb5ef91038d82db137ab9 || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" c65a89140f5d68137ffec67d631ec97002fb37077d9b4eb4ee45cbec39b1c38a || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 30a8e7773e1f274557e049a97f158b808f344247da03ae5240e4956c81d51cd5 || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 || goto error
call :downloadfile "libzip-%LIBZIP%.tar.gz" "https://github.com/nih-at/libzip/releases/download/v%LIBZIP%/libzip-%LIBZIP%.tar.gz" 6b2a43837005e1c23fdfee532b78f806863e412d2089b9c42b49ab08cbcd7665 || goto error
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://zlib.net/zlib%ZLIBSHORT%.zip" 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip" 180cec309e817ec50953cd4d4208025c1931203231cf455418b0dd4021091951 || goto error
call :downloadfile "lpng%LIBPNG%.zip" "https://download.sourceforge.net/libpng/lpng%LIBPNG%.zip" a66c4b1350b67776e90263e2550933067cd9ccbd318db489f84dcc0d2b033249 || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 9564c72b1dfd1d6fe6274c5f95a8d989b59854575d4bbee44ade7bc17aa9bc93 || goto error
call :downloadfile "SDL3-%SDL3%.zip" "https://github.com/libsdl-org/SDL/releases/download/release-%SDL3%/SDL3-%SDL3%.zip" 7f8ff5c8246db4145301bc122601a5f8cef25ee2c326eddb3e88668849c61ddf || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 44087aec0caa4aa81437e787917d29d97536484a682a5d51ec035878e57c0b5c || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 83c72b5dfad04854acf61d592e3f9cdc2ed894779aab8d0470d966715266caaf || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 144d55e4d199793a76c53f19872633a79aec0314039f6f99b6a10b5be7a78fbf || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 102539447c1c76d206f24bcca2c911270cf53991548d9c3d7d0d01855f651e3b || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 33ccac9f99a357ffd83cb2d7179a0c0ffcba85a14d23d86619d5dc9721ded42f || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c || goto error
call :downloadfile "libzip-%LIBZIP%.tar.gz" "https://github.com/nih-at/libzip/releases/download/v%LIBZIP%/libzip-%LIBZIP%.tar.gz" 76653f135dde3036036c500e11861648ffbf9e1fc5b233ff473c60897d9db0ea || goto error
call :downloadfile "zlib-ng-%ZLIBNG%.zip" "https://github.com/zlib-ng/zlib-ng/archive/refs/tags/%ZLIBNG%.zip" 5e78f0ebbe507fe294bf756c741a8af4766d3838c54460a087e906b3f20346e4 || goto error
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 3b1c3b46e416d36931efd34663122d7f51b550c87f74de2d38249516fe7d8be5 || goto error
call :downloadfile "zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" https://github.com/facebook/zstd/commit/fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch 8df152f4969b308546306c074628de761f0b80265de7de534e3822fab22d7535 || goto error
call :downloadfile "cpuinfo-%CPUINFO%.zip" "https://github.com/pytorch/cpuinfo/archive/%CPUINFO%.zip" 13146ae7983d767a678dd01b0d6af591e77cec82babd41264b9164ab808d7d41 || goto error
call :downloadfile "cpuinfo-%CPUINFO%.zip" "https://github.com/stenzek/cpuinfo/archive/%CPUINFO%.zip" 3430f8bae57623347b2b30a8ff041b0288f90ad99b4c2487c3d520863ce4a4e3 || goto error
call :downloadfile "discord-rpc-%DISCORD_RPC%.zip" "https://github.com/stenzek/discord-rpc/archive/%DISCORD_RPC%.zip" 61e185e75d37b360c314125bcdf4697192d15e2d5209db3306ed6cd736d508b3 || goto error
call :downloadfile "lunasvg-%LUNASVG%.zip" "https://github.com/stenzek/lunasvg/archive/%LUNASVG%.zip" 1425ec2bda0228b73ffdc70b0dc666fc7d2b69c33eec75a35c4421157c0e220c || goto error
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/stenzek/shaderc/archive/%SHADERC%.zip" c62c4a358a01cd8390246d4e0d35a5abe0a145a64b4f63861afbfc0fc4216d03 || goto error
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/stenzek/shaderc/archive/%SHADERC%.zip" e7766c54f289e89fc36ca4273693e6549024b5e540d7b46745cee2c61def5e4c || goto error
call :downloadfile "soundtouch-%SOUNDTOUCH%.zip" "https://github.com/stenzek/soundtouch/archive/%SOUNDTOUCH%.zip" 107a1941181a69abe28018b9ad26fc0218625758ac193bc979abc9e26b7c0c3a || goto error
call :downloadfile "dxcompiler-%DXCOMPILER%.zip" "https://www.nuget.org/api/v2/package/Microsoft.Direct3D.DXC/%DXCOMPILER%" eb4f6a3bb6b08aaa62f435b3dbf26b180702ca52398d3650d0dd538f56742cdc || goto error
call :downloadfile "dxagility-%DXAGILITY%.zip" "https://www.nuget.org/api/v2/package/Microsoft.Direct3D.D3D12/%DXAGILITY%" 9880aa91602dd51dd6cf7911a2bca7a2323513b15338573cde014b3356eeaff2 || goto error
@ -104,11 +103,12 @@ if %DEBUG%==1 (
set FORCEPDB=-DCMAKE_SHARED_LINKER_FLAGS_RELEASE="/DEBUG"
set ARM64TOOLCHAIN=-DCMAKE_TOOLCHAIN_FILE="%SCRIPTDIR%\cmake-toolchain-windows-arm64.cmake"
echo Building Zlib...
rmdir /S /Q "zlib-%ZLIB%"
%SEVENZIP% x "zlib%ZLIBSHORT%.zip" || goto error
cd "zlib-%ZLIB%" || goto error
cmake %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DZLIB_BUILD_EXAMPLES=OFF -B build -G Ninja || goto error
echo Building zlib-ng...
rmdir /S /Q "zlib-ng-%ZLIBNG%"
%SEVENZIP% x "zlib-ng-%ZLIBNG%.zip" || goto error
cd "zlib-ng-%ZLIBNG%" || goto error
rem BUILD_SHARED_LIBS deliberately ommitted so that both shared and static libraries are built, we need static for the updater.
cmake %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DZLIB_COMPAT=ON -DZLIBNG_ENABLE_TESTS=OFF -DZLIB_ENABLE_TESTS=OFF -DWITH_GTEST=OFF -B build -G Ninja || goto error
cmake --build build --parallel || goto error
ninja -C build install || goto error
cd .. || goto error
@ -186,14 +186,14 @@ cmake --build build --parallel || goto error
ninja -C build install || goto error
cd .. || goto error
echo Building SDL2...
rmdir /S /Q "SDL2-%SDL2%"
%SEVENZIP% x "SDL2-%SDL2%.zip" || goto error
cd "SDL2-%SDL2%" || goto error
cmake -B build %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release %FORCEPDB% -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -G Ninja || goto error
echo Building SDL...
rmdir /S /Q "SDL3-%SDL3%"
%SEVENZIP% x "SDL3-%SDL3%.zip" || goto error
cd "SDL3-%SDL3%" || goto error
cmake -B build %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release %FORCEPDB% -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -DSDL_TESTS=OFF -G Ninja || goto error
cmake --build build --parallel || goto error
ninja -C build install || goto error
copy build\SDL2.pdb "%INSTALLDIR%\bin" || goto error
copy build\SDL3.pdb "%INSTALLDIR%\bin" || goto error
cd .. || goto error
if %DEBUG%==1 (

View file

@ -1,7 +1,7 @@
@echo off
setlocal enabledelayedexpansion
rem SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
rem SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
rem SPDX-License-Identifier: CC-BY-NC-ND-4.0
echo Setting environment...
@ -44,47 +44,46 @@ set "PATH=%PATH%;%INSTALLDIR%\bin"
cd "%BUILDDIR%"
set FREETYPE=2.13.3
set HARFBUZZ=10.1.0
set LIBJPEGTURBO=3.0.4
set LIBPNG=1644
set QT=6.8.1
set HARFBUZZ=10.2.0
set LIBJPEGTURBO=3.1.0
set LIBPNG=1645
set QT=6.8.2
set QTMINOR=6.8
set SDL2=2.30.11
set WEBP=1.4.0
set LIBZIP=1.11.2
set ZLIB=1.3.1
set ZLIBSHORT=131
set SDL3=3.2.8
set WEBP=1.5.0
set LIBZIP=1.11.3
set ZLIBNG=2.2.4
set ZSTD=1.5.6
set CPUINFO=7524ad504fdcfcf75a18a133da6abd75c5d48053
set CPUINFO=3ebbfd45645650c4940bf0f3b4d25ab913466bb0
set DISCORD_RPC=144f3a3f1209994d8d9e8a87964a989cb9911c1e
set LUNASVG=9af1ac7b90658a279b372add52d6f77a4ebb482c
set SHADERC=1c0d3d18819aa75ec74f1fbd9ff0461e1b69a4d6
set SHADERC=fc65b19d2098cf81e55b4edc10adad2ad8268361
set SOUNDTOUCH=463ade388f3a51da078dc9ed062bf28e4ba29da7
set SPIRV_CROSS=vulkan-sdk-1.3.290.0
set SPIRV_CROSS=vulkan-sdk-1.4.304.0
set DXCOMPILER=1.8.2407.12
set DXAGILITY=1.614.1
call :downloadfile "freetype-%FREETYPE%.tar.gz" "https://download.savannah.gnu.org/releases/freetype/freetype-%FREETYPE%.tar.gz" 5c3a8e78f7b24c20b25b54ee575d6daa40007a5f4eea2845861c3409b3021747 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip" f93ff7ec6f2fcb9242256976a7e6d1da2588b5e57a559fb71a025b74bd1f5539 || goto error
call :downloadfile "lpng%LIBPNG%.zip" "https://download.sourceforge.net/libpng/lpng%LIBPNG%.zip" 7d7571a1faa1898b69888716dfdea0e4d466f1a5cf518e6aa626df2242bbadbe || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 99130559e7d62e8d695f2c0eaeef912c5828d5b84a0537dcb24c9678c9d5b76b || goto error
call :downloadfile "SDL2-%SDL2%.zip" "https://github.com/libsdl-org/SDL/releases/download/release-%SDL2%/SDL2-%SDL2%.zip" a0b3e7ac5f708042683ff0f22e069bdf75563540c615f9854ecc9bc8913e2488 || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" e22d997bd15b795a176c8da62c8c1da0a674eb534e02f7c01ca507bf11bce0c3 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 247a0a58039275a5a4fb499a600a90f66dc6e00321bb6f86a9b8d8020344d853 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 57bd332e5550ff70a852560c591b786b6ba587c5e41cb5ef91038d82db137ab9 || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" c65a89140f5d68137ffec67d631ec97002fb37077d9b4eb4ee45cbec39b1c38a || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 30a8e7773e1f274557e049a97f158b808f344247da03ae5240e4956c81d51cd5 || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 || goto error
call :downloadfile "libzip-%LIBZIP%.tar.gz" "https://github.com/nih-at/libzip/releases/download/v%LIBZIP%/libzip-%LIBZIP%.tar.gz" 6b2a43837005e1c23fdfee532b78f806863e412d2089b9c42b49ab08cbcd7665 || goto error
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://zlib.net/zlib%ZLIBSHORT%.zip" 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17 || goto error
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip" 180cec309e817ec50953cd4d4208025c1931203231cf455418b0dd4021091951 || goto error
call :downloadfile "lpng%LIBPNG%.zip" "https://download.sourceforge.net/libpng/lpng%LIBPNG%.zip" a66c4b1350b67776e90263e2550933067cd9ccbd318db489f84dcc0d2b033249 || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 9564c72b1dfd1d6fe6274c5f95a8d989b59854575d4bbee44ade7bc17aa9bc93 || goto error
call :downloadfile "SDL3-%SDL3%.zip" "https://github.com/libsdl-org/SDL/releases/download/release-%SDL3%/SDL3-%SDL3%.zip" 7f8ff5c8246db4145301bc122601a5f8cef25ee2c326eddb3e88668849c61ddf || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 44087aec0caa4aa81437e787917d29d97536484a682a5d51ec035878e57c0b5c || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 83c72b5dfad04854acf61d592e3f9cdc2ed894779aab8d0470d966715266caaf || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 144d55e4d199793a76c53f19872633a79aec0314039f6f99b6a10b5be7a78fbf || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 102539447c1c76d206f24bcca2c911270cf53991548d9c3d7d0d01855f651e3b || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 33ccac9f99a357ffd83cb2d7179a0c0ffcba85a14d23d86619d5dc9721ded42f || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c || goto error
call :downloadfile "libzip-%LIBZIP%.tar.gz" "https://github.com/nih-at/libzip/releases/download/v%LIBZIP%/libzip-%LIBZIP%.tar.gz" 76653f135dde3036036c500e11861648ffbf9e1fc5b233ff473c60897d9db0ea || goto error
call :downloadfile "zlib-ng-%ZLIBNG%.zip" "https://github.com/zlib-ng/zlib-ng/archive/refs/tags/%ZLIBNG%.zip" 5e78f0ebbe507fe294bf756c741a8af4766d3838c54460a087e906b3f20346e4 || goto error
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 3b1c3b46e416d36931efd34663122d7f51b550c87f74de2d38249516fe7d8be5 || goto error
call :downloadfile "zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" https://github.com/facebook/zstd/commit/fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch 8df152f4969b308546306c074628de761f0b80265de7de534e3822fab22d7535 || goto error
call :downloadfile "cpuinfo-%CPUINFO%.zip" "https://github.com/pytorch/cpuinfo/archive/%CPUINFO%.zip" 13146ae7983d767a678dd01b0d6af591e77cec82babd41264b9164ab808d7d41 || goto error
call :downloadfile "cpuinfo-%CPUINFO%.zip" "https://github.com/stenzek/cpuinfo/archive/%CPUINFO%.zip" 3430f8bae57623347b2b30a8ff041b0288f90ad99b4c2487c3d520863ce4a4e3 || goto error
call :downloadfile "discord-rpc-%DISCORD_RPC%.zip" "https://github.com/stenzek/discord-rpc/archive/%DISCORD_RPC%.zip" 61e185e75d37b360c314125bcdf4697192d15e2d5209db3306ed6cd736d508b3 || goto error
call :downloadfile "lunasvg-%LUNASVG%.zip" "https://github.com/stenzek/lunasvg/archive/%LUNASVG%.zip" 1425ec2bda0228b73ffdc70b0dc666fc7d2b69c33eec75a35c4421157c0e220c || goto error
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/stenzek/shaderc/archive/%SHADERC%.zip" c62c4a358a01cd8390246d4e0d35a5abe0a145a64b4f63861afbfc0fc4216d03 || goto error
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/stenzek/shaderc/archive/%SHADERC%.zip" e7766c54f289e89fc36ca4273693e6549024b5e540d7b46745cee2c61def5e4c || goto error
call :downloadfile "soundtouch-%SOUNDTOUCH%.zip" "https://github.com/stenzek/soundtouch/archive/%SOUNDTOUCH%.zip" 107a1941181a69abe28018b9ad26fc0218625758ac193bc979abc9e26b7c0c3a || goto error
call :downloadfile "dxcompiler-%DXCOMPILER%.zip" "https://www.nuget.org/api/v2/package/Microsoft.Direct3D.DXC/%DXCOMPILER%" eb4f6a3bb6b08aaa62f435b3dbf26b180702ca52398d3650d0dd538f56742cdc || goto error
call :downloadfile "dxagility-%DXAGILITY%.zip" "https://www.nuget.org/api/v2/package/Microsoft.Direct3D.D3D12/%DXAGILITY%" 9880aa91602dd51dd6cf7911a2bca7a2323513b15338573cde014b3356eeaff2 || goto error
@ -101,11 +100,12 @@ if %DEBUG%==1 (
set FORCEPDB=-DCMAKE_SHARED_LINKER_FLAGS_RELEASE="/DEBUG"
echo Building Zlib...
rmdir /S /Q "zlib-%ZLIB%"
%SEVENZIP% x "zlib%ZLIBSHORT%.zip" || goto error
cd "zlib-%ZLIB%" || goto error
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DZLIB_BUILD_EXAMPLES=OFF -B build -G Ninja || goto error
echo Building zlib-ng...
rmdir /S /Q "zlib-ng-%ZLIBNG%"
%SEVENZIP% x "zlib-ng-%ZLIBNG%.zip" || goto error
cd "zlib-ng-%ZLIBNG%" || goto error
rem BUILD_SHARED_LIBS deliberately ommitted so that both shared and static libraries are built, we need static for the updater.
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DZLIB_COMPAT=ON -DZLIBNG_ENABLE_TESTS=OFF -DZLIB_ENABLE_TESTS=OFF -DWITH_GTEST=OFF -B build -G Ninja || goto error
cmake --build build --parallel || goto error
ninja -C build install || goto error
cd .. || goto error
@ -184,13 +184,13 @@ ninja -C build install || goto error
cd .. || goto error
echo Building SDL...
rmdir /S /Q "SDL2-%SDL2%"
%SEVENZIP% x "SDL2-%SDL2%.zip" || goto error
cd "SDL2-%SDL2%" || goto error
cmake -B build -DCMAKE_BUILD_TYPE=Release %FORCEPDB% -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -G Ninja || goto error
rmdir /S /Q "SDL3-%SDL3%"
%SEVENZIP% x "SDL3-%SDL3%.zip" || goto error
cd "SDL3-%SDL3%" || goto error
cmake -B build -DCMAKE_BUILD_TYPE=Release %FORCEPDB% -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -DSDL_TESTS=OFF -G Ninja || goto error
cmake --build build --parallel || goto error
ninja -C build install || goto error
copy build\SDL2.pdb "%INSTALLDIR%\bin" || goto error
copy build\SDL3.pdb "%INSTALLDIR%\bin" || goto error
cd .. || goto error
if %DEBUG%==1 (

View file

@ -1,13 +0,0 @@
--- a/CMakeLists.txt 2024-12-29 21:34:43.219279282 +1000
+++ b/CMakeLists.txt 2024-12-29 21:34:59.495612349 +1000
@@ -3047,10 +3047,6 @@
listtostr(EXTRA_CFLAGS _EXTRA_CFLAGS)
set(EXTRA_CFLAGS ${_EXTRA_CFLAGS})
-if(USE_GCC OR USE_CLANG)
- string(REGEX REPLACE "(^| )-I" "\\1 -isystem" EXTRA_CFLAGS "${EXTRA_CFLAGS}")
-endif()
-
# Compat helpers for the configuration files
if(EXISTS "${PROJECT_SOURCE_DIR}/VERSION.txt")

View file

@ -0,0 +1,54 @@
from importlib.machinery import FileFinder
import json
import sys
import urllib.request
if len(sys.argv) < 3:
print(f"Syntax: {sys.argv[0]} WEB-API-KEY OUTPUT_FILE.yaml")
sys.exit(1)
print("Sending request...")
url = "https://retroachievements.org/API/API_GetGameList.php?y=" + sys.argv[1] + "&i=12&h=1&f=0"
req = urllib.request.Request(url)
req.add_header("User-Agent", "curl/8.10.1") # CF blocks urllib user agent
data = None
with urllib.request.urlopen(req) as response:
data = response.read().decode('utf-8')
data = json.loads(data)
print(f"Found {len(data)} entries in JSON")
games = {}
hashes = {}
for entry in data:
if ("ID" not in entry or \
"NumAchievements" not in entry or \
"Hashes" not in entry or \
len(entry["Hashes"]) == 0):
continue
game_id = int(entry["ID"])
num_achievements = int(entry["NumAchievements"])
if game_id not in games:
games[game_id] = num_achievements
else:
print(f"Duplicate game {game_id}")
for thash in entry["Hashes"]:
if thash in hashes:
print(f"Duplicate hash {thash}")
continue
hashes[thash] = game_id
print(f"Extracted {len(games)} games")
print(f"Extracted {len(hashes)} hashes")
with open(sys.argv[2], "w") as f:
f.write("hashes:\n")
for ghash, game_id in hashes.items():
f.write(f" {ghash}: {game_id}\n")
f.write("achievements:\n")
for game_id, num_achievements in games.items():
f.write(f" {game_id}: {num_achievements}\n")

View file

@ -1,9 +0,0 @@
if [[ -z "$I_WANT_A_BROKEN_WAYLAND_UI" ]]; then
echo "Forcing X11 instead of Wayland, due to various protocol limitations"
echo "and Qt issues. If you want to use Wayland, launch DuckStation with"
echo "I_WANT_A_BROKEN_WAYLAND_UI=YES set."
export QT_QPA_PLATFORM=xcb
else
echo "Wayland is not being disabled. Do not complain when things break."
fi

View file

@ -18,9 +18,9 @@ function retry_command {
this_dir="$(readlink -f "$(dirname "$0")")"
if [ "$#" -ne 5 ]; then
if [ "$#" -ne 4 ]; then
echo "Syntax: $0 <path to AppDir> <.deb arch> <triple> <ubuntu mirror> <binary to run>"
echo "e.g. $0 DuckStation.AppDir amd64 x86_64-linux-gnu https://archive.ubuntu.com/ubuntu/ duckstation-qt"
echo "e.g. $0 DuckStation.AppDir amd64 x86_64-linux-gnu duckstation-qt"
exit 1
fi
@ -28,22 +28,26 @@ fi
APPDIR=$1
DEBARCH=$2
TRIPLE=$3
MIRROR=$4
APPNAME=$5
APPNAME=$4
LIBC_PACKAGE_URL="${MIRROR}/pool/main/g/glibc/libc6_2.35-0ubuntu3.8_${DEBARCH}.deb"
LIBGCCS_PACKAGE_URL="${MIRROR}/pool/main/g/gcc-12/libgcc-s1_12.3.0-1ubuntu1~22.04_${DEBARCH}.deb"
LIBSTDCXX_PACKAGE_URL="${MIRROR}/pool/main/g/gcc-12/libstdc++6_12.3.0-1ubuntu1~22.04_${DEBARCH}.deb"
GLIBC_VERSION=2.35
if [ ! -f "libc.deb" ]; then
retry_command wget -O "libc.deb" "https://github.com/stenzek/duckstation-ext-qt-minimal/releases/download/linux/libc6_2.35-0ubuntu3.9_${DEBARCH}.deb"
fi
if [ ! -f "libgccs.deb" ]; then
retry_command wget -O "libgccs.deb" "https://github.com/stenzek/duckstation-ext-qt-minimal/releases/download/linux/libgcc-s1_12.3.0-1ubuntu1.22.04_${DEBARCH}.deb"
fi
if [ ! -f "libstdc++.deb" ]; then
retry_command wget -O "libstdc++.deb" "https://github.com/stenzek/duckstation-ext-qt-minimal/releases/download/linux/libstdc++6_12.3.0-1ubuntu1.22.04_${DEBARCH}.deb"
fi
rm -fr "temp"
mkdir "temp"
cd "temp"
retry_command wget -O "libc.deb" "${LIBC_PACKAGE_URL}"
retry_command wget -O "libgccs.deb" "${LIBGCCS_PACKAGE_URL}"
retry_command wget -O "libstdc++.deb" "${LIBSTDCXX_PACKAGE_URL}"
dpkg -x "libc.deb" .
dpkg -x "libgccs.deb" .
dpkg -x "libstdc++.deb" .
dpkg -x "../libc.deb" .
dpkg -x "../libgccs.deb" .
dpkg -x "../libstdc++.deb" .
# Copy everything into AppDir
RUNTIME="${APPDIR}/libc-runtime"

View file

@ -16,13 +16,13 @@ function retry_command {
# Workaround for https://github.com/actions/runner-images/issues/675
retry_command wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
retry_command sudo apt-add-repository -n 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-18 main'
retry_command sudo apt-add-repository -n 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-19 main'
retry_command sudo apt-get update
retry_command sudo apt-get -y install \
build-essential clang-18 cmake curl extra-cmake-modules git libasound2-dev libcurl4-openssl-dev libdbus-1-dev libdecor-0-dev libegl-dev libevdev-dev \
build-essential clang-19 cmake curl extra-cmake-modules git libasound2-dev libcurl4-openssl-dev libdbus-1-dev libdecor-0-dev libegl-dev libevdev-dev \
libfontconfig-dev libfreetype-dev libfuse2 libgtk-3-dev libgudev-1.0-dev libharfbuzz-dev libinput-dev libopengl-dev libpipewire-0.3-dev libpulse-dev \
libssl-dev libudev-dev libva-dev libwayland-dev libx11-dev libx11-xcb-dev libxcb1-dev libxcb-composite0-dev libxcb-cursor-dev libxcb-damage0-dev \
libxcb-glx0-dev libxcb-icccm4-dev libxcb-image0-dev libxcb-keysyms1-dev libxcb-present-dev libxcb-randr0-dev libxcb-render0-dev libxcb-render-util0-dev \
libxcb-shape0-dev libxcb-shm0-dev libxcb-sync-dev libxcb-util-dev libxcb-xfixes0-dev libxcb-xinput-dev libxcb-xkb-dev libxext-dev libxkbcommon-x11-dev \
libxrandr-dev lld-18 llvm-18 nasm ninja-build patchelf pkg-config zlib1g-dev
libxrandr-dev lld-19 llvm-19 nasm ninja-build patchelf pkg-config zlib1g-dev

View file

@ -34,6 +34,7 @@ APPDIRNAME=DuckStation.AppDir
STRIP=strip
declare -a MANUAL_LIBS=(
"libz.so.1"
"libavcodec.so.61"
"libavformat.so.61"
"libavutil.so.59"
@ -185,15 +186,6 @@ echo "Generating AppStream metainfo..."
mkdir -p "$OUTDIR/usr/share/metainfo"
"$SCRIPTDIR/../generate-metainfo.sh" "$OUTDIR/usr/share/metainfo"
# Copy in AppRun hooks.
echo "Copying AppRun hooks..."
mkdir -p "$OUTDIR/apprun-hooks"
for hookpath in "$SCRIPTDIR/apprun-hooks"/*; do
hookname=$(basename "$hookpath")
cp -v "$hookpath" "$OUTDIR/apprun-hooks/$hookname"
sed -i -e 's/exec /source "$this_dir"\/apprun-hooks\/"'"$hookname"'"\nexec /' "$OUTDIR/AppRun"
done
echo "Generating AppImage..."
rm -f "$NAME.AppImage"
"$APPIMAGETOOL" -v --runtime-file "$APPIMAGERUNTIME" "$OUTDIR" "$NAME.AppImage"

View file

@ -26,111 +26,74 @@ if [ "$1" == "-inject-libc" ]; then
fi
if [ "$#" -ne 5 ]; then
echo "Syntax: $0 [-inject-libc] <target arch> <path to build directory> <deps prefix> <chroot dir> <output name>"
echo "Syntax: $0 [-inject-libc] <duckstation-qt|duckstation-mini> <target arch> <path to build directory> <deps prefix> <chroot dir>"
exit 1
fi
ARCH=$1
BUILDDIR=$2
DEPSDIR=$3
CHROOTDIR=$4
NAME=$5
BINARY=$1
ARCH=$2
BUILDDIR=$3
DEPSDIR=$4
CHROOTDIR=$5
BINARY=duckstation-qt
APPDIRNAME=DuckStation.AppDir
STRIP=llvm-strip
TRIPLE="${ARCH}-linux-gnu"
if [ "$ARCH" == "arm64" ]; then
DEBARCH="arm64"
RUNTIMEARCH="aarch64"
TRIPLE="aarch64-linux-gnu"
elif [ "$ARCH" == "armhf" ]; then
DEBARCH="armhf"
RUNTIMEARCH="armhf"
TRIPLE="arm-linux-gnueabihf"
else
echo "Unknown arch ${ARCH}."
exit 1
fi
if [ "$BINARY" == "duckstation-qt" ]; then
echo "Building Qt AppImage."
ADD_QT_LIBS=true
APPIMAGENAME="DuckStation-${ARCH}"
elif [ "$BINARY" == "duckstation-mini" ]; then
echo "Building Mini AppImage."
ADD_QT_LIBS=false
APPIMAGENAME="DuckStation-Mini-${ARCH}"
else
echo "Unknown binary $BINARY"
exit 1
fi
APPDIRNAME="${APPIMAGENAME}.AppDir"
declare -a SYSLIBS=(
"libatk-1.0.so.0"
"libatk-bridge-2.0.so.0"
"libatspi.so.0"
"libblkid.so.1"
"libbrotlicommon.so.1"
"libbrotlidec.so.1"
"libbsd.so.0"
"libcairo-gobject.so.2"
"libcairo.so.2"
"libcap.so.2"
"libcrypto.so.3"
"libcurl.so.4"
"libdatrie.so.1"
"libdbus-1.so.3"
"libdeflate.so.0"
"libepoxy.so.0"
"libffi.so.8"
"libgcrypt.so.20"
"libgdk-3.so.0"
"libgdk_pixbuf-2.0.so.0"
"libgio-2.0.so.0"
"libglib-2.0.so.0"
"libgmodule-2.0.so.0"
"libgnutls.so.30"
"libgobject-2.0.so.0"
"libgraphite2.so.3"
"libgssapi_krb5.so.2"
"libgtk-3.so.0"
"libhogweed.so.6"
"libidn2.so.0"
"libjbig.so.0"
"libk5crypto.so.3"
"libkeyutils.so.1"
"libkrb5.so.3"
"libkrb5support.so.0"
"liblber-2.5.so.0"
"libldap-2.5.so.0"
"liblz4.so.1"
"liblzma.so.5"
"libmd.so.0"
"libmount.so.1"
"libnettle.so.8"
"libnghttp2.so.14"
"libp11-kit.so.0"
"libpango-1.0.so.0"
"libpangocairo-1.0.so.0"
"libpangoft2-1.0.so.0"
"libpcre2-16.so.0"
"libpcre2-8.so.0"
"libpcre.so.3"
"libpixman-1.so.0"
"libpsl.so.5"
"librtmp.so.1"
"libsasl2.so.2"
"libselinux.so.1"
"libssh.so.4"
"libssl.so.3"
"libsystemd.so.0"
"libtasn1.so.6"
"libtiff.so.5"
"libudev.so.1"
"libunistring.so.2"
"libXau.so.6"
"libxcb-cursor.so.0"
"libxcb-glx.so.0"
"libxcb-icccm.so.4"
"libxcb-image.so.0"
"libxcb-keysyms.so.1"
"libxcb-randr.so.0"
"libxcb-render.so.0"
"libxcb-render-util.so.0"
"libxcb-shape.so.0"
"libxcb-shm.so.0"
"libxcb-sync.so.1"
"libxcb-util.so.1"
"libxcb-xfixes.so.0"
"libxcb-xkb.so.1"
"libXcomposite.so.1"
"libXcursor.so.1"
"libXdamage.so.1"
"libXdmcp.so.6"
"libXext.so.6"
"libXfixes.so.3"
"libXinerama.so.1"
"libXi.so.6"
"libxkbcommon.so.0"
"libxkbcommon-x11.so.0"
"libXrandr.so.2"
"libXrender.so.1"
)
declare -a DEPLIBS=(
@ -139,7 +102,7 @@ declare -a DEPLIBS=(
"libharfbuzz.so"
"libjpeg.so.62"
"libpng16.so.16"
"libSDL2-2.0.so.0"
"libSDL3.so.0"
"libsharpyuv.so.0"
"libwebpdemux.so.2"
"libwebpmux.so.3"
@ -163,36 +126,103 @@ declare -a DEPLIBS=(
#"libva.so.2"
)
declare -a QTLIBS=(
"libQt6Core.so.6"
"libQt6DBus.so.6"
"libQt6Gui.so.6"
"libQt6OpenGL.so.6"
"libQt6Svg.so.6"
"libQt6WaylandClient.so.6"
"libQt6WaylandEglClientHwIntegration.so.6"
"libQt6Widgets.so.6"
"libQt6XcbQpa.so.6"
)
if [ "${ADD_QT_LIBS}" == true ]; then
SYSLIBS+=(
"libatk-1.0.so.0"
"libatk-bridge-2.0.so.0"
"libatspi.so.0"
"libblkid.so.1"
"libcairo-gobject.so.2"
"libcairo.so.2"
"libcap.so.2"
"libdatrie.so.1"
"libdeflate.so.0"
"libdbus-1.so.3"
"libepoxy.so.0"
"libgcrypt.so.20"
"libgdk-3.so.0"
"libgdk_pixbuf-2.0.so.0"
"libgio-2.0.so.0"
"libglib-2.0.so.0"
"libgmodule-2.0.so.0"
"libgobject-2.0.so.0"
"libgraphite2.so.3"
"libgtk-3.so.0"
"libjbig.so.0"
"liblz4.so.1"
"liblzma.so.5"
"libmd.so.0"
"libmount.so.1"
"libpango-1.0.so.0"
"libpangocairo-1.0.so.0"
"libpangoft2-1.0.so.0"
"libpcre2-16.so.0"
"libpcre2-8.so.0"
"libpcre.so.3"
"libpixman-1.so.0"
"libselinux.so.1"
"libsystemd.so.0"
"libtiff.so.5"
"libXau.so.6"
"libxcb-cursor.so.0"
"libxcb-glx.so.0"
"libxcb-icccm.so.4"
"libxcb-image.so.0"
"libxcb-keysyms.so.1"
"libxcb-randr.so.0"
"libxcb-render.so.0"
"libxcb-render-util.so.0"
"libxcb-shape.so.0"
"libxcb-shm.so.0"
"libxcb-sync.so.1"
"libxcb-util.so.1"
"libxcb-xfixes.so.0"
"libxcb-xkb.so.1"
"libXcomposite.so.1"
"libXcursor.so.1"
"libXdamage.so.1"
"libXdmcp.so.6"
"libXext.so.6"
"libXfixes.so.3"
"libXinerama.so.1"
"libXi.so.6"
"libxkbcommon.so.0"
"libxkbcommon-x11.so.0"
"libXrandr.so.2"
"libXrender.so.1"
)
declare -a QTPLUGINS=(
"plugins/iconengines"
"plugins/imageformats"
"plugins/platforminputcontexts"
"plugins/platforms"
"plugins/platformthemes"
"plugins/wayland-decoration-client"
"plugins/wayland-graphics-integration-client"
"plugins/wayland-shell-integration"
"plugins/xcbglintegrations"
)
declare -a QTLIBS=(
"libQt6Core.so.6"
"libQt6DBus.so.6"
"libQt6Gui.so.6"
"libQt6OpenGL.so.6"
"libQt6Svg.so.6"
"libQt6WaylandClient.so.6"
"libQt6WaylandEglClientHwIntegration.so.6"
"libQt6Widgets.so.6"
"libQt6XcbQpa.so.6"
)
declare -a QTPLUGINS=(
"plugins/iconengines"
"plugins/imageformats"
"plugins/platforminputcontexts"
"plugins/platforms"
"plugins/platformthemes"
"plugins/wayland-decoration-client"
"plugins/wayland-graphics-integration-client"
"plugins/wayland-shell-integration"
"plugins/xcbglintegrations"
)
fi
set -e
IFS="
"
APPIMAGETOOL=./appimagetool-x86_64
APPIMAGERUNTIME=./runtime-${ARCH}
APPIMAGERUNTIME=./runtime-${RUNTIMEARCH}
PATCHELF=patchelf
if [ ! -f "$APPIMAGETOOL" ]; then
@ -201,7 +231,7 @@ if [ ! -f "$APPIMAGETOOL" ]; then
fi
if [ ! -f "$APPIMAGERUNTIME" ]; then
retry_command wget -O "$APPIMAGERUNTIME" https://github.com/stenzek/type2-runtime/releases/download/continuous/runtime-${ARCH}
retry_command wget -O "$APPIMAGERUNTIME" https://github.com/stenzek/type2-runtime/releases/download/continuous/runtime-${RUNTIMEARCH}
fi
OUTDIR=$(realpath "./$APPDIRNAME")
@ -212,10 +242,6 @@ mkdir -p "$OUTDIR/usr/bin" "$OUTDIR/usr/lib"
echo "Copying binary and resources..."
cp -a "$BUILDDIR/bin/$BINARY" "$BUILDDIR/bin/resources" "$BUILDDIR/bin/translations" "$OUTDIR/usr/bin"
# Currently we leave the main binary unstripped, uncomment if this is not desired.
# NOTE: Strip must come before patchelf, otherwise shit breaks.
$STRIP "$OUTDIR/usr/bin/$BINARY"
# Patch RPATH so the binary goes hunting for shared libraries in the AppDir instead of system.
echo "Patching RPATH in ${BINARY}..."
patchelf --set-rpath '$ORIGIN/../lib' "$OUTDIR/usr/bin/$BINARY"
@ -238,7 +264,7 @@ for lib in "${SYSLIBS[@]}"; do
exit 1
fi
$STRIP $OUTDIR/usr/lib/$blib
"$STRIP" $OUTDIR/usr/lib/$blib
done
echo "Copying local libraries..."
@ -252,28 +278,37 @@ for lib in "${DEPLIBS[@]}"; do
exit 1
fi
$STRIP "$OUTDIR/usr/lib/$blib"
"$STRIP" "$OUTDIR/usr/lib/$blib"
done
echo "Copying Qt libraries..."
for lib in "${QTLIBS[@]}"; do
cp -avL "$DEPSDIR/lib/$lib" "$OUTDIR/usr/lib"
$STRIP "$OUTDIR/usr/lib/$lib"
done
if [ "${ADD_QT_LIBS}" == true ]; then
echo "Copying Qt libraries..."
for lib in "${QTLIBS[@]}"; do
cp -avL "$DEPSDIR/lib/$lib" "$OUTDIR/usr/lib"
"$STRIP" "$OUTDIR/usr/lib/$lib"
done
echo "Copying Qt plugins..."
mkdir -p $OUTDIR/usr/lib/plugins
for plugin in "${QTPLUGINS[@]}"; do
mkdir -p "$OUTDIR/usr/lib/$plugin"
cp -avL "$DEPSDIR/$plugin/"*.so "$OUTDIR/usr/lib/$plugin/"
done
echo "Copying Qt plugins..."
mkdir -p $OUTDIR/usr/lib/plugins
for plugin in "${QTPLUGINS[@]}"; do
mkdir -p "$OUTDIR/usr/lib/$plugin"
cp -avL "$DEPSDIR/$plugin/"*.so "$OUTDIR/usr/lib/$plugin/"
done
for so in $(find $OUTDIR/usr/lib/plugins -iname '*.so'); do
# This is ../../ because it's usually plugins/group/name.so
echo "Patching RPATH in ${so}..."
patchelf --set-rpath '$ORIGIN/../..' "$so"
$STRIP "$so"
done
for so in $(find $OUTDIR/usr/lib/plugins -iname '*.so'); do
# This is ../../ because it's usually plugins/group/name.so
echo "Patching RPATH in ${so}..."
patchelf --set-rpath '$ORIGIN/../..' "$so"
"$STRIP" "$so"
done
echo "Creating qt.conf..."
cat > "$OUTDIR/usr/bin/qt.conf" << EOF
[Paths]
Plugins = ../lib/plugins
EOF
fi
for so in $(find $OUTDIR/usr/lib -maxdepth 1); do
if [ -f "$so" ]; then
@ -282,12 +317,6 @@ for so in $(find $OUTDIR/usr/lib -maxdepth 1); do
fi
done
echo "Creating qt.conf..."
cat > "$OUTDIR/usr/bin/qt.conf" << EOF
[Paths]
Plugins = ../lib/plugins
EOF
# Copy desktop/icon
echo "Copying desktop/icon..."
mkdir -p "$OUTDIR/usr/share/applications"
@ -307,28 +336,15 @@ cp "$SCRIPTDIR/apprun-cross.sh" "$OUTDIR/AppRun"
chmod +x "$OUTDIR/AppRun"
ln -s "usr/bin/$BINARY" "$OUTDIR/AppRun.wrapped"
# Copy in AppRun hooks.
echo "Copying AppRun hooks..."
mkdir -p "$OUTDIR/apprun-hooks"
for hookpath in "$SCRIPTDIR/apprun-hooks"/*; do
hookname=$(basename "$hookpath")
cp -v "$hookpath" "$OUTDIR/apprun-hooks/$hookname"
sed -i -e 's/exec /source "$this_dir"\/apprun-hooks\/"'"$hookname"'"\nexec /' "$OUTDIR/AppRun"
done
# Optionally inject libc
if [ "$INJECT_LIBC" == true ]; then
echo "Injecting libc/libc++..."
if [ "$ARCH" == "aarch64" ]; then
DEBARCH="arm64"
else
echo "Unknown arch for libc injection."
exit 1
fi
"$SCRIPTDIR/inject-libc.sh" "$OUTDIR" "$DEBARCH" "$TRIPLE" "https://ports.ubuntu.com" "$BINARY"
"$SCRIPTDIR/inject-libc.sh" "$OUTDIR" "$DEBARCH" "$TRIPLE" "$BINARY"
fi
echo "Generating AppImage..."
rm -f "$NAME.AppImage"
"$APPIMAGETOOL" -v --runtime-file "$APPIMAGERUNTIME" "$OUTDIR" "$NAME.AppImage"
rm -f "$APPIMAGENAME.AppImage"
# Can't run the appimage in a docker container because no fuse, so extract it first.
"$APPIMAGETOOL" --appimage-extract
"$PWD/squashfs-root/AppRun" -v --runtime-file "$APPIMAGERUNTIME" "$OUTDIR" "$APPIMAGENAME.AppImage"

View file

@ -3,6 +3,11 @@
# NOTE: These package files are intended for your own personal/private use.
# You do not have permission to upload them independently to other package repositories.
#
# To build yourself:
# git clone https://github.com/stenzek/duckstation.git
# cd duckstation/scripts/packaging/arch
# makepkg -i
pkgname=duckstation
pkgver=0
@ -28,9 +33,9 @@ depends=('libjpeg.so' # libjpeg or libjpeg-turbo
'libx11'
'libxrandr'
'libzip'
'qt6-base>=6.8.0'
'qt6-imageformats>=6.8.0'
'qt6-svg>=6.8.0'
'qt6-base>=6.8.2'
'qt6-imageformats>=6.8.2'
'qt6-svg>=6.8.2'
'wayland'
'zlib'
'zstd'
@ -46,17 +51,26 @@ makedepends=('base-devel'
'lld'
'llvm'
'ninja'
'qt6-tools>=6.8.0')
'qt6-tools>=6.8.2')
source=(
"${pkgname}::git+file://${startdir}/../../.."
"https://github.com/duckstation/chtdb/releases/download/latest/cheats.zip"
"https://github.com/duckstation/chtdb/releases/download/latest/patches.zip"
)
sha256sums=(
"SKIP"
"SKIP"
"SKIP"
)
noextract=(
"cheats.zip"
"patches.zip"
)
# Name of the .desktop file that will be installed.
_desktopname=org.duckstation.DuckStation
_destdir=/opt/duckstation
# https://wiki.archlinux.org/title/VCS_package_guidelines#Git
# --dirty omitted, we need to ignore changes to this script because
@ -70,6 +84,9 @@ pkgver() {
prepare() {
cd "${pkgname}"
# Copy resources
cp "../cheats.zip" "../patches.zip" "data/resources"
# Are we creating a CI/official build?
_tagpath="${startdir}/../../../src/scmversion/tag.h"
if [[ -f "${_tagpath}" ]]; then
@ -87,7 +104,7 @@ prepare() {
./scripts/deps/build-dependencies-linux.sh \
-system-freetype -system-harfbuzz -system-libjpeg \
-system-libpng -system-libwebp -system-libzip \
-system-zstd -system-qt \
-system-zlib -system-zstd -system-qt \
"${_depsdir}"
fi
}
@ -108,7 +125,7 @@ build() {
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
-DALLOW_INSTALL=ON \
-DINSTALL_SELF_CONTAINED=ON \
-DCMAKE_INSTALL_PREFIX="${pkgdir}/opt/duckstation"
-DCMAKE_INSTALL_PREFIX="${pkgdir}${_destdir}"
ninja -C build-arch
}
@ -116,8 +133,9 @@ package() {
cd "${pkgname}"
ninja -C build-arch install
# install wrapper script
install -Dm755 scripts/packaging/duckstation-qt "${pkgdir}/usr/bin/duckstation-qt"
# install alias
mkdir -p "${pkgdir}/usr/bin"
ln -s "${_destdir}/duckstation-qt" "${pkgdir}/usr/bin/duckstation-qt"
# install desktop file and icon
install -Dm644 scripts/packaging/${_desktopname}.desktop "${pkgdir}/usr/share/applications/${_desktopname}.desktop"
@ -127,4 +145,3 @@ package() {
install -Dm644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
install -Dm644 data/resources/thirdparty.html "${pkgdir}/usr/share/licenses/${pkgname}/thirdparty.html"
}

View file

@ -1,13 +0,0 @@
#!/bin/sh
if [[ -z "$I_WANT_A_BROKEN_WAYLAND_UI" ]]; then
echo "Forcing X11 instead of Wayland, due to various protocol limitations"
echo "and Qt issues. If you want to use Wayland, launch DuckStation with"
echo "I_WANT_A_BROKEN_WAYLAND_UI=YES set."
export QT_QPA_PLATFORM=xcb
else
echo "Wayland is not being disabled. Do not complain when things break."
fi
exec /opt/duckstation/duckstation-qt "$@"

View file

@ -1,8 +1,13 @@
# SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
# SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
# SPDX-License-Identifier: CC-BY-NC-ND-4.0
# NOTE: These package files are intended for your own personal/private use.
# You do not have permission to upload them independently to other package repositories.
#
# To build:
# git clone https://github.com/stenzek/duckstation.git
# rpmbuild -bb scripts/packaging/fedora/duckstation.spec
# sudo rpm -ivh ~/rpmbuild/RPMS/duckstation-*.rpm
Name: duckstation
Version: 0.0.0
@ -14,7 +19,7 @@ BuildRequires: alsa-lib-devel, clang, cmake, dbus-devel, egl-wayland-devel, extr
BuildRequires: extra-cmake-modules, freetype-devel, libavcodec-free-devel, libavformat-free-devel
BuildRequires: libavutil-free-devel, libcurl-devel, libevdev-devel, libswresample-free-devel
BuildRequires: libswscale-free-devel, libpng-devel, libwebp-devel, libX11-devel, libXrandr-devel
BuildRequires: libzip-devel, libzstd-devel, lld, llvm, make, mesa-libEGL-devel, mesa-libGL-devel
BuildRequires: libzip-devel, libzip-tools, libzstd-devel, lld, llvm, make, mesa-libEGL-devel, mesa-libGL-devel
BuildRequires: ninja-build, patch, pipewire-devel pulseaudio-libs-devel, wayland-devel, zlib-devel
BuildRequires: qt6-qtbase-devel, qt6-qtbase-private-devel, qt6-qttools, qt6-qttools-devel
@ -28,7 +33,7 @@ Requires: qt6-qtbase qt6-qtbase-gui qt6-qtimageformats qt6-qtsvg
%undefine _include_frame_pointers
# Defines -O2, -flto, and others. We manage LTO ourselves.
%global _general_options "-O2" "-pipe"
%global _general_options "-O3" "-pipe"
%global _preprocessor_defines ""
# We include debug information in the main package for user backtrace reporting.
@ -44,6 +49,8 @@ DuckStation is an simulator/emulator of the Sony PlayStation(TM) console, focusi
%prep
%setup -n duckstation -c -T
git clone file://%{SOURCEURL0} .
curl -L -o "data/resources/cheats.zip" "https://github.com/duckstation/chtdb/releases/download/latest/cheats.zip"
curl -L -o "data/resources/patches.zip" "https://github.com/duckstation/chtdb/releases/download/latest/patches.zip"
if [ -f "%{SOURCEURL0}/src/scmversion/tag.h" ]; then
echo "Copying SCM release tag..."
cp "%{SOURCEURL0}/src/scmversion/tag.h" src/scmversion
@ -52,7 +59,7 @@ fi
%build
if [ ! -d "${PWD}/deps" ]; then
scripts/deps/build-dependencies-linux.sh -system-freetype -system-harfbuzz -system-libjpeg -system-libpng -system-libwebp -system-libzip -system-zstd -system-qt "${PWD}/deps"
scripts/deps/build-dependencies-linux.sh -system-freetype -system-harfbuzz -system-libjpeg -system-libpng -system-libwebp -system-libzip -system-zlib -system-zstd -system-qt "${PWD}/deps"
fi
rm -fr build
@ -70,7 +77,8 @@ ninja -C build %{?_smp_mflags}
%install
rm -fr %{buildroot}
ninja -C build install
install -Dm755 scripts/packaging/duckstation-qt %{buildroot}/usr/bin/duckstation-qt
mkdir -p %{buildroot}/usr/bin
ln -s /opt/duckstation/duckstation-qt %{buildroot}/usr/bin/duckstation-qt
install -Dm644 scripts/packaging/org.duckstation.DuckStation.png %{buildroot}/usr/share/icons/hicolor/512x512/apps/org.duckstation.DuckStation.png
install -Dm644 scripts/packaging/org.duckstation.DuckStation.desktop %{buildroot}/usr/share/applications/org.duckstation.DuckStation.desktop

View file

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
# SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
# SPDX-License-Identifier: CC-BY-NC-ND-4.0
name: libzip
@ -26,7 +26,7 @@ build-options:
sources:
- type: git
url: "https://github.com/nih-at/libzip.git"
commit: "64b62d6b1a686a1b0bac1b6b9dcb635be0499afb"
commit: "f30f5290de485348442d168cd7b2eb714d1f20f9"
cleanup:
- /bin
- /include

View file

@ -14,7 +14,7 @@ build-options:
sources:
- type: git
url: "https://github.com/stenzek/shaderc.git"
commit: "1c0d3d18819aa75ec74f1fbd9ff0461e1b69a4d6"
commit: "fc65b19d2098cf81e55b4edc10adad2ad8268361"
cleanup:
- /bin
- /include

View file

@ -22,8 +22,8 @@ build-options:
sources:
- type: git
url: "https://github.com/KhronosGroup/SPIRV-Cross.git"
tag: "vulkan-sdk-1.3.290.0"
commit: "5d127b917f080c6f052553c47170ec0ba702e54f"
tag: "vulkan-sdk-1.4.304.0"
commit: "ebe2aa0cd80f5eb5cd8a605da604cacf72205f3b"
cleanup:
- /bin
- /include

View file

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
# SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
# SPDX-License-Identifier: CC-BY-NC-ND-4.0
name: cpuinfo
@ -20,7 +20,7 @@ build-options:
sources:
- type: git
url: "https://github.com/stenzek/cpuinfo.git"
commit: "7524ad504fdcfcf75a18a133da6abd75c5d48053"
commit: "3ebbfd45645650c4940bf0f3b4d25ab913466bb0"
cleanup:
- /bin
- /include

View file

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
# SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
# SPDX-License-Identifier: CC-BY-NC-ND-4.0
name: soundtouch
@ -9,8 +9,8 @@ config-opts:
# Use clang with LTO for speed.
- "-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON"
- "-DCMAKE_C_COMPILER=/usr/lib/sdk/llvm18/bin/clang"
- "-DCMAKE_CXX_COMPILER=/usr/lib/sdk/llvm18/bin/clang++"
- "-DCMAKE_C_COMPILER=/usr/lib/sdk/llvm19/bin/clang"
- "-DCMAKE_CXX_COMPILER=/usr/lib/sdk/llvm19/bin/clang++"
- "-DCMAKE_EXE_LINKER_FLAGS_INIT=-fuse-ld=lld"
- "-DCMAKE_MODULE_LINKER_FLAGS_INIT=-fuse-ld=lld"
- "-DCMAKE_SHARED_LINKER_FLAGS_INIT=-fuse-ld=lld"

View file

@ -1,7 +1,7 @@
# SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
# SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
# SPDX-License-Identifier: CC-BY-NC-ND-4.0
name: sdl2
name: sdl3
buildsystem: cmake-ninja
builddir: true
config-opts:
@ -11,11 +11,12 @@ config-opts:
- "-DSDL_STATIC=OFF"
- "-DSDL_TESTS=OFF"
build-options:
strip: true
strip: false
no-debuginfo: true
sources:
- type: archive
url: "https://github.com/libsdl-org/SDL/releases/download/release-2.30.11/SDL2-2.30.11.tar.gz"
sha256: "8b8d4aef2038533da814965220f88f77d60dfa0f32685f80ead65e501337da7f"
url: "https://github.com/libsdl-org/SDL/releases/download/release-3.2.8/SDL3-3.2.8.tar.gz"
sha256: "13388fabb361de768ecdf2b65e52bb27d1054cae6ccb6942ba926e378e00db03"
cleanup:
- /bin
- /include

View file

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
# SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
# SPDX-License-Identifier: CC-BY-NC-ND-4.0
app-id: "org.duckstation.DuckStation"
@ -6,7 +6,7 @@ runtime: "org.kde.Platform"
runtime-version: "6.8"
sdk: "org.kde.Sdk"
sdk-extensions:
- "org.freedesktop.Sdk.Extension.llvm18"
- "org.freedesktop.Sdk.Extension.llvm19"
add-extensions:
"org.freedesktop.Platform.ffmpeg-full":
directory: "lib/ffmpeg"
@ -23,22 +23,20 @@ finish-args:
- "--share=ipc"
- "--socket=pulseaudio"
- "--talk-name=org.freedesktop.ScreenSaver"
# Wayland is disabled due to various QtWayland issues, causing broken UI.
- "--socket=x11"
- "--env=QT_QPA_PLATFORM=xcb"
- "--socket=wayland"
- "--socket=fallback-x11"
modules:
# Dependencies.
- "modules/10-libbacktrace.yaml"
- "modules/11-libzip.yaml"
- "modules/20-sdl2.yaml"
- "modules/21-shaderc.yaml"
- "modules/22-spirv-cross.yaml"
- "modules/23-cpuinfo.yaml"
- "modules/24-discord-rpc.yaml"
- "modules/25-soundtouch.yaml"
- "modules/26-lunasvg.yaml"
- "modules/20-shaderc.yaml"
- "modules/21-spirv-cross.yaml"
- "modules/22-cpuinfo.yaml"
- "modules/23-discord-rpc.yaml"
- "modules/24-soundtouch.yaml"
- "modules/25-lunasvg.yaml"
- "modules/30-sdl3.yaml"
# Main module.
- name: duckstation
@ -73,8 +71,8 @@ modules:
# Make sure we're using ThinLTO.
- "-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON"
- "-DCMAKE_C_COMPILER=/usr/lib/sdk/llvm18/bin/clang"
- "-DCMAKE_CXX_COMPILER=/usr/lib/sdk/llvm18/bin/clang++"
- "-DCMAKE_C_COMPILER=/usr/lib/sdk/llvm19/bin/clang"
- "-DCMAKE_CXX_COMPILER=/usr/lib/sdk/llvm19/bin/clang++"
- "-DCMAKE_EXE_LINKER_FLAGS_INIT=-fuse-ld=lld"
- "-DCMAKE_MODULE_LINKER_FLAGS_INIT=-fuse-ld=lld"
- "-DCMAKE_SHARED_LINKER_FLAGS_INIT=-fuse-ld=lld"

View file

@ -10,6 +10,44 @@
<description>
<p>DuckStation is an simulator/emulator of the Sony PlayStation(TM) console, focusing on playability, speed, and long-term maintainability. The goal is to be as accurate as possible while maintaining performance suitable for low-end devices.</p>
<p>"Hack" options are discouraged, the default configuration should support all playable games with only some of the enhancements having compatibility issues.</p>
<p>DuckStation features a fully-featured frontend built using Qt, as well as a fullscreen/TV UI based on Dear ImGui. Other features include:</p>
<ul>
<li>Hardware renderer supporting OpenGL and Vulkan APIs.</li>
<li>Upscaling, texture filtering, and true colour (24-bit) in hardware renderers.</li>
<li>PGXP for geometry precision, texture correction, and depth buffer emulation.</li>
<li>Accurate blending via Rasterizer Order Views/Fragment Shader Interlock.</li>
<li>Texture replacement system in hardware renderers.</li>
<li>Vectorized and multi-threaded software renderer.</li>
<li>Motion adaptive deinterlacing.</li>
<li>Adaptive downsampling filter.</li>
<li>Screen rotation for vertical or "TATE" shmup games.</li>
<li>Post processing shader chains (GLSL and Reshade FX).</li>
<li>Border overlays/bezels displayed around game content.</li>
<li>"Fast boot" for skipping BIOS splash/intro.</li>
<li>Save state support, with runahead and rewind.</li>
<li>Supports reading directly from CD, bin/cue images, raw bin/img files, MAME CHD, single-track ECM, MDS/MDF, and unencrypted PBP formats.</li>
<li>Preloading of disc images to RAM to avoid disk sleeping hitches.</li>
<li>Merging of multi-disc games in game list/grid with memory cards shared between discs.</li>
<li>Automatic loading/applying of PPF patches.</li>
<li>Direct booting of homebrew executables.</li>
<li>Direct loading of Portable Sound Format (psf) files.</li>
<li>Time stretched audio when running outside of 100% speed.</li>
<li>Digital and analog controllers for input (rumble is forwarded to host).</li>
<li>GunCon and Justifier lightgun support (simulated with mouse).</li>
<li>NeGcon support.</li>
<li>Controller presets and per-game configuration.</li>
<li>Automatic content scanning - game titles/hashes are provided by redump.org.</li>
<li>Optional automatic switching of memory cards for each game.</li>
<li>Supports loading cheats from existing lists.</li>
<li>Memory card editor and save importer.</li>
<li>Emulated CPU overclocking.</li>
<li>Integrated and remote debugging.</li>
<li>Multitap controllers (up to 8 devices).</li>
<li>RetroAchievements.</li>
<li>Video capture with FFmpeg backends.</li>
<li>Free camera function.</li>
<li>Parallel port cartridge emulation.</li>
</ul>
<p>"PlayStation" and "PSX" are registered trademarks of Sony Interactive Entertainment Europe Limited. This project is not affiliated in any way with Sony Interactive Entertainment.</p>
</description>
<content_rating type="oars-1.1"/>
@ -19,13 +57,21 @@
<url type="vcs-browser">https://github.com/stenzek/duckstation</url>
<screenshots>
<screenshot type="default">
<image>https://raw.githubusercontent.com/stenzek/duckstation/md-images/main-qt.png</image>
<image>https://raw.githubusercontent.com/stenzek/duckstation/md-images/linux-main-qt.png</image>
<caption>Desktop Interface</caption>
</screenshot>
<screenshot>
<image>https://raw.githubusercontent.com/stenzek/duckstation/md-images/bigduck.png</image>
<image>https://raw.githubusercontent.com/stenzek/duckstation/md-images/linux-bigpicture.png</image>
<caption>Big Picture Mode Interface</caption>
</screenshot>
<screenshot>
<image>https://raw.githubusercontent.com/stenzek/duckstation/md-images/linux-hover.png</image>
<caption>Hover Racing Game</caption>
</screenshot>
<screenshot>
<image>https://raw.githubusercontent.com/stenzek/duckstation/md-images/linux-fromage.png</image>
<caption>Fromage Game</caption>
</screenshot>
</screenshots>
<releases>
<release version="@GIT_VERSION@" date="@GIT_DATE@" />

Some files were not shown because too many files have changed in this diff Show more