Author SHA1 Message Date
fgsfds 32a1cb9f26 Merge pull request #747 from johnmcollier/stop-text-input
Prevent keyboard events from being swaollwed on certain Wayland systems
2026-08-13 07:51:05 +02:00
John Collier 9f30f50b79 Prevent keyboard events from being swaollwed on certain Wayland systems
Signed-off-by: John Collier <6880023+johnmcollier@users.noreply.github.com>
2026-08-13 01:10:48 -04:00
fgsfds 514bf7affd Merge pull request #731 from fpiesche/rename-freedesktop
Rename freedesktop
2026-05-29 09:46:49 +02:00
Florian Piesche 7477a6ce44 Update flatpak runtime 2026-05-26 13:13:55 +01:00
Florian Piesche f7c0cb8b03 update workflow to new freedesktop name 2026-05-26 13:09:30 +01:00
Florian Piesche accb882a36 Rename FreeDesktop files 2026-05-26 13:04:46 +01:00
fgsfds 0750c54200 Merge pull request #729 from ZenithMDC/mousewheel-scrollable-menus
Add mousewheel scrolling to scrollable menus
2026-05-25 15:06:30 +02:00
Matthew Coppola b81b7e260b Add mousewheel scrolling to scrollable menus 2026-05-25 08:24:12 -04:00
fgsfds 3f47f1ec6f Merge pull request #443 from blaiz/all-guns-cheat-multiplayer
Make "All Guns in Solo" cheat work in multiplayer
2026-05-24 10:45:03 +02:00
fgsfds f9d847df3b Merge pull request #698 from AL2009man/CameraAngleWrappingFix
Vertical Camera Angle wrapping fix
2026-05-24 10:44:00 +02:00
fgsfds c110f9cf42 Merge pull request #725 from joshuarwood/camspy_light_fix
Allow player character to block lights in camspy mode
2026-05-23 20:49:53 +02:00
joshuarwood cce73d91ce test for eyespy before checking mode 2026-05-21 21:10:29 -05:00
joshuarwood 3360eb429d allow player character to block lights in camspy mode 2026-05-21 20:10:33 -05:00
fgsfds 132e59d3ec Merge pull request #723 from joshuarwood/visiblelos_edge_case
Reset hit prop to continue los test following a glass surface
2026-05-21 17:55:20 +02:00
joshuarwood c166cf0f15 reset hit prop to continue los test following a glass surface 2026-05-20 22:31:58 -05:00
fgsfds 20fc4c6cc7 port: #721: scale glare brightness with FOV; add glare brightness settings 2026-05-17 12:42:54 +02:00
fgsfds 309bd45a01 port: #718: disable linear filtering and mipmaps when three-point is enabled 2026-05-17 12:40:43 +02:00
fgsfds 45139a9293 Merge pull request #719 from jonaeru/fix-menutexture
Fix menu character and weapon texture corruption
2026-05-02 12:19:48 +02:00
Jonaeru 998eee9c61 Fix menu character and weapon texture corruption 2026-05-01 21:28:41 +09:00
fgsfds d8962763b7 port: don't apply linear mag filter when using three-point either 2026-04-28 18:48:55 +02:00
fgsfds 783791064b port: actually use the filter array for the previous fix instead of smoking crack 2026-04-28 18:45:08 +02:00
fgsfds 8106349540 port: if three-point filtering is enabled, don't also enable bilinear filtering 2026-04-28 18:32:23 +02:00
fgsfds bed3bf52d0 Merge pull request #715 from Alex-LeTux/patch-1
Remove trailing slash from directory checks
2026-04-25 19:31:47 +02:00
Alex LeTux f25721da8f Remove trailing slash from directory checks
> The slash is unnecessary and causes issues when building with a recent version of MinGW.
2026-04-24 11:23:38 +02:00
fgsfds 7c949ed9d7 Merge pull request #675 from rafccq/port-tex-mips-aniso
Mipmaps and Anisotropic Filtering
2026-03-23 10:34:33 +01:00
fgsfds 8470d50f21 Merge pull request #697 from TartanSpartan/fix-scissor-viewport
Improve scissor operations to correct "thin blue line" bug
2026-03-23 10:33:12 +01:00
fgsfds 27b2dcc27d Merge pull request #700 from TartanSpartan/acknowledge-npc-gifts
Acknowledge npc gifts and suppress spurious cutscene notifications
2026-03-23 10:31:40 +01:00
fgsfds 2626434b69 Merge pull request #701 from TartanSpartan/fix-cheats-across-optimizations
Fix issue for some cheats across build optimizations
2026-03-23 10:30:44 +01:00
fgsfds 11df50b3ad Merge pull request #707 from cylonicboom/port
fixup keyboard input + vi insert shortcut
2026-03-14 23:35:33 +01:00
Catherine Reprobate ccb3c8668d fixup keyboard input + vi insert shortcut 2026-03-14 12:57:55 -07:00
fgsfds d58a423e5f Merge pull request #706 from joshuarwood/shield_light_fix
Fix for light visibility through shields
2026-03-14 09:15:55 +01:00
joshuarwood fc70da875e add a comment describing PC specific shield handling 2026-03-13 18:01:10 -05:00
fgsfds d4ac8b155d Merge pull request #705 from joshuarwood/fix_chr_light_regression
Fix a regression in light artifact handling through character models
2026-03-13 20:45:33 +01:00
joshuarwood 0946cd18c6 disable bbox padding when performing light los test to prevent shield transparency from blocking light artifacts 2026-03-12 23:59:10 -05:00
joshuarwood 23aafa4ffa use texturenum -1 for chr hits because cheap version of chrTestHit returns an uninitialized value 2026-03-12 18:31:17 -05:00
TartanSpartan 426f9c6890 Fix issue for some cheats across build optimizations 2026-02-12 00:55:28 +00:00
TartanSpartan cc3886888a Suppress gadget notifications in cutscenes 2026-02-12 00:18:36 +00:00
TartanSpartan 55ca51d8cc Have HUD acknowledge new weapons gifted from NPCs 2026-02-11 22:25:25 +00:00
AL2009man f251653317 Vertical camera angle wrapping fix
Solves a issue when using Input Remapper's Mouse-based Reset to Horizon camera function (e.g. Steam Input), where the recenter couldn't stay centered.
2026-01-31 23:38:58 -05:00
TartanSpartan bcb8c2720a Improve scissor operations for upstream. 2026-01-29 22:12:30 +00:00
fgsfds 246d737663 Merge pull request #680 from ZenithMDC/preserve-cs-sim-list
Preserve Combat Simulator sim list after Co-Op/Counter-Op
2026-01-07 09:21:18 +01:00
fgsfds 425b51e51c input: fix build with SDL<2.0.16 2026-01-07 09:17:34 +01:00
fgsfds 6e6ffad1a1 Merge pull request #687 from AL2009man/KB/M-Confirm-Cancel
default PC's KB/M Menu bindings navigation now reflects newer PC Games' KB/M setup
2026-01-04 20:47:11 +01:00
Al. Lopez 2028ae7412 changes default PC's Menu bindings to reflect Modern games' Menu UI design
Those who are playing the PC Port of Perfect Dark for the first time, but coming from newer PC Versions' menu bindings will find out Menu bindings don't confined towards a modern standard. This PR addresses it while retaining backwards compatibility.

the RETURN/ENTER key will become a proper CONFIRM action, as opposed to emulating as a START button. (the emulated START button will still be TAB key), while Right Mouse Click now behaves as a CANCEL key. 

This won't affect existing Perfect Dark PC Players' existing bindings. but the next time you reset the default Key Bindings will experience a more streamlined setup.
2026-01-03 20:14:20 -05:00
Matthew Coppola 0c82545ba9 Preserve Combat Simulator sim list after Co-Op/Counter-Op 2025-12-26 21:25:10 -05:00
fgsfds 2550ce72f4 Merge pull request #684 from AL2009man/XboxREADMEFix
corrected Xbox pad name (LS Click) on Crouch cycle over at `README.md` Controls page
2025-12-20 10:27:31 +01:00
fgsfds 50481b77d0 Merge pull request #683 from qubitnano/bcachefs
fix homeDir check
2025-12-20 10:27:10 +01:00
Al. Lopez 4ee8f3c077 Corrected Xbox Pad page on README.md
last I check: Xbox Controller doesn't refer "Left Stick Click" as "L3".

PlayStation and Steam Deck/Steam Controller (2026) actually refers their variant as "L3".
2025-12-19 21:01:25 -05:00
qubitnano 0df84ff180 fix homeDir check
bcachefs directories return stat.st_size=0
2025-12-19 20:18:18 -05:00
fgsfds a6374b016d Merge pull request #679 from ZenithMDC/fix-cs-load-settings-clobber
Prevent Combat Simulator 'Load Settings' clobber
2025-12-07 09:56:10 +01:00
Matthew Coppola 75d1b8ffd2 Prevent Combat Simulator 'Load Settings' clobber 2025-12-07 03:04:27 -05:00
fgsfds 8165b5005e Merge pull request #677 from AL2009man/CrosshairSwivelFix
fixed Crosshair Swivel conflicting when using Mixed Input
2025-12-05 12:55:07 +01:00
AL2009man 2d0375da2e fixed Crosshair Swivel conflicting when using Mixed Input
Addresses the issue with Crosshair Swivel conflciting with each other when using both Mouse and Camera at the same time.
2025-12-04 14:55:31 -05:00
fgsfds 4bcfeddca7 Merge pull request #674 from ZenithMDC/limit-start-armed-to-csim
Limit 'Start Armed' option to Combat Simulator
2025-12-04 18:20:39 +01:00
Raf 2d390ae5ce small code simplification 2025-12-04 18:55:52 +08:00
Raf c303c81f88 gfx: mipmaps and anisotropic filtering 2025-12-04 18:09:49 +08:00
Matthew Coppola 6b0c4a11e2 Limit 'Start Armed' option to Combat Simulator 2025-12-03 19:35:24 -05:00
fgsfds 7f68c46959 Merge pull request #671 from joshuarwood/light_fix_for_laser
Exclude laser doors from lighting line-of-sight test
2025-11-23 08:38:08 +01:00
joshuarwood f3f2a593e8 exclude laser doors from los test 2025-11-22 00:39:35 -06:00
fgsfds 79711364bb Merge pull request #668 from joshuarwood/light_fix_for_bg_glass
Fix for background lights
2025-11-09 10:39:11 +01:00
fgsfds 0896860d58 Merge pull request #670 from Project516/patch-1
fix link to fast
2025-11-09 10:36:46 +01:00
fgsfds e1dd49fc3a Merge pull request #669 from joshuarwood/light_fix_for_xlu_prop
Fix light transparency for tinted glass doors
2025-11-09 10:36:28 +01:00
joshuarwood b53a62189b protect against surface indexing errors 2025-11-09 01:30:49 -06:00
Project516 77dc12e41f fix link to fast 2025-11-08 15:36:29 -06:00
joshuarwood 42ef08d662 check surfacetype to better skip glass props 2025-11-07 19:50:42 -06:00
joshuarwood f5cbfe6692 disable xlu surface hits with a global to avoid initialization errors with struct flag 2025-11-07 18:38:27 -06:00
joshuarwood 550f1d3182 add flag to ignore line-of-sight hits for transparent background surfaces 2025-11-07 15:18:02 -06:00
joshuarwood 7a728c7feb Removing commit that was intended for a different branch
This reverts commit 857e755b92.
2025-11-07 15:11:09 -06:00
joshuarwood 857e755b92 added flag to ignore line-of-sight hits for transparent background surfaces 2025-11-07 15:08:50 -06:00
fgsfds 8ea7e7b410 Merge pull request #661 from AL2009man/RawInputFix
Temporarily disables RawInput driver by default
2025-10-08 20:50:23 +02:00
AL2009man 6dd3ec7fda Temporarily disables RawInput driver
Due to a Windows Update regression: RawInput driver has a issue related to Xbox Controllers' trigger input only being detected. For safety reasons, `useRawInput` will be disabled by default until the bug is fixed on Microsoft's end.

for those who still needs it: you can head over to `pd.ini` and revert `useRawInput` back to `1`
2025-10-08 14:15:58 -04:00
fgsfds bb4fcffeb5 port: fix #650 2025-08-25 09:26:07 +02:00
fgsfds 498e1667a4 Merge pull request #631 from AL2009man/CrosshairFix
Crosshair Edge Deadzone slider and fixed `insightaim` Camera Movement
2025-08-23 09:17:13 +02:00
fgsfds 19541418b0 Merge pull request #642 from OlegAckbar/port
port: fix multi-monitor issues on Wayland
2025-08-10 12:28:58 +02:00
fgsfds 75952f0395 Merge pull request #643 from OlegAckbar/window-title
port: do not change window title
2025-08-10 12:26:10 +02:00
Oleg 04d280cd42 port: do not change window title 2025-08-10 12:05:46 +03:00
Oleg 58c2f9d8fa port: fix multi-monitor issues on Wayland 2025-08-10 12:04:29 +03:00
fgsfds 6591281d99 Merge pull request #636 from AL2009man/SteamDeck-HID
Steam Controller/Deck HIDAPI Hint Support
2025-07-22 21:33:55 +02:00
AL2009man 5fd4a431b1 fixup whitespace on SDL_SetHint 2025-07-13 06:31:11 -04:00
AL2009man 27223802be added Steam Controller/Deck HIDAPI Hint
This enables HIDAPI support for Steam Controller (Bluetooth only) and Steam Deck.

Note: while SteamDeck HIDAPI is enabled, it works best while in Desktop Mode and without Steam Client running in the background (will show the actual device name instead of "Steam Virtual Gamepad"). It may not support more advanced feature sets, and it only remains that case until Valve adds Motion Sensor passthru support to SDL2/SDL3 while using SteamInput.
2025-07-12 14:56:41 -04:00
Al. Lopez 09df313d09 remove gyro leftover text 2025-06-27 21:24:25 -04:00
AL2009man 01b78105ff added Crosshair Edge Boundary Box 2025-06-27 21:18:52 -04:00
fgsfds 618a1f3386 port: set g_MaxExplosions to 6 by default 2025-06-14 09:59:19 +02:00
fgsfds 4bd6dd8617 Merge pull request #597 from rafccq/port-no-doors
"No Doors" option in multiplayer
2025-06-11 12:40:33 +02:00
fgsfds eabd7a438f Merge pull request #623 from rafccq/port-max-explosions
Maximum number of explosions now can be changed from the .ini file
2025-06-11 12:23:31 +02:00
fgsfds e8a69f39db port: fix deformation-related vertex explosions on 64-bit 2025-06-06 11:18:50 +02:00
fgsfds 38cb1557d0 cmake: enable compile_commands.json 2025-06-06 11:04:40 +02:00
Raf 97444de634 Merge branch 'fgs-port' into port-max-explosions 2025-06-04 01:21:03 -03:00
fgsfds d9185982f8 port: fix sun glare 2025-06-02 23:07:35 +02:00
fgsfds 790374e95f port: fix whitespace in input.c 2025-06-01 10:27:16 +02:00
fgsfds 9c98fe7976 port: fix inputMouseGetAbsScaledDelta 2025-06-01 10:23:56 +02:00
fgsfds 9bffab7e3e port: do not read past the end of EEPROM when scanning for headers 2025-05-31 13:24:13 +02:00
Raf 8037431686 port: moved the max explosions config to the .ini file 2025-05-30 01:25:18 -03:00
fgsfds a040b29d40 Merge pull request #621 from rafccq/port-enh-mpsetupfile
port-mp-setups: a bunch of bug fixes
2025-05-29 21:10:35 +02:00
Raf 5a3d45de65 port-mp-setups: spaces -> tabs (2) 2025-05-29 16:08:41 -03:00
Raf 5a90152991 port-mp-setups: spaces -> tabs (2) 2025-05-29 16:08:09 -03:00
Raf 8891bbf7ec port-mp-setups: spaces -> tabs 2025-05-29 16:05:25 -03:00
Raf abf2ae8115 Merge branch 'port-enh-mpsetupfile' of https://github.com/rafccq/perfect_dark into port-enh-mpsetupfile
# Conflicts:
#	src/game/filemgr.c
2025-05-29 15:33:58 -03:00
Raf 20bd9ddcbb port-mp-setups: a bunch of bug fixes
- only load the MP setup file when loading the agent, instead of when entering CS
- "clear default" was cause the game setup to become invalid upon re-entering it
- all challenges were showing the same text
2025-05-29 15:33:32 -03:00
Raf 1d7dd064fe port-mp-setups: a bunch of bug fixes
- only load the MP setup file when loading the agent, instead of when entering CS
- "clear default" was cause the game setup to become invalid upon re-entering it
- all challenges were showing the same text
2025-05-29 15:31:19 -03:00
fgsfds 629dbfe924 Merge pull request #613 from AL2009man/FOV-MouseSen-fix
Camera Sensitivity no longer tied to FOV Slider
2025-05-29 20:01:32 +02:00
fgsfds f72f93a270 Merge pull request #619 from AL2009man/PerfectQuakeDark2
Mouse Sensitivty cap increased to 30.00
2025-05-29 20:00:14 +02:00
AL2009man 57eead9078 cleaned up MouseGetScaledDelta and AbsScaledDelta
To prepare for the revised MouseScaledDelta: the current setup has been simplified for easier code reading
2025-05-29 00:07:33 -04:00
AL2009man 094d80a5cf fixed MouseSpeedX/Y config file number limit 2025-05-28 23:10:41 -04:00
AL2009man 11bf7aa638 Increased Mouse sensitivity to 30.00
this wil be more in line with id Tech's max mouse sens, which is also 30.00
2025-05-28 22:32:41 -04:00
Raf 79a47809da port-no-doors: another code quality improvement 2025-05-28 21:08:17 -03:00
Raf 33aa747386 port: enabled colors in the cmake build output 2025-05-28 21:00:16 -03:00
Raf a70868fba0 port-no-doors: moved new MP options to a new menu 2025-05-28 20:59:36 -03:00
Raf c866940873 port-no-doors: a couple code quality improvements 2025-05-28 20:57:21 -03:00
Raf 0973f70301 port-no-doors: reverted the menu changes 2025-05-28 20:55:01 -03:00
Raf 54b62c044f Merge branch 'port' into port-no-doors 2025-05-28 20:43:58 -03:00
fgsfds d5b4e0916c Merge pull request #618 from cylonicboom/pr/discover-dialogisopen
refactor(menu): rename unk5d5_06 and sp344 for clarity
2025-05-25 00:39:20 +02:00
Catherine Reprobate 45f25c704a refactor(menu): rename unk5d5_06 and sp344 for clarity
Backport from Friends of Joanna: renamed the bool member `unk5d5_06` in
the `menudata` struct to `isdialogopen` to clarify its purpose as a
dialog state flag. Also renamed the local bool variable `sp344` in
`menutick.c` to `isdialogopen` to reflect its relation to the struct
member. Updated all references for consistency and improved readability.
2025-05-24 13:38:43 -07:00
AL2009man d8aefc33fc fixed Sniper Rilfle zoom when using FOV higher than 60%
Removing the scaling entirely beraks Sniper Rifle zoom. So: we're switching back to FOV Scaling, but now it'll be based on `PLAYER_DEFAULT_FOV` instead of `60.0f`. This now ensures tha
2025-05-16 19:26:46 -04:00
AL2009man cdd116830d fixed tmp spacing 2025-05-16 00:50:57 -04:00
AL2009man 11d02dd8f2 last attempt on whitespace fix 2025-05-16 00:46:08 -04:00
AL2009man 73631e8d5f attempted whitespace fix 1 2025-05-16 00:42:34 -04:00
AL2009man a1136f4d61 fixed Mouse Sensitivity affecting FOV Slider
Your mouse sens scale should now behave exactly the same, regardless of FOV Slider
2025-05-16 00:36:17 -04:00
fgsfds 8bfaaf63ed Merge pull request #610 from joshuarwood/documented_zbuffer
Updated variable and function names for artifact handling
2025-05-12 16:43:07 +02:00
joshuarwood 2d59929261 syncing moved files 2025-05-11 12:23:32 -05:00
joshuarwood 86e6e54792 return ifdef to original position following the debugging tests 2025-05-11 12:22:01 -05:00
joshuarwood f12ae756ef rename game_13c510 files to artifact 2025-05-11 12:17:38 -05:00
joshuarwood 062de5bb7b clear up debugging statements 2025-05-11 11:59:11 -05:00
joshuarwood 400865ec25 added debugging to pin point seg fault 2025-05-03 20:17:29 -05:00
joshuarwood 0d6c557982 updated variable names to match Ryan Dwyer's work clarifying the zbuffer behavior 2025-05-03 19:57:52 -05:00
joshuarwood 75e34ace8c added Ryan Dwyer's comment describing how artifact handling behaves 2025-05-03 16:06:10 -05:00
joshuarwood a2428aac1e working to document format used for 16 bit depth integers 2025-05-02 11:53:02 -05:00
fgsfds 816d83a0b5 Merge pull request #605 from cylonicboom/pr/rename-unk008
rename `struct menudata.unk008|unk00c` properties
2025-04-28 09:23:05 +02:00
Catherine Reprobate 039eb8b562 rename struct menudata.unk00c-> prevmenudata 2025-04-27 16:01:10 -07:00
Catherine Reprobate 872aa3a4a4 rename struct menudata.unk008 -> prevmenuroot 2025-04-27 15:52:58 -07:00
fgsfds 4b8e1d52b5 port: move menuAlt functions to menu.c and make them global 2025-04-27 15:54:39 +02:00
fgsfds f96a03e60f port: clean up previous PR 2025-04-27 15:34:25 +02:00
fgsfds 9d2db1a346 Merge pull request #596 from rafccq/port-enh-mpsetupfile
Enhanced multiplayer game setup save files
2025-04-27 14:26:39 +02:00
fgsfds fc7141d0f2 Merge pull request #598 from AL2009man/PerfectQuakeDark
Mouse Sensitivity follows id Tech/Source sens scale
2025-04-27 13:46:01 +02:00
fgsfds f414e8a792 Merge pull request #601 from cylonicboom/pr/joyreset-on-controller-change
port: call `joyReset()` when changing controllers
2025-04-27 13:44:36 +02:00
Catherine Reprobate ab73fdcc30 fixup: include header for joyReset 2025-04-13 10:44:26 -07:00
Catherine Reprobate 30071e8f64 port: call joyReset() when changing controllers
This needs to be called for controller reassignments to take effect in
MP modes
2025-04-13 10:39:04 -07:00
AL2009man 9695856be6 updated player.c to account for 0.022f scale
while also changing input.c delta scale to ensure it has a divider
2025-04-11 19:24:25 -04:00
AL2009man 053f7dc8a5 Mouse Sensitivity follows Quake/id Tech mouse sens
this changes mouse sensitiivity scale to mirror id Tech's Mouse Sensitivity Scale. This also makes it easier for Steam Input users (Steam Deck and Steam Controller) to use Gyro To Mouse/Flick Stick's Natural Sensitivity Scale
2025-04-11 00:06:02 -04:00
Raf 52992009db port: no door option in multiplayer, moved the extra settings to a new sibling dialog 2025-04-04 01:49:15 +08:00
Raf 1555a4be84 missing semicolon after mkdir() in non-win platforms 2025-04-02 22:19:24 +08:00
Raf d4856a193b mpsetups: added weapon set num to the save file 2025-04-02 20:13:19 +08:00
Raf cb6dc1feab mpsetups: forgot to pop the dialog after import name conflict, removed debug print 2025-04-02 15:55:31 +08:00
Raf b93015c51c mpsetups: fixed reverse pitch/look ahead being reset when the mpsetups file is created for the first time 2025-04-02 00:33:45 +08:00
Raf 6198fbc479 mpsetups: a bunch of bug fixes
- "load settings" becoming invalid when entering and exiting the challenges screen
- when setting a setup as default, it would change the current setup
- larger window width causing the marquee text to be rendered off-bounds
- reduced the setup name's max length, as it wouldn't fit on the screen in some cases
2025-04-01 17:00:59 +08:00
Raf 0316317aa3 Merge branch 'fgs-port' into port-enh-mpsetupfile 2025-03-31 10:34:42 +08:00
Raf f9cfa0fa43 mpsetups: introduced "menu alt" button/key to toggle presets
Currently the "menu alt" (L/R buttons, or Ctrl/Alt keys) is fixed, but
we may make it bindable later
2025-03-31 10:34:25 +08:00
Raf 7a98095a0b mpsetups: bug fix - when deleting a setup that is behind the default setup in the list 2025-03-31 10:25:24 +08:00
Raf 8f477a36b6 mpsetups: convert existing setups from the eeprom, removed "combat settings" items from file menu
increased block size from 64 to 80 (it was insufficient)
2025-03-31 10:24:26 +08:00
Raf 4d4fa8f681 savebuffer: extended read/write to accept 64 bits, renamed a function, removed an unused function 2025-03-31 10:10:13 +08:00
fgsfds 0ac5fdd5c3 Merge pull request #593 from jonaeru/fix-mp-selectrandomweapon
Fix offset in weapon set by adding IR Scanner and Night Vision and Select Random Weapons feature
2025-03-30 18:44:18 +02:00
Jonaeru 33c5194a1b Fix "Select Dark" in Select Random Weapons feature to not select IR Scanner and Night Vision 2025-03-30 22:48:14 +09:00
Jonaeru edd58c8925 Fix offset in weapon set by adding IR Scanner and Night Vision 2025-03-30 22:31:51 +09:00
fgsfds e32d719c16 port: only enable SDL hints on SDL versions that support them 2025-03-29 12:48:38 +01:00
fgsfds be4d8330bd port: add settings for HIDAPI and raw input 2025-03-29 12:29:14 +01:00
fgsfds 91c207a51b Merge pull request #590 from AL2009man/SDLHint-Fix
SDL_SetHint Controller Update
2025-03-29 12:19:27 +01:00
fgsfds 0d76ad102f Merge pull request #589 from cylonicboom/pr/goggles-in-cs
Add Night Vision Goggles and IR Scanner to Combat Simulator
2025-03-29 12:03:54 +01:00
fgsfds 135c293656 Merge pull request #592 from peerchemist/port
Flatpak x86_64
2025-03-29 12:03:16 +01:00
Raf a1d6916871 mpsetups: manage default setup + save the selected random weapons 2025-03-29 18:34:01 +08:00
peerchemist 9a853077a0 correct Exec name 2025-03-29 11:15:57 +01:00
peerchemist dace9fd634 x86_64 2025-03-29 11:02:55 +01:00
Raf 9e19055348 mpsetups: fixed bugs caused by using a wrong constant + fixed the setup marquee display 2025-03-29 04:17:36 +08:00
Raf dcef8deed8 mpsetups: import/export settings 2025-03-29 02:57:55 +08:00
AL2009man c44704e2af added SDL Hint for Wii Controllers 2025-03-27 01:55:25 -04:00
AL2009man 1a5e42e55f changed note 2025-03-27 01:49:28 -04:00
AL2009man a26260e932 added SDL Hints field
For some reason: this sourceport isn't using SDL Hints. this is very crucial inorder to implement features sets like Gyro Aiming. Thus: most of the important hints will be forcefully enabled while improving Contorller compatibility when using RawInput
2025-03-27 01:47:49 -04:00
Raf 3d75365f2b mpsetups: increased max name length to 18 2025-03-27 01:01:46 +08:00
Raf ad9ed9ff3b mpsetupfile: scrapped groups, manage settings: rename/delete 2025-03-25 01:05:57 +08:00
Catherine Reprobate 4f55a41d99 add NVGs and IRGs to CS
- fixes n64-bug: NVGs and IR goggles should not be dual-wieldable
2025-03-23 12:48:16 -07:00
Catherine Reprobate 355f0ed0ee IR Goggle support for 4player and 1-2p draw fixes
- allocate memory for 4player's IR goggle scanlines
- fixes IR goggle alignment
- fixes IR lens for players 2 and 4
- fixes off-by-one rendering error for top two players (bottom of screen)
- fixes off-by-one rendering error for right-side players (right side of semicircle thing)
- fixes dark area flickering; use resolved shading for props if not wearing goggles
- port: fix IR goggle off-by-one draw issues
2025-03-23 12:47:06 -07:00
Raf f5d851f7c2 mpsetupfile (not 100% functional yet): load/save setup file, save new setups/groups, increased mp options/scenario data width 2025-03-24 03:33:34 +08:00
peerchemist 4019bd59cf Update io.github.fgsfdsfgs.perfect_dark.yaml 2025-03-18 09:13:23 +01:00
peerchemist 6c29e7ecc8 Update io.github.fgsfdsfgs.perfect_dark.sh 2025-03-18 09:00:38 +01:00
peerchemist e65f46d081 Update c-cpp.yml
It hardly makes sense to use 32bit binary for flatpak.
2025-03-18 08:51:17 +01:00
fgsfds 2ff8819265 Merge pull request #550 from ZenithMDC/slider-mouse-upgrades
Ergonomic upgrades for menu sliders while using the mouse
2025-03-16 09:03:23 +01:00
fgsfds 77d1ded519 Merge pull request #584 from SilentException/config-max-warning
Warn when CONFIG_MAX_SETTINGS limit is reached
2025-02-24 22:27:37 +01:00
SilentException 60b8e3b49e Log warning if configuration max settings is exceeded
+ snprintf instead of strncpy (null termination)
2025-02-24 21:35:02 +01:00
fgsfds 8b0b75d4ad port: increase CONFIG_MAX_SETTINGS 2025-02-24 20:26:38 +01:00
Matthew Coppola ea464ca6ac Allow dragging sliders with the mouse
Additional code was introduced to handle edge cases. Sliders are always
dimmed when clicked with the mouse, now. When the mouse button is
release, dimmed mode is turned off. This was done to prevent adjacent
slider items from being accidentally modified by moving the mouse over
them with the left mouse button held down, as well as to allow proper
functioning of deferred sliders with the mouse.
2025-02-24 00:05:51 -05:00
Matthew Coppola a9752198c3 Make mousescroll work effectively for fast sliders 2025-02-23 22:49:51 -05:00
Matthew Coppola fbd9ef002e Treat mousescroll as a mouse movement 2025-02-23 22:49:51 -05:00
Matthew Coppola e4972ddbe3 Allow adjusting sliders with mousescroll 2025-02-23 22:49:24 -05:00
fgsfds 8dbe6f2a63 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port 2025-02-22 13:51:02 +01:00
fgsfds 045c4c371a Revert "ci: temporarily disable flatpak autobuilds"
This reverts commit daade36e19.
2025-02-22 13:50:49 +01:00
fgsfds f4f1470e1e port: use a dynamic string for the vsync options 2025-02-22 13:48:25 +01:00
fgsfds 26251c0865 Update README.md 2025-02-22 13:28:23 +01:00
fgsfds ac4f317879 port: changes to the video settings PR:
- change FPS calculation to use average FPS, use real time instead of render time for interval timing

- remove Maximize Window (you already have a maximize button and it's saved to the INI)

- remove Display FPS Interval from settings (the average user won't care and whoever cares can change it in the INI)

- remove the tickrate override flag and implicit tickrate adjustment in the framerate limit option, instead add one checkbox to uncap tickrate (mostly because I'd like the game to default to the og 60 FPS cap since high FPS is still unstable)

- rearrange some options a bit
2025-02-22 13:22:00 +01:00
fgsfds e3104b7043 Merge pull request #538 from ZenithMDC/revamp-video-options
Allow changing video resolution at runtime + more
2025-02-22 11:26:43 +01:00
fgsfds 176b4282fc Merge pull request #577 from jonaeru/mp-random-weapon-filter
Add "Select Random Weapons" mp menu
2025-02-22 11:16:56 +01:00
fgsfds cd8f06d03a Merge pull request #578 from jonaeru/fix-friendly-fire
Fix to enable Friendly Fire option in Challenge
2025-02-22 11:15:38 +01:00
fgsfds 9cff3591dd port: add an option to make opposite c-buttons cancel each other
for #581
2025-02-22 10:49:48 +01:00
fgsfds daade36e19 ci: temporarily disable flatpak autobuilds
until this fucking action is fixed
2025-02-11 21:06:15 +01:00
fgsfds addc890628 ci: try to fix flatpak action 2025-02-11 20:47:52 +01:00
fgsfds 8a3dd74d5c port: add option to reload with use key in extcontrols 2025-02-11 20:02:35 +01:00
Jonaeru c0aa42759c fix "Select Random Weapons" mp menu, optionindex 2025-02-10 22:39:10 +09:00
Jonaeru b637c6aac6 Fix to enable Friendly Fire option in Challenge 2025-02-10 10:30:59 +09:00
Jonaeru 5cd436e848 Fix check status not being changed by Start button in Select Random Weapon Menu 2025-02-09 14:04:01 +09:00
Jonaeru d5225b7784 Fix Select Random Weapon Menu 2025-02-08 14:01:57 +09:00
Jonaeru 904faa5485 Add MP Select Random Weapon Menu 2025-02-08 14:01:22 +09:00
fgsfds f1084b6d93 ci: use ubuntu-22.04 for i686-linux because ubuntu-24.04 is wack 2025-01-25 12:00:48 +01:00
fgsfds 9a462d3ca8 port: log controller GUID to aid in binding generation 2025-01-25 11:55:50 +01:00
fgsfds 4f7817a0ca port: forgot the constant 2025-01-05 15:45:42 +01:00
fgsfds 5084b4be39 port: simplify the keyboard input a bit and match it to port-net's
backspace key now repeats properly

TYPE WITH KEYBOARD changes into a tooltip when typing

players with controllers are allowed to type, because that seems more convenient

players 2, 3 and 4 are allowed to type too if they hit the button, but only one player can have keyboard focus at a time
2025-01-05 15:27:45 +01:00
fgsfds a05c4290f5 Merge pull request #557 from ZenithMDC/text-input
Allow typing with keyboard in menuitemKeyboard
2025-01-05 13:44:43 +01:00
fgsfds 49cd478622 Merge pull request #564 from ZenithMDC/skip-credits
Allow skipping credits for the port
2024-12-29 15:05:55 +01:00
fgsfds 0443c708dd port: align size of bg light block to 4
this avoids unaligned accesses on ARM
2024-12-29 14:47:42 +01:00
fgsfds 7f105f1dcb port: on ARM, only enable DO_YIELD() if ARMv7 or ARM64 2024-12-29 13:56:44 +01:00
Matthew Coppola 721b9b004e Allow skipping credits for the port 2024-12-21 06:26:36 -05:00
fgsfds 23d5a5771a port: fix mouse X speed using wrong aspect in split screen 2024-12-20 13:38:19 +01:00
fgsfds 0701f43d6b Merge pull request #559 from cylonicboom/editorconfig
add editorconfig
2024-12-20 13:36:05 +01:00
fgsfds d5ae464f6d Merge pull request #561 from cylonicboom/rename-func0f0d5484
func0f0d5484 -> savebufferWriteData
2024-12-20 13:33:37 +01:00
Catherine Reprobate 701c854ced func0f0d5484 -> savebufferWriteData 2024-12-19 12:51:17 -08:00
Catherine Reprobate afd432444b add editorconfig 2024-12-19 10:14:50 -08:00
fgsfds 26b3b91433 Merge pull request #552 from ZenithMDC/resolution-independent-mouse-aim
Make mouse aim speed resolution-independent
2024-12-19 18:26:59 +01:00
Matthew Coppola 8945809c1f Factor in dstscroll to align mouse with chars in 3+ multiplayer 2024-12-17 17:40:10 -05:00
Matthew Coppola da07772b1c Allow typing with keyboard in menuitemKeyboard 2024-12-17 05:47:43 -05:00
fgsfds 1e76f6af69 port: actually parse allocation strings; double gfx buffer size on 64-bit 2024-12-17 10:44:33 +01:00
fgsfds a14e9ed97e port: retry creating SDL window when trying different GL versions 2024-12-11 14:06:44 +01:00
Matthew Coppola 615e9267d8 Make mouse aim speed resolution-independent 2024-12-10 17:36:57 -05:00
fgsfds 4f2b911802 Merge pull request #555 from ZenithMDC/fix-crash-on-copy
Prevent crash when copying player data
2024-12-09 23:34:30 +01:00
Matthew Coppola c43f550a7e Prevent crash when copying player data 2024-12-09 16:20:56 -05:00
fgsfds 2439eb6e8d Merge pull request #551 from ZenithMDC/increase-mouse-speed-precision
Increase precision for mouse speed options
2024-12-08 13:40:23 +01:00
fgsfds 903dd82ebf port: alternate fix for #548 2024-12-08 13:39:21 +01:00
Matthew Coppola cb449bf7ce Increase precision for mouse speed options 2024-12-06 22:40:57 -05:00
Matthew Coppola e2e5bc352d Call text_end (text0f153780) for correctness sake 2024-12-06 17:20:24 -05:00
Matthew Coppola 687b966c5e Allow overriding g_TickRateDiv at runtime 2024-12-06 17:20:24 -05:00
Matthew Coppola 0b8a333e2b Rearrange the menu, clean up, and change some things 2024-12-06 17:20:23 -05:00
Matthew Coppola b34bb01240 Actually sync fullscreen and maximized states with the backend 2024-12-06 17:20:23 -05:00
Matthew Coppola 1e2f6dcb91 Fix mouse input not updating deferred slider while in dimmed mode 2024-12-06 17:20:23 -05:00
Matthew Coppola 210b299bd4 Add Display FPS options to Extended Video Options
Also changed how the window title FPS works, which is now derived from
the difference in time between subsequent video frames.
2024-12-06 17:20:23 -05:00
Matthew Coppola 6de98cfcd4 Update GUI texture filtering setting immediately 2024-12-06 17:20:23 -05:00
Matthew Coppola d43c4c0cba Allow changing MSAA at runtime 2024-12-06 17:20:23 -05:00
Matthew Coppola 1d14877bec Allow changing vsync and framerate limit at runtime
Also implements a new menu item flag: MENUITEMFLAG_SLIDER_DEFERRED,
which only calls the MENUOP_GETSLIDER callback on entering dimmed mode,
storing its value for later ticks, and only calls the MENUOP_SET
callback on leaving dimmed mode. This was necessary to prevent the
framerate limit slider from immediately affecting the framerate, leading
to an annoying slow down as the value was decremented to 0.
2024-12-06 17:20:22 -05:00
Matthew Coppola 5aa1cc6117 Cache ints instead of strings for video modes 2024-12-06 17:20:22 -05:00
Matthew Coppola 1be0e3680b Add video option to center the window 2024-12-06 17:20:22 -05:00
Matthew Coppola 09b0a12b0a Allow changing video resolution at runtime + more
Fullscreen exclusive mode is togglable at runtime, as well, as a
dropdown menu with "borderless" and "exclusive" options. All variables
pertaining to video resolution, exclusive mode, and maximized state are
now synchronized. For instance, Alt+Enter will affect the state of the
fullscreen video option and maximizing the window via the title bar will
update the maximize window option accordingly.
2024-12-06 17:20:15 -05:00
fgsfds 05e462b680 Merge pull request #549 from ZenithMDC/fix-dialog-mousescroll
Forbid mousescroll if dialog is dimmed
2024-12-05 09:40:32 +01:00
Matthew Coppola a2e362caea Forbid mousescroll if dialog is dimmed 2024-12-04 21:23:21 -05:00
fgsfds 49ee5b7efb Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port 2024-12-04 16:28:15 +01:00
fgsfds a1ca69d9ee port: fix issues mentioned in #530 and #532 2024-12-04 16:27:53 +01:00
fgsfds 424d4de9ac Merge pull request #535 from ZenithMDC/fix-duel-momentum
Discard player momentum during autowalk sequences
2024-12-04 11:30:57 +01:00
fgsfds 0e1a7e136a port: fix uninitialized var in aiIfPresetsTargetIsNotMyTarget (fixes #542) 2024-12-04 10:42:48 +01:00
fgsfds 2386494030 port: 64-bit: fix mema end marker (fixes #545) 2024-12-02 13:43:28 +01:00
fgsfds 67675d8980 port: fix #541 2024-11-29 09:46:46 +01:00
fgsfds 9c4aded403 port: osx: restore 10.9 target version 2024-11-24 01:05:18 +01:00
fgsfds 92e1c4aa0b port: osx: temporarily bump target version to 10.13 to test something 2024-11-24 00:31:31 +01:00
fgsfds f53fb8e952 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port 2024-11-24 00:25:42 +01:00
fgsfds 0ad4492ff6 port: default to home directory for saves on OSX as well 2024-11-24 00:25:19 +01:00
fgsfds 33efd36278 readme: add note about save folder 2024-11-23 21:11:38 +01:00
fgsfds 37e69cb83d readme: add osx build instructions 2024-11-23 21:07:21 +01:00
fgsfds 5c5c33c116 readme: small style edit 2024-11-23 20:46:59 +01:00
fgsfds 13a3e0a0ea readme: specify OS versions 2024-11-23 20:46:17 +01:00
fgsfds ccb50c6021 readme: update supported platforms 2024-11-23 20:45:16 +01:00
fgsfds 563e8f9f64 port: osx: set minimum OS version to 11 for arm64 builds 2024-11-23 19:36:38 +01:00
fgsfds df3e0359b9 port: osx: bump OS target to 10.9, since some things in SDL2 won't work with lower 2024-11-23 19:21:25 +01:00
fgsfds 460cc25ef5 port: osx: bump OS target to 10.7, as current SDL2 does not support any lower 2024-11-23 19:13:41 +01:00
fgsfds 596dd7dd40 port: osx: build for MacOS 10.14 2024-11-23 19:05:51 +01:00
fgsfds b2338179d6 port: don't uncrouch in spaces where we don't fit when using extended controls 2024-11-23 12:14:03 +01:00
fgsfds 683d083fab port: don't round crosspos itself, round a copy instead 2024-11-23 09:54:43 +01:00
fgsfds f75a569075 Merge pull request #522 from ZenithMDC/centered-crosshairs
Center-align crosshairs, zoom range, and radar
2024-11-23 09:20:48 +01:00
fgsfds b97eaa9e12 port: simplify night vision check for prop flickering fix 2024-11-22 10:40:20 +01:00
fgsfds 3cadaecf96 Merge pull request #525 from cylonicboom/fix-mp-nvg
Fixes MP NVG flashing bug
2024-11-22 10:28:18 +01:00
fgsfds 4bc1a16d36 build: osx: set RPATH to executable path 2024-11-21 19:31:14 +01:00
fgsfds bc1f1c26db ci: osx: build with CMAKE_MACOSX_RPATH enabled 2024-11-20 13:59:06 +01:00
fgsfds d2d35263a4 port: sanitize controller names
because apparently some of them can't fucking resist putting a funny R or TM in there
2024-11-20 13:00:41 +01:00
fgsfds ba1b6c3232 port: turns out depth_clamp is in core GL since 3.2 2024-11-20 12:51:35 +01:00
fgsfds 3c020cad84 port: detect gl core and GLES3 at runtime; add hacks to make it work properly 2024-11-20 12:07:18 +01:00
fgsfds 140f6f24e8 ci: actually update osx builds to releases 2024-11-19 18:17:16 +01:00
fgsfds c7895d937f tools: fix the python warning about the \h 2024-11-19 18:15:05 +01:00
fgsfds 9f43c906db ci: osx: don't install packages already in runner; enable releases and port-net 2024-11-19 18:08:41 +01:00
fgsfds 31dbb5e7c6 ci: osx: actually install SDL2 2024-11-19 18:02:03 +01:00
fgsfds 7d8e755fc7 ci: forgor to checkout source 2024-11-19 17:58:21 +01:00
fgsfds 103fb0e0e9 ci: what the fuck? 2024-11-19 17:56:48 +01:00
fgsfds b220d73f2c ci: add osx autobuilds 2024-11-19 17:50:10 +01:00
fgsfds efda5a5f44 port: also try GL4.1 core; a little bit of cleanup 2024-11-19 17:37:19 +01:00
fgsfds 41d5630eec Merge pull request #534 from cylonicboom/port-osx
osx build
2024-11-19 17:28:02 +01:00
Catherine Reprobate cea20b6f31 osx build 2024-11-17 10:51:45 -08:00
fgsfds 06dcbcc1b1 port: rename random to rngRandom to avoid conflicts with libc 2024-11-17 11:03:57 +01:00
Matthew Coppola d7a612302e Discard player momentum during autowalk sequences
Prevents potential softlock during The Duel.
2024-11-17 03:56:20 -05:00
fgsfds d747588323 ci: only build the port branch for nswitch 2024-11-16 15:37:43 +01:00
fgsfds 363158a93d port: fix typo 2024-11-16 15:21:49 +01:00
fgsfds 7658a96c1c readme: clarify nswitch installation 2024-11-16 15:20:36 +01:00
fgsfds c332738f7a ci: fix typo 2024-11-16 15:08:51 +01:00
fgsfds 2542b21bfc ci: nswitch: add nswitch builds to releases 2024-11-16 15:07:31 +01:00
fgsfds ef8413ae58 ci: nswitch: put NROs into their subfolders 2024-11-16 15:05:54 +01:00
fgsfds 7969d84257 ci: nswitch: add autobuilds 2024-11-16 15:01:36 +01:00
fgsfds 3d8f63dbb6 port: use a separate fb for fullscreen menu background 2024-11-16 12:31:37 +01:00
fgsfds 08ec8e541b port: remove DUALFLIP from rocket launcher, nbomb, grenade and devastator
makes them look less broken when dual wielded
2024-11-16 12:16:52 +01:00
fgsfds 08afb2d90a readme: fix formatting 2024-11-15 19:13:53 +01:00
fgsfds d7e5ad5bc7 readme: clarify that these are commands 2024-11-15 19:12:09 +01:00
fgsfds 7830ccb88c readme: it's libnx, not switch-libnx 2024-11-15 19:10:59 +01:00
fgsfds 8075307e09 build: nswitch: use actual AND in the author string 2024-11-15 19:10:45 +01:00
Matthew Coppola fb18da239f Move subpixel offset code & fix radar UV map
The subpixel offset code has been moved into the draw_rectangle
function, so it can be applied to more than just the fill_rectangle
function.

The radar texture was displaced along its V component and has
been corrected. It has also been subpixel-adjusted to align with the
player's radar dot.
2024-11-15 03:16:33 -05:00
Matthew Coppola bc82328353 Improve crosshair position accuracy by rounding 2024-11-15 03:16:33 -05:00
Matthew Coppola 938223db28 Center Maian and Skedar tri sights 2024-11-15 03:16:32 -05:00
Matthew Coppola 942c966bf2 Replace centered rects with subpixel offsets 2024-11-15 03:16:32 -05:00
Matthew Coppola e0d59345c7 Center-align crosshairs and zoom range 2024-11-15 03:16:32 -05:00
fgsfds f514e25208 port: fix #219, #506 2024-11-15 01:32:21 +01:00
fgsfds 28fceb67de port: bring back the host_ structs for filemodel.c
this fixes the Pelagic 2 guard thing, but I still need to figure out how to get rid of them without breaking the shit out of everything
2024-11-15 00:42:04 +01:00
fgsfds 130b286d0d port: avoid stack corruption in bmoveProcessInput 2024-11-14 23:00:30 +01:00
fgsfds b88c3a120b port: add scopes to cases in preprocess to prevent older compilers from having a heart attack 2024-11-14 19:20:27 +01:00
fgsfds a6f5077609 port: 64-bit: fix crash site 2024-11-14 18:43:16 +01:00
fgsfds e2b708d442 port: set default opt level to -Og for now (see #529) 2024-11-14 18:38:20 +01:00
fgsfds 2cb29e91c6 port: only run the menu blur filter once 2024-11-13 14:04:36 +01:00
fgsfds 55cc2d8e72 port: nswitch: basic Nintendo Switch port 2024-11-13 12:50:42 +01:00
fgsfds 852349bbe0 mention python in the readme 2024-11-13 09:09:30 +01:00
fgsfds b408d54dfb port: cmake: remove console window on windows 2024-11-13 09:07:17 +01:00
fgsfds 5d9fe034ea tools: fix assetmgr on python <= 3.8 2024-11-13 08:55:04 +01:00
fgsfds 1d7c381ce2 port: cmake: fix stdc++ linking on windows; restore the icon 2024-11-13 08:50:35 +01:00
fgsfds 6c8e5ee4dc update README.md 2024-11-12 23:05:04 +01:00
fgsfds d37d9b7168 ci: move flatpak back to i686 for now 2024-11-12 22:50:36 +01:00
fgsfds fab41b6fcb ci: probably fix i686-linux builds; rename i386 back to i686 2024-11-12 22:34:44 +01:00
fgsfds ee7ce2d988 port: cmake: force disable gnu extensions 2024-11-12 22:19:49 +01:00
fgsfds 1a1accceca ci: update for cmake (i686-linux should be broken) 2024-11-12 22:15:28 +01:00
fgsfds 0bdf79cc51 port: build: move to CMake
god forgive me
2024-11-12 22:08:18 +01:00
fgsfds 91c43385dd update README.md 2024-11-12 14:34:40 +01:00
fgsfds 58e64ebfc9 port: flatpak: launch the x86_64 executable for now 2024-11-12 14:19:12 +01:00
fgsfds 36f9e59304 port: 64-bit: fix jpn builds 2024-11-12 14:05:43 +01:00
fgsfds 420a1b52c1 ci: re-enable CI (2) 2024-11-12 13:58:37 +01:00
fgsfds 345da23ebe ci: re-enable CI 2024-11-12 13:57:11 +01:00
fgsfds 3f887b2ecf port: 64-bit: shrink audio bank allocation after loading 2024-11-12 13:53:52 +01:00
fgsfds d5482f3453 port: build: name executables and build folders according to target platform 2024-11-12 13:53:30 +01:00
fgsfds fdbd1667ad port: build: name executables and build folders according to arch 2024-11-12 13:52:11 +01:00
fgsfds 421ac0af79 port: 64-bit: fix extra fields in modelrodata_type11 2024-11-12 13:18:02 +01:00
fgsfds 163dbf9495 port: 64-bit: get rid of host_ structs; further cleanup 2024-11-12 13:13:42 +01:00
fgsfds 2f221b9a1e port: 64-bit: fix warnings 2024-11-12 10:49:13 +01:00
fgsfds 1448cd597a port: 64-bit: more cleanup
replace the byte swapping macros with the ones from platform.h

rename and move things to match the rest of the code
2024-11-12 10:34:10 +01:00
fgsfds 68e3a79e47 port: 64-bit: replace another long 2024-11-12 10:11:23 +01:00
fgsfds 19ef4738b7 port: 64-bit: fix matrices on x86_64-linux 2024-11-11 20:44:27 +01:00
fgsfds 16f025cbbe port: 64-bit: fix pointer length in mp3.c 2024-11-10 15:25:47 +01:00
fgsfds 25cdfc991b port: 64-bit cleanup: don't use int128 to copy Gfx around 2024-11-10 15:24:26 +01:00
fgsfds 5c2082f58e port: 64-bit cleanup: remove FileType, use LOADTYPE instead 2024-11-10 14:02:04 +01:00
fgsfds 23539a02a5 port: 64-bit cleanup: remove exit()/fprintf() 2024-11-10 10:53:59 +01:00
fgsfds f37abc941e port: 64-bit cleanup: remove dead preprocess code 2024-11-10 10:41:15 +01:00
fgsfds 8468e69b9f Merge pull request #521 from rafccq/port-x64
64-bit port
2024-11-10 10:29:51 +01:00
Catherine Reprobate 8fe95d7d52 Fixes N64 MP NVG flashing bug 2024-11-09 00:10:09 -08:00
Raf 19167b8468 portx64: added back 32-bit targets to CI 2024-10-04 00:13:36 +08:00
Raf d5ee41fe5d Merge branch 'fgs-port' into port-x64
# Conflicts:
#	.github/workflows/c-cpp.yml
2024-10-03 23:58:40 +08:00
fgsfds 2a5c3a351e port: refactor gbcRomCheck a bit 2024-09-02 10:48:54 +02:00
fgsfds 2550b5a668 port: README: add icon credit 2024-09-02 10:27:38 +02:00
fgsfds 24d5679f4a port: add windows program icon 2024-09-02 10:26:38 +02:00
fgsfds a3d2b56dd9 port: flatpak: replace icon with the one suggested by NicNamSam in #238 2024-09-02 10:26:11 +02:00
fgsfds 34d3e082ec Merge pull request #501 from jonaeru/port-mpcopysimulantmenu
Add "Copy Simulant" mp menu
2024-09-02 09:55:04 +02:00
fgsfds a277ca7ee4 Merge pull request #499 from MaikelChan/transfer-pak
Check GameBoy Color ROM to emulate Transfer Pak
2024-09-02 09:54:36 +02:00
fgsfds af8e808e39 Merge pull request #502 from fpiesche/port
Add Flatpak build
2024-09-02 09:51:11 +02:00
Florian Piesche 8f445d344f Add .flatpak-builder to gitignore 2024-08-30 18:46:08 +01:00
Florian Piesche e9b946feb4 Fix executable detection 2024-08-30 18:45:55 +01:00
Florian Piesche 2d51c0a60a Switch to shell script to launch 2024-08-30 18:03:00 +01:00
Jonaeru cf13976db3 Add copy simulant mp menu 2024-08-31 00:46:04 +09:00
Florian Piesche 6344cc8914 Move actual flatpak bundle rather than parent directory 2024-08-30 12:52:14 +01:00
Florian Piesche b2657eb0c2 Use freedesktop 23.08 specifically 2024-08-30 12:29:31 +01:00
Florian Piesche 35d263e15b Use freedesktop container 2024-08-30 12:27:54 +01:00
Florian Piesche c224055ff7 Fix manifest file name. Duh. 2024-08-30 12:25:51 +01:00
Florian Piesche 096a833838 debug 2024-08-30 02:37:56 +01:00
Florian Piesche ee8d7a6e89 Build flatpak bundle manually 2024-08-30 02:30:00 +01:00
Florian Piesche 538385a991 Try workflow again 2024-08-30 02:13:07 +01:00
Florian Piesche b8348a45bc Try and debug workflow setup 2024-08-30 01:58:53 +01:00
Florian Piesche a6b516be15 Fix flatpak build step 2024-08-30 01:47:13 +01:00
Florian Piesche 9ac8af6639 Add comments for missing features in launcher script 2024-08-30 01:42:50 +01:00
Florian Piesche 28bdccd322 Add Flatpak build 2024-08-30 01:29:08 +01:00
MaikelChan 8865130c35 Added some instructions to README. 2024-08-25 21:42:54 +02:00
MaikelChan 153ca3341e Detect Perfect Dark GBC Rom, emulating Transfer Pak functionality. 2024-08-25 21:27:21 +02:00
Raf 8533189561 portx64: include "platform.h" wherever the flag PLATFORM_64bit is used, to avoid possible nasty surprises 2024-08-12 21:20:30 +08:00
Raf eabbdc612c portx64: fixes #5 - crossbow bolt beams not rendering correctly 2024-08-12 21:08:04 +08:00
Raf 5841fb9afa portx64: fixes #4 - jpn/pal versions crashing on startup 2024-08-12 18:56:49 +08:00
Raf 077cc67b79 portx64: fixes #3 - some weapons stuck after switching to 1st function
Tested in 32-bit as well
2024-08-12 16:35:20 +08:00
Raf 589bdf1cd9 portx64: fixes #2 - hoverbike not carrying over to crash-site 2024-08-12 16:33:55 +08:00
Raf 3524ec73b7 portx64: fixes #1 - muzzle flashes broken on some weapons 2024-08-12 16:32:49 +08:00
Raf ab514f39af Update c-cpp.yml
added missing dll: libgcc_s_seh-1.dll
2024-08-10 20:27:29 +08:00
Raf 8be982fdb6 Update c-cpp.yml 2024-08-10 17:31:41 +08:00
Raf ae2543de90 Update c-cpp.yml: fixed arch prefix (x86_64) everywhere 2024-08-10 17:19:56 +08:00
Raf 6a5d249e67 Update c-cpp.yml 2024-08-10 02:21:07 +08:00
Raf 4b44b5b4e3 Update c-cpp.yml 2024-08-10 01:18:49 +08:00
Raf 2fd1c49ef5 Update c-cpp.yml 2024-08-10 01:14:06 +08:00
Raf 22ad5a44db Merge branch 'port-x64' of https://github.com/rafccq/perfect_dark into port-x64 2024-08-09 23:21:57 +08:00
Raf e77b3172ed portx64: a bunch of gcc14 fixes
portx64: fixed pal

Update c-cpp.yml

portx64: fixed linux build

portx64: fixed linux build

ops

portx64: fixed linux build, one more time

portx64: fixed linux build, one more time
2024-08-09 22:37:23 +08:00
Raf a721349cff portx64: fixed linux build, one more time 2024-08-09 21:55:39 +08:00
Raf 40cc42a941 portx64: fixed linux build, one more time 2024-08-09 21:49:10 +08:00
Raf cec92dbcb6 portx64: fixed linux build
ops
2024-08-09 05:07:09 +08:00
Raf 2c4d3e7768 portx64: fixed linux build 2024-08-09 05:02:27 +08:00
Raf e09aebebe7 Update c-cpp.yml 2024-08-09 04:45:12 +08:00
Raf a5d9f02184 portx64: fixed pal 2024-08-09 04:22:57 +08:00
Raf d2dd109a05 portx64: a bunch of gcc14 fixes 2024-08-09 03:57:01 +08:00
Raf 01cbcd99cb portx64: fixed a bunch of instances of Wincompatible-pointer-types + filesetup.c: use ALIGN macro 2024-08-09 02:31:10 +08:00
Raf a9e82658fd portx64: a couple things breaking the build in github - actual fix, plus renamed more functions in filebg.c 2024-08-09 01:21:28 +08:00
Raf 5bee1b0cce portx64: a couple things breaking the build in github 2024-08-09 00:50:21 +08:00
Raf a11abc0511 portx64: forgot to commit the removal of pdextract files 2024-08-09 00:47:55 +08:00
Raf c36b6b286d Update c-cpp.yml 2024-08-09 00:36:42 +08:00
Raf 18fe7fd797 Update c-cpp.yml 2024-08-09 00:23:03 +08:00
Raf d6d4bc2c14 Update c-cpp.yml 2024-08-08 23:55:26 +08:00
Raf c519997b33 portx64: moved pdextract code to src/preprocess, renamed files and function names to follow the port standard 2024-08-08 22:00:08 +08:00
Raf 4d60c93beb portx64: romdata: proper estimated size for setup files, renamed getEstimatedFileSize function 2024-08-08 20:54:59 +08:00
Raf b44dbb16b5 Merge remote-tracking branch 'fgs/port' into port-x64 2024-08-08 17:17:20 +08:00
Raf 8b1e81f32a portx64: pd-extract,preprocess: renamed "_x64" functions, removed now unused preprocess functions, increased snd heap size (x86) 2024-08-08 17:15:33 +08:00
Raf 9e34f80a2c portx64: pd-extract audio: check for repeated pointers before converting 2024-08-08 04:13:08 +08:00
Raf c1c71ea21d portx64: pd-extract models: tons of fixes: data alignments, stargunfire, preprocess textures 2024-08-08 04:01:11 +08:00
fgsfds bdbf0ab789 Merge pull request #484 from MaikelChan/three_point_2
Three point mode and shader fixes
2024-08-06 16:46:35 +02:00
fgsfds ca76416e1c Merge pull request #487 from MaikelChan/mp-viewports
Fixed viewport calculations for models in menus, and other menu fixes
2024-08-06 16:46:19 +02:00
fgsfds b534a42685 Merge pull request #488 from MaikelChan/training-saving
Save data after successfully completing training mission
2024-08-06 16:44:15 +02:00
MaikelChan 6b71e622c7 Save data after successfully completing a mission in device / holo training. 2024-08-06 15:35:26 +02:00
MaikelChan 48c294fc24 Recalculate model position in character profile menu every tick, so it adjusts when resizing the window. 2024-08-06 14:21:36 +02:00
MaikelChan f0fe7f41f1 Forgot to remove something from previous commit. 2024-08-06 14:13:17 +02:00
MaikelChan 2844930a21 Recalculate model position in device training menu every tick, so it adjusts when resizing the window. 2024-08-06 14:10:43 +02:00
MaikelChan d36c55d048 - Fixed model position in device training menu. 2024-08-06 14:04:02 +02:00
MaikelChan f855dc32f1 Apply a small offset to the arrows in character selection so they don't get cut off by the scissor. 2024-08-06 13:17:43 +02:00
MaikelChan 08e2b49e88 Fixed viewport calculations of the character selection UIs from multiplayer. 2024-08-06 12:43:45 +02:00
MaikelChan 9cd978a7a9 Removed more APPLE checks. 2024-08-05 19:11:33 +02:00
MaikelChan a60880ef80 Three point and shader improvements
- Fixed blurry menu background being unfiltered when three point is enabled.
- Some shader code refactor to reduce the amount of __APPLE__ defines: use the SAMPLE_TEX macro to sample textures.
- Detach shaders before deleting them.
2024-08-05 17:09:00 +02:00
MaikelChan a4b5b110ec Don't perform a filter mode change if the new mode is the same as the previous one. 2024-08-05 16:33:55 +02:00
fgsfds 897020b3fd port: clean up depth_zfar remnants 2024-08-05 11:42:21 +02:00
fgsfds e85fdb3b9b port: exclude threepoint-related shader code when it's not enabled 2024-08-05 11:41:45 +02:00
fgsfds e3e72617a1 Merge pull request #483 from MaikelChan/three_point
Improvements to three point filtering
2024-08-05 10:38:15 +02:00
fgsfds bc365650ce Merge pull request #482 from MaikelChan/depth_clear
Implemented depth clear, and disabled some depth range functionality
2024-08-05 10:33:15 +02:00
MaikelChan 6fa78556f4 Implemented texture filtering setting with a dropdown showing all three options, and three point can be changed in real time. 2024-08-05 04:15:30 +02:00
MaikelChan 5fdeff6a82 Disabled depth range functionality. Doesn't seem needed anymore. 2024-08-04 22:10:46 +02:00
Raf 3573906eef portx64: pd-extract setup: fixed doorscale obj 2024-08-04 22:30:49 +08:00
Raf e36df05a4f portx64: pd-extract: renamed fin_marker 2024-08-04 22:29:13 +08:00
MaikelChan 673ba52cbd Not necessary to change depth range of bullet casings anymore. 2024-08-04 13:21:40 +02:00
MaikelChan 0ea8872471 Perform a depth only clear right before rendering the gun. 2024-08-04 13:14:03 +02:00
Raf 40273bdba1 portx64: romdata: check for PLATFORM_64BIT inside romdataGetEstimatedFileSize() 2024-08-04 18:37:01 +08:00
Raf e8006f3446 portx64: pd-extract util gbi: fixed gdl conversion so it works on x86
it works but is still a bit messy, may rewrite it later
2024-08-04 18:34:04 +08:00
Raf 373f08ca3e portx64: pd-extract setups: a few bug fixes and changed how lists are copied
- moved ptrmarkers out of ext_file_bg to common
- function to get ailist length
2024-08-04 18:26:09 +08:00
Raf 844d6c7ec8 portx64: pd-extract setups: a few bug fixes and changed how lists are copied 2024-08-04 18:19:41 +08:00
fgsfds b43c2ec617 Merge pull request #448 from blaiz/cloaking-respawn
Give Cloaking Device at respawn if cheat is active
2024-08-04 10:56:30 +02:00
fgsfds a8c68aed97 Merge pull request #476 from jonaeru/port-mpnoradar-player
Add "No Player on Radar" mp option
2024-08-04 10:56:02 +02:00
fgsfds 4c09de6de0 Merge pull request #480 from MaikelChan/depth_compare_fixes
Depth compare improvements based on GlideN64
2024-08-04 10:55:20 +02:00
MaikelChan 29d6392514 Forgot some extra checks. 2024-08-04 06:11:50 +02:00
MaikelChan b9f6961931 Depth compare improvements based on GlideN64. 2024-08-04 05:28:10 +02:00
Raf 949faf09d9 portx64: undo disable sound 2024-08-02 17:49:44 +08:00
Raf 5beef0916b portx64: warn if memory pool is full 2024-08-02 17:47:35 +08:00
Raf 89397bd566 portx64: makefile: added PLATFORM_64BIT define 2024-08-02 17:46:50 +08:00
Raf 288a007202 portx64: bug fix: mp3 code accessing out of bounds memory: increased alloc/audio heap size 2024-08-02 17:43:05 +08:00
Raf 50b912db98 portx64: bug fix: weatherResetRooms accessing invalid memory when returning to STAGE_TITLE 2024-08-02 17:37:33 +08:00
Raf 71dc521baa portx64: menu bug fix: code intermingling handlerdata_dropdown and handlerdata_list values 2024-08-02 17:36:49 +08:00
Raf 06a45738cc portx64: preprocess header left behind 2024-08-02 17:33:53 +08:00
Raf 5795634b9c portx64: files/romdata: getEstimatedFileSize() so we can preallocate enough memory for files in x64 2024-08-02 17:32:33 +08:00
Raf cec197e841 Merge branch 'port-x64' of https://github.com/rafccq/perfect_dark into port-x64 2024-08-02 17:26:20 +08:00
Raf 58c31075b0 portx64: pd-extract: replaced stdint types with ultratypes 2024-08-02 17:26:00 +08:00
Raf 167a4a5d81 portx64: pd-extract: replaced stdint types with ultratypes 2024-08-02 16:48:35 +08:00
Raf 06c01208d3 portx64: integrate pd-extract functions with romdata 2024-08-02 16:43:21 +08:00
Raf 86649345cd portx64: undo this nonsense 2024-07-30 17:56:40 +08:00
Raf 2e2dbfb578 portx64: pd-extract: setups
jesus didn't help in this off-by-one error hell
2024-07-30 17:56:15 +08:00
Raf 10a3992a62 portx64: pd-extract: bg (extract roomgfxdata) and some model fixes 2024-07-30 17:34:06 +08:00
Raf ef4b60d384 portx64: audio system changes 2024-07-30 16:57:17 +08:00
Raf 32faea2b95 portx64: gbi changes 2024-07-30 16:47:12 +08:00
Raf 8a94af6a1c portx64: and more s32 -> uintptr_t 2024-07-30 16:46:02 +08:00
Raf 315a5642da portx64: pd extract - font/anim/audio segments and tiles/pads files fixes 2024-07-23 01:58:47 +08:00
Raf 00c990eded portx64: lots of adjustments in memory allocations/data sizes/offsets etc 2024-07-23 01:52:35 +08:00
Jonaeru b6b7133e76 port: add no radar on player mp option 2024-07-22 22:44:00 +09:00
Raf b0e6e8f24f portx64: lots more u32 -> uintptr_t 2024-07-11 19:43:01 +08:00
Raf 4dbbcbeb58 portx64: changed pointers stored in u32 to uintptr_t
- adjusted hardcoded mask/hardcoded offsets used in memory operations (modelasm_c.c)
- makefile: enabled x64 support and added lib dependency
- title: increase alloc size
- tex: adjustment to calculations involving GDL sizes
2024-07-06 01:16:39 +08:00
Raf 8c8109e8cd Merge branch 'fgs-port' into port-x64 2024-06-02 20:48:29 +08:00
fgsfds b523b1e076 port: fix mouse controls in combat sim keyboard 2024-05-31 11:23:48 +02:00
fgsfds 07e6fdc1e0 port: add mouse lock mode option 2024-05-31 10:54:33 +02:00
Raf 3242105ef8 portx64: added pd-extract source 2024-05-26 16:10:24 +08:00
Raf 7c6508af28 Merge branch 'fgs-port' into port-x64
# Conflicts:
#	Makefile.port
2024-05-26 15:57:03 +08:00
Jonathan G. d7c4843eea Make "All Guns in Solo" cheat work in multiplayer 2024-05-24 17:27:52 -07:00
Jonathan G. 55ab679a81 port: give Cloaking Device at respawn if cheat is active 2024-05-19 23:51:40 -07:00
fgsfds de3b8ff548 port: revert multithreaded audio experiments
until I can figure out how to fix all the funny concurrency issues that cropped up
2024-05-19 19:44:34 +02:00
fgsfds dce96a4a3d port: add separate extra buttons for accept/cancel 2024-05-18 19:32:34 +02:00
fgsfds 08b4d780b7 port: temporary fix for the UI back button 2024-05-18 19:18:27 +02:00
fgsfds bc5911bfba port: formatting 2024-05-18 19:05:47 +02:00
fgsfds ada20c526a port: clean up previous commit 2024-05-18 19:00:40 +02:00
fgsfds 4c552a42f2 port: experimental multithreaded audio 2024-05-18 18:53:12 +02:00
fgsfds e8e513fecb port: possible fix for #401 2024-05-15 14:11:24 +02:00
fgsfds 4601a9c318 port: only respect friendly fire setting in team games 2024-05-15 13:39:12 +02:00
fgsfds 5c7d4ecf52 port: give correct ammo to bots when spawning armed; give at least one round when spawning armed 2024-05-15 12:29:39 +02:00
fgsfds 9edfd667b7 port: give start with weapon a better short name 2024-05-15 12:13:35 +02:00
fgsfds f3757e75e9 port: don't crash when spawn with weapon is on and that weapon is a shield 2024-05-15 12:10:17 +02:00
fgsfds a6e7d503e6 port: add mouse controls to sliders 2024-05-14 23:16:36 +02:00
fgsfds da8b9be09d port: completely disable back on WPNBACK if using mouse navigation 2024-05-14 22:59:20 +02:00
fgsfds 9530924c21 port: add mouse navigation toggle to options 2024-05-14 22:56:47 +02:00
fgsfds 2ba192d411 port: make menu mouse flag global 2024-05-14 22:53:02 +02:00
fgsfds bf8192ee84 Update README.md 2024-05-14 22:21:14 +02:00
fgsfds 45ec35172d ci: fix executable names on linux 2024-05-14 22:04:27 +02:00
fgsfds 926e4dce28 ci: autobuild pal and jpn and include them in release 2024-05-14 21:59:44 +02:00
fgsfds 548e2c1f0b port: only navigate with mouse if it's enabled in the dialog 2024-05-14 21:06:16 +02:00
fgsfds 85872d7e71 port: add mouse controls to virtual keyboard 2024-05-14 20:58:51 +02:00
fgsfds a83e0aa407 port: add mouse control to menus; mouse now unlocks when you pause 2024-05-14 20:28:59 +02:00
fgsfds 865ca682dc Update README.md 2024-05-14 11:58:04 +02:00
fgsfds dc9d0f3c9c ci: give write permission to release job 2024-05-14 11:50:07 +02:00
fgsfds 12d06001e7 Merge pull request #320 from djdv/port
Add CI action to publish development builds to GitHub releases
2024-05-14 11:42:17 +02:00
Raf 63c456a233 port-64: first changes, able to build 2024-01-27 18:25:55 +08:00
Dominic Della Valle 2ef2427419 ci: publish builds to a release tag ci-dev-build
This reserves the tag `ci-dev-build` for use by the CI.
2023-12-23 12:33:17 -05:00
Dominic Della Valle 5fcf1083d2 ci: update GitHub actions uses deps to latest 2023-12-23 12:33:17 -05:00
249 changed files with 14470 additions and 18423 deletions

No files matched your search

+32
View File
@@ -0,0 +1,32 @@
# EditorConfig is awesome: https://EditorConfig.org
# Top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
# Matches all C source files
[*.c]
indent_style = tab
tab_width = 2
charset = utf-8
trim_trailing_whitespace = true
# Matches all header files
[*.h]
indent_style = tab
tab_width = 2
charset = utf-8
trim_trailing_whitespace = true
# Matches Makefiles
[Makefile]
indent_style = tab
# Matches Markdown files
[*.md]
max_line_length = off
trim_trailing_whitespace = false
+269 -14
View File
@@ -2,7 +2,7 @@ name: C/C++ CI
on: on:
push: push:
branches: [ "port", "port-net" ] branches: [ "port" ]
pull_request: pull_request:
branches: [ "port" ] branches: [ "port" ]
workflow_dispatch: workflow_dispatch:
@@ -25,44 +25,299 @@ jobs:
mingw-w64-i686-toolchain mingw-w64-i686-toolchain
mingw-w64-i686-SDL2 mingw-w64-i686-SDL2
mingw-w64-i686-zlib mingw-w64-i686-zlib
mingw-w64-i686-cmake
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Build pd.exe - name: Build pd.i686.exe
run: make -f Makefile.port -j run: cmake -G"Unix Makefiles" -Bbuild . && cmake --build build -j
- name: Build pd.pal.i686.exe
run: cmake -G"Unix Makefiles" -Bbuild_pal -DROMID=pal-final . && cmake --build build_pal -j
- name: Build pd.jpn.i686.exe
run: cmake -G"Unix Makefiles" -Bbuild_jpn -DROMID=jpn-final . && cmake --build build_jpn -j
- name: Prepare artifact for packaging - name: Prepare artifact for packaging
run: | run: |
mkdir -p bin/data mkdir -p bin/data
cp build/ntsc-final-port/pd.exe bin/ cp build/pd.i686.exe bin/
cp build_pal/pd.pal.i686.exe bin/
cp build_jpn/pd.jpn.i686.exe bin/
cp /mingw32/bin/{SDL2.dll,zlib1.dll,libgcc_s_dw2-1.dll,libwinpthread-1.dll} bin/ cp /mingw32/bin/{SDL2.dll,zlib1.dll,libgcc_s_dw2-1.dll,libwinpthread-1.dll} bin/
touch bin/data/put_your_rom_here.txt touch bin/data/put_your_rom_here.txt
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: pd-i686-windows name: pd-i686-windows
path: bin/ path: bin/
retention-days: 0 retention-days: 0
build-i686-linux: build-i686-linux:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
steps: steps:
- name: Install dependencies - name: Install dependencies
run: | run: |
sudo dpkg --add-architecture i386 sudo dpkg --add-architecture i386
sudo apt-get update sudo apt-get update
sudo apt-get install git gcc g++ gcc-multilib g++-multilib make libsdl2-dev zlib1g-dev libsdl2-dev:i386 zlib1g-dev:i386 sudo apt-get install git gcc g++ gcc-multilib g++-multilib make libsdl2-dev zlib1g-dev libsdl2-dev:i386 zlib1g-dev:i386 cmake
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Build pd.exe - name: Build pd.i686
run: make -f Makefile.port TARGET_PLATFORM=i686-linux -j2 run: cmake -G"Unix Makefiles" -Bbuild -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32 . && cmake --build build -j
- name: Build pd.pal.i686
run: cmake -G"Unix Makefiles" -Bbuild_pal -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32 -DROMID=pal-final . && cmake --build build_pal -j
- name: Build pd.jpn.i686
run: cmake -G"Unix Makefiles" -Bbuild_jpn -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32 -DROMID=jpn-final . && cmake --build build_jpn -j
- name: Prepare artifact for packaging - name: Prepare artifact for packaging
run: | run: |
mkdir -p bin/data mkdir -p bin/data
cp build/ntsc-final-port/pd.exe bin/pd cp build/pd.i686 bin/
cp build_pal/pd.pal.i686 bin/
cp build_jpn/pd.jpn.i686 bin/
touch bin/data/put_your_rom_here.txt touch bin/data/put_your_rom_here.txt
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: pd-i686-linux name: pd-i686-linux
path: bin/ path: bin/
retention-days: 0 retention-days: 0
build-x86_64-windows:
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- name: Install MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: MINGW64
update: true
install: >-
git
make
mingw-w64-x86_64-toolchain
mingw-w64-x86_64-python
mingw-w64-x86_64-SDL2
mingw-w64-x86_64-zlib
mingw-w64-x86_64-cmake
- name: Checkout repository
uses: actions/checkout@v4
- name: Build pd.x86_64.exe
run: cmake -G"Unix Makefiles" -Bbuild . && cmake --build build -j
- name: Build pd.pal.x86_64.exe
run: cmake -G"Unix Makefiles" -Bbuild_pal -DROMID=pal-final . && cmake --build build_pal -j
- name: Build pd.jpn.x86_64.exe
run: cmake -G"Unix Makefiles" -Bbuild_jpn -DROMID=jpn-final . && cmake --build build_jpn -j
- name: Prepare artifact for packaging
run: |
mkdir -p bin/data
cp build/pd.x86_64.exe bin/
cp build_pal/pd.pal.x86_64.exe bin/
cp build_jpn/pd.jpn.x86_64.exe bin/
cp /mingw64/bin/{SDL2.dll,zlib1.dll,libwinpthread-1.dll,libgcc_s_seh-1.dll} bin/
touch bin/data/put_your_rom_here.txt
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: pd-x86_64-windows
path: bin/
retention-days: 0
build-x86_64-linux:
runs-on: ubuntu-latest
steps:
- name: Install dependencies
run: |
sudo dpkg --add-architecture amd64
sudo apt-get update
sudo apt-get install git gcc g++ gcc-multilib g++-multilib make libsdl2-dev zlib1g-dev libsdl2-2.0-0 cmake
- name: Checkout repository
uses: actions/checkout@v4
- name: Build pd.x86_64
run: cmake -G"Unix Makefiles" -Bbuild . && cmake --build build -j
- name: Build pd.pal.x86_64
run: cmake -G"Unix Makefiles" -Bbuild_pal -DROMID=pal-final . && cmake --build build_pal -j
- name: Build pd.jpn.x86_64
run: cmake -G"Unix Makefiles" -Bbuild_jpn -DROMID=jpn-final . && cmake --build build_jpn -j
- name: Prepare artifact for packaging
run: |
mkdir -p bin/data
cp build/pd.x86_64 bin/
cp build_pal/pd.pal.x86_64 bin/
cp build_jpn/pd.jpn.x86_64 bin/
touch bin/data/put_your_rom_here.txt
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: pd-x86_64-linux
path: bin/
retention-days: 0
build-x86_64-osx:
runs-on: macos-14
steps:
- name: Install dependencies
run: |
brew install zlib
wget http://libsdl.org/release/SDL2-2.30.9.dmg -O SDL2.dmg
hdiutil mount SDL2.dmg
sudo cp -vr /Volumes/SDL2/SDL2.framework /Library/Frameworks
- name: Checkout repository
uses: actions/checkout@v4
- name: Build pd.x86_64
run: |
cmake -G"Unix Makefiles" -Bbuild -DCMAKE_OSX_ARCHITECTURES=x86_64 .
cmake --build build --target pd -j4 --clean-first
- name: Build pd.pal.x86_64
run: |
cmake -G"Unix Makefiles" -Bbuild_pal -DCMAKE_OSX_ARCHITECTURES=x86_64 -DROMID=pal-final .
cmake --build build_pal --target pd -j4 --clean-first
- name: Build pd.jpn.x86_64
run: |
cmake -G"Unix Makefiles" -Bbuild_jpn -DCMAKE_OSX_ARCHITECTURES=x86_64 -DROMID=jpn-final .
cmake --build build_jpn --target pd -j4 --clean-first
- name: Prepare artifact for packaging
run: |
mkdir -p bin/data
cp build/pd.x86_64 bin/
cp build_pal/pd.pal.x86_64 bin/
cp build_jpn/pd.jpn.x86_64 bin/
cp -vr /Library/Frameworks/SDL2.framework bin/
touch bin/data/put_your_rom_here.txt
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: pd-x86_64-osx
path: bin/
retention-days: 0
build-arm64-osx:
runs-on: macos-14
steps:
- name: Install dependencies
run: |
brew install zlib
wget http://libsdl.org/release/SDL2-2.30.9.dmg -O SDL2.dmg
hdiutil mount SDL2.dmg
sudo cp -vr /Volumes/SDL2/SDL2.framework /Library/Frameworks
- name: Checkout repository
uses: actions/checkout@v4
- name: Build pd.arm64
run: |
cmake -G"Unix Makefiles" -Bbuild -DCMAKE_OSX_ARCHITECTURES=arm64 .
cmake --build build --target pd -j4 --clean-first
- name: Build pd.pal.arm64
run: |
cmake -G"Unix Makefiles" -Bbuild_pal -DCMAKE_OSX_ARCHITECTURES=arm64 -DROMID=pal-final .
cmake --build build_pal --target pd -j4 --clean-first
- name: Build pd.jpn.arm64
run: |
cmake -G"Unix Makefiles" -Bbuild_jpn -DCMAKE_OSX_ARCHITECTURES=arm64 -DROMID=jpn-final .
cmake --build build_jpn --target pd -j4 --clean-first
- name: Prepare artifact for packaging
run: |
mkdir -p bin/data
cp build/pd.arm64 bin/
cp build_pal/pd.pal.arm64 bin/
cp build_jpn/pd.jpn.arm64 bin/
cp -vr /Library/Frameworks/SDL2.framework bin/
touch bin/data/put_your_rom_here.txt
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: pd-arm64-osx
path: bin/
retention-days: 0
build-arm64-nswitch:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/port'
steps:
- name: Install host dependencies
run: |
sudo apt-get update
sudo apt-get install git make cmake curl
- name: Install devkitA64 docker image
run: sudo docker pull devkitpro/devkita64:latest
- name: Checkout repository
uses: actions/checkout@v4
- name: Build pd.arm64.nro
run: sudo docker run --name pd --rm -v `pwd`:`pwd` -w `pwd` devkitpro/devkita64:latest bash ./tools/buildscripts/nswitch_docker.sh build
- name: Build pd.pal.arm64.nro
run: sudo docker run --name pd --rm -v `pwd`:`pwd` -w `pwd` devkitpro/devkita64:latest bash ./tools/buildscripts/nswitch_docker.sh build_pal -DROMID=pal-final
- name: Build pd.jpn.arm64.nro
run: sudo docker run --name pd --rm -v `pwd`:`pwd` -w `pwd` devkitpro/devkita64:latest bash ./tools/buildscripts/nswitch_docker.sh build_jpn -DROMID=jpn-final
- name: Prepare artifact for packaging
run: |
mkdir -p bin/perfectdark/data
mkdir -p bin/perfectdark_pal/data
mkdir -p bin/perfectdark_jpn/data
cp build/pd.arm64.nro bin/perfectdark/
cp build_pal/pd.pal.arm64.nro bin/perfectdark_pal/
cp build_jpn/pd.jpn.arm64.nro bin/perfectdark_jpn/
touch bin/perfectdark/data/put_your_rom_here.txt
touch bin/perfectdark_pal/data/put_your_rom_here.txt
touch bin/perfectdark_jpn/data/put_your_rom_here.txt
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: pd-arm64-nswitch
path: bin/
retention-days: 0
build-flatpak-bundle:
name: "Build flatpak bundle"
runs-on: ubuntu-latest
needs: [build-x86_64-linux]
container:
image: ghcr.io/flathub-infra/flatpak-github-actions:freedesktop-25.08
options: --privileged
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: pd-x86_64-linux
path: dist/linux/bin/
- uses: flatpak/flatpak-github-actions/flatpak-builder@v6
with:
bundle: io.github.perfect_dark_pc_port.perfect_dark.flatpak
manifest-path: dist/linux/io.github.perfect_dark_pc_port.perfect_dark.yaml
cache-key: flatpak-builder-${{ github.sha }}
upload-artifact: false
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: io.github.perfect_dark_pc_port.perfect_dark.flatpak
path: io.github.perfect_dark_pc_port.perfect_dark.flatpak
retention-days: 0
publish-latest-build:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/port'
needs: [build-i686-windows, build-i686-linux, build-x86_64-windows, build-x86_64-linux, build-arm64-nswitch, build-x86_64-osx, build-arm64-osx, build-flatpak-bundle]
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
path: ci-artifacts
- name: Publish latest dev-build
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
mkdir ci-release
pushd ci-artifacts
tar czf ../ci-release/pd-i686-linux.tar.gz pd-i686-linux
tar czf ../ci-release/pd-x86_64-linux.tar.gz pd-x86_64-linux
tar cJf ../ci-release/pd-x86_64-osx.tar.xz pd-x86_64-osx
tar cJf ../ci-release/pd-arm64-osx.tar.xz pd-arm64-osx
zip -r ../ci-release/pd-i686-windows.zip pd-i686-windows
zip -r ../ci-release/pd-x86_64-windows.zip pd-x86_64-windows
zip -r ../ci-release/pd-arm64-nswitch.zip pd-arm64-nswitch
mv io.github.perfect_dark_pc_port.perfect_dark.flatpak/io.github.perfect_dark_pc_port.perfect_dark.flatpak ../ci-release/
popd
git tag --force ci-dev-build port
git push --force origin ci-dev-build
gh release upload --clobber ci-dev-build ci-release/*
+4
View File
@@ -4,6 +4,7 @@
*.exe *.exe
pd.*.z64 pd.*.z64
build build
.flatpak-builder
extracted extracted
src/assets/*/*.bin src/assets/*/*.bin
src/assets/*/*.ctl src/assets/*/*.ctl
@@ -22,3 +23,6 @@ src/assets/*/textures/*.bin
src/generated src/generated
tools/mkrom/mkrom tools/mkrom/mkrom
/.vs /.vs
CppProperties.json
.idea
cmake-build-debug
+360
View File
@@ -0,0 +1,360 @@
cmake_minimum_required(VERSION 3.16)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
if(APPLE)
if(CMAKE_OSX_ARCHITECTURES MATCHES "arm64")
# ARM Macs start at OS 11.
set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0" CACHE STRING "Minimum OS X deployment version")
else()
# SDL2 requires at least this version for everything to work properly.
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "Minimum OS X deployment version")
endif()
endif()
project(pd C CXX)
include(TargetArch)
include(FindPkgConfig)
include(AssetUtils)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# On first build set the build type to RelWithDebInfo if it's not already set
if (NOT EXISTS ${CMAKE_BINARY_DIR}/CMakeCache.txt)
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "" FORCE)
endif()
endif()
# Options
set(ROMID "ntsc-final" CACHE STRING "Which ROM to build an executable for: ntsc-final, pal-final or jpn-final")
option(FORCE_CROSSCOMPILE "Force cross compiling" NO)
# Determine target arch
target_architecture(TARGET_ARCH)
if(TARGET_ARCH STREQUAL "i386")
# for historical reasons
set(TARGET_ARCH "i686")
endif()
# TODO
set(TARGET_IS_BIG_ENDIAN FALSE)
if((TARGET_ARCH MATCHES "unknown") OR (TARGET_ARCH STREQUAL ""))
message(FATAL_ERROR "Unknown target arch")
elseif(TARGET_ARCH MATCHES "64")
set(TARGET_IS_64BIT TRUE)
else()
set(TARGET_IS_64BIT FALSE)
endif()
message(STATUS "Target arch: ${TARGET_ARCH}")
# Determine target OS and platform identifier ($arch-$os)
if(WIN32)
# Windows
set(TARGET_OS "windows")
elseif(APPLE)
# OSX
set(TARGET_OS "osx")
elseif(NINTENDO_SWITCH)
# Switch
set(TARGET_OS "nswitch")
elseif(UNIX)
# Generic *nix; assume Linux
set(TARGET_OS "linux")
else()
# ???
message(FATAL_ERROR "Unknown target OS or compiler")
endif()
set(TARGET_PLATFORM "${TARGET_ARCH}-${TARGET_OS}")
message(STATUS "Target platform: ${TARGET_PLATFORM}")
# Calculate version info and binary name
set(VERSION_IS_PAL 0)
if(ROMID STREQUAL "ntsc-final")
set(VERSION 2)
set(BIN_REGION "")
elseif(ROMID STREQUAL "pal-final")
set(VERSION 4)
set(BIN_REGION ".pal")
set(VERSION_IS_PAL 1)
elseif(ROMID STREQUAL "jpn-final")
set(VERSION 5)
set(BIN_REGION ".jpn")
else()
message(FATAL_ERROR "Unknown ROM ID: ${ROMID}")
endif()
# git commit hash
execute_process(
COMMAND git rev-parse --short HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE VERSION_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# git branch name
execute_process(
COMMAND git rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE VERSION_BRANCH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
set(VERSION_TARGET "${TARGET_PLATFORM}")
set(VERSION_ARCH "${TARGET_ARCH}")
set(VERSION_ROMID "${ROMID}")
set(VERSION_BUILD "${CMAKE_BUILD_TYPE}")
if((VERSION_BRANCH STREQUAL "") OR (VERSION_BRANCH STREQUAL "HEAD"))
set(VERSION_BRANCH "port-custom")
endif()
message(STATUS "Version: ${VERSION_ROMID}, hash ${VERSION_HASH}, branch ${VERSION_BRANCH}")
configure_file("${CMAKE_SOURCE_DIR}/port/include/versioninfo.h.in" "${CMAKE_BINARY_DIR}/port/include/versioninfo.h" @ONLY)
set(ASSET_DIR "src/assets/${ROMID}")
set(GENERATED_DIR "src/generated/${ROMID}")
set(ENV{ROMID} ${ROMID})
# Build folder postfix
set(BUILD_ID "${VERSION_ROMID}-${VERSION_TARGET}")
# Compiler defs
add_definitions(
-DMATCHING=0
-DPIRACYCHECKS=0
-DROM_SIZE=32
-DAVOID_UB=1
-D_LANGUAGE_C=1
-DPAL=${VERSION_IS_PAL}
-DVERSION=${VERSION}
)
if(TARGET_IS_64BIT)
add_definitions(-DPLATFORM_64BIT=1)
endif()
# Compiler flags
# Include directories
include_directories("${CMAKE_SOURCE_DIR}/include")
include_directories("${CMAKE_SOURCE_DIR}/include/PR")
include_directories("${CMAKE_SOURCE_DIR}/src/include")
include_directories("${CMAKE_BINARY_DIR}/src/generated/${ROMID}")
include_directories("${CMAKE_SOURCE_DIR}/src/lib/ultra/audio")
include_directories("${CMAKE_SOURCE_DIR}/port/include")
include_directories("${CMAKE_BINARY_DIR}/port/include")
# Set Release optimization to -Og until I fix the -O2 issues
if(NOT (CMAKE_BUILD_TYPE STREQUAL "Debug"))
add_compile_options(-Og)
endif()
# Common CFLAGS
add_compile_options(
-fno-inline-functions
-fno-strict-aliasing
-funsigned-char
-fwrapv
-include "versioninfo.h"
)
# Common warning flags
add_compile_options(
-Wall
-Wno-address
-Wno-int-in-bool-context
-Wno-misleading-indentation
-Wno-missing-braces
-Wno-multichar
-Wno-tautological-compare
-Wno-unused-but-set-variable
-Wno-unused-value
-Wno-unused-variable
-fdiagnostics-color=always
)
# C specific flags
add_compile_options($<$<COMPILE_LANGUAGE:C>:-Wno-pointer-sign>)
# C++ specific flags
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-Wno-unused-function>)
# Platform-specific flags
if (APPLE)
# Make it look for libs in the executable folder manually since CMake's rpath system is wack
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rpath @executable_path")
else()
# This warning is not recognized by XCode/Clang for some reason.
add_compile_options(-Wno-format-truncation)
endif()
# Dependencies
set(LIBS )
# SDL2
find_package(SDL2 REQUIRED)
if(NINTENDO_SWITCH)
if(NOT SDL2_LIBRARY OR NOT SDL2_INCLUDE_DIR)
# sometimes FindSDL2 just wants us to suffer and does not set these
set(SDL2_LIBRARY "SDL2")
set(SDL2_INCLUDE_DIR "${DEVKITPRO}/portlibs/switch/include/SDL2")
endif()
endif()
include_directories(SYSTEM "${SDL2_INCLUDE_DIR}")
list(APPEND LIBS "${SDL2_LIBRARY}")
# ZLib
find_package(ZLIB REQUIRED)
if(ZLIB_INCLUDE_DIR)
include_directories(SYSTEM "${ZLIB_INCLUDE_DIR}")
endif()
list(APPEND LIBS "${ZLIB_LIBRARY}")
# GL
if(NOT GL_LIBRARY)
if(WIN32)
set(GL_LIBRARY opengl32)
elseif(NINTENDO_SWITCH)
set(GL_LIBRARY EGL glapi drm_nouveau)
elseif(APPLE)
set(GL_LIBRARY "-framework OpenGL")
else()
set(GL_LIBRARY GL)
endif()
endif()
list(APPEND LIBS "${GL_LIBRARY}")
# Platform-specific extra libs
if(NOT EXTRA_LIBRARIES)
if(WIN32)
set(EXTRA_LIBRARIES dbghelp -static-libstdc++)
elseif(NINTENDO_SWITCH)
set(EXTRA_LIBRARIES stdc++ pthread)
else()
set(EXTRA_LIBRARIES stdc++ m dl)
endif()
endif()
list(APPEND LIBS "${EXTRA_LIBRARIES}")
# Sources
file(GLOB_RECURSE SRC_PORT "${CMAKE_SOURCE_DIR}/port/*.c")
file(GLOB_RECURSE SRC_PORT_CXX "${CMAKE_SOURCE_DIR}/port/*.cpp")
file(GLOB_RECURSE SRC_GAME "${CMAKE_SOURCE_DIR}/src/game/*.c")
file(GLOB SRC_LIB_MP3 "${CMAKE_SOURCE_DIR}/src/lib/mp3/*.c")
file(GLOB SRC_LIB_NAUDIO "${CMAKE_SOURCE_DIR}/src/lib/naudio/*.c")
file(GLOB SRC_LIB_ULTRA_AUDIO "${CMAKE_SOURCE_DIR}/src/lib/ultra/audio/*.c")
file(GLOB SRC_LIB_GU "${CMAKE_SOURCE_DIR}/src/lib/ultra/gu/*.c")
set(SRC_LIB
src/lib/ultra/io/vimodentsclan1.c
src/lib/ultra/io/vimodepallan1.c
src/lib/ultra/io/vimodempallan1.c
src/lib/ultra/io/vitbl.c
src/lib/ailist.c
src/lib/anim.c
src/lib/args.c
src/lib/audiodma.c
src/lib/audiomgr.c
src/lib/base.c
src/lib/collision.c
src/lib/debughud.c
src/lib/dma.c
src/lib/fault.c
src/lib/joy.c
src/lib/lib_2f490_c.c
src/lib/lib_2fc60.c
src/lib/lib_3e3e0.c
src/lib/lib_04f60nb.c
src/lib/lib_17ce0.c
src/lib/lib_034d0.c
src/lib/lib_39c80.c
src/lib/lib_15850.c
src/lib/mema.c
src/lib/memp.c
src/lib/model.c
src/lib/modelasm_c.c
src/lib/mp3.c
src/lib/mtx_c.c
src/lib/mtx.c
src/lib/music.c
src/lib/path.c
src/lib/profile.c
src/lib/rdp.c
src/lib/rmon.c
src/lib/rng_c.c
src/lib/rzip_c.c
src/lib/snd.c
src/lib/speaker.c
src/lib/varsinit.c
src/lib/vi.c
src/textureconfig.c
)
list(PREPEND SRC_LIB "${CMAKE_SOURCE_DIR}")
set(SRC
${SRC_GAME}
${SRC_PORT}
${SRC_PORT_CXX}
${SRC_LIB_MP3}
${SRC_LIB_NAUDIO}
${SRC_LIB_ULTRA_AUDIO}
${SRC_LIB_GU}
${SRC_LIB}
)
if(WIN32)
list(APPEND SRC "${CMAKE_SOURCE_DIR}/dist/windows/icon.rc")
endif()
# Asset files
generate_asset_headers("lang/" "${CMAKE_SOURCE_DIR}/tools/assetmgr/mklang" "en" JSON_HEADERS)
generate_asset_headers("pads/" "${CMAKE_SOURCE_DIR}/tools/assetmgr/mkpads" "" JSON_HEADERS)
generate_asset_headers("tiles/" "${CMAKE_SOURCE_DIR}/tools/assetmgr/mktiles" "" JSON_HEADERS)
generate_asset_headers("animations.json" "${CMAKE_SOURCE_DIR}/tools/assetmgr/mkanims" "" JSON_HEADERS)
generate_asset_headers("sequences.json" "${CMAKE_SOURCE_DIR}/tools/assetmgr/mksequences" "" JSON_HEADERS)
generate_asset_headers("textures.json" "${CMAKE_SOURCE_DIR}/tools/assetmgr/mktextures" "" JSON_HEADERS)
add_custom_target(pd_headers ALL DEPENDS ${JSON_HEADERS})
# Game target
set(BIN_NAME "pd${BIN_REGION}.${TARGET_ARCH}")
add_executable(pd ${SRC})
add_dependencies(pd pd_headers)
target_link_libraries(pd ${LIBS})
set_target_properties(pd PROPERTIES OUTPUT_NAME "${BIN_NAME}")
if(WIN32)
set_target_properties(pd PROPERTIES WIN32_EXECUTABLE TRUE)
endif()
# Additional commands for specific platforms.
if(NINTENDO_SWITCH)
add_custom_command(TARGET pd POST_BUILD
COMMAND nacptool --create "Perfect Dark" "fgsfds and contributors" "${VERSION_ROMID}/${VERSION_BRANCH}/${VERSION_HASH}" "${BIN_NAME}.nacp"
COMMAND aarch64-none-elf-strip -o ${CMAKE_BINARY_DIR}/${BIN_NAME}.stripped.elf ${CMAKE_BINARY_DIR}/${BIN_NAME}.elf
COMMAND elf2nro ${CMAKE_BINARY_DIR}/${BIN_NAME}.stripped.elf ${CMAKE_BINARY_DIR}/${BIN_NAME}.nro --icon=${CMAKE_SOURCE_DIR}/dist/nswitch/icon.jpg --nacp=${BIN_NAME}.nacp
)
endif()
-812
View File
@@ -1,812 +0,0 @@
################################################################################
# Options
# ROMID - The ROM version to build.
#
# Can be set in your environment using
# $ export ROMID=...
#
# Supported values:
# * ntsc-beta
# * ntsc-1.0
# * ntsc-final
# * pal-beta
# * pal-final
# * jpn-final
ROMID ?= ntsc-final
# MATCHING - Whether to build a matching ROM (1) or a custom one (0).
#
# Build a matching ROM to prove that the decompilation is accurate.
#
# If enabled, all further options are ignored and are set automatically.
MATCHING = 1
# COMPILER - Choose which compiler to use.
#
# A matching build uses ido. For non-matching builds, use gcc for performance.
#
# gcc is currently only supported when ROMID is ntsc-1.0 or ntsc-final.
#
# Supported values: ido, gcc
COMPILER = gcc
# GCC_OPT_LVL - the optimisation level if building with gcc.
#
# Supported values: -O0, -O1, -O2, -Os
GCC_OPT_LVL = -Os
# PAL - Whether to use the PAL television standard (1) or NTSC (0).
#
# PAL runs at 50Hz while NTSC is 60Hz, and PAL uses different screen dimensions.
PAL = 0
# ROMALLOCATION
#
# The lib, data and game segments are compressed in the final ROM.
#
# These options define how much space is allocated for the compressed segments.
#
# If any value is not big enough, the build system will tell you which one needs
# to be changed and what to change it to.
ROMALLOCATION_DATA = 0x015000
ROMALLOCATION_LIB = 0x038800
ROMALLOCATION_GAME = 0x144ee0
# ROM_SIZE - The desired ROM size in megabytes.
#
# All versions of the retail ROM are 32MB.
#
# If this is too low you might get this error from ld:
# "final link failed: memory exhausted"
ROM_SIZE := 32
# DEBUG - Enable (1) or disable (0) the debug menu and crash screen.
#
# When enabled, press C-up and C-down simultaneously to toggle the debug menu.
# Note that some emulators have problems displaying the crash screen text.
DEBUG = 0
################################################################################
# The VERSION constant is used in the source to handle version-specific code.
ifeq ($(ROMID), ntsc-beta)
VERSION = 0
endif
ifeq ($(ROMID), ntsc-1.0)
VERSION = 1
endif
ifeq ($(ROMID), ntsc-final)
VERSION = 2
endif
ifeq ($(ROMID), pal-beta)
VERSION = 3
endif
ifeq ($(ROMID), pal-final)
VERSION = 4
endif
ifeq ($(ROMID), jpn-final)
VERSION = 5
endif
# Set runtime piracy checks off. We turn this on for matching builds if needed.
PIRACYCHECKS = 0
# A magic value that's only used to produce a matching ROM.
# It's required because old-school zlib was influenced by uninitialised data.
# ZIPMAGIC is the value of the uninitialised data. We set it per version for
# matching builds, otherwise 0 is fine.
ZIPMAGIC = 0x0000
# This is also a value that's only used to produce a matching ROM.
# The final ROM has some duplicate bytes, and there doesn't seem to be any logic
# for determining how many bytes are duplicated.
COPYLEN = 2
# If a matching build has been requested, override directives as needed.
ifeq ($(MATCHING), 1)
COMPILER = ido
ROMALLOCATION_DATA = 0x015000
ROMALLOCATION_LIB = 0x038800
ROM_SIZE = 32
DEBUG = 0
ifeq ($(ROMID), ntsc-beta)
PAL = 0
PIRACYCHECKS = 0
ROMALLOCATION_DATA = 0x012000
ROMALLOCATION_LIB = 0x02f800
ROMALLOCATION_GAME = 0x105000
DEBUG = 1
endif
ifeq ($(ROMID), ntsc-1.0)
PAL = 0
PIRACYCHECKS = 1
ROMALLOCATION_GAME = 0x144ee0
ZIPMAGIC = 0xffff
endif
ifeq ($(ROMID), ntsc-final)
PAL = 0
PIRACYCHECKS = 1
ROMALLOCATION_GAME = 0x144ee0
ZIPMAGIC = 0xffff
endif
ifeq ($(ROMID), pal-beta)
PAL = 1
PIRACYCHECKS = 1
ROMALLOCATION_GAME = 0x1306f0
ZIPMAGIC = 0x0c00
COPYLEN = 6
DEBUG = 1
endif
ifeq ($(ROMID), pal-final)
PAL = 1
PIRACYCHECKS = 1
ROMALLOCATION_GAME = 0x1306f0
ZIPMAGIC = 0xaf00
endif
ifeq ($(ROMID), jpn-final)
PAL = 0
PIRACYCHECKS = 1
ROMALLOCATION_GAME = 0x1296f0
ZIPMAGIC = 0x0002
COPYLEN = 4
endif
endif
DEFINES := \
VERSION=$(VERSION) \
MATCHING=$(MATCHING) \
PAL=$(PAL) \
PIRACYCHECKS=$(PIRACYCHECKS) \
ROM_SIZE=$(ROM_SIZE) \
PLATFORM_N64=1
ifeq ($(DEBUG),1)
DEFINES := $(DEFINES) DEBUG=1
endif
C_DEFINES := $(foreach d,$(DEFINES),-D$(d))
AS_DEFINES := $(foreach d,$(DEFINES),--defsym $(d)) --defsym _LANGUAGE_ASSEMBLY=1
A_DIR := src/assets/$(ROMID)
B_DIR := build/$(ROMID)
E_DIR := extracted/$(ROMID)
ifneq ($(strip $(MIPS_BINUTILS_PREFIX)),)
TOOLCHAIN := $(MIPS_BINUTILS_PREFIX)
else ifeq ($(shell type mips-elf-ld >/dev/null 2>/dev/null; echo $$?), 0)
TOOLCHAIN := mips-elf
else ifeq ($(shell type mips-linux-gnu-ld >/dev/null 2>/dev/null; echo $$?), 0)
TOOLCHAIN := mips-linux-gnu
else ifeq ($(shell type mips64-elf-ld >/dev/null 2>/dev/null; echo $$?), 0)
TOOLCHAIN := mips64-elf
else ifeq ($(shell type mips64-linux-gnu-ld >/dev/null 2>/dev/null; echo $$?), 0)
TOOLCHAIN := mips64-linux-gnu
else
$(error You need to install a suitable MIPS binutils toolchain (eg. mips-elf-ld))
endif
# Asset files are files which are included in the "files" segment of the ROM.
# This excludes animations, fonts, SFX, MIDI and textures.
# And because setup files are part of the files segment they are included here,
# despite them being written in C.
#
# Create names such as $(B_DIR)/assets/files/PfooZ.
# These names (with .o added) will be dependenices for ld.
ASSET_FILES := \
$(patsubst $(A_DIR)/files/audio/%.mp3, $(B_DIR)/assets/files/A%M, $(shell find $(A_DIR) -path '*/files/audio/*.mp3')) \
$(patsubst $(A_DIR)/files/chrs/%.bin, $(B_DIR)/assets/files/C%Z, $(shell find $(A_DIR) -path '*/files/chrs/*.bin')) \
$(patsubst $(A_DIR)/files/guns/%.bin, $(B_DIR)/assets/files/G%Z, $(shell find $(A_DIR) -path '*/files/guns/*.bin')) \
$(patsubst $(A_DIR)/files/props/%.bin, $(B_DIR)/assets/files/P%Z, $(shell find $(A_DIR) -path '*/files/props/*.bin')) \
$(patsubst src/setups/%.c, $(B_DIR)/assets/files/U%Z, $(shell find src/setups -name '*.c')) \
$(patsubst $(A_DIR)/files/bgdata/%.seg, $(B_DIR)/assets/files/bgdata/%.seg, $(shell find $(A_DIR) -path '*/files/bgdata/*.seg')) \
$(B_DIR)/assets/files/ob/ob_mid.seg.o
LANG_JSON_FILES := $(shell find $(A_DIR) -path '*/lang/*.json')
PADS_JSON_FILES := $(shell find $(A_DIR) -path '*/pads/*.json')
TILES_JSON_FILES := $(shell find $(A_DIR) -path '*/tiles/*.json')
LANG_O_FILES := \
$(patsubst $(A_DIR)/lang/%.json, $(B_DIR)/assets/files/L%E.o, $(LANG_JSON_FILES)) \
$(patsubst $(A_DIR)/lang/%.json, $(B_DIR)/assets/files/L%J.o, $(LANG_JSON_FILES)) \
$(patsubst $(A_DIR)/lang/%.json, $(B_DIR)/assets/files/L%P.o, $(LANG_JSON_FILES)) \
$(patsubst $(A_DIR)/lang/%.json, $(B_DIR)/assets/files/L%_str_f.o, $(LANG_JSON_FILES)) \
$(patsubst $(A_DIR)/lang/%.json, $(B_DIR)/assets/files/L%_str_g.o, $(LANG_JSON_FILES)) \
$(patsubst $(A_DIR)/lang/%.json, $(B_DIR)/assets/files/L%_str_i.o, $(LANG_JSON_FILES)) \
$(patsubst $(A_DIR)/lang/%.json, $(B_DIR)/assets/files/L%_str_s.o, $(LANG_JSON_FILES))
PADS_O_FILES := $(patsubst $(A_DIR)/pads/%.json, $(B_DIR)/assets/files/bgdata/bg_%_padsZ.o, $(PADS_JSON_FILES))
TILES_O_FILES := $(patsubst $(A_DIR)/tiles/%.json, $(B_DIR)/assets/files/bgdata/bg_%_tilesZ.o, $(TILES_JSON_FILES))
C_FILES := $(shell find src/lib src/game src/inflate -name '*.c')
S_FILES := $(shell find src/lib src/game src/preamble -name '*.s')
C_O_FILES := $(patsubst src/%.c, $(B_DIR)/%.o, $(C_FILES))
S_O_FILES := $(patsubst src/%.s, $(B_DIR)/%.o, $(S_FILES))
O_FILES := \
$(C_O_FILES) \
$(S_O_FILES) \
$(patsubst %, %.o, $(ASSET_FILES)) \
$(LANG_O_FILES) \
$(PADS_O_FILES) \
$(TILES_O_FILES) \
$(B_DIR)/assets/animations.o \
$(B_DIR)/assets/copyrightZ.o \
$(B_DIR)/assets/files/list.o \
$(B_DIR)/assets/fonts/bankgothic.o \
$(B_DIR)/assets/fonts/handelgothiclg.o \
$(B_DIR)/assets/fonts/handelgothicmd.o \
$(B_DIR)/assets/fonts/handelgothicsm.o \
$(B_DIR)/assets/fonts/handelgothicxs.o \
$(B_DIR)/assets/fonts/numeric.o \
$(B_DIR)/assets/fonts/ocralg.o \
$(B_DIR)/assets/fonts/ocramd.o \
$(B_DIR)/assets/fonts/tahoma.o \
$(B_DIR)/assets/fonts/zurich.o \
$(B_DIR)/assets/mpstrings/mpstringsE.o \
$(B_DIR)/assets/mpstrings/mpstringsF.o \
$(B_DIR)/assets/mpstrings/mpstringsG.o \
$(B_DIR)/assets/mpstrings/mpstringsI.o \
$(B_DIR)/assets/mpstrings/mpstringsJ.o \
$(B_DIR)/assets/mpstrings/mpstringsP.o \
$(B_DIR)/assets/mpstrings/mpstringsS.o \
$(B_DIR)/assets/seq.ctl.o \
$(B_DIR)/assets/seq.tbl.o \
$(B_DIR)/assets/sequences.o \
$(B_DIR)/assets/sfx.ctl.o \
$(B_DIR)/assets/sfx.tbl.o \
$(B_DIR)/assets/textureslist.o \
$(B_DIR)/bootloader.o \
$(B_DIR)/firingrange.o \
$(B_DIR)/getitle.o \
$(B_DIR)/mpconfigs.o \
$(B_DIR)/romheader.o \
$(B_DIR)/rsp/asp.data.o \
$(B_DIR)/rsp/asp.text.o \
$(B_DIR)/rsp/gsp.data.o \
$(B_DIR)/rsp/gsp.text.o \
$(B_DIR)/rsp/rspboot.text.o \
$(B_DIR)/textureconfig.o
# ntsc-beta doesn't have this segment
ifneq ($(ROMID), ntsc-beta)
O_FILES := $(O_FILES) $(B_DIR)/assets/accessingpakZ.o
endif
ifeq ($(ROMID), jpn-final)
O_FILES := $(O_FILES) $(B_DIR)/assets/fonts/jpn.o
else
O_FILES := $(O_FILES) \
$(B_DIR)/assets/fonts/jpnsingle.o \
$(B_DIR)/assets/fonts/jpnmulti.o
endif
INCLUDES = \
-I include \
-I include/PR \
-I src/include \
-I src/include/lib/libc \
-I src/generated/$(ROMID) \
-I src/lib/ultra/audio \
AS := $(TOOLCHAIN)-as
ASFLAGS = -march=vr4300 -mabi=32 $(INCLUDES) $(AS_DEFINES)
ifeq ($(COMPILER), ido)
RECOMP_FILES := \
build/recomp/5.3/as1 \
build/recomp/5.3/cc \
build/recomp/5.3/cfe \
build/recomp/5.3/err.english.cc \
build/recomp/5.3/ugen \
build/recomp/5.3/ujoin \
build/recomp/5.3/uld \
build/recomp/5.3/umerge \
build/recomp/5.3/uopt \
build/recomp/5.3/usplit \
build/recomp/7.1/as1 \
build/recomp/7.1/cc \
build/recomp/7.1/cfe \
build/recomp/7.1/err.english.cc \
build/recomp/7.1/ugen \
build/recomp/7.1/uopt
LOOPUNROLL_C_FILES := \
src/lib/ultra/gu/frustum.c \
src/lib/ultra/gu/mtxutil.c \
src/lib/ultra/gu/ortho.c \
src/lib/ultra/io/conteepread.c \
src/lib/ultra/io/conteepwrite.c \
src/lib/ultra/io/contpfs.c \
src/lib/ultra/io/contramread.c \
src/lib/ultra/io/contramwrite.c \
src/lib/ultra/io/gbpakgetstatus.c \
src/lib/ultra/io/gbpakreadid.c \
src/lib/ultra/io/motor.c \
src/lib/ultra/io/pfschecker.c \
src/lib/ultra/io/pfsfreeblocks.c \
src/lib/ultra/io/pfsgetstatus.c \
src/lib/ultra/io/pfsinitpak2.c
MIPS3_C_FILES := \
src/lib/rng_c.c \
src/lib/ultra/libc/ll.c \
src/lib/ultra/libc/llcvt.c
G_C_FILES := \
$(shell find src/lib/ultra/audio -name '*.c') \
$(shell find src/lib/naudio -name '*.c') \
$(shell find src/lib/mp3 -name '*.c') \
src/lib/lib_2fc60.c \
src/lib/lib_317f0.c \
src/lib/lib_39c80.c \
src/lib/lib_3e3e0.c \
src/lib/mp3.c \
src/lib/speaker.c
O1_C_FILES := \
src/lib/lib_04f60nb.c \
src/lib/ultra/io/ai.c \
src/lib/ultra/io/aisetnextbuf.c \
src/lib/ultra/io/conteeplongread.c \
src/lib/ultra/io/contquery.c \
src/lib/ultra/io/controller.c \
src/lib/ultra/io/dpctr.c \
src/lib/ultra/io/pigetcmdq.c \
src/lib/ultra/io/pidma.c \
src/lib/ultra/io/si.c \
src/lib/ultra/io/sp.c \
src/lib/ultra/io/spsetpc.c \
src/lib/ultra/io/sptaskyielded.c \
src/lib/ultra/io/vi.c \
src/lib/ultra/io/viblack.c \
src/lib/ultra/io/vigetcurrframebuf.c \
src/lib/ultra/io/vigetnextframebuf.c \
src/lib/ultra/io/visetevent.c \
src/lib/ultra/io/visetmode.c \
src/lib/ultra/io/visetxscale.c \
src/lib/ultra/io/visetyscale.c \
src/lib/ultra/io/viswapbuf.c \
src/lib/ultra/libc/ll.c \
src/lib/ultra/libc/llcvt.c \
src/lib/ultra/os/atomic.c \
src/lib/ultra/os/createmesgqueue.c \
src/lib/ultra/os/destroythread.c \
src/lib/ultra/os/getmemsize.c \
src/lib/ultra/os/gettime.c \
src/lib/ultra/os/initialize2.c \
src/lib/ultra/os/jammesg.c \
src/lib/ultra/os/recvmesg.c \
src/lib/ultra/os/resetglobalintmask.c \
src/lib/ultra/os/sendmesg.c \
src/lib/ultra/os/seteventmesg.c \
src/lib/ultra/os/setglobalintmask.c \
src/lib/ultra/os/setthreadpri.c \
src/lib/ultra/os/settimer.c \
src/lib/ultra/os/startthread.c \
src/lib/ultra/os/stopthread.c \
src/lib/ultra/os/stoptimer.c \
src/lib/ultra/os/thread.c \
src/lib/ultra/os/timerintr.c \
src/lib/ultra/os/virtualtophysical.c \
src/lib/ultra/os/yieldthread.c
ifeq ($(ROMID), ntsc-beta)
O1_C_FILES := $(O1_C_FILES) src/lib/ultra/io/pfsisplug.c
endif
O3_C_FILES := \
src/lib/ultra/gu/align.c \
src/lib/ultra/gu/frustum.c \
src/lib/ultra/gu/ortho.c \
src/lib/ultra/gu/scale.c \
src/lib/ultra/libc/xprintf.c
IDO71_C_FILES := \
$(shell find src/lib/ultra/audio -name '*.c') \
$(shell find src/lib/naudio -name '*.c') \
$(shell find src/lib/mp3 -name '*.c') \
src/lib/lib_2fc60.c \
src/lib/lib_39c80.c
LOOPUNROLL_O_FILES = $(patsubst src/%.c, $(B_DIR)/%.o, $(LOOPUNROLL_C_FILES))
MIPS3_O_FILES = $(patsubst src/%.c, $(B_DIR)/%.o, $(MIPS3_C_FILES))
G_O_FILES = $(patsubst src/%.c, $(B_DIR)/%.o, $(G_C_FILES))
O1_O_FILES = $(patsubst src/%.c, $(B_DIR)/%.o, $(O1_C_FILES))
O3_O_FILES = $(patsubst src/%.c, $(B_DIR)/%.o, $(O3_C_FILES))
IDO71_O_FILES = $(patsubst src/%.c, $(B_DIR)/%.o, $(IDO71_C_FILES))
LOOPUNROLL := -Wo,-loopunroll,0
MIPSISET := -mips2
OPT_LVL := -O2
CC := build/recomp/5.3/cc
$(LOOPUNROLL_O_FILES): LOOPUNROLL :=
$(MIPS3_O_FILES): MIPSISET := -mips3
$(G_O_FILES): OPT_LVL := -g
$(O1_O_FILES): OPT_LVL := -O1
$(O3_O_FILES): OPT_LVL := -O3
$(IDO71_O_FILES): CC := build/recomp/7.1/cc
CFLAGS = $(C_DEFINES) $(INCLUDES) \
$(LOOPUNROLL) \
-Wab,-r4300_mul \
-non_shared \
-Olimit 2000 \
-G 0 \
-Xcpluscomm \
-w2 \
-Wab,-w \
-woff 581,649,819,820,821,838,852 \
$(MIPSISET) -32
# Files containing GLOBAL_ASM must be built with the asm_processor
ifeq ($(MATCHING), 1)
GLOBALASM_C_FILES != grep -rl 'GLOBAL_ASM(' $(C_FILES)
GLOBALASM_O_FILES = $(patsubst src/%.c, $(B_DIR)/%.o, $(GLOBALASM_C_FILES))
$(GLOBALASM_O_FILES): CC := /usr/bin/env python3 tools/asm_processor/build.py $(CC) -- $(TOOLCHAIN)-as $(ASFLAGS) --
endif
else ifeq ($(COMPILER), gcc)
CC := $(TOOLCHAIN)-gcc
$(C_O_FILES): OPT_LVL := $(GCC_OPT_LVL)
C_DEFINES += -DAVOID_UB
CFLAGS := $(C_DEFINES) $(INCLUDES) \
-EB \
-march=vr4300 \
-mabi=32 \
-mfix4300 \
-mdivide-breaks \
-mno-abicalls \
-ffreestanding \
-fno-builtin \
-fno-common \
-fno-inline-functions \
-fno-merge-constants \
-fno-strict-aliasing \
-fno-zero-initialized-in-bss \
-funsigned-char \
-fwrapv \
-Wall \
-Werror \
-Wno-address \
-Wno-aggressive-loop-optimizations \
-Wno-array-bounds \
-Wno-int-in-bool-context \
-Wno-int-to-pointer-cast \
-Wno-maybe-uninitialized \
-Wno-misleading-indentation \
-Wno-missing-braces \
-Wno-multichar \
-Wno-pointer-sign \
-Wno-pointer-to-int-cast \
-Wno-tautological-compare \
-Wno-uninitialized \
-Wno-unused-but-set-variable \
-Wno-unused-value \
-Wno-unused-variable \
-G 0
$(B_DIR)/lib/ultra/libc/xldtob.o: CFLAGS += -ffast-math -fno-unsafe-math-optimizations
else
$(error The COMPILER option must be "ido" or "gcc")
endif
# Make ROMID available as an environment variable to all tooling.
# (We use this a lot)
export ROMID
default: rom
################################################################################
# Recomp
# ------------------------------------------------------------------------------
# The ido-static-recomp project is installed as a git submodule at tools/recomp.
# The IRIX binaries are taken from that project and they are recompiled to
# build/recomp/<version>/
tools/recomp/recomp.cpp:
@echo "Please install ido-static-recomp by running:"
@echo
@echo " git submodule update --init --recursive"
@echo
@exit 1
build/recomp/recomp: tools/recomp/recomp.cpp
@mkdir -p build/recomp/5.3
@mkdir -p build/recomp/7.1
g++ tools/recomp/recomp.cpp -o build/recomp/recomp -g -lcapstone
build/recomp/5.3/ugen:
@mkdir -p build/recomp/5.3
g++ tools/recomp/recomp.cpp -o build/recomp/recomp-ugen53 -g -lcapstone -Dugen53
./build/recomp/recomp-ugen53 tools/recomp/ido/5.3/usr/lib/ugen > build/recomp/5.3/ugen.c
gcc tools/recomp/libc_impl.c build/recomp/5.3/ugen.c -Itools/recomp -o build/recomp/5.3/ugen -O2 -fno-strict-aliasing -lm -no-pie -DIDO53
build/recomp/5.3/cc: build/recomp/recomp
./build/recomp/recomp tools/recomp/ido/5.3/usr/bin/cc > build/recomp/5.3/cc.c
gcc tools/recomp/libc_impl.c build/recomp/5.3/cc.c -Itools/recomp -o build/recomp/5.3/cc -O2 -fno-strict-aliasing -lm -no-pie -DIDO53
build/recomp/5.3/%: build/recomp/recomp
./build/recomp/recomp tools/recomp/ido/5.3/usr/lib/$* > build/recomp/5.3/$*.c
gcc tools/recomp/libc_impl.c build/recomp/5.3/$*.c -Itools/recomp -o build/recomp/5.3/$* -O2 -fno-strict-aliasing -lm -no-pie -DIDO53
build/recomp/7.1/cc: build/recomp/recomp
./build/recomp/recomp tools/recomp/ido/7.1/usr/bin/cc > build/recomp/7.1/cc.c
gcc tools/recomp/libc_impl.c build/recomp/7.1/cc.c -Itools/recomp -o build/recomp/7.1/cc -O2 -fno-strict-aliasing -lm -no-pie -DIDO71
build/recomp/7.1/%: build/recomp/recomp
./build/recomp/recomp tools/recomp/ido/7.1/usr/lib/$* > build/recomp/7.1/$*.c
gcc tools/recomp/libc_impl.c build/recomp/7.1/$*.c -Itools/recomp -o build/recomp/7.1/$* -O2 -fno-strict-aliasing -lm -no-pie -DIDO71
build/recomp/%/err.english.cc:
@mkdir -p build/recomp/$?
cp tools/err.english.cc build/recomp/$*
################################################################################
# ROM Finalisation Stages
# Link all objects together with ld to make stage1.elf. In this stage, the game,
# lib and data segments are uncompressed and placed past the end of the ROM.
$(B_DIR)/stage1.elf: $(O_FILES) ld/pd.ld
cpp -DROMID=$(ROMID) -DVERSION=$(VERSION) -DROMALLOCATION_DATA=$(ROMALLOCATION_DATA) -DROMALLOCATION_LIB=$(ROMALLOCATION_LIB) -DROMALLOCATION_GAME=$(ROMALLOCATION_GAME) -DROM_SIZE=$(ROM_SIZE) -P ld/pd.ld -o $(B_DIR)/pd.ld
$(TOOLCHAIN)-ld --no-check-sections -z muldefs -T $(B_DIR)/pd.ld --print-map -o $@ > $(B_DIR)/pd.map
$(B_DIR)/stage1.bin: $(B_DIR)/stage1.elf
$(TOOLCHAIN)-objcopy $< $@ -O binary
# Build the final ROM from stage1.bin using mkrom
# mkrom handles calculating the piracy checksums, zipping segments and
# calculating the ROM checksum.
$(B_DIR)/pd.z64: $(B_DIR)/stage1.bin tools/mkrom/mkrom
tools/mkrom/mkrom $(B_DIR)/stage1.bin $(B_DIR)/pd.map $(PIRACYCHECKS) $(ZIPMAGIC) $(COPYLEN) $@
@echo -e "\033[0;32mROM written to $@\033[0m"
tools/mkrom/mkrom:
$(MAKE) -C tools/mkrom
################################################################################
# Testing Related
# ---------------------
# This works a little backwards, in that the ROM has to be built to at least
# stage 2, then extract-segment is used to slice out the segments.
CHECK_FILES := $(shell awk '{print $$2}' checksums.$(ROMID).md5)
test: $(CHECK_FILES)
@md5sum --quiet -c checksums.$(ROMID).md5
$(B_DIR)/segments/%.bin: $(B_DIR)/pd.z64
@B_DIR=$(B_DIR) tools/extract-segment $*
################################################################################
# Raw data segments
$(B_DIR)/assets/fonts/%.o: $(A_DIR)/fonts/%.bin
mkdir -p $(B_DIR)/assets/fonts
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
$(B_DIR)/getitle.o: $(E_DIR)/getitle.bin
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
$(B_DIR)/assets/seq.ctl.o: $(A_DIR)/seq.ctl
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
$(B_DIR)/assets/seq.tbl.o: $(A_DIR)/seq.tbl
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
$(B_DIR)/assets/sfx.ctl.o: $(A_DIR)/sfx.ctl
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
$(B_DIR)/assets/sfx.tbl.o: $(A_DIR)/sfx.tbl
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
################################################################################
# Asset Manager
ASSETMGR_O_FILES := \
$(B_DIR)/assets/animations.o \
$(LANG_O_FILES) \
$(PADS_O_FILES) \
$(TILES_O_FILES) \
$(B_DIR)/assets/sequences.o \
$(B_DIR)/assets/textureslist.o \
# Anims
$(B_DIR)/assets/animations.o: $(A_DIR)/animations.json
tools/assetmgr/mkanims
# Lang
$(B_DIR)/assets/files/L%E.o: $(A_DIR)/lang/%.json
tools/assetmgr/mklang $< en
$(B_DIR)/assets/files/L%J.o: $(A_DIR)/lang/%.json
tools/assetmgr/mklang $< jp
$(B_DIR)/assets/files/L%P.o: $(A_DIR)/lang/%.json
tools/assetmgr/mklang $< gb
$(B_DIR)/assets/files/L%_str_f.o: $(A_DIR)/lang/%.json
tools/assetmgr/mklang $< fr
$(B_DIR)/assets/files/L%_str_g.o: $(A_DIR)/lang/%.json
tools/assetmgr/mklang $< de
$(B_DIR)/assets/files/L%_str_i.o: $(A_DIR)/lang/%.json
tools/assetmgr/mklang $< it
$(B_DIR)/assets/files/L%_str_s.o: $(A_DIR)/lang/%.json
tools/assetmgr/mklang $< es
# Pads
$(B_DIR)/assets/files/bgdata/bg_%_padsZ.o: $(A_DIR)/pads/%.json
tools/assetmgr/mkpads $<
# Pads - but this is the zipped non-obj, for make test
$(B_DIR)/assets/files/bgdata/bg_%_padsZ: $(A_DIR)/pads/%.json
tools/assetmgr/mkpads $<
# Sequences
$(B_DIR)/assets/sequences.o: $(A_DIR)/sequences.json
tools/assetmgr/mksequences
# Textures
$(B_DIR)/assets/textureslist.o: $(A_DIR)/textures.json
tools/assetmgr/mktextures
# Tiles
$(B_DIR)/assets/files/bgdata/bg_%_tilesZ.o: $(A_DIR)/tiles/%.json
tools/assetmgr/mktiles $<
# Tiles - but this is the zipped non-obj, for make test
$(B_DIR)/assets/files/bgdata/bg_%_tilesZ: $(A_DIR)/tiles/%.json
tools/assetmgr/mktiles $<
################################################################################
# Files
# Audio
$(B_DIR)/assets/files/A%M: $(A_DIR)/files/audio/%.mp3
@mkdir -p $(B_DIR)/assets/files
cp $< $@
# BG segs
$(B_DIR)/assets/files/bgdata/bg_%.seg: $(A_DIR)/files/bgdata/bg_%.seg
@mkdir -p $(B_DIR)/assets/files/bgdata
cp $< $@
# Chrs
$(B_DIR)/assets/files/C%Z: $(A_DIR)/files/chrs/%.bin
@mkdir -p $(B_DIR)/assets/files
tools/rarezip $< > $@
# Guns
$(B_DIR)/assets/files/G%Z: $(A_DIR)/files/guns/%.bin
@mkdir -p $(B_DIR)/assets/files
tools/rarezip $< > $@
# OB seg
$(B_DIR)/assets/files/ob/ob_mid.seg.o: $(B_DIR)/assets/files/ob/ob_mid.seg
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
$(B_DIR)/assets/files/ob/ob_mid.seg:
@mkdir -p $(B_DIR)/assets/files/ob
> $@
# Props
$(B_DIR)/assets/files/P%Z: $(A_DIR)/files/props/%.bin
tools/rarezip $< > $@
# Stage setups
# $(A_DIR)/files/setup/foo.c
# -> B_DIR/assets/files/setup/foo.o (done here)
# -> B_DIR/assets/files/setup/foo.elf (done here)
# -> B_DIR/assets/files/setup/foo.bin (done here)
# -> B_DIR/assets/files/UsetupfooZ (done here)
# -> B_DIR/assets/files/UsetupfooZ.o (done elsewhere)
$(B_DIR)/assets/files/setup/%.o: src/setups/%.c $(ASSETMGR_O_FILES) $(RECOMP_FILES)
@mkdir -p $(dir $@)
$(CC) -c $(CFLAGS) -o $@ $<
$(B_DIR)/assets/files/setup/%.elf: $(B_DIR)/assets/files/setup/%.o
TOOLCHAIN=$(TOOLCHAIN) tools/mksimpleelf $< $@
$(B_DIR)/files/setup/%.bin: $(B_DIR)/assets/files/setup/%.elf
@mkdir -p $(dir $@)
$(TOOLCHAIN)-objcopy $< $@ -O binary
$(B_DIR)/assets/files/U%Z: $(B_DIR)/files/setup/%.bin
tools/rarezip $< > $@
# General target to convert any finalised file into a raw object for ld
$(B_DIR)/assets/files/%.o: $(B_DIR)/assets/files/%
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
$(B_DIR)/assets/files/%.bin: $(B_DIR)/assets/files/%.elf
$(TOOLCHAIN)-objcopy $< $@ -O binary
################################################################################
# Miscellaneous
$(B_DIR)/bootloader.o: $(E_DIR)/bootloader.bin
@mkdir -p $(dir $@)
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
$(B_DIR)/romheader.o: src/romheader/romheader.s
$(TOOLCHAIN)-as --defsym VERSION=$(VERSION) -march=vr4300 -mabi=32 -I src/include -EB -o $@ $<
$(B_DIR)/assets/accessingpakZ: $(A_DIR)/accessingpak.bin
tools/rarezip $< > $@
$(B_DIR)/assets/copyrightZ: $(A_DIR)/copyright.bin
tools/rarezip $< > $@
$(B_DIR)/assets/accessingpakZ.o: $(B_DIR)/assets/accessingpakZ
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
$(B_DIR)/assets/copyrightZ.o: $(B_DIR)/assets/copyrightZ
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
$(B_DIR)/rsp/%.text.bin $(B_DIR)/rsp/%.data.bin: src/rsp/%.s
@mkdir -p $(dir $@)
armips -strequ CODE_FILE $(B_DIR)/rsp/$*.text.bin -strequ DATA_FILE $(B_DIR)/rsp/$*.data.bin $<
$(B_DIR)/rsp/%.o: $(B_DIR)/rsp/%.bin
TOOLCHAIN=$(TOOLCHAIN) ROMID=$(ROMID) tools/mkrawobject $< $@
ifeq ($(COMPILER), ido)
$(B_DIR)/lib/rng_c.o: src/lib/rng_c.c $(ASSETMGR_O_FILES) $(RECOMP_FILES)
@mkdir -p $(dir $@)
$(CC) -c $(CFLAGS) $(OPT_LVL) -o $@ $<
tools/patchmips3 $@ || rm $@
$(B_DIR)/lib/ultra/libc/llcvt.o: src/lib/ultra/libc/llcvt.c $(ASSETMGR_O_FILES) $(RECOMP_FILES)
@mkdir -p $(dir $@)
$(CC) -c $(CFLAGS) $(OPT_LVL) -o $@ $<
tools/patchmips3 $@ || rm $@
$(B_DIR)/lib/ultra/libc/ll.o: src/lib/ultra/libc/ll.c $(ASSETMGR_O_FILES) $(RECOMP_FILES)
@mkdir -p $(dir $@)
$(CC) -c $(CFLAGS) $(OPT_LVL) $< -o $@
tools/patchmips3 $@ || rm $@
endif
$(B_DIR)/%.o: src/%.c $(ASSETMGR_O_FILES) $(RECOMP_FILES)
@mkdir -p $(dir $@)
$(CC) -c $(CFLAGS) $(OPT_LVL) -o $@ $<
$(B_DIR)/%.o: src/%.s
@mkdir -p $(dir $@)
cpp -P -Wno-trigraphs -I include -I include/PR -I src/include $(C_DEFINES) -D_LANGUAGE_ASSEMBLY -D_MIPSEB $< | $(AS) $(ASFLAGS) -o $@
$(B_DIR)/assets/%.o: $(A_DIR)/%.c $(RECOMP_FILES)
@mkdir -p $(dir $@)
$(CC) -c $(CFLAGS) -o $@ $<
extract:
ROMID=$(ROMID) tools/extract
rom: $(B_DIR)/pd.z64
clean:
rm -rf build/$(ROMID) src/generated/$(ROMID)
allclean:
rm -rf build/* src/generated
codeclean:
find $(B_DIR)/game $(B_DIR)/inflate $(B_DIR)/lib -name '*.o' -delete
-336
View File
@@ -1,336 +0,0 @@
# Options.
# HOST_PLATFORM - Which platform we're building on.
#
# Determined automatically if not specified on command line.
#
# Supported values:
# * i686-windows
# * i686-linux
HOST_PLATFORM ?=
# TARGET_PLATFORM - Which platform to build for.
#
# Determined from HOST_PLATFORM if not specified on command line.
#
# Supported values:
# * i686-windows
# * i686-linux
TARGET_PLATFORM ?=
# ROMID - The ROM version to use.
#
# Can be set in your environment using
# $ export ROMID=...
#
# Supported values:
# * ntsc-final
# * pal-final
# * jpn-final
ROMID ?= ntsc-final
# GCC_OPT_LVL - the optimisation level if building with gcc.
#
# Supported values: -O0, -O1, -O2, -O3, -Os, -Og
GCC_OPT_LVL = -Og
# ROM_SIZE - The desired ROM size in megabytes.
#
# All versions of the retail ROM are 32MB.
#
# If this is too low you might get this error from ld:
# "final link failed: memory exhausted"
ROM_SIZE := 32
# DEBUG - Enable (1) or disable (0) the debug menu and crash screen.
#
# When enabled, press C-up and C-down simultaneously to toggle the debug menu.
# Note that some emulators have problems displaying the crash screen text.
DEBUG = 0
################################################################################
# Detect host platform if not specified.
ifeq ($(HOST_PLATFORM),)
ifeq ($(OS),Windows_NT)
# assume msys for now
UNAME_OS := $(shell uname -s)
ifneq (,$(findstring MINGW64,$(UNAME_OS)))
HOST_PLATFORM := x86_64-windows
else
HOST_PLATFORM := i686-windows
endif
else # TODO
UNAME_ARCH := $(shell uname -m)
UNAME_OS := $(shell uname -s)
UNAME_OS := $(shell echo $(UNAME_OS) | tr A-Z a-z)
HOST_PLATFORM := $(UNAME_ARCH)-$(UNAME_OS)
endif
endif
# Set target platform to host platform if not specified.
ifeq ($(TARGET_PLATFORM),)
TARGET_PLATFORM := $(HOST_PLATFORM)
endif
ifeq (,$(findstring clean,$(MAKECMDGOALS)))
$(info Host platform: $(HOST_PLATFORM))
$(info Target platform: $(TARGET_PLATFORM))
endif
# Set whether the target arch is 64- or 32-bit.
ifneq (,$(findstring 64,$(TARGET_PLATFORM))$(findstring armv8,$(TARGET_PLATFORM)))
# TODO: we're not 64-bit compatible yet, error out if building the actual game
ifeq (,$(findstring clean,$(MAKECMDGOALS)))
$(error 64-bit target platforms are not supported yet)
endif
TARGET_64BIT = 1
else # TODO
TARGET_64BIT = 0
endif
# Set whether the target is big-endian or little-endian.
TARGET_BIG_ENDIAN = 0 # TODO
# The VERSION constant is used in the source to handle version-specific code.
ifeq ($(ROMID),ntsc-final)
BIN_NAME = pd.exe
VERSION = 2
IS_PAL = 0
else ifeq ($(ROMID),pal-final)
BIN_NAME = pd.pal.exe
VERSION = 4
IS_PAL = 1
else ifeq ($(ROMID),jpn-final)
BIN_NAME = pd.jpn.exe
VERSION = 5
IS_PAL = 0
else
$(error ROM version $(VERSION) is not supported)
endif
VERSION_HASH := $(shell git rev-parse --short HEAD)
VERSION_BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
VERSION_TARGET := $(TARGET_PLATFORM)
VERSION_ROMID := $(ROMID)
ifeq ($(VERSION_BRANCH),)
VERSION_BRANCH := port-custom
endif
ifeq ($(VERSION_BRANCH),HEAD)
VERSION_BRANCH := port-custom
endif
DEFINES := \
VERSION=$(VERSION) \
VERSION_HASH=\"$(VERSION_HASH)\" \
VERSION_TARGET=\"$(VERSION_TARGET)\" \
VERSION_ROMID=\"$(VERSION_ROMID)\" \
VERSION_BRANCH=\"$(VERSION_BRANCH)\" \
MATCHING=0 \
PAL=$(IS_PAL) \
PIRACYCHECKS=0 \
ROM_SIZE=$(ROM_SIZE) \
_LANGUAGE_C=1
ifeq ($(DEBUG),1)
DEFINES := $(DEFINES) DEBUG=1
endif
C_DEFINES := $(foreach d,$(DEFINES),-D$(d))
A_DIR := src/assets/$(ROMID)
B_DIR := build/$(ROMID)-port
G_DIR := src/generated/$(ROMID)
ifneq (,$(findstring windows,$(TARGET_PLATFORM)))
TARGET_CFLAGS := $(shell pkg-config sdl2 --cflags-only-I)
TARGET_LDFLAGS := $(shell pkg-config sdl2 --libs) -lz -lopengl32 -lws2_32 -lwinmm -ldbghelp
# on windows/mingw we need this to be built with a 32-bit compiler so it finds the correct libs
TOOLCHAIN ?= i686-w64-mingw32-
# on GCC link libstdc++ statically
ifeq (,$(findstring clang,$(CC))$(findstring clang,$(CXX)))
TARGET_LDFLAGS += -static-libstdc++
else
TARGET_LDFLAGS += -lstdc++
endif
else # assume *nix
TARGET_CFLAGS := $(shell pkg-config sdl2 --cflags-only-I)
TARGET_LDFLAGS := $(shell pkg-config sdl2 --libs) -lGL -lz -ldl
ifneq (,$(findstring arm,$(TARGET_PLATFORM))$(findstring aarch,$(TARGET_PLATFORM)))
# linux on arm or aarch64
# TODO: detect soft/hardfloat abi
TOOLCHAIN ?= arm-linux-gnueabihf-
endif
endif
# On x86_64 gcc add -m32 to CFLAGS if building a 32-bit executable.
ifneq (,$(findstring x86_64,$(HOST_PLATFORM))$(findstring x86_64,$(TOOLCHAIN)))
ifneq (1,$(TARGET_64BIT))
TARGET_CFLAGS += -m32
endif
endif
# These are still used in the port, but only to generate headers.
JSON_FILES := $(shell find $(A_DIR) -path '*/lang/*.json')
JSON_FILES += $(shell find $(A_DIR) -path '*/pads/*.json')
JSON_FILES += $(shell find $(A_DIR) -path '*/tiles/*.json')
JSON_FILES += $(wildcard $(A_DIR)/*.json)
JSON_HEADERS := $(patsubst $(A_DIR)/%.json, $(G_DIR)/%.h, $(JSON_FILES))
C_FILES := $(shell find src/game port -name '*.c')
C_FILES := $(C_FILES) \
$(wildcard src/lib/mp3/*.c) \
$(wildcard src/lib/naudio/*.c) \
$(wildcard src/lib/ultra/audio/*.c) \
$(wildcard src/lib/ultra/gu/*.c) \
src/lib/ultra/io/vimodentsclan1.c \
src/lib/ultra/io/vimodepallan1.c \
src/lib/ultra/io/vimodempallan1.c \
src/lib/ultra/io/vitbl.c \
$(wildcard src/lib/a*.c) \
src/lib/base.c \
src/lib/collision.c \
src/lib/debughud.c \
src/lib/dma.c \
src/lib/fault.c \
src/lib/joy.c \
$(wildcard src/lib/lib_*.c) \
src/lib/mema.c \
src/lib/memp.c \
src/lib/model.c \
src/lib/modelasm_c.c \
src/lib/mp3.c \
src/lib/mtx_c.c \
src/lib/mtx.c \
src/lib/music.c \
src/lib/path.c \
src/lib/profile.c \
src/lib/rdp.c \
src/lib/rmon.c \
src/lib/rng_c.c \
src/lib/rzip_c.c \
src/lib/snd.c \
src/lib/speaker.c \
src/lib/varsinit.c \
src/lib/vi.c \
src/textureconfig.c
CXX_FILES :=$(shell find port -name '*.cpp')
C_O_FILES := $(patsubst %.c, $(B_DIR)/%.o, $(C_FILES))
CXX_O_FILES := $(patsubst %.cpp, $(B_DIR)/%.o, $(CXX_FILES))
O_FILES := $(C_O_FILES) $(CXX_O_FILES)
INCLUDES = \
-I include \
-I include/PR \
-I src/include \
-I src/generated/$(ROMID) \
-I src/lib/ultra/audio \
-I port/include
TOOLCHAIN ?=
CC ?= $(TOOLCHAIN)gcc
CXX ?= $(TOOLCHAIN)g++
ifneq (,$(CXX_O_FILES))
LD := $(CXX)
else
LD := $(CC)
endif
$(C_O_FILES): OPT_LVL := $(GCC_OPT_LVL)
COMMON_CFLAGS := $(C_DEFINES) -DAVOID_UB=1 $(INCLUDES) $(TARGET_CFLAGS) -g \
-fno-inline-functions \
-fno-strict-aliasing \
-funsigned-char \
-fwrapv \
-Wall \
-Wno-address \
-Wno-int-in-bool-context \
-Wno-misleading-indentation \
-Wno-missing-braces \
-Wno-multichar \
-Wno-tautological-compare \
-Wno-unused-but-set-variable \
-Wno-unused-value \
-Wno-unused-variable \
-Wno-format-truncation
CFLAGS := -std=c11 $(COMMON_CFLAGS) -Wno-pointer-sign
CXXFLAGS := -std=c++20 $(COMMON_CFLAGS) -Wno-unused-function
LDFLAGS := $(TARGET_LDFLAGS)
# Make ROMID available as an environment variable to all tooling.
# (We use this a lot)
export ROMID
BIN := $(B_DIR)/$(BIN_NAME)
default: $(BIN)
################################################################################
# Asset Manager header generation
# Anims
$(G_DIR)/animations.h: $(A_DIR)/animations.json
tools/assetmgr/mkanims --headers-only
# Lang
$(G_DIR)/lang/%.h: $(A_DIR)/lang/%.json
tools/assetmgr/mklang $< en --headers-only
# Pads
$(G_DIR)/pads/%.h: $(A_DIR)/pads/%.json
tools/assetmgr/mkpads $< --headers-only
# Sequences
$(G_DIR)/sequences.h: $(A_DIR)/sequences.json
tools/assetmgr/mksequences --headers-only
# Textures
$(G_DIR)/textures.h: $(A_DIR)/textures.json
tools/assetmgr/mktextures --headers-only
# Tiles
$(G_DIR)/tiles/%.h: $(A_DIR)/tiles/%.json
tools/assetmgr/mktiles $< --headers-only
################################################################################
# Generic compilation rules
$(BIN): $(O_FILES)
$(LD) $(COMMON_CFLAGS) $(OPT_LVL) -o $(BIN) $^ $(LDFLAGS)
ifneq ($(CV2PDB),)
$(CV2PDB) $(BIN)
endif
$(B_DIR)/%.o: %.c $(JSON_HEADERS)
@mkdir -p $(dir $@)
$(CC) -c $(CFLAGS) $(OPT_LVL) -o $@ $<
$(B_DIR)/%.o: %.cpp $(JSON_HEADERS)
@mkdir -p $(dir $@)
$(CXX) -c $(CXXFLAGS) $(OPT_LVL) -o $@ $<
################################################################################
# Clean rules
clean:
rm -rf build/$(ROMID)-port
allclean:
rm -rf build/*
rm -rf src/generated
codeclean:
find $(B_DIR)/ -name '*.o' -delete
+113 -43
View File
@@ -1,14 +1,4 @@
# Perfect Dark port (`port-net`) # Perfect Dark port
## Experimental netplay branch
This branch of the port contains an **extremely** early and experimental implementation of network play.
**DISCLAIMER:** This is **NOT READY** for prime time. Use at your own risk if you are not a developer.
**Do not create issues about problems in this branch until this disclaimer is gone.**
See [this file](https://github.com/fgsfdsfgs/perfect_dark/blob/port-net/docs/netplay.md) for more information on how this works.
## Original description
This repository contains a work-in-progress port of the [Perfect Dark decompilation](https://github.com/n64decomp/perfect_dark) to modern platforms. This repository contains a work-in-progress port of the [Perfect Dark decompilation](https://github.com/n64decomp/perfect_dark) to modern platforms.
@@ -41,18 +31,24 @@ There are minor graphics- and gameplay-related issues, and possibly occasional c
* basic mod support, currently enough to load a few custom levels; * basic mod support, currently enough to load a few custom levels;
* slightly expanded memory heap size; * slightly expanded memory heap size;
* experimental high framerate support (up to 240 FPS): * experimental high framerate support (up to 240 FPS):
* set `Game.TickRateDivisor` to `0` in `pd.ini` to activate; * enable `Uncap Tickrate` in `Extended Video Options` to activate;
* in practice the game will have issues running faster than ~165 FPS, so use VSync or `Video.FramerateLimit` to cap it. * in practice the game will have issues running faster than ~165 FPS, so use VSync or `Video.FramerateLimit` to cap it.
* emulate the Transfer Pak functionality the game has on the Nintendo 64 to unlock some cheats automatically.
Currently only 32-bit platforms are supported, namely x86 Windows and Linux. **The following platforms are officially supported and tested:**
Note that 32-bit binaries will still work on 64-bit versions of those platforms, * Windows 7+: i686, x86_64
though you might have to install some additional libraries. * Linux: i686, x86_64
* MacOS: x86_64 (OS 10.9+), arm64 (OS 11.0+)
* Nintendo Switch: arm64
## Download ## Download
Latest [automatic builds](https://github.com/fgsfdsfgs/perfect_dark/actions) of the netplay branch for supported platforms: Latest [automatic builds](https://github.com/fgsfdsfgs/perfect_dark/releases/tag/ci-dev-build) for supported platforms:
* [i686-windows (`port-net`)](https://nightly.link/fgsfdsfgs/perfect_dark/workflows/c-cpp/port-net/pd-i686-windows.zip) * [x86_64-windows](https://github.com/fgsfdsfgs/perfect_dark/releases/download/ci-dev-build/pd-x86_64-windows.zip)
* [i686-linux (`port-net`)](https://nightly.link/fgsfdsfgs/perfect_dark/workflows/c-cpp/port-net/pd-i686-linux.zip) * [i686-windows](https://github.com/fgsfdsfgs/perfect_dark/releases/download/ci-dev-build/pd-i686-windows.zip)
* [x86_64-linux](https://github.com/fgsfdsfgs/perfect_dark/releases/download/ci-dev-build/pd-x86_64-linux.tar.gz)
* [i686-linux](https://github.com/fgsfdsfgs/perfect_dark/releases/download/ci-dev-build/pd-i686-linux.tar.gz)
* [arm64-nswitch](https://github.com/fgsfdsfgs/perfect_dark/releases/download/ci-dev-build/pd-arm64-nswitch.zip)
If you are looking for netplay builds (the `port-net` branch), see [this link](https://github.com/fgsfdsfgs/perfect_dark/blob/port-net/README.md#download). If you are looking for netplay builds (the `port-net` branch), see [this link](https://github.com/fgsfdsfgs/perfect_dark/blob/port-net/README.md#download).
@@ -60,13 +56,29 @@ If you are looking for netplay builds (the `port-net` branch), see [this link](h
You must already have a Perfect Dark ROM to run the game, as specified above. You must already have a Perfect Dark ROM to run the game, as specified above.
1. Create a directory named `data` next to `pd.exe`. This assumes that you're using an x86_64 build. If you aren't, replace `x86_64` below with your arch (e.g. `i686`).
2. Put your Perfect Dark ROM named `pd.ntsc-final.z64` into it.
3. Run `pd.exe`. 1. Create a directory named `data` next to `pd.x86_64` if it's not there.
2. Put your Perfect Dark NTSC ROM named `pd.ntsc-final.z64` into it.
3. Run the `pd.x86_64` executable.
If you want to use a PAL or JPN ROM instead, put them into the `data` directory and run the appropriate executable:
* PAL: ROM name `pd.pal-final.z64`, executable name `pd.pal.x86_64`.
* JPN: ROM name `pd.jpn-final.z64`, executable name `pd.jpn.x86_64`.
Optionally, you can also put your Perfect Dark for GameBoy Color ROM named `pd.gbc` in the `data` directory if you want to emulate having the Nintendo 64's Transfer Pak and unlock some cheats automatically.
Optionally, you can move the data folder to `~/.local/share/perfectdark` on Linux or `~/Library/Application Support/perfectdark` on MacOS.
Additional information can be found in the [wiki](https://github.com/fgsfdsfgs/perfect_dark/wiki). Additional information can be found in the [wiki](https://github.com/fgsfdsfgs/perfect_dark/wiki).
A GPU supporting OpenGL 3.0 or above is required to run the port. A GPU supporting OpenGL 3.0/ES3.0 or above is required to run the port.
### Installing the Nintendo Switch version
The Nintendo Switch build ZIP comes with all 3 regions in different folders: `perfectdark`, `perfectdark_pal` and `perfectdark_jpn`.
Take the folder for the region you want and put it into the `/switch` folder on your SD card, then put your ROM into the `data` folder inside of the folder you extracted as described above.
## Controls ## Controls
@@ -86,7 +98,7 @@ Controls can be rebound in `pd.ini`. Default control scheme is as follows:
| Aim mode | RMB/Z | LT | R Trigger | | Aim mode | RMB/Z | LT | R Trigger |
| Use / Cancel | E | N/A | B | | Use / Cancel | E | N/A | B |
| Use / Accept | N/A | A | A | | Use / Accept | N/A | A | A |
| Crouch cycle | N/A | L3 | `0x80000000` (Extra) | | Crouch cycle | N/A | LS Click | `0x80000000` (Extra) |
| Half-Crouch | Shift | N/A | `0x40000000` (Extra) | | Half-Crouch | Shift | N/A | `0x40000000` (Extra) |
| Full-Crouch | Control | N/A | `0x20000000` (Extra) | | Full-Crouch | Control | N/A | `0x20000000` (Extra) |
| Reload | R | X | X `(0x40)` | | Reload | R | X | X `(0x40)` |
@@ -102,43 +114,101 @@ Controls can be rebound in `pd.ini`. Default control scheme is as follows:
### Windows ### Windows
1. Install [MSYS2](https://www.msys2.org). 1. Install [MSYS2](https://www.msys2.org).
2. Open the `MINGW32` prompt. (**NOTE:** _not_ the `MSYS` prompt or the `MINGW64` prompt) 2. Open the `MINGW64` prompt if building for x86_64, or the `MINGW32` prompt if building for i686. (**NOTE:** _do not_ use the `MSYS` prompt)
3. Install dependencies: 3. Install dependencies:
`pacman -S mingw-w64-i686-toolchain mingw-w64-i686-SDL2 mingw-w64-i686-zlib make git` `pacman -S mingw-w64-x86_64-toolchain mingw-w64-x86_64-SDL2 mingw-w64-x86_64-zlib mingw-w64-x86_64-cmake mingw-w64-x86_64-python3 mingw-w64-i686-toolchain mingw-w64-i686-SDL2 mingw-w64-i686-zlib mingw-w64-i686-cmake mingw-w64-i686-python3 make git`
4. Get the source code: 4. Get the source code:
`git clone -b port-net --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark` `git clone --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark`
5. Run `make -f Makefile.port`. 5. Run `cmake -G"Unix Makefiles" -Bbuild .`.
* Add ` ROMID=pal-final` or ` ROMID=jpn-final` at the end of the command if you want to build a PAL or JPN executable respectively. * Add ` -DROMID=pal-final` or ` -DROMID=jpn-final` at the end of the command if you want to build a PAL or JPN executable respectively.\
6. The resulting executable will be at `build/ntsc-final-port/pd.exe`. 6. Run `cmake --build build -j4 -- -O`.
7. If you don't know where you downloaded the source to, you can run `explorer .` to open the current directory. 7. The resulting executable will be at `build/pd.x86_64.exe` (or at `build/pd.i686.exe` if building for i686).
8. If you don't know where you downloaded the source to, you can run `explorer .` to open the current directory.
### Linux ### Linux
1. Ensure you have gcc, g++ (version 10.0+) and 32-bit versions of SDL2 (version 2.0.12+), libGL and ZLib installed on your system. 1. Ensure you have gcc, g++ (version 10.0+), make, cmake, git, python3 and SDL2 (version 2.0.12+), libGL and ZLib installed on your system.
* On a 64-bit system you also need to have `gcc-multilib` and `g++-multilib` (or your distro's analogues) installed. * If you wish to crosscompile, you will also need to have libraries and compilers for the target platform installed, e.g. `gcc-multilib` and `g++-multilib` for x86_64 -> i686 crosscompilation.
2. Get the source code: 2. Get the source code:
`git clone -b port-net --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark` `git clone --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark`
3. Run the following command: 3. Run the following command:
* On a 64-bit system: ```make -f Makefile.port TARGET_PLATFORM=i686-linux``` * ```cmake -G"Unix Makefiles" -Bbuild .```
* On a 32-bit system: ```make -f Makefile.port``` * Add ` -DROMID=pal-final` or ` -DROMID=jpn-final` at the end of the command if you want to build a PAL or JPN executable respectively.
* Add ` ROMID=pal-final` or ` ROMID=jpn-final` at the end of the command if you want to build a PAL or JPN executable respectively. * Add ` -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32` at the end of the command if you want to crosscompile from x86_64 to x86.
4. The resulting executable will be at `build/ntsc-final-port/pd.exe`. 4. Run `cmake --build build -j4`.
5. The resulting executable will be at `build/pd.<arch>` (for example `build/pd.x86_64`).
Currently only `i686-linux` and `i686-windows` are supported, using `gcc -m32` and `i686-w64-mingw32-gcc` as compilers, respectively. ### MacOS
Alternate compilers can be specified by passing `TOOLCHAIN=i686-whatever-` as a command line argument.
You can build an executable with PAL or JPN ROM support by adding `ROMID=pal-final` or `ROMID=jpn-final` to the `make` command. 1. Set up Homebrew.
You will need to provide a `jpn-final` or `pal-final` ROM to run those, named `pd.jpn-final.z64` or `pd.pal-final.z64`. 2. Install dependencies:
* Execute command: `brew install cmake gcc python3 zlib git`
3. Install SDL2:
* Execute commands:
```
wget http://libsdl.org/release/SDL2-2.30.9.dmg -O SDL2.dmg
hdiutil mount SDL2.dmg
sudo cp -vr /Volumes/SDL2/SDL2.framework /Library/Frameworks
hdiutil detach /Volumes/SDL2
```
* This installs SDL2 system-wide and this is how the automatic builds are done. The game will also look for it in the executable path, so you could
download it locally instead.
4. Get the source code:
`git clone --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark`
5. Configure:
* Execute command: `cmake -G"Unix Makefiles" -Bbuild -DCMAKE_OSX_ARCHITECTURES=x86_64 .`
* Replace `x86_64` with `arm64` if building for an ARM64 Mac.
* Add ` -DROMID=pal-final` or ` -DROMID=jpn-final` at the end of the command if you want to build a PAL or JPN executable respectively.
6. Build:
* Execute command: `cmake --build build --target pd -j4 --clean-first`
7. The resulting executable will be at `build/pd.<arch>` (for example `build/pd.x86_64`).
* You might need to execute `chmod +x build/pd.x86-64` before you can run it.
It might be possible to build a 32-bit ARM executable, but this has not been tested. ### Nintendo Switch
1. Set up the [devkitA64 environment](https://devkitpro.org/wiki/Getting_Started).
* On Windows you can do it under MSYS2 or WSL, usually MSYS2 is recommended.
* If using MSYS2, make sure to use the **MSYS2** shell, **not** MINGW32 or MINGW64.
2. Install host dependencies:
* On MSYS2: execute command `pacman -Syuu && pacman -S git make cmake python3`
* On Linux: use your package manager as normal to install the above dependencies.
3. Install Switch toolchain and dependencies:
* Execute commands:
```
dkp-pacman -Syuu
dkp-pacman -S devkitA64 libnx switch-zlib switch-sdl2 switch-cmake dkp-toolchain-vars
```
* If in MSYS2 or `dkp-pacman` doesn't work, replace it with just `pacman`.
4. Get the source code:
`git clone --recursive https://github.com/fgsfdsfgs/perfect_dark.git && cd perfect_dark`
5. Ensure devkitA64 environment variables are set:
* Execute command: `source /opt/devkitpro/switchvars.sh`
* If your `$DEVKITPRO` path is different, substitute that instead or set the variables manually.
6. Configure:
* Execute command: `aarch64-none-elf-cmake -G"Unix Makefiles" -Bbuild .`
* Add ` -DROMID=pal-final` or ` -DROMID=jpn-final` at the end of the command if you want to build a PAL or JPN executable respectively.
7. Build:
* Execute command: `make -C build -j4`
8. The resulting executable will be at `build/pd.arm64.nro`.
### Notes
Alternate compilers or toolchains can be specified by passing `-DCMAKE_TOOLCHAIN_FILE=whatever` as normal. The port does not build with Visual Studio.
You will need to provide a `jpn-final` or `pal-final` ROM to run executables built for those regions, named `pd.jpn-final.z64` or `pd.pal-final.z64`.
It might be possible to build and run the game on platforms that are not specified in the supported platforms list (e.g. Linux on armv7), but this has not been tested.
## Credits ## Credits
* the original [decompilation project](https://github.com/n64decomp/perfect_dark) authors; * the original [decompilation project](https://github.com/n64decomp/perfect_dark) authors;
* Ryan Dwyer for the above, additional help, and `pd-extract`;
* doomhack for the only other publicly available [PD porting effort](https://github.com/doomhack/perfect_dark) I could find; * doomhack for the only other publicly available [PD porting effort](https://github.com/doomhack/perfect_dark) I could find;
* [sm64-port](https://github.com/sm64-port/sm64-port) authors for the audio mixer and some other changes; * [sm64-port](https://github.com/sm64-port/sm64-port) authors for the audio mixer and some other changes;
* [Ship of Harkinian team](https://github.com/Kenix3/libultraship/tree/main/src/graphic/Fast3D), Emill and MaikelChan for the libultraship version of fast3d that this port uses; * [Ship of Harkinian team](https://github.com/Kenix3/libultraship/tree/main/src/fast), Emill and MaikelChan for the libultraship version of fast3d that this port uses;
* lieff for [minimp3](https://github.com/lieff/minimp3); * lieff for [minimp3](https://github.com/lieff/minimp3);
* Mouse Injector and 1964GEPD authors for some of the 60FPS- and mouselook-related fixes; * Mouse Injector and 1964GEPD authors for some of the 60FPS- and mouselook-related fixes;
* Raf for the 64-bit port;
* NicNamSam for the icon;
* everyone who has submitted pull requests and issues to this repository and tested the port; * everyone who has submitted pull requests and issues to this repository and tested the port;
* probably more I'm forgetting. * probably more I'm forgetting.
+27
View File
@@ -0,0 +1,27 @@
# execute a header generator (execcmd) for every json file in jsonpath, collect headers in headerlist
# note that this reads ROMID
macro(generate_asset_headers jsonpath execcmd extraarg headerlist)
set(TMP_JSON "")
if (${jsonpath} MATCHES "\.json")
# is a json file
list(APPEND TMP_JSON "${CMAKE_SOURCE_DIR}/${ASSET_DIR}/${jsonpath}")
else()
# is a directory
file(GLOB TMP_JSON "${CMAKE_SOURCE_DIR}/${ASSET_DIR}/${jsonpath}*.json")
endif()
foreach(JSON ${TMP_JSON})
unset(HEADERNAME)
string(REPLACE ".json" ".h" HEADERNAME ${JSON})
string(REPLACE "${CMAKE_SOURCE_DIR}/${ASSET_DIR}" "${CMAKE_BINARY_DIR}/${GENERATED_DIR}" HEADERNAME ${HEADERNAME})
add_custom_command(
OUTPUT ${HEADERNAME}
DEPENDS ${JSON}
COMMAND ${execcmd} ${JSON} ${extraarg} --headers-only --romid=${ROMID}
)
list(APPEND ${headerlist} "${HEADERNAME}")
endforeach()
unset(TMP_JSON)
endmacro()
+172
View File
@@ -0,0 +1,172 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
# Locate SDL2 library
# This module defines
# SDL2_LIBRARY, the name of the library to link against
# SDL2_FOUND, if false, do not try to link to SDL2
# SDL2_INCLUDE_DIR, where to find SDL.h
#
# This module responds to the the flag:
# SDL2_BUILDING_LIBRARY
# If this is defined, then no SDL2_main will be linked in because
# only applications need main().
# Otherwise, it is assumed you are building an application and this
# module will attempt to locate and set the the proper link flags
# as part of the returned SDL2_LIBRARY variable.
#
# Don't forget to include SDL2main.h and SDL2main.m your project for the
# OS X framework based version. (Other versions link to -lSDL2main which
# this module will try to find on your behalf.) Also for OS X, this
# module will automatically add the -framework Cocoa on your behalf.
#
#
# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration
# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library
# (SDL2.dll, libsdl2.so, SDL2.framework, etc).
# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again.
# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value
# as appropriate. These values are used to generate the final SDL2_LIBRARY
# variable, but when these values are unset, SDL2_LIBRARY does not get created.
#
#
# $SDL2DIR is an environment variable that would
# correspond to the ./configure --prefix=$SDL2DIR
# used in building SDL2.
# l.e.galup 9-20-02
#
# Modified by Eric Wing.
# Added code to assist with automated building by using environmental variables
# and providing a more controlled/consistent search behavior.
# Added new modifications to recognize OS X frameworks and
# additional Unix paths (FreeBSD, etc).
# Also corrected the header search path to follow "proper" SDL2 guidelines.
# Added a search for SDL2main which is needed by some platforms.
# Added a search for threads which is needed by some platforms.
# Added needed compile switches for MinGW.
#
# On OSX, this will prefer the Framework version (if found) over others.
# People will have to manually change the cache values of
# SDL2_LIBRARY to override this selection or set the CMake environment
# CMAKE_INCLUDE_PATH to modify the search paths.
#
# Note that the header path has changed from SDL2/SDL.h to just SDL.h
# This needed to change because "proper" SDL2 convention
# is #include "SDL.h", not <SDL2/SDL.h>. This is done for portability
# reasons because not all systems place things in SDL2/ (see FreeBSD).
#
# Ported by Johnny Patterson. This is a literal port for SDL2 of the FindSDL.cmake
# module with the minor edit of changing "SDL" to "SDL2" where necessary. This
# was not created for redistribution, and exists temporarily pending official
# SDL2 CMake modules.
FIND_PATH(SDL2_INCLUDE_DIR SDL.h
HINTS
$ENV{SDL2DIR}
PATH_SUFFIXES include/SDL2 include
PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local/include/SDL2
/usr/include/SDL2
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt
/boot/system/develop/headers/SDL2 #Hiaku OS
)
#MESSAGE("SDL2_INCLUDE_DIR is ${SDL2_INCLUDE_DIR}")
FIND_LIBRARY(SDL2_LIBRARY_TEMP
NAMES SDL2
HINTS
$ENV{SDL2DIR}
PATH_SUFFIXES lib64 lib
PATHS
/sw
/opt/local
/opt/csw
/opt
/system/lib #Hiaku OS
)
#MESSAGE("SDL2_LIBRARY_TEMP is ${SDL2_LIBRARY_TEMP}")
IF(NOT SDL2_BUILDING_LIBRARY)
IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
# Non-OS X framework versions expect you to also dynamically link to
# SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms
# seem to provide SDL2main for compatibility even though they don't
# necessarily need it.
FIND_LIBRARY(SDL2MAIN_LIBRARY
NAMES SDL2main
HINTS
$ENV{SDL2DIR}
PATH_SUFFIXES lib64 lib
PATHS
/sw
/opt/local
/opt/csw
/opt
)
ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
ENDIF(NOT SDL2_BUILDING_LIBRARY)
# SDL2 may require threads on your system.
# The Apple build may not need an explicit flag because one of the
# frameworks may already provide it.
# But for non-OSX systems, I will use the CMake Threads package.
IF(NOT APPLE)
FIND_PACKAGE(Threads)
ENDIF(NOT APPLE)
# MinGW needs an additional library, mwindows
# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows
# (Actually on second look, I think it only needs one of the m* libraries.)
IF(MINGW)
SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW")
ENDIF(MINGW)
SET(SDL2_FOUND "NO")
IF(SDL2_LIBRARY_TEMP)
# For SDL2main
IF(NOT SDL2_BUILDING_LIBRARY)
IF(SDL2MAIN_LIBRARY)
SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP})
ENDIF(SDL2MAIN_LIBRARY)
ENDIF(NOT SDL2_BUILDING_LIBRARY)
# For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa.
# CMake doesn't display the -framework Cocoa string in the UI even
# though it actually is there if I modify a pre-used variable.
# I think it has something to do with the CACHE STRING.
# So I use a temporary variable until the end so I can set the
# "real" variable in one-shot.
IF(APPLE)
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa")
ENDIF(APPLE)
# For threads, as mentioned Apple doesn't need this.
# In fact, there seems to be a problem if I used the Threads package
# and try using this line, so I'm just skipping it entirely for OS X.
IF(NOT APPLE)
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT})
ENDIF(NOT APPLE)
# For MinGW library
IF(MINGW)
SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP})
ENDIF(MINGW)
# Set the final string here so the GUI reflects the final state.
SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found")
# Set the temp variable to INTERNAL so it is not seen in the CMake GUI
SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "")
SET(SDL2_FOUND "YES")
ENDIF(SDL2_LIBRARY_TEMP)
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2
REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR)
+165
View File
@@ -0,0 +1,165 @@
# Copyright (c) 2012 Petroules Corporation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation and/or
# other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
# OF SUCH DAMAGE.
# Based on the Qt 5 processor detection code, so should be very accurate
# https://qt.gitorious.org/qt/qtbase/blobs/master/src/corelib/global/qprocessordetection.h
# Currently handles arm (v5, v6, v7), x86 (32/64), ia64, and ppc (32/64)
# Regarding POWER/PowerPC, just as is noted in the Qt source,
# "There are many more known variants/revisions that we do not handle/detect."
set(archdetect_c_code "
#if defined(__arm__) || defined(__TARGET_ARCH_ARM) || defined(_M_ARM64) || defined (__aarch64__)
#if defined(__ARM_ARCH_7__) \\
|| defined(__ARM_ARCH_7A__) \\
|| defined(__ARM_ARCH_7R__) \\
|| defined(__ARM_ARCH_7M__) \\
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 7)
#error cmake_ARCH armv7
#elif defined(__ARM_ARCH_6__) \\
|| defined(__ARM_ARCH_6J__) \\
|| defined(__ARM_ARCH_6T2__) \\
|| defined(__ARM_ARCH_6Z__) \\
|| defined(__ARM_ARCH_6K__) \\
|| defined(__ARM_ARCH_6ZK__) \\
|| defined(__ARM_ARCH_6M__) \\
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 6)
#error cmake_ARCH armv6
#elif defined(__ARM_ARCH_5TEJ__) \\
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 5)
#error cmake_ARCH armv5
#elif defined(_M_ARM64) || defined (__aarch64__)
#error cmake_ARCH arm64
#else
#error cmake_ARCH arm
#endif
#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
#error cmake_ARCH i386
#elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64)
#error cmake_ARCH x86_64
#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
#error cmake_ARCH ia64
#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \\
|| defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \\
|| defined(_M_MPPC) || defined(_M_PPC)
#if defined(__ppc64__) || defined(__powerpc64__) || defined(__64BIT__)
#error cmake_ARCH ppc64
#else
#error cmake_ARCH ppc
#endif
#endif
#error cmake_ARCH unknown
")
# Set ppc_support to TRUE before including this file or ppc and ppc64
# will be treated as invalid architectures since they are no longer supported by Apple
function(target_architecture output_var)
if(APPLE AND CMAKE_OSX_ARCHITECTURES)
# On OS X we use CMAKE_OSX_ARCHITECTURES *if* it was set
# First let's normalize the order of the values
# Note that it's not possible to compile PowerPC applications if you are using
# the OS X SDK version 10.6 or later - you'll need 10.4/10.5 for that, so we
# disable it by default
# See this page for more information:
# http://stackoverflow.com/questions/5333490/how-can-we-restore-ppc-ppc64-as-well-as-full-10-4-10-5-sdk-support-to-xcode-4
# Architecture defaults to i386 or ppc on OS X 10.5 and earlier, depending on the CPU type detected at runtime.
# On OS X 10.6+ the default is x86_64 if the CPU supports it, i386 otherwise.
foreach(osx_arch ${CMAKE_OSX_ARCHITECTURES})
if("${osx_arch}" STREQUAL "ppc" AND ppc_support)
set(osx_arch_ppc TRUE)
elseif("${osx_arch}" STREQUAL "i386")
set(osx_arch_i386 TRUE)
elseif("${osx_arch}" STREQUAL "x86_64")
set(osx_arch_x86_64 TRUE)
elseif("${osx_arch}" STREQUAL "ppc64" AND ppc_support)
set(osx_arch_ppc64 TRUE)
elseif("${osx_arch}" STREQUAL "arm64")
set(osx_arch_arm64 TRUE)
else()
message(FATAL_ERROR "Invalid OS X arch name: ${osx_arch}")
endif()
endforeach()
# Now add all the architectures in our normalized order
if(osx_arch_ppc)
list(APPEND ARCH ppc)
endif()
if(osx_arch_i386)
list(APPEND ARCH i386)
endif()
if(osx_arch_x86_64)
list(APPEND ARCH x86_64)
endif()
if(osx_arch_ppc64)
list(APPEND ARCH ppc64)
endif()
if(osx_arch_arm64)
list(APPEND ARCH arm64)
endif()
else()
file(WRITE "${CMAKE_BINARY_DIR}/arch.c" "${archdetect_c_code}")
enable_language(C)
# Detect the architecture in a rather creative way...
# This compiles a small C program which is a series of ifdefs that selects a
# particular #error preprocessor directive whose message string contains the
# target architecture. The program will always fail to compile (both because
# file is not a valid C program, and obviously because of the presence of the
# #error preprocessor directives... but by exploiting the preprocessor in this
# way, we can detect the correct target architecture even when cross-compiling,
# since the program itself never needs to be run (only the compiler/preprocessor)
try_run(
run_result_unused
compile_result_unused
"${CMAKE_BINARY_DIR}"
"${CMAKE_BINARY_DIR}/arch.c"
COMPILE_OUTPUT_VARIABLE ARCH
CMAKE_FLAGS CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES}
)
# Parse the architecture name from the compiler output
string(REGEX MATCH "cmake_ARCH ([a-zA-Z0-9_]+)" ARCH "${ARCH}")
# Get rid of the value marker leaving just the architecture name
string(REPLACE "cmake_ARCH " "" ARCH "${ARCH}")
# If we are compiling with an unknown architecture this variable should
# already be set to "unknown" but in the case that it's empty (i.e. due
# to a typo in the code), then set it to unknown
if (NOT ARCH)
set(ARCH unknown)
endif()
endif()
set(${output_var} "${ARCH}" PARENT_SCOPE)
endfunction()
+9
View File
@@ -0,0 +1,9 @@
[Desktop Entry]
Name=Perfect Dark
Comment=Modern source port of Perfect Dark
Exec=io.github.perfect_dark_pc_port.perfect_dark.sh
Icon=io.github.perfect_dark_pc_port.perfect_dark
Terminal=false
Type=Application
Categories=Game;ActionGame;
StartupNotify=false
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>io.github.perfect_dark_pc_port.perfect_dark</id>
<name>Perfect Dark</name>
<developer id="io.github.perfect_dark_pc_port.perfect_dark">
<name>Perfect Dark Contributors</name>
<url>https://github.com/fgsfdsfgs/perfect_dark/graphs/contributors</url>
</developer>
<launchable type="desktop-id">io.github.perfect_dark_pc_port.perfect_dark.desktop</launchable>
<summary>Modern cross-platform port of Perfect Dark</summary>
<metadata_license>CC0-1.0</metadata_license>
<project_license>MIT</project_license>
<url type="homepage">https://github.com/fgsfdsfgs/perfect_dark/</url>
<description>
<p>This is a port of Ryan Dywer's decompilation of classic N64 shooter Perfect Dark to modern systems.</p>
</description>
<!--
<screenshots>
<screenshot type="default">
<image type="source"></image>
<caption>Screenshot</caption>
</screenshot>
<screenshots>
-->
<categories>
<category>Game</category>
<category>ActionGame</category>
<category>Shooter</category>
</categories>
<keywords>
<keyword>n64</keyword>
<keyword>scifi</keyword>
<keyword>cyberpunk</keyword>
<keyword>retro</keyword>
<keyword>sourceport</keyword>
<keyword>port</keyword>
</keywords>
<releases>
<release version="latest" date="2024-05-14"/>
</releases>
<content_rating type="oars-1.1">
<content_attribute id="violence-realistic">moderate</content_attribute>
<content_attribute id="violence-bloodshed">mild</content_attribute>
</content_rating>
<update_contact>https://github.com/fgsfdsfgs/perfect_dark/</update_contact>
</component>
Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

@@ -0,0 +1,39 @@
#!/bin/sh
# Create user data directories if necessary
userdirs=( roms saves mods )
for path in "${userdirs[@]}"; do
if [ ! -d "${XDG_DATA_HOME}/${path}" ]; then
mkdir -p "${XDG_DATA_HOME}/${path}"
fi
done
# Default to pd as executable but switch to jpn/pal if the NTSC rom
# is missing but JPN/PAL are present.
# TODO: Other arch
executable="pd.x86_64"
if [ -f ${XDG_DATA_HOME}/roms/pd.ntsc-final.z64 ] | \
[ -f ${XDG_DATA_HOME}/roms/pd.ntsc-1.0.z64 ]; then
executable="pd.x86_64"
elif [ -f ${XDG_DATA_HOME}/roms/pd.jpn-final.z64 ]; then
executable="pd.jpn.x86_64"
elif [ -f ${XDG_DATA_HOME}/roms/pd.pal-final.z64 ]; then
executable="pd.pal.x86_64"
fi
# If first parameter passed to this script is one of the pd executables,
# run that regardless of ROM auto-detection above and pass the remaining
# parameters to it; otherwise pass all arguments to the executable selected
# above
case $1 in
"pd."*)
executable=$1
params="${@:2}"
;;
*)
params="$@"
;;
esac
# Run game
$executable --basedir ${XDG_DATA_HOME}/roms --savedir ${XDG_DATA_HOME}/saves $params
@@ -0,0 +1,41 @@
app-id: io.github.perfect_dark_pc_port.perfect_dark
runtime: org.freedesktop.Platform
runtime-version: "25.08"
sdk: org.freedesktop.Sdk
command: io.github.perfect_dark_pc_port.perfect_dark.sh
finish-args:
- --device=all
- --share=ipc
- --socket=x11
# Audio
- --socket=pulseaudio
# Enable network for multiplayer
- --share=network
modules:
- name: perfect_dark
buildsystem: simple
sources:
- type: file
path: bin/pd.x86_64
- type: file
path: bin/pd.jpn.x86_64
- type: file
path: bin/pd.pal.x86_64
- type: file
path: io.github.perfect_dark_pc_port.perfect_dark.sh
- type: file
path: io.github.perfect_dark_pc_port.perfect_dark.png
- type: file
path: io.github.perfect_dark_pc_port.perfect_dark.metainfo.xml
- type: file
path: io.github.perfect_dark_pc_port.perfect_dark.desktop
build-commands: []
post-install:
# Install the binaries
- install -Dm 755 -t /app/bin/ pd.*
- install -Dm 755 ${FLATPAK_ID}.sh /app/bin/${FLATPAK_ID}.sh
- install -Dm 644 ${FLATPAK_ID}.desktop /app/share/applications/${FLATPAK_ID}.desktop
- install -Dm 644 ${FLATPAK_ID}.metainfo.xml /app/share/metainfo/${FLATPAK_ID}.metainfo.xml
- install -Dm 644 ${FLATPAK_ID}.png /app/share/icons/hicolor/256x256/apps/${FLATPAK_ID}.png
+2
View File
@@ -0,0 +1,2 @@
# Switch (SDL_GetPlatform is not changed in switch-sdl2)
000038f853776974636820436f6e7400,Switch Controller,a:b0,b:b1,back:b11,dpdown:b15,dpleft:b12,dpright:b14,dpup:b13,leftshoulder:b6,leftstick:b4,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Unknown (see SDL_platform.h),
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

+1
View File
@@ -0,0 +1 @@
id ICON icon.ico
-47
View File
@@ -1,47 +0,0 @@
## Experimental netplay branch
This branch contains a **highly experimental** implementation of network play.
Currently only Combat Sim is partially working with experimental 8 player support and really bad netcode.
Expect nothing to work right.
### Hosting
1. Forward the server port (`27100` by default, can be changed in `pd.ini`).
* You can also use something like ZeroTier or Hamachi if you can't port forward.
3. Choose `Network Game` -> `Host Game`, configure the player cap, press `Start Game`.
4. Configure Combat Sim as desired, but do not start it yet. Keep in mind:
* You can save and load the settings as normal.
* Your player will have the config of Combat Sim player 1.
5. Wait for everyone to join. You can use the console (press `~`) to chat in the meantime.
6. Hit Enter/Start. During the game no more players will be able to join.
7. After game is over, you will be kicked back to Combat Sim settings, at which point people can join again and the process repeats from step 3.
### Joining
1. Your player will have the config of Combat Sim player 1, so set that up beforehand in the Combat Sim menu.
2. Choose `Network Game` -> `Join Game`, enter the address (and port if it's not 27100), press `Start Game`.
3. If the message says `Waiting for host`, wait until the host configures the game. You can use the console (press `~`) to chat in the meantime or `ESC` to disconnect.
4. The game will start automatically.
5. After the game is over, press Enter/Start on the stats screen and you will be kicked back to the `Waiting for host` screen, at which point the process repeats from step 3.
### Misc
* Everyone has to have the same ROM. The game only compares the file name, but different regions in one game will definitely break everything.
* Press `~` to bring up the console, press `F9` for network stats.
* You can chat at any time during a net game by entering messages in the console and hitting Enter.
* Server port and other network settings can be configured in `pd.ini`.
* For a 4+ player game I would recommend changing `Net.Server.UpdateFrames` to `2` in `pd.ini` on the server to lower the bandwidth usage.
* You can paste stuff into the `Enter Address` prompt by hitting `CTRL+V`.
* Expect nothing to work right.
### Known issues
* Clients can't throw laptop guns.
* Clients see rocket rotation incorrectly.
* Clients can't use Slayer fly-by-wire rockets and they will not correctly sync if the server uses them.
* Clients can't use the alt fire mode on the FarSight and probably a couple other guns.
* Cloaking device is not synced.
* Most likely only Combat works properly.
* Sims don't work in netgames.
* Bandwidth consumption on the server is pretty large on the default settings, especially with 8 players.
+1
View File
@@ -22,6 +22,7 @@
#define __R4300_H__ #define __R4300_H__
#include <PR/ultratypes.h> #include <PR/ultratypes.h>
#include "platform.h"
/* /*
* Segment base addresses and sizes * Segment base addresses and sizes
+62 -30
View File
@@ -22,6 +22,12 @@
#include <PR/ultratypes.h> #include <PR/ultratypes.h>
#include "gbiex.h" #include "gbiex.h"
#include <stdint.h>
#ifndef PLATFORM_N64
#include "platform.h"
#endif
/* /*
* To use the F3DEX ucodes, define F3DEX_GBI before include this file. * To use the F3DEX ucodes, define F3DEX_GBI before include this file.
@@ -594,10 +600,10 @@
#define G_BL_0 3 #define G_BL_0 3
#define GBL_c1(m1a, m1b, m2a, m2b) \ #define GBL_c1(m1a, m1b, m2a, m2b) \
(m1a) << 30 | (m1b) << 26 | (m2a) << 22 | (m2b) << 18 (u32)(m1a) << 30 | (u32)(m1b) << 26 | (u32)(m2a) << 22 | (u32)(m2b) << 18
#define GBL_c2(m1a, m1b, m2a, m2b) \ #define GBL_c2(m1a, m1b, m2a, m2b) \
(m1a) << 28 | (m1b) << 24 | (m2a) << 20 | (m2b) << 16 (u32)(m1a) << 28 | (u32)(m1b) << 24 | (u32)(m2a) << 20 | (u32)(m2b) << 16
#define RM_AA_ZB_OPA_SURF(clk) \ #define RM_AA_ZB_OPA_SURF(clk) \
AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \
@@ -1053,7 +1059,7 @@ typedef struct {
// 4x4 float matrix // 4x4 float matrix
typedef float Mtx_t[4][4]; typedef float Mtx_t[4][4];
#else #else
typedef long Mtx_t[4][4]; typedef int32_t Mtx_t[4][4];
#endif #endif
typedef union { typedef union {
@@ -1306,6 +1312,14 @@ typedef union {
/* /*
* Graphics DMA Packet * Graphics DMA Packet
*/ */
#ifdef PLATFORM_64BIT
typedef struct {
intptr_t par : 24;
intptr_t cmd : 8;
intptr_t len : 32;
uintptr_t addr;
} Gdma;
#else
typedef struct { typedef struct {
#ifdef PLATFORM_BIG_ENDIAN #ifdef PLATFORM_BIG_ENDIAN
int cmd:8; int cmd:8;
@@ -1319,6 +1333,7 @@ typedef struct {
unsigned int addr; unsigned int addr;
#endif #endif
} Gdma; } Gdma;
#endif
/* /*
* Graphics Immediate Mode Packet types * Graphics Immediate Mode Packet types
@@ -1357,6 +1372,9 @@ typedef struct {
unsigned char z4:4; unsigned char z4:4;
unsigned char pad:8; unsigned char pad:8;
unsigned char cmd:8; unsigned char cmd:8;
#ifdef PLATFORM_64BIT
unsigned char pad2[4];
#endif
unsigned char x1:4; unsigned char x1:4;
unsigned char y1:4; unsigned char y1:4;
unsigned char x2:4; unsigned char x2:4;
@@ -1365,6 +1383,9 @@ typedef struct {
unsigned char y3:4; unsigned char y3:4;
unsigned char x4:4; unsigned char x4:4;
unsigned char y4:4; unsigned char y4:4;
#ifdef PLATFORM_64BIT
unsigned char pad3[4];
#endif
#endif #endif
} Gtri4; } Gtri4;
@@ -1538,8 +1559,8 @@ typedef struct {
* Generic Gfx Packet * Generic Gfx Packet
*/ */
typedef struct { typedef struct {
unsigned int w0; uintptr_t w0;
unsigned int w1; uintptr_t w1;
} Gwords; } Gwords;
// xxxxxxxx 11223344 44555566 66666777 // xxxxxxxx 11223344 44555566 66666777
@@ -1596,7 +1617,11 @@ typedef struct {
*/ */
typedef union { typedef union {
Gwords words; Gwords words;
#ifdef PLATFORM_64BIT
u8 bytes[16];
#else
u8 bytes[8]; u8 bytes[8];
#endif
Gdma dma; Gdma dma;
Gvtx vtx; Gvtx vtx;
Gtri tri; Gtri tri;
@@ -1619,12 +1644,19 @@ typedef union {
Gloadtlut loadtlut; Gloadtlut loadtlut;
#endif #endif
GunkC0 unkc0; GunkC0 unkc0;
#ifdef PLATFORM_64BIT
long long int force_structure_alignment[2];
#else
long long int force_structure_alignment; long long int force_structure_alignment;
#endif
} Gfx; } Gfx;
#ifdef PLATFORM_BIG_ENDIAN #ifdef PLATFORM_BIG_ENDIAN
#define GFX_W0_BYTE(i) (i) #define GFX_W0_BYTE(i) (i)
#define GFX_W1_BYTE(i) (4 + (i)) #define GFX_W1_BYTE(i) (4 + (i))
#elif PLATFORM_64BIT
#define GFX_W0_BYTE(i) (3 - (i))
#define GFX_W1_BYTE(i) (11 - (i))
#else #else
#define GFX_W0_BYTE(i) (3 - (i)) #define GFX_W0_BYTE(i) (3 - (i))
#define GFX_W1_BYTE(i) (7 - (i)) #define GFX_W1_BYTE(i) (7 - (i))
@@ -1642,12 +1674,12 @@ typedef union {
Gfx *_g = (Gfx *)(pkt); \ Gfx *_g = (Gfx *)(pkt); \
\ \
_g->words.w0 = _SHIFTL((c), 24, 8) | _SHIFTL((l), 0, 24); \ _g->words.w0 = _SHIFTL((c), 24, 8) | _SHIFTL((l), 0, 24); \
_g->words.w1 = (unsigned int)(s); \ _g->words.w1 = (uintptr_t)(s); \
} }
#define gsDma0p(c, s, l) \ #define gsDma0p(c, s, l) \
{ \ { \
_SHIFTL((c), 24, 8) | _SHIFTL((l), 0, 24), (unsigned int)(s) \ _SHIFTL((c), 24, 8) | _SHIFTL((l), 0, 24), (uintptr_t)(s) \
} }
#define gDma1p(pkt, c, s, l, p) \ #define gDma1p(pkt, c, s, l, p) \
@@ -1656,14 +1688,14 @@ typedef union {
\ \
_g->words.w0 = (_SHIFTL((c), 24, 8) | _SHIFTL((p), 16, 8) | \ _g->words.w0 = (_SHIFTL((c), 24, 8) | _SHIFTL((p), 16, 8) | \
_SHIFTL((l), 0, 16)); \ _SHIFTL((l), 0, 16)); \
_g->words.w1 = (unsigned int)(s); \ _g->words.w1 = (uintptr_t)(s); \
} }
#define gsDma1p(c, s, l, p) \ #define gsDma1p(c, s, l, p) \
{ \ { \
(_SHIFTL((c), 24, 8) | _SHIFTL((p), 16, 8) | \ (_SHIFTL((c), 24, 8) | _SHIFTL((p), 16, 8) | \
_SHIFTL((l), 0, 16)), \ _SHIFTL((l), 0, 16)), \
(unsigned int)(s) \ (uintptr_t)(s) \
} }
#define gDma2p(pkt, c, adrs, len, idx, ofs) \ #define gDma2p(pkt, c, adrs, len, idx, ofs) \
@@ -1671,14 +1703,14 @@ typedef union {
Gfx *_g = (Gfx *)(pkt); \ Gfx *_g = (Gfx *)(pkt); \
_g->words.w0 = (_SHIFTL((c),24,8)|_SHIFTL(((len)-1)/8,19,5)| \ _g->words.w0 = (_SHIFTL((c),24,8)|_SHIFTL(((len)-1)/8,19,5)| \
_SHIFTL((ofs)/8,8,8)|_SHIFTL((idx),0,8)); \ _SHIFTL((ofs)/8,8,8)|_SHIFTL((idx),0,8)); \
_g->words.w1 = (unsigned int)(adrs); \ _g->words.w1 = (uintptr_t)(adrs); \
} }
#define gsDma2p(c, adrs, len, idx, ofs) \ #define gsDma2p(c, adrs, len, idx, ofs) \
{ \ { \
(_SHIFTL((c),24,8)|_SHIFTL(((len)-1)/8,19,5)| \ (_SHIFTL((c),24,8)|_SHIFTL(((len)-1)/8,19,5)| \
_SHIFTL((ofs)/8,8,8)|_SHIFTL((idx),0,8)), \ _SHIFTL((ofs)/8,8,8)|_SHIFTL((idx),0,8)), \
(unsigned int)(adrs) \ (uintptr_t)(adrs) \
} }
#define gSPNoOp(pkt) gDma0p(pkt, G_SPNOOP, 0, 0) #define gSPNoOp(pkt) gDma0p(pkt, G_SPNOOP, 0, 0)
@@ -1727,12 +1759,12 @@ typedef union {
Gfx *_g = (Gfx *)(pkt); \ Gfx *_g = (Gfx *)(pkt); \
\ \
_g->words.w0 = _SHIFTL((c), 24, 8); \ _g->words.w0 = _SHIFTL((c), 24, 8); \
_g->words.w1 = (unsigned int)(p0); \ _g->words.w1 = (uintptr_t)(p0); \
} }
#define gsImmp1(c, p0) \ #define gsImmp1(c, p0) \
{ \ { \
_SHIFTL((c), 24, 8), (unsigned int)(p0) \ _SHIFTL((c), 24, 8), (uintptr_t)(p0) \
} }
#define gImmp2(pkt, c, p0, p1) \ #define gImmp2(pkt, c, p0, p1) \
@@ -1769,13 +1801,13 @@ typedef union {
\ \
_g->words.w0 = (_SHIFTL((c), 24, 8) | _SHIFTL((p0), 8, 16) | \ _g->words.w0 = (_SHIFTL((c), 24, 8) | _SHIFTL((p0), 8, 16) | \
_SHIFTL((p1), 0, 8)); \ _SHIFTL((p1), 0, 8)); \
_g->words.w1 = (unsigned int) (dat); \ _g->words.w1 = (uintptr_t) (dat); \
} }
#define gsImmp21(c, p0, p1, dat) \ #define gsImmp21(c, p0, p1, dat) \
{ \ { \
_SHIFTL((c), 24, 8) | _SHIFTL((p0), 8, 16) | _SHIFTL((p1), 0, 8), \ _SHIFTL((c), 24, 8) | _SHIFTL((p0), 8, 16) | _SHIFTL((p1), 0, 8), \
(unsigned int) (dat) \ (uintptr_t) (dat) \
} }
#define gMoveWd(pkt, index, offset, data) \ #define gMoveWd(pkt, index, offset, data) \
@@ -1918,7 +1950,7 @@ typedef union {
\ \
_g->words.w0 = _SHIFTL(G_CULLDL, 24, 8) | \ _g->words.w0 = _SHIFTL(G_CULLDL, 24, 8) | \
((0x0f & (vstart))*40); \ ((0x0f & (vstart))*40); \
_g->words.w1 = (unsigned int)((0x0f & ((vend)+1))*40); \ _g->words.w1 = (uintptr_t)((0x0f & ((vend)+1))*40); \
} }
// Removed in PD // Removed in PD
@@ -2239,12 +2271,12 @@ typedef union {
Gfx *_g = (Gfx *)(pkt); \ Gfx *_g = (Gfx *)(pkt); \
\ \
_g->words.w0 = _SHIFTL(G_SETGEOMETRYMODE, 24, 8); \ _g->words.w0 = _SHIFTL(G_SETGEOMETRYMODE, 24, 8); \
_g->words.w1 = (unsigned int)(word); \ _g->words.w1 = (uintptr_t)(word); \
} }
#define gsSPSetGeometryMode(word) \ #define gsSPSetGeometryMode(word) \
{ \ { \
_SHIFTL(G_SETGEOMETRYMODE, 24, 8), (unsigned int)(word) \ _SHIFTL(G_SETGEOMETRYMODE, 24, 8), (uintptr_t)(word) \
} }
#define gSPClearGeometryMode(pkt, word) \ #define gSPClearGeometryMode(pkt, word) \
@@ -2252,12 +2284,12 @@ typedef union {
Gfx *_g = (Gfx *)(pkt); \ Gfx *_g = (Gfx *)(pkt); \
\ \
_g->words.w0 = _SHIFTL(G_CLEARGEOMETRYMODE, 24, 8); \ _g->words.w0 = _SHIFTL(G_CLEARGEOMETRYMODE, 24, 8); \
_g->words.w1 = (unsigned int)(word); \ _g->words.w1 = (uintptr_t)(word); \
} }
#define gsSPClearGeometryMode(word) \ #define gsSPClearGeometryMode(word) \
{ \ { \
_SHIFTL(G_CLEARGEOMETRYMODE, 24, 8), (unsigned int)(word) \ _SHIFTL(G_CLEARGEOMETRYMODE, 24, 8), (uintptr_t)(word) \
} }
#define gSPSetOtherMode(pkt, cmd, sft, len, data) \ #define gSPSetOtherMode(pkt, cmd, sft, len, data) \
@@ -2266,13 +2298,13 @@ typedef union {
\ \
_g->words.w0 = (_SHIFTL(cmd, 24, 8) | _SHIFTL(sft, 8, 8) | \ _g->words.w0 = (_SHIFTL(cmd, 24, 8) | _SHIFTL(sft, 8, 8) | \
_SHIFTL(len, 0, 8)); \ _SHIFTL(len, 0, 8)); \
_g->words.w1 = (unsigned int)(data); \ _g->words.w1 = (uintptr_t)(data); \
} }
#define gsSPSetOtherMode(cmd, sft, len, data) \ #define gsSPSetOtherMode(cmd, sft, len, data) \
{ \ { \
_SHIFTL(cmd, 24, 8) | _SHIFTL(sft, 8, 8) | _SHIFTL(len, 0, 8), \ _SHIFTL(cmd, 24, 8) | _SHIFTL(sft, 8, 8) | _SHIFTL(len, 0, 8), \
(unsigned int)(data) \ (uintptr_t)(data) \
} }
/* /*
@@ -2323,14 +2355,14 @@ typedef union {
\ \
_g->words.w0 = _SHIFTL(cmd, 24, 8) | _SHIFTL(fmt, 21, 3) | \ _g->words.w0 = _SHIFTL(cmd, 24, 8) | _SHIFTL(fmt, 21, 3) | \
_SHIFTL(siz, 19, 2) | _SHIFTL((width)-1, 0, 12); \ _SHIFTL(siz, 19, 2) | _SHIFTL((width)-1, 0, 12); \
_g->words.w1 = (unsigned int)(i); \ _g->words.w1 = (uintptr_t)(i); \
} }
#define gsSetImage(cmd, fmt, siz, width, i) \ #define gsSetImage(cmd, fmt, siz, width, i) \
{ \ { \
_SHIFTL(cmd, 24, 8) | _SHIFTL(fmt, 21, 3) | \ _SHIFTL(cmd, 24, 8) | _SHIFTL(fmt, 21, 3) | \
_SHIFTL(siz, 19, 2) | _SHIFTL((width)-1, 0, 12), \ _SHIFTL(siz, 19, 2) | _SHIFTL((width)-1, 0, 12), \
(unsigned int)(i) \ (uintptr_t)(i) \
} }
#define gDPSetColorImage(pkt, f, s, w, i) gSetImage(pkt, G_SETCIMG, f, s, w, i) #define gDPSetColorImage(pkt, f, s, w, i) gSetImage(pkt, G_SETCIMG, f, s, w, i)
@@ -2356,13 +2388,13 @@ typedef union {
Gfx *_g = (Gfx *)(pkt); \ Gfx *_g = (Gfx *)(pkt); \
\ \
_g->words.w0 = _SHIFTL(G_SETCOMBINE, 24, 8) | _SHIFTL(muxs0, 0, 24); \ _g->words.w0 = _SHIFTL(G_SETCOMBINE, 24, 8) | _SHIFTL(muxs0, 0, 24); \
_g->words.w1 = (unsigned int)(muxs1); \ _g->words.w1 = (uintptr_t)(muxs1); \
} }
#define gsDPSetCombine(muxs0, muxs1) \ #define gsDPSetCombine(muxs0, muxs1) \
{ \ { \
_SHIFTL(G_SETCOMBINE, 24, 8) | _SHIFTL(muxs0, 0, 24), \ _SHIFTL(G_SETCOMBINE, 24, 8) | _SHIFTL(muxs0, 0, 24), \
(unsigned int)(muxs1) \ (uintptr_t)(muxs1) \
} }
#define GCCc0w0(saRGB0, mRGB0, saA0, mA0) \ #define GCCc0w0(saRGB0, mRGB0, saA0, mA0) \
@@ -2435,12 +2467,12 @@ typedef union {
Gfx *_g = (Gfx *)(pkt); \ Gfx *_g = (Gfx *)(pkt); \
\ \
_g->words.w0 = _SHIFTL(c, 24, 8); \ _g->words.w0 = _SHIFTL(c, 24, 8); \
_g->words.w1 = (unsigned int)(d); \ _g->words.w1 = (uintptr_t)(d); \
} }
#define gsDPSetColor(c, d) \ #define gsDPSetColor(c, d) \
{ \ { \
_SHIFTL(c, 24, 8), (unsigned int)(d) \ _SHIFTL(c, 24, 8), (uintptr_t)(d) \
} }
#define DPRGBColor(pkt, cmd, r, g, b, a) \ #define DPRGBColor(pkt, cmd, r, g, b, a) \
@@ -2521,13 +2553,13 @@ typedef union {
Gfx *_g = (Gfx *)(pkt); \ Gfx *_g = (Gfx *)(pkt); \
\ \
_g->words.w0 = _SHIFTL(G_RDPSETOTHERMODE,24,8)|_SHIFTL(mode0,0,24); \ _g->words.w0 = _SHIFTL(G_RDPSETOTHERMODE,24,8)|_SHIFTL(mode0,0,24); \
_g->words.w1 = (unsigned int)(mode1); \ _g->words.w1 = (uintptr_t)(mode1); \
} }
#define gsDPSetOtherMode(mode0, mode1) \ #define gsDPSetOtherMode(mode0, mode1) \
{ \ { \
_SHIFTL(G_RDPSETOTHERMODE,24,8)|_SHIFTL(mode0,0,24), \ _SHIFTL(G_RDPSETOTHERMODE,24,8)|_SHIFTL(mode0,0,24), \
(unsigned int)(mode1) \ (uintptr_t)(mode1) \
} }
/* /*
+1 -1
View File
@@ -35,7 +35,7 @@
#define OS_M_PI 3.14159265358979323846 #define OS_M_PI 3.14159265358979323846
#define M_DTOR (3.14159265358979323846/180.0) #define M_DTOR (3.14159265358979323846/180.0)
#define FTOFIX32(x) (long)((x) * (float)0x00010000) #define FTOFIX32(x) (int)((x) * (float)0x00010000)
#define FIX32TOF(x) ((float)(x) * (1.0f / (float)0x00010000)) #define FIX32TOF(x) ((float)(x) * (1.0f / (float)0x00010000))
#define FTOFRAC8(x) ((int) MIN(((x) * (128.0f)), 127.0f) & 0xff) #define FTOFRAC8(x) ((int) MIN(((x) * (128.0f)), 127.0f) & 0xff)
+12 -1
View File
@@ -28,6 +28,7 @@ extern "C" {
#include <PR/ultratypes.h> #include <PR/ultratypes.h>
#include <PR/mbi.h> #include <PR/mbi.h>
#include "platform.h"
struct var8009c340 { struct var8009c340 {
u8 surround; u8 surround;
@@ -256,7 +257,7 @@ typedef struct {
ALOscStop stopOsc; ALOscStop stopOsc;
ALSeqMarker *loopStart; ALSeqMarker *loopStart;
ALSeqMarker *loopEnd; ALSeqMarker *loopEnd;
s32 loopCount; /* -1 = loop forever, 0 = no loop */ intptr_t loopCount; /* -1 = loop forever, 0 = no loop */
u8 unk88; u8 unk88;
u8 unk89; u8 unk89;
} N_ALSeqPlayer; } N_ALSeqPlayer;
@@ -284,9 +285,19 @@ typedef struct {
ALOscInit initOsc; ALOscInit initOsc;
ALOscUpdate updateOsc; ALOscUpdate updateOsc;
ALOscStop stopOsc; ALOscStop stopOsc;
#ifdef PLATFORM_64BIT
s32 _pad1_;
f32 unk7c;
s32 _pad2_;
f32 unk80;
#else
f32 unk7c; f32 unk7c;
f32 unk80; f32 unk80;
#endif
void *queue; void *queue;
u8 unk88; u8 unk88;
u8 unk89; u8 unk89;
} N_ALCSPlayer; } N_ALCSPlayer;
+6
View File
@@ -31,10 +31,14 @@
#define _OS_LIBC_H_ #define _OS_LIBC_H_
#include "os_pfs.h" #include "os_pfs.h"
#include "platform.h"
#ifndef PLATFORM_N64 #ifndef PLATFORM_N64
#include <stdio.h> #include <stdio.h>
#endif #endif
#ifdef PLATFORM_OSX
#include <strings.h>
#endif
#ifdef _LANGUAGE_C_PLUS_PLUS #ifdef _LANGUAGE_C_PLUS_PLUS
extern "C" { extern "C" {
@@ -84,9 +88,11 @@ extern "C" {
/* byte string operations */ /* byte string operations */
#ifndef PLATFORM_OSX
extern void bcopy(const void *, void *, size_t); extern void bcopy(const void *, void *, size_t);
extern int bcmp(const void *, const void *, size_t); extern int bcmp(const void *, const void *, size_t);
extern void bzero(void *, size_t); extern void bzero(void *, size_t);
#endif
/* Printf */ /* Printf */
+2 -2
View File
@@ -37,7 +37,7 @@ extern "C" {
#include <PR/ultratypes.h> #include <PR/ultratypes.h>
#include "os_thread.h" #include "os_thread.h"
#include "os_message.h" #include "os_message.h"
#include <stdint.h>
#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) #if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS)
@@ -198,7 +198,7 @@ extern u32 osPiGetStatus(void);
extern s32 osPiGetDeviceType(void); extern s32 osPiGetDeviceType(void);
extern s32 osPiWriteIo(u32, u32); extern s32 osPiWriteIo(u32, u32);
extern s32 osPiReadIo(u32, u32 *); extern s32 osPiReadIo(u32, u32 *);
extern s32 osPiStartDma(OSIoMesg *, s32, s32, u32, void *, u32, extern s32 osPiStartDma(OSIoMesg *, s32, s32, uintptr_t, void *, u32,
OSMesgQueue *); OSMesgQueue *);
extern void osCreatePiManager(OSPri, OSMesgQueue *, OSMesg *, s32); extern void osCreatePiManager(OSPri, OSMesgQueue *, OSMesg *, s32);
-10
View File
@@ -1,10 +0,0 @@
#ifndef _WIN32
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200809L
#endif
#endif
#define ENET_IMPLEMENTATION 1
#define ENET_NO_PRAGMA_LINK 1
#include "external/enet.h"
-2
View File
@@ -1,2 +0,0 @@
#define MINIMP3_IMPLEMENTATION
#include "external/minimp3.h"
+3 -3
View File
@@ -44,15 +44,15 @@ void gfx_start_frame(void);
void gfx_run(Gfx* commands); void gfx_run(Gfx* commands);
void gfx_end_frame(void); void gfx_end_frame(void);
void gfx_set_target_fps(int); void gfx_set_target_fps(int);
void gfx_set_maximum_frame_latency(int latency); void gfx_set_texture_filter(enum FilteringMode mode);
void gfx_set_mipmap_filter(enum MipmapFilteringMode mode);
void gfx_texture_cache_clear(void); void gfx_texture_cache_clear(void);
void gfx_texture_cache_delete(const uint8_t *orig_addr); void gfx_texture_cache_delete(const uint8_t *orig_addr);
void gfx_texture_cache_delete_range(const uint8_t *start, const uint8_t *end);
int gfx_create_framebuffer(uint32_t width, uint32_t height, int upscale, int autoresize); int gfx_create_framebuffer(uint32_t width, uint32_t height, int upscale, int autoresize);
void gfx_resize_framebuffer(int fb, uint32_t width, uint32_t height, int upscale, int autoresize); void gfx_resize_framebuffer(int fb, uint32_t width, uint32_t height, int upscale, int autoresize);
void gfx_set_framebuffer(int fb, float noise_scale) ; void gfx_set_framebuffer(int fb, float noise_scale) ;
void gfx_reset_framebuffer(void); void gfx_reset_framebuffer(void);
void gfx_copy_framebuffer(int fb_dst, int fb_src, int left, int top, int use_back); void gfx_copy_framebuffer(int fb_dst, int fb_src, int left, int top, int use_back);
void gfx_get_pixel_depth_prepare(float x, float y);
uint16_t gfx_get_pixel_depth(float x, float y);
#endif #endif
+341 -202
View File
@@ -32,6 +32,7 @@ struct ShaderProgram {
uint8_t num_attribs; uint8_t num_attribs;
GLint frame_count_location; GLint frame_count_location;
GLint noise_scale_location; GLint noise_scale_location;
GLint three_point_filter_locations[2];
}; };
struct Framebuffer { struct Framebuffer {
@@ -53,10 +54,15 @@ static uint32_t frame_count;
static std::vector<Framebuffer> framebuffers; static std::vector<Framebuffer> framebuffers;
static size_t current_framebuffer; static size_t current_framebuffer;
static float current_noise_scale; static float current_noise_scale;
static int current_anisotropy_level;
static FilteringMode current_filter_mode = FILTER_LINEAR; static FilteringMode current_filter_mode = FILTER_LINEAR;
static MipmapFilteringMode current_mipmap_filter_mode = MIPMAP_LINEAR;
static bool current_textures_linear_filter[2] = {false, false};
static int gl_glsl_version = 130;
static char gl_glsl_version_str[16] = "130";
static GLenum gl_mirror_clamp = GL_MIRROR_CLAMP_TO_EDGE; static GLenum gl_mirror_clamp = GL_MIRROR_CLAMP_TO_EDGE;
static bool gl_es = false;
static bool gl_core_profile = false; static bool gl_core_profile = false;
static int gfx_opengl_get_max_texture_size() { static int gfx_opengl_get_max_texture_size() {
@@ -94,6 +100,12 @@ static void gfx_opengl_set_uniforms(struct ShaderProgram* prg) {
if (prg->noise_scale_location >= 0) { if (prg->noise_scale_location >= 0) {
glUniform1f(prg->noise_scale_location, current_noise_scale); glUniform1f(prg->noise_scale_location, current_noise_scale);
} }
if (prg->three_point_filter_locations[0] >= 0) {
glUniform1i(prg->three_point_filter_locations[0], current_textures_linear_filter[0]);
}
if (prg->three_point_filter_locations[1] >= 0) {
glUniform1i(prg->three_point_filter_locations[1], current_textures_linear_filter[1]);
}
} }
static void gfx_opengl_unload_shader(struct ShaderProgram* old_prg) { static void gfx_opengl_unload_shader(struct ShaderProgram* old_prg) {
@@ -234,144 +246,138 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
size_t num_floats = 4; size_t num_floats = 4;
// Vertex shader // Vertex shader
#ifdef __APPLE__
append_line(vs_buf, &vs_len, "#version 410 core"); vs_len += sprintf(vs_buf + vs_len, "#version %s\n", gl_glsl_version_str);
append_line(vs_buf, &vs_len, "in vec4 aVtxPos;");
#else if (gl_es) {
append_line(vs_buf, &vs_len, "#version 110"); append_line(vs_buf, &vs_len, "precision mediump float;");
append_line(vs_buf, &vs_len, "attribute vec4 aVtxPos;"); }
#endif
if (gl_glsl_version >= 130) {
append_line(vs_buf, &vs_len, "#define INPUT in");
append_line(vs_buf, &vs_len, "#define OUTPUT out");
} else {
append_line(vs_buf, &vs_len, "#define INPUT attribute");
append_line(vs_buf, &vs_len, "#define OUTPUT varying");
}
append_line(vs_buf, &vs_len, "INPUT vec4 aVtxPos;");
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
if (cc_features.used_textures[i]) { if (cc_features.used_textures[i]) {
#ifdef __APPLE__ vs_len += sprintf(vs_buf + vs_len, "INPUT vec2 aTexCoord%d;\n", i);
vs_len += sprintf(vs_buf + vs_len, "in vec2 aTexCoord%d;\n", i); vs_len += sprintf(vs_buf + vs_len, "OUTPUT vec2 vTexCoord%d;\n", i);
vs_len += sprintf(vs_buf + vs_len, "out vec2 vTexCoord%d;\n", i);
#else
vs_len += sprintf(vs_buf + vs_len, "attribute vec2 aTexCoord%d;\n", i);
vs_len += sprintf(vs_buf + vs_len, "varying vec2 vTexCoord%d;\n", i);
#endif
num_floats += 2; num_floats += 2;
for (int j = 0; j < 2; j++) { for (int j = 0; j < 2; j++) {
if (cc_features.clamp[i][j]) { if (cc_features.clamp[i][j]) {
#ifdef __APPLE__ vs_len += sprintf(vs_buf + vs_len, "INPUT float aTexClamp%s%d;\n", j == 0 ? "S" : "T", i);
vs_len += sprintf(vs_buf + vs_len, "in float aTexClamp%s%d;\n", j == 0 ? "S" : "T", i); vs_len += sprintf(vs_buf + vs_len, "OUTPUT float vTexClamp%s%d;\n", j == 0 ? "S" : "T", i);
vs_len += sprintf(vs_buf + vs_len, "out float vTexClamp%s%d;\n", j == 0 ? "S" : "T", i);
#else
vs_len += sprintf(vs_buf + vs_len, "attribute float aTexClamp%s%d;\n", j == 0 ? "S" : "T", i);
vs_len += sprintf(vs_buf + vs_len, "varying float vTexClamp%s%d;\n", j == 0 ? "S" : "T", i);
#endif
num_floats += 1; num_floats += 1;
} }
} }
} }
} }
if (cc_features.opt_fog) { if (cc_features.opt_fog) {
#ifdef __APPLE__ append_line(vs_buf, &vs_len, "INPUT vec4 aFog;");
append_line(vs_buf, &vs_len, "in vec4 aFog;"); append_line(vs_buf, &vs_len, "OUTPUT vec4 vFog;");
append_line(vs_buf, &vs_len, "out vec4 vFog;");
#else
append_line(vs_buf, &vs_len, "attribute vec4 aFog;");
append_line(vs_buf, &vs_len, "varying vec4 vFog;");
#endif
num_floats += 4; num_floats += 4;
} }
if (cc_features.opt_grayscale) { if (cc_features.opt_grayscale) {
#ifdef __APPLE__ append_line(vs_buf, &vs_len, "INPUT vec4 aGrayscaleColor;");
append_line(vs_buf, &vs_len, "in vec4 aGrayscaleColor;"); append_line(vs_buf, &vs_len, "OUTPUT vec4 vGrayscaleColor;");
append_line(vs_buf, &vs_len, "out vec4 vGrayscaleColor;");
#else
append_line(vs_buf, &vs_len, "attribute vec4 aGrayscaleColor;");
append_line(vs_buf, &vs_len, "varying vec4 vGrayscaleColor;");
#endif
num_floats += 4; num_floats += 4;
} }
for (int i = 0; i < cc_features.num_inputs; i++) { for (int i = 0; i < cc_features.num_inputs; i++) {
#ifdef __APPLE__ vs_len += sprintf(vs_buf + vs_len, "INPUT vec%d aInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1);
vs_len += sprintf(vs_buf + vs_len, "in vec%d aInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1); vs_len += sprintf(vs_buf + vs_len, "OUTPUT vec%d vInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1);
vs_len += sprintf(vs_buf + vs_len, "out vec%d vInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1);
#else
vs_len += sprintf(vs_buf + vs_len, "attribute vec%d aInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1);
vs_len += sprintf(vs_buf + vs_len, "varying vec%d vInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1);
#endif
num_floats += cc_features.opt_alpha ? 4 : 3; num_floats += cc_features.opt_alpha ? 4 : 3;
} }
append_line(vs_buf, &vs_len, "void main() {"); append_line(vs_buf, &vs_len, "void main() {");
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
if (cc_features.used_textures[i]) { if (cc_features.used_textures[i]) {
vs_len += sprintf(vs_buf + vs_len, "vTexCoord%d = aTexCoord%d;\n", i, i); vs_len += sprintf(vs_buf + vs_len, " vTexCoord%d = aTexCoord%d;\n", i, i);
for (int j = 0; j < 2; j++) { for (int j = 0; j < 2; j++) {
if (cc_features.clamp[i][j]) { if (cc_features.clamp[i][j]) {
vs_len += sprintf(vs_buf + vs_len, "vTexClamp%s%d = aTexClamp%s%d;\n", j == 0 ? "S" : "T", i, vs_len += sprintf(vs_buf + vs_len, " vTexClamp%s%d = aTexClamp%s%d;\n", j == 0 ? "S" : "T", i,
j == 0 ? "S" : "T", i); j == 0 ? "S" : "T", i);
} }
} }
} }
} }
if (cc_features.opt_fog) { if (cc_features.opt_fog) {
append_line(vs_buf, &vs_len, "vFog = aFog;"); append_line(vs_buf, &vs_len, " vFog = aFog;");
} }
if (cc_features.opt_grayscale) { if (cc_features.opt_grayscale) {
append_line(vs_buf, &vs_len, "vGrayscaleColor = aGrayscaleColor;"); append_line(vs_buf, &vs_len, " vGrayscaleColor = aGrayscaleColor;");
} }
for (int i = 0; i < cc_features.num_inputs; i++) { for (int i = 0; i < cc_features.num_inputs; i++) {
vs_len += sprintf(vs_buf + vs_len, "vInput%d = aInput%d;\n", i + 1, i + 1); vs_len += sprintf(vs_buf + vs_len, " vInput%d = aInput%d;\n", i + 1, i + 1);
}
append_line(vs_buf, &vs_len, " gl_Position = aVtxPos;");
if (!GLAD_GL_ARB_depth_clamp) {
// HACK: workaround for no GL_DEPTH_CLAMP
append_line(vs_buf, &vs_len, " gl_Position.z *= 0.3f;");
} }
append_line(vs_buf, &vs_len, "gl_Position = aVtxPos;");
append_line(vs_buf, &vs_len, "}"); append_line(vs_buf, &vs_len, "}");
// Fragment shader // Fragment shader
#ifdef __APPLE__
append_line(fs_buf, &fs_len, "#version 410 core"); fs_len += sprintf(fs_buf + fs_len, "#version %s\n", gl_glsl_version_str);
#else
append_line(fs_buf, &fs_len, "#version 130"); if (gl_es) {
#endif append_line(fs_buf, &fs_len, "precision mediump float;");
}
if (gl_glsl_version >= 130) {
append_line(fs_buf, &fs_len, "#define INPUT in");
append_line(fs_buf, &fs_len, "#define OUTPUT_COLOR outColor");
append_line(fs_buf, &fs_len, "#define SAMPLE_TEX(tex, uv) texture(tex, uv)");
} else {
append_line(fs_buf, &fs_len, "#define INPUT varying");
append_line(fs_buf, &fs_len, "#define OUTPUT_COLOR gl_FragColor");
append_line(fs_buf, &fs_len, "#define SAMPLE_TEX(tex, uv) texture2D(tex, uv)");
}
// Reference approach to color wrapping as per GLideN64
// Return wrapped value of x in interval [low, high)
append_line(fs_buf, &fs_len, "#define WRAP(x, low, high) mod((x)-(low), (high)-(low)) + (low)");
append_line(fs_buf, &fs_len, "#define TEX_OFFSET(tex, uv, texSize, off) SAMPLE_TEX(tex, uv - (off)/texSize)");
// append_line(fs_buf, &fs_len, "precision mediump float;"); // append_line(fs_buf, &fs_len, "precision mediump float;");
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
if (cc_features.used_textures[i]) { if (cc_features.used_textures[i]) {
#ifdef __APPLE__ fs_len += sprintf(fs_buf + fs_len, "INPUT vec2 vTexCoord%d;\n", i);
fs_len += sprintf(fs_buf + fs_len, "in vec2 vTexCoord%d;\n", i);
#else
fs_len += sprintf(fs_buf + fs_len, "varying vec2 vTexCoord%d;\n", i);
#endif
for (int j = 0; j < 2; j++) { for (int j = 0; j < 2; j++) {
if (cc_features.clamp[i][j]) { if (cc_features.clamp[i][j]) {
#ifdef __APPLE__ fs_len += sprintf(fs_buf + fs_len, "INPUT float vTexClamp%s%d;\n", j == 0 ? "S" : "T", i);
fs_len += sprintf(fs_buf + fs_len, "in float vTexClamp%s%d;\n", j == 0 ? "S" : "T", i);
#else
fs_len += sprintf(fs_buf + fs_len, "varying float vTexClamp%s%d;\n", j == 0 ? "S" : "T", i);
#endif
} }
} }
} }
} }
if (cc_features.opt_fog) { if (cc_features.opt_fog) {
#ifdef __APPLE__ append_line(fs_buf, &fs_len, "INPUT vec4 vFog;");
append_line(fs_buf, &fs_len, "in vec4 vFog;");
#else
append_line(fs_buf, &fs_len, "varying vec4 vFog;");
#endif
} }
if (cc_features.opt_grayscale) { if (cc_features.opt_grayscale) {
#ifdef __APPLE__ append_line(fs_buf, &fs_len, "INPUT vec4 vGrayscaleColor;");
append_line(fs_buf, &fs_len, "in vec4 vGrayscaleColor;");
#else
append_line(fs_buf, &fs_len, "varying vec4 vGrayscaleColor;");
#endif
} }
for (int i = 0; i < cc_features.num_inputs; i++) { for (int i = 0; i < cc_features.num_inputs; i++) {
#ifdef __APPLE__ fs_len += sprintf(fs_buf + fs_len, "INPUT vec%d vInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1);
fs_len += sprintf(fs_buf + fs_len, "in vec%d vInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1);
#else
fs_len += sprintf(fs_buf + fs_len, "varying vec%d vInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1);
#endif
} }
if (cc_features.used_textures[0]) { if (cc_features.used_textures[0]) {
append_line(fs_buf, &fs_len, "uniform sampler2D uTex0;"); append_line(fs_buf, &fs_len, "uniform sampler2D uTex0;");
if (current_filter_mode == FILTER_THREE_POINT)
append_line(fs_buf, &fs_len, "uniform int three_point_filter0;");
} }
if (cc_features.used_textures[1]) { if (cc_features.used_textures[1]) {
append_line(fs_buf, &fs_len, "uniform sampler2D uTex1;"); append_line(fs_buf, &fs_len, "uniform sampler2D uTex1;");
if (current_filter_mode == FILTER_THREE_POINT)
append_line(fs_buf, &fs_len, "uniform int three_point_filter1;");
} }
append_line(fs_buf, &fs_len, "uniform int frame_count;"); append_line(fs_buf, &fs_len, "uniform int frame_count;");
@@ -382,92 +388,97 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
append_line(fs_buf, &fs_len, " return fract(sin(random) * 143758.5453);"); append_line(fs_buf, &fs_len, " return fract(sin(random) * 143758.5453);");
append_line(fs_buf, &fs_len, "}"); append_line(fs_buf, &fs_len, "}");
if (current_filter_mode == FILTER_THREE_POINT) {
append_line(fs_buf, &fs_len, "vec4 filter3point(in sampler2D tex, in vec2 texCoord, in vec2 texSize) {");
append_line(fs_buf, &fs_len, " vec2 offset = fract(texCoord*texSize - vec2(0.5));");
append_line(fs_buf, &fs_len, " offset -= step(1.0, offset.x + offset.y);");
append_line(fs_buf, &fs_len, " vec4 c0 = TEX_OFFSET(tex, texCoord, texSize, offset);");
append_line(fs_buf, &fs_len, " vec4 c1 = TEX_OFFSET(tex, texCoord, texSize, vec2(offset.x - sign(offset.x), offset.y));");
append_line(fs_buf, &fs_len, " vec4 c2 = TEX_OFFSET(tex, texCoord, texSize, vec2(offset.x, offset.y - sign(offset.y)));");
append_line(fs_buf, &fs_len, " return c0 + abs(offset.x)*(c1-c0) + abs(offset.y)*(c2-c0);");
append_line(fs_buf, &fs_len, "}");
}
if (cc_features.opt_blur) { if (cc_features.opt_blur) {
// blur filter, used for menu backgrounds // blur filter, used for menu backgrounds
// used to be two for loops from 0 to 4, but apparently intel drivers crashed trying to unroll it // used to be two for loops from 0 to 4, but apparently intel drivers crashed trying to unroll it
// used to have a const weight array, but apparently drivers for the GT620 don't like const array initializers // used to have a const weight array, but apparently drivers for the GT620 don't like const array initializers
append_line(fs_buf, &fs_len, R"(
lowp vec4 hookTexture2D(in sampler2D t, in vec2 uv, in vec2 tsize) { if (current_filter_mode == FILTER_THREE_POINT)
lowp vec4 cw = vec4(0.0); append_line(fs_buf, &fs_len, "lowp vec4 hookTexture2D(in sampler2D t, in vec2 uv, in vec2 texSize, in int three_point_filter) {");
for (int i = 0; i < 16; ++i) { else
vec2 xy = vec2(float(i & 3), float(i >> 2)); append_line(fs_buf, &fs_len, "lowp vec4 hookTexture2D(in sampler2D t, in vec2 uv, in vec2 texSize) {");
lowp float w = 0.009947 - length(xy) * 0.001;
cw += vec4(texture2D(t, uv + (vec2(-1.5) + xy) / tsize).rgb * w, w); append_line(fs_buf, &fs_len, " lowp vec4 cw = vec4(0.0);");
} append_line(fs_buf, &fs_len, " for (int i = 0; i < 16; ++i) {");
return vec4(cw.rgb / cw.a, 1.0); append_line(fs_buf, &fs_len, " vec2 xy = vec2(float(i & 3), float(i >> 2));");
})" append_line(fs_buf, &fs_len, " lowp float w = 0.009947 - length(xy) * 0.001;");
); append_line(fs_buf, &fs_len, " vec2 scaled_uv = uv + (vec2(-1.5) + xy) / texSize;");
} else if (current_filter_mode == FILTER_THREE_POINT) {
#if __APPLE__ if (current_filter_mode == FILTER_THREE_POINT)
append_line(fs_buf, &fs_len, "#define TEX_OFFSET(off) texture(tex, texCoord - (off)/texSize)"); append_line(fs_buf, &fs_len, " lowp vec4 tex = mix(SAMPLE_TEX(t, scaled_uv), filter3point(t, scaled_uv, texSize), three_point_filter);");
#else else
append_line(fs_buf, &fs_len, "#define TEX_OFFSET(off) texture2D(tex, texCoord - (off)/texSize)"); append_line(fs_buf, &fs_len, " lowp vec4 tex = SAMPLE_TEX(t, scaled_uv);");
#endif
append_line(fs_buf, &fs_len, "vec4 filter3point(in sampler2D tex, in vec2 texCoord, in vec2 texSize) {"); append_line(fs_buf, &fs_len, " cw += vec4(tex.rgb * w, w);");
append_line(fs_buf, &fs_len, " vec2 offset = fract(texCoord*texSize - vec2(0.5));"); append_line(fs_buf, &fs_len, " }");
append_line(fs_buf, &fs_len, " offset -= step(1.0, offset.x + offset.y);"); append_line(fs_buf, &fs_len, " return vec4(cw.rgb / cw.a, 1.0);");
append_line(fs_buf, &fs_len, " vec4 c0 = TEX_OFFSET(offset);");
append_line(fs_buf, &fs_len, " vec4 c1 = TEX_OFFSET(vec2(offset.x - sign(offset.x), offset.y));");
append_line(fs_buf, &fs_len, " vec4 c2 = TEX_OFFSET(vec2(offset.x, offset.y - sign(offset.y)));");
append_line(fs_buf, &fs_len, " return c0 + abs(offset.x)*(c1-c0) + abs(offset.y)*(c2-c0);");
append_line(fs_buf, &fs_len, "}");
append_line(fs_buf, &fs_len, "vec4 hookTexture2D(in sampler2D tex, in vec2 uv, in vec2 texSize) {");
append_line(fs_buf, &fs_len, " return filter3point(tex, uv, texSize);");
append_line(fs_buf, &fs_len, "}"); append_line(fs_buf, &fs_len, "}");
} else { } else {
append_line(fs_buf, &fs_len, "vec4 hookTexture2D(in sampler2D tex, in vec2 uv, in vec2 texSize) {"); if (current_filter_mode == FILTER_THREE_POINT) {
#if __APPLE__ append_line(fs_buf, &fs_len, "vec4 hookTexture2D(in sampler2D tex, in vec2 uv, in vec2 texSize, in int three_point_filter) {");
append_line(fs_buf, &fs_len, " return texture(tex, uv);"); append_line(fs_buf, &fs_len, " return mix(SAMPLE_TEX(tex, uv), filter3point(tex, uv, texSize), three_point_filter);");
#else append_line(fs_buf, &fs_len, "}");
append_line(fs_buf, &fs_len, " return texture2D(tex, uv);"); } else {
#endif append_line(fs_buf, &fs_len, "vec4 hookTexture2D(in sampler2D tex, in vec2 uv, in vec2 texSize) {");
append_line(fs_buf, &fs_len, "}"); append_line(fs_buf, &fs_len, " return SAMPLE_TEX(tex, uv);");
append_line(fs_buf, &fs_len, "}");
}
} }
#if __APPLE__ if (gl_glsl_version >= 130) {
append_line(fs_buf, &fs_len, "out vec4 outColor;"); append_line(fs_buf, &fs_len, "out vec4 outColor;");
#endif }
append_line(fs_buf, &fs_len, "void main() {"); append_line(fs_buf, &fs_len, "void main() {");
// Reference approach to color wrapping as per GLideN64
// Return wrapped value of x in interval [low, high)
append_line(fs_buf, &fs_len, "#define WRAP(x, low, high) mod((x)-(low), (high)-(low)) + (low)");
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
if (cc_features.used_textures[i]) { if (cc_features.used_textures[i]) {
bool s = cc_features.clamp[i][0], t = cc_features.clamp[i][1]; bool s = cc_features.clamp[i][0], t = cc_features.clamp[i][1];
fs_len += sprintf(fs_buf + fs_len, "vec2 texSize%d = textureSize(uTex%d, 0);\n", i, i); fs_len += sprintf(fs_buf + fs_len, " vec2 texSize%d = vec2(textureSize(uTex%d, 0));\n", i, i);
if (!s && !t) { if (!s && !t) {
fs_len += sprintf(fs_buf + fs_len, "vec2 vTexCoordAdj%d = vTexCoord%d;\n", i, i); fs_len += sprintf(fs_buf + fs_len, " vec2 vTexCoordAdj%d = vTexCoord%d;\n", i, i);
} else { } else {
if (s && t) { if (s && t) {
fs_len += sprintf(fs_buf + fs_len, fs_len += sprintf(fs_buf + fs_len,
"vec2 vTexCoordAdj%d = clamp(vTexCoord%d, 0.5 / texSize%d, " " vec2 vTexCoordAdj%d = clamp(vTexCoord%d, 0.5 / texSize%d, "
"vec2(vTexClampS%d, vTexClampT%d));\n", "vec2(vTexClampS%d, vTexClampT%d));\n",
i, i, i, i, i); i, i, i, i, i);
} else if (s) { } else if (s) {
fs_len += sprintf(fs_buf + fs_len, fs_len += sprintf(fs_buf + fs_len,
"vec2 vTexCoordAdj%d = vec2(clamp(vTexCoord%d.s, 0.5 / " " vec2 vTexCoordAdj%d = vec2(clamp(vTexCoord%d.s, 0.5 / "
"texSize%d.s, vTexClampS%d), vTexCoord%d.t);\n", "texSize%d.s, vTexClampS%d), vTexCoord%d.t);\n",
i, i, i, i, i); i, i, i, i, i);
} else { } else {
fs_len += sprintf(fs_buf + fs_len, fs_len += sprintf(fs_buf + fs_len,
"vec2 vTexCoordAdj%d = vec2(vTexCoord%d.s, clamp(vTexCoord%d.t, " " vec2 vTexCoordAdj%d = vec2(vTexCoord%d.s, clamp(vTexCoord%d.t, "
"0.5 / texSize%d.t, vTexClampT%d));\n", "0.5 / texSize%d.t, vTexClampT%d));\n",
i, i, i, i, i); i, i, i, i, i);
} }
} }
fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = hookTexture2D(uTex%d, vTexCoordAdj%d, texSize%d);\n", i, i, i, i); if (current_filter_mode == FILTER_THREE_POINT)
fs_len += sprintf(fs_buf + fs_len, " vec4 texVal%d = hookTexture2D(uTex%d, vTexCoordAdj%d, texSize%d, three_point_filter%d);\n", i, i, i, i, i);
else
fs_len += sprintf(fs_buf + fs_len, " vec4 texVal%d = hookTexture2D(uTex%d, vTexCoordAdj%d, texSize%d);\n", i, i, i, i);
} }
} }
append_line(fs_buf, &fs_len, cc_features.opt_alpha ? "vec4 texel;" : "vec3 texel;"); append_line(fs_buf, &fs_len, cc_features.opt_alpha ? " vec4 texel;" : " vec3 texel;");
for (int c = 0; c < (cc_features.opt_2cyc ? 2 : 1); c++) { for (int c = 0; c < (cc_features.opt_2cyc ? 2 : 1); c++) {
append_str(fs_buf, &fs_len, "texel = "); append_str(fs_buf, &fs_len, " texel = ");
if (!cc_features.color_alpha_same[c] && cc_features.opt_alpha) { if (!cc_features.color_alpha_same[c] && cc_features.opt_alpha) {
append_str(fs_buf, &fs_len, "vec4("); append_str(fs_buf, &fs_len, "vec4(");
append_formula(fs_buf, &fs_len, cc_features.c[c], cc_features.do_single[c][0], append_formula(fs_buf, &fs_len, cc_features.c[c], cc_features.do_single[c][0],
@@ -484,56 +495,50 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
append_line(fs_buf, &fs_len, ";"); append_line(fs_buf, &fs_len, ";");
if (c == 0) { if (c == 0) {
append_str(fs_buf, &fs_len, "texel = WRAP(texel, -1.01, 1.01);"); append_line(fs_buf, &fs_len, " texel = WRAP(texel, -1.01, 1.01);");
} }
} }
append_str(fs_buf, &fs_len, "texel = WRAP(texel, -0.51, 1.51);"); append_line(fs_buf, &fs_len, " texel = WRAP(texel, -0.51, 1.51);");
append_str(fs_buf, &fs_len, "texel = clamp(texel, 0.0, 1.0);"); append_line(fs_buf, &fs_len, " texel = clamp(texel, 0.0, 1.0);");
// TODO discard if alpha is 0? // TODO discard if alpha is 0?
if (cc_features.opt_fog) { if (cc_features.opt_fog) {
if (cc_features.opt_alpha) { if (cc_features.opt_alpha) {
append_line(fs_buf, &fs_len, "texel = vec4(mix(texel.rgb, vFog.rgb, vFog.a), texel.a);"); append_line(fs_buf, &fs_len, " texel = vec4(mix(texel.rgb, vFog.rgb, vFog.a), texel.a);");
} else { } else {
append_line(fs_buf, &fs_len, "texel = mix(texel, vFog.rgb, vFog.a);"); append_line(fs_buf, &fs_len, " texel = mix(texel, vFog.rgb, vFog.a);");
} }
} }
if (cc_features.opt_texture_edge && cc_features.opt_alpha) { if (cc_features.opt_texture_edge && cc_features.opt_alpha) {
append_line(fs_buf, &fs_len, "if (texel.a > 0.19) texel.a = 1.0; else discard;"); append_line(fs_buf, &fs_len, " if (texel.a > 0.19) texel.a = 1.0; else discard;");
} }
if (cc_features.opt_alpha && cc_features.opt_noise) { if (cc_features.opt_alpha && cc_features.opt_noise) {
append_line(fs_buf, &fs_len, append_line(fs_buf, &fs_len,
"texel.a *= floor(clamp(random(vec3(floor(gl_FragCoord.xy * noise_scale), float(frame_count))) + " " texel.a *= floor(clamp(random(vec3(floor(gl_FragCoord.xy * noise_scale), float(frame_count))) + "
"texel.a, 0.0, 1.0));"); "texel.a, 0.0, 1.0));");
} }
if (cc_features.opt_grayscale) { if (cc_features.opt_grayscale) {
append_line(fs_buf, &fs_len, "float intensity = (texel.r + texel.g + texel.b) / 3.0;"); append_line(fs_buf, &fs_len, " float intensity = (texel.r + texel.g + texel.b) / 3.0;");
append_line(fs_buf, &fs_len, "vec3 new_texel = vGrayscaleColor.rgb * intensity;"); append_line(fs_buf, &fs_len, " vec3 new_texel = vGrayscaleColor.rgb * intensity;");
append_line(fs_buf, &fs_len, "texel.rgb = mix(texel.rgb, new_texel, vGrayscaleColor.a);"); append_line(fs_buf, &fs_len, " texel.rgb = mix(texel.rgb, new_texel, vGrayscaleColor.a);");
} }
if (cc_features.opt_alpha) { if (cc_features.opt_alpha) {
if (cc_features.opt_alpha_threshold) { if (cc_features.opt_alpha_threshold) {
append_line(fs_buf, &fs_len, "if (texel.a < 8.0 / 256.0) discard;"); append_line(fs_buf, &fs_len, " if (texel.a < 8.0 / 256.0) discard;");
} }
if (cc_features.opt_invisible) { if (cc_features.opt_invisible) {
append_line(fs_buf, &fs_len, "texel.a = 0.0;"); append_line(fs_buf, &fs_len, " texel.a = 0.0;");
} }
#if __APPLE__
append_line(fs_buf, &fs_len, "outColor = texel;"); append_line(fs_buf, &fs_len, " OUTPUT_COLOR = texel;");
#else
append_line(fs_buf, &fs_len, "gl_FragColor = texel;");
#endif
} else { } else {
#if __APPLE__ append_line(fs_buf, &fs_len, " OUTPUT_COLOR = vec4(texel, 1.0);");
append_line(fs_buf, &fs_len, "outColor = vec4(texel, 1.0);");
#else
append_line(fs_buf, &fs_len, "gl_FragColor = vec4(texel, 1.0);");
#endif
} }
append_line(fs_buf, &fs_len, "}"); append_line(fs_buf, &fs_len, "}");
vs_buf[vs_len] = '\0'; vs_buf[vs_len] = '\0';
@@ -574,6 +579,11 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
glAttachShader(shader_program, fragment_shader); glAttachShader(shader_program, fragment_shader);
glLinkProgram(shader_program); glLinkProgram(shader_program);
glDetachShader(shader_program, vertex_shader);
glDetachShader(shader_program, fragment_shader);
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
size_t cnt = 0; size_t cnt = 0;
struct ShaderProgram* prg = &shader_program_pool[make_pair(shader_id0, shader_id1)]; struct ShaderProgram* prg = &shader_program_pool[make_pair(shader_id0, shader_id1)];
@@ -640,6 +650,8 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
prg->frame_count_location = glGetUniformLocation(shader_program, "frame_count"); prg->frame_count_location = glGetUniformLocation(shader_program, "frame_count");
prg->noise_scale_location = glGetUniformLocation(shader_program, "noise_scale"); prg->noise_scale_location = glGetUniformLocation(shader_program, "noise_scale");
prg->three_point_filter_locations[0] = glGetUniformLocation(shader_program, "three_point_filter0");
prg->three_point_filter_locations[1] = glGetUniformLocation(shader_program, "three_point_filter1");
gfx_opengl_load_shader(prg); gfx_opengl_load_shader(prg);
@@ -657,6 +669,14 @@ static void gfx_opengl_shader_get_info(struct ShaderProgram* prg, uint8_t* num_i
used_textures[1] = prg->used_textures[1]; used_textures[1] = prg->used_textures[1];
} }
static void gfx_opengl_clear_shaders(void) {
glUseProgram(0);
for (auto& pair : shader_program_pool) {
glDeleteProgram(pair.second.opengl_program_id);
}
shader_program_pool.clear();
}
static GLuint gfx_opengl_new_texture(void) { static GLuint gfx_opengl_new_texture(void) {
GLuint ret; GLuint ret;
glGenTextures(1, &ret); glGenTextures(1, &ret);
@@ -667,13 +687,18 @@ static void gfx_opengl_delete_texture(uint32_t texID) {
glDeleteTextures(1, &texID); glDeleteTextures(1, &texID);
} }
static void gfx_opengl_select_texture(int tile, GLuint texture_id) { static void gfx_opengl_select_texture(int tile, GLuint texture_id, bool linear_filter) {
glActiveTexture(GL_TEXTURE0 + tile); glActiveTexture(GL_TEXTURE0 + tile);
glBindTexture(GL_TEXTURE_2D, texture_id); glBindTexture(GL_TEXTURE_2D, texture_id);
current_textures_linear_filter[tile] = linear_filter;
} }
static void gfx_opengl_upload_texture(const uint8_t* rgba32_buf, uint32_t width, uint32_t height) { static void gfx_opengl_upload_texture(const uint8_t* rgba32_buf, uint32_t width, uint32_t height, bool gen_mipmaps) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba32_buf); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba32_buf);
if (gen_mipmaps || current_filter_mode == FILTER_THREE_POINT) {
glGenerateMipmap(GL_TEXTURE_2D);
}
} }
static uint32_t gfx_cm_to_opengl(uint32_t val) { static uint32_t gfx_cm_to_opengl(uint32_t val) {
@@ -690,37 +715,77 @@ static uint32_t gfx_cm_to_opengl(uint32_t val) {
return 0; return 0;
} }
static void gfx_opengl_set_sampler_parameters(int tile, bool linear_filter, uint32_t cms, uint32_t cmt) { static void gfx_opengl_set_sampler_parameters(int tile, bool linear_filter, uint32_t cms, uint32_t cmt, bool mipmaps) {
const GLint filter = linear_filter && (current_filter_mode == FILTER_LINEAR) ? GL_LINEAR : GL_NEAREST; const GLint min_filters[3][3] = {
// MIPMAP_DISABLED MIPMAP_NEAREST MIPMAP_LINEAR
{ GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR }, // FILTER_NONE
{ GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR }, // FILTER_BILINEAR
{ GL_NEAREST, GL_NEAREST, GL_NEAREST }, // FILTER_THREE_POINT
};
mipmaps = mipmaps && (current_mipmap_filter_mode != MIPMAP_DISABLED);
const int mip_idx = mipmaps ? current_mipmap_filter_mode : 0;
const GLint min_filter = linear_filter ? min_filters[current_filter_mode][mip_idx] : GL_NEAREST;
const GLint max_filter = linear_filter && (current_filter_mode == FILTER_LINEAR) ? GL_LINEAR : GL_NEAREST;
glActiveTexture(GL_TEXTURE0 + tile); glActiveTexture(GL_TEXTURE0 + tile);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, max_filter);
if (mipmaps) {
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, current_anisotropy_level);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gfx_cm_to_opengl(cms)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gfx_cm_to_opengl(cms));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gfx_cm_to_opengl(cmt)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gfx_cm_to_opengl(cmt));
} }
static void gfx_opengl_set_depth_test_and_mask(bool depth_test, bool z_upd) { static void gfx_opengl_set_depth_mode(bool depth_test, bool depth_update, bool depth_compare, bool depth_source_prim, uint16_t zmode) {
if (depth_test || z_upd) { if (depth_test) {
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glDepthMask(z_upd ? GL_TRUE : GL_FALSE); glDepthMask(depth_update ? GL_TRUE : GL_FALSE);
glDepthFunc(depth_test ? GL_LEQUAL : GL_ALWAYS); current_depth_mask = depth_update;
current_depth_mask = z_upd;
if (depth_compare) {
switch (zmode) {
case ZMODE_INTER:
glDepthFunc(GL_LEQUAL);
glDisable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(0, 0);
break;
case ZMODE_OPA:
case ZMODE_XLU:
if (depth_source_prim) {
glDepthFunc(GL_LEQUAL);
} else {
glDepthFunc(GL_LESS);
}
glDisable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(0, 0);
break;
case ZMODE_DEC:
glDepthFunc(GL_LEQUAL);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(-2, -2);
break;
}
} else {
glDepthFunc(GL_ALWAYS);
glDisable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(0, 0);
}
} else { } else {
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
} }
} }
static void gfx_opengl_set_depth_range(float znear, float zfar) { static void gfx_opengl_set_depth_range(float znear, float zfar) {
glDepthRange(znear, zfar); if (glDepthRangef) {
} glDepthRangef(znear, zfar);
static void gfx_opengl_set_zmode_decal(bool zmode_decal) {
if (zmode_decal) {
glPolygonOffset(-2, -2);
glEnable(GL_POLYGON_OFFSET_FILL);
} else { } else {
glPolygonOffset(0, 0); glDepthRange(znear, zfar);
glDisable(GL_POLYGON_OFFSET_FILL);
} }
} }
@@ -791,18 +856,6 @@ static bool gfx_opengl_supports_framebuffers(void) {
return (glad_glBlitFramebuffer && glad_glRenderbufferStorageMultisample); return (glad_glBlitFramebuffer && glad_glRenderbufferStorageMultisample);
} }
if (GLAD_GL_EXT_framebuffer_object && GLAD_GL_EXT_framebuffer_blit && GLAD_GL_EXT_framebuffer_multisample) { if (GLAD_GL_EXT_framebuffer_object && GLAD_GL_EXT_framebuffer_blit && GLAD_GL_EXT_framebuffer_multisample) {
// because of the way glad works we'll have to copy the pointers over
glad_glGenFramebuffers = glad_glGenFramebuffersEXT;
glad_glGenRenderbuffers = glad_glGenRenderbuffersEXT;
glad_glDeleteFramebuffers = glad_glDeleteFramebuffersEXT;
glad_glDeleteRenderbuffers = glad_glDeleteRenderbuffersEXT;
glad_glBindFramebuffer = glad_glBindFramebufferEXT;
glad_glBindRenderbuffer = glad_glBindRenderbufferEXT;
glad_glFramebufferRenderbuffer = glad_glFramebufferRenderbufferEXT;
glad_glFramebufferTexture2D = glad_glFramebufferTexture2DEXT;
glad_glRenderbufferStorage = glad_glRenderbufferStorageEXT;
glad_glRenderbufferStorageMultisample = glad_glRenderbufferStorageMultisampleEXT;
glad_glBlitFramebuffer = glad_glBlitFramebufferEXT;
// sanity check // sanity check
return (glad_glFramebufferRenderbuffer && glad_glBlitFramebuffer && glad_glRenderbufferStorageMultisample); return (glad_glFramebufferRenderbuffer && glad_glBlitFramebuffer && glad_glRenderbufferStorageMultisample);
} }
@@ -867,11 +920,52 @@ static void *gl_load_proc(const char *name) {
return NULL; return NULL;
} }
static void gfx_opengl_init_extensions(void) {
// patch up some extension values and pointers
if (!GLAD_GL_ARB_depth_clamp) {
if (GLAD_GL_EXT_depth_clamp || GLAD_GL_NV_depth_clamp) {
GLAD_GL_ARB_depth_clamp = 1;
} else if (!gl_es && GLVersion.major >= 3) {
// GL3.2+ should have depth_clamp as part of the spec, but some devices don't report it for some reason
GLAD_GL_ARB_depth_clamp = (GLVersion.major > 3 || (GLVersion.major == 3 && GLVersion.minor >= 2));
}
}
if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) {
GLAD_GL_ARB_texture_mirror_clamp_to_edge = GLAD_GL_EXT_texture_mirror_clamp_to_edge;
}
if (GLVersion.major < 3 && !GLAD_GL_ARB_framebuffer_object) {
if (GLAD_GL_EXT_framebuffer_object && GLAD_GL_EXT_framebuffer_blit && GLAD_GL_EXT_framebuffer_multisample) {
// because of the way glad works we'll have to copy the pointers over
glad_glGenFramebuffers = glad_glGenFramebuffersEXT;
glad_glGenRenderbuffers = glad_glGenRenderbuffersEXT;
glad_glDeleteFramebuffers = glad_glDeleteFramebuffersEXT;
glad_glDeleteRenderbuffers = glad_glDeleteRenderbuffersEXT;
glad_glBindFramebuffer = glad_glBindFramebufferEXT;
glad_glBindRenderbuffer = glad_glBindRenderbufferEXT;
glad_glFramebufferRenderbuffer = glad_glFramebufferRenderbufferEXT;
glad_glFramebufferTexture2D = glad_glFramebufferTexture2DEXT;
glad_glRenderbufferStorage = glad_glRenderbufferStorageEXT;
glad_glRenderbufferStorageMultisample = glad_glRenderbufferStorageMultisampleEXT;
glad_glBlitFramebuffer = glad_glBlitFramebufferEXT;
}
}
}
static void gfx_opengl_init(void) { static void gfx_opengl_init(void) {
if (!gladLoadGLLoader(gl_load_proc) || glGetString == NULL || glEnable == NULL) { if (!gladLoadGLLoader(gl_load_proc) || glGetString == NULL || glEnable == NULL) {
sysFatalError("Could not load OpenGL.\nReported SDL error: %s", SDL_GetError()); sysFatalError("Could not load OpenGL.\nReported SDL error: %s", SDL_GetError());
} }
// check if we're using ES or core, which have more limited feature sets
int val = 0;
SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &val);
gl_core_profile = (val == SDL_GL_CONTEXT_PROFILE_CORE);
gl_es = (val == SDL_GL_CONTEXT_PROFILE_ES);
gfx_opengl_init_extensions();
if (sysArgCheck("--debug-gl")) { if (sysArgCheck("--debug-gl")) {
gfx_opengl_enable_debug(); gfx_opengl_enable_debug();
// dump version info as early as possible // dump version info as early as possible
@@ -885,7 +979,7 @@ static void gfx_opengl_init(void) {
} }
if (!gfx_opengl_supports_shaders()) { if (!gfx_opengl_supports_shaders()) {
sysLogPrintf(LOG_WARNING, "GL: GLSL 1.30 unsupported"); sysLogPrintf(LOG_WARNING, "GL: GLSL 1.30 may be unsupported");
// maybe replace this with sysFatalError, though the GLSL compiler will cause that later anyway // maybe replace this with sysFatalError, though the GLSL compiler will cause that later anyway
} }
@@ -901,20 +995,35 @@ static void gfx_opengl_init(void) {
gl_mirror_clamp = GL_MIRRORED_REPEAT; gl_mirror_clamp = GL_MIRRORED_REPEAT;
} }
if ((GLVersion.major == 3 && GLVersion.minor >= 2) || GLVersion.major > 3) { // determine GLSL version
// check if we're using core profile, which is more strict if (gl_es) {
int val = 0; // ES has its own numbering scheme, but it should support 300 even on 3.1 and 3.2
SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &val); gl_glsl_version = 300;
gl_core_profile = (val == SDL_GL_CONTEXT_PROFILE_CORE); snprintf(gl_glsl_version_str, sizeof(gl_glsl_version_str), "%d es", gl_glsl_version);
} else if (!gl_core_profile) {
// in compat profile we can just request the lowest possible
gl_glsl_version = 130;
snprintf(gl_glsl_version_str, sizeof(gl_glsl_version_str), "%d", gl_glsl_version);
} else {
// otherwise we have to pick a specific version
if (GLVersion.major == 3 && GLVersion.minor == 2) {
// 3.2core is the earliest core version and it follows the old numbering scheme
gl_glsl_version = 150;
} else {
// 3.3+ follow the new numbering scheme
gl_glsl_version = GLVersion.major * 100 + GLVersion.minor * 10;
}
snprintf(gl_glsl_version_str, sizeof(gl_glsl_version_str), "%d core", gl_glsl_version);
} }
sysLogPrintf(LOG_NOTE, "GL: using GLSL version %s", gl_glsl_version_str);
glGenBuffers(1, &opengl_vbo); glGenBuffers(1, &opengl_vbo);
glBindBuffer(GL_ARRAY_BUFFER, opengl_vbo); glBindBuffer(GL_ARRAY_BUFFER, opengl_vbo);
if (gl_core_profile) { if (gl_core_profile || gl_es) {
// warn user that funny things can happen // warn user that funny things can happen
sysLogPrintf(LOG_WARNING, "GL: using core profile, watch out for errors"); sysLogPrintf(LOG_WARNING, "GL: using core profile or ES, watch out for errors");
// core will explode if we don't use a VAO for our VBO // core/es will explode if we don't use a VAO for our VBO
glGenVertexArrays(1, &opengl_vao); glGenVertexArrays(1, &opengl_vao);
glBindVertexArray(opengl_vao); glBindVertexArray(opengl_vao);
} }
@@ -1045,12 +1154,23 @@ bool gfx_opengl_start_draw_to_framebuffer(int fb_id, float noise_scale) {
} }
} }
void gfx_opengl_clear_framebuffer() { void gfx_opengl_clear_framebuffer(bool clear_color, bool clear_depth) {
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
glDepthMask(GL_TRUE);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); GLbitfield mask = 0;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (clear_color) {
glDepthMask(current_depth_mask ? GL_TRUE : GL_FALSE); glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
mask |= GL_COLOR_BUFFER_BIT;
}
if (clear_depth) {
glDepthMask(GL_TRUE);
mask |= GL_DEPTH_BUFFER_BIT;
}
glClear(mask);
if (clear_depth) {
glDepthMask(current_depth_mask ? GL_TRUE : GL_FALSE);
}
glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
} }
@@ -1078,6 +1198,8 @@ void gfx_opengl_select_texture_fb(int fb_id) {
// glDisable(GL_DEPTH_TEST); // glDisable(GL_DEPTH_TEST);
glActiveTexture(GL_TEXTURE0 + 0); glActiveTexture(GL_TEXTURE0 + 0);
glBindTexture(GL_TEXTURE_2D, framebuffers[fb_id].clrbuf); glBindTexture(GL_TEXTURE_2D, framebuffers[fb_id].clrbuf);
current_textures_linear_filter[0] = true;
} }
void gfx_opengl_copy_framebuffer(int fb_dst, int fb_src, int left, int top, bool flip_y, bool use_back) { void gfx_opengl_copy_framebuffer(int fb_dst, int fb_src, int left, int top, bool flip_y, bool use_back) {
@@ -1120,7 +1242,8 @@ void gfx_opengl_copy_framebuffer(int fb_dst, int fb_src, int left, int top, bool
} }
if (fb_src == 0) { if (fb_src == 0) {
glReadBuffer(use_back ? GL_BACK : GL_FRONT); // GLES does not support GL_FRONT here
glReadBuffer((use_back || gl_es) ? GL_BACK : GL_FRONT);
} else { } else {
glReadBuffer(GL_COLOR_ATTACHMENT0); glReadBuffer(GL_COLOR_ATTACHMENT0);
} }
@@ -1136,14 +1259,27 @@ void gfx_opengl_copy_framebuffer(int fb_dst, int fb_src, int left, int top, bool
void gfx_opengl_set_texture_filter(FilteringMode mode) { void gfx_opengl_set_texture_filter(FilteringMode mode) {
current_filter_mode = mode; current_filter_mode = mode;
gfx_texture_cache_clear();
} }
FilteringMode gfx_opengl_get_texture_filter(void) { FilteringMode gfx_opengl_get_texture_filter(void) {
return current_filter_mode; return current_filter_mode;
} }
struct GfxRenderingAPI gfx_opengl_api = { void gfx_opengl_set_mipmap_filter(MipmapFilteringMode mode) {
current_mipmap_filter_mode = mode;
}
static int gfx_opengl_get_max_anisotropy_level() {
GLfloat max_aniso_level;
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &max_aniso_level);
return (int)max_aniso_level;
}
static void gfx_opengl_set_anisotropy_level(int level) {
current_anisotropy_level = level;
}
struct GfxRenderingAPI gfx_opengl_api = {
gfx_opengl_get_name, gfx_opengl_get_name,
gfx_opengl_get_max_texture_size, gfx_opengl_get_max_texture_size,
gfx_opengl_get_clip_parameters, gfx_opengl_get_clip_parameters,
@@ -1152,13 +1288,13 @@ struct GfxRenderingAPI gfx_opengl_api = {
gfx_opengl_create_and_load_new_shader, gfx_opengl_create_and_load_new_shader,
gfx_opengl_lookup_shader, gfx_opengl_lookup_shader,
gfx_opengl_shader_get_info, gfx_opengl_shader_get_info,
gfx_opengl_clear_shaders,
gfx_opengl_new_texture, gfx_opengl_new_texture,
gfx_opengl_select_texture, gfx_opengl_select_texture,
gfx_opengl_upload_texture, gfx_opengl_upload_texture,
gfx_opengl_set_sampler_parameters, gfx_opengl_set_sampler_parameters,
gfx_opengl_set_depth_test_and_mask, gfx_opengl_set_depth_mode,
gfx_opengl_set_depth_range, gfx_opengl_set_depth_range,
gfx_opengl_set_zmode_decal,
gfx_opengl_set_viewport, gfx_opengl_set_viewport,
gfx_opengl_set_scissor, gfx_opengl_set_scissor,
gfx_opengl_set_use_alpha, gfx_opengl_set_use_alpha,
@@ -1178,5 +1314,8 @@ struct GfxRenderingAPI gfx_opengl_api = {
gfx_opengl_select_texture_fb, gfx_opengl_select_texture_fb,
gfx_opengl_delete_texture, gfx_opengl_delete_texture,
gfx_opengl_set_texture_filter, gfx_opengl_set_texture_filter,
gfx_opengl_get_texture_filter gfx_opengl_get_texture_filter,
gfx_opengl_set_mipmap_filter,
gfx_opengl_set_anisotropy_level,
gfx_opengl_get_max_anisotropy_level
}; };
+142 -102
View File
@@ -125,8 +125,6 @@ static struct RSP {
float aspect_ofs; float aspect_ofs;
float aspect_scale; float aspect_scale;
float depth_zfar;
struct { struct {
// U0.16 // U0.16
uint16_t s, t; uint16_t s, t;
@@ -194,12 +192,13 @@ static struct RDP {
bool viewport_or_scissor_changed; bool viewport_or_scissor_changed;
void* z_buf_address; void* z_buf_address;
void* color_image_address; void* color_image_address;
int16_t subpixel_ofs_x;
int16_t subpixel_ofs_y;
} rdp; } rdp;
static struct RenderingState { static struct RenderingState {
uint8_t depth_test_and_mask; // 1: depth test, 2: depth mask uint8_t depth_mode;
float depth_zfar;
bool decal_mode;
bool alpha_blend; bool alpha_blend;
bool modulate; bool modulate;
struct XYWidthHeight viewport, scissor; struct XYWidthHeight viewport, scissor;
@@ -523,7 +522,7 @@ static bool gfx_texture_cache_lookup(int i, const TextureCacheKey& key) {
TextureCacheNode** n = &rendering_state.textures[i]; TextureCacheNode** n = &rendering_state.textures[i];
if (it != gfx_texture_cache.map.end()) { if (it != gfx_texture_cache.map.end()) {
gfx_rapi->select_texture(i, it->second.texture_id); gfx_rapi->select_texture(i, it->second.texture_id, it->second.linear_filter);
*n = &*it; *n = &*it;
gfx_texture_cache.lru.splice(gfx_texture_cache.lru.end(), gfx_texture_cache.lru, gfx_texture_cache.lru.splice(gfx_texture_cache.lru.end(), gfx_texture_cache.lru,
it->second.lru_location); // move to back it->second.lru_location); // move to back
@@ -551,8 +550,8 @@ static bool gfx_texture_cache_lookup(int i, const TextureCacheKey& key) {
node->second.texture_id = texture_id; node->second.texture_id = texture_id;
node->second.lru_location = gfx_texture_cache.lru.insert(gfx_texture_cache.lru.end(), { it }); node->second.lru_location = gfx_texture_cache.lru.insert(gfx_texture_cache.lru.end(), { it });
gfx_rapi->select_texture(i, texture_id); gfx_rapi->select_texture(i, texture_id, false);
gfx_rapi->set_sampler_parameters(i, false, 0, 0); gfx_rapi->set_sampler_parameters(i, false, 0, 0, rdp.tex_lod);
*n = node; *n = node;
return false; return false;
} }
@@ -586,8 +585,30 @@ void gfx_texture_cache_delete(const uint8_t* orig_addr) {
} }
} }
static void import_texture_rgba16(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { void gfx_texture_cache_delete_range(const uint8_t* start, const uint8_t* end) {
const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; gfx_flush();
for (int i = 0; i < 2; ++i) {
if (rendering_state.textures[i]
&& rendering_state.textures[i]->first.texture_addr >= start
&& rendering_state.textures[i]->first.texture_addr < end) {
rdp.textures_changed[i] = true;
rendering_state.textures[i] = nullptr;
}
}
for (auto it = gfx_texture_cache.map.begin(); it != gfx_texture_cache.map.end(); ) {
if (it->first.texture_addr >= start && it->first.texture_addr < end) {
gfx_texture_cache.lru.erase(it->second.lru_location);
gfx_texture_cache.free_texture_ids.push_back(it->second.texture_id);
it = gfx_texture_cache.map.erase(it);
} else {
++it;
}
}
}
static void import_texture_rgba16(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) {
const uint8_t* addr = loaded_texture.addr; const uint8_t* addr = loaded_texture.addr;
const uint32_t size_bytes = loaded_texture.size_bytes; const uint32_t size_bytes = loaded_texture.size_bytes;
const uint32_t full_image_line_size_bytes = const uint32_t full_image_line_size_bytes =
@@ -613,11 +634,11 @@ static void import_texture_rgba16(int tile, const LoadedTexture& loaded_texture,
const uint32_t width = rdp.texture_tile[tile].line_size_bytes / 2; const uint32_t width = rdp.texture_tile[tile].line_size_bytes / 2;
const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes; const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes;
gfx_rapi->upload_texture(tex_upload_buffer, width, height); gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps);
// DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height);
} }
static void import_texture_rgba32(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { static void import_texture_rgba32(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) {
const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata;
const uint8_t* addr = loaded_texture.addr; const uint8_t* addr = loaded_texture.addr;
const uint32_t size_bytes = loaded_texture.size_bytes; const uint32_t size_bytes = loaded_texture.size_bytes;
@@ -634,11 +655,11 @@ static void import_texture_rgba32(int tile, const LoadedTexture& loaded_texture,
const uint32_t width = rdp.texture_tile[tile].line_size_bytes / 2; const uint32_t width = rdp.texture_tile[tile].line_size_bytes / 2;
const uint32_t height = (size_bytes / 2) / rdp.texture_tile[tile].line_size_bytes; const uint32_t height = (size_bytes / 2) / rdp.texture_tile[tile].line_size_bytes;
gfx_rapi->upload_texture(tex_upload_buffer, width, height); gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps);
// DumpTexture(loaded_texture.otr_path, addr, width, height); // DumpTexture(loaded_texture.otr_path, addr, width, height);
} }
static void import_texture_ia4(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { static void import_texture_ia4(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) {
const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata;
const uint8_t* addr = loaded_texture.addr; const uint8_t* addr = loaded_texture.addr;
const uint32_t size_bytes = loaded_texture.size_bytes; const uint32_t size_bytes = loaded_texture.size_bytes;
@@ -663,11 +684,11 @@ static void import_texture_ia4(int tile, const LoadedTexture& loaded_texture, bo
const uint32_t width = rdp.texture_tile[tile].line_size_bytes * 2; const uint32_t width = rdp.texture_tile[tile].line_size_bytes * 2;
const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes; const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes;
gfx_rapi->upload_texture(tex_upload_buffer, width, height); gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps);
// DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height);
} }
static void import_texture_ia8(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { static void import_texture_ia8(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) {
const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata;
const uint8_t* addr = loaded_texture.addr; const uint8_t* addr = loaded_texture.addr;
const uint32_t size_bytes = loaded_texture.size_bytes; const uint32_t size_bytes = loaded_texture.size_bytes;
@@ -689,11 +710,11 @@ static void import_texture_ia8(int tile, const LoadedTexture& loaded_texture, bo
const uint32_t width = rdp.texture_tile[tile].line_size_bytes; const uint32_t width = rdp.texture_tile[tile].line_size_bytes;
const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes; const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes;
gfx_rapi->upload_texture(tex_upload_buffer, width, height); gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps);
// DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height);
} }
static void import_texture_ia16(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { static void import_texture_ia16(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) {
const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata;
const uint8_t* addr = loaded_texture.addr; const uint8_t* addr = loaded_texture.addr;
const uint32_t size_bytes = loaded_texture.size_bytes; const uint32_t size_bytes = loaded_texture.size_bytes;
@@ -715,11 +736,11 @@ static void import_texture_ia16(int tile, const LoadedTexture& loaded_texture, b
const uint32_t width = rdp.texture_tile[tile].line_size_bytes / 2; const uint32_t width = rdp.texture_tile[tile].line_size_bytes / 2;
const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes; const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes;
gfx_rapi->upload_texture(tex_upload_buffer, width, height); gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps);
// DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height);
} }
static void import_texture_i4(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { static void import_texture_i4(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) {
const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata;
const uint8_t* addr = loaded_texture.addr; const uint8_t* addr = loaded_texture.addr;
const uint32_t size_bytes = loaded_texture.size_bytes; const uint32_t size_bytes = loaded_texture.size_bytes;
@@ -742,11 +763,11 @@ static void import_texture_i4(int tile, const LoadedTexture& loaded_texture, boo
const uint32_t width = rdp.texture_tile[tile].line_size_bytes * 2; const uint32_t width = rdp.texture_tile[tile].line_size_bytes * 2;
const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes; const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes;
gfx_rapi->upload_texture(tex_upload_buffer, width, height); gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps);
// DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height);
} }
static void import_texture_i8(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { static void import_texture_i8(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) {
const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata;
const uint8_t* addr = loaded_texture.addr; const uint8_t* addr = loaded_texture.addr;
const uint32_t size_bytes = loaded_texture.size_bytes; const uint32_t size_bytes = loaded_texture.size_bytes;
@@ -767,7 +788,7 @@ static void import_texture_i8(int tile, const LoadedTexture& loaded_texture, boo
const uint32_t width = rdp.texture_tile[tile].line_size_bytes; const uint32_t width = rdp.texture_tile[tile].line_size_bytes;
const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes; const uint32_t height = size_bytes / rdp.texture_tile[tile].line_size_bytes;
gfx_rapi->upload_texture(tex_upload_buffer, width, height); gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps);
// DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height); // DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height);
} }
@@ -792,8 +813,8 @@ static inline void palette_to_rgba32(const uint16_t palentry, uint8_t *rgba32_bu
} }
} }
static void import_texture_ci4(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { static void import_texture_ci4(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) {
const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata;
const uint8_t* addr = loaded_texture.addr; const uint8_t* addr = loaded_texture.addr;
const uint32_t size_bytes = loaded_texture.size_bytes; const uint32_t size_bytes = loaded_texture.size_bytes;
const uint32_t full_image_line_size_bytes = const uint32_t full_image_line_size_bytes =
@@ -817,11 +838,11 @@ static void import_texture_ci4(int tile, const LoadedTexture& loaded_texture, bo
const uint32_t width = result_line_size * 2; const uint32_t width = result_line_size * 2;
const uint32_t height = size_bytes / result_line_size; const uint32_t height = size_bytes / result_line_size;
gfx_rapi->upload_texture(tex_upload_buffer, width, height); gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps);
} }
static void import_texture_ci8(int tile, const LoadedTexture& loaded_texture, bool importReplacement) { static void import_texture_ci8(int tile, const LoadedTexture& loaded_texture, bool gen_mipmaps) {
const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata; const RawTexMetadata* metadata = &loaded_texture.raw_tex_metadata;
const uint8_t* addr = loaded_texture.addr; const uint8_t* addr = loaded_texture.addr;
const uint32_t size_bytes = loaded_texture.size_bytes; const uint32_t size_bytes = loaded_texture.size_bytes;
const uint32_t full_image_line_size_bytes = const uint32_t full_image_line_size_bytes =
@@ -843,8 +864,7 @@ static void import_texture_ci8(int tile, const LoadedTexture& loaded_texture, bo
const uint32_t width = result_line_size; const uint32_t width = result_line_size;
const uint32_t height = size_bytes / result_line_size; const uint32_t height = size_bytes / result_line_size;
gfx_rapi->upload_texture(tex_upload_buffer, width, height); gfx_rapi->upload_texture(tex_upload_buffer, width, height, gen_mipmaps);
// DumpTexture(loaded_texture.otr_path, rgba32_buf, width, height);
} }
static void import_texture(int i, int tile, bool importReplacement) { static void import_texture(int i, int tile, bool importReplacement) {
@@ -886,35 +906,35 @@ static void import_texture(int i, int tile, bool importReplacement) {
if (fmt == G_IM_FMT_RGBA) { if (fmt == G_IM_FMT_RGBA) {
if (siz == G_IM_SIZ_16b) { if (siz == G_IM_SIZ_16b) {
import_texture_rgba16(tile, loaded_texture, importReplacement); import_texture_rgba16(tile, loaded_texture, rdp.tex_lod);
} else if (siz == G_IM_SIZ_32b) { } else if (siz == G_IM_SIZ_32b) {
import_texture_rgba32(tile, loaded_texture, importReplacement); import_texture_rgba32(tile, loaded_texture, rdp.tex_lod);
} else { } else {
sysFatalError("Bad size for RGBA texture in tile %d: %02x", tile, siz); sysFatalError("Bad size for RGBA texture in tile %d: %02x", tile, siz);
} }
} else if (fmt == G_IM_FMT_IA) { } else if (fmt == G_IM_FMT_IA) {
if (siz == G_IM_SIZ_4b) { if (siz == G_IM_SIZ_4b) {
import_texture_ia4(tile, loaded_texture, importReplacement); import_texture_ia4(tile, loaded_texture, rdp.tex_lod);
} else if (siz == G_IM_SIZ_8b) { } else if (siz == G_IM_SIZ_8b) {
import_texture_ia8(tile, loaded_texture, importReplacement); import_texture_ia8(tile, loaded_texture, rdp.tex_lod);
} else if (siz == G_IM_SIZ_16b) { } else if (siz == G_IM_SIZ_16b) {
import_texture_ia16(tile, loaded_texture, importReplacement); import_texture_ia16(tile, loaded_texture, rdp.tex_lod);
} else { } else {
sysFatalError("Bad size for IA texture in tile %d: %02x", tile, siz); sysFatalError("Bad size for IA texture in tile %d: %02x", tile, siz);
} }
} else if (fmt == G_IM_FMT_CI) { } else if (fmt == G_IM_FMT_CI) {
if (siz == G_IM_SIZ_4b) { if (siz == G_IM_SIZ_4b) {
import_texture_ci4(tile, loaded_texture, importReplacement); import_texture_ci4(tile, loaded_texture, rdp.tex_lod);
} else if (siz == G_IM_SIZ_8b) { } else if (siz == G_IM_SIZ_8b) {
import_texture_ci8(tile, loaded_texture, importReplacement); import_texture_ci8(tile, loaded_texture, rdp.tex_lod);
} else { } else {
sysFatalError("Bad size for CI texture in tile %d: %02x", tile, siz); sysFatalError("Bad size for CI texture in tile %d: %02x", tile, siz);
} }
} else if (fmt == G_IM_FMT_I) { } else if (fmt == G_IM_FMT_I) {
if (siz == G_IM_SIZ_4b) { if (siz == G_IM_SIZ_4b) {
import_texture_i4(tile, loaded_texture, importReplacement); import_texture_i4(tile, loaded_texture, rdp.tex_lod);
} else if (siz == G_IM_SIZ_8b) { } else if (siz == G_IM_SIZ_8b) {
import_texture_i8(tile, loaded_texture, importReplacement); import_texture_i8(tile, loaded_texture, rdp.tex_lod);
} else { } else {
sysFatalError("Bad size for I texture in tile %d: %02x", tile, siz); sysFatalError("Bad size for I texture in tile %d: %02x", tile, siz);
} }
@@ -1240,25 +1260,18 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
} }
} }
bool depth_test = (rsp.geometry_mode & G_ZBUFFER) == G_ZBUFFER; bool depth_test = ((rsp.geometry_mode & G_ZBUFFER) == G_ZBUFFER || (rdp.other_mode_l & G_ZS_PRIM) == G_ZS_PRIM) &&
bool depth_mask = (rdp.other_mode_l & Z_UPD) == Z_UPD; ((rdp.other_mode_h & G_CYC_1CYCLE) == G_CYC_1CYCLE || (rdp.other_mode_h & G_CYC_2CYCLE) == G_CYC_2CYCLE);
uint8_t depth_test_and_mask = (depth_test ? 1 : 0) | (depth_mask ? 2 : 0); bool depth_update = (rdp.other_mode_l & Z_UPD) == Z_UPD;
if (depth_test_and_mask != rendering_state.depth_test_and_mask) { bool depth_compare = (rdp.other_mode_l & Z_CMP) == Z_CMP;
gfx_flush(); bool depth_source_prim = (rdp.other_mode_l & G_ZS_PRIM) == G_ZS_PRIM /* && gDP.primDepth.z == 1.0f */;
gfx_rapi->set_depth_test_and_mask(depth_test, depth_mask); uint16_t zmode = rdp.other_mode_l & ZMODE_DEC;
rendering_state.depth_test_and_mask = depth_test_and_mask; uint8_t depth_mode = (depth_test ? 1 : 0) | (depth_update ? 2 : 0) | (depth_compare ? 4 : 0) | (depth_source_prim ? 8 : 0) | (zmode >> 6);
}
if (rsp.depth_zfar != rendering_state.depth_zfar) {
gfx_flush();
gfx_rapi->set_depth_range(0.0f, rsp.depth_zfar);
rendering_state.depth_zfar = rsp.depth_zfar;
}
bool zmode_decal = (rdp.other_mode_l & ZMODE_DEC) == ZMODE_DEC; if (depth_mode != rendering_state.depth_mode) {
if (zmode_decal != rendering_state.decal_mode) {
gfx_flush(); gfx_flush();
gfx_rapi->set_zmode_decal(zmode_decal); gfx_rapi->set_depth_mode(depth_test, depth_update, depth_compare, depth_source_prim, zmode);
rendering_state.decal_mode = zmode_decal; rendering_state.depth_mode = depth_mode;
} }
if (rdp.viewport_or_scissor_changed) { if (rdp.viewport_or_scissor_changed) {
@@ -1391,7 +1404,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
if (linear_filter != rendering_state.textures[i]->second.linear_filter || if (linear_filter != rendering_state.textures[i]->second.linear_filter ||
cms != rendering_state.textures[i]->second.cms || cmt != rendering_state.textures[i]->second.cmt) { cms != rendering_state.textures[i]->second.cms || cmt != rendering_state.textures[i]->second.cmt) {
gfx_flush(); gfx_flush();
gfx_rapi->set_sampler_parameters(i, linear_filter, cms, cmt); gfx_rapi->set_sampler_parameters(i, linear_filter, cms, cmt, rdp.tex_lod);
rendering_state.textures[i]->second.linear_filter = linear_filter; rendering_state.textures[i]->second.linear_filter = linear_filter;
rendering_state.textures[i]->second.cms = cms; rendering_state.textures[i]->second.cms = cms;
rendering_state.textures[i]->second.cmt = cmt; rendering_state.textures[i]->second.cmt = cmt;
@@ -1584,7 +1597,7 @@ static inline void gfx_sp_tri4(Gfx *cmd) {
uint8_t x = C1(0, 4); uint8_t x = C1(0, 4);
uint8_t y = C1(4, 4); uint8_t y = C1(4, 4);
uint8_t z = C0(0, 4); uint8_t z = C0(0, 4);
if(x || y || z) { if(x || y || z) {
gfx_sp_tri1(x, y, z, false); gfx_sp_tri1(x, y, z, false);
} }
@@ -1648,34 +1661,34 @@ static void gfx_sp_extra_geometry_mode(uint32_t clear, uint32_t set) {
} }
static void gfx_adjust_viewport_or_scissor(XYWidthHeight* area, bool preserve_aspect = false) { static void gfx_adjust_viewport_or_scissor(XYWidthHeight* area, bool preserve_aspect = false) {
if (!fbActive) { // HACK: assume all target framebuffers have the same aspect
area->width *= RATIO_X; // Use floor/ceil to ensure scissor fully contains the logical region
area->x *= RATIO_X; // and prevents sub-pixel gaps at viewport edges
area->height *= RATIO_Y; float x1 = area->x * RATIO_X;
area->y = SCREEN_HEIGHT - area->y; float y1 = (SCREEN_HEIGHT - area->y) * RATIO_Y;
area->y *= RATIO_Y; float x2 = (area->x + area->width) * RATIO_X;
if (preserve_aspect) { float y2 = (SCREEN_HEIGHT - area->y + area->height) * RATIO_Y;
// preserve native aspect ratio
const float ratio = gfx_current_native_aspect / gfx_current_dimensions.aspect_ratio; area->x = std::floor(x1);
const float midx = gfx_current_dimensions.width * 0.5f; area->y = std::floor(y1);
area->x = midx + (area->x - midx) * ratio; area->width = std::ceil(x2) - area->x;
area->x += rsp.aspect_ofs * gfx_current_dimensions.width * 0.5f; area->height = std::ceil(y2) - area->y;
area->width *= ratio;
} if (preserve_aspect) {
// preserve native aspect ratio
const float ratio = gfx_current_native_aspect / gfx_current_dimensions.aspect_ratio;
const float midx = gfx_current_dimensions.width * 0.5f;
area->x = midx + (area->x - midx) * ratio;
area->x += rsp.aspect_ofs * gfx_current_dimensions.width * 0.5f;
area->width *= ratio;
}
if (!game_renders_to_framebuffer || if (!game_renders_to_framebuffer ||
(gfx_msaa_level > 1 && gfx_current_dimensions.width == gfx_current_game_window_viewport.width && (gfx_msaa_level > 1 && gfx_current_dimensions.width == gfx_current_game_window_viewport.width &&
gfx_current_dimensions.height == gfx_current_game_window_viewport.height)) { gfx_current_dimensions.height == gfx_current_game_window_viewport.height)) {
area->x += gfx_current_game_window_viewport.x; area->x += gfx_current_game_window_viewport.x;
area->y += gfx_current_window_dimensions.height - area->y += gfx_current_window_dimensions.height -
(gfx_current_game_window_viewport.y + gfx_current_game_window_viewport.height); (gfx_current_game_window_viewport.y + gfx_current_game_window_viewport.height);
}
} else {
area->width *= RATIO_Y;
area->height *= RATIO_Y;
area->x *= RATIO_Y;
area->y = active_fb->second.orig_height - area->y;
area->y *= RATIO_Y;
} }
} }
@@ -1733,18 +1746,6 @@ static void gfx_sp_moveword(uint8_t index, uint16_t offset, uintptr_t data) {
case G_MW_SEGMENT: case G_MW_SEGMENT:
segmentPointers[(offset >> 2) & 0xff] = data; segmentPointers[(offset >> 2) & 0xff] = data;
break; break;
case G_MW_PERSPNORM:
// the default z range is around [100, 10000]
// data is 2 / (znear + zfar) represented as a 0.16 fixed point
// => (znear + zfar) = (2 / (data / 65536)) = 131072 / data
constexpr float full_range_mul = 1.f / 11000.f; // that's around the biggest value I got when testing
if (data == 0) {
rsp.depth_zfar = 1.f;
} else {
// sometimes this will overshoot 1 but GL can handle that
rsp.depth_zfar =((131072.f * full_range_mul) / (float)data);
}
break;
} }
} }
@@ -1999,6 +2000,11 @@ static void gfx_dp_set_fill_color(uint32_t packed_color) {
rdp.fill_color.a = a * 255; rdp.fill_color.a = a * 255;
} }
static void gfx_dp_set_subpixel_offset(int16_t x, int16_t y) {
rdp.subpixel_ofs_x = x;
rdp.subpixel_ofs_y = y;
}
static void gfx_draw_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry) { static void gfx_draw_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry) {
uint32_t saved_other_mode_h = rdp.other_mode_h; uint32_t saved_other_mode_h = rdp.other_mode_h;
uint32_t cycle_type = (rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE)); uint32_t cycle_type = (rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE));
@@ -2007,6 +2013,11 @@ static void gfx_draw_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lr
rdp.other_mode_h = (rdp.other_mode_h & ~(3U << G_MDSFT_TEXTFILT)) | G_TF_POINT; rdp.other_mode_h = (rdp.other_mode_h & ~(3U << G_MDSFT_TEXTFILT)) | G_TF_POINT;
} }
ulx += rdp.subpixel_ofs_x;
lrx += rdp.subpixel_ofs_x;
uly += rdp.subpixel_ofs_y;
lry += rdp.subpixel_ofs_y;
// U10.2 coordinates // U10.2 coordinates
float ulxf = ulx; float ulxf = ulx;
float ulyf = uly; float ulyf = uly;
@@ -2391,6 +2402,10 @@ static void gfx_run_dl(Gfx* cmd) {
break; break;
// G_SETPRIMCOLOR, G_CCMUX_PRIMITIVE, G_ACMUX_PRIMITIVE, is used by Goddard // G_SETPRIMCOLOR, G_CCMUX_PRIMITIVE, G_ACMUX_PRIMITIVE, is used by Goddard
// G_CCMUX_TEXEL1, LOD_FRACTION is used in Bowser room 1 // G_CCMUX_TEXEL1, LOD_FRACTION is used in Bowser room 1
case G_SETSUBPIXELOFFSET_EXT: {
gfx_dp_set_subpixel_offset(C0(0, 16), C1(0, 16));
break;
}
case G_TEXRECT: case G_TEXRECT:
case G_TEXRECTFLIP: { case G_TEXRECTFLIP: {
int32_t lrx, lry, tile, ulx, uly; int32_t lrx, lry, tile, ulx, uly;
@@ -2504,6 +2519,10 @@ static void gfx_run_dl(Gfx* cmd) {
case G_RDPFLUSH_EXT: case G_RDPFLUSH_EXT:
gfx_flush(); gfx_flush();
break; break;
case G_CLEAR_DEPTH_EXT:
gfx_flush();
gfx_rapi->clear_framebuffer(false, true);
break;
case G_RDPPIPESYNC: case G_RDPPIPESYNC:
case G_RDPFULLSYNC: case G_RDPFULLSYNC:
case G_RDPLOADSYNC: case G_RDPLOADSYNC:
@@ -2554,8 +2573,6 @@ extern "C" void gfx_init(const GfxInitSettings *settings) {
tex_upload_buffer = (uint8_t*)malloc(max_tex_size * max_tex_size * 4); tex_upload_buffer = (uint8_t*)malloc(max_tex_size * max_tex_size * 4);
} }
rsp.depth_zfar = 1.0f;
rsp.lookat[0].dir[0] = rsp.lookat[1].dir[1] = 0x7F; rsp.lookat[0].dir[0] = rsp.lookat[1].dir[1] = 0x7F;
rsp.current_lookat_coeffs[0][0] = rsp.current_lookat_coeffs[1][1] = 1.f; rsp.current_lookat_coeffs[0][0] = rsp.current_lookat_coeffs[1][1] = 1.f;
rsp.lookat_enabled = true; rsp.lookat_enabled = true;
@@ -2661,7 +2678,7 @@ extern "C" void gfx_run(Gfx* commands) {
gfx_rapi->start_frame(); gfx_rapi->start_frame();
gfx_rapi->start_draw_to_framebuffer(game_renders_to_framebuffer ? game_framebuffer : 0, gfx_rapi->start_draw_to_framebuffer(game_renders_to_framebuffer ? game_framebuffer : 0,
(float)gfx_current_dimensions.height / SCREEN_HEIGHT); (float)gfx_current_dimensions.height / SCREEN_HEIGHT);
gfx_rapi->clear_framebuffer(); gfx_rapi->clear_framebuffer(true, false);
rdp.viewport_or_scissor_changed = true; rdp.viewport_or_scissor_changed = true;
rendering_state.viewport = {}; rendering_state.viewport = {};
rendering_state.scissor = {}; rendering_state.scissor = {};
@@ -2671,7 +2688,7 @@ extern "C" void gfx_run(Gfx* commands) {
if (game_renders_to_framebuffer) { if (game_renders_to_framebuffer) {
gfx_rapi->start_draw_to_framebuffer(0, 1); gfx_rapi->start_draw_to_framebuffer(0, 1);
gfx_rapi->clear_framebuffer(); gfx_rapi->clear_framebuffer(true, true);
if (gfx_msaa_level > 1) { if (gfx_msaa_level > 1) {
bool different_size = gfx_current_dimensions.width != gfx_current_game_window_viewport.width || bool different_size = gfx_current_dimensions.width != gfx_current_game_window_viewport.width ||
@@ -2703,6 +2720,27 @@ extern "C" void gfx_set_target_fps(int fps) {
gfx_wapi->set_target_fps(fps); gfx_wapi->set_target_fps(fps);
} }
extern "C" void reset_texture_state() {
gfx_texture_cache_clear();
if (rendering_state.shader_program) {
gfx_rapi->unload_shader(rendering_state.shader_program);
rendering_state.shader_program = nullptr;
}
gfx_rapi->clear_shaders();
color_combiner_pool.clear();
prev_combiner = color_combiner_pool.end();
}
extern "C" void gfx_set_texture_filter(enum FilteringMode mode) {
reset_texture_state();
gfx_rapi->set_texture_filter(mode);
}
extern "C" void gfx_set_mipmap_filter(enum MipmapFilteringMode mode) {
reset_texture_state();
gfx_rapi->set_mipmap_filter(mode);
}
extern "C" int gfx_create_framebuffer(uint32_t width, uint32_t height, int upscale, int autoresize) { extern "C" int gfx_create_framebuffer(uint32_t width, uint32_t height, int upscale, int autoresize) {
int fb = gfx_rapi->create_framebuffer(); int fb = gfx_rapi->create_framebuffer();
gfx_resize_framebuffer(fb, width, height, upscale, autoresize); gfx_resize_framebuffer(fb, width, height, upscale, autoresize);
@@ -2734,7 +2772,8 @@ extern "C" void gfx_resize_framebuffer(int fb, uint32_t width, uint32_t height,
extern "C" void gfx_set_framebuffer(int fb, float noise_scale) { extern "C" void gfx_set_framebuffer(int fb, float noise_scale) {
gfx_rapi->start_draw_to_framebuffer(fb, noise_scale); gfx_rapi->start_draw_to_framebuffer(fb, noise_scale);
gfx_rapi->clear_framebuffer(); gfx_rapi->clear_framebuffer(true, true);
active_fb = framebuffers.find(fb);
} }
extern "C" void gfx_copy_framebuffer(int fb_dst, int fb_src, int left, int top, int use_back) { extern "C" void gfx_copy_framebuffer(int fb_dst, int fb_src, int left, int top, int use_back) {
@@ -2759,4 +2798,5 @@ extern "C" void gfx_copy_framebuffer(int fb_dst, int fb_src, int left, int top,
extern "C" void gfx_reset_framebuffer(void) { extern "C" void gfx_reset_framebuffer(void) {
gfx_rapi->start_draw_to_framebuffer(0, (float)gfx_current_dimensions.height / SCREEN_HEIGHT); gfx_rapi->start_draw_to_framebuffer(0, (float)gfx_current_dimensions.height / SCREEN_HEIGHT);
active_fb = framebuffers.end();
} }
+10 -6
View File
@@ -13,6 +13,7 @@ struct GfxClipParameters {
}; };
enum FilteringMode { FILTER_NONE, FILTER_LINEAR, FILTER_THREE_POINT }; enum FilteringMode { FILTER_NONE, FILTER_LINEAR, FILTER_THREE_POINT };
enum MipmapFilteringMode { MIPMAP_DISABLED, MIPMAP_NEAREST, MIPMAP_LINEAR };
struct GfxRenderingAPI { struct GfxRenderingAPI {
const char* (*get_name)(void); const char* (*get_name)(void);
@@ -23,13 +24,13 @@ struct GfxRenderingAPI {
struct ShaderProgram* (*create_and_load_new_shader)(uint64_t shader_id0, uint32_t shader_id1); struct ShaderProgram* (*create_and_load_new_shader)(uint64_t shader_id0, uint32_t shader_id1);
struct ShaderProgram* (*lookup_shader)(uint64_t shader_id0, uint32_t shader_id1); struct ShaderProgram* (*lookup_shader)(uint64_t shader_id0, uint32_t shader_id1);
void (*shader_get_info)(struct ShaderProgram* prg, uint8_t* num_inputs, bool used_textures[2]); void (*shader_get_info)(struct ShaderProgram* prg, uint8_t* num_inputs, bool used_textures[2]);
void (*clear_shaders)(void);
uint32_t (*new_texture)(void); uint32_t (*new_texture)(void);
void (*select_texture)(int tile, uint32_t texture_id); void (*select_texture)(int tile, uint32_t texture_id, bool linear_filter);
void (*upload_texture)(const uint8_t* rgba32_buf, uint32_t width, uint32_t height); void (*upload_texture)(const uint8_t* rgba32_buf, uint32_t width, uint32_t height, bool gen_mipmaps);
void (*set_sampler_parameters)(int sampler, bool linear_filter, uint32_t cms, uint32_t cmt); void (*set_sampler_parameters)(int sampler, bool linear_filter, uint32_t cms, uint32_t cmt, bool mipmaps);
void (*set_depth_test_and_mask)(bool depth_test, bool z_upd); void (*set_depth_mode)(bool depth_test, bool depth_update, bool depth_compare, bool depth_source_prim, uint16_t zmode);
void (*set_depth_range)(float znear, float zfar); void (*set_depth_range)(float znear, float zfar);
void (*set_zmode_decal)(bool zmode_decal);
void (*set_viewport)(int x, int y, int width, int height); void (*set_viewport)(int x, int y, int width, int height);
void (*set_scissor)(int x, int y, int width, int height); void (*set_scissor)(int x, int y, int width, int height);
void (*set_use_alpha)(bool use_alpha, bool modulate); void (*set_use_alpha)(bool use_alpha, bool modulate);
@@ -45,13 +46,16 @@ struct GfxRenderingAPI {
bool can_extract_depth); bool can_extract_depth);
bool (*start_draw_to_framebuffer)(int fb_id, float noise_scale); bool (*start_draw_to_framebuffer)(int fb_id, float noise_scale);
void (*copy_framebuffer)(int fb_dst, int fb_src, int left, int top, bool flip_y, bool use_back); void (*copy_framebuffer)(int fb_dst, int fb_src, int left, int top, bool flip_y, bool use_back);
void (*clear_framebuffer)(void); void (*clear_framebuffer)(bool clear_color, bool clear_depth);
void (*resolve_msaa_color_buffer)(int fb_id_target, int fb_id_source); void (*resolve_msaa_color_buffer)(int fb_id_target, int fb_id_source);
void* (*get_framebuffer_texture_id)(int fb_id); void* (*get_framebuffer_texture_id)(int fb_id);
void (*select_texture_fb)(int fb_id); void (*select_texture_fb)(int fb_id);
void (*delete_texture)(uint32_t texID); void (*delete_texture)(uint32_t texID);
void (*set_texture_filter)(enum FilteringMode mode); void (*set_texture_filter)(enum FilteringMode mode);
enum FilteringMode (*get_texture_filter)(void); enum FilteringMode (*get_texture_filter)(void);
void (*set_mipmap_filter)(enum MipmapFilteringMode mode);
void (*set_anisotropy_level)(int);
int (*get_max_anisotropy_level)(void);
}; };
#endif #endif
+152 -31
View File
@@ -30,10 +30,30 @@ static uint64_t qpc_freq;
#define FRAME_INTERVAL_US_NUMERATOR 1000000 #define FRAME_INTERVAL_US_NUMERATOR 1000000
#define FRAME_INTERVAL_US_DENOMINATOR (target_fps) #define FRAME_INTERVAL_US_DENOMINATOR (target_fps)
static void set_fullscreen(bool on, bool call_callback) { static int32_t gfx_sdl_get_maximized_state(void) {
if (fullscreen_state == on) { return (int32_t)maximized_state;
return; }
static int32_t gfx_sdl_get_fullscreen_state(void) {
return (int32_t)fullscreen_state;
}
static int32_t gfx_sdl_get_fullscreen_flag_mode(void) {
return fullscreen_flag == SDL_WINDOW_FULLSCREEN_DESKTOP ? 0 : 1;
}
static void gfx_sdl_set_fullscreen_flag(int32_t mode) {
switch (mode) {
case 0: {
fullscreen_flag = SDL_WINDOW_FULLSCREEN_DESKTOP;
} break;
case 1: {
fullscreen_flag = SDL_WINDOW_FULLSCREEN;
} break;
} }
}
static void set_fullscreen(bool on, bool call_callback) {
fullscreen_state = on; fullscreen_state = on;
SDL_SetWindowFullscreen(wnd, on ? fullscreen_flag : 0); SDL_SetWindowFullscreen(wnd, on ? fullscreen_flag : 0);
if (call_callback && on_fullscreen_changed_callback) { if (call_callback && on_fullscreen_changed_callback) {
@@ -42,9 +62,6 @@ static void set_fullscreen(bool on, bool call_callback) {
} }
static void set_maximize_window(bool on) { static void set_maximize_window(bool on) {
if (maximized_state == on) {
return;
}
maximized_state = on; maximized_state = on;
if (on) { if (on) {
SDL_MaximizeWindow(wnd); SDL_MaximizeWindow(wnd);
@@ -83,7 +100,6 @@ static void gfx_sdl_init(const struct GfxWindowInitSettings *set) {
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
if (sysArgCheck("--debug-gl")) { if (sysArgCheck("--debug-gl")) {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
} }
@@ -92,15 +108,23 @@ static void gfx_sdl_init(const struct GfxWindowInitSettings *set) {
int posY = set->y; int posY = set->y;
int display_in_use = SDL_GetWindowDisplayIndex(wnd); int display_in_use = SDL_GetWindowDisplayIndex(wnd);
if (display_in_use < 0) { // Fallback to default if out of bounds if (display_in_use < 0) { // Fallback to default if out of bounds
posX = 100; posX = SDL_WINDOWPOS_UNDEFINED;
posY = 100; posY = SDL_WINDOWPOS_UNDEFINED;
}
if (set->centered) {
SDL_DisplayMode mode = {};
SDL_GetCurrentDisplayMode(0, &mode);
posX = mode.w / 2 - window_width / 2;
posY = mode.h / 2 - window_height / 2;
} }
if (set->fullscreen_is_exclusive) { if (set->fullscreen_is_exclusive) {
fullscreen_flag = SDL_WINDOW_FULLSCREEN; fullscreen_flag = SDL_WINDOW_FULLSCREEN;
} }
Uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL; // we will unhide the window once the GL context is successfully created
Uint32 flags = SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL;
// if fullscreen was requested, start the window in fullscreen right away // if fullscreen was requested, start the window in fullscreen right away
if (set->fullscreen) { if (set->fullscreen) {
@@ -119,28 +143,25 @@ static void gfx_sdl_init(const struct GfxWindowInitSettings *set) {
} }
#endif #endif
wnd = SDL_CreateWindow(set->title, posX, posY, window_width, window_height, flags);
if (!wnd) {
sysFatalError("Could not open SDL window:\n%s", SDL_GetError());
}
// ideally we need 3.0 compat // ideally we need 3.0 compat
// if that doesn't work, try 3.2 core in case we're on mac, 2.1 compat as a last resort // if that doesn't work, try 3.2 core in case we're on mac, 2.1 compat as a last resort
static u32 glver[][3] = { static u32 glver[][3] = {
{ 0, 0, 0 }, // for command line override { 0, 0, 0 }, // for command line override
{ 3, 0, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY }, { 3, 0, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY }, // 3.0: default, has all the features required
{ 3, 2, SDL_GL_CONTEXT_PROFILE_CORE }, { 4, 1, SDL_GL_CONTEXT_PROFILE_CORE }, // 4.1core: macs only have core profile and this is the latest
{ 2, 1, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY }, { 3, 2, SDL_GL_CONTEXT_PROFILE_CORE }, // 3.2core: older macs will only have this at best
{ 3, 0, SDL_GL_CONTEXT_PROFILE_ES }, // es3: don't really support ES properly, but we can try
{ 2, 1, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY }, // 2.1: absolute last resort, will still require GLSL130 as an extension
}; };
u32 glcore = false;
u32 verstart = 1; u32 verstart = 1;
const u32 verend = sizeof(glver) / sizeof(*glver); const u32 verend = sizeof(glver) / sizeof(*glver);
const char *verstr = sysArgGetString("--gl-version"); const char *verstr = sysArgGetString("--gl-version");
if (verstr && *verstr) { if (verstr && *verstr) {
// user override // user override
glver[0][2] = strstr(verstr, "core") ? SDL_GL_CONTEXT_PROFILE_CORE : glver[0][2] = strstr(verstr, "core") ? SDL_GL_CONTEXT_PROFILE_CORE :
SDL_GL_CONTEXT_PROFILE_COMPATIBILITY; (strstr(verstr, "es") ? SDL_GL_CONTEXT_PROFILE_ES :
SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
sscanf(verstr, "%d.%d", &glver[0][0], &glver[0][1]); sscanf(verstr, "%d.%d", &glver[0][0], &glver[0][1]);
if (glver[0][0] >= 1 && glver[0][0] <= 4 && glver[0][1] < 9) { if (glver[0][0] >= 1 && glver[0][0] <= 4 && glver[0][1] < 9) {
verstart = 0; verstart = 0;
@@ -148,31 +169,44 @@ static void gfx_sdl_init(const struct GfxWindowInitSettings *set) {
} }
ctx = NULL; ctx = NULL;
u32 vmin = 0, vmaj = 0; u32 vmin = 0, vmaj = 0, vprof = SDL_GL_CONTEXT_PROFILE_COMPATIBILITY;
for (u32 i = verstart; i < verend; ++i) { const char *vprofstr = "";
for (u32 i = verstart; i < verend && !ctx; ++i) {
vmaj = glver[i][0]; vmaj = glver[i][0];
vmin = glver[i][1]; vmin = glver[i][1];
vprof = glver[i][2];
vprofstr = (vprof == SDL_GL_CONTEXT_PROFILE_CORE ? "core" :
(vprof == SDL_GL_CONTEXT_PROFILE_ES ? "es" : ""));
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, vmaj); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, vmaj);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, vmin); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, vmin);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, glver[i][2]); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, vprof);
wnd = SDL_CreateWindow(set->title, posX, posY, window_width, window_height, flags);
if (!wnd) {
sysLogPrintf(LOG_WARNING, "SDL: could not open SDL window for GL%d.%d%s:\n%s", vmaj, vmin, vprofstr, SDL_GetError());
continue;
}
ctx = SDL_GL_CreateContext(wnd); ctx = SDL_GL_CreateContext(wnd);
if (!ctx) { if (!ctx) {
sysLogPrintf(LOG_WARNING, "GL: could not create GL%d.%d context: %s", vmaj, vmin, SDL_GetError()); sysLogPrintf(LOG_WARNING, "SDL: could not create GL%d.%d%s context: %s", vmaj, vmin, vprofstr, SDL_GetError());
} else { SDL_DestroyWindow(wnd);
glcore = (glver[i][2] == SDL_GL_CONTEXT_PROFILE_CORE); wnd = nullptr;
break;
} }
} }
if (!ctx) { if (!wnd || !ctx) {
sysFatalError("Could not create an OpenGL context of any supported version.\nSDL error: %s", SDL_GetError()); sysFatalError("Could not open SDL window with an OpenGL context of any supported version:\n%s", SDL_GetError());
} else { } else {
sysLogPrintf(LOG_NOTE, "GL: created GL%d.%d%s context", vmaj, vmin, glcore ? "core" : ""); sysLogPrintf(LOG_NOTE, "SDL: created GL%d.%d%s context", vmaj, vmin, vprofstr);
} }
SDL_GL_MakeCurrent(wnd, ctx); SDL_GL_MakeCurrent(wnd, ctx);
SDL_GL_SetSwapInterval(1); SDL_GL_SetSwapInterval(1);
SDL_ShowWindow(wnd);
qpc_freq = SDL_GetPerformanceFrequency(); qpc_freq = SDL_GetPerformanceFrequency();
} }
@@ -212,6 +246,43 @@ static void gfx_sdl_set_cursor_visibility(bool visible) {
} }
} }
static void get_centered_positions_native(int32_t width, int32_t height, int32_t *posX, int32_t *posY) {
const int disp_idx = SDL_GetWindowDisplayIndex(wnd);
SDL_DisplayMode mode = {};
SDL_GetDesktopDisplayMode(disp_idx, &mode);
*posX = mode.w / 2 - width / 2;
*posY = mode.h / 2 - height / 2;
}
static void gfx_sdl_get_centered_positions(int32_t width, int32_t height, int32_t *posX, int32_t *posY) {
const int disp_idx = SDL_GetWindowDisplayIndex(wnd);
SDL_DisplayMode mode = {};
SDL_GetCurrentDisplayMode(disp_idx, &mode);
*posX = mode.w / 2 - width / 2;
*posY = mode.h / 2 - height / 2;
}
static void gfx_sdl_set_closest_resolution(int32_t width, int32_t height, bool should_center) {
const SDL_DisplayMode mode = {.w = width, .h = height};
const int disp_idx = SDL_GetWindowDisplayIndex(wnd);
SDL_DisplayMode closest = {};
if (SDL_GetClosestDisplayMode(disp_idx, &mode, &closest)) {
SDL_SetWindowDisplayMode(wnd, &closest);
SDL_SetWindowSize(wnd, closest.w, closest.h);
if (should_center) {
int32_t posX = 0;
int32_t posY = 0;
get_centered_positions_native(closest.w, closest.h, &posX, &posY);
SDL_SetWindowPosition(wnd, posX, posY);
}
}
}
static void gfx_sdl_set_dimensions(uint32_t width, uint32_t height, int32_t posX, int32_t posY) {
SDL_SetWindowSize(wnd, width, height);
SDL_SetWindowPosition(wnd, posX, posY);
}
static void gfx_sdl_get_dimensions(uint32_t* width, uint32_t* height, int32_t* posX, int32_t* posY) { static void gfx_sdl_get_dimensions(uint32_t* width, uint32_t* height, int32_t* posX, int32_t* posY) {
SDL_GL_GetDrawableSize(wnd, static_cast<int*>((void*)width), static_cast<int*>((void*)height)); SDL_GL_GetDrawableSize(wnd, static_cast<int*>((void*)width), static_cast<int*>((void*)height));
SDL_GetWindowPosition(wnd, static_cast<int*>(posX), static_cast<int*>(posY)); SDL_GetWindowPosition(wnd, static_cast<int*>(posX), static_cast<int*>(posY));
@@ -230,6 +301,9 @@ static void gfx_sdl_handle_events(void) {
case SDL_WINDOWEVENT: case SDL_WINDOWEVENT:
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
SDL_GL_GetDrawableSize(wnd, &window_width, &window_height); SDL_GL_GetDrawableSize(wnd, &window_width, &window_height);
if (!fullscreen_state) {
maximized_state = SDL_GetWindowFlags(wnd) & SDL_WINDOW_MAXIMIZED ? true : false;
}
} else if (event.window.event == SDL_WINDOWEVENT_CLOSE && } else if (event.window.event == SDL_WINDOWEVENT_CLOSE &&
event.window.windowID == SDL_GetWindowID(wnd)) { event.window.windowID == SDL_GetWindowID(wnd)) {
// We listen specifically for main window close because closing main window // We listen specifically for main window close because closing main window
@@ -294,6 +368,10 @@ static double gfx_sdl_get_time(void) {
return SDL_GetPerformanceCounter() / (double)qpc_freq; return SDL_GetPerformanceCounter() / (double)qpc_freq;
} }
static int32_t gfx_sdl_get_target_fps(void) {
return target_fps;
}
static void gfx_sdl_set_target_fps(int fps) { static void gfx_sdl_set_target_fps(int fps) {
target_fps = fps; target_fps = fps;
} }
@@ -310,6 +388,10 @@ static void gfx_sdl_set_window_title(const char *title) {
SDL_SetWindowTitle(wnd, title); SDL_SetWindowTitle(wnd, title);
} }
static int gfx_sdl_get_swap_interval(void) {
return SDL_GL_GetSwapInterval();
}
static bool gfx_sdl_set_swap_interval(int interval) { static bool gfx_sdl_set_swap_interval(int interval) {
const bool success = SDL_GL_SetSwapInterval(interval) >= 0; const bool success = SDL_GL_SetSwapInterval(interval) >= 0;
vsync_enabled = success && (interval != 0); vsync_enabled = success && (interval != 0);
@@ -319,24 +401,63 @@ static bool gfx_sdl_set_swap_interval(int interval) {
return success; return success;
} }
struct GfxWindowManagerAPI gfx_sdl = { int gfx_sdl_get_display_mode(int modenum, int *out_w, int *out_h) {
const int display_in_use = SDL_GetWindowDisplayIndex(wnd);
SDL_DisplayMode sdlmode;
if (SDL_GetDisplayMode(display_in_use, modenum, &sdlmode) == 0) {
*out_w = sdlmode.w;
*out_h = sdlmode.h;
return 1;
}
return 0;
}
int gfx_sdl_get_current_display_mode(int *out_w, int *out_h) {
const int display_in_use = SDL_GetWindowDisplayIndex(wnd);
SDL_DisplayMode sdlmode;
if (SDL_GetCurrentDisplayMode(display_in_use, &sdlmode) == 0) {
*out_w = sdlmode.w;
*out_h = sdlmode.h;
return 1;
}
return 0;
}
int gfx_sdl_get_num_display_modes(void) {
const int display_in_use = SDL_GetWindowDisplayIndex(wnd);
return SDL_GetNumDisplayModes(display_in_use);
}
struct GfxWindowManagerAPI gfx_sdl = {
gfx_sdl_init, gfx_sdl_init,
gfx_sdl_close, gfx_sdl_close,
gfx_sdl_get_display_mode,
gfx_sdl_get_current_display_mode,
gfx_sdl_get_num_display_modes,
gfx_sdl_get_fullscreen_state,
gfx_sdl_set_fullscreen_changed_callback, gfx_sdl_set_fullscreen_changed_callback,
gfx_sdl_set_fullscreen, gfx_sdl_set_fullscreen,
gfx_sdl_set_fullscreen_exclusive, gfx_sdl_set_fullscreen_exclusive,
gfx_sdl_set_fullscreen_flag,
gfx_sdl_get_fullscreen_flag_mode,
gfx_sdl_get_maximized_state,
gfx_sdl_set_maximize_window, gfx_sdl_set_maximize_window,
gfx_sdl_get_active_window_refresh_rate, gfx_sdl_get_active_window_refresh_rate,
gfx_sdl_set_cursor_visibility, gfx_sdl_set_cursor_visibility,
gfx_sdl_set_closest_resolution,
gfx_sdl_set_dimensions,
gfx_sdl_get_dimensions, gfx_sdl_get_dimensions,
gfx_sdl_get_centered_positions,
gfx_sdl_handle_events, gfx_sdl_handle_events,
gfx_sdl_start_frame, gfx_sdl_start_frame,
gfx_sdl_swap_buffers_begin, gfx_sdl_swap_buffers_begin,
gfx_sdl_swap_buffers_end, gfx_sdl_swap_buffers_end,
gfx_sdl_get_time, gfx_sdl_get_time,
gfx_sdl_get_target_fps,
gfx_sdl_set_target_fps, gfx_sdl_set_target_fps,
gfx_sdl_can_disable_vsync, gfx_sdl_can_disable_vsync,
gfx_sdl_get_window_handle, gfx_sdl_get_window_handle,
gfx_sdl_set_window_title, gfx_sdl_set_window_title,
gfx_sdl_get_swap_interval,
gfx_sdl_set_swap_interval, gfx_sdl_set_swap_interval,
}; };
+13
View File
@@ -13,28 +13,41 @@ struct GfxWindowInitSettings {
bool fullscreen; bool fullscreen;
bool fullscreen_is_exclusive; bool fullscreen_is_exclusive;
bool maximized; bool maximized;
bool centered;
bool allow_hidpi; bool allow_hidpi;
}; };
struct GfxWindowManagerAPI { struct GfxWindowManagerAPI {
void (*init)(const struct GfxWindowInitSettings *settings); void (*init)(const struct GfxWindowInitSettings *settings);
void (*close)(void); void (*close)(void);
int (*get_display_mode)(int modenum, int *out_w, int *out_h);
int (*get_current_display_mode)(int *out_w, int *out_h);
int (*get_num_display_modes)(void);
int32_t (*get_fullscreen_state)(void);
void (*set_fullscreen_changed_callback)(void (*on_fullscreen_changed)(bool is_now_fullscreen)); void (*set_fullscreen_changed_callback)(void (*on_fullscreen_changed)(bool is_now_fullscreen));
void (*set_fullscreen)(bool enable); void (*set_fullscreen)(bool enable);
void (*set_fullscreen_exclusive)(bool exc); void (*set_fullscreen_exclusive)(bool exc);
void (*set_fullscreen_flag)(int32_t mode);
int32_t (*get_fullscreen_flag_mode)(void);
int32_t (*get_maximized_state)(void);
void (*set_maximize)(bool enable); void (*set_maximize)(bool enable);
void (*get_active_window_refresh_rate)(uint32_t* refresh_rate); void (*get_active_window_refresh_rate)(uint32_t* refresh_rate);
void (*set_cursor_visibility)(bool visible); void (*set_cursor_visibility)(bool visible);
void (*set_closest_resolution)(int32_t width, int32_t height, bool should_center);
void (*set_dimensions)(uint32_t width, uint32_t height, int32_t posX, int32_t posY);
void (*get_dimensions)(uint32_t* width, uint32_t* height, int32_t* posX, int32_t* posY); void (*get_dimensions)(uint32_t* width, uint32_t* height, int32_t* posX, int32_t* posY);
void (*get_centered_positions)(int32_t width, int32_t height, int32_t *posX, int32_t *posY);
void (*handle_events)(void); void (*handle_events)(void);
bool (*start_frame)(void); bool (*start_frame)(void);
void (*swap_buffers_begin)(void); void (*swap_buffers_begin)(void);
void (*swap_buffers_end)(void); void (*swap_buffers_end)(void);
double (*get_time)(void); // For debug double (*get_time)(void); // For debug
int32_t (*get_target_fps)(void);
void (*set_target_fps)(int fps); void (*set_target_fps)(int fps);
bool (*can_disable_vsync)(void); bool (*can_disable_vsync)(void);
void *(*get_window_handle)(void); void *(*get_window_handle)(void);
void (*set_window_title)(const char *); void (*set_window_title)(const char *);
int (*get_swap_interval)(void);
bool (*set_swap_interval)(int); bool (*set_swap_interval)(int);
}; };
+773 -844
View File
File diff suppressed because it is too large. Load diff
+860 -1492
View File
File diff suppressed because it is too large. Load diff
-14
View File
@@ -1,14 +0,0 @@
#ifndef _IN_CONSOLE_H
#define _IN_CONSOLE_H
#include <PR/ultratypes.h>
#include "types.h"
void conInit(void);
Gfx *conRender(Gfx *gdl);
void conTick(void);
void conPrint(s32 showmsg, const char *s);
void conPrintf(s32 showmsg, const char *fmt, ...);
void conPrintLn(s32 showmsg, const char *s);
#endif
-5098
View File
File diff suppressed because it is too large. Load diff
+2 -1
View File
@@ -19,8 +19,9 @@ s32 fsFileSize(const char *name);
FILE *fsFileOpenWrite(const char *name); FILE *fsFileOpenWrite(const char *name);
FILE *fsFileOpenRead(const char *name); FILE *fsFileOpenRead(const char *name);
void fsFileClose(FILE *f); void fsFileFree(FILE *f);
const char *fsGetModDir(void); const char *fsGetModDir(void);
s32 fsCreateDir(const char *path);
#endif #endif
+118 -82
View File
@@ -17,88 +17,108 @@
#define CONT_NUM_BUTTONS 32 // not including the stick axes #define CONT_NUM_BUTTONS 32 // not including the stick axes
enum virtkey { enum virtkey {
/* same order as SDL scancodes */ /* same order as SDL scancodes */
VK_KEYBOARD_BEGIN = 0, VK_KEYBOARD_BEGIN = 0,
VK_A = 4, VK_A = 4,
VK_Z = 29, VK_Z = 29,
VK_1 = 30, VK_1 = 30,
VK_9 = 38, VK_9 = 38,
VK_0 = 39, VK_0 = 39,
VK_RETURN = 40, VK_RETURN = 40,
VK_ESCAPE = 41, VK_ESCAPE = 41,
VK_BACKSPACE = 42, VK_BACKSPACE = 42,
VK_SPACE = 44, VK_SPACE = 44,
VK_MINUS = 45, VK_MINUS = 45,
VK_LEFTBRACKET = 47, VK_LEFTBRACKET = 47,
VK_RIGHTBRACKET = 48, VK_RIGHTBRACKET = 48,
VK_SEMICOLON = 51, VK_SEMICOLON = 51,
VK_GRAVE = 53, VK_GRAVE = 53,
VK_COMMA = 54, VK_COMMA = 54,
VK_PERIOD = 55, VK_PERIOD = 55,
VK_F1 = 58, VK_F1 = 58,
VK_F9 = 66, VK_F9 = 66,
VK_DELETE = 76, VK_DELETE = 76,
VK_LCTRL = 224, VK_LCTRL = 224,
VK_LSHIFT = 225, VK_LSHIFT = 225,
VK_RCTRL = 228, VK_LALT = 226,
VK_RSHIFT = 229, VK_RCTRL = 228,
VK_RSHIFT = 229,
/* same order as SDL mouse buttons */ /* same order as SDL mouse buttons */
VK_MOUSE_BEGIN = 512, VK_MOUSE_BEGIN = 512,
VK_MOUSE_LEFT = VK_MOUSE_BEGIN, VK_MOUSE_LEFT = VK_MOUSE_BEGIN,
VK_MOUSE_MIDDLE, VK_MOUSE_MIDDLE,
VK_MOUSE_RIGHT, VK_MOUSE_RIGHT,
VK_MOUSE_X1, VK_MOUSE_X1,
VK_MOUSE_X2, VK_MOUSE_X2,
VK_MOUSE_WHEEL_UP, VK_MOUSE_WHEEL_UP,
VK_MOUSE_WHEEL_DN, VK_MOUSE_WHEEL_DN,
/* same order as SDL gamecontroller buttons plus two buttons for triggers */ /* same order as SDL gamecontroller buttons plus two buttons for triggers */
VK_JOY_BEGIN, VK_JOY_BEGIN,
VK_JOY1_BEGIN = VK_JOY_BEGIN, VK_JOY1_BEGIN = VK_JOY_BEGIN,
VK_JOY1_LTRIG = VK_JOY1_BEGIN + 30, VK_JOY1_LSHOULDER = VK_JOY1_BEGIN + 9,
VK_JOY1_RTRIG = VK_JOY1_BEGIN + 31, VK_JOY1_RSHOULDER = VK_JOY1_BEGIN + 10,
VK_JOY2_BEGIN = VK_JOY1_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS, VK_JOY1_LTRIG = VK_JOY1_BEGIN + 30,
VK_JOY3_BEGIN = VK_JOY2_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS, VK_JOY1_RTRIG = VK_JOY1_BEGIN + 31,
VK_JOY4_BEGIN = VK_JOY3_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS, VK_JOY2_BEGIN = VK_JOY1_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS,
VK_JOY3_BEGIN = VK_JOY2_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS,
VK_JOY4_BEGIN = VK_JOY3_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS,
VK_TOTAL_COUNT = VK_JOY_BEGIN + INPUT_MAX_CONTROLLERS * INPUT_MAX_CONTROLLER_BUTTONS, VK_TOTAL_COUNT = VK_JOY_BEGIN + INPUT_MAX_CONTROLLERS * INPUT_MAX_CONTROLLER_BUTTONS,
};
enum keymod {
/* same order as SDL keymods */
KM_LSHIFT = 0x0001,
KM_RSHIFT = 0x0002,
KM_LCTRL = 0x0040,
KM_RCTRL = 0x0080,
KM_CAPS = 0x2000,
KM_CTRL = KM_LCTRL | KM_RCTRL,
KM_SHIFT = KM_LSHIFT | KM_RSHIFT
}; };
enum contkey { enum contkey {
CK_C_R, CK_C_R,
CK_C_L, CK_C_L,
CK_C_D, CK_C_D,
CK_C_U, CK_C_U,
CK_RTRIG, CK_RTRIG,
CK_LTRIG, CK_LTRIG,
CK_X, // gap in CONT_ CK_X, // gap in CONT_
CK_Y, // gap in CONT_ CK_Y, // gap in CONT_
CK_DPAD_R, CK_DPAD_R,
CK_DPAD_L, CK_DPAD_L,
CK_DPAD_D, CK_DPAD_D,
CK_DPAD_U, CK_DPAD_U,
CK_START, CK_START,
CK_ZTRIG, CK_ZTRIG,
CK_B, CK_B,
CK_A, CK_A,
CK_STICK_XNEG, CK_STICK_XNEG,
CK_STICK_XPOS, CK_STICK_XPOS,
CK_STICK_YNEG, CK_STICK_YNEG,
CK_STICK_YPOS, CK_STICK_YPOS,
CK_0010, CK_ACCEPT,
CK_0020, CK_CANCEL,
CK_0040, CK_0040,
CK_0080, CK_0080,
CK_0100, CK_0100,
CK_0200, CK_0200,
CK_0400, CK_0400,
CK_0800, CK_0800,
CK_1000, CK_1000,
CK_2000, CK_2000,
CK_4000, CK_4000,
CK_8000, CK_8000,
CK_TOTAL_COUNT CK_TOTAL_COUNT
};
enum mouselockmode {
MLOCK_OFF = 0,
MLOCK_ON = 1,
MLOCK_AUTO = 2
}; };
// returns bitmask of connected controllers or -1 if failed // returns bitmask of connected controllers or -1 if failed
@@ -125,6 +145,10 @@ void inputControllerSetSticksSwapped(s32 cidx, s32 swapped);
s32 inputControllerGetDualAnalog(s32 cidx); s32 inputControllerGetDualAnalog(s32 cidx);
void inputControllerSetDualAnalog(s32 cidx, s32 enable); void inputControllerSetDualAnalog(s32 cidx, s32 enable);
// get/set Input.Player%d.CancelCButtons
s32 inputControllerGetCancelCButtons(s32 cidx);
void inputControllerSetCancelCButtons(s32 cidx, s32 cancel);
// get/set sensitivity for a given player // get/set sensitivity for a given player
f32 inputControllerGetAxisScale(s32 cidx, s32 stick, s32 axis); f32 inputControllerGetAxisScale(s32 cidx, s32 stick, s32 axis);
void inputControllerSetAxisScale(s32 cidx, s32 stick, s32 axis, f32 value); void inputControllerSetAxisScale(s32 cidx, s32 stick, s32 axis, f32 value);
@@ -152,6 +176,7 @@ s32 inputAssignController(s32 cidx, s32 id);
// vk is a value from the virtkey enum above // vk is a value from the virtkey enum above
s32 inputKeyPressed(u32 vk); s32 inputKeyPressed(u32 vk);
s32 inputKeyJustPressed(u32 vk);
// idx is controller index, contbtn is one of the CONT_ constants // idx is controller index, contbtn is one of the CONT_ constants
s32 inputButtonPressed(s32 idx, u32 contbtn); s32 inputButtonPressed(s32 idx, u32 contbtn);
@@ -186,8 +211,9 @@ void inputLockMouse(s32 lock);
// returns the current state of the above // returns the current state of the above
s32 inputMouseIsLocked(void); s32 inputMouseIsLocked(void);
// returns mouse position in native viewport coordinates (ie, 320x240 most of the time) // sets x, y to mouse position in native viewport coordinates (ie, 320x240 most of the time)
void inputMouseGetPosition(s32 *x, s32 *y); // returns true if mouse has moved this input frame
s32 inputMouseGetPosition(s32 *x, s32 *y);
// returns changes in mouse position since last frame, in window coordinates // returns changes in mouse position since last frame, in window coordinates
void inputMouseGetRawDelta(s32 *dx, s32 *dy); void inputMouseGetRawDelta(s32 *dx, s32 *dy);
@@ -219,19 +245,29 @@ void inputSetDefaultKeyBinds(s32 cidx, s32 n64mode);
void inputClearLastKey(void); void inputClearLastKey(void);
s32 inputGetLastKey(void); s32 inputGetLastKey(void);
// get/set Input.MouseLockMode
s32 inputGetMouseLockMode(void);
void inputSetMouseLockMode(s32 lockmode);
// same as inputLockMouse but works only if mouse is enabled and lockmode == MLOCK_AUTO
s32 inputAutoLockMouse(s32 wantlock);
// show/hide mouse cursor; if mouse lock is on the cursor is always hidden
void inputMouseShowCursor(s32 show);
void inputStartTextInput(void); void inputStartTextInput(void);
void inputStopTextInput(void); void inputStopTextInput(void);
s32 inputIsTextInputActive(void);
void inputClearLastTextChar(void); void inputClearLastTextChar(void);
char inputGetLastTextChar(void); char inputGetLastTextChar(void);
s32 inputTextHandler(char *out, const u32 outSize, s32 *curCol); s32 inputTextHandler(char *out, const u32 outSize, s32 *curCol, s32 oskCharsOnly);
void inputClearClipboard(void); void inputClearClipboard(void);
const char *inputGetClipboard(void); const char *inputGetClipboard(void);
// get/set Input.MouseDefaultLocked // returns keymod values
s32 inputGetMouseDefaultLocked(void); u32 inputGetKeyModState(void);
void inputSetMouseDefaultLocked(s32 defaultLocked);
#endif #endif
+12
View File
@@ -0,0 +1,12 @@
#ifndef _IN_MPSETUPS_H
#define _IN_MPSETUPS_H
#include "types.h"
s32 mpsetupLoadCurrentFile(void);
s32 mpsetupSaveCurrentFile(void);
void mpsetupLoadSetup(s32 slotindex);
s32 mpsetupSaveSetup(s32 slotindex, u8 savefile);
void mpsetupCopyAllFromPak(void);
#endif
-163
View File
@@ -1,163 +0,0 @@
#ifndef _IN_NET_H
#define _IN_NET_H
#include "types.h"
#include "constants.h"
#include "net/netbuf.h"
#define NET_PROTOCOL_VER 12
#define NET_QUERY_MAGIC "PDQM\x01"
#define NET_MAX_CLIENTS MAX_PLAYERS
#define NET_MAX_NAME MAX_PLAYERNAME
#define NET_MAX_ADDR 256
#define NET_BUFSIZE 1440
#define NET_DEFAULT_PORT 27100
#define NET_NULL_CLIENT 0xFF
#define NET_NULL_PROP 0
#define NETCHAN_DEFAULT 0
#define NETCHAN_CONTROL 1
#define NETCHAN_COUNT 2
#define DISCONNECT_UNKNOWN 0
#define DISCONNECT_SHUTDOWN 1
#define DISCONNECT_VERSION 2
#define DISCONNECT_KICKED 3
#define DISCONNECT_BANNED 4
#define DISCONNECT_TIMEOUT 5
#define DISCONNECT_FULL 6
#define DISCONNECT_LATE 7
#define DISCONNECT_FILES 8
#define CLSTATE_DISCONNECTED 0
#define CLSTATE_CONNECTING 1
#define CLSTATE_AUTH 2
#define CLSTATE_LOBBY 3
#define CLSTATE_GAME 4
#define UCMD_FIRE (1 << 0)
#define UCMD_ACTIVATE (1 << 1)
#define UCMD_RELOAD (1 << 2)
#define UCMD_AIMMODE (1 << 3)
#define UCMD_DUCK (1 << 4)
#define UCMD_SQUAT (1 << 5)
#define UCMD_ZOOMIN (1 << 6)
#define UCMD_SELECT (1 << 7)
#define UCMD_SELECT_DUAL (1 << 8)
#define UCMD_EYESSHUT (1 << 9)
#define UCMD_SECONDARY (1 << 10)
#define UCMD_RESPAWN (1 << 27)
#define UCMD_CHAT (1 << 28)
#define UCMD_IMPORTANT_MASK (UCMD_FIRE | UCMD_ACTIVATE | UCMD_RELOAD | UCMD_AIMMODE | UCMD_SELECT | UCMD_SELECT_DUAL)
#define UCMD_FL_FORCEPOS (1 << 29)
#define UCMD_FL_FORCEANGLE (1 << 30)
#define UCMD_FL_FORCEGROUND (1 << 31)
#define UCMD_FL_FORCEMASK (UCMD_FL_FORCEPOS | UCMD_FL_FORCEANGLE | UCMD_FL_FORCEGROUND)
struct netplayermove {
u32 tick; // g_NetTIck value when this struct was written; if 0, this struct is invalid
u32 ucmd; // player commands (UCMD_)
f32 leanofs; // analog lean value (-1 .. 1; equal to player->swaytarget / 75.f)
f32 crouchofs; // analog crouch value (-90 for SQUAT, 0 for STAND; player->crouchofs)
f32 zoomfov; // manual zoom fov for the current gun; synced only if UCMD_AIMING is set
f32 movespeed[2]; // move inputs, [0] is forward, [1] is sideways; used mostly for animation
f32 angles[2]; // view angles, [0] is theta, [1] is verta
f32 crosspos[2]; // crosshair position in aiming mode; normalized to default aspect ratio
s8 weaponnum; // switch to this weapon if UCMD_SELECT is set
struct coord pos; // player position at g_NetTick == tick
};
struct netclient {
struct _ENetPeer *peer;
u32 id; // remote client number, server is always 0, even on clients
u32 state; // CLSTATE_
u32 flags; // CLFLAG_
struct {
char name[NET_MAX_NAME];
u16 options;
u8 headnum;
u8 bodynum;
u8 team;
f32 fovy;
f32 fovzoommult;
} settings;
struct mpplayerconfig *config;
struct player *player;
u8 playernum;
struct netplayermove outmove[2]; // last 2 outgoing player inputs, newest one first
struct netplayermove inmove[2]; // last 2 incoming player inputs, newest one first
u32 inmovetick; // last inmove tick which was applied to the player
u32 outmoveack; // last acked outmove tick
u32 forcetick; // tick on which the client's position was forced, or 0 if not forcing
u32 lerpticks; // how many ticks we've been lerping the position
struct netbuf out; // outbound messages are written here, except broadcasts
struct netbuf in; // incoming packets are fed here
u8 out_data[NET_BUFSIZE]; // buffer for out
};
extern s32 g_NetMode;
extern s32 g_NetJoinLatch;
extern s32 g_NetHostLatch;
// net frame, ticks at 60 fps, starts at 0 when the server is started
extern u32 g_NetTick;
extern u32 g_NetNextSyncId;
extern u64 g_NetRngSeeds[2];
extern u32 g_NetRngLatch;
extern u32 g_NetInterpTicks;
extern u32 g_NetServerPort;
extern char g_NetLastJoinAddr[NET_MAX_ADDR + 1];
extern s32 g_NetDebugDraw;
extern s32 g_NetMaxClients;
extern s32 g_NetNumClients;
extern struct netclient g_NetClients[NET_MAX_CLIENTS + 1]; // last is an extra temporary client
extern struct netclient *g_NetLocalClient;
extern struct netbuf g_NetMsg;
extern struct netbuf g_NetMsgRel;
const char *netFormatClientAddr(const struct netclient *cl);
void netInit(void);
s32 netDisconnect(void);
void netStartFrame(void);
void netEndFrame(void);
s32 netStartServer(u16 port, s32 maxclients);
s32 netStartClient(const char *addr);
u32 netSend(struct netclient *dstcl, struct netbuf *buf, const s32 reliable, const s32 chan);
void netChat(struct netclient *dst, const char *text);
void netChatPrintf(struct netclient *dst, const char *fmt, ...);
void netServerStageStart(void);
void netServerStageEnd(void);
void netServerKick(struct netclient *cl, const u32 reason);
struct netclient *netClientForPlayerNum(s32 playernum);
void netClientSyncRng(void);
void netClientSettingsChanged(void);
void netPlayersAllocate(void);
void netSyncIdsAllocate(void);
Gfx *netDebugRender(Gfx *gdl);
#endif // _IN_NET_H
-50
View File
@@ -1,50 +0,0 @@
#ifndef _IN_NETBUF_H
#define _IN_NETBUF_H
#include "types.h"
struct netbuf {
u8 *data;
u32 size;
u32 rp;
u32 wp;
u32 error;
};
void netbufStartRead(struct netbuf *buf);
void netbufStartReadData(struct netbuf *buf, const void *data, u32 size);
s32 netbufReadLeft(const struct netbuf *buf);
u32 netbufReadData(struct netbuf *buf, void *out, u32 num);
u8 netbufReadU8(struct netbuf *buf);
u16 netbufReadU16(struct netbuf *buf);
u32 netbufReadU32(struct netbuf *buf);
u64 netbufReadU64(struct netbuf *buf);
s8 netbufReadS8(struct netbuf *buf);
s16 netbufReadS16(struct netbuf *buf);
s32 netbufReadS32(struct netbuf *buf);
s64 netbufReadS64(struct netbuf *buf);
f32 netbufReadF32(struct netbuf *buf);
char *netbufReadStr(struct netbuf *buf);
u32 netbufReadCoord(struct netbuf *buf, struct coord *out);
u32 netbufReadMtxf(struct netbuf *buf, Mtxf *out);
u32 netbufReadSkip(struct netbuf *buf, u32 count);
void netbufStartWrite(struct netbuf *buf);
s32 netbufWriteLeft(const struct netbuf *buf);
u32 netbufWriteData(struct netbuf *buf, const void *data, u32 num);
u32 netbufWriteU8(struct netbuf *buf, const u8 v);
u32 netbufWriteU16(struct netbuf *buf, const u16 v);
u32 netbufWriteU32(struct netbuf *buf, const u32 v);
u32 netbufWriteU64(struct netbuf *buf, const u64 v);
u32 netbufWriteS8(struct netbuf *buf, const s8 v);
u32 netbufWriteS16(struct netbuf *buf, const s16 v);
u32 netbufWriteS32(struct netbuf *buf, const s32 v);
u32 netbufWriteS64(struct netbuf *buf, const s64 v);
u32 netbufWriteF32(struct netbuf *buf, const f32 v);
u32 netbufWriteStr(struct netbuf *buf, const char *v);
u32 netbufWriteCoord(struct netbuf *buf, const struct coord *v);
u32 netbufWriteMtxf(struct netbuf *buf, const Mtxf *in);
void netbufReset(struct netbuf *buf);
#endif
-10
View File
@@ -1,10 +0,0 @@
#ifndef _IN_NETENET_H
#define _IN_NETENET_H
#define ENET_NO_PRAGMA_LINK 1
#include "external/enet.h"
#undef bool
#undef near
#undef far
#endif
-74
View File
@@ -1,74 +0,0 @@
#ifndef _IN_NETMSG_H
#define _IN_NETMSG_H
#include <PR/ultratypes.h>
#include "net/net.h"
#include "net/netbuf.h"
#define SVC_BAD 0x00 // trash
#define SVC_NOP 0x01 // does nothing
#define SVC_AUTH 0x02 // auth response, sent in response to CLC_AUTH
#define SVC_CHAT 0x03 // chat message
#define SVC_STAGE_START 0x10 // start level
#define SVC_STAGE_END 0x11 // end level
#define SVC_PLAYER_MOVE 0x20 // player movement and inputs
#define SVC_PLAYER_GUNS 0x21 // player gun state
#define SVC_PLAYER_STATS 0x22 // player stats (health etc)
#define SVC_PROP_MOVE 0x30 // prop movement
#define SVC_PROP_SPAWN 0x31 // new prop spawned
#define SVC_PROP_DAMAGE 0x32 // prop was damaged
#define SVC_PROP_PICKUP 0x33 // prop was picked up
#define SVC_PROP_USE 0x34 // door/lift/etc was used
#define SVC_PROP_DOOR 0x35 // door state changed
#define SVC_PROP_LIFT 0x36 // lift state changed
#define SVC_CHR_DAMAGE 0x42 // chr was damaged
#define SVC_CHR_DISARM 0x43 // chr's weapons were dropped
#define CLC_BAD 0x00 // trash
#define CLC_NOP 0x01 // does nothing
#define CLC_AUTH 0x02 // auth request, sent immediately after connecting
#define CLC_CHAT 0x03 // chat message
#define CLC_MOVE 0x04 // player input
#define CLC_SETTINGS 0x05 // player settings changed
u32 netmsgClcAuthWrite(struct netbuf *dst);
u32 netmsgClcAuthRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgClcChatWrite(struct netbuf *dst, const char *str);
u32 netmsgClcChatRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgClcMoveWrite(struct netbuf *dst);
u32 netmsgClcMoveRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgClcSettingsWrite(struct netbuf *dst);
u32 netmsgClcSettingsRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcAuthWrite(struct netbuf *dst, struct netclient *authcl);
u32 netmsgSvcAuthRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcChatWrite(struct netbuf *dst, const char *str);
u32 netmsgSvcChatRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcStageStartWrite(struct netbuf *dst);
u32 netmsgSvcStageStartRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcStageEndWrite(struct netbuf *dst);
u32 netmsgSvcStageEndRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcPlayerMoveWrite(struct netbuf *dst, struct netclient *movecl);
u32 netmsgSvcPlayerMoveRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcPlayerStatsWrite(struct netbuf *dst, struct netclient *actcl);
u32 netmsgSvcPlayerStatsRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcPropSpawnWrite(struct netbuf *dst, struct prop *prop);
u32 netmsgSvcPropSpawnRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcPropMoveWrite(struct netbuf *dst, struct prop *prop, struct coord *initrot);
u32 netmsgSvcPropMoveRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcPropDamageWrite(struct netbuf *dst, struct prop *prop, f32 damage, struct coord *pos, s32 weaponnum, s32 playernum);
u32 netmsgSvcPropDamageRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcPropPickupWrite(struct netbuf *dst, struct netclient *actcl, struct prop *prop, const s32 tickop);
u32 netmsgSvcPropPickupRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcPropUseWrite(struct netbuf *dst, struct prop *prop, struct netclient *usercl, const s32 tickop);
u32 netmsgSvcPropUseRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcPropDoorWrite(struct netbuf *dst, struct prop *prop, struct netclient *usercl);
u32 netmsgSvcPropDoorRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcPropLiftWrite(struct netbuf *dst, struct prop *prop);
u32 netmsgSvcPropLiftRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcChrDamageWrite(struct netbuf *dst, struct chrdata *chr, f32 damage, struct coord *vector, struct gset *gset, struct prop *aprop, s32 hitpart, bool damageshield, struct prop *prop2, s32 side, s16 *arg11, bool explosion, struct coord *explosionpos);
u32 netmsgSvcChrDamageRead(struct netbuf *src, struct netclient *srccl);
u32 netmsgSvcChrDisarmWrite(struct netbuf *dst, struct chrdata *chr, struct prop *attacker, u8 weaponnum, f32 wpndamage, struct coord *wpnpos);
u32 netmsgSvcChrDisarmRead(struct netbuf *src, struct netclient *srccl);
#endif
+20 -22
View File
@@ -3,32 +3,30 @@
#include <PR/ultratypes.h> #include <PR/ultratypes.h>
typedef void (*preprocessfunc)(u8 *data, u32 size); typedef u8 *(*preprocessfunc)(u8 *data, u32 size, u32 *outSize);
void preprocessAnimations(u8 *data, u32 size); u8* preprocessAnimations(u8 *data, u32 size, u32 *outSize);
void preprocessMpConfigs(u8 *data, u32 size); u8* preprocessMpConfigs(u8 *data, u32 size, u32 *outSize);
void preprocessFont(u8 *data, u32 size); u8* preprocessFont(u8 *data, u32 size, u32 *outSize);
void preprocessJpnFont(u8 *data, u32 size); u8* preprocessJpnFont(u8 *data, u32 size, u32 *outSize);
void preprocessALBankFile(u8 *data, u32 size); u8* preprocessALBankFile(u8 *data, u32 size, u32 *outSize);
void preprocessALCMidiHdr(u8 *data, u32 size); u8 *preprocessALCMidiHdr(u8 *data, u32 size, u32 *outSize);
void preprocessSequences(u8 *data, u32 size); u8* preprocessSequences(u8 *data, u32 size, u32 *outSize);
void preprocessFiringRange(u8 *data, u32 size); u8* preprocessTexturesList(u8 *data, u32 size, u32 *outSize);
void preprocessTexturesList(u8 *data, u32 size);
void preprocessBgSection1Header(u8 *data, u32 size); void preprocessBgSection1(u8* data, u32 size, u32 ofs);
void preprocessBgSection1(u8 *data, u32 size);
void preprocessBgSection2Header(u8 *data, u32 size);
void preprocessBgSection2(u8 *data, u32 size); void preprocessBgSection2(u8 *data, u32 size);
void preprocessBgSection3(u8* data, u32 size);
void preprocessBgSection1Header(u8 *data, u32 size);
void preprocessBgSection2Header(u8 *data, u32 size);
void preprocessBgSection3Header(u8 *data, u32 size); void preprocessBgSection3Header(u8 *data, u32 size);
void preprocessBgSection3(u8 *data, u32 size); u32 preprocessBgRoom(u8* data, u32 size, u32 room_ofs);
void preprocessBgRoom(u8 *data, u32 ofs);
void preprocessBgLights(u8 *data, u32 ofs);
void preprocessLangFile(u8 *data, u32 size); u8 *preprocessLangFile(u8 *data, u32 size, u32 *outSize);
void preprocessPadsFile(u8 *data, u32 size); u8 *preprocessPadsFile(u8 *data, u32 size, u32 *outSize);
void preprocessTilesFile(u8 *data, u32 size); u8 *preprocessTilesFile(u8 *data, u32 size, u32 *outSize);
void preprocessSetupFile(u8 *data, u32 size); u8 *preprocessSetupFile(u8 *data, u32 size, u32 *outSize);
void preprocessModelFile(u8 *data, u32 size); u8 *preprocessModelFile(u8 *data, u32 size, u32 *outSize);
void preprocessGunFile(u8 *data, u32 size); u8 *preprocessGunFile(u8 *data, u32 size, u32 *outSize);
#endif #endif
+59
View File
@@ -0,0 +1,59 @@
#ifndef _IN_PREPROCESS_COMMON_H
#define _IN_PREPROCESS_COMMON_H
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <PR/ultratypes.h>
#include "types.h"
#include "constants.h"
#include "platform.h"
#include "system.h"
#include "romdata.h"
#include "preprocess.h"
#define MAX_PTR_MARKERS (1024 * 8)
#define PD_ALIGN(val, size) (((val) + ((size) - 1)) & ~((size) - 1))
#define PD_PTR_BASE(x, b) (void *)((u8 *)b + (uintptr_t)x)
#define PD_PTR_BASEOFS(x, b, d) (void *)((u8 *)b - d + (uintptr_t)x)
static inline f32 swapF32(f32 x) { *(u32*)&x = PD_BE32(*(u32*)&x); return x; }
static inline u32 swapU32(u32 x) { return PD_BE32(x); }
static inline s32 swapS32(s32 x) { return PD_BE32(x); }
static inline u16 swapU16(u16 x) { return PD_BE16(x); }
static inline s16 swapS16(s16 x) { return PD_BE16(x); }
static inline void* swapPtr(void** x) { return (void*)PD_BEPTR((uintptr_t)x); }
static inline struct coord swapCrd(struct coord crd) { crd.x = swapF32(crd.x); crd.y = swapF32(crd.y); crd.z = swapF32(crd.z); return crd; }
static inline u32 swapUnk(u32 x) { assert(0 && "unknown type"); return x; }
#define PD_SWAPPED_VAL(x) _Generic((x), \
f32: swapF32, \
u32: swapU32, \
s32: swapS32, \
u16: swapU16, \
s16: swapS16, \
struct coord: swapCrd, \
default: swapUnk \
)(x)
#define PD_SWAP_VAL(x) x = PD_SWAPPED_VAL(x)
#define PD_SWAP_PTR(x) x = swapPtr((void *)(x))
// ptr marker functions
struct ptrmarker {
u32 ptr_src;
uintptr_t ptr_host;
};
void ptrAdd(u32 ptr_src, uintptr_t ptr_host);
struct ptrmarker* ptrFind(uintptr_t ptr_src);
void ptrReset(void);
#endif
+15
View File
@@ -0,0 +1,15 @@
#ifndef _IN_PREPROCESS_GBI_H
#define _IN_PREPROCESS_GBI_H
#include "preprocess/common.h"
// gbi related functions
void gbiReset(void);
void gbiSetSegment(int segment, u32 offset);
void gbiSetVtx(u32 src_offset, u32 dst_offset);
u32 gbiConvertGdl(u8 *dst, u32 dstpos, u8 *src, u32 srcpos, int segment_cmds);
void gbiConvertVtx(u8* dst, u32 dstpos, int count);
void gbiGdlRewriteAddrs(u8* dst, u32 offset);
void gbiAddTexAddr(u32 src_offset, u32 dst_offset);
#endif
+640
View File
@@ -0,0 +1,640 @@
#ifndef _IN_SETUP_DECL
#define _IN_SETUP_DECL
#include "preprocess/common.h"
struct n64_stagesetup {
u32 ptr_waypoints;
u32 ptr_waygroups;
u32 ptr_cover;
u32 ptr_intro;
u32 ptr_props;
u32 ptr_paths;
u32 ptr_ailists;
u32 ptr_padfiledata;
};
struct n64_coord {
f32 x;
f32 y;
f32 z;
};
struct n64_defaultobj {
u16 extrascale;
u8 hidden2;
u8 type;
s16 modelnum;
s16 pad;
u32 flags;
u32 flags2;
u32 flags3;
u32 ptr_prop;
u32 ptr_model;
f32 realrot[3][3];
u32 hidden;
union {
u32 ptr_geotilef;
u32 ptr_geoblock;
u32 ptr_geocyl;
u32 ptr_unkgeo;
};
union {
u32 ptr_projectile;
u32 ptr_embedment;
};
s16 damage;
s16 maxdamage;
u8 shadecol[4];
u8 nextcol[4];
u16 floorcol;
s8 geocount;
s8 _pad_;
};
struct n64_doorobj {
struct n64_defaultobj base;
f32 maxfrac;
f32 perimfrac;
f32 accel;
f32 decel;
f32 maxspeed;
u16 doorflags;
u16 doortype;
u32 keyflags;
s32 autoclosetime;
f32 frac;
f32 fracspeed;
s8 mode;
s8 glasshits;
s16 fadealpha;
s16 xludist;
s16 opadist;
struct n64_coord startpos;
f32 mtx98[3][3];
u32 ptr_sibling;
s32 lastopen60;
s16 portalnum;
s8 soundtype;
s8 fadetime60;
s32 lastcalc60;
u8 laserfade;
u8 unusedmaybe[3];
u8 shadeinfo1[4];
u8 shadeinfo2[4];
u8 actual1;
u8 actual2;
u8 extra1;
u8 extra2;
};
struct n64_doorscaleobj {
u32 unk00;
s32 scale;
};
struct n64_keyobj {
struct n64_defaultobj base;
u32 keyflags;
};
struct n64_alarmobj {
struct n64_defaultobj base;
};
struct n64_cctvobj {
struct n64_defaultobj base;
s16 lookatpadnum;
s16 toleft;
//Mtxf camrotm;
f32 m[4][4];
f32 yzero;
f32 yrot;
f32 yleft;
f32 yright;
f32 yspeed;
f32 ymaxspeed;
s32 seebondtime60;
f32 maxdist;
f32 xzero;
};
struct n64_ammocrateobj {
struct n64_defaultobj base;
s32 ammotype;
};
struct n64_gset {
u8 weaponnum;
u8 unk0639;
u8 unk063a;
u8 weaponfunc;
};
struct n64_weaponobj {
struct n64_defaultobj base;
union {
struct n64_gset gset;
struct {
u8 weaponnum;
s8 unk5d;
s8 unk5e;
u8 gunfunc;
};
};
s8 fadeouttimer60;
s8 dualweaponnum;
union {
s16 timer240;
s16 team;
};
u32 ptr_dualweapon;
};
struct n64_packedchr {
s16 chrindex;
s8 unk02;
s8 typenum;
u32 spawnflags;
s16 chrnum;
u16 padnum;
u8 bodynum;
s8 headnum;
u16 ailistnum;
u16 padpreset;
u16 chrpreset;
u16 hearscale;
u16 viewdist;
u32 flags;
u32 flags2;
u8 team;
u8 squadron;
s16 chair;
u32 convtalk;
u8 tude;
u8 naturalanim;
u8 yvisang;
u8 teamscandist;
};
struct n64_tvscreen {
u32 ptr_cmdlist;
u16 offset;
s16 pause60;
u32 ptr_tconfig;
f32 rot;
f32 xscale;
f32 xscalefrac;
f32 xscaleinc;
f32 xscaleold;
f32 xscalenew;
f32 yscale;
f32 yscalefrac;
f32 yscaleinc;
f32 yscaleold;
f32 yscalenew;
f32 xmid;
f32 xmidfrac;
f32 xmidinc;
f32 xmidold;
f32 xmidnew;
f32 ymid;
f32 ymidfrac;
f32 ymidinc;
f32 ymidold;
f32 ymidnew;
u8 red;
u8 redold;
u8 rednew;
u8 green;
u8 greenold;
u8 greennew;
u8 blue;
u8 blueold;
u8 bluenew;
u8 alpha;
u8 alphaold;
u8 alphanew;
f32 colfrac;
f32 colinc;
};
struct n64_singlemonitorobj {
struct n64_defaultobj base;
struct n64_tvscreen screen;
s16 owneroffset;
s8 ownerpart;
u8 imagenum;
};
struct n64_multimonitorobj {
struct n64_defaultobj base;
struct n64_tvscreen screens[4];
u8 imagenums[4];
};
struct n64_hangingmonitorsobj {
struct n64_defaultobj base;
};
struct n64_autogunobj {
struct n64_defaultobj base;
s16 targetpad;
s8 firing;
u8 firecount;
f32 yzero;
f32 ymaxleft;
f32 ymaxright;
f32 yrot;
f32 yspeed;
f32 xzero;
f32 xrot;
f32 xspeed;
f32 maxspeed;
f32 aimdist;
f32 barrelspeed;
f32 barrelrot;
s32 lastseebond60;
s32 lastaimbond60;
s32 allowsoundframe;
u32 ptr_beam;
f32 shotbondsum;
u32 ptr_target;
u8 targetteam;
u8 ammoquantity;
s16 nextchrtest;
};
struct n64_linkgunsobj {
u32 unk00;
s16 offset1;
s16 offset2;
};
struct n64_debrisobj {
struct n64_defaultobj base;
};
struct n64_hatobj {
struct n64_defaultobj base;
};
struct n64_grenadeprobobj { // objtype 0x12
u32 unk00;
s16 chrnum;
u16 probability;
};
struct n64_linkliftdoorobj {
u32 unk00;
u32 ptr_door;
u32 ptr_lift;
u32 ptr_next;
s32 stopnum;
};
struct n64_multiammocrateslot {
u16 modelnum;
u16 quantity;
};
struct n64_multiammocrateobj {
struct n64_defaultobj base;
struct n64_multiammocrateslot slots[19];
};
struct n64_shieldobj {
struct n64_defaultobj base;
f32 initialamount;
f32 amount;
u32 unk64;
};
struct n64_tag {
u32 identifier;
u16 tagnum;
s16 cmdoffset;
u32 ptr_next;
u32 ptr_obj;
};
struct n64_objective {
u32 unk00;
s32 index;
u32 text;
u16 unk0c;
u8 flags;
s8 difficulties;
};
struct n64_stdobjective {
u32 cmd;
};
struct n64_objectivecmd {
u8 cmd0[4];
u32 cmd1;
};
struct n64_briefingobj {
u32 unk00;
u32 type;
u32 text;
u32 ptr_next;
};
struct n64_padlockeddoorobj {
u32 unk00;
u32 ptr_door;
u32 ptr_lock;
u32 ptr_next;
};
struct n64_truckobj {
struct n64_defaultobj base;
u32 ptr_ailist;
u16 aioffset;
s16 aireturnlist;
f32 speed;
f32 wheelxrot;
f32 wheelyrot;
f32 speedaim;
f32 speedtime60;
f32 turnrot60;
f32 roty;
u32 ptr_path;
s32 nextstep;
};
struct n64_tankobj {
u8 _pad_[128];
};
struct n64_heliobj {
struct n64_defaultobj base;
u32 ptr_ailist;
u16 aioffset;
s16 aireturnlist;
f32 rotoryrot;
f32 rotoryspeed;
f32 rotoryspeedaim;
f32 rotoryspeedtime;
f32 speed;
f32 speedaim;
f32 speedtime60;
f32 yrot;
u32 ptr_path;
s32 nextstep;
};
struct n64_glassobj {
struct n64_defaultobj base;
s16 portalnum;
s16 _pad_;
};
struct n64_safeobj {
struct n64_defaultobj base;
};
struct n64_safeitemobj {
u32 unk00;
u32 ptr_item;
u32 ptr_safe;
u32 ptr_door;
u32 ptr_next;
};
struct n64_cameraposobj {
s32 type;
f32 x;
f32 y;
f32 z;
f32 theta;
f32 verta;
s32 pad;
};
struct n64_tintedglassobj {
struct n64_defaultobj base;
s16 xludist;
s16 opadist;
s16 opacity;
s16 portalnum;
f32 unk64;
};
struct n64_liftobj {
struct n64_defaultobj base;
s16 pads[4];
u32 ptr_doors[4];
f32 dist;
f32 speed;
f32 accel;
f32 maxspeed;
s8 soundtype;
s8 levelcur;
s8 levelaim;
s8 _pad_;
struct n64_coord prevpos;
};
struct n64_linksceneryobj {
u32 unk00;
u32 ptr_trigger;
u32 ptr_unexp;
u32 ptr_exp;
u32 ptr_next;
};
struct n64_blockedpathobj {
u32 unk00;
u32 ptr_blocker;
s16 waypoint1;
s16 waypoint2;
u32 ptr_next;
};
struct n64_hov {
u8 type;
u8 flags;
s16 _pad_;
f32 bobycur;
f32 bobytarget;
f32 bobyspeed;
f32 yrot;
f32 bobpitchcur;
f32 bobpitchtarget;
f32 bobpitchspeed;
f32 bobrollcur;
f32 bobrolltarget;
f32 bobrollspeed;
f32 groundpitch;
f32 y;
f32 ground;
s32 prevframe60;
s32 prevgroundframe60;
};
struct n64_hoverbikeobj {
struct n64_defaultobj base;
struct n64_hov hov;
f32 speed[2];
f32 prevpos[2];
f32 w;
f32 rels[2];
f32 exreal;
f32 ezreal;
f32 ezreal2;
f32 leanspeed;
f32 leandiff;
s32 maxspeedtime240;
f32 speedabs[2];
f32 speedrel[2];
};
struct n64_hoverpropobj {
struct n64_defaultobj base;
struct n64_hov hov;
};
struct n64_fanobj {
struct n64_defaultobj base;
f32 yrot;
f32 yrotprev;
f32 ymaxspeed;
f32 yspeed;
f32 yaccel;
s8 on;
u8 _pad_[3];
};
struct n64_hovercarobj {
struct n64_defaultobj base;
u32 ptr_ailist;
u16 aioffset;
s16 aireturnlist;
f32 speed;
f32 speedaim;
f32 speedtime60;
f32 turnyspeed60;
f32 turnxspeed60;
f32 turnrot60;
f32 roty;
f32 rotx;
f32 rotz;
u32 ptr_path;
s32 nextstep;
s16 status;
s16 dead;
s16 deadtimer60;
s16 sparkstimer60;
};
struct n64_chopperobj {
struct n64_defaultobj base;
u32 ptr_ailist;
u16 aioffset;
s16 aireturnlist;
union {
struct {
f32 speed;
f32 speedaim;
f32 speedtime60;
};
struct n64_coord fall;
};
f32 turnyspeed60;
f32 turnxspeed60;
f32 turnrot60;
f32 roty;
f32 rotx;
f32 rotz;
u32 ptr_path;
s32 nextstep;//
s16 weaponsarmed;
s16 ontarget;
s16 target;
u8 attackmode;
u8 cw;
f32 vx;
f32 vy;
f32 vz;
f32 power;
f32 otx;
f32 oty;
f32 otz;
f32 bob;
f32 bobstrength;
s32 targetvisible;
s32 timer60;
s32 patroltimer60;
f32 gunturnyspeed60;
f32 gunturnxspeed60;
f32 gunroty;
f32 gunrotx;
f32 barrelrotspeed;
f32 barrelrot;
u32 ptr_fireslotthing;
s32 dead;
};
struct n64_escalatorobj {
struct n64_defaultobj base;
s32 frame;
struct n64_coord prevpos;
};
struct n64_textoverride {
u32 unk00;
s32 objoffset;
s32 weapon;
u32 obtaintext;
u32 ownertext;
u32 inventorytext;
u32 inventory2text;
u32 pickuptext;
u32 ptr_next;
u32 ptr_obj;
};
struct n64_criteria_roomentered {
u32 unk00;
u32 pad;
u32 status;
u32 ptr_next;
};
struct n64_criteria_throwinroom {
u32 unk00;
u32 unk04;
u32 pad;
u32 status;
u32 ptr_next;
};
struct n64_criteria_holograph {
u32 unk00;
u32 obj;
u32 status;
u32 ptr_next;
};
struct n64_ailist {
u32 ptr_list;
s32 id;
};
struct n64_path {
u32 ptr_pads;
u8 id;
u8 flags;
u16 len;
};
#endif
+4 -2
View File
@@ -5,12 +5,11 @@
extern u8 *g_RomFile; extern u8 *g_RomFile;
extern u32 g_RomFileSize; extern u32 g_RomFileSize;
extern const char *g_RomName;
s32 romdataInit(void); s32 romdataInit(void);
u8 *romdataFileLoad(s32 fileNum, u32 *outSize); u8 *romdataFileLoad(s32 fileNum, u32 *outSize);
void romdataFilePreprocess(s32 fileNum, s32 loadType, u8 *data, u32 size); void romdataFilePreprocess(s32 fileNum, s32 loadType, u8 *data, u32 size, u32 *outSize);
void romdataFileFree(s32 fileNum); void romdataFileFree(s32 fileNum);
const char *romdataFileGetName(s32 fileNum); const char *romdataFileGetName(s32 fileNum);
@@ -22,5 +21,8 @@ s32 romdataFileGetNumForName(const char *name);
u8 *romdataSegGetData(const char *segName); u8 *romdataSegGetData(const char *segName);
u8 *romdataSegGetDataEnd(const char *segName); u8 *romdataSegGetDataEnd(const char *segName);
u32 romdataSegGetSize(const char *segName); u32 romdataSegGetSize(const char *segName);
u32 romdataFileGetEstimatedSize(const u32 size, const u32 loadtype);
s32 romdataCheckGbcRom(void);
#endif #endif
+5 -9
View File
@@ -7,14 +7,10 @@ extern "C" {
#include <PR/ultratypes.h> #include <PR/ultratypes.h>
#define LOGFLAG_NOCON (1 << 6) enum LogLevel {
#define LOGFLAG_SHOWMSG (1 << 7) LOG_NOTE,
LOG_WARNING,
enum loglevel { LOG_ERROR,
LOG_NOTE = 0,
LOG_CHAT = 0 | LOGFLAG_SHOWMSG,
LOG_WARNING = 1 | LOGFLAG_SHOWMSG,
LOG_ERROR = 2 | LOGFLAG_SHOWMSG,
}; };
void sysInitArgs(s32 argc, const char **argv); void sysInitArgs(s32 argc, const char **argv);
@@ -25,7 +21,6 @@ const char *sysArgGetString(const char *arg);
s32 sysArgGetInt(const char *arg, s32 defval); s32 sysArgGetInt(const char *arg, s32 defval);
u64 sysGetMicroseconds(void); u64 sysGetMicroseconds(void);
f32 sysGetSeconds(void);
void sysFatalError(const char *fmt, ...) __attribute__((noreturn)); void sysFatalError(const char *fmt, ...) __attribute__((noreturn));
@@ -37,6 +32,7 @@ void sysGetHomePath(char *outPath, const u32 outLen);
void *sysMemAlloc(const u32 size); void *sysMemAlloc(const u32 size);
void *sysMemZeroAlloc(const u32 size); void *sysMemZeroAlloc(const u32 size);
void *sysMemRealloc(void *ptr, const u32 newSize);
void sysMemFree(void *ptr); void sysMemFree(void *ptr);
// hns is specified in 100ns units // hns is specified in 100ns units
-14
View File
@@ -12,18 +12,4 @@ char *strParseToken(char *str, char *out, s32 *outCount);
char *strFmt(const char *fmt, ...); char *strFmt(const char *fmt, ...);
char *strDuplicate(const char *str); char *strDuplicate(const char *str);
static inline f32 lerpf(const f32 a, const f32 b, const f32 t) {
return a + (b - a) * t;
}
static inline f32 lerpanglef(const f32 a, const f32 b, const f32 t) {
f32 d = b - a;
if (d > 180.f) {
d -= 360.f;
} else if (d < -180.f) {
d += 360.f;
}
return a + d * t;
}
#endif #endif
+11
View File
@@ -0,0 +1,11 @@
#ifndef _IN_VERSIONINFO_H
#define _IN_VERSIONINFO_H
#define VERSION_TARGET "@VERSION_TARGET@"
#define VERSION_ARCH "@VERSION_ARCH@"
#define VERSION_ROMID "@VERSION_ROMID@"
#define VERSION_BUILD "@VERSION_BUILD@"
#define VERSION_HASH "@VERSION_HASH@"
#define VERSION_BRANCH "@VERSION_BRANCH@"
#endif
+33 -1
View File
@@ -11,6 +11,11 @@
#define VIDEO_MAX_FPS 240 #define VIDEO_MAX_FPS 240
#endif #endif
typedef struct {
s32 width;
s32 height;
} displaymode;
s32 videoInit(void); s32 videoInit(void);
void videoStartFrame(void); void videoStartFrame(void);
void videoSubmitCommands(Gfx *cmds); void videoSubmitCommands(Gfx *cmds);
@@ -27,18 +32,42 @@ s32 videoGetWidth(void);
s32 videoGetHeight(void); s32 videoGetHeight(void);
f32 videoGetAspect(void); f32 videoGetAspect(void);
s32 videoGetFullscreen(void); s32 videoGetFullscreen(void);
s32 videoGetFullscreenMode(void);
s32 videoGetMaximizeWindow(void); s32 videoGetMaximizeWindow(void);
void videoSetMaximizeWindow(s32 fs); void videoSetMaximizeWindow(s32 fs);
s32 videoGetCenterWindow(void);
void videoSetCenterWindow(s32 center);
u32 videoGetTextureFilter(void); u32 videoGetTextureFilter(void);
s32 videoGetTextureFilter2D(void); s32 videoGetTextureFilter2D(void);
u32 videoGetAnisotropicFilter(void);
u32 videoGetMaxAnisotropyLevel(void);
s32 videoGetDetailTextures(void); s32 videoGetDetailTextures(void);
s32 videoGetDisplayModeIndex(void);
s32 videoGetDisplayMode(displaymode *out, const s32 index);
s32 videoGetNumDisplayModes(void);
s32 videoGetVsync(void);
s32 videoGetFramerateLimit(void);
s32 videoGetDisplayFPS(void);
s32 videoGetMSAA(void);
f32 videoGetGlareBrightness(void);
f32 videoGetOverexposureScale(void);
f32 videoGetAverageFPS(void);
void videoSetWindowOffset(s32 x, s32 y); void videoSetWindowOffset(s32 x, s32 y);
void videoSetFullscreen(s32 fs); void videoSetFullscreen(s32 fs);
void videoSetFullscreenMode(s32 mode);
void videoSetTextureFilter(u32 filter); void videoSetTextureFilter(u32 filter);
void videoSetTextureFilter2D(s32 filter); void videoSetTextureFilter2D(s32 filter);
void videoSetAnisotropicFilter(u32 filter);
void videoSetDetailTextures(s32 detail); void videoSetDetailTextures(s32 detail);
void videoCapFramerate(s32 limit); void videoSetDisplayMode(const s32 index);
void videoSetVsync(const s32 vsync);
void videoSetFramerateLimit(const s32 limit);
void videoSetDisplayFPS(const s32 displayfps);
void videoSetMSAA(const s32 msaa);
void videoSetGlareBrightness(f32 bright);
void videoSetOverexposureScale(f32 scale);
s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize); s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize);
void videoSetFramebuffer(s32 target); void videoSetFramebuffer(s32 target);
@@ -49,5 +78,8 @@ s32 videoFramebuffersSupported(void);
void videoResetTextureCache(void); void videoResetTextureCache(void);
void videoFreeCachedTexture(const void *texptr); void videoFreeCachedTexture(const void *texptr);
void videoFreeCachedTextures(const void *start, const void *end);
void videoShutdown(void);
#endif #endif
+9 -4
View File
@@ -10,7 +10,7 @@
#define CONFIG_MAX_SECNAME 128 #define CONFIG_MAX_SECNAME 128
#define CONFIG_MAX_KEYNAME 256 #define CONFIG_MAX_KEYNAME 256
#define CONFIG_MAX_SETTINGS 256 #define CONFIG_MAX_SETTINGS 300
typedef enum { typedef enum {
CFG_NONE, CFG_NONE,
@@ -34,6 +34,7 @@ struct configentry {
} settings[CONFIG_MAX_SETTINGS]; } settings[CONFIG_MAX_SETTINGS];
static s32 numSettings = 0; static s32 numSettings = 0;
static u8 configMaxWarningLogged = 0;
static inline s32 configClampInt(s32 val, s32 min, s32 max) static inline s32 configClampInt(s32 val, s32 min, s32 max)
{ {
@@ -64,11 +65,15 @@ static inline struct configentry *configAddEntry(const char *key)
{ {
if (numSettings < CONFIG_MAX_SETTINGS) { if (numSettings < CONFIG_MAX_SETTINGS) {
struct configentry *cfg = &settings[numSettings++]; struct configentry *cfg = &settings[numSettings++];
strncpy(cfg->key, key, CONFIG_MAX_KEYNAME); snprintf(cfg->key, CONFIG_MAX_KEYNAME, "%s", key);
const char *delim = strrchr(cfg->key, '.'); const char *delim = strrchr(cfg->key, '.');
cfg->seclen = delim ? (delim - cfg->key) : 0; cfg->seclen = delim ? (delim - cfg->key) : 0;
return cfg; return cfg;
} }
if (!configMaxWarningLogged) {
sysLogPrintf(LOG_WARNING, "Maximum number of configuration entries exceeded: %d", CONFIG_MAX_SETTINGS);
configMaxWarningLogged = 1;
}
return NULL; return NULL;
} }
@@ -228,7 +233,7 @@ s32 configSave(const char *fname)
configSaveEntry(cfg, f); configSaveEntry(cfg, f);
} }
fsFileClose(f); fsFileFree(f);
return 1; return 1;
} }
@@ -282,7 +287,7 @@ s32 configLoad(const char *fname)
} }
} }
fsFileClose(f); fsFileFree(f);
return 1; return 1;
} }
-213
View File
@@ -1,213 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include "platform.h"
#include "types.h"
#include "constants.h"
#include "data.h"
#include "bss.h"
#include "config.h"
#include "video.h"
#include "input.h"
#include "console.h"
#include "system.h"
#include "utils.h"
#include "net/net.h"
#include "game/hudmsg.h"
#include "game/game_1531a0.h"
#include "lib/vi.h"
#define CON_ROWS 80
#define CON_COLS 56
#define CON_VISROWS 10
#define CON_MSGROWS 4
#define CON_MSGTIMER 3.f
static char conBuf[CON_ROWS][CON_COLS + 1];
static char conInput[CON_COLS + 1];
static char *conVisRows[CON_VISROWS];
static s32 conPrintRow = 0;
static s32 conPrintCol = 0;
static s32 conMsgRows = 0;
static f32 conMsgTimer = 0.f;
static s32 conInputCol = 0;
static u32 conTextColour = 0x00ff00ff;
static s32 conOpen = 0;
static s32 conButton = 0;
void conInit(void)
{
memset(conBuf, 0, sizeof(conBuf));
memset(conInput, 0, sizeof(conInput));
memset(conVisRows, 0, sizeof(conVisRows));
conPrintRow = conPrintCol = 0;
conOpen = 0;
conMsgRows = 0;
conMsgTimer = 0.0f;
conInputCol = 0;
}
void conPrint(s32 showmsg, const char *str)
{
if (!str || !*str) {
return;
}
const s32 oldRow = conPrintRow;
for (const char *s = str; *s; ++s) {
char ch = *s;
switch (ch) {
case '\n':
if (conPrintCol) {
conPrintCol = 0;
conPrintRow = (conPrintRow + 1) % CON_ROWS;
}
break;
case '\r':
break;
case '\t':
ch = ' ';
/* fallthrough */
default:
conBuf[conPrintRow][conPrintCol++] = ch;
if (conPrintCol == CON_COLS) {
conPrintCol = 0;
conPrintRow = (conPrintRow + 1) % CON_ROWS;
}
break;
}
conBuf[conPrintRow][conPrintCol] = '\0';
}
if (conPrintRow != oldRow) {
// scroll time
for (s32 i = 0; i < ARRAYCOUNT(conVisRows); ++i) {
s32 row = conPrintRow - i - 1;
if (row < 0) {
row = CON_ROWS + row;
}
conVisRows[i] = &conBuf[row][0];
}
if (showmsg) {
if (conMsgRows < CON_MSGROWS) {
if (conPrintRow > oldRow) {
conMsgRows += conPrintRow - oldRow;
} else {
conMsgRows += conPrintRow + (CON_ROWS - oldRow);
}
}
conMsgTimer = sysGetSeconds() + CON_MSGTIMER;
}
}
}
void conPrintLn(s32 showmsg, const char *s)
{
char tmp[4096];
snprintf(tmp, sizeof(tmp), "%s\n", s);
conPrint(showmsg, tmp);
}
void conPrintf(s32 showmsg, const char *fmt, ...)
{
char tmp[4096];
tmp[sizeof(tmp) - 1] = '\0';
tmp[0] = '\0';
va_list args;
va_start(args, fmt);
vsnprintf(tmp, sizeof(tmp), fmt, args);
va_end(args);
conPrint(showmsg, tmp);
}
static inline Gfx *conRenderMsgs(Gfx *gdl)
{
if (conMsgRows) {
s32 x, y;
const u32 c = (conTextColour & 0xffffff00) | 0xa0;
for (s32 i = 0; i < conMsgRows; ++i) {
char *s = conVisRows[i];
if (s) {
x = 4;
y = 4 + 8 * (conMsgRows - i - 1);
gdl = textRenderProjected(gdl, &x, &y, s, g_CharsHandelGothicXs, g_FontHandelGothicXs, c, viGetWidth(), viGetHeight(), 0, 0);
}
}
const f32 t = sysGetSeconds();
if (conMsgTimer <= t) {
conMsgTimer = t + CON_MSGTIMER;
--conMsgRows;
}
} else {
conMsgTimer = 0;
}
return gdl;
}
Gfx *conRender(Gfx *gdl)
{
if (!g_CharsHandelGothicXs || !g_FontHandelGothicXs) {
return gdl;
}
gdl = text0f153628(gdl);
if (!conOpen) {
gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, G_ASPECT_LEFT_EXT);
gdl = conRenderMsgs(gdl);
} else {
s32 x, y;
gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, G_ASPECT_CENTER_EXT);
gdl = hudmsgRenderBox(gdl, 16, 0, SCREEN_WIDTH_LO - 16, 4 + 8 * (CON_VISROWS + 1), 1.f, conTextColour, 0.9f);
for (s32 i = 0; i < CON_VISROWS; ++i) {
char *s = conVisRows[i];
if (s) {
x = 18;
y = 4 + 8 * (CON_VISROWS - i - 1);
gdl = textRenderProjected(gdl, &x, &y, s, g_CharsHandelGothicXs, g_FontHandelGothicXs, conTextColour, viGetWidth(), viGetHeight(), 0, 0);
}
}
char tmp[CON_COLS + 3];
snprintf(tmp, sizeof(tmp), "> %s", conInput);
x = 18;
y = 4 + 8 * CON_VISROWS;
gdl = textRenderProjected(gdl, &x, &y, tmp, g_CharsHandelGothicXs, g_FontHandelGothicXs, conTextColour, viGetWidth(), viGetHeight(), 0, 0);
}
gSPClearExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT);
gdl = text0f153780(gdl);
return gdl;
}
void conTick(void)
{
const s32 button = inputKeyPressed(VK_GRAVE);
if (button && !conButton) {
conOpen = !conOpen;
if (conOpen) {
inputStartTextInput();
} else {
inputStopTextInput();
}
}
conButton = button;
if (conOpen) {
if (inputTextHandler(conInput, CON_COLS, &conInputCol)) {
if (g_NetMode) {
netChat(NULL, conInput);
}
conInput[0] = '\0';
conInputCol = 0;
}
}
}
+15 -3
View File
@@ -11,6 +11,9 @@
#include "platform.h" #include "platform.h"
#include "utils.h" #include "utils.h"
#include "fs.h" #include "fs.h"
#ifdef PLATFORM_WIN32
#include <direct.h>
#endif
#define DEFAULT_BASEDIR_NAME "data" #define DEFAULT_BASEDIR_NAME "data"
@@ -111,7 +114,7 @@ s32 fsInit(void)
if (!portable) { if (!portable) {
if (fsFileSize("./" DEFAULT_BASEDIR_NAME) >= 0) { if (fsFileSize("./" DEFAULT_BASEDIR_NAME) >= 0) {
path = "./" DEFAULT_BASEDIR_NAME; path = "./" DEFAULT_BASEDIR_NAME;
} else if (fsFileSize("$H/" DEFAULT_BASEDIR_NAME)) { } else if (fsFileSize("$H/" DEFAULT_BASEDIR_NAME) >= 0) {
path = "$H/" DEFAULT_BASEDIR_NAME; path = "$H/" DEFAULT_BASEDIR_NAME;
} }
} }
@@ -149,7 +152,7 @@ s32 fsInit(void)
if (portable) { if (portable) {
path = "$E"; path = "$E";
} else { } else {
#ifdef PLATFORM_LINUX #if defined(PLATFORM_LINUX) || defined(PLATFORM_OSX)
// check if there's a config in the working directory, otherwise default to homeDir // check if there's a config in the working directory, otherwise default to homeDir
if (fsFileSize("./" CONFIG_FNAME) >= 0) { if (fsFileSize("./" CONFIG_FNAME) >= 0) {
path = "."; path = ".";
@@ -276,7 +279,16 @@ FILE *fsFileOpenRead(const char *name)
return fopen(fsFullPath(name), "rb"); return fopen(fsFullPath(name), "rb");
} }
void fsFileClose(FILE *f) void fsFileFree(FILE *f)
{ {
fclose(f); fclose(f);
} }
s32 fsCreateDir(const char *path)
{
#ifdef PLATFORM_WIN32
return _mkdir(fsFullPath(path));
#else
return mkdir(fsFullPath(path), 0777);
#endif
}
+205 -52
View File
@@ -28,6 +28,9 @@
#define WHEEL_UP_MASK SDL_BUTTON(VK_MOUSE_WHEEL_UP - VK_MOUSE_BEGIN + 1) #define WHEEL_UP_MASK SDL_BUTTON(VK_MOUSE_WHEEL_UP - VK_MOUSE_BEGIN + 1)
#define WHEEL_DN_MASK SDL_BUTTON(VK_MOUSE_WHEEL_DN - VK_MOUSE_BEGIN + 1) #define WHEEL_DN_MASK SDL_BUTTON(VK_MOUSE_WHEEL_DN - VK_MOUSE_BEGIN + 1)
#define CURSOR_HIDE_THRESHOLD 1
#define CURSOR_HIDE_TIME 3000000 // us
static SDL_GameController *pads[INPUT_MAX_CONTROLLERS]; static SDL_GameController *pads[INPUT_MAX_CONTROLLERS];
#define CONTROLLERCFG_DEFAULT { \ #define CONTROLLERCFG_DEFAULT { \
@@ -41,7 +44,8 @@ static SDL_GameController *pads[INPUT_MAX_CONTROLLERS];
.deadzone = { DEFAULT_DEADZONE, DEFAULT_DEADZONE, DEFAULT_DEADZONE, DEFAULT_DEADZONE_RY }, \ .deadzone = { DEFAULT_DEADZONE, DEFAULT_DEADZONE, DEFAULT_DEADZONE, DEFAULT_DEADZONE_RY }, \
.stickCButtons = 0, \ .stickCButtons = 0, \
.swapSticks = 1, \ .swapSticks = 1, \
.deviceIndex = -1 \ .deviceIndex = -1, \
.cancelCButtons = 0, \
} }
static struct controllercfg { static struct controllercfg {
@@ -53,6 +57,7 @@ static struct controllercfg {
s32 stickCButtons; s32 stickCButtons;
s32 swapSticks; s32 swapSticks;
s32 deviceIndex; s32 deviceIndex;
s32 cancelCButtons;
} padsCfg[INPUT_MAX_CONTROLLERS] = { } padsCfg[INPUT_MAX_CONTROLLERS] = {
CONTROLLERCFG_DEFAULT, CONTROLLERCFG_DEFAULT,
CONTROLLERCFG_DEFAULT, CONTROLLERCFG_DEFAULT,
@@ -69,16 +74,22 @@ static s32 connectedMask = 0;
static s32 numJoysticks = 0; static s32 numJoysticks = 0;
static s32 useHIDAPI = 1;
static s32 useRawInput = 0;
static s32 mouseEnabled = 1; static s32 mouseEnabled = 1;
static s32 mouseLocked = 0;
static s32 mouseDefaultLocked = 0;
static s32 mouseX, mouseY; static s32 mouseX, mouseY;
static s32 mouseDX, mouseDY; static s32 mouseDX, mouseDY;
static u32 mouseButtons; static u32 mouseButtons;
static s32 mouseWheel = 0; static s32 mouseWheel = 0;
static f32 mouseSensX = 1.5f; static s32 mouseLocked = 0;
static f32 mouseSensY = 1.5f; static s32 mouseLockMode = MLOCK_AUTO;
static u64 mouseCursorTime = 0;
static s32 mouseShowCursor = 1;
static f32 mouseSensX = 2.5f;
static f32 mouseSensY = 2.5f;
static s32 lastKey = 0; static s32 lastKey = 0;
static char lastChar = 0; static char lastChar = 0;
@@ -107,8 +118,8 @@ static const char *ckNames[CK_TOTAL_COUNT] = {
"STICK_XPOS", "STICK_XPOS",
"STICK_YNEG", "STICK_YNEG",
"STICK_YPOS", "STICK_YPOS",
"CK_0010", "ACCEPT_BUTTON",
"CK_0020", "CANCEL_BUTTON",
"CK_0040", "CK_0040",
"CK_0080", "CK_0080",
"CK_0100", "CK_0100",
@@ -173,6 +184,8 @@ static const char *vkJoyNames[] = {
static char vkNames[VK_TOTAL_COUNT][64]; static char vkNames[VK_TOTAL_COUNT][64];
static s8 vkPrevState[VK_TOTAL_COUNT];
void inputSetDefaultKeyBinds(s32 cidx, s32 n64mode) void inputSetDefaultKeyBinds(s32 cidx, s32 n64mode)
{ {
// TODO: make VK constants for all these // TODO: make VK constants for all these
@@ -182,7 +195,7 @@ void inputSetDefaultKeyBinds(s32 cidx, s32 n64mode)
{ CK_RTRIG, VK_MOUSE_RIGHT, SDL_SCANCODE_Z }, { CK_RTRIG, VK_MOUSE_RIGHT, SDL_SCANCODE_Z },
{ CK_LTRIG, SDL_SCANCODE_F, SDL_SCANCODE_X }, { CK_LTRIG, SDL_SCANCODE_F, SDL_SCANCODE_X },
{ CK_ZTRIG, VK_MOUSE_LEFT, SDL_SCANCODE_SPACE }, { CK_ZTRIG, VK_MOUSE_LEFT, SDL_SCANCODE_SPACE },
{ CK_START, SDL_SCANCODE_RETURN, SDL_SCANCODE_TAB }, { CK_START, SDL_SCANCODE_TAB, 0 },
{ CK_DPAD_D, SDL_SCANCODE_Q, VK_MOUSE_MIDDLE }, { CK_DPAD_D, SDL_SCANCODE_Q, VK_MOUSE_MIDDLE },
{ CK_DPAD_U, 0, 0 }, { CK_DPAD_U, 0, 0 },
{ CK_Y, VK_MOUSE_WHEEL_DN, 0 }, { CK_Y, VK_MOUSE_WHEEL_DN, 0 },
@@ -196,7 +209,9 @@ void inputSetDefaultKeyBinds(s32 cidx, s32 n64mode)
{ CK_STICK_YNEG, SDL_SCANCODE_DOWN, 0 }, { CK_STICK_YNEG, SDL_SCANCODE_DOWN, 0 },
{ CK_STICK_YPOS, SDL_SCANCODE_UP, 0 }, { CK_STICK_YPOS, SDL_SCANCODE_UP, 0 },
{ CK_4000, SDL_SCANCODE_LSHIFT, 0 }, { CK_4000, SDL_SCANCODE_LSHIFT, 0 },
{ CK_2000, SDL_SCANCODE_LCTRL, 0 } { CK_2000, SDL_SCANCODE_LCTRL, 0 },
{ CK_ACCEPT, SDL_SCANCODE_RETURN, SDL_SCANCODE_E },
{ CK_CANCEL, VK_MOUSE_RIGHT, 0 },
}; };
static const u32 pcjoybinds[][2] = { static const u32 pcjoybinds[][2] = {
@@ -213,6 +228,8 @@ void inputSetDefaultKeyBinds(s32 cidx, s32 n64mode)
{ CK_C_U, SDL_CONTROLLER_BUTTON_DPAD_UP }, { CK_C_U, SDL_CONTROLLER_BUTTON_DPAD_UP },
{ CK_C_R, SDL_CONTROLLER_BUTTON_DPAD_RIGHT }, { CK_C_R, SDL_CONTROLLER_BUTTON_DPAD_RIGHT },
{ CK_C_L, SDL_CONTROLLER_BUTTON_DPAD_LEFT }, { CK_C_L, SDL_CONTROLLER_BUTTON_DPAD_LEFT },
{ CK_ACCEPT, SDL_CONTROLLER_BUTTON_A },
{ CK_CANCEL, SDL_CONTROLLER_BUTTON_B },
{ CK_8000, SDL_CONTROLLER_BUTTON_LEFTSTICK }, { CK_8000, SDL_CONTROLLER_BUTTON_LEFTSTICK },
}; };
@@ -323,6 +340,14 @@ static inline void inputInitController(const s32 cidx, const s32 jidx)
sysLogPrintf(LOG_NOTE, "input: assigned controller '%d: (%s)' (id %d) to player %d", sysLogPrintf(LOG_NOTE, "input: assigned controller '%d: (%s)' (id %d) to player %d",
jidx, SDL_GameControllerName(pads[cidx]), inputControllerGetId(pads[cidx]), cidx); jidx, SDL_GameControllerName(pads[cidx]), inputControllerGetId(pads[cidx]), cidx);
SDL_Joystick* joy = SDL_GameControllerGetJoystick(pads[cidx]);
if (joy) {
char guidStr[1024] = "";
SDL_JoystickGUID guid = SDL_JoystickGetGUID(joy);
SDL_JoystickGetGUIDString(guid, guidStr, sizeof(guidStr));
sysLogPrintf(LOG_NOTE, "input: GUID for controller %d: %s", jidx, guidStr);
}
} }
static inline void inputCloseController(const s32 cidx) static inline void inputCloseController(const s32 cidx)
@@ -654,6 +679,47 @@ static inline void inputLoadBinds(void)
s32 inputInit(void) s32 inputInit(void)
{ {
// Set SDL hints before initializing the controller subsystem.
if (useHIDAPI) {
#if SDL_VERSION_ATLEAST(2, 0, 12)
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE, "1");
#endif
#if SDL_VERSION_ATLEAST(2, 0, 14)
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5, "1");
#endif
#if SDL_VERSION_ATLEAST(2, 0, 22)
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI, "1");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4, "1");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "1");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1");
// the two hints below enable Rumble and Motion Sensor for PS4/5 pads connected via bluetooth
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_STEAM, "1");
#endif
#if SDL_VERSION_ATLEAST(2, 23, 2)
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, "1");
#endif
#if SDL_VERSION_ATLEAST(2, 25, 1)
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS3, "1");
#endif
#if SDL_VERSION_ATLEAST(2, 26, 0)
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_WII, "1");
#endif
#if SDL_VERSION_ATLEAST(2, 30, 0)
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_STEAMDECK, "1");
#endif
}
if (useRawInput) {
SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "1");
#ifdef SDL_HINT_JOYSTICK_RAWINPUT_CORRELATE_XINPUT
SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT_CORRELATE_XINPUT, "1");
#elif defined(SDL_HINT_JOYSTICK_HIDAPI_CORRELATE_XINPUT)
// old name for SDL_HINT_JOYSTICK_RAWINPUT_CORRELATE_XINPUT before SDL2.0.16
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_CORRELATE_XINPUT, "1");
#endif
}
if (!SDL_WasInit(SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC)) { if (!SDL_WasInit(SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC)) {
SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC); SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC);
} }
@@ -678,7 +744,9 @@ s32 inputInit(void)
inputSetDefaultKeyBinds(i, 0); inputSetDefaultKeyBinds(i, 0);
} }
inputLockMouse(mouseDefaultLocked); if (mouseLockMode != MLOCK_AUTO) {
inputLockMouse(mouseLockMode);
}
// update the axis maps // update the axis maps
// NOTE: by default sticks get swapped for 1.2: "right stick" here means left stick on your controller // NOTE: by default sticks get swapped for 1.2: "right stick" here means left stick on your controller
@@ -688,6 +756,9 @@ s32 inputInit(void)
inputLoadBinds(); inputLoadBinds();
// Explicitly stop text input to prevent key events being swallowed on certain Wayland systems
inputStopTextInput();
return connectedMask; return connectedMask;
} }
@@ -748,12 +819,22 @@ s32 inputReadController(s32 idx, OSContPad *npad)
npad->stick_x = xdiff < 0 ? -0x80 : (xdiff > 0 ? 0x7F : 0); npad->stick_x = xdiff < 0 ? -0x80 : (xdiff > 0 ? 0x7F : 0);
npad->stick_y = ydiff < 0 ? -0x80 : (ydiff > 0 ? 0x7F : 0); npad->stick_y = ydiff < 0 ? -0x80 : (ydiff > 0 ? 0x7F : 0);
const struct controllercfg *cfg = &padsCfg[idx];
if (cfg->cancelCButtons) {
// opposite C buttons cancel each other out
if ((npad->button & (L_CBUTTONS | R_CBUTTONS)) == (L_CBUTTONS | R_CBUTTONS)) {
npad->button &= ~(L_CBUTTONS | R_CBUTTONS);
}
if ((npad->button & (U_CBUTTONS | D_CBUTTONS)) == (U_CBUTTONS | D_CBUTTONS)) {
npad->button &= ~(U_CBUTTONS | D_CBUTTONS);
}
}
if (!pads[idx]) { if (!pads[idx]) {
return 0; return 0;
} }
const struct controllercfg *cfg = &padsCfg[idx];
s32 leftX = SDL_GameControllerGetAxis(pads[idx], cfg->axisMap[0][0]); s32 leftX = SDL_GameControllerGetAxis(pads[idx], cfg->axisMap[0][0]);
s32 leftY = SDL_GameControllerGetAxis(pads[idx], cfg->axisMap[0][1]); s32 leftY = SDL_GameControllerGetAxis(pads[idx], cfg->axisMap[0][1]);
s32 rightX = SDL_GameControllerGetAxis(pads[idx], cfg->axisMap[1][0]); s32 rightX = SDL_GameControllerGetAxis(pads[idx], cfg->axisMap[1][0]);
@@ -808,8 +889,12 @@ static inline void inputUpdateMouse(void)
mouseWheel = 0; mouseWheel = 0;
s32 mdx = 0;
s32 mdy = 0;
SDL_GetRelativeMouseState(&mdx, &mdy);
if (mouseLocked) { if (mouseLocked) {
SDL_GetRelativeMouseState(&mouseDX, &mouseDY); mouseDX = mdx;
mouseDY = mdy;
} else { } else {
mouseDX = mx - mouseX; mouseDX = mx - mouseX;
mouseDY = my - mouseY; mouseDY = my - mouseY;
@@ -818,10 +903,18 @@ static inline void inputUpdateMouse(void)
mouseX = mx; mouseX = mx;
mouseY = my; mouseY = my;
if (!mouseLocked && (mouseButtons & SDL_BUTTON_LMASK)) { // if MLOCK_AUTO is enabled, disable cursor if mouse is unlocked
inputLockMouse(1); // and we haven't moved it for a few seconds
} else if (mouseLocked && inputKeyPressed(VK_ESCAPE)) { if (mouseLockMode == MLOCK_AUTO && !mouseLocked) {
inputLockMouse(0); if (abs(mouseDX) > CURSOR_HIDE_THRESHOLD || abs(mouseDY) > CURSOR_HIDE_THRESHOLD) {
if (!mouseShowCursor) {
inputMouseShowCursor(1);
}
} else if (sysGetMicroseconds() > mouseCursorTime) {
if (mouseShowCursor) {
inputMouseShowCursor(0);
}
}
} }
} }
@@ -919,6 +1012,16 @@ void inputControllerSetDualAnalog(s32 cidx, s32 enable)
padsCfg[cidx].stickCButtons = !enable; padsCfg[cidx].stickCButtons = !enable;
} }
s32 inputControllerGetCancelCButtons(s32 cidx)
{
return padsCfg[cidx].cancelCButtons;
}
void inputControllerSetCancelCButtons(s32 cidx, s32 cancel)
{
padsCfg[cidx].cancelCButtons = cancel;
}
f32 inputControllerGetAxisScale(s32 cidx, s32 stick, s32 axis) f32 inputControllerGetAxisScale(s32 cidx, s32 stick, s32 axis)
{ {
return padsCfg[cidx].sens[stick * 2 + axis]; return padsCfg[cidx].sens[stick * 2 + axis];
@@ -988,6 +1091,13 @@ const char *inputGetConnectedControllerName(s32 id)
snprintf(fullName, sizeof(fullName), "%d: %s", jidx, name); snprintf(fullName, sizeof(fullName), "%d: %s", jidx, name);
// replace non-ascii chars with spaces
for (char *p = fullName; *p; ++p) {
if ((u32)*p >= 0x7f) {
*p = ' ';
}
}
return fullName; return fullName;
} }
@@ -1069,9 +1179,13 @@ s32 inputKeyPressed(u32 vk)
if (vk >= VK_KEYBOARD_BEGIN && vk < VK_MOUSE_BEGIN) { if (vk >= VK_KEYBOARD_BEGIN && vk < VK_MOUSE_BEGIN) {
const u8 *state = SDL_GetKeyboardState(NULL); const u8 *state = SDL_GetKeyboardState(NULL);
return state[vk - VK_KEYBOARD_BEGIN]; return state[vk - VK_KEYBOARD_BEGIN];
} else if (vk >= VK_MOUSE_BEGIN && vk < VK_JOY_BEGIN) { }
return mouseButtons & SDL_BUTTON(vk - VK_MOUSE_BEGIN + 1);
} else if (vk >= VK_JOY_BEGIN && vk < VK_TOTAL_COUNT) { if (vk >= VK_MOUSE_BEGIN && vk < VK_JOY_BEGIN) {
return (mouseButtons & SDL_BUTTON(vk - VK_MOUSE_BEGIN + 1)) != 0;
}
if (vk >= VK_JOY_BEGIN && vk < VK_TOTAL_COUNT) {
vk -= VK_JOY_BEGIN; vk -= VK_JOY_BEGIN;
const s32 idx = vk / INPUT_MAX_CONTROLLER_BUTTONS; const s32 idx = vk / INPUT_MAX_CONTROLLER_BUTTONS;
if (idx < 0 || idx >= INPUT_MAX_CONTROLLERS || !pads[idx]) { if (idx < 0 || idx >= INPUT_MAX_CONTROLLERS || !pads[idx]) {
@@ -1085,9 +1199,18 @@ s32 inputKeyPressed(u32 vk)
} }
return SDL_GameControllerGetButton(pads[idx], vk); return SDL_GameControllerGetButton(pads[idx], vk);
} }
return 0; return 0;
} }
s32 inputKeyJustPressed(u32 vk)
{
const s8 pressed = inputKeyPressed(vk);
const s32 result = pressed && !vkPrevState[vk];
vkPrevState[vk] = pressed;
return result;
}
static inline u32 inputContToContKey(const u32 cont) static inline u32 inputContToContKey(const u32 cont)
{ {
if (cont == 0) { if (cont == 0) {
@@ -1117,10 +1240,11 @@ s32 inputMouseIsLocked(void)
return mouseLocked; return mouseLocked;
} }
void inputMouseGetPosition(s32 *x, s32 *y) s32 inputMouseGetPosition(s32 *x, s32 *y)
{ {
if (x) *x = mouseX * videoGetNativeWidth() / videoGetWidth(); if (x) *x = mouseX * videoGetNativeWidth() / videoGetWidth();
if (y) *y = mouseY * videoGetNativeHeight() / videoGetHeight(); if (y) *y = mouseY * videoGetNativeHeight() / videoGetHeight();
return (mouseDX != 0 || mouseDY != 0);
} }
void inputMouseGetRawDelta(s32 *dx, s32 *dy) void inputMouseGetRawDelta(s32 *dx, s32 *dy)
@@ -1129,29 +1253,23 @@ void inputMouseGetRawDelta(s32 *dx, s32 *dy)
if (dy) *dy = mouseDY; if (dy) *dy = mouseDY;
} }
void inputMouseGetScaledDelta(f32 *dx, f32 *dy) void inputMouseGetScaledDelta(f32* dx, f32* dy)
{ {
f32 mdx, mdy; f32 mdx = 0.f, mdy = 0.f;
if (mouseLocked) { if (mouseLocked) {
mdx = mouseSensX * (f32)mouseDX / 100.0f; mdx = mouseDX * (0.022f / 3.5f) * mouseSensX;
mdy = mouseSensY * (f32)mouseDY / 100.0f; mdy = mouseDY * (0.022f / 3.5f) * mouseSensY;
} else {
mdx = 0.f;
mdy = 0.f;
} }
if (dx) *dx = mdx; if (dx) *dx = mdx;
if (dy) *dy = mdy; if (dy) *dy = mdy;
} }
void inputMouseGetAbsScaledDelta(f32 *dx, f32 *dy) void inputMouseGetAbsScaledDelta(f32* dx, f32* dy)
{ {
f32 mdx, mdy; f32 mdx = 0.f, mdy = 0.f;
if (mouseLocked) { if (mouseLocked) {
mdx = fabsf(mouseSensX) * (f32)mouseDX / 100.0f; mdx = mouseDX * (0.022f / 3.5f) * fabsf(mouseSensX);
mdy = fabsf(mouseSensY) * (f32)mouseDY / 100.0f; mdy = mouseDY * (0.022f / 3.5f) * fabsf(mouseSensY);
} else {
mdx = 0.f;
mdy = 0.f;
} }
if (dx) *dx = mdx; if (dx) *dx = mdx;
if (dy) *dy = mdy; if (dy) *dy = mdy;
@@ -1177,21 +1295,41 @@ s32 inputMouseIsEnabled(void)
void inputMouseEnable(s32 enabled) void inputMouseEnable(s32 enabled)
{ {
mouseEnabled = !!enabled; mouseEnabled = !!enabled;
if (!mouseEnabled && mouseLocked) { if (!mouseEnabled && mouseLockMode != MLOCK_ON && mouseLocked) {
inputLockMouse(0); inputLockMouse(0);
} }
} }
s32 inputGetMouseDefaultLocked(void) s32 inputAutoLockMouse(s32 wantlock)
{ {
return mouseDefaultLocked; if (mouseEnabled && mouseLockMode == MLOCK_AUTO) {
inputLockMouse(wantlock);
return 1;
}
return 0;
} }
void inputSetMouseDefaultLocked(s32 defaultLocked) void inputMouseShowCursor(s32 show)
{ {
mouseDefaultLocked = !!defaultLocked; mouseShowCursor = !!show;
if (mouseEnabled) { SDL_ShowCursor(mouseShowCursor);
inputLockMouse(mouseDefaultLocked); if (show) {
mouseCursorTime = sysGetMicroseconds() + CURSOR_HIDE_TIME;
}
}
s32 inputGetMouseLockMode(void)
{
return mouseLockMode;
}
void inputSetMouseLockMode(s32 lockmode)
{
mouseLockMode = lockmode;
if (lockmode == MLOCK_ON) {
inputLockMouse(1);
} else {
inputLockMouse(0);
} }
} }
@@ -1287,14 +1425,20 @@ char inputGetLastTextChar(void)
return lastChar; return lastChar;
} }
s32 inputTextHandler(char *out, const u32 outSize, s32 *curCol) static inline s32 filterChar(const char ch)
{ {
const s32 ctrlHeld = inputKeyPressed(VK_LCTRL) || inputKeyPressed(VK_RCTRL); return isalnum(ch) || ch == ' ' || ch == '?' || ch == '!' || ch == '.';
}
s32 inputTextHandler(char *out, const u32 outSize, s32 *curCol, s32 oskCharsOnly)
{
const s32 ctrlHeld = inputGetKeyModState() & KM_CTRL;
if (!ctrlHeld) { if (!ctrlHeld) {
const char chr = inputGetLastTextChar(); const char chr = inputGetLastTextChar();
inputClearLastTextChar(); inputClearLastTextChar();
if (chr && isprint(chr)) { const s32 valid = chr && (oskCharsOnly ? filterChar(chr) : isprint(chr));
if (valid) {
if (*curCol < outSize - 1) { if (*curCol < outSize - 1) {
out[(*curCol)++] = chr; out[(*curCol)++] = chr;
out[*curCol] = '\0'; out[*curCol] = '\0';
@@ -1321,10 +1465,6 @@ s32 inputTextHandler(char *out, const u32 outSize, s32 *curCol)
} else { } else {
out[0] = '\0'; out[0] = '\0';
} }
} else if (key == VK_RETURN) {
if (out[0] && *curCol) {
return 1;
}
} else if (key == VK_ESCAPE) { } else if (key == VK_ESCAPE) {
return -1; return -1;
} }
@@ -1363,14 +1503,26 @@ void inputStopTextInput(void)
textInput = 0; textInput = 0;
} }
s32 inputIsTextInputActive(void)
{
return textInput;
}
u32 inputGetKeyModState(void)
{
return SDL_GetModState();
}
PD_CONSTRUCTOR static void inputConfigInit(void) PD_CONSTRUCTOR static void inputConfigInit(void)
{ {
configRegisterInt("Input.MouseEnabled", &mouseEnabled, 0, 1); configRegisterInt("Input.MouseEnabled", &mouseEnabled, 0, 1);
configRegisterInt("Input.MouseDefaultLocked", &mouseDefaultLocked, 0, 1); configRegisterInt("Input.MouseLockMode", &mouseLockMode, MLOCK_OFF, MLOCK_AUTO);
configRegisterFloat("Input.MouseSpeedX", &mouseSensX, -10.f, 10.f); configRegisterFloat("Input.MouseSpeedX", &mouseSensX, -30.f, 30.f);
configRegisterFloat("Input.MouseSpeedY", &mouseSensY, -10.f, 10.f); configRegisterFloat("Input.MouseSpeedY", &mouseSensY, -30.f, 30.f);
configRegisterInt("Input.FakeGamepads", &fakeControllers, 0, 4); configRegisterInt("Input.FakeGamepads", &fakeControllers, 0, 4);
configRegisterInt("Input.FirstGamepadNum", &firstController, 0, 3); configRegisterInt("Input.FirstGamepadNum", &firstController, 0, 3);
configRegisterInt("Input.UseHIDAPI", &useHIDAPI, 0, 1);
configRegisterInt("Input.UseRawInput", &useRawInput, 0, 1);
char secname[] = "Input.Player1.Binds"; char secname[] = "Input.Player1.Binds";
char keyname[256] = { 0 }; char keyname[256] = { 0 };
@@ -1387,6 +1539,7 @@ PD_CONSTRUCTOR static void inputConfigInit(void)
configRegisterFloat(strFmt("%s.RStickScaleX", secname), &padsCfg[c].sens[2], -10.f, 10.f); configRegisterFloat(strFmt("%s.RStickScaleX", secname), &padsCfg[c].sens[2], -10.f, 10.f);
configRegisterFloat(strFmt("%s.RStickScaleY", secname), &padsCfg[c].sens[3], -10.f, 10.f); configRegisterFloat(strFmt("%s.RStickScaleY", secname), &padsCfg[c].sens[3], -10.f, 10.f);
configRegisterInt(strFmt("%s.StickCButtons", secname), &padsCfg[c].stickCButtons, 0, 1); configRegisterInt(strFmt("%s.StickCButtons", secname), &padsCfg[c].stickCButtons, 0, 1);
configRegisterInt(strFmt("%s.CancelCButtons", secname), &padsCfg[c].cancelCButtons, 0, 1);
configRegisterInt(strFmt("%s.SwapSticks", secname), &padsCfg[c].swapSticks, 0, 1); configRegisterInt(strFmt("%s.SwapSticks", secname), &padsCfg[c].swapSticks, 0, 1);
configRegisterInt(strFmt("%s.ControllerIndex", secname), &padsCfg[c].deviceIndex, -1, 0x7FFFFFFF); configRegisterInt(strFmt("%s.ControllerIndex", secname), &padsCfg[c].deviceIndex, -1, 0x7FFFFFFF);
secname[13] = '.'; secname[13] = '.';
+7 -8
View File
@@ -6,6 +6,7 @@
#include <errno.h> #include <errno.h>
#include <PR/os_internal.h> #include <PR/os_internal.h>
#include <PR/rcp.h> #include <PR/rcp.h>
#include "platform.h"
#include "system.h" #include "system.h"
#include "input.h" #include "input.h"
#include "video.h" #include "video.h"
@@ -277,7 +278,7 @@ static inline void osEeepromLoad(const char *fname)
FILE *fp = fsFileOpenRead(fname); FILE *fp = fsFileOpenRead(fname);
if (fp) { if (fp) {
fread(eeprom, 1, EEPROM_SIZE, fp); fread(eeprom, 1, EEPROM_SIZE, fp);
fsFileClose(fp); fsFileFree(fp);
} else { } else {
sysLogPrintf(LOG_NOTE, "could not read EEPROM from `%s`: %s", fsFullPath(fname), strerror(errno)); sysLogPrintf(LOG_NOTE, "could not read EEPROM from `%s`: %s", fsFullPath(fname), strerror(errno));
} }
@@ -289,7 +290,7 @@ static inline void osEeepromSave(const char *fname)
FILE* fp = fsFileOpenWrite(fname); FILE* fp = fsFileOpenWrite(fname);
if (fp) { if (fp) {
fwrite(eeprom, 1, EEPROM_SIZE, fp); fwrite(eeprom, 1, EEPROM_SIZE, fp);
fsFileClose(fp); fsFileFree(fp);
} else { } else {
sysLogPrintf(LOG_ERROR, "could not save EEPROM to `%s`: %s", fsFullPath(fname), strerror(errno)); sysLogPrintf(LOG_ERROR, "could not save EEPROM to `%s`: %s", fsFullPath(fname), strerror(errno));
} }
@@ -433,7 +434,7 @@ void osInvalDCache(void *a, s32 b)
} }
s32 osPiStartDma(OSIoMesg *mb, s32 priority, s32 direction, uintptr_t devAddr, void *vAddr, size_t nbytes, OSMesgQueue *mq) s32 osPiStartDma(OSIoMesg *mb, s32 priority, s32 direction, uintptr_t devAddr, void *vAddr, u32 nbytes, OSMesgQueue *mq)
{ {
memcpy(vAddr, (const void *)devAddr, nbytes); memcpy(vAddr, (const void *)devAddr, nbytes);
return 0; return 0;
@@ -466,23 +467,21 @@ OSIntMask osSetIntMask(OSIntMask mask)
/* libc compatibility wrappers */ /* libc compatibility wrappers */
#ifndef HAVE_BZERO #ifndef PLATFORM_OSX
void bzero(void *ptr, size_t size) void bzero(void *ptr, size_t size)
{ {
memset(ptr, 0, size); memset(ptr, 0, size);
} }
#endif
#ifndef HAVE_BCOPY
void bcopy(const void *src, void *dst, size_t n) void bcopy(const void *src, void *dst, size_t n)
{ {
memcpy(dst, src, n); memcpy(dst, src, n);
} }
#endif
#ifndef HAVE_BCMP
s32 bcmp(const void *s1, const void *s2, size_t n) s32 bcmp(const void *s1, const void *s2, size_t n)
{ {
return memcmp(s1, s2, n); return memcmp(s1, s2, n);
} }
#endif #endif
+10 -18
View File
@@ -16,9 +16,7 @@
#include "config.h" #include "config.h"
#include "mod.h" #include "mod.h"
#include "system.h" #include "system.h"
#include "console.h"
#include "utils.h" #include "utils.h"
#include "net/net.h"
u32 g_OsMemSize = 0; u32 g_OsMemSize = 0;
s32 g_OsMemSizeMb = 16; s32 g_OsMemSizeMb = 16;
@@ -71,7 +69,7 @@ static void gameInit(void)
{ {
osMemSize = g_OsMemSizeMb * 1024 * 1024; osMemSize = g_OsMemSizeMb * 1024 * 1024;
for (s32 i = 0; i < MAX_LOCAL_PLAYERS; ++i) { for (s32 i = 0; i < MAX_PLAYERS; ++i) {
struct extplayerconfig *cfg = g_PlayerExtCfg + i; struct extplayerconfig *cfg = g_PlayerExtCfg + i;
cfg->fovzoommult = cfg->fovzoom ? cfg->fovy / 60.0f : 1.0f; cfg->fovzoommult = cfg->fovzoom ? cfg->fovy / 60.0f : 1.0f;
} }
@@ -88,9 +86,9 @@ static void gameInit(void)
static void cleanup(void) static void cleanup(void)
{ {
sysLogPrintf(LOG_NOTE, "shutdown"); sysLogPrintf(LOG_NOTE, "shutdown");
netDisconnect();
inputSaveBinds(); inputSaveBinds();
configSave(CONFIG_PATH); configSave(CONFIG_PATH);
videoShutdown();
crashShutdown(); crashShutdown();
// TODO: actually shut down all subsystems // TODO: actually shut down all subsystems
} }
@@ -103,7 +101,6 @@ int main(int argc, const char **argv)
crashInit(); crashInit();
} }
conInit();
sysInit(); sysInit();
fsInit(); fsInit();
configInit(); configInit();
@@ -111,7 +108,8 @@ int main(int argc, const char **argv)
inputInit(); inputInit();
audioInit(); audioInit();
romdataInit(); romdataInit();
netInit();
g_ValidGbcRomFound = romdataCheckGbcRom();
gameInit(); gameInit();
@@ -138,8 +136,6 @@ int main(int argc, const char **argv)
g_StageNum = sysArgGetInt("--boot-stage", STAGE_TITLE); g_StageNum = sysArgGetInt("--boot-stage", STAGE_TITLE);
g_FileAutoSelect = sysArgGetInt("--profile", -1);
if (g_StageNum == STAGE_TITLE && (sysArgCheck("--skip-intro") || g_SkipIntro)) { if (g_StageNum == STAGE_TITLE && (sysArgCheck("--skip-intro") || g_SkipIntro)) {
// shorthand for --boot-stage 0x26 // shorthand for --boot-stage 0x26
g_StageNum = STAGE_CITRAINING; g_StageNum = STAGE_CITRAINING;
@@ -148,19 +144,11 @@ int main(int argc, const char **argv)
g_StageNum = STAGE_TITLE; g_StageNum = STAGE_TITLE;
} }
if (g_NetJoinLatch || g_NetHostLatch) {
if (g_FileAutoSelect < 0) {
// default to profile 0 if going into a net game
g_FileAutoSelect = 0;
}
// skip the intro if going into a net game
g_StageNum = STAGE_CITRAINING;
}
if (g_StageNum != STAGE_TITLE) { if (g_StageNum != STAGE_TITLE) {
sysLogPrintf(LOG_NOTE, "boot stage set to 0x%02x", g_StageNum); sysLogPrintf(LOG_NOTE, "boot stage set to 0x%02x", g_StageNum);
} }
g_FileAutoSelect = sysArgGetInt("--profile", -1);
if (g_FileAutoSelect >= 0) { if (g_FileAutoSelect >= 0) {
sysLogPrintf(LOG_NOTE, "player profile set to %d", g_FileAutoSelect); sysLogPrintf(LOG_NOTE, "player profile set to %d", g_FileAutoSelect);
} }
@@ -174,13 +162,15 @@ PD_CONSTRUCTOR static void gameConfigInit(void)
{ {
configRegisterInt("Game.MemorySize", &g_OsMemSizeMb, 4, 2048); configRegisterInt("Game.MemorySize", &g_OsMemSizeMb, 4, 2048);
configRegisterInt("Game.CenterHUD", &g_HudCenter, 0, 2); configRegisterInt("Game.CenterHUD", &g_HudCenter, 0, 2);
configRegisterInt("Game.MenuMouseControl", &g_MenuMouseControl, 0, 1);
configRegisterFloat("Game.ScreenShakeIntensity", &g_ViShakeIntensityMult, 0.f, 10.f); configRegisterFloat("Game.ScreenShakeIntensity", &g_ViShakeIntensityMult, 0.f, 10.f);
configRegisterInt("Game.TickRateDivisor", &g_TickRateDiv, 0, 10); configRegisterInt("Game.TickRateDivisor", &g_TickRateDiv, 0, 10);
configRegisterInt("Game.ExtraSleep", &g_TickExtraSleep, 0, 1); configRegisterInt("Game.ExtraSleep", &g_TickExtraSleep, 0, 1);
configRegisterInt("Game.SkipIntro", &g_SkipIntro, 0, 1); configRegisterInt("Game.SkipIntro", &g_SkipIntro, 0, 1);
configRegisterInt("Game.DisableMpDeathMusic", &g_MusicDisableMpDeath, 0, 1); configRegisterInt("Game.DisableMpDeathMusic", &g_MusicDisableMpDeath, 0, 1);
configRegisterInt("Game.GEMuzzleFlashes", &g_BgunGeMuzzleFlashes, 0, 1); configRegisterInt("Game.GEMuzzleFlashes", &g_BgunGeMuzzleFlashes, 0, 1);
for (s32 j = 0; j < MAX_LOCAL_PLAYERS; ++j) { configRegisterInt("Game.MaxExplosions", &g_MaxExplosions, 6, 96);
for (s32 j = 0; j < MAX_PLAYERS; ++j) {
const s32 i = j + 1; const s32 i = j + 1;
configRegisterFloat(strFmt("Game.Player%d.FovY", i), &g_PlayerExtCfg[j].fovy, 5.f, 175.f); configRegisterFloat(strFmt("Game.Player%d.FovY", i), &g_PlayerExtCfg[j].fovy, 5.f, 175.f);
configRegisterInt(strFmt("Game.Player%d.FovAffectsZoom", i), &g_PlayerExtCfg[j].fovzoom, 0, 1); configRegisterInt(strFmt("Game.Player%d.FovAffectsZoom", i), &g_PlayerExtCfg[j].fovzoom, 0, 1);
@@ -189,10 +179,12 @@ PD_CONSTRUCTOR static void gameConfigInit(void)
configRegisterFloat(strFmt("Game.Player%d.MouseAimSpeedY", i), &g_PlayerExtCfg[j].mouseaimspeedy, 0.f, 10.f); configRegisterFloat(strFmt("Game.Player%d.MouseAimSpeedY", i), &g_PlayerExtCfg[j].mouseaimspeedy, 0.f, 10.f);
configRegisterFloat(strFmt("Game.Player%d.RadialMenuSpeed", i), &g_PlayerExtCfg[j].radialmenuspeed, 0.f, 10.f); configRegisterFloat(strFmt("Game.Player%d.RadialMenuSpeed", i), &g_PlayerExtCfg[j].radialmenuspeed, 0.f, 10.f);
configRegisterFloat(strFmt("Game.Player%d.CrosshairSway", i), &g_PlayerExtCfg[j].crosshairsway, 0.f, 10.f); configRegisterFloat(strFmt("Game.Player%d.CrosshairSway", i), &g_PlayerExtCfg[j].crosshairsway, 0.f, 10.f);
configRegisterFloat(strFmt("Game.Player%d.CrosshairEdgeBoundary", i), &g_PlayerExtCfg[j].crosshairedgeboundary, 0.0f, 1.0f);
configRegisterInt(strFmt("Game.Player%d.CrouchMode", i), &g_PlayerExtCfg[j].crouchmode, 0, CROUCHMODE_TOGGLE_ANALOG); configRegisterInt(strFmt("Game.Player%d.CrouchMode", i), &g_PlayerExtCfg[j].crouchmode, 0, CROUCHMODE_TOGGLE_ANALOG);
configRegisterInt(strFmt("Game.Player%d.ExtendedControls", i), &g_PlayerExtCfg[j].extcontrols, 0, 1); configRegisterInt(strFmt("Game.Player%d.ExtendedControls", i), &g_PlayerExtCfg[j].extcontrols, 0, 1);
configRegisterUInt(strFmt("Game.Player%d.CrosshairColour", i), &g_PlayerExtCfg[j].crosshaircolour, 0, 0xFFFFFFFF); configRegisterUInt(strFmt("Game.Player%d.CrosshairColour", i), &g_PlayerExtCfg[j].crosshaircolour, 0, 0xFFFFFFFF);
configRegisterUInt(strFmt("Game.Player%d.CrosshairSize", i), &g_PlayerExtCfg[j].crosshairsize, 0, 4); configRegisterUInt(strFmt("Game.Player%d.CrosshairSize", i), &g_PlayerExtCfg[j].crosshairsize, 0, 4);
configRegisterInt(strFmt("Game.Player%d.CrosshairHealth", i), &g_PlayerExtCfg[j].crosshairhealth, 0, CROSSHAIR_HEALTH_ON_WHITE); configRegisterInt(strFmt("Game.Player%d.CrosshairHealth", i), &g_PlayerExtCfg[j].crosshairhealth, 0, CROSSHAIR_HEALTH_ON_WHITE);
configRegisterInt(strFmt("Game.Player%d.UseKeyReloads", i), &g_PlayerExtCfg[j].usereloads, 0, false);
} }
} }
+1
View File
@@ -6,6 +6,7 @@
#include "mixer.h" #include "mixer.h"
#include "platform.h" #include "platform.h"
#define MINIMP3_IMPLEMENTATION
#include "external/minimp3.h" #include "external/minimp3.h"
#ifdef __SSE4_1__ #ifdef __SSE4_1__
+3 -3
View File
@@ -420,7 +420,7 @@ s32 modTextureLoad(u16 num, void *dst, u32 dstSize)
{ {
static s32 dirExists = -1; static s32 dirExists = -1;
if (dirExists < 0) { if (dirExists < 0) {
dirExists = (fsFileSize(MOD_TEXTURES_DIR "/") >= 0); dirExists = (fsFileSize(MOD_TEXTURES_DIR) >= 0);
} }
if (!dirExists) { if (!dirExists) {
@@ -442,7 +442,7 @@ void *modSequenceLoad(u16 num, u32 *outSize)
{ {
static s32 dirExists = -1; static s32 dirExists = -1;
if (dirExists < 0) { if (dirExists < 0) {
dirExists = (fsFileSize(MOD_SEQUENCES_DIR "/") >= 0); dirExists = (fsFileSize(MOD_SEQUENCES_DIR) >= 0);
} }
if (!dirExists) { if (!dirExists) {
@@ -478,7 +478,7 @@ s32 modAnimationLoadDescriptor(u16 num, struct animtableentry *anim)
{ {
static s32 dirExists = -1; static s32 dirExists = -1;
if (dirExists < 0) { if (dirExists < 0) {
dirExists = (fsFileSize(MOD_ANIMATIONS_DIR "/") >= 0); dirExists = (fsFileSize(MOD_ANIMATIONS_DIR) >= 0);
} }
if (!dirExists) { if (!dirExists) {
+896
View File
@@ -0,0 +1,896 @@
#include "types.h"
#include "constants.h"
#include "bss.h"
#include "game/pak.h"
#include "game/filelist.h"
#include "game/menu.h"
#include "game/savebuffer.h"
#include "game/mplayer/mplayer.h"
#include <string.h>
#include "fs.h"
#include "system.h"
#include "mpsetups.h"
/*
MP Setup File Format
# header
[version{1}]
[defaultsetup{1}]
[numsetups{1}]
# setups
[setup_1{80}]
...
[setup_n{80}]
*/
#define MPSETUP_VERSION 1
#define MPSETUP_EXPORTDIR "$S/exported/"
#define MPSETUP_FILENAME "mpsetups"
#define MPSETUP_FILENAME_EXP "mpsetups-ext"
#define MPSETUP_OP_DEFAULT 0
#define MPSETUP_OP_IMPORT 1
#define MPSETUP_OP_EXPORT 2
#define MPSETUP_IMPORT_OVERWRITE 0
#define MPSETUP_IMPORT_ADD 1
#define MPSETUP_IMPORT_CONFLICT 0x1313
extern struct menudialogdef g_MpSaveSetupNameMenuDialog;
s16 g_MpCurrentSetup = -1;
struct mpsetupfile g_MpSetupFile;
static struct mpsetupfile g_ImportMpSetupFile;
static u64 g_MpImportExportFilter[2];
static char g_StatusText[128];
static char g_TitleImportExportDialog[20];
static char g_LabelSetDefault[20] = "Set Default\n";
/* extended mpsetup menu definitions */
static MenuItemHandlerResult menuhandlerRenameSetup(s32 operation, struct menuitem *item, union handlerdata *data);
static MenuItemHandlerResult menuhandlerDeleteSetup(s32 operation, struct menuitem *item, union handlerdata *data);
static MenuItemHandlerResult menuhandlerImportOrExportSettings(s32 operation, struct menuitem *item, union handlerdata *data);
static MenuItemHandlerResult menuhandlerImportAction(s32 operation, struct menuitem *item, union handlerdata *data);
static MenuItemHandlerResult menuhandlerOpenImportExportDialog(s32 operation, struct menuitem *item, union handlerdata *data);
static MenuItemHandlerResult menuhandlerSelectSetupHandler(s32 operation, struct menuitem *item, union handlerdata *data);
static MenuItemHandlerResult menuhandlerSetupRename(s32 operation, struct menuitem *item, union handlerdata *data);
static MenuItemHandlerResult menuhandlerSetupDelete(s32 operation, struct menuitem *item, union handlerdata *data);
static MenuItemHandlerResult menuhandlerSetupSetDefault(s32 operation, struct menuitem *item, union handlerdata *data);
static struct menuitem g_StatusOkMenuItems[] = {
{
MENUITEMTYPE_LABEL,
0,
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING,
(uintptr_t)g_StatusText,
0,
NULL,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG | MENUITEMFLAG_SELECTABLE_CENTRE,
L_OPTIONS_347, // "OK"
0,
NULL,
},
{ MENUITEMTYPE_END },
};
static struct menudialogdef g_StatusOkDialog = {
MENUDIALOGTYPE_SUCCESS,
L_OPTIONS_345, // "Cool!"
g_StatusOkMenuItems,
NULL,
MENUDIALOGFLAG_DISABLEBANNER,
NULL,
};
static struct menuitem g_StatusErrorMenuItems[] = {
{
MENUITEMTYPE_LABEL,
0,
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING,
(uintptr_t)g_StatusText,
0,
NULL,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG | MENUITEMFLAG_SELECTABLE_CENTRE,
L_OPTIONS_347, // "OK"
0,
NULL,
},
{ MENUITEMTYPE_END },
};
/* public */
struct menudialogdef g_StatusErrorDialog = {
MENUDIALOGTYPE_DANGER,
L_OPTIONS_277, // "Failed"
g_StatusErrorMenuItems,
NULL,
MENUDIALOGFLAG_DISABLEBANNER,
NULL,
};
static struct menuitem g_RenameSetupItems[] = {
#if VERSION != VERSION_JPN_FINAL
{
MENUITEMTYPE_LABEL,
0,
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING,
(uintptr_t)"Enter the setup name:\n",
0,
NULL,
},
#endif
{
MENUITEMTYPE_KEYBOARD,
18,
0,
0,
1,
menuhandlerRenameSetup,
},
{ MENUITEMTYPE_END },
};
static struct menudialogdef g_RenameSetupDialog = {
MENUDIALOGTYPE_DEFAULT,
(uintptr_t)"Setup Name:\n",
g_RenameSetupItems,
NULL,
MENUDIALOGFLAG_LITERAL_TEXT,
NULL,
};
static struct menuitem g_DeleteSetupItems[] = {
{
MENUITEMTYPE_LABEL,
0,
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING,
(uintptr_t)"Delete Setup?\n",
0,
NULL,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG | MENUITEMFLAG_SELECTABLE_CENTRE,
L_OPTIONS_385, // "No"
0,
NULL,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_SELECTABLE_CENTRE,
L_OPTIONS_386, // "Yes"
0,
menuhandlerDeleteSetup,
},
{ MENUITEMTYPE_END },
};
static struct menudialogdef g_DeleteSetupDialog = {
MENUDIALOGTYPE_DANGER,
(uintptr_t)"Delete Setup\n",
g_DeleteSetupItems,
NULL,
MENUDIALOGFLAG_LITERAL_TEXT,
NULL,
};
static struct menuitem g_ImportExportItems[] = {
{
MENUITEMTYPE_LIST,
0,
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LABEL_CUSTOMCOLOUR,
140,
0x0000004d,
menuhandlerImportOrExportSettings,
},
{ MENUITEMTYPE_END },
};
static struct menudialogdef g_ImportExportDialog = {
MENUDIALOGTYPE_DEFAULT,
(uintptr_t) g_TitleImportExportDialog,
g_ImportExportItems,
NULL,
MENUDIALOGFLAG_LITERAL_TEXT,
NULL,
};
static struct menuitem g_ManageImportExportItems[] = {
{
MENUITEMTYPE_SELECTABLE,
MPSETUP_OP_IMPORT,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Import Settings\n",
0,
menuhandlerOpenImportExportDialog,
},
{
MENUITEMTYPE_SELECTABLE,
MPSETUP_OP_EXPORT,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Export Settings\n",
0,
menuhandlerOpenImportExportDialog,
},
{ MENUITEMTYPE_END },
};
static struct menudialogdef g_ManageImportExportDialog = {
MENUDIALOGTYPE_DEFAULT,
(uintptr_t) "Import/Export\n",
g_ManageImportExportItems,
NULL,
MENUDIALOGFLAG_LITERAL_TEXT,
NULL,
};
static struct menuitem g_MpManageSettingsListItems[] = {
{
MENUITEMTYPE_LIST,
0,
MENUITEMFLAG_LABEL_CUSTOMCOLOUR,
160,
0x00000042,
menuhandlerSelectSetupHandler,
},
{ MENUITEMTYPE_END },
};
/* public */
struct menudialogdef g_ManageSettingsDialog = {
MENUDIALOGTYPE_DEFAULT,
(uintptr_t) "Manage Settings\n",
g_MpManageSettingsListItems,
NULL,
MENUDIALOGFLAG_LITERAL_TEXT,
&g_ManageImportExportDialog,
};
static struct menuitem g_ManageSetupItems[] = {
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Rename\n",
0,
menuhandlerSetupRename,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Delete\n",
0,
menuhandlerSetupDelete,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)g_LabelSetDefault,
0,
menuhandlerSetupSetDefault,
},
{
MENUITEMTYPE_SEPARATOR,
0,
0,
0,
0,
NULL,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
L_OPTIONS_213, // "Back"
0,
NULL,
},
{ MENUITEMTYPE_END },
};
static struct menudialogdef g_ManageSetupDialog = {
MENUDIALOGTYPE_DEFAULT,
(uintptr_t)"Manage Setup",
g_ManageSetupItems,
NULL,
MENUDIALOGFLAG_LITERAL_TEXT,
NULL,
};
static struct menuitem g_ImportOverrideItems[] = {
{
MENUITEMTYPE_LABEL,
0,
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_LESSLEFTPADDING,
(uintptr_t) "How to resolve setups\nwith the same name?\n",
0,
NULL,
},
{
MENUITEMTYPE_SELECTABLE,
MPSETUP_IMPORT_ADD,
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
(uintptr_t) "Add\n",
0,
menuhandlerImportAction,
},
{
MENUITEMTYPE_SELECTABLE,
MPSETUP_IMPORT_OVERWRITE,
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
(uintptr_t) "Overwrite\n",
0,
menuhandlerImportAction,
},
{ MENUITEMTYPE_END },
};
static struct menudialogdef g_ImportOverrideDialog = {
MENUDIALOGTYPE_DEFAULT,
(uintptr_t)"Name Conflicts\n",
g_ImportOverrideItems,
NULL,
MENUDIALOGFLAG_LITERAL_TEXT,
NULL,
};
/* common utils */
static s32 mpsetupDeserialize(FILE *f, struct mpsetupfile *setupfile)
{
s32 rx = 0;
rx += fread(&setupfile->version, sizeof(setupfile->version), 1, f);
rx += fread(&setupfile->defaultsetup, sizeof(setupfile->defaultsetup), 1, f);
rx += fread(&setupfile->numsetups, sizeof(setupfile->numsetups), 1, f);
for (int i = 0; i < setupfile->numsetups; ++i) {
rx += fread(setupfile->setups[i].bytes, sizeof(setupfile->setups[i].bytes), 1, f);
}
return rx;
}
static s32 mpsetupSerialize(FILE *f, struct mpsetupfile *setupfile)
{
s32 wx = 0;
wx += fwrite(&setupfile->version, sizeof(setupfile->version), 1, f);
wx += fwrite(&setupfile->defaultsetup, sizeof(setupfile->defaultsetup), 1, f);
wx += fwrite(&setupfile->numsetups, sizeof(setupfile->numsetups), 1, f);
for (int i = 0; i < setupfile->numsetups; ++i) {
wx += fwrite(setupfile->setups[i].bytes, sizeof(setupfile->setups[i].bytes), 1, f);
}
return wx;
}
static FILE *mpsetupOpenFile(bool write, u8 op) {
const char *filename = fsFullPath("$S/" MPSETUP_FILENAME ".bin");
if (op == MPSETUP_OP_EXPORT) {
// create export directory if it doesn't exist
if (fsFileSize(MPSETUP_EXPORTDIR) < 0) {
if (fsCreateDir(MPSETUP_EXPORTDIR) != 0) {
return NULL;
}
}
filename = fsFullPath(MPSETUP_EXPORTDIR MPSETUP_FILENAME_EXP ".bin");
} else if (op == MPSETUP_OP_IMPORT) {
// same name as export but different folder
filename = fsFullPath("$S/" MPSETUP_FILENAME_EXP ".bin");
}
FILE *f;
if (fsFileSize(filename) < 0) {
// setup file doesn't exist: create one
f = fsFileOpenWrite(filename);
fsFileFree(f);
}
if (write) {
f = fsFileOpenWrite(filename);
} else {
f = fsFileOpenRead(filename);
}
if (f == NULL) {
sysLogPrintf(LOG_ERROR, "Unable to open mp setup file");
return NULL;
}
return f;
}
static s32 mpsetupSaveFile(u8 op, struct mpsetupfile *setupfile)
{
FILE *f = mpsetupOpenFile(true, op);
if (f == NULL) {
return -1;
}
s32 nwritten = mpsetupSerialize(f, setupfile);
if (nwritten < 1) {
fsFileFree(f);
sysLogPrintf(LOG_ERROR, "Unable to write the MP setup file");
snprintf(g_StatusText, sizeof(g_StatusText), "Unable to write the setup file\n");
return -1;
}
fsFileFree(f);
return 0;
}
static s32 mpsetupLoadFile(struct mpsetupfile *setupfile, u8 op)
{
FILE *f = mpsetupOpenFile(false, op);
if (f == NULL) {
return -1;
}
mpsetupDeserialize(f, setupfile);
if (op == MPSETUP_OP_DEFAULT && setupfile->defaultsetup > 0) {
mpsetupLoadSetup(setupfile->defaultsetup - 1);
}
fsFileFree(f);
return 0;
}
static s32 mpsetupImportFile(u8 op, u8 skipOverlap)
{
if (!skipOverlap) {
// check for names overlap
u8 overlap = false;
for (int i = 0; i < g_ImportMpSetupFile.numsetups; ++i) {
for (int j = 0; j < g_MpSetupFile.numsetups; ++j) {
if (strcmp(g_ImportMpSetupFile.setups[i].bytes, g_MpSetupFile.setups[j].bytes) == 0) {
overlap = true;
return MPSETUP_IMPORT_CONFLICT;
}
}
}
}
for (int i = 0; i < g_ImportMpSetupFile.numsetups; ++i) {
s16 overlapIdx = -1;
for (int j = g_MpSetupFile.numsetups-1; j >= 0; --j) {
if (strcmp(g_ImportMpSetupFile.setups[i].bytes, g_MpSetupFile.setups[j].bytes) == 0) {
overlapIdx = j;
break;
}
}
s16 importIdx = overlapIdx;
if (overlapIdx < 0 || op == MPSETUP_IMPORT_ADD) {
if (g_MpSetupFile.numsetups == MPSETUP_MAXSETUPS) {
snprintf(g_StatusText, sizeof(g_StatusText), "Number of setups exceeds %d\n", MPSETUP_MAXSETUPS);
return -1;
}
importIdx = g_MpSetupFile.numsetups++;
}
memcpy(g_MpSetupFile.setups[importIdx].bytes, g_ImportMpSetupFile.setups[i].bytes, MPSETUP_BLOCKSIZE);
}
return mpsetupSaveCurrentFile();
}
static s32 mpsetupExportFile(void)
{
struct mpsetupfile expMpSetupFile;
expMpSetupFile.numsetups = 0;
expMpSetupFile.defaultsetup = 0;
expMpSetupFile.version = MPSETUP_VERSION;
u8 maxsetups = MPSETUP_MAXSETUPS;
maxsetups = MIN(maxsetups, g_MpSetupFile.numsetups);
for (int i = 0; i < maxsetups; ++i) {
u8 bank = i < 64 ? 0 : 1;
u8 bit = i - bank * 64;
if (g_MpImportExportFilter[bank] & (1 << bit)) {
u8 n = expMpSetupFile.numsetups;
expMpSetupFile.numsetups++;
char *name = g_MpSetupFile.setups[i].bytes;
memcpy(expMpSetupFile.setups[n].bytes, g_MpSetupFile.setups[i].bytes, MPSETUP_BLOCKSIZE);
expMpSetupFile.numsetups = n + 1;
}
}
s32 err = mpsetupSaveFile(MPSETUP_OP_EXPORT, &expMpSetupFile);
if (err) {
snprintf(g_StatusText, sizeof(g_StatusText), "Unable to write\nsetup file\n");
}
return err;
}
static s32 mpsetupDelete(void)
{
s32 slotindex = g_Menus[g_MpPlayerNum].mpsetup.slotindex;
for (int i = slotindex; i < g_MpSetupFile.numsetups - 1; ++i) {
u8* dst = g_MpSetupFile.setups[i].bytes;
u8* src = g_MpSetupFile.setups[i+1].bytes;
memcpy(dst, src, MPSETUP_BLOCKSIZE);
}
if (g_MpCurrentSetup > slotindex) {
g_MpCurrentSetup--;
}
else if (g_MpCurrentSetup == slotindex) {
g_MpCurrentSetup = -1;
}
if (g_MpSetupFile.defaultsetup > slotindex + 1) {
g_MpSetupFile.defaultsetup--;
}
else if (g_MpSetupFile.defaultsetup == slotindex + 1) {
g_MpSetupFile.defaultsetup = 0;
}
g_MpSetupFile.numsetups--;
return mpsetupSaveCurrentFile();
}
/* menu handlers */
// Rename setup dialog
static MenuItemHandlerResult menuhandlerRenameSetup(s32 operation, struct menuitem *item, union handlerdata *data)
{
char *name = data->keyboard.string;
s32 slotindex = g_Menus[g_MpPlayerNum].mpsetup.slotindex;
struct setupblock *setup = &g_MpSetupFile.setups[slotindex];
s32 err;
switch (operation) {
case MENUOP_GETTEXT:
strcpy(name, setup->bytes);
break;
case MENUOP_SETTEXT:
strcpy(g_MpSetup.name, name);
break;
case MENUOP_SET:
strcpy(setup->bytes, name);
err = mpsetupSaveSetup(slotindex, true);
if (!err) {
menuPopDialog();
} else {
// TODO
// menuPushDialog(&g_FilemgrFileSavedMenuDialog);
}
break;
}
return 0;
}
// Delete setup dialog
static MenuItemHandlerResult menuhandlerDeleteSetup(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (operation == MENUOP_SET) {
s32 err = mpsetupDelete();
if (!err) {
menuPopDialog();
menuPopDialog();
} else {
// TODO
}
}
return 0;
}
// Import (or Export) settings dialog
static MenuItemHandlerResult menuhandlerImportOrExportSettings(s32 operation, struct menuitem *item, union handlerdata *data)
{
static const char *labels[] = {
"Select All",
"Select None",
"Import",
"Export",
};
s32 op = g_Menus[g_MpPlayerNum].mpsetup.unke24;
struct mpsetupfile *setupfile = op == MPSETUP_OP_IMPORT ? &g_ImportMpSetupFile : &g_MpSetupFile;
u8 numsetups = setupfile->numsetups;
u8 numitems = numsetups + 3;
u8 bank = data->list.value < 64 ? 0 : 1;
u8 bit = data->list.value - bank * 64;
u8 hasselection = (g_MpImportExportFilter[0] | g_MpImportExportFilter[1]) != 0;
u8 ofs;
s32 err;
u32 colour;
s32 index;
switch (operation) {
case MENUOP_GETCOLOUR:
colour = data->list.unk04;
if (data->list.value == numitems - 1) {
data->list.unk04 = hasselection ? colour : (colour & 0xffffff00) | 0x66;
}
break;
case MENUOP_GETOPTIONCOUNT:
data->list.value = numitems;
break;
case MENUOP_GETOPTIONTEXT:
if (data->list.value < numsetups) {
return (uintptr_t) setupfile->setups[data->list.value].bytes;
} else {
// creates an offset to select the "Export" or "Import" label for the last item
ofs = (data->list.value == numitems - 1) ? op - 1 : 0;
return (intptr_t)labels[data->list.value - numsetups + ofs];
}
case MENUOP_SET:
if (data->list.value < setupfile->numsetups) {
g_MpImportExportFilter[bank] ^= (1 << bit);
} else {
index = data->list.value - setupfile->numsetups;
switch (index) {
// Select All
case 0:
g_MpImportExportFilter[0] = g_MpImportExportFilter[1] = -1;
break;
// Select None
case 1:
g_MpImportExportFilter[0] = g_MpImportExportFilter[1] = 0;
break;
// Export (or Import)
case 2:
if (hasselection) {
err = op == MPSETUP_OP_IMPORT ? mpsetupImportFile(0, false) : mpsetupExportFile();
if (!err) {
menuPopDialog();
if (op == MPSETUP_OP_IMPORT) {
// back to the 'Manage Settings' screen
menuPopDialog();
menuPushDialog(&g_ManageSettingsDialog);
} else {
snprintf(g_StatusText, sizeof(g_StatusText), "File %s.bin\nwritten to the folder 'exported'\n", MPSETUP_FILENAME_EXP);
menuPushDialog(&g_StatusOkDialog);
}
} else {
if (err == MPSETUP_IMPORT_CONFLICT) {
menuPopDialog();
menuPushDialog(&g_ImportOverrideDialog);
} else {
menuPushDialog(&g_StatusErrorDialog);
}
}
}
break;
}
}
break;
case MENUOP_GETSELECTEDINDEX:
data->list.value = 0x000fffff;
break;
case MENUOP_GETLISTITEMCHECKBOX:
if (data->list.value < numsetups) {
data->list.unk04 = (g_MpImportExportFilter[bank] & (1 << bit));
}
break;
}
return 0;
}
// Import: overwrite dialog
static MenuItemHandlerResult menuhandlerImportAction(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (operation == MENUOP_SET) {
s32 err = mpsetupImportFile(item->param, true);
if (!err) {
menuPopDialog();
menuPushDialog(&g_ManageSettingsDialog);
} else {
menuPushDialog(&g_StatusErrorDialog);
}
}
return 0;
}
// Manage Import/Export settings dialog
static MenuItemHandlerResult menuhandlerOpenImportExportDialog(s32 operation, struct menuitem *item, union handlerdata *data)
{
switch (operation) {
case MENUOP_SET:
if (item->param == MPSETUP_OP_IMPORT) {
strcpy(g_TitleImportExportDialog, "Import Settings\n");
if (fsFileSize("$S/" MPSETUP_FILENAME_EXP ".bin") < 0) {
snprintf(
g_StatusText, sizeof(g_StatusText),
"No import file found.\n"
"Place the file %s.bin\n"
"Next to your %s.bin file\n",
MPSETUP_FILENAME_EXP, MPSETUP_FILENAME
);
menuPushDialog(&g_StatusErrorDialog);
return 0;
}
mpsetupLoadFile(&g_ImportMpSetupFile, MPSETUP_OP_IMPORT);
} else {
strcpy(g_TitleImportExportDialog, "Export Settings\n");
}
g_Menus[g_MpPlayerNum].mpsetup.unke24 = item->param;
g_MpImportExportFilter[0] = g_MpImportExportFilter[1] = -1;
menuPushDialog(&g_ImportExportDialog);
break;
}
return 0;
}
// Manage settings dialog
static MenuItemHandlerResult menuhandlerSelectSetupHandler(s32 operation, struct menuitem *item, union handlerdata *data)
{
u32 colour;
switch (operation) {
case MENUOP_GETCOLOUR:
colour = data->list.unk04;
if (data->list.value + 1 == g_MpSetupFile.defaultsetup) {
data->list.unk04 = (colour & 0xffff0000) | 0xff;
}
break;
case MENUOP_GETOPTIONCOUNT:
data->list.value = g_MpSetupFile.numsetups;
break;
case MENUOP_GETOPTIONTEXT:
return (uintptr_t) g_MpSetupFile.setups[data->list.value].bytes;
case MENUOP_SET:
g_Menus[g_MpPlayerNum].mpsetup.slotindex = data->list.value;
if (data->list.value == g_MpSetupFile.defaultsetup - 1) {
strcpy(g_LabelSetDefault, "Clear Default\n");
} else {
strcpy(g_LabelSetDefault, "Set Default\n");
}
menuPushDialog(&g_ManageSetupDialog);
break;
case MENUOP_GETSELECTEDINDEX:
data->list.value = 0xfffff;
break;
}
return 0;
}
static MenuItemHandlerResult menuhandlerSetupRename(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (operation == MENUOP_SET) {
menuPushDialog(&g_RenameSetupDialog);
}
return 0;
}
static MenuItemHandlerResult menuhandlerSetupDelete(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (operation == MENUOP_SET) {
menuPushDialog(&g_DeleteSetupDialog);
}
return 0;
}
static MenuItemHandlerResult menuhandlerSetupSetDefault(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (operation == MENUOP_SET) {
s32 selected = g_Menus[g_MpPlayerNum].mpsetup.slotindex;
// clicked on "clear default"
if (selected == g_MpSetupFile.defaultsetup - 1) {
g_MpSetupFile.defaultsetup = 0;
strcpy(g_LabelSetDefault, "Set Default\n");
} else {
g_MpSetupFile.defaultsetup = selected + 1;
strcpy(g_LabelSetDefault, "Clear Default\n");
}
mpsetupSaveCurrentFile();
}
return 0;
}
/* public functions */
s32 mpsetupLoadCurrentFile(void)
{
return mpsetupLoadFile(&g_MpSetupFile, MPSETUP_OP_DEFAULT);
}
s32 mpsetupSaveCurrentFile(void)
{
g_MpSetupFile.version = MPSETUP_VERSION;
return mpsetupSaveFile(MPSETUP_OP_DEFAULT, &g_MpSetupFile);
}
s32 mpsetupSaveSetup(s32 slotindex, u8 savefile)
{
struct savebuffer setup;
// request to add a new setup
if (slotindex == g_MpSetupFile.numsetups) {
g_MpCurrentSetup = g_MpSetupFile.numsetups++;
}
savebufferClear(&setup);
mpsetupfileSaveWad(&setup);
memcpy(g_MpSetupFile.setups[slotindex].bytes, setup.bytes, MPSETUP_BLOCKSIZE);
return savefile ? mpsetupSaveCurrentFile() : 0;
}
void mpsetupLoadSetup(s32 index)
{
struct savebuffer buffer;
savebufferClear(&buffer);
struct setupblock *block = &g_MpSetupFile.setups[index];
memcpy(&buffer.bytes, block->bytes, MPSETUP_BLOCKSIZE);
mpsetupfileLoadWad(&buffer, g_MpSetupFile.version);
g_MpCurrentSetup = index;
}
void mpsetupCopyAllFromPak(void)
{
if (fsFileSize("$S/" MPSETUP_FILENAME ".bin") > 0) {
return;
}
filelistCreate(1, FILETYPE_MPSETUP);
filelistsTick();
for (int i = 0; i < g_FileLists[1]->numfiles; ++i) {
struct savebuffer buffer;
savebufferClear(&buffer);
struct filelistfile *file = &g_FileLists[1]->files[i];
s32 device = pakFindBySerial(file->deviceserial);
s32 err = pakReadBodyAtGuid(device, file->fileid, buffer.bytes, 0);
if (err != 0) {
sysLogPrintf(LOG_ERROR, "Unable to read pak. device %d fileid %d deviceserial %d err %d",
device, file->fileid, file->deviceserial, err);
continue;
}
mpsetupfileLoadWad(&buffer, 0);
// save the file when writing the last setup
u8 savefile = i == g_FileLists[1]->numfiles - 1;
mpsetupSaveSetup(g_MpSetupFile.numsetups, savefile);
}
// to reset the mp setup
mpInit(false);
}
-1127
View File
File diff suppressed because it is too large. Load diff
-305
View File
@@ -1,305 +0,0 @@
#include <string.h>
#include "types.h"
#include "platform.h"
#include "system.h"
#include "net/netbuf.h"
/* read */
void netbufStartRead(struct netbuf *buf)
{
buf->error = 0;
buf->wp = buf->size;
buf->rp = 0;
}
void netbufStartReadData(struct netbuf *buf, const void *data, u32 size)
{
buf->size = size;
buf->data = (void *)data;
netbufStartRead(buf);
}
s32 netbufReadLeft(const struct netbuf *buf)
{
return buf->wp - buf->rp;
}
static inline u32 netbufCanRead(struct netbuf *buf, const u32 num)
{
if (buf->error || buf->rp + num > buf->wp) {
sysLogPrintf(LOG_ERROR, "NET: could not read %u bytes", num);
__builtin_trap();
buf->error = 1;
return false;
}
return true;
}
u32 netbufReadData(struct netbuf *buf, void *out, u32 num)
{
if (netbufCanRead(buf, num)) {
memcpy(out, buf->data + buf->rp, num);
buf->rp += num;
return num;
}
return 0;
}
u8 netbufReadU8(struct netbuf *buf)
{
if (netbufCanRead(buf, 1)) {
return buf->data[buf->rp++];
}
return 0;
}
u16 netbufReadU16(struct netbuf *buf)
{
if (netbufCanRead(buf, 2)) {
const u16 ret = *(u16 *)&buf->data[buf->rp];
buf->rp += sizeof(ret);
return PD_LE16(ret);
}
return 0;
}
u32 netbufReadU32(struct netbuf *buf)
{
if (netbufCanRead(buf, 4)) {
const u32 ret = *(u32 *)&buf->data[buf->rp];
buf->rp += sizeof(ret);
return PD_LE32(ret);
}
return 0;
}
u64 netbufReadU64(struct netbuf *buf)
{
if (netbufCanRead(buf, 8)) {
const u64 ret = *(u64 *)&buf->data[buf->rp];
buf->rp += sizeof(ret);
return PD_LE64(ret);
}
return 0;
}
s8 netbufReadS8(struct netbuf *buf) {
return (s8)netbufReadU8(buf);
}
s16 netbufReadS16(struct netbuf *buf) {
return (s16)netbufReadU16(buf);
}
s32 netbufReadS32(struct netbuf *buf) {
return (s32)netbufReadU32(buf);
}
s64 netbufReadS64(struct netbuf *buf) {
return (s64)netbufReadU64(buf);
}
f32 netbufReadF32(struct netbuf *buf)
{
union {
f32 f;
u32 i;
} hack;
hack.i = netbufReadU32(buf);
return hack.f;
}
char *netbufReadStr(struct netbuf *buf)
{
const u16 len = netbufReadU16(buf);
if (netbufCanRead(buf, len)) {
char *ret = (char *)&buf->data[buf->rp];
buf->rp += len;
return ret;
}
return NULL;
}
u32 netbufReadCoord(struct netbuf *buf, struct coord *out)
{
if (netbufCanRead(buf, sizeof(*out))) {
out->x = netbufReadF32(buf);
out->y = netbufReadF32(buf);
out->z = netbufReadF32(buf);
return sizeof(*out);
}
return 0;
}
u32 netbufReadMtxf(struct netbuf *buf, Mtxf *out)
{
if (netbufCanRead(buf, sizeof(*out))) {
for (s32 i = 0; i < 4; ++i) {
for (s32 j = 0; j < 4; ++j) {
out->m[i][j] = netbufReadF32(buf);
}
}
return sizeof(*out);
}
return 0;
}
u32 netbufReadSkip(struct netbuf *buf, u32 count)
{
if (netbufCanRead(buf, count)) {
buf->rp += count;
return count;
}
return 0;
}
/* write */
void netbufStartWrite(struct netbuf *buf)
{
buf->wp = 0;
buf->error = 0;
}
static inline u32 netbufCanWrite(struct netbuf *buf, const u32 num)
{
if (buf->error || buf->wp + num > buf->size) {
buf->error = 1;
return false;
}
return true;
}
s32 netbufWriteLeft(const struct netbuf *buf)
{
return buf->size - buf->wp;
}
u32 netbufWriteData(struct netbuf *buf, const void *data, u32 num)
{
if (netbufCanWrite(buf, num)) {
memcpy(buf->data + buf->wp, data, num);
buf->wp += num;
return num;
}
return 0;
}
u32 netbufWriteU8(struct netbuf *buf, const u8 v)
{
if (netbufCanWrite(buf, sizeof(v))) {
buf->data[buf->wp++] = v;
return sizeof(v);
}
return 0;
}
u32 netbufWriteU16(struct netbuf *buf, const u16 v)
{
if (netbufCanWrite(buf, sizeof(v))) {
*(u16 *)&buf->data[buf->wp] = PD_LE16(v);
buf->wp += sizeof(v);
return sizeof(v);
}
return 0;
}
u32 netbufWriteU32(struct netbuf *buf, const u32 v)
{
if (netbufCanWrite(buf, sizeof(v))) {
*(u32 *)&buf->data[buf->wp] = PD_LE32(v);
buf->wp += sizeof(v);
return sizeof(v);
}
return 0;
}
u32 netbufWriteU64(struct netbuf *buf, const u64 v)
{
if (netbufCanWrite(buf, sizeof(v))) {
*(u64 *)&buf->data[buf->wp] = PD_LE64(v);
buf->wp += sizeof(v);
return sizeof(v);
}
return 0;
}
u32 netbufWriteS8(struct netbuf *buf, const s8 v)
{
return netbufWriteU8(buf, (u8)v);
}
u32 netbufWriteS16(struct netbuf *buf, const s16 v)
{
return netbufWriteU16(buf, (u16)v);
}
u32 netbufWriteS32(struct netbuf *buf, const s32 v)
{
return netbufWriteU32(buf, (u32)v);
}
u32 netbufWriteS64(struct netbuf *buf, const s64 v)
{
return netbufWriteU64(buf, (u64)v);
}
u32 netbufWriteF32(struct netbuf *buf, const f32 v)
{
const union {
f32 f;
u32 i;
} hack = { .f = v };
return netbufWriteU32(buf, hack.i);
}
u32 netbufWriteStr(struct netbuf *buf, const char *v)
{
if (!v) {
return 0;
}
u32 len = strlen(v) + 1;
if (len > 0xFFFF) {
len = 0xFFFF;
}
if (netbufCanWrite(buf, len + sizeof(u16))) {
netbufWriteU16(buf, len);
netbufWriteData(buf, v, len);
buf->data[buf->wp - 1] = 0;
return sizeof(u16) + len;
}
return 0;
}
u32 netbufWriteCoord(struct netbuf *buf, const struct coord *v)
{
if (netbufCanWrite(buf, sizeof(*v))) {
netbufWriteF32(buf, v->x);
netbufWriteF32(buf, v->y);
netbufWriteF32(buf, v->z);
return sizeof(*v);
}
return 0;
}
u32 netbufWriteMtxf(struct netbuf *buf, const Mtxf *in)
{
if (netbufCanWrite(buf, sizeof(*in))) {
for (s32 i = 0; i < 4; ++i) {
for (s32 j = 0; j < 4; ++j) {
netbufWriteF32(buf, in->m[i][j]);
}
}
return sizeof(*in);
}
return 0;
}
void netbufReset(struct netbuf *buf)
{
memset(buf, 0, sizeof(*buf));
}
-386
View File
@@ -1,386 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <PR/ultratypes.h>
#include "platform.h"
#include "data.h"
#include "types.h"
#include "game/mainmenu.h"
#include "game/menu.h"
#include "game/gamefile.h"
#include "video.h"
#include "input.h"
#include "config.h"
#include "net/net.h"
extern MenuItemHandlerResult menuhandlerMainMenuCombatSimulator(s32 operation, struct menuitem *item, union handlerdata *data);
extern MenuItemHandlerResult menuhandlerMpAdvancedSetup(s32 operation, struct menuitem *item, union handlerdata *data);
static s32 g_NetMenuMaxPlayers = NET_MAX_CLIENTS;
static s32 g_NetMenuPort = NET_DEFAULT_PORT;
static char g_NetJoinAddr[NET_MAX_ADDR + 1];
static s32 g_NetJoinAddrPtr = 0;
/* host */
static MenuItemHandlerResult menuhandlerHostMaxPlayers(s32 operation, struct menuitem *item, union handlerdata *data)
{
switch (operation) {
case MENUOP_GETSLIDER:
data->slider.value = g_NetMenuMaxPlayers;
break;
case MENUOP_SET:
if (data->slider.value) {
g_NetMenuMaxPlayers = data->slider.value;
}
break;
}
return 0;
}
static MenuItemHandlerResult menuhandlerHostPort(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (operation == MENUOP_SET) {
}
return 0;
}
static char *menuhandlerHostPortValue(struct menuitem *item)
{
static char tmp[16];
snprintf(tmp, sizeof(tmp), "%u\n", g_NetMenuPort);
return tmp;
}
MenuItemHandlerResult menuhandlerHostStart(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (operation == MENUOP_SET) {
if (netStartServer(g_NetMenuPort, g_NetMenuMaxPlayers) == 0) {
menuhandlerMainMenuCombatSimulator(MENUOP_SET, NULL, NULL);
menuhandlerMpAdvancedSetup(MENUOP_SET, NULL, NULL);
}
}
return 0;
}
struct menuitem g_NetHostMenuItems[] = {
{
MENUITEMTYPE_SLIDER,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Max Players",
NET_MAX_CLIENTS,
menuhandlerHostMaxPlayers,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Port\n",
(uintptr_t)&menuhandlerHostPortValue,
menuhandlerHostPort,
},
{
MENUITEMTYPE_SELECTABLE,
0,
0,
L_MPMENU_036, // "Start Game"
0,
menuhandlerHostStart,
},
{
MENUITEMTYPE_SEPARATOR,
0,
0,
0,
0,
NULL,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
L_OPTIONS_213, // "Back"
0,
NULL,
},
{ MENUITEMTYPE_END },
};
struct menudialogdef g_NetHostMenuDialog = {
MENUDIALOGTYPE_DEFAULT,
(uintptr_t)"Host Network Game",
g_NetHostMenuItems,
NULL,
MENUDIALOGFLAG_LITERAL_TEXT,
NULL,
};
/* join */
static const char *menutextJoinAddress(struct menuitem *item)
{
static char tmp[256 + 1];
if (item && item->flags & MENUITEMFLAG_SELECTABLE_CENTRE) {
// in centered dialog
if (g_NetMode == NETMODE_NONE) {
snprintf(tmp, sizeof(tmp), "%s_\n", g_NetJoinAddr);
} else if (g_NetLocalClient->state == CLSTATE_CONNECTING) {
snprintf(tmp, sizeof(tmp), "Connecting to %s...\n", g_NetJoinAddr);
} else if (g_NetLocalClient->state == CLSTATE_AUTH) {
snprintf(tmp, sizeof(tmp), "Authenticating with %s...\n", g_NetJoinAddr);
} else if (g_NetLocalClient->state == CLSTATE_LOBBY) {
snprintf(tmp, sizeof(tmp), "Waiting for host...\n");
}
} else {
// label
snprintf(tmp, sizeof(tmp), "%s\n", g_NetJoinAddr);
}
return tmp;
}
static MenuItemHandlerResult menuhandlerJoining(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (inputKeyPressed(VK_ESCAPE)) {
netDisconnect();
menuPopDialog();
}
return 0;
}
struct menuitem g_NetJoiningMenuItems[] = {
{
MENUITEMTYPE_LABEL,
0,
MENUITEMFLAG_SELECTABLE_CENTRE,
(uintptr_t)&menutextJoinAddress,
0,
NULL,
},
{
MENUITEMTYPE_SEPARATOR,
0,
0,
0,
0,
NULL,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_SELECTABLE_CENTRE | MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"ESC to abort\n",
0,
menuhandlerJoining,
},
{ MENUITEMTYPE_END },
};
struct menudialogdef g_NetJoiningDialog = {
MENUDIALOGTYPE_SUCCESS,
(uintptr_t)"Joining Game...",
g_NetJoiningMenuItems,
NULL,
MENUDIALOGFLAG_LITERAL_TEXT | MENUDIALOGFLAG_IGNOREBACK | MENUDIALOGFLAG_STARTSELECTS,
NULL,
};
static MenuItemHandlerResult menuhandlerEnterJoinAddress(s32 operation, struct menuitem *item, union handlerdata *data);
struct menuitem g_NetJoinAddressMenuItems[] = {
{
MENUITEMTYPE_LABEL,
0,
MENUITEMFLAG_SELECTABLE_CENTRE,
(uintptr_t)&menutextJoinAddress,
0,
NULL,
},
{
MENUITEMTYPE_SEPARATOR,
0,
0,
0,
0,
NULL,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_SELECTABLE_CENTRE | MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"ESC to return\n",
0,
menuhandlerEnterJoinAddress,
},
{ MENUITEMTYPE_END },
};
struct menudialogdef g_NetJoinAddressDialog = {
MENUDIALOGTYPE_SUCCESS,
(uintptr_t)"Enter Address",
g_NetJoinAddressMenuItems,
NULL,
MENUDIALOGFLAG_LITERAL_TEXT | MENUDIALOGFLAG_IGNOREBACK | MENUDIALOGFLAG_STARTSELECTS,
NULL,
};
static MenuItemHandlerResult menuhandlerEnterJoinAddress(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (!menuIsDialogOpen(&g_NetJoinAddressDialog)) {
return 0;
}
if (inputTextHandler(g_NetJoinAddr, NET_MAX_ADDR, &g_NetJoinAddrPtr) < 0) {
// escape has been pressed, stop editing
inputStopTextInput();
menuPopDialog();
}
return 0;
}
static MenuItemHandlerResult menuhandlerJoinAddress(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (operation == MENUOP_SET) {
inputClearLastKey();
inputClearLastTextChar();
inputStartTextInput();
g_NetJoinAddrPtr = strlen(g_NetJoinAddr);
menuPushDialog(&g_NetJoinAddressDialog);
}
return 0;
}
MenuItemHandlerResult menuhandlerJoinStart(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (operation == MENUOP_SET) {
if (netStartClient(g_NetJoinAddr) == 0) {
menuPushDialog(&g_NetJoiningDialog);
}
}
return 0;
}
struct menuitem g_NetJoinMenuItems[] = {
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Address: \n",
(uintptr_t)&menutextJoinAddress,
menuhandlerJoinAddress,
},
{
MENUITEMTYPE_SELECTABLE,
0,
0,
L_MPMENU_036, // "Start Game"
0,
menuhandlerJoinStart,
},
{
MENUITEMTYPE_SEPARATOR,
0,
0,
0,
0,
NULL,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
L_OPTIONS_213, // "Back"
0,
NULL,
},
{ MENUITEMTYPE_END },
};
struct menudialogdef g_NetJoinMenuDialog = {
MENUDIALOGTYPE_DEFAULT,
(uintptr_t)"Join Network Game",
g_NetJoinMenuItems,
NULL,
MENUDIALOGFLAG_LITERAL_TEXT | MENUDIALOGFLAG_STARTSELECTS | MENUDIALOGFLAG_IGNOREBACK,
NULL,
};
/* main */
MenuItemHandlerResult menuhandlerHostGame(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (operation == MENUOP_SET) {
g_NetMenuPort = g_NetServerPort;
g_NetMenuMaxPlayers = g_NetMaxClients;
menuPushDialog(&g_NetHostMenuDialog);
}
return 0;
}
MenuItemHandlerResult menuhandlerJoinGame(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (operation == MENUOP_SET) {
if (g_NetJoinAddr[0] == '\0') {
strncpy(g_NetJoinAddr, g_NetLastJoinAddr, NET_MAX_ADDR);
g_NetJoinAddrPtr = strlen(g_NetJoinAddr);
}
menuPushDialog(&g_NetJoinMenuDialog);
}
return 0;
}
struct menuitem g_NetMenuItems[] = {
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Host Game\n",
0,
menuhandlerHostGame,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Join Game\n",
0,
menuhandlerJoinGame,
},
{
MENUITEMTYPE_SEPARATOR,
0,
0,
0,
0,
NULL,
},
{
MENUITEMTYPE_SELECTABLE,
0,
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
L_OPTIONS_213, // "Back"
0,
NULL,
},
{ MENUITEMTYPE_END },
};
struct menudialogdef g_NetMenuDialog = {
MENUDIALOGTYPE_DEFAULT,
(uintptr_t)"Network Game",
g_NetMenuItems,
NULL,
MENUDIALOGFLAG_MPLOCKABLE | MENUDIALOGFLAG_LITERAL_TEXT,
NULL,
};
File diff suppressed because it is too large. Load diff
+495 -41
View File
@@ -9,6 +9,8 @@
#include "game/mainmenu.h" #include "game/mainmenu.h"
#include "game/menu.h" #include "game/menu.h"
#include "game/gamefile.h" #include "game/gamefile.h"
#include "game/player.h"
#include "lib/joy.h"
#include "video.h" #include "video.h"
#include "input.h" #include "input.h"
#include "config.h" #include "config.h"
@@ -119,13 +121,40 @@ static MenuItemHandlerResult menuhandlerMouseAimLock(s32 operation, struct menui
return 0; return 0;
} }
static MenuItemHandlerResult menuhandlerMouseDefaultLocked(s32 operation, struct menuitem *item, union handlerdata *data) static MenuItemHandlerResult menuhandlerMouseLockMode(s32 operation, struct menuitem *item, union handlerdata *data)
{
static const char *opts[] = {
"Always Off",
"Always On",
"Auto"
};
switch (operation) {
case MENUOP_GETOPTIONCOUNT:
data->dropdown.value = ARRAYCOUNT(opts);
break;
case MENUOP_GETOPTIONTEXT:
return (intptr_t)opts[data->dropdown.value];
case MENUOP_SET:
inputSetMouseLockMode(data->checkbox.value);
break;
case MENUOP_GETSELECTEDINDEX:
data->dropdown.value = inputGetMouseLockMode();
}
return 0;
}
static MenuItemHandlerResult menuhandlerMenuMouseControl(s32 operation, struct menuitem *item, union handlerdata *data)
{ {
switch (operation) { switch (operation) {
case MENUOP_GET: case MENUOP_GET:
return inputGetMouseDefaultLocked(); return g_MenuMouseControl;
case MENUOP_SET: case MENUOP_SET:
inputSetMouseDefaultLocked(data->checkbox.value); g_MenuMouseControl = data->checkbox.value;
if (!g_MenuMouseControl) {
g_MenuUsingMouse = false;
}
break; break;
} }
@@ -141,15 +170,16 @@ static MenuItemHandlerResult menuhandlerMouseSpeedX(s32 operation, struct menuit
inputMouseGetSpeed(&x, &y); inputMouseGetSpeed(&x, &y);
if (x < 0.f) { if (x < 0.f) {
data->slider.value = 0; data->slider.value = 0;
} else if (x > 10.f) {
data->slider.value = 100;
} else { } else {
data->slider.value = x * 10.f + 0.5f; data->slider.value = x * 100.f + 0.5f;
} }
break; break;
case MENUOP_SET: case MENUOP_SET:
inputMouseGetSpeed(&x, &y); inputMouseGetSpeed(&x, &y);
inputMouseSetSpeed((f32)data->slider.value / 10.f, y); inputMouseSetSpeed((f32)data->slider.value / 100.f, y);
break;
case MENUOP_GETSLIDERLABEL:
sprintf(data->slider.label, "%.2f", (f32)data->slider.value / 100.f);
break; break;
} }
@@ -165,15 +195,16 @@ static MenuItemHandlerResult menuhandlerMouseSpeedY(s32 operation, struct menuit
inputMouseGetSpeed(&x, &y); inputMouseGetSpeed(&x, &y);
if (y < 0.f) { if (y < 0.f) {
data->slider.value = 0; data->slider.value = 0;
} else if (y > 10.f) {
data->slider.value = 100;
} else { } else {
data->slider.value = y * 10.f + 0.5f; data->slider.value = y * 100.f + 0.5f;
} }
break; break;
case MENUOP_SET: case MENUOP_SET:
inputMouseGetSpeed(&x, &y); inputMouseGetSpeed(&x, &y);
inputMouseSetSpeed(x, (f32)data->slider.value / 10.f); inputMouseSetSpeed(x, (f32)data->slider.value / 100.f);
break;
case MENUOP_GETSLIDERLABEL:
sprintf(data->slider.label, "%.2f", (f32)data->slider.value / 100.f);
break; break;
} }
@@ -187,14 +218,16 @@ static MenuItemHandlerResult menuhandlerMouseAimSpeedX(s32 operation, struct men
if (g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedx < 0.f) { if (g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedx < 0.f) {
data->slider.value = 0; data->slider.value = 0;
} else if (g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedx > 10.f) { } else if (g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedx > 10.f) {
data->slider.value = 100; data->slider.value = 1000;
} else { } else {
data->slider.value = g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedx * 10.f + 0.5f; data->slider.value = g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedx * 100.f + 0.5f;
} }
break; break;
case MENUOP_SET: case MENUOP_SET:
g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedx = (f32)data->slider.value / 10.f; g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedx = (f32)data->slider.value / 100.f;
break; break;
case MENUOP_GETSLIDERLABEL:
sprintf(data->slider.label, "%.2f", (f32)data->slider.value / 100.f);
} }
return 0; return 0;
@@ -207,14 +240,16 @@ static MenuItemHandlerResult menuhandlerMouseAimSpeedY(s32 operation, struct men
if (g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedy < 0.f) { if (g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedy < 0.f) {
data->slider.value = 0; data->slider.value = 0;
} else if (g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedy > 10.f) { } else if (g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedy > 10.f) {
data->slider.value = 100; data->slider.value = 1000;
} else { } else {
data->slider.value = g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedy * 10.f + 0.5f; data->slider.value = g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedy * 100.f + 0.5f;
} }
break; break;
case MENUOP_SET: case MENUOP_SET:
g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedy = (f32)data->slider.value / 10.f; g_PlayerExtCfg[g_ExtMenuPlayer].mouseaimspeedy = (f32)data->slider.value / 100.f;
break; break;
case MENUOP_GETSLIDERLABEL:
sprintf(data->slider.label, "%.2f", (f32)data->slider.value / 100.f);
} }
return 0; return 0;
@@ -227,14 +262,16 @@ static MenuItemHandlerResult menuhandlerRadialMenuSpeed(s32 operation, struct me
if (g_PlayerExtCfg[0].radialmenuspeed < 0.f) { if (g_PlayerExtCfg[0].radialmenuspeed < 0.f) {
data->slider.value = 0; data->slider.value = 0;
} else if (g_PlayerExtCfg[0].radialmenuspeed > 10.f) { } else if (g_PlayerExtCfg[0].radialmenuspeed > 10.f) {
data->slider.value = 100; data->slider.value = 1000;
} else { } else {
data->slider.value = g_PlayerExtCfg[0].radialmenuspeed * 10.f + 0.5f; data->slider.value = g_PlayerExtCfg[0].radialmenuspeed * 100.f + 0.5f;
} }
break; break;
case MENUOP_SET: case MENUOP_SET:
g_PlayerExtCfg[0].radialmenuspeed = (f32)data->slider.value / 10.f; g_PlayerExtCfg[0].radialmenuspeed = (f32)data->slider.value / 100.f;
break; break;
case MENUOP_GETSLIDERLABEL:
sprintf(data->slider.label, "%.2f", (f32)data->slider.value / 100.f);
} }
return 0; return 0;
@@ -257,13 +294,21 @@ struct menuitem g_ExtendedMouseMenuItems[] = {
0, 0,
menuhandlerMouseAimLock, menuhandlerMouseAimLock,
}, },
{
MENUITEMTYPE_DROPDOWN,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Mouse Lock Mode",
0,
menuhandlerMouseLockMode,
},
{ {
MENUITEMTYPE_CHECKBOX, MENUITEMTYPE_CHECKBOX,
0, 0,
MENUITEMFLAG_LITERAL_TEXT, MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Grab Mouse Input by Default", (uintptr_t)"Mouse Menu Navigation",
0, 0,
menuhandlerMouseDefaultLocked, menuhandlerMenuMouseControl,
}, },
{ {
MENUITEMTYPE_SEPARATOR, MENUITEMTYPE_SEPARATOR,
@@ -278,7 +323,7 @@ struct menuitem g_ExtendedMouseMenuItems[] = {
0, 0,
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE, MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE,
(uintptr_t)"Mouse Speed X", (uintptr_t)"Mouse Speed X",
100, 3000,
menuhandlerMouseSpeedX, menuhandlerMouseSpeedX,
}, },
{ {
@@ -286,7 +331,7 @@ struct menuitem g_ExtendedMouseMenuItems[] = {
0, 0,
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE, MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE,
(uintptr_t)"Mouse Speed Y", (uintptr_t)"Mouse Speed Y",
100, 3000,
menuhandlerMouseSpeedY, menuhandlerMouseSpeedY,
}, },
{ {
@@ -294,7 +339,7 @@ struct menuitem g_ExtendedMouseMenuItems[] = {
0, 0,
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE, MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE,
(uintptr_t)"Crosshair Speed X", (uintptr_t)"Crosshair Speed X",
100, 1000,
menuhandlerMouseAimSpeedX, menuhandlerMouseAimSpeedX,
}, },
{ {
@@ -302,7 +347,7 @@ struct menuitem g_ExtendedMouseMenuItems[] = {
0, 0,
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE, MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE,
(uintptr_t)"Crosshair Speed Y", (uintptr_t)"Crosshair Speed Y",
100, 1000,
menuhandlerMouseAimSpeedY, menuhandlerMouseAimSpeedY,
}, },
{ {
@@ -310,7 +355,7 @@ struct menuitem g_ExtendedMouseMenuItems[] = {
0, 0,
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE, MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE,
(uintptr_t)"Radial Menu Speed", (uintptr_t)"Radial Menu Speed",
100, 1000,
menuhandlerRadialMenuSpeed, menuhandlerRadialMenuSpeed,
}, },
{ {
@@ -551,8 +596,10 @@ static MenuItemHandlerResult menuhandlerController(s32 operation, struct menuite
if (data->dropdown.value == 0) { if (data->dropdown.value == 0) {
// unassign controller // unassign controller
inputAssignController(g_ExtMenuPlayer, -1); inputAssignController(g_ExtMenuPlayer, -1);
joyReset();
} else if (data->dropdown.value <= numCtrls) { } else if (data->dropdown.value <= numCtrls) {
inputAssignController(g_ExtMenuPlayer, ctrls[data->dropdown.value - 1]); inputAssignController(g_ExtMenuPlayer, ctrls[data->dropdown.value - 1]);
joyReset();
} }
break; break;
case MENUOP_GETSELECTEDINDEX: case MENUOP_GETSELECTEDINDEX:
@@ -652,27 +699,183 @@ static MenuItemHandlerResult menuhandlerFullScreen(s32 operation, struct menuite
return 0; return 0;
} }
static MenuItemHandlerResult menuhandlerMaximizeWindow(s32 operation, struct menuitem *item, union handlerdata *data) static MenuItemHandlerResult menuhandlerFullScreenMode(s32 operation, struct menuitem *item, union handlerdata *data)
{
static const char *opts[] = {
"Borderless",
"Exclusive"
};
switch (operation) {
case MENUOP_GETOPTIONCOUNT:
data->dropdown.value = ARRAYCOUNT(opts);
break;
case MENUOP_GETOPTIONTEXT:
return (intptr_t)opts[data->dropdown.value];
case MENUOP_SET:
videoSetFullscreenMode(data->dropdown.value);
break;
case MENUOP_GETSELECTEDINDEX:
data->dropdown.value = videoGetFullscreenMode();
}
return 0;
}
static MenuItemHandlerResult menuhandlerCenterWindow(s32 operation, struct menuitem *item, union handlerdata *data)
{ {
switch (operation) { switch (operation) {
case MENUOP_GET: case MENUOP_GET:
return videoGetMaximizeWindow(); return videoGetCenterWindow();
case MENUOP_SET: case MENUOP_SET:
videoSetMaximizeWindow(data->checkbox.value); videoSetCenterWindow(data->checkbox.value);
break; break;
} }
return 0; return 0;
} }
static MenuItemHandlerResult menuhandlerVsync(s32 operation, struct menuitem *item, union handlerdata *data)
{
static const s32 numOpts = 10;
static const char *constOpts[] = {
"Adaptive",
"Off",
"On"
};
static char dynOpt[20];
s32 vblanks;
switch (operation) {
case MENUOP_GETOPTIONCOUNT:
data->dropdown.value = numOpts;
break;
case MENUOP_GETOPTIONTEXT:
if (data->dropdown.value < ARRAYCOUNT(constOpts))
return (intptr_t)constOpts[data->dropdown.value];
vblanks = (s32)data->dropdown.value - 1;
snprintf(dynOpt, sizeof(dynOpt), "On (%d frames)", vblanks);
return (intptr_t)dynOpt;
case MENUOP_SET:
videoSetVsync(data->dropdown.value - 1);
case MENUOP_GETSELECTEDINDEX:
data->dropdown.value = videoGetVsync() + 1;
}
return 0;
}
static MenuItemHandlerResult menuhandlerFramerateLimit(s32 operation, struct menuitem *item, union handlerdata *data)
{
switch (operation) {
case MENUOP_GETSLIDER:
data->slider.value = videoGetFramerateLimit();
break;
case MENUOP_SET:
videoSetFramerateLimit(data->slider.value);
break;
case MENUOP_GETSLIDERLABEL:
// NOTE: data->slider.label length must not exceed 15.
if (data->slider.value == 0) {
strcpy(data->slider.label, "Off");
} else {
sprintf(data->slider.label, "%d FPS", data->slider.value);
}
}
return 0;
}
static MenuItemHandlerResult menuhandlerMSAA(s32 operation, struct menuitem *item, union handlerdata *data)
{
s32 msaa;
static const char *opts[] = {
"Off",
"2x (MSAA)",
"4x (MSAA)",
"8x (MSAA)",
"16x (MSAA)"
};
switch (operation) {
case MENUOP_GETOPTIONCOUNT:
data->dropdown.value = ARRAYCOUNT(opts);
break;
case MENUOP_GETOPTIONTEXT:
return (intptr_t)opts[data->dropdown.value];
case MENUOP_SET:
videoSetMSAA(1 << data->dropdown.value);
break;
case MENUOP_GETSELECTEDINDEX:
msaa = videoGetMSAA();
if (msaa < 2) {
data->dropdown.value = 0;
} else if (msaa < 4) {
data->dropdown.value = 1;
} else if (msaa < 8) {
data->dropdown.value = 2;
} else if (msaa < 16) {
data->dropdown.value = 3;
} else {
data->dropdown.value = 4;
}
}
return 0;
}
static MenuItemHandlerResult menuhandlerResolution(s32 operation, struct menuitem *item, union handlerdata *data)
{
static char resstring[32];
static const char *rescustom = "Custom";
displaymode mode;
switch (operation) {
case MENUOP_CHECKDISABLED:
if (videoGetFullscreen() && videoGetFullscreenMode() == 0) {
return true;
}
break;
case MENUOP_GETOPTIONCOUNT:
data->dropdown.value = videoGetNumDisplayModes();
break;
case MENUOP_GETOPTIONTEXT:
videoGetDisplayMode(&mode, data->dropdown.value);
if (mode.width == 0 && mode.height == 0) {
return (intptr_t)rescustom;
} else {
snprintf(resstring, sizeof(resstring), "%dx%d", mode.width, mode.height);
}
return (intptr_t)resstring;
case MENUOP_SET:
videoSetDisplayMode(data->dropdown.value);
break;
case MENUOP_GETSELECTEDINDEX:
data->dropdown.value = videoGetDisplayModeIndex();
}
return 0;
}
static MenuItemHandlerResult menuhandlerTexFilter(s32 operation, struct menuitem *item, union handlerdata *data) static MenuItemHandlerResult menuhandlerTexFilter(s32 operation, struct menuitem *item, union handlerdata *data)
{ {
static const char *opts[] = {
"Nearest",
"Bilinear",
"Three Point"
};
switch (operation) { switch (operation) {
case MENUOP_GET: case MENUOP_GETOPTIONCOUNT:
return (videoGetTextureFilter() != 0); data->dropdown.value = ARRAYCOUNT(opts);
case MENUOP_SET:
videoSetTextureFilter(data->checkbox.value);
break; break;
case MENUOP_GETOPTIONTEXT:
return (intptr_t)opts[data->dropdown.value];
case MENUOP_SET:
videoSetTextureFilter(data->dropdown.value);
break;
case MENUOP_GETSELECTEDINDEX:
data->dropdown.value = videoGetTextureFilter();
} }
return 0; return 0;
@@ -698,12 +901,39 @@ static MenuItemHandlerResult menuhandlerTexFilter2D(s32 operation, struct menuit
return videoGetTextureFilter2D(); return videoGetTextureFilter2D();
case MENUOP_SET: case MENUOP_SET:
videoSetTextureFilter2D(data->checkbox.value); videoSetTextureFilter2D(data->checkbox.value);
g_TexFilter2D = videoGetTextureFilter2D() ? G_TF_BILERP : G_TF_POINT;
break; break;
} }
return 0; return 0;
} }
static MenuItemHandlerResult menuhandlerAnisotropicFiltering(s32 operation, struct menuitem *item, union handlerdata *data)
{
switch (operation) {
case MENUOP_GETSLIDER:
data->slider.value = videoGetAnisotropicFilter();
break;
case MENUOP_SET:
videoSetAnisotropicFilter(data->slider.value);
break;
}
return 0;
}
static MenuItemHandlerResult menuhandlerDisplayFPS(s32 operation, struct menuitem *item, union handlerdata *data)
{
switch (operation) {
case MENUOP_GET:
return videoGetDisplayFPS();
case MENUOP_SET:
videoSetDisplayFPS(data->checkbox.value);
}
return 0;
}
static MenuItemHandlerResult menuhandlerGeMuzzleFlashes(s32 operation, struct menuitem *item, union handlerdata *data) static MenuItemHandlerResult menuhandlerGeMuzzleFlashes(s32 operation, struct menuitem *item, union handlerdata *data)
{ {
switch (operation) { switch (operation) {
@@ -717,6 +947,19 @@ static MenuItemHandlerResult menuhandlerGeMuzzleFlashes(s32 operation, struct me
return 0; return 0;
} }
static MenuItemHandlerResult menuhandlerUncapTickrate(s32 operation, struct menuitem *item, union handlerdata *data)
{
switch (operation) {
case MENUOP_GET:
return (g_TickRateDiv == 0);
case MENUOP_SET:
g_TickRateDiv = !data->checkbox.value;
break;
}
return 0;
}
static MenuItemHandlerResult menuhandlerCenterHUD(s32 operation, struct menuitem *item, union handlerdata *data) static MenuItemHandlerResult menuhandlerCenterHUD(s32 operation, struct menuitem *item, union handlerdata *data)
{ {
static const char *opts[] = { static const char *opts[] = {
@@ -765,6 +1008,34 @@ static MenuItemHandlerResult menuhandlerScreenShake(s32 operation, struct menuit
return 0; return 0;
} }
static MenuItemHandlerResult menuhandlerGlareBrightness(s32 operation, struct menuitem *item, union handlerdata *data)
{
switch (operation) {
case MENUOP_GETSLIDER:
data->slider.value = videoGetGlareBrightness() * 10.f + 0.5f;
break;
case MENUOP_SET:
videoSetGlareBrightness((f32)data->slider.value / 10.f);
break;
}
return 0;
}
static MenuItemHandlerResult menuhandlerOverexposureScale(s32 operation, struct menuitem *item, union handlerdata *data)
{
switch (operation) {
case MENUOP_GETSLIDER:
data->slider.value = videoGetOverexposureScale() * 10.f + 0.5f;
break;
case MENUOP_SET:
videoSetOverexposureScale((f32)data->slider.value / 10.f);
break;
}
return 0;
}
struct menuitem g_ExtendedVideoMenuItems[] = { struct menuitem g_ExtendedVideoMenuItems[] = {
{ {
MENUITEMTYPE_CHECKBOX, MENUITEMTYPE_CHECKBOX,
@@ -775,25 +1046,89 @@ struct menuitem g_ExtendedVideoMenuItems[] = {
menuhandlerFullScreen, menuhandlerFullScreen,
}, },
{ {
MENUITEMTYPE_CHECKBOX, MENUITEMTYPE_DROPDOWN,
0, 0,
MENUITEMFLAG_LITERAL_TEXT, MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Maximize Window", (uintptr_t)"Full Screen Mode",
0, 0,
menuhandlerMaximizeWindow, menuhandlerFullScreenMode,
},
{
MENUITEMTYPE_DROPDOWN,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Resolution",
0,
menuhandlerResolution,
}, },
{ {
MENUITEMTYPE_CHECKBOX, MENUITEMTYPE_CHECKBOX,
0, 0,
MENUITEMFLAG_LITERAL_TEXT, MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Detail Textures", (uintptr_t)"Center Window",
0, 0,
menuhandlerTexDetail, menuhandlerCenterWindow,
},
{
MENUITEMTYPE_DROPDOWN,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Anti-aliasing",
0,
menuhandlerMSAA,
},
{
MENUITEMTYPE_SEPARATOR,
0,
0,
0,
0,
NULL,
},
{
MENUITEMTYPE_DROPDOWN,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Vsync",
0,
menuhandlerVsync,
},
{
MENUITEMTYPE_SLIDER,
0,
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE | MENUITEMFLAG_SLIDER_DEFERRED,
(uintptr_t)"Framerate Limit",
VIDEO_MAX_FPS,
menuhandlerFramerateLimit,
}, },
{ {
MENUITEMTYPE_CHECKBOX, MENUITEMTYPE_CHECKBOX,
0, 0,
MENUITEMFLAG_LITERAL_TEXT, MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Uncap Tickrate",
0,
menuhandlerUncapTickrate,
},
{
MENUITEMTYPE_CHECKBOX,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Display FPS",
0,
menuhandlerDisplayFPS,
},
{
MENUITEMTYPE_SEPARATOR,
0,
0,
0,
0,
NULL,
},
{
MENUITEMTYPE_DROPDOWN,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Texture Filtering", (uintptr_t)"Texture Filtering",
0, 0,
menuhandlerTexFilter, menuhandlerTexFilter,
@@ -806,13 +1141,29 @@ struct menuitem g_ExtendedVideoMenuItems[] = {
0, 0,
menuhandlerTexFilter2D, menuhandlerTexFilter2D,
}, },
{
MENUITEMTYPE_SLIDER,
0,
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE,
(uintptr_t)"Anisotropic Filtering",
8,
menuhandlerAnisotropicFiltering,
},
{ {
MENUITEMTYPE_CHECKBOX, MENUITEMTYPE_CHECKBOX,
0, 0,
MENUITEMFLAG_LITERAL_TEXT, MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"GE64-style Muzzle Flashes", (uintptr_t)"Detail Textures",
0, 0,
menuhandlerGeMuzzleFlashes, menuhandlerTexDetail,
},
{
MENUITEMTYPE_SEPARATOR,
0,
0,
0,
0,
NULL,
}, },
{ {
MENUITEMTYPE_DROPDOWN, MENUITEMTYPE_DROPDOWN,
@@ -822,6 +1173,14 @@ struct menuitem g_ExtendedVideoMenuItems[] = {
0, 0,
menuhandlerCenterHUD, menuhandlerCenterHUD,
}, },
{
MENUITEMTYPE_CHECKBOX,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"GE64-style Muzzle Flashes",
0,
menuhandlerGeMuzzleFlashes,
},
{ {
MENUITEMTYPE_SLIDER, MENUITEMTYPE_SLIDER,
0, 0,
@@ -838,6 +1197,30 @@ struct menuitem g_ExtendedVideoMenuItems[] = {
0, 0,
NULL, NULL,
}, },
{
MENUITEMTYPE_SLIDER,
0,
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE,
(uintptr_t)"Glare Brightness",
10,
menuhandlerGlareBrightness,
},
{
MENUITEMTYPE_SLIDER,
0,
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE,
(uintptr_t)"Overexposure Scale",
10,
menuhandlerOverexposureScale,
},
{
MENUITEMTYPE_SEPARATOR,
0,
0,
0,
0,
NULL,
},
{ {
MENUITEMTYPE_SELECTABLE, MENUITEMTYPE_SELECTABLE,
0, 0,
@@ -908,6 +1291,21 @@ struct menudialogdef g_ExtendedAudioMenuDialog = {
NULL, NULL,
}; };
static MenuItemHandlerResult menuhandlerUseKeyReloads(s32 operation, struct menuitem *item, union handlerdata *data)
{
switch (operation) {
case MENUOP_CHECKDISABLED:
return !g_PlayerExtCfg[g_ExtMenuPlayer].extcontrols;
case MENUOP_GET:
return g_PlayerExtCfg[g_ExtMenuPlayer].usereloads;
case MENUOP_SET:
g_PlayerExtCfg[g_ExtMenuPlayer].usereloads = data->checkbox.value;
break;
}
return 0;
}
static MenuItemHandlerResult menuhandlerCrouchMode(s32 operation, struct menuitem *item, union handlerdata *data) static MenuItemHandlerResult menuhandlerCrouchMode(s32 operation, struct menuitem *item, union handlerdata *data)
{ {
static const char *opts[] = { static const char *opts[] = {
@@ -944,6 +1342,7 @@ static MenuItemHandlerResult menuhandlerFieldOfView(s32 operation, struct menuit
g_PlayerExtCfg[g_ExtMenuPlayer].fovy = data->slider.value; g_PlayerExtCfg[g_ExtMenuPlayer].fovy = data->slider.value;
if (g_PlayerExtCfg[g_ExtMenuPlayer].fovzoom) { if (g_PlayerExtCfg[g_ExtMenuPlayer].fovzoom) {
g_PlayerExtCfg[g_ExtMenuPlayer].fovzoommult = g_PlayerExtCfg[g_ExtMenuPlayer].fovy / 60.f; g_PlayerExtCfg[g_ExtMenuPlayer].fovzoommult = g_PlayerExtCfg[g_ExtMenuPlayer].fovy / 60.f;
playerClampGunZoomFovY(g_ExtMenuPlayer);
} }
} }
break; break;
@@ -966,6 +1365,22 @@ static MenuItemHandlerResult menuhandlerCrosshairSway(s32 operation, struct menu
return 0; return 0;
} }
static MenuItemHandlerResult menuhandlerCrosshairEdgeBoundary(s32 operation, struct menuitem* item, union handlerdata *data)
{
switch (operation) {
case MENUOP_GETSLIDER:
data->slider.value = (s32)(g_PlayerExtCfg[g_ExtMenuPlayer].crosshairedgeboundary * 10.f + 0.5f);
break;
case MENUOP_SET:
g_PlayerExtCfg[g_ExtMenuPlayer].crosshairedgeboundary = (f32)data->slider.value / 10.f;
break;
case MENUOP_GETSLIDERLABEL:
sprintf(data->slider.label, "%d", (s32)data->slider.value);
break;
}
return 0;
}
static MenuItemHandlerResult menuhandlerCrosshairR(s32 operation, struct menuitem* item, union handlerdata* data) static MenuItemHandlerResult menuhandlerCrosshairR(s32 operation, struct menuitem* item, union handlerdata* data)
{ {
u32 newColor; u32 newColor;
@@ -1187,6 +1602,14 @@ struct menuitem g_ExtendedGameMenuItems[] = {
20, 20,
menuhandlerCrosshairSway, menuhandlerCrosshairSway,
}, },
{
MENUITEMTYPE_SLIDER,
0,
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE,
(uintptr_t)"Crosshair Edge Deadzone",
10,
menuhandlerCrosshairEdgeBoundary,
},
{ {
MENUITEMTYPE_SLIDER, MENUITEMTYPE_SLIDER,
0, 0,
@@ -1211,6 +1634,14 @@ struct menuitem g_ExtendedGameMenuItems[] = {
0, 0,
menuhandlerCrosshairHealth, menuhandlerCrosshairHealth,
}, },
{
MENUITEMTYPE_CHECKBOX,
0,
MENUITEMFLAG_LITERAL_TEXT,
(uintptr_t)"Use Key Reloads",
0,
menuhandlerUseKeyReloads,
},
{ {
MENUITEMTYPE_SEPARATOR, MENUITEMTYPE_SEPARATOR,
0, 0,
@@ -1313,6 +1744,8 @@ static const struct menubind menuBinds[] = {
{ CK_8000, "Cycle Crouch [+]\n", "N64 Ext 8000\n" }, { CK_8000, "Cycle Crouch [+]\n", "N64 Ext 8000\n" },
{ CK_4000, "Half Crouch [+]\n", "N64 Ext 4000\n" }, { CK_4000, "Half Crouch [+]\n", "N64 Ext 4000\n" },
{ CK_2000, "Full Crouch [+]\n", "N64 Ext 2000\n" }, { CK_2000, "Full Crouch [+]\n", "N64 Ext 2000\n" },
{ CK_ACCEPT, "UI Accept [+]\n", "EXT UI Accept\n" },
{ CK_CANCEL, "UI Cancel [+]\n", "EXT UI Cancel\n" },
}; };
static const char *menutextBind(struct menuitem *item); static const char *menutextBind(struct menuitem *item);
@@ -1350,6 +1783,8 @@ struct menuitem g_ExtendedBindsMenuItems[] = {
DEFINE_MENU_BIND(), DEFINE_MENU_BIND(),
DEFINE_MENU_BIND(), DEFINE_MENU_BIND(),
DEFINE_MENU_BIND(), DEFINE_MENU_BIND(),
DEFINE_MENU_BIND(),
DEFINE_MENU_BIND(),
{ {
MENUITEMTYPE_SEPARATOR, MENUITEMTYPE_SEPARATOR,
0, 0,
@@ -1586,3 +2021,22 @@ struct menudialogdef g_ExtendedMenuDialog = {
MENUDIALOGFLAG_LITERAL_TEXT, MENUDIALOGFLAG_LITERAL_TEXT,
NULL, NULL,
}; };
void updateMaxAnisotropyLevel()
{
for (int i = 0; i < ARRAYCOUNT(g_ExtendedVideoMenuItems); ++i) {
struct menuitem *item = &g_ExtendedVideoMenuItems[i];
const char *text = menuResolveParam2Text(item);
if (text && strstr(text, "Anisotropic Filtering") != NULL) {
item->param3 = videoGetMaxAnisotropyLevel();
break;
}
}
}
void optionsMenuInit()
{
updateMaxAnisotropyLevel();
}
+19 -25
View File
@@ -73,9 +73,6 @@
#include "data.h" #include "data.h"
#include "types.h" #include "types.h"
#include "system.h" #include "system.h"
#include "console.h"
#include "net/net.h"
#include "net/netmsg.h"
extern u8 *g_MempHeap; extern u8 *g_MempHeap;
extern u32 g_MempHeapSize; extern u32 g_MempHeapSize;
@@ -228,6 +225,8 @@ void mainInit(void)
joyInit(); joyInit();
joyReset(); joyReset();
var8005d9b0 = rmonIsDisabled();
g_Is4Mb = (osGetMemSize() <= 0x400000); g_Is4Mb = (osGetMemSize() <= 0x400000);
g_VmShowStats = 0; g_VmShowStats = 0;
@@ -260,7 +259,7 @@ void mainInit(void)
frametimeInit(); frametimeInit();
profileInit(); profileInit();
smokesInit(); smokesInit();
mpInit(); mpInit(true);
pheadInit(); pheadInit();
paksInit(); paksInit();
pheadInit2(); pheadInit2();
@@ -422,9 +421,6 @@ void mainLoop(void)
if (argFindByPrefix(1, "-ma")) { if (argFindByPrefix(1, "-ma")) {
g_MainMemaHeapSize = strtol(argFindByPrefix(1, "-ma"), NULL, 0) * 1024; g_MainMemaHeapSize = strtol(argFindByPrefix(1, "-ma"), NULL, 0) * 1024;
if (g_NetMode && g_NetMaxClients > MAX_LOCAL_PLAYERS) {
g_MainMemaHeapSize *= MAX_PLAYERS / MAX_LOCAL_PLAYERS;
}
} }
memaReset(mempAlloc(g_MainMemaHeapSize, MEMPOOL_STAGE), g_MainMemaHeapSize); memaReset(mempAlloc(g_MainMemaHeapSize, MEMPOOL_STAGE), g_MainMemaHeapSize);
@@ -466,15 +462,10 @@ void mainLoop(void)
} }
if (g_Vars.coopplayernum >= 0 || g_Vars.antiplayernum >= 0) { if (g_Vars.coopplayernum >= 0 || g_Vars.antiplayernum >= 0) {
#ifdef PLATFORM_N64 if (g_MpSetup.chrslots & 0xfff0) {
g_MpSetup.chrslots = 0x03; g_MpSetup.storedbotbits = g_MpSetup.chrslots & 0xfff0;
#else
if (g_Vars.antiplayernum < 0) {
// Counter-Operative now uses a different approach which allows more than 2 players.
// Co-Operative, on the other hand, is currently limited to 2 players.
g_MpSetup.chrslots = 0x03;
} }
#endif g_MpSetup.chrslots = 0x03;
mpReset(); mpReset();
} else if (g_Vars.perfectbuddynum) { } else if (g_Vars.perfectbuddynum) {
mpReset(); mpReset();
@@ -482,8 +473,16 @@ void mainLoop(void)
&& (numplayers >= 2 || g_Vars.lvmpbotlevel || argFindByPrefix(1, "-play"))) { && (numplayers >= 2 || g_Vars.lvmpbotlevel || argFindByPrefix(1, "-play"))) {
g_MpSetup.chrslots = 1; g_MpSetup.chrslots = 1;
for (s32 i = 1; i < numplayers; ++i) { if (numplayers >= 2) {
g_MpSetup.chrslots |= 1 << i; g_MpSetup.chrslots |= 1 << 1;
}
if (numplayers >= 3) {
g_MpSetup.chrslots |= 1 << 2;
}
if (numplayers >= 4) {
g_MpSetup.chrslots |= 1 << 3;
} }
g_MpSetup.stagenum = g_StageNum; g_MpSetup.stagenum = g_StageNum;
@@ -567,9 +566,6 @@ void mainTick(void)
gdl = profileRender(gdl); gdl = profileRender(gdl);
} }
gdl = conRender(gdl);
gdl = netDebugRender(gdl);
gDPFullSync(gdl++); gDPFullSync(gdl++);
gSPEndDisplayList(gdl++); gSPEndDisplayList(gdl++);
} }
@@ -579,7 +575,7 @@ void mainTick(void)
viUpdateMode(); viUpdateMode();
} }
rdpCreateTask(gdlstart, gdl, 0, (s32) &msg); rdpCreateTask(gdlstart, gdl, 0, (uintptr_t) &msg);
memaPrint(); memaPrint();
profileSetMarker(PROFILE_MAINTICK_END); profileSetMarker(PROFILE_MAINTICK_END);
} }
@@ -597,7 +593,7 @@ void mainEndStage(void)
s32 prevplayernum = g_Vars.currentplayernum; s32 prevplayernum = g_Vars.currentplayernum;
s32 i; s32 i;
for (i = 0; i < LOCALPLAYERCOUNT(); i++) { for (i = 0; i < PLAYERCOUNT(); i++) {
setCurrentPlayerNum(i); setCurrentPlayerNum(i);
endscreenPushCoop(); endscreenPushCoop();
} }
@@ -608,7 +604,7 @@ void mainEndStage(void)
s32 prevplayernum = g_Vars.currentplayernum; s32 prevplayernum = g_Vars.currentplayernum;
s32 i; s32 i;
for (i = 0; i < LOCALPLAYERCOUNT(); i++) { for (i = 0; i < PLAYERCOUNT(); i++) {
setCurrentPlayerNum(i); setCurrentPlayerNum(i);
endscreenPushAnti(); endscreenPushAnti();
} }
@@ -621,8 +617,6 @@ void mainEndStage(void)
endscreenPrepare(); endscreenPrepare();
musicStartMenu(); musicStartMenu();
} }
netServerStageEnd();
} }
g_MainIsEndscreen = true; g_MainIsEndscreen = true;
-23
View File
@@ -24,9 +24,7 @@
#include "video.h" #include "video.h"
#include "audio.h" #include "audio.h"
#include "input.h" #include "input.h"
#include "console.h"
#include "mixer.h" #include "mixer.h"
#include "net/net.h"
/* /*
* private typedefs and defines * private typedefs and defines
@@ -242,14 +240,6 @@ void schedSubmitTask(OSSched *sc, OSScTask *t)
void schedStartFrame(OSSched *sc) void schedStartFrame(OSSched *sc)
{ {
videoStartFrame(); videoStartFrame();
if (g_Vars.diffframe60) {
if (g_NetMode) {
videoCapFramerate(120);
netStartFrame();
} else {
videoCapFramerate(0);
}
}
} }
void schedAudioFrame(OSSched *sc) void schedAudioFrame(OSSched *sc)
@@ -280,8 +270,6 @@ void schedAudioFrame(OSSched *sc)
*/ */
void schedEndFrame(OSSched *sc) void schedEndFrame(OSSched *sc)
{ {
static bool netDebugKey = false;
sc->frameCount++; sc->frameCount++;
#if PAL #if PAL
@@ -301,22 +289,11 @@ void schedEndFrame(OSSched *sc)
} }
inputUpdate(); inputUpdate();
conTick();
const bool newKey = inputKeyPressed(VK_F9);
if (!netDebugKey && newKey) {
g_NetDebugDraw = !g_NetDebugDraw;
}
netDebugKey = newKey;
joyStartReadData(&g_PiMesgQueue); joyStartReadData(&g_PiMesgQueue);
joyReadData(); joyReadData();
joy00014238(); joy00014238();
if (g_Vars.diffframe60) {
netEndFrame();
}
sndHandleRetrace(); sndHandleRetrace();
schedAudioFrame(sc); schedAudioFrame(sc);
schedRenderCrashPeriodically(sc->frameCount); schedRenderCrashPeriodically(sc->frameCount);
File diff suppressed because it is too large. Load diff
+31
View File
@@ -0,0 +1,31 @@
#include "preprocess/common.h"
static struct ptrmarker ptrMarkers[MAX_PTR_MARKERS];
static int numPtrMarkers;
void ptrAdd(u32 ptr_src, uintptr_t ptr_host)
{
if (numPtrMarkers >= ARRAYCOUNT(ptrMarkers)) {
sysFatalError("ptrAdd(%p, %p): ptrmarker limit exceeded", (void *)(uintptr_t)ptr_src, (void *)ptr_host);
}
ptrMarkers[numPtrMarkers].ptr_src = ptr_src;
ptrMarkers[numPtrMarkers].ptr_host = ptr_host;
numPtrMarkers++;
}
struct ptrmarker *ptrFind(uintptr_t ptr_src)
{
for (int i = 0; i < numPtrMarkers; i++) {
if (ptrMarkers[i].ptr_src == ptr_src) {
return &ptrMarkers[i];
}
}
return NULL;
}
void ptrReset(void)
{
numPtrMarkers = 0;
}
+524
View File
@@ -0,0 +1,524 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "data.h"
#include "bss.h"
#include "preprocess/common.h"
#include "preprocess/gbi.h"
/**
* 4 bytes decompressed size of primary data
* 4 bytes compressed size of section 1 in its entirety
* 4 bytes compressed size of primary data
* Section 1:
* Primary: (zipped)
* 4 bytes null
* 4 bytes pointer to room table
* 4 bytes pointer to portal table
* 4 bytes pointer to bgcmds
* 4 bytes pointer to lights table
* 4 bytes null
* (room table)
* (portal table)
* (bgcmds)
* (lights table)
* room 1 (zipped)
* room 2 (zipped)
* ...
* Section 2:
* 2 bytes decompressed size of section (mask with 0x7fff)
* 2 bytes compressed size of section
* Texture ID list (zipped)
* Section 3:
* 2 bytes decompressed size of section (mask with 0x7fff)
* 2 bytes compressed size of section
* Zipped:
* (room bbox table)
* (list of roomgfxdata sizes)
* (list of light counts per room)
*/
struct fileheader {
u32 primary_infsize;
u32 section1_cmpsize;
u32 primary_cmpsize;
};
struct sectionheader {
u16 infsize;
u16 cmpsize;
};
struct n64_primaryheader {
u32 unused1;
u32 ptr_rooms;
u32 ptr_portals;
u32 ptr_bgcmds;
u32 ptr_lights;
u32 unused2;
};
struct host_primaryheader {
uintptr_t unused1;
uintptr_t ptr_rooms;
uintptr_t ptr_portals;
uintptr_t ptr_bgcmds;
uintptr_t ptr_lights;
uintptr_t unused2;
};
struct n64_bgroom {
u32 ptr_gfxdata;
struct coord pos;
u8 br_light_min;
u8 br_light_max;
};
struct n64_roomblock {
u8 type;
u32 ptr_next;
u32 ptr_gdl;
u32 ptr_vertices;
u32 ptr_colours;
};
struct n64_roomgfxdata {
u32 ptr_vertices;
u32 ptr_colours;
u32 ptr_opablocks;
u32 ptr_xlublocks;
s16 lightsindex;
s16 numlights;
s16 numvertices;
s16 numcolours;
// roomblocks[]
};
struct vtx {
s16 coord[3];
u8 flag;
u8 color;
u16 s;
u16 t;
};
static void convertPrimaryRooms(u8 *dst, u32 *dstpos, u8 *src, u32 *srcpos)
{
struct n64_bgroom *n64_rooms = (struct n64_bgroom *) &src[*srcpos];
struct bgroom *host_rooms = (struct bgroom *) &dst[*dstpos];
s32 numRooms = 0;
for (int i = 1; n64_rooms[i].ptr_gfxdata != 0; i++) {
numRooms++;
}
for (int i = 0; i < numRooms + 1; i++) {
host_rooms[i].unk00 = PD_BE32(n64_rooms[i].ptr_gfxdata);
host_rooms[i].pos = PD_SWAPPED_VAL(n64_rooms[i].pos);
host_rooms[i].br_light_min = n64_rooms[i].br_light_min;
host_rooms[i].br_light_max = n64_rooms[i].br_light_max;
}
*srcpos += sizeof(*n64_rooms) * (numRooms + 2);
*dstpos += sizeof(*host_rooms) * (numRooms +2);
}
static void convertPrimaryPortals(u8 *dst, u32 *dstpos, u8 *src, u32 *srcpos, u32 *src_portalvtxs, u32 *dst_portalvtxs)
{
struct bgportal *n64_portals = (struct bgportal *) &src[*srcpos];
struct bgportal *host_portals = (struct bgportal *) &dst[*dstpos];
// Count portals
int numportals = 0;
for (int i = 0; n64_portals[i].verticesoffset != 0; i++) {
numportals++;
}
// Convert portals
for (int i = 0; i < numportals; i++) {
host_portals[i].verticesoffset = PD_BE16(n64_portals[i].verticesoffset);
host_portals[i].roomnum1 = PD_BE16(n64_portals[i].roomnum1);
host_portals[i].roomnum2 = PD_BE16(n64_portals[i].roomnum2);
host_portals[i].flags = n64_portals[i].flags;
}
*srcpos += sizeof(*n64_portals) * (numportals + 1);
*dstpos += sizeof(*host_portals) * (numportals + 1);
*src_portalvtxs = *srcpos;
*dst_portalvtxs = *dstpos;
while (1) {
struct portalvertices *n64_pvertices = (struct portalvertices *)&src[*srcpos];
struct portalvertices *host_pvertices = (struct portalvertices *)&dst[*dstpos];
host_pvertices->count = n64_pvertices->count;
for (int j = 0; j < host_pvertices->count; j++) {
host_pvertices->vertices[j] = PD_SWAPPED_VAL(n64_pvertices->vertices[j]);
}
*srcpos += 4 + host_pvertices->count * 12;
*dstpos += 4 + host_pvertices->count * 12;
if (host_pvertices->count == 0) break;
}
}
static void convertPrimaryBgCmds(u8 *dst, u32 *dstpos, u8 *src, u32 dst_portalvtxs, u32 src_portalvtxs)
{
struct bgcmd *n64_cmds = (struct bgcmd *) src;
struct bgcmd *host_cmds = (struct bgcmd *) &dst[*dstpos];
int num_cmds = 0;
for (int i = 0; n64_cmds[i].type != 0; i++) {
num_cmds++;
}
num_cmds++;
for (int i = 0; i < num_cmds; i++) {
host_cmds[i].type = n64_cmds[i].type;
host_cmds[i].len = n64_cmds[i].len;
host_cmds[i].param = PD_BE32(n64_cmds[i].param);
if (host_cmds[i].type == 0x64) {
u32 offset = host_cmds[i].param - src_portalvtxs;
host_cmds[i].param = dst_portalvtxs + offset;
}
}
*dstpos += sizeof(*host_cmds) * num_cmds;
}
static void convertPrimaryLights(u8 *dst, u32 *dstpos, u8 *src, u32 *srcpos, u32 end)
{
struct light *n64_lights = (struct light *) &src[*srcpos];
struct light *host_lights = (struct light *) &dst[*dstpos];
int num_lights = (end - *srcpos) / sizeof(struct light);
for (int i = 0; i < num_lights; i++) {
host_lights[i].roomnum = PD_BE16(n64_lights[i].roomnum);
host_lights[i].colour = PD_BE16(n64_lights[i].colour);
host_lights[i].brightness = n64_lights[i].brightness;
host_lights[i].sparkable = n64_lights[i].sparkable;
host_lights[i].healthy = n64_lights[i].healthy;
host_lights[i].on = n64_lights[i].on;
host_lights[i].sparking = n64_lights[i].sparking;
host_lights[i].vulnerable = n64_lights[i].vulnerable;
host_lights[i].brightnessmult = n64_lights[i].brightnessmult;
host_lights[i].dirx = n64_lights[i].dirx;
host_lights[i].diry = n64_lights[i].diry;
host_lights[i].dirz = n64_lights[i].dirz;
for (int j = 0; j < 4; j++) {
host_lights[i].bbox[j].x = PD_BE16(n64_lights[i].bbox[j].x);
host_lights[i].bbox[j].y = PD_BE16(n64_lights[i].bbox[j].y);
host_lights[i].bbox[j].z = PD_BE16(n64_lights[i].bbox[j].z);
}
}
*srcpos += sizeof(*n64_lights) * num_lights;
*dstpos += ALIGN(sizeof(*host_lights) * num_lights, 4);
}
#define BLOCK_LEAF 0
#define BLOCK_PARENT 1
void relinkPtr(uintptr_t* ptr)
{
if (!*ptr) return;
struct ptrmarker* marker = ptrFind(*ptr);
if (!marker) {
sysFatalError("[BG] WARNING: Unable to relink pointer: %p\n", ptr);
}
*ptr = marker->ptr_host;
}
static u32 convertRoomGfxData(u8 *dst, u8 *src, u32 infsize, u32 src_ofs)
{
ptrReset();
gbiReset();
u32 dst_roomoffset = src_ofs;
uintptr_t gdls_addr[64];
int numgdls = 0;
struct n64_roomgfxdata *src_header = (struct n64_roomgfxdata*)src;
struct roomgfxdata *dst_header = (struct roomgfxdata*)dst;
dst_header->vertices = (void *)(uintptr_t)PD_BE32(src_header->ptr_vertices);
dst_header->colours = (void *)(uintptr_t)PD_BE32(src_header->ptr_colours);
dst_header->opablocks = (void *)(uintptr_t)PD_BE32(src_header->ptr_opablocks);
dst_header->xlublocks = (void *)(uintptr_t)PD_BE32(src_header->ptr_xlublocks);
dst_header->lightsindex = PD_BE16(src_header->lightsindex);
dst_header->numlights = PD_BE16(src_header->numlights);
dst_header->numvertices = PD_BE16(src_header->numvertices);
dst_header->numcolours = PD_BE16(src_header->numcolours);
intptr_t endpos = (uintptr_t)dst_header->vertices - src_ofs;
uintptr_t curpos_src = sizeof(struct n64_roomgfxdata);
uintptr_t curpos_dst = sizeof(struct roomgfxdata) - sizeof(struct roomblock); // compensate for the [1]
// roomblocks
int ncoords = 0;
// save the ptr to roomblocks here to iterate later to fix the pointers
struct roomblock *ptr_dst_roomblocks = (struct roomblock*)&dst[curpos_dst];
int numblocks = 0;
while ((intptr_t)(curpos_src + sizeof(struct n64_roomblock)) <= endpos) {
struct n64_roomblock *src_roomblock = (struct n64_roomblock*)&src[curpos_src];
struct roomblock *dest_roomblock = (struct roomblock*)&dst[curpos_dst];
dest_roomblock->type = src_roomblock->type;
dest_roomblock->next = (void *)(uintptr_t)PD_BE32(src_roomblock->ptr_next);
dest_roomblock->gdl = (void *)(uintptr_t)PD_BE32(src_roomblock->ptr_gdl);
dest_roomblock->vertices = (void *)(uintptr_t)PD_BE32(src_roomblock->ptr_vertices);
dest_roomblock->colours = (void *)(uintptr_t)PD_BE32(src_roomblock->ptr_colours);
ptrAdd(curpos_src + src_ofs, curpos_dst + dst_roomoffset);
if (src_roomblock->type == BLOCK_PARENT) {
ncoords++;
uintptr_t vtx_ptr = (uintptr_t)dest_roomblock->vertices - src_ofs;
if (vtx_ptr < endpos) endpos = vtx_ptr;
}
else if (src_roomblock->ptr_gdl) {
gdls_addr[numgdls++] = PD_BE32(src_roomblock->ptr_gdl) - src_ofs;
}
curpos_src += sizeof(struct n64_roomblock);
curpos_dst += sizeof(struct roomblock);
numblocks++;
}
// block coords
for (size_t i = 0; i < ncoords; i++) {
u32 *src_coord = (u32*)(src + curpos_src);
u32 *dst_coord = (u32*)(dst + curpos_dst);
dst_coord[0] = PD_BE32(src_coord[0]);
dst_coord[1] = PD_BE32(src_coord[1]);
dst_coord[2] = PD_BE32(src_coord[2]);
dst_coord[3] = PD_BE32(src_coord[3]);
dst_coord[4] = PD_BE32(src_coord[4]);
dst_coord[5] = PD_BE32(src_coord[5]);
ptrAdd(curpos_src + src_ofs, curpos_dst + dst_roomoffset);
curpos_src += 6 * sizeof(u32);
curpos_dst += 6 * sizeof(u32);
}
curpos_dst = ALIGN8(curpos_dst);
// vertices
uintptr_t ptr_src_vertices = curpos_src = ALIGN8((uintptr_t)dst_header->vertices - src_ofs);
uintptr_t ptr_dst_vertices = curpos_dst + dst_roomoffset;
ptrAdd(curpos_src + src_ofs, curpos_dst + dst_roomoffset);
uintptr_t vtx_end = (uintptr_t)dst_header->colours - src_ofs;
while (dst_header->colours && curpos_src < vtx_end) {
struct vtx *src_vtx = (struct vtx*)(src + curpos_src);
struct vtx *dst_vtx = (struct vtx*)(dst + curpos_dst);
dst_vtx->coord[0] = PD_BE16(src_vtx->coord[0]);
dst_vtx->coord[1] = PD_BE16(src_vtx->coord[1]);
dst_vtx->coord[2] = PD_BE16(src_vtx->coord[2]);
dst_vtx->flag = src_vtx->flag;
dst_vtx->color = src_vtx->color;
dst_vtx->s = PD_BE16(src_vtx->s);
dst_vtx->t = PD_BE16(src_vtx->t);
curpos_src += sizeof(struct vtx);
curpos_dst += sizeof(struct vtx);
}
curpos_dst = ALIGN8(curpos_dst);
// colors
uintptr_t ptr_src_colors = 0;
uintptr_t ptr_dst_colors = 0;
if (dst_header->colours) {
ptr_src_colors = curpos_src = ALIGN8((uintptr_t)dst_header->colours - src_ofs);
ptr_dst_colors = curpos_dst + dst_roomoffset;
ptrAdd(curpos_src + src_ofs, curpos_dst + dst_roomoffset);
uintptr_t col_end = (numgdls > 0) ? gdls_addr[0] : infsize;
size_t col_len = col_end - curpos_src;
memcpy(dst + curpos_dst, src + curpos_src, col_len);
curpos_src += col_len;
curpos_dst += col_len;
}
// gdls
gbiSetVtx(src_header->ptr_vertices, ptr_src_vertices);
gbiSetSegment(0x0e, (uintptr_t)dst_header->vertices);
uintptr_t gdlstart = curpos_dst;
for (size_t i = 0; i < numgdls; i++) {
ptrAdd(gdls_addr[i] + src_ofs, curpos_dst + dst_roomoffset);
curpos_dst = gbiConvertGdl(dst, curpos_dst, src, gdls_addr[i], 1);
}
// relink ptrs: roomblocks
for (size_t i = 0; i < numblocks; i++) {
struct roomblock *block = (struct roomblock*)&ptr_dst_roomblocks[i];
relinkPtr((uintptr_t*)&block->next);
if (block->type == BLOCK_LEAF) {
relinkPtr((uintptr_t*)&block->gdl);
u32 offset_vtx = (uintptr_t)block->vertices - ptr_src_vertices - src_ofs;
u32 offset_col = (uintptr_t)block->colours - ptr_src_colors - src_ofs;
block->vertices = (void *)(ptr_dst_vertices + offset_vtx);
block->colours = (void *)(ptr_dst_colors + offset_col);
}
else {
relinkPtr((uintptr_t*)&block->gdl); // child
relinkPtr((uintptr_t*)&block->vertices); // coord
}
}
// relink ptrs: header
relinkPtr((uintptr_t*)&dst_header->vertices);
relinkPtr((uintptr_t*)&dst_header->colours);
relinkPtr((uintptr_t*)&dst_header->opablocks);
relinkPtr((uintptr_t*)&dst_header->xlublocks);
return curpos_dst;
}
static u32 convertSection1(u8 *dst, u8 *src, u32 ofs)
{
// Convert primary
u32 srcpos = 0;
u32 dstpos = 0;
struct host_primaryheader *host_primary_header = (struct host_primaryheader *) dst;
struct n64_primaryheader *n64_primary_header = (struct n64_primaryheader *) src;
srcpos += sizeof(struct n64_primaryheader);
dstpos += sizeof(*host_primary_header);
u32 src_bgcmds = PD_BE32(n64_primary_header->ptr_bgcmds) - ofs;
host_primary_header->unused1 = 0;
host_primary_header->unused2 = 0;
host_primary_header->ptr_rooms = dstpos + ofs;
convertPrimaryRooms(dst, &dstpos, src, &srcpos);
if (n64_primary_header->ptr_lights) {
host_primary_header->ptr_lights = dstpos + ofs;
srcpos = PD_BE32(n64_primary_header->ptr_lights) - ofs;
convertPrimaryLights(dst, &dstpos, src, &srcpos, src_bgcmds);
}
host_primary_header->ptr_portals = dstpos + ofs;
srcpos = PD_BE32(n64_primary_header->ptr_portals) - ofs;
u32 src_portalvtxs, dst_portalvtxs;
convertPrimaryPortals(dst, &dstpos, src, &srcpos, &src_portalvtxs, &dst_portalvtxs);
host_primary_header->ptr_bgcmds = dstpos + ofs;
convertPrimaryBgCmds(dst, &dstpos, &src[src_bgcmds], dst_portalvtxs, src_portalvtxs);
return dstpos;
}
void preprocessBgSection1(u8 *data, u32 size, u32 ofs)
{
u8 *dst = sysMemZeroAlloc(size);
u32 newSize = convertSection1(dst, data, ofs);
if (newSize > size) {
sysFatalError("overflow when trying to preprocess a bg file, size %d newsize %d", size, newSize);
}
memcpy(data, dst, newSize);
sysMemFree(dst);
}
u32 preprocessBgRoom(u8 *data, u32 size, u32 room_ofs)
{
size *= 2;
u8 *dst = sysMemZeroAlloc(size);
u32 newSize = convertRoomGfxData(dst, data, size, room_ofs);
if (newSize > size) {
sysFatalError("overflow when trying to preprocess a bg room, size %d newsize %d", size, newSize);
}
memcpy(data, dst, newSize);
sysMemFree(dst);
return newSize;
}
void preprocessBgSection1Header(u8* data, u32 size)
{
u32* header = (u32*)data;
PD_SWAP_VAL(header[0]); // inflatedsize
PD_SWAP_VAL(header[1]); // section1size
PD_SWAP_VAL(header[2]); // primcompsize
}
void preprocessBgSection2Header(u8* data, u32 size)
{
u16* header = (u16*)data;
PD_SWAP_VAL(header[0]); // inflatedsize
PD_SWAP_VAL(header[1]); // section2compsize
}
void preprocessBgSection2(u8* data, u32 size)
{
// section2 is a texture id list
u16* section2 = (u16*)data;
for (s32 i = 0; i < size; ++i) {
PD_SWAP_VAL(section2[i]);
}
}
void preprocessBgSection3Header(u8* data, u32 size)
{
u16* header = (u16*)data;
PD_SWAP_VAL(header[0]);
PD_SWAP_VAL(header[1]);
}
void preprocessBgSection3(u8* data, u32 size)
{
// room bounding boxes, 6x s16 per room
s16* bbox = (s16*)data;
for (s32 i = 1; i < g_Vars.roomcount; ++i) {
PD_SWAP_VAL(*bbox); ++bbox;
PD_SWAP_VAL(*bbox); ++bbox;
PD_SWAP_VAL(*bbox); ++bbox;
PD_SWAP_VAL(*bbox); ++bbox;
PD_SWAP_VAL(*bbox); ++bbox;
PD_SWAP_VAL(*bbox); ++bbox;
}
// gfxdatalen list
u16* gfxdatalen = (u16*)bbox;
for (s32 i = 1; i < g_Vars.roomcount; ++i) {
PD_SWAP_VAL(*gfxdatalen); ++gfxdatalen;
}
}
+92
View File
@@ -0,0 +1,92 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "preprocess/common.h"
static int getNextNonZero(u8 *src, u32 offset, size_t len)
{
u32 *ptr = (u32 *) &src[offset];
u32 *end = (u32 *) &src[len];
while (ptr < end) {
if (*ptr != 0) {
return PD_BE32(*ptr);
}
ptr++;
}
return 0;
}
static int getNumStrings(u8 *src, size_t len)
{
u32 ptr_table_len = getNextNonZero(src, 0, len);
if (ptr_table_len) {
return ptr_table_len / sizeof(u32);
}
return 1;
}
static u32 convertLangFile(u8 *dst, u8 *src, size_t srclen)
{
// Convert it
u32 *src_offsets = (u32 *) src;
size_t src_ptr_table_len = PD_BE32(src_offsets[0]);
size_t src_str_table_len = srclen - src_ptr_table_len;
int num_strings = getNumStrings(src, srclen);
size_t dst_ptr_table_len = num_strings * sizeof(uintptr_t);
size_t dst_str_table_len = src_str_table_len;
int cur_dst_offset = dst_ptr_table_len;
uintptr_t *dst_offsets = (uintptr_t *) dst;
for (int i = 0; i < num_strings; i++) {
u32 src_offset = PD_BE32(src_offsets[i]);
if (src_offset) {
// Write pointer
dst_offsets[i] = (cur_dst_offset);
// Write string
u32 end = getNextNonZero(src, (i + 1) * 4, num_strings * 4);
if (!end) {
end = srclen;
}
size_t len = end - src_offset;
len = ALIGN4(len);
memcpy(&dst[cur_dst_offset], &src[src_offset], len);
cur_dst_offset += len;
} else {
// Write pointer
dst_offsets[i] = 0;
}
}
return ALIGN16(cur_dst_offset);
}
u8 *preprocessLangFile(u8 *data, u32 size, u32 *outSize) {
u32 newSizeEstimated = romdataFileGetEstimatedSize(size, LOADTYPE_LANG);
u8 *dst = sysMemZeroAlloc(newSizeEstimated);
u32 newSize = convertLangFile(dst, data, size);
if (newSize > newSizeEstimated) {
sysFatalError("overflow when trying to preprocess a lang file, size %d newsize %d", size, newSize);
}
memcpy(data, dst, newSize);
sysMemFree(dst);
*outSize = newSize;
return 0;
}
File diff suppressed because it is too large. Load diff
+292
View File
@@ -0,0 +1,292 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "preprocess/common.h"
#include "constants.h"
struct n64_header {
s32 num_pads;
s32 num_covers;
u32 ptr_waypoints;
u32 ptr_waygroups;
u32 ptr_cover;
};
struct host_header {
s32 num_pads;
s32 num_covers;
uintptr_t ptr_waypoints;
uintptr_t ptr_waygroups;
uintptr_t ptr_cover;
};
struct padheader {
u32 flags : 18;
u32 room : 10;
u32 liftnum : 4;
};
struct n64_waypoint {
s32 padnum;
u32 ptr_neighbours;
s32 groupnum;
s32 step;
};
struct n64_waygroup {
u32 ptr_neighbours;
u32 ptr_waypoints;
s32 step;
};
static u32 convertPads(u8 *dst, u32 dstpos, u8 *src, u32 srcpos, int num_pads)
{
u16 *src_offsets = (u16 *) &src[srcpos];
u16 *dst_offsets = (u16 *) &dst[dstpos];
dstpos += num_pads * sizeof(u16);
for (int i = 0; i < num_pads; i++) {
srcpos = PD_BE16(src_offsets[i]);
dst_offsets[i] = (dstpos);
// Header
u32 n64_padheader = PD_BE32(*(u32 *) &src[srcpos]);
struct padheader *host_padheader = (struct padheader *) &dst[dstpos];
u32 flags = (n64_padheader >> 14) & 0x3ffff;
*(u32*)host_padheader = (n64_padheader);
srcpos += sizeof(struct padheader);
dstpos += sizeof(struct padheader);
// Position
if (flags & PADFLAG_INTPOS) {
s16 *srcptr = (s16 *) &src[srcpos];
s16 *dstptr = (s16 *) &dst[dstpos];
dstptr[0] = PD_BE16(srcptr[0]);
dstptr[1] = PD_BE16(srcptr[1]);
dstptr[2] = PD_BE16(srcptr[2]);
srcpos += 8;
dstpos += 8;
} else {
u32 *srcptr = (u32 *) &src[srcpos];
u32 *dstptr = (u32 *) &dst[dstpos];
dstptr[0] = PD_BE32(srcptr[0]);
dstptr[1] = PD_BE32(srcptr[1]);
dstptr[2] = PD_BE32(srcptr[2]);
srcpos += 12;
dstpos += 12;
}
// Up
if ((flags & (PADFLAG_UPALIGNTOX | PADFLAG_UPALIGNTOY | PADFLAG_UPALIGNTOZ)) == 0) {
u32 *srcptr = (u32 *) &src[srcpos];
u32 *dstptr = (u32 *) &dst[dstpos];
dstptr[0] = PD_BE32(srcptr[0]);
dstptr[1] = PD_BE32(srcptr[1]);
dstptr[2] = PD_BE32(srcptr[2]);
srcpos += 12;
dstpos += 12;
}
// Look
if ((flags & (PADFLAG_LOOKALIGNTOX | PADFLAG_LOOKALIGNTOY | PADFLAG_LOOKALIGNTOZ)) == 0) {
u32 *srcptr = (u32 *) &src[srcpos];
u32 *dstptr = (u32 *) &dst[dstpos];
dstptr[0] = PD_BE32(srcptr[0]);
dstptr[1] = PD_BE32(srcptr[1]);
dstptr[2] = PD_BE32(srcptr[2]);
srcpos += 12;
dstpos += 12;
}
// Bbox
if (flags & PADFLAG_HASBBOXDATA) {
u32 *srcptr = (u32 *) &src[srcpos];
u32 *dstptr = (u32 *) &dst[dstpos];
dstptr[0] = PD_BE32(srcptr[0]);
dstptr[1] = PD_BE32(srcptr[1]);
dstptr[2] = PD_BE32(srcptr[2]);
dstptr[3] = PD_BE32(srcptr[3]);
dstptr[4] = PD_BE32(srcptr[4]);
dstptr[5] = PD_BE32(srcptr[5]);
srcpos += 4 * 6;
dstpos += 4 * 6;
}
}
return dstpos;
}
static u32 convertWayPoints(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
{
struct n64_waypoint *n64_waypoints = (struct n64_waypoint *) &src[srcpos];
struct waypoint *host_waypoints = (struct waypoint *) &dst[dstpos];
int num_waypoints;
for (num_waypoints = 0; n64_waypoints[num_waypoints].padnum != -1; num_waypoints++);
dstpos += (num_waypoints + 1) * sizeof(struct waypoint);
u32 *host_neighbours = (u32 *) &dst[dstpos];
int n = 0;
for (int i = 0; i < num_waypoints; i++) {
host_waypoints[i].padnum = PD_BE32(n64_waypoints[i].padnum);
host_waypoints[i].neighbours = (void *)(uintptr_t)dstpos;
host_waypoints[i].groupnum = PD_BE32(n64_waypoints[i].groupnum);
host_waypoints[i].step = 0;
u32 *n64_neighbours = (u32 *) &src[PD_BE32(n64_waypoints[i].ptr_neighbours)];
for (int j = 0; n64_neighbours[j] != 0xffffffff; j++) {
host_neighbours[n++] = PD_BE32(n64_neighbours[j]);
dstpos += 4;
}
host_neighbours[n++] = 0xffffffff;
dstpos += 4;
}
// Terminator
host_waypoints[num_waypoints].padnum = 0xffffffff;
host_waypoints[num_waypoints].neighbours = NULL;
host_waypoints[num_waypoints].groupnum = 0;
host_waypoints[num_waypoints].step = 0;
return dstpos;
}
static u32 convertWayGroups(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
{
struct n64_waygroup *n64_waygroups = (struct n64_waygroup *) &src[srcpos];
struct waygroup *host_waygroups = (struct waygroup *) &dst[dstpos];
int num_waygroups;
for (num_waygroups = 0; n64_waygroups[num_waygroups].ptr_neighbours != 0; num_waygroups++);
dstpos += (num_waygroups + 1) * sizeof(struct waygroup);
// Waygroups and child waypoints
u32 *host_waypoints = (u32 *) &dst[dstpos];
int n = 0;
for (int i = 0; i < num_waygroups; i++) {
host_waygroups[i].waypoints = (void *)(uintptr_t)dstpos;
host_waygroups[i].step = 0;
u32 *n64_waypoints = (u32 *) &src[PD_BE32(n64_waygroups[i].ptr_waypoints)];
for (int j = 0; n64_waypoints[j] != 0xffffffff; j++) {
host_waypoints[n++] = PD_BE32(n64_waypoints[j]);
dstpos += 4;
}
host_waypoints[n++] = 0xffffffff;
dstpos += 4;
}
// Terminator
host_waygroups[num_waygroups].neighbours = NULL;
host_waygroups[num_waygroups].waypoints = NULL;
host_waygroups[num_waygroups].step = 0;
// Waygroup neighbours
u32 *host_neighbours = (u32 *) &dst[dstpos];
n = 0;
for (int i = 0; i < num_waygroups; i++) {
host_waygroups[i].neighbours = (void *)(uintptr_t)dstpos;
u32 *n64_neighbours = (u32 *) &src[PD_BE32(n64_waygroups[i].ptr_neighbours)];
for (int j = 0; n64_neighbours[j] != 0xffffffff; j++) {
host_neighbours[n++] = PD_BE32(n64_neighbours[j]);
dstpos += 4;
}
host_neighbours[n++] = 0xffffffff;
dstpos += 4;
}
return dstpos;
}
static u32 convertCover(u8 *dst, u32 dstpos, u8 *src, u32 srcpos, int num_covers)
{
struct coverdefinition *n64_covers = (struct coverdefinition *) &src[srcpos];
struct coverdefinition *host_covers = (struct coverdefinition *) &dst[dstpos];
for (int i = 0; i < num_covers; i++) {
host_covers[i].pos = PD_SWAPPED_VAL(n64_covers[i].pos);
host_covers[i].look = PD_SWAPPED_VAL(n64_covers[i].look);
host_covers[i].flags = PD_BE16(n64_covers[i].flags);
}
dstpos += num_covers * sizeof(struct coverdefinition);
return dstpos;
}
static u32 convertPadsFile(u8 *dst, u8 *src)
{
u32 dstpos = 0;
struct n64_header *n64_header = (struct n64_header *) src;
struct host_header *host_header = (struct host_header *) dst;
int num_pads = PD_BE32(n64_header->num_pads);
int num_covers = PD_BE32(n64_header->num_covers);
host_header->num_pads = (num_pads);
host_header->num_covers = (num_covers);
dstpos += sizeof(struct host_header);
// Pads
dstpos = convertPads(dst, dstpos, src, sizeof(struct n64_header), num_pads);
// Waypoints
host_header->ptr_waypoints = (dstpos);
dstpos = convertWayPoints(dst, dstpos, src, PD_BE32(n64_header->ptr_waypoints));
// Waygroups
host_header->ptr_waygroups = (dstpos);
dstpos = convertWayGroups(dst, dstpos, src, PD_BE32(n64_header->ptr_waygroups));
// Cover
host_header->ptr_cover = (dstpos);
dstpos = convertCover(dst, dstpos, src, PD_BE32(n64_header->ptr_cover), num_covers);
return dstpos;
}
u8* preprocessPadsFile(u8 *data, u32 size, u32 *outSize) {
u32 newSizeEstimated = romdataFileGetEstimatedSize(size, LOADTYPE_PADS);
u8* dst = sysMemZeroAlloc(newSizeEstimated);
u32 newSize = convertPadsFile(dst, data);
if (newSize > newSizeEstimated) {
sysFatalError("overflow when trying to preprocess a pads file, size %d newsize %d", size, newSize);
}
memcpy(data, dst, newSize);
sysMemFree(dst);
*outSize = newSize;
return 0;
}
File diff suppressed because it is too large. Load diff
+103
View File
@@ -0,0 +1,103 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "preprocess/common.h"
struct tile {
u8 type;
u8 numvertices;
u16 flags;
u16 floortype;
u8 xmin;
u8 ymin;
u8 zmin;
u8 xmax;
u8 ymax;
u8 zmax;
u16 floorcol;
};
static u32 convertTiles(u8 *dst, u8 *src, size_t srclen)
{
int num_rooms = PD_BE32(*(u32 *) src);
size_t src_ptr_table_len = (num_rooms + 1) * 4;
size_t dst_ptr_table_len = (num_rooms + 1) * sizeof(u32);
u32 *src_offsets = (u32 *) &src[4];
size_t data_len = srclen - src_ptr_table_len - 4;
*(u32 *) dst = (num_rooms);
u32 *dst_offsets = (u32 *) (dst + sizeof(u32));
u32 cur_dst_offset = dst_ptr_table_len + sizeof(u32);
u32 cur_src_offset = PD_BE32(src_offsets[0]);
u32 end_src_offset = PD_BE32(src_offsets[num_rooms]);
int room = 0;
while (1) {
// Check if this is a new room and write the pointer offset if so
while (room < (num_rooms + 1) && PD_BE32(src_offsets[room]) == cur_src_offset) {
dst_offsets[room] = (cur_dst_offset);
room++;
}
if (cur_src_offset >= end_src_offset) {
break;
}
// Write tile data
struct tile *n64tile = (struct tile *) &src[cur_src_offset];
struct tile hosttile;
hosttile.type = n64tile->type;
hosttile.numvertices = n64tile->numvertices;
hosttile.flags = PD_BE16(n64tile->flags);
hosttile.floortype = PD_BE16(n64tile->floortype);
hosttile.xmin = n64tile->xmin;
hosttile.ymin = n64tile->ymin;
hosttile.zmin = n64tile->zmin;
hosttile.xmax = n64tile->xmax;
hosttile.ymax = n64tile->ymax;
hosttile.zmax = n64tile->zmax;
hosttile.floorcol = PD_BE16(n64tile->floorcol);
memcpy(&dst[cur_dst_offset], &hosttile, sizeof(struct tile));
cur_dst_offset += sizeof(struct tile);
cur_src_offset += sizeof(struct tile);
// Write tile vertices
for (int i = 0; i < hosttile.numvertices; i++) {
*(s16 *) &dst[cur_dst_offset + 0] = PD_BE16(*(s16 *) &src[cur_src_offset + 0]);
*(s16 *) &dst[cur_dst_offset + 2] = PD_BE16(*(s16 *) &src[cur_src_offset + 2]);
*(s16 *) &dst[cur_dst_offset + 4] = PD_BE16(*(s16 *) &src[cur_src_offset + 4]);
cur_dst_offset += 6;
cur_src_offset += 6;
}
}
return ALIGN16(cur_dst_offset);
}
u8 *preprocessTilesFile(u8 *data, u32 size, u32 *outSize)
{
u32 newSizeEstimated = romdataFileGetEstimatedSize(size, LOADTYPE_TILES);
u8 *dst = sysMemZeroAlloc(newSizeEstimated);
u32 newSize = convertTiles(dst, data, size);
if (newSize > newSizeEstimated) {
sysFatalError("overflow when trying to preprocess a tiles file, size %d newsize %d", size, newSize);
}
memcpy(data, dst, newSize);
sysMemFree(dst);
*outSize = newSize;
return 0;
}
+208
View File
@@ -0,0 +1,208 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "preprocess/common.h"
#include "preprocess/gbi.h"
#if UINTPTR_MAX > 0xFFFFFFFFu
#define HOST_DWORDS_PER_CMD 2
#else
#define HOST_DWORDS_PER_CMD 1
#endif
struct vtx {
s16 x;
s16 y;
s16 z;
u8 flags;
u8 colour;
s16 s;
s16 t;
};
struct texaddr {
u32 src;
u32 dst;
};
static u32 gbiSegments[16];
static u32 srcVtxOffset;
static u32 dstVtxOffset;
static struct texaddr texAddrs[64];
static int numTexAddrs;
void gbiReset(void)
{
for (int i = 0; i < ARRAYCOUNT(gbiSegments); i++) {
gbiSegments[i] = 0;
}
srcVtxOffset = 0;
dstVtxOffset = 0;
numTexAddrs = 0;
}
void gbiSetSegment(int segment, u32 offset)
{
gbiSegments[segment] = offset & 0x00ffffff;
}
void gbiSetVtx(u32 src_offset, u32 dst_offset)
{
srcVtxOffset = src_offset & 0x00ffffff;
dstVtxOffset = dst_offset & 0x00ffffff;
}
void gbiAddTexAddr(u32 src_offset, u32 dst_offset)
{
texAddrs[numTexAddrs].src = src_offset & 0x00ffffff;
texAddrs[numTexAddrs++].dst = dst_offset & 0x00ffffff;
}
u32 gbiFindTexAddr(u32 src_offset)
{
for (int i = 0; i < numTexAddrs; i++) {
if (texAddrs[i].src == src_offset)
return texAddrs[i].dst;
}
return 0;
}
void gbiConvertVtx(u8 *dst, u32 offset, int count)
{
if (!offset) return;
struct vtx* vtxs = (struct vtx*)(dst + offset);
for (int i = 0; i < count; i++) {
struct vtx* vtx = &vtxs[i];
vtx->x = PD_BE16(vtx->x);
vtx->y = PD_BE16(vtx->y);
vtx->z = PD_BE16(vtx->z);
vtx->s = PD_BE16(vtx->s);
vtx->t = PD_BE16(vtx->t);
}
}
#define CMD_IS_VTX(cmd) ((cmd & 0xff00000000000000) == 0x0400000000000000)
#define CMD_IS_DL(cmd) ((cmd & 0xff00000000000000) == 0x0600000000000000)
#define CMD_IS_COL(cmd) ((cmd & 0xff00000000000000) == 0x0700000000000000)
#define CMD_IS_ENDDL(cmd) ((cmd & 0xff00000000000000) == 0xb800000000000000)
#define CMD_IS_MOVEWORD(cmd) ((cmd & 0xff00000000000000) == 0xbc00000000000000)
#define CMD_IS_MOVEMEM(cmd) ((cmd & 0xff00000000000000) == 0x0300000000000000)
#define CMD_IS_MTX(cmd) ((cmd & 0xff00000000000000) == 0x0100000000000000)
#define CMD_IS_SETTIMG(cmd) ((cmd & 0xff00000000000000) == 0xfd00000000000000)
#define CMD_IS_SETZIMG(cmd) ((cmd & 0xff00000000000000) == 0xfe00000000000000)
#define CMD_IS_SETCIMG(cmd) ((cmd & 0xff00000000000000) == 0xff00000000000000)
#define CMD_HAS_ADDR(cmd) CMD_IS_VTX(cmd) \
|| CMD_IS_COL(cmd) \
|| CMD_IS_MOVEWORD(cmd) \
|| CMD_IS_SETTIMG(cmd)
#define CMD_IS_SEGMENTED(cmd) ( CMD_IS_MOVEMEM(cmd) \
|| CMD_IS_MTX(cmd) \
|| CMD_IS_VTX(cmd) \
|| CMD_IS_COL(cmd) \
|| CMD_IS_DL(cmd) \
|| CMD_IS_SETTIMG(cmd) \
|| CMD_IS_SETCIMG(cmd) \
|| CMD_IS_SETZIMG(cmd))
/**
* Segment 5 is the start of the model file. The data in these files shifts
* depending on the pointer size, so this function adjusts the offset accordingly.
*/
static u64 gbiRewriteAddr(u64 cmd, u8 opcode)
{
u8 segment = (cmd & 0x0f000000) >> 24;
u32 offset = cmd & 0x00ffffff;
if (segment == 5) {
if (opcode == 0xfd) {
offset = gbiFindTexAddr(offset);
}
else {
if (offset < srcVtxOffset) {
sysFatalError("Tried to load data from offset 0x%x but segment starts at 0x%x\n", offset, srcVtxOffset);
}
offset = offset - srcVtxOffset + dstVtxOffset;
}
}
return (cmd & 0xffffffffff000000) | offset;
}
void gbiGdlRewriteAddrs(u8 *dst, u32 offset)
{
if (!offset) return;
u64 *cmds = (u64 *)(dst + (offset & 0x00ffffff));
if (!cmds) return;
u64 cmd;
do {
cmd = *cmds;
Gfx* gfxcmd = (Gfx *)cmds;
int idx = 0;
u8 opcode = (cmd >> 24) & 0xff;
#if HOST_DWORDS_PER_CMD == 2
idx = 1;
opcode = (cmd >> 24) & 0xff;
#endif
cmd = (u64)opcode << 56;
if (CMD_HAS_ADDR(cmd)) {
cmds[idx] = gbiRewriteAddr(cmds[idx], opcode);
}
if (CMD_IS_SEGMENTED(cmd)) {
gfxcmd->words.w1 |= 1;
}
cmds += HOST_DWORDS_PER_CMD;
} while (!CMD_IS_ENDDL(cmd));
}
u32 gbiConvertGdl(u8 *dst, u32 dstpos, u8 *src, u32 srcpos, int segment_cmds)
{
dstpos = ALIGN8(dstpos);
u64 *n64_cmd = (u64*)&src[srcpos];
u64 *host_cmd = (u64*)&dst[dstpos];
u64 cmd;
do {
cmd = PD_BE64(*n64_cmd);
#if HOST_DWORDS_PER_CMD == 2
host_cmd[0] = ((cmd & 0xffffffff00000000) >> 32);
host_cmd[1] = (cmd & 0xffffffff);
if (segment_cmds && CMD_IS_SEGMENTED(cmd)) {
host_cmd[1] |= 1;
}
#else
host_cmd[0] = (cmd >> 32) | ((cmd & 0xffffffff) << 32);
if (segment_cmds && CMD_IS_SEGMENTED(cmd)) {
Gfx* gfxcmd = (Gfx*)host_cmd;
gfxcmd->words.w1 |= 1;
}
#endif
dstpos += sizeof(*host_cmd) * HOST_DWORDS_PER_CMD;
host_cmd += HOST_DWORDS_PER_CMD;
n64_cmd++;
} while (!CMD_IS_ENDDL(cmd));
return dstpos;
}
+103
View File
@@ -0,0 +1,103 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <PR/ultratypes.h>
#include <PR/gbi.h>
#include "data.h"
#include "bss.h"
#include "game/setuputils.h"
#include "game/texdecompress.h"
#include "mod.h"
#include "preprocess/common.h"
u8 *preprocessAnimations(u8* data, u32 size, u32* outSize)
{
// set the anim table pointers as well
extern u8 *_animationsTableRomStart;
extern u8 *_animationsTableRomEnd;
// the animation table is at the end of the segment
u32 *animtbl = (void *)(data + size - 0x38a0);
_animationsTableRomStart = (u8 *)animtbl;
_animationsTableRomEnd = data + size;
PD_SWAP_VAL(*animtbl);
const u32 count = *animtbl++;
struct animtableentry *anim = (struct animtableentry *)animtbl;
for (u32 i = 0; i < count; ++i, ++anim) {
PD_SWAP_VAL(anim->numframes);
PD_SWAP_VAL(anim->bytesperframe);
PD_SWAP_VAL(anim->headerlen);
PD_SWAP_VAL(anim->data);
// if an external replacement exists, replace the table entry and mark the offset
if (modAnimationLoadDescriptor(i, anim) > 0) {
anim->data = 0xffffffff;
}
}
return NULL;
}
u8 *preprocessMpConfigs(u8* data, u32 size, u32* outSize)
{
const u32 count = size / sizeof(struct mpconfig);
struct mpconfig *cfg = (struct mpconfig *)data;
for (u32 i = 0; i < count; ++i, ++cfg) {
PD_SWAP_VAL(cfg->setup.options);
PD_SWAP_VAL(cfg->setup.teamscorelimit);
PD_SWAP_VAL(cfg->setup.chrslots);
// TODO: are these required or are they always 0?
PD_SWAP_VAL(cfg->setup.fileguid.deviceserial);
PD_SWAP_VAL(cfg->setup.fileguid.fileid);
// convert MPWEAPON_ to take classic weapons and JPN weapons into account
for (s32 j = 0; j < ARRAYCOUNT(cfg->setup.weapons); ++j) {
#if VERSION == VERSION_JPN_FINAL /* TODO: replace with runtime check */
if (cfg->setup.weapons[j] >= 0x24) {
// weapons after and including the shield need to be shifted (for classic weapons)
cfg->setup.weapons[j] += (MPWEAPON_SHIELD - MPWEAPON_PP9I);
}
if (cfg->setup.weapons[j] >= 0x22) {
// weapons after and including the cloaking device need to be shifted (for IR Scanner and Night Vision)
cfg->setup.weapons[j] += (MPWEAPON_CLOAKINGDEVICE - MPWEAPON_NIGHTVISION);
}
if (cfg->setup.weapons[j] >= 0x19) {
// weapons after the combat knife also need to be shifted up in JPN
cfg->setup.weapons[j]++;
}
#else
if (cfg->setup.weapons[j] >= 0x25) {
// weapons after and including the shield need to be shifted (for classic weapons)
cfg->setup.weapons[j] += (MPWEAPON_SHIELD - MPWEAPON_PP9I);
}
if (cfg->setup.weapons[j] >= 0x23) {
// weapons after and including the cloaking device need to be shifted (for IR Scanner and Night Vision)
cfg->setup.weapons[j] += (MPWEAPON_CLOAKINGDEVICE - MPWEAPON_NIGHTVISION);
}
#endif
}
}
return NULL;
}
u8 *preprocessTexturesList(u8* data, u32 size, u32* outSize)
{
struct texture *tex = (struct texture *)data;
const u32 count = size / sizeof(*tex);
for (u32 i = 0; i < count; ++i, ++tex) {
// TODO: it sure looks like none of the fields except soundsurfacetype, surfacetype and dataoffset are set
// just swap the last 3 bytes of the first word...
const u32 dofs = (u32)tex->dataoffset << 8;
tex->dataoffset = PD_BE32(dofs);
// ...and the surface types in the first byte
const u8 tmp = tex->soundsurfacetype;
tex->soundsurfacetype = tex->surfacetype;
tex->surfacetype = tmp;
}
return NULL;
}
+362
View File
@@ -0,0 +1,362 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libaudio.h"
#include "preprocess/common.h"
struct n64_adpcm_waveinfo {
u32 loop; // ptr to ALADPCMloop
u32 book; // ptr to ALADPCMBook
};
struct n64_raw_waveinfo {
u32 loop; // ptr to ALRawLoop
};
struct n64_wavetable {
u32 base;
s32 len;
u8 type;
u8 flags;
union {
struct n64_adpcm_waveinfo adpcmWave;
struct n64_raw_waveinfo rawWave;
} waveInfo;
};
struct n64_sound {
u32 envelope; // ptr to ALEnvelope
u32 keyMap; // ptr to ALKeyMap
u32 wavetable; // ptr to struct n64_wavetable
u8 samplePan;
u8 sampleVolume;
u8 flags;
};
struct n64_instrument {
u8 volume;
u8 pan;
u8 priority;
u8 flags;
u8 tremType;
u8 tremRate;
u8 tremDepth;
u8 tremDelay;
u8 vibType;
u8 vibRate;
u8 vibDepth;
u8 vibDelay;
s16 bendRange;
s16 soundCount;
u32 soundArray[1]; // ptr to struct n64_sound
};
struct n64_bank {
s16 instCount;
u8 flags;
u8 pad;
s32 sampleRate;
u32 percussion; // ptr to struct n64_instrument
u32 instArray[1]; // ptr to struct n64_instrument
};
struct n64_bankfile {
s16 revision;
s16 bankCount;
u32 bankArray[1]; // ptr to struct n64_bank
};
// only proceeds to convert the next item if it's not already converted
#define AL_NEXT_ITEM(field, func) { \
struct ptrmarker *marker = ptrFind(srcpos); \
if (marker == NULL) { \
field = (void *)(uintptr_t)(dstpos); \
ptrAdd(srcpos, (uintptr_t)(field)); \
dstpos = func(dst, dstpos, src, srcpos); \
} else { \
field = (void *)marker->ptr_host; } \
}
static u32 convertAudioEnvelope(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
{
ALEnvelope *n64_envelope = (ALEnvelope *) &src[srcpos];
ALEnvelope *host_envelope = (ALEnvelope *) &dst[dstpos];
dstpos += sizeof(ALEnvelope);
host_envelope->attackTime = PD_BE32(n64_envelope->attackTime);
host_envelope->decayTime = PD_BE32(n64_envelope->decayTime);
host_envelope->releaseTime = PD_BE32(n64_envelope->releaseTime);
host_envelope->attackVolume = n64_envelope->attackVolume;
host_envelope->decayVolume = n64_envelope->decayVolume;
return dstpos;
}
static u32 convertAudioKeyMap(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
{
ALKeyMap *n64_keymap = (ALKeyMap *) &src[srcpos];
ALKeyMap *host_keymap = (ALKeyMap *) &dst[dstpos];
dstpos += sizeof(ALKeyMap);
host_keymap->velocityMin = n64_keymap->velocityMin;
host_keymap->velocityMax = n64_keymap->velocityMax;
host_keymap->keyMin = n64_keymap->keyMin;
host_keymap->keyMax = n64_keymap->keyMax;
host_keymap->keyBase = n64_keymap->keyBase;
host_keymap->detune = n64_keymap->detune;
return dstpos;
}
static u32 convertAudioAdpcmLoop(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
{
ALADPCMloop *n64_loop = (ALADPCMloop *) &src[srcpos];
ALADPCMloop *host_loop = (ALADPCMloop *) &dst[dstpos];
dstpos += sizeof(ALADPCMloop);
host_loop->start = PD_BE32(n64_loop->start);
host_loop->end = PD_BE32(n64_loop->end);
host_loop->count = PD_BE32(n64_loop->count);
for (int i = 0; i < ARRAYCOUNT(host_loop->state); i++) {
host_loop->state[i] = PD_BE16(n64_loop->state[i]);
}
return dstpos;
}
static u32 convertAudioAdpcmBook(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
{
ALADPCMBook *n64_book = (ALADPCMBook *) &src[srcpos];
ALADPCMBook *host_book = (ALADPCMBook *) &dst[dstpos];
dstpos += sizeof(ALADPCMBook);
host_book->order = PD_BE32(n64_book->order);
host_book->npredictors = PD_BE32(n64_book->npredictors);
for (int i = 0; i < ARRAYCOUNT(host_book->book); i++) {
host_book->book[i] = PD_BE16(n64_book->book[i]);
}
return dstpos;
}
static u32 convertAudioRawLoop(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
{
ALRawLoop *n64_loop = (ALRawLoop *) &src[srcpos];
ALRawLoop *host_loop = (ALRawLoop *) &dst[dstpos];
dstpos += sizeof(ALRawLoop);
host_loop->start = PD_BE32(n64_loop->start);
host_loop->end = PD_BE32(n64_loop->end);
host_loop->count = PD_BE32(n64_loop->count);
return dstpos;
}
static u32 convertAudioWaveTable(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
{
struct n64_wavetable *n64_wavetable = (struct n64_wavetable *) &src[srcpos];
ALWaveTable *host_wavetable = (ALWaveTable *) &dst[dstpos];
dstpos += sizeof(ALWaveTable);
host_wavetable->base = (void *)(uintptr_t)PD_BE32(n64_wavetable->base);
host_wavetable->len = PD_BE32(n64_wavetable->len);
host_wavetable->type = n64_wavetable->type;
host_wavetable->flags = n64_wavetable->flags;
if (host_wavetable->type == AL_ADPCM_WAVE) {
if (n64_wavetable->waveInfo.adpcmWave.loop) {
srcpos = PD_BE32(n64_wavetable->waveInfo.adpcmWave.loop);
AL_NEXT_ITEM(host_wavetable->waveInfo.adpcmWave.loop, convertAudioAdpcmLoop);
} else {
host_wavetable->waveInfo.adpcmWave.loop = NULL;
}
if (n64_wavetable->waveInfo.adpcmWave.book) {
srcpos = PD_BE32(n64_wavetable->waveInfo.adpcmWave.book);
AL_NEXT_ITEM(host_wavetable->waveInfo.adpcmWave.book, convertAudioAdpcmBook);
} else {
host_wavetable->waveInfo.adpcmWave.book = NULL;
}
} else if (host_wavetable->type == AL_RAW16_WAVE) {
if (n64_wavetable->waveInfo.rawWave.loop) {
srcpos = PD_BE32(n64_wavetable->waveInfo.rawWave.loop);
AL_NEXT_ITEM(host_wavetable->waveInfo.rawWave.loop, convertAudioRawLoop);
} else {
host_wavetable->waveInfo.rawWave.loop = NULL;
}
}
return dstpos;
}
static u32 convertAudioSound(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
{
struct n64_sound *n64_sound = (struct n64_sound *) &src[srcpos];
ALSound *host_sound = (ALSound *) &dst[dstpos];
dstpos += sizeof(ALSound);
if (n64_sound->envelope) {
srcpos = PD_BE32(n64_sound->envelope);
AL_NEXT_ITEM(host_sound->envelope, convertAudioEnvelope);
} else {
host_sound->envelope = NULL;
}
if (n64_sound->keyMap) {
srcpos = PD_BE32(n64_sound->keyMap);
AL_NEXT_ITEM(host_sound->keyMap, convertAudioKeyMap);
} else {
host_sound->keyMap = NULL;
}
if (n64_sound->wavetable) {
srcpos = PD_BE32(n64_sound->wavetable);
AL_NEXT_ITEM(host_sound->wavetable, convertAudioWaveTable);
} else {
host_sound->wavetable = NULL;
}
host_sound->samplePan = n64_sound->samplePan;
host_sound->sampleVolume = n64_sound->sampleVolume;
host_sound->flags = n64_sound->flags;
return dstpos;
}
static u32 convertAudioInstrument(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
{
struct n64_instrument *n64_instrument = (struct n64_instrument *) &src[srcpos];
ALInstrument *host_instrument = (ALInstrument *) &dst[dstpos];
const s16 soundCount = PD_BE16(n64_instrument->soundCount);
host_instrument->volume = n64_instrument->volume;
host_instrument->pan = n64_instrument->pan;
host_instrument->priority = n64_instrument->priority;
host_instrument->flags = n64_instrument->flags;
host_instrument->tremType = n64_instrument->tremType;
host_instrument->tremRate = n64_instrument->tremRate;
host_instrument->tremDepth = n64_instrument->tremDepth;
host_instrument->tremDelay = n64_instrument->tremDelay;
host_instrument->vibType = n64_instrument->vibType;
host_instrument->vibRate = n64_instrument->vibRate;
host_instrument->vibDepth = n64_instrument->vibDepth;
host_instrument->vibDelay = n64_instrument->vibDelay;
host_instrument->bendRange = PD_BE16(n64_instrument->bendRange);
host_instrument->soundCount = (soundCount);
dstpos = dstpos + sizeof(ALInstrument) + sizeof(uintptr_t) * (soundCount - 1);
for (int i = 0; i < soundCount; i++) {
srcpos = PD_BE32(n64_instrument->soundArray[i]);
AL_NEXT_ITEM(host_instrument->soundArray[i], convertAudioSound);
}
return dstpos;
}
static u32 convertAudioBank(u8 *dst, u32 dstpos, u8 *src, u32 srcpos)
{
struct n64_bank *n64_bank = (struct n64_bank *) &src[srcpos];
ALBank *host_bank = (ALBank *) &dst[dstpos];
const s16 instCount = PD_BE16(n64_bank->instCount);
host_bank->instCount = (instCount);
host_bank->flags = n64_bank->flags;
host_bank->pad = n64_bank->pad;
host_bank->sampleRate = PD_BE32(n64_bank->sampleRate);
dstpos = dstpos + sizeof(ALBank) + sizeof(uintptr_t) * (instCount - 1);
if (n64_bank->percussion) {
srcpos = PD_BE32(n64_bank->percussion);
AL_NEXT_ITEM(host_bank->percussion, convertAudioInstrument);
} else {
host_bank->percussion = 0;
}
for (int i = 0; i < instCount; i++) {
srcpos = PD_BE32(n64_bank->instArray[i]);
AL_NEXT_ITEM(host_bank->instArray[i], convertAudioInstrument);
}
return dstpos;
}
static u32 convertAudioBankFile(u8 *dst, u8 *src)
{
struct n64_bankfile *n64_bankfile = (struct n64_bankfile *)src;
ALBankFile *host_bankfile = (ALBankFile *)dst;
const s16 bankCount = PD_BE16(n64_bankfile->bankCount);
host_bankfile->revision = PD_BE16(n64_bankfile->revision);
host_bankfile->bankCount = (bankCount);
u32 dstpos = sizeof(ALBankFile) + sizeof(uintptr_t) * (bankCount - 1);
for (int i = 0; i < bankCount; i++) {
host_bankfile->bankArray[i] = (void *)(uintptr_t)(dstpos);
u32 srcpos = PD_BE32(n64_bankfile->bankArray[i]);
dstpos = convertAudioBank(dst, dstpos, src, srcpos);
}
return dstpos;
}
u8 *preprocessALBankFile(u8 *src, u32 size, u32 *outSize)
{
ptrReset();
const u32 dstlen = size * 3; // this should overshoot any possible bank size, but * 2 also works for vanilla banks
u8 *dst = sysMemZeroAlloc(dstlen);
u32 reallen = convertAudioBankFile(dst, src);
if (reallen > dstlen || ALIGN16(reallen) > dstlen) {
sysFatalError("overflow when trying to preprocess an ALBankFile, size %u dstlen %u reallen %u", size, dstlen, reallen);
}
reallen = ALIGN16(reallen);
if (reallen < dstlen) {
dst = sysMemRealloc(dst, reallen);
}
*outSize = reallen;
return dst;
}
u8 *preprocessALCMidiHdr(u8 *data, u32 size, u32 *outSize)
{
ALCMidiHdr *hdr = (ALCMidiHdr *)data;
PD_SWAP_VAL(hdr->division);
for (s32 i = 0; i < ARRAYCOUNT(hdr->trackOffset); ++i) {
PD_SWAP_VAL(hdr->trackOffset[i]);
}
return NULL;
}
u8 *preprocessSequences(u8* data, u32 size, u32 *outSize)
{
struct seqtable *seq = (struct seqtable *)data;
PD_SWAP_VAL(seq->count);
for (s16 i = 0; i < seq->count; ++i) {
PD_SWAP_VAL(seq->entries[i].binlen);
PD_SWAP_VAL(seq->entries[i].ziplen);
PD_SWAP_VAL(seq->entries[i].romaddr);
}
return NULL;
}
+104
View File
@@ -0,0 +1,104 @@
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "preprocess/common.h"
struct n64_fontchar {
u8 index;
s8 baseline;
u8 height;
u8 width;
s32 kerningindex;
u32 pixeldata;
};
struct n64_fontcharjpn {
u16 index;
s8 baseline;
u8 height;
u8 width;
s16 kerningindex;
u32 pixeldata;
};
u8 *preprocessFont(u8 *src, u32 srclen, u32 *outSize)
{
int num_chars = 94;
#if VERSION == VERSION_PAL_FINAL
// PAL has more characters in these fonts
extern u8* _fonthandelgothicsmSegmentRomStart;
extern u8* _fonthandelgothicxsSegmentRomStart;
extern u8* _fonthandelgothicmdSegmentRomStart;
if (src == _fonthandelgothicsmSegmentRomStart
|| src == _fonthandelgothicxsSegmentRomStart
|| src == _fonthandelgothicmdSegmentRomStart) {
num_chars = 135;
}
#endif
size_t dstlen = srclen - (num_chars * sizeof(struct n64_fontchar)) + (num_chars * sizeof(struct fontchar)) + 0x20;
u8* dst = sysMemZeroAlloc(dstlen);
// Kerning table
s32 *src_kerning_table = (s32 *)src;
s32 *dst_kerning_table = (s32 *)dst;
for (int i = 0; i < 13 * 13; i++) {
dst_kerning_table[i] = PD_BE32(src_kerning_table[i]);
}
u32 src_offset = PD_ALIGN(13 * 13 * 4, sizeof(u32));
u32 dst_offset = PD_ALIGN(13 * 13 * 4, sizeof(uintptr_t));
// Character table
#if VERSION == VERSION_JPN_FINAL
struct n64_fontcharjpn *src_char_table = (struct n64_fontcharjpn *) &src[src_offset];
struct fontchar *dst_char_table = (struct fontchar *) &dst[dst_offset];
u32 diff = (dst_offset + num_chars * sizeof(struct fontchar)) - (src_offset + num_chars * sizeof(struct n64_fontcharjpn));
for (int i = 0; i < num_chars; i++) {
dst_char_table[i].index = PD_BE16(src_char_table[i].index);
dst_char_table[i].baseline = src_char_table[i].baseline;
dst_char_table[i].height = src_char_table[i].height;
dst_char_table[i].width = src_char_table[i].width;
dst_char_table[i].kerningindex = PD_BE16(src_char_table[i].kerningindex);
dst_char_table[i].pixeldata = (void *)(uintptr_t)(src_char_table[i].pixeldata ? PD_BE32(src_char_table[i].pixeldata) + diff : 0);
}
src_offset += num_chars * sizeof(struct n64_fontcharjpn);
dst_offset += num_chars * sizeof(struct fontchar);
#else
struct n64_fontchar *src_char_table = (struct n64_fontchar *) &src[src_offset];
struct fontchar *dst_char_table = (struct fontchar *) &dst[dst_offset];
u32 diff = (dst_offset + num_chars * sizeof(struct fontchar)) - (src_offset + num_chars * sizeof(struct n64_fontchar));
for (int i = 0; i < num_chars; i++) {
dst_char_table[i].index = src_char_table[i].index;
dst_char_table[i].baseline = src_char_table[i].baseline;
dst_char_table[i].height = src_char_table[i].height;
dst_char_table[i].width = src_char_table[i].width;
dst_char_table[i].kerningindex = PD_BE32(src_char_table[i].kerningindex);
dst_char_table[i].pixeldata = (void *)(uintptr_t)(src_char_table[i].pixeldata ? PD_BE32(src_char_table[i].pixeldata) + diff : 0);
}
src_offset += num_chars * sizeof(struct n64_fontchar);
dst_offset += num_chars * sizeof(struct fontchar);
#endif
// Pixel data
u32 len = srclen - src_offset;
memcpy(&dst[dst_offset], &src[src_offset], len);
if (outSize) *outSize = ALIGN16(dst_offset + len);
return dst;
}
u8 *preprocessJpnFont(u8* data, u32 size, u32* outSize)
{
// ???
return NULL;
}
+98 -18
View File
@@ -4,7 +4,6 @@
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <PR/ultratypes.h> #include <PR/ultratypes.h>
#include <PR/ultratypes.h>
#include "lib/rzip.h" #include "lib/rzip.h"
#include "romdata.h" #include "romdata.h"
#include "fs.h" #include "fs.h"
@@ -51,12 +50,15 @@
#define ROMDATA_MAX_FILES 2048 #define ROMDATA_MAX_FILES 2048
#define GBC_ROM_NAME "pd.gbc"
#define GBC_ROM_SIZE 4194304
u8 *g_RomFile; u8 *g_RomFile;
u32 g_RomFileSize; u32 g_RomFileSize;
const char *g_RomName = ROMDATA_ROM_NAME;
static u8 *romDataSeg; static u8 *romDataSeg;
static u32 romDataSegSize; static u32 romDataSegSize;
static const char *romName = ROMDATA_ROM_NAME;
enum loadsource { enum loadsource {
SRC_UNLOADED = 0, SRC_UNLOADED = 0,
@@ -188,12 +190,12 @@ static inline void romdataWrongRomError(const char *fmt, ...)
static inline void romdataLoadRom(void) static inline void romdataLoadRom(void)
{ {
sysLogPrintf(LOG_NOTE, "ROM file: %s", g_RomName); sysLogPrintf(LOG_NOTE, "ROM file: %s", romName);
g_RomFile = fsFileLoad(g_RomName, &g_RomFileSize); g_RomFile = fsFileLoad(romName, &g_RomFileSize);
if (!g_RomFile) { if (!g_RomFile) {
sysFatalError("Could not open ROM file %s.\nEnsure that it is in the %s directory.", g_RomName, fsFullPath("")); sysFatalError("Could not open ROM file %s.\nEnsure that it is in the %s directory.", romName, fsFullPath(""));
} }
// zips are not guaranteed to start with PK, but might as well at least try // zips are not guaranteed to start with PK, but might as well at least try
@@ -236,6 +238,17 @@ static inline void romdataLoadRom(void)
romDataSegSize = dataSegLen; romDataSegSize = dataSegLen;
} }
static inline void romdataUpdateSegStartEnd(struct romfile* seg)
{
if (seg->segstart) {
*seg->segstart = seg->data;
}
if (seg->segend) {
*seg->segend = seg->data + seg->size;
}
}
static inline void romdataInitSegment(struct romfile *seg) static inline void romdataInitSegment(struct romfile *seg)
{ {
if (!seg->data) { if (!seg->data) {
@@ -251,7 +264,7 @@ static inline void romdataInitSegment(struct romfile *seg)
seg->size = seg[1].data - seg->data; seg->size = seg[1].data - seg->data;
} else { } else {
// this is the last segment, calculate based on rom size // this is the last segment, calculate based on rom size
seg->size = (u8 *)g_RomFileSize - seg->data; seg->size = (uintptr_t)g_RomFileSize - (uintptr_t)seg->data;
} }
} }
@@ -269,7 +282,7 @@ static inline void romdataInitSegment(struct romfile *seg)
if (g_RomFile) { if (g_RomFile) {
newData = g_RomFile + (uintptr_t)seg->data; newData = g_RomFile + (uintptr_t)seg->data;
seg->source = SRC_ROM; seg->source = SRC_ROM;
sysLogPrintf(LOG_NOTE, "loading segment %s from ROM (offset %08x pointer %p)", seg->name, (u32)seg->data, newData); sysLogPrintf(LOG_NOTE, "loading segment %s from ROM (offset %08x pointer %p)", seg->name, (uintptr_t)seg->data, newData);
} else { } else {
sysFatalError("No ROM or external file for segment:\n%s", seg->name); sysFatalError("No ROM or external file for segment:\n%s", seg->name);
} }
@@ -281,17 +294,19 @@ static inline void romdataInitSegment(struct romfile *seg)
seg->data = newData; seg->data = newData;
if (seg->segstart) { romdataUpdateSegStartEnd(seg);
*seg->segstart = seg->data;
}
if (seg->segend) {
*seg->segend = seg->data + seg->size;
}
// call the post load function if any // call the post load function if any
if (seg->preprocess && !seg->preprocessed) { if (seg->preprocess && !seg->preprocessed) {
seg->preprocess(seg->data, seg->size); newData = seg->preprocess(seg->data, seg->size, &seg->size);
if (newData) {
if (seg->source == SRC_EXTERNAL)
sysMemFree(seg->data);
seg->data = newData;
romdataUpdateSegStartEnd(seg);
}
seg->preprocessed = 1; seg->preprocessed = 1;
} }
} }
@@ -368,7 +383,7 @@ s32 romdataInit(void)
{ {
const char *altRomName = sysArgGetString("--rom-file"); const char *altRomName = sysArgGetString("--rom-file");
if (altRomName) { if (altRomName) {
g_RomName = altRomName; romName = altRomName;
} }
romdataLoadRom(); romdataLoadRom();
@@ -386,6 +401,53 @@ s32 romdataInit(void)
return 0; return 0;
} }
static inline bool romdataCheckGbcRomContents(const u8 *gbcRomFile, const u32 gbcRomSize)
{
if (gbcRomSize != GBC_ROM_SIZE) {
return false;
}
// ROM title
if (memcmp(gbcRomFile + 0x134, "PerfDark VPDE", 15) != 0) {
return false;
}
// Licensee code
if (memcmp(gbcRomFile + 0x144, "4Y", 2) != 0) {
return false;
}
// Header and global checksums
if (gbcRomFile[0x14D] != 0xA1 || gbcRomFile[0x14E] != 0xAD || gbcRomFile[0x14F] != 0x0F) {
return false;
}
return true;
}
s32 romdataCheckGbcRom(void)
{
if (fsFileSize(GBC_ROM_NAME) < 0) {
// bail early if it doesn't exist to avoid generating error messages
return false;
}
u32 gbcRomSize = 0;
u8 *gbcRomFile = fsFileLoad(GBC_ROM_NAME, &gbcRomSize);
if (!gbcRomFile) {
return false;
}
const bool ret = romdataCheckGbcRomContents(gbcRomFile, gbcRomSize);
sysMemFree(gbcRomFile);
if (ret) {
sysLogPrintf(LOG_NOTE, "romdataCheckGbcRom: valid GBC rom found");
}
return ret;
}
s32 romdataFileGetSize(s32 fileNum) s32 romdataFileGetSize(s32 fileNum)
{ {
if (fileNum < 1 || fileNum >= ROMDATA_MAX_FILES) { if (fileNum < 1 || fileNum >= ROMDATA_MAX_FILES) {
@@ -447,7 +509,7 @@ u8 *romdataFileLoad(s32 fileNum, u32 *outSize)
return out; return out;
} }
void romdataFilePreprocess(s32 fileNum, s32 loadType, u8 *data, u32 size) void romdataFilePreprocess(s32 fileNum, s32 loadType, u8 *data, u32 size, u32 *outSize)
{ {
if (fileNum < 1 || fileNum >= ROMDATA_MAX_FILES) { if (fileNum < 1 || fileNum >= ROMDATA_MAX_FILES) {
sysLogPrintf(LOG_ERROR, "romdataFilePreprocess: invalid file num %d", fileNum); sysLogPrintf(LOG_ERROR, "romdataFilePreprocess: invalid file num %d", fileNum);
@@ -465,7 +527,7 @@ void romdataFilePreprocess(s32 fileNum, s32 loadType, u8 *data, u32 size)
} }
} }
// then preprocess // then preprocess
filePreprocFuncs[loadType](data, size); filePreprocFuncs[loadType](data, size, outSize);
// fileSlots[fileNum].preprocessed = 1; // fileSlots[fileNum].preprocessed = 1;
} }
} }
@@ -524,3 +586,21 @@ u32 romdataSegGetSize(const char *segName)
{ {
return romdataGetSeg(segName)->size; return romdataGetSeg(segName)->size;
} }
u32 romdataFileGetEstimatedSize(const u32 size, const u32 loadtype)
{
#ifdef PLATFORM_64BIT
switch (loadtype) {
case LOADTYPE_BG: return (u32)(size * 1.1f);
case LOADTYPE_TILES: return (u32)(size * 1.1f);
case LOADTYPE_LANG: return (u32)(size * 1.3f);
case LOADTYPE_SETUP: return (u32)(size * 1.5f);
case LOADTYPE_PADS: return (u32)(size * 1.7f);
case LOADTYPE_MODEL: return (u32)(size * 1.7f);
case LOADTYPE_GUN: return (u32)(size * 1.7f);
default:
sysLogPrintf(LOG_WARNING, "romdataFileGetEstimatedSize: wrong loadtype %d", loadtype);
}
#endif
return size;
}
+8 -15
View File
@@ -12,7 +12,6 @@
#include <SDL.h> #include <SDL.h>
#include <PR/ultratypes.h> #include <PR/ultratypes.h>
#include "platform.h" #include "platform.h"
#include "console.h"
#include "system.h" #include "system.h"
#ifdef PLATFORM_WIN32 #ifdef PLATFORM_WIN32
@@ -41,7 +40,7 @@ __attribute__((dllexport)) u32 AmdPowerXpressRequestHighPerformance = 1;
// but if it doesn't we'll have to use __builtin_ia32_pause() or something // but if it doesn't we'll have to use __builtin_ia32_pause() or something
#include <immintrin.h> #include <immintrin.h>
#define DO_YIELD() _mm_pause() #define DO_YIELD() _mm_pause()
#elif defined(PLATFORM_ARM) #elif defined(PLATFORM_ARM) && (defined(PLATFORM_64BIT) || PLATFORM_ARM == 7 || PLATFORM_ARM == 8)
// same as YieldProcessor() on ARM Windows // same as YieldProcessor() on ARM Windows
#define DO_YIELD() __asm__ volatile("dmb ishst\n\tyield":::"memory") #define DO_YIELD() __asm__ volatile("dmb ishst\n\tyield":::"memory")
#else #else
@@ -158,12 +157,6 @@ u64 sysGetMicroseconds(void)
return ((u64)tv.tv_sec * USEC_IN_SEC + (u64)tv.tv_usec) - startTick; return ((u64)tv.tv_sec * USEC_IN_SEC + (u64)tv.tv_usec) - startTick;
} }
float sysGetSeconds(void)
{
u64 t = sysGetMicroseconds();
return (f32)t / 1000000.f;
}
s32 sysLogIsOpen(void) s32 sysLogIsOpen(void)
{ {
return (logPath[0] != '\0'); return (logPath[0] != '\0');
@@ -190,13 +183,8 @@ void sysLogPrintf(s32 level, const char *fmt, ...)
} }
} }
FILE *fout = ((level & 0x0f) == LOG_NOTE) ? stdout : stderr; FILE *fout = (level == LOG_NOTE) ? stdout : stderr;
fprintf(fout, "%s%s\n", prefix[level & 0x0f], logmsg); fprintf(fout, "%s%s\n", prefix[level], logmsg);
fflush(fout);
if ((level & LOGFLAG_NOCON) == 0) {
conPrintLn((level & LOGFLAG_SHOWMSG) != 0, logmsg);
}
} }
void sysFatalError(const char *fmt, ...) void sysFatalError(const char *fmt, ...)
@@ -300,6 +288,11 @@ void *sysMemZeroAlloc(const u32 size)
return calloc(1, size); return calloc(1, size);
} }
void *sysMemRealloc(void *ptr, const u32 newSize)
{
return realloc(ptr, newSize);
}
void sysMemFree(void *ptr) void sysMemFree(void *ptr)
{ {
free(ptr); free(ptr);
+318 -30
View File
@@ -6,36 +6,68 @@
#include <PR/gbi.h> #include <PR/gbi.h>
#include "platform.h" #include "platform.h"
#include "config.h" #include "config.h"
#include "system.h"
#include "video.h" #include "video.h"
#include "../fast3d/gfx_api.h" #include "../fast3d/gfx_api.h"
#include "../fast3d/gfx_sdl.h" #include "../fast3d/gfx_sdl.h"
#include "../fast3d/gfx_opengl.h" #include "../fast3d/gfx_opengl.h"
#ifdef PLATFORM_NSWITCH
#define DEFAULT_VID_WIDTH 1280
#define DEFAULT_VID_HEIGHT 720
#define DEFAULT_VID_FULLSCREEN true
#define DEFAULT_VID_FULLSCREEN_EXCLUSIVE true
#else
#define DEFAULT_VID_WIDTH 640
#define DEFAULT_VID_HEIGHT 480
#define DEFAULT_VID_FULLSCREEN false
#define DEFAULT_VID_FULLSCREEN_EXCLUSIVE false
#endif
static struct GfxWindowManagerAPI *wmAPI; static struct GfxWindowManagerAPI *wmAPI;
static struct GfxRenderingAPI *renderingAPI; static struct GfxRenderingAPI *renderingAPI;
static bool initDone = false; static bool initDone = false;
static s32 vidWidth = 640; static s32 vidWidth = DEFAULT_VID_WIDTH;
static s32 vidHeight = 480; static s32 vidHeight = DEFAULT_VID_HEIGHT;
static s32 vidFramebuffers = true; static s32 vidFramebuffers = true;
static s32 vidFullscreen = false; static s32 vidFullscreen = DEFAULT_VID_FULLSCREEN;
static s32 vidFullscreenExclusive = false; static s32 vidFullscreenExclusive = DEFAULT_VID_FULLSCREEN_EXCLUSIVE;
static s32 vidMaximize = false; static s32 vidMaximize = false;
static s32 vidCenter = false;
static s32 vidAllowHiDpi = false; static s32 vidAllowHiDpi = false;
static s32 vidVsync = 1; static s32 vidVsync = 1;
static s32 vidMSAA = 1; static s32 vidMSAA = 1;
static s32 vidFramerateLimit = 0; static s32 vidFramerateLimit = 0;
static s32 vidDisplayFPS = 0;
static f32 vidDisplayFPSInterval = 1.f;
static f32 vidAvgFPS = 0;
static s32 vidNumModes = 1;
static displaymode vidModeDefault;
static displaymode *vidModes = &vidModeDefault;
static f32 vidGlareBrightness = 1.f;
static f32 vidOverexposureScale = 1.f;
static s32 texFilter = FILTER_LINEAR; static s32 texFilter = FILTER_LINEAR;
static s32 texFilter2D = true; static s32 texFilter2D = true;
static s32 texDetail = true; static s32 texDetail = false;
static s32 texMipmapFilter = MIPMAP_LINEAR;
static u32 texAnisotropicFilter = 4;
static u32 dlcount = 0; static u32 dlcount = 0;
static u32 frames = 0; static u32 frames = 0;
static u32 framesPerSec = 0; static f64 startTime, endTime;
static f64 startTime, endTime, fpsTime; static f64 accumDelta = 0.0;
static f64 fpsTime = 0.0;
static s32 fpsNumFrames = 0;
static s32 videoInitDisplayModes(void);
void optionsMenuInit();
s32 videoInit(void) s32 videoInit(void)
{ {
@@ -61,23 +93,21 @@ s32 videoInit(void)
.fullscreen = vidFullscreen, .fullscreen = vidFullscreen,
.fullscreen_is_exclusive = vidFullscreenExclusive, .fullscreen_is_exclusive = vidFullscreenExclusive,
.maximized = vidMaximize, .maximized = vidMaximize,
.centered = vidCenter,
.allow_hidpi = vidAllowHiDpi .allow_hidpi = vidAllowHiDpi
} }
}; };
gfx_init(&set); gfx_init(&set);
if (!wmAPI->set_swap_interval(vidVsync)) { videoInitDisplayModes();
vidVsync = 0; videoSetVsync(vidVsync);
} videoSetFramerateLimit(vidFramerateLimit);
if (vidVsync == 0 && vidFramerateLimit == 0) { gfx_set_texture_filter((enum FilteringMode)texFilter);
// cap FPS if there's no vsync to prevent the game from exploding gfx_set_mipmap_filter((enum MipmapFilteringMode)texMipmapFilter);
vidFramerateLimit = VIDEO_MAX_FPS; videoSetAnisotropicFilter(texAnisotropicFilter);
} optionsMenuInit();
wmAPI->set_target_fps(vidFramerateLimit); // disabled because vsync is on
renderingAPI->set_texture_filter((enum FilteringMode)texFilter);
initDone = true; initDone = true;
return 0; return 0;
@@ -89,6 +119,10 @@ void videoStartFrame(void)
startTime = wmAPI->get_time(); startTime = wmAPI->get_time();
gfx_start_frame(); gfx_start_frame();
} }
// Synchronize with their backend counterparts.
vidFullscreen = videoGetFullscreen();
vidMaximize = videoGetMaximizeWindow();
} }
void videoSubmitCommands(Gfx *cmds) void videoSubmitCommands(Gfx *cmds)
@@ -107,20 +141,29 @@ void videoEndFrame(void)
gfx_end_frame(); gfx_end_frame();
endTime = wmAPI->get_time();
++frames; ++frames;
++framesPerSec; ++fpsNumFrames;
const f64 flipTime = wmAPI->get_time();
accumDelta += flipTime - endTime;
endTime = flipTime;
if (endTime >= fpsTime) { if (endTime >= fpsTime) {
char tmp[128]; char tmp[128];
snprintf(tmp, sizeof(tmp), "fps %3u frt %lf frm %u", framesPerSec, endTime - startTime, frames); vidAvgFPS = fpsNumFrames ? ((f64)fpsNumFrames / accumDelta) : 0.f;
wmAPI->set_window_title(tmp); fpsNumFrames = 0;
framesPerSec = 0; accumDelta = 0.0;
fpsTime = endTime + 1.0; fpsTime = endTime + vidDisplayFPSInterval;
} }
} }
f32 videoGetAverageFPS(void)
{
return vidAvgFPS;
}
void videoClearScreen(void) void videoClearScreen(void)
{ {
videoStartFrame(); videoStartFrame();
@@ -165,19 +208,159 @@ s32 videoGetHeight(void)
s32 videoGetFullscreen(void) s32 videoGetFullscreen(void)
{ {
vidFullscreen = wmAPI->get_fullscreen_state();
return vidFullscreen; return vidFullscreen;
} }
s32 videoGetFullscreenMode(void)
{
vidFullscreenExclusive = wmAPI->get_fullscreen_flag_mode();
return vidFullscreenExclusive;
}
s32 videoGetMaximizeWindow(void) s32 videoGetMaximizeWindow(void)
{ {
vidMaximize = wmAPI->get_maximized_state();
return vidMaximize; return vidMaximize;
} }
s32 videoGetCenterWindow(void)
{
return vidCenter;
}
f32 videoGetAspect(void) f32 videoGetAspect(void)
{ {
return gfx_current_dimensions.aspect_ratio; return gfx_current_dimensions.aspect_ratio;
} }
s32 videoGetDisplayModeIndex(void)
{
for (s32 i = 1; i < vidNumModes; ++i) {
if (vidModes[i].width == gfx_current_dimensions.width &&
vidModes[i].height == gfx_current_dimensions.height) {
return i;
}
}
// Current dimensions don't match any known mode, so return index 0, "Custom".
return 0;
}
s32 videoGetMSAA(void)
{
vidMSAA = (s32)gfx_msaa_level;
return vidMSAA;
}
s32 videoGetVsync(void)
{
vidVsync = wmAPI->get_swap_interval();
return vidVsync;
}
s32 videoGetFramerateLimit(void)
{
vidFramerateLimit = wmAPI->get_target_fps();
return vidFramerateLimit;
}
s32 videoGetDisplayFPS(void)
{
return vidDisplayFPS;
}
static s32 videoInitDisplayModes(void)
{
if (!wmAPI->get_current_display_mode(&vidModeDefault.width, &vidModeDefault.height)) {
vidModeDefault.width = 640;
vidModeDefault.height = 480;
return false;
}
const s32 numBaseModes = wmAPI->get_num_display_modes();
if (!numBaseModes) {
return false;
}
const s32 numCustomModes = 1;
displaymode *modeList = sysMemZeroAlloc((numBaseModes + numCustomModes) * sizeof(displaymode));
if (!modeList) {
return false;
}
modeList[0].width = 0;
modeList[0].height = 0;
s32 numModes = 1;
s32 w = -1, h = w, neww = w, newh = w;
// SDL modes are guaranteed to be sorted high to low
for (s32 i = 0; i < numBaseModes; ++i) {
wmAPI->get_display_mode(i, &neww, &newh);
if (neww != w || newh != h) {
w = neww;
h = newh;
modeList[numModes].width = w;
modeList[numModes].height = h;
++numModes;
}
}
modeList = sysMemRealloc(modeList, numModes * sizeof(displaymode));
if (!modeList) {
return false;
}
vidModes = modeList;
vidNumModes = numModes;
return true;
}
s32 videoGetDisplayMode(displaymode *out, const s32 index)
{
if (index >= 0 && index < vidNumModes) {
*out = vidModes[index];
return true;
}
return false;
}
s32 videoGetNumDisplayModes(void)
{
return vidNumModes;
}
void videoSetDisplayMode(const s32 index)
{
const displaymode dm = vidModes[index];
if (index == 0) {
// "Custom" video mode.
return;
}
vidWidth = dm.width;
vidHeight = dm.height;
s32 posX = 100;
s32 posY = 100;
if (vidCenter) {
wmAPI->get_centered_positions(vidWidth, vidHeight, &posX, &posY);
}
if (vidFullscreen) {
wmAPI->set_closest_resolution(vidWidth, vidHeight, vidCenter);
} else {
if (vidMaximize) {
videoSetMaximizeWindow(false);
} else {
wmAPI->set_dimensions(vidWidth, vidHeight, posX, posY);
}
}
}
s32 videoGetTextureFilter2D(void) s32 videoGetTextureFilter2D(void)
{ {
return texFilter2D; return texFilter2D;
@@ -188,11 +371,31 @@ u32 videoGetTextureFilter(void)
return texFilter; return texFilter;
} }
u32 videoGetAnisotropicFilter()
{
return texAnisotropicFilter;
}
u32 videoGetMaxAnisotropyLevel()
{
return renderingAPI->get_max_anisotropy_level();
}
s32 videoGetDetailTextures(void) s32 videoGetDetailTextures(void)
{ {
return texDetail; return texDetail;
} }
f32 videoGetGlareBrightness(void)
{
return vidGlareBrightness;
}
f32 videoGetOverexposureScale(void)
{
return vidOverexposureScale;
}
void videoSetWindowOffset(s32 x, s32 y) void videoSetWindowOffset(s32 x, s32 y)
{ {
gfx_current_game_window_viewport.x = x; gfx_current_game_window_viewport.x = x;
@@ -203,7 +406,22 @@ void videoSetFullscreen(s32 fs)
{ {
if (fs != vidFullscreen) { if (fs != vidFullscreen) {
vidFullscreen = !!fs; vidFullscreen = !!fs;
wmAPI->set_closest_resolution(vidWidth, vidHeight, vidCenter);
wmAPI->set_fullscreen(vidFullscreen); wmAPI->set_fullscreen(vidFullscreen);
if (!vidFullscreen && vidMaximize) {
wmAPI->set_maximize(false);
wmAPI->set_maximize(true);
}
}
}
void videoSetFullscreenMode(s32 mode)
{
vidFullscreenExclusive = mode;
wmAPI->set_fullscreen_flag(mode);
if (vidFullscreen) {
wmAPI->set_fullscreen(false);
wmAPI->set_fullscreen(true);
} }
} }
@@ -212,14 +430,32 @@ void videoSetMaximizeWindow(s32 fs)
if (fs != vidMaximize) { if (fs != vidMaximize) {
vidMaximize = !!fs; vidMaximize = !!fs;
wmAPI->set_maximize(vidMaximize); wmAPI->set_maximize(vidMaximize);
if (vidCenter && !vidMaximize) {
s32 posX = 0;
s32 posY = 0;
wmAPI->get_centered_positions(vidWidth, vidHeight, &posX, &posY);
wmAPI->set_dimensions(vidWidth, vidHeight, posX, posY);
}
}
}
void videoSetCenterWindow(s32 center)
{
vidCenter = center;
if (vidCenter && !vidMaximize) {
s32 posX = 0;
s32 posY = 0;
wmAPI->get_centered_positions(vidWidth, vidHeight, &posX, &posY);
wmAPI->set_dimensions(vidWidth, vidHeight, posX, posY);
} }
} }
void videoSetTextureFilter(u32 filter) void videoSetTextureFilter(u32 filter)
{ {
if (filter > FILTER_THREE_POINT) filter = FILTER_THREE_POINT; if (filter > FILTER_THREE_POINT) filter = FILTER_THREE_POINT;
if (texFilter == filter) return;
texFilter = filter; texFilter = filter;
renderingAPI->set_texture_filter((enum FilteringMode)filter); gfx_set_texture_filter((enum FilteringMode)filter);
} }
void videoSetTextureFilter2D(s32 filter) void videoSetTextureFilter2D(s32 filter)
@@ -227,18 +463,26 @@ void videoSetTextureFilter2D(s32 filter)
texFilter2D = !!filter; texFilter2D = !!filter;
} }
void videoSetAnisotropicFilter(u32 level)
{
texAnisotropicFilter = level;
renderingAPI->set_anisotropy_level(level);
}
void videoSetDetailTextures(s32 detail) void videoSetDetailTextures(s32 detail)
{ {
texDetail = !!detail; texDetail = !!detail;
gfx_detail_textures_enabled = (bool)texDetail; gfx_detail_textures_enabled = (bool)texDetail;
} }
void videoCapFramerate(s32 limit) void videoSetGlareBrightness(f32 bright)
{ {
if (vidFramerateLimit > 0 && vidFramerateLimit < limit) { vidGlareBrightness = (bright < 0.f ? 0.f : (bright > 1.f ? 1.f : bright));
limit = vidFramerateLimit; }
}
wmAPI->set_target_fps(limit ? limit : vidFramerateLimit); void videoSetOverexposureScale(f32 scale)
{
vidOverexposureScale = (scale < 0.f ? 0.f : (scale > 1.f ? 1.f : scale));
} }
s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize) s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize)
@@ -246,6 +490,33 @@ s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize)
return gfx_create_framebuffer(w, h, upscale, autoresize); return gfx_create_framebuffer(w, h, upscale, autoresize);
} }
void videoSetMSAA(const s32 msaa)
{
vidMSAA = msaa;
gfx_msaa_level = (u32)vidMSAA;
}
void videoSetVsync(const s32 vsync)
{
vidVsync = wmAPI->set_swap_interval(vsync) ? vsync : 0;
if (vidVsync == 0 && vidFramerateLimit == 0) {
// cap FPS if there's no vsync to prevent the game from exploding
videoSetFramerateLimit(VIDEO_MAX_FPS);
}
}
void videoSetFramerateLimit(const s32 limit)
{
vidFramerateLimit = (vidVsync == 0 && limit == 0) ? VIDEO_MAX_FPS : limit;
wmAPI->set_target_fps(vidFramerateLimit);
}
void videoSetDisplayFPS(const s32 displayfps)
{
vidDisplayFPS = displayfps;
}
void videoSetFramebuffer(s32 target) void videoSetFramebuffer(s32 target)
{ {
return gfx_set_framebuffer(target, 1.f); return gfx_set_framebuffer(target, 1.f);
@@ -282,6 +553,16 @@ void videoFreeCachedTexture(const void *texptr)
gfx_texture_cache_delete(texptr); gfx_texture_cache_delete(texptr);
} }
void videoFreeCachedTextures(const void *start, const void *end)
{
gfx_texture_cache_delete_range(start, end);
}
void videoShutdown(void)
{
free(vidModes);
}
PD_CONSTRUCTOR static void videoConfigInit(void) PD_CONSTRUCTOR static void videoConfigInit(void)
{ {
configRegisterInt("Video.DefaultFullscreen", &vidFullscreen, 0, 1); configRegisterInt("Video.DefaultFullscreen", &vidFullscreen, 0, 1);
@@ -289,12 +570,19 @@ PD_CONSTRUCTOR static void videoConfigInit(void)
configRegisterInt("Video.DefaultWidth", &vidWidth, 0, 32767); configRegisterInt("Video.DefaultWidth", &vidWidth, 0, 32767);
configRegisterInt("Video.DefaultHeight", &vidHeight, 0, 32767); configRegisterInt("Video.DefaultHeight", &vidHeight, 0, 32767);
configRegisterInt("Video.ExclusiveFullscreen", &vidFullscreenExclusive, 0, 1); configRegisterInt("Video.ExclusiveFullscreen", &vidFullscreenExclusive, 0, 1);
configRegisterInt("Video.CenterWindow", &vidCenter, 0, 1);
configRegisterInt("Video.AllowHiDpi", &vidAllowHiDpi, 0, 1); configRegisterInt("Video.AllowHiDpi", &vidAllowHiDpi, 0, 1);
configRegisterInt("Video.VSync", &vidVsync, -1, 10); configRegisterInt("Video.VSync", &vidVsync, -1, 10);
configRegisterInt("Video.FramebufferEffects", &vidFramebuffers, 0, 1); configRegisterInt("Video.FramebufferEffects", &vidFramebuffers, 0, 1);
configRegisterInt("Video.FramerateLimit", &vidFramerateLimit, 0, VIDEO_MAX_FPS); configRegisterInt("Video.FramerateLimit", &vidFramerateLimit, 0, VIDEO_MAX_FPS);
configRegisterInt("Video.DisplayFPS", &vidDisplayFPS, 0, 1);
configRegisterFloat("Video.DisplayFPSInterval", &vidDisplayFPSInterval, 0.01f, 32.f);
configRegisterInt("Video.MSAA", &vidMSAA, 1, 16); configRegisterInt("Video.MSAA", &vidMSAA, 1, 16);
configRegisterInt("Video.TextureFilter", &texFilter, 0, 2); configRegisterInt("Video.TextureFilter", &texFilter, 0, 2);
configRegisterInt("Video.TextureFilter2D", &texFilter2D, 0, 1); configRegisterInt("Video.TextureFilter2D", &texFilter2D, 0, 1);
configRegisterInt("Video.DetailTextures", &texDetail, 0, 1); configRegisterInt("Video.DetailTextures", &texDetail, 0, 1);
configRegisterInt("Video.MipmapFilter", &texMipmapFilter, 0, 2);
configRegisterInt("Video.AnisotropicFilter", &texAnisotropicFilter, 0, 16);
configRegisterFloat("Video.GlareBrightness", &vidGlareBrightness, 0.f, 1.f);
configRegisterFloat("Video.OverexposureScale", &vidOverexposureScale, 0.f, 1.f);
} }
+30 -30
View File
@@ -26,7 +26,7 @@
#include "data.h" #include "data.h"
#include "types.h" #include "types.h"
struct activemenu g_AmMenus[MAX_LOCAL_PLAYERS]; struct activemenu g_AmMenus[MAX_PLAYERS];
struct fontchar *g_AmFont1; struct fontchar *g_AmFont1;
struct font *g_AmFont2; struct font *g_AmFont2;
s32 g_AmIndex; s32 g_AmIndex;
@@ -177,7 +177,7 @@ MenuItemHandlerResult amPickTargetMenuList(s32 operation, struct menuitem *item,
gdl = text0f153628(gdl); gdl = text0f153628(gdl);
gdl = textRenderProjected(gdl, &x, &y, g_MpAllChrConfigPtrs[chrindex]->name, g_CharsHandelGothicSm, g_FontHandelGothicSm, colour, viGetWidth(), viGetHeight(), 0, 0); gdl = textRenderProjected(gdl, &x, &y, g_MpAllChrConfigPtrs[chrindex]->name, g_CharsHandelGothicSm, g_FontHandelGothicSm, colour, viGetWidth(), viGetHeight(), 0, 0);
gdl = text0f153780(gdl); gdl = text0f153780(gdl);
return (s32)gdl; return (uintptr_t)gdl;
} }
case MENUOP_GETOPTIONHEIGHT: case MENUOP_GETOPTIONHEIGHT:
data->list.value = LINEHEIGHT; data->list.value = LINEHEIGHT;
@@ -547,7 +547,7 @@ void amReset(void)
g_AmFont1 = g_CharsHandelGothicSm; g_AmFont1 = g_CharsHandelGothicSm;
g_AmFont2 = g_FontHandelGothicSm; g_AmFont2 = g_FontHandelGothicSm;
#else #else
if (LOCALPLAYERCOUNT() >= 2) { if (PLAYERCOUNT() >= 2) {
g_AmFont1 = g_CharsHandelGothicXs; g_AmFont1 = g_CharsHandelGothicXs;
g_AmFont2 = g_FontHandelGothicXs; g_AmFont2 = g_FontHandelGothicXs;
} else { } else {
@@ -578,7 +578,7 @@ s16 amCalculateSlotWidth(void)
} }
#if VERSION >= VERSION_NTSC_1_0 #if VERSION >= VERSION_NTSC_1_0
if (LOCALPLAYERCOUNT() > 1) { if (PLAYERCOUNT() > 1) {
max += 3; max += 3;
} else { } else {
max += 4; max += 4;
@@ -762,32 +762,32 @@ void amClose(void)
bool amIsCramped(void) bool amIsCramped(void)
{ {
#if VERSION == VERSION_JPN_FINAL #if VERSION == VERSION_JPN_FINAL
if (LOCALPLAYERCOUNT() >= 3 && g_AmMenus[g_AmIndex].screenindex != 1) { if (PLAYERCOUNT() >= 3 && g_AmMenus[g_AmIndex].screenindex != 1) {
return true; return true;
} }
if (IS4MB() && LOCALPLAYERCOUNT() == 2) { if (IS4MB() && PLAYERCOUNT() == 2) {
return true; return true;
} }
if (optionsGetScreenSplit() == SCREENSPLIT_VERTICAL if (optionsGetScreenSplit() == SCREENSPLIT_VERTICAL
&& LOCALPLAYERCOUNT() == 2 && PLAYERCOUNT() == 2
&& g_AmMenus[g_AmIndex].screenindex != 1) { && g_AmMenus[g_AmIndex].screenindex != 1) {
return true; return true;
} }
return false; return false;
#else #else
return (g_AmMenus[g_AmIndex].screenindex == 0 && LOCALPLAYERCOUNT() >= 3) return (g_AmMenus[g_AmIndex].screenindex == 0 && PLAYERCOUNT() >= 3)
|| (IS4MB() && LOCALPLAYERCOUNT() == 2) || (IS4MB() && PLAYERCOUNT() == 2)
|| (LOCALPLAYERCOUNT() == 2 && optionsGetScreenSplit() == SCREENSPLIT_VERTICAL); || (PLAYERCOUNT() == 2 && optionsGetScreenSplit() == SCREENSPLIT_VERTICAL);
#endif #endif
} }
void amCalculateSlotPosition(s16 column, s16 row, s16 *x, s16 *y) void amCalculateSlotPosition(s16 column, s16 row, s16 *x, s16 *y)
{ {
#if VERSION == VERSION_JPN_FINAL #if VERSION == VERSION_JPN_FINAL
s32 playercount = LOCALPLAYERCOUNT(); s32 playercount = PLAYERCOUNT();
*x = g_AmMenus[g_AmIndex].xradius * (column - 1); *x = g_AmMenus[g_AmIndex].xradius * (column - 1);
*y = (row - 1) * 50; *y = (row - 1) * 50;
@@ -841,7 +841,7 @@ void amCalculateSlotPosition(s16 column, s16 row, s16 *x, s16 *y)
} }
} }
#elif VERSION >= VERSION_NTSC_1_0 #elif VERSION >= VERSION_NTSC_1_0
s32 playercount = LOCALPLAYERCOUNT(); s32 playercount = PLAYERCOUNT();
*x = g_AmMenus[g_AmIndex].xradius * (column - 1); *x = g_AmMenus[g_AmIndex].xradius * (column - 1);
*y = (row - 1) * 50; *y = (row - 1) * 50;
@@ -893,7 +893,7 @@ void amCalculateSlotPosition(s16 column, s16 row, s16 *x, s16 *y)
} }
} }
#else #else
s32 playercount = LOCALPLAYERCOUNT(); s32 playercount = PLAYERCOUNT();
*x = g_AmMenus[g_AmIndex].xradius * (column - 1); *x = g_AmMenus[g_AmIndex].xradius * (column - 1);
*y = (row - 1) * 50; *y = (row - 1) * 50;
@@ -973,15 +973,15 @@ Gfx *amRenderAibotInfo(Gfx *gdl, s32 buddynum)
#endif #endif
#if VERSION >= VERSION_NTSC_1_0 #if VERSION >= VERSION_NTSC_1_0
if (LOCALPLAYERCOUNT() == 1 && optionsGetEffectiveScreenSize() != SCREENSIZE_FULL) { if (PLAYERCOUNT() == 1 && optionsGetEffectiveScreenSize() != SCREENSIZE_FULL) {
wide = true; wide = true;
} }
#endif #endif
#if VERSION >= VERSION_NTSC_1_0 #if VERSION >= VERSION_NTSC_1_0
if ((LOCALPLAYERCOUNT() == 2 && (optionsGetScreenSplit() == SCREENSPLIT_VERTICAL || IS4MB())) || LOCALPLAYERCOUNT() >= 3) if ((PLAYERCOUNT() == 2 && (optionsGetScreenSplit() == SCREENSPLIT_VERTICAL || IS4MB())) || PLAYERCOUNT() >= 3)
#else #else
if ((LOCALPLAYERCOUNT() == 2 && optionsGetScreenSplit() == SCREENSPLIT_VERTICAL) || LOCALPLAYERCOUNT() >= 3) if ((PLAYERCOUNT() == 2 && optionsGetScreenSplit() == SCREENSPLIT_VERTICAL) || PLAYERCOUNT() >= 3)
#endif #endif
{ {
if ((g_Vars.currentplayernum % 2) == 0) { if ((g_Vars.currentplayernum % 2) == 0) {
@@ -1014,7 +1014,7 @@ Gfx *amRenderAibotInfo(Gfx *gdl, s32 buddynum)
- (s32)(textwidth * 0.5f) - (s32)(textwidth * 0.5f)
+ offset; + offset;
if (LOCALPLAYERCOUNT() >= 2) { if (PLAYERCOUNT() >= 2) {
y = viGetViewTop() + 5; y = viGetViewTop() + 5;
} else { } else {
y = viGetViewTop() + 10; y = viGetViewTop() + 10;
@@ -1030,12 +1030,12 @@ Gfx *amRenderAibotInfo(Gfx *gdl, s32 buddynum)
gdl = func0f1574d0jf(gdl, &x, &y, aibotname, g_AmFont1, g_AmFont2, -1, gdl = func0f1574d0jf(gdl, &x, &y, aibotname, g_AmFont1, g_AmFont2, -1,
0x000000ff, SCREEN_320, SCREEN_240, 0, 0); 0x000000ff, SCREEN_320, SCREEN_240, 0, 0);
y += (LOCALPLAYERCOUNT() >= 2) ? 0 : (s32)(textheight * 1.1f); y += (PLAYERCOUNT() >= 2) ? 0 : (s32)(textheight * 1.1f);
#else #else
gdl = textRender(gdl, &x, &y, aibotname, g_AmFont1, g_AmFont2, -1, gdl = textRender(gdl, &x, &y, aibotname, g_AmFont1, g_AmFont2, -1,
0x000000ff, SCREEN_320, SCREEN_240, 0, 0); 0x000000ff, SCREEN_320, SCREEN_240, 0, 0);
y += (LOCALPLAYERCOUNT() >= 2) ? 0 : (s32)(textheight * 1.1f); y += (PLAYERCOUNT() >= 2) ? 0 : (s32)(textheight * 1.1f);
textMeasure(&textheight, &textwidth, weaponname, g_AmFont1, g_AmFont2, 0); textMeasure(&textheight, &textwidth, weaponname, g_AmFont1, g_AmFont2, 0);
x = viGetViewLeft() / g_ScaleX x = viGetViewLeft() / g_ScaleX
@@ -1064,7 +1064,7 @@ Gfx *amRenderAibotInfo(Gfx *gdl, s32 buddynum)
- (s32)(textwidth * 0.5f) - (s32)(textwidth * 0.5f)
+ offset; + offset;
if (LOCALPLAYERCOUNT() >= 2) { if (PLAYERCOUNT() >= 2) {
y = viGetViewTop() + 5; y = viGetViewTop() + 5;
} else { } else {
y = viGetViewTop() + 10; y = viGetViewTop() + 10;
@@ -1123,7 +1123,7 @@ Gfx *amRenderSlot(Gfx *gdl, char *text, s16 x, s16 y, s32 mode, s32 flags)
paddingtop = 6; paddingtop = 6;
paddingbottom = 6; paddingbottom = 6;
if (LOCALPLAYERCOUNT() >= 2) { if (PLAYERCOUNT() >= 2) {
paddingtop = 5; paddingtop = 5;
paddingbottom = 3; paddingbottom = 3;
} }
@@ -1262,7 +1262,7 @@ Gfx *amRender(Gfx *gdl)
#endif #endif
#ifndef PLATFORM_N64 #ifndef PLATFORM_N64
const s32 playercount = LOCALPLAYERCOUNT(); const s32 playercount = PLAYERCOUNT();
if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) { if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) {
gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT); gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT);
} }
@@ -1487,7 +1487,7 @@ Gfx *amRender(Gfx *gdl)
above = 6; above = 6;
below = 6; below = 6;
if (LOCALPLAYERCOUNT() >= 2) { if (PLAYERCOUNT() >= 2) {
above = 5; above = 5;
below = 3; below = 3;
} }
@@ -1510,7 +1510,7 @@ Gfx *amRender(Gfx *gdl)
halfwidth = 1; halfwidth = 1;
above = 2; above = 2;
below = 0; below = 0;
} else if (LOCALPLAYERCOUNT() >= 2) { } else if (PLAYERCOUNT() >= 2) {
s32 textheight; s32 textheight;
s32 textwidth; s32 textwidth;
char text[32]; char text[32];
@@ -1592,16 +1592,16 @@ Gfx *amRender(Gfx *gdl)
} }
#endif #endif
barwidth = LOCALPLAYERCOUNT() >= 2 ? 48 : 64; barwidth = PLAYERCOUNT() >= 2 ? 48 : 64;
barheight = LOCALPLAYERCOUNT() >= 2 ? 7 : 11; barheight = PLAYERCOUNT() >= 2 ? 7 : 11;
xoffset = 0; xoffset = 0;
#if VERSION >= VERSION_NTSC_1_0 #if VERSION >= VERSION_NTSC_1_0
if ((LOCALPLAYERCOUNT() == 2 && (optionsGetScreenSplit() == SCREENSPLIT_VERTICAL || IS4MB())) || LOCALPLAYERCOUNT() >= 3) { if ((PLAYERCOUNT() == 2 && (optionsGetScreenSplit() == SCREENSPLIT_VERTICAL || IS4MB())) || PLAYERCOUNT() >= 3) {
xoffset = (g_Vars.currentplayernum & 1) == 0 ? 8 : -8; xoffset = (g_Vars.currentplayernum & 1) == 0 ? 8 : -8;
} }
if (LOCALPLAYERCOUNT() == 1 && optionsGetEffectiveScreenSize() != SCREENSIZE_FULL) { if (PLAYERCOUNT() == 1 && optionsGetEffectiveScreenSize() != SCREENSIZE_FULL) {
part1left = viGetViewLeft() / g_ScaleX + 32; part1left = viGetViewLeft() / g_ScaleX + 32;
} else { } else {
part1left = (s32) ((viGetViewWidth() / g_ScaleX) * 0.5f) part1left = (s32) ((viGetViewWidth() / g_ScaleX) * 0.5f)
@@ -1610,7 +1610,7 @@ Gfx *amRender(Gfx *gdl)
+ xoffset; + xoffset;
} }
#else #else
if ((LOCALPLAYERCOUNT() == 2 && optionsGetScreenSplit() == SCREENSPLIT_VERTICAL) || LOCALPLAYERCOUNT() >= 3) { if ((PLAYERCOUNT() == 2 && optionsGetScreenSplit() == SCREENSPLIT_VERTICAL) || PLAYERCOUNT() >= 3) {
xoffset = (g_Vars.currentplayernum & 1) == 0 ? 8 : -8; xoffset = (g_Vars.currentplayernum & 1) == 0 ? 8 : -8;
} }
@@ -1636,7 +1636,7 @@ Gfx *amRender(Gfx *gdl)
gDPSetRenderMode(gdl++, G_RM_XLU_SURF, G_RM_XLU_SURF2); gDPSetRenderMode(gdl++, G_RM_XLU_SURF, G_RM_XLU_SURF2);
gDPSetCombineMode(gdl++, G_CC_PRIMITIVE, G_CC_PRIMITIVE); gDPSetCombineMode(gdl++, G_CC_PRIMITIVE, G_CC_PRIMITIVE);
y = viGetViewTop() + viGetViewHeight() - (LOCALPLAYERCOUNT() >= 2 ? 19 : 34); y = viGetViewTop() + viGetViewHeight() - (PLAYERCOUNT() >= 2 ? 19 : 34);
// NTSC beta doesn't scale the health bar when hi-res is on, // NTSC beta doesn't scale the health bar when hi-res is on,
// and it only matches if part2left is an inline expression // and it only matches if part2left is an inline expression
+1 -1
View File
@@ -22,7 +22,7 @@ void amTick(void)
s32 prevplayernum = g_Vars.currentplayernum; s32 prevplayernum = g_Vars.currentplayernum;
s32 i; s32 i;
for (i = 0; i < LOCALPLAYERCOUNT(); i++) { for (i = 0; i < PLAYERCOUNT(); i++) {
setCurrentPlayerNum(i); setCurrentPlayerNum(i);
g_AmIndex = g_Vars.currentplayernum; g_AmIndex = g_Vars.currentplayernum;
+167 -38
View File
@@ -7,7 +7,7 @@
#include "game/game_0b2150.h" #include "game/game_0b2150.h"
#include "game/tex.h" #include "game/tex.h"
#include "game/sky.h" #include "game/sky.h"
#include "game/game_13c510.h" #include "game/artifact.h"
#include "game/bg.h" #include "game/bg.h"
#include "game/stagetable.h" #include "game/stagetable.h"
#include "game/room.h" #include "game/room.h"
@@ -21,8 +21,73 @@
#include "lib/lib_17ce0.h" #include "lib/lib_17ce0.h"
#include "game/player.h" #include "game/player.h"
#include "game/prop.h" #include "game/prop.h"
#include "video.h"
#endif #endif
/**
* Artifacts are points of interest in the z-buffer.
*
* They correspond to:
* - Individual circles in the lens flare effect from the sun.
* - Individual corners of each light fixture's box.
*
* The game needs to do line of sight checks to these points. The collision
* system would normally be used for line of sight checks, but it only works
* with basic geometric volumes and also doesn't take into account the player's
* gun. Instead, the checks are done by reading from the previous frame's
* z-buffer.
*
* Typically, the z-buffer would be read by the scheduler after a graphics frame
* is rendered, but this only works if the z-buffer is a complete image.
* PD draws the scene, then clears the z-buffer before drawing the player's gun,
* so the z-buffer at the end only contains the player's gun. To work around
* this, the GPU is given commands to read the z-buffer as a texture and copy
* depth values to a safe place before clearing it. Then once the frame is
* rendered, the scheduler compares the saved depths with the current z-buffer
* and updates the artifact, applying the minimum of the two depths.
*
* The scheduler maintains 3 arrays of artifacts, each referenced by indexes
* which rotate between them.
* - Artifacts are written by the main thread using the write index.
* The write and front indexes are then incremented.
* - The same artifacts are updated by the scheduler using the pending index.
* The pending index is then updated.
* - The artifacts are then rendered on a later frame using the front index.
*
* In each artifacts array, the first several slots are reserved for the sun
* flare artifacts. The quantity depends on the number of suns in the stage
* (Skedar Ruins has 3) and there are 8 artifacts per sun. The remaining slots
* are used for light fixture corners. The array is big enough to handle at
* least 90 lights on screen at a time.
*
* The initial state of the indexes are write=0, front=1, pending=0.
* These are set in sched_reset_artifacts.
*
* The detailed workflow is:
* - CPU: Light artifacts are determined and added to write artifacts (0) array
* - CPU: Constructs the gdl in this order:
* - Render scene
* - Copy relevant parts of z-buffer to write depths (0) array
* - Clear z-buffer and render gun
* - Render artifacts by reading from front artifacts (1) array
* - CPU: increments write (0 -> 1) and front (1 -> 2) indexes
* - GPU: Executes above task. g_ArtifactDepths0 now contains depths, and is
* pointed to by pending.
* - Scheduler: Reads the z-buffer, which at this point only contains the gun
* depth information, and updates the artifact with the minimum of the two
* - Scheduler: Increments pending (0 -> 1)
*
* It appears that the front index should be initialised to 2 instead, so that
* it's one frame behind the others rather than two frames behind.
*
* There's no doubt this went through several iterations before landing on this
* implementation. It's likely that this was implemented using a single and full
* z-buffer and it worked well until they decided to clear the z-buffer before
* rendering the gun. There is evidence in zbuf.c that they allocated a second
* z-buffer and swapped it. But when memory got too tight they had to change it
* to this texture read method.
*/
u8 *var800a41a0; u8 *var800a41a0;
u32 var800a41a4; u32 var800a41a4;
u32 var800a41a8; u32 var800a41a8;
@@ -44,11 +109,25 @@ void artifactsTick(void)
schedIncrementFrontArtifacts(); schedIncrementFrontArtifacts();
} }
u16 func0f13c574(f32 arg0) u16 floatToN64Depth(f32 arg0)
{ {
/**
* Method to convert a 32 bit floating point depth value to the
* unsigned 16 bit integer format used by the zbuffer on the N64.
* The argument arg0 represents z normalized to [0, 1] * 32704.0f.
*
* It works by converting the depth value to a large, unsigned 32 bit
* integer before scaling back down to an unsigned 16 bit integer.
* The scaling is done using bit shift operations on the most & least
* significant bytes of the resulting 16 bit integer, likely because
* bit shift operations are faster than division. The segmentation of
* this calculation at values 0x3f800, 0x3f000, etc. is probably
* intended to reduce z-fighting by adding more differentiation for
* distant z values.
*/
u32 value = arg0 * 8.0f; u32 value = arg0 * 8.0f;
u32 left; u32 left; // forms the most significant byte of the final u16
u32 right = value; u32 right = value; // forms the least significant byte of the final u16
if (value > 0x3f800) { if (value > 0x3f800) {
right = value & 0x7ff; right = value & 0x7ff;
@@ -87,7 +166,7 @@ u16 func0f13c574(f32 arg0)
return left << 13 | (right << 2); return left << 13 | (right << 2);
} }
s32 func0f13c710(f32 arg0) s32 artifactsFloatToInt(f32 arg0)
{ {
if (arg0 > 0.0f) { if (arg0 > 0.0f) {
if (arg0 > 2147483520.0f) { if (arg0 > 2147483520.0f) {
@@ -168,6 +247,12 @@ void artifactsCalculateGlaresForRoom(s32 roomnum)
struct coord *campos = &g_Vars.currentplayer->cam_pos; struct coord *campos = &g_Vars.currentplayer->cam_pos;
struct artifact *artifact; struct artifact *artifact;
#ifndef PLATFORM_N64
if (videoGetGlareBrightness() <= 0.f) {
return;
}
#endif
if (g_Rooms[roomnum].gfxdata != NULL && g_Rooms[roomnum].loaded240) { if (g_Rooms[roomnum].gfxdata != NULL && g_Rooms[roomnum].loaded240) {
numlights = g_Rooms[roomnum].gfxdata->numlights; numlights = g_Rooms[roomnum].gfxdata->numlights;
@@ -232,8 +317,8 @@ void artifactsCalculateGlaresForRoom(s32 roomnum)
if (spdc[3] > 0.0001f) { if (spdc[3] > 0.0001f) {
f20 = 1.0f / spdc[3]; f20 = 1.0f / spdc[3];
x = func0f13c710(viewleft + (1.0f + spdc[0] * f20) * (viewwidth * 0.5f)); x = artifactsFloatToInt(viewleft + (1.0f + spdc[0] * f20) * (viewwidth * 0.5f));
y = func0f13c710(viewtop + (1.0f - spdc[1] * f20) * (viewheight * 0.5f)); y = artifactsFloatToInt(viewtop + (1.0f - spdc[1] * f20) * (viewheight * 0.5f));
f0 = (spdc[2] * f20 * 511.0f + 511.0f) * 32.0f; f0 = (spdc[2] * f20 * 511.0f + 511.0f) * 32.0f;
if (f0 < 32576.0f) { if (f0 < 32576.0f) {
@@ -335,8 +420,8 @@ void artifactsCalculateGlaresForRoom(s32 roomnum)
f20 = -9999.0f; f20 = -9999.0f;
} }
xi = func0f13c710(viewleft + (1.0f + spdc[0] * f20) * (viewwidth * 0.5f)); xi = artifactsFloatToInt(viewleft + (1.0f + spdc[0] * f20) * (viewwidth * 0.5f));
yi = func0f13c710(viewtop + (1.0f - spdc[1] * f20) * (viewheight * 0.5f)); yi = artifactsFloatToInt(viewtop + (1.0f - spdc[1] * f20) * (viewheight * 0.5f));
f0 = (spdc[2] * f20 * 511.0f + 511.0f) * 32.0f; f0 = (spdc[2] * f20 * 511.0f + 511.0f) * 32.0f;
if (g_ZbufPtr1 if (g_ZbufPtr1
@@ -357,14 +442,20 @@ void artifactsCalculateGlaresForRoom(s32 roomnum)
if (index < MAX_ARTIFACTS) { if (index < MAX_ARTIFACTS) {
#ifndef PLATFORM_N64 #ifndef PLATFORM_N64
artifact->unk02 = artifactTestLos(&spec, &g_BgRooms[roomnum].pos, xi, yi); artifact->visiblelos = artifactTestLos(&spec, &g_BgRooms[roomnum].pos, xi, yi);
#endif #endif
artifact->unk04 = func0f13c574(f0) >> 2; /**
artifact->unk08 = &g_ZbufPtr1[viGetWidth() * yi + xi]; * the original game performs artifact depth comparison
* using the N64 depth values divided by 4. This is
* accomplished by bit shifting the N64 depth value
* to the right using >> 2
*/
artifact->expecteddepth = floatToN64Depth(f0) >> 2;
artifact->zbufptr = &g_ZbufPtr1[viGetWidth() * yi + xi];
artifact->light = &roomlights[i]; artifact->light = &roomlights[i];
artifact->type = ARTIFACTTYPE_GLARE; artifact->type = ARTIFACTTYPE_GLARE;
artifact->unk0c.u16_2 = xi; artifact->screenx = xi;
artifact->unk0c.u16_1 = yi; artifact->screeny = yi;
} }
} }
} }
@@ -375,7 +466,7 @@ void artifactsCalculateGlaresForRoom(s32 roomnum)
} }
} }
u8 func0f13d3c4(u8 arg0, u8 arg1) u8 artifactsClamp(u8 arg0, u8 arg1)
{ {
if (arg1 >= arg0 + 7) { if (arg1 >= arg0 + 7) {
return arg0 + 7; return arg0 + 7;
@@ -423,18 +514,18 @@ Gfx *artifactsRenderGlaresForRoom(Gfx *gdl, s32 roomnum)
u16 min; u16 min;
u16 max; u16 max;
f32 lightop_cur_frac; f32 lightop_cur_frac;
s32 t2; s32 numgood;
struct light *light; struct light *light;
u8 *s3; u8 *s3;
s32 k; s32 k;
s32 count; s32 count;
u16 t4; u16 actualdepth;
f32 add; f32 add;
s32 l; s32 l;
f32 brightness; f32 brightness;
s32 avg; s32 tolerance;
f32 f0; f32 f0;
s32 v1; s32 difference;
s32 r; s32 r;
s32 g; s32 g;
s32 b; s32 b;
@@ -448,6 +539,13 @@ Gfx *artifactsRenderGlaresForRoom(Gfx *gdl, s32 roomnum)
f32 f24; f32 f24;
bool extra; bool extra;
f32 f26; f32 f26;
#ifndef PLATFORM_N64
const f32 pfov = g_Vars.currentplayerstats ? PLAYER_DEFAULT_FOV : 60.f;
const f32 brightscale = videoGetGlareBrightness();
if (brightscale <= 0.f) {
return gdl;
}
#endif
artifacts = schedGetFrontArtifacts(); artifacts = schedGetFrontArtifacts();
lightop_cur_frac = roomGetLightOpCurFrac(roomnum); lightop_cur_frac = roomGetLightOpCurFrac(roomnum);
@@ -460,6 +558,12 @@ Gfx *artifactsRenderGlaresForRoom(Gfx *gdl, s32 roomnum)
struct light *light2 = artifacts[i].light; struct light *light2 = artifacts[i].light;
count = 0; count = 0;
/**
* light arifacts are created from several, closely spaced
* textures that give the appearance of a dynamic light glare
* as the character moves. Loop to count all the sub-artifacts
* in this light.
*/
for (j = i; j < MAX_ARTIFACTS && artifacts[j].type == ARTIFACTTYPE_GLARE && artifacts[j].light == light2; j++) { for (j = i; j < MAX_ARTIFACTS && artifacts[j].type == ARTIFACTTYPE_GLARE && artifacts[j].light == light2; j++) {
count++; count++;
} }
@@ -470,52 +574,70 @@ Gfx *artifactsRenderGlaresForRoom(Gfx *gdl, s32 roomnum)
if (roomnum == light->roomnum) { if (roomnum == light->roomnum) {
lightindex = ((uintptr_t)light - (uintptr_t)g_BgLightsFileData) / sizeof(struct light); lightindex = ((uintptr_t)light - (uintptr_t)g_BgLightsFileData) / sizeof(struct light);
s3 = &var800a41a0[lightindex * 3]; s3 = &var800a41a0[lightindex * 3];
t2 = 0; numgood = 0;
min = 0xffff; min = 0xffff;
max = 0; max = 0;
/**
* loop to determine the min & max depth of
* the sub-artifacts composing this room light.
*/
for (k = i; k < i + count; k++) { for (k = i; k < i + count; k++) {
if (artifacts[k].unk04 > max) { if (artifacts[k].expecteddepth > max) {
max = artifacts[k].unk04; max = artifacts[k].expecteddepth;
} }
if (artifacts[k].unk04 < min) { if (artifacts[k].expecteddepth < min) {
min = artifacts[k].unk04; min = artifacts[k].expecteddepth;
} }
} }
avg = (max - min) >> 1; /**
* Define a depth tolerance from the min & max
* depths of sub-artifacts for a given light.
* This will be used to determine which light
* artifacts are visible when comparing depth
* values of lights to other items rendered
* on screen. Without this, the lights would
* constantly flicker due to z-fighting caused
* by the low precision of the N64 depth.
*/
tolerance = (max - min) >> 1;
if (avg < 25) { if (tolerance < 25) {
avg = 25; tolerance = 25;
} }
for (k = i; k < i + count; k++) { for (k = i; k < i + count; k++) {
#ifdef PLATFORM_N64 #ifdef PLATFORM_N64
u16 tmp; u16 expecteddepth;
t4 = (artifacts[k].unk02 & 0xfffc) >> 2; actualdepth = (artifacts[k].actualdepth & 0xfffc) >> 2;
tmp = artifacts[k].unk04; expecteddepth = artifacts[k].expecteddepth;
if (tmp < t4) { if (expecteddepth < actualdepth) {
v1 = t4 - tmp; difference = actualdepth - expecteddepth;
} else { } else {
v1 = tmp - t4; difference = expecteddepth - actualdepth;
} }
if (avg >= v1) { if (difference <= tolerance) {
t2++; numgood++;
} }
#else #else
t2 += artifacts[k].unk02; numgood += artifacts[k].visiblelos;
#endif #endif
artifacts[k].type = ARTIFACTTYPE_FREE; artifacts[k].type = ARTIFACTTYPE_FREE;
} }
s3[0] = func0f13d3c4(s3[0], t2 * 2); s3[0] = artifactsClamp(s3[0], numgood * 2);
if (t2 > 0) { if (numgood > 0) {
#ifndef PLATFORM_N64
brightness = viGetFovY() / pfov;
#else
brightness = viGetFovY() * 0.017453292f; brightness = viGetFovY() * 0.017453292f;
#endif
add = cosf(brightness) / sinf(brightness) * 14.6f; add = cosf(brightness) / sinf(brightness) * 14.6f;
if (lightIsHealthy(roomnum, lightindex - g_Rooms[roomnum].gfxdata->lightsindex)) { if (lightIsHealthy(roomnum, lightindex - g_Rooms[roomnum].gfxdata->lightsindex)) {
@@ -545,6 +667,9 @@ Gfx *artifactsRenderGlaresForRoom(Gfx *gdl, s32 roomnum)
} }
f0 = s3[2] * (1.0f / 255.0f); f0 = s3[2] * (1.0f / 255.0f);
#ifndef PLATFORM_N64
f0 *= (60.f / pfov);
#endif
skySetOverexposure((s32) ((f32)f0 * r), (s32) ((f32)f0 * g), (s32) ((f32)f0 * b)); skySetOverexposure((s32) ((f32)f0 * r), (s32) ((f32)f0 * g), (s32) ((f32)f0 * b));
@@ -594,6 +719,10 @@ Gfx *artifactsRenderGlaresForRoom(Gfx *gdl, s32 roomnum)
alpha *= (s3[1] / 255.0f); alpha *= (s3[1] / 255.0f);
alpha *= (s3[0] / 8.0f); alpha *= (s3[0] / 8.0f);
#ifndef PLATFORM_N64
alpha *= brightscale;
#endif
if (USINGDEVICE(DEVICE_NIGHTVISION)) { if (USINGDEVICE(DEVICE_NIGHTVISION)) {
alpha *= lightop_cur_frac * 7.0f; alpha *= lightop_cur_frac * 7.0f;
} }
+37 -16
View File
@@ -15,7 +15,7 @@
#include "game/sky.h" #include "game/sky.h"
#include "game/stars.h" #include "game/stars.h"
#include "game/dyntex.h" #include "game/dyntex.h"
#include "game/game_13c510.h" #include "game/artifact.h"
#include "game/game_1531a0.h" #include "game/game_1531a0.h"
#include "game/gfxmemory.h" #include "game/gfxmemory.h"
#include "game/gfxreplace.h" #include "game/gfxreplace.h"
@@ -47,6 +47,7 @@
#include "preprocess.h" #include "preprocess.h"
#include "system.h" #include "system.h"
#include "video.h" #include "video.h"
#include "platform.h"
#endif #endif
#define BGCMD_END 0x00 #define BGCMD_END 0x00
@@ -97,7 +98,7 @@ u16 g_BgUnloadDelay240;
u16 g_BgUnloadDelay240_2; u16 g_BgUnloadDelay240_2;
u32 var800a4bf4; u32 var800a4bf4;
RoomNum g_GlareRooms[100]; RoomNum g_GlareRooms[100];
u32 *g_BgPrimaryData2; uintptr_t *g_BgPrimaryData2;
struct bgroom *g_BgRooms; struct bgroom *g_BgRooms;
struct bgportal *g_BgPortals; struct bgportal *g_BgPortals;
struct portalmetric *g_PortalMetrics; struct portalmetric *g_PortalMetrics;
@@ -113,7 +114,7 @@ struct portalcamcacheitem *g_PortalCameraCache;
struct bgsnake g_BgSnake; struct bgsnake g_BgSnake;
s32 g_StageIndex = 1; s32 g_StageIndex = 1;
u32 var8007fc04 = 0; uintptr_t var8007fc04 = 0;
u8 *var8007fc08 = NULL; u8 *var8007fc08 = NULL;
#if VERSION < VERSION_NTSC_1_0 #if VERSION < VERSION_NTSC_1_0
@@ -134,6 +135,9 @@ s32 g_BgMostAttemptedDrawSlots = 0;
s32 g_BgNumRoomLoadCandidates = 0; s32 g_BgNumRoomLoadCandidates = 0;
u16 g_BgFrameCount = 0xfffe; u16 g_BgFrameCount = 0xfffe;
s32 g_BgNumPortalCameraCacheItems = 0; s32 g_BgNumPortalCameraCacheItems = 0;
#ifndef PLATFORM_N64
bool g_BgHitXluDisabled = false;
#endif
void bgUnpausePropsInRoom(u32 roomnum, bool tintedglassonly) void bgUnpausePropsInRoom(u32 roomnum, bool tintedglassonly)
{ {
@@ -763,7 +767,7 @@ Gfx *bgRenderGdlInXray(Gfx *gdl, s8 *readgdl, Vtx *vertices, s16 arg3[3])
gdl = bgProcessXrayTri(gdl, &xraydata, dmemvertices[x], dmemvertices[y], dmemvertices[z], dmemcolours[x], dmemcolours[y], dmemcolours[z], inrange[x], inrange[y], inrange[z]); gdl = bgProcessXrayTri(gdl, &xraydata, dmemvertices[x], dmemvertices[y], dmemvertices[z], dmemcolours[x], dmemcolours[y], dmemcolours[z], inrange[x], inrange[y], inrange[z]);
} }
readgdl += 8; readgdl += sizeof(Gfx);
} }
gdl = bgRenderXrayData(gdl, &xraydata); gdl = bgRenderXrayData(gdl, &xraydata);
@@ -1468,7 +1472,7 @@ void bgReset(s32 stagenum)
u32 section2compsize; u32 section2compsize;
u32 section2start; u32 section2start;
u32 section1compsize; u32 section1compsize;
u32 scratch; uintptr_t scratch;
var8007fc0c = 8; var8007fc0c = 8;
@@ -1509,6 +1513,11 @@ void bgReset(s32 stagenum)
primcompsize = *(u32 *)&header[8]; primcompsize = *(u32 *)&header[8];
var8007fc54 = inflatedsize - primcompsize; var8007fc54 = inflatedsize - primcompsize;
var8007fc54 -= 0xc; var8007fc54 -= 0xc;
#ifdef PLATFORM_64BIT
inflatedsize = romdataFileGetEstimatedSize(inflatedsize, LOADTYPE_BG);
#endif
inflatedsize = ALIGN16(inflatedsize); inflatedsize = ALIGN16(inflatedsize);
// Allocate space for the primary bg data // Allocate space for the primary bg data
@@ -1529,7 +1538,7 @@ void bgReset(s32 stagenum)
bgInflate((u8 *) scratch, g_BgPrimaryData, primcompsize); bgInflate((u8 *) scratch, g_BgPrimaryData, primcompsize);
#ifndef PLATFORM_N64 #ifndef PLATFORM_N64
preprocessBgSection1(g_BgPrimaryData, 0x0f000000); preprocessBgSection1(g_BgPrimaryData, inflatedsize, 0x0f000000);
#endif #endif
// Shrink the allocation (ie. free the scratch space) // Shrink the allocation (ie. free the scratch space)
@@ -1598,7 +1607,7 @@ void bgReset(s32 stagenum)
// Copy 0x40 bytes from a random location in ROM to a random // Copy 0x40 bytes from a random location in ROM to a random
// location in RAM. The write address can be anywhere in the // location in RAM. The write address can be anywhere in the
// boot segment or in the lib segment up to modelRenderNodeDl. // boot segment or in the lib segment up to modelRenderNodeDl.
dmaExec((void *)(PHYS_TO_K0(0x1000) + (random() & 0x1fff8)), random() & 0x1fffe, 0x40); dmaExec((void *)(PHYS_TO_K0(0x1000) + (rngRandom() & 0x1fff8)), rngRandom() & 0x1fffe, 0x40);
} }
} }
#endif #endif
@@ -1606,7 +1615,7 @@ void bgReset(s32 stagenum)
var800a4920 = *(u32 *)g_BgPrimaryData; var800a4920 = *(u32 *)g_BgPrimaryData;
if (var800a4920 == 0) { if (var800a4920 == 0) {
g_BgPrimaryData2 = (u32 *)g_BgPrimaryData; g_BgPrimaryData2 = (uintptr_t*)g_BgPrimaryData;
g_BgRooms = (struct bgroom *)(g_BgPrimaryData2[1] + g_BgPrimaryData - 0x0f000000); g_BgRooms = (struct bgroom *)(g_BgPrimaryData2[1] + g_BgPrimaryData - 0x0f000000);
goto foo; foo:; goto foo; foo:;
g_Vars.roomcount = 0; g_Vars.roomcount = 0;
@@ -1998,10 +2007,6 @@ void bgBuildTables(s32 stagenum)
numlightsptr++; numlightsptr++;
} }
#ifndef PLATFORM_N64
preprocessBgLights(g_BgLightsFileData, 0);
#endif
// Free the section 3 allocation // Free the section 3 allocation
mempRealloc(section3, 0, MEMPOOL_STAGE); mempRealloc(section3, 0, MEMPOOL_STAGE);
@@ -2820,6 +2825,11 @@ void bgLoadRoom(s32 roomnum)
#endif #endif
} }
#ifdef PLATFORM_64BIT
alloclen = alloclen * 4; // just to be safe for now, adjust properly later #TODO
#endif
#ifdef PLATFORM_N64 #ifdef PLATFORM_N64
bgGarbageCollectRooms(alloclen, false); bgGarbageCollectRooms(alloclen, false);
@@ -2856,7 +2866,7 @@ void bgLoadRoom(s32 roomnum)
// Inflate the data to the left side of the allocation // Inflate the data to the left side of the allocation
inflatedlen = bgInflate(memaddr, allocation, g_BgRooms[roomnum + 1].unk00 - g_BgRooms[roomnum].unk00); inflatedlen = bgInflate(memaddr, allocation, g_BgRooms[roomnum + 1].unk00 - g_BgRooms[roomnum].unk00);
#ifndef PLATFORM_N64 #ifndef PLATFORM_N64
preprocessBgRoom(allocation, g_BgRooms[roomnum].unk00); inflatedlen = preprocessBgRoom(allocation, inflatedlen, g_BgRooms[roomnum].unk00);
#endif #endif
g_Rooms[roomnum].gfxdata = (struct roomgfxdata *)allocation; g_Rooms[roomnum].gfxdata = (struct roomgfxdata *)allocation;
@@ -2937,7 +2947,7 @@ void bgLoadRoom(s32 roomnum)
// Copy gdls to the right-side of the allocation // Copy gdls to the right-side of the allocation
// and build a pointer array to them // and build a pointer array to them
texCopyGdls((void *) gfxblocks[0], (void *) (allocation + alloclen - (gfxblocks[numgdls] - gfxblocks[0])), (u32) (gfxblocks[numgdls] - gfxblocks[0])); texCopyGdls((void *) gfxblocks[0], (void *) (allocation + alloclen - (gfxblocks[numgdls] - gfxblocks[0])), (uintptr_t) (gfxblocks[numgdls] - gfxblocks[0]));
for (i = 0; i < numgdls + 1; i++) { for (i = 0; i < numgdls + 1; i++) {
gdlpointers[i] = gfxblocks[i] + (allocation + alloclen - gfxblocks[numgdls]); gdlpointers[i] = gfxblocks[i] + (allocation + alloclen - gfxblocks[numgdls]);
@@ -3640,7 +3650,7 @@ bool bgTestHitOnObj(struct coord *arg0, struct coord *arg1, struct coord *arg2,
Gfx *imggdl = NULL; Gfx *imggdl = NULL;
s32 texturenum; s32 texturenum;
f32 lowestsqdist = MAXFLOAT; f32 lowestsqdist = MAXFLOAT;
s32 offset; uintptr_t offset;
s32 numvertices; s32 numvertices;
Gfx *tri4gdl; Gfx *tri4gdl;
s32 count; s32 count;
@@ -4243,7 +4253,7 @@ bool bgTestHitInVtxBatch(struct coord *arg0, struct coord *arg1, struct coord *a
vtx = bgFindVerticesForGdl(roomnum, gdl); vtx = bgFindVerticesForGdl(roomnum, gdl);
iter = &gdl[batch->gbicmdindex]; iter = &gdl[batch->gbicmdindex];
vtx = (Vtx *)((UNSEGADDR(iter->words.w1) & 0xffffff) + (s32)vtx); vtx = (Vtx *)((UNSEGADDR(iter->words.w1) & 0xffffff) + (uintptr_t)vtx);
numvertices = (((u32) iter->bytes[GFX_W0_BYTE(1)] >> 4) & 0xf) + 1; numvertices = (((u32) iter->bytes[GFX_W0_BYTE(1)] >> 4) & 0xf) + 1;
ptr = var800a6470; ptr = var800a6470;
@@ -4583,6 +4593,10 @@ bool bgTestHitInRoom(struct coord *frompos, struct coord *topos, s32 roomnum, st
numbatches = g_Rooms[roomnum].numvtxbatches; numbatches = g_Rooms[roomnum].numvtxbatches;
for (i = 0; i < numbatches; batch++, i++) { for (i = 0; i < numbatches; batch++, i++) {
#ifndef PLATFORM_N64
if (g_BgHitXluDisabled && batch->type == VTXBATCHTYPE_XLU)
continue;
#endif
j = bg0f1612e4(&batch->bbmin, &batch->bbmax, &from, &dist, &sp94, &hitthing->pos); j = bg0f1612e4(&batch->bbmin, &batch->bbmax, &from, &dist, &sp94, &hitthing->pos);
if (j == 0) { if (j == 0) {
@@ -6410,6 +6424,10 @@ void bgCalculateGlaresForVisibleRooms(void)
g_NumRoomsWithGlares = 0; g_NumRoomsWithGlares = 0;
// disable line-of-sight hits for transparent background
// surfaces before testing for light obstructions
g_BgHitXluDisabled = true;
if (!g_Vars.mplayerisrunning) { if (!g_Vars.mplayerisrunning) {
for (i = 1; i < g_Vars.roomcount; i++) { for (i = 1; i < g_Vars.roomcount; i++) {
if (g_Rooms[i].flags & ROOMFLAG_ONSCREEN) { if (g_Rooms[i].flags & ROOMFLAG_ONSCREEN) {
@@ -6420,6 +6438,9 @@ void bgCalculateGlaresForVisibleRooms(void)
} }
} }
} }
// re-enable background hits for transparent surfaces
g_BgHitXluDisabled = false;
} }
#endif #endif
+7 -7
View File
@@ -299,7 +299,7 @@ struct model *bodyAllocateModel(s32 bodynum, s32 headnum, u32 spawnflags)
if (spawnflags & SPAWNFLAG_FORCESUNGLASSES) { if (spawnflags & SPAWNFLAG_FORCESUNGLASSES) {
sunglasses = true; sunglasses = true;
} else if (spawnflags & SPAWNFLAG_MAYBESUNGLASSES) { } else if (spawnflags & SPAWNFLAG_MAYBESUNGLASSES) {
sunglasses = random() % 2 == 0; sunglasses = rngRandom() % 2 == 0;
} }
if (spawnflags & SPAWNFLAG_FIXEDHEIGHT) { if (spawnflags & SPAWNFLAG_FIXEDHEIGHT) {
@@ -325,7 +325,7 @@ s32 bodyChooseHead(s32 bodynum)
g_ActiveMaleHeadsIndex = 0; g_ActiveMaleHeadsIndex = 0;
} }
} else if (bodynum == BODY_FEM_GUARD) { } else if (bodynum == BODY_FEM_GUARD) {
head = g_FemGuardHeads[random() % 3]; head = g_FemGuardHeads[rngRandom() % 3];
} else { } else {
head = g_ActiveFemaleHeads[g_ActiveFemaleHeadsIndex++]; head = g_ActiveFemaleHeads[g_ActiveFemaleHeadsIndex++];
@@ -493,10 +493,10 @@ void bodyAllocateChr(s32 stagenum, struct packedchr *packed, s32 cmdindex)
if (packed->tude != 4) { if (packed->tude != 4) {
chr->tude = packed->tude; chr->tude = packed->tude;
} else { } else {
chr->tude = random() % 4; chr->tude = rngRandom() % 4;
} }
chr->voicebox = random() % 3; chr->voicebox = rngRandom() % 3;
if (!g_HeadsAndBodies[chr->bodynum].ismale) { if (!g_HeadsAndBodies[chr->bodynum].ismale) {
chr->voicebox = VOICEBOX_FEMALE; chr->voicebox = VOICEBOX_FEMALE;
@@ -519,7 +519,7 @@ void bodyAllocateChr(s32 stagenum, struct packedchr *packed, s32 cmdindex)
chr->flags |= CHRFLAG0_AIVSAI; chr->flags |= CHRFLAG0_AIVSAI;
} }
if (random() % 5 == 0) { if (rngRandom() % 5 == 0) {
// Make chr punch slower // Make chr punch slower
chr->flags2 |= CHRFLAG1_ADJUSTPUNCHSPEED; chr->flags2 |= CHRFLAG1_ADJUSTPUNCHSPEED;
} }
@@ -596,8 +596,8 @@ struct prop *bodyAllocateEyespy(struct pad *pad, RoomNum room)
chr->team = 0; chr->team = 0;
chr->squadron = 0; chr->squadron = 0;
chr->maxdamage = 2; chr->maxdamage = 2;
chr->tude = random() & 3; chr->tude = rngRandom() & 3;
chr->voicebox = random() % 3; chr->voicebox = rngRandom() % 3;
chr->naturalanim = 0; chr->naturalanim = 0;
chr->myspecial = 0; chr->myspecial = 0;
chr->yvisang = 0; chr->yvisang = 0;
+3 -3
View File
@@ -26,7 +26,7 @@ void bodiesReset(s32 stagenum)
g_HeadsAndBodies[i].modeldef = NULL; g_HeadsAndBodies[i].modeldef = NULL;
} }
var80062c80 = random() % g_NumBondBodies; var80062c80 = rngRandom() % g_NumBondBodies;
var80062b14 = 0; var80062b14 = 0;
var80062b18 = 0; var80062b18 = 0;
@@ -67,7 +67,7 @@ void bodiesReset(s32 stagenum)
for (i = 0; i < g_NumActiveHeadsPerGender; i++) { for (i = 0; i < g_NumActiveHeadsPerGender; i++) {
do { do {
done = true; done = true;
g_ActiveMaleHeads[i] = headsavailablelist[random() % headsavailablelen]; g_ActiveMaleHeads[i] = headsavailablelist[rngRandom() % headsavailablelen];
if (headsavailablelen > g_NumActiveHeadsPerGender) { if (headsavailablelen > g_NumActiveHeadsPerGender) {
for (j = 0; j < i; j++) { for (j = 0; j < i; j++) {
@@ -97,7 +97,7 @@ void bodiesReset(s32 stagenum)
for (i = 0; i < g_NumActiveHeadsPerGender; i++) { for (i = 0; i < g_NumActiveHeadsPerGender; i++) {
do { do {
done = true; done = true;
g_ActiveFemaleHeads[i] = headsavailablelist[random() % headsavailablelen]; g_ActiveFemaleHeads[i] = headsavailablelist[rngRandom() % headsavailablelen];
if (headsavailablelen > g_NumActiveHeadsPerGender) { if (headsavailablelen > g_NumActiveHeadsPerGender) {
for (j = 0; j < i; j++) { for (j = 0; j < i; j++) {
+1 -1
View File
@@ -1016,7 +1016,7 @@ void eyespyProcessInput(bool allowbuttons)
// Make eyespy look horizontally // Make eyespy look horizontally
if (domovecentre) { if (domovecentre) {
if (g_Vars.currentplayer->eyespy->verta > 0.0f && forwardspeed != 0) { if (g_Vars.currentplayer->eyespy->verta > 0.0f && forwardspeed != 0) {
if (controlmode < CONTROLMODE_PC) { if (controlmode != CONTROLMODE_PC) {
if (g_Vars.currentplayer->eyespy->verta < 180.0f) { if (g_Vars.currentplayer->eyespy->verta < 180.0f) {
tmp = g_Vars.currentplayer->eyespy->verta; tmp = g_Vars.currentplayer->eyespy->verta;
+75 -127
View File
@@ -56,8 +56,7 @@
#ifndef PLATFORM_N64 #ifndef PLATFORM_N64
#include "game/stagetable.h" #include "game/stagetable.h"
#include "video.h" #include "video.h"
#include "net/net.h" #include "platform.h"
#include "net/netmsg.h"
#endif #endif
#define GUNLOADSTATE_FLUX 0 #define GUNLOADSTATE_FLUX 0
@@ -167,8 +166,13 @@ u32 fill2[1];
Lights1 var80070090 = gdSPDefLights1(0x96, 0x96, 0x96, 0xff, 0xff, 0xff, 0xb2, 0x4d, 0x2e); Lights1 var80070090 = gdSPDefLights1(0x96, 0x96, 0x96, 0xff, 0xff, 0xff, 0xb2, 0x4d, 0x2e);
#ifdef PLATFORM_64BIT
u32 g_BgunGunMemBaseSizeDefault = 150 * 1024 * 2; // #TODO adjust these values properly
u32 g_BgunGunMemBaseSize4Mb2P = 120 * 1024 * 2;
#else
u32 g_BgunGunMemBaseSizeDefault = 150 * 1024; u32 g_BgunGunMemBaseSizeDefault = 150 * 1024;
u32 g_BgunGunMemBaseSize4Mb2P = 120 * 1024; u32 g_BgunGunMemBaseSize4Mb2P = 120 * 1024;
#endif
u16 g_CartFileNums[] = { u16 g_CartFileNums[] = {
FILE_GCARTRIDGE, FILE_GCARTRIDGE,
@@ -892,7 +896,7 @@ void bgunStartAnimation(struct guncmd *cmd, s32 handnum, struct hand *hand)
if (cmd->type != GUNCMD_PLAYANIMATION) { if (cmd->type != GUNCMD_PLAYANIMATION) {
struct guncmd *loopcmd = cmd; struct guncmd *loopcmd = cmd;
s32 done = false; s32 done = false;
u32 rand = random() % 100; u32 rand = rngRandom() % 100;
while (loopcmd->type != GUNCMD_END) { while (loopcmd->type != GUNCMD_END) {
if (bgun0f098884(loopcmd, &hand->gset) && !done) { if (bgun0f098884(loopcmd, &hand->gset) && !done) {
@@ -3796,17 +3800,17 @@ void bgunTickGunLoad(void)
{ {
s32 i; s32 i;
s32 numthistick; s32 numthistick;
u32 remaining; u64 remaining;
s32 padding; s32 padding;
u32 allocsize; u64 allocsize;
u32 loadsize; u64 loadsize;
u32 ptr; uintptr_t ptr;
struct player *player = g_Vars.currentplayer; struct player *player = g_Vars.currentplayer;
struct modeldef *modeldef; struct modeldef *modeldef;
struct fileinfo *fileinfo; struct fileinfo *fileinfo;
struct fileinfo *gunfileinfo; struct fileinfo *gunfileinfo;
s32 newvalue; uintptr_t newvalue;
u32 end; uintptr_t end;
u32 stack; u32 stack;
#if VERSION >= VERSION_NTSC_1_0 #if VERSION >= VERSION_NTSC_1_0
u32 stack2; u32 stack2;
@@ -3828,7 +3832,7 @@ void bgunTickGunLoad(void)
*player->gunctrl.loadmemptr = ptr; *player->gunctrl.loadmemptr = ptr;
*player->gunctrl.loadmemremaining = remaining; *player->gunctrl.loadmemremaining = remaining;
loadsize = ALIGN64(fileGetInflatedSize(player->gunctrl.loadfilenum)) + 0x8000; loadsize = ALIGN64(fileGetInflatedSize(player->gunctrl.loadfilenum, LOADTYPE_MODEL)) + 0x8000;
osSyncPrintf("BriGun: Loading - %s, pMem 0x%08x Size %d\n"); osSyncPrintf("BriGun: Loading - %s, pMem 0x%08x Size %d\n");
@@ -3846,6 +3850,9 @@ void bgunTickGunLoad(void)
// Reserve some space for textures // Reserve some space for textures
allocsize = fileGetLoadedSize(player->gunctrl.loadfilenum) + 0xe00; allocsize = fileGetLoadedSize(player->gunctrl.loadfilenum) + 0xe00;
#ifdef PLATFORM_64BIT
allocsize += 0xe00;
#endif
osSyncPrintf("BriGun: Used size %d (Ob Size %d)\n"); osSyncPrintf("BriGun: Used size %d (Ob Size %d)\n");
osSyncPrintf("BriGun: block len %d usedsize %d\n"); osSyncPrintf("BriGun: block len %d usedsize %d\n");
@@ -3856,7 +3863,7 @@ void bgunTickGunLoad(void)
fileinfo = &g_FileInfo[player->gunctrl.loadfilenum]; fileinfo = &g_FileInfo[player->gunctrl.loadfilenum];
fileinfo->allocsize = allocsize; fileinfo->allocsize = allocsize;
end = ALIGN16((s32)ptr + allocsize); end = ALIGN16((uintptr_t)ptr + allocsize);
allocsize = end - ptr; allocsize = end - ptr;
if (1); if (1);
remaining -= allocsize; remaining -= allocsize;
@@ -3927,7 +3934,7 @@ void bgunTickGunLoad(void)
modeldef0f1a7560(modeldef, player->gunctrl.loadfilenum, 0x05000000, modeldef, &player->gunctrl.texpool, false); modeldef0f1a7560(modeldef, player->gunctrl.loadfilenum, 0x05000000, modeldef, &player->gunctrl.texpool, false);
fileGetInflatedSize(player->gunctrl.loadfilenum); fileGetInflatedSize(player->gunctrl.loadfilenum, LOADTYPE_MODEL);
fileGetLoadedSize(player->gunctrl.loadfilenum); fileGetLoadedSize(player->gunctrl.loadfilenum);
fileGetLoadedSize(player->gunctrl.loadfilenum); fileGetLoadedSize(player->gunctrl.loadfilenum);
fileGetLoadedSize(player->gunctrl.loadfilenum); fileGetLoadedSize(player->gunctrl.loadfilenum);
@@ -3940,7 +3947,7 @@ void bgunTickGunLoad(void)
newvalue = ALIGN64(texGetPoolLeftPos(&player->gunctrl.texpool)); newvalue = ALIGN64(texGetPoolLeftPos(&player->gunctrl.texpool));
remaining = *player->gunctrl.loadmemremaining; remaining = *player->gunctrl.loadmemremaining;
remaining -= (s32)(newvalue - *player->gunctrl.loadmemptr); remaining -= (intptr_t)(newvalue - *player->gunctrl.loadmemptr);
*player->gunctrl.loadmemptr = newvalue; *player->gunctrl.loadmemptr = newvalue;
*player->gunctrl.loadmemremaining = remaining; *player->gunctrl.loadmemremaining = remaining;
@@ -4089,8 +4096,8 @@ void bgunTickMasterLoad(void)
player->gunctrl.gunloadstate = GUNLOADSTATE_MODEL; player->gunctrl.gunloadstate = GUNLOADSTATE_MODEL;
player->gunctrl.loadfilenum = handfilenum; player->gunctrl.loadfilenum = handfilenum;
player->gunctrl.loadtomodeldef = &player->gunctrl.handmodeldef; player->gunctrl.loadtomodeldef = &player->gunctrl.handmodeldef;
player->gunctrl.loadmemptr = (u32 *) &player->gunctrl.handmemloadptr; player->gunctrl.loadmemptr = (uintptr_t *) &player->gunctrl.handmemloadptr;
player->gunctrl.loadmemremaining = (u32 *) &player->gunctrl.handmemloadremaining; player->gunctrl.loadmemremaining = (uintptr_t*) &player->gunctrl.handmemloadremaining;
} }
bgunTickGunLoad(); bgunTickGunLoad();
@@ -4117,8 +4124,8 @@ void bgunTickMasterLoad(void)
player->gunctrl.gunloadstate = GUNLOADSTATE_MODEL; player->gunctrl.gunloadstate = GUNLOADSTATE_MODEL;
player->gunctrl.loadfilenum = filenum; player->gunctrl.loadfilenum = filenum;
player->gunctrl.loadtomodeldef = &player->gunctrl.gunmodeldef; player->gunctrl.loadtomodeldef = &player->gunctrl.gunmodeldef;
player->gunctrl.loadmemptr = (u32 *) &player->gunctrl.memloadptr; player->gunctrl.loadmemptr = (uintptr_t*) &player->gunctrl.memloadptr;
player->gunctrl.loadmemremaining = (u32 *) &player->gunctrl.memloadremaining; player->gunctrl.loadmemremaining = (uintptr_t*) &player->gunctrl.memloadremaining;
} }
bgunTickGunLoad(); bgunTickGunLoad();
@@ -4159,8 +4166,8 @@ void bgunTickMasterLoad(void)
player->gunctrl.loadfilenum = filenum; player->gunctrl.loadfilenum = filenum;
player->gunctrl.gunloadstate = GUNLOADSTATE_MODEL; player->gunctrl.gunloadstate = GUNLOADSTATE_MODEL;
player->gunctrl.loadtomodeldef = &player->gunctrl.cartmodeldef; player->gunctrl.loadtomodeldef = &player->gunctrl.cartmodeldef;
player->gunctrl.loadmemptr = (u32 *) &player->gunctrl.memloadptr; player->gunctrl.loadmemptr = (uintptr_t *) &player->gunctrl.memloadptr;
player->gunctrl.loadmemremaining = (u32 *) &player->gunctrl.memloadremaining; player->gunctrl.loadmemremaining = (uintptr_t*) &player->gunctrl.memloadremaining;
break; break;
} }
@@ -4186,18 +4193,18 @@ void bgunTickMasterLoad(void)
modelInit(&hand->handmodel, player->gunctrl.handmodeldef, hand->handsavedata, false); modelInit(&hand->handmodel, player->gunctrl.handmodeldef, hand->handsavedata, false);
} }
hand->unk0dcc = (s32 *) player->gunctrl.memloadptr; hand->unk0dcc = (uintptr_t *) player->gunctrl.memloadptr;
value = bgunCreateModelCmdList(&hand->gunmodel, player->gunctrl.gunmodeldef->rootnode, (s32 *) player->gunctrl.memloadptr); value = bgunCreateModelCmdList(&hand->gunmodel, player->gunctrl.gunmodeldef->rootnode, (uintptr_t *) player->gunctrl.memloadptr);
sum += value; sum += value;
player->gunctrl.memloadptr += value; player->gunctrl.memloadptr += value;
player->gunctrl.memloadremaining -= value; player->gunctrl.memloadremaining -= value;
if (player->gunctrl.handmodeldef != 0) { if (player->gunctrl.handmodeldef != 0) {
hand->unk0dd0 = (s32 *) player->gunctrl.memloadptr; hand->unk0dd0 = (uintptr_t*) player->gunctrl.memloadptr;
value = bgunCreateModelCmdList(&hand->handmodel, player->gunctrl.handmodeldef->rootnode, (s32 *) player->gunctrl.memloadptr); value = bgunCreateModelCmdList(&hand->handmodel, player->gunctrl.handmodeldef->rootnode, (uintptr_t*) player->gunctrl.memloadptr);
sum += value; sum += value;
player->gunctrl.memloadptr += value; player->gunctrl.memloadptr += value;
@@ -4474,7 +4481,7 @@ struct defaultobj *bgunCreateThrownProjectile2(struct chrdata *chr, struct gset
* 2 = fumbling grenade from right hand (due to nbomb) * 2 = fumbling grenade from right hand (due to nbomb)
* 3 = fumbling grenade from left hand (actually not possible) * 3 = fumbling grenade from left hand (actually not possible)
*/ */
struct defaultobj *bgunCreateThrownProjectile(s32 handnum, struct gset *gset) void bgunCreateThrownProjectile(s32 handnum, struct gset *gset)
{ {
struct coord velocity = {0, 0, 0}; struct coord velocity = {0, 0, 0};
Mtxf sp1f4; Mtxf sp1f4;
@@ -4504,13 +4511,6 @@ struct defaultobj *bgunCreateThrownProjectile(s32 handnum, struct gset *gset)
struct trainingdata *data; struct trainingdata *data;
u32 stack; u32 stack;
#ifndef PLATFORM_N64
// don't do anything if we're not the authority
if (g_NetMode == NETMODE_CLIENT) {
return NULL;
}
#endif
if (handnum >= 2) { if (handnum >= 2) {
droppinggrenade = true; droppinggrenade = true;
handnum -= 2; handnum -= 2;
@@ -4676,16 +4676,7 @@ struct defaultobj *bgunCreateThrownProjectile(s32 handnum, struct gset *gset)
weapon->base.hidden |= OBJHFLAG_THROWNKNIFE; weapon->base.hidden |= OBJHFLAG_THROWNKNIFE;
} }
} }
#ifndef PLATFORM_N64
if (obj && g_NetMode == NETMODE_SERVER) {
netmsgSvcPropSpawnWrite(&g_NetMsgRel, obj->prop);
netmsgSvcPropMoveWrite(&g_NetMsgRel, obj->prop, NULL);
}
#endif
} }
return obj;
} }
void bgunUpdateHeldRocket(s32 handnum) void bgunUpdateHeldRocket(s32 handnum)
@@ -4789,12 +4780,6 @@ void bgunCreateFiredProjectile(s32 handnum)
f32 spd4[4]; f32 spd4[4];
f32 spc4[4]; f32 spc4[4];
#ifndef PLATFORM_N64
if (g_NetMode == NETMODE_CLIENT) {
return;
}
#endif
hand = g_Vars.currentplayer->hands + handnum; hand = g_Vars.currentplayer->hands + handnum;
playerprop = g_Vars.currentplayer->prop; playerprop = g_Vars.currentplayer->prop;
@@ -5007,12 +4992,6 @@ void bgunCreateFiredProjectile(s32 handnum)
weapon->base.prop = NULL; weapon->base.prop = NULL;
weapon->base.model = NULL; weapon->base.model = NULL;
} }
#ifndef PLATFORM_N64
else if (g_NetMode == NETMODE_SERVER) {
netmsgSvcPropSpawnWrite(&g_NetMsgRel, weapon->base.prop);
netmsgSvcPropMoveWrite(&g_NetMsgRel, weapon->base.prop, NULL);
}
#endif
#else #else
// NTSC beta doesn't have any of the failure checks // NTSC beta doesn't have any of the failure checks
Mtxf sp78; Mtxf sp78;
@@ -6343,13 +6322,6 @@ void bgunDisarm(struct prop *attackerprop)
s32 modelnum; s32 modelnum;
s32 i; s32 i;
bool drop; bool drop;
struct defaultobj *obj;
#ifndef PLATFORM_N64
// don't do anything if we're not the authority
if (g_NetMode == NETMODE_CLIENT) {
return;
}
#endif
if (!weaponHasFlag(weaponnum, WEAPONFLAG_UNDROPPABLE) && weaponnum <= WEAPON_RCP45) { if (!weaponHasFlag(weaponnum, WEAPONFLAG_UNDROPPABLE) && weaponnum <= WEAPON_RCP45) {
#if VERSION >= VERSION_NTSC_1_0 #if VERSION >= VERSION_NTSC_1_0
@@ -6367,12 +6339,6 @@ void bgunDisarm(struct prop *attackerprop)
return; return;
} }
#ifndef PLATFORM_N64
if (g_NetMode == NETMODE_SERVER) {
netmsgSvcChrDisarmWrite(&g_NetMsgRel, player->prop->chr, attackerprop, weaponnum, 0.f, NULL);
}
#endif
chr = player->prop->chr; chr = player->prop->chr;
drop = true; drop = true;
@@ -6401,7 +6367,7 @@ void bgunDisarm(struct prop *attackerprop)
&& player->hands[i].stateminor == HANDSTATEMINOR_ATTACK_THROW_0) { && player->hands[i].stateminor == HANDSTATEMINOR_ATTACK_THROW_0) {
#endif #endif
drop = false; drop = false;
obj = bgunCreateThrownProjectile(i + 2, &player->hands[i].gset); bgunCreateThrownProjectile(i + 2, &player->hands[i].gset);
} }
} }
} }
@@ -6425,13 +6391,6 @@ void bgunDisarm(struct prop *attackerprop)
} }
objDrop(prop2, true); objDrop(prop2, true);
#ifndef PLATFORM_N64
if (g_NetMode == NETMODE_SERVER) {
netmsgSvcPropSpawnWrite(&g_NetMsgRel, prop2);
netmsgSvcPropMoveWrite(&g_NetMsgRel, prop2, NULL);
}
#endif
} }
} }
@@ -6465,7 +6424,7 @@ void bgunDisarm(struct prop *attackerprop)
* *
* With this function stubbed, part of the CMP150 model does not render. * With this function stubbed, part of the CMP150 model does not render.
*/ */
void bgunExecuteModelCmdList(s32 *ptr) void bgunExecuteModelCmdList(uintptr_t *ptr)
{ {
union modelrwdata *rwdata; union modelrwdata *rwdata;
struct modelnode *node; struct modelnode *node;
@@ -6522,7 +6481,7 @@ void bgunExecuteModelCmdList(s32 *ptr)
* iterate the command list to update part visibility rather than iterate the * iterate the command list to update part visibility rather than iterate the
* full model tree. * full model tree.
*/ */
s32 bgunCreateModelCmdList(struct model *model, struct modelnode *nodearg, s32 *ptr) s32 bgunCreateModelCmdList(struct model *model, struct modelnode *nodearg, uintptr_t *ptr)
{ {
s32 len = 0; s32 len = 0;
struct modelnode *node = nodearg; struct modelnode *node = nodearg;
@@ -6539,11 +6498,11 @@ s32 bgunCreateModelCmdList(struct model *model, struct modelnode *nodearg, s32 *
rwdata->distance.visible = false; rwdata->distance.visible = false;
node->child = rodata->distance.target; node->child = rodata->distance.target;
ptr[0] = 0; ptr[0] = 0;
ptr[1] = (s32)rwdata; ptr[1] = (uintptr_t)rwdata;
ptr[2] = (s32)node; ptr[2] = (uintptr_t)node;
ptr[3] = (s32)rodata->distance.target; ptr[3] = (uintptr_t)rodata->distance.target;
ptr += 4; ptr += 4;
len += 16; len += 4 * sizeof(uintptr_t);
break; break;
case MODELNODETYPE_TOGGLE: case MODELNODETYPE_TOGGLE:
rodata = node->rodata; rodata = node->rodata;
@@ -6551,36 +6510,36 @@ s32 bgunCreateModelCmdList(struct model *model, struct modelnode *nodearg, s32 *
rwdata->toggle.visible = true; rwdata->toggle.visible = true;
node->child = rodata->toggle.target; node->child = rodata->toggle.target;
ptr[0] = 1; ptr[0] = 1;
ptr[1] = (s32)rwdata; ptr[1] = (uintptr_t)rwdata;
ptr[2] = (s32)node; ptr[2] = (uintptr_t)node;
ptr[3] = (s32)rodata->toggle.target; ptr[3] = (uintptr_t)rodata->toggle.target;
ptr += 4; ptr += 4;
len += 16; len += 4 * sizeof(uintptr_t);
break; break;
case MODELNODETYPE_HEADSPOT: case MODELNODETYPE_HEADSPOT:
rwdata = modelGetNodeRwData(model, node); rwdata = modelGetNodeRwData(model, node);
rwdata->headspot.headmodeldef = NULL; rwdata->headspot.headmodeldef = NULL;
rwdata->headspot.rwdatas = NULL; rwdata->headspot.rwdatas = NULL;
ptr[0] = 2; ptr[0] = 2;
ptr[1] = (s32)rwdata; ptr[1] = (uintptr_t)rwdata;
ptr += 2; ptr += 2;
len += 8; len += 2 * sizeof(uintptr_t);
break; break;
case MODELNODETYPE_0B: case MODELNODETYPE_0B:
rwdata = modelGetNodeRwData(model, node); rwdata = modelGetNodeRwData(model, node);
rwdata->type0b.unk00 = 0; rwdata->type0b.unk00 = 0;
ptr[0] = 3; ptr[0] = 3;
ptr[1] = (s32)rwdata; ptr[1] = (uintptr_t)rwdata;
ptr += 2; ptr += 2;
len += 8; len += 2 * sizeof(uintptr_t);
break; break;
case MODELNODETYPE_CHRGUNFIRE: case MODELNODETYPE_CHRGUNFIRE:
rwdata = modelGetNodeRwData(model, node); rwdata = modelGetNodeRwData(model, node);
rwdata->chrgunfire.visible = false; rwdata->chrgunfire.visible = false;
ptr[0] = 4; ptr[0] = 4;
ptr[1] = (s32)rwdata; ptr[1] = (uintptr_t)rwdata;
ptr += 2; ptr += 2;
len += 8; len += 2 * sizeof(uintptr_t);
break; break;
case MODELNODETYPE_DL: case MODELNODETYPE_DL:
rodata = node->rodata; rodata = node->rodata;
@@ -6589,12 +6548,12 @@ s32 bgunCreateModelCmdList(struct model *model, struct modelnode *nodearg, s32 *
rwdata->dl.gdl = rodata->dl.opagdl; rwdata->dl.gdl = rodata->dl.opagdl;
rwdata->dl.colours = (void *)ALIGN8((uintptr_t)&rodata->dl.vertices[rodata->dl.numvertices]); rwdata->dl.colours = (void *)ALIGN8((uintptr_t)&rodata->dl.vertices[rodata->dl.numvertices]);
ptr[0] = 5; ptr[0] = 5;
ptr[1] = (s32)rwdata; ptr[1] = (uintptr_t)rwdata;
ptr[2] = (s32)rwdata->dl.vertices; ptr[2] = (uintptr_t)rwdata->dl.vertices;
ptr[3] = (s32)rwdata->dl.gdl; ptr[3] = (uintptr_t)rwdata->dl.gdl;
ptr[4] = (s32)rwdata->dl.colours; ptr[4] = (uintptr_t)rwdata->dl.colours;
ptr += 5; ptr += 5;
len += 20; len += 5 * sizeof(uintptr_t);
break; break;
} }
@@ -6618,7 +6577,7 @@ s32 bgunCreateModelCmdList(struct model *model, struct modelnode *nodearg, s32 *
} }
*ptr = 6; *ptr = 6;
len += 4; len += sizeof(uintptr_t);
return len; return len;
} }
@@ -7211,7 +7170,7 @@ void bgunUpdateMagnum(struct hand *hand, s32 handnum, struct modeldef *modeldef,
if (modeldef != NULL) { if (modeldef != NULL) {
for (i = 0; i < hand->unk0cc8_04; i++) { for (i = 0; i < hand->unk0cc8_04; i++) {
struct modelnode *node = modelGetPart(modeldef, 0x0a + random() % 6); struct modelnode *node = modelGetPart(modeldef, 0x0a + rngRandom() % 6);
if (node) { if (node) {
s32 index = modelFindNodeMtxIndex(node, 0); s32 index = modelFindNodeMtxIndex(node, 0);
@@ -8518,7 +8477,7 @@ glabel var7f1aca90
/* f0a71e4: 100002d5 */ b .L0f0a7d3c /* f0a71e4: 100002d5 */ b .L0f0a7d3c
/* f0a71e8: 8fbf0034 */ lw $ra,0x34($sp) /* f0a71e8: 8fbf0034 */ lw $ra,0x34($sp)
.L0f0a71ec: .L0f0a71ec:
/* f0a71ec: 0fc5d9ad */ jal zbufDrawArtifactsOffscreen /* f0a71ec: 0fc5d9ad */ jal zbufSaveArtifactDepths
/* f0a71f0: 8fa4014c */ lw $a0,0x14c($sp) /* f0a71f0: 8fa4014c */ lw $a0,0x14c($sp)
/* f0a71f4: afa2014c */ sw $v0,0x14c($sp) /* f0a71f4: afa2014c */ sw $v0,0x14c($sp)
/* f0a71f8: 0c002ca0 */ jal viPrepareZbuf /* f0a71f8: 0c002ca0 */ jal viPrepareZbuf
@@ -9359,7 +9318,7 @@ glabel var7f1aca90
/* f0a71e4: 100002d5 */ b .L0f0a7d3c /* f0a71e4: 100002d5 */ b .L0f0a7d3c
/* f0a71e8: 8fbf0034 */ lw $ra,0x34($sp) /* f0a71e8: 8fbf0034 */ lw $ra,0x34($sp)
.L0f0a71ec: .L0f0a71ec:
/* f0a71ec: 0fc5d9ad */ jal zbufDrawArtifactsOffscreen /* f0a71ec: 0fc5d9ad */ jal zbufSaveArtifactDepths
/* f0a71f0: 8fa4014c */ lw $a0,0x14c($sp) /* f0a71f0: 8fa4014c */ lw $a0,0x14c($sp)
/* f0a71f4: afa2014c */ sw $v0,0x14c($sp) /* f0a71f4: afa2014c */ sw $v0,0x14c($sp)
/* f0a71f8: 0c002ca0 */ jal viPrepareZbuf /* f0a71f8: 0c002ca0 */ jal viPrepareZbuf
@@ -10200,7 +10159,7 @@ glabel var7f1aca90
/* f0a4f30: 100002cd */ beqz $zero,.NB0f0a5a68 /* f0a4f30: 100002cd */ beqz $zero,.NB0f0a5a68
/* f0a4f34: 8fbf0034 */ lw $ra,0x34($sp) /* f0a4f34: 8fbf0034 */ lw $ra,0x34($sp)
.NB0f0a4f38: .NB0f0a4f38:
/* f0a4f38: 0fc5c4d5 */ jal zbufDrawArtifactsOffscreen /* f0a4f38: 0fc5c4d5 */ jal zbufSaveArtifactDepths
/* f0a4f3c: 8fa40144 */ lw $a0,0x144($sp) /* f0a4f3c: 8fa40144 */ lw $a0,0x144($sp)
/* f0a4f40: afa20144 */ sw $v0,0x144($sp) /* f0a4f40: afa20144 */ sw $v0,0x144($sp)
/* f0a4f44: 0c002d00 */ jal viPrepareZbuf /* f0a4f44: 0c002d00 */ jal viPrepareZbuf
@@ -10983,7 +10942,6 @@ void bgunRender(Gfx **gdlptr)
struct modelrenderdata renderdata = {NULL, true, 3}; // 10c struct modelrenderdata renderdata = {NULL, true, 3}; // 10c
struct player *player; struct player *player;
s32 i; s32 i;
const u32 wnorm = mtx00016dcc(0, 300);
static bool renderhand = true; // var800702dc static bool renderhand = true; // var800702dc
@@ -10999,7 +10957,7 @@ void bgunRender(Gfx **gdlptr)
} }
#ifdef PLATFORM_N64 // TODO #ifdef PLATFORM_N64 // TODO
gdl = zbufDrawArtifactsOffscreen(gdl); gdl = zbufSaveArtifactDepths(gdl);
#endif #endif
gdl = viPrepareZbuf(gdl); gdl = viPrepareZbuf(gdl);
gdl = vi0000b1d0(gdl); gdl = vi0000b1d0(gdl);
@@ -11049,7 +11007,7 @@ void bgunRender(Gfx **gdlptr)
gSPLookAt(gdl++, camGetLookAt()); gSPLookAt(gdl++, camGetLookAt());
} }
gSPPerspNormalize(gdl++, wnorm); gSPPerspNormalize(gdl++, mtx00016dcc(0, 300));
// There is support for guns having a TV screen on them // There is support for guns having a TV screen on them
// but no guns have this model part so it's not used. // but no guns have this model part so it's not used.
@@ -11224,17 +11182,7 @@ void bgunRender(Gfx **gdlptr)
} }
} }
#ifndef PLATFORM_N64
// put the casings into the same Z range as the gun
gSPPerspNormalize(gdl++, wnorm);
#endif
casingsRender(&gdl); casingsRender(&gdl);
#ifndef PLATFORM_N64
gSPPerspNormalize(gdl++, viGetPerspScale());
#endif
zbufSwap(); zbufSwap();
gdl = zbufConfigureRdp(gdl); gdl = zbufConfigureRdp(gdl);
@@ -11266,8 +11214,8 @@ struct sndstate **bgunAllocateAudioHandle(void)
void bgunPlayPropHitSound(struct gset *gset, struct prop *prop, s32 texturenum) void bgunPlayPropHitSound(struct gset *gset, struct prop *prop, s32 texturenum)
{ {
#if VERSION >= VERSION_NTSC_1_0 #if VERSION >= VERSION_NTSC_1_0
u32 rand1 = random(); u32 rand1 = rngRandom();
u32 rand2 = random(); u32 rand2 = rngRandom();
struct sndstate **handle; struct sndstate **handle;
if (g_Vars.lvupdate240 <= 0) { if (g_Vars.lvupdate240 <= 0) {
@@ -11346,8 +11294,8 @@ void bgunPlayPropHitSound(struct gset *gset, struct prop *prop, s32 texturenum)
if (texturenum == 10000) { if (texturenum == 10000) {
soundnum = SFX_SHIELD_DAMAGE; soundnum = SFX_SHIELD_DAMAGE;
} else if (gset->weaponnum == WEAPON_LASER) { } else if (gset->weaponnum == WEAPON_LASER) {
if (gset->weaponfunc == FUNC_PRIMARY || ((gset->unk063a % 4) == 0 && (random() % 2))) { if (gset->weaponfunc == FUNC_PRIMARY || ((gset->unk063a % 4) == 0 && (rngRandom() % 2))) {
if ((random() % 2) == 0) { if ((rngRandom() % 2) == 0) {
soundnum = SFX_CLOAK_ON; soundnum = SFX_CLOAK_ON;
} else { } else {
soundnum = SFX_CLOAK_OFF; soundnum = SFX_CLOAK_OFF;
@@ -11411,8 +11359,8 @@ void bgunPlayPropHitSound(struct gset *gset, struct prop *prop, s32 texturenum)
} }
} }
#else #else
u32 rand1 = random(); u32 rand1 = rngRandom();
u32 rand2 = random(); u32 rand2 = rngRandom();
struct sndstate **handle; struct sndstate **handle;
if (g_Vars.lvupdate240 <= 0) { if (g_Vars.lvupdate240 <= 0) {
@@ -11485,7 +11433,7 @@ void bgunPlayPropHitSound(struct gset *gset, struct prop *prop, s32 texturenum)
soundnum = SFX_SHIELD_DAMAGE; soundnum = SFX_SHIELD_DAMAGE;
} else if (gset->weaponnum == WEAPON_LASER) { } else if (gset->weaponnum == WEAPON_LASER) {
if (gset->weaponfunc == FUNC_PRIMARY || (gset->unk063a % 8) == 0) { if (gset->weaponfunc == FUNC_PRIMARY || (gset->unk063a % 8) == 0) {
if ((random() % 2) == 0) { if ((rngRandom() % 2) == 0) {
soundnum = SFX_CLOAK_ON; soundnum = SFX_CLOAK_ON;
} else { } else {
soundnum = SFX_CLOAK_OFF; soundnum = SFX_CLOAK_OFF;
@@ -11563,8 +11511,8 @@ void bgunPlayBgHitSound(struct gset *gset, struct coord *hitpos, s32 texturenum,
{ {
#if VERSION >= VERSION_NTSC_1_0 #if VERSION >= VERSION_NTSC_1_0
struct sndstate **handle; struct sndstate **handle;
u32 rand1 = random(); u32 rand1 = rngRandom();
u32 rand2 = random(); u32 rand2 = rngRandom();
bool playdefault; bool playdefault;
s16 soundnum; s16 soundnum;
bool overridden; bool overridden;
@@ -11587,7 +11535,7 @@ void bgunPlayBgHitSound(struct gset *gset, struct coord *hitpos, s32 texturenum,
if (gset->weaponnum == WEAPON_LASER) { if (gset->weaponnum == WEAPON_LASER) {
playdefault = false; playdefault = false;
if (gset->weaponfunc == FUNC_PRIMARY || ((gset->unk063a % 4) == 0 && (random() % 2))) { if (gset->weaponfunc == FUNC_PRIMARY || ((gset->unk063a % 4) == 0 && (rngRandom() % 2))) {
// Laser sounds // Laser sounds
s16 sounds[] = {SFX_CLOAK_ON, SFX_CLOAK_OFF}; s16 sounds[] = {SFX_CLOAK_ON, SFX_CLOAK_OFF};
soundnum = sounds[rand1 % ARRAYCOUNT(sounds)]; soundnum = sounds[rand1 % ARRAYCOUNT(sounds)];
@@ -11662,8 +11610,8 @@ void bgunPlayBgHitSound(struct gset *gset, struct coord *hitpos, s32 texturenum,
} }
#else #else
struct sndstate **handle; struct sndstate **handle;
u32 rand1 = random(); u32 rand1 = rngRandom();
u32 rand2 = random(); u32 rand2 = rngRandom();
s16 soundnum; s16 soundnum;
bool overridden; bool overridden;
@@ -11784,7 +11732,7 @@ void bgunSetTriggerOn(s32 handnum, bool on)
s32 bgunConsiderToggleGunFunction(s32 usedowntime, bool trigpressed, bool fromactivemenu, bool fromdedicatedbutton) s32 bgunConsiderToggleGunFunction(s32 usedowntime, bool trigpressed, bool fromactivemenu, bool fromdedicatedbutton)
{ {
#ifndef PLATFORM_N64 #ifndef PLATFORM_N64
const bool extcontrols = PLAYER_EXTCFG().extcontrols || g_Vars.currentplayer->isremote; const bool extcontrols = PLAYER_EXTCFG().extcontrols;
bool docontinue; bool docontinue;
#endif #endif
switch (bgunGetWeaponNum(HAND_RIGHT)) { switch (bgunGetWeaponNum(HAND_RIGHT)) {
@@ -11903,7 +11851,7 @@ void bgun0f0a8c50(void)
case WEAPON_LAPTOPGUN: case WEAPON_LAPTOPGUN:
case WEAPON_DRAGON: case WEAPON_DRAGON:
case WEAPON_REMOTEMINE: case WEAPON_REMOTEMINE:
if (PLAYER_EXTCFG().extcontrols || g_Vars.currentplayer->isremote) { if (PLAYER_EXTCFG().extcontrols) {
return; return;
} }
break; break;
@@ -12806,7 +12754,7 @@ Gfx *bgunDrawHud(Gfx *gdl)
{ {
struct player *player = g_Vars.currentplayer; struct player *player = g_Vars.currentplayer;
s32 bottom = viGetViewTop() + viGetViewHeight() - 13; s32 bottom = viGetViewTop() + viGetViewHeight() - 13;
s32 playercount = LOCALPLAYERCOUNT(); s32 playercount = PLAYERCOUNT();
s32 playernum = g_Vars.currentplayernum; s32 playernum = g_Vars.currentplayernum;
struct gunctrl *ctrl; struct gunctrl *ctrl;
s32 secs60; s32 secs60;
+90 -261
View File
@@ -42,10 +42,6 @@
#include <math.h> #include <math.h>
#include "input.h" #include "input.h"
#include "video.h" #include "video.h"
#include "system.h"
#include "utils.h"
#include "net/net.h"
#include "net/netmsg.h"
static void bgunProcessQuickDetonate(struct movedata *data, u32 c1buttons, u32 c1buttonsthisframe, u32 buttons1, u32 buttons2) { static void bgunProcessQuickDetonate(struct movedata *data, u32 c1buttons, u32 c1buttonsthisframe, u32 buttons1, u32 buttons2) {
if ((((c1buttons & (buttons1)) && (c1buttonsthisframe & (buttons2))) if ((((c1buttons & (buttons1)) && (c1buttonsthisframe & (buttons2)))
@@ -109,159 +105,6 @@ static void bgunProcessInputAltButton(struct movedata *data, s8 contpad, s32 i)
} }
} }
static inline void bmoveProcessRemoteInput(const bool allowc1buttons)
{
struct player *pl = g_Vars.currentplayer;
if (!pl->client) {
return;
}
struct netplayermove *inmove = &pl->client->inmove[0];
struct netplayermove *inmoveprev = &pl->client->inmove[1];
s32 moveticks = inmove->tick - inmoveprev->tick;
if (moveticks > g_NetInterpTicks) {
moveticks = g_NetInterpTicks;
}
const bool handled = (pl->client->inmovetick >= inmove->tick);
if (!inmove->tick) {
// no input
inmove->pos = inmoveprev->pos = pl->prop->pos;
inmove->angles[0] = inmoveprev->angles[0] = pl->vv_theta;
inmove->angles[1] = inmoveprev->angles[1] = pl->vv_verta;
inmove->ucmd = 0;
}
if (inmove->ucmd & UCMD_DUCK) {
pl->crouchpos = CROUCHPOS_DUCK;
} else if (inmove->ucmd & UCMD_SQUAT) {
pl->crouchpos = CROUCHPOS_SQUAT;
} else {
pl->crouchpos = CROUCHPOS_STAND;
}
pl->bondactivateorreload = 0;
pl->eyesshut = (inmove->ucmd & UCMD_EYESSHUT) != 0;
pl->speedtheta = 0.f; // TODO: figure out if anglespeed is even required
pl->speedverta = 0.f;
pl->crouchoffset = inmove->crouchofs;
pl->oldcrosspos[0] = pl->crosspos[0];
pl->oldcrosspos[1] = pl->crosspos[1];
pl->crosspos[0] = inmove->crosspos[0];
pl->crosspos[1] = inmove->crosspos[1];
// denormalize crosspos x
pl->crosspos[0] -= (f32)(SCREEN_WIDTH_LO / 2);
pl->crosspos[0] = (f32)(SCREEN_WIDTH_LO / 2) + pl->crosspos[0] / pl->aspect * SCREEN_ASPECT;
pl->crosspos2[0] = pl->crosspos[0];
pl->crosspos2[1] = pl->crosspos[1];
pl->insightaimmode = (inmove->ucmd & UCMD_AIMMODE) != 0;
if (pl->insightaimmode) {
pl->gunzoomfovs[0] = pl->gunzoomfovs[1] = pl->gunzoomfovs[2] = inmove->zoomfov;
}
f32 zoomfov = 0.f;
if (pl->insightaimmode) {
zoomfov = currentPlayerGetGunZoomFov();
}
if (bgunGetWeaponNum(HAND_RIGHT) == WEAPON_AR34 && pl->hands[HAND_RIGHT].gset.weaponfunc == FUNC_SECONDARY) {
zoomfov = currentPlayerGetGunZoomFov();
}
if (zoomfov <= 0.f) {
zoomfov = pl->client->settings.fovy;
}
playerTweenFovY(zoomfov);
playerUpdateZoom();
for (s32 h = 0; h < 2; ++h) {
pl->hands[h].crosspos[0] = pl->crosspos[0];
pl->hands[h].crosspos[1] = pl->crosspos[1];
}
if (inmove->ucmd & UCMD_SELECT) {
pl->gunctrl.dualwielding = (inmove->ucmd & UCMD_SELECT_DUAL) != 0;
if (inmove->weaponnum >= 0) {
bgunEquipWeapon(inmove->weaponnum);
}
}
if ((inmove->ucmd & UCMD_SECONDARY) && !bgunIsUsingSecondaryFunction()) {
bgunConsiderToggleGunFunction(0, false, false, true);
} else if (!(inmove->ucmd & UCMD_SECONDARY) && bgunIsUsingSecondaryFunction()) {
// do not switch back to primary if in the process of throwing laptop
if (!(bgunGetWeaponNum(HAND_RIGHT) == WEAPON_LAPTOPGUN && pl->hands[HAND_RIGHT].state == HANDSTATE_ATTACK)) {
bgunConsiderToggleGunFunction(0, false, false, true);
}
}
const bool fireguns = (inmove->ucmd & UCMD_FIRE) && !pl->waitforzrelease && allowc1buttons;
bgunTickGameplay(fireguns);
if (fireguns && g_NetMode == NETMODE_SERVER) {
netmsgSvcPlayerStatsWrite(&g_NetMsgRel, pl->client);
}
if (!handled && (inmove->ucmd & UCMD_RELOAD)) {
pl->bondactivateorreload |= JO_ACTION_RELOAD;
}
if (g_NetMode == NETMODE_SERVER) {
if (!handled && (inmove->ucmd & UCMD_ACTIVATE)) {
pl->bondactivateorreload |= JO_ACTION_ACTIVATE;
}
if (g_Vars.bondvisible && (bgunIsFiring(HAND_RIGHT) || bgunIsFiring(HAND_LEFT))) {
f32 noiseradius = 0.f;
if (bgunIsFiring(HAND_RIGHT) && bgunGetNoiseRadius(HAND_RIGHT) > noiseradius) {
noiseradius = bgunGetNoiseRadius(HAND_RIGHT);
}
if (bgunIsFiring(HAND_LEFT) && bgunGetNoiseRadius(HAND_LEFT) > noiseradius) {
noiseradius = bgunGetNoiseRadius(HAND_LEFT);
}
chrsCheckForNoise(noiseradius);
}
}
bgunSetSightVisible(GUNSIGHTREASON_NOTAIMING, pl->insightaimmode);
const bool forcepos = !inmoveprev->tick || !moveticks || (inmove->ucmd & UCMD_FL_FORCEANGLE);
// lerp towards the current speeds and angles
const f32 dt = (forcepos ? 1.f : (1.f / (f32)moveticks));
f32 t = (forcepos ? 1.f : ((f32)pl->client->lerpticks / (f32)moveticks));
if (t > 1.f) {
t = 1.f;
}
pl->speedgo = pl->speedforwards = lerpf(inmoveprev->movespeed[0], inmove->movespeed[0], t);
pl->speedstrafe = pl->speedsideways = lerpf(inmoveprev->movespeed[1], inmove->movespeed[1], t);
pl->vv_theta = lerpanglef(pl->vv_theta, inmove->angles[0], dt);
pl->vv_verta = lerpanglef(pl->vv_verta, inmove->angles[1], dt);
if (pl->bondmovemode == MOVEMODE_GRAB) {
bgrabUpdateSpeedTheta();
} else if (pl->bondmovemode == MOVEMODE_WALK) {
if (bmoveGetCrouchPos() != CROUCHPOS_STAND) {
pl->speedmaxtime60 = 0;
}
bwalkSetSwayTargetf(inmove->leanofs);
} else if (pl->bondmovemode == MOVEMODE_BIKE) {
// TODO
}
if (inmove->movespeed[0] > 0.95f) {
pl->speedmaxtime60 += g_Vars.lvupdate60;
} else {
pl->speedmaxtime60 = 0;
}
}
#endif // PLATFORM_N64 #endif // PLATFORM_N64
void bmoveSetControlDef(u32 controldef) void bmoveSetControlDef(u32 controldef)
@@ -470,39 +313,6 @@ void bmoveApplyMoveData(struct movedata *data)
} else if (g_Vars.currentplayer->bondmovemode == MOVEMODE_WALK) { } else if (g_Vars.currentplayer->bondmovemode == MOVEMODE_WALK) {
bwalkApplyMoveData(data); bwalkApplyMoveData(data);
} }
#ifndef PLATFORM_N64
// record some inputs if this is a local player
if (g_NetMode && !g_Vars.currentplayer->isremote) {
g_Vars.currentplayer->ucmd = 0;
if (g_Vars.currentplayer->isdead) {
if (g_NetMode == NETMODE_CLIENT) {
if (joyGetButtons(optionsGetContpadNum1(g_Vars.currentplayerstats->mpindex), 0xb000)) {
g_Vars.currentplayer->ucmd |= UCMD_RESPAWN;
}
}
} else {
if (data->triggeron) {
g_Vars.currentplayer->ucmd |= UCMD_FIRE;
}
if (data->aiming) {
g_Vars.currentplayer->ucmd |= UCMD_AIMMODE;
}
if (g_Vars.currentplayer->bondactivateorreload & JO_ACTION_ACTIVATE) {
g_Vars.currentplayer->ucmd |= UCMD_ACTIVATE;
}
if (g_Vars.currentplayer->bondactivateorreload & JO_ACTION_RELOAD) {
g_Vars.currentplayer->ucmd |= UCMD_RELOAD;
}
if (data->eyesshut) {
g_Vars.currentplayer->ucmd |= UCMD_EYESSHUT;
}
if (data->weaponbackoffset || data->weaponforwardoffset) {
g_Vars.currentplayer->ucmd |= UCMD_SELECT;
}
}
}
#endif
} }
void bmoveUpdateSpeedTheta(void) void bmoveUpdateSpeedTheta(void)
@@ -519,11 +329,11 @@ void bmoveUpdateSpeedTheta(void)
f32 bmoveGetSpeedVertaLimit(f32 value) f32 bmoveGetSpeedVertaLimit(f32 value)
{ {
if (value > 0) { if (value > 0) {
return (viGetFovY() * value * -0.7f) / 60.0f; return (viGetFovY() * value * -0.7f) / PLAYER_DEFAULT_FOV;
} }
if (value < 0) { if (value < 0) {
return (viGetFovY() * -value * 0.7f) / 60.0f; return (viGetFovY() * -value * 0.7f) / PLAYER_DEFAULT_FOV;
} }
return 0; return 0;
@@ -531,7 +341,7 @@ f32 bmoveGetSpeedVertaLimit(f32 value)
void bmoveUpdateSpeedVerta(f32 value) void bmoveUpdateSpeedVerta(f32 value)
{ {
f32 mult = viGetFovY() / 60.0f; f32 mult = viGetFovY() / PLAYER_DEFAULT_FOV;
f32 limit = bmoveGetSpeedVertaLimit(value); f32 limit = bmoveGetSpeedVertaLimit(value);
if (value > 0) { if (value > 0) {
@@ -574,11 +384,11 @@ void bmoveUpdateSpeedVerta(f32 value)
f32 bmoveGetSpeedThetaControlLimit(f32 value) f32 bmoveGetSpeedThetaControlLimit(f32 value)
{ {
if (value > 0) { if (value > 0) {
return (viGetFovY() * value * -0.7f) / 60.0f; return (viGetFovY() * value * -0.7f) / PLAYER_DEFAULT_FOV;
} }
if (value < 0) { if (value < 0) {
return (viGetFovY() * -value * 0.7f) / 60.0f; return (viGetFovY() * -value * 0.7f) / PLAYER_DEFAULT_FOV;
} }
return 0; return 0;
@@ -586,7 +396,7 @@ f32 bmoveGetSpeedThetaControlLimit(f32 value)
void bmoveUpdateSpeedThetaControl(f32 value) void bmoveUpdateSpeedThetaControl(f32 value)
{ {
f32 mult = viGetFovY() / 60.0f; f32 mult = viGetFovY() / PLAYER_DEFAULT_FOV;
f32 limit = bmoveGetSpeedThetaControlLimit(value); f32 limit = bmoveGetSpeedThetaControlLimit(value);
if (value > 0) { if (value > 0) {
@@ -626,6 +436,38 @@ void bmoveUpdateSpeedThetaControl(f32 value)
} }
} }
/**
* Apply crosshair swivel based on camera movement with input detection
*/
static void bmoveApplyCrosshairSwivel(struct movedata *movedata, f32 mlookscale, f32 *x, f32 *y)
{
#ifdef PLATFORM_N64
*x = g_Vars.currentplayer->speedtheta * 0.3f + g_Vars.currentplayer->gunextraaimx;
*y = -g_Vars.currentplayer->speedverta * 0.1f + g_Vars.currentplayer->gunextraaimy;
#else
f32 xscale, yscale;
bool mouse_active = (movedata->freelookdx || movedata->freelookdy);
bool joystick_active = (movedata->c1stickxraw != 0 || movedata->c1stickyraw != 0);
if ((mouse_active) && joystick_active) {
// Mouse + joystick sway
xscale = PLAYER_EXTCFG().crosshairsway * 0.80f; // 80% for precision+joystick sway
yscale = PLAYER_EXTCFG().crosshairsway * 0.80f; // 80% for precision+joystick sway
} else if (mouse_active) {
// Mouse sway
xscale = PLAYER_EXTCFG().crosshairsway * 0.20f; // 20% for mouse sway
yscale = PLAYER_EXTCFG().crosshairsway * 0.30f; // 30% for mouse sway
} else {
// Joystick only or no input - full sway
xscale = yscale = PLAYER_EXTCFG().crosshairsway;
}
// Joystick x/y scaling
// 0.3f for x, 0.1f for y
*x = g_Vars.currentplayer->speedtheta * 0.3f * xscale + g_Vars.currentplayer->gunextraaimx;
*y = -g_Vars.currentplayer->speedverta * 0.1f * yscale + g_Vars.currentplayer->gunextraaimy;
#endif
}
/** /**
* Calculate the lookahead angle. * Calculate the lookahead angle.
* *
@@ -908,14 +750,6 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
#endif #endif
controlmode = optionsGetControlMode(g_Vars.currentplayerstats->mpindex); controlmode = optionsGetControlMode(g_Vars.currentplayerstats->mpindex);
#ifndef PLATFORM_N64
if (g_Vars.currentplayer->isremote || controlmode == CONTROLMODE_NA) {
bmoveProcessRemoteInput(allowc1buttons);
return;
}
#endif
weaponnum = bgunGetWeaponNum(HAND_RIGHT); weaponnum = bgunGetWeaponNum(HAND_RIGHT);
canmanualzoom = weaponHasAimFlag(weaponnum, INVAIMFLAG_MANUALZOOM); canmanualzoom = weaponHasAimFlag(weaponnum, INVAIMFLAG_MANUALZOOM);
contpad1 = optionsGetContpadNum1(g_Vars.currentplayerstats->mpindex); contpad1 = optionsGetContpadNum1(g_Vars.currentplayerstats->mpindex);
@@ -978,6 +812,12 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
movedata.freelookdy = -movedata.freelookdy; movedata.freelookdy = -movedata.freelookdy;
} }
} }
// always pause with ESC
if (allowc1buttons && g_Vars.currentplayer->isdead == false && g_Vars.currentplayer->pausemode == PAUSEMODE_UNPAUSED) {
if (inputKeyJustPressed(VK_ESCAPE)) {
c1buttonsthisframe |= START_BUTTON;
}
}
#endif #endif
// Pausing // Pausing
@@ -1099,7 +939,9 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
aimoffhist[i] = !aimonhist[i]; aimoffhist[i] = !aimonhist[i];
} }
g_Vars.currentplayer->insightaimmode = aimonhist[numsamples - 1]; if (numsamples > 0) {
g_Vars.currentplayer->insightaimmode = aimonhist[numsamples - 1];
}
} }
if (!lvIsPaused()) { if (!lvIsPaused()) {
@@ -1223,7 +1065,7 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
} }
// Handle B button activation // Handle B button activation
if (allowc1buttons && controlmode < CONTROLMODE_PC) { if (allowc1buttons && controlmode != CONTROLMODE_PC) {
for (i = 0; i < numsamples; i++) { for (i = 0; i < numsamples; i++) {
if (joyGetButtonsOnSample(i, contpad1, c1allowedbuttons & B_BUTTON) if (joyGetButtonsOnSample(i, contpad1, c1allowedbuttons & B_BUTTON)
|| joyGetButtonsOnSample(i, contpad2, c2allowedbuttons & B_BUTTON)) { || joyGetButtonsOnSample(i, contpad2, c2allowedbuttons & B_BUTTON)) {
@@ -1430,10 +1272,9 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
aimoffhist[i] = !aimonhist[i]; aimoffhist[i] = !aimonhist[i];
} }
#ifdef AVOID_UB if (numsamples > 0) {
if (numsamples) g_Vars.currentplayer->insightaimmode = aimonhist[numsamples - 1];
#endif }
g_Vars.currentplayer->insightaimmode = aimonhist[numsamples - 1];
} }
if (!lvIsPaused()) { if (!lvIsPaused()) {
@@ -1603,31 +1444,31 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
} }
#ifndef PLATFORM_N64 #ifndef PLATFORM_N64
// Handle turning and looking up/down via mouselook when aiming // Handle turning and looking (x/y) via mouselook when aiming
if (g_Vars.currentplayer->insightaimmode && allowmcross && bgunGetWeaponNum(HAND_RIGHT) != WEAPON_HORIZONSCANNER) { bool allowcross = allowmcross;
if (g_Vars.currentplayer->swivelpos[0] > 0.9f) { if (g_Vars.currentplayer->insightaimmode && allowcross && bgunGetWeaponNum(HAND_RIGHT) != WEAPON_HORIZONSCANNER) {
movedata.aimturnrightspeed = (g_Vars.currentplayer->swivelpos[0] - 0.9f) / 0.1f; float edge_boundary = PLAYER_EXTCFG().crosshairedgeboundary;
movedata.aimturnleftspeed = 0.f; if (g_Vars.currentplayer->swivelpos[0] > edge_boundary) {
} else if (g_Vars.currentplayer->swivelpos[0] < -0.9f) { movedata.aimturnrightspeed += (g_Vars.currentplayer->swivelpos[0] - edge_boundary) / (1.0f - edge_boundary);
movedata.aimturnleftspeed = (g_Vars.currentplayer->swivelpos[0] - -0.9f) / -0.1f; } else if (g_Vars.currentplayer->swivelpos[0] < -edge_boundary) {
movedata.aimturnrightspeed = 0.f; movedata.aimturnleftspeed += (g_Vars.currentplayer->swivelpos[0] + edge_boundary) / -(1.0f - edge_boundary);
} }
f32 vertaup = 0.f, vertadown = 0.f; f32 vertaup = 0.f, vertadown = 0.f;
if (g_Vars.currentplayer->swivelpos[1] > 0.9f) { if (g_Vars.currentplayer->swivelpos[1] > edge_boundary) {
vertaup = (g_Vars.currentplayer->swivelpos[1] - 0.9f) / 0.1f; vertaup = (g_Vars.currentplayer->swivelpos[1] - edge_boundary) / (1.0f - edge_boundary);
} else if (g_Vars.currentplayer->swivelpos[1] < -0.9f) { } else if (g_Vars.currentplayer->swivelpos[1] < -edge_boundary) {
vertadown = (g_Vars.currentplayer->swivelpos[1] - -0.9f) / -0.1f; vertadown = (g_Vars.currentplayer->swivelpos[1] + edge_boundary) / -(1.0f - edge_boundary);
} }
// Uninvert pitch if needed // Uninvert pitch if needed
if (movedata.invertpitch) { if (movedata.invertpitch) {
movedata.speedvertaup = vertadown; movedata.speedvertaup += vertadown;
movedata.speedvertadown = vertaup; movedata.speedvertadown += vertaup;
} else { } else {
movedata.speedvertaup = vertaup; movedata.speedvertaup += vertaup;
movedata.speedvertadown = vertadown; movedata.speedvertadown += vertadown;
} }
} else { } else {
// Reset mouse aim position when not mouse aiming // Reset mouse aim position when not aiming
g_Vars.currentplayer->swivelpos[0] = 0.f; g_Vars.currentplayer->swivelpos[0] = 0.f;
g_Vars.currentplayer->swivelpos[1] = 0.f; g_Vars.currentplayer->swivelpos[1] = 0.f;
} }
@@ -1694,7 +1535,7 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
for (i = 0; i < numsamples; i++) { for (i = 0; i < numsamples; i++) {
if (joyGetButtonsOnSample(i, contpad1, c1allowedbuttons & usemask)) { if (joyGetButtonsOnSample(i, contpad1, c1allowedbuttons & usemask)) {
if (g_Vars.currentplayer->usedowntime >= -1) { if (g_Vars.currentplayer->usedowntime >= -1) {
if (controlmode < CONTROLMODE_PC) { if (controlmode != CONTROLMODE_PC) {
if (joyGetButtonsPressedOnSample(i, contpad1, shootbuttons & c1allowedbuttons) if (joyGetButtonsPressedOnSample(i, contpad1, shootbuttons & c1allowedbuttons)
&& g_Vars.currentplayer->usedowntime >= 0 && g_Vars.currentplayer->usedowntime >= 0
&& bgunConsiderToggleGunFunction(g_Vars.currentplayer->usedowntime, true, false, 0) != USETIMER_CONTINUE) { && bgunConsiderToggleGunFunction(g_Vars.currentplayer->usedowntime, true, false, 0) != USETIMER_CONTINUE) {
@@ -1719,7 +1560,7 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
} }
} }
} else { } else {
if ((controlmode < CONTROLMODE_PC) && g_Vars.currentplayer->usedowntime >= -2) { if ((controlmode != CONTROLMODE_PC) && g_Vars.currentplayer->usedowntime >= -2) {
bgunConsiderToggleGunFunction(g_Vars.currentplayer->usedowntime, false, false, 0); bgunConsiderToggleGunFunction(g_Vars.currentplayer->usedowntime, false, false, 0);
} }
} }
@@ -1774,6 +1615,7 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
} }
// Handle xbla-style crouch cycling // Handle xbla-style crouch cycling
const s32 oldcrouchpos = g_Vars.currentplayer->crouchpos;
for (i = 0; i < numsamples; i++) { for (i = 0; i < numsamples; i++) {
// handle 1964GEPD style crouch setting // handle 1964GEPD style crouch setting
s32 crouchsample; s32 crouchsample;
@@ -1815,6 +1657,10 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
} }
} }
} }
// prevent uncrouching if we don't fit
while (g_Vars.currentplayer->crouchpos > oldcrouchpos && !bwalkCanUncrouch()) {
g_Vars.currentplayer->crouchpos--;
}
} }
#endif #endif
@@ -1865,7 +1711,7 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
#ifdef PLATFORM_N64 #ifdef PLATFORM_N64
if (allowc1buttons) { if (allowc1buttons) {
#else #else
if (allowc1buttons && (controlmode < CONTROLMODE_PC || (PLAYER_EXTCFG().crouchmode & CROUCHMODE_ANALOG))) { if (allowc1buttons && (controlmode != CONTROLMODE_PC || (PLAYER_EXTCFG().crouchmode & CROUCHMODE_ANALOG))) {
#endif #endif
for (i = 0; i < numsamples; i++) { for (i = 0; i < numsamples; i++) {
if (!canmanualzoom && aimonhist[i]) { if (!canmanualzoom && aimonhist[i]) {
@@ -1949,7 +1795,7 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
} }
// Handle mine detonation // Handle mine detonation
if (controlmode < CONTROLMODE_PC) { if (controlmode != CONTROLMODE_PC) {
if ((((c1buttons & invbuttons) && (c1buttonsthisframe & B_BUTTON)) if ((((c1buttons & invbuttons) && (c1buttonsthisframe & B_BUTTON))
|| ((c1buttons & B_BUTTON) && (c1buttonsthisframe & invbuttons))) || ((c1buttons & B_BUTTON) && (c1buttonsthisframe & invbuttons)))
&& weaponnum == WEAPON_REMOTEMINE) { && weaponnum == WEAPON_REMOTEMINE) {
@@ -1982,7 +1828,7 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
movedata.triggeron = g_Vars.currentplayer->waitforzrelease == false movedata.triggeron = g_Vars.currentplayer->waitforzrelease == false
&& (c1buttons & shootbuttons) && (c1buttons & shootbuttons)
&& g_Vars.currentplayer->pausemode == PAUSEMODE_UNPAUSED; && g_Vars.currentplayer->pausemode == PAUSEMODE_UNPAUSED;
if (controlmode < CONTROLMODE_PC) { if (controlmode != CONTROLMODE_PC) {
movedata.triggeron = movedata.triggeron && ((c1buttons & invbuttons) == 0); movedata.triggeron = movedata.triggeron && ((c1buttons & invbuttons) == 0);
} }
} }
@@ -1996,7 +1842,9 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
g_Vars.currentplayer->bondactivateorreload = 0; g_Vars.currentplayer->bondactivateorreload = 0;
s32 usereloads = (controlmode != CONTROLMODE_PC);
#ifndef PLATFORM_N64 #ifndef PLATFORM_N64
usereloads = usereloads || PLAYER_EXTCFG().usereloads;
if (controlmode == CONTROLMODE_PC && movedata.alt1tapcount) { if (controlmode == CONTROLMODE_PC && movedata.alt1tapcount) {
g_Vars.currentplayer->bondactivateorreload = g_Vars.currentplayer->bondactivateorreload | JO_ACTION_RELOAD; g_Vars.currentplayer->bondactivateorreload = g_Vars.currentplayer->bondactivateorreload | JO_ACTION_RELOAD;
} }
@@ -2004,7 +1852,7 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
if (movedata.btapcount) { if (movedata.btapcount) {
g_Vars.currentplayer->activatetimelast = g_Vars.currentplayer->activatetimethis; g_Vars.currentplayer->activatetimelast = g_Vars.currentplayer->activatetimethis;
g_Vars.currentplayer->activatetimethis = g_Vars.lvframe60; g_Vars.currentplayer->activatetimethis = g_Vars.lvframe60;
if (controlmode == CONTROLMODE_PC) { if (!usereloads) {
g_Vars.currentplayer->bondactivateorreload = g_Vars.currentplayer->bondactivateorreload | JO_ACTION_ACTIVATE; g_Vars.currentplayer->bondactivateorreload = g_Vars.currentplayer->bondactivateorreload | JO_ACTION_ACTIVATE;
} else { } else {
g_Vars.currentplayer->bondactivateorreload = movedata.btapcount ? g_Vars.currentplayer->bondactivateorreload = movedata.btapcount ?
@@ -2216,7 +2064,7 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
} }
} else { } else {
if (movedata.cannaturalpitch) { if (movedata.cannaturalpitch) {
tmp = viGetFovY() / 60.0f; tmp = viGetFovY() / PLAYER_DEFAULT_FOV;
fVar25 = movedata.analogpitch / 70.0f; fVar25 = movedata.analogpitch / 70.0f;
if (fVar25 > 1) { if (fVar25 > 1) {
@@ -2257,7 +2105,7 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
} }
if (movedata.cannaturalturn) { if (movedata.cannaturalturn) {
tmp = viGetFovY() / 60.0f; tmp = viGetFovY() / PLAYER_DEFAULT_FOV;
fVar25 = movedata.analogturn / 70.0f; fVar25 = movedata.analogturn / 70.0f;
if (fVar25 > 1) { if (fVar25 > 1) {
@@ -2370,15 +2218,8 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
x = g_Vars.currentplayer->speedtheta * 0.3f + g_Vars.currentplayer->gunextraaimx; x = g_Vars.currentplayer->speedtheta * 0.3f + g_Vars.currentplayer->gunextraaimx;
y = -g_Vars.currentplayer->speedverta * 0.1f + g_Vars.currentplayer->gunextraaimy; y = -g_Vars.currentplayer->speedverta * 0.1f + g_Vars.currentplayer->gunextraaimy;
#else #else
f32 xscale, yscale; // Crosshair swivel movement system
if (movedata.freelookdx || movedata.freelookdy) { bmoveApplyCrosshairSwivel(&movedata, mlookscale, &x, &y);
xscale = PLAYER_EXTCFG().crosshairsway * 0.20f;
yscale = PLAYER_EXTCFG().crosshairsway * 0.30f;
} else {
xscale = yscale = PLAYER_EXTCFG().crosshairsway;
}
x = g_Vars.currentplayer->speedtheta * 0.3f * xscale + g_Vars.currentplayer->gunextraaimx;
y = -g_Vars.currentplayer->speedverta * 0.1f * yscale + g_Vars.currentplayer->gunextraaimy;
#endif #endif
bgunSwivelWithDamp(x, y, PAL ? 0.955f : 0.963f); bgunSwivelWithDamp(x, y, PAL ? 0.955f : 0.963f);
@@ -2390,8 +2231,10 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i
#ifndef PLATFORM_N64 #ifndef PLATFORM_N64
if (allowmcross) { if (allowmcross) {
// joystick is inactive, move crosshair using the mouse // joystick is inactive, move crosshair using the mouse
const f32 xscale = PLAYER_EXTCFG().mouseaimspeedx * 320.f / (f32)videoGetWidth(); const f32 xcoeff = 320.f / 1080.f;
const f32 yscale = PLAYER_EXTCFG().mouseaimspeedy * 240.f / (f32)videoGetHeight(); const f32 ycoeff = 240.f / 1080.f;
const f32 xscale = (PLAYER_EXTCFG().mouseaimspeedx * xcoeff) / g_Vars.currentplayer->aspect;
const f32 yscale = PLAYER_EXTCFG().mouseaimspeedy * ycoeff;
f32 x = g_Vars.currentplayer->swivelpos[0] + movedata.freelookdx * xscale; f32 x = g_Vars.currentplayer->swivelpos[0] + movedata.freelookdx * xscale;
f32 y = g_Vars.currentplayer->swivelpos[1] + movedata.freelookdy * yscale; f32 y = g_Vars.currentplayer->swivelpos[1] + movedata.freelookdy * yscale;
x = (x < -1.f) ? -1.f : ((x > 1.f) ? 1.f : x); x = (x < -1.f) ? -1.f : ((x > 1.f) ? 1.f : x);
@@ -2572,14 +2415,6 @@ void bmoveTick(bool allowc1x, bool allowc1y, bool allowc1buttons, bool ignorec2)
void bmoveUpdateVerta(void) void bmoveUpdateVerta(void)
{ {
while (g_Vars.currentplayer->vv_verta < -180) {
g_Vars.currentplayer->vv_verta += 360;
}
while (g_Vars.currentplayer->vv_verta >= 180) {
g_Vars.currentplayer->vv_verta -= 360;
}
if (g_Vars.currentplayer->vv_verta > 90) { if (g_Vars.currentplayer->vv_verta > 90) {
g_Vars.currentplayer->vv_verta = 90; g_Vars.currentplayer->vv_verta = 90;
} else if (g_Vars.currentplayer->vv_verta < -90) { } else if (g_Vars.currentplayer->vv_verta < -90) {
@@ -2684,7 +2519,7 @@ void bmoveUpdateHead(f32 arg0, f32 arg1, f32 arg2, Mtxf *arg3, f32 arg4)
} }
} else { } else {
if (g_Vars.currentplayer->startnewbonddie) { if (g_Vars.currentplayer->startnewbonddie) {
bheadStartDeathAnimation(g_DeathAnimations[random() % g_NumDeathAnimations], random() % 2, 0, 1); bheadStartDeathAnimation(g_DeathAnimations[rngRandom() % g_NumDeathAnimations], rngRandom() % 2, 0, 1);
g_Vars.currentplayer->startnewbonddie = false; g_Vars.currentplayer->startnewbonddie = false;
} }
@@ -2695,13 +2530,7 @@ void bmoveUpdateHead(f32 arg0, f32 arg1, f32 arg2, Mtxf *arg3, f32 arg4)
bheadUpdate(sp244, arg2); bheadUpdate(sp244, arg2);
mtx4LoadXRotation(BADDEG2RAD(360 - g_Vars.currentplayer->vv_verta360), &sp180); mtx4LoadXRotation(BADDEG2RAD(360 - g_Vars.currentplayer->vv_verta360), &sp180);
#ifdef PLATFORM_N64
if (optionsGetHeadRoll(g_Vars.currentplayerstats->mpindex)) { if (optionsGetHeadRoll(g_Vars.currentplayerstats->mpindex)) {
#else
// in net games only allow headroll in the death animation
// TODO: figure out how to deal with headroll in other situations
if (optionsGetHeadRoll(g_Vars.currentplayerstats->mpindex) && (!g_NetMode || g_Vars.currentplayer->isdead)) {
#endif
mtx00016d58(&sp116, mtx00016d58(&sp116,
0, 0, 0, 0, 0, 0,
-g_Vars.currentplayer->headlook.x, -g_Vars.currentplayer->headlook.y, -g_Vars.currentplayer->headlook.z, -g_Vars.currentplayer->headlook.x, -g_Vars.currentplayer->headlook.y, -g_Vars.currentplayer->headlook.z,
+48 -13
View File
@@ -31,7 +31,7 @@ char var800a41c0[26];
char var800a41c0[24]; char var800a41c0[24];
#endif #endif
u8 g_IrScanlines[2][480]; u8 g_IrScanlines[4][480];
#if VERSION < VERSION_NTSC_1_0 #if VERSION < VERSION_NTSC_1_0
u8 var800a8b58nb[0x1c0]; u8 var800a8b58nb[0x1c0];
@@ -335,7 +335,7 @@ Gfx *bviewDrawStatic(Gfx *gdl, u32 arg1, s32 arg2)
s32 viewheight = viGetViewHeight(); s32 viewheight = viGetViewHeight();
s32 viewwidth = viGetViewWidth(); s32 viewwidth = viGetViewWidth();
s32 viewleft = viGetViewLeft(); s32 viewleft = viGetViewLeft();
u16 *fb2 = (u16 *) PHYS_TO_K0(random() & 0xfff00); u16 *fb2 = (u16 *) PHYS_TO_K0(rngRandom() & 0xfff00);
s32 y; s32 y;
gDPPipeSync(gdl++); gDPPipeSync(gdl++);
@@ -344,7 +344,7 @@ Gfx *bviewDrawStatic(Gfx *gdl, u32 arg1, s32 arg2)
#ifdef PLATFORM_N64 #ifdef PLATFORM_N64
for (y = viewtop; y < viewtop + viewheight; y++) { for (y = viewtop; y < viewtop + viewheight; y++) {
gdl = bviewCopyPixels(gdl, fb2, random() % 240, 5, y, 1.0f, viewleft, viewwidth); gdl = bviewCopyPixels(gdl, fb2, rngRandom() % 240, 5, y, 1.0f, viewleft, viewwidth);
} }
#else #else
gDPSetCombineLERP(gdl++, gDPSetCombineLERP(gdl++,
@@ -468,8 +468,8 @@ Gfx *bviewDrawFilmInterlace(Gfx *gdl, u32 colour, u32 alpha)
} }
} }
if (random() % 20 == 1) { if (rngRandom() % 20 == 1) {
tmpy = random() % 200; tmpy = rngRandom() % 200;
} }
gdl = bviewCopyPixels(gdl, fb, tmpy, 5, y, 1, viewleft, viewwidth); gdl = bviewCopyPixels(gdl, fb, tmpy, 5, y, 1, viewleft, viewwidth);
@@ -490,8 +490,8 @@ Gfx *bviewDrawFilmInterlace(Gfx *gdl, u32 colour, u32 alpha)
} }
} }
if (random() % 20 == 1) { if (rngRandom() % 20 == 1) {
tmpy += random() % 200; tmpy += rngRandom() % 200;
} }
gDPFillRectangle(gdl++, viewleft, tmpy, viewleft + viewwidth, tmpy + 1); gDPFillRectangle(gdl++, viewleft, tmpy, viewleft + viewwidth, tmpy + 1);
@@ -762,9 +762,9 @@ Gfx *bviewDrawFisheye(Gfx *gdl, u32 colour, u32 alpha, s32 shuttertime60, s8 sta
for (i = viewtop; i < viewtop + viewheight; i++) { for (i = viewtop; i < viewtop + viewheight; i++) {
if (hit == EYESPYHIT_DAMAGE) { if (hit == EYESPYHIT_DAMAGE) {
alpha2 = (random() % 120) + 120; alpha2 = (rngRandom() % 120) + 120;
colour = 0xff333300 | (alpha2 & 0xff); colour = 0xff333300 | (alpha2 & 0xff);
f22 = ((random() % 32) + (f32) FBALLOC_HEIGHT) * (1.0f / 256.0f); f22 = ((rngRandom() % 32) + (f32) FBALLOC_HEIGHT) * (1.0f / 256.0f);
gDPSetEnvColorViaWord(gdl++, colour); gDPSetEnvColorViaWord(gdl++, colour);
} else { } else {
@@ -1109,6 +1109,10 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
s32 x = viewleft + (viewwidth >> 1); s32 x = viewleft + (viewwidth >> 1);
s32 y = viewtop + (viewheight >> 1); s32 y = viewtop + (viewheight >> 1);
#ifndef PLATFORM_N64
gDPSetSubpixelOffsetEXT(gdl++, -2, -2);
#endif
gDPFillRectangle(gdl++, x + 2, y + 0, x + 7, y + 1); gDPFillRectangle(gdl++, x + 2, y + 0, x + 7, y + 1);
gDPFillRectangle(gdl++, x + 2, y + 0, x + 5, y + 1); gDPFillRectangle(gdl++, x + 2, y + 0, x + 5, y + 1);
gDPFillRectangle(gdl++, x - 6, y + 0, x - 1, y + 1); gDPFillRectangle(gdl++, x - 6, y + 0, x - 1, y + 1);
@@ -1117,6 +1121,10 @@ Gfx *bviewDrawEyespyMetrics(Gfx *gdl)
gDPFillRectangle(gdl++, x + 0, y + 2, x + 1, y + 5); gDPFillRectangle(gdl++, x + 0, y + 2, x + 1, y + 5);
gDPFillRectangle(gdl++, x + 0, y - 6, x + 1, y - 1); gDPFillRectangle(gdl++, x + 0, y - 6, x + 1, y - 1);
gDPFillRectangle(gdl++, x + 0, y - 4, x + 1, y - 1); gDPFillRectangle(gdl++, x + 0, y - 4, x + 1, y - 1);
#ifndef PLATFORM_N64
gDPSetSubpixelOffsetEXT(gdl++, 0, 0);
#endif
} }
if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_CAMSPY) { if (g_Vars.currentplayer->eyespy->mode == EYESPYMODE_CAMSPY) {
@@ -2163,7 +2171,7 @@ Gfx *bviewDrawNvLens(Gfx *gdl)
u8 green; u8 green;
if (((var8007f878 & 1) != (y & 1)) != 0) { if (((var8007f878 & 1) != (y & 1)) != 0) {
u8 tmp = random() % 12; u8 tmp = rngRandom() % 12;
green = 0xff - tmp; green = 0xff - tmp;
} else { } else {
green = 0x94; green = 0x94;
@@ -2181,7 +2189,7 @@ Gfx *bviewDrawNvLens(Gfx *gdl)
u8 green; u8 green;
if (((var8007f878 & 1) != (y & 1)) != 0) { if (((var8007f878 & 1) != (y & 1)) != 0) {
u8 tmp = random() % 12; u8 tmp = rngRandom() % 12;
green = 0xff - tmp; green = 0xff - tmp;
} else { } else {
green = 0x94; green = 0x94;
@@ -2348,6 +2356,10 @@ Gfx *bviewDrawIrLens(Gfx *gdl)
gSPSetExtraGeometryModeEXT(gdl++, G_MODULATE_EXT); gSPSetExtraGeometryModeEXT(gdl++, G_MODULATE_EXT);
#endif #endif
// fixes off by one error w/ two top players
if (g_Vars.currentplayernum == 0 || g_Vars.currentplayernum == 1) {
scanbottom++;
}
for (i = scantop; i < scanbottom; i++) { for (i = scantop; i < scanbottom; i++) {
#if VERSION >= VERSION_NTSC_1_0 #if VERSION >= VERSION_NTSC_1_0
if (i & 1) { if (i & 1) {
@@ -2363,7 +2375,7 @@ Gfx *bviewDrawIrLens(Gfx *gdl)
} }
#endif #endif
red += random() % 8; red += rngRandom() % 8;
if (red > 255) { if (red > 255) {
red = 255; red = 255;
@@ -2384,6 +2396,10 @@ Gfx *bviewDrawIrLens(Gfx *gdl)
s32 semicirclewidth = sqrtf(sqinnerradius - (s32) (f0 * f0)) * (viewwidth / (f32) SCREEN_WIDTH_LO); s32 semicirclewidth = sqrtf(sqinnerradius - (s32) (f0 * f0)) * (viewwidth / (f32) SCREEN_WIDTH_LO);
s32 semicircleright = viewcentrex + semicirclewidth; s32 semicircleright = viewcentrex + semicirclewidth;
s32 rightsidewidth = viewwidth - semicircleright; s32 rightsidewidth = viewwidth - semicircleright;
// if playernum is 1 or 3, shift to the right by viewwidth
if (g_Vars.currentplayernum == 1 || g_Vars.currentplayernum == 3) {
rightsidewidth += viewwidth;
}
#ifdef PLATFORM_N64 #ifdef PLATFORM_N64
// Left and right of semicircle // Left and right of semicircle
@@ -2397,14 +2413,22 @@ Gfx *bviewDrawIrLens(Gfx *gdl)
gdl = bviewCopyPixels(gdl, fb, i, 5, i, 1.0f, viewleft, viewwidth); gdl = bviewCopyPixels(gdl, fb, i, 5, i, 1.0f, viewleft, viewwidth);
} }
#else #else
// Left and right of semicircle
// Scanlines to the left and right of the semicircle
gDPFillRectangle(gdl++, viewleft, i, viewcentrex, i + 1); gDPFillRectangle(gdl++, viewleft, i, viewcentrex, i + 1);
if (PLAYERCOUNT() <= 2 && g_Vars.currentplayernum == 0 && i == viewcentrey) {
semicircleright -= 1;
}
else if (PLAYERCOUNT() > 2 && (g_Vars.currentplayernum == 1 || g_Vars.currentplayernum == 3 ) && i == viewcentrey) {
semicircleright -= 1;
}
gDPFillRectangle(gdl++, semicircleright, i, semicircleright + rightsidewidth, i + 1); gDPFillRectangle(gdl++, semicircleright, i, semicircleright + rightsidewidth, i + 1);
// The semicircle itself has a static colour // The semicircle itself has a static colour
gDPSetPrimColorViaWord(gdl++, 0, 0, 0xee0000ff); gDPSetPrimColorViaWord(gdl++, 0, 0, 0xee0000ff);
gDPFillRectangle(gdl++, viewcentrex, i, viewcentrex + semicirclewidth, i + 1); gDPFillRectangle(gdl++, viewcentrex, i, viewcentrex + semicirclewidth, i + 1);
} else { } else {
// scanlines above and below the semicircle
gDPFillRectangle(gdl++, viewleft, i, viewleft + viewwidth, i + 1); gDPFillRectangle(gdl++, viewleft, i, viewleft + viewwidth, i + 1);
} }
#endif #endif
@@ -2773,6 +2797,10 @@ Gfx *bviewDrawIrBinoculars(Gfx *gdl)
s32 viewleft = viGetViewLeft(); s32 viewleft = viGetViewLeft();
s32 viewright = viewleft + viewwidth; s32 viewright = viewleft + viewwidth;
s32 viewbottom = viewtop + viewheight; s32 viewbottom = viewtop + viewheight;
// fixes off by one error w/ two top players
if (g_Vars.currentplayernum == 0 || g_Vars.currentplayernum == 1) {
viewbottom++;
}
s32 leftx = viewleft + viewwidth / 3; s32 leftx = viewleft + viewwidth / 3;
s32 rightx = viewleft + (viewwidth * 2) / 3; s32 rightx = viewleft + (viewwidth * 2) / 3;
s32 centrey = (viewtop + viewbottom) / 2; s32 centrey = (viewtop + viewbottom) / 2;
@@ -2790,6 +2818,13 @@ Gfx *bviewDrawIrBinoculars(Gfx *gdl)
for (y = viewtop; y < viewbottom; y++) { for (y = viewtop; y < viewbottom; y++) {
s32 ytocentre = centrey - y; s32 ytocentre = centrey - y;
s32 sqytocentre = ytocentre * ytocentre; s32 sqytocentre = ytocentre * ytocentre;
if (PLAYERCOUNT() <= 2) {
sqytocentre += 1;
} else if (PLAYERCOUNT() > 2) {
if (g_Vars.currentplayernum == 1 || g_Vars.currentplayernum == 3) {
sqytocentre += 1;
}
}
if (sqytocentre < sqradius) { if (sqytocentre < sqradius) {
s32 xoffset = (viewwidth / (f32) SCREEN_WIDTH_LO) * sqrtf(sqradius - sqytocentre); s32 xoffset = (viewwidth / (f32) SCREEN_WIDTH_LO) * sqrtf(sqradius - sqytocentre);
+80 -73
View File
@@ -27,69 +27,7 @@
#include "data.h" #include "data.h"
#include "types.h" #include "types.h"
#ifndef PLATFORM_N64 #ifndef PLATFORM_N64
#include "net/net.h" extern f32 fabsf(f32);
#include "system.h"
#include "utils.h"
static inline void lerpcoord(struct coord *c, const struct coord *a, const struct coord *b, const f32 t) {
c->x = lerpf(a->x, b->x, t);
c->y = lerpf(a->y, b->y, t);
c->z = lerpf(a->z, b->z, t);
}
static void bwalkUpdateRemote(void)
{
struct player *pl = g_Vars.currentplayer;
const struct netplayermove *inmove = &pl->client->inmove[0];
const struct netplayermove *inmoveprev = &pl->client->inmove[1];
struct coord delta;
u16 cdtype = CDTYPE_ALL;
s32 moveticks = inmove->tick - inmoveprev->tick;
if (moveticks > g_NetInterpTicks) {
moveticks = g_NetInterpTicks;
}
pl->client->inmovetick = inmove->tick;
pl->bondshotspeed.x = 0.f;
pl->bondshotspeed.y = 0.f;
pl->bondshotspeed.z = 0.f;
pl->bondbreathing = 0.f;
const bool forcepos = !inmoveprev->tick ||
(inmove->ucmd & UCMD_FL_FORCEPOS) ||
(fabsf(pl->prop->pos.x - inmove->pos.x) > 512.f) ||
(fabsf(pl->prop->pos.y - inmove->pos.y) > 512.f) ||
(fabsf(pl->prop->pos.z - inmove->pos.z) > 512.f);
delta.x = 0.f;
delta.y = 0.f;
delta.z = 0.f;
// extrapolate
bwalk0f0c69b8();
if (forcepos) {
// no interpolation, set position and lock the lad in place
pl->prop->pos = inmove->pos;
pl->client->lerpticks = g_NetInterpTicks + 1;
cdtype = CDTYPE_PLAYERS; // don't get stuck in the local client
} else if (!moveticks) {
// duplicate move, reposition to correct coords
delta.x = inmove->pos.x - pl->prop->pos.x;
delta.x = inmove->pos.y - pl->prop->pos.y;
delta.x = inmove->pos.z - pl->prop->pos.z;
bwalk0f0c63bc(&delta, pl->swaytarget == 0.0f, cdtype);
} else if (pl->client->lerpticks <= moveticks) {
// lerp towards the correct position
const f32 dt = (f32)1.f / (f32)moveticks;
delta.x = g_Vars.lvupdate60freal * (inmove->pos.x - pl->prop->pos.x) * dt;
delta.y = g_Vars.lvupdate60freal * (inmove->pos.y - pl->prop->pos.y) * dt;
delta.z = g_Vars.lvupdate60freal * (inmove->pos.z - pl->prop->pos.z) * dt;
bwalk0f0c63bc(&delta, pl->swaytarget == 0.0f, cdtype);
pl->client->lerpticks += g_Vars.lvupdate60;
}
}
#endif #endif
void bwalkInit(void) void bwalkInit(void)
@@ -299,6 +237,47 @@ s32 bwalkTryMoveUpwards(f32 amount)
return result; return result;
} }
bool bwalkCanMoveUpwards(f32 amount)
{
bool result;
struct coord newpos;
RoomNum rooms[8];
u32 stack;
u32 types;
f32 ymax;
f32 ymin;
f32 radius;
if (g_Vars.currentplayer->floorflags & GEOFLAG_SLOPE) {
g_Vars.enableslopes = false;
} else {
g_Vars.enableslopes = true;
}
newpos.x = g_Vars.currentplayer->prop->pos.x;
newpos.y = g_Vars.currentplayer->prop->pos.y + amount;
newpos.z = g_Vars.currentplayer->prop->pos.z;
types = g_Vars.bondcollisions ? CDTYPE_ALL : CDTYPE_BG;
playerGetBbox(g_Vars.currentplayer->prop, &radius, &ymax, &ymin);
func0f065e74(&g_Vars.currentplayer->prop->pos, g_Vars.currentplayer->prop->rooms, &newpos, rooms);
bmoveFindEnteredRoomsByPos(g_Vars.currentplayer, &newpos, rooms);
propSetPerimEnabled(g_Vars.currentplayer->prop, false);
ymin -= 0.1f;
result = cdTestVolume(&newpos, radius, rooms, types, CHECKVERTICAL_YES,
ymax - g_Vars.currentplayer->prop->pos.y,
ymin - g_Vars.currentplayer->prop->pos.y);
propSetPerimEnabled(g_Vars.currentplayer->prop, true);
g_Vars.enableslopes = true;
return (result == CDRESULT_NOCOLLISION);
}
bool bwalkCalculateNewPosition(struct coord *vel, f32 rotateamount, bool apply, f32 extrawidth, s32 checktypes) bool bwalkCalculateNewPosition(struct coord *vel, f32 rotateamount, bool apply, f32 extrawidth, s32 checktypes)
{ {
s32 result = CDRESULT_NOCOLLISION; s32 result = CDRESULT_NOCOLLISION;
@@ -475,7 +454,7 @@ bool bwalkCalculateNewPositionWithPush(struct coord *delta, f32 rotateamount, bo
} }
} else if (chr->chrflags & CHRCFLAG_PUSHABLE) { } else if (chr->chrflags & CHRCFLAG_PUSHABLE) {
if (g_Vars.antiplayernum < 0 if (g_Vars.antiplayernum < 0
|| PLAYER_IS_NOT_ANTI(g_Vars.currentplayer) || g_Vars.currentplayer != g_Vars.anti
|| (chr->hidden & CHRHFLAG_ANTINONINTERACTABLE) == 0) { || (chr->hidden & CHRHFLAG_ANTINONINTERACTABLE) == 0) {
canpush = true; canpush = true;
} }
@@ -809,7 +788,7 @@ void bwalkUpdateVertical(void)
// Maybe reset counter-op's radius - not sure why // Maybe reset counter-op's radius - not sure why
// Maybe it gets set to 0 when they die? // Maybe it gets set to 0 when they die?
if (g_Vars.antiplayernum >= 0 if (g_Vars.antiplayernum >= 0
&& PLAYER_IS_ANTI(g_Vars.currentplayer) && g_Vars.currentplayer == g_Vars.anti
&& g_Vars.currentplayer->bond2.radius != 30 && g_Vars.currentplayer->bond2.radius != 30
&& cdTestVolume(&g_Vars.currentplayer->prop->pos, 30, g_Vars.currentplayer->prop->rooms, CDTYPE_ALL, CHECKVERTICAL_YES, ymax - g_Vars.currentplayer->prop->pos.y, ymin - g_Vars.currentplayer->prop->pos.y)) { && cdTestVolume(&g_Vars.currentplayer->prop->pos, 30, g_Vars.currentplayer->prop->rooms, CDTYPE_ALL, CHECKVERTICAL_YES, ymax - g_Vars.currentplayer->prop->pos.y, ymin - g_Vars.currentplayer->prop->pos.y)) {
g_Vars.currentplayer->prop->chr->radius = 30; g_Vars.currentplayer->prop->chr->radius = 30;
@@ -1132,7 +1111,7 @@ void bwalkUpdateVertical(void)
SFX_JO_LANDING_05B7 SFX_JO_LANDING_05B7
}; };
psCreate(NULL, g_Vars.currentplayer->prop, sounds[random() % 3], psCreate(NULL, g_Vars.currentplayer->prop, sounds[rngRandom() % 3],
-1, -1, PSFLAG_0400 | PSFLAG_IGNOREROOMS, 0, PSTYPE_NONE, 0, -1, NULL, -1, -1, -1, -1); -1, -1, PSFLAG_0400 | PSFLAG_IGNOREROOMS, 0, PSTYPE_NONE, 0, -1, NULL, -1, -1, -1, -1);
} }
} }
@@ -1230,6 +1209,41 @@ void bwalkUpdateCrouchOffsetReal(void)
} }
} }
bool bwalkCanUncrouch(void)
{
f32 targetoffset = 0;
if (g_Vars.currentplayer->crouchpos == CROUCHPOS_SQUAT) {
targetoffset = -90;
} else if (g_Vars.currentplayer->crouchpos == CROUCHPOS_DUCK) {
targetoffset = -45;
}
if (targetoffset != g_Vars.currentplayer->crouchoffset) {
f32 prevcrouchoffset = g_Vars.currentplayer->crouchoffset;
f32 prevcrouchoffsetreal = g_Vars.currentplayer->crouchoffsetreal;
f32 prevcrouchoffsetsmall = g_Vars.currentplayer->crouchoffsetsmall;
f32 prevcrouchoffsetrealsmall = g_Vars.currentplayer->crouchoffsetrealsmall;
f32 prevcrouchspeed = g_Vars.currentplayer->crouchspeed;
g_Vars.currentplayer->crouchoffset = targetoffset;
bwalkUpdateCrouchOffsetReal();
const bool result = bwalkCanMoveUpwards(0);
g_Vars.currentplayer->crouchoffset = prevcrouchoffset;
g_Vars.currentplayer->crouchoffsetreal = prevcrouchoffsetreal;
g_Vars.currentplayer->crouchoffsetsmall = prevcrouchoffsetsmall;
g_Vars.currentplayer->crouchoffsetrealsmall = prevcrouchoffsetrealsmall;
g_Vars.currentplayer->crouchspeed = prevcrouchspeed;
return result;
}
return true;
}
void bwalkUpdateCrouchOffset(void) void bwalkUpdateCrouchOffset(void)
{ {
f32 targetoffset = 0; f32 targetoffset = 0;
@@ -1829,14 +1843,7 @@ void bwalkTick(void)
bwalkUpdatePrevPos(); bwalkUpdatePrevPos();
bwalkUpdateTheta(); bwalkUpdateTheta();
bmoveUpdateVerta(); bmoveUpdateVerta();
#ifndef PLATFORM_N64
if (g_Vars.currentplayer->isremote) {
bwalkUpdateRemote();
} else
#endif
bwalk0f0c69b8(); bwalk0f0c69b8();
bwalkUpdateVertical(); bwalkUpdateVertical();
#if VERSION >= VERSION_NTSC_1_0 #if VERSION >= VERSION_NTSC_1_0
+1 -5
View File
@@ -138,8 +138,6 @@ void bossfileLoad(void)
g_BossFile.usingmultipletunes = savebufferReadBits(&buffer, 1); g_BossFile.usingmultipletunes = savebufferReadBits(&buffer, 1);
g_AltTitleUnlocked = savebufferReadBits(&buffer, 1); g_AltTitleUnlocked = savebufferReadBits(&buffer, 1);
g_AltTitleEnabled = savebufferReadBits(&buffer, 1); g_AltTitleEnabled = savebufferReadBits(&buffer, 1);
func0f0d54c4(&buffer);
} }
if (failed) { if (failed) {
@@ -168,7 +166,7 @@ void bossfileSave(void)
savebufferOr(&buffer, g_Vars.language, 4); savebufferOr(&buffer, g_Vars.language, 4);
for (i = 0; i < ARRAYCOUNT(g_BossFile.teamnames); i++) { for (i = 0; i < ARRAYCOUNT(g_BossFile.teamnames); i++) {
func0f0d55a4(&buffer, g_BossFile.teamnames[i]); savebufferWriteString(&buffer, g_BossFile.teamnames[i]);
} }
if (g_BossFile.tracknum == -1) { if (g_BossFile.tracknum == -1) {
@@ -185,8 +183,6 @@ void bossfileSave(void)
savebufferOr(&buffer, g_AltTitleUnlocked, 1); savebufferOr(&buffer, g_AltTitleUnlocked, 1);
savebufferOr(&buffer, g_AltTitleEnabled, 1); savebufferOr(&buffer, g_AltTitleEnabled, 1);
func0f0d54c4(&buffer);
fileid = bossfileFindFileId(); fileid = bossfileFindFileId();
if (fileid == 0) { if (fileid == 0) {
+52 -43
View File
@@ -185,13 +185,13 @@ void botReset(struct chrdata *chr, u8 respawning)
aibot->waypoints[0] = NULL; aibot->waypoints[0] = NULL;
aibot->numwaystepstotarget = 0; aibot->numwaystepstotarget = 0;
aibot->random1 = random(); aibot->random1 = rngRandom();
aibot->random1ttl60 = 0; aibot->random1ttl60 = 0;
aibot->targetcloaktimer60 = 0; aibot->targetcloaktimer60 = 0;
aibot->canseecloaked = 0; aibot->canseecloaked = 0;
aibot->rcpcloaktimer60 = 0; aibot->rcpcloaktimer60 = 0;
aibot->random2ttl60 = 0; aibot->random2ttl60 = 0;
aibot->random2 = random(); aibot->random2 = rngRandom();
aibot->randomfrac = RANDOMFRAC(); aibot->randomfrac = RANDOMFRAC();
aibot->cheap = 0; aibot->cheap = 0;
@@ -262,12 +262,21 @@ void botSpawn(struct chrdata *chr, u8 respawning)
func0f02e9a0(chr, 0); func0f02e9a0(chr, 0);
#ifndef PLATFORM_N64 #ifndef PLATFORM_N64
if ((g_MpSetup.options & MPOPTION_SPAWNWITHWEAPON) if (g_Vars.normmplayerisrunning
&& (g_MpSetup.options & MPOPTION_SPAWNWITHWEAPON)
&& g_MpSetup.weapons[0] != MPWEAPON_NONE && g_MpSetup.weapons[0] != MPWEAPON_NONE
&& g_MpSetup.weapons[0] != MPWEAPON_DISABLED) { && g_MpSetup.weapons[0] != MPWEAPON_DISABLED
&& g_MpSetup.weapons[0] != MPWEAPON_SHIELD) {
struct mpweapon *mpweapon = &g_MpWeapons[g_MpSetup.weapons[0]]; struct mpweapon *mpweapon = &g_MpWeapons[g_MpSetup.weapons[0]];
botinvGiveSingleWeapon(chr, mpweapon->weaponnum); botinvGiveSingleWeapon(chr, mpweapon->weaponnum);
botactGiveAmmoByType(aibot, mpweapon->priammotype - 1, mpweapon->priammoqty / 2); const s32 ammotype = (g_MpSetup.weapons[0] == MPWEAPON_COMBATBOOST) ? AMMOTYPE_BOOST : mpweapon->priammotype;
if (ammotype) {
s32 startammo = mpweapon->priammoqty / 2;
if (startammo == 0) {
startammo = 1;
}
botactGiveAmmoByType(aibot, ammotype, startammo);
}
botinvSwitchToWeapon(chr, mpweapon->weaponnum, FUNC_PRIMARY); botinvSwitchToWeapon(chr, mpweapon->weaponnum, FUNC_PRIMARY);
} }
#endif #endif
@@ -1409,8 +1418,8 @@ void bot0f192a74(struct chrdata *chr)
aibot->random3ttl60 -= g_Vars.lvupdate60; aibot->random3ttl60 -= g_Vars.lvupdate60;
if (aibot->random3ttl60 <= 0) { if (aibot->random3ttl60 <= 0) {
aibot->random3 = random(); aibot->random3 = rngRandom();
aibot->random3ttl60 = TICKS(20) + random() % TICKS(20); aibot->random3ttl60 = TICKS(20) + rngRandom() % TICKS(20);
} }
if (g_Vars.lvupdate240 > 0) { if (g_Vars.lvupdate240 > 0) {
@@ -1551,7 +1560,7 @@ void botChooseGeneralTarget(struct chrdata *botchr)
// However, the usage of canseecloaked appears to be botched. // However, the usage of canseecloaked appears to be botched.
// It is implemented in botIsTargetInvisible, but that function is not // It is implemented in botIsTargetInvisible, but that function is not
// called here while canseecloaked is true. // called here while canseecloaked is true.
if (random() % TICKS(4 * 60 * 60) < g_MpNumChrs * g_Vars.lvupdate60) { if (rngRandom() % TICKS(4 * 60 * 60) < g_MpNumChrs * g_Vars.lvupdate60) {
aibot->canseecloaked = true; aibot->canseecloaked = true;
} }
@@ -1746,7 +1755,7 @@ s32 botFindTeammateToFollow(struct chrdata *chr, f32 range)
if ((g_MpSetup.options & MPOPTION_TEAMSENABLED) if ((g_MpSetup.options & MPOPTION_TEAMSENABLED)
&& chr->myaction != MA_AIBOTFOLLOW && chr->myaction != MA_AIBOTFOLLOW
&& (random() % 100) < chr->aibot->followchance) { && (rngRandom() % 100) < chr->aibot->followchance) {
f32 closestdistance = 0; f32 closestdistance = 0;
s32 closestplayernum = -1; s32 closestplayernum = -1;
s32 i; s32 i;
@@ -1884,8 +1893,8 @@ struct prop *botFindPickup(struct chrdata *chr, s32 criteria)
for (i = 0; i < ARRAYCOUNT(weaponnums); i++) { for (i = 0; i < ARRAYCOUNT(weaponnums); i++) {
if (weaponnums[i] > WEAPON_UNARMED && weaponnums[i] == weapon->weaponnum) { if (weaponnums[i] > WEAPON_UNARMED && weaponnums[i] == weapon->weaponnum) {
if (random() % 16) { if (rngRandom() % 16) {
if (weapproplist[i] == NULL || sqdist1 < weapdistlist[i] || random() % 16 == 0) { if (weapproplist[i] == NULL || sqdist1 < weapdistlist[i] || rngRandom() % 16 == 0) {
weapproplist[i] = prop; weapproplist[i] = prop;
weapdistlist[i] = sqdist1; weapdistlist[i] = sqdist1;
} }
@@ -1896,8 +1905,8 @@ struct prop *botFindPickup(struct chrdata *chr, s32 criteria)
ammotype = botactGetAmmoTypeByFunction(weapon->weaponnum, FUNC_PRIMARY); ammotype = botactGetAmmoTypeByFunction(weapon->weaponnum, FUNC_PRIMARY);
if (ammotype > 0 && random() % 16) { if (ammotype > 0 && rngRandom() % 16) {
if (ammoproplist[ammotype] == NULL || sqdist1 < ammodistlist[ammotype] || random() % 16 == 0) { if (ammoproplist[ammotype] == NULL || sqdist1 < ammodistlist[ammotype] || rngRandom() % 16 == 0) {
ammoproplist[ammotype] = prop; ammoproplist[ammotype] = prop;
ammodistlist[ammotype] = sqdist1; ammodistlist[ammotype] = sqdist1;
} }
@@ -1920,8 +1929,8 @@ struct prop *botFindPickup(struct chrdata *chr, s32 criteria)
if (weaponnum > 0) { if (weaponnum > 0) {
for (j = 0; j < ARRAYCOUNT(weaponnums); j++) { for (j = 0; j < ARRAYCOUNT(weaponnums); j++) {
if (weaponnums[j] > WEAPON_UNARMED && weaponnum == weaponnums[j]) { if (weaponnums[j] > WEAPON_UNARMED && weaponnum == weaponnums[j]) {
if (random() % 16) { if (rngRandom() % 16) {
if (weapproplist[j] == NULL || sqdist2 < weapdistlist[j] || random() % 16 == 0) { if (weapproplist[j] == NULL || sqdist2 < weapdistlist[j] || rngRandom() % 16 == 0) {
weapproplist[j] = prop; weapproplist[j] = prop;
weapdistlist[j] = sqdist2; weapdistlist[j] = sqdist2;
} }
@@ -1931,8 +1940,8 @@ struct prop *botFindPickup(struct chrdata *chr, s32 criteria)
} }
} }
if (random() % 16) { if (rngRandom() % 16) {
if (ammoproplist[ammotype] == NULL || sqdist2 < ammodistlist[ammotype] || random() % 16 == 0) { if (ammoproplist[ammotype] == NULL || sqdist2 < ammodistlist[ammotype] || rngRandom() % 16 == 0) {
ammoproplist[ammotype] = prop; ammoproplist[ammotype] = prop;
ammodistlist[ammotype] = sqdist2; ammodistlist[ammotype] = sqdist2;
} }
@@ -1944,11 +1953,11 @@ struct prop *botFindPickup(struct chrdata *chr, s32 criteria)
if (weaponnums[i] == WEAPON_MPSHIELD) { if (weaponnums[i] == WEAPON_MPSHIELD) {
sqdist2 = chrGetSquaredDistanceToCoord(chr, &prop->pos); sqdist2 = chrGetSquaredDistanceToCoord(chr, &prop->pos);
if (random() % 16 == 0) { if (rngRandom() % 16 == 0) {
break; break;
} }
if (weapproplist[i] == NULL || sqdist2 < weapdistlist[i] || random() % 16 == 0) { if (weapproplist[i] == NULL || sqdist2 < weapdistlist[i] || rngRandom() % 16 == 0) {
weapproplist[i] = prop; weapproplist[i] = prop;
weapdistlist[i] = sqdist2; weapdistlist[i] = sqdist2;
} }
@@ -2399,8 +2408,8 @@ void botTickUnpaused(struct chrdata *chr)
aibot->random2ttl60 -= g_Vars.lvupdate60; aibot->random2ttl60 -= g_Vars.lvupdate60;
if (aibot->random2ttl60 < 0) { if (aibot->random2ttl60 < 0) {
aibot->random2ttl60 = TICKS(1800) + random() % TICKS(60 * 240); aibot->random2ttl60 = TICKS(1800) + rngRandom() % TICKS(60 * 240);
aibot->random2 = random(); aibot->random2 = rngRandom();
aibot->randomfrac = RANDOMFRAC(); aibot->randomfrac = RANDOMFRAC();
} }
@@ -2531,7 +2540,7 @@ void botTickUnpaused(struct chrdata *chr)
if (g_MpSetup.scenario == MPSCENARIO_HOLDTHEBRIEFCASE) { if (g_MpSetup.scenario == MPSCENARIO_HOLDTHEBRIEFCASE) {
s32 numgetting = botGetCountInTeamDoingCommand(chr, AIBOTCMD_GETCASE2, false); s32 numgetting = botGetCountInTeamDoingCommand(chr, AIBOTCMD_GETCASE2, false);
if (numgetting <= 0 || (numgetting < (teamsize + 1) / 2 || random() % 100 < 66)) { if (numgetting <= 0 || (numgetting < (teamsize + 1) / 2 || rngRandom() % 100 < 66)) {
botApplyScenarioCommand(chr, AIBOTCMD_GETCASE2); botApplyScenarioCommand(chr, AIBOTCMD_GETCASE2);
} else { } else {
botApplyScenarioCommand(chr, AIBOTCMD_NORMAL); botApplyScenarioCommand(chr, AIBOTCMD_NORMAL);
@@ -2539,7 +2548,7 @@ void botTickUnpaused(struct chrdata *chr)
} else if (g_MpSetup.scenario == MPSCENARIO_HACKERCENTRAL) { } else if (g_MpSetup.scenario == MPSCENARIO_HACKERCENTRAL) {
s32 numbots = botGetCountInTeamDoingCommand(chr, AIBOTCMD_DOWNLOAD, false); s32 numbots = botGetCountInTeamDoingCommand(chr, AIBOTCMD_DOWNLOAD, false);
if (aibot->hasuplink || numbots <= 0 || (numbots < (teamsize + 1) / 2 || random() % 100 < 50)) { if (aibot->hasuplink || numbots <= 0 || (numbots < (teamsize + 1) / 2 || rngRandom() % 100 < 50)) {
botApplyScenarioCommand(chr, AIBOTCMD_DOWNLOAD); botApplyScenarioCommand(chr, AIBOTCMD_DOWNLOAD);
} else { } else {
botApplyScenarioCommand(chr, AIBOTCMD_NORMAL); botApplyScenarioCommand(chr, AIBOTCMD_NORMAL);
@@ -2547,7 +2556,7 @@ void botTickUnpaused(struct chrdata *chr)
} else if (g_MpSetup.scenario == MPSCENARIO_POPACAP) { } else if (g_MpSetup.scenario == MPSCENARIO_POPACAP) {
s32 numchasing = botGetCountInTeamDoingCommand(chr, AIBOTCMD_POPCAP, false); s32 numchasing = botGetCountInTeamDoingCommand(chr, AIBOTCMD_POPCAP, false);
if (numchasing <= 0 || numchasing < (teamsize + 1) / 2 || random() % 100 < 50) { if (numchasing <= 0 || numchasing < (teamsize + 1) / 2 || rngRandom() % 100 < 50) {
botApplyScenarioCommand(chr, AIBOTCMD_POPCAP); botApplyScenarioCommand(chr, AIBOTCMD_POPCAP);
} else { } else {
botApplyScenarioCommand(chr, AIBOTCMD_NORMAL); botApplyScenarioCommand(chr, AIBOTCMD_NORMAL);
@@ -2563,7 +2572,7 @@ void botTickUnpaused(struct chrdata *chr)
if (numinhill <= 0 || numinhill < teamsize / 2) { if (numinhill <= 0 || numinhill < teamsize / 2) {
botApplyScenarioCommand(chr, AIBOTCMD_HOLDHILL); botApplyScenarioCommand(chr, AIBOTCMD_HOLDHILL);
} else if (numinhill > botGetNumOpponentsInHill(chr)) { } else if (numinhill > botGetNumOpponentsInHill(chr)) {
if (random() % 100 < 50) { if (rngRandom() % 100 < 50) {
botApplyScenarioCommand(chr, AIBOTCMD_DEFHILL); botApplyScenarioCommand(chr, AIBOTCMD_DEFHILL);
} else { } else {
botApplyScenarioCommand(chr, AIBOTCMD_NORMAL); botApplyScenarioCommand(chr, AIBOTCMD_NORMAL);
@@ -2579,13 +2588,13 @@ void botTickUnpaused(struct chrdata *chr)
if (botShouldReturnCtcToken(chr)) { if (botShouldReturnCtcToken(chr)) {
botApplyScenarioCommand(chr, AIBOTCMD_GETCASE); botApplyScenarioCommand(chr, AIBOTCMD_GETCASE);
} else if (botIsChrsCtcTokenHeld(chr)) { } else if (botIsChrsCtcTokenHeld(chr)) {
if (random() % 100 < 30) { if (rngRandom() % 100 < 30) {
botApplyScenarioCommand(chr, AIBOTCMD_GETCASE); botApplyScenarioCommand(chr, AIBOTCMD_GETCASE);
} else { } else {
botApplyScenarioCommand(chr, AIBOTCMD_SAVECASE); botApplyScenarioCommand(chr, AIBOTCMD_SAVECASE);
} }
} else { } else {
if (random() % 100 < 70 || numgetting <= 0) { if (rngRandom() % 100 < 70 || numgetting <= 0) {
botApplyScenarioCommand(chr, AIBOTCMD_GETCASE); botApplyScenarioCommand(chr, AIBOTCMD_GETCASE);
} else { } else {
botApplyScenarioCommand(chr, AIBOTCMD_SAVECASE); botApplyScenarioCommand(chr, AIBOTCMD_SAVECASE);
@@ -2599,7 +2608,7 @@ void botTickUnpaused(struct chrdata *chr)
if (botShouldReturnCtcToken(chr)) { if (botShouldReturnCtcToken(chr)) {
botApplyScenarioCommand(chr, AIBOTCMD_GETCASE); botApplyScenarioCommand(chr, AIBOTCMD_GETCASE);
} else if (botIsChrsCtcTokenHeld(chr)) { } else if (botIsChrsCtcTokenHeld(chr)) {
if (numsaving <= 0 || random() % 100 < 70) { if (numsaving <= 0 || rngRandom() % 100 < 70) {
botApplyScenarioCommand(chr, AIBOTCMD_SAVECASE); botApplyScenarioCommand(chr, AIBOTCMD_SAVECASE);
} else { } else {
botApplyScenarioCommand(chr, AIBOTCMD_GETCASE); botApplyScenarioCommand(chr, AIBOTCMD_GETCASE);
@@ -2608,9 +2617,9 @@ void botTickUnpaused(struct chrdata *chr)
botApplyScenarioCommand(chr, AIBOTCMD_GETCASE); botApplyScenarioCommand(chr, AIBOTCMD_GETCASE);
} else if (numsaving <= 0 || numsaving < teamsize / 4) { } else if (numsaving <= 0 || numsaving < teamsize / 4) {
botApplyScenarioCommand(chr, AIBOTCMD_SAVECASE); botApplyScenarioCommand(chr, AIBOTCMD_SAVECASE);
} else if (random() % 100 < 30) { } else if (rngRandom() % 100 < 30) {
botApplyScenarioCommand(chr, AIBOTCMD_GETCASE); botApplyScenarioCommand(chr, AIBOTCMD_GETCASE);
} else if (random() % 100 < 30) { } else if (rngRandom() % 100 < 30) {
botApplyScenarioCommand(chr, AIBOTCMD_SAVECASE); botApplyScenarioCommand(chr, AIBOTCMD_SAVECASE);
} else { } else {
botApplyScenarioCommand(chr, AIBOTCMD_NORMAL); botApplyScenarioCommand(chr, AIBOTCMD_NORMAL);
@@ -2619,7 +2628,7 @@ void botTickUnpaused(struct chrdata *chr)
} }
// Consider changing command in 20 to 60 seconds // Consider changing command in 20 to 60 seconds
aibot->commandtimer60 = TICKS(1200) + random() % TICKS(2400); aibot->commandtimer60 = TICKS(1200) + rngRandom() % TICKS(2400);
} }
} }
@@ -2716,7 +2725,7 @@ void botTickUnpaused(struct chrdata *chr)
s32 index; s32 index;
s32 i; s32 i;
index = random() % numtokens; index = rngRandom() % numtokens;
i = (index + 1) % numtokens; i = (index + 1) % numtokens;
@@ -2744,7 +2753,7 @@ void botTickUnpaused(struct chrdata *chr)
aibot->gotoprop = tokens[index]; aibot->gotoprop = tokens[index];
} else if (botCanFollow(chr, tokens[index]->chr)) { } else if (botCanFollow(chr, tokens[index]->chr)) {
newaction = MA_AIBOTFOLLOW; newaction = MA_AIBOTFOLLOW;
aibot->canbreakfollow = random() % 4 == 0; aibot->canbreakfollow = rngRandom() % 4 == 0;
aibot->followingplayernum = mpPlayerGetIndex(tokens[index]->chr); aibot->followingplayernum = mpPlayerGetIndex(tokens[index]->chr);
} }
} }
@@ -2762,7 +2771,7 @@ void botTickUnpaused(struct chrdata *chr)
// Held by a teammate - follow/protect them // Held by a teammate - follow/protect them
if (botCanFollow(chr, tokenchr)) { if (botCanFollow(chr, tokenchr)) {
newaction = MA_AIBOTFOLLOW; newaction = MA_AIBOTFOLLOW;
aibot->canbreakfollow = random() % 4 == 0; aibot->canbreakfollow = rngRandom() % 4 == 0;
aibot->followingplayernum = mpPlayerGetIndex(tokenchr); aibot->followingplayernum = mpPlayerGetIndex(tokenchr);
} }
} else { } else {
@@ -2852,7 +2861,7 @@ void botTickUnpaused(struct chrdata *chr)
// Uplink is held by teammate - protect them // Uplink is held by teammate - protect them
if (botCanFollow(chr, uplinkchr)) { if (botCanFollow(chr, uplinkchr)) {
newaction = MA_AIBOTFOLLOW; newaction = MA_AIBOTFOLLOW;
aibot->canbreakfollow = random() % 4 == 0; aibot->canbreakfollow = rngRandom() % 4 == 0;
aibot->followingplayernum = mpPlayerGetIndex(uplinkchr); aibot->followingplayernum = mpPlayerGetIndex(uplinkchr);
} }
} else { } else {
@@ -2883,7 +2892,7 @@ void botTickUnpaused(struct chrdata *chr)
// Briefcase is held by teammate - protect them // Briefcase is held by teammate - protect them
if (botCanFollow(chr, tokenchr)) { if (botCanFollow(chr, tokenchr)) {
newaction = MA_AIBOTFOLLOW; newaction = MA_AIBOTFOLLOW;
aibot->canbreakfollow = random() % 4 == 0; aibot->canbreakfollow = rngRandom() % 4 == 0;
aibot->followingplayernum = mpPlayerGetIndex(tokenchr); aibot->followingplayernum = mpPlayerGetIndex(tokenchr);
} }
} else if (!botIsTargetInvisible(chr, tokenchr) && botPassesCowardCheck(chr, tokenchr)) { } else if (!botIsTargetInvisible(chr, tokenchr) && botPassesCowardCheck(chr, tokenchr)) {
@@ -2911,7 +2920,7 @@ void botTickUnpaused(struct chrdata *chr)
// Victim is a teammate - protect them // Victim is a teammate - protect them
if (botCanFollow(chr, victimchr)) { if (botCanFollow(chr, victimchr)) {
newaction = MA_AIBOTFOLLOW; newaction = MA_AIBOTFOLLOW;
aibot->canbreakfollow = random() % 4 == 0; aibot->canbreakfollow = rngRandom() % 4 == 0;
aibot->followingplayernum = mpPlayerGetIndex(victimchr); aibot->followingplayernum = mpPlayerGetIndex(victimchr);
} }
} else { } else {
@@ -2936,13 +2945,13 @@ void botTickUnpaused(struct chrdata *chr)
// Current bot has the briefcase - follow a teammate for protection // Current bot has the briefcase - follow a teammate for protection
s32 playernum = -1; s32 playernum = -1;
if (random() % 100 < 66) { if (rngRandom() % 100 < 66) {
playernum = botFindTeammateToFollow(chr, 100000); playernum = botFindTeammateToFollow(chr, 100000);
} }
if (playernum >= 0) { if (playernum >= 0) {
newaction = MA_AIBOTFOLLOW; newaction = MA_AIBOTFOLLOW;
aibot->canbreakfollow = random() % 4 == 0; aibot->canbreakfollow = rngRandom() % 4 == 0;
aibot->followingplayernum = playernum; aibot->followingplayernum = playernum;
} }
} }
@@ -2954,13 +2963,13 @@ void botTickUnpaused(struct chrdata *chr)
// Current bot is the victim - follow a teammate for protection // Current bot is the victim - follow a teammate for protection
s32 playernum = -1; s32 playernum = -1;
if (random() % 100 < 66) { if (rngRandom() % 100 < 66) {
playernum = botFindTeammateToFollow(chr, 100000); playernum = botFindTeammateToFollow(chr, 100000);
} }
if (playernum >= 0) { if (playernum >= 0) {
newaction = MA_AIBOTFOLLOW; newaction = MA_AIBOTFOLLOW;
aibot->canbreakfollow = random() % 4 == 0; aibot->canbreakfollow = rngRandom() % 4 == 0;
aibot->followingplayernum = playernum; aibot->followingplayernum = playernum;
} }
} }
@@ -3087,7 +3096,7 @@ void botTickUnpaused(struct chrdata *chr)
if (playernum >= 0) { if (playernum >= 0) {
newaction = MA_AIBOTFOLLOW; newaction = MA_AIBOTFOLLOW;
aibot->canbreakfollow = random() % 4 == 0; aibot->canbreakfollow = rngRandom() % 4 == 0;
aibot->followingplayernum = playernum; aibot->followingplayernum = playernum;
} }
} }
@@ -3427,7 +3436,7 @@ void botTickUnpaused(struct chrdata *chr)
aibot->punchtimer60[0] = TICKS(30); aibot->punchtimer60[0] = TICKS(30);
} }
if (random() % 3 == 0) { if (rngRandom() % 3 == 0) {
aibot->punchtimer60[1] = aibot->punchtimer60[0] - TICKS(20); aibot->punchtimer60[1] = aibot->punchtimer60[0] - TICKS(20);
} }
break; break;
+1 -1
View File
@@ -223,7 +223,7 @@ bool botactShootFarsight(struct chrdata *chr, s32 arg1, struct coord *vector, st
aibot = chr->aibot; aibot = chr->aibot;
if (aibot->weaponnum == WEAPON_FARSIGHT) { if (aibot->weaponnum == WEAPON_FARSIGHT) {
rand = random() % 100; rand = rngRandom() % 100;
// 3 in 10 chance of this passing // 3 in 10 chance of this passing
if (rand < 30) { if (rand < 30) {
+1 -1
View File
@@ -149,7 +149,7 @@ void botcmdTickDistMode(struct chrdata *chr)
if (!insight) { if (!insight) {
newmode = BOTDISTMODE_ADVANCE; newmode = BOTDISTMODE_ADVANCE;
aibot->distoverrideprop = targetprop; aibot->distoverrideprop = targetprop;
aibot->distoverridetimer60 = TICKS(20) + (random() % TICKS(120)); aibot->distoverridetimer60 = TICKS(20) + (rngRandom() % TICKS(120));
} else if (aibot->distoverrideprop) { } else if (aibot->distoverrideprop) {
if (g_Vars.lvupdate60 < aibot->distoverridetimer60) { if (g_Vars.lvupdate60 < aibot->distoverridetimer60) {
aibot->distoverridetimer60 -= g_Vars.lvupdate60; aibot->distoverridetimer60 -= g_Vars.lvupdate60;
Loaded 100 of 249 files, more files were not shown because too many files have changed in this diff. Show more