mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-08 08:10:30 -10:00
Compare commits
344
Commits
SAPI_NVDA_auto
...
v1.8.7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1158b988c | ||
|
|
fb073544d2 | ||
|
|
a8d8523747 | ||
|
|
ef9a3c2007 | ||
|
|
b0a549716f | ||
|
|
435af0f982 | ||
|
|
8c2c094830 | ||
|
|
feb39a114d | ||
|
|
b7f56fc551 | ||
|
|
d3a55ef732 | ||
|
|
b910e6230f | ||
|
|
69949187f6 | ||
|
|
b53f635441 | ||
|
|
c31d4e6b69 | ||
|
|
706875160e | ||
|
|
a8eaf82e06 | ||
|
|
82666abbdd | ||
|
|
e7c909fe66 | ||
|
|
d9673b8c8f | ||
|
|
383fdae18f | ||
|
|
9d5a54ced4 | ||
|
|
50b4492fef | ||
|
|
eff8c31ffd | ||
|
|
89c7d1a835 | ||
|
|
7d517a431d | ||
|
|
718e9eaf37 | ||
|
|
fe42f6bb73 | ||
|
|
f1f248dd11 | ||
|
|
cab004f08a | ||
|
|
1545285953 | ||
|
|
31d9fedf47 | ||
|
|
6c4c93e17b | ||
|
|
ba452c204b | ||
|
|
70c57beea9 | ||
|
|
edb308ceb2 | ||
|
|
2ab7da36f2 | ||
|
|
cfd0731422 | ||
|
|
494c0f8fe4 | ||
|
|
1d1c7e5a0d | ||
|
|
bde18ba86a | ||
|
|
9088137051 | ||
|
|
cc50eaa88f | ||
|
|
86b78e2fea | ||
|
|
57bbf7c944 | ||
|
|
84369cf6ba | ||
|
|
3981b1cc82 | ||
|
|
e8d2ea7a56 | ||
|
|
1fabb661a6 | ||
|
|
709d6a2214 | ||
|
|
ca9c022a7f | ||
|
|
34b8b457c7 | ||
|
|
6d184abf84 | ||
|
|
05500c6c39 | ||
|
|
306fed32f6 | ||
|
|
67c3c93aec | ||
|
|
7b351da006 | ||
|
|
cc73de48d6 | ||
|
|
cc52f140d0 | ||
|
|
4093616e09 | ||
|
|
96cfa57d1b | ||
|
|
ef4261e1f8 | ||
|
|
4fe372662a | ||
|
|
43b890a269 | ||
|
|
6a4a522244 | ||
|
|
dd721def41 | ||
|
|
81a623c2b6 | ||
|
|
1534e81bed | ||
|
|
718d9801da | ||
|
|
42c5bb970e | ||
|
|
26c01dd34c | ||
|
|
98daa0d28c | ||
|
|
01667b5fc3 | ||
|
|
4a9e1e6c7e | ||
|
|
f5b33c8912 | ||
|
|
35269cce93 | ||
|
|
685db05032 | ||
|
|
39dbfd1db4 | ||
|
|
57cd3fdf06 | ||
|
|
1d2dd249f3 | ||
|
|
cdfb8348b0 | ||
|
|
211a8a149b | ||
|
|
c2b7ebbcdf | ||
|
|
c4ee0463aa | ||
|
|
edfafd9fad | ||
|
|
9c749f03eb | ||
|
|
58b9b6c875 | ||
|
|
29929acdba | ||
|
|
3c192419dd | ||
|
|
7b8983a0e0 | ||
|
|
e74161bc6c | ||
|
|
10e6ea21a3 | ||
|
|
ba8a07a2b6 | ||
|
|
a8e3917613 | ||
|
|
1e9b94ded4 | ||
|
|
2f3ef75bf6 | ||
|
|
3ad4b057f9 | ||
|
|
1fc64df5f6 | ||
|
|
1e6ccb2310 | ||
|
|
29a28f0d02 | ||
|
|
aa5ddee807 | ||
|
|
7a3ddcd77d | ||
|
|
63644ac761 | ||
|
|
df3af35ee4 | ||
|
|
e519ccd0be | ||
|
|
470756e22c | ||
|
|
09e54d1e75 | ||
|
|
38c8369e58 | ||
|
|
9fb170bcd4 | ||
|
|
e1d0514ec5 | ||
|
|
ad7612eef3 | ||
|
|
33cf0e160c | ||
|
|
b78c48c2c3 | ||
|
|
778b42de58 | ||
|
|
2f392f2260 | ||
|
|
ad34f4845b | ||
|
|
36802f7133 | ||
|
|
ca782bd015 | ||
|
|
7b3aaa6bbb | ||
|
|
16d12e804c | ||
|
|
25be09acd3 | ||
|
|
621e220177 | ||
|
|
a305a48a11 | ||
|
|
877a7f8d6c | ||
|
|
702bc18128 | ||
|
|
afe68f9cd8 | ||
|
|
3ecde62930 | ||
|
|
ab7c2f23cf | ||
|
|
0554e3cb3d | ||
|
|
c9dcc18fa4 | ||
|
|
43c521de44 | ||
|
|
4ef5eb1eb2 | ||
|
|
1a07476138 | ||
|
|
3f2ba2e791 | ||
|
|
9dc963e15a | ||
|
|
fb28c79e13 | ||
|
|
1e751d00ea | ||
|
|
548c5dc925 | ||
|
|
9c100ded3a | ||
|
|
5160f35bd8 | ||
|
|
34d3641d0a | ||
|
|
4198a0d3a8 | ||
|
|
8f0ef54455 | ||
|
|
e92331cf1f | ||
|
|
3a3c4f60bf | ||
|
|
19a8a815f0 | ||
|
|
35bf716766 | ||
|
|
3883616d93 | ||
|
|
de0b34aa0a | ||
|
|
e14fc1b087 | ||
|
|
53d07b30cc | ||
|
|
0b294faa71 | ||
|
|
d995fa045a | ||
|
|
5ed60cde04 | ||
|
|
bb27496e2e | ||
|
|
9b8c596057 | ||
|
|
30555f8132 | ||
|
|
a319db9119 | ||
|
|
b5eabf633a | ||
|
|
a27912b816 | ||
|
|
156d3629e6 | ||
|
|
4f9a3f6813 | ||
|
|
3b6b067fe5 | ||
|
|
1ac544b612 | ||
|
|
e3a78e0ecf | ||
|
|
58e6ca9ad4 | ||
|
|
0c40b2b3ef | ||
|
|
6642868b86 | ||
|
|
14c63e0cd5 | ||
|
|
fcb4933671 | ||
|
|
571d9708e1 | ||
|
|
bd319de5cf | ||
|
|
78a67bd775 | ||
|
|
3744f2454c | ||
|
|
39aae2872d | ||
|
|
e9a35c1cab | ||
|
|
d87fa1799e | ||
|
|
9eb8472805 | ||
|
|
6921ca44a7 | ||
|
|
7b4a4d1da4 | ||
|
|
60cfbce48b | ||
|
|
3e3a84a602 | ||
|
|
0e4857c8f6 | ||
|
|
68021903c9 | ||
|
|
f803ee2c0b | ||
|
|
c40f2ae5bb | ||
|
|
8d71714446 | ||
|
|
cc6a5a6077 | ||
|
|
004588d627 | ||
|
|
49d0045434 | ||
|
|
f5c7b1bf73 | ||
|
|
6972492fb4 | ||
|
|
311a7d40d2 | ||
|
|
c88ffa56ff | ||
|
|
05b1785f24 | ||
|
|
9b99393c20 | ||
|
|
38c70d5705 | ||
|
|
8def289271 | ||
|
|
88abadce43 | ||
|
|
7f7680da6e | ||
|
|
7b71f22e85 | ||
|
|
c4d6c9541c | ||
|
|
5a468c8b3e | ||
|
|
12e68bf477 | ||
|
|
1040e57c94 | ||
|
|
b18219687c | ||
|
|
e6fcf73a1e | ||
|
|
b92ac7d439 | ||
|
|
0e3026d41f | ||
|
|
3346124d21 | ||
|
|
89c405b196 | ||
|
|
69305fda96 | ||
|
|
8cf629b3c2 | ||
|
|
25c6499c5d | ||
|
|
bdf9969c7e | ||
|
|
62c2842c86 | ||
|
|
e8fe4e26ff | ||
|
|
1085e553d5 | ||
|
|
e38808b17c | ||
|
|
21f15d5cbd | ||
|
|
0c42b643a9 | ||
|
|
28bf33cd78 | ||
|
|
7f0f36fb7a | ||
|
|
941b369016 | ||
|
|
a85ed986de | ||
|
|
21d0320e42 | ||
|
|
843503e92a | ||
|
|
08dfd58994 | ||
|
|
ed24d05752 | ||
|
|
28d30064b6 | ||
|
|
7bac0220dc | ||
|
|
cb510f04d8 | ||
|
|
92dc0dc6d0 | ||
|
|
fa9290cf1e | ||
|
|
1fcdddf579 | ||
|
|
ce4c750326 | ||
|
|
ce99109001 | ||
|
|
8a15f0094a | ||
|
|
3a2a365ec9 | ||
|
|
3529f2da4c | ||
|
|
64bbe5b646 | ||
|
|
2427d90f48 | ||
|
|
6c49ae5152 | ||
|
|
0d1fd657ab | ||
|
|
b4cadb1a16 | ||
|
|
a2192b14db | ||
|
|
ae467486ba | ||
|
|
88d162452a | ||
|
|
3fa60d08de | ||
|
|
1eb612135b | ||
|
|
7e3a400cb7 | ||
|
|
48b6b4ca8e | ||
|
|
c2319b3a21 | ||
|
|
9a50205867 | ||
|
|
b1503bc7c8 | ||
|
|
d5d4c1a319 | ||
|
|
8988e2d34b | ||
|
|
9588eb451b | ||
|
|
acfa3fc4d4 | ||
|
|
6ef5fa1aa5 | ||
|
|
af140741bc | ||
|
|
ddc860d4b0 | ||
|
|
c1f4a7536a | ||
|
|
b91c342ff4 | ||
|
|
352519c91e | ||
|
|
f3b82dc998 | ||
|
|
9f3a2db44e | ||
|
|
018a0baed6 | ||
|
|
ddaeb2b24b | ||
|
|
51183787af | ||
|
|
2e3b6c5a17 | ||
|
|
f5a8e16109 | ||
|
|
950cd41dfa | ||
|
|
0b86348711 | ||
|
|
c8555924e0 | ||
|
|
a029cb9fc5 | ||
|
|
5b668ae421 | ||
|
|
99e9a1ea0d | ||
|
|
56159976af | ||
|
|
ac4b49f1c2 | ||
|
|
875bb8bda3 | ||
|
|
c76e46d930 | ||
|
|
baf67a7dff | ||
|
|
adb5c4c7dd | ||
|
|
5303ecee22 | ||
|
|
233456df47 | ||
|
|
725ee77383 | ||
|
|
289be872f3 | ||
|
|
910da74519 | ||
|
|
2e0f85ac93 | ||
|
|
ef2e51b4f6 | ||
|
|
af3980ff66 | ||
|
|
e3cbd2e62f | ||
|
|
d98731d5d9 | ||
|
|
ca4328b53c | ||
|
|
26bed1e264 | ||
|
|
4dec80e9e3 | ||
|
|
587a425f77 | ||
|
|
8096ced303 | ||
|
|
86e8aeaaa5 | ||
|
|
223cae66c1 | ||
|
|
d6058bba82 | ||
|
|
3249c10215 | ||
|
|
c957e07399 | ||
|
|
df1fefd775 | ||
|
|
d521945479 | ||
|
|
74fb8cb7b2 | ||
|
|
887999904b | ||
|
|
545e5fd6ab | ||
|
|
ac5e151d1e | ||
|
|
c8d269e5de | ||
|
|
e7173e974b | ||
|
|
7b0d527ffe | ||
|
|
6f5f600f47 | ||
|
|
ad8a1174f7 | ||
|
|
24b5e5234f | ||
|
|
1d438d8d06 | ||
|
|
891372c4b1 | ||
|
|
3de030ba74 | ||
|
|
a6dd70a320 | ||
|
|
ffe79897e5 | ||
|
|
b01aabf7d1 | ||
|
|
304e13ac16 | ||
|
|
c1d41e190c | ||
|
|
13df7795fc | ||
|
|
f559798750 | ||
|
|
e88568625c | ||
|
|
0716fa02d6 | ||
|
|
325a8a4cbd | ||
|
|
b0820ca1db | ||
|
|
8d44c0c752 | ||
|
|
5b5a086fd3 | ||
|
|
f7e6d9e7b8 | ||
|
|
1f43533ff9 | ||
|
|
4f5616cb91 | ||
|
|
23ba478f82 | ||
|
|
ff3b033815 | ||
|
|
a08840de6d | ||
|
|
ed34643f01 | ||
|
|
a9c496e01f | ||
|
|
a9154373fc | ||
|
|
92c472c227 | ||
|
|
4589fde775 | ||
|
|
8b8d9e0841 | ||
|
|
19c68fad43 |
No files matched your search
+88
-1
@@ -1,18 +1,105 @@
|
||||
# Future
|
||||
|
||||
# 1.8.7
|
||||
- 3DS: Add IDs for Frodo
|
||||
- 3DS: Enable basic networking / cheevos
|
||||
- CHEEVOS/BUGFIX: Opening achievements list would crash RetroArch with badges enabled (on new games)
|
||||
- CHEEVOS: Option to start a session with all achievements active
|
||||
- CHEEVOS: Don't perform unnecessary cheevos initialisation when cheevos are disabled. Should reduce startup times when loading content.
|
||||
- CORE OPTIONS: Disable 'Use Global Core Options File' by default
|
||||
- DOS/DJGPP: Add 32bit color support for cores
|
||||
- GLCORE: Switch to glcore video driver when requested by a core
|
||||
- LINUX/XDG: Use GenericName correctly in desktop entry
|
||||
- MAC/COCOA: Fix mouse cursor tracking
|
||||
- MENU/MATERIALUI: Add desktop-style playlist view mode
|
||||
- MENU/MATERIALUI/DESKTOPVIEW: When scrolling playlists, show last selected thumbnails while waiting for next entry to load
|
||||
- MENU/MATERIALUI: Limit tab switch rate when input repeat is active
|
||||
- MENU/OZONE: Fix sidebar playlist sort order when 'Truncate Playlist Names' is enabled
|
||||
- MENU/RGUI: Adjusted menu defaults, adjusted default scrolling speed
|
||||
- MENU/RGUI: Enable custom wallpaper when menu size is reduced at low resolutions
|
||||
- MENU/XMB: Limit tab switch rate when input repeat is active
|
||||
- NETPLAY: Fix regressions introduced in 1.8.5
|
||||
- RGUI: Add option to always stretch menu to fill the screen
|
||||
- WIIU: Enable graphics widgets
|
||||
|
||||
# 1.8.6
|
||||
- 3DS: Add IDs for UZEM, TGB Dual, and NeoCD
|
||||
- 3DS: Fix font driver horizontal text alignment
|
||||
- 3DS: Allow button presses up to INPUT_MAX_USERS - this enables the 3DS to bind and use buttons and axis for users up to the maximum set by 'Max Users' in the input settings menu.
|
||||
- 3DS: Disable video filter if upscaled resolution exceeds hardware limits. The 3DS has a maximum video buffer size of 2048x2048. This is sufficient for every core that it supports, but when using software video filters the core output resolution is doubled. This is made worse by the fact that the video filter upscaling buffer size is dependent upon the maximum output resolution of the core - which in some cases is very large indeed (e.g. pcsx-rearmed sets a maximum width of 1024, for enhanced resolution support). The 3DS has very limited 'linear memory' for graphics buffer purposes, and a large base core buffer + video filter buffer can easily exceed this - which may also disable video output, or cause a crash. This PR very simply adds a 3DS-specific check to the video filter initialisation: if the resultant upscaling buffer exceeds the hardware limitation, then the filter is automatically disabled.
|
||||
- 3DS/FONT/BUGFIX: Text colour was wrong: the RGBA channels were muddled, and R was always set to 255
|
||||
- 3DS/FONT/BUGFIX: When drawing multiline strings, the line spacing was completely incorrect
|
||||
- 3DS/FONT: Improves the appearance of the drop shadow effect on notification text.
|
||||
- 3DS/ARCHIVE/7Z: Re-enable 7zip support.
|
||||
- ARCHIVE/ZIP: Expand functionality of 'rzip_stream' interface. This PR expands the functionality of the new rzip_stream archived stream interface such that it now has almost complete feature parity with the standard file_stream interface, and can therefore be used as a drop-in replacement in most situations
|
||||
- AI SERVICE: Hide redundant entries when service is disabled
|
||||
- AI SERVICE: Added in auto-translate support
|
||||
- AI SERVICE: support for NVDA and SAPI narration
|
||||
- AUTOCONFIG: Use correct port index in input device configured/disconnected notifications
|
||||
- CHD: Fixes a crash caused by ignoring the return value from one of the CHD library functions.
|
||||
- BUGFIX: Fix race condition where task could momentarily not be in the queue when reordering
|
||||
- CHEEVOS/BUGFIX: Prevent null reference rendering achievement list while closing application
|
||||
- CHEEVOS/BUGFIX: Report non-memorymap GBA cores as unsupported
|
||||
- COMMANDLINE: Advise against using -s and -S variables on the command line. …
|
||||
- CONFIG FILE: Only write config files to disk when parameters change
|
||||
- CONFIG FILE/BUGFIX: RetroArch no longer crashes when attempting to save a config file after 'unsetting' a parameter (currently, this can be triggered quite easily by manipulating input remaps)
|
||||
- CONFIG FILE/BUGFIX: When using Material UI, RetroArch no longer modifies the wrong setting (or segfaults...) when tapping entries in the Quick Menu > Controls input remapping submenu
|
||||
- CONFIG FILE/BUGFIX: Quite a few real and potential memory leaks have been fixed.
|
||||
- CHD: Fixes a crash caused by ignoring the return value from one of the CHD library functions
|
||||
- FASTFORWARDING: A new Mute When Fast-Forwarding option has been added under Settings > Audio. When enabled, users can fast forward without having to listen to distorted audio.
|
||||
- GLCORE/SLANG: Set filter and wrap mode correctly when intialising shader textures. Before, the glcore shader driver did not correctly initialise loaded textures. The texture filtering and wrap mode were forced on texture creation, but these settings were not recorded - subsequent updates would set garbage values, that would resolve to linear filtering OFF and wrap mode = CLAMP_TO_EDGE.
|
||||
- LOCALIZATION: Update Japanese translation
|
||||
- LOCALIZATION: Update Spanish translation
|
||||
- LOCALIZATION: Update Portuguese Brazilian translation
|
||||
- IOS: Set audio session category to ambient so sound does not get cut off on interruption (phone call/playing back audio)
|
||||
- MAC/IOHIDMANAGER/BUGFIX: Fix for Mayflash N64 adapter. In case last hatswitch does not match cookie. For the mayflash N64 adapter, I was getting a BAD EXC ADDRESS (in mac OS 10.13) for this line (tmp was NULL). Retroarch would crash in the gui if I pressed a button from the DPAD on controller 2. With this change, it no longer crashes in the gui and still registers the button push.
|
||||
- MAC/COCOA: Fix mouse input - this brings back two lines of code that have been removed over time but
|
||||
appear to be required in order for mouse input to work on macOS
|
||||
- METAL/BUGFIX: GPU capture on Metal/OSX/NVidia could crash
|
||||
- METAL/BUGFIX: Taking screenshots could capture black frames. Resulting PNG screenshots were black.
|
||||
- METAL/BUGFIX: Corrupted image due to incorrect viewport copy when taking screenshot
|
||||
- MENU: Prevent font-related segfaults when using extremely small scales/window sizes
|
||||
- MENU: Fix 'gfx_display_draw_texture_slice()'
|
||||
- MENU/FONT: Enable correct vertical alignment of text (+ font rendering fixes)
|
||||
- MENU/RGUI: Enable automatic menu size reduction when running at low resolutions (down to 256x192)
|
||||
- MENU/OZONE: Update timedate style options for Last Played sublabel metadata
|
||||
- MENU/OZONE: Hide 'Menu Color Theme' setting when 'Use preferred system color theme' is enabled
|
||||
- MENU/OZONE: Fix thumbnail switching via 'scan' button functionality
|
||||
- MENU/OZONE: Prevent glitches when rendering Ozone's selection cursor
|
||||
- MENU/OZONE: Enable proper vertical text alignment + thumbnail display improvements
|
||||
- MENU/OZONE: Enable second thumbnail/content metadata toggle using RetroPad 'select'
|
||||
- MENU/OZONE: Refactor footer display
|
||||
- MENU/OZONE: Hide thumbnail button hints when viewing file browser lists
|
||||
- MENU/OZONE/INPUT/BUGFIX: Fix undefined behaviour when using touch screen to change input remaps
|
||||
- MENU/OZONE/INPUT/BUGFIX: It turns out that Windows reports negative pointer coordinates when the mouse cursor goes beyond the left hand edge of the RetroArch window (this doesn't happen on Linux, so I never encountered this issue before!). As a result, if Ozone is currently not showing the sidebar (menu depth > 1), moving the cursor off the left edge of the window generates a false positive 'cursor in sidebar' event - which breaks menu navigation, as described in #10419. With this PR, we now handle 'cursor in sidebar' status correctly in all cases
|
||||
- MENU/OZONE/INPUT/BUGFIX: Pointer input is now correctly disabled when message boxes are displayed
|
||||
- MENU/XMB: Fix thumbnail switching via 'scan' button functionality
|
||||
- ODROID GO ADVANCE: Add DRM HW context driver
|
||||
- PSL1GHT: Initial port
|
||||
- PSL1GHT/KEYBOARD: Implement PSL1GHT keyboard
|
||||
- PLAYLIST/BUGFIX: Improve handling of 'broken' playlists - RetroArch will no longer segfault when attempting to run content via a playlist entry with missing path or core path fields.
|
||||
- PLAYLIST/BUGFIX: Improve handling of 'broken' playlists - when a playlist entry has either core path and/or core name set to NULL, DETECT or an empty string, attempting to load content will fallback to the normal 'core selection' code (currently this happens only if both core path and core name are DETECT - this is wholly inadequate!)
|
||||
- PLAYLIST/BUGFIX: RetroArch will no longer segfault when attempting to fetch content runtime information when core path is NULL
|
||||
- PLAYLIST/BUGFIX: Core name + runtime info will only be displayed on playlists and in the Information submenu if both the core path and core name fields are 'valid' (i.e. not NULL or DETECT)
|
||||
- PLAYLIST/BUGFIX: When handling entries with missing path fields, the menu sorting order now matches that of the playlist sorting order (at present, everything goes out of sync when paths are empty). Moreover, entries with missing path fields can now be 'selected', so users can remove them (currently, hitting A on such an entry immediately tries - and fails - to load the content, so the only way to remove the broken entry is via the Playlist Management > Clean Playlist feature)
|
||||
- PLAYLIST: Add optional per-playlist alphabetical sorting
|
||||
- PLAYLIST: Omit whitespace when writing compressed JSON format playlists
|
||||
- PLAYLIST: Add optional playlist compression
|
||||
- QNX: Support analog sticks
|
||||
- SAVESTATES: Add optional save state compression (enabled by default now)
|
||||
- SRAM: Add optional save (SRAM) file compression
|
||||
- SCANNER: Prevent redundant playlist entries when handling M3U content
|
||||
- SCANNER/ANDROID: Fix content scanner being unable to identify certain games from CHD images (raw data sector/subcode)
|
||||
- TASKS/BUGFIX: Fix task deadlocks
|
||||
- TASKS/SCREENSHOT/BUGFIX: Fix heap-use-after-free error when widgets are disabled
|
||||
- TVOS: Disable overlays for tvOS, fix app icon
|
||||
- VIDEO/WIDGETS/BUGFIX: The font ascender/descender metrics added in #10375 are now used to achieve 'pixel perfect' vertical text alignment
|
||||
- VIDEO/WIDGETS/BUGFIX: Message queue text now uses its own dedicated font. Previously, a single (larger) font was used for all active widgets, and this was scaled down for message queue items. This 'squished' the text a little; more importantly, when using the stb font renderers (on Android. etc.) it caused ugly artefacts around the edges of glyphs due to pixel interpolation errors. Now that a correctly sized font is used, the message queue is always rendered cleanly.
|
||||
- VIDEO/WIDGETS/BUGFIX: Previously, each widget font was 'flushed' (font_driver_flush()) at least once a frame. This is quite a slow operation. Now we only flush fonts if they have actually been used.
|
||||
- VULKAN/BUGFIX: Fix display of statistics text
|
||||
- UNIX/BUGFIX: Fix overflow when computing total memory on i386
|
||||
- WIIU/BUGFIX: Fix font driver horizontal text alignment
|
||||
- WIIU/BUGFIX: Fix non-vertex coordinates in draws using tex shader
|
||||
- WIIU/BUGFIX: Update and fix meta.xml file for the WiiU release. This change makes it so the information from the meta.xml file parsed for the WiiU's Homebrew Launcher is displayed properly.
|
||||
|
||||
# 1.8.5
|
||||
- 3DS: Keep the bottom screen hidden on sleep/wakeup. When the 3DS wakes back up after being closed, the bottom screen needs to be reinitialized. Adding the condition here will cause the screen to be turned on or off based on the state of ctr_bottom_screen_enabled, as you'd expect
|
||||
|
||||
+33
-9
@@ -19,6 +19,16 @@ ifeq ($(HAVE_CXX11), 1)
|
||||
CXXFLAGS += $(CXX11_CFLAGS)
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_NVDA), 1)
|
||||
LIBS += nvdaControllerClient64.dll
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_SAPI), 1)
|
||||
LIBS += sapi.dll
|
||||
endif
|
||||
|
||||
|
||||
|
||||
ifeq ($(HAVE_GL_CONTEXT),)
|
||||
HAVE_GL_CONTEXT = 0
|
||||
HAVE_GL_MODERN = 0
|
||||
@@ -1681,7 +1691,8 @@ endif
|
||||
|
||||
ifeq ($(HAVE_ZLIB_COMMON), 1)
|
||||
OBJ += $(LIBRETRO_COMM_DIR)/file/archive_file_zlib.o \
|
||||
$(LIBRETRO_COMM_DIR)/streams/trans_stream_zlib.o
|
||||
$(LIBRETRO_COMM_DIR)/streams/trans_stream_zlib.o \
|
||||
$(LIBRETRO_COMM_DIR)/streams/rzip_stream.o
|
||||
DEFINES += -DHAVE_ZLIB
|
||||
HAVE_COMPRESSION = 1
|
||||
|
||||
@@ -1764,7 +1775,16 @@ endif
|
||||
# Accessibility
|
||||
ifeq ($(HAVE_ACCESSIBILITY), 1)
|
||||
DEFINES += -DHAVE_ACCESSIBILITY
|
||||
|
||||
ifeq ($(HAVE_SAPI), 1)
|
||||
ifneq ($(findstring Win32,$(OS)),)
|
||||
LIBS += -lsapi
|
||||
endif
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
|
||||
|
||||
# Things that depend on network availability
|
||||
|
||||
@@ -1810,6 +1830,7 @@ ifeq ($(HAVE_NETWORKING), 1)
|
||||
# Netplay
|
||||
DEFINES += -DHAVE_NETWORK_CMD
|
||||
OBJ += network/netplay/netplay_delta.o \
|
||||
network/netplay/netplay_frontend.o \
|
||||
network/netplay/netplay_handshake.o \
|
||||
network/netplay/netplay_init.o \
|
||||
network/netplay/netplay_io.o \
|
||||
@@ -1830,18 +1851,21 @@ ifeq ($(HAVE_NETWORKING), 1)
|
||||
cheevos-new/parser.o \
|
||||
cheevos-new/hash.o \
|
||||
$(LIBRETRO_COMM_DIR)/formats/cdfs/cdfs.o \
|
||||
deps/rcheevos/src/rcheevos/trigger.o \
|
||||
deps/rcheevos/src/rcheevos/condset.o \
|
||||
deps/rcheevos/src/rcheevos/condition.o \
|
||||
deps/rcheevos/src/rcheevos/operand.o \
|
||||
deps/rcheevos/src/rcheevos/term.o \
|
||||
deps/rcheevos/src/rcheevos/expression.o \
|
||||
deps/rcheevos/src/rcheevos/value.o \
|
||||
deps/rcheevos/src/rcheevos/lboard.o \
|
||||
deps/rcheevos/src/rcheevos/alloc.o \
|
||||
deps/rcheevos/src/rcheevos/compat.o \
|
||||
deps/rcheevos/src/rcheevos/condition.o \
|
||||
deps/rcheevos/src/rcheevos/condset.o \
|
||||
deps/rcheevos/src/rcheevos/consoleinfo.o \
|
||||
deps/rcheevos/src/rcheevos/format.o \
|
||||
deps/rcheevos/src/rcheevos/lboard.o \
|
||||
deps/rcheevos/src/rcheevos/memref.o \
|
||||
deps/rcheevos/src/rcheevos/operand.o \
|
||||
deps/rcheevos/src/rcheevos/richpresence.o \
|
||||
deps/rcheevos/src/rcheevos/runtime.o \
|
||||
deps/rcheevos/src/rcheevos/runtime_progress.o \
|
||||
deps/rcheevos/src/rcheevos/trigger.o \
|
||||
deps/rcheevos/src/rcheevos/value.o \
|
||||
deps/rcheevos/src/rhash/hash.o \
|
||||
deps/rcheevos/src/rurl/url.o
|
||||
|
||||
ifeq ($(HAVE_LUA), 1)
|
||||
|
||||
+4
-2
@@ -51,8 +51,9 @@ DEFINES :=
|
||||
ifeq ($(GRIFFIN_BUILD), 1)
|
||||
OBJ += griffin/griffin.o
|
||||
DEFINES += -DHAVE_GRIFFIN=1 -DHAVE_MENU -DHAVE_CONFIGFILE -DHAVE_RGUI -DHAVE_XMB -DHAVE_MATERIALUI -DHAVE_LIBRETRODB -DHAVE_CC_RESAMPLER
|
||||
DEFINES += -DHAVE_ZLIB -DHAVE_RPNG -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA
|
||||
#DEFINES += -DHAVE_NETWORKING -DHAVE_CHEEVOS -DRC_DISABLE_LUA -DHAVE_SOCKET_LEGACY -DHAVE_THREADS
|
||||
DEFINES += -DHAVE_ZLIB -DHAVE_7ZIP -DHAVE_RPNG -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA
|
||||
DEFINES += -DHAVE_NETWORKING -DHAVE_CHEEVOS -DRC_DISABLE_LUA
|
||||
#DEFINES += -DHAVE_SOCKET_LEGACY -DHAVE_THREADS
|
||||
#-DHAVE_SSL -DHAVE_BUILTINMBEDTLS -DMBEDTLS_SSL_DEBUG_ALL
|
||||
#ssl is currently incompatible with griffin due to use of the "static" flag on repeating functions that will conflict when included in one file
|
||||
else
|
||||
@@ -135,6 +136,7 @@ CFLAGS += -I. \
|
||||
-Ideps \
|
||||
-Ideps/7zip \
|
||||
-Ideps/stb \
|
||||
-Ideps/rcheevos/include \
|
||||
-Ilibretro-common/include \
|
||||
-Ilibretro-common/include/compat/zlib
|
||||
|
||||
|
||||
+41
-1
@@ -155,7 +155,7 @@ else ifeq ($(libogc_platform), 1)
|
||||
endif
|
||||
|
||||
LIBDIRS += -L.
|
||||
MACHDEP += -DGEKKO -mcpu=750 -meabi -mhard-float -DMSB_FIRST
|
||||
MACHDEP += -DGEKKO -mcpu=750 -meabi -mhard-float
|
||||
|
||||
ifeq ($(platform), ngc)
|
||||
LDFLAGS += $(MACHDEP) -Wl,-Map,$(notdir $(EXT_INTER_TARGET)).map
|
||||
@@ -868,6 +868,46 @@ else ifneq (,$(findstring unix,$(platform)))
|
||||
EXT_INTER_TARGET := $(TARGET_NAME)
|
||||
INCLUDE += -Ilibretro-common/include -Igfx/include -Ideps -Ideps/stb -Ideps/rcheevos/include -Ideps/SPIRV-Cross -Ideps/glslang -I.
|
||||
LIBS += -ldl -lm -lpthread -lGL -ludev -lpulse -lX11 -lX11-xcb -lXxf86vm
|
||||
else ifeq (dos,$(platform))
|
||||
HAVE_AUDIOMIXER := 1
|
||||
HAVE_RPNG := 1
|
||||
HAVE_RJPEG := 1
|
||||
HAVE_RBMP := 1
|
||||
HAVE_RTGA := 1
|
||||
HAVE_ZLIB := 1
|
||||
HAVE_7ZIP := 1
|
||||
HAVE_NETWORKING := 0
|
||||
HAVE_NETWORK_CMD := 0
|
||||
HAVE_NETPLAYDISCOVERY := 0
|
||||
HAVE_OVERLAY := 1
|
||||
HAVE_VIDEO_LAYOUT := 0
|
||||
HAVE_MATERIALUI := 1
|
||||
HAVE_XMB := 0
|
||||
HAVE_STB_FONT := 1
|
||||
HAVE_THREADS := 0
|
||||
HAVE_LIBRETRODB := 1
|
||||
HAVE_COMMAND := 1
|
||||
HAVE_STDIN_CMD := 1
|
||||
HAVE_CMD := 1
|
||||
HAVE_DYLIB := 0
|
||||
HAVE_DYNAMIC := 0
|
||||
HAVE_GRIFFIN_CPP := 0
|
||||
WANT_GLSLANG := 0
|
||||
HAVE_CONFIGFILE := 1
|
||||
CC=i586-pc-msdosdjgpp-gcc
|
||||
CXX=i586-pc-msdosdjgpp-g++
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
LDFLAGS += -g
|
||||
endif
|
||||
|
||||
PLATCFLAGS += -DHAVE_SHADERPIPELINE -DHAVE_CC_RESAMPLER -DRC_DISABLE_LUA -DHAVE_FBO -DHAVE_IMAGEVIEWER -DHAVE_LANGEXTRA -DHAVE_GFX_WIDGETS -DHAVE_CONFIGFILE -DHAVE_SPIRV_CROSS -DHAVE_STB_FONT -DRARCH_INTERNAL -DHAVE_XCB
|
||||
TARGET_NAME := retrodos
|
||||
EXT_TARGET := $(TARGET_NAME).exe
|
||||
EXT_INTER_TARGET := $(TARGET_NAME).exe
|
||||
INCLUDE += -Ilibretro-common/include -Igfx/include -Ideps -Ideps/stb -Ideps/SPIRV-Cross -Ideps/glslang -I.
|
||||
LIBS += -lm
|
||||
LIBDIRS += -L.
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring msvc,$(platform)))
|
||||
|
||||
+1
-1
@@ -70,7 +70,7 @@ endif
|
||||
PPU_SRCS = griffin/griffin.c
|
||||
|
||||
DEFINES += -DHAVE_VIDEO_LAYOUT
|
||||
DEFINES += -DHAVE_MENU -DHAVE_CONFIGFILE -DHAVE_GFX_WIDGETS -DHAVE_RGUI -DHAVE_XMB -DHAVE_OZONE -DHAVE_LIBRETRODB -DHAVE_MATERIALUI -DHAVE_SHADERPIPELINE -DRARCH_INTERNAL -DMSB_FIRST -DHAVE_OVERLAY -DHAVE_CC_RESAMPLER -DHAVE_STB_VORBIS -DHAVE_STB_FONT -DHAVE_RUNAHEAD -DHAVE_DR_MP3 -DHAVE_DR_FLAC
|
||||
DEFINES += -DHAVE_MENU -DHAVE_CONFIGFILE -DHAVE_GFX_WIDGETS -DHAVE_RGUI -DHAVE_XMB -DHAVE_OZONE -DHAVE_LIBRETRODB -DHAVE_MATERIALUI -DHAVE_SHADERPIPELINE -DRARCH_INTERNAL -DHAVE_OVERLAY -DHAVE_CC_RESAMPLER -DHAVE_STB_VORBIS -DHAVE_STB_FONT -DHAVE_RUNAHEAD -DHAVE_DR_MP3 -DHAVE_DR_FLAC
|
||||
DEFINES += -DHAVE_ONLINE_UPDATER -DHAVE_UPDATE_ASSETS -DHAVE_UPDATE_CORES
|
||||
|
||||
ifeq ($(DEX_BUILD), 1)
|
||||
|
||||
+2
-2
@@ -87,7 +87,7 @@ AR := $(PREFIX)ar
|
||||
OBJCOPY := $(PREFIX)objcopy
|
||||
STRIP := $(PREFIX)strip
|
||||
NM := $(PREFIX)nm
|
||||
LD := $(CXX)
|
||||
LD := $(CC)
|
||||
|
||||
LIBDIRS := -L.
|
||||
|
||||
@@ -122,7 +122,7 @@ CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
||||
VITA_LIBS := -lSceDisplay_stub -lSceGxm_stub -lSceNet_stub -lSceNetCtl_stub -lSceAppUtil_stub \
|
||||
-lSceSysmodule_stub -lSceCtrl_stub -lSceHid_stub -lSceTouch_stub -lSceAudio_stub \
|
||||
-lScePower_stub -lSceRtc_stub -lSceCommonDialog_stub -lScePgf_stub -lSceMotion_stub \
|
||||
-lSceFiber_stub -lSceMotion_stub -lSceAppMgr_stub -lpthread -lpng -lz
|
||||
-lSceFiber_stub -lSceMotion_stub -lSceAppMgr_stub -lstdc++ -lpthread -lpng -lz
|
||||
|
||||
LIBS := $(WHOLE_START) -lretro_vita $(WHOLE_END) $(VITA_LIBS) -lm -lc
|
||||
|
||||
|
||||
+5
-4
@@ -97,7 +97,7 @@ endif
|
||||
OBJ += gfx/drivers/gx2_shaders/snowflake.o
|
||||
|
||||
ifeq ($(GRIFFIN_BUILD), 1)
|
||||
OBJ += griffin/griffin.o
|
||||
OBJ += griffin/griffin.o griffin/griffin_cpp.o
|
||||
|
||||
INCDIRS += -Ilibretro-common/include/compat/zlib
|
||||
# for stb, libfat, iosuhax
|
||||
@@ -107,7 +107,7 @@ endif
|
||||
INCDIRS += -Ideps/SPIRV-Cross
|
||||
|
||||
DEFINES += -DHAVE_AUDIOMIXER
|
||||
DEFINES += -DHAVE_GRIFFIN=1 -DHAVE_MENU -DHAVE_CONFIGFILE -DHAVE_RGUI -DHAVE_LIBRETRODB
|
||||
DEFINES += -DHAVE_GRIFFIN=1 -DHAVE_MENU -DHAVE_GFX_WIDGETS -DHAVE_CONFIGFILE -DHAVE_RGUI -DHAVE_LIBRETRODB
|
||||
DEFINES += -DHAVE_ZLIB -DHAVE_RPNG -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA -DHAVE_CC_RESAMPLER
|
||||
DEFINES += -DHAVE_SPIRV_CROSS -DHAVE_SLANG
|
||||
DEFINES += -DHAVE_STB_FONT -DHAVE_STB_VORBIS -DHAVE_LANGEXTRA -DHAVE_LIBRETRODB -DHAVE_NETWORKING -DHAVE_NETPLAYDISCOVERY
|
||||
@@ -122,6 +122,7 @@ endif
|
||||
else
|
||||
HAVE_AUDIOMIXER = 1
|
||||
HAVE_MENU_COMMON = 1
|
||||
HAVE_GFX_WIDGETS = 1
|
||||
HAVE_RTGA = 1
|
||||
HAVE_RPNG = 1
|
||||
HAVE_RJPEG = 1
|
||||
@@ -163,7 +164,7 @@ OBJ := $(addprefix $(BUILD_DIR)/,$(OBJ))
|
||||
#-----------------------------
|
||||
# Compile flags
|
||||
|
||||
DEFINES += -DWIIU -DMSB_FIRST -D__WUT__ -DHW_WUP -D__wiiu__
|
||||
DEFINES += -DWIIU -D__WUT__ -DHW_WUP -D__wiiu__
|
||||
DEFINES += -DHAVE_MAIN
|
||||
DEFINES += -DRARCH_CONSOLE
|
||||
|
||||
@@ -184,7 +185,7 @@ CFLAGS := -mcpu=750 -meabi -mhard-float
|
||||
CFLAGS += -ffast-math -Werror=implicit-function-declaration
|
||||
CFLAGS += -ffunction-sections -fdata-sections
|
||||
#CFLAGS += -fomit-frame-pointer -mword-relocations
|
||||
#CFLAGS += -Wall
|
||||
CFLAGS += -Wall
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -O0 -g
|
||||
|
||||
@@ -106,7 +106,7 @@ static ssize_t switch_audio_write(void *data, const void *buf, size_t size)
|
||||
num = 0;
|
||||
|
||||
#ifdef HAVE_LIBNX
|
||||
if (audoutWaitPlayFinish(&swa->current_buffer, &num, U64_MAX) != 0) { }
|
||||
if (audoutWaitPlayFinish(&swa->current_buffer, &num, UINT64_MAX) != 0) { }
|
||||
#else
|
||||
svcWaitSynchronization(&handle_idx, &swa->event, 1, 33333333);
|
||||
svcResetSignal(swa->event);
|
||||
|
||||
@@ -46,6 +46,10 @@ typedef AudioOutBuffer compat_audio_out_buffer;
|
||||
#define switch_audio_ipc_output_stop(a) audoutStopAudioOut()
|
||||
#define switch_audio_ipc_output_start(a) audoutStartAudioOut()
|
||||
|
||||
#ifndef UINT64_MAX
|
||||
#define UINT64_MAX U64_MAX
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
/* libtransistor definitions */
|
||||
|
||||
@@ -86,7 +86,7 @@ static void mainLoop(void* data)
|
||||
if (!released_out_buffer)
|
||||
{
|
||||
#ifdef HAVE_LIBNX
|
||||
rc = audoutWaitPlayFinish(&released_out_buffer, &released_out_count, U64_MAX);
|
||||
rc = audoutWaitPlayFinish(&released_out_buffer, &released_out_count, UINT64_MAX);
|
||||
#else
|
||||
uint32_t handle_idx = 0;
|
||||
svcWaitSynchronization(&handle_idx, &swa->event, 1, 33333333);
|
||||
|
||||
@@ -54,7 +54,7 @@ void cheevos_set_menu_badge(int index, const char *badge, bool locked)
|
||||
uintptr_t cheevos_get_menu_badge_texture(int index)
|
||||
{
|
||||
if (index < CHEEVOS_MENU_BADGE_LIMIT)
|
||||
return cheevos_badge_menu_texture_list[index];
|
||||
return cheevos_badge_menu_texture_list[index];
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -65,7 +65,7 @@ uintptr_t cheevos_get_badge_texture(const char *badge, bool locked)
|
||||
{
|
||||
char badge_file[24];
|
||||
char fullpath[PATH_MAX_LENGTH];
|
||||
uintptr_t tex;
|
||||
uintptr_t tex = 0;
|
||||
|
||||
if (!badge)
|
||||
return 0;
|
||||
@@ -76,8 +76,9 @@ uintptr_t cheevos_get_badge_texture(const char *badge, bool locked)
|
||||
PATH_MAX_LENGTH * sizeof(char),
|
||||
APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES);
|
||||
|
||||
gfx_display_reset_textures_list(badge_file, fullpath,
|
||||
&tex, TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL);
|
||||
if (!gfx_display_reset_textures_list(badge_file, fullpath,
|
||||
&tex, TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL))
|
||||
tex = 0;
|
||||
|
||||
return tex;
|
||||
}
|
||||
+193
-174
@@ -23,7 +23,7 @@
|
||||
#include <features/features_cpu.h>
|
||||
#include <formats/cdfs.h>
|
||||
#include <compat/strl.h>
|
||||
#include <rhash.h>
|
||||
#include <../libretro-common/include/rhash.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <retro_math.h>
|
||||
#include <net/net_http.h>
|
||||
@@ -81,9 +81,6 @@
|
||||
/* Define this macro to dump all cheevos' addresses. */
|
||||
#undef CHEEVOS_DUMP_ADDRS
|
||||
|
||||
/* Define this macro to remove HTTP timeouts. */
|
||||
#undef CHEEVOS_NO_TIMEOUT
|
||||
|
||||
/* Define this macro to load a JSON file from disk instead of downloading
|
||||
* from retroachievements.org. */
|
||||
#undef CHEEVOS_JSON_OVERRIDE
|
||||
@@ -92,7 +89,7 @@
|
||||
* that name. */
|
||||
#undef CHEEVOS_SAVE_JSON
|
||||
|
||||
/* Define this macro to log URLs. */
|
||||
/* Define this macro to log URLs. */
|
||||
#undef CHEEVOS_LOG_URLS
|
||||
|
||||
/* Define this macro to have the password and token logged. THIS WILL DISCLOSE
|
||||
@@ -311,69 +308,94 @@ static void rcheevos_get_user_agent(char* buffer)
|
||||
*ptr = '\0';
|
||||
}
|
||||
|
||||
static void rcheevos_log_url(const char* format, const char* url)
|
||||
#ifdef CHEEVOS_LOG_URLS
|
||||
static void rcheevos_filter_url_param(char* url, char* param)
|
||||
{
|
||||
char* start;
|
||||
char* next;
|
||||
size_t param_len = strlen(param);
|
||||
|
||||
start = strchr(url, '?');
|
||||
if (!start)
|
||||
start = url;
|
||||
else
|
||||
++start;
|
||||
|
||||
do
|
||||
{
|
||||
next = strchr(start, '&');
|
||||
|
||||
if (start[param_len] == '=' && memcmp(start, param, param_len) == 0)
|
||||
{
|
||||
if (next)
|
||||
strcpy(start, next + 1);
|
||||
else if (start > url)
|
||||
start[-1] = '\0';
|
||||
else
|
||||
*start = '\0';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!next)
|
||||
return;
|
||||
|
||||
start = next + 1;
|
||||
} while (1);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void rcheevos_log_url(const char* api, const char* url)
|
||||
{
|
||||
#ifdef CHEEVOS_LOG_URLS
|
||||
#ifdef CHEEVOS_LOG_PASSWORD
|
||||
CHEEVOS_LOG(format, url);
|
||||
#else
|
||||
#ifdef CHEEVOS_LOG_PASSWORD
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "%s: %s\n", api, url);
|
||||
#else
|
||||
char copy[256];
|
||||
char* aux = NULL;
|
||||
char* next = NULL;
|
||||
|
||||
if (!string_is_empty(url))
|
||||
strlcpy(copy, url, sizeof(copy));
|
||||
|
||||
aux = strstr(copy, "?p=");
|
||||
|
||||
if (!aux)
|
||||
aux = strstr(copy, "&p=");
|
||||
|
||||
if (aux)
|
||||
{
|
||||
aux += 3;
|
||||
next = strchr(aux, '&');
|
||||
|
||||
if (next)
|
||||
{
|
||||
do
|
||||
{
|
||||
*aux++ = *next++;
|
||||
} while (next[-1] != 0);
|
||||
}
|
||||
else
|
||||
*aux = 0;
|
||||
}
|
||||
|
||||
aux = strstr(copy, "?t=");
|
||||
|
||||
if (!aux)
|
||||
aux = strstr(copy, "&t=");
|
||||
|
||||
if (aux)
|
||||
{
|
||||
aux += 3;
|
||||
next = strchr(aux, '&');
|
||||
|
||||
if (next)
|
||||
{
|
||||
do
|
||||
{
|
||||
*aux++ = *next++;
|
||||
} while (next[-1] != 0);
|
||||
}
|
||||
else
|
||||
*aux = 0;
|
||||
}
|
||||
|
||||
CHEEVOS_LOG(format, copy);
|
||||
#endif
|
||||
strlcpy(copy, url, sizeof(copy));
|
||||
rcheevos_filter_url_param(copy, "p");
|
||||
rcheevos_filter_url_param(copy, "t");
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "%s: %s\n", api, copy);
|
||||
#endif
|
||||
#else
|
||||
(void)format;
|
||||
(void)api;
|
||||
(void)url;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void rcheevos_log_post_url(const char* api, const char* url, const char* post)
|
||||
{
|
||||
#ifdef CHEEVOS_LOG_URLS
|
||||
#ifdef CHEEVOS_LOG_PASSWORD
|
||||
if (post && post[0])
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "%s: %s&%s\n", api, url, post);
|
||||
else
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "%s: %s\n", api, url);
|
||||
#else
|
||||
if (post && post[0])
|
||||
{
|
||||
char post_copy[2048];
|
||||
strlcpy(post_copy, post, sizeof(post_copy));
|
||||
rcheevos_filter_url_param(post_copy, "p");
|
||||
rcheevos_filter_url_param(post_copy, "t");
|
||||
|
||||
if (post_copy[0])
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "%s: %s&%s\n", api, url, post_copy);
|
||||
else
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "%s: %s\n", api, url);
|
||||
}
|
||||
else
|
||||
{
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "%s: %s\n", api, url);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
(void)api;
|
||||
(void)url;
|
||||
(void)post;
|
||||
#endif
|
||||
}
|
||||
|
||||
static retro_time_t rcheevos_async_send_rich_presence(rcheevos_async_io_request* request);
|
||||
static void rcheevos_async_award_achievement(rcheevos_async_io_request* request);
|
||||
static void rcheevos_async_submit_lboard(rcheevos_async_io_request* request);
|
||||
@@ -442,39 +464,6 @@ static void rcheevos_async_task_callback(retro_task_t* task, void* task_data, vo
|
||||
}
|
||||
}
|
||||
|
||||
static const char* rcheevos_rc_error(int ret)
|
||||
{
|
||||
switch (ret)
|
||||
{
|
||||
case RC_OK: return "Ok";
|
||||
case RC_INVALID_LUA_OPERAND: return "Invalid Lua operand";
|
||||
case RC_INVALID_MEMORY_OPERAND: return "Invalid memory operand";
|
||||
case RC_INVALID_CONST_OPERAND: return "Invalid constant operand";
|
||||
case RC_INVALID_FP_OPERAND: return "Invalid floating-point operand";
|
||||
case RC_INVALID_CONDITION_TYPE: return "Invalid condition type";
|
||||
case RC_INVALID_OPERATOR: return "Invalid operator";
|
||||
case RC_INVALID_REQUIRED_HITS: return "Invalid required hits";
|
||||
case RC_DUPLICATED_START: return "Duplicated start condition";
|
||||
case RC_DUPLICATED_CANCEL: return "Duplicated cancel condition";
|
||||
case RC_DUPLICATED_SUBMIT: return "Duplicated submit condition";
|
||||
case RC_DUPLICATED_VALUE: return "Duplicated value expression";
|
||||
case RC_DUPLICATED_PROGRESS: return "Duplicated progress expression";
|
||||
case RC_MISSING_START: return "Missing start condition";
|
||||
case RC_MISSING_CANCEL: return "Missing cancel condition";
|
||||
case RC_MISSING_SUBMIT: return "Missing submit condition";
|
||||
case RC_MISSING_VALUE: return "Missing value expression";
|
||||
case RC_INVALID_LBOARD_FIELD: return "Invalid field in leaderboard";
|
||||
case RC_MISSING_DISPLAY_STRING: return "Missing display string";
|
||||
case RC_OUT_OF_MEMORY: return "Out of memory";
|
||||
case RC_INVALID_VALUE_FLAG: return "Invalid flag in value expression";
|
||||
case RC_MISSING_VALUE_MEASURED: return "Missing measured flag in value expression";
|
||||
case RC_MULTIPLE_MEASURED: return "Multiple measured targets";
|
||||
case RC_INVALID_MEASURED_TARGET: return "Invalid measured target";
|
||||
|
||||
default: return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
static int rcheevos_parse(const char* json)
|
||||
{
|
||||
char buffer[256];
|
||||
@@ -604,7 +593,7 @@ static int rcheevos_parse(const char* json)
|
||||
if (res < 0)
|
||||
{
|
||||
snprintf(buffer, sizeof(buffer), "Error in achievement %d \"%s\": %s",
|
||||
cheevo->info->id, cheevo->info->title, rcheevos_rc_error(res));
|
||||
cheevo->info->id, cheevo->info->title, rc_error_str(res));
|
||||
|
||||
if (settings->bools.cheevos_verbose_enable)
|
||||
runloop_msg_queue_push(buffer, 0, 4 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||
@@ -641,7 +630,7 @@ static int rcheevos_parse(const char* json)
|
||||
if (res < 0)
|
||||
{
|
||||
snprintf(buffer, sizeof(buffer), "Error in leaderboard %d \"%s\": %s",
|
||||
lboard->info->id, lboard->info->title, rcheevos_rc_error(res));
|
||||
lboard->info->id, lboard->info->title, rc_error_str(res));
|
||||
|
||||
if (settings->bools.cheevos_verbose_enable)
|
||||
runloop_msg_queue_push(buffer, 0, 4 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||
@@ -671,7 +660,7 @@ static int rcheevos_parse(const char* json)
|
||||
int buffer_size = rc_richpresence_size(rcheevos_locals.patchdata.richpresence_script);
|
||||
if (buffer_size <= 0)
|
||||
{
|
||||
snprintf(buffer, sizeof(buffer), "Error in rich presence: %s", rcheevos_rc_error(buffer_size));
|
||||
snprintf(buffer, sizeof(buffer), "Error in rich presence: %s", rc_error_str(buffer_size));
|
||||
|
||||
if (settings->bools.cheevos_verbose_enable)
|
||||
runloop_msg_queue_push(buffer, 0, 4 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||
@@ -721,7 +710,7 @@ static void rcheevos_async_award_achievement(rcheevos_async_io_request* request)
|
||||
{
|
||||
char buffer[256];
|
||||
settings_t *settings = config_get_ptr();
|
||||
int ret = rc_url_award_cheevo(buffer, sizeof(buffer), settings->arrays.cheevos_username, rcheevos_locals.token, request->id, request->hardcore);
|
||||
int ret = rc_url_award_cheevo(buffer, sizeof(buffer), settings->arrays.cheevos_username, rcheevos_locals.token, request->id, request->hardcore, rcheevos_locals.hash);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
@@ -730,7 +719,7 @@ static void rcheevos_async_award_achievement(rcheevos_async_io_request* request)
|
||||
return;
|
||||
}
|
||||
|
||||
rcheevos_log_url(RCHEEVOS_TAG "rc_url_award_cheevo: %s\n", buffer);
|
||||
rcheevos_log_url("rc_url_award_cheevo", buffer);
|
||||
task_push_http_transfer_with_user_agent(buffer, true, NULL, request->user_agent, rcheevos_async_task_callback, request);
|
||||
}
|
||||
|
||||
@@ -907,7 +896,7 @@ static void rcheevos_async_submit_lboard(rcheevos_async_io_request* request)
|
||||
char buffer[256];
|
||||
settings_t *settings = config_get_ptr();
|
||||
int ret = rc_url_submit_lboard(buffer, sizeof(buffer), settings->arrays.cheevos_username,
|
||||
rcheevos_locals.token, request->id, request->value, rcheevos_locals.hash);
|
||||
rcheevos_locals.token, request->id, request->value);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
@@ -916,7 +905,7 @@ static void rcheevos_async_submit_lboard(rcheevos_async_io_request* request)
|
||||
return;
|
||||
}
|
||||
|
||||
rcheevos_log_url(RCHEEVOS_TAG "rc_url_submit_lboard: %s\n", buffer);
|
||||
rcheevos_log_url("rc_url_submit_lboard", buffer);
|
||||
task_push_http_transfer_with_user_agent(buffer, true, NULL, request->user_agent, rcheevos_async_task_callback, request);
|
||||
}
|
||||
|
||||
@@ -971,39 +960,33 @@ static void rcheevos_test_leaderboards(void)
|
||||
switch (rc_evaluate_lboard(lboard->lboard, &lboard->last_value, rcheevos_peek, NULL, NULL))
|
||||
{
|
||||
default:
|
||||
case RC_LBOARD_INACTIVE:
|
||||
break;
|
||||
|
||||
case RC_LBOARD_ACTIVE:
|
||||
/* this is where we would update the onscreen tracker */
|
||||
break;
|
||||
|
||||
case RC_LBOARD_TRIGGERED:
|
||||
case RC_LBOARD_STATE_TRIGGERED:
|
||||
rcheevos_lboard_submit(lboard);
|
||||
break;
|
||||
|
||||
case RC_LBOARD_CANCELED:
|
||||
{
|
||||
case RC_LBOARD_STATE_CANCELED:
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "Cancel leaderboard %s\n", lboard->info->title);
|
||||
lboard->active = 0;
|
||||
runloop_msg_queue_push("Leaderboard attempt cancelled!",
|
||||
0, 2 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||
break;
|
||||
}
|
||||
|
||||
case RC_LBOARD_STARTED:
|
||||
{
|
||||
char buffer[256];
|
||||
case RC_LBOARD_STATE_STARTED:
|
||||
if (!lboard->active)
|
||||
{
|
||||
char buffer[256];
|
||||
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "Leaderboard started: %s\n", lboard->info->title);
|
||||
lboard->active = 1;
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "Leaderboard started: %s\n", lboard->info->title);
|
||||
lboard->active = 1;
|
||||
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"Leaderboard Active: %s", lboard->info->title);
|
||||
runloop_msg_queue_push(buffer, 0, 2 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||
runloop_msg_queue_push(lboard->info->description, 0, 3 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"Leaderboard Active: %s", lboard->info->title);
|
||||
runloop_msg_queue_push(buffer, 0, 2 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||
runloop_msg_queue_push(lboard->info->description, 0, 3 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rcheevos_locals.invalid_peek_address)
|
||||
@@ -1046,30 +1029,31 @@ static retro_time_t rcheevos_async_send_rich_presence(rcheevos_async_io_request*
|
||||
|
||||
{
|
||||
char url[256], post_data[1024];
|
||||
int ret = rc_url_ping(url, sizeof(url), post_data, sizeof(post_data),
|
||||
cheevos_username, rcheevos_locals.token, rcheevos_locals.patchdata.game_id,
|
||||
rcheevos_locals.richpresence.evaluation);
|
||||
|
||||
snprintf(url, sizeof(url),
|
||||
"http://retroachievements.org/dorequest.php?r=ping&u=%s&t=%s",
|
||||
cheevos_username, rcheevos_locals.token);
|
||||
|
||||
if (rcheevos_locals.richpresence.evaluation[0])
|
||||
if (ret < 0)
|
||||
{
|
||||
char* tmp = NULL;
|
||||
net_http_urlencode(&tmp, rcheevos_locals.richpresence.evaluation);
|
||||
snprintf(post_data, sizeof(post_data), "g=%u&m=%s", rcheevos_locals.patchdata.game_id, tmp);
|
||||
CHEEVOS_FREE(tmp);
|
||||
|
||||
#ifdef HAVE_DISCORD
|
||||
if (settings->bools.discord_enable)
|
||||
discord_update(DISCORD_PRESENCE_RETROACHIEVEMENTS, false);
|
||||
#endif
|
||||
CHEEVOS_ERR(RCHEEVOS_TAG "buffer too small to create URL\n");
|
||||
}
|
||||
else
|
||||
snprintf(post_data, sizeof(post_data), "g=%u", rcheevos_locals.patchdata.game_id);
|
||||
{
|
||||
rcheevos_log_post_url("rc_url_ping", url, post_data);
|
||||
|
||||
rcheevos_get_user_agent(request->user_agent);
|
||||
task_push_http_post_transfer_with_user_agent(url, post_data, true, "POST", request->user_agent, NULL, NULL);
|
||||
rcheevos_get_user_agent(request->user_agent);
|
||||
task_push_http_post_transfer_with_user_agent(url, post_data, true, "POST", request->user_agent, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_DISCORD
|
||||
if (rcheevos_locals.richpresence.evaluation[0])
|
||||
{
|
||||
if (settings->bools.discord_enable)
|
||||
discord_update(DISCORD_PRESENCE_RETROACHIEVEMENTS, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Update rich presence every two minutes */
|
||||
if (settings->bools.cheevos_richpresence_enable)
|
||||
return cpu_features_get_time_usec() + CHEEVOS_PING_FREQUENCY;
|
||||
@@ -1109,15 +1093,7 @@ void rcheevos_reset_game(void)
|
||||
rc_reset_lboard(lboard->lboard);
|
||||
|
||||
if (lboard->active)
|
||||
{
|
||||
lboard->active = 0;
|
||||
|
||||
/* This ensures the leaderboard won't restart
|
||||
* until the start trigger is false for at
|
||||
* least one frame */
|
||||
if (lboard->lboard)
|
||||
lboard->lboard->submitted = 1;
|
||||
}
|
||||
}
|
||||
|
||||
rcheevos_locals.richpresence.last_update = cpu_features_get_time_usec();
|
||||
@@ -1133,12 +1109,12 @@ void rcheevos_get_achievement_state(unsigned index, char *buffer, size_t buffer_
|
||||
if (index < rcheevos_locals.patchdata.core_count)
|
||||
{
|
||||
enum_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ENTRY;
|
||||
cheevo = &rcheevos_locals.core[index];
|
||||
cheevo = rcheevos_locals.core ? &rcheevos_locals.core[index] : NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
enum_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNOFFICIAL_ENTRY;
|
||||
cheevo = &rcheevos_locals.unofficial[index - rcheevos_locals.patchdata.core_count];
|
||||
cheevo = rcheevos_locals.unofficial ? &rcheevos_locals.unofficial[index - rcheevos_locals.patchdata.core_count] : NULL;
|
||||
}
|
||||
|
||||
if (!cheevo || !cheevo->trigger)
|
||||
@@ -1576,7 +1552,7 @@ static int rcheevos_prepare_hash_psx(rcheevos_coro_t* coro)
|
||||
|
||||
/* find the data track - it should be the first one */
|
||||
coro->track = cdfs_open_data_track(coro->path);
|
||||
|
||||
|
||||
if (!coro->track)
|
||||
{
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "could not open CD\n");
|
||||
@@ -2015,7 +1991,8 @@ found:
|
||||
* Inputs: CHEEVOS_VAR_GAMEID
|
||||
* Outputs:
|
||||
*/
|
||||
CORO_GOSUB(RCHEEVOS_DEACTIVATE);
|
||||
if (!coro->settings->bools.cheevos_start_active)
|
||||
CORO_GOSUB(RCHEEVOS_DEACTIVATE);
|
||||
|
||||
/*
|
||||
* Inputs: CHEEVOS_VAR_GAMEID
|
||||
@@ -2045,15 +2022,33 @@ found:
|
||||
|
||||
if (!number_of_unsupported)
|
||||
{
|
||||
snprintf(msg, sizeof(msg),
|
||||
"You have %d of %d achievements unlocked.",
|
||||
number_of_unlocked, rcheevos_locals.patchdata.core_count);
|
||||
if (coro->settings->bools.cheevos_start_active) {
|
||||
snprintf(msg, sizeof(msg),
|
||||
"All %d achievements activated for this session.",
|
||||
rcheevos_locals.patchdata.core_count);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(msg, sizeof(msg),
|
||||
"You have %d of %d achievements unlocked.",
|
||||
number_of_unlocked, rcheevos_locals.patchdata.core_count);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(msg, sizeof(msg),
|
||||
"You have %d of %d achievements unlocked (%d unsupported).",
|
||||
number_of_unlocked - number_of_unsupported, rcheevos_locals.patchdata.core_count, number_of_unsupported);
|
||||
if (coro->settings->bools.cheevos_start_active) {
|
||||
snprintf(msg, sizeof(msg),
|
||||
"All %d achievements activated for this session (%d unsupported).",
|
||||
rcheevos_locals.patchdata.core_count,
|
||||
number_of_unsupported);
|
||||
}
|
||||
else{
|
||||
snprintf(msg, sizeof(msg),
|
||||
"You have %d of %d achievements unlocked (%d unsupported).",
|
||||
number_of_unlocked - number_of_unsupported,
|
||||
rcheevos_locals.patchdata.core_count,
|
||||
number_of_unsupported);
|
||||
}
|
||||
}
|
||||
|
||||
msg[sizeof(msg) - 1] = 0;
|
||||
@@ -2463,14 +2458,6 @@ found:
|
||||
}
|
||||
memcpy(coro->last_hash, coro->hash, sizeof(coro->hash));
|
||||
|
||||
size = rc_url_get_gameid(coro->url, sizeof(coro->url), coro->hash);
|
||||
|
||||
if (size < 0)
|
||||
{
|
||||
CHEEVOS_ERR(RCHEEVOS_TAG "buffer too small to create URL\n");
|
||||
CORO_RET();
|
||||
}
|
||||
|
||||
sprintf(rcheevos_locals.hash, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
coro->hash[0], coro->hash[1], coro->hash[2], coro->hash[3],
|
||||
coro->hash[4], coro->hash[5], coro->hash[6], coro->hash[7],
|
||||
@@ -2478,7 +2465,16 @@ found:
|
||||
coro->hash[12], coro->hash[13], coro->hash[14], coro->hash[15]);
|
||||
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "checking %s\n", rcheevos_locals.hash);
|
||||
rcheevos_log_url(RCHEEVOS_TAG "rc_url_get_gameid: %s\n", coro->url);
|
||||
|
||||
size = rc_url_get_gameid(coro->url, sizeof(coro->url), rcheevos_locals.hash);
|
||||
|
||||
if (size < 0)
|
||||
{
|
||||
CHEEVOS_ERR(RCHEEVOS_TAG "buffer too small to create URL\n");
|
||||
CORO_RET();
|
||||
}
|
||||
|
||||
rcheevos_log_url("rc_url_get_gameid", coro->url);
|
||||
CORO_GOSUB(RCHEEVOS_HTTP_GET);
|
||||
|
||||
if (!coro->json)
|
||||
@@ -2511,7 +2507,7 @@ found:
|
||||
CORO_STOP();
|
||||
}
|
||||
|
||||
rcheevos_log_url(RCHEEVOS_TAG "rc_url_get_patch: %s\n", coro->url);
|
||||
rcheevos_log_url("rc_url_get_patch", coro->url);
|
||||
CORO_GOSUB(RCHEEVOS_HTTP_GET);
|
||||
|
||||
if (!coro->json)
|
||||
@@ -2651,21 +2647,36 @@ found:
|
||||
}
|
||||
|
||||
if (string_is_empty(coro->settings->arrays.cheevos_token))
|
||||
{
|
||||
ret = rc_url_login_with_password(coro->url, sizeof(coro->url),
|
||||
coro->settings->arrays.cheevos_username,
|
||||
coro->settings->arrays.cheevos_password);
|
||||
|
||||
if (ret == RC_OK)
|
||||
{
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "attempting to login %s (with password)\n", coro->settings->arrays.cheevos_username);
|
||||
rcheevos_log_url("rc_url_login_with_password", coro->url);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = rc_url_login_with_token(coro->url, sizeof(coro->url),
|
||||
coro->settings->arrays.cheevos_username,
|
||||
coro->settings->arrays.cheevos_token);
|
||||
|
||||
if (ret == RC_OK)
|
||||
{
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "attempting to login %s (with token)\n", coro->settings->arrays.cheevos_username);
|
||||
rcheevos_log_url("rc_url_login_with_token", coro->url);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
CHEEVOS_ERR(RCHEEVOS_TAG "buffer too small to create URL\n");
|
||||
CORO_STOP();
|
||||
}
|
||||
|
||||
rcheevos_log_url(RCHEEVOS_TAG "rc_url_login_with_password: %s\n", coro->url);
|
||||
CORO_GOSUB(RCHEEVOS_HTTP_GET);
|
||||
|
||||
if (!coro->json)
|
||||
@@ -2686,6 +2697,7 @@ found:
|
||||
tok);
|
||||
runloop_msg_queue_push(msg, 0, 5 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||
*coro->settings->arrays.cheevos_token = 0;
|
||||
CHEEVOS_ERR(RCHEEVOS_TAG "login error: %s\n", tok);
|
||||
|
||||
CHEEVOS_FREE(coro->json);
|
||||
CORO_STOP();
|
||||
@@ -2703,6 +2715,7 @@ found:
|
||||
runloop_msg_queue_push(msg, 0, 3 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||
}
|
||||
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "logged in successfully\n");
|
||||
strlcpy(rcheevos_locals.token, tok,
|
||||
sizeof(rcheevos_locals.token));
|
||||
|
||||
@@ -2838,7 +2851,7 @@ found:
|
||||
CORO_STOP();
|
||||
}
|
||||
|
||||
rcheevos_log_url(RCHEEVOS_TAG "rc_url_get_unlock_list: %s\n", coro->url);
|
||||
rcheevos_log_url("rc_url_get_unlock_list", coro->url);
|
||||
CORO_GOSUB(RCHEEVOS_HTTP_GET);
|
||||
|
||||
if (coro->json)
|
||||
@@ -2862,15 +2875,19 @@ found:
|
||||
*************************************************************************/
|
||||
CORO_SUB(RCHEEVOS_PLAYING)
|
||||
|
||||
snprintf(
|
||||
coro->url, sizeof(coro->url),
|
||||
"http://retroachievements.org/dorequest.php?r=postactivity&u=%s&t=%s&a=3&m=%u",
|
||||
{
|
||||
int ret = rc_url_post_playing(coro->url, sizeof(coro->url),
|
||||
coro->settings->arrays.cheevos_username,
|
||||
rcheevos_locals.token, coro->gameid
|
||||
);
|
||||
rcheevos_locals.token, coro->gameid);
|
||||
|
||||
coro->url[sizeof(coro->url) - 1] = 0;
|
||||
rcheevos_log_url(RCHEEVOS_TAG "url to post the 'playing' activity: %s\n", coro->url);
|
||||
if (ret < 0)
|
||||
{
|
||||
CHEEVOS_ERR(RCHEEVOS_TAG "buffer too small to create URL\n");
|
||||
CORO_STOP();
|
||||
}
|
||||
}
|
||||
|
||||
rcheevos_log_url("rc_url_post_playing", coro->url);
|
||||
|
||||
CORO_GOSUB(RCHEEVOS_HTTP_GET);
|
||||
|
||||
@@ -2923,11 +2940,13 @@ bool rcheevos_load(const void *data)
|
||||
retro_task_t *task = NULL;
|
||||
const struct retro_game_info *info = NULL;
|
||||
rcheevos_coro_t *coro = NULL;
|
||||
settings_t *settings = config_get_ptr();
|
||||
bool cheevos_enable = settings && settings->bools.cheevos_enable;
|
||||
|
||||
rcheevos_loaded = false;
|
||||
rcheevos_hardcore_paused = false;
|
||||
|
||||
if (!rcheevos_locals.core_supports || !data)
|
||||
if (!cheevos_enable || !rcheevos_locals.core_supports || !data)
|
||||
{
|
||||
rcheevos_hardcore_paused = true;
|
||||
return false;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "../core.h"
|
||||
|
||||
#include "../deps/rcheevos/include/rcheevos.h"
|
||||
#include "../deps/rcheevos/include/rconsoles.h"
|
||||
|
||||
static int rcheevos_cmpaddr(const void* e1, const void* e2)
|
||||
{
|
||||
@@ -248,6 +249,14 @@ const uint8_t* rcheevos_patch_address(unsigned address, int console)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (console == RC_CONSOLE_GAMEBOY_ADVANCE)
|
||||
{
|
||||
/* The RetroAchievements implementation of memory access for GBA puts the save RAM first,
|
||||
* so the default looping behavior below is backwards. If the core doesn't expose a
|
||||
* memory map, say it isn't supported.
|
||||
*/
|
||||
pointer = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
+29
-10
@@ -517,8 +517,8 @@ static const bool menu_show_sublabels = true;
|
||||
|
||||
static const bool menu_scroll_fast = false;
|
||||
|
||||
#define DEFAULT_MENU_TICKER_TYPE (TICKER_TYPE_BOUNCE)
|
||||
static const float menu_ticker_speed = 1.0f;
|
||||
#define DEFAULT_MENU_TICKER_TYPE (TICKER_TYPE_LOOP)
|
||||
static const float menu_ticker_speed = 2.0f;
|
||||
|
||||
#define DEFAULT_MENU_TICKER_SMOOTH true
|
||||
|
||||
@@ -539,11 +539,15 @@ static const bool content_show_music = true;
|
||||
#if defined(HAVE_FFMPEG) || defined(HAVE_MPV)
|
||||
static const bool content_show_video = true;
|
||||
#endif
|
||||
#ifdef HAVE_NETWORKING
|
||||
#if defined(HAVE_NETWORKING)
|
||||
#if defined(_3DS)
|
||||
static const bool content_show_netplay = false;
|
||||
#else
|
||||
static const bool content_show_netplay = true;
|
||||
#endif
|
||||
#endif
|
||||
static const bool content_show_history = true;
|
||||
static const bool content_show_add = true;
|
||||
static const bool content_show_add = true;
|
||||
static const bool content_show_playlists = true;
|
||||
|
||||
#ifdef HAVE_XMB
|
||||
@@ -610,7 +614,7 @@ static const bool rgui_extended_ascii = false;
|
||||
static const bool default_game_specific_options = true;
|
||||
static const bool default_auto_overrides_enable = true;
|
||||
static const bool default_auto_remaps_enable = true;
|
||||
static const bool default_global_core_options = true;
|
||||
static const bool default_global_core_options = false;
|
||||
static const bool default_auto_shaders_enable = true;
|
||||
|
||||
static const bool default_sort_savefiles_enable = false;
|
||||
@@ -803,6 +807,10 @@ static const bool audio_enable_menu_bgm = false;
|
||||
#define DEFAULT_WASAPI_SH_BUFFER_LENGTH -16
|
||||
#endif
|
||||
|
||||
/* Automatically mute audio when fast forward
|
||||
* is enabled */
|
||||
#define DEFAULT_AUDIO_FASTFORWARD_MUTE false
|
||||
|
||||
/* MISC */
|
||||
|
||||
/* Enables displaying the current frames per second. */
|
||||
@@ -911,6 +919,14 @@ static const bool savestate_auto_load = false;
|
||||
|
||||
static const bool savestate_thumbnail_enable = false;
|
||||
|
||||
/* When creating save (srm) files, compress
|
||||
* written data */
|
||||
#define DEFAULT_SAVE_FILE_COMPRESSION false
|
||||
|
||||
/* When creating save state files, compress
|
||||
* written data */
|
||||
#define DEFAULT_SAVESTATE_FILE_COMPRESSION true
|
||||
|
||||
/* Slowmotion ratio. */
|
||||
#define DEFAULT_SLOWMOTION_RATIO 3.0
|
||||
|
||||
@@ -950,22 +966,25 @@ static const unsigned default_content_history_size = 200;
|
||||
static const int default_content_favorites_size = 200;
|
||||
|
||||
/* Sort all playlists (apart from histories) alphabetically */
|
||||
static const bool playlist_sort_alphabetical = true;
|
||||
#define DEFAULT_PLAYLIST_SORT_ALPHABETICAL true
|
||||
|
||||
/* File format to use when writing playlists to disk */
|
||||
static const bool playlist_use_old_format = false;
|
||||
#define DEFAULT_PLAYLIST_USE_OLD_FORMAT false
|
||||
|
||||
/* When creating/updating playlists, compress written data */
|
||||
#define DEFAULT_PLAYLIST_COMPRESSION false
|
||||
|
||||
#ifdef HAVE_MENU
|
||||
/* Specify when to display 'core name' inline on playlist entries */
|
||||
static const unsigned playlist_show_inline_core_name = PLAYLIST_INLINE_CORE_DISPLAY_HIST_FAV;
|
||||
#define DEFAULT_PLAYLIST_SHOW_INLINE_CORE_NAME PLAYLIST_INLINE_CORE_DISPLAY_HIST_FAV
|
||||
|
||||
/* Specifies which runtime record to use on playlist sublabels */
|
||||
static const unsigned playlist_sublabel_runtime_type = PLAYLIST_RUNTIME_PER_CORE;
|
||||
#define DEFAULT_PLAYLIST_SUBLABEL_RUNTIME_TYPE PLAYLIST_RUNTIME_PER_CORE
|
||||
|
||||
/* Specifies time/date display format for runtime 'last played' data */
|
||||
#define DEFAULT_PLAYLIST_SUBLABEL_LAST_PLAYED_STYLE PLAYLIST_LAST_PLAYED_STYLE_YMD_HMS
|
||||
|
||||
static const unsigned playlist_entry_remove_enable = PLAYLIST_ENTRY_REMOVE_ENABLE_ALL;
|
||||
#define DEFAULT_PLAYLIST_ENTRY_REMOVE_ENABLE PLAYLIST_ENTRY_REMOVE_ENABLE_ALL
|
||||
#endif
|
||||
|
||||
#define DEFAULT_SCAN_WITHOUT_CORE_MATCH false
|
||||
|
||||
+15
-9
@@ -332,7 +332,7 @@ static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_XENON360;
|
||||
#elif defined(HAVE_D3D11)
|
||||
static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_D3D11;
|
||||
#elif defined(HAVE_D3D12)
|
||||
/* FIXME/WARNING: DX12 performance on Xbox is horrible for
|
||||
/* FIXME/WARNING: DX12 performance on Xbox is horrible for
|
||||
* some reason. For now, we will default to D3D11 when possible. */
|
||||
static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_D3D12;
|
||||
#elif defined(HAVE_D3D10)
|
||||
@@ -1432,6 +1432,7 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings,
|
||||
#ifdef HAVE_AUDIOMIXER
|
||||
SETTING_BOOL("audio_mixer_mute_enable", audio_get_bool_ptr(AUDIO_ACTION_MIXER_MUTE_ENABLE), true, false, false);
|
||||
#endif
|
||||
SETTING_BOOL("audio_fastforward_mute", &settings->bools.audio_fastforward_mute, true, DEFAULT_AUDIO_FASTFORWARD_MUTE, false);
|
||||
SETTING_BOOL("location_allow", &settings->bools.location_allow, true, false, false);
|
||||
SETTING_BOOL("video_font_enable", &settings->bools.video_font_enable, true, DEFAULT_FONT_ENABLE, false);
|
||||
SETTING_BOOL("core_updater_auto_extract_archive", &settings->bools.network_buildbot_auto_extract_archive, true, true, false);
|
||||
@@ -1453,7 +1454,7 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings,
|
||||
#ifdef HAVE_MENU
|
||||
SETTING_BOOL("menu_unified_controls", &settings->bools.menu_unified_controls, true, false, false);
|
||||
SETTING_BOOL("menu_throttle_framerate", &settings->bools.menu_throttle_framerate, true, true, false);
|
||||
SETTING_BOOL("menu_linear_filter", &settings->bools.menu_linear_filter, true, true, false);
|
||||
SETTING_BOOL("menu_linear_filter", &settings->bools.menu_linear_filter, true, DEFAULT_VIDEO_SMOOTH, false);
|
||||
SETTING_BOOL("menu_horizontal_animation", &settings->bools.menu_horizontal_animation, true, DEFAULT_MENU_HORIZONTAL_ANIMATION, false);
|
||||
SETTING_BOOL("menu_pause_libretro", &settings->bools.menu_pause_libretro, true, true, false);
|
||||
SETTING_BOOL("menu_savestate_resume", &settings->bools.menu_savestate_resume, true, menu_savestate_resume, false);
|
||||
@@ -1587,6 +1588,7 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings,
|
||||
SETTING_BOOL("cheevos_verbose_enable", &settings->bools.cheevos_verbose_enable, true, false, false);
|
||||
SETTING_BOOL("cheevos_auto_screenshot", &settings->bools.cheevos_auto_screenshot, true, false, false);
|
||||
SETTING_BOOL("cheevos_badges_enable", &settings->bools.cheevos_badges_enable, true, false, false);
|
||||
SETTING_BOOL("cheevos_start_active", &settings->bools.cheevos_start_active, true, false, false);
|
||||
#endif
|
||||
#ifdef HAVE_OVERLAY
|
||||
SETTING_BOOL("input_overlay_enable", &settings->bools.input_overlay_enable, true, config_overlay_enable_default(), false);
|
||||
@@ -1614,6 +1616,8 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings,
|
||||
SETTING_BOOL("savestate_auto_save", &settings->bools.savestate_auto_save, true, savestate_auto_save, false);
|
||||
SETTING_BOOL("savestate_auto_load", &settings->bools.savestate_auto_load, true, savestate_auto_load, false);
|
||||
SETTING_BOOL("savestate_thumbnail_enable", &settings->bools.savestate_thumbnail_enable, true, savestate_thumbnail_enable, false);
|
||||
SETTING_BOOL("save_file_compression", &settings->bools.save_file_compression, true, DEFAULT_SAVE_FILE_COMPRESSION, false);
|
||||
SETTING_BOOL("savestate_file_compression", &settings->bools.savestate_file_compression, true, DEFAULT_SAVESTATE_FILE_COMPRESSION, false);
|
||||
SETTING_BOOL("history_list_enable", &settings->bools.history_list_enable, true, DEFAULT_HISTORY_LIST_ENABLE, false);
|
||||
SETTING_BOOL("playlist_entry_rename", &settings->bools.playlist_entry_rename, true, DEFAULT_PLAYLIST_ENTRY_RENAME, false);
|
||||
SETTING_BOOL("game_specific_options", &settings->bools.game_specific_options, true, default_game_specific_options, false);
|
||||
@@ -1648,11 +1652,12 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings,
|
||||
SETTING_BOOL("video_3ds_lcd_bottom", &settings->bools.video_3ds_lcd_bottom, true, video_3ds_lcd_bottom, false);
|
||||
#endif
|
||||
|
||||
SETTING_BOOL("playlist_use_old_format", &settings->bools.playlist_use_old_format, true, playlist_use_old_format, false);
|
||||
SETTING_BOOL("playlist_use_old_format", &settings->bools.playlist_use_old_format, true, DEFAULT_PLAYLIST_USE_OLD_FORMAT, false);
|
||||
SETTING_BOOL("playlist_compression", &settings->bools.playlist_compression, true, DEFAULT_PLAYLIST_COMPRESSION, false);
|
||||
SETTING_BOOL("content_runtime_log", &settings->bools.content_runtime_log, true, DEFAULT_CONTENT_RUNTIME_LOG, false);
|
||||
SETTING_BOOL("content_runtime_log_aggregate", &settings->bools.content_runtime_log_aggregate, true, DEFAULT_CONTENT_RUNTIME_LOG_AGGREGATE, false);
|
||||
SETTING_BOOL("playlist_show_sublabels", &settings->bools.playlist_show_sublabels, true, DEFAULT_PLAYLIST_SHOW_SUBLABELS, false);
|
||||
SETTING_BOOL("playlist_sort_alphabetical", &settings->bools.playlist_sort_alphabetical, true, playlist_sort_alphabetical, false);
|
||||
SETTING_BOOL("playlist_sort_alphabetical", &settings->bools.playlist_sort_alphabetical, true, DEFAULT_PLAYLIST_SORT_ALPHABETICAL, false);
|
||||
SETTING_BOOL("playlist_fuzzy_archive_match", &settings->bools.playlist_fuzzy_archive_match, true, DEFAULT_PLAYLIST_FUZZY_ARCHIVE_MATCH, false);
|
||||
|
||||
SETTING_BOOL("quit_press_twice", &settings->bools.quit_press_twice, true, DEFAULT_QUIT_PRESS_TWICE, false);
|
||||
@@ -1894,9 +1899,9 @@ static struct config_uint_setting *populate_settings_uint(settings_t *settings,
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MENU
|
||||
SETTING_UINT("playlist_entry_remove_enable", &settings->uints.playlist_entry_remove_enable, true, playlist_entry_remove_enable, false);
|
||||
SETTING_UINT("playlist_show_inline_core_name", &settings->uints.playlist_show_inline_core_name, true, playlist_show_inline_core_name, false);
|
||||
SETTING_UINT("playlist_sublabel_runtime_type", &settings->uints.playlist_sublabel_runtime_type, true, playlist_sublabel_runtime_type, false);
|
||||
SETTING_UINT("playlist_entry_remove_enable", &settings->uints.playlist_entry_remove_enable, true, DEFAULT_PLAYLIST_ENTRY_REMOVE_ENABLE, false);
|
||||
SETTING_UINT("playlist_show_inline_core_name", &settings->uints.playlist_show_inline_core_name, true, DEFAULT_PLAYLIST_SHOW_INLINE_CORE_NAME, false);
|
||||
SETTING_UINT("playlist_sublabel_runtime_type", &settings->uints.playlist_sublabel_runtime_type, true, DEFAULT_PLAYLIST_SUBLABEL_RUNTIME_TYPE, false);
|
||||
SETTING_UINT("playlist_sublabel_last_played_style", &settings->uints.playlist_sublabel_last_played_style, true, DEFAULT_PLAYLIST_SUBLABEL_LAST_PLAYED_STYLE, false);
|
||||
#endif
|
||||
|
||||
@@ -2670,7 +2675,7 @@ static config_file_t *open_default_config_file(void)
|
||||
|
||||
skeleton_conf[0] = '\0';
|
||||
|
||||
/* Build a retroarch.cfg path from the
|
||||
/* Build a retroarch.cfg path from the
|
||||
* global config directory (/etc). */
|
||||
fill_pathname_join(skeleton_conf, GLOBAL_CONFIG_DIR,
|
||||
file_path_str(FILE_PATH_MAIN_CONFIG), path_size);
|
||||
@@ -2685,7 +2690,7 @@ static config_file_t *open_default_config_file(void)
|
||||
|
||||
if (conf)
|
||||
{
|
||||
/* Since this is a clean config file, we can
|
||||
/* Since this is a clean config file, we can
|
||||
* safely use config_save_on_exit. */
|
||||
config_set_bool(conf, "config_save_on_exit", true);
|
||||
saved = config_file_write(conf, conf_path, true);
|
||||
@@ -4245,6 +4250,7 @@ bool config_save_overrides(enum override_type type, void *data)
|
||||
free(override_directory);
|
||||
free(core_path);
|
||||
free(game_path);
|
||||
free(content_path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -131,6 +131,7 @@ typedef struct settings
|
||||
bool audio_rate_control;
|
||||
bool audio_wasapi_exclusive_mode;
|
||||
bool audio_wasapi_float_format;
|
||||
bool audio_fastforward_mute;
|
||||
|
||||
/* Input */
|
||||
bool input_remap_binds_enable;
|
||||
@@ -303,6 +304,7 @@ typedef struct settings
|
||||
bool cheevos_badges_enable;
|
||||
bool cheevos_verbose_enable;
|
||||
bool cheevos_auto_screenshot;
|
||||
bool cheevos_start_active;
|
||||
|
||||
/* Camera */
|
||||
bool camera_allow;
|
||||
@@ -344,6 +346,8 @@ typedef struct settings
|
||||
bool savestate_auto_save;
|
||||
bool savestate_auto_load;
|
||||
bool savestate_thumbnail_enable;
|
||||
bool save_file_compression;
|
||||
bool savestate_file_compression;
|
||||
bool network_cmd_enable;
|
||||
bool stdin_cmd_enable;
|
||||
bool keymapper_enable;
|
||||
@@ -377,6 +381,7 @@ typedef struct settings
|
||||
|
||||
bool sustained_performance_mode;
|
||||
bool playlist_use_old_format;
|
||||
bool playlist_compression;
|
||||
bool content_runtime_log;
|
||||
bool content_runtime_log_aggregate;
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ typedef struct content_ctx_info
|
||||
bool content_load_ram_file(unsigned slot);
|
||||
|
||||
/* Save a RAM state from memory to disk. */
|
||||
bool content_save_ram_file(unsigned slot);
|
||||
bool content_save_ram_file(unsigned slot, bool compress);
|
||||
|
||||
/* Load a state from disk to memory. */
|
||||
bool content_load_state(const char* path, bool load_to_backup_buffer, bool autoload);
|
||||
|
||||
+78
-60
@@ -140,15 +140,17 @@ static void core_info_list_resolve_all_firmware(
|
||||
snprintf(desc_key, sizeof(desc_key), "firmware%u_desc", c);
|
||||
snprintf(opt_key, sizeof(opt_key), "firmware%u_opt", c);
|
||||
|
||||
if (config_get_string(config, path_key, &tmp) && !string_is_empty(tmp))
|
||||
if (config_get_string(config, path_key, &tmp))
|
||||
{
|
||||
info->firmware[c].path = strdup(tmp);
|
||||
if (!string_is_empty(tmp))
|
||||
info->firmware[c].path = strdup(tmp);
|
||||
free(tmp);
|
||||
tmp = NULL;
|
||||
}
|
||||
if (config_get_string(config, desc_key, &tmp) && !string_is_empty(tmp))
|
||||
if (config_get_string(config, desc_key, &tmp))
|
||||
{
|
||||
info->firmware[c].desc = strdup(tmp);
|
||||
if (!string_is_empty(tmp))
|
||||
info->firmware[c].desc = strdup(tmp);
|
||||
free(tmp);
|
||||
tmp = NULL;
|
||||
}
|
||||
@@ -315,48 +317,48 @@ static core_info_list_t *core_info_list_new(const char *path,
|
||||
{
|
||||
char *tmp = NULL;
|
||||
|
||||
if (config_get_string(conf, "display_name", &tmp)
|
||||
&& !string_is_empty(tmp))
|
||||
if (config_get_string(conf, "display_name", &tmp))
|
||||
{
|
||||
core_info[i].display_name = strdup(tmp);
|
||||
if (!string_is_empty(tmp))
|
||||
core_info[i].display_name = strdup(tmp);
|
||||
free(tmp);
|
||||
tmp = NULL;
|
||||
}
|
||||
if (config_get_string(conf, "display_version", &tmp)
|
||||
&& !string_is_empty(tmp))
|
||||
if (config_get_string(conf, "display_version", &tmp))
|
||||
{
|
||||
core_info[i].display_version = strdup(tmp);
|
||||
if (!string_is_empty(tmp))
|
||||
core_info[i].display_version = strdup(tmp);
|
||||
free(tmp);
|
||||
tmp = NULL;
|
||||
}
|
||||
if (config_get_string(conf, "corename", &tmp)
|
||||
&& !string_is_empty(tmp))
|
||||
if (config_get_string(conf, "corename", &tmp))
|
||||
{
|
||||
core_info[i].core_name = strdup(tmp);
|
||||
if (!string_is_empty(tmp))
|
||||
core_info[i].core_name = strdup(tmp);
|
||||
free(tmp);
|
||||
tmp = NULL;
|
||||
}
|
||||
|
||||
if (config_get_string(conf, "systemname", &tmp)
|
||||
&& !string_is_empty(tmp))
|
||||
if (config_get_string(conf, "systemname", &tmp))
|
||||
{
|
||||
core_info[i].systemname = strdup(tmp);
|
||||
if (!string_is_empty(tmp))
|
||||
core_info[i].systemname = strdup(tmp);
|
||||
free(tmp);
|
||||
tmp = NULL;
|
||||
}
|
||||
|
||||
if (config_get_string(conf, "systemid", &tmp)
|
||||
&& !string_is_empty(tmp))
|
||||
if (config_get_string(conf, "systemid", &tmp))
|
||||
{
|
||||
core_info[i].system_id = strdup(tmp);
|
||||
if (!string_is_empty(tmp))
|
||||
core_info[i].system_id = strdup(tmp);
|
||||
free(tmp);
|
||||
tmp = NULL;
|
||||
}
|
||||
|
||||
if (config_get_string(conf, "manufacturer", &tmp)
|
||||
&& !string_is_empty(tmp))
|
||||
if (config_get_string(conf, "manufacturer", &tmp))
|
||||
{
|
||||
core_info[i].system_manufacturer = strdup(tmp);
|
||||
if (!string_is_empty(tmp))
|
||||
core_info[i].system_manufacturer = strdup(tmp);
|
||||
free(tmp);
|
||||
tmp = NULL;
|
||||
}
|
||||
@@ -367,87 +369,103 @@ static core_info_list_t *core_info_list_new(const char *path,
|
||||
core_info[i].firmware_count = count;
|
||||
}
|
||||
|
||||
if (config_get_string(conf, "supported_extensions", &tmp)
|
||||
&& !string_is_empty(tmp))
|
||||
if (config_get_string(conf, "supported_extensions", &tmp))
|
||||
{
|
||||
core_info[i].supported_extensions = strdup(tmp);
|
||||
core_info[i].supported_extensions_list =
|
||||
string_split(core_info[i].supported_extensions, "|");
|
||||
if (!string_is_empty(tmp))
|
||||
{
|
||||
core_info[i].supported_extensions = strdup(tmp);
|
||||
core_info[i].supported_extensions_list =
|
||||
string_split(core_info[i].supported_extensions, "|");
|
||||
}
|
||||
|
||||
free(tmp);
|
||||
tmp = NULL;
|
||||
}
|
||||
|
||||
if (config_get_string(conf, "authors", &tmp)
|
||||
&& !string_is_empty(tmp))
|
||||
if (config_get_string(conf, "authors", &tmp))
|
||||
{
|
||||
core_info[i].authors = strdup(tmp);
|
||||
core_info[i].authors_list =
|
||||
string_split(core_info[i].authors, "|");
|
||||
if (!string_is_empty(tmp))
|
||||
{
|
||||
core_info[i].authors = strdup(tmp);
|
||||
core_info[i].authors_list =
|
||||
string_split(core_info[i].authors, "|");
|
||||
}
|
||||
|
||||
free(tmp);
|
||||
tmp = NULL;
|
||||
}
|
||||
|
||||
if (config_get_string(conf, "permissions", &tmp)
|
||||
&& !string_is_empty(tmp))
|
||||
if (config_get_string(conf, "permissions", &tmp))
|
||||
{
|
||||
core_info[i].permissions = strdup(tmp);
|
||||
core_info[i].permissions_list =
|
||||
string_split(core_info[i].permissions, "|");
|
||||
if (!string_is_empty(tmp))
|
||||
{
|
||||
core_info[i].permissions = strdup(tmp);
|
||||
core_info[i].permissions_list =
|
||||
string_split(core_info[i].permissions, "|");
|
||||
}
|
||||
|
||||
free(tmp);
|
||||
tmp = NULL;
|
||||
}
|
||||
|
||||
if (config_get_string(conf, "license", &tmp)
|
||||
&& !string_is_empty(tmp))
|
||||
if (config_get_string(conf, "license", &tmp))
|
||||
{
|
||||
core_info[i].licenses = strdup(tmp);
|
||||
core_info[i].licenses_list =
|
||||
string_split(core_info[i].licenses, "|");
|
||||
if (!string_is_empty(tmp))
|
||||
{
|
||||
core_info[i].licenses = strdup(tmp);
|
||||
core_info[i].licenses_list =
|
||||
string_split(core_info[i].licenses, "|");
|
||||
}
|
||||
|
||||
free(tmp);
|
||||
tmp = NULL;
|
||||
}
|
||||
|
||||
if (config_get_string(conf, "categories", &tmp)
|
||||
&& !string_is_empty(tmp))
|
||||
if (config_get_string(conf, "categories", &tmp))
|
||||
{
|
||||
core_info[i].categories = strdup(tmp);
|
||||
core_info[i].categories_list =
|
||||
string_split(core_info[i].categories, "|");
|
||||
if (!string_is_empty(tmp))
|
||||
{
|
||||
core_info[i].categories = strdup(tmp);
|
||||
core_info[i].categories_list =
|
||||
string_split(core_info[i].categories, "|");
|
||||
}
|
||||
|
||||
free(tmp);
|
||||
tmp = NULL;
|
||||
}
|
||||
|
||||
if (config_get_string(conf, "database", &tmp)
|
||||
&& !string_is_empty(tmp))
|
||||
if (config_get_string(conf, "database", &tmp))
|
||||
{
|
||||
core_info[i].databases = strdup(tmp);
|
||||
core_info[i].databases_list =
|
||||
string_split(core_info[i].databases, "|");
|
||||
if (!string_is_empty(tmp))
|
||||
{
|
||||
core_info[i].databases = strdup(tmp);
|
||||
core_info[i].databases_list =
|
||||
string_split(core_info[i].databases, "|");
|
||||
}
|
||||
|
||||
free(tmp);
|
||||
tmp = NULL;
|
||||
}
|
||||
|
||||
if (config_get_string(conf, "notes", &tmp)
|
||||
&& !string_is_empty(tmp))
|
||||
if (config_get_string(conf, "notes", &tmp))
|
||||
{
|
||||
core_info[i].notes = strdup(tmp);
|
||||
core_info[i].note_list = string_split(core_info[i].notes, "|");
|
||||
if (!string_is_empty(tmp))
|
||||
{
|
||||
core_info[i].notes = strdup(tmp);
|
||||
core_info[i].note_list = string_split(core_info[i].notes, "|");
|
||||
}
|
||||
|
||||
free(tmp);
|
||||
tmp = NULL;
|
||||
}
|
||||
|
||||
if (config_get_string(conf, "required_hw_api", &tmp)
|
||||
&& !string_is_empty(tmp))
|
||||
if (config_get_string(conf, "required_hw_api", &tmp))
|
||||
{
|
||||
core_info[i].required_hw_api = strdup(tmp);
|
||||
core_info[i].required_hw_api_list = string_split(core_info[i].required_hw_api, "|");
|
||||
if (!string_is_empty(tmp))
|
||||
{
|
||||
core_info[i].required_hw_api = strdup(tmp);
|
||||
core_info[i].required_hw_api_list = string_split(core_info[i].required_hw_api, "|");
|
||||
}
|
||||
|
||||
free(tmp);
|
||||
tmp = NULL;
|
||||
|
||||
@@ -126,12 +126,6 @@ else ifneq (,$(findstring win,$(platform)))
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_BIGENDIAN),1)
|
||||
CPUOPTS += -DHAVE_BIGENDIAN=1 -DMSB_FIRST
|
||||
else
|
||||
CPUOPTS += -DHAVE_BIGENDIAN=0
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_SSA), 1)
|
||||
LIBS += $(shell pkg-config libass --libs)
|
||||
DEFINES += -DHAVE_SSA
|
||||
|
||||
Vendored
+1
@@ -4,6 +4,7 @@
|
||||
#ifndef __CPU_ARCH_H
|
||||
#define __CPU_ARCH_H
|
||||
|
||||
#include <retro_endianness.h>
|
||||
#include "7zTypes.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
Vendored
-5
@@ -1162,19 +1162,14 @@ void _FAT_directory_entryStat (PARTITION* partition, DIR_ENTRY* entry, struct st
|
||||
0,
|
||||
u8array_to_u16 (entry->entryData, DIR_ENTRY_aDate)
|
||||
);
|
||||
st->st_spare1 = 0;
|
||||
st->st_mtime = _FAT_filetime_to_time_t (
|
||||
u8array_to_u16 (entry->entryData, DIR_ENTRY_mTime),
|
||||
u8array_to_u16 (entry->entryData, DIR_ENTRY_mDate)
|
||||
);
|
||||
st->st_spare2 = 0;
|
||||
st->st_ctime = _FAT_filetime_to_time_t (
|
||||
u8array_to_u16 (entry->entryData, DIR_ENTRY_cTime),
|
||||
u8array_to_u16 (entry->entryData, DIR_ENTRY_cDate)
|
||||
);
|
||||
st->st_spare3 = 0;
|
||||
st->st_blksize = partition->bytesPerSector; /* Prefered file I/O block size */
|
||||
st->st_blocks = (st->st_size + partition->bytesPerSector - 1) / partition->bytesPerSector; /* File size in blocks */
|
||||
st->st_spare4[0] = 0;
|
||||
st->st_spare4[1] = 0;
|
||||
}
|
||||
Vendored
+49
@@ -1,3 +1,52 @@
|
||||
# v9.0.0
|
||||
|
||||
* new size: RC_MEMSIZE_BITCOUNT
|
||||
* new flag: RC_CONDITION_OR_NEXT
|
||||
* new flag: RC_CONDITION_TRIGGER
|
||||
* new flag: RC_CONDITION_MEASURED_IF
|
||||
* new operators: RC_OPERATOR_MULT / RC_OPERATOR_DIV
|
||||
* is_bcd removed from memref - now part of RC_MEMSIZE
|
||||
* add rc_runtime_t and associated functions
|
||||
* add rc_hash_ functions
|
||||
* add rc_error_str function
|
||||
* add game_hash parameter to rc_url_award_cheevo
|
||||
* remove hash parameter from rc_url_submit_lboard
|
||||
* add rc_url_ping function
|
||||
* add rc_console_ functions
|
||||
|
||||
# v8.1.0
|
||||
|
||||
* new flag: RC_CONDITION_MEASURED
|
||||
* new flag: RC_CONDITION_ADD_ADDRESS
|
||||
* add rc_evaluate_trigger - extended version of rc_test_trigger with more granular return codes
|
||||
* make rc_evaluate_value return a signed int (was unsigned int)
|
||||
* new formats: RC_FORMAT_MINUTES and RC_FORMAT_SECONDS_AS_MINUTES
|
||||
* removed " Points" text from RC_FORMAT_SCORE format
|
||||
* removed RC_FORMAT_OTHER format. "OTHER" format now parses to RC_FORMAT_SCORE
|
||||
* bugfix: AddHits will now honor AndNext on previous condition
|
||||
|
||||
# v8.0.1
|
||||
|
||||
* bugfix: prevent null reference exception if rich presence contains condition without display string
|
||||
* bugfix: 24-bit read from memory should only read 24-bits
|
||||
|
||||
# v8.0.0
|
||||
|
||||
* support for prior operand type
|
||||
* support for AndNext condition flag
|
||||
* support for rich presence
|
||||
* bugfix: update delta/prior memory values while group is paused
|
||||
* bugfix: allow floating point number without leading 0
|
||||
* bugfix: support empty alt groups
|
||||
|
||||
# v7.1.1
|
||||
|
||||
* Address signed/unsigned mismatch warnings
|
||||
|
||||
# v7.1.0
|
||||
|
||||
* Added the RC_DISABLE_LUA macro to compile rcheevos without Lua support
|
||||
|
||||
# v7.0.2
|
||||
|
||||
* Make sure the code is C89-compliant
|
||||
|
||||
Vendored
+191
-96
@@ -59,10 +59,16 @@ enum {
|
||||
RC_INVALID_VALUE_FLAG = -20,
|
||||
RC_MISSING_VALUE_MEASURED = -21,
|
||||
RC_MULTIPLE_MEASURED = -22,
|
||||
RC_INVALID_MEASURED_TARGET = -23
|
||||
RC_INVALID_MEASURED_TARGET = -23,
|
||||
RC_INVALID_COMPARISON = -24
|
||||
};
|
||||
```
|
||||
|
||||
To convert the return code into something human-readable, pass it to:
|
||||
```c
|
||||
const char* rc_error_str(int ret);
|
||||
```
|
||||
|
||||
### Console identifiers
|
||||
|
||||
This enumeration uniquely identifies each of the supported platforms in RetroAchievements.
|
||||
@@ -92,14 +98,38 @@ enum {
|
||||
RC_CONSOLE_PLAYSTATION_2 = 21,
|
||||
RC_CONSOLE_XBOX = 22,
|
||||
RC_CONSOLE_SKYNET = 23,
|
||||
RC_CONSOLE_XBOX_ONE = 24,
|
||||
RC_CONSOLE_POKEMON_MINI = 24,
|
||||
RC_CONSOLE_ATARI_2600 = 25,
|
||||
RC_CONSOLE_MS_DOS = 26,
|
||||
RC_CONSOLE_ARCADE = 27,
|
||||
RC_CONSOLE_VIRTUAL_BOY = 28,
|
||||
RC_CONSOLE_MSX = 29,
|
||||
RC_CONSOLE_COMMODORE_64 = 30,
|
||||
RC_CONSOLE_ZX81 = 31
|
||||
RC_CONSOLE_ZX81 = 31,
|
||||
RC_CONSOLE_ORIC = 32,
|
||||
RC_CONSOLE_SG1000 = 33,
|
||||
RC_CONSOLE_VIC20 = 34,
|
||||
RC_CONSOLE_AMIGA = 35,
|
||||
RC_CONSOLE_AMIGA_ST = 36,
|
||||
RC_CONSOLE_AMSTRAD_PC = 37,
|
||||
RC_CONSOLE_APPLE_II = 38,
|
||||
RC_CONSOLE_SATURN = 39,
|
||||
RC_CONSOLE_DREAMCAST = 40,
|
||||
RC_CONSOLE_PSP = 41,
|
||||
RC_CONSOLE_CDI = 42,
|
||||
RC_CONSOLE_3DO = 43,
|
||||
RC_CONSOLE_COLECOVISION = 44,
|
||||
RC_CONSOLE_INTELLIVISION = 45,
|
||||
RC_CONSOLE_VECTREX = 46,
|
||||
RC_CONSOLE_PC8800 = 47,
|
||||
RC_CONSOLE_PC9800 = 48,
|
||||
RC_CONSOLE_PCFX = 49,
|
||||
RC_CONSOLE_ATARI_5200 = 50,
|
||||
RC_CONSOLE_ATARI_7800 = 51,
|
||||
RC_CONSOLE_X68K = 52,
|
||||
RC_CONSOLE_WONDERSWAN = 53,
|
||||
RC_CONSOLE_CASSETTEVISION = 54,
|
||||
RC_CONSOLE_SUPER_CASSETTEVISION = 55
|
||||
};
|
||||
```
|
||||
|
||||
@@ -115,27 +145,23 @@ An operand is the leaf node of RetroAchievements expressions, and can hold one o
|
||||
typedef struct {
|
||||
union {
|
||||
/* A value read from memory. */
|
||||
struct {
|
||||
/* The memory address or constant value of this variable. */
|
||||
unsigned value;
|
||||
/* The previous memory contents if RC_OPERAND_DELTA. */
|
||||
unsigned previous;
|
||||
rc_memref_value_t* memref;
|
||||
|
||||
/* The size of the variable. */
|
||||
char size;
|
||||
/* True if the value is in BCD. */
|
||||
char is_bcd;
|
||||
/* The type of the variable. */
|
||||
};
|
||||
/* An integer value. */
|
||||
unsigned num;
|
||||
|
||||
/* A floating point value. */
|
||||
double fp_value;
|
||||
double dbl;
|
||||
|
||||
/* A reference to the Lua function that provides the value. */
|
||||
int function_ref;
|
||||
int luafunc;
|
||||
};
|
||||
|
||||
/* specifies which member of the value union is being used */
|
||||
char type;
|
||||
|
||||
/* the actual RC_MEMSIZE of the operand - memref.size may differ */
|
||||
char size;
|
||||
}
|
||||
rc_operand_t;
|
||||
```
|
||||
@@ -144,20 +170,21 @@ The `size` field, when applicable, holds one of these values:
|
||||
|
||||
```c
|
||||
enum {
|
||||
RC_OPERAND_BIT_0,
|
||||
RC_OPERAND_BIT_1,
|
||||
RC_OPERAND_BIT_2,
|
||||
RC_OPERAND_BIT_3,
|
||||
RC_OPERAND_BIT_4,
|
||||
RC_OPERAND_BIT_5,
|
||||
RC_OPERAND_BIT_6,
|
||||
RC_OPERAND_BIT_7,
|
||||
RC_OPERAND_LOW,
|
||||
RC_OPERAND_HIGH,
|
||||
RC_OPERAND_8_BITS,
|
||||
RC_OPERAND_16_BITS,
|
||||
RC_OPERAND_24_BITS,
|
||||
RC_OPERAND_32_BITS,
|
||||
RC_MEMSIZE_8_BITS,
|
||||
RC_MEMSIZE_16_BITS,
|
||||
RC_MEMSIZE_24_BITS,
|
||||
RC_MEMSIZE_32_BITS,
|
||||
RC_MEMSIZE_LOW,
|
||||
RC_MEMSIZE_HIGH,
|
||||
RC_MEMSIZE_BIT_0,
|
||||
RC_MEMSIZE_BIT_1,
|
||||
RC_MEMSIZE_BIT_2,
|
||||
RC_MEMSIZE_BIT_3,
|
||||
RC_MEMSIZE_BIT_4,
|
||||
RC_MEMSIZE_BIT_5,
|
||||
RC_MEMSIZE_BIT_6,
|
||||
RC_MEMSIZE_BIT_7,
|
||||
RC_MEMSIZE_BITCOUNT
|
||||
};
|
||||
```
|
||||
|
||||
@@ -165,15 +192,18 @@ The `type` field is always valid, and holds one of these values:
|
||||
|
||||
```c
|
||||
enum {
|
||||
RC_OPERAND_ADDRESS, /* Compare to the value of a live address in RAM. */
|
||||
RC_OPERAND_DELTA, /* The value last known at this address. */
|
||||
RC_OPERAND_CONST, /* A 32-bit unsigned integer. */
|
||||
RC_OPERAND_FP, /* A floating point value. */
|
||||
RC_OPERAND_LUA /* A Lua function that provides the value. */
|
||||
RC_OPERAND_ADDRESS, /* The value of a live address in RAM. */
|
||||
RC_OPERAND_DELTA, /* The value last known at this address. */
|
||||
RC_OPERAND_CONST, /* A 32-bit unsigned integer. */
|
||||
RC_OPERAND_FP, /* A floating point value. */
|
||||
RC_OPERAND_LUA, /* A Lua function that provides the value. */
|
||||
RC_OPERAND_PRIOR, /* The last differing value at this address. */
|
||||
RC_OPERAND_BCD, /* The BCD-decoded value of a live address in RAM */
|
||||
RC_OPERAND_INVERTED /* The twos-complement value of a live address in RAM */
|
||||
};
|
||||
```
|
||||
|
||||
`RC_OPERAND_ADDRESS`, `RC_OPERAND_DELTA` and `RC_OPERAND_CONST` mean that the anonymous structure in the union is active. `RC_OPERAND_FP` means that `fp_value` is active. `RC_OPERAND_LUA` means `function_ref` is active.
|
||||
`RC_OPERAND_ADDRESS`, `RC_OPERAND_DELTA`, `RC_OPERAND_PRIOR`, `RC_OPERAND_BCD`, and `RC_OPERAND_INVERTED` mean that `memref` is active. `RC_OPERAND_CONST` means that `num` is active. `RC_OPERAND_FP` means that `dbl` is active. `RC_OPERAND_LUA` means `luafunc` is active.
|
||||
|
||||
|
||||
### `rc_condition_t`
|
||||
@@ -184,9 +214,6 @@ A condition compares its two operands according to the defined operator. It also
|
||||
typedef struct rc_condition_t rc_condition_t;
|
||||
|
||||
struct rc_condition_t {
|
||||
/* The next condition in the chain. */
|
||||
rc_condition_t* next;
|
||||
|
||||
/* The condition's operands. */
|
||||
rc_operand_t operand1;
|
||||
rc_operand_t operand2;
|
||||
@@ -196,6 +223,9 @@ struct rc_condition_t {
|
||||
/* Number of hits so far. */
|
||||
unsigned current_hits;
|
||||
|
||||
/* The next condition in the chain. */
|
||||
rc_condition_t* next;
|
||||
|
||||
/* The type of the condition. */
|
||||
char type;
|
||||
/* The comparison operator to use. */
|
||||
@@ -219,7 +249,9 @@ enum {
|
||||
RC_CONDITION_ADD_HITS,
|
||||
RC_CONDITION_AND_NEXT,
|
||||
RC_CONDITION_MEASURED,
|
||||
RC_CONDITION_ADD_ADDRESS
|
||||
RC_CONDITION_ADD_ADDRESS,
|
||||
RC_CONDITION_TRIGGER,
|
||||
RC_CONDITION_MEASURED_IF
|
||||
};
|
||||
```
|
||||
|
||||
@@ -227,13 +259,16 @@ enum {
|
||||
|
||||
```c
|
||||
enum {
|
||||
RC_CONDITION_EQ,
|
||||
RC_CONDITION_LT,
|
||||
RC_CONDITION_LE,
|
||||
RC_CONDITION_GT,
|
||||
RC_CONDITION_GE,
|
||||
RC_CONDITION_NE,
|
||||
RC_CONDITION_NONE
|
||||
RC_OPERATOR_EQ,
|
||||
RC_OPERATOR_LT,
|
||||
RC_OPERATOR_LE,
|
||||
RC_OPERATOR_GT,
|
||||
RC_OPERATOR_GE,
|
||||
RC_OPERATOR_NE,
|
||||
RC_OPERATOR_NONE,
|
||||
RC_OPERATOR_MULT,
|
||||
RC_OPERATOR_DIV,
|
||||
RC_OPERATOR_AND
|
||||
};
|
||||
```
|
||||
|
||||
@@ -267,6 +302,9 @@ typedef struct {
|
||||
|
||||
/* The list of sub condition sets in this test. */
|
||||
rc_condset_t* alternative;
|
||||
|
||||
/* The memory references required by the trigger. */
|
||||
rc_memref_value_t* memrefs;
|
||||
}
|
||||
rc_trigger_t;
|
||||
```
|
||||
@@ -313,7 +351,8 @@ enum {
|
||||
RC_TRIGGER_STATE_ACTIVE, /* achievement is active and may trigger */
|
||||
RC_TRIGGER_STATE_PAUSED, /* achievement is currently paused and will not trigger */
|
||||
RC_TRIGGER_STATE_RESET, /* achievement hit counts were reset */
|
||||
RC_TRIGGER_STATE_TRIGGERED /* achievement has triggered */
|
||||
RC_TRIGGER_STATE_TRIGGERED, /* achievement has triggered */
|
||||
RC_TRIGGER_STATE_PRIMED /* all non-Trigger conditions are true */
|
||||
};
|
||||
```
|
||||
|
||||
@@ -323,52 +362,12 @@ Finally, `rc_reset_trigger` can be used to reset the internal state of a trigger
|
||||
void rc_reset_trigger(rc_trigger_t* self);
|
||||
```
|
||||
|
||||
### `rc_term_t`
|
||||
|
||||
A term is the leaf node of expressions used to compute values from operands. A term is evaluated by multiplying its two operands. `invert` is used to invert the bits of the second operand of the term, when the unary operator `~` is used.
|
||||
|
||||
```c
|
||||
typedef struct rc_term_t rc_term_t;
|
||||
|
||||
struct rc_term_t {
|
||||
/* The next term in this chain. */
|
||||
rc_term_t* next;
|
||||
|
||||
/* The first operand. */
|
||||
rc_operand_t operand1;
|
||||
/* The second operand. */
|
||||
rc_operand_t operand2;
|
||||
|
||||
/* A value that is applied to the second variable to invert its bits. */
|
||||
unsigned invert;
|
||||
};
|
||||
```
|
||||
|
||||
### `rc_expression_t`
|
||||
|
||||
An expression is a collection of terms. All terms in the collection are added together to give the value of the expression.
|
||||
|
||||
```c
|
||||
typedef struct rc_expression_t rc_expression_t;
|
||||
|
||||
struct rc_expression_t {
|
||||
/* The next expression in this chain. */
|
||||
rc_expression_t* next;
|
||||
|
||||
/* The list of terms in this expression. */
|
||||
rc_term_t* terms;
|
||||
};
|
||||
```
|
||||
|
||||
### `rc_value_t`
|
||||
|
||||
A value is a collection of expressions. It's used to give the value for a leaderboard, and it evaluates to value of the expression with the greatest value in the collection.
|
||||
A value is a collection of conditions that result in a single RC_CONDITION_MEASURED expression. It's used to calculate the value for a leaderboard and for lookups in rich presence.
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
/* The list of expression to evaluate. */
|
||||
rc_expression_t* expressions;
|
||||
|
||||
/* The list of conditions to evaluate. */
|
||||
rc_condset_t* conditions;
|
||||
|
||||
@@ -413,9 +412,9 @@ typedef struct {
|
||||
rc_trigger_t cancel;
|
||||
rc_value_t value;
|
||||
rc_value_t* progress;
|
||||
rc_memref_value_t* memrefs;
|
||||
|
||||
char started;
|
||||
char submitted;
|
||||
char state;
|
||||
}
|
||||
rc_lboard_t;
|
||||
```
|
||||
@@ -437,11 +436,12 @@ The function returns an action that must be performed by the caller, and `value`
|
||||
|
||||
```c
|
||||
enum {
|
||||
RC_LBOARD_INACTIVE,
|
||||
RC_LBOARD_ACTIVE,
|
||||
RC_LBOARD_STARTED,
|
||||
RC_LBOARD_CANCELED,
|
||||
RC_LBOARD_TRIGGERED
|
||||
RC_LBOARD_STATE_INACTIVE, /* leaderboard is not being processed */
|
||||
RC_LBOARD_STATE_WAITING, /* leaderboard cannot activate until the start condition has been false for at least one frame */
|
||||
RC_LBOARD_STATE_ACTIVE, /* leaderboard is active and may start */
|
||||
RC_LBOARD_STATE_STARTED, /* leaderboard attempt in progress */
|
||||
RC_LBOARD_STATE_CANCELED, /* leaderboard attempt canceled */
|
||||
RC_LBOARD_STATE_TRIGGERED /* leaderboard attempt complete, value should be submitted */
|
||||
};
|
||||
```
|
||||
|
||||
@@ -458,6 +458,101 @@ The caller must keep track of these values and do the necessary actions:
|
||||
void rc_reset_lboard(rc_lboard_t* lboard);
|
||||
```
|
||||
|
||||
### `rc_runtime_t`
|
||||
|
||||
The runtime encapsulates a set of achievements and leaderboards and manages processing them for each frame. When important things occur, events are raised for the caller via a callback.
|
||||
|
||||
```c
|
||||
typedef struct rc_runtime_t {
|
||||
rc_runtime_trigger_t* triggers;
|
||||
unsigned trigger_count;
|
||||
unsigned trigger_capacity;
|
||||
|
||||
rc_runtime_lboard_t* lboards;
|
||||
unsigned lboard_count;
|
||||
unsigned lboard_capacity;
|
||||
|
||||
rc_runtime_richpresence_t* richpresence;
|
||||
char* richpresence_display_buffer;
|
||||
char richpresence_update_timer;
|
||||
|
||||
rc_memref_value_t* memrefs;
|
||||
rc_memref_value_t** next_memref;
|
||||
}
|
||||
rc_runtime_t;
|
||||
```
|
||||
|
||||
The runtime must first be initialized.
|
||||
```c
|
||||
void rc_runtime_init(rc_runtime_t* runtime);
|
||||
```
|
||||
|
||||
Then individual achievements, leaderboards, and even rich presence can be loaded into the runtime. These functions return RC_OK, or one of the negative value error codes listed above.
|
||||
```c
|
||||
int rc_runtime_activate_achievement(rc_runtime_t* runtime, unsigned id, const char* memaddr, lua_State* L, int funcs_idx);
|
||||
int rc_runtime_activate_lboard(rc_runtime_t* runtime, unsigned id, const char* memaddr, lua_State* L, int funcs_idx);
|
||||
int rc_runtime_activate_richpresence(rc_runtime_t* runtime, const char* script, lua_State* L, int funcs_idx);
|
||||
```
|
||||
|
||||
The runtime should be called once per frame to evaluate the state of the active achievements/leaderboards:
|
||||
```c
|
||||
void rc_runtime_do_frame(rc_runtime_t* runtime, rc_runtime_event_handler_t event_handler, rc_peek_t peek, void* ud, lua_State* L);
|
||||
```
|
||||
|
||||
The `event_handler` is a callback function that is called for each event that occurs when processing the frame.
|
||||
```c
|
||||
typedef struct rc_runtime_event_t {
|
||||
unsigned id;
|
||||
int value;
|
||||
char type;
|
||||
}
|
||||
rc_runtime_event_t;
|
||||
|
||||
typedef void (*rc_runtime_event_handler_t)(const rc_runtime_event_t* runtime_event);
|
||||
```
|
||||
|
||||
The `event.type` field will be one of the following:
|
||||
* RC_RUNTIME_EVENT_ACHIEVEMENT_ACTIVATED (id=achievement id)
|
||||
An achievement starts in the RC_TRIGGER_STATE_WAITING state and cannot trigger until it has been false for at least one frame. This event indicates the achievement is no longer waiting and may trigger on a future frame.
|
||||
* RC_RUNTIME_EVENT_ACHIEVEMENT_PAUSED (id=achievement id)
|
||||
One or more conditions in the achievement have disabled the achievement.
|
||||
* RC_RUNTIME_EVENT_ACHIEVEMENT_RESET (id=achievement id)
|
||||
One or more conditions in the achievement have reset any progress captured in the achievement.
|
||||
* RC_RUNTIME_EVENT_ACHIEVEMENT_TRIGGERED (id=achievement id)
|
||||
All conditions for the achievement have been met and the user should be informed.
|
||||
NOTE: If `rc_runtime_reset` is called without deactivating the achievement, it may trigger again.
|
||||
* RC_RUNTIME_EVENT_ACHIEVEMENT_PRIMED (id=achievement id)
|
||||
All non-trigger conditions for the achievement have been met. This typically indicates the achievement is a challenge achievement and the challenge is active.
|
||||
* RC_RUNTIME_EVENT_LBOARD_STARTED (id=leaderboard id, value=leaderboard value)
|
||||
The leaderboard's start condition has been met and the user should be informed that a leaderboard attempt has started.
|
||||
* RC_RUNTIME_EVENT_LBOARD_CANCELED (id=leaderboard id, value=leaderboard value)
|
||||
The leaderboard's cancel condition has been met and the user should be informed that a leaderboard attempt has failed.
|
||||
* RC_RUNTIME_EVENT_LBOARD_UPDATED (id=leaderboard id, value=leaderboard value)
|
||||
The leaderboard value has changed.
|
||||
* RC_RUNTIME_EVENT_LBOARD_TRIGGERED (id=leaderboard id, value=leaderboard value)
|
||||
The leaderboard's submit condition has been met and the user should be informed that a leaderboard attempt was successful. The value should be submitted.
|
||||
|
||||
When an achievement triggers, it should be deactivated so it won't trigger again:
|
||||
```c
|
||||
void rc_runtime_deactivate_achievement(rc_runtime_t* runtime, unsigned id);
|
||||
```
|
||||
Additionally, the unlock should be submitted to the server.
|
||||
|
||||
When a leaderboard triggers, it should not be deactivated in case the player wants to try again for a better score. The value should be submitted to the server.
|
||||
|
||||
`rc_runtime_do_frame` also periodically updates the rich presense string (every 60 frames). To get the current value, call
|
||||
```c
|
||||
const char* rc_runtime_get_richpresence(const rc_runtime_t* runtime);
|
||||
```
|
||||
|
||||
When the game is reset, the runtime should also be reset:
|
||||
```c
|
||||
void rc_runtime_reset(rc_runtime_t* runtime);
|
||||
```
|
||||
|
||||
This ensures any active achievements/leaderboards are set back to their initial states and prevents unexpected triggers when the memory changes in atypical way.
|
||||
|
||||
|
||||
### Value Formatting
|
||||
|
||||
**rcheevos** includes helper functions to parse formatting strings from RetroAchievements, and format values according to them.
|
||||
|
||||
Vendored
+169
-97
@@ -35,46 +35,12 @@ enum {
|
||||
RC_INVALID_VALUE_FLAG = -20,
|
||||
RC_MISSING_VALUE_MEASURED = -21,
|
||||
RC_MULTIPLE_MEASURED = -22,
|
||||
RC_INVALID_MEASURED_TARGET = -23
|
||||
RC_INVALID_MEASURED_TARGET = -23,
|
||||
RC_INVALID_COMPARISON = -24,
|
||||
RC_INVALID_STATE = -25
|
||||
};
|
||||
|
||||
/*****************************************************************************\
|
||||
| Console identifiers |
|
||||
\*****************************************************************************/
|
||||
|
||||
enum {
|
||||
RC_CONSOLE_MEGA_DRIVE = 1,
|
||||
RC_CONSOLE_NINTENDO_64 = 2,
|
||||
RC_CONSOLE_SUPER_NINTENDO = 3,
|
||||
RC_CONSOLE_GAMEBOY = 4,
|
||||
RC_CONSOLE_GAMEBOY_ADVANCE = 5,
|
||||
RC_CONSOLE_GAMEBOY_COLOR = 6,
|
||||
RC_CONSOLE_NINTENDO = 7,
|
||||
RC_CONSOLE_PC_ENGINE = 8,
|
||||
RC_CONSOLE_SEGA_CD = 9,
|
||||
RC_CONSOLE_SEGA_32X = 10,
|
||||
RC_CONSOLE_MASTER_SYSTEM = 11,
|
||||
RC_CONSOLE_PLAYSTATION = 12,
|
||||
RC_CONSOLE_ATARI_LYNX = 13,
|
||||
RC_CONSOLE_NEOGEO_POCKET = 14,
|
||||
RC_CONSOLE_GAME_GEAR = 15,
|
||||
RC_CONSOLE_GAMECUBE = 16,
|
||||
RC_CONSOLE_ATARI_JAGUAR = 17,
|
||||
RC_CONSOLE_NINTENDO_DS = 18,
|
||||
RC_CONSOLE_WII = 19,
|
||||
RC_CONSOLE_WII_U = 20,
|
||||
RC_CONSOLE_PLAYSTATION_2 = 21,
|
||||
RC_CONSOLE_XBOX = 22,
|
||||
RC_CONSOLE_SKYNET = 23,
|
||||
RC_CONSOLE_XBOX_ONE = 24,
|
||||
RC_CONSOLE_ATARI_2600 = 25,
|
||||
RC_CONSOLE_MS_DOS = 26,
|
||||
RC_CONSOLE_ARCADE = 27,
|
||||
RC_CONSOLE_VIRTUAL_BOY = 28,
|
||||
RC_CONSOLE_MSX = 29,
|
||||
RC_CONSOLE_COMMODORE_64 = 30,
|
||||
RC_CONSOLE_ZX81 = 31
|
||||
};
|
||||
const char* rc_error_str(int ret);
|
||||
|
||||
/*****************************************************************************\
|
||||
| Callbacks |
|
||||
@@ -93,6 +59,12 @@ typedef unsigned (*rc_peek_t)(unsigned address, unsigned num_bytes, void* ud);
|
||||
|
||||
/* Sizes. */
|
||||
enum {
|
||||
RC_MEMSIZE_8_BITS,
|
||||
RC_MEMSIZE_16_BITS,
|
||||
RC_MEMSIZE_24_BITS,
|
||||
RC_MEMSIZE_32_BITS,
|
||||
RC_MEMSIZE_LOW,
|
||||
RC_MEMSIZE_HIGH,
|
||||
RC_MEMSIZE_BIT_0,
|
||||
RC_MEMSIZE_BIT_1,
|
||||
RC_MEMSIZE_BIT_2,
|
||||
@@ -101,12 +73,7 @@ enum {
|
||||
RC_MEMSIZE_BIT_5,
|
||||
RC_MEMSIZE_BIT_6,
|
||||
RC_MEMSIZE_BIT_7,
|
||||
RC_MEMSIZE_LOW,
|
||||
RC_MEMSIZE_HIGH,
|
||||
RC_MEMSIZE_8_BITS,
|
||||
RC_MEMSIZE_16_BITS,
|
||||
RC_MEMSIZE_24_BITS,
|
||||
RC_MEMSIZE_32_BITS
|
||||
RC_MEMSIZE_BITCOUNT
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -114,8 +81,6 @@ typedef struct {
|
||||
unsigned address;
|
||||
/* The size of the variable. */
|
||||
char size;
|
||||
/* True if the value is in BCD. */
|
||||
char is_bcd;
|
||||
/* True if the reference will be used in indirection */
|
||||
char is_indirect;
|
||||
} rc_memref_t;
|
||||
@@ -143,12 +108,14 @@ struct rc_memref_value_t {
|
||||
|
||||
/* types */
|
||||
enum {
|
||||
RC_OPERAND_ADDRESS, /* Compare to the value of a live address in RAM. */
|
||||
RC_OPERAND_DELTA, /* The value last known at this address. */
|
||||
RC_OPERAND_CONST, /* A 32-bit unsigned integer. */
|
||||
RC_OPERAND_FP, /* A floating point value. */
|
||||
RC_OPERAND_LUA, /* A Lua function that provides the value. */
|
||||
RC_OPERAND_PRIOR /* The last differing value at this address. */
|
||||
RC_OPERAND_ADDRESS, /* The value of a live address in RAM. */
|
||||
RC_OPERAND_DELTA, /* The value last known at this address. */
|
||||
RC_OPERAND_CONST, /* A 32-bit unsigned integer. */
|
||||
RC_OPERAND_FP, /* A floating point value. */
|
||||
RC_OPERAND_LUA, /* A Lua function that provides the value. */
|
||||
RC_OPERAND_PRIOR, /* The last differing value at this address. */
|
||||
RC_OPERAND_BCD, /* The BCD-decoded value of a live address in RAM */
|
||||
RC_OPERAND_INVERTED /* The twos-complement value of a live address in RAM */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -166,7 +133,11 @@ typedef struct {
|
||||
int luafunc;
|
||||
} value;
|
||||
|
||||
/* specifies which member of the value union is being used */
|
||||
char type;
|
||||
|
||||
/* the actual RC_MEMSIZE of the operand - memref.size may differ */
|
||||
char size;
|
||||
}
|
||||
rc_operand_t;
|
||||
|
||||
@@ -184,18 +155,24 @@ enum {
|
||||
RC_CONDITION_ADD_HITS,
|
||||
RC_CONDITION_AND_NEXT,
|
||||
RC_CONDITION_MEASURED,
|
||||
RC_CONDITION_ADD_ADDRESS
|
||||
RC_CONDITION_ADD_ADDRESS,
|
||||
RC_CONDITION_OR_NEXT,
|
||||
RC_CONDITION_TRIGGER,
|
||||
RC_CONDITION_MEASURED_IF
|
||||
};
|
||||
|
||||
/* operators */
|
||||
enum {
|
||||
RC_CONDITION_EQ,
|
||||
RC_CONDITION_LT,
|
||||
RC_CONDITION_LE,
|
||||
RC_CONDITION_GT,
|
||||
RC_CONDITION_GE,
|
||||
RC_CONDITION_NE,
|
||||
RC_CONDITION_NONE
|
||||
RC_OPERATOR_EQ,
|
||||
RC_OPERATOR_LT,
|
||||
RC_OPERATOR_LE,
|
||||
RC_OPERATOR_GT,
|
||||
RC_OPERATOR_GE,
|
||||
RC_OPERATOR_NE,
|
||||
RC_OPERATOR_NONE,
|
||||
RC_OPERATOR_MULT,
|
||||
RC_OPERATOR_DIV,
|
||||
RC_OPERATOR_AND
|
||||
};
|
||||
|
||||
typedef struct rc_condition_t rc_condition_t;
|
||||
@@ -256,7 +233,8 @@ enum {
|
||||
RC_TRIGGER_STATE_ACTIVE, /* achievement is active and may trigger */
|
||||
RC_TRIGGER_STATE_PAUSED, /* achievement is currently paused and will not trigger */
|
||||
RC_TRIGGER_STATE_RESET, /* achievement hit counts were reset */
|
||||
RC_TRIGGER_STATE_TRIGGERED /* achievement has triggered */
|
||||
RC_TRIGGER_STATE_TRIGGERED, /* achievement has triggered */
|
||||
RC_TRIGGER_STATE_PRIMED /* all non-Trigger conditions are true */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -290,38 +268,10 @@ int rc_test_trigger(rc_trigger_t* trigger, rc_peek_t peek, void* ud, lua_State*
|
||||
void rc_reset_trigger(rc_trigger_t* self);
|
||||
|
||||
/*****************************************************************************\
|
||||
| Expressions and values |
|
||||
| Values |
|
||||
\*****************************************************************************/
|
||||
|
||||
typedef struct rc_term_t rc_term_t;
|
||||
|
||||
struct rc_term_t {
|
||||
/* The next term in this chain. */
|
||||
rc_term_t* next;
|
||||
|
||||
/* The first operand. */
|
||||
rc_operand_t operand1;
|
||||
/* The second operand. */
|
||||
rc_operand_t operand2;
|
||||
|
||||
/* A value that is applied to the second variable to invert its bits. */
|
||||
unsigned invert;
|
||||
};
|
||||
|
||||
typedef struct rc_expression_t rc_expression_t;
|
||||
|
||||
struct rc_expression_t {
|
||||
/* The next expression in this chain. */
|
||||
rc_expression_t* next;
|
||||
|
||||
/* The list of terms in this expression. */
|
||||
rc_term_t* terms;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
/* The list of expression to evaluate. */
|
||||
rc_expression_t* expressions;
|
||||
|
||||
/* The list of conditions to evaluate. */
|
||||
rc_condset_t* conditions;
|
||||
|
||||
@@ -340,11 +290,12 @@ int rc_evaluate_value(rc_value_t* value, rc_peek_t peek, void* ud, lua_State* L)
|
||||
|
||||
/* Return values for rc_evaluate_lboard. */
|
||||
enum {
|
||||
RC_LBOARD_INACTIVE,
|
||||
RC_LBOARD_ACTIVE,
|
||||
RC_LBOARD_STARTED,
|
||||
RC_LBOARD_CANCELED,
|
||||
RC_LBOARD_TRIGGERED
|
||||
RC_LBOARD_STATE_INACTIVE, /* leaderboard is not being processed */
|
||||
RC_LBOARD_STATE_WAITING, /* leaderboard cannot activate until the start condition has been false for at least one frame */
|
||||
RC_LBOARD_STATE_ACTIVE, /* leaderboard is active and may start */
|
||||
RC_LBOARD_STATE_STARTED, /* leaderboard attempt in progress */
|
||||
RC_LBOARD_STATE_CANCELED, /* leaderboard attempt canceled */
|
||||
RC_LBOARD_STATE_TRIGGERED /* leaderboard attempt complete, value should be submitted */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -355,8 +306,7 @@ typedef struct {
|
||||
rc_value_t* progress;
|
||||
rc_memref_value_t* memrefs;
|
||||
|
||||
char started;
|
||||
char submitted;
|
||||
char state;
|
||||
}
|
||||
rc_lboard_t;
|
||||
|
||||
@@ -433,6 +383,128 @@ int rc_richpresence_size(const char* script);
|
||||
rc_richpresence_t* rc_parse_richpresence(void* buffer, const char* script, lua_State* L, int funcs_ndx);
|
||||
int rc_evaluate_richpresence(rc_richpresence_t* richpresence, char* buffer, unsigned buffersize, rc_peek_t peek, void* peek_ud, lua_State* L);
|
||||
|
||||
/*****************************************************************************\
|
||||
| Runtime |
|
||||
\*****************************************************************************/
|
||||
|
||||
typedef struct rc_runtime_trigger_t {
|
||||
unsigned id;
|
||||
rc_trigger_t* trigger;
|
||||
void* buffer;
|
||||
unsigned char md5[16];
|
||||
char owns_memrefs;
|
||||
}
|
||||
rc_runtime_trigger_t;
|
||||
|
||||
typedef struct rc_runtime_lboard_t {
|
||||
unsigned id;
|
||||
int value;
|
||||
rc_lboard_t* lboard;
|
||||
void* buffer;
|
||||
unsigned char md5[16];
|
||||
char owns_memrefs;
|
||||
}
|
||||
rc_runtime_lboard_t;
|
||||
|
||||
typedef struct rc_runtime_richpresence_t {
|
||||
rc_richpresence_t* richpresence;
|
||||
void* buffer;
|
||||
struct rc_runtime_richpresence_t* previous;
|
||||
char owns_memrefs;
|
||||
}
|
||||
rc_runtime_richpresence_t;
|
||||
|
||||
typedef struct rc_runtime_t {
|
||||
rc_runtime_trigger_t* triggers;
|
||||
unsigned trigger_count;
|
||||
unsigned trigger_capacity;
|
||||
|
||||
rc_runtime_lboard_t* lboards;
|
||||
unsigned lboard_count;
|
||||
unsigned lboard_capacity;
|
||||
|
||||
rc_runtime_richpresence_t* richpresence;
|
||||
char* richpresence_display_buffer;
|
||||
char richpresence_update_timer;
|
||||
|
||||
rc_memref_value_t* memrefs;
|
||||
rc_memref_value_t** next_memref;
|
||||
}
|
||||
rc_runtime_t;
|
||||
|
||||
void rc_runtime_init(rc_runtime_t* runtime);
|
||||
void rc_runtime_destroy(rc_runtime_t* runtime);
|
||||
|
||||
int rc_runtime_activate_achievement(rc_runtime_t* runtime, unsigned id, const char* memaddr, lua_State* L, int funcs_idx);
|
||||
void rc_runtime_deactivate_achievement(rc_runtime_t* runtime, unsigned id);
|
||||
rc_trigger_t* rc_runtime_get_achievement(const rc_runtime_t* runtime, unsigned id);
|
||||
|
||||
int rc_runtime_activate_lboard(rc_runtime_t* runtime, unsigned id, const char* memaddr, lua_State* L, int funcs_idx);
|
||||
void rc_runtime_deactivate_lboard(rc_runtime_t* runtime, unsigned id);
|
||||
rc_lboard_t* rc_runtime_get_lboard(const rc_runtime_t* runtime, unsigned id);
|
||||
|
||||
int rc_runtime_activate_richpresence(rc_runtime_t* runtime, const char* script, lua_State* L, int funcs_idx);
|
||||
const char* rc_runtime_get_richpresence(const rc_runtime_t* runtime);
|
||||
|
||||
enum {
|
||||
RC_RUNTIME_EVENT_ACHIEVEMENT_ACTIVATED, /* from WAITING, PAUSED, or PRIMED to ACTIVE */
|
||||
RC_RUNTIME_EVENT_ACHIEVEMENT_PAUSED,
|
||||
RC_RUNTIME_EVENT_ACHIEVEMENT_RESET,
|
||||
RC_RUNTIME_EVENT_ACHIEVEMENT_TRIGGERED,
|
||||
RC_RUNTIME_EVENT_ACHIEVEMENT_PRIMED,
|
||||
RC_RUNTIME_EVENT_LBOARD_STARTED,
|
||||
RC_RUNTIME_EVENT_LBOARD_CANCELED,
|
||||
RC_RUNTIME_EVENT_LBOARD_UPDATED,
|
||||
RC_RUNTIME_EVENT_LBOARD_TRIGGERED
|
||||
};
|
||||
|
||||
typedef struct rc_runtime_event_t {
|
||||
unsigned id;
|
||||
int value;
|
||||
char type;
|
||||
}
|
||||
rc_runtime_event_t;
|
||||
|
||||
typedef void (*rc_runtime_event_handler_t)(const rc_runtime_event_t* runtime_event);
|
||||
|
||||
void rc_runtime_do_frame(rc_runtime_t* runtime, rc_runtime_event_handler_t event_handler, rc_peek_t peek, void* ud, lua_State* L);
|
||||
void rc_runtime_reset(rc_runtime_t* runtime);
|
||||
|
||||
int rc_runtime_progress_size(const rc_runtime_t* runtime, lua_State* L);
|
||||
int rc_runtime_serialize_progress(void* buffer, const rc_runtime_t* runtime, lua_State* L);
|
||||
int rc_runtime_deserialize_progress(rc_runtime_t* runtime, const unsigned char* serialized, lua_State* L);
|
||||
|
||||
/*****************************************************************************\
|
||||
| Memory mapping |
|
||||
\*****************************************************************************/
|
||||
|
||||
enum {
|
||||
RC_MEMORY_TYPE_SYSTEM_RAM, /* normal system memory */
|
||||
RC_MEMORY_TYPE_SAVE_RAM, /* memory that persists between sessions */
|
||||
RC_MEMORY_TYPE_VIDEO_RAM, /* memory reserved for graphical processing */
|
||||
RC_MEMORY_TYPE_READONLY, /* memory that maps to read only data */
|
||||
RC_MEMORY_TYPE_HARDWARE_CONTROLLER, /* memory for interacting with system components */
|
||||
RC_MEMORY_TYPE_VIRTUAL_RAM, /* secondary address space that maps to real memory in system RAM */
|
||||
RC_MEMORY_TYPE_UNUSED /* these addresses don't really exist */
|
||||
};
|
||||
|
||||
typedef struct rc_memory_region_t {
|
||||
unsigned start_address; /* first address of block as queried by RetroAchievements */
|
||||
unsigned end_address; /* last address of block as queried by RetroAchievements */
|
||||
unsigned real_address; /* real address for first address of block */
|
||||
char type; /* RC_MEMORY_TYPE_ for block */
|
||||
const char* description; /* short description of block */
|
||||
}
|
||||
rc_memory_region_t;
|
||||
|
||||
typedef struct rc_memory_regions_t {
|
||||
const rc_memory_region_t* region;
|
||||
unsigned num_regions;
|
||||
}
|
||||
rc_memory_regions_t;
|
||||
|
||||
const rc_memory_regions_t* rc_console_memory_regions(int console_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
Vendored
+79
@@ -0,0 +1,79 @@
|
||||
#ifndef RCONSOLES_H
|
||||
#define RCONSOLES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*****************************************************************************\
|
||||
| Console identifiers |
|
||||
\*****************************************************************************/
|
||||
|
||||
enum {
|
||||
RC_CONSOLE_MEGA_DRIVE = 1,
|
||||
RC_CONSOLE_NINTENDO_64 = 2,
|
||||
RC_CONSOLE_SUPER_NINTENDO = 3,
|
||||
RC_CONSOLE_GAMEBOY = 4,
|
||||
RC_CONSOLE_GAMEBOY_ADVANCE = 5,
|
||||
RC_CONSOLE_GAMEBOY_COLOR = 6,
|
||||
RC_CONSOLE_NINTENDO = 7,
|
||||
RC_CONSOLE_PC_ENGINE = 8,
|
||||
RC_CONSOLE_SEGA_CD = 9,
|
||||
RC_CONSOLE_SEGA_32X = 10,
|
||||
RC_CONSOLE_MASTER_SYSTEM = 11,
|
||||
RC_CONSOLE_PLAYSTATION = 12,
|
||||
RC_CONSOLE_ATARI_LYNX = 13,
|
||||
RC_CONSOLE_NEOGEO_POCKET = 14,
|
||||
RC_CONSOLE_GAME_GEAR = 15,
|
||||
RC_CONSOLE_GAMECUBE = 16,
|
||||
RC_CONSOLE_ATARI_JAGUAR = 17,
|
||||
RC_CONSOLE_NINTENDO_DS = 18,
|
||||
RC_CONSOLE_WII = 19,
|
||||
RC_CONSOLE_WII_U = 20,
|
||||
RC_CONSOLE_PLAYSTATION_2 = 21,
|
||||
RC_CONSOLE_XBOX = 22,
|
||||
/* 23 used to be EVENTS */
|
||||
RC_CONSOLE_POKEMON_MINI = 24,
|
||||
RC_CONSOLE_ATARI_2600 = 25,
|
||||
RC_CONSOLE_MS_DOS = 26,
|
||||
RC_CONSOLE_ARCADE = 27,
|
||||
RC_CONSOLE_VIRTUAL_BOY = 28,
|
||||
RC_CONSOLE_MSX = 29,
|
||||
RC_CONSOLE_COMMODORE_64 = 30,
|
||||
RC_CONSOLE_ZX81 = 31,
|
||||
RC_CONSOLE_ORIC = 32,
|
||||
RC_CONSOLE_SG1000 = 33,
|
||||
RC_CONSOLE_VIC20 = 34,
|
||||
RC_CONSOLE_AMIGA = 35,
|
||||
RC_CONSOLE_AMIGA_ST = 36,
|
||||
RC_CONSOLE_AMSTRAD_PC = 37,
|
||||
RC_CONSOLE_APPLE_II = 38,
|
||||
RC_CONSOLE_SATURN = 39,
|
||||
RC_CONSOLE_DREAMCAST = 40,
|
||||
RC_CONSOLE_PSP = 41,
|
||||
RC_CONSOLE_CDI = 42,
|
||||
RC_CONSOLE_3DO = 43,
|
||||
RC_CONSOLE_COLECOVISION = 44,
|
||||
RC_CONSOLE_INTELLIVISION = 45,
|
||||
RC_CONSOLE_VECTREX = 46,
|
||||
RC_CONSOLE_PC8800 = 47,
|
||||
RC_CONSOLE_PC9800 = 48,
|
||||
RC_CONSOLE_PCFX = 49,
|
||||
RC_CONSOLE_ATARI_5200 = 50,
|
||||
RC_CONSOLE_ATARI_7800 = 51,
|
||||
RC_CONSOLE_X68K = 52,
|
||||
RC_CONSOLE_WONDERSWAN = 53,
|
||||
RC_CONSOLE_CASSETTEVISION = 54,
|
||||
RC_CONSOLE_SUPER_CASSETTEVISION = 55,
|
||||
|
||||
RC_CONSOLE_HUBS = 100,
|
||||
RC_CONSOLE_EVENTS = 101
|
||||
};
|
||||
|
||||
const char* rc_console_name(int console_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* RCONSOLES_H */
|
||||
Vendored
+124
@@ -0,0 +1,124 @@
|
||||
#ifndef RHASH_H
|
||||
#define RHASH_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "rconsoles.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ===================================================== */
|
||||
|
||||
/* generates a hash from a block of memory.
|
||||
* returns non-zero on success, or zero on failure.
|
||||
*/
|
||||
int rc_hash_generate_from_buffer(char hash[33], int console_id, uint8_t* buffer, size_t buffer_size);
|
||||
|
||||
/* generates a hash from a file.
|
||||
* returns non-zero on success, or zero on failure.
|
||||
*/
|
||||
int rc_hash_generate_from_file(char hash[33], int console_id, const char* path);
|
||||
|
||||
/* ===================================================== */
|
||||
|
||||
/* data for rc_hash_iterate
|
||||
*/
|
||||
struct rc_hash_iterator
|
||||
{
|
||||
uint8_t* buffer;
|
||||
size_t buffer_size;
|
||||
uint8_t consoles[12];
|
||||
int index;
|
||||
const char* path;
|
||||
};
|
||||
|
||||
/* initializes a rc_hash_iterator
|
||||
* - path must be provided
|
||||
* - if buffer and buffer_size are provided, path may be a filename (i.e. for something extracted from a zip file)
|
||||
*/
|
||||
void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char* path, uint8_t* buffer, size_t buffer_size);
|
||||
|
||||
/* releases resources associated to a rc_hash_iterator
|
||||
*/
|
||||
void rc_hash_destroy_iterator(struct rc_hash_iterator* iterator);
|
||||
|
||||
/* generates the next hash for the data in the rc_hash_iterator.
|
||||
* returns non-zero if a hash was generated, or zero if no more hashes can be generated for the data.
|
||||
*/
|
||||
int rc_hash_iterate(char hash[33], struct rc_hash_iterator* iterator);
|
||||
|
||||
/* ===================================================== */
|
||||
|
||||
/* specifies a function to call when an error occurs to display the error message */
|
||||
typedef void (*rc_hash_message_callback)(const char*);
|
||||
void rc_hash_init_error_message_callback(rc_hash_message_callback callback);
|
||||
|
||||
/* specifies a function to call for verbose logging */
|
||||
void rc_hash_init_verbose_message_callback(rc_hash_message_callback callback);
|
||||
|
||||
/* ===================================================== */
|
||||
|
||||
/* opens a file */
|
||||
typedef void* (*rc_hash_filereader_open_file_handler)(const char* path_utf8);
|
||||
|
||||
/* moves the file pointer - standard fseek parameters */
|
||||
typedef void (*rc_hash_filereader_seek_handler)(void* file_handle, size_t offset, int origin);
|
||||
|
||||
/* locates the file pointer */
|
||||
typedef size_t (*rc_hash_filereader_tell_handler)(void* file_handle);
|
||||
|
||||
/* reads the specified number of bytes from the file starting at the read pointer.
|
||||
* returns the number of bytes actually read.
|
||||
*/
|
||||
typedef size_t (*rc_hash_filereader_read_handler)(void* file_handle, void* buffer, size_t requested_bytes);
|
||||
|
||||
/* closes the file */
|
||||
typedef void (*rc_hash_filereader_close_file_handler)(void* file_handle);
|
||||
|
||||
struct rc_hash_filereader
|
||||
{
|
||||
rc_hash_filereader_open_file_handler open;
|
||||
rc_hash_filereader_seek_handler seek;
|
||||
rc_hash_filereader_tell_handler tell;
|
||||
rc_hash_filereader_read_handler read;
|
||||
rc_hash_filereader_close_file_handler close;
|
||||
};
|
||||
|
||||
void rc_hash_init_custom_filereader(struct rc_hash_filereader* reader);
|
||||
|
||||
/* ===================================================== */
|
||||
|
||||
/* opens a track from the specified file. track 0 indicates the first data track should be opened.
|
||||
* returns a handle to be passed to the other functions, or NULL if the track could not be opened.
|
||||
*/
|
||||
typedef void* (*rc_hash_cdreader_open_track_handler)(const char* path, uint32_t track);
|
||||
|
||||
/* attempts to read the specified number of bytes from the file starting at the read pointer.
|
||||
* returns the number of bytes actually read.
|
||||
*/
|
||||
typedef size_t (*rc_hash_cdreader_read_sector_handler)(void* track_handle, uint32_t sector, void* buffer, size_t requested_bytes);
|
||||
|
||||
/* closes the track handle */
|
||||
typedef void (*rc_hash_cdreader_close_track_handler)(void* track_handle);
|
||||
|
||||
struct rc_hash_cdreader
|
||||
{
|
||||
rc_hash_cdreader_open_track_handler open_track;
|
||||
rc_hash_cdreader_read_sector_handler read_sector;
|
||||
rc_hash_cdreader_close_track_handler close_track;
|
||||
};
|
||||
|
||||
void rc_hash_init_default_cdreader();
|
||||
void rc_hash_init_custom_cdreader(struct rc_hash_cdreader* reader);
|
||||
|
||||
/* ===================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* RHASH_H */
|
||||
Vendored
+6
-3
@@ -7,11 +7,11 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int rc_url_award_cheevo(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned cheevo_id, int hardcore);
|
||||
int rc_url_award_cheevo(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned cheevo_id, int hardcore, const char* game_hash);
|
||||
|
||||
int rc_url_submit_lboard(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned lboard_id, int value, const char* game_hash);
|
||||
int rc_url_submit_lboard(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned lboard_id, int value);
|
||||
|
||||
int rc_url_get_gameid(char* buffer, size_t size, unsigned char hash[16]);
|
||||
int rc_url_get_gameid(char* buffer, size_t size, const char* hash);
|
||||
|
||||
int rc_url_get_patch(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned gameid);
|
||||
|
||||
@@ -25,6 +25,9 @@ int rc_url_get_unlock_list(char* buffer, size_t size, const char* user_name, con
|
||||
|
||||
int rc_url_post_playing(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned gameid);
|
||||
|
||||
int rc_url_ping(char* url_buffer, size_t url_buffer_size, char* post_buffer, size_t post_buffer_size,
|
||||
const char* user_name, const char* login_token, unsigned gameid, const char* rich_presence);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
Vendored
+34
@@ -52,3 +52,37 @@ void rc_destroy_parse_state(rc_parse_state_t* parse)
|
||||
if (parse->scratch.memref != parse->scratch.memref_buffer)
|
||||
free(parse->scratch.memref);
|
||||
}
|
||||
|
||||
const char* rc_error_str(int ret)
|
||||
{
|
||||
switch (ret) {
|
||||
case RC_OK: return "OK";
|
||||
case RC_INVALID_LUA_OPERAND: return "Invalid Lua operand";
|
||||
case RC_INVALID_MEMORY_OPERAND: return "Invalid memory operand";
|
||||
case RC_INVALID_CONST_OPERAND: return "Invalid constant operand";
|
||||
case RC_INVALID_FP_OPERAND: return "Invalid floating-point operand";
|
||||
case RC_INVALID_CONDITION_TYPE: return "Invalid condition type";
|
||||
case RC_INVALID_OPERATOR: return "Invalid operator";
|
||||
case RC_INVALID_REQUIRED_HITS: return "Invalid required hits";
|
||||
case RC_DUPLICATED_START: return "Duplicated start condition";
|
||||
case RC_DUPLICATED_CANCEL: return "Duplicated cancel condition";
|
||||
case RC_DUPLICATED_SUBMIT: return "Duplicated submit condition";
|
||||
case RC_DUPLICATED_VALUE: return "Duplicated value expression";
|
||||
case RC_DUPLICATED_PROGRESS: return "Duplicated progress expression";
|
||||
case RC_MISSING_START: return "Missing start condition";
|
||||
case RC_MISSING_CANCEL: return "Missing cancel condition";
|
||||
case RC_MISSING_SUBMIT: return "Missing submit condition";
|
||||
case RC_MISSING_VALUE: return "Missing value expression";
|
||||
case RC_INVALID_LBOARD_FIELD: return "Invalid field in leaderboard";
|
||||
case RC_MISSING_DISPLAY_STRING: return "Missing display string";
|
||||
case RC_OUT_OF_MEMORY: return "Out of memory";
|
||||
case RC_INVALID_VALUE_FLAG: return "Invalid flag in value expression";
|
||||
case RC_MISSING_VALUE_MEASURED: return "Missing measured flag in value expression";
|
||||
case RC_MULTIPLE_MEASURED: return "Multiple measured targets";
|
||||
case RC_INVALID_MEASURED_TARGET: return "Invalid measured target";
|
||||
case RC_INVALID_COMPARISON: return "Invalid comparison";
|
||||
case RC_INVALID_STATE: return "Invalid state";
|
||||
|
||||
default: return "Unknown error";
|
||||
}
|
||||
}
|
||||
Vendored
+44
@@ -0,0 +1,44 @@
|
||||
#include "compat.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
int rc_strncasecmp(const char* left, const char* right, size_t length)
|
||||
{
|
||||
while (length)
|
||||
{
|
||||
if (*left != *right)
|
||||
{
|
||||
const int diff = tolower(*left) - tolower(*right);
|
||||
if (diff != 0)
|
||||
return diff;
|
||||
}
|
||||
|
||||
++left;
|
||||
++right;
|
||||
--length;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* rc_strdup(const char* str)
|
||||
{
|
||||
const size_t length = strlen(str);
|
||||
char* buffer = (char*)malloc(length + 1);
|
||||
memcpy(buffer, str, length + 1);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int rc_snprintf(char* buffer, size_t size, const char* format, ...)
|
||||
{
|
||||
int result;
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
/* assume buffer is large enough and ignore size */
|
||||
result = vsprintf(buffer, format, args);
|
||||
va_end(args);
|
||||
|
||||
return result;
|
||||
}
|
||||
Vendored
+55
@@ -0,0 +1,55 @@
|
||||
#ifndef RC_COMPAT_H
|
||||
#define RC_COMPAT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(MINGW) || defined(__MINGW32__) || defined(__MINGW64__)
|
||||
|
||||
/* MinGW redefinitions */
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
/* Visual Studio redefinitions */
|
||||
|
||||
#ifndef strcasecmp
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
#ifndef strncasecmp
|
||||
#define strncasecmp _strnicmp
|
||||
#endif
|
||||
#ifndef strdup
|
||||
#define strdup _strdup
|
||||
#endif
|
||||
|
||||
#elif __STDC_VERSION__ < 199901L
|
||||
|
||||
/* C89 redefinitions */
|
||||
|
||||
#ifndef snprintf
|
||||
extern int rc_snprintf(char* buffer, size_t size, const char* format, ...);
|
||||
#define snprintf rc_snprintf
|
||||
#endif
|
||||
|
||||
#ifndef strncasecmp
|
||||
extern int rc_strncasecmp(const char* left, const char* right, size_t length);
|
||||
#define strncasecmp rc_strncasecmp
|
||||
#endif
|
||||
|
||||
#ifndef strdup
|
||||
extern char* rc_strdup(const char* str);
|
||||
#define strdup rc_strdup
|
||||
#endif
|
||||
|
||||
#endif /* __STDC_VERSION__ < 199901L */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* RC_COMPAT_H */
|
||||
+105
-17
@@ -6,6 +6,7 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
|
||||
rc_condition_t* self;
|
||||
const char* aux;
|
||||
int ret2;
|
||||
int can_modify = 0;
|
||||
|
||||
aux = *memaddr;
|
||||
self = RC_ALLOC(rc_condition_t, parse);
|
||||
@@ -15,12 +16,15 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
|
||||
switch (*aux) {
|
||||
case 'p': case 'P': self->type = RC_CONDITION_PAUSE_IF; break;
|
||||
case 'r': case 'R': self->type = RC_CONDITION_RESET_IF; break;
|
||||
case 'a': case 'A': self->type = RC_CONDITION_ADD_SOURCE; break;
|
||||
case 'b': case 'B': self->type = RC_CONDITION_SUB_SOURCE; break;
|
||||
case 'a': case 'A': self->type = RC_CONDITION_ADD_SOURCE; can_modify = 1; break;
|
||||
case 'b': case 'B': self->type = RC_CONDITION_SUB_SOURCE; can_modify = 1; break;
|
||||
case 'c': case 'C': self->type = RC_CONDITION_ADD_HITS; break;
|
||||
case 'n': case 'N': self->type = RC_CONDITION_AND_NEXT; break;
|
||||
case 'o': case 'O': self->type = RC_CONDITION_OR_NEXT; break;
|
||||
case 'm': case 'M': self->type = RC_CONDITION_MEASURED; break;
|
||||
case 'i': case 'I': self->type = RC_CONDITION_ADD_ADDRESS; break;
|
||||
case 'q': case 'Q': self->type = RC_CONDITION_MEASURED_IF; break;
|
||||
case 'i': case 'I': self->type = RC_CONDITION_ADD_ADDRESS; can_modify = 1; break;
|
||||
case 't': case 'T': self->type = RC_CONDITION_TRIGGER; break;
|
||||
default: parse->offset = RC_INVALID_CONDITION_TYPE; return 0;
|
||||
}
|
||||
|
||||
@@ -37,9 +41,14 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (self->operand1.type == RC_OPERAND_FP) {
|
||||
parse->offset = can_modify ? RC_INVALID_FP_OPERAND : RC_INVALID_COMPARISON;
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (*aux++) {
|
||||
case '=':
|
||||
self->oper = RC_CONDITION_EQ;
|
||||
self->oper = RC_OPERATOR_EQ;
|
||||
aux += *aux == '=';
|
||||
break;
|
||||
|
||||
@@ -51,33 +60,45 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
|
||||
return 0;
|
||||
}
|
||||
|
||||
self->oper = RC_CONDITION_NE;
|
||||
self->oper = RC_OPERATOR_NE;
|
||||
break;
|
||||
|
||||
case '<':
|
||||
self->oper = RC_CONDITION_LT;
|
||||
self->oper = RC_OPERATOR_LT;
|
||||
|
||||
if (*aux == '=') {
|
||||
self->oper = RC_CONDITION_LE;
|
||||
self->oper = RC_OPERATOR_LE;
|
||||
aux++;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case '>':
|
||||
self->oper = RC_CONDITION_GT;
|
||||
self->oper = RC_OPERATOR_GT;
|
||||
|
||||
if (*aux == '=') {
|
||||
self->oper = RC_CONDITION_GE;
|
||||
self->oper = RC_OPERATOR_GE;
|
||||
aux++;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case '*':
|
||||
self->oper = RC_OPERATOR_MULT;
|
||||
break;
|
||||
|
||||
case '/':
|
||||
self->oper = RC_OPERATOR_DIV;
|
||||
break;
|
||||
|
||||
case '&':
|
||||
self->oper = RC_OPERATOR_AND;
|
||||
break;
|
||||
|
||||
case '_':
|
||||
case ')':
|
||||
case '\0':
|
||||
self->oper = RC_CONDITION_NONE;
|
||||
self->oper = RC_OPERATOR_NONE;
|
||||
self->operand2.type = RC_OPERAND_CONST;
|
||||
self->operand2.value.num = 1;
|
||||
self->required_hits = 0;
|
||||
@@ -85,6 +106,36 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
|
||||
return self;
|
||||
}
|
||||
|
||||
switch (self->oper) {
|
||||
case RC_OPERATOR_MULT:
|
||||
case RC_OPERATOR_DIV:
|
||||
case RC_OPERATOR_AND:
|
||||
/* modifying operators are only valid on modifying statements */
|
||||
if (!can_modify) {
|
||||
parse->offset = RC_INVALID_OPERATOR;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* comparison operators are not valid on modifying statements */
|
||||
if (can_modify) {
|
||||
switch (self->type) {
|
||||
case RC_CONDITION_ADD_SOURCE:
|
||||
case RC_CONDITION_SUB_SOURCE:
|
||||
case RC_CONDITION_ADD_ADDRESS:
|
||||
/* prevent parse errors on legacy achievements where a condition was present before changing the type */
|
||||
self->oper = RC_OPERATOR_NONE;
|
||||
break;
|
||||
|
||||
default:
|
||||
parse->offset = RC_INVALID_OPERATOR;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ret2 = rc_parse_operand(&self->operand2, &aux, 1, is_indirect, parse);
|
||||
|
||||
if (ret2 < 0) {
|
||||
@@ -92,6 +143,17 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (self->oper == RC_OPERATOR_NONE) {
|
||||
/* if operator is none, explicitly clear out the right side */
|
||||
self->operand2.type = RC_INVALID_CONST_OPERAND;
|
||||
self->operand2.value.num = 0;
|
||||
}
|
||||
|
||||
if (!can_modify && self->operand2.type == RC_OPERAND_FP) {
|
||||
parse->offset = RC_INVALID_COMPARISON;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*aux == '(') {
|
||||
char* end;
|
||||
self->required_hits = (unsigned)strtoul(++aux, &end, 10);
|
||||
@@ -127,13 +189,39 @@ int rc_test_condition(rc_condition_t* self, rc_eval_state_t* eval_state) {
|
||||
unsigned value2 = rc_evaluate_operand(&self->operand2, eval_state);
|
||||
|
||||
switch (self->oper) {
|
||||
case RC_CONDITION_EQ: return value1 == value2;
|
||||
case RC_CONDITION_NE: return value1 != value2;
|
||||
case RC_CONDITION_LT: return value1 < value2;
|
||||
case RC_CONDITION_LE: return value1 <= value2;
|
||||
case RC_CONDITION_GT: return value1 > value2;
|
||||
case RC_CONDITION_GE: return value1 >= value2;
|
||||
case RC_CONDITION_NONE: return 1;
|
||||
case RC_OPERATOR_EQ: return value1 == value2;
|
||||
case RC_OPERATOR_NE: return value1 != value2;
|
||||
case RC_OPERATOR_LT: return value1 < value2;
|
||||
case RC_OPERATOR_LE: return value1 <= value2;
|
||||
case RC_OPERATOR_GT: return value1 > value2;
|
||||
case RC_OPERATOR_GE: return value1 >= value2;
|
||||
case RC_OPERATOR_NONE: return 1;
|
||||
default: return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int rc_evaluate_condition_value(rc_condition_t* self, rc_eval_state_t* eval_state) {
|
||||
unsigned value = rc_evaluate_operand(&self->operand1, eval_state);
|
||||
|
||||
switch (self->oper) {
|
||||
case RC_OPERATOR_MULT:
|
||||
if (self->operand2.type == RC_OPERAND_FP)
|
||||
value = (int)((double)value * self->operand2.value.dbl);
|
||||
else
|
||||
value *= rc_evaluate_operand(&self->operand2, eval_state);
|
||||
break;
|
||||
|
||||
case RC_OPERATOR_DIV:
|
||||
if (self->operand2.type == RC_OPERAND_FP)
|
||||
value = (int)((double)value / self->operand2.value.dbl);
|
||||
else
|
||||
value /= rc_evaluate_operand(&self->operand2, eval_state);
|
||||
break;
|
||||
|
||||
case RC_OPERATOR_AND:
|
||||
value &= rc_evaluate_operand(&self->operand2, eval_state);
|
||||
break;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
Vendored
+111
-72
@@ -9,15 +9,16 @@ static void rc_update_condition_pause(rc_condition_t* condition, int* in_pause)
|
||||
case RC_CONDITION_PAUSE_IF:
|
||||
*in_pause = condition->pause = 1;
|
||||
break;
|
||||
|
||||
|
||||
case RC_CONDITION_ADD_SOURCE:
|
||||
case RC_CONDITION_SUB_SOURCE:
|
||||
case RC_CONDITION_ADD_HITS:
|
||||
case RC_CONDITION_AND_NEXT:
|
||||
case RC_CONDITION_OR_NEXT:
|
||||
case RC_CONDITION_ADD_ADDRESS:
|
||||
condition->pause = *in_pause;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
*in_pause = condition->pause = 0;
|
||||
break;
|
||||
@@ -48,14 +49,15 @@ rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((*next)->oper == RC_CONDITION_NONE) {
|
||||
if ((*next)->oper == RC_OPERATOR_NONE) {
|
||||
switch ((*next)->type) {
|
||||
case RC_CONDITION_ADD_ADDRESS:
|
||||
case RC_CONDITION_ADD_HITS:
|
||||
case RC_CONDITION_ADD_SOURCE:
|
||||
case RC_CONDITION_SUB_SOURCE:
|
||||
case RC_CONDITION_AND_NEXT:
|
||||
break;
|
||||
case RC_CONDITION_OR_NEXT:
|
||||
break;
|
||||
|
||||
default:
|
||||
parse->offset = RC_INVALID_OPERATOR;
|
||||
@@ -110,10 +112,14 @@ rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse) {
|
||||
|
||||
static int rc_test_condset_internal(rc_condset_t* self, int processing_pause, rc_eval_state_t* eval_state) {
|
||||
rc_condition_t* condition;
|
||||
int set_valid, cond_valid, prev_cond;
|
||||
int set_valid, cond_valid, and_next, or_next;
|
||||
unsigned measured_value = 0;
|
||||
int can_measure = 1, measured_from_hits = 0;
|
||||
|
||||
eval_state->primed = 1;
|
||||
set_valid = 1;
|
||||
prev_cond = 1;
|
||||
and_next = 1;
|
||||
or_next = 0;
|
||||
eval_state->add_value = eval_state->add_hits = eval_state->add_address = 0;
|
||||
|
||||
for (condition = self->conditions; condition != 0; condition = condition->next) {
|
||||
@@ -121,93 +127,107 @@ static int rc_test_condset_internal(rc_condset_t* self, int processing_pause, rc
|
||||
continue;
|
||||
}
|
||||
|
||||
/* STEP 1: process modifier conditions */
|
||||
switch (condition->type) {
|
||||
case RC_CONDITION_ADD_SOURCE:
|
||||
eval_state->add_value += rc_evaluate_operand(&condition->operand1, eval_state);
|
||||
eval_state->add_value += rc_evaluate_condition_value(condition, eval_state);
|
||||
eval_state->add_address = 0;
|
||||
continue;
|
||||
|
||||
|
||||
case RC_CONDITION_SUB_SOURCE:
|
||||
eval_state->add_value -= rc_evaluate_operand(&condition->operand1, eval_state);
|
||||
eval_state->add_address = 0;
|
||||
continue;
|
||||
|
||||
case RC_CONDITION_ADD_HITS:
|
||||
/* always evaluate the condition to ensure everything is updated correctly */
|
||||
cond_valid = rc_test_condition(condition, eval_state);
|
||||
|
||||
/* merge AndNext value and reset it for the next condition */
|
||||
cond_valid &= prev_cond;
|
||||
prev_cond = 1;
|
||||
|
||||
/* if the condition is true, tally it */
|
||||
if (cond_valid) {
|
||||
if (condition->required_hits == 0 || condition->current_hits < condition->required_hits) {
|
||||
condition->current_hits++;
|
||||
}
|
||||
|
||||
condition->is_true = (condition->required_hits == 0 || condition->current_hits >= condition->required_hits);
|
||||
}
|
||||
else {
|
||||
condition->is_true = 0;
|
||||
}
|
||||
|
||||
eval_state->add_value = 0;
|
||||
eval_state->add_address = 0;
|
||||
eval_state->add_hits += condition->current_hits;
|
||||
continue;
|
||||
|
||||
case RC_CONDITION_AND_NEXT:
|
||||
prev_cond &= rc_test_condition(condition, eval_state);
|
||||
eval_state->add_value = 0;
|
||||
eval_state->add_value -= rc_evaluate_condition_value(condition, eval_state);
|
||||
eval_state->add_address = 0;
|
||||
continue;
|
||||
|
||||
case RC_CONDITION_ADD_ADDRESS:
|
||||
eval_state->add_address = rc_evaluate_operand(&condition->operand1, eval_state);
|
||||
eval_state->add_address = rc_evaluate_condition_value(condition, eval_state);
|
||||
continue;
|
||||
|
||||
case RC_CONDITION_MEASURED:
|
||||
if (condition->required_hits == 0) {
|
||||
/* Measured condition without a hit target measures the value of the left operand */
|
||||
measured_value = rc_evaluate_condition_value(condition, eval_state) + eval_state->add_value;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* always evaluate the condition to ensure everything is updated correctly */
|
||||
cond_valid = rc_test_condition(condition, eval_state);
|
||||
/* STEP 2: evaluate the current condition */
|
||||
condition->is_true = rc_test_condition(condition, eval_state);
|
||||
eval_state->add_value = 0;
|
||||
eval_state->add_address = 0;
|
||||
|
||||
/* merge AndNext value and reset it for the next condition */
|
||||
cond_valid &= prev_cond;
|
||||
prev_cond = 1;
|
||||
/* apply logic flags and reset them for the next condition */
|
||||
cond_valid = condition->is_true;
|
||||
cond_valid &= and_next;
|
||||
cond_valid |= or_next;
|
||||
and_next = 1;
|
||||
or_next = 0;
|
||||
|
||||
/* if the condition has a target hit count that has already been met, it's automatically true, even if not currently true. */
|
||||
if (condition->required_hits != 0 && (condition->current_hits + eval_state->add_hits) >= condition->required_hits) {
|
||||
cond_valid = 1;
|
||||
}
|
||||
else if (cond_valid) {
|
||||
condition->current_hits++;
|
||||
/* true conditions should update hit count */
|
||||
if (cond_valid) {
|
||||
eval_state->has_hits = 1;
|
||||
|
||||
if (condition->required_hits == 0) {
|
||||
/* not a hit-based requirement: ignore any additional logic! */
|
||||
/* no target hit count, just keep tallying */
|
||||
++condition->current_hits;
|
||||
}
|
||||
else if ((condition->current_hits + eval_state->add_hits) < condition->required_hits) {
|
||||
/* HitCount target has not yet been met, condition is not yet valid */
|
||||
cond_valid = 0;
|
||||
else if (condition->current_hits < condition->required_hits) {
|
||||
/* target hit count hasn't been met, tally and revalidate - only true if hit count becomes met */
|
||||
++condition->current_hits;
|
||||
cond_valid = (condition->current_hits == condition->required_hits);
|
||||
}
|
||||
else {
|
||||
/* target hit count has been met, do nothing */
|
||||
}
|
||||
}
|
||||
condition->is_true = cond_valid;
|
||||
eval_state->has_hits |= (condition->current_hits || eval_state->add_hits);
|
||||
else if (condition->current_hits > 0) {
|
||||
/* target has been true in the past, if the hit target is met, consider it true now */
|
||||
eval_state->has_hits = 1;
|
||||
cond_valid = (condition->current_hits == condition->required_hits);
|
||||
}
|
||||
|
||||
/* capture measured state */
|
||||
if (condition->type == RC_CONDITION_MEASURED) {
|
||||
unsigned int measured_value;
|
||||
if (condition->required_hits > 0)
|
||||
/* STEP 3: handle logic flags */
|
||||
switch (condition->type) {
|
||||
case RC_CONDITION_ADD_HITS:
|
||||
eval_state->add_hits += condition->current_hits;
|
||||
continue;
|
||||
|
||||
case RC_CONDITION_AND_NEXT:
|
||||
and_next = cond_valid;
|
||||
continue;
|
||||
|
||||
case RC_CONDITION_OR_NEXT:
|
||||
or_next = cond_valid;
|
||||
continue;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (eval_state->add_hits) {
|
||||
if (condition->required_hits != 0) {
|
||||
/* if the condition has a target hit count, we have to recalculate cond_valid including the AddHits counter */
|
||||
measured_from_hits = 1;
|
||||
measured_value = condition->current_hits + eval_state->add_hits;
|
||||
else
|
||||
measured_value = rc_evaluate_operand(&condition->operand1, eval_state) + eval_state->add_value;
|
||||
cond_valid = (measured_value >= condition->required_hits);
|
||||
}
|
||||
else {
|
||||
/* no target hit count. we can't tell if the add_hits value is from this frame or not, so ignore it.
|
||||
complex condition will only be true if the current condition is true */
|
||||
}
|
||||
|
||||
if (measured_value > eval_state->measured_value)
|
||||
eval_state->measured_value = measured_value;
|
||||
eval_state->add_hits = 0;
|
||||
}
|
||||
else if (condition->required_hits != 0) {
|
||||
/* if there's a hit target, capture the current hits for recording Measured value later */
|
||||
measured_from_hits = 1;
|
||||
measured_value = condition->current_hits;
|
||||
}
|
||||
|
||||
/* reset AddHits and AddSource/SubSource values */
|
||||
eval_state->add_value = eval_state->add_hits = eval_state->add_address = 0;
|
||||
|
||||
/* STEP 4: handle special flags */
|
||||
switch (condition->type) {
|
||||
case RC_CONDITION_PAUSE_IF:
|
||||
/* as soon as we find a PauseIf that evaluates to true, stop processing the rest of the group */
|
||||
@@ -227,20 +247,38 @@ static int rc_test_condset_internal(rc_condset_t* self, int processing_pause, rc
|
||||
/* PauseIf has a HitCount that hasn't been met, ignore it for now. */
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
continue;
|
||||
|
||||
case RC_CONDITION_RESET_IF:
|
||||
if (cond_valid) {
|
||||
eval_state->was_reset = 1; /* let caller know to reset all hit counts */
|
||||
set_valid = 0; /* cannot be valid if we've hit a reset condition */
|
||||
}
|
||||
continue;
|
||||
|
||||
case RC_CONDITION_MEASURED_IF:
|
||||
if (!cond_valid)
|
||||
can_measure = 0;
|
||||
break;
|
||||
|
||||
case RC_CONDITION_TRIGGER:
|
||||
/* update truthiness of set, but do not update truthiness of primed state */
|
||||
set_valid &= cond_valid;
|
||||
continue;
|
||||
|
||||
default:
|
||||
set_valid &= cond_valid;
|
||||
break;
|
||||
}
|
||||
|
||||
/* STEP 5: update overall truthiness of set and primed state */
|
||||
eval_state->primed &= cond_valid;
|
||||
set_valid &= cond_valid;
|
||||
}
|
||||
|
||||
/* if not suppressed, update the measured value */
|
||||
if (measured_value > eval_state->measured_value && can_measure) {
|
||||
eval_state->measured_value = measured_value;
|
||||
eval_state->measured_from_hits = measured_from_hits;
|
||||
}
|
||||
|
||||
return set_valid;
|
||||
@@ -255,6 +293,7 @@ int rc_test_condset(rc_condset_t* self, rc_eval_state_t* eval_state) {
|
||||
if (self->has_pause) {
|
||||
if ((self->is_paused = rc_test_condset_internal(self, 1, eval_state))) {
|
||||
/* one or more Pause conditions exists, if any of them are true, stop processing this group */
|
||||
eval_state->primed = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
+573
@@ -0,0 +1,573 @@
|
||||
#include "rcheevos.h"
|
||||
#include "rconsoles.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
const char* rc_console_name(int console_id)
|
||||
{
|
||||
switch (console_id)
|
||||
{
|
||||
case RC_CONSOLE_3DO:
|
||||
return "3DO";
|
||||
|
||||
case RC_CONSOLE_AMIGA:
|
||||
return "Amiga";
|
||||
|
||||
case RC_CONSOLE_AMIGA_ST:
|
||||
return "Amiga ST";
|
||||
|
||||
case RC_CONSOLE_AMSTRAD_PC:
|
||||
return "Amstrad CPC";
|
||||
|
||||
case RC_CONSOLE_APPLE_II:
|
||||
return "Apple II";
|
||||
|
||||
case RC_CONSOLE_ARCADE:
|
||||
return "Arcade";
|
||||
|
||||
case RC_CONSOLE_ATARI_2600:
|
||||
return "Atari 2600";
|
||||
|
||||
case RC_CONSOLE_ATARI_5200:
|
||||
return "Atari 5200";
|
||||
|
||||
case RC_CONSOLE_ATARI_7800:
|
||||
return "Atari 7800";
|
||||
|
||||
case RC_CONSOLE_ATARI_JAGUAR:
|
||||
return "Atari Jaguar";
|
||||
|
||||
case RC_CONSOLE_ATARI_LYNX:
|
||||
return "Atari Lynx";
|
||||
|
||||
case RC_CONSOLE_CASSETTEVISION:
|
||||
return "CassetteVision";
|
||||
|
||||
case RC_CONSOLE_CDI:
|
||||
return "CD-I";
|
||||
|
||||
case RC_CONSOLE_COLECOVISION:
|
||||
return "ColecoVision";
|
||||
|
||||
case RC_CONSOLE_COMMODORE_64:
|
||||
return "Commodore 64";
|
||||
|
||||
case RC_CONSOLE_DREAMCAST:
|
||||
return "Dreamcast";
|
||||
|
||||
case RC_CONSOLE_EVENTS:
|
||||
return "Events";
|
||||
|
||||
case RC_CONSOLE_GAMEBOY:
|
||||
return "GameBoy";
|
||||
|
||||
case RC_CONSOLE_GAMEBOY_ADVANCE:
|
||||
return "GameBoy Advance";
|
||||
|
||||
case RC_CONSOLE_GAMEBOY_COLOR:
|
||||
return "GameBoy Color";
|
||||
|
||||
case RC_CONSOLE_GAMECUBE:
|
||||
return "GameCube";
|
||||
|
||||
case RC_CONSOLE_GAME_GEAR:
|
||||
return "Game Gear";
|
||||
|
||||
case RC_CONSOLE_HUBS:
|
||||
return "Hubs";
|
||||
|
||||
case RC_CONSOLE_INTELLIVISION:
|
||||
return "Intellivision";
|
||||
|
||||
case RC_CONSOLE_MASTER_SYSTEM:
|
||||
return "Master System";
|
||||
|
||||
case RC_CONSOLE_MEGA_DRIVE:
|
||||
return "Sega Genesis";
|
||||
|
||||
case RC_CONSOLE_MS_DOS:
|
||||
return "MS-DOS";
|
||||
|
||||
case RC_CONSOLE_MSX:
|
||||
return "MSX";
|
||||
|
||||
case RC_CONSOLE_NINTENDO:
|
||||
return "Nintendo Entertainment System";
|
||||
|
||||
case RC_CONSOLE_NINTENDO_64:
|
||||
return "Nintendo 64";
|
||||
|
||||
case RC_CONSOLE_NINTENDO_DS:
|
||||
return "Nintendo DS";
|
||||
|
||||
case RC_CONSOLE_NEOGEO_POCKET:
|
||||
return "Neo Geo Pocket";
|
||||
|
||||
case RC_CONSOLE_ORIC:
|
||||
return "Oric";
|
||||
|
||||
case RC_CONSOLE_PC8800:
|
||||
return "PC-8000/8800";
|
||||
|
||||
case RC_CONSOLE_PC9800:
|
||||
return "PC-9800";
|
||||
|
||||
case RC_CONSOLE_PCFX:
|
||||
return "PCFX";
|
||||
|
||||
case RC_CONSOLE_PC_ENGINE:
|
||||
return "PCEngine";
|
||||
|
||||
case RC_CONSOLE_PLAYSTATION:
|
||||
return "PlayStation";
|
||||
|
||||
case RC_CONSOLE_PLAYSTATION_2:
|
||||
return "PlayStation 2";
|
||||
|
||||
case RC_CONSOLE_PSP:
|
||||
return "PlayStation Portable";
|
||||
|
||||
case RC_CONSOLE_POKEMON_MINI:
|
||||
return "Pokemon Mini";
|
||||
|
||||
case RC_CONSOLE_SEGA_32X:
|
||||
return "Sega 32X";
|
||||
|
||||
case RC_CONSOLE_SEGA_CD:
|
||||
return "Sega CD";
|
||||
|
||||
case RC_CONSOLE_SATURN:
|
||||
return "Sega Saturn";
|
||||
|
||||
case RC_CONSOLE_SG1000:
|
||||
return "SG-1000";
|
||||
|
||||
case RC_CONSOLE_SUPER_NINTENDO:
|
||||
return "Super Nintendo Entertainment System";
|
||||
|
||||
case RC_CONSOLE_SUPER_CASSETTEVISION:
|
||||
return "Super CassetteVision";
|
||||
|
||||
case RC_CONSOLE_WONDERSWAN:
|
||||
return "WonderSwan";
|
||||
|
||||
case RC_CONSOLE_VECTREX:
|
||||
return "Vectrex";
|
||||
|
||||
case RC_CONSOLE_VIC20:
|
||||
return "VIC-20";
|
||||
|
||||
case RC_CONSOLE_VIRTUAL_BOY:
|
||||
return "Virtual Boy";
|
||||
|
||||
case RC_CONSOLE_WII:
|
||||
return "Wii";
|
||||
|
||||
case RC_CONSOLE_WII_U:
|
||||
return "Wii-U";
|
||||
|
||||
case RC_CONSOLE_X68K:
|
||||
return "X68K";
|
||||
|
||||
case RC_CONSOLE_XBOX:
|
||||
return "XBOX";
|
||||
|
||||
case RC_CONSOLE_ZX81:
|
||||
return "ZX-81";
|
||||
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== 3DO ===== */
|
||||
/* http://www.arcaderestoration.com/memorymap/48/3DO+Bios.aspx */
|
||||
/* NOTE: the Opera core attempts to expose the NVRAM as RETRO_SAVE_RAM, but the 3DO documentation
|
||||
* says that applications should only access NVRAM through API calls as it's shared across mulitple
|
||||
* games. This suggests that even if the core does expose it, it may change depending on which other
|
||||
* games the user has played - so ignore it.
|
||||
*/
|
||||
static const rc_memory_region_t _rc_memory_regions_3do[] = {
|
||||
{ 0x000000U, 0x1FFFFFU, 0x000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Main RAM" },
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_3do = { _rc_memory_regions_3do, 1 };
|
||||
|
||||
/* ===== Apple II ===== */
|
||||
static const rc_memory_region_t _rc_memory_regions_appleii[] = {
|
||||
{ 0x000000U, 0x00FFFFU, 0x000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Main RAM" },
|
||||
{ 0x010000U, 0x01FFFFU, 0x010000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Auxillary RAM" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_appleii = { _rc_memory_regions_appleii, 2 };
|
||||
|
||||
/* ===== Atari 2600 ===== */
|
||||
static const rc_memory_region_t _rc_memory_regions_atari2600[] = {
|
||||
{ 0x000000U, 0x00007FU, 0x000080U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_atari2600 = { _rc_memory_regions_atari2600, 1 };
|
||||
|
||||
/* ===== Atari 7800 ===== */
|
||||
/* http://www.atarihq.com/danb/files/78map.txt */
|
||||
/* http://pdf.textfiles.com/technical/7800_devkit.pdf */
|
||||
static const rc_memory_region_t _rc_memory_regions_atari7800[] = {
|
||||
{ 0x000000U, 0x0017FFU, 0x000000U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "Hardware Interface" },
|
||||
{ 0x001800U, 0x0027FFU, 0x001800U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
|
||||
{ 0x002800U, 0x002FFFU, 0x002800U, RC_MEMORY_TYPE_VIRTUAL_RAM, "Mirrored RAM" },
|
||||
{ 0x003000U, 0x0037FFU, 0x003000U, RC_MEMORY_TYPE_VIRTUAL_RAM, "Mirrored RAM" },
|
||||
{ 0x003800U, 0x003FFFU, 0x003800U, RC_MEMORY_TYPE_VIRTUAL_RAM, "Mirrored RAM" },
|
||||
{ 0x004000U, 0x007FFFU, 0x004000U, RC_MEMORY_TYPE_SAVE_RAM, "Cartridge RAM" },
|
||||
{ 0x008000U, 0x00FFFFU, 0x008000U, RC_MEMORY_TYPE_READONLY, "Cartridge ROM" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_atari7800 = { _rc_memory_regions_atari7800, 7 };
|
||||
|
||||
/* ===== Atari Jaguar ===== */
|
||||
/* https://www.mulle-kybernetik.com/jagdox/memorymap.html */
|
||||
static const rc_memory_region_t _rc_memory_regions_atari_jaguar[] = {
|
||||
{ 0x000000U, 0x1FFFFFU, 0x000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_atari_jaguar = { _rc_memory_regions_atari_jaguar, 1 };
|
||||
|
||||
/* ===== Atari Lynx ===== */
|
||||
/* http://www.retroisle.com/atari/lynx/Technical/Programming/lynxprgdumm.php */
|
||||
static const rc_memory_region_t _rc_memory_regions_atari_lynx[] = {
|
||||
{ 0x000000U, 0x0000FFU, 0x000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Zero Page" },
|
||||
{ 0x000100U, 0x0001FFU, 0x000100U, RC_MEMORY_TYPE_SYSTEM_RAM, "Stack" },
|
||||
{ 0x000200U, 0x00FBFFU, 0x000200U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
|
||||
{ 0x00FC00U, 0x00FCFFU, 0x00FC00U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "SUZY hardware access" },
|
||||
{ 0x00FD00U, 0x00FDFFU, 0x00FD00U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "MIKEY hardware access" },
|
||||
{ 0x00FE00U, 0x00FFF7U, 0x00FE00U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "Boot ROM" },
|
||||
{ 0x00FFF8U, 0x00FFFFU, 0x00FFF8U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "Hardware vectors" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_atari_lynx = { _rc_memory_regions_atari_lynx, 7 };
|
||||
|
||||
/* ===== ColecoVision ===== */
|
||||
static const rc_memory_region_t _rc_memory_regions_colecovision[] = {
|
||||
{ 0x000000U, 0x0003FFU, 0x006000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_colecovision = { _rc_memory_regions_colecovision, 1 };
|
||||
|
||||
/* ===== GameBoy / GameBoy Color ===== */
|
||||
static const rc_memory_region_t _rc_memory_regions_gameboy[] = {
|
||||
{ 0x000000U, 0x0000FFU, 0x000000U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "Interrupt vector" },
|
||||
{ 0x000100U, 0x00014FU, 0x000100U, RC_MEMORY_TYPE_READONLY, "Cartridge header" },
|
||||
{ 0x000150U, 0x003FFFU, 0x000150U, RC_MEMORY_TYPE_READONLY, "Cartridge ROM (fixed)" }, /* bank 0 */
|
||||
{ 0x004000U, 0x007FFFU, 0x004000U, RC_MEMORY_TYPE_READONLY, "Cartridge ROM (paged)" }, /* bank 1-XX (switchable) */
|
||||
{ 0x008000U, 0x0097FFU, 0x008000U, RC_MEMORY_TYPE_VIDEO_RAM, "Tile RAM" },
|
||||
{ 0x009800U, 0x009BFFU, 0x009800U, RC_MEMORY_TYPE_VIDEO_RAM, "BG1 map data" },
|
||||
{ 0x009C00U, 0x009FFFU, 0x009C00U, RC_MEMORY_TYPE_VIDEO_RAM, "BG2 map data" },
|
||||
{ 0x00A000U, 0x00BFFFU, 0x00A000U, RC_MEMORY_TYPE_SAVE_RAM, "Cartridge RAM"},
|
||||
{ 0x00C000U, 0x00CFFFU, 0x00C000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM (fixed)" },
|
||||
{ 0x00D000U, 0x00DFFFU, 0x00D000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM (bank 1)" },
|
||||
{ 0x00E000U, 0x00FDFFU, 0x00C000U, RC_MEMORY_TYPE_VIRTUAL_RAM, "Echo RAM" },
|
||||
{ 0x00FE00U, 0x00FE9FU, 0x00FE00U, RC_MEMORY_TYPE_VIDEO_RAM, "Sprite RAM"},
|
||||
{ 0x00FEA0U, 0x00FEFFU, 0x00FEA0U, RC_MEMORY_TYPE_READONLY, "Unusable"},
|
||||
{ 0x00FF00U, 0x00FF7FU, 0x00FF00U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "Hardware I/O"},
|
||||
{ 0x00FF80U, 0x00FFFEU, 0x00FF80U, RC_MEMORY_TYPE_SYSTEM_RAM, "Quick RAM"},
|
||||
{ 0x00FFFFU, 0x00FFFFU, 0x00FFFFU, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "Interrupt enable"},
|
||||
|
||||
/* GameBoy Color provides six extra banks of memory that can be paged out through the $DXXX
|
||||
* memory space, but the timing of that does not correspond with blanks, which is when achievements
|
||||
* are processed. As such, it is desirable to always have access to these extra banks. We do this
|
||||
* by expecting the extra banks to be addressable at addresses not supported by the native system. */
|
||||
{ 0x010000U, 0x015FFFU, 0x010000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM (banks 2-7, GBC only)" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_gameboy = { _rc_memory_regions_gameboy, 16 };
|
||||
static const rc_memory_regions_t rc_memory_regions_gameboy_color = { _rc_memory_regions_gameboy, 17 };
|
||||
|
||||
/* ===== GameBoy Advance ===== */
|
||||
static const rc_memory_region_t _rc_memory_regions_gameboy_advance[] = {
|
||||
{ 0x000000U, 0x007FFFU, 0x03000000U, RC_MEMORY_TYPE_SAVE_RAM, "Cartridge RAM" },
|
||||
{ 0x008000U, 0x047FFFU, 0x02000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_gameboy_advance = { _rc_memory_regions_gameboy_advance, 2 };
|
||||
|
||||
/* ===== Game Gear ===== */
|
||||
/* http://www.smspower.org/Development/MemoryMap */
|
||||
static const rc_memory_region_t _rc_memory_regions_game_gear[] = {
|
||||
{ 0x000000U, 0x001FFFU, 0x00C000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_game_gear = { _rc_memory_regions_game_gear, 1 };
|
||||
|
||||
/* ===== Intellivision ===== */
|
||||
/* http://wiki.intellivision.us/index.php%3Ftitle%3DMemory_Map */
|
||||
static const rc_memory_region_t _rc_memory_regions_intellivision[] = {
|
||||
{ 0x000000U, 0x00007FU, 0x000000U, RC_MEMORY_TYPE_VIDEO_RAM, "STIC Registers" },
|
||||
{ 0x000080U, 0x0000FFU, 0x000080U, RC_MEMORY_TYPE_UNUSED, "" },
|
||||
{ 0x000100U, 0x00035FU, 0x000100U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
|
||||
{ 0x000360U, 0x0003FFU, 0x000360U, RC_MEMORY_TYPE_UNUSED, "" },
|
||||
{ 0x000400U, 0x000FFFU, 0x000400U, RC_MEMORY_TYPE_SYSTEM_RAM, "Cartridge RAM" },
|
||||
{ 0x001000U, 0x001FFFU, 0x001000U, RC_MEMORY_TYPE_UNUSED, "" },
|
||||
{ 0x002000U, 0x002FFFU, 0x002000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Cartridge RAM" },
|
||||
{ 0x003000U, 0x003FFFU, 0x003000U, RC_MEMORY_TYPE_VIDEO_RAM, "Video RAM" },
|
||||
{ 0x004000U, 0x00FFFFU, 0x004000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Cartridge RAM" },
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_intellivision = { _rc_memory_regions_intellivision, 9 };
|
||||
|
||||
/* ===== Master System ===== */
|
||||
/* http://www.smspower.org/Development/MemoryMap */
|
||||
static const rc_memory_region_t _rc_memory_regions_master_system[] = {
|
||||
{ 0x000000U, 0x001FFFU, 0x00C000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_master_system = { _rc_memory_regions_master_system, 1 };
|
||||
|
||||
/* ===== MegaDrive (Genesis) ===== */
|
||||
/* http://www.smspower.org/Development/MemoryMap */
|
||||
static const rc_memory_region_t _rc_memory_regions_megadrive[] = {
|
||||
{ 0x000000U, 0x00FFFFU, 0xFF0000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
|
||||
{ 0x010000U, 0x01FFFFU, 0x000000U, RC_MEMORY_TYPE_SAVE_RAM, "Cartridge RAM" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_megadrive = { _rc_memory_regions_megadrive, 2 };
|
||||
|
||||
/* ===== Neo Geo Pocket ===== */
|
||||
/* http://neopocott.emuunlim.com/docs/tech-11.txt */
|
||||
static const rc_memory_region_t _rc_memory_regions_neo_geo_pocket[] = {
|
||||
/* MednafenNGP exposes 16KB, but the doc suggests there's 24-32KB */
|
||||
{ 0x000000U, 0x003FFFU, 0x000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_neo_geo_pocket = { _rc_memory_regions_neo_geo_pocket, 1 };
|
||||
|
||||
/* ===== Nintendo Entertainment System ===== */
|
||||
/* https://wiki.nesdev.com/w/index.php/CPU_memory_map */
|
||||
static const rc_memory_region_t _rc_memory_regions_nes[] = {
|
||||
{ 0x0000U, 0x07FFU, 0x0000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
|
||||
{ 0x0800U, 0x0FFFU, 0x0000U, RC_MEMORY_TYPE_VIRTUAL_RAM, "Mirror RAM" }, /* duplicates memory from $0000-$07FF */
|
||||
{ 0x1000U, 0x17FFU, 0x0000U, RC_MEMORY_TYPE_VIRTUAL_RAM, "Mirror RAM" }, /* duplicates memory from $0000-$07FF */
|
||||
{ 0x1800U, 0x1FFFU, 0x0000U, RC_MEMORY_TYPE_VIRTUAL_RAM, "Mirror RAM" }, /* duplicates memory from $0000-$07FF */
|
||||
{ 0x2000U, 0x2007U, 0x2000U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "PPU Register" },
|
||||
{ 0x2008U, 0x3FFFU, 0x2008U, RC_MEMORY_TYPE_VIRTUAL_RAM, "Mirrored PPU Register" }, /* repeats every 8 bytes */
|
||||
{ 0x4000U, 0x4017U, 0x4000U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "APU and I/O register" },
|
||||
{ 0x4018U, 0x401FU, 0x4018U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "APU and I/O test register" },
|
||||
{ 0x4020U, 0x5FFFU, 0x4020U, RC_MEMORY_TYPE_READONLY, "Cartridge data"}, /* varies by mapper */
|
||||
{ 0x6000U, 0x7FFFU, 0x6000U, RC_MEMORY_TYPE_SAVE_RAM, "Cartridge RAM"},
|
||||
{ 0x8000U, 0xFFFFU, 0x8000U, RC_MEMORY_TYPE_READONLY, "Cartridge ROM"},
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_nes = { _rc_memory_regions_nes, 11 };
|
||||
|
||||
/* ===== Nintendo 64 ===== */
|
||||
/* https://raw.githubusercontent.com/mikeryan/n64dev/master/docs/n64ops/n64ops%23h.txt */
|
||||
static const rc_memory_region_t _rc_memory_regions_n64[] = {
|
||||
{ 0x000000U, 0x1FFFFFU, 0x00000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* RDRAM 1 */
|
||||
{ 0x200000U, 0x3FFFFFU, 0x00020000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* RDRAM 2 */
|
||||
{ 0x400000U, 0x7FFFFFU, 0x80000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" } /* expansion pak - cannot find any details for real address */
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_n64 = { _rc_memory_regions_n64, 3 };
|
||||
|
||||
/* ===== Nintendo DS ===== */
|
||||
/* https://www.akkit.org/info/gbatek.htm#dsmemorymaps */
|
||||
static const rc_memory_region_t _rc_memory_regions_nintendo_ds[] = {
|
||||
{ 0x000000U, 0x3FFFFFU, 0x02000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_nintendo_ds = { _rc_memory_regions_nintendo_ds, 1 };
|
||||
|
||||
/* ===== Oric ===== */
|
||||
static const rc_memory_region_t _rc_memory_regions_oric[] = {
|
||||
/* actual size depends on machine type - up to 64KB */
|
||||
{ 0x000000U, 0x00FFFFU, 0x000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_oric = { _rc_memory_regions_oric, 1 };
|
||||
|
||||
/* ===== PC-8800 ===== */
|
||||
static const rc_memory_region_t _rc_memory_regions_pc8800[] = {
|
||||
{ 0x000000U, 0x00FFFFU, 0x000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Main RAM" },
|
||||
{ 0x010000U, 0x010FFFU, 0x010000U, RC_MEMORY_TYPE_VIDEO_RAM, "Text VRAM" } /* technically VRAM, but often used as system RAM */
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_pc8800 = { _rc_memory_regions_pc8800, 2 };
|
||||
|
||||
/* ===== PC Engine ===== */
|
||||
static const rc_memory_region_t _rc_memory_regions_pcengine[] = {
|
||||
{ 0x000000U, 0x001FFFU, 0x1F0000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
|
||||
{ 0x002000U, 0x011FFFU, 0x100000U, RC_MEMORY_TYPE_SYSTEM_RAM, "CD RAM" },
|
||||
{ 0x012000U, 0x041FFFU, 0x0D0000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Super System Card RAM" },
|
||||
{ 0x042000U, 0x0427FFU, 0x1EE000U, RC_MEMORY_TYPE_SAVE_RAM, "CD Battery-backed RAM" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_pcengine = { _rc_memory_regions_pcengine, 4 };
|
||||
|
||||
/* ===== PlayStation ===== */
|
||||
/* http://www.raphnet.net/electronique/psx_adaptor/Playstation.txt */
|
||||
static const rc_memory_region_t _rc_memory_regions_playstation[] = {
|
||||
{ 0x000000U, 0x00FFFFU, 0x000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Kernel RAM" },
|
||||
{ 0x010000U, 0x1FFFFFU, 0x010000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_playstation = { _rc_memory_regions_playstation, 2 };
|
||||
|
||||
/* ===== Pokemon Mini ===== */
|
||||
/* https://www.pokemon-mini.net/documentation/memory-map/ */
|
||||
static const rc_memory_region_t _rc_memory_regions_pokemini[] = {
|
||||
{ 0x000000U, 0x000FFFU, 0x000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "BIOS RAM" },
|
||||
{ 0x001000U, 0x001FFFU, 0x001000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_pokemini = { _rc_memory_regions_pokemini, 2 };
|
||||
|
||||
/* ===== Sega CD ===== */
|
||||
static const rc_memory_region_t _rc_memory_regions_segacd[] = {
|
||||
{ 0x000000U, 0x00FFFFU, 0x00FF0000U, RC_MEMORY_TYPE_SYSTEM_RAM, "68000 RAM" },
|
||||
{ 0x010000U, 0x08FFFFU, 0x80000000U, RC_MEMORY_TYPE_SAVE_RAM, "CD PRG RAM" } /* normally banked into $020000-$03FFFF */
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_segacd = { _rc_memory_regions_segacd, 2 };
|
||||
|
||||
/* ===== Sega Saturn ===== */
|
||||
/* https://segaretro.org/Sega_Saturn_hardware_notes_(2004-04-27) */
|
||||
static const rc_memory_region_t _rc_memory_regions_saturn[] = {
|
||||
{ 0x000000U, 0x0FFFFFU, 0x00200000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Work RAM Low" },
|
||||
{ 0x100000U, 0x1FFFFFU, 0x06000000U, RC_MEMORY_TYPE_SAVE_RAM, "Work RAM High" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_saturn = { _rc_memory_regions_saturn, 2 };
|
||||
|
||||
/* ===== SG-1000 ===== */
|
||||
/* http://www.smspower.org/Development/MemoryMap */
|
||||
static const rc_memory_region_t _rc_memory_regions_sg1000[] = {
|
||||
{ 0x000000U, 0x0003FFU, 0xC000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
|
||||
/* TODO: should cartridge memory be exposed ($0000-$BFFF)? it's usually just ROM data, but may contain on-cartridge RAM
|
||||
* This not is also concerning: http://www.smspower.org/Development/MemoryMap
|
||||
* Cartridges may disable the system RAM and thus take over the full 64KB address space. */
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_sg1000 = { _rc_memory_regions_sg1000, 1 };
|
||||
|
||||
/* ===== Super Cassette Vision ===== */
|
||||
static const rc_memory_region_t _rc_memory_regions_scv[] = {
|
||||
{ 0x000000U, 0x000FFFU, 0x000000U, RC_MEMORY_TYPE_READONLY, "System ROM" },
|
||||
{ 0x001000U, 0x001FFFU, 0x001000U, RC_MEMORY_TYPE_UNUSED, "" },
|
||||
{ 0x002000U, 0x003FFFU, 0x002000U, RC_MEMORY_TYPE_VIDEO_RAM, "Video RAM" },
|
||||
{ 0x004000U, 0x007FFFU, 0x004000U, RC_MEMORY_TYPE_UNUSED, "" },
|
||||
{ 0x008000U, 0x00DFFFU, 0x008000U, RC_MEMORY_TYPE_READONLY, "Cartridge ROM" },
|
||||
{ 0x00E000U, 0x00FF7FU, 0x00E000U, RC_MEMORY_TYPE_SAVE_RAM, "Cartridge RAM" },
|
||||
{ 0x00FF80U, 0x00FFFFU, 0x00FF80U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_scv = { _rc_memory_regions_scv, 7 };
|
||||
|
||||
/* ===== Super Nintendo ===== */
|
||||
/* https://segaretro.org/Sega_Saturn_hardware_notes_(2004-04-27) */
|
||||
static const rc_memory_region_t _rc_memory_regions_snes[] = {
|
||||
{ 0x000000U, 0x01FFFFU, 0x7E0000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
|
||||
{ 0x020000U, 0x03FFFFU, 0xFE0000U, RC_MEMORY_TYPE_SAVE_RAM, "Cartridge RAM" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_snes = { _rc_memory_regions_snes, 2 };
|
||||
|
||||
/* ===== WonderSwan ===== */
|
||||
/* http://daifukkat.su/docs/wsman/#ovr_memmap */
|
||||
static const rc_memory_region_t _rc_memory_regions_wonderswan[] = {
|
||||
/* RAM ends at 0x3FFF for WonderSwan, WonderSwan color uses all 64KB */
|
||||
{ 0x000000U, 0x00FFFFU, 0x000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_wonderswan = { _rc_memory_regions_wonderswan, 1 };
|
||||
|
||||
/* ===== Vectrex ===== */
|
||||
/* https://roadsidethoughts.com/vectrex/vectrex-memory-map.htm */
|
||||
static const rc_memory_region_t _rc_memory_regions_vectrex[] = {
|
||||
{ 0x000000U, 0x0003FFU, 0x00C800U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_vectrex = { _rc_memory_regions_vectrex, 1 };
|
||||
|
||||
/* ===== Virtual Boy ===== */
|
||||
static const rc_memory_region_t _rc_memory_regions_virtualboy[] = {
|
||||
{ 0x000000U, 0x00FFFFU, 0x05000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
|
||||
{ 0x010000U, 0x01FFFFU, 0x06000000U, RC_MEMORY_TYPE_SAVE_RAM, "Cartridge RAM" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_virtualboy = { _rc_memory_regions_virtualboy, 2 };
|
||||
|
||||
/* ===== default ===== */
|
||||
static const rc_memory_regions_t rc_memory_regions_none = { 0, 0 };
|
||||
|
||||
const rc_memory_regions_t* rc_console_memory_regions(int console_id)
|
||||
{
|
||||
switch (console_id)
|
||||
{
|
||||
case RC_CONSOLE_3DO:
|
||||
return &rc_memory_regions_3do;
|
||||
|
||||
case RC_CONSOLE_APPLE_II:
|
||||
return &rc_memory_regions_appleii;
|
||||
|
||||
case RC_CONSOLE_ATARI_2600:
|
||||
return &rc_memory_regions_atari2600;
|
||||
|
||||
case RC_CONSOLE_ATARI_7800:
|
||||
return &rc_memory_regions_atari7800;
|
||||
|
||||
case RC_CONSOLE_ATARI_JAGUAR:
|
||||
return &rc_memory_regions_atari_jaguar;
|
||||
|
||||
case RC_CONSOLE_ATARI_LYNX:
|
||||
return &rc_memory_regions_atari_lynx;
|
||||
|
||||
case RC_CONSOLE_COLECOVISION:
|
||||
return &rc_memory_regions_colecovision;
|
||||
|
||||
case RC_CONSOLE_GAMEBOY:
|
||||
return &rc_memory_regions_gameboy;
|
||||
|
||||
case RC_CONSOLE_GAMEBOY_COLOR:
|
||||
return &rc_memory_regions_gameboy_color;
|
||||
|
||||
case RC_CONSOLE_GAMEBOY_ADVANCE:
|
||||
return &rc_memory_regions_gameboy_advance;
|
||||
|
||||
case RC_CONSOLE_GAME_GEAR:
|
||||
return &rc_memory_regions_game_gear;
|
||||
|
||||
case RC_CONSOLE_INTELLIVISION:
|
||||
return &rc_memory_regions_intellivision;
|
||||
|
||||
case RC_CONSOLE_MASTER_SYSTEM:
|
||||
return &rc_memory_regions_master_system;
|
||||
|
||||
case RC_CONSOLE_MEGA_DRIVE:
|
||||
case RC_CONSOLE_SEGA_32X:
|
||||
/* NOTE: 32x adds an extra 512KB of memory (256KB RAM + 256KB VRAM) to the
|
||||
* Genesis, but we currently don't support it. */
|
||||
return &rc_memory_regions_megadrive;
|
||||
|
||||
case RC_CONSOLE_NEOGEO_POCKET:
|
||||
return &rc_memory_regions_neo_geo_pocket;
|
||||
|
||||
case RC_CONSOLE_NINTENDO:
|
||||
return &rc_memory_regions_nes;
|
||||
|
||||
case RC_CONSOLE_NINTENDO_64:
|
||||
return &rc_memory_regions_n64;
|
||||
|
||||
case RC_CONSOLE_NINTENDO_DS:
|
||||
return &rc_memory_regions_nintendo_ds;
|
||||
|
||||
case RC_CONSOLE_ORIC:
|
||||
return &rc_memory_regions_oric;
|
||||
|
||||
case RC_CONSOLE_PC8800:
|
||||
return &rc_memory_regions_pc8800;
|
||||
|
||||
case RC_CONSOLE_PC_ENGINE:
|
||||
return &rc_memory_regions_pcengine;
|
||||
|
||||
case RC_CONSOLE_PLAYSTATION:
|
||||
return &rc_memory_regions_playstation;
|
||||
|
||||
case RC_CONSOLE_POKEMON_MINI:
|
||||
return &rc_memory_regions_pokemini;
|
||||
|
||||
case RC_CONSOLE_SATURN:
|
||||
return &rc_memory_regions_saturn;
|
||||
|
||||
case RC_CONSOLE_SEGA_CD:
|
||||
return &rc_memory_regions_segacd;
|
||||
|
||||
case RC_CONSOLE_SG1000:
|
||||
return &rc_memory_regions_sg1000;
|
||||
|
||||
case RC_CONSOLE_SUPER_CASSETTEVISION:
|
||||
return &rc_memory_regions_scv;
|
||||
|
||||
case RC_CONSOLE_SUPER_NINTENDO:
|
||||
return &rc_memory_regions_snes;
|
||||
|
||||
case RC_CONSOLE_WONDERSWAN:
|
||||
return &rc_memory_regions_wonderswan;
|
||||
|
||||
case RC_CONSOLE_VECTREX:
|
||||
return &rc_memory_regions_vectrex;
|
||||
|
||||
case RC_CONSOLE_VIRTUAL_BOY:
|
||||
return &rc_memory_regions_virtualboy;
|
||||
|
||||
default:
|
||||
return &rc_memory_regions_none;
|
||||
}
|
||||
}
|
||||
-41
@@ -1,41 +0,0 @@
|
||||
#include "internal.h"
|
||||
|
||||
rc_expression_t* rc_parse_expression(const char** memaddr, rc_parse_state_t* parse) {
|
||||
rc_expression_t* self;
|
||||
rc_term_t** next;
|
||||
|
||||
self = RC_ALLOC(rc_expression_t, parse);
|
||||
next = &self->terms;
|
||||
|
||||
for (;;) {
|
||||
*next = rc_parse_term(memaddr, 0, parse);
|
||||
|
||||
if (parse->offset < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
next = &(*next)->next;
|
||||
|
||||
if (**memaddr != '_') {
|
||||
break;
|
||||
}
|
||||
|
||||
(*memaddr)++;
|
||||
}
|
||||
|
||||
*next = 0;
|
||||
return self;
|
||||
}
|
||||
|
||||
int rc_evaluate_expression(rc_expression_t* self, rc_eval_state_t* eval_state) {
|
||||
rc_term_t* term;
|
||||
int value;
|
||||
|
||||
value = 0;
|
||||
|
||||
for (term = self->terms; term != 0; term = term->next) {
|
||||
value += rc_evaluate_term(term, eval_state);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
Vendored
+5
-3
@@ -1,5 +1,7 @@
|
||||
#include "internal.h"
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -11,7 +13,7 @@ int rc_parse_format(const char* format_str) {
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case 'T':
|
||||
if (!strcmp(format_str, "IME")) {
|
||||
return RC_FORMAT_FRAMES;
|
||||
@@ -21,7 +23,7 @@ int rc_parse_format(const char* format_str) {
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case 'S':
|
||||
if (!strcmp(format_str, "ECS")) {
|
||||
return RC_FORMAT_SECONDS;
|
||||
@@ -34,7 +36,7 @@ int rc_parse_format(const char* format_str) {
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case 'M':
|
||||
if (!strcmp(format_str, "ILLISECS")) {
|
||||
return RC_FORMAT_CENTISECS;
|
||||
|
||||
+4
-11
@@ -6,7 +6,6 @@
|
||||
#define RC_ALLOW_ALIGN(T) struct __align_ ## T { char ch; T t; };
|
||||
RC_ALLOW_ALIGN(rc_condition_t)
|
||||
RC_ALLOW_ALIGN(rc_condset_t)
|
||||
RC_ALLOW_ALIGN(rc_expression_t)
|
||||
RC_ALLOW_ALIGN(rc_lboard_t)
|
||||
RC_ALLOW_ALIGN(rc_memref_value_t)
|
||||
RC_ALLOW_ALIGN(rc_operand_t)
|
||||
@@ -15,7 +14,6 @@ RC_ALLOW_ALIGN(rc_richpresence_display_t)
|
||||
RC_ALLOW_ALIGN(rc_richpresence_display_part_t)
|
||||
RC_ALLOW_ALIGN(rc_richpresence_lookup_t)
|
||||
RC_ALLOW_ALIGN(rc_richpresence_lookup_item_t)
|
||||
RC_ALLOW_ALIGN(rc_term_t)
|
||||
RC_ALLOW_ALIGN(rc_trigger_t)
|
||||
RC_ALLOW_ALIGN(rc_value_t)
|
||||
RC_ALLOW_ALIGN(char)
|
||||
@@ -36,8 +34,6 @@ typedef struct {
|
||||
rc_condition_t condition;
|
||||
rc_condset_t condset;
|
||||
rc_trigger_t trigger;
|
||||
rc_term_t term;
|
||||
rc_expression_t expression;
|
||||
rc_lboard_t lboard;
|
||||
rc_memref_value_t memref_value;
|
||||
rc_richpresence_t richpresence;
|
||||
@@ -61,6 +57,8 @@ typedef struct {
|
||||
unsigned measured_value; /* Measured */
|
||||
char was_reset; /* ResetIf triggered */
|
||||
char has_hits; /* one of more hit counts is non-zero */
|
||||
char primed; /* true if all non-Trigger conditions are true */
|
||||
char measured_from_hits; /* true if the measured_value came from a condition's hit count */
|
||||
}
|
||||
rc_eval_state_t;
|
||||
|
||||
@@ -86,7 +84,7 @@ void rc_destroy_parse_state(rc_parse_state_t* parse);
|
||||
void* rc_alloc(void* pointer, int* offset, int size, int alignment, rc_scratch_t* scratch);
|
||||
char* rc_alloc_str(rc_parse_state_t* parse, const char* text, int length);
|
||||
|
||||
rc_memref_value_t* rc_alloc_memref_value(rc_parse_state_t* parse, unsigned address, char size, char is_bcd, char is_indirect);
|
||||
rc_memref_value_t* rc_alloc_memref_value(rc_parse_state_t* parse, unsigned address, char size, char is_indirect);
|
||||
void rc_update_memref_values(rc_memref_value_t* memref, rc_peek_t peek, void* ud);
|
||||
void rc_update_memref_value(rc_memref_value_t* memref, rc_peek_t peek, void* ud);
|
||||
rc_memref_value_t* rc_get_indirect_memref(rc_memref_value_t* memref, rc_eval_state_t* eval_state);
|
||||
@@ -99,16 +97,11 @@ void rc_reset_condset(rc_condset_t* self);
|
||||
|
||||
rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse, int is_indirect);
|
||||
int rc_test_condition(rc_condition_t* self, rc_eval_state_t* eval_state);
|
||||
int rc_evaluate_condition_value(rc_condition_t* self, rc_eval_state_t* eval_state);
|
||||
|
||||
int rc_parse_operand(rc_operand_t* self, const char** memaddr, int is_trigger, int is_indirect, rc_parse_state_t* parse);
|
||||
unsigned rc_evaluate_operand(rc_operand_t* self, rc_eval_state_t* eval_state);
|
||||
|
||||
rc_term_t* rc_parse_term(const char** memaddr, int is_indirect, rc_parse_state_t* parse);
|
||||
int rc_evaluate_term(rc_term_t* self, rc_eval_state_t* eval_state);
|
||||
|
||||
rc_expression_t* rc_parse_expression(const char** memaddr, rc_parse_state_t* parse);
|
||||
int rc_evaluate_expression(rc_expression_t* self, rc_eval_state_t* eval_state);
|
||||
|
||||
void rc_parse_value_internal(rc_value_t* self, const char** memaddr, rc_parse_state_t* parse);
|
||||
|
||||
void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_state_t* parse);
|
||||
|
||||
Vendored
+61
-54
@@ -133,7 +133,7 @@ void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_s
|
||||
return;
|
||||
}
|
||||
|
||||
self->started = self->submitted = 0;
|
||||
self->state = RC_LBOARD_STATE_WAITING;
|
||||
}
|
||||
|
||||
int rc_lboard_size(const char* memaddr) {
|
||||
@@ -164,82 +164,89 @@ rc_lboard_t* rc_parse_lboard(void* buffer, const char* memaddr, lua_State* L, in
|
||||
|
||||
int rc_evaluate_lboard(rc_lboard_t* self, int* value, rc_peek_t peek, void* peek_ud, lua_State* L) {
|
||||
int start_ok, cancel_ok, submit_ok;
|
||||
int action = -1;
|
||||
|
||||
rc_update_memref_values(self->memrefs, peek, peek_ud);
|
||||
|
||||
/* ASSERT: these are always tested once every frame, to ensure delta variables work properly */
|
||||
if (self->state == RC_LBOARD_STATE_INACTIVE)
|
||||
return RC_LBOARD_STATE_INACTIVE;
|
||||
|
||||
/* these are always tested once every frame, to ensure hit counts work properly */
|
||||
start_ok = rc_test_trigger(&self->start, peek, peek_ud, L);
|
||||
cancel_ok = rc_test_trigger(&self->cancel, peek, peek_ud, L);
|
||||
submit_ok = rc_test_trigger(&self->submit, peek, peek_ud, L);
|
||||
|
||||
if (self->submitted) {
|
||||
/* if we've already submitted or canceled the leaderboard, don't reactivate it until it becomes inactive. */
|
||||
if (!start_ok) {
|
||||
self->submitted = 0;
|
||||
}
|
||||
}
|
||||
else if (!self->started) {
|
||||
/* leaderboard is not active, if the start condition is true, activate it */
|
||||
if (start_ok && !cancel_ok) {
|
||||
if (submit_ok) {
|
||||
/* start and submit both true in the same frame, just submit without announcing the leaderboard is available */
|
||||
action = RC_LBOARD_TRIGGERED;
|
||||
/* prevent multiple submissions/notifications */
|
||||
self->submitted = 1;
|
||||
switch (self->state)
|
||||
{
|
||||
case RC_LBOARD_STATE_WAITING:
|
||||
case RC_LBOARD_STATE_TRIGGERED:
|
||||
case RC_LBOARD_STATE_CANCELED:
|
||||
/* don't activate/reactivate until the start condition becomes false */
|
||||
if (start_ok) {
|
||||
*value = 0;
|
||||
return RC_LBOARD_STATE_INACTIVE; /* just return inactive for all of these */
|
||||
}
|
||||
else if (self->start.requirement != 0 || self->start.alternative != 0) {
|
||||
self->started = 1;
|
||||
action = RC_LBOARD_STARTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* leaderboard is active */
|
||||
if (cancel_ok) {
|
||||
/* cancel condition is true, deactivate the leaderboard */
|
||||
self->started = 0;
|
||||
action = RC_LBOARD_CANCELED;
|
||||
/* prevent multiple cancel notifications */
|
||||
self->submitted = 1;
|
||||
}
|
||||
else if (submit_ok) {
|
||||
/* submit condition is true, submit the current value */
|
||||
self->started = 0;
|
||||
action = RC_LBOARD_TRIGGERED;
|
||||
self->submitted = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (action == -1) {
|
||||
action = self->started ? RC_LBOARD_ACTIVE : RC_LBOARD_INACTIVE;
|
||||
/* start condition is false, allow the leaderboard to start on future frames */
|
||||
self->state = RC_LBOARD_STATE_ACTIVE;
|
||||
break;
|
||||
|
||||
case RC_LBOARD_STATE_ACTIVE:
|
||||
/* leaderboard attempt is not in progress. if the start condition is true and the cancel condition is not, start the attempt */
|
||||
if (start_ok && !cancel_ok) {
|
||||
if (submit_ok) {
|
||||
/* start and submit are both true in the same frame, just submit without announcing the leaderboard is available */
|
||||
self->state = RC_LBOARD_STATE_TRIGGERED;
|
||||
}
|
||||
else if (self->start.requirement == 0 && self->start.alternative == 0) {
|
||||
/* start condition is empty - this leaderboard is submit-only with no measured progress */
|
||||
}
|
||||
else {
|
||||
/* start the leaderboard attempt */
|
||||
self->state = RC_LBOARD_STATE_STARTED;
|
||||
|
||||
/* reset any hit counts in the value */
|
||||
if (self->value.conditions)
|
||||
rc_reset_condset(self->value.conditions);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RC_LBOARD_STATE_STARTED:
|
||||
/* leaderboard attempt in progress */
|
||||
if (cancel_ok) {
|
||||
/* cancel condition is true, abort the attempt */
|
||||
self->state = RC_LBOARD_STATE_CANCELED;
|
||||
}
|
||||
else if (submit_ok) {
|
||||
/* submit condition is true, submit the current value */
|
||||
self->state = RC_LBOARD_STATE_TRIGGERED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Calculate the value */
|
||||
switch (action) {
|
||||
case RC_LBOARD_STARTED:
|
||||
if (self->value.conditions)
|
||||
rc_reset_condset(self->value.conditions);
|
||||
/* fall through */
|
||||
case RC_LBOARD_ACTIVE:
|
||||
*value = rc_evaluate_value(self->progress != 0 ? self->progress : &self->value, peek, peek_ud, L);
|
||||
break;
|
||||
switch (self->state) {
|
||||
case RC_LBOARD_STATE_STARTED:
|
||||
if (self->progress) {
|
||||
*value = rc_evaluate_value(self->progress, peek, peek_ud, L);
|
||||
break;
|
||||
}
|
||||
/* fallthrough to RC_LBOARD_STATE_TRIGGERED */
|
||||
|
||||
case RC_LBOARD_TRIGGERED:
|
||||
case RC_LBOARD_STATE_TRIGGERED:
|
||||
*value = rc_evaluate_value(&self->value, peek, peek_ud, L);
|
||||
break;
|
||||
|
||||
case RC_LBOARD_INACTIVE:
|
||||
case RC_LBOARD_CANCELED:
|
||||
default:
|
||||
*value = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return action;
|
||||
return self->state;
|
||||
}
|
||||
|
||||
void rc_reset_lboard(rc_lboard_t* self) {
|
||||
self->started = self->submitted = 0;
|
||||
self->state = RC_LBOARD_STATE_WAITING;
|
||||
|
||||
rc_reset_trigger(&self->start);
|
||||
rc_reset_trigger(&self->submit);
|
||||
|
||||
Vendored
+12
-49
@@ -5,7 +5,7 @@
|
||||
|
||||
#define MEMREF_PLACEHOLDER_ADDRESS 0xFFFFFFFF
|
||||
|
||||
static rc_memref_value_t* rc_alloc_memref_value_sizing_mode(rc_parse_state_t* parse, unsigned address, char size, char is_bcd, char is_indirect) {
|
||||
static rc_memref_value_t* rc_alloc_memref_value_sizing_mode(rc_parse_state_t* parse, unsigned address, char size, char is_indirect) {
|
||||
rc_memref_t* memref;
|
||||
int i;
|
||||
|
||||
@@ -20,7 +20,7 @@ static rc_memref_value_t* rc_alloc_memref_value_sizing_mode(rc_parse_state_t* pa
|
||||
/* have to track unique address/size/bcd combinations - use scratch.memref for sizing mode */
|
||||
for (i = 0; i < parse->scratch.memref_count; ++i) {
|
||||
memref = &parse->scratch.memref[i];
|
||||
if (memref->address == address && memref->size == size && memref->is_bcd == is_bcd) {
|
||||
if (memref->address == address && memref->size == size) {
|
||||
return &parse->scratch.obj.memref_value;
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,6 @@ static rc_memref_value_t* rc_alloc_memref_value_sizing_mode(rc_parse_state_t* pa
|
||||
memref = &parse->scratch.memref[parse->scratch.memref_count++];
|
||||
memref->address = address;
|
||||
memref->size = size;
|
||||
memref->is_bcd = is_bcd;
|
||||
memref->is_indirect = is_indirect;
|
||||
}
|
||||
|
||||
@@ -65,7 +64,7 @@ static rc_memref_value_t* rc_alloc_memref_value_sizing_mode(rc_parse_state_t* pa
|
||||
return RC_ALLOC(rc_memref_value_t, parse);
|
||||
}
|
||||
|
||||
static rc_memref_value_t* rc_alloc_memref_value_constuct_mode(rc_parse_state_t* parse, unsigned address, char size, char is_bcd, char is_indirect) {
|
||||
static rc_memref_value_t* rc_alloc_memref_value_constuct_mode(rc_parse_state_t* parse, unsigned address, char size, char is_indirect) {
|
||||
rc_memref_value_t** next_memref_value;
|
||||
rc_memref_value_t* memref_value;
|
||||
rc_memref_value_t* indirect_memref_value;
|
||||
@@ -75,8 +74,8 @@ static rc_memref_value_t* rc_alloc_memref_value_constuct_mode(rc_parse_state_t*
|
||||
next_memref_value = parse->first_memref;
|
||||
while (*next_memref_value) {
|
||||
memref_value = *next_memref_value;
|
||||
if (!memref_value->memref.is_indirect && memref_value->memref.address == address &&
|
||||
memref_value->memref.size == size && memref_value->memref.is_bcd == is_bcd) {
|
||||
if (!memref_value->memref.is_indirect && memref_value->memref.address == address &&
|
||||
memref_value->memref.size == size) {
|
||||
return memref_value;
|
||||
}
|
||||
|
||||
@@ -96,7 +95,6 @@ static rc_memref_value_t* rc_alloc_memref_value_constuct_mode(rc_parse_state_t*
|
||||
memref_value = RC_ALLOC(rc_memref_value_t, parse);
|
||||
memref_value->memref.address = address;
|
||||
memref_value->memref.size = size;
|
||||
memref_value->memref.is_bcd = is_bcd;
|
||||
memref_value->memref.is_indirect = is_indirect;
|
||||
memref_value->value = 0;
|
||||
memref_value->previous = 0;
|
||||
@@ -110,7 +108,6 @@ static rc_memref_value_t* rc_alloc_memref_value_constuct_mode(rc_parse_state_t*
|
||||
indirect_memref_value = RC_ALLOC(rc_memref_value_t, parse);
|
||||
indirect_memref_value->memref.address = MEMREF_PLACEHOLDER_ADDRESS;
|
||||
indirect_memref_value->memref.size = size;
|
||||
indirect_memref_value->memref.is_bcd = is_bcd;
|
||||
indirect_memref_value->memref.is_indirect = 1;
|
||||
indirect_memref_value->value = 0;
|
||||
indirect_memref_value->previous = 0;
|
||||
@@ -123,16 +120,19 @@ static rc_memref_value_t* rc_alloc_memref_value_constuct_mode(rc_parse_state_t*
|
||||
return memref_value;
|
||||
}
|
||||
|
||||
rc_memref_value_t* rc_alloc_memref_value(rc_parse_state_t* parse, unsigned address, char size, char is_bcd, char is_indirect) {
|
||||
rc_memref_value_t* rc_alloc_memref_value(rc_parse_state_t* parse, unsigned address, char size, char is_indirect) {
|
||||
if (!parse->first_memref)
|
||||
return rc_alloc_memref_value_sizing_mode(parse, address, size, is_bcd, is_indirect);
|
||||
return rc_alloc_memref_value_sizing_mode(parse, address, size, is_indirect);
|
||||
|
||||
return rc_alloc_memref_value_constuct_mode(parse, address, size, is_bcd, is_indirect);
|
||||
return rc_alloc_memref_value_constuct_mode(parse, address, size, is_indirect);
|
||||
}
|
||||
|
||||
static unsigned rc_memref_get_value(rc_memref_t* self, rc_peek_t peek, void* ud) {
|
||||
unsigned value;
|
||||
|
||||
if (!peek)
|
||||
return 0;
|
||||
|
||||
switch (self->size)
|
||||
{
|
||||
case RC_MEMSIZE_BIT_0:
|
||||
@@ -177,56 +177,19 @@ static unsigned rc_memref_get_value(rc_memref_t* self, rc_peek_t peek, void* ud)
|
||||
|
||||
case RC_MEMSIZE_8_BITS:
|
||||
value = peek(self->address, 1, ud);
|
||||
|
||||
if (self->is_bcd) {
|
||||
value = ((value >> 4) & 0x0f) * 10 + (value & 0x0f);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_16_BITS:
|
||||
value = peek(self->address, 2, ud);
|
||||
|
||||
if (self->is_bcd) {
|
||||
value = ((value >> 12) & 0x0f) * 1000
|
||||
+ ((value >> 8) & 0x0f) * 100
|
||||
+ ((value >> 4) & 0x0f) * 10
|
||||
+ ((value >> 0) & 0x0f) * 1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_24_BITS:
|
||||
/* peek 4 bytes - don't expect the caller to understand 24-bit numbers */
|
||||
value = peek(self->address, 4, ud);
|
||||
|
||||
if (self->is_bcd) {
|
||||
value = ((value >> 20) & 0x0f) * 100000
|
||||
+ ((value >> 16) & 0x0f) * 10000
|
||||
+ ((value >> 12) & 0x0f) * 1000
|
||||
+ ((value >> 8) & 0x0f) * 100
|
||||
+ ((value >> 4) & 0x0f) * 10
|
||||
+ ((value >> 0) & 0x0f) * 1;
|
||||
} else {
|
||||
value &= 0x00FFFFFF;
|
||||
}
|
||||
|
||||
value = peek(self->address, 4, ud) & 0x00FFFFFF;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_32_BITS:
|
||||
value = peek(self->address, 4, ud);
|
||||
|
||||
if (self->is_bcd) {
|
||||
value = ((value >> 28) & 0x0f) * 10000000
|
||||
+ ((value >> 24) & 0x0f) * 1000000
|
||||
+ ((value >> 20) & 0x0f) * 100000
|
||||
+ ((value >> 16) & 0x0f) * 10000
|
||||
+ ((value >> 12) & 0x0f) * 1000
|
||||
+ ((value >> 8) & 0x0f) * 100
|
||||
+ ((value >> 4) & 0x0f) * 10
|
||||
+ ((value >> 0) & 0x0f) * 1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
Vendored
+243
-147
@@ -70,7 +70,6 @@ static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_
|
||||
const char* aux = *memaddr;
|
||||
char* end;
|
||||
unsigned long address;
|
||||
char is_bcd = 0;
|
||||
char size;
|
||||
|
||||
switch (*aux++) {
|
||||
@@ -78,15 +77,18 @@ static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_
|
||||
self->type = RC_OPERAND_DELTA;
|
||||
break;
|
||||
|
||||
case 'b': case 'B':
|
||||
self->type = RC_OPERAND_ADDRESS;
|
||||
is_bcd = 1;
|
||||
break;
|
||||
|
||||
case 'p': case 'P':
|
||||
self->type = RC_OPERAND_PRIOR;
|
||||
break;
|
||||
|
||||
case 'b': case 'B':
|
||||
self->type = RC_OPERAND_BCD;
|
||||
break;
|
||||
|
||||
case '~':
|
||||
self->type = RC_OPERAND_INVERTED;
|
||||
break;
|
||||
|
||||
default:
|
||||
self->type = RC_OPERAND_ADDRESS;
|
||||
aux--;
|
||||
@@ -104,25 +106,33 @@ static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_
|
||||
aux++;
|
||||
|
||||
switch (*aux++) {
|
||||
case 'm': case 'M': size = RC_MEMSIZE_BIT_0; break;
|
||||
case 'n': case 'N': size = RC_MEMSIZE_BIT_1; break;
|
||||
case 'o': case 'O': size = RC_MEMSIZE_BIT_2; break;
|
||||
case 'p': case 'P': size = RC_MEMSIZE_BIT_3; break;
|
||||
case 'q': case 'Q': size = RC_MEMSIZE_BIT_4; break;
|
||||
case 'r': case 'R': size = RC_MEMSIZE_BIT_5; break;
|
||||
case 's': case 'S': size = RC_MEMSIZE_BIT_6; break;
|
||||
case 't': case 'T': size = RC_MEMSIZE_BIT_7; break;
|
||||
case 'l': case 'L': size = RC_MEMSIZE_LOW; break;
|
||||
case 'u': case 'U': size = RC_MEMSIZE_HIGH; break;
|
||||
case 'h': case 'H': size = RC_MEMSIZE_8_BITS; break;
|
||||
case 'w': case 'W': size = RC_MEMSIZE_24_BITS; break;
|
||||
case 'x': case 'X': size = RC_MEMSIZE_32_BITS; break;
|
||||
case 'm': case 'M': self->size = RC_MEMSIZE_BIT_0; size = RC_MEMSIZE_8_BITS; break;
|
||||
case 'n': case 'N': self->size = RC_MEMSIZE_BIT_1; size = RC_MEMSIZE_8_BITS; break;
|
||||
case 'o': case 'O': self->size = RC_MEMSIZE_BIT_2; size = RC_MEMSIZE_8_BITS; break;
|
||||
case 'p': case 'P': self->size = RC_MEMSIZE_BIT_3; size = RC_MEMSIZE_8_BITS; break;
|
||||
case 'q': case 'Q': self->size = RC_MEMSIZE_BIT_4; size = RC_MEMSIZE_8_BITS; break;
|
||||
case 'r': case 'R': self->size = RC_MEMSIZE_BIT_5; size = RC_MEMSIZE_8_BITS; break;
|
||||
case 's': case 'S': self->size = RC_MEMSIZE_BIT_6; size = RC_MEMSIZE_8_BITS; break;
|
||||
case 't': case 'T': self->size = RC_MEMSIZE_BIT_7; size = RC_MEMSIZE_8_BITS; break;
|
||||
case 'l': case 'L': self->size = RC_MEMSIZE_LOW; size = RC_MEMSIZE_8_BITS; break;
|
||||
case 'u': case 'U': self->size = RC_MEMSIZE_HIGH; size = RC_MEMSIZE_8_BITS; break;
|
||||
case 'k': case 'K': self->size = RC_MEMSIZE_BITCOUNT; size = RC_MEMSIZE_8_BITS; break;
|
||||
case 'h': case 'H': self->size = size = RC_MEMSIZE_8_BITS; break;
|
||||
case 'w': case 'W': self->size = size = RC_MEMSIZE_24_BITS; break;
|
||||
case 'x': case 'X': self->size = size = RC_MEMSIZE_32_BITS; break;
|
||||
|
||||
default: /* fall through */
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
|
||||
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
|
||||
aux--;
|
||||
/* fallthrough */
|
||||
case ' ':
|
||||
size = RC_MEMSIZE_16_BITS;
|
||||
self->size = size = RC_MEMSIZE_16_BITS;
|
||||
break;
|
||||
|
||||
default:
|
||||
return RC_INVALID_MEMORY_OPERAND;
|
||||
}
|
||||
|
||||
address = strtoul(aux, &end, 16);
|
||||
@@ -135,7 +145,7 @@ static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_
|
||||
address = 0xffffffffU;
|
||||
}
|
||||
|
||||
self->value.memref = rc_alloc_memref_value(parse, address, size, is_bcd, is_indirect);
|
||||
self->value.memref = rc_alloc_memref_value(parse, address, size, is_indirect);
|
||||
if (parse->offset < 0)
|
||||
return parse->offset;
|
||||
|
||||
@@ -143,14 +153,17 @@ static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
static int rc_parse_operand_trigger(rc_operand_t* self, const char** memaddr, int is_indirect, rc_parse_state_t* parse) {
|
||||
int rc_parse_operand(rc_operand_t* self, const char** memaddr, int is_trigger, int is_indirect, rc_parse_state_t* parse) {
|
||||
const char* aux = *memaddr;
|
||||
char* end;
|
||||
int ret;
|
||||
unsigned long value;
|
||||
int negative;
|
||||
|
||||
self->size = RC_MEMSIZE_32_BITS;
|
||||
|
||||
switch (*aux) {
|
||||
case 'h': case 'H':
|
||||
case 'h': case 'H': /* hex constant */
|
||||
if (aux[2] == 'x' || aux[2] == 'X') {
|
||||
/* H0x1234 is a typo - either H1234 or 0xH1234 was probably meant */
|
||||
return RC_INVALID_CONST_OPERAND;
|
||||
@@ -171,115 +184,9 @@ static int rc_parse_operand_trigger(rc_operand_t* self, const char** memaddr, in
|
||||
|
||||
aux = end;
|
||||
break;
|
||||
|
||||
case '0':
|
||||
if (aux[1] == 'x' || aux[1] == 'X') {
|
||||
/* fall through */
|
||||
default:
|
||||
ret = rc_parse_operand_memory(self, &aux, parse, is_indirect);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* fall through */
|
||||
case '+': case '-':
|
||||
case '1': case '2': case '3': case '4': case '5':
|
||||
case '6': case '7': case '8': case '9':
|
||||
value = strtoul(aux, &end, 10);
|
||||
|
||||
if (end == aux) {
|
||||
return RC_INVALID_CONST_OPERAND;
|
||||
}
|
||||
|
||||
if (value > 0xffffffffU) {
|
||||
value = 0xffffffffU;
|
||||
}
|
||||
|
||||
self->type = RC_OPERAND_CONST;
|
||||
self->value.num = (unsigned)value;
|
||||
|
||||
aux = end;
|
||||
break;
|
||||
|
||||
case '@':
|
||||
ret = rc_parse_operand_lua(self, &aux, parse);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
*memaddr = aux;
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
static int rc_parse_operand_term(rc_operand_t* self, const char** memaddr, int is_indirect, rc_parse_state_t* parse) {
|
||||
const char* aux = *memaddr;
|
||||
char* end;
|
||||
int ret;
|
||||
unsigned long value;
|
||||
long svalue;
|
||||
|
||||
switch (*aux) {
|
||||
case 'h': case 'H':
|
||||
value = strtoul(++aux, &end, 16);
|
||||
|
||||
if (end == aux) {
|
||||
return RC_INVALID_CONST_OPERAND;
|
||||
}
|
||||
|
||||
if (value > 0xffffffffU) {
|
||||
value = 0xffffffffU;
|
||||
}
|
||||
|
||||
self->type = RC_OPERAND_CONST;
|
||||
self->value.num = (unsigned)value;
|
||||
|
||||
aux = end;
|
||||
break;
|
||||
|
||||
case 'v': case 'V':
|
||||
svalue = strtol(++aux, &end, 10);
|
||||
|
||||
if (end == aux) {
|
||||
return RC_INVALID_CONST_OPERAND;
|
||||
}
|
||||
|
||||
if (svalue > 0xffffffffU) {
|
||||
svalue = 0xffffffffU;
|
||||
}
|
||||
|
||||
self->type = RC_OPERAND_CONST;
|
||||
self->value.num = (unsigned)svalue;
|
||||
|
||||
aux = end;
|
||||
break;
|
||||
|
||||
case '0':
|
||||
if (aux[1] == 'x' || aux[1] == 'X') {
|
||||
/* fall through */
|
||||
default:
|
||||
ret = rc_parse_operand_memory(self, &aux, parse, is_indirect);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* fall through */
|
||||
case '.':
|
||||
case '+': case '-':
|
||||
case '1': case '2': case '3': case '4': case '5':
|
||||
case '6': case '7': case '8': case '9':
|
||||
self->value.dbl = strtod(aux, &end);
|
||||
case 'f': case 'F': /* floating point constant */
|
||||
self->value.dbl = strtod(++aux, &end);
|
||||
|
||||
if (end == aux) {
|
||||
return RC_INVALID_FP_OPERAND;
|
||||
@@ -292,9 +199,77 @@ static int rc_parse_operand_term(rc_operand_t* self, const char** memaddr, int i
|
||||
else {
|
||||
self->type = RC_OPERAND_FP;
|
||||
}
|
||||
|
||||
aux = end;
|
||||
break;
|
||||
|
||||
|
||||
case 'v': case 'V': /* signed integer constant */
|
||||
negative = 0;
|
||||
++aux;
|
||||
|
||||
if (*aux == '-')
|
||||
{
|
||||
negative = 1;
|
||||
++aux;
|
||||
}
|
||||
else if (*aux == '+')
|
||||
{
|
||||
++aux;
|
||||
}
|
||||
|
||||
value = strtoul(aux, &end, 10);
|
||||
|
||||
if (end == aux) {
|
||||
return RC_INVALID_CONST_OPERAND;
|
||||
}
|
||||
|
||||
if (value > 0x7fffffffU) {
|
||||
value = 0x7fffffffU;
|
||||
}
|
||||
|
||||
self->type = RC_OPERAND_CONST;
|
||||
|
||||
if (negative)
|
||||
self->value.num = (unsigned)(-((long)value));
|
||||
else
|
||||
self->value.num = (unsigned)value;
|
||||
|
||||
aux = end;
|
||||
break;
|
||||
|
||||
case '0':
|
||||
if (aux[1] == 'x' || aux[1] == 'X') {
|
||||
/* fall through */
|
||||
default:
|
||||
ret = rc_parse_operand_memory(self, &aux, parse, is_indirect);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* fall through for case '0' where not '0x' */
|
||||
case '+': case '-':
|
||||
case '1': case '2': case '3': case '4': case '5':
|
||||
case '6': case '7': case '8': case '9':
|
||||
value = strtoul(aux, &end, 10);
|
||||
|
||||
if (end == aux) {
|
||||
return RC_INVALID_CONST_OPERAND;
|
||||
}
|
||||
|
||||
if (value > 0xffffffffU) {
|
||||
value = 0xffffffffU;
|
||||
}
|
||||
|
||||
self->type = RC_OPERAND_CONST;
|
||||
self->value.num = (unsigned)value;
|
||||
|
||||
aux = end;
|
||||
break;
|
||||
|
||||
case '@':
|
||||
ret = rc_parse_operand_lua(self, &aux, parse);
|
||||
|
||||
@@ -309,15 +284,6 @@ static int rc_parse_operand_term(rc_operand_t* self, const char** memaddr, int i
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
int rc_parse_operand(rc_operand_t* self, const char** memaddr, int is_trigger, int is_indirect, rc_parse_state_t* parse) {
|
||||
if (is_trigger) {
|
||||
return rc_parse_operand_trigger(self, memaddr, is_indirect, parse);
|
||||
}
|
||||
else {
|
||||
return rc_parse_operand_term(self, memaddr, is_indirect, parse);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef RC_DISABLE_LUA
|
||||
|
||||
typedef struct {
|
||||
@@ -339,6 +305,8 @@ static int rc_luapeek(lua_State* L) {
|
||||
|
||||
#endif /* RC_DISABLE_LUA */
|
||||
|
||||
static const unsigned char rc_bits_set[16] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
|
||||
|
||||
unsigned rc_evaluate_operand(rc_operand_t* self, rc_eval_state_t* eval_state) {
|
||||
#ifndef RC_DISABLE_LUA
|
||||
rc_luapeek_t luapeek;
|
||||
@@ -346,15 +314,15 @@ unsigned rc_evaluate_operand(rc_operand_t* self, rc_eval_state_t* eval_state) {
|
||||
|
||||
unsigned value = 0;
|
||||
|
||||
/* step 1: read memory */
|
||||
switch (self->type) {
|
||||
case RC_OPERAND_CONST:
|
||||
value = self->value.num;
|
||||
break;
|
||||
return self->value.num;
|
||||
|
||||
case RC_OPERAND_FP:
|
||||
/* This is handled by rc_evaluate_expression. */
|
||||
/* This is handled by rc_evaluate_condition_value. */
|
||||
return 0;
|
||||
|
||||
|
||||
case RC_OPERAND_LUA:
|
||||
#ifndef RC_DISABLE_LUA
|
||||
|
||||
@@ -366,7 +334,7 @@ unsigned rc_evaluate_operand(rc_operand_t* self, rc_eval_state_t* eval_state) {
|
||||
luapeek.ud = eval_state->peek_userdata;
|
||||
|
||||
lua_pushlightuserdata(eval_state->L, &luapeek);
|
||||
|
||||
|
||||
if (lua_pcall(eval_state->L, 2, 1, 0) == LUA_OK) {
|
||||
if (lua_isboolean(eval_state->L, -1)) {
|
||||
value = lua_toboolean(eval_state->L, -1);
|
||||
@@ -384,6 +352,8 @@ unsigned rc_evaluate_operand(rc_operand_t* self, rc_eval_state_t* eval_state) {
|
||||
break;
|
||||
|
||||
case RC_OPERAND_ADDRESS:
|
||||
case RC_OPERAND_BCD:
|
||||
case RC_OPERAND_INVERTED:
|
||||
value = rc_get_indirect_memref(self->value.memref, eval_state)->value;
|
||||
break;
|
||||
|
||||
@@ -396,5 +366,131 @@ unsigned rc_evaluate_operand(rc_operand_t* self, rc_eval_state_t* eval_state) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* step 2: mask off appropriate bits */
|
||||
switch (self->size)
|
||||
{
|
||||
case RC_MEMSIZE_BIT_0:
|
||||
value = (value >> 0) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_1:
|
||||
value = (value >> 1) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_2:
|
||||
value = (value >> 2) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_3:
|
||||
value = (value >> 3) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_4:
|
||||
value = (value >> 4) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_5:
|
||||
value = (value >> 5) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_6:
|
||||
value = (value >> 6) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_7:
|
||||
value = (value >> 7) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_LOW:
|
||||
value = value & 0x0f;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_HIGH:
|
||||
value = (value >> 4) & 0x0f;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BITCOUNT:
|
||||
value = rc_bits_set[(value & 0x0F)]
|
||||
+ rc_bits_set[((value >> 4) & 0x0F)];
|
||||
break;
|
||||
}
|
||||
|
||||
/* step 3: apply logic */
|
||||
switch (self->type)
|
||||
{
|
||||
case RC_OPERAND_BCD:
|
||||
switch (self->size)
|
||||
{
|
||||
case RC_MEMSIZE_8_BITS:
|
||||
value = ((value >> 4) & 0x0f) * 10
|
||||
+ ((value ) & 0x0f);
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_16_BITS:
|
||||
value = ((value >> 12) & 0x0f) * 1000
|
||||
+ ((value >> 8) & 0x0f) * 100
|
||||
+ ((value >> 4) & 0x0f) * 10
|
||||
+ ((value ) & 0x0f);
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_24_BITS:
|
||||
value = ((value >> 20) & 0x0f) * 100000
|
||||
+ ((value >> 16) & 0x0f) * 10000
|
||||
+ ((value >> 12) & 0x0f) * 1000
|
||||
+ ((value >> 8) & 0x0f) * 100
|
||||
+ ((value >> 4) & 0x0f) * 10
|
||||
+ ((value ) & 0x0f);
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_32_BITS:
|
||||
value = ((value >> 28) & 0x0f) * 10000000
|
||||
+ ((value >> 24) & 0x0f) * 1000000
|
||||
+ ((value >> 20) & 0x0f) * 100000
|
||||
+ ((value >> 16) & 0x0f) * 10000
|
||||
+ ((value >> 12) & 0x0f) * 1000
|
||||
+ ((value >> 8) & 0x0f) * 100
|
||||
+ ((value >> 4) & 0x0f) * 10
|
||||
+ ((value ) & 0x0f);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case RC_OPERAND_INVERTED:
|
||||
switch (self->size)
|
||||
{
|
||||
case RC_MEMSIZE_LOW:
|
||||
case RC_MEMSIZE_HIGH:
|
||||
value ^= 0x0f;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_8_BITS:
|
||||
value ^= 0xff;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_16_BITS:
|
||||
value ^= 0xffff;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_24_BITS:
|
||||
value ^= 0xffffff;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_32_BITS:
|
||||
value ^= 0xffffffff;
|
||||
break;
|
||||
|
||||
default:
|
||||
value ^= 0x01;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
+43
-15
@@ -1,9 +1,8 @@
|
||||
#include "internal.h"
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* special formats only used by rc_richpresence_display_part_t.display_type. must not overlap other RC_FORMAT values */
|
||||
enum {
|
||||
@@ -116,6 +115,7 @@ static rc_richpresence_display_t* rc_parse_richpresence_display_internal(const c
|
||||
/* just calculating size, can't confirm lookup exists */
|
||||
part = RC_ALLOC(rc_richpresence_display_part_t, parse);
|
||||
|
||||
in = line;
|
||||
line = ++ptr;
|
||||
while (ptr < endline && *ptr != ')')
|
||||
++ptr;
|
||||
@@ -124,6 +124,10 @@ static rc_richpresence_display_t* rc_parse_richpresence_display_internal(const c
|
||||
if (parse->offset < 0)
|
||||
return 0;
|
||||
++ptr;
|
||||
} else {
|
||||
/* no closing parenthesis - allocate space for the invalid string */
|
||||
--in; /* already skipped over @ */
|
||||
rc_alloc_str(parse, line, (int)(ptr - in));
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -139,6 +143,7 @@ static rc_richpresence_display_t* rc_parse_richpresence_display_internal(const c
|
||||
part->first_lookup_item = lookup->first_item;
|
||||
part->display_type = lookup->format;
|
||||
|
||||
in = line;
|
||||
line = ++ptr;
|
||||
while (ptr < endline && *ptr != ')')
|
||||
++ptr;
|
||||
@@ -149,6 +154,12 @@ static rc_richpresence_display_t* rc_parse_richpresence_display_internal(const c
|
||||
return 0;
|
||||
++ptr;
|
||||
}
|
||||
else {
|
||||
/* non-terminated macro, dump the macro and the remaining portion of the line */
|
||||
--in; /* already skipped over @ */
|
||||
part->display_type = RC_FORMAT_STRING;
|
||||
part->text = rc_alloc_str(parse, in, (int)(ptr - in));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -170,7 +181,7 @@ static rc_richpresence_display_t* rc_parse_richpresence_display_internal(const c
|
||||
|
||||
/* assert: the allocated string is going to be smaller than the memory used for the parameter of the macro */
|
||||
part->display_type = RC_FORMAT_UNKNOWN_MACRO;
|
||||
part->text = rc_alloc_str(parse, line, ptr - line);
|
||||
part->text = rc_alloc_str(parse, line, (int)(ptr - line));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -194,7 +205,7 @@ static const char* rc_parse_richpresence_lookup(rc_richpresence_lookup_t* lookup
|
||||
const char* defaultlabel = 0;
|
||||
char* endptr = 0;
|
||||
unsigned key;
|
||||
int chars;
|
||||
unsigned chars;
|
||||
|
||||
next = &lookup->first_item;
|
||||
|
||||
@@ -372,7 +383,7 @@ int rc_richpresence_size(const char* script) {
|
||||
rc_richpresence_t* self;
|
||||
rc_parse_state_t parse;
|
||||
rc_init_parse_state(&parse, 0, 0, 0);
|
||||
|
||||
|
||||
self = RC_ALLOC(rc_richpresence_t, &parse);
|
||||
rc_parse_richpresence_internal(self, script, &parse);
|
||||
|
||||
@@ -389,7 +400,7 @@ rc_richpresence_t* rc_parse_richpresence(void* buffer, const char* script, lua_S
|
||||
rc_init_parse_state_memrefs(&parse, &self->memrefs);
|
||||
|
||||
rc_parse_richpresence_internal(self, script, &parse);
|
||||
|
||||
|
||||
rc_destroy_parse_state(&parse);
|
||||
return parse.offset >= 0 ? self : 0;
|
||||
}
|
||||
@@ -398,8 +409,10 @@ int rc_evaluate_richpresence(rc_richpresence_t* richpresence, char* buffer, unsi
|
||||
rc_richpresence_display_t* display;
|
||||
rc_richpresence_display_part_t* part;
|
||||
rc_richpresence_lookup_item_t* item;
|
||||
char tmp[256];
|
||||
char* ptr;
|
||||
int chars;
|
||||
const char* text;
|
||||
size_t chars;
|
||||
unsigned value;
|
||||
|
||||
rc_update_memref_values(richpresence->memrefs, peek, peek_ud);
|
||||
@@ -412,37 +425,52 @@ int rc_evaluate_richpresence(rc_richpresence_t* richpresence, char* buffer, unsi
|
||||
while (part) {
|
||||
switch (part->display_type) {
|
||||
case RC_FORMAT_STRING:
|
||||
chars = snprintf(ptr, buffersize, "%s", part->text);
|
||||
text = part->text;
|
||||
chars = strlen(text);
|
||||
break;
|
||||
|
||||
case RC_FORMAT_LOOKUP:
|
||||
value = rc_evaluate_value(&part->value, peek, peek_ud, L);
|
||||
item = part->first_lookup_item;
|
||||
if (!item) {
|
||||
text = "";
|
||||
chars = 0;
|
||||
} else {
|
||||
while (item->next_item && item->value != value)
|
||||
item = item->next_item;
|
||||
|
||||
chars = snprintf(ptr, buffersize, "%s", item->label);
|
||||
text = item->label;
|
||||
chars = strlen(text);
|
||||
}
|
||||
break;
|
||||
|
||||
case RC_FORMAT_UNKNOWN_MACRO:
|
||||
chars = snprintf(ptr, buffersize, "[Unknown macro]%s", part->text);
|
||||
chars = snprintf(tmp, sizeof(tmp), "[Unknown macro]%s", part->text);
|
||||
text = tmp;
|
||||
break;
|
||||
|
||||
default:
|
||||
value = rc_evaluate_value(&part->value, peek, peek_ud, L);
|
||||
chars = rc_format_value(ptr, buffersize, value, part->display_type);
|
||||
chars = rc_format_value(tmp, sizeof(tmp), value, part->display_type);
|
||||
text = tmp;
|
||||
break;
|
||||
}
|
||||
|
||||
if (chars > 0) {
|
||||
ptr += chars;
|
||||
buffersize -= chars;
|
||||
if (chars > 0 && buffersize > 0) {
|
||||
if ((unsigned)chars >= buffersize) {
|
||||
/* prevent write past end of buffer */
|
||||
memcpy(ptr, text, buffersize - 1);
|
||||
ptr[buffersize - 1] = '\0';
|
||||
buffersize = 0;
|
||||
}
|
||||
else {
|
||||
memcpy(ptr, text, chars);
|
||||
ptr[chars] = '\0';
|
||||
buffersize -= (unsigned)chars;
|
||||
}
|
||||
}
|
||||
|
||||
ptr += chars;
|
||||
part = part->next;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+589
@@ -0,0 +1,589 @@
|
||||
#include "internal.h"
|
||||
|
||||
#include "../rhash/md5.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define RC_RICHPRESENCE_DISPLAY_BUFFER_SIZE 256
|
||||
|
||||
void rc_runtime_init(rc_runtime_t* self) {
|
||||
memset(self, 0, sizeof(rc_runtime_t));
|
||||
self->next_memref = &self->memrefs;
|
||||
}
|
||||
|
||||
void rc_runtime_destroy(rc_runtime_t* self) {
|
||||
unsigned i;
|
||||
|
||||
if (self->triggers) {
|
||||
for (i = 0; i < self->trigger_count; ++i)
|
||||
free(self->triggers[i].buffer);
|
||||
|
||||
free(self->triggers);
|
||||
self->triggers = NULL;
|
||||
|
||||
self->trigger_count = self->trigger_capacity = 0;
|
||||
}
|
||||
|
||||
if (self->lboards) {
|
||||
free(self->lboards);
|
||||
self->lboards = NULL;
|
||||
|
||||
self->lboard_count = self->lboard_capacity = 0;
|
||||
}
|
||||
|
||||
while (self->richpresence) {
|
||||
rc_runtime_richpresence_t* previous = self->richpresence->previous;
|
||||
|
||||
free(self->richpresence->buffer);
|
||||
free(self->richpresence);
|
||||
self->richpresence = previous;
|
||||
}
|
||||
|
||||
if (self->richpresence_display_buffer) {
|
||||
free(self->richpresence_display_buffer);
|
||||
self->richpresence_display_buffer = NULL;
|
||||
}
|
||||
|
||||
self->next_memref = 0;
|
||||
self->memrefs = 0;
|
||||
}
|
||||
|
||||
static void rc_runtime_checksum(const char* memaddr, unsigned char* md5) {
|
||||
md5_state_t state;
|
||||
md5_init(&state);
|
||||
md5_append(&state, (unsigned char*)memaddr, (int)strlen(memaddr));
|
||||
md5_finish(&state, md5);
|
||||
}
|
||||
|
||||
static void rc_runtime_deactivate_trigger_by_index(rc_runtime_t* self, unsigned index) {
|
||||
if (self->triggers[index].owns_memrefs) {
|
||||
/* if the trigger has one or more memrefs in its buffer, we can't free the buffer.
|
||||
* just null out the trigger so the runtime processor will skip it
|
||||
*/
|
||||
rc_reset_trigger(self->triggers[index].trigger);
|
||||
self->triggers[index].trigger = NULL;
|
||||
}
|
||||
else {
|
||||
/* trigger doesn't own any memrefs, go ahead and free it, then replace it with the last trigger */
|
||||
free(self->triggers[index].buffer);
|
||||
|
||||
if (--self->trigger_count > index)
|
||||
memcpy(&self->triggers[index], &self->triggers[self->trigger_count], sizeof(rc_runtime_trigger_t));
|
||||
}
|
||||
}
|
||||
|
||||
void rc_runtime_deactivate_achievement(rc_runtime_t* self, unsigned id) {
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < self->trigger_count; ++i) {
|
||||
if (self->triggers[i].id == id && self->triggers[i].trigger != NULL)
|
||||
rc_runtime_deactivate_trigger_by_index(self, i);
|
||||
}
|
||||
}
|
||||
|
||||
int rc_runtime_activate_achievement(rc_runtime_t* self, unsigned id, const char* memaddr, lua_State* L, int funcs_idx) {
|
||||
void* trigger_buffer;
|
||||
rc_trigger_t* trigger;
|
||||
rc_parse_state_t parse;
|
||||
unsigned char md5[16];
|
||||
int size;
|
||||
char owns_memref;
|
||||
unsigned i;
|
||||
|
||||
if (memaddr == NULL)
|
||||
return RC_INVALID_MEMORY_OPERAND;
|
||||
|
||||
rc_runtime_checksum(memaddr, md5);
|
||||
|
||||
/* check to see if the id is already registered with an active trigger */
|
||||
for (i = 0; i < self->trigger_count; ++i) {
|
||||
if (self->triggers[i].id == id && self->triggers[i].trigger != NULL) {
|
||||
if (memcmp(self->triggers[i].md5, md5, 16) == 0) {
|
||||
/* if the checksum hasn't changed, we can reuse the existing item */
|
||||
rc_reset_trigger(self->triggers[i].trigger);
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
/* checksum has changed, deactivate the the item */
|
||||
rc_runtime_deactivate_trigger_by_index(self, i);
|
||||
|
||||
/* deactivate may reorder the list so we should continue from the current index. however, we
|
||||
* assume that only one trigger is active per id, so having found that, just stop scanning.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* check to see if a disabled trigger for the specific id matches the trigger being registered */
|
||||
for (i = 0; i < self->trigger_count; ++i) {
|
||||
if (self->triggers[i].id == id && memcmp(self->triggers[i].md5, md5, 16) == 0) {
|
||||
/* retrieve the trigger pointer from the buffer */
|
||||
size = 0;
|
||||
trigger = (rc_trigger_t*)rc_alloc(self->triggers[i].buffer, &size, sizeof(rc_trigger_t), RC_ALIGNOF(rc_trigger_t), 0);
|
||||
self->triggers[i].trigger = trigger;
|
||||
|
||||
rc_reset_trigger(trigger);
|
||||
return RC_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/* item has not been previously registered, determine how much space we need for it, and allocate it */
|
||||
size = rc_trigger_size(memaddr);
|
||||
if (size < 0)
|
||||
return size;
|
||||
|
||||
trigger_buffer = malloc(size);
|
||||
if (!trigger_buffer)
|
||||
return RC_OUT_OF_MEMORY;
|
||||
|
||||
/* populate the item, using the communal memrefs pool */
|
||||
rc_init_parse_state(&parse, trigger_buffer, L, funcs_idx);
|
||||
parse.first_memref = &self->memrefs;
|
||||
trigger = RC_ALLOC(rc_trigger_t, &parse);
|
||||
rc_parse_trigger_internal(trigger, &memaddr, &parse);
|
||||
rc_destroy_parse_state(&parse);
|
||||
|
||||
if (parse.offset < 0) {
|
||||
free(trigger_buffer);
|
||||
*self->next_memref = NULL; /* disassociate any memrefs allocated by the failed parse */
|
||||
return parse.offset;
|
||||
}
|
||||
|
||||
/* if at least one memref was allocated within the trigger, we can't free the buffer when the trigger is deactivated */
|
||||
owns_memref = (*self->next_memref != NULL);
|
||||
if (owns_memref) {
|
||||
/* advance through the new memrefs so we're ready for the next allocation */
|
||||
do {
|
||||
self->next_memref = &(*self->next_memref)->next;
|
||||
} while (*self->next_memref != NULL);
|
||||
}
|
||||
|
||||
/* grow the trigger buffer if necessary */
|
||||
if (self->trigger_count == self->trigger_capacity) {
|
||||
self->trigger_capacity += 32;
|
||||
if (!self->triggers)
|
||||
self->triggers = (rc_runtime_trigger_t*)malloc(self->trigger_capacity * sizeof(rc_runtime_trigger_t));
|
||||
else
|
||||
self->triggers = (rc_runtime_trigger_t*)realloc(self->triggers, self->trigger_capacity * sizeof(rc_runtime_trigger_t));
|
||||
}
|
||||
|
||||
/* assign the new trigger */
|
||||
self->triggers[self->trigger_count].id = id;
|
||||
self->triggers[self->trigger_count].trigger = trigger;
|
||||
self->triggers[self->trigger_count].buffer = trigger_buffer;
|
||||
memcpy(self->triggers[self->trigger_count].md5, md5, 16);
|
||||
self->triggers[self->trigger_count].owns_memrefs = owns_memref;
|
||||
++self->trigger_count;
|
||||
|
||||
/* reset it, and return it */
|
||||
trigger->memrefs = NULL;
|
||||
rc_reset_trigger(trigger);
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
rc_trigger_t* rc_runtime_get_achievement(const rc_runtime_t* self, unsigned id)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < self->trigger_count; ++i) {
|
||||
if (self->triggers[i].id == id && self->triggers[i].trigger != NULL)
|
||||
return self->triggers[i].trigger;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void rc_runtime_deactivate_lboard_by_index(rc_runtime_t* self, unsigned index) {
|
||||
if (self->lboards[index].owns_memrefs) {
|
||||
/* if the lboard has one or more memrefs in its buffer, we can't free the buffer.
|
||||
* just null out the lboard so the runtime processor will skip it
|
||||
*/
|
||||
rc_reset_lboard(self->lboards[index].lboard);
|
||||
self->lboards[index].lboard = NULL;
|
||||
}
|
||||
else {
|
||||
/* lboard doesn't own any memrefs, go ahead and free it, then replace it with the last lboard */
|
||||
free(self->lboards[index].buffer);
|
||||
|
||||
if (--self->lboard_count > index)
|
||||
memcpy(&self->lboards[index], &self->lboards[self->lboard_count], sizeof(rc_runtime_lboard_t));
|
||||
}
|
||||
}
|
||||
|
||||
void rc_runtime_deactivate_lboard(rc_runtime_t* self, unsigned id) {
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < self->lboard_count; ++i) {
|
||||
if (self->lboards[i].id == id && self->lboards[i].lboard != NULL)
|
||||
rc_runtime_deactivate_lboard_by_index(self, i);
|
||||
}
|
||||
}
|
||||
|
||||
int rc_runtime_activate_lboard(rc_runtime_t* self, unsigned id, const char* memaddr, lua_State* L, int funcs_idx) {
|
||||
void* lboard_buffer;
|
||||
unsigned char md5[16];
|
||||
rc_lboard_t* lboard;
|
||||
rc_parse_state_t parse;
|
||||
int size;
|
||||
char owns_memref;
|
||||
unsigned i;
|
||||
|
||||
if (memaddr == 0)
|
||||
return RC_INVALID_MEMORY_OPERAND;
|
||||
|
||||
rc_runtime_checksum(memaddr, md5);
|
||||
|
||||
/* check to see if the id is already registered with an active lboard */
|
||||
for (i = 0; i < self->lboard_count; ++i) {
|
||||
if (self->lboards[i].id == id && self->lboards[i].lboard != NULL) {
|
||||
if (memcmp(self->lboards[i].md5, md5, 16) == 0) {
|
||||
/* if the checksum hasn't changed, we can reuse the existing item */
|
||||
rc_reset_lboard(self->lboards[i].lboard);
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
/* checksum has changed, deactivate the the item */
|
||||
rc_runtime_deactivate_lboard_by_index(self, i);
|
||||
|
||||
/* deactivate may reorder the list so we should continue from the current index. however, we
|
||||
* assume that only one trigger is active per id, so having found that, just stop scanning.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* check to see if a disabled lboard for the specific id matches the lboard being registered */
|
||||
for (i = 0; i < self->lboard_count; ++i) {
|
||||
if (self->lboards[i].id == id && memcmp(self->lboards[i].md5, md5, 16) == 0) {
|
||||
/* retrieve the lboard pointer from the buffer */
|
||||
size = 0;
|
||||
lboard = (rc_lboard_t*)rc_alloc(self->lboards[i].buffer, &size, sizeof(rc_lboard_t), RC_ALIGNOF(rc_lboard_t), 0);
|
||||
self->lboards[i].lboard = lboard;
|
||||
|
||||
rc_reset_lboard(lboard);
|
||||
return RC_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/* item has not been previously registered, determine how much space we need for it, and allocate it */
|
||||
size = rc_lboard_size(memaddr);
|
||||
if (size < 0)
|
||||
return size;
|
||||
|
||||
lboard_buffer = malloc(size);
|
||||
if (!lboard_buffer)
|
||||
return RC_OUT_OF_MEMORY;
|
||||
|
||||
/* populate the item, using the communal memrefs pool */
|
||||
rc_init_parse_state(&parse, lboard_buffer, L, funcs_idx);
|
||||
lboard = RC_ALLOC(rc_lboard_t, &parse);
|
||||
parse.first_memref = &self->memrefs;
|
||||
rc_parse_lboard_internal(lboard, memaddr, &parse);
|
||||
rc_destroy_parse_state(&parse);
|
||||
|
||||
if (parse.offset < 0) {
|
||||
free(lboard_buffer);
|
||||
*self->next_memref = NULL; /* disassociate any memrefs allocated by the failed parse */
|
||||
return parse.offset;
|
||||
}
|
||||
|
||||
/* if at least one memref was allocated within the trigger, we can't free the buffer when the trigger is deactivated */
|
||||
owns_memref = (*self->next_memref != NULL);
|
||||
if (owns_memref) {
|
||||
/* advance through the new memrefs so we're ready for the next allocation */
|
||||
do {
|
||||
self->next_memref = &(*self->next_memref)->next;
|
||||
} while (*self->next_memref != NULL);
|
||||
}
|
||||
|
||||
/* grow the lboard buffer if necessary */
|
||||
if (self->lboard_count == self->lboard_capacity) {
|
||||
self->lboard_capacity += 16;
|
||||
if (!self->lboards)
|
||||
self->lboards = (rc_runtime_lboard_t*)malloc(self->lboard_capacity * sizeof(rc_runtime_lboard_t));
|
||||
else
|
||||
self->lboards = (rc_runtime_lboard_t*)realloc(self->lboards, self->lboard_capacity * sizeof(rc_runtime_lboard_t));
|
||||
}
|
||||
|
||||
/* assign the new lboard */
|
||||
self->lboards[self->lboard_count].id = id;
|
||||
self->lboards[self->lboard_count].value = 0;
|
||||
self->lboards[self->lboard_count].lboard = lboard;
|
||||
self->lboards[self->lboard_count].buffer = lboard_buffer;
|
||||
memcpy(self->lboards[self->lboard_count].md5, md5, 16);
|
||||
self->lboards[self->lboard_count].owns_memrefs = owns_memref;
|
||||
++self->lboard_count;
|
||||
|
||||
/* reset it, and return it */
|
||||
lboard->memrefs = NULL;
|
||||
rc_reset_lboard(lboard);
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
rc_lboard_t* rc_runtime_get_lboard(const rc_runtime_t* self, unsigned id)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < self->lboard_count; ++i) {
|
||||
if (self->lboards[i].id == id && self->lboards[i].lboard != NULL)
|
||||
return self->lboards[i].lboard;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int rc_runtime_activate_richpresence(rc_runtime_t* self, const char* script, lua_State* L, int funcs_idx) {
|
||||
rc_richpresence_t* richpresence;
|
||||
rc_runtime_richpresence_t* previous;
|
||||
rc_richpresence_display_t* display;
|
||||
rc_parse_state_t parse;
|
||||
int size;
|
||||
|
||||
if (script == NULL)
|
||||
return RC_MISSING_DISPLAY_STRING;
|
||||
|
||||
size = rc_richpresence_size(script);
|
||||
if (size < 0)
|
||||
return size;
|
||||
|
||||
if (!self->richpresence_display_buffer) {
|
||||
self->richpresence_display_buffer = (char*)malloc(RC_RICHPRESENCE_DISPLAY_BUFFER_SIZE * sizeof(char));
|
||||
if (!self->richpresence_display_buffer)
|
||||
return RC_OUT_OF_MEMORY;
|
||||
}
|
||||
self->richpresence_display_buffer[0] = '\0';
|
||||
|
||||
previous = self->richpresence;
|
||||
if (previous) {
|
||||
if (!previous->owns_memrefs) {
|
||||
free(previous->buffer);
|
||||
previous = previous->previous;
|
||||
}
|
||||
}
|
||||
|
||||
self->richpresence = (rc_runtime_richpresence_t*)malloc(sizeof(rc_runtime_richpresence_t));
|
||||
if (!self->richpresence)
|
||||
return RC_OUT_OF_MEMORY;
|
||||
|
||||
self->richpresence->previous = previous;
|
||||
self->richpresence->owns_memrefs = 0;
|
||||
self->richpresence->buffer = malloc(size);
|
||||
|
||||
if (!self->richpresence->buffer)
|
||||
return RC_OUT_OF_MEMORY;
|
||||
|
||||
rc_init_parse_state(&parse, self->richpresence->buffer, L, funcs_idx);
|
||||
self->richpresence->richpresence = richpresence = RC_ALLOC(rc_richpresence_t, &parse);
|
||||
parse.first_memref = &self->memrefs;
|
||||
rc_parse_richpresence_internal(richpresence, script, &parse);
|
||||
rc_destroy_parse_state(&parse);
|
||||
|
||||
if (parse.offset < 0) {
|
||||
free(self->richpresence->buffer);
|
||||
free(self->richpresence);
|
||||
self->richpresence = previous;
|
||||
*self->next_memref = NULL; /* disassociate any memrefs allocated by the failed parse */
|
||||
return parse.offset;
|
||||
}
|
||||
|
||||
/* if at least one memref was allocated within the rich presence, we can't free the buffer when the rich presence is deactivated */
|
||||
self->richpresence->owns_memrefs = (*self->next_memref != NULL);
|
||||
if (self->richpresence->owns_memrefs) {
|
||||
/* advance through the new memrefs so we're ready for the next allocation */
|
||||
do {
|
||||
self->next_memref = &(*self->next_memref)->next;
|
||||
} while (*self->next_memref != NULL);
|
||||
}
|
||||
|
||||
richpresence->memrefs = NULL;
|
||||
self->richpresence_update_timer = 0;
|
||||
|
||||
if (!richpresence->first_display || !richpresence->first_display->display) {
|
||||
/* non-existant rich presence, treat like static empty string */
|
||||
*self->richpresence_display_buffer = '\0';
|
||||
self->richpresence->richpresence = NULL;
|
||||
}
|
||||
else if (richpresence->first_display->next || /* has conditional display strings */
|
||||
richpresence->first_display->display->next || /* has macros */
|
||||
richpresence->first_display->display->value.conditions) { /* is only a macro */
|
||||
/* dynamic rich presence - reset all of the conditions */
|
||||
display = richpresence->first_display;
|
||||
while (display != NULL) {
|
||||
rc_reset_trigger(&display->trigger);
|
||||
display = display->next;
|
||||
}
|
||||
|
||||
rc_evaluate_richpresence(self->richpresence->richpresence, self->richpresence_display_buffer, RC_RICHPRESENCE_DISPLAY_BUFFER_SIZE - 1, NULL, NULL, L);
|
||||
}
|
||||
else {
|
||||
/* static rich presence - copy the static string */
|
||||
const char* src = richpresence->first_display->display->text;
|
||||
char* dst = self->richpresence_display_buffer;
|
||||
const char* end = dst + RC_RICHPRESENCE_DISPLAY_BUFFER_SIZE - 1;
|
||||
while (*src && dst < end)
|
||||
*dst++ = *src++;
|
||||
*dst = '\0';
|
||||
|
||||
/* by setting self->richpresence to null, it won't be evaluated in do_frame() */
|
||||
self->richpresence = NULL;
|
||||
}
|
||||
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
const char* rc_runtime_get_richpresence(const rc_runtime_t* self)
|
||||
{
|
||||
if (self->richpresence_display_buffer)
|
||||
return self->richpresence_display_buffer;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void rc_runtime_do_frame(rc_runtime_t* self, rc_runtime_event_handler_t event_handler, rc_peek_t peek, void* ud, lua_State* L) {
|
||||
rc_runtime_event_t runtime_event;
|
||||
unsigned i;
|
||||
|
||||
runtime_event.value = 0;
|
||||
|
||||
rc_update_memref_values(self->memrefs, peek, ud);
|
||||
|
||||
for (i = 0; i < self->trigger_count; ++i) {
|
||||
rc_trigger_t* trigger = self->triggers[i].trigger;
|
||||
int trigger_state;
|
||||
|
||||
if (!trigger)
|
||||
continue;
|
||||
|
||||
trigger_state = trigger->state;
|
||||
|
||||
switch (rc_evaluate_trigger(trigger, peek, ud, L))
|
||||
{
|
||||
case RC_TRIGGER_STATE_RESET:
|
||||
runtime_event.type = RC_RUNTIME_EVENT_ACHIEVEMENT_RESET;
|
||||
runtime_event.id = self->triggers[i].id;
|
||||
event_handler(&runtime_event);
|
||||
break;
|
||||
|
||||
case RC_TRIGGER_STATE_TRIGGERED:
|
||||
runtime_event.type = RC_RUNTIME_EVENT_ACHIEVEMENT_TRIGGERED;
|
||||
runtime_event.id = self->triggers[i].id;
|
||||
event_handler(&runtime_event);
|
||||
break;
|
||||
|
||||
case RC_TRIGGER_STATE_PAUSED:
|
||||
if (trigger_state != RC_TRIGGER_STATE_PAUSED) {
|
||||
runtime_event.type = RC_RUNTIME_EVENT_ACHIEVEMENT_PAUSED;
|
||||
runtime_event.id = self->triggers[i].id;
|
||||
event_handler(&runtime_event);
|
||||
}
|
||||
break;
|
||||
|
||||
case RC_TRIGGER_STATE_PRIMED:
|
||||
if (trigger_state != RC_TRIGGER_STATE_PRIMED) {
|
||||
runtime_event.type = RC_RUNTIME_EVENT_ACHIEVEMENT_PRIMED;
|
||||
runtime_event.id = self->triggers[i].id;
|
||||
event_handler(&runtime_event);
|
||||
}
|
||||
break;
|
||||
|
||||
case RC_TRIGGER_STATE_ACTIVE:
|
||||
if (trigger_state != RC_TRIGGER_STATE_ACTIVE) {
|
||||
runtime_event.type = RC_RUNTIME_EVENT_ACHIEVEMENT_ACTIVATED;
|
||||
runtime_event.id = self->triggers[i].id;
|
||||
event_handler(&runtime_event);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < self->lboard_count; ++i) {
|
||||
rc_lboard_t* lboard = self->lboards[i].lboard;
|
||||
int lboard_state;
|
||||
|
||||
if (!lboard)
|
||||
continue;
|
||||
|
||||
lboard_state = lboard->state;
|
||||
switch (rc_evaluate_lboard(lboard, &runtime_event.value, peek, ud, L))
|
||||
{
|
||||
case RC_LBOARD_STATE_STARTED: /* leaderboard is running */
|
||||
if (lboard_state != RC_LBOARD_STATE_STARTED) {
|
||||
self->lboards[i].value = runtime_event.value;
|
||||
|
||||
runtime_event.type = RC_RUNTIME_EVENT_LBOARD_STARTED;
|
||||
runtime_event.id = self->lboards[i].id;
|
||||
event_handler(&runtime_event);
|
||||
}
|
||||
else if (runtime_event.value != self->lboards[i].value) {
|
||||
self->lboards[i].value = runtime_event.value;
|
||||
|
||||
runtime_event.type = RC_RUNTIME_EVENT_LBOARD_UPDATED;
|
||||
runtime_event.id = self->lboards[i].id;
|
||||
event_handler(&runtime_event);
|
||||
}
|
||||
break;
|
||||
|
||||
case RC_LBOARD_STATE_CANCELED:
|
||||
if (lboard_state != RC_LBOARD_STATE_CANCELED) {
|
||||
runtime_event.type = RC_RUNTIME_EVENT_LBOARD_CANCELED;
|
||||
runtime_event.id = self->lboards[i].id;
|
||||
event_handler(&runtime_event);
|
||||
}
|
||||
break;
|
||||
|
||||
case RC_LBOARD_STATE_TRIGGERED:
|
||||
if (lboard_state != RC_RUNTIME_EVENT_LBOARD_TRIGGERED) {
|
||||
runtime_event.type = RC_RUNTIME_EVENT_LBOARD_TRIGGERED;
|
||||
runtime_event.id = self->lboards[i].id;
|
||||
event_handler(&runtime_event);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (self->richpresence && self->richpresence->richpresence) {
|
||||
if (self->richpresence_update_timer == 0) {
|
||||
/* generate into a temporary buffer so we don't get a partially updated string if it's read while its being updated */
|
||||
char buffer[RC_RICHPRESENCE_DISPLAY_BUFFER_SIZE];
|
||||
int len = rc_evaluate_richpresence(self->richpresence->richpresence, buffer, RC_RICHPRESENCE_DISPLAY_BUFFER_SIZE - 1, peek, ud, L);
|
||||
|
||||
/* copy into the real buffer - write the 0 terminator first to ensure reads don't overflow the buffer */
|
||||
if (len > 0) {
|
||||
buffer[RC_RICHPRESENCE_DISPLAY_BUFFER_SIZE - 1] = '\0';
|
||||
memcpy(self->richpresence_display_buffer, buffer, RC_RICHPRESENCE_DISPLAY_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
/* schedule the next update for 60 frames later - most systems use a 60 fps framerate (some use more 50 or 75)
|
||||
* since we're only sending to the server every two minutes, that's only every 7200 frames while active, which
|
||||
* is evenly divisible by 50, 60, and 75.
|
||||
*/
|
||||
self->richpresence_update_timer = 59;
|
||||
}
|
||||
else {
|
||||
self->richpresence_update_timer--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rc_runtime_reset(rc_runtime_t* self) {
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < self->trigger_count; ++i) {
|
||||
if (self->triggers[i].trigger)
|
||||
rc_reset_trigger(self->triggers[i].trigger);
|
||||
}
|
||||
|
||||
for (i = 0; i < self->lboard_count; ++i) {
|
||||
if (self->lboards[i].lboard)
|
||||
rc_reset_lboard(self->lboards[i].lboard);
|
||||
}
|
||||
|
||||
if (self->richpresence) {
|
||||
rc_richpresence_display_t* display = self->richpresence->richpresence->first_display;
|
||||
while (display != 0) {
|
||||
rc_reset_trigger(&display->trigger);
|
||||
display = display->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
+445
@@ -0,0 +1,445 @@
|
||||
#include "internal.h"
|
||||
|
||||
#include "../rhash/md5.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define RC_RUNTIME_MARKER 0x0A504152 /* RAP\n */
|
||||
|
||||
#define RC_RUNTIME_CHUNK_MEMREFS 0x4645524D /* MREF */
|
||||
#define RC_RUNTIME_CHUNK_ACHIEVEMENT 0x56484341 /* ACHV */
|
||||
|
||||
#define RC_RUNTIME_CHUNK_DONE 0x454E4F44 /* DONE */
|
||||
|
||||
typedef struct rc_runtime_progress_t {
|
||||
rc_runtime_t* runtime;
|
||||
|
||||
int offset;
|
||||
unsigned char* buffer;
|
||||
|
||||
int chunk_size_offset;
|
||||
|
||||
lua_State* L;
|
||||
} rc_runtime_progress_t;
|
||||
|
||||
#define RC_TRIGGER_STATE_UNUPDATED 0x7F
|
||||
|
||||
#define RC_MEMREF_FLAG_PREV_IS_PRIOR 0x00010000
|
||||
|
||||
static void rc_runtime_progress_write_uint(rc_runtime_progress_t* progress, unsigned value)
|
||||
{
|
||||
if (progress->buffer) {
|
||||
progress->buffer[progress->offset + 0] = value & 0xFF; value >>= 8;
|
||||
progress->buffer[progress->offset + 1] = value & 0xFF; value >>= 8;
|
||||
progress->buffer[progress->offset + 2] = value & 0xFF; value >>= 8;
|
||||
progress->buffer[progress->offset + 3] = value & 0xFF;
|
||||
}
|
||||
|
||||
progress->offset += 4;
|
||||
}
|
||||
|
||||
static unsigned rc_runtime_progress_read_uint(rc_runtime_progress_t* progress)
|
||||
{
|
||||
unsigned value = progress->buffer[progress->offset + 0] |
|
||||
(progress->buffer[progress->offset + 1] << 8) |
|
||||
(progress->buffer[progress->offset + 2] << 16) |
|
||||
(progress->buffer[progress->offset + 3] << 24);
|
||||
|
||||
progress->offset += 4;
|
||||
return value;
|
||||
}
|
||||
|
||||
static void rc_runtime_progress_write_md5(rc_runtime_progress_t* progress, unsigned char* md5)
|
||||
{
|
||||
if (progress->buffer)
|
||||
memcpy(&progress->buffer[progress->offset], md5, 16);
|
||||
|
||||
progress->offset += 16;
|
||||
}
|
||||
|
||||
static int rc_runtime_progress_match_md5(rc_runtime_progress_t* progress, unsigned char* md5)
|
||||
{
|
||||
int result = 0;
|
||||
if (progress->buffer)
|
||||
result = (memcmp(&progress->buffer[progress->offset], md5, 16) == 0);
|
||||
|
||||
progress->offset += 16;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void rc_runtime_progress_start_chunk(rc_runtime_progress_t* progress, unsigned chunk_id)
|
||||
{
|
||||
rc_runtime_progress_write_uint(progress, chunk_id);
|
||||
|
||||
progress->chunk_size_offset = progress->offset;
|
||||
|
||||
progress->offset += 4;
|
||||
}
|
||||
|
||||
static void rc_runtime_progress_end_chunk(rc_runtime_progress_t* progress)
|
||||
{
|
||||
unsigned length;
|
||||
int offset;
|
||||
|
||||
progress->offset = (progress->offset + 3) & ~0x03; /* align to 4 byte boundary */
|
||||
|
||||
if (progress->buffer) {
|
||||
/* ignore chunk size field when calculating chunk size */
|
||||
length = (unsigned)(progress->offset - progress->chunk_size_offset - 4);
|
||||
|
||||
/* temporarily update the write pointer to write the chunk size field */
|
||||
offset = progress->offset;
|
||||
progress->offset = progress->chunk_size_offset;
|
||||
rc_runtime_progress_write_uint(progress, length);
|
||||
progress->offset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
static void rc_runtime_progress_init(rc_runtime_progress_t* progress, rc_runtime_t* runtime, lua_State* L)
|
||||
{
|
||||
memset(progress, 0, sizeof(rc_runtime_progress_t));
|
||||
progress->runtime = runtime;
|
||||
progress->L = L;
|
||||
}
|
||||
|
||||
static int rc_runtime_progress_write_memrefs(rc_runtime_progress_t* progress)
|
||||
{
|
||||
rc_memref_value_t* memref = progress->runtime->memrefs;
|
||||
unsigned int flags = 0;
|
||||
|
||||
rc_runtime_progress_start_chunk(progress, RC_RUNTIME_CHUNK_MEMREFS);
|
||||
|
||||
while (memref) {
|
||||
flags = memref->memref.size;
|
||||
if (memref->previous == memref->prior)
|
||||
flags |= RC_MEMREF_FLAG_PREV_IS_PRIOR;
|
||||
|
||||
rc_runtime_progress_write_uint(progress, memref->memref.address);
|
||||
rc_runtime_progress_write_uint(progress, flags);
|
||||
rc_runtime_progress_write_uint(progress, memref->value);
|
||||
rc_runtime_progress_write_uint(progress, memref->prior);
|
||||
|
||||
memref = memref->next;
|
||||
}
|
||||
|
||||
rc_runtime_progress_end_chunk(progress);
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
static int rc_runtime_progress_read_memrefs(rc_runtime_progress_t* progress)
|
||||
{
|
||||
unsigned entries;
|
||||
unsigned address, flags, value, prior;
|
||||
char size;
|
||||
rc_memref_value_t* memref;
|
||||
|
||||
/* re-read the chunk size to determine how many memrefs are present */
|
||||
progress->offset -= 4;
|
||||
entries = rc_runtime_progress_read_uint(progress) / 16;
|
||||
|
||||
while (entries != 0) {
|
||||
address = rc_runtime_progress_read_uint(progress);
|
||||
flags = rc_runtime_progress_read_uint(progress);
|
||||
value = rc_runtime_progress_read_uint(progress);
|
||||
prior = rc_runtime_progress_read_uint(progress);
|
||||
|
||||
size = flags & 0xFF;
|
||||
|
||||
memref = progress->runtime->memrefs;
|
||||
while (memref) {
|
||||
if (memref->memref.address == address && memref->memref.size == size) {
|
||||
memref->value = value;
|
||||
memref->previous = (flags & RC_MEMREF_FLAG_PREV_IS_PRIOR) ? prior : value;
|
||||
memref->prior = prior;
|
||||
}
|
||||
|
||||
memref = memref->next;
|
||||
}
|
||||
|
||||
--entries;
|
||||
}
|
||||
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
static int rc_runtime_progress_write_condset(rc_runtime_progress_t* progress, rc_condset_t* condset)
|
||||
{
|
||||
rc_condition_t* cond;
|
||||
|
||||
rc_runtime_progress_write_uint(progress, condset->is_paused);
|
||||
|
||||
cond = condset->conditions;
|
||||
while (cond) {
|
||||
rc_runtime_progress_write_uint(progress, cond->current_hits);
|
||||
rc_runtime_progress_write_uint(progress, cond->is_true);
|
||||
|
||||
cond = cond->next;
|
||||
}
|
||||
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
static int rc_runtime_progress_read_condset(rc_runtime_progress_t* progress, rc_condset_t* condset)
|
||||
{
|
||||
rc_condition_t* cond;
|
||||
|
||||
condset->is_paused = rc_runtime_progress_read_uint(progress);
|
||||
|
||||
cond = condset->conditions;
|
||||
while (cond) {
|
||||
cond->current_hits = rc_runtime_progress_read_uint(progress);
|
||||
cond->is_true = rc_runtime_progress_read_uint(progress) & 0xFF;
|
||||
|
||||
cond = cond->next;
|
||||
}
|
||||
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
static int rc_runtime_progress_write_trigger(rc_runtime_progress_t* progress, rc_trigger_t* trigger)
|
||||
{
|
||||
rc_condset_t* condset;
|
||||
int result;
|
||||
|
||||
rc_runtime_progress_write_uint(progress, trigger->state);
|
||||
rc_runtime_progress_write_uint(progress, trigger->measured_value);
|
||||
|
||||
if (trigger->requirement) {
|
||||
result = rc_runtime_progress_write_condset(progress, trigger->requirement);
|
||||
if (result != RC_OK)
|
||||
return result;
|
||||
}
|
||||
|
||||
condset = trigger->alternative;
|
||||
while (condset)
|
||||
{
|
||||
result = rc_runtime_progress_write_condset(progress, condset);
|
||||
if (result != RC_OK)
|
||||
return result;
|
||||
|
||||
condset = condset->next;
|
||||
}
|
||||
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
static int rc_runtime_progress_read_trigger(rc_runtime_progress_t* progress, rc_trigger_t* trigger)
|
||||
{
|
||||
rc_condset_t* condset;
|
||||
int result;
|
||||
|
||||
trigger->state = rc_runtime_progress_read_uint(progress);
|
||||
trigger->measured_value = rc_runtime_progress_read_uint(progress);
|
||||
|
||||
if (trigger->requirement) {
|
||||
result = rc_runtime_progress_read_condset(progress, trigger->requirement);
|
||||
if (result != RC_OK)
|
||||
return result;
|
||||
}
|
||||
|
||||
condset = trigger->alternative;
|
||||
while (condset)
|
||||
{
|
||||
result = rc_runtime_progress_read_condset(progress, condset);
|
||||
if (result != RC_OK)
|
||||
return result;
|
||||
|
||||
condset = condset->next;
|
||||
}
|
||||
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
static int rc_runtime_progress_write_achievements(rc_runtime_progress_t* progress)
|
||||
{
|
||||
unsigned i;
|
||||
int result;
|
||||
|
||||
for (i = 0; i < progress->runtime->trigger_count; ++i)
|
||||
{
|
||||
rc_runtime_trigger_t* runtime_trigger = &progress->runtime->triggers[i];
|
||||
if (!runtime_trigger->trigger)
|
||||
continue;
|
||||
|
||||
switch (runtime_trigger->trigger->state)
|
||||
{
|
||||
case RC_TRIGGER_STATE_INACTIVE:
|
||||
case RC_TRIGGER_STATE_TRIGGERED:
|
||||
/* don't store state for inactive or triggered achievements */
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
rc_runtime_progress_start_chunk(progress, RC_RUNTIME_CHUNK_ACHIEVEMENT);
|
||||
rc_runtime_progress_write_uint(progress, runtime_trigger->id);
|
||||
rc_runtime_progress_write_md5(progress, runtime_trigger->md5);
|
||||
|
||||
result = rc_runtime_progress_write_trigger(progress, runtime_trigger->trigger);
|
||||
if (result != RC_OK)
|
||||
return result;
|
||||
|
||||
rc_runtime_progress_end_chunk(progress);
|
||||
}
|
||||
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
static int rc_runtime_progress_read_achievement(rc_runtime_progress_t* progress)
|
||||
{
|
||||
unsigned id = rc_runtime_progress_read_uint(progress);
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < progress->runtime->trigger_count; ++i) {
|
||||
rc_runtime_trigger_t* runtime_trigger = &progress->runtime->triggers[i];
|
||||
if (runtime_trigger->id == id && runtime_trigger->trigger != NULL) {
|
||||
/* ignore triggered and waiting achievements */
|
||||
if (runtime_trigger->trigger->state == RC_TRIGGER_STATE_UNUPDATED) {
|
||||
/* only update state if definition hasn't changed (md5 matches) */
|
||||
if (rc_runtime_progress_match_md5(progress, runtime_trigger->md5))
|
||||
return rc_runtime_progress_read_trigger(progress, runtime_trigger->trigger);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
static int rc_runtime_progress_serialize_internal(rc_runtime_progress_t* progress)
|
||||
{
|
||||
md5_state_t state;
|
||||
unsigned char md5[16];
|
||||
int result;
|
||||
|
||||
rc_runtime_progress_write_uint(progress, RC_RUNTIME_MARKER);
|
||||
|
||||
if ((result = rc_runtime_progress_write_memrefs(progress)) != RC_OK)
|
||||
return result;
|
||||
|
||||
if ((result = rc_runtime_progress_write_achievements(progress)) != RC_OK)
|
||||
return result;
|
||||
|
||||
rc_runtime_progress_write_uint(progress, RC_RUNTIME_CHUNK_DONE);
|
||||
rc_runtime_progress_write_uint(progress, 16);
|
||||
|
||||
if (progress->buffer) {
|
||||
md5_init(&state);
|
||||
md5_append(&state, progress->buffer, progress->offset);
|
||||
md5_finish(&state, md5);
|
||||
}
|
||||
|
||||
rc_runtime_progress_write_md5(progress, md5);
|
||||
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
int rc_runtime_progress_size(const rc_runtime_t* runtime, lua_State* L)
|
||||
{
|
||||
rc_runtime_progress_t progress;
|
||||
int result;
|
||||
|
||||
rc_runtime_progress_init(&progress, (rc_runtime_t*)runtime, L);
|
||||
|
||||
result = rc_runtime_progress_serialize_internal(&progress);
|
||||
if (result != RC_OK)
|
||||
return result;
|
||||
|
||||
return progress.offset;
|
||||
}
|
||||
|
||||
int rc_runtime_serialize_progress(void* buffer, const rc_runtime_t* runtime, lua_State* L)
|
||||
{
|
||||
rc_runtime_progress_t progress;
|
||||
|
||||
rc_runtime_progress_init(&progress, (rc_runtime_t*)runtime, L);
|
||||
progress.buffer = (unsigned char*)buffer;
|
||||
|
||||
return rc_runtime_progress_serialize_internal(&progress);
|
||||
}
|
||||
|
||||
int rc_runtime_deserialize_progress(rc_runtime_t* runtime, const unsigned char* serialized, lua_State* L)
|
||||
{
|
||||
rc_runtime_progress_t progress;
|
||||
md5_state_t state;
|
||||
unsigned char md5[16];
|
||||
unsigned chunk_id;
|
||||
unsigned chunk_size;
|
||||
unsigned next_chunk_offset;
|
||||
unsigned i;
|
||||
int result = RC_OK;
|
||||
|
||||
rc_runtime_progress_init(&progress, runtime, L);
|
||||
progress.buffer = (unsigned char*)serialized;
|
||||
|
||||
if (rc_runtime_progress_read_uint(&progress) != RC_RUNTIME_MARKER) {
|
||||
rc_runtime_reset(runtime);
|
||||
return RC_INVALID_STATE;
|
||||
}
|
||||
|
||||
for (i = 0; i < runtime->trigger_count; ++i) {
|
||||
rc_runtime_trigger_t* runtime_trigger = &runtime->triggers[i];
|
||||
if (runtime_trigger->trigger) {
|
||||
switch (runtime_trigger->trigger->state)
|
||||
{
|
||||
case RC_TRIGGER_STATE_INACTIVE:
|
||||
case RC_TRIGGER_STATE_TRIGGERED:
|
||||
/* don't update state for inactive or triggered achievements */
|
||||
break;
|
||||
|
||||
default:
|
||||
/* mark active achievements as unupdated. anything that's still unupdated
|
||||
* after deserializing the progress will be reset to waiting */
|
||||
runtime_trigger->trigger->state = RC_TRIGGER_STATE_UNUPDATED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
chunk_id = rc_runtime_progress_read_uint(&progress);
|
||||
chunk_size = rc_runtime_progress_read_uint(&progress);
|
||||
next_chunk_offset = progress.offset + chunk_size;
|
||||
|
||||
switch (chunk_id)
|
||||
{
|
||||
case RC_RUNTIME_CHUNK_MEMREFS:
|
||||
result = rc_runtime_progress_read_memrefs(&progress);
|
||||
break;
|
||||
|
||||
case RC_RUNTIME_CHUNK_ACHIEVEMENT:
|
||||
result = rc_runtime_progress_read_achievement(&progress);
|
||||
break;
|
||||
|
||||
case RC_RUNTIME_CHUNK_DONE:
|
||||
md5_init(&state);
|
||||
md5_append(&state, progress.buffer, progress.offset);
|
||||
md5_finish(&state, md5);
|
||||
if (!rc_runtime_progress_match_md5(&progress, md5))
|
||||
result = RC_INVALID_STATE;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (chunk_size & 0xFFFF0000)
|
||||
result = RC_INVALID_STATE; /* assume unknown chunk > 64KB is invalid */
|
||||
break;
|
||||
}
|
||||
|
||||
progress.offset = next_chunk_offset;
|
||||
} while (result == RC_OK && chunk_id != RC_RUNTIME_CHUNK_DONE);
|
||||
|
||||
if (result != RC_OK) {
|
||||
rc_runtime_reset(runtime);
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < runtime->trigger_count; ++i) {
|
||||
rc_trigger_t* trigger = runtime->triggers[i].trigger;
|
||||
if (trigger && trigger->state == RC_TRIGGER_STATE_UNUPDATED)
|
||||
rc_reset_trigger(trigger);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
Vendored
-103
@@ -1,103 +0,0 @@
|
||||
#include "internal.h"
|
||||
|
||||
rc_term_t* rc_parse_term(const char** memaddr, int is_indirect, rc_parse_state_t* parse) {
|
||||
rc_term_t* self;
|
||||
const char* aux;
|
||||
char size;
|
||||
int ret2;
|
||||
|
||||
aux = *memaddr;
|
||||
self = RC_ALLOC(rc_term_t, parse);
|
||||
self->invert = 0;
|
||||
|
||||
ret2 = rc_parse_operand(&self->operand1, &aux, 0, is_indirect, parse);
|
||||
|
||||
if (ret2 < 0) {
|
||||
parse->offset = ret2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*aux == '*') {
|
||||
aux++;
|
||||
|
||||
if (*aux == '~') {
|
||||
aux++;
|
||||
self->invert = 1;
|
||||
}
|
||||
|
||||
ret2 = rc_parse_operand(&self->operand2, &aux, 0, is_indirect, parse);
|
||||
|
||||
if (ret2 < 0) {
|
||||
parse->offset = ret2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (self->invert) {
|
||||
switch (self->operand2.type) {
|
||||
case RC_OPERAND_ADDRESS:
|
||||
case RC_OPERAND_DELTA:
|
||||
case RC_OPERAND_PRIOR:
|
||||
size = self->operand2.value.memref->memref.size;
|
||||
break;
|
||||
default:
|
||||
size = RC_MEMSIZE_32_BITS;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (size) {
|
||||
case RC_MEMSIZE_BIT_0:
|
||||
case RC_MEMSIZE_BIT_1:
|
||||
case RC_MEMSIZE_BIT_2:
|
||||
case RC_MEMSIZE_BIT_3:
|
||||
case RC_MEMSIZE_BIT_4:
|
||||
case RC_MEMSIZE_BIT_5:
|
||||
case RC_MEMSIZE_BIT_6:
|
||||
case RC_MEMSIZE_BIT_7:
|
||||
/* invert is already 1 */
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_LOW:
|
||||
case RC_MEMSIZE_HIGH:
|
||||
self->invert = 0xf;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_8_BITS:
|
||||
self->invert = 0xffU;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_16_BITS:
|
||||
self->invert = 0xffffU;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_24_BITS:
|
||||
self->invert = 0xffffffU;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_32_BITS:
|
||||
self->invert = 0xffffffffU;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
self->operand2.type = RC_OPERAND_CONST;
|
||||
self->operand2.value.num = 1;
|
||||
}
|
||||
|
||||
*memaddr = aux;
|
||||
return self;
|
||||
}
|
||||
|
||||
int rc_evaluate_term(rc_term_t* self, rc_eval_state_t* eval_state) {
|
||||
/* Operands are usually memory references and are always retrieved as unsigned. The floating
|
||||
* point operand is signed, and will automatically make the result signed. Otherwise, multiply
|
||||
* by the secondary operand (which is usually 1) and cast to signed.
|
||||
*/
|
||||
unsigned value = rc_evaluate_operand(&self->operand1, eval_state);
|
||||
|
||||
if (self->operand2.type != RC_OPERAND_FP) {
|
||||
return (int)(value * (rc_evaluate_operand(&self->operand2, eval_state) ^ self->invert));
|
||||
}
|
||||
|
||||
return (int)((double)value * self->operand2.value.dbl);
|
||||
}
|
||||
Vendored
+46
-26
@@ -1,10 +1,7 @@
|
||||
#include "internal.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#if !defined( __CELLOS_LV2__) && !defined(__MWERKS__)
|
||||
#include <memory.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <string.h> /* memset */
|
||||
|
||||
void rc_parse_trigger_internal(rc_trigger_t* self, const char** memaddr, rc_parse_state_t* parse) {
|
||||
rc_condset_t** next;
|
||||
@@ -36,7 +33,7 @@ void rc_parse_trigger_internal(rc_trigger_t* self, const char** memaddr, rc_pars
|
||||
|
||||
next = &(*next)->next;
|
||||
}
|
||||
|
||||
|
||||
*next = 0;
|
||||
*memaddr = aux;
|
||||
|
||||
@@ -62,7 +59,7 @@ rc_trigger_t* rc_parse_trigger(void* buffer, const char* memaddr, lua_State* L,
|
||||
rc_trigger_t* self;
|
||||
rc_parse_state_t parse;
|
||||
rc_init_parse_state(&parse, buffer, L, funcs_ndx);
|
||||
|
||||
|
||||
self = RC_ALLOC(rc_trigger_t, &parse);
|
||||
rc_init_parse_state_memrefs(&parse, &self->memrefs);
|
||||
|
||||
@@ -92,14 +89,15 @@ int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State*
|
||||
rc_condset_t* condset;
|
||||
int ret;
|
||||
char is_paused;
|
||||
char is_primed;
|
||||
|
||||
/* previously triggered, do nothing - return INACTIVE so caller doesn't report a repeated trigger */
|
||||
if (self->state == RC_TRIGGER_STATE_TRIGGERED)
|
||||
return RC_TRIGGER_STATE_INACTIVE;
|
||||
return RC_TRIGGER_STATE_INACTIVE;
|
||||
|
||||
rc_update_memref_values(self->memrefs, peek, ud);
|
||||
|
||||
/* not yet active, only update the memrefs - so deltas are corrent when it becomes active */
|
||||
/* not yet active, only update the memrefs - so deltas are correct when it becomes active */
|
||||
if (self->state == RC_TRIGGER_STATE_INACTIVE)
|
||||
return RC_TRIGGER_STATE_INACTIVE;
|
||||
|
||||
@@ -109,22 +107,41 @@ int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State*
|
||||
eval_state.peek_userdata = ud;
|
||||
eval_state.L = L;
|
||||
|
||||
ret = self->requirement != 0 ? rc_test_condset(self->requirement, &eval_state) : 1;
|
||||
condset = self->alternative;
|
||||
if (self->requirement != NULL) {
|
||||
ret = rc_test_condset(self->requirement, &eval_state);
|
||||
is_paused = self->requirement->is_paused;
|
||||
is_primed = eval_state.primed;
|
||||
} else {
|
||||
ret = 1;
|
||||
is_paused = 0;
|
||||
is_primed = 1;
|
||||
}
|
||||
|
||||
condset = self->alternative;
|
||||
if (condset) {
|
||||
int sub = 0;
|
||||
char sub_paused = 1;
|
||||
char sub_primed = 0;
|
||||
|
||||
do {
|
||||
sub |= rc_test_condset(condset, &eval_state);
|
||||
condset = condset->next;
|
||||
}
|
||||
while (condset != 0);
|
||||
sub_paused &= condset->is_paused;
|
||||
sub_primed |= eval_state.primed;
|
||||
|
||||
condset = condset->next;
|
||||
} while (condset != 0);
|
||||
|
||||
/* to trigger, the core must be true and at least one alt must be true */
|
||||
ret &= sub;
|
||||
is_primed &= sub_primed;
|
||||
|
||||
/* if the core is not paused, all alts must be paused to count as a paused trigger */
|
||||
is_paused |= sub_paused;
|
||||
}
|
||||
|
||||
self->measured_value = eval_state.measured_value;
|
||||
/* if paused, the measured value may not be captured, keep the old value */
|
||||
if (!is_paused)
|
||||
self->measured_value = eval_state.measured_value;
|
||||
|
||||
/* if the state is WAITING and the trigger is ready to fire, ignore it and reset the hit counts */
|
||||
/* otherwise, if the state is WAITING, proceed to activating the trigger */
|
||||
@@ -138,6 +155,10 @@ int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State*
|
||||
/* if any ResetIf condition was true, reset the hit counts */
|
||||
rc_reset_trigger_hitcounts(self);
|
||||
|
||||
/* if the measured value came from a hit count, reset it too */
|
||||
if (eval_state.measured_from_hits)
|
||||
self->measured_value = 0;
|
||||
|
||||
/* if there were hit counts to clear, return RESET, but don't change the state */
|
||||
if (self->has_hits) {
|
||||
self->has_hits = 0;
|
||||
@@ -146,6 +167,7 @@ int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State*
|
||||
|
||||
/* any hits that were tallied were just reset */
|
||||
eval_state.has_hits = 0;
|
||||
is_primed = 0;
|
||||
}
|
||||
else if (ret) {
|
||||
/* trigger was triggered */
|
||||
@@ -156,20 +178,16 @@ int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State*
|
||||
/* did not trigger this frame - update the information we'll need for next time */
|
||||
self->has_hits = eval_state.has_hits;
|
||||
|
||||
/* check to see if the trigger is paused */
|
||||
is_paused = (self->requirement != NULL) ? self->requirement->is_paused : 0;
|
||||
if (!is_paused) {
|
||||
/* if the core is not paused, all alts must be paused to count as a paused trigger */
|
||||
is_paused = (self->alternative != NULL);
|
||||
for (condset = self->alternative; condset != NULL; condset = condset->next) {
|
||||
if (!condset->is_paused) {
|
||||
is_paused = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_paused) {
|
||||
self->state = RC_TRIGGER_STATE_PAUSED;
|
||||
}
|
||||
else if (is_primed) {
|
||||
self->state = RC_TRIGGER_STATE_PRIMED;
|
||||
}
|
||||
else {
|
||||
self->state = RC_TRIGGER_STATE_ACTIVE;
|
||||
}
|
||||
|
||||
self->state = is_paused ? RC_TRIGGER_STATE_PAUSED : RC_TRIGGER_STATE_ACTIVE;
|
||||
return self->state;
|
||||
}
|
||||
|
||||
@@ -184,4 +202,6 @@ void rc_reset_trigger(rc_trigger_t* self) {
|
||||
rc_reset_trigger_hitcounts(self);
|
||||
|
||||
self->state = RC_TRIGGER_STATE_WAITING;
|
||||
self->measured_value = 0;
|
||||
self->has_hits = 0;
|
||||
}
|
||||
Vendored
+120
-49
@@ -1,9 +1,7 @@
|
||||
#include "internal.h"
|
||||
|
||||
#if !defined( __CELLOS_LV2__) && !defined(__MWERKS__)
|
||||
#include <memory.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <string.h> /* memset */
|
||||
#include <ctype.h> /* isdigit */
|
||||
|
||||
static void rc_parse_cond_value(rc_value_t* self, const char** memaddr, rc_parse_state_t* parse) {
|
||||
rc_condition_t** next;
|
||||
@@ -12,12 +10,10 @@ static void rc_parse_cond_value(rc_value_t* self, const char** memaddr, rc_parse
|
||||
|
||||
has_measured = 0;
|
||||
in_add_address = 0;
|
||||
self->expressions = 0;
|
||||
|
||||
/* this largely duplicates rc_parse_condset, but we cannot call it directly, as we need to check the
|
||||
/* this largely duplicates rc_parse_condset, but we cannot call it directly, as we need to check the
|
||||
* type of each condition as we go */
|
||||
self->conditions = RC_ALLOC(rc_condset_t, parse);
|
||||
self->conditions->next = 0;
|
||||
self->conditions->has_pause = 0;
|
||||
|
||||
next = &self->conditions->conditions;
|
||||
@@ -49,7 +45,7 @@ static void rc_parse_cond_value(rc_value_t* self, const char** memaddr, rc_parse
|
||||
return;
|
||||
}
|
||||
has_measured = 1;
|
||||
if ((*next)->required_hits == 0 && (*next)->oper != RC_CONDITION_NONE)
|
||||
if ((*next)->required_hits == 0 && (*next)->oper != RC_OPERATOR_NONE)
|
||||
(*next)->required_hits = (unsigned)-1;
|
||||
break;
|
||||
|
||||
@@ -69,42 +65,125 @@ static void rc_parse_cond_value(rc_value_t* self, const char** memaddr, rc_parse
|
||||
(*memaddr)++;
|
||||
}
|
||||
|
||||
*next = 0;
|
||||
|
||||
if (!has_measured) {
|
||||
parse->offset = RC_MISSING_VALUE_MEASURED;
|
||||
}
|
||||
|
||||
if (parse->buffer) {
|
||||
*next = 0;
|
||||
self->conditions->next = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void rc_parse_value_internal(rc_value_t* self, const char** memaddr, rc_parse_state_t* parse) {
|
||||
rc_expression_t** next;
|
||||
void rc_parse_legacy_value(rc_value_t* self, const char** memaddr, rc_parse_state_t* parse) {
|
||||
rc_condition_t** next;
|
||||
rc_condset_t** next_clause;
|
||||
rc_condition_t* cond;
|
||||
char buffer[64] = "A:";
|
||||
const char* buffer_ptr;
|
||||
char* ptr;
|
||||
int end_of_clause;
|
||||
|
||||
/* if it starts with a condition flag (M: A: B: C:), parse the conditions */
|
||||
if ((*memaddr)[1] == ':') {
|
||||
rc_parse_cond_value(self, memaddr, parse);
|
||||
return;
|
||||
}
|
||||
/* convert legacy format into condset */
|
||||
self->conditions = RC_ALLOC(rc_condset_t, parse);
|
||||
self->conditions->has_pause = 0;
|
||||
|
||||
self->conditions = 0;
|
||||
next = &self->expressions;
|
||||
next = &self->conditions->conditions;
|
||||
next_clause = &self->conditions->next;
|
||||
|
||||
for (;;) {
|
||||
*next = rc_parse_expression(memaddr, parse);
|
||||
ptr = &buffer[2];
|
||||
end_of_clause = 0;
|
||||
|
||||
do {
|
||||
switch (**memaddr) {
|
||||
case '_': /* add next */
|
||||
case '$': /* maximum of */
|
||||
case '\0': /* end of string */
|
||||
case ':': /* end of leaderboard clause */
|
||||
case ')': /* end of rich presence macro */
|
||||
end_of_clause = 1;
|
||||
*ptr = '\0';
|
||||
break;
|
||||
|
||||
case '*':
|
||||
*ptr++ = '*';
|
||||
|
||||
buffer_ptr = *memaddr + 1;
|
||||
if (*buffer_ptr == '-') {
|
||||
/* negative value automatically needs prefix, 'f' handles both float and digits, so use it */
|
||||
*ptr++ = 'f';
|
||||
}
|
||||
else {
|
||||
/* if it looks like a floating point number, add the 'f' prefix */
|
||||
while (isdigit(*buffer_ptr))
|
||||
++buffer_ptr;
|
||||
if (*buffer_ptr == '.')
|
||||
*ptr++ = 'f';
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
*ptr++ = **memaddr;
|
||||
break;
|
||||
}
|
||||
|
||||
++(*memaddr);
|
||||
} while (!end_of_clause);
|
||||
|
||||
buffer_ptr = buffer;
|
||||
cond = rc_parse_condition(&buffer_ptr, parse, 0);
|
||||
if (parse->offset < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
next = &(*next)->next;
|
||||
switch (cond->oper) {
|
||||
case RC_OPERATOR_MULT:
|
||||
case RC_OPERATOR_DIV:
|
||||
case RC_OPERATOR_AND:
|
||||
case RC_OPERATOR_NONE:
|
||||
break;
|
||||
|
||||
if (**memaddr != '$') {
|
||||
break;
|
||||
default:
|
||||
parse->offset = RC_INVALID_OPERATOR;
|
||||
return;
|
||||
}
|
||||
|
||||
(*memaddr)++;
|
||||
}
|
||||
cond->pause = 0;
|
||||
*next = cond;
|
||||
|
||||
*next = 0;
|
||||
switch ((*memaddr)[-1]) {
|
||||
case '_': /* add next */
|
||||
next = &cond->next;
|
||||
break;
|
||||
|
||||
case '$': /* max of */
|
||||
cond->type = RC_CONDITION_MEASURED;
|
||||
cond->next = 0;
|
||||
*next_clause = RC_ALLOC(rc_condset_t, parse);
|
||||
(*next_clause)->has_pause = 0;
|
||||
next = &(*next_clause)->conditions;
|
||||
next_clause = &(*next_clause)->next;
|
||||
break;
|
||||
|
||||
default: /* end of valid string */
|
||||
--(*memaddr); /* undo the increment we performed when copying the string */
|
||||
cond->type = RC_CONDITION_MEASURED;
|
||||
cond->next = 0;
|
||||
*next_clause = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rc_parse_value_internal(rc_value_t* self, const char** memaddr, rc_parse_state_t* parse) {
|
||||
/* if it starts with a condition flag (M: A: B: C:), parse the conditions */
|
||||
if ((*memaddr)[1] == ':') {
|
||||
rc_parse_cond_value(self, memaddr, parse);
|
||||
}
|
||||
else {
|
||||
rc_parse_legacy_value(self, memaddr, parse);
|
||||
}
|
||||
}
|
||||
|
||||
int rc_value_size(const char* memaddr) {
|
||||
@@ -123,7 +202,7 @@ rc_value_t* rc_parse_value(void* buffer, const char* memaddr, lua_State* L, int
|
||||
rc_value_t* self;
|
||||
rc_parse_state_t parse;
|
||||
rc_init_parse_state(&parse, buffer, L, funcs_ndx);
|
||||
|
||||
|
||||
self = RC_ALLOC(rc_value_t, &parse);
|
||||
rc_init_parse_state_memrefs(&parse, &self->memrefs);
|
||||
|
||||
@@ -133,26 +212,11 @@ rc_value_t* rc_parse_value(void* buffer, const char* memaddr, lua_State* L, int
|
||||
return parse.offset >= 0 ? self : 0;
|
||||
}
|
||||
|
||||
static int rc_evaluate_expr_value(rc_value_t* self, rc_eval_state_t* eval_state) {
|
||||
rc_expression_t* exp;
|
||||
int value, max;
|
||||
|
||||
exp = self->expressions;
|
||||
max = rc_evaluate_expression(exp, eval_state);
|
||||
|
||||
for (exp = exp->next; exp != 0; exp = exp->next) {
|
||||
value = rc_evaluate_expression(exp, eval_state);
|
||||
|
||||
if (value > max) {
|
||||
max = value;
|
||||
}
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
int rc_evaluate_value(rc_value_t* self, rc_peek_t peek, void* ud, lua_State* L) {
|
||||
rc_eval_state_t eval_state;
|
||||
rc_condset_t* condset;
|
||||
int result = 0;
|
||||
|
||||
memset(&eval_state, 0, sizeof(eval_state));
|
||||
eval_state.peek = peek;
|
||||
eval_state.peek_userdata = ud;
|
||||
@@ -160,10 +224,17 @@ int rc_evaluate_value(rc_value_t* self, rc_peek_t peek, void* ud, lua_State* L)
|
||||
|
||||
rc_update_memref_values(self->memrefs, peek, ud);
|
||||
|
||||
if (self->expressions) {
|
||||
return rc_evaluate_expr_value(self, &eval_state);
|
||||
rc_test_condset(self->conditions, &eval_state);
|
||||
result = (int)eval_state.measured_value;
|
||||
|
||||
condset = self->conditions->next;
|
||||
while (condset != NULL) {
|
||||
rc_test_condset(condset, &eval_state);
|
||||
if ((int)eval_state.measured_value > result)
|
||||
result = (int)eval_state.measured_value;
|
||||
|
||||
condset = condset->next;
|
||||
}
|
||||
|
||||
rc_test_condset(self->conditions, &eval_state);
|
||||
return (int)eval_state.measured_value;
|
||||
return result;
|
||||
}
|
||||
Vendored
+1491
File diff suppressed because it is too large.
Load diff
Vendored
+18
@@ -0,0 +1,18 @@
|
||||
#ifndef RC_MD5_H
|
||||
#define RC_MD5_H
|
||||
|
||||
/* NOTE: this is NOT the md5.h included in the rcheevos repository. It provides the same
|
||||
* functionality using code already present in RetroArch */
|
||||
|
||||
/* android build has libretro-common/include in path, but not the base directory.
|
||||
* other builds prioritize rcheevos/include over libretro-common/include.
|
||||
* to ensure we get the correct include file, use a complicated relative path */
|
||||
#include <../../../libretro-common/include/rhash.h>
|
||||
|
||||
#define md5_state_t MD5_CTX
|
||||
#define md5_byte_t unsigned char
|
||||
#define md5_init(state) MD5_Init(state)
|
||||
#define md5_append(state, buffer, size) MD5_Update(state, buffer, size)
|
||||
#define md5_finish(state, hash) MD5_Final(hash, state)
|
||||
|
||||
#endif
|
||||
Vendored
+153
-50
@@ -1,15 +1,7 @@
|
||||
#include "rurl.h"
|
||||
|
||||
#ifdef RARCH_INTERNAL
|
||||
#include <rhash.h> /* libretro-common/include/rhash.h */
|
||||
#define md5_state_t MD5_CTX
|
||||
#define md5_byte_t unsigned char
|
||||
#define md5_init(state) MD5_Init(state)
|
||||
#define md5_append(state, buffer, size) MD5_Update(state, buffer, size)
|
||||
#define md5_finish(state, hash) MD5_Final(hash, state)
|
||||
#else
|
||||
#include "..\rhash\md5.h"
|
||||
#endif
|
||||
#include "../rcheevos/compat.h"
|
||||
#include "../rhash/md5.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -25,37 +17,41 @@ static int rc_url_encode(char* encoded, size_t len, const char* str) {
|
||||
case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
|
||||
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
|
||||
case '-': case '_': case '.': case '~':
|
||||
if (len >= 2) {
|
||||
*encoded++ = *str++;
|
||||
len--;
|
||||
}
|
||||
else {
|
||||
if (len < 2)
|
||||
return -1;
|
||||
}
|
||||
|
||||
*encoded++ = *str++;
|
||||
--len;
|
||||
break;
|
||||
|
||||
|
||||
case ' ':
|
||||
if (len < 2)
|
||||
return -1;
|
||||
|
||||
*encoded++ = '+';
|
||||
++str;
|
||||
--len;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (len >= 4) {
|
||||
snprintf(encoded, len, "%%%02x", (unsigned char)*str);
|
||||
encoded += 3;
|
||||
str++;
|
||||
len -= 3;
|
||||
}
|
||||
else {
|
||||
if (len < 4)
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(encoded, len, "%%%02x", (unsigned char)*str);
|
||||
encoded += 3;
|
||||
++str;
|
||||
len -= 3;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
|
||||
case '\0':
|
||||
*encoded = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int rc_url_award_cheevo(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned cheevo_id, int hardcore) {
|
||||
int rc_url_award_cheevo(char* buffer, size_t size, const char* user_name, const char* login_token,
|
||||
unsigned cheevo_id, int hardcore, const char* game_hash) {
|
||||
char urle_user_name[64];
|
||||
char urle_login_token[64];
|
||||
int written;
|
||||
@@ -63,11 +59,11 @@ int rc_url_award_cheevo(char* buffer, size_t size, const char* user_name, const
|
||||
if (rc_url_encode(urle_user_name, sizeof(urle_user_name), user_name) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (rc_url_encode(urle_login_token, sizeof(urle_login_token), login_token) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
written = snprintf(
|
||||
buffer,
|
||||
size,
|
||||
@@ -78,10 +74,14 @@ int rc_url_award_cheevo(char* buffer, size_t size, const char* user_name, const
|
||||
hardcore ? 1 : 0
|
||||
);
|
||||
|
||||
if (game_hash && strlen(game_hash) == 32 && (size - (size_t)written) >= 35) {
|
||||
written += snprintf(buffer + written, size - (size_t)written, "&m=%s", game_hash);
|
||||
}
|
||||
|
||||
return (size_t)written >= size ? -1 : 0;
|
||||
}
|
||||
|
||||
int rc_url_submit_lboard(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned lboard_id, int value, const char* game_hash) {
|
||||
int rc_url_submit_lboard(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned lboard_id, int value) {
|
||||
char urle_user_name[64];
|
||||
char urle_login_token[64];
|
||||
char signature[64];
|
||||
@@ -92,7 +92,7 @@ int rc_url_submit_lboard(char* buffer, size_t size, const char* user_name, const
|
||||
if (rc_url_encode(urle_user_name, sizeof(urle_user_name), user_name) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (rc_url_encode(urle_login_token, sizeof(urle_login_token), login_token) != 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -115,20 +115,15 @@ int rc_url_submit_lboard(char* buffer, size_t size, const char* user_name, const
|
||||
hash[ 8], hash[ 9], hash[10], hash[11],hash[12], hash[13], hash[14], hash[15]
|
||||
);
|
||||
|
||||
if (game_hash && strlen(game_hash) == 32 && (size - (size_t)written) >= 35) {
|
||||
written += snprintf(buffer + written, size - (size_t)written, "&m=%s", game_hash);
|
||||
}
|
||||
|
||||
return (size_t)written >= size ? -1 : 0;
|
||||
}
|
||||
|
||||
int rc_url_get_gameid(char* buffer, size_t size, unsigned char hash[16]) {
|
||||
int rc_url_get_gameid(char* buffer, size_t size, const char* hash) {
|
||||
int written = snprintf(
|
||||
buffer,
|
||||
size,
|
||||
"http://retroachievements.org/dorequest.php?r=gameid&m=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
hash[ 0], hash[ 1], hash[ 2], hash[ 3], hash[ 4], hash[ 5], hash[ 6], hash[ 7],
|
||||
hash[ 8], hash[ 9], hash[10], hash[11],hash[12], hash[13], hash[14], hash[15]
|
||||
"http://retroachievements.org/dorequest.php?r=gameid&m=%s",
|
||||
hash
|
||||
);
|
||||
|
||||
return (size_t)written >= size ? -1 : 0;
|
||||
@@ -142,11 +137,11 @@ int rc_url_get_patch(char* buffer, size_t size, const char* user_name, const cha
|
||||
if (rc_url_encode(urle_user_name, sizeof(urle_user_name), user_name) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (rc_url_encode(urle_login_token, sizeof(urle_login_token), login_token) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
written = snprintf(
|
||||
buffer,
|
||||
size,
|
||||
@@ -178,11 +173,11 @@ int rc_url_login_with_password(char* buffer, size_t size, const char* user_name,
|
||||
if (rc_url_encode(urle_user_name, sizeof(urle_user_name), user_name) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (rc_url_encode(urle_password, sizeof(urle_password), password) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
written = snprintf(
|
||||
buffer,
|
||||
size,
|
||||
@@ -202,11 +197,11 @@ int rc_url_login_with_token(char* buffer, size_t size, const char* user_name, co
|
||||
if (rc_url_encode(urle_user_name, sizeof(urle_user_name), user_name) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (rc_url_encode(urle_login_token, sizeof(urle_login_token), login_token) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
written = snprintf(
|
||||
buffer,
|
||||
size,
|
||||
@@ -226,11 +221,11 @@ int rc_url_get_unlock_list(char* buffer, size_t size, const char* user_name, con
|
||||
if (rc_url_encode(urle_user_name, sizeof(urle_user_name), user_name) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (rc_url_encode(urle_login_token, sizeof(urle_login_token), login_token) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
written = snprintf(
|
||||
buffer,
|
||||
size,
|
||||
@@ -252,11 +247,11 @@ int rc_url_post_playing(char* buffer, size_t size, const char* user_name, const
|
||||
if (rc_url_encode(urle_user_name, sizeof(urle_user_name), user_name) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (rc_url_encode(urle_login_token, sizeof(urle_login_token), login_token) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
written = snprintf(
|
||||
buffer,
|
||||
size,
|
||||
@@ -268,3 +263,111 @@ int rc_url_post_playing(char* buffer, size_t size, const char* user_name, const
|
||||
|
||||
return (size_t)written >= size ? -1 : 0;
|
||||
}
|
||||
|
||||
static int rc_url_append_param_equals(char* buffer, size_t buffer_size, size_t buffer_offset, const char* param)
|
||||
{
|
||||
int written = 0;
|
||||
size_t param_len;
|
||||
|
||||
if (buffer_offset >= buffer_size)
|
||||
return -1;
|
||||
|
||||
if (buffer_offset) {
|
||||
buffer += buffer_offset;
|
||||
buffer_size -= buffer_offset;
|
||||
|
||||
if (buffer[-1] != '?') {
|
||||
*buffer++ = '&';
|
||||
buffer_size--;
|
||||
written = 1;
|
||||
}
|
||||
}
|
||||
|
||||
param_len = strlen(param);
|
||||
if (param_len + 1 >= buffer_size)
|
||||
return -1;
|
||||
memcpy(buffer, param, param_len);
|
||||
buffer[param_len] = '=';
|
||||
|
||||
written += (int)param_len + 1;
|
||||
return written + (int)buffer_offset;
|
||||
}
|
||||
|
||||
static int rc_url_append_unum(char* buffer, size_t buffer_size, size_t* buffer_offset, const char* param, unsigned value)
|
||||
{
|
||||
int written = rc_url_append_param_equals(buffer, buffer_size, *buffer_offset, param);
|
||||
if (written > 0) {
|
||||
char num[16];
|
||||
int chars = sprintf(num, "%u", value);
|
||||
|
||||
if (chars + written < (int)buffer_size)
|
||||
{
|
||||
memcpy(&buffer[written], num, chars + 1);
|
||||
*buffer_offset = written + chars;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int rc_url_append_str(char* buffer, size_t buffer_size, size_t* buffer_offset, const char* param, const char* value)
|
||||
{
|
||||
int written = rc_url_append_param_equals(buffer, buffer_size, *buffer_offset, param);
|
||||
if (written > 0)
|
||||
{
|
||||
buffer += written;
|
||||
buffer_size -= written;
|
||||
|
||||
if (rc_url_encode(buffer, buffer_size, value) == 0)
|
||||
{
|
||||
written += (int)strlen(buffer);
|
||||
*buffer_offset = written;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int rc_url_build_dorequest(char* url_buffer, size_t url_buffer_size, size_t* buffer_offset,
|
||||
const char* api, const char* user_name)
|
||||
{
|
||||
const char* base_url = "http://retroachievements.org/dorequest.php";
|
||||
size_t written = strlen(base_url);
|
||||
int failure = 0;
|
||||
|
||||
if (url_buffer_size < written + 1)
|
||||
return -1;
|
||||
memcpy(url_buffer, base_url, written);
|
||||
url_buffer[written++] = '?';
|
||||
|
||||
failure |= rc_url_append_str(url_buffer, url_buffer_size, &written, "r", api);
|
||||
failure |= rc_url_append_str(url_buffer, url_buffer_size, &written, "u", user_name);
|
||||
|
||||
*buffer_offset += written;
|
||||
return failure;
|
||||
}
|
||||
|
||||
int rc_url_ping(char* url_buffer, size_t url_buffer_size, char* post_buffer, size_t post_buffer_size,
|
||||
const char* user_name, const char* login_token, unsigned gameid, const char* rich_presence)
|
||||
{
|
||||
size_t written = 0;
|
||||
int failure = rc_url_build_dorequest(url_buffer, url_buffer_size, &written, "ping", user_name);
|
||||
failure |= rc_url_append_unum(url_buffer, url_buffer_size, &written, "g", gameid);
|
||||
|
||||
written = 0;
|
||||
failure |= rc_url_append_str(post_buffer, post_buffer_size, &written, "t", login_token);
|
||||
|
||||
if (rich_presence && *rich_presence)
|
||||
failure |= rc_url_append_str(post_buffer, post_buffer_size, &written, "m", rich_presence);
|
||||
|
||||
if (failure) {
|
||||
if (url_buffer_size)
|
||||
url_buffer[0] = '\0';
|
||||
if (post_buffer_size)
|
||||
post_buffer[0] = '\0';
|
||||
}
|
||||
|
||||
return failure;
|
||||
}
|
||||
Vendored
+1
@@ -812,6 +812,7 @@ enum
|
||||
#endif /* __STB_INCLUDE_STB_TRUETYPE_H__ */
|
||||
|
||||
#include <retro_assert.h>
|
||||
#include <retro_endianness.h>
|
||||
|
||||
/* IMPLEMENTATION */
|
||||
|
||||
|
||||
@@ -125,6 +125,11 @@ EXE_PATH=${CELL_SDK}/host-win32/bin
|
||||
GENPS3ISO_PATH=${PS3TOOLS_PATH}/ODE/genps3iso_v2.5
|
||||
SCETOOL_PATH=${PS3TOOLS_PATH}/scetool/scetool.exe
|
||||
SCETOOL_FLAGS_ODE="--sce-type=SELF --compress-data=TRUE --self-type=APP --key-revision=04 --self-fw-version=0003004100000000 --self-app-version=0001000000000000 --self-auth-id=1010000001000003 --self-vendor-id=01000002 --self-cap-flags=00000000000000000000000000000000000000000000003b0000000100040000 --encrypt"
|
||||
elif [ $PLATFORM = "dos" ]; then
|
||||
platform=dos
|
||||
MAKEFILE_GRIFFIN=yes
|
||||
EXT=a
|
||||
SALAMANDER=yes
|
||||
fi
|
||||
|
||||
# Cleanup Salamander core if it exists
|
||||
@@ -149,6 +154,10 @@ if [ $SALAMANDER = "yes" ]; then
|
||||
if [ $PLATFORM = "psp1" ] ; then
|
||||
mv -f ../EBOOT.PBP ../pkg/${platform}/EBOOT.PBP
|
||||
fi
|
||||
if [ $platform = "dos" ] ; then
|
||||
mkdir -p ../pkg/${platform}
|
||||
mv -f ../retrodos_salamander.exe ../pkg/${platform}/RETRODOS.EXE
|
||||
fi
|
||||
if [ $PLATFORM = "vita" ] ; then
|
||||
mkdir -p ../pkg/${platform}/retroarch.vpk/vpk/sce_sys/livearea/contents
|
||||
vita-make-fself -c -s ../retroarchvita_salamander.velf ../pkg/${platform}/retroarch.vpk/vpk/eboot.bin
|
||||
@@ -260,8 +269,8 @@ for f in `ls -v *_${platform}.${EXT}`; do
|
||||
if [ $platform = "psl1ght" ] ; then
|
||||
mv -fv ../retroarch_psl1ght.self ../pkg/psl1ght/pkg/USRDIR/cores/"${name}_libretro_${platform}.SELF"
|
||||
if [ -d ../../dist/info ]; then
|
||||
mkdir -p ../pkg/psl1ght/USRDIR/cores/info
|
||||
cp -fv ../../dist/info/"${name}_libretro.info" ../pkg/psl1ght/USRDIR/pkg/cores/info/"${name}_libretro.info"
|
||||
mkdir -p ../pkg/psl1ght/pkg/USRDIR/cores/info
|
||||
cp -fv ../../dist/info/"${name}_libretro.info" ../pkg/psl1ght/pkg/USRDIR/cores/info/"${name}_libretro.info"
|
||||
fi
|
||||
elif [ $platform = "ps3" ] ; then
|
||||
if [ $PLATFORM = "ode-ps3" ] ; then
|
||||
@@ -301,7 +310,10 @@ for f in `ls -v *_${platform}.${EXT}`; do
|
||||
elif [ $PLATFORM = "ngc" ] ; then
|
||||
mv -f ../retroarch_${platform}.dol ../pkg/${platform}/${name}_libretro_${platform}.dol
|
||||
elif [ $PLATFORM = "wii" ] ; then
|
||||
mv -f ../retroarch_${platform}.dol ../pkg/${platform}/${name}_libretro_${platform}.dol
|
||||
mv -f ../retroarch_${platform}.dol ../pkg/${platform}/${name}_libretro_${platform}.dol
|
||||
elif [ $PLATFORM = "dos" ] ; then
|
||||
mkdir -p ../pkg/${platform}/cores
|
||||
mv -f ../retrodos.exe ../pkg/${platform}/cores/${name}.exe
|
||||
elif [ $PLATFORM = "emscripten" ] ; then
|
||||
mkdir -p ../pkg/emscripten/
|
||||
mv -f ../${name}_libretro.js ../pkg/emscripten/${name}_libretro.js
|
||||
@@ -428,7 +440,7 @@ elif [ $PLATFORM = "cex-ps3" ] ; then
|
||||
find ../tools/ps3/ps3py/build -name '*.dll' -exec cp {} ../tools/ps3/ps3py \;
|
||||
../tools/ps3/ps3py/pkg.py --contentid UP0001-SSNE10000_00-0000000000000001 ../pkg/${platform}/SSNE10000/ ../pkg/${platform}/RetroArch.PS3.CEX.PS3.pkg
|
||||
elif [ $PLATFORM = "psl1ght" ] ; then
|
||||
pkg.py --contentid UP0001-SSNE10001_00-0000000000000001 ../pkg/psl1ght/pkg/ ../pkg/psl1ght/RetroArch.PSL1GHT.pkg
|
||||
${PS3DEV}/bin/pkg.py --contentid UP0001-SSNE10001_00-0000000000000001 ../pkg/psl1ght/pkg/ ../pkg/psl1ght/RetroArch.PSL1GHT.pkg
|
||||
elif [ $PLATFORM = "ode-ps3" ] ; then
|
||||
rsync -av ../pkg/${platform}_iso/PS3_GAME/USRDIR/cores/*.SELF ../pkg/${platform}/${PLATFORM}/
|
||||
$SCETOOL_PATH $SCETOOL_FLAGS_ODE ../retroarch-salamander_${platform}.elf ../pkg/${platform}_iso/PS3_GAME/USRDIR/EBOOT.BIN
|
||||
|
||||
@@ -414,53 +414,3 @@ void fill_pathname_application_special(char *s,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fill_short_pathname_representation:
|
||||
* @out_rep : output representation
|
||||
* @in_path : input path
|
||||
* @size : size of output representation
|
||||
*
|
||||
* Generates a short representation of path. It should only
|
||||
* be used for displaying the result; the output representation is not
|
||||
* binding in any meaningful way (for a normal path, this is the same as basename)
|
||||
* In case of more complex URLs, this should cut everything except for
|
||||
* the main image file.
|
||||
*
|
||||
* E.g.: "/path/to/game.img" -> game.img
|
||||
* "/path/to/myarchive.7z#folder/to/game.img" -> game.img
|
||||
*/
|
||||
void fill_short_pathname_representation_wrapper(char* out_rep,
|
||||
const char *in_path, size_t size)
|
||||
{
|
||||
#ifdef HAVE_COMPRESSION
|
||||
char *path_short = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
|
||||
char *last_slash = NULL;
|
||||
|
||||
path_short[0] = '\0';
|
||||
|
||||
fill_pathname(path_short, path_basename(in_path), "",
|
||||
PATH_MAX_LENGTH * sizeof(char)
|
||||
);
|
||||
|
||||
last_slash = find_last_slash(path_short);
|
||||
|
||||
if (last_slash != NULL)
|
||||
{
|
||||
/* We handle paths like:
|
||||
* /path/to/file.7z#mygame.img
|
||||
* short_name: mygame.img:
|
||||
*
|
||||
* We check whether something is actually
|
||||
* after the hash to avoid going over the buffer.
|
||||
*/
|
||||
strlcpy(out_rep, last_slash + 1, size);
|
||||
free(path_short);
|
||||
return;
|
||||
}
|
||||
|
||||
free(path_short);
|
||||
#endif
|
||||
|
||||
fill_short_pathname_representation(out_rep, in_path, size);
|
||||
}
|
||||
@@ -117,24 +117,6 @@ enum application_special_type
|
||||
APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_DISCORD_AVATARS
|
||||
};
|
||||
|
||||
/**
|
||||
* fill_short_pathname_representation:
|
||||
* @out_rep : output representation
|
||||
* @in_path : input path
|
||||
* @size : size of output representation
|
||||
*
|
||||
* Generates a short representation of path. It should only
|
||||
* be used for displaying the result; the output representation is not
|
||||
* binding in any meaningful way (for a normal path, this is the same as basename)
|
||||
* In case of more complex URLs, this should cut everything except for
|
||||
* the main image file.
|
||||
*
|
||||
* E.g.: "/path/to/game.img" -> game.img
|
||||
* "/path/to/myarchive.7z#folder/to/game.img" -> game.img
|
||||
*/
|
||||
void fill_short_pathname_representation_wrapper(char* out_rep,
|
||||
const char *in_path, size_t size);
|
||||
|
||||
const char *file_path_str(enum file_path_enum enum_idx);
|
||||
|
||||
bool fill_pathname_application_data(char *s, size_t len);
|
||||
|
||||
+170
-35
@@ -16,64 +16,199 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <process.h>
|
||||
#include <string/stdstring.h>
|
||||
#include <file/file_path.h>
|
||||
|
||||
#include "../frontend_driver.h"
|
||||
#include "../../defaults.h"
|
||||
|
||||
static enum frontend_fork dos_fork_mode = FRONTEND_FORK_NONE;
|
||||
|
||||
static void frontend_dos_init(void *data)
|
||||
{
|
||||
printf("Loading RetroArch...\n");
|
||||
printf("Loading RetroArch...\n");
|
||||
}
|
||||
|
||||
static void frontend_dos_shutdown(bool unused)
|
||||
{
|
||||
(void)unused;
|
||||
(void)unused;
|
||||
}
|
||||
|
||||
static int frontend_dos_get_rating(void)
|
||||
{
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
enum frontend_architecture frontend_dos_get_architecture(void)
|
||||
{
|
||||
return FRONTEND_ARCH_X86;
|
||||
return FRONTEND_ARCH_X86;
|
||||
}
|
||||
|
||||
static void frontend_dos_get_env_settings(int *argc, char *argv[],
|
||||
void *data, void *params_data)
|
||||
{
|
||||
char base_path[PATH_MAX] = {0};
|
||||
int i;
|
||||
|
||||
retro_main_log_file_init("retrodos.txt", false);
|
||||
|
||||
strlcpy(base_path, argv[0], sizeof(base_path));
|
||||
char *slash = strrchr(base_path, '/');
|
||||
if (slash)
|
||||
*slash = '\0';
|
||||
slash = strrchr(base_path, '/');
|
||||
if (slash && strcasecmp(slash, "/cores"))
|
||||
*slash = '\0';
|
||||
|
||||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE], base_path,
|
||||
"cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE]));
|
||||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_INFO], base_path,
|
||||
"coreinfo", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO]));
|
||||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG], base_path,
|
||||
"autoconf", sizeof(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG]));
|
||||
|
||||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS], base_path,
|
||||
"assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
|
||||
|
||||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG], base_path,
|
||||
"config", sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG]));
|
||||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_REMAP],
|
||||
g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG],
|
||||
"remaps", sizeof(g_defaults.dirs[DEFAULT_DIR_REMAP]));
|
||||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_PLAYLIST], base_path,
|
||||
"playlist", sizeof(g_defaults.dirs[DEFAULT_DIR_PLAYLIST]));
|
||||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_RECORD_CONFIG], base_path,
|
||||
"recrdcfg", sizeof(g_defaults.dirs[DEFAULT_DIR_RECORD_CONFIG]));
|
||||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_RECORD_OUTPUT], base_path,
|
||||
"records", sizeof(g_defaults.dirs[DEFAULT_DIR_RECORD_OUTPUT]));
|
||||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CURSOR], base_path,
|
||||
"database/cursors", sizeof(g_defaults.dirs[DEFAULT_DIR_CURSOR]));
|
||||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_DATABASE], base_path,
|
||||
"database/rdb", sizeof(g_defaults.dirs[DEFAULT_DIR_DATABASE]));
|
||||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SHADER], base_path,
|
||||
"shaders", sizeof(g_defaults.dirs[DEFAULT_DIR_SHADER]));
|
||||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CHEATS], base_path,
|
||||
"cheats", sizeof(g_defaults.dirs[DEFAULT_DIR_CHEATS]));
|
||||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_OVERLAY], base_path,
|
||||
"overlay", sizeof(g_defaults.dirs[DEFAULT_DIR_OVERLAY]));
|
||||
#ifdef HAVE_VIDEO_LAYOUT
|
||||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_LAYOUT], base_path,
|
||||
"layouts", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_LAYOUT]));
|
||||
#endif
|
||||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], base_path,
|
||||
"download", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS]));
|
||||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT], base_path,
|
||||
"scrnshot", sizeof(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT]));
|
||||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_THUMBNAILS], base_path,
|
||||
"thumbs", sizeof(g_defaults.dirs[DEFAULT_DIR_THUMBNAILS]));
|
||||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_LOGS], base_path,
|
||||
"logs", sizeof(g_defaults.dirs[DEFAULT_DIR_LOGS]));
|
||||
|
||||
for (i = 0; i < DEFAULT_DIR_LAST; i++)
|
||||
{
|
||||
const char *dir_path = g_defaults.dirs[i];
|
||||
if (!string_is_empty(dir_path))
|
||||
path_mkdir(dir_path);
|
||||
}
|
||||
}
|
||||
|
||||
static void frontend_dos_exec(const char *path, bool should_load_game)
|
||||
{
|
||||
printf("Loading %s, %d\n", path, should_load_game);
|
||||
|
||||
char *newargv[] = { NULL, NULL };
|
||||
size_t len = strlen(path);
|
||||
|
||||
newargv[0] = (char*)malloc(len);
|
||||
|
||||
strlcpy(newargv[0], path, len);
|
||||
|
||||
execv(path, newargv);
|
||||
}
|
||||
|
||||
static void frontend_dos_exitspawn(char *s, size_t len, char *args)
|
||||
{
|
||||
bool should_load_content = false;
|
||||
|
||||
if (dos_fork_mode == FRONTEND_FORK_NONE)
|
||||
return;
|
||||
|
||||
switch (dos_fork_mode)
|
||||
{
|
||||
case FRONTEND_FORK_CORE_WITH_ARGS:
|
||||
should_load_content = true;
|
||||
break;
|
||||
case FRONTEND_FORK_NONE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
frontend_dos_exec(s, should_load_content);
|
||||
}
|
||||
|
||||
static bool frontend_unix_set_fork(enum frontend_fork fork_mode)
|
||||
{
|
||||
switch (fork_mode)
|
||||
{
|
||||
case FRONTEND_FORK_CORE:
|
||||
RARCH_LOG("FRONTEND_FORK_CORE\n");
|
||||
unix_fork_mode = fork_mode;
|
||||
break;
|
||||
case FRONTEND_FORK_CORE_WITH_ARGS:
|
||||
RARCH_LOG("FRONTEND_FORK_CORE_WITH_ARGS\n");
|
||||
unix_fork_mode = fork_mode;
|
||||
break;
|
||||
case FRONTEND_FORK_RESTART:
|
||||
RARCH_LOG("FRONTEND_FORK_RESTART\n");
|
||||
unix_fork_mode = FRONTEND_FORK_CORE;
|
||||
|
||||
{
|
||||
char executable_path[PATH_MAX_LENGTH] = {0};
|
||||
fill_pathname_application_path(executable_path,
|
||||
sizeof(executable_path));
|
||||
path_set(RARCH_PATH_CORE, executable_path);
|
||||
}
|
||||
command_event(CMD_EVENT_QUIT, NULL);
|
||||
break;
|
||||
case FRONTEND_FORK_NONE:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
frontend_ctx_driver_t frontend_ctx_dos = {
|
||||
frontend_dos_get_env_settings,/* environment_get */
|
||||
frontend_dos_init, /* init */
|
||||
NULL, /* deinit */
|
||||
NULL, /* exitspawn */
|
||||
NULL, /* process_args */
|
||||
NULL, /* exec */
|
||||
NULL, /* set_fork */
|
||||
frontend_dos_shutdown, /* shutdown */
|
||||
NULL, /* get_name */
|
||||
NULL, /* get_os */
|
||||
frontend_dos_get_rating, /* get_rating */
|
||||
NULL, /* load_content */
|
||||
frontend_dos_get_architecture,/* get_architecture */
|
||||
NULL, /* get_powerstate */
|
||||
NULL, /* parse_drive_list */
|
||||
NULL, /* get_mem_total */
|
||||
NULL, /* get_mem_free */
|
||||
NULL, /* install_signal_handler */
|
||||
NULL, /* get_sighandler_state */
|
||||
NULL, /* set_sighandler_state */
|
||||
NULL, /* destroy_sighandler_state */
|
||||
NULL, /* attach_console */
|
||||
NULL, /* detach_console */
|
||||
NULL, /* watch_path_for_changes */
|
||||
NULL, /* check_for_path_changes */
|
||||
NULL, /* set_sustained_performance_mode */
|
||||
NULL, /* get_cpu_model_name */
|
||||
NULL, /* get_user_language */
|
||||
NULL, /* is_narrator_running */
|
||||
NULL, /* accessibility_speak */
|
||||
"dos",
|
||||
frontend_dos_get_env_settings,/* environment_get */
|
||||
frontend_dos_init, /* init */
|
||||
NULL, /* deinit */
|
||||
frontend_dos_exitspawn, /* exitspawn */
|
||||
NULL, /* process_args */
|
||||
frontend_dos_exec, /* exec */
|
||||
frontend_dos_set_fork, /* set_fork */
|
||||
frontend_dos_shutdown, /* shutdown */
|
||||
NULL, /* get_name */
|
||||
NULL, /* get_os */
|
||||
frontend_dos_get_rating, /* get_rating */
|
||||
NULL, /* load_content */
|
||||
frontend_dos_get_architecture,/* get_architecture */
|
||||
NULL, /* get_powerstate */
|
||||
NULL, /* parse_drive_list */
|
||||
NULL, /* get_mem_total */
|
||||
NULL, /* get_mem_free */
|
||||
NULL, /* install_signal_handler */
|
||||
NULL, /* get_sighandler_state */
|
||||
NULL, /* set_sighandler_state */
|
||||
NULL, /* destroy_sighandler_state */
|
||||
NULL, /* attach_console */
|
||||
NULL, /* detach_console */
|
||||
NULL, /* watch_path_for_changes */
|
||||
NULL, /* check_for_path_changes */
|
||||
NULL, /* set_sustained_performance_mode */
|
||||
NULL, /* get_cpu_model_name */
|
||||
NULL, /* get_user_language */
|
||||
NULL, /* is_narrator_running */
|
||||
NULL, /* accessibility_speak */
|
||||
"dos",
|
||||
};
|
||||
@@ -83,7 +83,6 @@ static void frontend_ps3_shutdown(bool unused)
|
||||
static void callback_sysutil_exit(uint64_t status,
|
||||
uint64_t param, void *userdata)
|
||||
{
|
||||
|
||||
(void)param;
|
||||
(void)userdata;
|
||||
(void)status;
|
||||
@@ -107,7 +106,7 @@ static void callback_sysutil_exit(uint64_t status,
|
||||
}
|
||||
#endif
|
||||
|
||||
static void fill_derived_paths()
|
||||
static void fill_derived_paths(void)
|
||||
{
|
||||
strlcpy(g_defaults.dirs[DEFAULT_DIR_CONTENT_HISTORY],
|
||||
g_defaults.dirs[DEFAULT_DIR_PORT],
|
||||
@@ -276,7 +275,8 @@ static void frontend_ps3_get_environment_settings(int *argc, char *argv[],
|
||||
memset(&size, 0x00, sizeof(CellGameContentSize));
|
||||
|
||||
ret = cellGameBootCheck(&get_type, &get_attributes, &size, dirName);
|
||||
if(ret < 0)
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
RARCH_ERR("cellGameBootCheck() Error: 0x%x.\n", ret);
|
||||
}
|
||||
@@ -299,7 +299,7 @@ static void frontend_ps3_get_environment_settings(int *argc, char *argv[],
|
||||
break;
|
||||
}
|
||||
|
||||
if((get_attributes & CELL_GAME_ATTRIBUTE_APP_HOME)
|
||||
if ((get_attributes & CELL_GAME_ATTRIBUTE_APP_HOME)
|
||||
== CELL_GAME_ATTRIBUTE_APP_HOME)
|
||||
RARCH_LOG("RetroArch was launched from host machine (APP_HOME).\n");
|
||||
|
||||
@@ -307,12 +307,10 @@ static void frontend_ps3_get_environment_settings(int *argc, char *argv[],
|
||||
|
||||
#ifdef HAVE_MULTIMAN
|
||||
if (multiman_detected)
|
||||
{
|
||||
use_app_path(content_info_path);
|
||||
}
|
||||
use_app_path(content_info_path);
|
||||
#endif
|
||||
|
||||
if(ret < 0)
|
||||
if (ret < 0)
|
||||
RARCH_ERR("cellGameContentPermit() Error: 0x%x\n", ret);
|
||||
else
|
||||
{
|
||||
@@ -468,7 +466,7 @@ static int frontend_ps3_exec_exitspawn(const char *path,
|
||||
ret = -1;
|
||||
#endif
|
||||
|
||||
if(ret < 0)
|
||||
if (ret < 0)
|
||||
{
|
||||
RARCH_WARN("SELF file is not of NPDRM type, trying another approach to boot it...\n");
|
||||
sys_game_process_exitspawn(path, (const char** const)argv,
|
||||
|
||||
@@ -2091,8 +2091,8 @@ static void frontend_unix_exitspawn(char *s, size_t len, char *args)
|
||||
|
||||
static uint64_t frontend_unix_get_mem_total(void)
|
||||
{
|
||||
long pages = sysconf(_SC_PHYS_PAGES);
|
||||
long page_size = sysconf(_SC_PAGE_SIZE);
|
||||
uint64_t pages = sysconf(_SC_PHYS_PAGES);
|
||||
uint64_t page_size = sysconf(_SC_PAGE_SIZE);
|
||||
return pages * page_size;
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
|
||||
#define WIIU_SD_PATH "sd:/"
|
||||
#define WIIU_USB_PATH "usb:/"
|
||||
#define WIIU_STORAGE_USB_PATH "storage_usb:/"
|
||||
|
||||
/**
|
||||
* The Wii U frontend driver, along with the main() method.
|
||||
@@ -79,7 +80,8 @@ static bool exists(char *path)
|
||||
return (stat(path, &stat_buf) == 0);
|
||||
}
|
||||
|
||||
static void fix_asset_directory(void) {
|
||||
static void fix_asset_directory(void)
|
||||
{
|
||||
char src_path_buf[PATH_MAX_LENGTH] = {0};
|
||||
char dst_path_buf[PATH_MAX_LENGTH] = {0};
|
||||
|
||||
@@ -188,13 +190,16 @@ static int frontend_wiiu_parse_drive_list(void *data, bool load_content)
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
|
||||
enum_idx,
|
||||
FILE_TYPE_DIRECTORY, 0, 0);
|
||||
menu_entries_append_enum(list, WIIU_STORAGE_USB_PATH,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
|
||||
enum_idx,
|
||||
FILE_TYPE_DIRECTORY, 0, 0);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void frontend_wiiu_exec(const char *path, bool should_load_content)
|
||||
{
|
||||
|
||||
struct
|
||||
{
|
||||
u32 magic;
|
||||
|
||||
@@ -51,6 +51,10 @@
|
||||
#include "../../msg_hash.h"
|
||||
#include "platform_win32.h"
|
||||
|
||||
#ifdef HAVE_NVDA
|
||||
#include "../../nvda_controller.h"
|
||||
#endif
|
||||
|
||||
#ifndef SM_SERVERR2
|
||||
#define SM_SERVERR2 89
|
||||
#endif
|
||||
@@ -612,15 +616,17 @@ static void frontend_win32_attach_console(void)
|
||||
bool need_stderr = (GetFileType(GetStdHandle(STD_ERROR_HANDLE))
|
||||
== FILE_TYPE_UNKNOWN);
|
||||
|
||||
if(need_stdout || need_stderr)
|
||||
if (need_stdout || need_stderr)
|
||||
{
|
||||
if(!AttachConsole( ATTACH_PARENT_PROCESS))
|
||||
if (!AttachConsole( ATTACH_PARENT_PROCESS))
|
||||
AllocConsole();
|
||||
|
||||
SetConsoleTitle("Log Console");
|
||||
|
||||
if(need_stdout) freopen( "CONOUT$", "w", stdout );
|
||||
if(need_stderr) freopen( "CONOUT$", "w", stderr );
|
||||
if (need_stdout)
|
||||
freopen( "CONOUT$", "w", stdout );
|
||||
if (need_stderr)
|
||||
freopen( "CONOUT$", "w", stderr );
|
||||
|
||||
console_needs_free = true;
|
||||
}
|
||||
@@ -633,7 +639,7 @@ static void frontend_win32_detach_console(void)
|
||||
{
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
#ifdef _WIN32_WINNT_WINXP
|
||||
if(console_needs_free)
|
||||
if (console_needs_free)
|
||||
{
|
||||
/* we don't reconnect stdout/stderr to anything here,
|
||||
* because by definition, they weren't connected to
|
||||
@@ -689,7 +695,7 @@ static void frontend_win32_respawn(char *s, size_t len, char *args)
|
||||
si.cb = sizeof(si);
|
||||
memset(&pi, 0, sizeof(pi));
|
||||
|
||||
if(!CreateProcess( executable_path, args,
|
||||
if (!CreateProcess( executable_path, args,
|
||||
NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
|
||||
{
|
||||
RARCH_LOG("Failed to restart RetroArch\n");
|
||||
@@ -717,6 +723,74 @@ static bool frontend_win32_set_fork(enum frontend_fork fork_mode)
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
static const char *accessibility_win_language_id(const char* language)
|
||||
{
|
||||
if (string_is_equal(language,"en"))
|
||||
return "409";
|
||||
else if (string_is_equal(language,"it"))
|
||||
return "410";
|
||||
else if (string_is_equal(language,"sv"))
|
||||
return "041d";
|
||||
else if (string_is_equal(language,"fr"))
|
||||
return "040c";
|
||||
else if (string_is_equal(language,"de"))
|
||||
return "407";
|
||||
else if (string_is_equal(language,"he"))
|
||||
return "040d";
|
||||
else if (string_is_equal(language,"id"))
|
||||
return "421";
|
||||
else if (string_is_equal(language,"es"))
|
||||
return "040a";
|
||||
else if (string_is_equal(language,"nl"))
|
||||
return "413";
|
||||
else if (string_is_equal(language,"ro"))
|
||||
return "418";
|
||||
else if (string_is_equal(language,"pt_pt"))
|
||||
return "816";
|
||||
else if (string_is_equal(language,"pt_bt") || string_is_equal(language,"pt"))
|
||||
return "416";
|
||||
else if (string_is_equal(language,"th"))
|
||||
return "041e";
|
||||
else if (string_is_equal(language,"ja"))
|
||||
return "411";
|
||||
else if (string_is_equal(language,"sk"))
|
||||
return "041b";
|
||||
else if (string_is_equal(language,"hi"))
|
||||
return "439";
|
||||
else if (string_is_equal(language,"ar"))
|
||||
return "401";
|
||||
else if (string_is_equal(language,"hu"))
|
||||
return "040e";
|
||||
else if (string_is_equal(language,"zh_tw") || string_is_equal(language,"zh"))
|
||||
return "804";
|
||||
else if (string_is_equal(language,"el"))
|
||||
return "408";
|
||||
else if (string_is_equal(language,"ru"))
|
||||
return "419";
|
||||
else if (string_is_equal(language,"nb"))
|
||||
return "414";
|
||||
else if (string_is_equal(language,"da"))
|
||||
return "406";
|
||||
else if (string_is_equal(language,"fi"))
|
||||
return "040b";
|
||||
else if (string_is_equal(language,"zh_hk"))
|
||||
return "0c04";
|
||||
else if (string_is_equal(language,"zh_cn"))
|
||||
return "804";
|
||||
else if (string_is_equal(language,"tr"))
|
||||
return "041f";
|
||||
else if (string_is_equal(language,"ko"))
|
||||
return "412";
|
||||
else if (string_is_equal(language,"pl"))
|
||||
return "415";
|
||||
else if (string_is_equal(language,"cs"))
|
||||
return "405";
|
||||
else
|
||||
return "";
|
||||
|
||||
|
||||
}
|
||||
|
||||
static const char *accessibility_win_language_code(const char* language)
|
||||
{
|
||||
if (string_is_equal(language,"en"))
|
||||
@@ -730,9 +804,9 @@ static const char *accessibility_win_language_code(const char* language)
|
||||
else if (string_is_equal(language,"de"))
|
||||
return "Microsoft Stefan Desktop";
|
||||
else if (string_is_equal(language,"he"))
|
||||
return "Microsoft Hemant Desktop";
|
||||
else if (string_is_equal(language,"id"))
|
||||
return "Microsoft Asaf Desktop";
|
||||
else if (string_is_equal(language,"id"))
|
||||
return "Microsoft Andika Desktop";
|
||||
else if (string_is_equal(language,"es"))
|
||||
return "Microsoft Pablo Desktop";
|
||||
else if (string_is_equal(language,"nl"))
|
||||
@@ -806,13 +880,69 @@ static bool create_win32_process(char* cmd)
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SAPI
|
||||
#define COBJMACROS
|
||||
#include <sapi.h>
|
||||
#include <ole2.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SAPI
|
||||
static ISpVoice* pVoice = NULL;
|
||||
#endif
|
||||
#ifdef HAVE_NVDA
|
||||
bool USE_POWERSHELL = false;
|
||||
bool USE_NVDA = true;
|
||||
#else
|
||||
bool USE_POWERSHELL = true;
|
||||
bool USE_NVDA = false;
|
||||
#endif
|
||||
bool USE_NVDA_BRAILLE = false;
|
||||
|
||||
static bool is_narrator_running_windows(void)
|
||||
{
|
||||
DWORD status = 0;
|
||||
if (pi_set == false)
|
||||
|
||||
if (USE_POWERSHELL)
|
||||
{
|
||||
if (pi_set == false)
|
||||
return false;
|
||||
if (GetExitCodeProcess(g_pi.hProcess, &status))
|
||||
{
|
||||
if (status == STILL_ACTIVE)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if (GetExitCodeProcess(&g_pi, &status) && status == STILL_ACTIVE)
|
||||
return true;
|
||||
}
|
||||
#ifdef HAVE_NVDA
|
||||
else if (USE_NVDA)
|
||||
{
|
||||
long res = nvdaController_testIfRunning();
|
||||
|
||||
if (res != 0)
|
||||
{
|
||||
/* The running nvda service wasn't found, so revert
|
||||
back to the powershell method
|
||||
*/
|
||||
RARCH_LOG("Error communicating with NVDA\n");
|
||||
USE_POWERSHELL = true;
|
||||
USE_NVDA = false;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_SAPI
|
||||
else
|
||||
{
|
||||
SPVOICESTATUS pStatus;
|
||||
if (pVoice)
|
||||
{
|
||||
ISpVoice_GetStatus(pVoice, &pStatus, NULL);
|
||||
if (pStatus.dwRunningState == SPRS_IS_SPEAKING)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -822,9 +952,12 @@ static bool accessibility_speak_windows(int speed,
|
||||
char cmd[1200];
|
||||
const char *voice = get_user_language_iso639_1(true);
|
||||
const char *language = accessibility_win_language_code(voice);
|
||||
const char *langid = accessibility_win_language_id(voice);
|
||||
bool res = false;
|
||||
const char* speeds[10] = {"-10", "-7.5", "-5", "-2.5", "0", "2", "4", "6", "8", "10"};
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
if (speed < 1)
|
||||
speed = 1;
|
||||
else if (speed > 10)
|
||||
@@ -836,21 +969,83 @@ static bool accessibility_speak_windows(int speed,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (strlen(language) > 0)
|
||||
snprintf(cmd, sizeof(cmd),
|
||||
"powershell.exe -NoProfile -WindowStyle Hidden -Command \"Add-Type -AssemblyName System.Speech; $synth = New-Object System.Speech.Synthesis.SpeechSynthesizer; $synth.SelectVoice(\\\"%s\\\"); $synth.Rate = %s; $synth.Speak(\\\"%s\\\");\"", language, speeds[speed-1], (char*) speak_text);
|
||||
else
|
||||
snprintf(cmd, sizeof(cmd),
|
||||
"powershell.exe -NoProfile -WindowStyle Hidden -Command \"Add-Type -AssemblyName System.Speech; $synth = New-Object System.Speech.Synthesis.SpeechSynthesizer; $synth.Rate = %s; $synth.Speak(\\\"%s\\\");\"", speeds[speed-1], (char*) speak_text);
|
||||
if (pi_set)
|
||||
terminate_win32_process(g_pi);
|
||||
res = create_win32_process(cmd);
|
||||
if (!res)
|
||||
if (USE_POWERSHELL)
|
||||
{
|
||||
pi_set = false;
|
||||
if (strlen(language) > 0)
|
||||
snprintf(cmd, sizeof(cmd),
|
||||
"powershell.exe -NoProfile -WindowStyle Hidden -Command \"Add-Type -AssemblyName System.Speech; $synth = New-Object System.Speech.Synthesis.SpeechSynthesizer; $synth.SelectVoice(\\\"%s\\\"); $synth.Rate = %s; $synth.Speak(\\\"%s\\\");\"", language, speeds[speed-1], (char*) speak_text);
|
||||
else
|
||||
snprintf(cmd, sizeof(cmd),
|
||||
"powershell.exe -NoProfile -WindowStyle Hidden -Command \"Add-Type -AssemblyName System.Speech; $synth = New-Object System.Speech.Synthesis.SpeechSynthesizer; $synth.Rate = %s; $synth.Speak(\\\"%s\\\");\"", speeds[speed-1], (char*) speak_text);
|
||||
if (pi_set)
|
||||
terminate_win32_process(g_pi);
|
||||
res = create_win32_process(cmd);
|
||||
if (!res)
|
||||
{
|
||||
pi_set = false;
|
||||
return true;
|
||||
}
|
||||
pi_set = true;
|
||||
return true;
|
||||
}
|
||||
pi_set = true;
|
||||
#ifdef HAVE_NVDA
|
||||
else if (USE_NVDA)
|
||||
{
|
||||
long res = nvdaController_testIfRunning();
|
||||
const size_t cSize = strlen(speak_text) + 1;
|
||||
wchar_t *wc = malloc(sizeof(wchar_t) * cSize);
|
||||
|
||||
mbstowcs(wc, speak_text, cSize);
|
||||
|
||||
if (res != 0)
|
||||
{
|
||||
RARCH_LOG("Error communicating with NVDA\n");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
nvdaController_cancelSpeech();
|
||||
}
|
||||
|
||||
if (USE_NVDA_BRAILLE)
|
||||
nvdaController_brailleMessage(wc);
|
||||
else
|
||||
{
|
||||
nvdaController_speakText(wc);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_SAPI
|
||||
else
|
||||
{
|
||||
/* stop the old voice if running */
|
||||
if (pVoice)
|
||||
{
|
||||
CoUninitialize();
|
||||
ISpVoice_Release(pVoice);
|
||||
}
|
||||
pVoice = NULL;
|
||||
|
||||
/* Play the new voice */
|
||||
if (FAILED(CoInitialize(NULL)))
|
||||
return NULL;
|
||||
|
||||
hr = CoCreateInstance(&CLSID_SpVoice, NULL,
|
||||
CLSCTX_ALL, &IID_ISpVoice, (void **)&pVoice);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
wchar_t wtext[1200];
|
||||
snprintf(cmd, sizeof(cmd),
|
||||
"<rate speed=\"%s\"/><volume level=\"80\"/><lang langid=\"%s\"/>%s", speeds[speed], langid, speak_text);
|
||||
mbstowcs(wtext, speak_text, sizeof(wtext));
|
||||
|
||||
hr = ISpVoice_Speak(pVoice, wtext, SPF_ASYNC /*SVSFlagsAsync*/, NULL);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -218,6 +218,9 @@ bool frontend_driver_get_core_extension(char *s, size_t len)
|
||||
#elif defined(HAVE_LIBNX)
|
||||
strlcpy(s, "nro", len);
|
||||
return true;
|
||||
#elif defined(DJGPP)
|
||||
strlcpy(s, "exe", len);
|
||||
return true;
|
||||
#elif defined(_3DS)
|
||||
if (envIsHomebrew())
|
||||
strlcpy(s, "3dsx", len);
|
||||
@@ -264,6 +267,9 @@ bool frontend_driver_get_salamander_basename(char *s, size_t len)
|
||||
#elif defined(_3DS)
|
||||
strlcpy(s, "retroarch.core", len);
|
||||
return true;
|
||||
#elif defined(DJGPP)
|
||||
strlcpy(s, "retrodos.exe", len);
|
||||
return true;
|
||||
#elif defined(SWITCH)
|
||||
strlcpy(s, "retroarch_switch.nro", len);
|
||||
return true;
|
||||
|
||||
@@ -52,10 +52,13 @@ static VkDevice cached_device_vk;
|
||||
static retro_vulkan_destroy_device_t cached_destroy_device_vk;
|
||||
static struct string_list *vulkan_gpu_list = NULL;
|
||||
|
||||
//#define WSI_HARDENING_TEST
|
||||
#if 0
|
||||
#define WSI_HARDENING_TEST
|
||||
#endif
|
||||
|
||||
#ifdef WSI_HARDENING_TEST
|
||||
static unsigned wsi_harden_counter = 0;
|
||||
static unsigned wsi_harden_counter2 = 0;
|
||||
static unsigned wsi_harden_counter = 0;
|
||||
static unsigned wsi_harden_counter2 = 0;
|
||||
|
||||
static void trigger_spurious_error_vkresult(VkResult *res)
|
||||
{
|
||||
@@ -1978,9 +1981,7 @@ bool vulkan_context_init(gfx_ctx_vulkan_data_t *vk,
|
||||
#else
|
||||
vulkan_library = dylib_load("libvulkan.so");
|
||||
if (!vulkan_library)
|
||||
{
|
||||
vulkan_library = dylib_load("libvulkan.so.1");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+101
-82
@@ -117,97 +117,114 @@ extern bool dinput_handle_message(void *dinput, UINT message,
|
||||
WPARAM wParam, LPARAM lParam);
|
||||
#endif
|
||||
|
||||
typedef struct DISPLAYCONFIG_RATIONAL_CUSTOM {
|
||||
UINT32 Numerator;
|
||||
UINT32 Denominator;
|
||||
typedef struct DISPLAYCONFIG_RATIONAL_CUSTOM
|
||||
{
|
||||
UINT32 Numerator;
|
||||
UINT32 Denominator;
|
||||
} DISPLAYCONFIG_RATIONAL_CUSTOM;
|
||||
|
||||
typedef struct DISPLAYCONFIG_2DREGION_CUSTOM {
|
||||
UINT32 cx;
|
||||
UINT32 cy;
|
||||
typedef struct DISPLAYCONFIG_2DREGION_CUSTOM
|
||||
{
|
||||
UINT32 cx;
|
||||
UINT32 cy;
|
||||
} DISPLAYCONFIG_2DREGION_CUSTOM;
|
||||
|
||||
typedef struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO_CUSTOM {
|
||||
UINT64 pixelRate;
|
||||
DISPLAYCONFIG_RATIONAL_CUSTOM hSyncFreq;
|
||||
DISPLAYCONFIG_RATIONAL_CUSTOM vSyncFreq;
|
||||
DISPLAYCONFIG_2DREGION_CUSTOM activeSize;
|
||||
DISPLAYCONFIG_2DREGION_CUSTOM totalSize;
|
||||
union {
|
||||
struct {
|
||||
UINT32 videoStandard :16;
|
||||
UINT32 vSyncFreqDivider :6;
|
||||
UINT32 reserved :10;
|
||||
} AdditionalSignalInfo;
|
||||
UINT32 videoStandard;
|
||||
} dummyunionname;
|
||||
UINT32 scanLineOrdering;
|
||||
typedef struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO_CUSTOM
|
||||
{
|
||||
UINT64 pixelRate;
|
||||
DISPLAYCONFIG_RATIONAL_CUSTOM hSyncFreq;
|
||||
DISPLAYCONFIG_RATIONAL_CUSTOM vSyncFreq;
|
||||
DISPLAYCONFIG_2DREGION_CUSTOM activeSize;
|
||||
DISPLAYCONFIG_2DREGION_CUSTOM totalSize;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
UINT32 videoStandard :16;
|
||||
UINT32 vSyncFreqDivider :6;
|
||||
UINT32 reserved :10;
|
||||
} AdditionalSignalInfo;
|
||||
UINT32 videoStandard;
|
||||
} dummyunionname;
|
||||
UINT32 scanLineOrdering;
|
||||
} DISPLAYCONFIG_VIDEO_SIGNAL_INFO_CUSTOM;
|
||||
|
||||
typedef struct DISPLAYCONFIG_TARGET_MODE_CUSTOM {
|
||||
DISPLAYCONFIG_VIDEO_SIGNAL_INFO_CUSTOM targetVideoSignalInfo;
|
||||
typedef struct DISPLAYCONFIG_TARGET_MODE_CUSTOM
|
||||
{
|
||||
DISPLAYCONFIG_VIDEO_SIGNAL_INFO_CUSTOM targetVideoSignalInfo;
|
||||
} DISPLAYCONFIG_TARGET_MODE_CUSTOM;
|
||||
|
||||
typedef struct DISPLAYCONFIG_PATH_SOURCE_INFO_CUSTOM {
|
||||
LUID adapterId;
|
||||
UINT32 id;
|
||||
union {
|
||||
UINT32 modeInfoIdx;
|
||||
struct {
|
||||
UINT32 cloneGroupId :16;
|
||||
UINT32 sourceModeInfoIdx :16;
|
||||
} dummystructname;
|
||||
} dummyunionname;
|
||||
UINT32 statusFlags;
|
||||
typedef struct DISPLAYCONFIG_PATH_SOURCE_INFO_CUSTOM
|
||||
{
|
||||
LUID adapterId;
|
||||
UINT32 id;
|
||||
union
|
||||
{
|
||||
UINT32 modeInfoIdx;
|
||||
struct
|
||||
{
|
||||
UINT32 cloneGroupId :16;
|
||||
UINT32 sourceModeInfoIdx :16;
|
||||
} dummystructname;
|
||||
} dummyunionname;
|
||||
UINT32 statusFlags;
|
||||
} DISPLAYCONFIG_PATH_SOURCE_INFO_CUSTOM;
|
||||
|
||||
typedef struct DISPLAYCONFIG_DESKTOP_IMAGE_INFO_CUSTOM {
|
||||
POINTL PathSourceSize;
|
||||
RECTL DesktopImageRegion;
|
||||
RECTL DesktopImageClip;
|
||||
typedef struct DISPLAYCONFIG_DESKTOP_IMAGE_INFO_CUSTOM
|
||||
{
|
||||
POINTL PathSourceSize;
|
||||
RECTL DesktopImageRegion;
|
||||
RECTL DesktopImageClip;
|
||||
} DISPLAYCONFIG_DESKTOP_IMAGE_INFO_CUSTOM;
|
||||
|
||||
typedef struct DISPLAYCONFIG_SOURCE_MODE_CUSTOM {
|
||||
UINT32 width;
|
||||
UINT32 height;
|
||||
UINT32 pixelFormat;
|
||||
POINTL position;
|
||||
typedef struct DISPLAYCONFIG_SOURCE_MODE_CUSTOM
|
||||
{
|
||||
UINT32 width;
|
||||
UINT32 height;
|
||||
UINT32 pixelFormat;
|
||||
POINTL position;
|
||||
} DISPLAYCONFIG_SOURCE_MODE_CUSTOM;
|
||||
|
||||
typedef struct DISPLAYCONFIG_MODE_INFO_CUSTOM {
|
||||
UINT32 infoType;
|
||||
UINT32 id;
|
||||
LUID adapterId;
|
||||
union {
|
||||
DISPLAYCONFIG_TARGET_MODE_CUSTOM targetMode;
|
||||
DISPLAYCONFIG_SOURCE_MODE_CUSTOM sourceMode;
|
||||
DISPLAYCONFIG_DESKTOP_IMAGE_INFO_CUSTOM desktopImageInfo;
|
||||
} dummyunionname;
|
||||
typedef struct DISPLAYCONFIG_MODE_INFO_CUSTOM
|
||||
{
|
||||
UINT32 infoType;
|
||||
UINT32 id;
|
||||
LUID adapterId;
|
||||
union
|
||||
{
|
||||
DISPLAYCONFIG_TARGET_MODE_CUSTOM targetMode;
|
||||
DISPLAYCONFIG_SOURCE_MODE_CUSTOM sourceMode;
|
||||
DISPLAYCONFIG_DESKTOP_IMAGE_INFO_CUSTOM desktopImageInfo;
|
||||
} dummyunionname;
|
||||
} DISPLAYCONFIG_MODE_INFO_CUSTOM;
|
||||
|
||||
typedef struct DISPLAYCONFIG_PATH_TARGET_INFO_CUSTOM {
|
||||
LUID adapterId;
|
||||
UINT32 id;
|
||||
union {
|
||||
UINT32 modeInfoIdx;
|
||||
struct {
|
||||
UINT32 desktopModeInfoIdx :16;
|
||||
UINT32 targetModeInfoIdx :16;
|
||||
} dummystructname;
|
||||
} dummyunionname;
|
||||
UINT32 outputTechnology;
|
||||
UINT32 rotation;
|
||||
UINT32 scaling;
|
||||
DISPLAYCONFIG_RATIONAL_CUSTOM refreshRate;
|
||||
UINT32 scanLineOrdering;
|
||||
BOOL targetAvailable;
|
||||
UINT32 statusFlags;
|
||||
typedef struct DISPLAYCONFIG_PATH_TARGET_INFO_CUSTOM
|
||||
{
|
||||
LUID adapterId;
|
||||
UINT32 id;
|
||||
union
|
||||
{
|
||||
UINT32 modeInfoIdx;
|
||||
struct
|
||||
{
|
||||
UINT32 desktopModeInfoIdx :16;
|
||||
UINT32 targetModeInfoIdx :16;
|
||||
} dummystructname;
|
||||
} dummyunionname;
|
||||
UINT32 outputTechnology;
|
||||
UINT32 rotation;
|
||||
UINT32 scaling;
|
||||
DISPLAYCONFIG_RATIONAL_CUSTOM refreshRate;
|
||||
UINT32 scanLineOrdering;
|
||||
BOOL targetAvailable;
|
||||
UINT32 statusFlags;
|
||||
} DISPLAYCONFIG_PATH_TARGET_INFO_CUSTOM;
|
||||
|
||||
typedef struct DISPLAYCONFIG_PATH_INFO_CUSTOM {
|
||||
DISPLAYCONFIG_PATH_SOURCE_INFO_CUSTOM sourceInfo;
|
||||
DISPLAYCONFIG_PATH_TARGET_INFO_CUSTOM targetInfo;
|
||||
UINT32 flags;
|
||||
typedef struct DISPLAYCONFIG_PATH_INFO_CUSTOM
|
||||
{
|
||||
DISPLAYCONFIG_PATH_SOURCE_INFO_CUSTOM sourceInfo;
|
||||
DISPLAYCONFIG_PATH_TARGET_INFO_CUSTOM targetInfo;
|
||||
UINT32 flags;
|
||||
} DISPLAYCONFIG_PATH_INFO_CUSTOM;
|
||||
|
||||
typedef LONG (WINAPI *QUERYDISPLAYCONFIG)(UINT32, UINT32*, DISPLAYCONFIG_PATH_INFO_CUSTOM*, UINT32*, DISPLAYCONFIG_MODE_INFO_CUSTOM*, UINT32*);
|
||||
@@ -301,9 +318,9 @@ bool win32_taskbar_is_created(void)
|
||||
return taskbar_is_created;
|
||||
}
|
||||
|
||||
static INT_PTR_COMPAT CALLBACK PickCoreProc(
|
||||
static INT_PTR_COMPAT CALLBACK pick_core_proc(
|
||||
HWND hDlg, UINT message,
|
||||
WPARAM wParam, LPARAM lParam)
|
||||
WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
size_t list_size;
|
||||
core_info_list_t *core_info_list = NULL;
|
||||
@@ -528,7 +545,7 @@ bool win32_load_content_from_gui(const char *szFilename)
|
||||
|
||||
/* Pick one core that could be compatible, ew */
|
||||
if (DialogBoxParam(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_PICKCORE),
|
||||
main_window.hwnd, PickCoreProc, (LPARAM)NULL) == IDOK)
|
||||
main_window.hwnd, pick_core_proc, (LPARAM)NULL) == IDOK)
|
||||
{
|
||||
task_push_load_content_with_current_core_from_companion_ui(
|
||||
NULL, &content_info, CORE_TYPE_PLAIN, NULL, NULL);
|
||||
@@ -822,7 +839,8 @@ static LRESULT win32_menu_loop(HWND owner, WPARAM wparam)
|
||||
return 0L;
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK WndProcCommon(bool *quit, HWND hwnd, UINT message,
|
||||
static LRESULT CALLBACK wnd_proc_common(
|
||||
bool *quit, HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
bool keydown = true;
|
||||
@@ -1028,7 +1046,7 @@ LRESULT CALLBACK WndProcD3D(HWND hwnd, UINT message,
|
||||
case WM_MOVE:
|
||||
case WM_SIZE:
|
||||
case WM_COMMAND:
|
||||
ret = WndProcCommon(&quit, hwnd, message, wparam, lparam);
|
||||
ret = wnd_proc_common(&quit, hwnd, message, wparam, lparam);
|
||||
if (quit)
|
||||
return ret;
|
||||
#if _WIN32_WINNT >= 0x0500 /* 2K */
|
||||
@@ -1092,8 +1110,7 @@ LRESULT CALLBACK WndProcWGL(HWND hwnd, UINT message,
|
||||
case WM_MOVE:
|
||||
case WM_SIZE:
|
||||
case WM_COMMAND:
|
||||
ret = WndProcCommon(&quit,
|
||||
hwnd, message, wparam, lparam);
|
||||
ret = wnd_proc_common(&quit, hwnd, message, wparam, lparam);
|
||||
if (quit)
|
||||
return ret;
|
||||
#if _WIN32_WINNT >= 0x0500 /* 2K */
|
||||
@@ -1195,7 +1212,7 @@ LRESULT CALLBACK WndProcGDI(HWND hwnd, UINT message,
|
||||
case WM_MOVE:
|
||||
case WM_SIZE:
|
||||
case WM_COMMAND:
|
||||
ret = WndProcCommon(&quit, hwnd, message, wparam, lparam);
|
||||
ret = wnd_proc_common(&quit, hwnd, message, wparam, lparam);
|
||||
if (quit)
|
||||
return ret;
|
||||
#if _WIN32_WINNT >= 0x0500 /* 2K */
|
||||
@@ -1856,7 +1873,9 @@ bool win32_get_video_output(DEVMODE *dm, int mode, size_t len)
|
||||
memset(dm, 0, len);
|
||||
dm->dmSize = len;
|
||||
|
||||
if (win32_internal_get_video_output((mode == -1) ? ENUM_CURRENT_SETTINGS : mode,
|
||||
if (win32_internal_get_video_output((mode == -1)
|
||||
? ENUM_CURRENT_SETTINGS
|
||||
: mode,
|
||||
dm) == 0)
|
||||
return false;
|
||||
return true;
|
||||
|
||||
@@ -43,24 +43,27 @@
|
||||
#ifdef __ITaskbarList3_INTERFACE_DEFINED__
|
||||
#define HAS_TASKBAR_EXT
|
||||
|
||||
static ITaskbarList3 *g_taskbarList = NULL;
|
||||
|
||||
/* MSVC really doesn't want CINTERFACE to be used with shobjidl for some reason, but since we use C++ mode,
|
||||
* we need a workaround... so use the names of the COBJMACROS functions instead. */
|
||||
#if defined(__cplusplus) && !defined(CINTERFACE)
|
||||
#define ITaskbarList3_HrInit(x) g_taskbarList->HrInit()
|
||||
#define ITaskbarList3_Release(x) g_taskbarList->Release()
|
||||
#define ITaskbarList3_SetProgressState(a, b, c) g_taskbarList->SetProgressState(b, c)
|
||||
#define ITaskbarList3_SetProgressValue(a, b, c, d) g_taskbarList->SetProgressValue(b, c, d)
|
||||
#define ITaskbarList3_HrInit(x) (x)->HrInit()
|
||||
#define ITaskbarList3_Release(x) (x)->Release()
|
||||
#define ITaskbarList3_SetProgressState(a, b, c) (a)->SetProgressState(b, c)
|
||||
#define ITaskbarList3_SetProgressValue(a, b, c, d) (a)->SetProgressValue(b, c, d)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned opacity;
|
||||
int progress;
|
||||
bool decorations;
|
||||
int progress;
|
||||
int crt_center;
|
||||
unsigned opacity;
|
||||
unsigned orig_width;
|
||||
unsigned orig_height;
|
||||
unsigned orig_refresh;
|
||||
ITaskbarList3 *taskbar_list;
|
||||
} dispserv_win32_t;
|
||||
|
||||
/*
|
||||
@@ -71,12 +74,7 @@ typedef struct
|
||||
be received by your application before it calls any ITaskbarList3 method.
|
||||
*/
|
||||
|
||||
static unsigned win32_orig_width = 0;
|
||||
static unsigned win32_orig_height = 0;
|
||||
static unsigned win32_orig_refresh = 0;
|
||||
static int crt_center = 0;
|
||||
|
||||
static void* win32_display_server_init(void)
|
||||
static void *win32_display_server_init(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
dispserv_win32_t *dispserv = (dispserv_win32_t*)calloc(1, sizeof(*dispserv));
|
||||
@@ -90,23 +88,25 @@ static void* win32_display_server_init(void)
|
||||
#ifdef __cplusplus
|
||||
/* When compiling in C++ mode, GUIDs are references instead of pointers */
|
||||
hr = CoCreateInstance(CLSID_TaskbarList, NULL,
|
||||
CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (void**)&g_taskbarList);
|
||||
CLSCTX_INPROC_SERVER, IID_ITaskbarList3,
|
||||
(void**)&dispserv->taskbar_list);
|
||||
#else
|
||||
/* Mingw GUIDs are pointers instead of references since we're in C mode */
|
||||
hr = CoCreateInstance(&CLSID_TaskbarList, NULL,
|
||||
CLSCTX_INPROC_SERVER, &IID_ITaskbarList3, (void**)&g_taskbarList);
|
||||
CLSCTX_INPROC_SERVER, &IID_ITaskbarList3,
|
||||
(void**)&dispserv->taskbar_list);
|
||||
#endif
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = ITaskbarList3_HrInit(g_taskbarList);
|
||||
hr = ITaskbarList3_HrInit(dispserv->taskbar_list);
|
||||
|
||||
if (!SUCCEEDED(hr))
|
||||
RARCH_ERR("[dispserv]: HrInit of ITaskbarList3 failed.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_taskbarList = NULL;
|
||||
dispserv->taskbar_list = NULL;
|
||||
RARCH_ERR("[dispserv]: CoCreateInstance of ITaskbarList3 failed.\n");
|
||||
}
|
||||
#endif
|
||||
@@ -118,15 +118,19 @@ static void win32_display_server_destroy(void *data)
|
||||
{
|
||||
dispserv_win32_t *dispserv = (dispserv_win32_t*)data;
|
||||
|
||||
if (win32_orig_width > 0 && win32_orig_height > 0)
|
||||
video_display_server_set_resolution(win32_orig_width, win32_orig_height,
|
||||
win32_orig_refresh, (float)win32_orig_refresh, crt_center, 0, 0);
|
||||
if (dispserv->orig_width > 0 && dispserv->orig_height > 0)
|
||||
video_display_server_set_resolution(
|
||||
dispserv->orig_width,
|
||||
dispserv->orig_height,
|
||||
dispserv->orig_refresh,
|
||||
(float)dispserv->orig_refresh,
|
||||
dispserv->crt_center, 0, 0);
|
||||
|
||||
#ifdef HAS_TASKBAR_EXT
|
||||
if (g_taskbarList)
|
||||
if (dispserv->taskbar_list)
|
||||
{
|
||||
ITaskbarList3_Release(g_taskbarList);
|
||||
g_taskbarList = NULL;
|
||||
ITaskbarList3_Release(dispserv->taskbar_list);
|
||||
dispserv->taskbar_list = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -170,29 +174,29 @@ static bool win32_display_server_set_window_progress(void *data, int progress, b
|
||||
serv->progress = progress;
|
||||
|
||||
#ifdef HAS_TASKBAR_EXT
|
||||
if (!g_taskbarList || !win32_taskbar_is_created())
|
||||
if (!serv->taskbar_list || !win32_taskbar_is_created())
|
||||
return false;
|
||||
|
||||
if (progress == -1)
|
||||
{
|
||||
if (ITaskbarList3_SetProgressState(
|
||||
g_taskbarList, hwnd, TBPF_INDETERMINATE) != S_OK)
|
||||
serv->taskbar_list, hwnd, TBPF_INDETERMINATE) != S_OK)
|
||||
return false;
|
||||
}
|
||||
else if (finished)
|
||||
{
|
||||
if (ITaskbarList3_SetProgressState(
|
||||
g_taskbarList, hwnd, TBPF_NOPROGRESS) != S_OK)
|
||||
serv->taskbar_list, hwnd, TBPF_NOPROGRESS) != S_OK)
|
||||
return false;
|
||||
}
|
||||
else if (progress >= 0)
|
||||
{
|
||||
if (ITaskbarList3_SetProgressState(
|
||||
g_taskbarList, hwnd, TBPF_NORMAL) != S_OK)
|
||||
serv->taskbar_list, hwnd, TBPF_NORMAL) != S_OK)
|
||||
return false;
|
||||
|
||||
if (ITaskbarList3_SetProgressValue(
|
||||
g_taskbarList, hwnd, progress, 100) != S_OK)
|
||||
serv->taskbar_list, hwnd, progress, 100) != S_OK)
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
@@ -227,11 +231,11 @@ static bool win32_display_server_set_resolution(void *data,
|
||||
|
||||
win32_get_video_output(&curDevmode, -1, sizeof(curDevmode));
|
||||
|
||||
if (win32_orig_width == 0)
|
||||
win32_orig_width = GetSystemMetrics(SM_CXSCREEN);
|
||||
win32_orig_refresh = curDevmode.dmDisplayFrequency;
|
||||
if (win32_orig_height == 0)
|
||||
win32_orig_height = GetSystemMetrics(SM_CYSCREEN);
|
||||
if (serv->orig_width == 0)
|
||||
serv->orig_width = GetSystemMetrics(SM_CXSCREEN);
|
||||
serv->orig_refresh = curDevmode.dmDisplayFrequency;
|
||||
if (serv->orig_height == 0)
|
||||
serv->orig_height = GetSystemMetrics(SM_CYSCREEN);
|
||||
|
||||
/* Used to stop super resolution bug */
|
||||
if (width == curDevmode.dmPelsWidth)
|
||||
|
||||
@@ -793,9 +793,6 @@ static bool drm_gfx_frame(void *data, const void *frame, unsigned width,
|
||||
menu_driver_frame(video_info);
|
||||
#endif
|
||||
|
||||
video_info->cb_update_window_title(
|
||||
video_info->context_data);
|
||||
|
||||
/* Update main surface: locate free page, blit and flip. */
|
||||
drm_surface_update(_drmvars, frame, _drmvars->main_surface);
|
||||
return true;
|
||||
|
||||
+235
-222
@@ -66,13 +66,12 @@
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
int height;
|
||||
int width;
|
||||
int id;
|
||||
uint32_t *ptr;
|
||||
// Internal stuff
|
||||
uint32_t offset;
|
||||
int height;
|
||||
int width;
|
||||
int id;
|
||||
uint32_t *ptr;
|
||||
/* Internal stuff */
|
||||
uint32_t offset;
|
||||
} rsxBuffer;
|
||||
|
||||
typedef struct
|
||||
@@ -91,26 +90,25 @@ typedef struct
|
||||
|
||||
typedef struct gcm_video
|
||||
{
|
||||
video_viewport_t vp;
|
||||
rsxBuffer buffers[MAX_BUFFERS];
|
||||
rsxBuffer menuBuffers[MAX_BUFFERS];
|
||||
int currentBuffer, menuBuffer;
|
||||
gcmContextData *context;
|
||||
u16 width;
|
||||
u16 height;
|
||||
bool menu_frame_enable;
|
||||
bool rgb32;
|
||||
bool vsync;
|
||||
u32 depth_pitch;
|
||||
u32 depth_offset;
|
||||
u32 *depth_buffer;
|
||||
video_viewport_t vp;
|
||||
rsxBuffer buffers[MAX_BUFFERS];
|
||||
rsxBuffer menuBuffers[MAX_BUFFERS];
|
||||
int currentBuffer, menuBuffer;
|
||||
gcmContextData *context;
|
||||
u16 width;
|
||||
u16 height;
|
||||
bool menu_frame_enable;
|
||||
bool rgb32;
|
||||
bool vsync;
|
||||
u32 depth_pitch;
|
||||
u32 depth_offset;
|
||||
u32 *depth_buffer;
|
||||
|
||||
bool smooth;
|
||||
unsigned rotation;
|
||||
bool keep_aspect;
|
||||
bool should_resize;
|
||||
bool msg_rendering_enabled;
|
||||
|
||||
} gcm_video_t;
|
||||
|
||||
#ifndef HAVE_THREADS
|
||||
@@ -121,136 +119,138 @@ static bool gcm_tasks_finder(retro_task_t *task,void *userdata)
|
||||
task_finder_data_t gcm_tasks_finder_data = {gcm_tasks_finder, NULL};
|
||||
#endif
|
||||
|
||||
static int
|
||||
makeBuffer (rsxBuffer * buffer, u16 width, u16 height, int id)
|
||||
static int gcm_make_buffer(rsxBuffer * buffer, u16 width, u16 height, int id)
|
||||
{
|
||||
int depth = sizeof(u32);
|
||||
int pitch = depth * width;
|
||||
int size = depth * width * height;
|
||||
int depth = sizeof(u32);
|
||||
int pitch = depth * width;
|
||||
int size = depth * width * height;
|
||||
|
||||
buffer->ptr = (uint32_t*) rsxMemalign (64, size);
|
||||
if (buffer->ptr == NULL)
|
||||
goto error;
|
||||
buffer->ptr = (uint32_t*)rsxMemalign (64, size);
|
||||
if (!buffer->ptr)
|
||||
goto error;
|
||||
|
||||
if (rsxAddressToOffset (buffer->ptr, &buffer->offset) != 0)
|
||||
goto error;
|
||||
if (rsxAddressToOffset (buffer->ptr, &buffer->offset) != 0)
|
||||
goto error;
|
||||
|
||||
/* Register the display buffer with the RSX */
|
||||
if (gcmSetDisplayBuffer (id, buffer->offset, pitch, width, height) != 0)
|
||||
goto error;
|
||||
/* Register the display buffer with the RSX */
|
||||
if (gcmSetDisplayBuffer (id, buffer->offset, pitch, width, height) != 0)
|
||||
goto error;
|
||||
|
||||
buffer->width = width;
|
||||
buffer->height = height;
|
||||
buffer->id = id;
|
||||
buffer->width = width;
|
||||
buffer->height = height;
|
||||
buffer->id = id;
|
||||
|
||||
return TRUE;
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
if (buffer->ptr != NULL)
|
||||
rsxFree (buffer->ptr);
|
||||
error:
|
||||
if (buffer->ptr)
|
||||
rsxFree (buffer->ptr);
|
||||
|
||||
return FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int
|
||||
flip (gcmContextData *context, s32 buffer)
|
||||
static int gcm_flip(gcmContextData *context, s32 buffer)
|
||||
{
|
||||
if (gcmSetFlip (context, buffer) == 0) {
|
||||
rsxFlushBuffer (context);
|
||||
// Prevent the RSX from continuing until the flip has finished.
|
||||
gcmSetWaitFlip (context);
|
||||
if (gcmSetFlip(context, buffer) == 0)
|
||||
{
|
||||
rsxFlushBuffer (context);
|
||||
/* Prevent the RSX from continuing until the flip has finished. */
|
||||
gcmSetWaitFlip (context);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#define GCM_LABEL_INDEX 255
|
||||
|
||||
static void waitRSXIdle(gcmContextData *context);
|
||||
static void gcm_wait_rsx_idle(gcmContextData *context);
|
||||
|
||||
static void
|
||||
waitFlip ()
|
||||
static void gcm_wait_flip(void)
|
||||
{
|
||||
while (gcmGetFlipStatus () != 0)
|
||||
while (gcmGetFlipStatus() != 0)
|
||||
usleep (200); /* Sleep, to not stress the cpu. */
|
||||
gcmResetFlipStatus ();
|
||||
gcmResetFlipStatus();
|
||||
}
|
||||
|
||||
static gcmContextData *
|
||||
initScreen (gcm_video_t* gcm)
|
||||
static gcmContextData *gcm_init_screen(gcm_video_t* gcm)
|
||||
{
|
||||
gcmContextData *context = NULL; /* Context to keep track of the RSX buffer. */
|
||||
static gcmContextData *saved_context = NULL;
|
||||
videoState state;
|
||||
videoConfiguration vconfig;
|
||||
videoResolution res; /* Screen Resolution */
|
||||
/* Context to keep track of the RSX buffer. */
|
||||
gcmContextData *context = NULL;
|
||||
static gcmContextData *saved_context = NULL;
|
||||
videoState state;
|
||||
videoConfiguration vconfig;
|
||||
videoResolution res; /* Screen Resolution */
|
||||
|
||||
if (!saved_context) {
|
||||
/* Allocate a 1Mb buffer, alligned to a 1Mb boundary
|
||||
* to be our shared IO memory with the RSX. */
|
||||
void *host_addr = memalign (1024*1024, HOST_SIZE);
|
||||
if (!saved_context)
|
||||
{
|
||||
/* Allocate a 1Mb buffer, alligned to a 1Mb boundary
|
||||
* to be our shared IO memory with the RSX. */
|
||||
void *host_addr = memalign (1024*1024, HOST_SIZE);
|
||||
|
||||
if (host_addr == NULL)
|
||||
if (!host_addr)
|
||||
goto error;
|
||||
|
||||
/* Initialise Reality, which sets up the
|
||||
* command buffer and shared I/O memory */
|
||||
context = rsxInit (CB_SIZE, HOST_SIZE, host_addr);
|
||||
if (!context)
|
||||
goto error;
|
||||
saved_context = context;
|
||||
}
|
||||
else
|
||||
context = saved_context;
|
||||
|
||||
/* Get the state of the display */
|
||||
if (videoGetState (0, 0, &state) != 0)
|
||||
goto error;
|
||||
|
||||
/* Initilise Reality, which sets up the command buffer and shared IO memory */
|
||||
context = rsxInit (CB_SIZE, HOST_SIZE, host_addr);
|
||||
if (context == NULL)
|
||||
/* Make sure display is enabled */
|
||||
if (state.state != 0)
|
||||
goto error;
|
||||
saved_context = context;
|
||||
} else {
|
||||
context = saved_context;
|
||||
}
|
||||
|
||||
/* Get the state of the display */
|
||||
if (videoGetState (0, 0, &state) != 0)
|
||||
goto error;
|
||||
/* Get the current resolution */
|
||||
if (videoGetResolution (state.displayMode.resolution, &res) != 0)
|
||||
goto error;
|
||||
|
||||
/* Make sure display is enabled */
|
||||
if (state.state != 0)
|
||||
goto error;
|
||||
/* Configure the buffer format to xRGB */
|
||||
memset (&vconfig, 0, sizeof(videoConfiguration));
|
||||
vconfig.resolution = state.displayMode.resolution;
|
||||
vconfig.format = VIDEO_BUFFER_FORMAT_XRGB;
|
||||
vconfig.pitch = res.width * sizeof(u32);
|
||||
vconfig.aspect = state.displayMode.aspect;
|
||||
|
||||
/* Get the current resolution */
|
||||
if (videoGetResolution (state.displayMode.resolution, &res) != 0)
|
||||
goto error;
|
||||
gcm->width = res.width;
|
||||
gcm->height = res.height;
|
||||
|
||||
/* Configure the buffer format to xRGB */
|
||||
memset (&vconfig, 0, sizeof(videoConfiguration));
|
||||
vconfig.resolution = state.displayMode.resolution;
|
||||
vconfig.format = VIDEO_BUFFER_FORMAT_XRGB;
|
||||
vconfig.pitch = res.width * sizeof(u32);
|
||||
vconfig.aspect = state.displayMode.aspect;
|
||||
gcm_wait_rsx_idle(context);
|
||||
|
||||
gcm->width = res.width;
|
||||
gcm->height = res.height;
|
||||
if (videoConfigure (0, &vconfig, NULL, 0) != 0)
|
||||
goto error;
|
||||
|
||||
waitRSXIdle(context);
|
||||
if (videoGetState (0, 0, &state) != 0)
|
||||
goto error;
|
||||
|
||||
if (videoConfigure (0, &vconfig, NULL, 0) != 0)
|
||||
goto error;
|
||||
gcmSetFlipMode (GCM_FLIP_VSYNC); /* Wait for VSYNC to flip */
|
||||
|
||||
if (videoGetState (0, 0, &state) != 0)
|
||||
goto error;
|
||||
gcm->depth_pitch = res.width * sizeof(u32);
|
||||
gcm->depth_buffer = (u32 *) rsxMemalign (64, (res.height * gcm->depth_pitch)* 2);
|
||||
rsxAddressToOffset (gcm->depth_buffer, &gcm->depth_offset);
|
||||
|
||||
gcmSetFlipMode (GCM_FLIP_VSYNC); // Wait for VSYNC to flip
|
||||
gcmResetFlipStatus();
|
||||
|
||||
gcm->depth_pitch = res.width * sizeof(u32);
|
||||
gcm->depth_buffer = (u32 *) rsxMemalign (64, (res.height * gcm->depth_pitch)* 2);
|
||||
rsxAddressToOffset (gcm->depth_buffer, &gcm->depth_offset);
|
||||
return context;
|
||||
|
||||
gcmResetFlipStatus();
|
||||
error:
|
||||
#if 0
|
||||
if (context)
|
||||
rsxFinish (context, 0);
|
||||
|
||||
return context;
|
||||
if (gcm->host_addr)
|
||||
free (gcm->host_addr);
|
||||
#endif
|
||||
|
||||
error:
|
||||
// if (context)
|
||||
// rsxFinish (context, 0);
|
||||
|
||||
// if (gcm->host_addr)
|
||||
// free (gcm->host_addr);
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -267,8 +267,7 @@ waitFinish(gcmContextData *context, u32 sLabelVal)
|
||||
sLabelVal++;
|
||||
}
|
||||
|
||||
static void
|
||||
waitRSXIdle(gcmContextData *context)
|
||||
static void gcm_wait_rsx_idle(gcmContextData *context)
|
||||
{
|
||||
u32 sLabelVal = 1;
|
||||
|
||||
@@ -283,7 +282,7 @@ waitRSXIdle(gcmContextData *context)
|
||||
static void* gcm_init(const video_info_t* video,
|
||||
input_driver_t** input, void** input_data)
|
||||
{
|
||||
RARCH_LOG("Reached gcm_init\n");
|
||||
int i;
|
||||
gcm_video_t* gcm = malloc(sizeof(gcm_video_t));
|
||||
|
||||
if (!gcm)
|
||||
@@ -291,17 +290,15 @@ static void* gcm_init(const video_info_t* video,
|
||||
|
||||
memset(gcm, 0, sizeof(gcm_video_t));
|
||||
|
||||
int i;
|
||||
|
||||
gcm->context = initScreen (gcm);
|
||||
gcm->context = gcm_init_screen(gcm);
|
||||
|
||||
for (i = 0; i < MAX_BUFFERS; i++)
|
||||
makeBuffer( &gcm->buffers[i], gcm->width, gcm->height, i);
|
||||
gcm_make_buffer(&gcm->buffers[i], gcm->width, gcm->height, i);
|
||||
|
||||
for (i = 0; i < MAX_BUFFERS; i++)
|
||||
makeBuffer( &gcm->menuBuffers[i], gcm->width, gcm->height, i + MAX_BUFFERS);
|
||||
gcm_make_buffer(&gcm->menuBuffers[i], gcm->width, gcm->height, i + MAX_BUFFERS);
|
||||
|
||||
flip(gcm->context, MAX_BUFFERS - 1);
|
||||
gcm_flip(gcm->context, MAX_BUFFERS - 1);
|
||||
|
||||
gcm->vp.x = 0;
|
||||
gcm->vp.y = 0;
|
||||
@@ -318,41 +315,44 @@ static void* gcm_init(const video_info_t* video,
|
||||
*input = ps3input ? &input_ps3 : NULL;
|
||||
*input_data = ps3input;
|
||||
}
|
||||
RARCH_LOG("gcm_init done\n");
|
||||
|
||||
return gcm;
|
||||
}
|
||||
|
||||
static void black (uint32_t *dst, uint32_t *dst_end, size_t sz)
|
||||
static void gcm_fill_black(uint32_t *dst, uint32_t *dst_end, size_t sz)
|
||||
{
|
||||
if (sz > dst_end - dst)
|
||||
sz = dst_end - dst;
|
||||
memset (dst, 0, sz * 4);
|
||||
}
|
||||
|
||||
static void blitBuffer(rsxBuffer *buffer, const void *frame, unsigned width,
|
||||
unsigned height, unsigned pitch, int rgb32, bool do_scaling)
|
||||
static void gcm_blit_buffer(
|
||||
rsxBuffer *buffer, const void *frame, unsigned width,
|
||||
unsigned height, unsigned pitch, int rgb32, bool do_scaling)
|
||||
{
|
||||
if (width > buffer->width)
|
||||
int scale = 1, xofs = 0, yofs = 0;
|
||||
if (width > buffer->width)
|
||||
width = buffer->width;
|
||||
if (height > buffer->height)
|
||||
height = buffer->height;
|
||||
int scale = 1, xofs = 0, yofs = 0;
|
||||
|
||||
if (do_scaling) {
|
||||
scale = buffer->width / width;
|
||||
if (scale > buffer->height / height)
|
||||
scale = buffer->height / height;
|
||||
if (scale >= 10)
|
||||
scale = 10;
|
||||
if (scale >= 1) {
|
||||
xofs = (buffer->width - width * scale) / 2;
|
||||
yofs = (buffer->height - height * scale) / 2;
|
||||
} else
|
||||
scale = 1;
|
||||
if (do_scaling)
|
||||
{
|
||||
scale = buffer->width / width;
|
||||
if (scale > buffer->height / height)
|
||||
scale = buffer->height / height;
|
||||
if (scale >= 10)
|
||||
scale = 10;
|
||||
if (scale >= 1)
|
||||
{
|
||||
xofs = (buffer->width - width * scale) / 2;
|
||||
yofs = (buffer->height - height * scale) / 2;
|
||||
}
|
||||
else
|
||||
scale = 1;
|
||||
}
|
||||
|
||||
// TODO: let rsx do the copy
|
||||
/* TODO: let rsx do the copy */
|
||||
int i;
|
||||
int pre_clean = xofs + buffer->width * yofs;
|
||||
uint32_t *dst = buffer->ptr;
|
||||
@@ -361,83 +361,94 @@ static void blitBuffer(rsxBuffer *buffer, const void *frame, unsigned width,
|
||||
memset (dst, 0, pre_clean * 4);
|
||||
dst += pre_clean;
|
||||
|
||||
if (scale == 1) {
|
||||
if (rgb32) {
|
||||
const uint8_t *src = frame;
|
||||
for (i = 0; i < height; i++)
|
||||
{
|
||||
memcpy(dst, src, width * 4);
|
||||
black(dst + width, dst_end, buffer->width - width);
|
||||
dst += buffer->width;
|
||||
src += pitch;
|
||||
}
|
||||
} else {
|
||||
const uint16_t *src = frame;
|
||||
for (i = 0; i < height; i++)
|
||||
{
|
||||
for (int j = 0; j < width; j++, src++, dst++) {
|
||||
u16 rgb565 = *src;
|
||||
u8 r = ((rgb565 >> 8) & 0xf8);
|
||||
u8 g = ((rgb565 >> 3) & 0xfc);
|
||||
u8 b = ((rgb565 << 3) & 0xfc);
|
||||
*dst = (r<<16) | (g<<8) | b;
|
||||
}
|
||||
black(dst, dst_end, buffer->width - width);
|
||||
if (scale == 1)
|
||||
{
|
||||
if (rgb32)
|
||||
{
|
||||
const uint8_t *src = frame;
|
||||
for (i = 0; i < height; i++)
|
||||
{
|
||||
memcpy(dst, src, width * 4);
|
||||
gcm_fill_black(dst + width, dst_end, buffer->width - width);
|
||||
dst += buffer->width;
|
||||
src += pitch;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint16_t *src = frame;
|
||||
for (i = 0; i < height; i++)
|
||||
{
|
||||
for (int j = 0; j < width; j++, src++, dst++)
|
||||
{
|
||||
u16 rgb565 = *src;
|
||||
u8 r = ((rgb565 >> 8) & 0xf8);
|
||||
u8 g = ((rgb565 >> 3) & 0xfc);
|
||||
u8 b = ((rgb565 << 3) & 0xfc);
|
||||
*dst = (r<<16) | (g<<8) | b;
|
||||
}
|
||||
gcm_fill_black(dst, dst_end, buffer->width - width);
|
||||
|
||||
dst += buffer->width - width;
|
||||
src += pitch / 2 - width;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (rgb32) {
|
||||
const uint32_t *src = frame;
|
||||
for (i = 0; i < height; i++)
|
||||
{
|
||||
for (int j = 0; j < width; j++, src++) {
|
||||
u32 c = *src;
|
||||
for (int k = 0; k < scale; k++, dst++)
|
||||
for (int l = 0; l < scale; l++)
|
||||
dst[l * buffer->width] = c;
|
||||
}
|
||||
for (int l = 0; l < scale; l++)
|
||||
black(dst + l * buffer->width, dst_end, buffer->width - width * scale);
|
||||
dst += buffer->width - width;
|
||||
src += pitch / 2 - width;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rgb32)
|
||||
{
|
||||
const uint32_t *src = frame;
|
||||
for (i = 0; i < height; i++)
|
||||
{
|
||||
for (int j = 0; j < width; j++, src++)
|
||||
{
|
||||
u32 c = *src;
|
||||
for (int k = 0; k < scale; k++, dst++)
|
||||
for (int l = 0; l < scale; l++)
|
||||
dst[l * buffer->width] = c;
|
||||
}
|
||||
for (int l = 0; l < scale; l++)
|
||||
gcm_fill_black(dst + l * buffer->width, dst_end, buffer->width - width * scale);
|
||||
|
||||
dst += buffer->width * scale - width * scale;
|
||||
src += pitch / 4 - width;
|
||||
}
|
||||
} else {
|
||||
const uint16_t *src = frame;
|
||||
for (i = 0; i < height; i++)
|
||||
{
|
||||
for (int j = 0; j < width; j++, src++) {
|
||||
u16 rgb565 = *src;
|
||||
u8 r = ((rgb565 >> 8) & 0xf8);
|
||||
u8 g = ((rgb565 >> 3) & 0xfc);
|
||||
u8 b = ((rgb565 << 3) & 0xfc);
|
||||
u32 c = (r<<16) | (g<<8) | b;
|
||||
for (int k = 0; k < scale; k++, dst++)
|
||||
for (int l = 0; l < scale; l++)
|
||||
dst[l * buffer->width] = c;
|
||||
}
|
||||
for (int l = 0; l < scale; l++)
|
||||
black(dst + l * buffer->width, dst_end, buffer->width - width * scale);
|
||||
dst += buffer->width * scale - width * scale;
|
||||
src += pitch / 4 - width;
|
||||
}
|
||||
} else {
|
||||
const uint16_t *src = frame;
|
||||
for (i = 0; i < height; i++)
|
||||
{
|
||||
for (int j = 0; j < width; j++, src++)
|
||||
{
|
||||
u16 rgb565 = *src;
|
||||
u8 r = ((rgb565 >> 8) & 0xf8);
|
||||
u8 g = ((rgb565 >> 3) & 0xfc);
|
||||
u8 b = ((rgb565 << 3) & 0xfc);
|
||||
u32 c = (r<<16) | (g<<8) | b;
|
||||
for (int k = 0; k < scale; k++, dst++)
|
||||
for (int l = 0; l < scale; l++)
|
||||
dst[l * buffer->width] = c;
|
||||
}
|
||||
for (int l = 0; l < scale; l++)
|
||||
gcm_fill_black(dst + l * buffer->width, dst_end, buffer->width - width * scale);
|
||||
|
||||
dst += buffer->width * scale - width * scale;
|
||||
src += pitch / 2 - width;
|
||||
}
|
||||
}
|
||||
dst += buffer->width * scale - width * scale;
|
||||
src += pitch / 2 - width;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dst < dst_end)
|
||||
memset(dst, 0, 4 * (dst_end - dst));
|
||||
memset(dst, 0, 4 * (dst_end - dst));
|
||||
}
|
||||
|
||||
static void gcm_update_screen(gcm_video_t *gcm) {
|
||||
rsxBuffer *buffer = gcm->menu_frame_enable
|
||||
? &gcm->menuBuffers[gcm->menuBuffer]
|
||||
: &gcm->buffers[gcm->currentBuffer];
|
||||
flip(gcm->context, buffer->id);
|
||||
if (gcm->vsync)
|
||||
waitFlip();
|
||||
static void gcm_update_screen(gcm_video_t *gcm)
|
||||
{
|
||||
rsxBuffer *buffer = gcm->menu_frame_enable
|
||||
? &gcm->menuBuffers[gcm->menuBuffer]
|
||||
: &gcm->buffers[gcm->currentBuffer];
|
||||
gcm_flip(gcm->context, buffer->id);
|
||||
if (gcm->vsync)
|
||||
gcm_wait_flip();
|
||||
#ifdef HAVE_SYSUTILS
|
||||
cellSysutilCheckCallback();
|
||||
#endif
|
||||
@@ -452,14 +463,15 @@ static bool gcm_frame(void* data, const void* frame,
|
||||
|
||||
if(frame && width && height)
|
||||
{
|
||||
gcm->currentBuffer++;
|
||||
if (gcm->currentBuffer >= MAX_BUFFERS)
|
||||
gcm->currentBuffer = 0;
|
||||
blitBuffer(&gcm->buffers[gcm->currentBuffer], frame, width, height, pitch,
|
||||
gcm->rgb32, true);
|
||||
gcm->currentBuffer++;
|
||||
if (gcm->currentBuffer >= MAX_BUFFERS)
|
||||
gcm->currentBuffer = 0;
|
||||
gcm_blit_buffer(
|
||||
&gcm->buffers[gcm->currentBuffer], frame, width, height, pitch,
|
||||
gcm->rgb32, true);
|
||||
}
|
||||
|
||||
// TODO: translucid menu
|
||||
/* TODO: translucid menu */
|
||||
gcm_update_screen(gcm);
|
||||
|
||||
return true;
|
||||
@@ -524,21 +536,23 @@ static void gcm_free(void* data)
|
||||
for (int i = 0; i < MAX_BUFFERS; i++)
|
||||
rsxFree(gcm->menuBuffers[i].ptr);
|
||||
|
||||
//rsxFinish(gcm->context, 1);
|
||||
// free(gcm->host_addr);
|
||||
#if 0
|
||||
rsxFinish(gcm->context, 1);
|
||||
free(gcm->host_addr);
|
||||
#endif
|
||||
free (gcm);
|
||||
}
|
||||
|
||||
static void gcm_set_texture_frame(void* data, const void* frame, bool rgb32,
|
||||
unsigned width, unsigned height, float alpha)
|
||||
unsigned width, unsigned height, float alpha)
|
||||
{
|
||||
gcm_video_t* gcm = (gcm_video_t*)data;
|
||||
|
||||
int newBuffer = gcm->menuBuffer + 1;
|
||||
if (newBuffer >= MAX_BUFFERS)
|
||||
newBuffer = 0;
|
||||
// TODO: respect alpha
|
||||
blitBuffer(&gcm->menuBuffers[newBuffer], frame, width, height,
|
||||
/* TODO: respect alpha */
|
||||
gcm_blit_buffer(&gcm->menuBuffers[newBuffer], frame, width, height,
|
||||
width * (rgb32 ? 4 : 2), rgb32, true);
|
||||
gcm->menuBuffer = newBuffer;
|
||||
|
||||
@@ -605,7 +619,6 @@ static void gcm_viewport_info(void* data, struct video_viewport* vp)
|
||||
*vp = gcm->vp;
|
||||
}
|
||||
|
||||
|
||||
static void gcm_set_osd_msg(void *data,
|
||||
video_frame_info_t *video_info,
|
||||
const char *msg,
|
||||
@@ -649,14 +662,14 @@ static const video_poke_interface_t gcm_poke_interface = {
|
||||
};
|
||||
|
||||
static void gcm_get_poke_interface(void* data,
|
||||
const video_poke_interface_t** iface)
|
||||
const video_poke_interface_t** iface)
|
||||
{
|
||||
(void)data;
|
||||
*iface = &gcm_poke_interface;
|
||||
}
|
||||
|
||||
static bool gcm_set_shader(void* data,
|
||||
enum rarch_shader_type type, const char* path)
|
||||
enum rarch_shader_type type, const char* path)
|
||||
{
|
||||
(void)data;
|
||||
(void)type;
|
||||
|
||||
+6
-24
@@ -349,8 +349,9 @@ static bool gdi_gfx_frame(void *data, const void *frame,
|
||||
|
||||
InvalidateRect(hwnd, NULL, false);
|
||||
|
||||
video_info->cb_update_window_title(
|
||||
video_info->context_data);
|
||||
if (gdi->ctx_driver->update_window_title)
|
||||
gdi->ctx_driver->update_window_title(
|
||||
video_info->context_data);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -490,25 +491,6 @@ static void gdi_set_texture_frame(void *data,
|
||||
}
|
||||
}
|
||||
|
||||
static void gdi_get_video_output_size(void *data,
|
||||
unsigned *width, unsigned *height)
|
||||
{
|
||||
gfx_ctx_size_t size_data;
|
||||
size_data.width = width;
|
||||
size_data.height = height;
|
||||
video_context_driver_get_video_output_size(&size_data);
|
||||
}
|
||||
|
||||
static void gdi_get_video_output_prev(void *data)
|
||||
{
|
||||
video_context_driver_get_video_output_prev();
|
||||
}
|
||||
|
||||
static void gdi_get_video_output_next(void *data)
|
||||
{
|
||||
video_context_driver_get_video_output_next();
|
||||
}
|
||||
|
||||
static void gdi_set_video_mode(void *data, unsigned width, unsigned height,
|
||||
bool fullscreen)
|
||||
{
|
||||
@@ -589,9 +571,9 @@ static const video_poke_interface_t gdi_poke_interface = {
|
||||
gdi_set_video_mode,
|
||||
win32_get_refresh_rate,
|
||||
NULL,
|
||||
gdi_get_video_output_size,
|
||||
gdi_get_video_output_prev,
|
||||
gdi_get_video_output_next,
|
||||
NULL, /* get_video_output_size */
|
||||
NULL, /* get_video_output_prev */
|
||||
NULL, /* get_video_output_next */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
+5
-4
@@ -3065,8 +3065,8 @@ static bool gl2_frame(void *data, const void *frame,
|
||||
font_driver_render_msg(gl, msg, NULL, NULL);
|
||||
}
|
||||
|
||||
if (video_info->cb_update_window_title)
|
||||
video_info->cb_update_window_title(context_data);
|
||||
if (gl->ctx_driver->update_window_title)
|
||||
gl->ctx_driver->update_window_title(context_data);
|
||||
|
||||
/* Reset state which could easily mess up libretro core. */
|
||||
if (gl->hw_render_fbo_init)
|
||||
@@ -3100,12 +3100,13 @@ static bool gl2_frame(void *data, const void *frame,
|
||||
&& !runloop_is_slowmotion
|
||||
&& !runloop_is_paused)
|
||||
{
|
||||
video_info->cb_swap_buffers(context_data);
|
||||
if (gl->ctx_driver->swap_buffers)
|
||||
gl->ctx_driver->swap_buffers(context_data);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
#endif
|
||||
|
||||
video_info->cb_swap_buffers(context_data);
|
||||
gl->ctx_driver->swap_buffers(context_data);
|
||||
|
||||
/* check if we are fast forwarding or in menu, if we are ignore hard sync */
|
||||
if ( gl->have_sync
|
||||
|
||||
+5
-4
@@ -869,8 +869,9 @@ static bool gl1_gfx_frame(void *data, const void *frame,
|
||||
if (msg)
|
||||
font_driver_render_msg(gl1, msg, NULL, NULL);
|
||||
|
||||
video_info->cb_update_window_title(
|
||||
video_info->context_data);
|
||||
if (gl1->ctx_driver->update_window_title)
|
||||
gl1->ctx_driver->update_window_title(
|
||||
video_info->context_data);
|
||||
|
||||
/* Screenshots. */
|
||||
if (gl1->readback_buffer_screenshot)
|
||||
@@ -888,12 +889,12 @@ static bool gl1_gfx_frame(void *data, const void *frame,
|
||||
&& !video_info->runloop_is_slowmotion
|
||||
&& !video_info->runloop_is_paused)
|
||||
{
|
||||
video_info->cb_swap_buffers(video_info->context_data);
|
||||
gl1->ctx_driver->swap_buffers(video_info->context_data);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
#endif
|
||||
|
||||
video_info->cb_swap_buffers(video_info->context_data);
|
||||
gl1->ctx_driver->swap_buffers(video_info->context_data);
|
||||
|
||||
/* check if we are fast forwarding or in menu, if we are ignore hard sync */
|
||||
if (video_info->hard_sync
|
||||
|
||||
@@ -1949,7 +1949,8 @@ static bool gl_core_frame(void *data, const void *frame,
|
||||
font_driver_render_msg(gl, msg, NULL, NULL);
|
||||
}
|
||||
|
||||
video_info->cb_update_window_title(context_data);
|
||||
if (gl->ctx_driver->update_window_title)
|
||||
gl->ctx_driver->update_window_title(context_data);
|
||||
|
||||
if (gl->readback_buffer_screenshot)
|
||||
{
|
||||
@@ -1973,11 +1974,11 @@ static bool gl_core_frame(void *data, const void *frame,
|
||||
&& !runloop_is_slowmotion
|
||||
&& !runloop_is_paused)
|
||||
{
|
||||
video_info->cb_swap_buffers(context_data);
|
||||
gl->ctx_driver->swap_buffers(context_data);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
video_info->cb_swap_buffers(context_data);
|
||||
gl->ctx_driver->swap_buffers(context_data);
|
||||
|
||||
if (video_info->hard_sync &&
|
||||
!input_driver_nonblock_state &&
|
||||
|
||||
@@ -176,6 +176,7 @@ static void render_msg(oga_video_t* vid, go2_surface_t* surface, const char* msg
|
||||
const struct font_atlas* atlas = vid->font_driver->get_atlas(vid->font);
|
||||
int msg_width = get_message_width(vid, msg);
|
||||
int dest_x = MAX(0, width - get_message_width(vid, msg));
|
||||
int dest_stride = go2_surface_stride_get(surface);
|
||||
|
||||
const char* c = msg;
|
||||
while (*c) {
|
||||
@@ -202,7 +203,7 @@ static void render_msg(oga_video_t* vid, go2_surface_t* surface, const char* msg
|
||||
*(dest++) = px;
|
||||
}
|
||||
}
|
||||
dest += go2_surface_stride_get(surface) - g->advance_x * bpp;
|
||||
dest += dest_stride - g->advance_x * bpp;
|
||||
source += atlas->width - g->width;
|
||||
}
|
||||
|
||||
@@ -239,10 +240,11 @@ static bool oga_gfx_frame(void *data, const void *frame, unsigned width,
|
||||
uint8_t* dst = (uint8_t*)go2_surface_map(dst_surface);
|
||||
int yy = height;
|
||||
int stride = width * bpp;
|
||||
int dst_stride = go2_surface_stride_get(dst_surface);
|
||||
while (yy > 0) {
|
||||
memcpy(dst, src, stride);
|
||||
src += pitch;
|
||||
dst += go2_surface_stride_get(dst_surface);
|
||||
dst += dst_stride;
|
||||
--yy;
|
||||
}
|
||||
|
||||
|
||||
+4
-3
@@ -454,9 +454,10 @@ static bool vg_frame(void *data, const void *frame,
|
||||
vg_draw_message(vg, msg);
|
||||
#endif
|
||||
|
||||
video_info->cb_update_window_title(
|
||||
video_info->context_data);
|
||||
video_info->cb_swap_buffers(video_info->context_data);
|
||||
if (vg->ctx_driver->update_window_title)
|
||||
vg->ctx_driver->update_window_title(video_info->context_data);
|
||||
|
||||
vg->ctx_driver->swap_buffers(video_info->context_data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+71
-55
@@ -33,7 +33,7 @@
|
||||
|
||||
static void vga_set_mode_13h(void)
|
||||
{
|
||||
__dpmi_regs r;
|
||||
__dpmi_regs r = {0};
|
||||
|
||||
r.x.ax = 0x13;
|
||||
__dpmi_int(0x10, &r);
|
||||
@@ -41,7 +41,7 @@ static void vga_set_mode_13h(void)
|
||||
|
||||
static void vga_return_to_text_mode(void)
|
||||
{
|
||||
__dpmi_regs r;
|
||||
__dpmi_regs r = {0};
|
||||
|
||||
r.x.ax = 3;
|
||||
__dpmi_int(0x10, &r);
|
||||
@@ -106,22 +106,22 @@ static void *vga_gfx_init(const video_info_t *video,
|
||||
*input = NULL;
|
||||
*input_data = NULL;
|
||||
|
||||
vga->video_width = video->width;
|
||||
vga->video_height = video->height;
|
||||
vga->rgb32 = video->rgb32;
|
||||
vga->vga_video_width = video->width;
|
||||
vga->vga_video_height = video->height;
|
||||
vga->vga_rgb32 = video->rgb32;
|
||||
|
||||
if (video->rgb32)
|
||||
{
|
||||
vga->video_pitch = video->width * 4;
|
||||
vga->video_bits = 32;
|
||||
vga->vga_video_pitch = video->width * 4;
|
||||
vga->vga_video_bits = 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
vga->video_pitch = video->width * 2;
|
||||
vga->video_bits = 16;
|
||||
vga->vga_video_pitch = video->width * 2;
|
||||
vga->vga_video_bits = 16;
|
||||
}
|
||||
|
||||
vga->frame = (unsigned char*)malloc(VGA_WIDTH * VGA_HEIGHT);
|
||||
vga->vga_frame = (unsigned char*)malloc(VGA_WIDTH * VGA_HEIGHT);
|
||||
|
||||
vga_gfx_create();
|
||||
|
||||
@@ -152,32 +152,32 @@ static bool vga_gfx_frame(void *data, const void *frame,
|
||||
menu_driver_frame(video_info);
|
||||
#endif
|
||||
|
||||
if ( vga->video_width != frame_width ||
|
||||
vga->video_height != frame_height ||
|
||||
vga->video_pitch != pitch)
|
||||
if ( vga->vga_video_width != frame_width ||
|
||||
vga->vga_video_height != frame_height ||
|
||||
vga->vga_video_pitch != pitch)
|
||||
{
|
||||
if (frame_width > 4 && frame_height > 4)
|
||||
{
|
||||
vga->video_width = frame_width;
|
||||
vga->video_height = frame_height;
|
||||
vga->video_pitch = pitch;
|
||||
vga->vga_video_width = frame_width;
|
||||
vga->vga_video_height = frame_height;
|
||||
vga->vga_video_pitch = pitch;
|
||||
}
|
||||
}
|
||||
|
||||
if (vga->menu_frame && video_info->menu_is_alive)
|
||||
if (vga->vga_menu_frame && video_info->menu_is_alive)
|
||||
{
|
||||
frame_to_copy = vga->menu_frame;
|
||||
width = vga->menu_width;
|
||||
height = vga->menu_height;
|
||||
pitch = vga->menu_pitch;
|
||||
bits = vga->menu_bits;
|
||||
frame_to_copy = vga->vga_menu_frame;
|
||||
width = vga->vga_menu_width;
|
||||
height = vga->vga_menu_height;
|
||||
pitch = vga->vga_menu_pitch;
|
||||
bits = vga->vga_menu_bits;
|
||||
}
|
||||
else
|
||||
{
|
||||
width = vga->video_width;
|
||||
height = vga->video_height;
|
||||
pitch = vga->video_pitch;
|
||||
bits = vga->video_bits;
|
||||
width = vga->vga_video_width;
|
||||
height = vga->vga_video_height;
|
||||
pitch = vga->vga_video_pitch;
|
||||
bits = vga->vga_video_bits;
|
||||
|
||||
if (frame_width == 4 && frame_height == 4 && (frame_width < width && frame_height < height))
|
||||
draw = false;
|
||||
@@ -190,14 +190,33 @@ static bool vga_gfx_frame(void *data, const void *frame,
|
||||
{
|
||||
vga_vsync();
|
||||
|
||||
if (frame_to_copy == vga->menu_frame)
|
||||
if (frame_to_copy == vga->vga_menu_frame)
|
||||
dosmemput(frame_to_copy,
|
||||
MIN(VGA_WIDTH,width)*MIN(VGA_HEIGHT,height), 0xA0000);
|
||||
else
|
||||
{
|
||||
if (bits == 32)
|
||||
{
|
||||
/* TODO/FIXME - needs to be implemented */
|
||||
unsigned x, y;
|
||||
for (y = 0; y < VGA_HEIGHT; y++)
|
||||
{
|
||||
for (x = 0; x < VGA_WIDTH; x++)
|
||||
{
|
||||
/* scale incoming frame to fit the screen */
|
||||
unsigned scaled_x = (width * x) / VGA_WIDTH;
|
||||
unsigned scaled_y = (height * y) / VGA_HEIGHT;
|
||||
uint32_t pixel = ((uint32_t*)frame_to_copy)[width * scaled_y + scaled_x];
|
||||
|
||||
/* convert RGB888 to BGR332 */
|
||||
unsigned r = ((pixel & 0xFF0000) >> 21);
|
||||
unsigned g = ((pixel & 0x00FF00) >> 13);
|
||||
unsigned b = ((pixel & 0x0000FF) >> 6);
|
||||
|
||||
vga->vga_frame[VGA_WIDTH * y + x] = (b << 6) | (g << 3) | r;
|
||||
}
|
||||
}
|
||||
|
||||
dosmemput(vga->vga_frame, VGA_WIDTH*VGA_HEIGHT, 0xA0000);
|
||||
}
|
||||
else if (bits == 16)
|
||||
{
|
||||
@@ -217,11 +236,11 @@ static bool vga_gfx_frame(void *data, const void *frame,
|
||||
unsigned g = ((pixel & 0x07E0) >> 8);
|
||||
unsigned b = ((pixel & 0x001F) >> 3);
|
||||
|
||||
vga->frame[VGA_WIDTH * y + x] = (b << 6) | (g << 3) | r;
|
||||
vga->vga_frame[VGA_WIDTH * y + x] = (b << 6) | (g << 3) | r;
|
||||
}
|
||||
}
|
||||
|
||||
dosmemput(vga->frame, VGA_WIDTH*VGA_HEIGHT, 0xA0000);
|
||||
dosmemput(vga->vga_frame, VGA_WIDTH*VGA_HEIGHT, 0xA0000);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -229,9 +248,6 @@ static bool vga_gfx_frame(void *data, const void *frame,
|
||||
if (msg)
|
||||
font_driver_render_msg(data, msg, NULL, NULL);
|
||||
|
||||
video_info->cb_update_window_title(
|
||||
video_info->context_data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -242,7 +258,7 @@ static bool vga_gfx_alive(void *data)
|
||||
{
|
||||
vga_t *vga = (vga_t*)data;
|
||||
/* TODO/FIXME - check if this is valid */
|
||||
video_driver_set_size(vga->video_width, vga->video_height);
|
||||
video_driver_set_size(vga->vga_video_width, vga->vga_video_height);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -266,13 +282,13 @@ static void vga_gfx_free(void *data)
|
||||
if (!vga)
|
||||
return;
|
||||
|
||||
if (vga->frame)
|
||||
free(vga->frame);
|
||||
vga->frame = NULL;
|
||||
if (vga->vga_frame)
|
||||
free(vga->vga_frame);
|
||||
vga->vga_frame = NULL;
|
||||
|
||||
if (vga->menu_frame)
|
||||
free(vga->menu_frame);
|
||||
vga->menu_frame = NULL;
|
||||
if (vga->vga_menu_frame)
|
||||
free(vga->vga_menu_frame);
|
||||
vga->vga_menu_frame = NULL;
|
||||
|
||||
vga_return_to_text_mode();
|
||||
}
|
||||
@@ -297,18 +313,18 @@ static void vga_set_texture_frame(void *data,
|
||||
if (rgb32)
|
||||
pitch = width * 4;
|
||||
|
||||
if (vga->menu_frame)
|
||||
free(vga->menu_frame);
|
||||
vga->menu_frame = NULL;
|
||||
if (vga->vga_menu_frame)
|
||||
free(vga->vga_menu_frame);
|
||||
vga->vga_menu_frame = NULL;
|
||||
|
||||
if ( !vga->menu_frame ||
|
||||
vga->menu_width != width ||
|
||||
vga->menu_height != height ||
|
||||
vga->menu_pitch != pitch)
|
||||
if ( !vga->vga_menu_frame ||
|
||||
vga->vga_menu_width != width ||
|
||||
vga->vga_menu_height != height ||
|
||||
vga->vga_menu_pitch != pitch)
|
||||
if (pitch && height)
|
||||
vga->menu_frame = (unsigned char*)malloc(VGA_WIDTH * VGA_HEIGHT);
|
||||
vga->vga_menu_frame = (unsigned char*)malloc(VGA_WIDTH * VGA_HEIGHT);
|
||||
|
||||
if (vga->menu_frame && frame && pitch && height)
|
||||
if (vga->vga_menu_frame && frame && pitch && height)
|
||||
{
|
||||
unsigned x, y;
|
||||
|
||||
@@ -327,15 +343,15 @@ static void vga_set_texture_frame(void *data,
|
||||
unsigned r = ((pixel & 0xF000) >> 13);
|
||||
unsigned g = ((pixel & 0xF00) >> 9);
|
||||
unsigned b = ((pixel & 0xF0) >> 6);
|
||||
vga->menu_frame[VGA_WIDTH * y + x] = (b << 6) | (g << 3) | r;
|
||||
vga->vga_menu_frame[VGA_WIDTH * y + x] = (b << 6) | (g << 3) | r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vga->menu_width = width;
|
||||
vga->menu_height = height;
|
||||
vga->menu_pitch = pitch;
|
||||
vga->menu_bits = rgb32 ? 32 : 16;
|
||||
vga->vga_menu_width = width;
|
||||
vga->vga_menu_height = height;
|
||||
vga->vga_menu_pitch = pitch;
|
||||
vga->vga_menu_bits = rgb32 ? 32 : 16;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,7 +363,7 @@ static uint32_t vga_get_flags(void *data)
|
||||
}
|
||||
|
||||
static const video_poke_interface_t vga_poke_interface = {
|
||||
vga_gfx_get_flags,
|
||||
vga_get_flags,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -1659,7 +1659,7 @@ static void vulkan_inject_black_frame(vk_t *vk, video_frame_info_t *video_info,
|
||||
slock_unlock(vk->context->queue_lock);
|
||||
#endif
|
||||
|
||||
video_info->cb_swap_buffers(context_data);
|
||||
vk->ctx_driver->swap_buffers(context_data);
|
||||
}
|
||||
|
||||
static bool vulkan_frame(void *data, const void *frame,
|
||||
@@ -1686,7 +1686,6 @@ static bool vulkan_frame(void *data, const void *frame,
|
||||
struct font_params *osd_params = (struct font_params*)
|
||||
&video_info->osd_stat_params;
|
||||
|
||||
|
||||
VkCommandBufferBeginInfo begin_info = {
|
||||
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
|
||||
VkRenderPassBeginInfo rp_info = {
|
||||
@@ -1974,7 +1973,7 @@ static bool vulkan_frame(void *data, const void *frame,
|
||||
if (osd_params)
|
||||
font_driver_render_msg(vk,
|
||||
stat_text,
|
||||
&osd_params, NULL);
|
||||
osd_params, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2116,10 +2115,13 @@ static bool vulkan_frame(void *data, const void *frame,
|
||||
slock_unlock(vk->context->queue_lock);
|
||||
#endif
|
||||
|
||||
video_info->cb_swap_buffers(context_data);
|
||||
vk->ctx_driver->swap_buffers(context_data);
|
||||
|
||||
if (!vk->context->swap_interval_emulation_lock)
|
||||
video_info->cb_update_window_title(context_data);
|
||||
{
|
||||
if (vk->ctx_driver->update_window_title)
|
||||
vk->ctx_driver->update_window_title(context_data);
|
||||
}
|
||||
|
||||
/* Handle spurious swapchain invalidations as soon as we can,
|
||||
* i.e. right after swap buffers. */
|
||||
|
||||
@@ -89,6 +89,7 @@ static void gfx_display_wiiu_draw(gfx_display_ctx_draw_t *draw,
|
||||
}
|
||||
|
||||
}
|
||||
/* TODO come up with a better check for "not all vertexes are the same color" */
|
||||
else if (draw->coords->vertex || draw->coords->color[0] != draw->coords->color[12])
|
||||
{
|
||||
if (wiiu->vertex_cache_tex.current + 4 > wiiu->vertex_cache_tex.size)
|
||||
@@ -106,14 +107,20 @@ static void gfx_display_wiiu_draw(gfx_display_ctx_draw_t *draw,
|
||||
|
||||
if (!draw->coords->vertex)
|
||||
{
|
||||
v[0].pos.x = 0.0f;
|
||||
v[0].pos.y = 1.0f;
|
||||
v[1].pos.x = 1.0f;
|
||||
v[1].pos.y = 1.0f;
|
||||
v[2].pos.x = 0.0f;
|
||||
v[2].pos.y = 0.0f;
|
||||
v[3].pos.x = 1.0f;
|
||||
v[3].pos.y = 0.0f;
|
||||
/* Convert the libretro bottom-up coordinate system to GX2 - low y at
|
||||
the top of the screen, large y at the bottom
|
||||
The compiler will optimise 90% of this out anyway */
|
||||
float y = -(draw->y + draw->height - video_height);
|
||||
/* Remember: this is a triangle strip, not a quad, draw in a Z shape
|
||||
Bottom-left, right, top-left, right */
|
||||
v[0].pos.x = (draw->x ) / video_width;
|
||||
v[0].pos.y = (y + draw->height) / video_height;
|
||||
v[1].pos.x = (draw->x + draw->width ) / video_width;
|
||||
v[1].pos.y = (y + draw->height) / video_height;
|
||||
v[2].pos.x = (draw->x ) / video_width;
|
||||
v[2].pos.y = (y ) / video_height;
|
||||
v[3].pos.x = (draw->x + draw->width ) / video_width;
|
||||
v[3].pos.y = (y ) / video_height;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -243,7 +243,7 @@ static void ctr_font_render_line(
|
||||
GPU_TEVSOURCES(GPU_TEXTURE0, GPU_CONSTANT, 0),
|
||||
GPU_TEVSOURCES(GPU_TEXTURE0, GPU_CONSTANT, 0),
|
||||
0,
|
||||
GPU_TEVOPERANDS(GPU_TEVOP_RGB_SRC_R, GPU_TEVOP_RGB_SRC_ALPHA, 0),
|
||||
GPU_TEVOPERANDS(GPU_TEVOP_RGB_SRC_ALPHA, 0, 0),
|
||||
GPU_MODULATE, GPU_MODULATE,
|
||||
color);
|
||||
|
||||
@@ -329,7 +329,7 @@ static void ctr_font_render_message(
|
||||
return;
|
||||
}
|
||||
|
||||
line_height = scale / line_metrics->height;
|
||||
line_height = (float)line_metrics->height * scale / (float)height;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
@@ -369,8 +369,8 @@ static void ctr_font_render_msg(
|
||||
alpha, r_dark, g_dark, b_dark, alpha_dark;
|
||||
ctr_font_t * font = (ctr_font_t*)data;
|
||||
ctr_video_t *ctr = (ctr_video_t*)userdata;
|
||||
unsigned width = ctr->vp.width;
|
||||
unsigned height = ctr->vp.height;
|
||||
unsigned width = ctr->vp.full_width;
|
||||
unsigned height = ctr->vp.full_height;
|
||||
settings_t *settings = config_get_ptr();
|
||||
float video_msg_pos_x = settings->floats.video_msg_pos_x;
|
||||
float video_msg_pos_y = settings->floats.video_msg_pos_y;
|
||||
@@ -397,7 +397,7 @@ static void ctr_font_render_msg(
|
||||
b = FONT_COLOR_GET_BLUE(params->color);
|
||||
alpha = FONT_COLOR_GET_ALPHA(params->color);
|
||||
|
||||
color = params->color;
|
||||
color = COLOR_ABGR(r, g, b, alpha);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -412,10 +412,10 @@ static void ctr_font_render_msg(
|
||||
alpha = 255;
|
||||
color = COLOR_ABGR(r, g, b, alpha);
|
||||
|
||||
drop_x = -2;
|
||||
drop_y = -2;
|
||||
drop_mod = 0.3f;
|
||||
drop_alpha = 1.0f;
|
||||
drop_x = 1;
|
||||
drop_y = -1;
|
||||
drop_mod = 0.0f;
|
||||
drop_alpha = 0.75f;
|
||||
}
|
||||
|
||||
max_glyphs = strlen(msg);
|
||||
|
||||
@@ -299,8 +299,8 @@ static void wiiu_font_render_msg(
|
||||
alpha, r_dark, g_dark, b_dark, alpha_dark;
|
||||
wiiu_video_t *wiiu = (wiiu_video_t*)userdata;
|
||||
wiiu_font_t *font = (wiiu_font_t*)data;
|
||||
unsigned width = wiiu->vp.width;
|
||||
unsigned height = wiiu->vp.height;
|
||||
unsigned width = wiiu->vp.full_width;
|
||||
unsigned height = wiiu->vp.full_height;
|
||||
settings_t *settings = config_get_ptr();
|
||||
float video_msg_pos_x = settings->floats.video_msg_pos_x;
|
||||
float video_msg_pos_y = settings->floats.video_msg_pos_y;
|
||||
|
||||
@@ -431,7 +431,7 @@ public:
|
||||
unsigned width, unsigned height,
|
||||
bool linear,
|
||||
bool mipmap,
|
||||
GLenum address);
|
||||
gl_core_filter_chain_address address);
|
||||
~StaticTexture();
|
||||
|
||||
StaticTexture(StaticTexture&&) = delete;
|
||||
@@ -449,17 +449,27 @@ private:
|
||||
|
||||
StaticTexture::StaticTexture(string id_, GLuint image_,
|
||||
unsigned width, unsigned height, bool linear, bool mipmap,
|
||||
GLenum address)
|
||||
gl_core_filter_chain_address address)
|
||||
: id(std::move(id_)), image(image_)
|
||||
{
|
||||
texture.texture.width = width;
|
||||
GLenum gl_address = address_to_gl(address);
|
||||
|
||||
texture.filter = GL_CORE_FILTER_CHAIN_NEAREST;
|
||||
texture.mip_filter = GL_CORE_FILTER_CHAIN_NEAREST;
|
||||
texture.address = address;
|
||||
texture.texture.width = width;
|
||||
texture.texture.height = height;
|
||||
texture.texture.format = 0;
|
||||
texture.texture.image = image;
|
||||
texture.texture.image = image;
|
||||
|
||||
if (linear)
|
||||
texture.filter = GL_CORE_FILTER_CHAIN_LINEAR;
|
||||
if (mipmap && linear)
|
||||
texture.mip_filter = GL_CORE_FILTER_CHAIN_LINEAR;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, image);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, address);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, address);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gl_address);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gl_address);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linear ? GL_LINEAR : GL_NEAREST);
|
||||
if (linear && mipmap)
|
||||
@@ -2126,7 +2136,7 @@ static unique_ptr<gl_core_shader::StaticTexture> gl_core_filter_chain_load_lut(
|
||||
tex, image.width, image.height,
|
||||
shader->filter != RARCH_FILTER_NEAREST,
|
||||
levels > 1,
|
||||
gl_core_shader::address_to_gl(gl_core_shader::wrap_to_address(shader->wrap))));
|
||||
gl_core_shader::wrap_to_address(shader->wrap)));
|
||||
}
|
||||
|
||||
static bool gl_core_filter_chain_load_luts(
|
||||
|
||||
+85
-26
@@ -51,6 +51,10 @@ struct gfx_thumbnail_state
|
||||
/* Duration in ms of the thumbnail 'fade in' animation */
|
||||
float fade_duration;
|
||||
|
||||
/* When true, 'fade in' animation will also be
|
||||
* triggered for missing thumbnails */
|
||||
bool fade_missing;
|
||||
|
||||
/* Due to the asynchronous nature of thumbnail
|
||||
* loading, it is quite possible to trigger a load
|
||||
* then navigate to a different menu list before
|
||||
@@ -111,6 +115,17 @@ void gfx_thumbnail_set_fade_duration(float duration)
|
||||
duration : DEFAULT_GFX_THUMBNAIL_FADE_DURATION;
|
||||
}
|
||||
|
||||
/* Specifies whether 'fade in' animation should be
|
||||
* triggered for missing thumbnails
|
||||
* > When 'true', allows menu driver to animate
|
||||
* any 'thumbnail unavailable' notifications */
|
||||
void gfx_thumbnail_set_fade_missing(bool fade_missing)
|
||||
{
|
||||
gfx_thumbnail_state_t *p_gfx_thumb = gfx_thumb_get_ptr();
|
||||
|
||||
p_gfx_thumb->fade_missing = fade_missing;
|
||||
}
|
||||
|
||||
/* Getters */
|
||||
|
||||
/* Fetches current streaming thumbnails request delay */
|
||||
@@ -129,17 +144,63 @@ float gfx_thumbnail_get_fade_duration(void)
|
||||
return p_gfx_thumb->fade_duration;
|
||||
}
|
||||
|
||||
/* Fetches current enable state for missing
|
||||
* thumbnail 'fade in' animations */
|
||||
bool gfx_thumbnail_get_fade_missing(bool fade_missing)
|
||||
{
|
||||
gfx_thumbnail_state_t *p_gfx_thumb = gfx_thumb_get_ptr();
|
||||
|
||||
return p_gfx_thumb->fade_missing;
|
||||
}
|
||||
|
||||
/* Callbacks */
|
||||
|
||||
/* Initialises thumbnail 'fade in' animation */
|
||||
static void gfx_thumbnail_init_fade(gfx_thumbnail_t *thumbnail)
|
||||
{
|
||||
gfx_thumbnail_state_t *p_gfx_thumb = gfx_thumb_get_ptr();
|
||||
|
||||
/* Sanity check */
|
||||
if (!thumbnail)
|
||||
return;
|
||||
|
||||
/* A 'fade in' animation is triggered if:
|
||||
* - Thumbnail is available
|
||||
* - Thumbnail is missing and 'fade_missing' is enabled */
|
||||
if ((thumbnail->status == GFX_THUMBNAIL_STATUS_AVAILABLE) ||
|
||||
(p_gfx_thumb->fade_missing &&
|
||||
(thumbnail->status == GFX_THUMBNAIL_STATUS_MISSING)))
|
||||
{
|
||||
if (p_gfx_thumb->fade_duration > 0.0f)
|
||||
{
|
||||
gfx_animation_ctx_entry_t animation_entry;
|
||||
|
||||
thumbnail->alpha = 0.0f;
|
||||
|
||||
animation_entry.easing_enum = EASING_OUT_QUAD;
|
||||
animation_entry.tag = (uintptr_t)&thumbnail->alpha;
|
||||
animation_entry.duration = p_gfx_thumb->fade_duration;
|
||||
animation_entry.target_value = 1.0f;
|
||||
animation_entry.subject = &thumbnail->alpha;
|
||||
animation_entry.cb = NULL;
|
||||
animation_entry.userdata = NULL;
|
||||
|
||||
gfx_animation_push(&animation_entry);
|
||||
}
|
||||
else
|
||||
thumbnail->alpha = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/* Used to process thumbnail data following completion
|
||||
* of image load task */
|
||||
static void gfx_thumbnail_handle_upload(
|
||||
retro_task_t *task, void *task_data, void *user_data, const char *err)
|
||||
{
|
||||
gfx_animation_ctx_entry_t animation_entry;
|
||||
gfx_thumbnail_state_t *p_gfx_thumb = gfx_thumb_get_ptr();
|
||||
struct texture_image *img = (struct texture_image*)task_data;
|
||||
gfx_thumbnail_tag_t *thumbnail_tag = (gfx_thumbnail_tag_t*)user_data;
|
||||
bool fade_enabled = false;
|
||||
|
||||
/* Sanity check */
|
||||
if (!thumbnail_tag)
|
||||
@@ -165,6 +226,11 @@ static void gfx_thumbnail_handle_upload(
|
||||
* (saves a number of checks later) */
|
||||
thumbnail_tag->thumbnail->status = GFX_THUMBNAIL_STATUS_MISSING;
|
||||
|
||||
/* If we reach this stage, thumbnail 'fade in'
|
||||
* animations should be applied (based on current
|
||||
* thumbnail status and global configuration) */
|
||||
fade_enabled = true;
|
||||
|
||||
/* Check we have a valid image */
|
||||
if (!img)
|
||||
goto end;
|
||||
@@ -184,24 +250,6 @@ static void gfx_thumbnail_handle_upload(
|
||||
/* Update thumbnail status */
|
||||
thumbnail_tag->thumbnail->status = GFX_THUMBNAIL_STATUS_AVAILABLE;
|
||||
|
||||
/* Trigger 'fade in' animation, if required */
|
||||
if (p_gfx_thumb->fade_duration > 0.0f)
|
||||
{
|
||||
thumbnail_tag->thumbnail->alpha = 0.0f;
|
||||
|
||||
animation_entry.easing_enum = EASING_OUT_QUAD;
|
||||
animation_entry.tag = (uintptr_t)&thumbnail_tag->thumbnail->alpha;
|
||||
animation_entry.duration = p_gfx_thumb->fade_duration;
|
||||
animation_entry.target_value = 1.0f;
|
||||
animation_entry.subject = &thumbnail_tag->thumbnail->alpha;
|
||||
animation_entry.cb = NULL;
|
||||
animation_entry.userdata = NULL;
|
||||
|
||||
gfx_animation_push(&animation_entry);
|
||||
}
|
||||
else
|
||||
thumbnail_tag->thumbnail->alpha = 1.0f;
|
||||
|
||||
end:
|
||||
/* Clean up */
|
||||
if (img)
|
||||
@@ -211,7 +259,13 @@ end:
|
||||
}
|
||||
|
||||
if (thumbnail_tag)
|
||||
{
|
||||
/* Trigger 'fade in' animation, if required */
|
||||
if (fade_enabled)
|
||||
gfx_thumbnail_init_fade(thumbnail_tag->thumbnail);
|
||||
|
||||
free(thumbnail_tag);
|
||||
}
|
||||
}
|
||||
|
||||
/* Core interface */
|
||||
@@ -248,8 +302,8 @@ void gfx_thumbnail_request(
|
||||
bool network_on_demand_thumbnails
|
||||
)
|
||||
{
|
||||
const char *thumbnail_path = NULL;
|
||||
bool has_thumbnail = false;
|
||||
const char *thumbnail_path = NULL;
|
||||
bool has_thumbnail = false;
|
||||
|
||||
if (!path_data || !thumbnail)
|
||||
return;
|
||||
@@ -274,7 +328,7 @@ void gfx_thumbnail_request(
|
||||
(gfx_thumbnail_tag_t*)calloc(1, sizeof(gfx_thumbnail_tag_t));
|
||||
|
||||
if (!thumbnail_tag)
|
||||
return;
|
||||
goto end;
|
||||
|
||||
/* Configure user data */
|
||||
thumbnail_tag->thumbnail = thumbnail;
|
||||
@@ -297,11 +351,11 @@ void gfx_thumbnail_request(
|
||||
static char last_img_name[PATH_MAX_LENGTH] = {0};
|
||||
|
||||
if (!playlist)
|
||||
return;
|
||||
goto end;
|
||||
|
||||
/* Get current image name */
|
||||
if (!gfx_thumbnail_get_img_name(path_data, &img_name))
|
||||
return;
|
||||
goto end;
|
||||
|
||||
/* Only trigger a thumbnail download if image
|
||||
* name has changed since the last call of
|
||||
@@ -316,13 +370,13 @@ void gfx_thumbnail_request(
|
||||
* overheads. We can avoid this entirely with
|
||||
* a simple string comparison) */
|
||||
if (string_is_equal(img_name, last_img_name))
|
||||
return;
|
||||
goto end;
|
||||
|
||||
strlcpy(last_img_name, img_name, sizeof(last_img_name));
|
||||
|
||||
/* Get system name */
|
||||
if (!gfx_thumbnail_get_system(path_data, &system))
|
||||
return;
|
||||
goto end;
|
||||
|
||||
/* Trigger thumbnail download */
|
||||
task_push_pl_entry_thumbnail_download(
|
||||
@@ -331,6 +385,11 @@ void gfx_thumbnail_request(
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
end:
|
||||
/* Trigger 'fade in' animation, if required */
|
||||
if (thumbnail->status != GFX_THUMBNAIL_STATUS_PENDING)
|
||||
gfx_thumbnail_init_fade(thumbnail);
|
||||
}
|
||||
|
||||
/* Requests loading of a specific thumbnail image file
|
||||
|
||||
@@ -104,6 +104,12 @@ void gfx_thumbnail_set_stream_delay(float delay);
|
||||
* > If 'duration' is negative, default value is set */
|
||||
void gfx_thumbnail_set_fade_duration(float duration);
|
||||
|
||||
/* Specifies whether 'fade in' animation should be
|
||||
* triggered for missing thumbnails
|
||||
* > When 'true', allows menu driver to animate
|
||||
* any 'thumbnail unavailable' notifications */
|
||||
void gfx_thumbnail_set_fade_missing(bool fade_missing);
|
||||
|
||||
/* Getters */
|
||||
|
||||
/* Fetches current streaming thumbnails request delay */
|
||||
@@ -112,6 +118,10 @@ float gfx_thumbnail_get_stream_delay(void);
|
||||
/* Fetches current 'fade in' animation duration */
|
||||
float gfx_thumbnail_get_fade_duration(void);
|
||||
|
||||
/* Fetches current enable state for missing
|
||||
* thumbnail 'fade in' animations */
|
||||
bool gfx_thumbnail_get_fade_missing(bool fade_missing);
|
||||
|
||||
/* Core interface */
|
||||
|
||||
/* When called, prevents the handling of any pending
|
||||
|
||||
+304
-272
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <retro_inline.h>
|
||||
|
||||
#include <lists/file_list.h>
|
||||
#include <queues/fifo_queue.h>
|
||||
@@ -46,20 +47,9 @@
|
||||
#include "../cheevos-new/badges.h"
|
||||
#endif
|
||||
|
||||
static bool widgets_inited = false;
|
||||
static bool widgets_active = false;
|
||||
|
||||
bool gfx_widgets_active(void)
|
||||
{
|
||||
return widgets_active;
|
||||
}
|
||||
|
||||
static bool widgets_persisting = false;
|
||||
|
||||
void gfx_widgets_set_persistence(bool persist)
|
||||
{
|
||||
widgets_persisting = persist;
|
||||
}
|
||||
static bool widgets_inited = false;
|
||||
static bool widgets_active = false;
|
||||
static bool widgets_persisting = false;
|
||||
|
||||
static float msg_queue_background[16] = COLOR_HEX_TO_FLOAT(0x3A3A3A, 1.0f);
|
||||
static float msg_queue_info[16] = COLOR_HEX_TO_FLOAT(0x12ACF8, 1.0f);
|
||||
@@ -73,23 +63,6 @@ static float color_task_progress_bar[16] = COLOR_HEX_TO_FLOAT(0x22B14C, 1.0f);
|
||||
|
||||
static uint64_t gfx_widgets_frame_count = 0;
|
||||
|
||||
/* Font data */
|
||||
static font_data_t *font_regular = NULL;
|
||||
static font_data_t *font_bold = NULL;
|
||||
|
||||
font_data_t* gfx_widgets_get_font_regular(void)
|
||||
{
|
||||
return font_regular;
|
||||
}
|
||||
|
||||
font_data_t* gfx_widgets_get_font_bold(void)
|
||||
{
|
||||
return font_bold;
|
||||
}
|
||||
|
||||
static video_font_raster_block_t font_raster_regular;
|
||||
static video_font_raster_block_t font_raster_bold;
|
||||
|
||||
static float gfx_widgets_pure_white[16] = {
|
||||
1.00, 1.00, 1.00, 1.00,
|
||||
1.00, 1.00, 1.00, 1.00,
|
||||
@@ -97,10 +70,16 @@ static float gfx_widgets_pure_white[16] = {
|
||||
1.00, 1.00, 1.00, 1.00,
|
||||
};
|
||||
|
||||
float* gfx_widgets_get_pure_white(void)
|
||||
|
||||
/* Font data */
|
||||
typedef struct
|
||||
{
|
||||
return gfx_widgets_pure_white;
|
||||
}
|
||||
gfx_widget_font_data_t regular;
|
||||
gfx_widget_font_data_t bold;
|
||||
gfx_widget_font_data_t msg_queue;
|
||||
} gfx_widget_fonts_t;
|
||||
|
||||
static gfx_widget_fonts_t gfx_widget_fonts;
|
||||
|
||||
/* FPS */
|
||||
static char gfx_widgets_fps_text[255] = {0};
|
||||
@@ -163,11 +142,6 @@ static float gfx_widgets_backdrop_orig[16] = {
|
||||
0.00, 0.00, 0.00, 0.75,
|
||||
};
|
||||
|
||||
float* gfx_widgets_get_backdrop_orig(void)
|
||||
{
|
||||
return gfx_widgets_backdrop_orig;
|
||||
}
|
||||
|
||||
static float gfx_widgets_backdrop[16] = {
|
||||
0.00, 0.00, 0.00, 0.75,
|
||||
0.00, 0.00, 0.00, 0.75,
|
||||
@@ -175,8 +149,6 @@ static float gfx_widgets_backdrop[16] = {
|
||||
0.00, 0.00, 0.00, 0.75,
|
||||
};
|
||||
|
||||
/* Messages queue */
|
||||
|
||||
typedef struct menu_widget_msg
|
||||
{
|
||||
char *msg;
|
||||
@@ -234,11 +206,6 @@ static bool msg_queue_has_icons = false;
|
||||
|
||||
static gfx_animation_ctx_tag gfx_widgets_generic_tag = (uintptr_t)&widgets_active;
|
||||
|
||||
gfx_animation_ctx_tag gfx_widgets_get_generic_tag(void)
|
||||
{
|
||||
return gfx_widgets_generic_tag;
|
||||
}
|
||||
|
||||
/* There can only be one message animation at a time to
|
||||
* avoid confusing users */
|
||||
static bool widgets_moving = false;
|
||||
@@ -288,19 +255,79 @@ static uintptr_t ai_service_overlay_texture = 0;
|
||||
|
||||
/* Metrics */
|
||||
#define BASE_FONT_SIZE 32.0f
|
||||
#define MSG_QUEUE_FONT_SIZE (BASE_FONT_SIZE * 0.69f)
|
||||
|
||||
static float last_scale_factor = 0.0f;
|
||||
static float msg_queue_text_scale_factor = 0.0f;
|
||||
static float widget_font_size = 0.0f;
|
||||
|
||||
float gfx_widgets_get_font_size(void)
|
||||
{
|
||||
return widget_font_size;
|
||||
}
|
||||
|
||||
static unsigned simple_widget_padding = 0;
|
||||
static unsigned simple_widget_height = 0;
|
||||
static unsigned glyph_width = 0;
|
||||
|
||||
static unsigned msg_queue_height;
|
||||
static unsigned msg_queue_icon_size_x;
|
||||
static unsigned msg_queue_icon_size_y;
|
||||
static unsigned msg_queue_spacing;
|
||||
static unsigned msg_queue_rect_start_x;
|
||||
static unsigned msg_queue_internal_icon_size;
|
||||
static unsigned msg_queue_internal_icon_offset;
|
||||
static unsigned msg_queue_icon_offset_y;
|
||||
static unsigned msg_queue_scissor_start_x;
|
||||
static unsigned msg_queue_default_rect_width_menu_alive;
|
||||
static unsigned msg_queue_default_rect_width;
|
||||
static unsigned msg_queue_task_text_start_x;
|
||||
static unsigned msg_queue_regular_padding_x;
|
||||
static unsigned msg_queue_regular_text_start;
|
||||
static unsigned msg_queue_task_rect_start_x;
|
||||
static unsigned msg_queue_task_hourglass_x;
|
||||
|
||||
/* Used for both generic and libretro messages */
|
||||
static unsigned generic_message_height;
|
||||
|
||||
static unsigned divider_width_1px = 1;
|
||||
|
||||
static unsigned last_video_width = 0;
|
||||
static unsigned last_video_height = 0;
|
||||
|
||||
bool gfx_widgets_active(void)
|
||||
{
|
||||
return widgets_active;
|
||||
}
|
||||
|
||||
void gfx_widgets_set_persistence(bool persist)
|
||||
{
|
||||
widgets_persisting = persist;
|
||||
}
|
||||
|
||||
gfx_widget_font_data_t* gfx_widgets_get_font_regular(void)
|
||||
{
|
||||
return &gfx_widget_fonts.regular;
|
||||
}
|
||||
|
||||
gfx_widget_font_data_t* gfx_widgets_get_font_bold(void)
|
||||
{
|
||||
return &gfx_widget_fonts.bold;
|
||||
}
|
||||
|
||||
gfx_widget_font_data_t* gfx_widgets_get_font_msg_queue(void)
|
||||
{
|
||||
return &gfx_widget_fonts.msg_queue;
|
||||
}
|
||||
|
||||
float* gfx_widgets_get_pure_white(void)
|
||||
{
|
||||
return gfx_widgets_pure_white;
|
||||
}
|
||||
|
||||
float* gfx_widgets_get_backdrop_orig(void)
|
||||
{
|
||||
return gfx_widgets_backdrop_orig;
|
||||
}
|
||||
|
||||
/* Messages queue */
|
||||
|
||||
gfx_animation_ctx_tag gfx_widgets_get_generic_tag(void)
|
||||
{
|
||||
return gfx_widgets_generic_tag;
|
||||
}
|
||||
|
||||
unsigned gfx_widgets_get_padding(void)
|
||||
{
|
||||
@@ -312,43 +339,12 @@ unsigned gfx_widgets_get_height(void)
|
||||
return simple_widget_height;
|
||||
}
|
||||
|
||||
unsigned gfx_widgets_get_glyph_width(void)
|
||||
{
|
||||
return glyph_width;
|
||||
}
|
||||
|
||||
static unsigned msg_queue_height;
|
||||
static unsigned msg_queue_icon_size_x;
|
||||
static unsigned msg_queue_icon_size_y;
|
||||
static unsigned msg_queue_spacing;
|
||||
static unsigned msg_queue_glyph_width;
|
||||
static unsigned msg_queue_rect_start_x;
|
||||
static unsigned msg_queue_internal_icon_size;
|
||||
static unsigned msg_queue_internal_icon_offset;
|
||||
static unsigned msg_queue_icon_offset_y;
|
||||
static unsigned msg_queue_scissor_start_x;
|
||||
static unsigned msg_queue_default_rect_width_menu_alive;
|
||||
static unsigned msg_queue_default_rect_width;
|
||||
static unsigned msg_queue_task_text_start_x;
|
||||
static unsigned msg_queue_regular_padding_x;
|
||||
static unsigned msg_queue_regular_text_start;
|
||||
static unsigned msg_queue_regular_text_base_y;
|
||||
static unsigned msg_queue_task_rect_start_x;
|
||||
static unsigned msg_queue_task_hourglass_x;
|
||||
|
||||
/* Used for both generic and libretro messages */
|
||||
static unsigned generic_message_height;
|
||||
|
||||
unsigned gfx_widgets_get_generic_message_height(void)
|
||||
{
|
||||
return generic_message_height;
|
||||
}
|
||||
|
||||
static unsigned divider_width_1px = 1;
|
||||
|
||||
static unsigned last_video_width = 0;
|
||||
static unsigned last_video_height = 0;
|
||||
|
||||
unsigned gfx_widgets_get_last_video_width(void)
|
||||
{
|
||||
return last_video_width;
|
||||
@@ -463,8 +459,8 @@ void gfx_widgets_msg_queue_push(
|
||||
msg_widget->unfolded = true;
|
||||
|
||||
msg_widget->width = font_driver_get_message_width(
|
||||
font_regular, title, msg_widget->msg_len,
|
||||
msg_queue_text_scale_factor) + simple_widget_padding/2;
|
||||
gfx_widget_fonts.msg_queue.font, title, msg_widget->msg_len, 1) +
|
||||
simple_widget_padding/2;
|
||||
|
||||
task->frontend_userdata = msg_widget;
|
||||
|
||||
@@ -481,9 +477,8 @@ void gfx_widgets_msg_queue_push(
|
||||
? msg_queue_default_rect_width_menu_alive
|
||||
: msg_queue_default_rect_width;
|
||||
unsigned text_width = font_driver_get_message_width(
|
||||
font_regular, title, title_length, msg_queue_text_scale_factor);
|
||||
msg_widget->text_height = msg_queue_text_scale_factor
|
||||
* widget_font_size;
|
||||
gfx_widget_fonts.msg_queue.font, title, title_length, 1);
|
||||
msg_widget->text_height = gfx_widget_fonts.msg_queue.line_height;
|
||||
|
||||
/* Text is too wide, split it into two lines */
|
||||
if (text_width > width)
|
||||
@@ -497,13 +492,10 @@ void gfx_widgets_msg_queue_push(
|
||||
word_wrap(msg, msg, (title_length * width) / text_width,
|
||||
false, 2);
|
||||
|
||||
msg_widget->text_height *= 2.5f;
|
||||
msg_widget->text_height *= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
width = text_width;
|
||||
msg_widget->text_height *= 1.35f;
|
||||
}
|
||||
width = text_width;
|
||||
|
||||
msg_widget->msg = msg;
|
||||
msg_widget->msg_len = (unsigned)strlen(msg);
|
||||
@@ -525,7 +517,7 @@ void gfx_widgets_msg_queue_push(
|
||||
{
|
||||
unsigned len = (unsigned)strlen(task->title);
|
||||
unsigned new_width = font_driver_get_message_width(
|
||||
font_regular, task->title, len, msg_queue_text_scale_factor);
|
||||
gfx_widget_fonts.msg_queue.font, task->title, len, 1);
|
||||
|
||||
if (msg_widget->msg_new)
|
||||
{
|
||||
@@ -850,6 +842,47 @@ static void gfx_widgets_draw_icon_blend(
|
||||
}
|
||||
#endif
|
||||
|
||||
void gfx_widgets_draw_text(
|
||||
gfx_widget_font_data_t* font_data,
|
||||
const char *text,
|
||||
float x, float y,
|
||||
int width, int height,
|
||||
uint32_t color,
|
||||
enum text_alignment text_align,
|
||||
bool draw_outside)
|
||||
{
|
||||
if (!font_data || string_is_empty(text))
|
||||
return;
|
||||
|
||||
gfx_display_draw_text(
|
||||
font_data->font,
|
||||
text,
|
||||
x, y,
|
||||
width, height,
|
||||
color,
|
||||
text_align,
|
||||
1.0f,
|
||||
false,
|
||||
0.0f,
|
||||
draw_outside);
|
||||
|
||||
font_data->usage_count++;
|
||||
}
|
||||
|
||||
void gfx_widgets_flush_text(
|
||||
unsigned video_width, unsigned video_height,
|
||||
gfx_widget_font_data_t* font_data)
|
||||
{
|
||||
/* Flushing is slow - only do it if font
|
||||
* has actually been used */
|
||||
if (!font_data || (font_data->usage_count == 0))
|
||||
return;
|
||||
|
||||
font_driver_flush(video_width, video_height, font_data->font);
|
||||
font_data->raster_block.carr.coords.vertices = 0;
|
||||
font_data->usage_count = 0;
|
||||
}
|
||||
|
||||
float gfx_widgets_get_thumbnail_scale_factor(
|
||||
const float dst_width, const float dst_height,
|
||||
const float image_width, const float image_height)
|
||||
@@ -1084,7 +1117,7 @@ static int gfx_widgets_draw_indicator(
|
||||
unsigned height = simple_widget_height;
|
||||
const char *txt = msg_hash_to_str(msg);
|
||||
|
||||
width = font_driver_get_message_width(font_regular, txt, (unsigned)strlen(txt), 1) + simple_widget_padding*2;
|
||||
width = font_driver_get_message_width(gfx_widget_fonts.regular.font, txt, (unsigned)strlen(txt), 1) + simple_widget_padding*2;
|
||||
|
||||
gfx_display_draw_quad(userdata,
|
||||
video_width, video_height,
|
||||
@@ -1094,14 +1127,12 @@ static int gfx_widgets_draw_indicator(
|
||||
gfx_widgets_backdrop_orig
|
||||
);
|
||||
|
||||
gfx_display_draw_text(font_regular,
|
||||
txt,
|
||||
top_right_x_advance - width + simple_widget_padding, widget_font_size + simple_widget_padding/4,
|
||||
video_width, video_height,
|
||||
0xFFFFFFFF, TEXT_ALIGN_LEFT,
|
||||
1.0f,
|
||||
false, 0, false
|
||||
);
|
||||
gfx_widgets_draw_text(&gfx_widget_fonts.regular,
|
||||
txt,
|
||||
top_right_x_advance - width + simple_widget_padding, y + (height / 2.0f) + gfx_widget_fonts.regular.line_centre_offset,
|
||||
video_width, video_height,
|
||||
0xFFFFFFFF, TEXT_ALIGN_LEFT,
|
||||
false);
|
||||
}
|
||||
|
||||
return width;
|
||||
@@ -1120,6 +1151,7 @@ static void gfx_widgets_draw_task_msg(
|
||||
unsigned rect_y;
|
||||
unsigned rect_width;
|
||||
unsigned rect_height;
|
||||
float text_y_base;
|
||||
|
||||
float *msg_queue_current_background;
|
||||
float *msg_queue_current_bar;
|
||||
@@ -1131,7 +1163,7 @@ static void gfx_widgets_draw_task_msg(
|
||||
if (msg->msg_new)
|
||||
draw_msg_new = !string_is_equal(msg->msg_new, msg->msg);
|
||||
|
||||
task_percentage_offset = glyph_width * (msg->task_error ? 12 : 5) + simple_widget_padding * 1.25f; /*11 = strlen("Task failed")+1 */
|
||||
task_percentage_offset = gfx_widget_fonts.msg_queue.glyph_width * (msg->task_error ? 12 : 5) + simple_widget_padding * 1.25f; /*11 = strlen("Task failed")+1 */
|
||||
|
||||
if (msg->task_finished)
|
||||
{
|
||||
@@ -1210,64 +1242,52 @@ static void gfx_widgets_draw_task_msg(
|
||||
gfx_display_blend_end(userdata);
|
||||
|
||||
/* Text */
|
||||
text_y_base = video_height - msg->offset_y + msg_queue_height/4.0f + gfx_widget_fonts.msg_queue.line_centre_offset;
|
||||
|
||||
if (draw_msg_new)
|
||||
{
|
||||
font_driver_flush(video_width, video_height, font_regular);
|
||||
font_raster_regular.carr.coords.vertices = 0;
|
||||
gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.msg_queue);
|
||||
|
||||
gfx_display_scissor_begin(userdata,
|
||||
video_width, video_height,
|
||||
rect_x, rect_y, rect_width, rect_height);
|
||||
gfx_display_draw_text(font_regular,
|
||||
msg->msg_new,
|
||||
|
||||
gfx_widgets_draw_text(&gfx_widget_fonts.msg_queue,
|
||||
msg->msg_new,
|
||||
msg_queue_task_text_start_x,
|
||||
text_y_base - msg_queue_height/2.0f + msg->msg_transition_animation,
|
||||
video_width, video_height,
|
||||
text_color,
|
||||
TEXT_ALIGN_LEFT,
|
||||
true);
|
||||
}
|
||||
|
||||
gfx_widgets_draw_text(&gfx_widget_fonts.msg_queue,
|
||||
msg->msg,
|
||||
msg_queue_task_text_start_x,
|
||||
video_height - msg->offset_y + msg_queue_text_scale_factor * widget_font_size + msg_queue_height/4 - widget_font_size/2.25f - msg_queue_height/2 + msg->msg_transition_animation,
|
||||
text_y_base + msg->msg_transition_animation,
|
||||
video_width, video_height,
|
||||
text_color,
|
||||
TEXT_ALIGN_LEFT,
|
||||
msg_queue_text_scale_factor,
|
||||
false,
|
||||
0,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
gfx_display_draw_text(font_regular,
|
||||
msg->msg,
|
||||
msg_queue_task_text_start_x,
|
||||
video_height - msg->offset_y + msg_queue_text_scale_factor * widget_font_size + msg_queue_height/4 - widget_font_size/2.25f + msg->msg_transition_animation,
|
||||
video_width, video_height,
|
||||
text_color,
|
||||
TEXT_ALIGN_LEFT,
|
||||
msg_queue_text_scale_factor,
|
||||
false,
|
||||
0,
|
||||
true
|
||||
);
|
||||
true);
|
||||
|
||||
if (draw_msg_new)
|
||||
{
|
||||
font_driver_flush(video_width, video_height, font_regular);
|
||||
font_raster_regular.carr.coords.vertices = 0;
|
||||
|
||||
gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.msg_queue);
|
||||
gfx_display_scissor_end(userdata,
|
||||
video_width, video_height);
|
||||
}
|
||||
|
||||
/* Progress text */
|
||||
text_color = COLOR_TEXT_ALPHA(0xFFFFFF00, (unsigned)(msg->alpha/2*255.0f));
|
||||
gfx_display_draw_text(font_regular,
|
||||
gfx_widgets_draw_text(&gfx_widget_fonts.msg_queue,
|
||||
task_percentage,
|
||||
msg_queue_rect_start_x - msg_queue_icon_size_x + rect_width - msg_queue_glyph_width,
|
||||
video_height - msg->offset_y + msg_queue_text_scale_factor * widget_font_size + msg_queue_height/4 - widget_font_size/2.25f,
|
||||
msg_queue_rect_start_x - msg_queue_icon_size_x + rect_width - gfx_widget_fonts.msg_queue.glyph_width,
|
||||
text_y_base,
|
||||
video_width, video_height,
|
||||
text_color,
|
||||
TEXT_ALIGN_RIGHT,
|
||||
msg_queue_text_scale_factor,
|
||||
false,
|
||||
0,
|
||||
true
|
||||
);
|
||||
true);
|
||||
}
|
||||
|
||||
static void gfx_widgets_draw_regular_msg(
|
||||
@@ -1290,11 +1310,9 @@ static void gfx_widgets_draw_regular_msg(
|
||||
|
||||
if (!msg->unfolded || msg->unfolding)
|
||||
{
|
||||
font_driver_flush(video_width, video_height, font_regular);
|
||||
font_driver_flush(video_width, video_height, font_bold);
|
||||
|
||||
font_raster_regular.carr.coords.vertices = 0;
|
||||
font_raster_bold.carr.coords.vertices = 0;
|
||||
gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.regular);
|
||||
gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.bold);
|
||||
gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.msg_queue);
|
||||
|
||||
gfx_display_scissor_begin(userdata,
|
||||
video_width, video_height,
|
||||
@@ -1333,23 +1351,20 @@ static void gfx_widgets_draw_regular_msg(
|
||||
/* Text */
|
||||
text_color = COLOR_TEXT_ALPHA(0xFFFFFF00, (unsigned)(msg->alpha*255.0f));
|
||||
|
||||
gfx_display_draw_text(font_regular,
|
||||
gfx_widgets_draw_text(&gfx_widget_fonts.msg_queue,
|
||||
msg->msg,
|
||||
msg_queue_regular_text_start - ((1.0f-msg->unfold) * msg->width/2),
|
||||
video_height - msg->offset_y + msg_queue_regular_text_base_y - msg->text_height/2,
|
||||
video_height - msg->offset_y + (msg_queue_height - msg->text_height)/2.0f + gfx_widget_fonts.msg_queue.line_ascender,
|
||||
video_width, video_height,
|
||||
text_color,
|
||||
TEXT_ALIGN_LEFT,
|
||||
msg_queue_text_scale_factor, false, 0, true
|
||||
);
|
||||
true);
|
||||
|
||||
if (!msg->unfolded || msg->unfolding)
|
||||
{
|
||||
font_driver_flush(video_width, video_height, font_regular);
|
||||
font_driver_flush(video_width, video_height, font_bold);
|
||||
|
||||
font_raster_regular.carr.coords.vertices = 0;
|
||||
font_raster_bold.carr.coords.vertices = 0;
|
||||
gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.regular);
|
||||
gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.bold);
|
||||
gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.msg_queue);
|
||||
|
||||
gfx_display_scissor_end(userdata,
|
||||
video_width, video_height);
|
||||
@@ -1439,27 +1454,23 @@ static void gfx_widgets_draw_load_content_animation(
|
||||
);
|
||||
gfx_display_blend_end(userdata);
|
||||
|
||||
/* Text */
|
||||
gfx_display_draw_text(font_bold,
|
||||
load_content_animation_content_name,
|
||||
video_width / 2,
|
||||
video_height / 2 + (175 + 25) * last_scale_factor + text_offset,
|
||||
video_width,
|
||||
video_height,
|
||||
text_color,
|
||||
TEXT_ALIGN_CENTER,
|
||||
1,
|
||||
false,
|
||||
0,
|
||||
false
|
||||
);
|
||||
/* Text
|
||||
* TODO/FIXME: Check vertical alignment - where is
|
||||
* this text actually meant to go...? */
|
||||
gfx_widgets_draw_text(&gfx_widget_fonts.bold,
|
||||
load_content_animation_content_name,
|
||||
video_width / 2,
|
||||
video_height / 2 + (175 + 25) * last_scale_factor + text_offset + gfx_widget_fonts.bold.line_centre_offset,
|
||||
video_width,
|
||||
video_height,
|
||||
text_color,
|
||||
TEXT_ALIGN_CENTER,
|
||||
false);
|
||||
|
||||
/* Flush text layer */
|
||||
font_driver_flush(video_width, video_height, font_regular);
|
||||
font_driver_flush(video_width, video_height, font_bold);
|
||||
|
||||
font_raster_regular.carr.coords.vertices = 0;
|
||||
font_raster_bold.carr.coords.vertices = 0;
|
||||
gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.regular);
|
||||
gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.bold);
|
||||
gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.msg_queue);
|
||||
|
||||
/* Everything disappears */
|
||||
gfx_widgets_draw_backdrop(userdata,
|
||||
@@ -1468,6 +1479,18 @@ static void gfx_widgets_draw_load_content_animation(
|
||||
#endif
|
||||
}
|
||||
|
||||
static void INLINE gfx_widgets_font_bind(gfx_widget_font_data_t *font_data)
|
||||
{
|
||||
font_driver_bind_block(font_data->font, &font_data->raster_block);
|
||||
font_data->raster_block.carr.coords.vertices = 0;
|
||||
font_data->usage_count = 0;
|
||||
}
|
||||
|
||||
static void INLINE gfx_widgets_font_unbind(gfx_widget_font_data_t *font_data)
|
||||
{
|
||||
font_driver_bind_block(font_data->font, NULL);
|
||||
}
|
||||
|
||||
void gfx_widgets_frame(void *data)
|
||||
{
|
||||
/* (Pointless) optimisation: allocating these
|
||||
@@ -1512,11 +1535,9 @@ void gfx_widgets_frame(void *data)
|
||||
gfx_display_set_viewport(video_width, video_height);
|
||||
|
||||
/* Font setup */
|
||||
font_driver_bind_block(font_regular, &font_raster_regular);
|
||||
font_driver_bind_block(font_bold, &font_raster_bold);
|
||||
|
||||
font_raster_regular.carr.coords.vertices = 0;
|
||||
font_raster_bold.carr.coords.vertices = 0;
|
||||
gfx_widgets_font_bind(&gfx_widget_fonts.regular);
|
||||
gfx_widgets_font_bind(&gfx_widget_fonts.bold);
|
||||
gfx_widgets_font_bind(&gfx_widget_fonts.msg_queue);
|
||||
|
||||
#ifdef HAVE_TRANSLATE
|
||||
/* AI Service overlay */
|
||||
@@ -1650,33 +1671,30 @@ void gfx_widgets_frame(void *data)
|
||||
gfx_widgets_backdrop_orig);
|
||||
|
||||
/* Title */
|
||||
gfx_display_draw_text(font_regular,
|
||||
msg_hash_to_str(MSG_ACHIEVEMENT_UNLOCKED),
|
||||
cheevo_height + simple_widget_padding - unfold_offet,
|
||||
widget_font_size * 1.9f + cheevo_y,
|
||||
video_width, video_height,
|
||||
TEXT_COLOR_FAINT,
|
||||
TEXT_ALIGN_LEFT,
|
||||
1, false, 0, true
|
||||
);
|
||||
gfx_widgets_draw_text(&gfx_widget_fonts.regular,
|
||||
msg_hash_to_str(MSG_ACHIEVEMENT_UNLOCKED),
|
||||
cheevo_height + simple_widget_padding - unfold_offet,
|
||||
cheevo_y + gfx_widget_fonts.regular.line_height + gfx_widget_fonts.regular.line_ascender,
|
||||
video_width, video_height,
|
||||
TEXT_COLOR_FAINT,
|
||||
TEXT_ALIGN_LEFT,
|
||||
true);
|
||||
|
||||
/* Title */
|
||||
/* Cheevo name */
|
||||
|
||||
/* TODO: is a ticker necessary ? */
|
||||
|
||||
gfx_display_draw_text(font_regular,
|
||||
cheevo_popup_queue[cheevo_popup_queue_read_index].title,
|
||||
cheevo_height + simple_widget_padding - unfold_offet, widget_font_size * 2.9f + cheevo_y,
|
||||
video_width, video_height,
|
||||
TEXT_COLOR_INFO,
|
||||
TEXT_ALIGN_LEFT,
|
||||
1, false, 0, true
|
||||
);
|
||||
gfx_widgets_draw_text(&gfx_widget_fonts.regular,
|
||||
cheevo_popup_queue[cheevo_popup_queue_read_index].title,
|
||||
cheevo_height + simple_widget_padding - unfold_offet,
|
||||
cheevo_y + cheevo_height - gfx_widget_fonts.regular.line_height - gfx_widget_fonts.regular.line_descender,
|
||||
video_width, video_height,
|
||||
TEXT_COLOR_INFO,
|
||||
TEXT_ALIGN_LEFT,
|
||||
true);
|
||||
|
||||
if (scissor_me_timbers)
|
||||
{
|
||||
font_driver_flush(video_width, video_height, font_regular);
|
||||
font_raster_regular.carr.coords.vertices = 0;
|
||||
gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.regular);
|
||||
gfx_display_scissor_end(userdata,
|
||||
video_width, video_height);
|
||||
}
|
||||
@@ -1710,7 +1728,7 @@ void gfx_widgets_frame(void *data)
|
||||
{
|
||||
const char *text = *gfx_widgets_fps_text == '\0' ? "N/A" : gfx_widgets_fps_text;
|
||||
|
||||
int text_width = font_driver_get_message_width(font_regular, text, (unsigned)strlen(text), 1.0f);
|
||||
int text_width = font_driver_get_message_width(gfx_widget_fonts.regular.font, text, (unsigned)strlen(text), 1.0f);
|
||||
int total_width = text_width + simple_widget_padding * 2;
|
||||
|
||||
int fps_text_x = top_right_x_advance - simple_widget_padding - text_width;
|
||||
@@ -1729,14 +1747,13 @@ void gfx_widgets_frame(void *data)
|
||||
gfx_widgets_backdrop_orig
|
||||
);
|
||||
|
||||
gfx_display_draw_text(font_regular,
|
||||
text,
|
||||
fps_text_x, widget_font_size + simple_widget_padding/4,
|
||||
video_width, video_height,
|
||||
0xFFFFFFFF,
|
||||
TEXT_ALIGN_LEFT,
|
||||
1, false,0, true
|
||||
);
|
||||
gfx_widgets_draw_text(&gfx_widget_fonts.regular,
|
||||
text,
|
||||
fps_text_x, simple_widget_height/2.0f + gfx_widget_fonts.regular.line_centre_offset,
|
||||
video_width, video_height,
|
||||
0xFFFFFFFF,
|
||||
TEXT_ALIGN_LEFT,
|
||||
true);
|
||||
}
|
||||
|
||||
/* Indicators */
|
||||
@@ -1754,7 +1771,7 @@ void gfx_widgets_frame(void *data)
|
||||
video_width,
|
||||
video_height,
|
||||
gfx_widgets_icons_textures[MENU_WIDGETS_ICON_FAST_FORWARD], (fps_show ? simple_widget_height : 0), top_right_x_advance,
|
||||
MSG_PAUSED);
|
||||
MSG_FAST_FORWARD);
|
||||
|
||||
if (widgets_is_rewinding)
|
||||
top_right_x_advance -= gfx_widgets_draw_indicator(
|
||||
@@ -1788,13 +1805,16 @@ void gfx_widgets_frame(void *data)
|
||||
else
|
||||
#endif
|
||||
{
|
||||
font_driver_flush(video_width, video_height, font_regular);
|
||||
font_driver_flush(video_width, video_height, font_bold);
|
||||
|
||||
font_raster_regular.carr.coords.vertices = 0;
|
||||
font_raster_bold.carr.coords.vertices = 0;
|
||||
gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.regular);
|
||||
gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.bold);
|
||||
gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.msg_queue);
|
||||
}
|
||||
|
||||
/* Unbind fonts */
|
||||
gfx_widgets_font_unbind(&gfx_widget_fonts.regular);
|
||||
gfx_widgets_font_unbind(&gfx_widget_fonts.bold);
|
||||
gfx_widgets_font_unbind(&gfx_widget_fonts.msg_queue);
|
||||
|
||||
gfx_display_unset_viewport(video_width, video_height);
|
||||
}
|
||||
|
||||
@@ -1861,71 +1881,80 @@ void gfx_widgets_deinit(void)
|
||||
gfx_widgets_free();
|
||||
}
|
||||
|
||||
static void gfx_widgets_font_init(
|
||||
gfx_widget_font_data_t *font_data,
|
||||
bool is_threaded, char *font_path, float font_size)
|
||||
{
|
||||
float scaled_size = font_size * last_scale_factor;
|
||||
int glyph_width = 0;
|
||||
|
||||
/* Free existing font */
|
||||
if (font_data->font)
|
||||
{
|
||||
gfx_display_font_free(font_data->font);
|
||||
font_data->font = NULL;
|
||||
}
|
||||
|
||||
/* Get approximate glyph width */
|
||||
font_data->glyph_width = scaled_size * (3.0f / 4.0f);
|
||||
|
||||
/* Create font */
|
||||
font_data->font = gfx_display_font_file(font_path, scaled_size, is_threaded);
|
||||
|
||||
/* Get font metadata */
|
||||
glyph_width = font_driver_get_message_width(font_data->font, "a", 1, 1.0f);
|
||||
if (glyph_width > 0)
|
||||
font_data->glyph_width = (float)glyph_width;
|
||||
font_data->line_height = (float)font_driver_get_line_height(font_data->font, 1.0f);
|
||||
font_data->line_ascender = (float)font_driver_get_line_ascender(font_data->font, 1.0f);
|
||||
font_data->line_descender = (float)font_driver_get_line_descender(font_data->font, 1.0f);
|
||||
font_data->line_centre_offset = (float)font_driver_get_line_centre_offset(font_data->font, 1.0f);
|
||||
|
||||
font_data->usage_count = 0;
|
||||
}
|
||||
|
||||
static void gfx_widgets_layout(
|
||||
bool is_threaded, const char *dir_assets, char *font_path)
|
||||
{
|
||||
size_t i;
|
||||
int font_height = 0;
|
||||
|
||||
/* Base font size must be determined first
|
||||
* > Note that size must be at least 2,
|
||||
* otherwise gfx_display_font_file() will
|
||||
* generate a heap-buffer-overflow */
|
||||
widget_font_size = BASE_FONT_SIZE * last_scale_factor;
|
||||
widget_font_size = (widget_font_size > 2.0f) ? widget_font_size : 2.0f;
|
||||
|
||||
/* Initialise fonts */
|
||||
|
||||
/* > Free existing */
|
||||
if (font_regular)
|
||||
{
|
||||
gfx_display_font_free(font_regular);
|
||||
font_regular = NULL;
|
||||
}
|
||||
if (font_bold)
|
||||
{
|
||||
gfx_display_font_free(font_bold);
|
||||
font_bold = NULL;
|
||||
}
|
||||
|
||||
/* > Create new */
|
||||
if (string_is_empty(font_path))
|
||||
{
|
||||
char ozone_path[PATH_MAX_LENGTH];
|
||||
char font_path[PATH_MAX_LENGTH];
|
||||
char font_file[PATH_MAX_LENGTH];
|
||||
|
||||
ozone_path[0] = '\0';
|
||||
font_path[0] = '\0';
|
||||
font_file[0] = '\0';
|
||||
|
||||
/* Base path */
|
||||
fill_pathname_join(ozone_path, dir_assets, "ozone", sizeof(ozone_path));
|
||||
|
||||
/* Create regular font */
|
||||
fill_pathname_join(font_path, ozone_path, "regular.ttf", sizeof(font_path));
|
||||
font_regular = gfx_display_font_file(font_path, widget_font_size, is_threaded);
|
||||
fill_pathname_join(font_file, ozone_path, "regular.ttf", sizeof(font_file));
|
||||
gfx_widgets_font_init(&gfx_widget_fonts.regular, is_threaded, font_file, BASE_FONT_SIZE);
|
||||
|
||||
/* Create bold font */
|
||||
fill_pathname_join(font_path, ozone_path, "bold.ttf", sizeof(font_path));
|
||||
font_bold = gfx_display_font_file(font_path, widget_font_size, is_threaded);
|
||||
fill_pathname_join(font_file, ozone_path, "bold.ttf", sizeof(font_file));
|
||||
gfx_widgets_font_init(&gfx_widget_fonts.bold, is_threaded, font_file, BASE_FONT_SIZE);
|
||||
|
||||
/* Create msg_queue font */
|
||||
fill_pathname_join(font_file, ozone_path, "regular.ttf", sizeof(font_file));
|
||||
gfx_widgets_font_init(&gfx_widget_fonts.msg_queue, is_threaded, font_file, MSG_QUEUE_FONT_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Load fonts from user-supplied path */
|
||||
font_regular = gfx_display_font_file(font_path, widget_font_size, is_threaded);
|
||||
font_bold = gfx_display_font_file(font_path, widget_font_size, is_threaded);
|
||||
gfx_widgets_font_init(&gfx_widget_fonts.regular, is_threaded, font_path, BASE_FONT_SIZE);
|
||||
gfx_widgets_font_init(&gfx_widget_fonts.bold, is_threaded, font_path, BASE_FONT_SIZE);
|
||||
gfx_widgets_font_init(&gfx_widget_fonts.msg_queue, is_threaded, font_path, MSG_QUEUE_FONT_SIZE);
|
||||
}
|
||||
|
||||
/* > Get actual font size */
|
||||
font_height = font_driver_get_line_height(font_regular, 1.0f);
|
||||
if (font_height > 0)
|
||||
widget_font_size = (float)font_height;
|
||||
|
||||
/* Calculate dimensions */
|
||||
simple_widget_padding = widget_font_size * 2.0f/3.0f;
|
||||
simple_widget_height = widget_font_size + simple_widget_padding;
|
||||
glyph_width = font_driver_get_message_width(font_regular, "a", 1, 1);
|
||||
simple_widget_padding = gfx_widget_fonts.regular.line_height * 2.0f/3.0f;
|
||||
simple_widget_height = gfx_widget_fonts.regular.line_height + simple_widget_padding;
|
||||
|
||||
msg_queue_height = widget_font_size * 2.5f;
|
||||
msg_queue_height = gfx_widget_fonts.msg_queue.line_height * 2.5f * (BASE_FONT_SIZE / MSG_QUEUE_FONT_SIZE);
|
||||
|
||||
if (msg_queue_has_icons)
|
||||
{
|
||||
@@ -1938,9 +1967,7 @@ static void gfx_widgets_layout(
|
||||
msg_queue_icon_size_y = 0;
|
||||
}
|
||||
|
||||
msg_queue_text_scale_factor = 0.69f;
|
||||
msg_queue_spacing = msg_queue_height / 3;
|
||||
msg_queue_glyph_width = glyph_width * msg_queue_text_scale_factor;
|
||||
msg_queue_rect_start_x = msg_queue_spacing + msg_queue_icon_size_x;
|
||||
msg_queue_internal_icon_size = msg_queue_icon_size_y;
|
||||
msg_queue_internal_icon_offset = (msg_queue_icon_size_y - msg_queue_internal_icon_size)/2;
|
||||
@@ -1957,16 +1984,15 @@ static void gfx_widgets_layout(
|
||||
msg_queue_task_text_start_x = msg_queue_task_rect_start_x + msg_queue_height/2;
|
||||
|
||||
if (!gfx_widgets_icons_textures[MENU_WIDGETS_ICON_HOURGLASS])
|
||||
msg_queue_task_text_start_x -= msg_queue_glyph_width*2;
|
||||
msg_queue_task_text_start_x -= gfx_widget_fonts.msg_queue.glyph_width * 2.0f;
|
||||
|
||||
msg_queue_regular_text_start = msg_queue_rect_start_x + msg_queue_regular_padding_x;
|
||||
msg_queue_regular_text_base_y = widget_font_size * msg_queue_text_scale_factor + msg_queue_height/2;
|
||||
|
||||
msg_queue_task_hourglass_x = msg_queue_rect_start_x - msg_queue_icon_size_x;
|
||||
|
||||
generic_message_height = widget_font_size * 2;
|
||||
generic_message_height = gfx_widget_fonts.regular.line_height * 2.0f;
|
||||
|
||||
msg_queue_default_rect_width_menu_alive = msg_queue_glyph_width * 40;
|
||||
msg_queue_default_rect_width_menu_alive = gfx_widget_fonts.msg_queue.glyph_width * 40.0f;
|
||||
msg_queue_default_rect_width = last_video_width - msg_queue_regular_text_start - (2 * simple_widget_padding);
|
||||
|
||||
#ifdef HAVE_MENU
|
||||
@@ -2065,6 +2091,15 @@ static void gfx_widgets_context_reset(bool is_threaded,
|
||||
video_driver_monitor_reset();
|
||||
}
|
||||
|
||||
static void INLINE gfx_widgets_font_free(gfx_widget_font_data_t *font_data)
|
||||
{
|
||||
if (font_data->font)
|
||||
gfx_display_font_free(font_data->font);
|
||||
|
||||
font_data->font = NULL;
|
||||
font_data->usage_count = 0;
|
||||
}
|
||||
|
||||
static void gfx_widgets_context_destroy(void)
|
||||
{
|
||||
size_t i;
|
||||
@@ -2092,13 +2127,9 @@ static void gfx_widgets_context_destroy(void)
|
||||
msg_queue_icon_rect = 0;
|
||||
|
||||
/* Fonts */
|
||||
if (font_regular)
|
||||
gfx_display_font_free(font_regular);
|
||||
if (font_bold)
|
||||
gfx_display_font_free(font_bold);
|
||||
|
||||
font_regular = NULL;
|
||||
font_bold = NULL;
|
||||
gfx_widgets_font_free(&gfx_widget_fonts.regular);
|
||||
gfx_widgets_font_free(&gfx_widget_fonts.bold);
|
||||
gfx_widgets_font_free(&gfx_widget_fonts.msg_queue);
|
||||
}
|
||||
|
||||
#ifdef HAVE_CHEEVOS
|
||||
@@ -2198,8 +2229,9 @@ static void gfx_widgets_free(void)
|
||||
#endif
|
||||
|
||||
/* Font */
|
||||
video_coord_array_free(&font_raster_regular.carr);
|
||||
video_coord_array_free(&font_raster_bold.carr);
|
||||
video_coord_array_free(&gfx_widget_fonts.regular.raster_block.carr);
|
||||
video_coord_array_free(&gfx_widget_fonts.bold.raster_block.carr);
|
||||
video_coord_array_free(&gfx_widget_fonts.msg_queue.raster_block.carr);
|
||||
|
||||
font_driver_bind_block(NULL, NULL);
|
||||
}
|
||||
@@ -2439,10 +2471,10 @@ static void gfx_widgets_achievement_unfold(void *userdata)
|
||||
static void gfx_widgets_start_achievement_notification(void)
|
||||
{
|
||||
gfx_animation_ctx_entry_t entry;
|
||||
cheevo_height = widget_font_size * 4;
|
||||
cheevo_height = gfx_widget_fonts.regular.line_height * 4;
|
||||
cheevo_width = MAX(
|
||||
font_driver_get_message_width(font_regular, msg_hash_to_str(MSG_ACHIEVEMENT_UNLOCKED), 0, 1),
|
||||
font_driver_get_message_width(font_regular, cheevo_popup_queue[cheevo_popup_queue_read_index].title, 0, 1)
|
||||
font_driver_get_message_width(gfx_widget_fonts.regular.font, msg_hash_to_str(MSG_ACHIEVEMENT_UNLOCKED), 0, 1),
|
||||
font_driver_get_message_width(gfx_widget_fonts.regular.font, cheevo_popup_queue[cheevo_popup_queue_read_index].title, 0, 1)
|
||||
);
|
||||
cheevo_width += simple_widget_padding * 2;
|
||||
cheevo_y = (float)(-(int)cheevo_height);
|
||||
|
||||
+30
-4
@@ -88,14 +88,27 @@ struct gfx_widget
|
||||
void (*frame)(void* data);
|
||||
};
|
||||
|
||||
/* This structure holds all objects + metadata
|
||||
* corresponding to a particular font */
|
||||
typedef struct
|
||||
{
|
||||
font_data_t *font;
|
||||
video_font_raster_block_t raster_block;
|
||||
unsigned glyph_width;
|
||||
float line_height;
|
||||
float line_ascender;
|
||||
float line_descender;
|
||||
float line_centre_offset;
|
||||
size_t usage_count;
|
||||
} gfx_widget_font_data_t;
|
||||
|
||||
gfx_animation_ctx_tag gfx_widgets_get_generic_tag(void);
|
||||
float* gfx_widgets_get_pure_white(void);
|
||||
unsigned gfx_widgets_get_padding(void);
|
||||
unsigned gfx_widgets_get_height(void);
|
||||
unsigned gfx_widgets_get_glyph_width(void);
|
||||
float gfx_widgets_get_font_size(void);
|
||||
font_data_t* gfx_widgets_get_font_regular(void);
|
||||
font_data_t* gfx_widgets_get_font_bold(void);
|
||||
gfx_widget_font_data_t* gfx_widgets_get_font_regular(void);
|
||||
gfx_widget_font_data_t* gfx_widgets_get_font_bold(void);
|
||||
gfx_widget_font_data_t* gfx_widgets_get_font_msg_queue(void);
|
||||
float* gfx_widgets_get_backdrop_orig(void);
|
||||
unsigned gfx_widgets_get_last_video_width(void);
|
||||
unsigned gfx_widgets_get_last_video_height(void);
|
||||
@@ -117,6 +130,19 @@ void gfx_widgets_draw_icon(
|
||||
float rotation, float scale_factor,
|
||||
float *color);
|
||||
|
||||
void gfx_widgets_draw_text(
|
||||
gfx_widget_font_data_t* font_data,
|
||||
const char *text,
|
||||
float x, float y,
|
||||
int width, int height,
|
||||
uint32_t color,
|
||||
enum text_alignment text_align,
|
||||
bool draw_outside);
|
||||
|
||||
void gfx_widgets_flush_text(
|
||||
unsigned video_width, unsigned video_height,
|
||||
gfx_widget_font_data_t* font_data);
|
||||
|
||||
typedef struct gfx_widget gfx_widget_t;
|
||||
|
||||
extern const gfx_widget_t gfx_widget_screenshot;
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <retro_endianness.h>
|
||||
|
||||
#ifdef RARCH_INTERNAL
|
||||
#define softfilter_get_implementation twoxbr_get_implementation
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <retro_endianness.h>
|
||||
|
||||
#ifdef RARCH_INTERNAL
|
||||
#define softfilter_get_implementation epx_get_implementation
|
||||
#define softfilter_thread_data epx_softfilter_thread_data
|
||||
|
||||
@@ -643,6 +643,10 @@ bool video_shader_write_preset(const char *path,
|
||||
config_file_t *conf;
|
||||
bool ret;
|
||||
|
||||
/* Note: We always create a new/blank config
|
||||
* file here. Loading and updating an existing
|
||||
* file could leave us with unwanted/invalid
|
||||
* parameters. */
|
||||
if (!(conf = config_file_new_alloc()))
|
||||
return false;
|
||||
|
||||
|
||||
@@ -88,14 +88,14 @@ static void gfx_widget_generic_message_frame(void* data)
|
||||
|
||||
if (state->alpha > 0.0f)
|
||||
{
|
||||
video_frame_info_t* video_info = (video_frame_info_t*)data;
|
||||
void* userdata = video_info->userdata;
|
||||
unsigned video_width = video_info->width;
|
||||
unsigned video_height = video_info->height;
|
||||
video_frame_info_t* video_info = (video_frame_info_t*)data;
|
||||
void* userdata = video_info->userdata;
|
||||
unsigned video_width = video_info->width;
|
||||
unsigned video_height = video_info->height;
|
||||
unsigned height = gfx_widgets_get_generic_message_height();
|
||||
unsigned text_color = COLOR_TEXT_ALPHA(0xffffffff, (unsigned)(state->alpha*255.0f));
|
||||
gfx_widget_font_data_t* font_regular = gfx_widgets_get_font_regular();
|
||||
|
||||
unsigned height = gfx_widgets_get_generic_message_height();
|
||||
|
||||
unsigned text_color = COLOR_TEXT_ALPHA(0xffffffff, (unsigned)(state->alpha*255.0f));
|
||||
gfx_display_set_alpha(gfx_widgets_get_backdrop_orig(), state->alpha);
|
||||
|
||||
gfx_display_draw_quad(userdata,
|
||||
@@ -105,12 +105,12 @@ static void gfx_widget_generic_message_frame(void* data)
|
||||
video_width, video_height,
|
||||
gfx_widgets_get_backdrop_orig());
|
||||
|
||||
gfx_display_draw_text(gfx_widgets_get_font_regular(), state->message,
|
||||
video_width/2,
|
||||
video_height - height/2 + gfx_widgets_get_font_size()/4,
|
||||
video_width, video_height,
|
||||
text_color, TEXT_ALIGN_CENTER,
|
||||
1, false, 0, false);
|
||||
gfx_widgets_draw_text(font_regular, state->message,
|
||||
video_width/2,
|
||||
video_height - height/2.0f + font_regular->line_centre_offset,
|
||||
video_width, video_height,
|
||||
text_color, TEXT_ALIGN_CENTER,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,8 +64,9 @@ static void gfx_widget_libretro_message_fadeout(void *userdata)
|
||||
void gfx_widget_set_libretro_message(const char *msg, unsigned duration)
|
||||
{
|
||||
gfx_widget_libretro_message_state_t* state = gfx_widget_libretro_message_get_state();
|
||||
gfx_animation_ctx_tag tag = (uintptr_t) &state->timer;
|
||||
gfx_widget_font_data_t* font_regular = gfx_widgets_get_font_regular();
|
||||
gfx_timer_ctx_entry_t timer;
|
||||
gfx_animation_ctx_tag tag = (uintptr_t) &state->timer;
|
||||
|
||||
if (!gfx_widgets_active())
|
||||
return;
|
||||
@@ -85,7 +86,7 @@ void gfx_widget_set_libretro_message(const char *msg, unsigned duration)
|
||||
gfx_timer_start(&state->timer, &timer);
|
||||
|
||||
/* Compute text width */
|
||||
state->width = font_driver_get_message_width(gfx_widgets_get_font_regular(), msg, (unsigned)strlen(msg), 1) + gfx_widgets_get_padding() * 2;
|
||||
state->width = font_driver_get_message_width(font_regular->font, msg, (unsigned)strlen(msg), 1) + gfx_widgets_get_padding() * 2;
|
||||
}
|
||||
|
||||
static void gfx_widget_libretro_message_frame(void *data)
|
||||
@@ -94,15 +95,14 @@ static void gfx_widget_libretro_message_frame(void *data)
|
||||
|
||||
if (state->alpha > 0.0f)
|
||||
{
|
||||
video_frame_info_t* video_info = (video_frame_info_t*)data;
|
||||
void* userdata = video_info->userdata;
|
||||
unsigned video_width = video_info->width;
|
||||
unsigned video_height = video_info->height;
|
||||
|
||||
unsigned height = gfx_widgets_get_generic_message_height();
|
||||
|
||||
float* backdrop_orign = gfx_widgets_get_backdrop_orig();
|
||||
unsigned text_color = COLOR_TEXT_ALPHA(0xffffffff, (unsigned)(state->alpha*255.0f));
|
||||
video_frame_info_t* video_info = (video_frame_info_t*)data;
|
||||
void* userdata = video_info->userdata;
|
||||
unsigned video_width = video_info->width;
|
||||
unsigned video_height = video_info->height;
|
||||
unsigned height = gfx_widgets_get_generic_message_height();
|
||||
float* backdrop_orign = gfx_widgets_get_backdrop_orig();
|
||||
unsigned text_color = COLOR_TEXT_ALPHA(0xffffffff, (unsigned)(state->alpha*255.0f));
|
||||
gfx_widget_font_data_t* font_regular = gfx_widgets_get_font_regular();
|
||||
|
||||
gfx_display_set_alpha(backdrop_orign, state->alpha);
|
||||
|
||||
@@ -113,12 +113,12 @@ static void gfx_widget_libretro_message_frame(void *data)
|
||||
video_width, video_height,
|
||||
backdrop_orign);
|
||||
|
||||
gfx_display_draw_text(gfx_widgets_get_font_regular(), state->message,
|
||||
gfx_widgets_get_padding(),
|
||||
video_height - height/2 + gfx_widgets_get_font_size()/4,
|
||||
video_width, video_height,
|
||||
text_color, TEXT_ALIGN_LEFT,
|
||||
1, false, 0, false);
|
||||
gfx_widgets_draw_text(font_regular, state->message,
|
||||
gfx_widgets_get_padding(),
|
||||
video_height - height/2 + font_regular->line_centre_offset,
|
||||
video_width, video_height,
|
||||
text_color, TEXT_ALIGN_LEFT,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -150,19 +150,14 @@ static void gfx_widget_screenshot_free(void)
|
||||
|
||||
static void gfx_widget_screenshot_frame(void* data)
|
||||
{
|
||||
video_frame_info_t *video_info = (video_frame_info_t*)data;
|
||||
void *userdata = video_info->userdata;
|
||||
unsigned video_width = video_info->width;
|
||||
unsigned video_height = video_info->height;
|
||||
|
||||
unsigned padding = gfx_widgets_get_padding();
|
||||
float font_size = gfx_widgets_get_font_size();
|
||||
|
||||
font_data_t* font_regular = gfx_widgets_get_font_regular();
|
||||
|
||||
float* pure_white = gfx_widgets_get_pure_white();
|
||||
|
||||
video_frame_info_t *video_info = (video_frame_info_t*)data;
|
||||
void *userdata = video_info->userdata;
|
||||
unsigned video_width = video_info->width;
|
||||
unsigned video_height = video_info->height;
|
||||
gfx_widget_font_data_t* font_regular = gfx_widgets_get_font_regular();
|
||||
float* pure_white = gfx_widgets_get_pure_white();
|
||||
gfx_widget_screenshot_state_t* state = gfx_widget_screenshot_get_ptr();
|
||||
int padding = (state->height - (font_regular->line_height * 2.0f)) / 2.0f;
|
||||
|
||||
/* Screenshot */
|
||||
if (state->loaded)
|
||||
@@ -193,14 +188,14 @@ static void gfx_widget_screenshot_frame(void* data)
|
||||
0, 1, pure_white
|
||||
);
|
||||
|
||||
gfx_display_draw_text(font_regular,
|
||||
msg_hash_to_str(MSG_SCREENSHOT_SAVED),
|
||||
state->thumbnail_width + padding, font_size * 1.9f + state->y,
|
||||
video_width, video_height,
|
||||
TEXT_COLOR_FAINT,
|
||||
TEXT_ALIGN_LEFT,
|
||||
1, false, 0, true
|
||||
);
|
||||
gfx_widgets_draw_text(font_regular,
|
||||
msg_hash_to_str(MSG_SCREENSHOT_SAVED),
|
||||
state->thumbnail_width + padding,
|
||||
padding + font_regular->line_ascender + state->y,
|
||||
video_width, video_height,
|
||||
TEXT_COLOR_FAINT,
|
||||
TEXT_ALIGN_LEFT,
|
||||
true);
|
||||
|
||||
ticker.idx = gfx_animation_get_ticker_idx();
|
||||
ticker.len = state->shotname_length;
|
||||
@@ -210,14 +205,14 @@ static void gfx_widget_screenshot_frame(void* data)
|
||||
|
||||
gfx_animation_ticker(&ticker);
|
||||
|
||||
gfx_display_draw_text(font_regular,
|
||||
shotname,
|
||||
state->thumbnail_width + padding, font_size * 2.9f + state->y,
|
||||
video_width, video_height,
|
||||
TEXT_COLOR_INFO,
|
||||
TEXT_ALIGN_LEFT,
|
||||
1, false, 0, true
|
||||
);
|
||||
gfx_widgets_draw_text(font_regular,
|
||||
shotname,
|
||||
state->thumbnail_width + padding,
|
||||
state->height - padding - font_regular->line_descender + state->y,
|
||||
video_width, video_height,
|
||||
TEXT_COLOR_INFO,
|
||||
TEXT_ALIGN_LEFT,
|
||||
true);
|
||||
}
|
||||
|
||||
/* Flash effect */
|
||||
@@ -240,10 +235,8 @@ static void gfx_widget_screenshot_iterate(unsigned width, unsigned height, bool
|
||||
bool is_threaded)
|
||||
{
|
||||
gfx_widget_screenshot_state_t* state = gfx_widget_screenshot_get_ptr();
|
||||
|
||||
float font_size = gfx_widgets_get_font_size();
|
||||
unsigned padding = gfx_widgets_get_padding();
|
||||
unsigned glyph_width = gfx_widgets_get_glyph_width();
|
||||
unsigned padding = gfx_widgets_get_padding();
|
||||
gfx_widget_font_data_t* font_regular = gfx_widgets_get_font_regular();
|
||||
|
||||
/* Load screenshot and start its animation */
|
||||
if (state->filename[0] != '\0')
|
||||
@@ -258,7 +251,7 @@ static void gfx_widget_screenshot_iterate(unsigned width, unsigned height, bool
|
||||
"", &state->texture, TEXTURE_FILTER_MIPMAP_LINEAR,
|
||||
&state->texture_width, &state->texture_height);
|
||||
|
||||
state->height = font_size * 4;
|
||||
state->height = font_regular->line_height * 4;
|
||||
state->width = width;
|
||||
|
||||
state->scale_factor = gfx_widgets_get_thumbnail_scale_factor(
|
||||
@@ -269,7 +262,7 @@ static void gfx_widget_screenshot_iterate(unsigned width, unsigned height, bool
|
||||
state->thumbnail_width = state->texture_width * state->scale_factor;
|
||||
state->thumbnail_height = state->texture_height * state->scale_factor;
|
||||
|
||||
state->shotname_length = (width - state->thumbnail_width - padding*2) / glyph_width;
|
||||
state->shotname_length = (width - state->thumbnail_width - padding*2) / font_regular->glyph_width;
|
||||
|
||||
state->y = 0.0f;
|
||||
|
||||
|
||||
@@ -102,13 +102,12 @@ static void gfx_widget_volume_frame(void* data)
|
||||
char msg[255];
|
||||
char percentage_msg[255];
|
||||
|
||||
gfx_widget_font_data_t* font_regular = gfx_widgets_get_font_regular();
|
||||
|
||||
void *userdata = video_info->userdata;
|
||||
unsigned video_width = video_info->width;
|
||||
unsigned video_height = video_info->height;
|
||||
|
||||
font_data_t* font_regular = gfx_widgets_get_font_regular();
|
||||
|
||||
float font_size = gfx_widgets_get_font_size();
|
||||
unsigned padding = gfx_widgets_get_padding();
|
||||
|
||||
float* backdrop_orig = gfx_widgets_get_backdrop_orig();
|
||||
@@ -120,15 +119,22 @@ static void gfx_widget_volume_frame(void* data)
|
||||
unsigned text_color_db = COLOR_TEXT_ALPHA(TEXT_COLOR_FAINT, (unsigned)(state->text_alpha*255.0f));
|
||||
|
||||
unsigned bar_x = icon_size;
|
||||
unsigned bar_height = font_size / 2;
|
||||
unsigned bar_height = font_regular->line_height / 2;
|
||||
unsigned bar_width = state->widget_width - bar_x - padding;
|
||||
unsigned bar_y = state->widget_height / 2 + bar_height/2;
|
||||
unsigned bar_y = state->widget_height / 2 + bar_height;
|
||||
|
||||
float *bar_background = NULL;
|
||||
float *bar_foreground = NULL;
|
||||
float bar_percentage = 0.0f;
|
||||
|
||||
unsigned volume_text_y = bar_y - (font_size / 3);
|
||||
/* Note: Volume + percentage text has no component
|
||||
* that extends below the baseline, so we shift
|
||||
* the text down by the font descender to achieve
|
||||
* better spacing */
|
||||
unsigned volume_text_y = (bar_y / 2.0f) + font_regular->line_centre_offset + font_regular->line_descender;
|
||||
|
||||
msg[0] = '\0';
|
||||
percentage_msg[0] = '\0';
|
||||
|
||||
if (state->mute)
|
||||
volume_icon = state->textures[ICON_MUTE];
|
||||
@@ -201,13 +207,12 @@ static void gfx_widget_volume_frame(void* data)
|
||||
if (!state->textures[ICON_MUTE])
|
||||
{
|
||||
const char *text = msg_hash_to_str(MSG_AUDIO_MUTED);
|
||||
gfx_display_draw_text(font_regular,
|
||||
text,
|
||||
state->widget_width/2, state->widget_height/2 + font_size / 3,
|
||||
video_width, video_height,
|
||||
text_color, TEXT_ALIGN_CENTER,
|
||||
1, false, 0, true
|
||||
);
|
||||
gfx_widgets_draw_text(font_regular,
|
||||
text,
|
||||
state->widget_width/2, state->widget_height/2.0f + font_regular->line_centre_offset,
|
||||
video_width, video_height,
|
||||
text_color, TEXT_ALIGN_CENTER,
|
||||
true);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -241,23 +246,21 @@ static void gfx_widget_volume_frame(void* data)
|
||||
snprintf(percentage_msg, sizeof(percentage_msg), "%d%%",
|
||||
(int)(state->percent * 100.0f));
|
||||
|
||||
gfx_display_draw_text(font_regular,
|
||||
msg,
|
||||
state->widget_width - padding, volume_text_y,
|
||||
video_width, video_height,
|
||||
text_color_db,
|
||||
TEXT_ALIGN_RIGHT,
|
||||
1, false, 0, false
|
||||
);
|
||||
gfx_widgets_draw_text(font_regular,
|
||||
msg,
|
||||
state->widget_width - padding, volume_text_y,
|
||||
video_width, video_height,
|
||||
text_color_db,
|
||||
TEXT_ALIGN_RIGHT,
|
||||
false);
|
||||
|
||||
gfx_display_draw_text(font_regular,
|
||||
gfx_widgets_draw_text(font_regular,
|
||||
percentage_msg,
|
||||
icon_size, volume_text_y,
|
||||
video_width, video_height,
|
||||
text_color,
|
||||
TEXT_ALIGN_LEFT,
|
||||
1, false, 0, false
|
||||
);
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -304,12 +307,11 @@ void gfx_widget_volume_update_and_show(float new_volume, bool mute)
|
||||
|
||||
static void gfx_widget_volume_layout(bool is_threaded, const char *dir_assets, char *font_path)
|
||||
{
|
||||
gfx_widget_volume_state_t* state = gfx_widget_volume_get_ptr();
|
||||
gfx_widget_volume_state_t* state = gfx_widget_volume_get_ptr();
|
||||
unsigned last_video_width = gfx_widgets_get_last_video_width();
|
||||
gfx_widget_font_data_t* font_regular = gfx_widgets_get_font_regular();
|
||||
|
||||
float font_size = gfx_widgets_get_font_size();
|
||||
unsigned last_video_width = gfx_widgets_get_last_video_width();
|
||||
|
||||
state->widget_height = font_size * 4;
|
||||
state->widget_height = font_regular->line_height * 4;
|
||||
state->widget_width = state->widget_height * 4;
|
||||
|
||||
/* Volume widget cannot exceed screen width
|
||||
|
||||
+9
-4
@@ -128,6 +128,7 @@ COMPRESSION
|
||||
|
||||
#ifdef HAVE_ZLIB
|
||||
#include "../libretro-common/streams/trans_stream_zlib.c"
|
||||
#include "../libretro-common/streams/rzip_stream.c"
|
||||
#endif
|
||||
|
||||
/*============================================================
|
||||
@@ -180,17 +181,20 @@ ACHIEVEMENTS
|
||||
#include "../cheevos-new/parser.c"
|
||||
|
||||
#include "../deps/rcheevos/src/rcheevos/alloc.c"
|
||||
#include "../deps/rcheevos/src/rcheevos/compat.c"
|
||||
#include "../deps/rcheevos/src/rcheevos/condition.c"
|
||||
#include "../deps/rcheevos/src/rcheevos/condset.c"
|
||||
#include "../deps/rcheevos/src/rcheevos/expression.c"
|
||||
#include "../deps/rcheevos/src/rcheevos/consoleinfo.c"
|
||||
#include "../deps/rcheevos/src/rcheevos/format.c"
|
||||
#include "../deps/rcheevos/src/rcheevos/lboard.c"
|
||||
#include "../deps/rcheevos/src/rcheevos/memref.c"
|
||||
#include "../deps/rcheevos/src/rcheevos/operand.c"
|
||||
#include "../deps/rcheevos/src/rcheevos/term.c"
|
||||
#include "../deps/rcheevos/src/rcheevos/richpresence.c"
|
||||
#include "../deps/rcheevos/src/rcheevos/runtime.c"
|
||||
#include "../deps/rcheevos/src/rcheevos/runtime_progress.c"
|
||||
#include "../deps/rcheevos/src/rcheevos/trigger.c"
|
||||
#include "../deps/rcheevos/src/rcheevos/value.c"
|
||||
#include "../deps/rcheevos/src/rcheevos/memref.c"
|
||||
#include "../deps/rcheevos/src/rcheevos/richpresence.c"
|
||||
#include "../deps/rcheevos/src/rhash/hash.c"
|
||||
#include "../deps/rcheevos/src/rurl/url.c"
|
||||
|
||||
#endif
|
||||
@@ -1204,6 +1208,7 @@ NETPLAY
|
||||
#ifdef HAVE_NETWORKING
|
||||
#include "../network/netplay/netplay_delta.c"
|
||||
#include "../network/netplay/netplay_handshake.c"
|
||||
#include "../network/netplay/netplay_frontend.c"
|
||||
#include "../network/netplay/netplay_init.c"
|
||||
#include "../network/netplay/netplay_io.c"
|
||||
#include "../network/netplay/netplay_keyboard.c"
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
#define HAVE_COMPRESSION 1
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <string.h>
|
||||
#include <compat/posix_string.h>
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <boolean.h>
|
||||
#include <retro_environment.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <retro_endianness.h>
|
||||
|
||||
#include "joypad_connection.h"
|
||||
#include "../input_defines.h"
|
||||
|
||||
+25
-23
@@ -192,35 +192,37 @@ static void cocoa_input_poll(void *data)
|
||||
apple->joypad->poll();
|
||||
if (apple->sec_joypad)
|
||||
apple->sec_joypad->poll();
|
||||
|
||||
apple->mouse_x_last = apple->mouse_rel_x;
|
||||
apple->mouse_y_last = apple->mouse_rel_y;
|
||||
}
|
||||
|
||||
static int16_t cocoa_mouse_state(cocoa_input_data_t *apple,
|
||||
unsigned id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case RETRO_DEVICE_ID_MOUSE_X:
|
||||
return apple->mouse_rel_x - apple->mouse_x_last;
|
||||
case RETRO_DEVICE_ID_MOUSE_Y:
|
||||
return apple->mouse_rel_y - apple->mouse_y_last;
|
||||
case RETRO_DEVICE_ID_MOUSE_LEFT:
|
||||
return apple->mouse_buttons & 1;
|
||||
case RETRO_DEVICE_ID_MOUSE_RIGHT:
|
||||
return apple->mouse_buttons & 2;
|
||||
case RETRO_DEVICE_ID_MOUSE_WHEELUP:
|
||||
return apple->mouse_wu;
|
||||
case RETRO_DEVICE_ID_MOUSE_WHEELDOWN:
|
||||
return apple->mouse_wd;
|
||||
case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP:
|
||||
return apple->mouse_wl;
|
||||
case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN:
|
||||
return apple->mouse_wr;
|
||||
}
|
||||
int16_t val;
|
||||
switch (id)
|
||||
{
|
||||
case RETRO_DEVICE_ID_MOUSE_X:
|
||||
val = apple->window_pos_x - apple->mouse_x_last;
|
||||
apple->mouse_x_last = apple->window_pos_x;
|
||||
return val;
|
||||
case RETRO_DEVICE_ID_MOUSE_Y:
|
||||
val = apple->window_pos_y - apple->mouse_y_last;
|
||||
apple->mouse_y_last = apple->window_pos_y;
|
||||
return val;
|
||||
case RETRO_DEVICE_ID_MOUSE_LEFT:
|
||||
return apple->mouse_buttons & 1;
|
||||
case RETRO_DEVICE_ID_MOUSE_RIGHT:
|
||||
return apple->mouse_buttons & 2;
|
||||
case RETRO_DEVICE_ID_MOUSE_WHEELUP:
|
||||
return apple->mouse_wu;
|
||||
case RETRO_DEVICE_ID_MOUSE_WHEELDOWN:
|
||||
return apple->mouse_wd;
|
||||
case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP:
|
||||
return apple->mouse_wl;
|
||||
case RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN:
|
||||
return apple->mouse_wr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int16_t cocoa_mouse_state_screen(cocoa_input_data_t *apple,
|
||||
|
||||
@@ -51,7 +51,7 @@ static int16_t ctr_input_state(void *data,
|
||||
{
|
||||
ctr_input_t *ctr = (ctr_input_t*)data;
|
||||
|
||||
if (port > 0)
|
||||
if (port >= MENU_ENUM_LABEL_VALUE_INPUT_MAX_USERS)
|
||||
return 0;
|
||||
|
||||
switch (device)
|
||||
|
||||
@@ -43,7 +43,7 @@ static bool dos_keyboard_port_input_pressed(
|
||||
const struct retro_keybind *binds, unsigned id)
|
||||
{
|
||||
if (id < RARCH_BIND_LIST_END)
|
||||
return dos_key_state[DOS_KEYBOARD_PORT][rarch_keysym_lut[&binds[id].key]];
|
||||
return dos_key_state[DOS_KEYBOARD_PORT][rarch_keysym_lut[binds[id].key]];
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+212
-45
@@ -55,14 +55,109 @@ typedef struct ps3_input
|
||||
unsigned mice_connected;
|
||||
#endif
|
||||
const input_device_driver_t *joypad;
|
||||
KbInfo kbinfo;
|
||||
KbData kbdata[MAX_KB_PORT_NUM];
|
||||
int connected[MAX_KB_PORT_NUM];
|
||||
} ps3_input_t;
|
||||
|
||||
static int mod_table[] = {
|
||||
RETROK_RSUPER,
|
||||
RETROK_RALT,
|
||||
RETROK_RSHIFT,
|
||||
RETROK_RCTRL,
|
||||
RETROK_LSUPER,
|
||||
RETROK_LALT,
|
||||
RETROK_LSHIFT,
|
||||
RETROK_LCTRL
|
||||
};
|
||||
|
||||
static void ps3_connect_keyboard(ps3_input_t *ps3, int port)
|
||||
{
|
||||
ioKbSetCodeType(port, KB_CODETYPE_RAW);
|
||||
ioKbSetReadMode(port, KB_RMODE_INPUTCHAR);
|
||||
ps3->connected[port] = 1;
|
||||
}
|
||||
|
||||
static void ps3_disconnect_keyboard(ps3_input_t *ps3, int port)
|
||||
{
|
||||
ps3->connected[port] = 0;
|
||||
}
|
||||
|
||||
static void ps3_input_poll(void *data)
|
||||
{
|
||||
unsigned i, j;
|
||||
ps3_input_t *ps3 = (ps3_input_t*)data;
|
||||
KbData last_kbdata[MAX_KB_PORT_NUM];
|
||||
|
||||
if (ps3 && ps3->joypad)
|
||||
ps3->joypad->poll();
|
||||
|
||||
ioKbGetInfo(&ps3->kbinfo);
|
||||
for (i = 0; i < MAX_KB_PORT_NUM; i++)
|
||||
{
|
||||
if (ps3->kbinfo.status[i] && !ps3->connected[i])
|
||||
ps3_connect_keyboard(ps3, i);
|
||||
#if 0
|
||||
if (!ps3->kbinfo.status[i] && ps3->connected[i])
|
||||
ps3_disconnect_keyboard(ps3, i);
|
||||
#endif
|
||||
}
|
||||
|
||||
memcpy(last_kbdata, ps3->kbdata, sizeof(last_kbdata));
|
||||
for (i = 0; i < MAX_KB_PORT_NUM; i++)
|
||||
{
|
||||
if (ps3->kbinfo.status[i])
|
||||
ioKbRead(i, &ps3->kbdata[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_KB_PORT_NUM; i++)
|
||||
{
|
||||
/* Set keyboard modifier based on shift,ctrl and alt state */
|
||||
uint16_t mod = 0;
|
||||
|
||||
if (ps3->kbdata[i].mkey._KbMkeyU._KbMkeyS.l_alt || ps3->kbdata[i].mkey._KbMkeyU._KbMkeyS.r_alt)
|
||||
mod |= RETROKMOD_ALT;
|
||||
if (ps3->kbdata[i].mkey._KbMkeyU._KbMkeyS.l_ctrl || ps3->kbdata[i].mkey._KbMkeyU._KbMkeyS.r_ctrl)
|
||||
mod |= RETROKMOD_CTRL;
|
||||
if (ps3->kbdata[i].mkey._KbMkeyU._KbMkeyS.l_shift || ps3->kbdata[i].mkey._KbMkeyU._KbMkeyS.r_shift)
|
||||
mod |= RETROKMOD_SHIFT;
|
||||
/* TODO: windows keys. */
|
||||
|
||||
for (j = 0; j < last_kbdata[i].nb_keycode; j++)
|
||||
{
|
||||
int code = last_kbdata[i].keycode[j];
|
||||
int newly_depressed = 1;
|
||||
for (int k = 0; k < MAX_KB_PORT_NUM; i++)
|
||||
if (ps3->kbdata[i].keycode[k] == code)
|
||||
{
|
||||
newly_depressed = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (newly_depressed)
|
||||
{
|
||||
unsigned keyboardcode = input_keymaps_translate_keysym_to_rk(code);
|
||||
input_keyboard_event(false, keyboardcode, keyboardcode, mod, RETRO_DEVICE_KEYBOARD);
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < ps3->kbdata[i].nb_keycode; j++)
|
||||
{
|
||||
int code = ps3->kbdata[i].keycode[j];
|
||||
int newly_pressed = 1;
|
||||
for (int k = 0; k < MAX_KB_PORT_NUM; i++)
|
||||
if (last_kbdata[i].keycode[k] == code)
|
||||
{
|
||||
newly_pressed = 0;
|
||||
break;
|
||||
}
|
||||
if (newly_pressed)
|
||||
{
|
||||
unsigned keyboardcode = input_keymaps_translate_keysym_to_rk(code);
|
||||
input_keyboard_event(true, keyboardcode, keyboardcode, mod, RETRO_DEVICE_KEYBOARD);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_MOUSE
|
||||
@@ -74,13 +169,51 @@ static int16_t ps3_mouse_device_state(ps3_input_t *ps3,
|
||||
|
||||
#endif
|
||||
|
||||
static bool psl1ght_keyboard_port_input_pressed(ps3_input_t *ps3, unsigned id)
|
||||
{
|
||||
int code;
|
||||
unsigned i, j;
|
||||
|
||||
if (id >= RETROK_LAST || id == 0)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if (id == mod_table[i])
|
||||
{
|
||||
for (j = 0; j < MAX_KB_PORT_NUM; j++)
|
||||
{
|
||||
if (ps3->kbinfo.status[j] && (ps3->kbdata[j].mkey._KbMkeyU.mkeys &
|
||||
(1 << i)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
code = rarch_keysym_lut[id];
|
||||
if (code == 0)
|
||||
return false;
|
||||
for (i = 0; i < MAX_KB_PORT_NUM; i++)
|
||||
{
|
||||
if (ps3->kbinfo.status[i])
|
||||
for (j = 0; j < ps3->kbdata[i].nb_keycode; j++)
|
||||
{
|
||||
if (ps3->kbdata[i].keycode[j] == code)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int16_t ps3_input_state(void *data,
|
||||
rarch_joypad_info_t *joypad_info,
|
||||
const struct retro_keybind **binds,
|
||||
unsigned port, unsigned device,
|
||||
unsigned idx, unsigned id)
|
||||
{
|
||||
ps3_input_t *ps3 = (ps3_input_t*)data;
|
||||
ps3_input_t *ps3 = (ps3_input_t*)data;
|
||||
|
||||
if (!ps3)
|
||||
return 0;
|
||||
@@ -112,6 +245,9 @@ static int16_t ps3_input_state(void *data,
|
||||
ret |= (1 << i);
|
||||
continue;
|
||||
}
|
||||
else if (psl1ght_keyboard_port_input_pressed(ps3, binds[port][i].key))
|
||||
ret |= (1 << i);
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -129,12 +265,16 @@ static int16_t ps3_input_state(void *data,
|
||||
return true;
|
||||
if (((float)abs(ps3->joypad->axis(joypad_info->joy_idx, joyaxis)) / 0x8000) > joypad_info->axis_threshold)
|
||||
return true;
|
||||
if (psl1ght_keyboard_port_input_pressed(ps3, binds[port][id].key))
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case RETRO_DEVICE_ANALOG:
|
||||
if (binds[port])
|
||||
return input_joypad_analog(ps3->joypad, joypad_info, port, idx, id, binds[port]);
|
||||
if (binds[port])
|
||||
return input_joypad_analog(ps3->joypad, joypad_info, port, idx, id, binds[port]);
|
||||
break;
|
||||
case RETRO_DEVICE_KEYBOARD:
|
||||
return (psl1ght_keyboard_port_input_pressed(ps3, id));
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -142,11 +282,14 @@ static int16_t ps3_input_state(void *data,
|
||||
|
||||
static void ps3_input_free_input(void *data)
|
||||
{
|
||||
RARCH_LOG("alive " __FILE__ ":%d\n", __LINE__);
|
||||
ioPadEnd();
|
||||
ioKbEnd();
|
||||
}
|
||||
|
||||
static void* ps3_input_init(const char *joypad_driver)
|
||||
{
|
||||
int status;
|
||||
unsigned i;
|
||||
ps3_input_t *ps3 = (ps3_input_t*)calloc(1, sizeof(*ps3));
|
||||
if (!ps3)
|
||||
return NULL;
|
||||
@@ -156,6 +299,24 @@ static void* ps3_input_init(const char *joypad_driver)
|
||||
if (ps3->joypad)
|
||||
ps3->joypad->init(ps3);
|
||||
|
||||
/* Keyboard */
|
||||
|
||||
input_keymaps_init_keyboard_lut(rarch_key_map_psl1ght);
|
||||
|
||||
status = ioKbInit(MAX_KB_PORT_NUM);
|
||||
RARCH_LOG("Calling ioKbInit(%d) returned %d\r\n", MAX_KB_PORT_NUM, status);
|
||||
|
||||
status = ioKbGetInfo(&ps3->kbinfo);
|
||||
RARCH_LOG("Calling ioKbGetInfo() returned %d\r\n", status);
|
||||
|
||||
RARCH_LOG("KbInfo:\r\nMax Kbs: %u\r\nConnected Kbs: %u\r\nInfo Field: %08x\r\n", ps3->kbinfo.max, ps3->kbinfo.connected, ps3->kbinfo.info);
|
||||
|
||||
for (i = 0; i < MAX_KB_PORT_NUM; i++)
|
||||
{
|
||||
if (ps3->kbinfo.status[i])
|
||||
ps3_connect_keyboard(ps3, i);
|
||||
}
|
||||
|
||||
return ps3;
|
||||
}
|
||||
|
||||
@@ -166,6 +327,7 @@ static uint64_t ps3_input_get_capabilities(void *data)
|
||||
#ifdef HAVE_MOUSE
|
||||
(1 << RETRO_DEVICE_MOUSE) |
|
||||
#endif
|
||||
(1 << RETRO_DEVICE_KEYBOARD) |
|
||||
(1 << RETRO_DEVICE_JOYPAD) |
|
||||
(1 << RETRO_DEVICE_ANALOG);
|
||||
}
|
||||
@@ -173,14 +335,14 @@ static uint64_t ps3_input_get_capabilities(void *data)
|
||||
static bool ps3_input_set_sensor_state(void *data, unsigned port,
|
||||
enum retro_sensor_action action, unsigned event_rate)
|
||||
{
|
||||
RARCH_LOG("alive " __FILE__ ":%d\n", __LINE__);
|
||||
RARCH_LOG("alive " __FILE__ ":%d\n", __LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ps3_input_set_rumble(void *data, unsigned port,
|
||||
enum retro_rumble_effect effect, uint16_t strength)
|
||||
{
|
||||
RARCH_LOG("alive " __FILE__ ":%d\n", __LINE__);
|
||||
RARCH_LOG("alive " __FILE__ ":%d\n", __LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -269,25 +431,26 @@ static bool ps3_joypad_init(void *data)
|
||||
return true;
|
||||
}
|
||||
|
||||
static u16 transform_buttons(const padData *data) {
|
||||
return (
|
||||
(data->BTN_CROSS << RETRO_DEVICE_ID_JOYPAD_B)
|
||||
| (data->BTN_SQUARE << RETRO_DEVICE_ID_JOYPAD_Y)
|
||||
| (data->BTN_SELECT << RETRO_DEVICE_ID_JOYPAD_SELECT)
|
||||
| (data->BTN_START << RETRO_DEVICE_ID_JOYPAD_START)
|
||||
| (data->BTN_UP << RETRO_DEVICE_ID_JOYPAD_UP)
|
||||
| (data->BTN_DOWN << RETRO_DEVICE_ID_JOYPAD_DOWN)
|
||||
| (data->BTN_LEFT << RETRO_DEVICE_ID_JOYPAD_LEFT)
|
||||
| (data->BTN_RIGHT << RETRO_DEVICE_ID_JOYPAD_RIGHT)
|
||||
| (data->BTN_CIRCLE << RETRO_DEVICE_ID_JOYPAD_A)
|
||||
| (data->BTN_TRIANGLE << RETRO_DEVICE_ID_JOYPAD_X)
|
||||
| (data->BTN_L1 << RETRO_DEVICE_ID_JOYPAD_L)
|
||||
| (data->BTN_R1 << RETRO_DEVICE_ID_JOYPAD_R)
|
||||
| (data->BTN_L2 << RETRO_DEVICE_ID_JOYPAD_L2)
|
||||
| (data->BTN_R2 << RETRO_DEVICE_ID_JOYPAD_R2)
|
||||
| (data->BTN_L3 << RETRO_DEVICE_ID_JOYPAD_L3)
|
||||
| (data->BTN_R3 << RETRO_DEVICE_ID_JOYPAD_R3)
|
||||
);
|
||||
static u16 transform_buttons(const padData *data)
|
||||
{
|
||||
return (
|
||||
(data->BTN_CROSS << RETRO_DEVICE_ID_JOYPAD_B)
|
||||
| (data->BTN_SQUARE << RETRO_DEVICE_ID_JOYPAD_Y)
|
||||
| (data->BTN_SELECT << RETRO_DEVICE_ID_JOYPAD_SELECT)
|
||||
| (data->BTN_START << RETRO_DEVICE_ID_JOYPAD_START)
|
||||
| (data->BTN_UP << RETRO_DEVICE_ID_JOYPAD_UP)
|
||||
| (data->BTN_DOWN << RETRO_DEVICE_ID_JOYPAD_DOWN)
|
||||
| (data->BTN_LEFT << RETRO_DEVICE_ID_JOYPAD_LEFT)
|
||||
| (data->BTN_RIGHT << RETRO_DEVICE_ID_JOYPAD_RIGHT)
|
||||
| (data->BTN_CIRCLE << RETRO_DEVICE_ID_JOYPAD_A)
|
||||
| (data->BTN_TRIANGLE << RETRO_DEVICE_ID_JOYPAD_X)
|
||||
| (data->BTN_L1 << RETRO_DEVICE_ID_JOYPAD_L)
|
||||
| (data->BTN_R1 << RETRO_DEVICE_ID_JOYPAD_R)
|
||||
| (data->BTN_L2 << RETRO_DEVICE_ID_JOYPAD_L2)
|
||||
| (data->BTN_R2 << RETRO_DEVICE_ID_JOYPAD_R2)
|
||||
| (data->BTN_L3 << RETRO_DEVICE_ID_JOYPAD_L3)
|
||||
| (data->BTN_R3 << RETRO_DEVICE_ID_JOYPAD_R3)
|
||||
);
|
||||
}
|
||||
|
||||
static bool ps3_joypad_button(unsigned port_num, uint16_t joykey)
|
||||
@@ -300,13 +463,13 @@ static bool ps3_joypad_button(unsigned port_num, uint16_t joykey)
|
||||
|
||||
static void ps3_joypad_get_buttons(unsigned port_num, input_bits_t *state)
|
||||
{
|
||||
if (port_num < MAX_PADS)
|
||||
if (port_num < MAX_PADS)
|
||||
{
|
||||
u16 v = transform_buttons(&pad_state[port_num]);
|
||||
BITS_COPY16_PTR( state, v);
|
||||
}
|
||||
u16 v = transform_buttons(&pad_state[port_num]);
|
||||
BITS_COPY16_PTR( state, v);
|
||||
}
|
||||
else
|
||||
BIT256_CLEAR_ALL_PTR(state);
|
||||
BIT256_CLEAR_ALL_PTR(state);
|
||||
}
|
||||
|
||||
static int16_t ps3_joypad_axis(unsigned port_num, uint32_t joyaxis)
|
||||
@@ -357,23 +520,29 @@ static int16_t ps3_joypad_axis(unsigned port_num, uint32_t joyaxis)
|
||||
|
||||
static void ps3_joypad_poll(void)
|
||||
{
|
||||
padInfo padinfo;
|
||||
ioPadGetInfo(&padinfo);
|
||||
for(int port=0; port<MAX_PADS; port++){
|
||||
if(padinfo.status[port]){
|
||||
ioPadGetData(port, &pad_state[port]);
|
||||
}
|
||||
if (!pads_connected[port] && padinfo.status[port]) {
|
||||
ps3_joypad_autodetect_add(port);
|
||||
pads_connected[port] = 1;
|
||||
} else
|
||||
unsigned port;
|
||||
padInfo padinfo;
|
||||
|
||||
ioPadGetInfo(&padinfo);
|
||||
|
||||
for (port = 0; port < MAX_PADS; port++)
|
||||
{
|
||||
if (padinfo.status[port])
|
||||
ioPadGetData(port, &pad_state[port]);
|
||||
|
||||
if (!pads_connected[port] && padinfo.status[port])
|
||||
{
|
||||
input_autoconfigure_disconnect(port, ps3_joypad.ident);
|
||||
pads_connected[port] = 0;
|
||||
ps3_joypad_autodetect_add(port);
|
||||
pads_connected[port] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
input_autoconfigure_disconnect(port, ps3_joypad.ident);
|
||||
pads_connected[port] = 0;
|
||||
}
|
||||
|
||||
pads_connected[port] = padinfo.status[port];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool ps3_joypad_query_pad(unsigned pad)
|
||||
@@ -384,13 +553,11 @@ static bool ps3_joypad_query_pad(unsigned pad)
|
||||
static bool ps3_joypad_rumble(unsigned pad,
|
||||
enum retro_rumble_effect effect, uint16_t strength)
|
||||
{
|
||||
RARCH_LOG("alive " __FILE__ ":%d\n", __LINE__);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ps3_joypad_destroy(void)
|
||||
{
|
||||
RARCH_LOG("alive " __FILE__ ":%d\n", __LINE__);
|
||||
}
|
||||
|
||||
input_device_driver_t ps3_joypad = {
|
||||
|
||||
@@ -290,7 +290,7 @@ static void iohidmanager_hid_device_input_callback(void *data, IOReturn result,
|
||||
while (tmp && tmp->cookie != (IOHIDElementCookie)cookie)
|
||||
tmp = tmp->next;
|
||||
|
||||
if (tmp->cookie == (IOHIDElementCookie)cookie)
|
||||
if (tmp && tmp->cookie == (IOHIDElementCookie)cookie)
|
||||
{
|
||||
CFIndex min = IOHIDElementGetLogicalMin(element);
|
||||
CFIndex range = IOHIDElementGetLogicalMax(element) - min;
|
||||
|
||||
@@ -41,6 +41,10 @@
|
||||
#include <sys/keycodes.h>
|
||||
#endif
|
||||
|
||||
#ifdef __PSL1GHT__
|
||||
#include <io/kb.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SDL) || defined(HAVE_SDL2)
|
||||
#include "SDL.h"
|
||||
#endif
|
||||
@@ -1649,6 +1653,134 @@ const struct rarch_key_map rarch_key_map_dos[] = {
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef __PSL1GHT__
|
||||
const struct rarch_key_map rarch_key_map_psl1ght[] = {
|
||||
{ KB_RAWKEY_A, RETROK_a },
|
||||
{ KB_RAWKEY_B, RETROK_b },
|
||||
{ KB_RAWKEY_C, RETROK_c },
|
||||
{ KB_RAWKEY_D, RETROK_d },
|
||||
{ KB_RAWKEY_E, RETROK_e },
|
||||
{ KB_RAWKEY_F, RETROK_f },
|
||||
{ KB_RAWKEY_G, RETROK_g },
|
||||
{ KB_RAWKEY_H, RETROK_h },
|
||||
{ KB_RAWKEY_I, RETROK_i },
|
||||
{ KB_RAWKEY_J, RETROK_j },
|
||||
{ KB_RAWKEY_K, RETROK_k },
|
||||
{ KB_RAWKEY_L, RETROK_l },
|
||||
{ KB_RAWKEY_M, RETROK_m },
|
||||
{ KB_RAWKEY_N, RETROK_n },
|
||||
{ KB_RAWKEY_O, RETROK_o },
|
||||
{ KB_RAWKEY_P, RETROK_p },
|
||||
{ KB_RAWKEY_Q, RETROK_q },
|
||||
{ KB_RAWKEY_R, RETROK_r },
|
||||
{ KB_RAWKEY_S, RETROK_s },
|
||||
{ KB_RAWKEY_T, RETROK_t },
|
||||
{ KB_RAWKEY_U, RETROK_u },
|
||||
{ KB_RAWKEY_V, RETROK_v },
|
||||
{ KB_RAWKEY_W, RETROK_w },
|
||||
{ KB_RAWKEY_X, RETROK_x },
|
||||
{ KB_RAWKEY_Y, RETROK_y },
|
||||
{ KB_RAWKEY_Z, RETROK_z },
|
||||
{ KB_RAWKEY_BS, RETROK_BACKSPACE },
|
||||
{ KB_RAWKEY_TAB, RETROK_TAB },
|
||||
{ KB_RAWKEY_ENTER, RETROK_RETURN },
|
||||
{ KB_RAWKEY_PAUSE, RETROK_PAUSE },
|
||||
{ KB_RAWKEY_ESCAPE, RETROK_ESCAPE },
|
||||
{ KB_RAWKEY_SPACE, RETROK_SPACE },
|
||||
{ KB_RAWKEY_QUOTATION_101, RETROK_QUOTE },
|
||||
{ KB_RAWKEY_COMMA, RETROK_COMMA },
|
||||
{ KB_RAWKEY_MINUS, RETROK_MINUS },
|
||||
{ KB_RAWKEY_PERIOD, RETROK_PERIOD },
|
||||
{ KB_RAWKEY_SLASH, RETROK_SLASH },
|
||||
{ KB_RAWKEY_0, RETROK_0 },
|
||||
{ KB_RAWKEY_1, RETROK_1 },
|
||||
{ KB_RAWKEY_2, RETROK_2 },
|
||||
{ KB_RAWKEY_3, RETROK_3 },
|
||||
{ KB_RAWKEY_4, RETROK_4 },
|
||||
{ KB_RAWKEY_5, RETROK_5 },
|
||||
{ KB_RAWKEY_6, RETROK_6 },
|
||||
{ KB_RAWKEY_7, RETROK_7 },
|
||||
{ KB_RAWKEY_8, RETROK_8 },
|
||||
{ KB_RAWKEY_9, RETROK_9 },
|
||||
{ KB_RAWKEY_SEMICOLON, RETROK_SEMICOLON },
|
||||
{ KB_RAWKEY_EQUAL_101, RETROK_EQUALS },
|
||||
{ KB_RAWKEY_LEFT_BRACKET_101, RETROK_LEFTBRACKET },
|
||||
{ KB_RAWKEY_BACKSLASH_101, RETROK_BACKSLASH },
|
||||
{ KB_RAWKEY_RIGHT_BRACKET_101, RETROK_RIGHTBRACKET },
|
||||
{ KB_RAWKEY_DELETE, RETROK_DELETE },
|
||||
{ KB_RAWKEY_KPAD_0, RETROK_KP0 },
|
||||
{ KB_RAWKEY_KPAD_1, RETROK_KP1 },
|
||||
{ KB_RAWKEY_KPAD_2, RETROK_KP2 },
|
||||
{ KB_RAWKEY_KPAD_3, RETROK_KP3 },
|
||||
{ KB_RAWKEY_KPAD_4, RETROK_KP4 },
|
||||
{ KB_RAWKEY_KPAD_5, RETROK_KP5 },
|
||||
{ KB_RAWKEY_KPAD_6, RETROK_KP6 },
|
||||
{ KB_RAWKEY_KPAD_7, RETROK_KP7 },
|
||||
{ KB_RAWKEY_KPAD_8, RETROK_KP8 },
|
||||
{ KB_RAWKEY_KPAD_9, RETROK_KP9 },
|
||||
{ KB_RAWKEY_KPAD_PERIOD, RETROK_KP_PERIOD },
|
||||
{ KB_RAWKEY_KPAD_SLASH, RETROK_KP_DIVIDE },
|
||||
{ KB_RAWKEY_KPAD_ASTERISK, RETROK_KP_MULTIPLY },
|
||||
{ KB_RAWKEY_KPAD_MINUS, RETROK_KP_MINUS },
|
||||
{ KB_RAWKEY_KPAD_PLUS, RETROK_KP_PLUS },
|
||||
{ KB_RAWKEY_KPAD_ENTER, RETROK_KP_ENTER },
|
||||
{ KB_RAWKEY_UP_ARROW, RETROK_UP },
|
||||
{ KB_RAWKEY_DOWN_ARROW, RETROK_DOWN },
|
||||
{ KB_RAWKEY_RIGHT_ARROW, RETROK_RIGHT },
|
||||
{ KB_RAWKEY_LEFT_ARROW, RETROK_LEFT },
|
||||
{ KB_RAWKEY_INSERT, RETROK_INSERT },
|
||||
{ KB_RAWKEY_HOME, RETROK_HOME },
|
||||
{ KB_RAWKEY_END, RETROK_END },
|
||||
{ KB_RAWKEY_PAGE_UP, RETROK_PAGEUP },
|
||||
{ KB_RAWKEY_PAGE_DOWN, RETROK_PAGEDOWN },
|
||||
{ KB_RAWKEY_F1, RETROK_F1 },
|
||||
{ KB_RAWKEY_F2, RETROK_F2 },
|
||||
{ KB_RAWKEY_F3, RETROK_F3 },
|
||||
{ KB_RAWKEY_F4, RETROK_F4 },
|
||||
{ KB_RAWKEY_F5, RETROK_F5 },
|
||||
{ KB_RAWKEY_F6, RETROK_F6 },
|
||||
{ KB_RAWKEY_F7, RETROK_F7 },
|
||||
{ KB_RAWKEY_F8, RETROK_F8 },
|
||||
{ KB_RAWKEY_F9, RETROK_F9 },
|
||||
{ KB_RAWKEY_F10, RETROK_F10 },
|
||||
{ KB_RAWKEY_F11, RETROK_F11 },
|
||||
{ KB_RAWKEY_F12, RETROK_F12 },
|
||||
{ KB_RAWKEY_KPAD_NUMLOCK, RETROK_NUMLOCK },
|
||||
{ KB_RAWKEY_CAPS_LOCK, RETROK_CAPSLOCK },
|
||||
{ KB_RAWKEY_SCROLL_LOCK, RETROK_SCROLLOCK },
|
||||
{ KB_RAWKEY_PAUSE, RETROK_BREAK },
|
||||
|
||||
/*
|
||||
{ KB_RAWKEY_HASHTILDE, RETROK_HASH },
|
||||
{ KB_RAWKEY_KPLEFTPAREN, RETROK_LEFTPAREN },
|
||||
{ KB_RAWKEY_KPRIGHTPAREN, RETROK_RIGHTPAREN },
|
||||
{ KB_RAWKEY_LEFTMETA, RETROK_LMETA },
|
||||
{ KB_RAWKEY_RIGHTMETA, RETROK_RMETA },
|
||||
{ KB_RAWKEY_COMPOSE, RETROK_COMPOSE },
|
||||
{ KB_RAWKEY_HELP, RETROK_HELP },
|
||||
{ KB_RAWKEY_POWER, RETROK_POWER },
|
||||
{ KB_RAWKEY_UNDO, RETROK_UNDO },
|
||||
{ KB_RAWKEY_KPAD_EQUAL, RETROK_KP_EQUALS },
|
||||
|
||||
KB_RAWKEY_PRINTSCREEN
|
||||
KB_RAWKEY_APPLICATION
|
||||
|
||||
KB_RAWKEY_106_KANJI
|
||||
KB_RAWKEY_KANA
|
||||
KB_RAWKEY_HENKAN
|
||||
KB_RAWKEY_MUHENKAN
|
||||
KB_RAWKEY_ACCENT_CIRCONFLEX_106
|
||||
KB_RAWKEY_ATMARK_106
|
||||
KB_RAWKEY_LEFT_BRACKET_106
|
||||
KB_RAWKEY_RIGHT_BRACKET_106
|
||||
KB_RAWKEY_COLON_106
|
||||
KB_RAWKEY_BACKSLASH_106
|
||||
KB_RAWKEY_YEN_106 */
|
||||
|
||||
{ 0, RETROK_UNKNOWN }
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && _WIN32_WINNT >= 0x0501 && !defined(__WINRT__)
|
||||
const struct rarch_key_map rarch_key_map_winraw[] = {
|
||||
{ VK_BACK, RETROK_BACKSPACE },
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#endif
|
||||
|
||||
#include "../configuration.h"
|
||||
#include "../retroarch.h"
|
||||
|
||||
void input_mapper_poll(input_mapper_t *handle,
|
||||
void *ol_pointer,
|
||||
@@ -124,6 +125,14 @@ void input_mapper_poll(input_mapper_t *handle,
|
||||
remap_valid = (current_button_value == 1) &&
|
||||
(j != remap_button) && (remap_button != RARCH_UNMAPPED);
|
||||
|
||||
#ifdef HAVE_ACCESSIBILITY
|
||||
/* gamepad override */
|
||||
if (i==0 && get_gamepad_input_override() & (1<<j))
|
||||
{
|
||||
BIT256_SET(handle->buttons[i], j);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (remap_valid)
|
||||
{
|
||||
if (remap_button < RARCH_FIRST_CUSTOM_BIND)
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
## Steps
|
||||
|
||||
- Developers update strings in `msg_hash_us.h`.
|
||||
- Developers (can set a cron job) run `./h2json.py msg_hash_us.h` to generate `msg_hash_us.json`. It is just a convenient format that is supported by Weblate/Crowdin/Transifex and doesn't need to be inversion control.
|
||||
- Developers (can set a cron job) run `./h2json.py msg_hash_us.h` to generate `msg_hash_us.json`. It is just a convenient format that is supported by Weblate/Crowdin/Transifex and doesn't need to be in version control.
|
||||
- Developers (can set a cron job) upload `msg_hash_us.json` to Weblate/Crowdin/Transifex.
|
||||
- Translators translate strings on Weblate/Crowdin/Transifex.
|
||||
- Developers (can set a cron job) download `msg_hash_xx.json` files.
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2011-2017 - Daniel De Matteis
|
||||
* Copyright (C) 2016-2019 - Brad Parker
|
||||
*
|
||||
@@ -30,7 +30,7 @@
|
||||
/* https://support.microsoft.com/en-us/kb/980263 */
|
||||
#pragma execution_character_set("utf-8")
|
||||
#endif
|
||||
#pragma warning(disable: 4566)
|
||||
#pragma warning(disable:4566)
|
||||
#endif
|
||||
|
||||
int menu_hash_get_help_ar_enum(enum msg_hash_enums msg, char *s, size_t len)
|
||||
|
||||
+149
-87
@@ -7,96 +7,158 @@
|
||||
#endif
|
||||
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_CONFIGURATIONS_LIST,
|
||||
"ملفات التكوين"
|
||||
)
|
||||
MENU_ENUM_LABEL_VALUE_CONFIGURATIONS_LIST,
|
||||
"ملفات التكوين"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_AUDIO_DRIVER,
|
||||
"نظام تشغيل الصوت"
|
||||
)
|
||||
MENU_ENUM_LABEL_VALUE_AUDIO_DRIVER,
|
||||
"نظام تشغيل الصوت"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_AUDIO_SETTINGS,
|
||||
"الصوت"
|
||||
)
|
||||
MENU_ENUM_LABEL_VALUE_AUDIO_SETTINGS,
|
||||
"الصوت"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_CAMERA_DRIVER,
|
||||
"نظام تشغيل الكاميرا"
|
||||
)
|
||||
MENU_ENUM_LABEL_VALUE_CAMERA_DRIVER,
|
||||
"نظام تشغيل الكاميرا"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_CONFIGURATIONS,
|
||||
"تحميل ملف التكوين"
|
||||
)
|
||||
MENU_ENUM_LABEL_VALUE_CONFIGURATIONS,
|
||||
"تحميل ملف التكوين"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_CONFIGURATION_SETTINGS,
|
||||
"ملفات التكوين"
|
||||
)
|
||||
MENU_ENUM_LABEL_VALUE_CONFIGURATION_SETTINGS,
|
||||
"ملفات التكوين"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_CONFIG_SAVE_ON_EXIT,
|
||||
"Save Configuration on Exit"
|
||||
)
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SETTINGS,
|
||||
"القائمة السريعة")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_LIST,
|
||||
"تحميل الكور")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_SETTINGS,
|
||||
"الدلائل")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_DRIVER_SETTINGS,
|
||||
"أنظمة التشغيل")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP,
|
||||
"مساعدة")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_LIST,
|
||||
"مساعدة")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_INFORMATION,
|
||||
"معلومات")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_INFORMATION_LIST,
|
||||
"معلومات")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DRIVER,
|
||||
"نظام تشغيل أجهزة الادخال")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_SETTINGS,
|
||||
"أجهزة الادخال")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_JOYPAD_DRIVER,
|
||||
"نظام تشغيل الجوي باد")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ARABIC,
|
||||
"عربى")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST,
|
||||
"تحميل المحتوى")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_MAIN_MENU,
|
||||
"القائمة الرئيسية")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_DRIVER,
|
||||
"نظام تشغيل القائمة")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_SETTINGS,
|
||||
"الشبكة")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_ONLINE_UPDATER,
|
||||
"التحديث عبر الانترنت")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_ONSCREEN_DISPLAY_SETTINGS,
|
||||
"العرض على الشاشة")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLISTS_TAB,
|
||||
"قوائم التشغيل")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY,
|
||||
"قائمة التشغيل")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_SETTINGS,
|
||||
"قوائم التشغيل")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_PRIVACY_SETTINGS,
|
||||
"خصوصية")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_QUIT_RETROARCH,
|
||||
"إنهاء البرنامج")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_DRIVER,
|
||||
"نظام تشغيل التسجيل")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_RETRO_ACHIEVEMENTS_SETTINGS,
|
||||
"الإنجازات")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVING_SETTINGS,
|
||||
"الحفظ")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_USER_INTERFACE_SETTINGS,
|
||||
"واجهة المستخدم")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_USER_SETTINGS,
|
||||
"المستخدم")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_DRIVER,
|
||||
"نظام تشغيل الفيديو")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SETTINGS,
|
||||
"الفيديو")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_WIFI_DRIVER,
|
||||
"نظام تشغيل الواي-فاي")
|
||||
MSG_HASH(MENU_ENUM_SUBLABEL_DRIVER_SETTINGS,
|
||||
"تغيير أنظمة التشغيل المستخدمة من قبل البرنامج.")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_DELETE_PLAYLIST,
|
||||
"إحذف قائمة التشغيل")
|
||||
MENU_ENUM_LABEL_VALUE_CONTENT_SETTINGS,
|
||||
"القائمة السريعة"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_CORE_LIST,
|
||||
"تحميل الكور"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_DIRECTORY_SETTINGS,
|
||||
"الدلائل"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_DRIVER_SETTINGS,
|
||||
"أنظمة التشغيل"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_HELP,
|
||||
"مساعدة"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_HELP_LIST,
|
||||
"مساعدة"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_INFORMATION,
|
||||
"معلومات"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_INFORMATION_LIST,
|
||||
"معلومات"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_INPUT_DRIVER,
|
||||
"نظام تشغيل أجهزة الادخال"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_INPUT_SETTINGS,
|
||||
"أجهزة الادخال"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_JOYPAD_DRIVER,
|
||||
"نظام تشغيل الجوي باد"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_LANG_ARABIC,
|
||||
"عربى"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST,
|
||||
"تحميل المحتوى"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_MAIN_MENU,
|
||||
"القائمة الرئيسية"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_MENU_DRIVER,
|
||||
"نظام تشغيل القائمة"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_NETWORK_SETTINGS,
|
||||
"الشبكة"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_ONLINE_UPDATER,
|
||||
"التحديث عبر الانترنت"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_ONSCREEN_DISPLAY_SETTINGS,
|
||||
"العرض على الشاشة"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_PLAYLISTS_TAB,
|
||||
"قوائم التشغيل"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY,
|
||||
"قائمة التشغيل"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_PLAYLIST_SETTINGS,
|
||||
"قوائم التشغيل"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_PRIVACY_SETTINGS,
|
||||
"خصوصية"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_QUIT_RETROARCH,
|
||||
"إنهاء البرنامج"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_RECORD_DRIVER,
|
||||
"نظام تشغيل التسجيل"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_RETRO_ACHIEVEMENTS_SETTINGS,
|
||||
"الإنجازات"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_SAVING_SETTINGS,
|
||||
"الحفظ"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_USER_INTERFACE_SETTINGS,
|
||||
"واجهة المستخدم"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_USER_SETTINGS,
|
||||
"المستخدم"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_VIDEO_DRIVER,
|
||||
"نظام تشغيل الفيديو"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_VIDEO_SETTINGS,
|
||||
"الفيديو"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_WIFI_DRIVER,
|
||||
"نظام تشغيل الواي-فاي"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_SUBLABEL_DRIVER_SETTINGS,
|
||||
"تغيير أنظمة التشغيل المستخدمة من قبل البرنامج."
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_LABEL_VALUE_DELETE_PLAYLIST,
|
||||
"إحذف قائمة التشغيل"
|
||||
)
|
||||
+5954
-3615
File diff suppressed because it is too large.
Load diff
Loaded 100 of 235 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user